Skip to content

WebSocket wrappers discard all query args; ReasoningWs dials literal /ws/ml/reasoning/{{.id}} #407

Description

@sneg55

WebSocket wrappers discard every query argument, and ReasoningWs dials the literal template path /ws/ml/reasoning/{{.id}}

Context: API Makeathon participant. Found reviewing the official clients; independently confirmed by a second review pass. Root cause is the generator template cmd/tmpl/websocket.tmpl.

Every generated WebSocket wrapper accepts configuration parameters in its signature but never serializes them into the dialed URL. Unlike the REST wrappers, the WS wrappers never call expandURL.

Evidence

paths.go (CommandsWs ~10605):

func (s *ModelingService) CommandsWs(videoResWidth int, videoResHeight int, fps int,
    unlockedFramerate bool, postEffect PostEffectType, webrtc bool, pool string,
    showGrid bool, replay string, apicallId string, orderIndependentTransparency bool,
    pr int, body any) (*websocket.Conn, error) {
    path := "/ws/modeling/commands"
    targetURL := resolveRelative(s.client.server, path)   // none of the 13 params used
    ...
    conn, _, err := websocket.DefaultDialer.Dial(strings.ReplaceAll(targetURL, "https://", "wss://"), headers)

ReasoningWs (~10571) is worse: path := "/ws/ml/reasoning/{{.id}}" is dialed verbatim. REST paths call expandURL to substitute {{.id}}; the WS wrapper skips that step, so the dialed URL is literally wss://api.zoo.dev/ws/ml/reasoning/{{.id}} and id is silently discarded. Affected: CopilotWs, CommandsWs, CreateTerm, ReasoningWs. The body any parameter is dead in all of them.

Concrete failure

  • ReasoningWs(id, ...) can never reach a valid per-id endpoint (404 on a garbage path) for any input.
  • CommandsWs(1024, 768, ...webrtc=true...) connects but silently gets the server defaults; the video resolution, fps, webrtc, pool, replay, and copilot conversation_id never leave the process. Nothing errors. The Rust client sends all of these correctly (kittycad.rs/kittycad/src/modeling.rs).

Verify

Point the client at an httptest WebSocket server and assert r.URL.RawQuery on the server side for CommandsWs(...) with non-default values: it is empty. For ReasoningWs, the dial target still contains {{.id}}.

Suggested fix

Have the WS template build the query string from its parameters and call expandURL for path templating, mirroring the REST template.

Environment

Reviewed against the current main of KittyCAD/kittycad.go.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions