Skip to content

chore: sync fantasy fork with upstream v0.40.0 and openai-go with v3.50.0 - #27981

Merged
ibetitsmike merged 2 commits into
mainfrom
mike/fantasy-upstream-v0.40-sync
Aug 11, 2026
Merged

chore: sync fantasy fork with upstream v0.40.0 and openai-go with v3.50.0#27981
ibetitsmike merged 2 commits into
mainfrom
mike/fantasy-upstream-v0.40-sync

Conversation

@ibetitsmike

@ibetitsmike ibetitsmike commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Our fantasy fork had drifted far behind upstream charmbracelet/fantasy (base v0.31.0 vs current v0.40.0). This PR updates the pinned forks after reconciling which fork hacks upstream has fixed and which we still need, and adapts this repo to the new APIs.

Fork updates

  • charm.land/fantasy -> coder/fantasy#51 (merged): coder_2_33 synced with upstream v0.40.0, pinned at the merge commit bb10946892ef.
  • github.com/openai/openai-go/v3 -> coder/openai-go#10 (merged): coder/pinned rebased from v3.16.0 onto upstream v3.50.0 (required by upstream fantasy), pinned at the merge commit 92b5addb22d2.
  • coder/anthropic-sdk-go pin unchanged; the fantasy fork now tracks the same revision this repo ships.

Hack reconciliation summary

Dropped from our fantasy diff (upstream now has equivalents, often stricter): truncated-stream fail-closed detection, Anthropic EffortXHigh / computer use / thinking effort / thinking display, replay fidelity for signed reasoning and web_search errors, PDF and text documents with sanitized filename titles, refusal finish-reason mapping (upstream also maps Bedrock content_filtered/guardrail_intervened), gpt-5.5/5.6 Responses routing, the Go 1.25 downgrade, and the openai-go SSE decoder and appendCompact patches.

Still fork-only and preserved: OpenAI computer use, OpenAI Responses replay continuity validation, Anthropic pre-4.6 budget-thinking conversion plus explicit thinking disable for effort none, Anthropic RefusalMetadata parsing, Bedrock cross-region inference profile region mirroring, and openai-go deferred body serialization with the WithJSONSet fix.

Picked up new upstream features: stream transport retry with in-band SSE error classification, Bedrock expired-credential refresh, per-message cache markers for OpenAI-compatible models, tool panic recovery, extra usage fields in provider metadata, and ClientMetadata on tool results.

Changes in this repo

  • aibridge/intercept/responses: ResponseOutputItemUnion.Arguments became a union type in openai-go v3.50; read function-call arguments via .OfString (plus test literal updates).
  • coderd/x/chatd/chatdebug: register the new fantasy Call.Headers, ObjectCall.Headers, and ToolResultPart.ClientMetadata fields in the normalization coverage map (all skipped).
  • aibridge/internal/integrationtest: make the RST test listener drain the request before resetting the connection. The new SDK's write path exposed the previous 1-byte-read race as sporadic use of closed network connection failures; the fix holds over 40 consecutive runs.
  • go.mod: rewrite the fork provenance comments to describe the post-sync state.

Validation

  • go build ./... and go vet ./... clean (vet findings identical to base).
  • Fresh (-count=1) runs of ./coderd/x/chatd/..., ./aibridge/..., ./coderd/aibridged/..., ./coderd/database/db2sdk/: 37 packages pass.
  • TestClientAndConnectionError stress-tested 40x clean.
  • Both fork PRs have green CI.

Mux acted on Mike's behalf to create this PR.

…50.0

Bumps the charm.land/fantasy replace to coder/fantasy coder_2_33 synced
with upstream charmbracelet/fantasy v0.40.0 (coder/fantasy#51), and the
openai-go/v3 replace to coder/openai-go coder/pinned rebased onto
upstream v3.50.0 (coder/openai-go#10).

Fork hacks now superseded upstream and dropped from our diff: truncated
stream fail-closed detection (Anthropic + OpenAI Responses), Anthropic
EffortXHigh, computer use, thinking effort/display, replay fidelity for
signed reasoning and web_search errors, PDF/text documents with
sanitized filename titles, refusal finish-reason mapping, gpt-5.5/5.6
Responses routing, the Go 1.25 downgrade, and the openai-go SSE decoder
and appendCompact patches.

Fork hacks still needed and preserved: OpenAI computer use, Responses
replay continuity validation, Anthropic pre-4.6 budget-thinking
conversion and effort none, RefusalMetadata parsing, Bedrock
cross-region profile mirroring, and openai-go deferred body
serialization with the WithJSONSet fix.

New upstream features picked up along the way include stream transport
retry with in-band SSE error classification, Bedrock auth error refresh,
per-message cache markers for OpenAI-compatible models, tool panic
recovery, and extra usage fields in provider metadata.

Adaptations in this repo:
- responses.ResponseOutputItemUnion.Arguments became a union in
  openai-go v3.50; read the JSON string via .OfString.
- Register the new fantasy Call.Headers, ObjectCall.Headers, and
  ToolResultPart.ClientMetadata fields in the chatdebug coverage map.
- Make the integration-test RST listener drain the request before
  resetting so the client error is deterministic; the new SDK's write
  path exposed the previous race as sporadic "use of closed network
  connection" failures.
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

Remote UAT: PASS

Dogfooded this PR on a fresh dev.coder.com workspace at commit 6371e8121ca5cab66b7b505efd6fb07d6b67f4fa with real Anthropic (claude-sonnet-4-5) and OpenAI (gpt-5-mini, Responses API) models.

Validated:

  1. Anthropic streaming happy path incl. thinking/reasoning rendering.
  2. OpenAI Responses API streaming + multi-turn follow-up after a tool call (replay/continuity path).
  3. Tool-call round trip (list_templates), result fed back, model continued.
  4. PDF attachment read by the Anthropic model (document-support path).
  5. Interrupt mid-stream: running -> interrupting -> waiting, partial content preserved, chat immediately usable.
  6. Server logs clean: no provider errors, no replay validation warnings, no stream truncation; only expected context canceled from the intentional interrupts.

No issues found in the PR's risk surface. Full evidence (screenshots, recording, manifest) attached to the UAT chat: https://dev.coder.com/agents/32b33ee2-68f1-41ec-bb18-3142234e363b

Not covered at runtime: Bedrock/Azure/Google providers, AI Bridge intercept beyond unit-test coverage, load/concurrency.

Mux acted on Mike's behalf: remote UAT executed by a Coder Agent, summarized here.

@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

Remote UAT round 2 (OpenAI focus): PASS

Same chat, same commit 6371e8121ca5cab66b7b505efd6fb07d6b67f4fa, exercising the OpenAI Responses API path that this PR's fork changes touch most.

Validated with real gpt-5 and gpt-5-mini:

  1. Both models usable on the Responses API path.
  2. Reasoning display: with reasoning_summary: auto a full Thinking block streams and renders; default config shows only a transient indicator because OpenAI returns empty summary parts (by design, predates this PR).
  3. PDF attachment extracted the passphrase via the OpenAI file-input path.
  4. Multi-turn replay continuity, the fork's key OpenAI risk surface: tool-call turn (gpt-5 issued parallel function_calls), follow-up recalling the tool result, third turn recalling turn-1 context. No item-reference, function_call pairing, or replay validation warnings in logs.
  5. Interrupt mid-stream: running -> interrupting -> waiting, immediately usable.
  6. Rapid-fire queued prompts completed in order without stream errors.
  7. Logs: no OpenAI 4xx/5xx, no truncation.

Findings (neither blocks this PR):

  • Low/cosmetic: interrupting an OpenAI stream logs a secondary failed to send custom error: ... io: read/write on closed pipe warning next to the expected context canceled; candidate for downgrade-to-debug on cancel.
  • Info/pre-existing: reasoning-capable OpenAI models show no persistent reasoning unless reasoning_summary is set; possible docs/default improvement.

Evidence attached to the UAT chat: https://dev.coder.com/agents/32b33ee2-68f1-41ec-bb18-3142234e363b

Mux acted on Mike's behalf: remote UAT executed by a Coder Agent, summarized here.

@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

UAT round 3: baseline check on main (no regression)

Round 2 flagged two OpenAI observations on this branch. To rule out regressions, the same remote UAT agent reran those scenarios on latest main (27414788f78, which still pins the pre-sync fantasy a63de4b and openai-go v3.28.0), reusing the same dev DB and model configs.

Result: both behaviors reproduce identically on main. Neither is introduced by this PR.

Scenario Main (pre-PR) This branch
Interrupt gpt-5 mid-stream Same failed to send custom error: ... io: read/write on closed pipe + interception failed ... context canceled log lines, chat recovers fine Same
Default gpt-5, no reasoning_summary Reasoning part present but empty, no persistent Thinking block in UI Same
gpt-5 with reasoning_summary=auto Persistent Thinking block with full reasoning text Same

The closed-pipe warning is a pre-existing cosmetic issue (candidate for a separate downgrade-to-debug cleanup), and the empty-reasoning default is by-design OpenAI behavior. No fixes needed in this PR.

Evidence: UAT chat rounds 1-3 at https://dev.coder.com/agents/32b33ee2-68f1-41ec-bb18-3142234e363b (EVIDENCE-R3.md has the verbatim log lines from main).

Mux acted on Mike's behalf for this comment.

coder/fantasy#51 merged into coder_2_33 (bb10946892ef) and
coder/openai-go#10 merged into coder/pinned (92b5addb22d2). Both merge
commits carry trees identical to the previously pinned PR heads, so
this is a metadata-only repin onto branch history.
Comment on lines -1161 to +1167
// Read at least 1 byte so the client has started writing
// before we RST, ensuring a consistent "connection reset by peer".
buf := make([]byte, 1)
_, _ = c.Read(buf)
// Drain the request before the RST so the client observes a
// read-side reset rather than a racy body-write failure.
if req, err := http.ReadRequest(bufio.NewReader(c)); err == nil {
_, _ = io.Copy(io.Discard, req.Body)
_ = req.Body.Close()
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separate change?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a consequence of the openai ref change. I'll double check

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair question, so I measured it. This change is coupled to the openai-go v3.50 bump, not an independent flake fix:

  • New SDK + old helper (read 1 byte then RST): streaming_connection_refused fails 3+/40 runs with readfrom tcp ... write: broken pipe or use of closed network connection, neither of which matches the asserted connection reset by peer|forcibly closed.
  • Old SDK + old helper (current main): 160/160 runs pass, so there is nothing to fix on main and a standalone PR would have no defect to point at.
  • New SDK + new helper (drain the request, then RST): 160/160 runs pass.

Mechanism: with v3.50 the request body reaches net/http as a reader (the readfrom in the error is the transport streaming it), so an RST fired after 1 byte races the client's body write and surfaces as a write-side error instead of the read-side reset the test asserts. Draining the full request first makes the client deterministically blocked on the response read when the RST lands.

Without this hunk the PR's own CI is flaky, so keeping it here seemed right, but happy to split it if you prefer.

Mux acted on Mike's behalf for this reply.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine, I was mainly curious about the rationale.

@ibetitsmike
ibetitsmike merged commit c97f4da into main Aug 11, 2026
32 checks passed
@ibetitsmike
ibetitsmike deleted the mike/fantasy-upstream-v0.40-sync branch August 11, 2026 09:20
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 11, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants