Repository navigation
chore: sync upstream fantasy v0.45.5 into coder_2_33 - #72
Conversation
When the agent's final step was tool-only (no text content), AgentResult.Response copied that empty step, causing callers to see no output even though earlier steps produced text. finalResponse now walks backwards to find the most recent step with non-blank text. Also clarifies that Text() returns the first text block.
Add ReasoningEffortMax constant and handle it in both the openai and openaicompat provider hooks. Without this, models that accept "max" (e.g. GLM-5.2 via Neuralwatt) error with "reasoning model `max` not supported" before the request reaches the API. Assisted-by: Crush:glm-5.2
…-effort-max feat(openai): add max reasoning effort
…ning ReasoningStart was carrying the first reasoning token in its Delta field, which broke consumers that treat Start as a pure signal (matching TextStart convention). Split into empty Start + separate ReasoningDelta. Encrypted single-shot blocks still use atomic Start+Delta+End since they don't stream. Assisted-by: Crush:qwen3.7-max
Providers that stream tool call arguments across many fragments (e.g. GLM 5.2) can produce a valid JSON prefix before the full payload arrives. The old code finalized on the first valid JSON, truncating the remaining fragments and producing malformed arguments that caused API rejections and session crashes on the next turn. Now deltas flow through incrementally for progress visibility, but ToolInputEnd and ToolCall are emitted only after the stream completes. Also fixes a stale delta bug in the new-tool-call branch and adds deterministic index-sorted finalization for parallel tool calls. 💘 Generated with Crush Assisted-by: Crush:qwen3.7-max
…acelet#290) When a model generates an invalid tool name (e.g. Kimi putting call IDs in the function name field), the error message now lists all available tools so the model can self-correct on the next turn. Assisted-by: Crush:claude-opus-4-6
Bumps the all group with 2 updates: [github.com/kaptinlin/jsonschema](https://github.com/kaptinlin/jsonschema) and [google.golang.org/genai](https://github.com/googleapis/go-genai). Updates `github.com/kaptinlin/jsonschema` from 0.8.0 to 0.9.2 - [Release notes](https://github.com/kaptinlin/jsonschema/releases) - [Commits](kaptinlin/jsonschema@v0.8.0...v0.9.2) Updates `google.golang.org/genai` from 1.60.0 to 1.61.0 - [Release notes](https://github.com/googleapis/go-genai/releases) - [Changelog](https://github.com/googleapis/go-genai/blob/main/CHANGELOG.md) - [Commits](googleapis/go-genai@v1.60.0...v1.61.0) --- updated-dependencies: - dependency-name: github.com/kaptinlin/jsonschema dependency-version: 0.9.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all - dependency-name: google.golang.org/genai dependency-version: 1.61.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…mbracelet#292) Bumps the kronk group with 1 update: [github.com/ardanlabs/kronk](https://github.com/ardanlabs/kronk). Updates `github.com/ardanlabs/kronk` from 1.27.9 to 1.28.0 - [Release notes](https://github.com/ardanlabs/kronk/releases) - [Commits](ardanlabs/kronk@v1.27.9...v1.28.0) --- updated-dependencies: - dependency-name: github.com/ardanlabs/kronk dependency-version: 1.28.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: kronk ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
When a model returns more than one tool call in a single turn, the streamed output stopped marking where one call ended and the next began. Anything reading the stream as it arrived would merge the calls together, producing malformed arguments that the provider rejected on the next turn (seen with GLM 5.2 on Fireworks). Each tool call is now fully delimited as it streams, so a reader can tell the calls apart without waiting for the whole response. The final result of every call is unchanged.
Parse "Input too long" errors from Vercel AI Gateway to extract token counts and mark as context-too-large errors. Assisted-by: Crush:qwen3.7-plus
…mbracelet#301) Bumps the kronk group with 1 update: [github.com/ardanlabs/kronk](https://github.com/ardanlabs/kronk). Updates `github.com/ardanlabs/kronk` from 1.28.4 to 1.28.5 - [Release notes](https://github.com/ardanlabs/kronk/releases) - [Commits](ardanlabs/kronk@v1.28.4...v1.28.5) --- updated-dependencies: - dependency-name: github.com/ardanlabs/kronk dependency-version: 1.28.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: kronk ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the all group with 2 updates: [github.com/aws/smithy-go](https://github.com/aws/smithy-go) and [google.golang.org/genai](https://github.com/googleapis/go-genai). Updates `github.com/aws/smithy-go` from 1.27.2 to 1.27.3 - [Release notes](https://github.com/aws/smithy-go/releases) - [Changelog](https://github.com/aws/smithy-go/blob/main/CHANGELOG.md) - [Commits](aws/smithy-go@v1.27.2...v1.27.3) Updates `google.golang.org/genai` from 1.61.0 to 1.62.0 - [Release notes](https://github.com/googleapis/go-genai/releases) - [Changelog](https://github.com/googleapis/go-genai/blob/main/CHANGELOG.md) - [Commits](googleapis/go-genai@v1.61.0...v1.62.0) --- updated-dependencies: - dependency-name: github.com/aws/smithy-go dependency-version: 1.27.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all - dependency-name: google.golang.org/genai dependency-version: 1.62.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…r-message cache markers Some providers (notably Alibaba Qwen 3.6) only cache prompts when each cached message block is explicitly tagged, unlike providers that cache automatically. Previously there was no way to attach those tags, so cache hits were always zero for those models and every request paid full price. This adds a general way to attach non-standard fields onto individual message content blocks, mirroring the existing root-level extra-body mechanism. When such fields are present the message is sent in the array form the provider requires; otherwise the simpler plain-text form is kept. The same mechanism covers any future provider extension without further changes. 💘 Generated with Crush Assisted-by: Crush:us.anthropic.claude-opus-4-8
Bumps the all group with 3 updates: [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) and [github.com/kaptinlin/jsonschema](https://github.com/kaptinlin/jsonschema). Updates `github.com/aws/aws-sdk-go-v2` from 1.42.0 to 1.42.1 - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Commits](aws/aws-sdk-go-v2@v1.42.0...v1.42.1) Updates `github.com/aws/aws-sdk-go-v2/config` from 1.32.25 to 1.32.27 - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Commits](aws/aws-sdk-go-v2@config/v1.32.25...config/v1.32.27) Updates `github.com/kaptinlin/jsonschema` from 0.9.2 to 0.9.3 - [Release notes](https://github.com/kaptinlin/jsonschema/releases) - [Commits](kaptinlin/jsonschema@v0.9.2...v0.9.3) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2 dependency-version: 1.42.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all - dependency-name: github.com/aws/aws-sdk-go-v2/config dependency-version: 1.32.27 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all - dependency-name: github.com/kaptinlin/jsonschema dependency-version: 0.9.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…flow (charmbracelet#431) Parasail reports an oversized prompt with "this model's maximum context length is N tokens, but the prompt contains M input tokens", which was not matched, so a context overflow looked like a generic provider failure. Capture the maximum and used token counts so it is handled like the other providers. Assisted-by: Crush:prism
Assisted-by: Crush:prism
Update both modules and adapt the Kronk provider to the typed NUMA strategy and string model metadata. Remove the unsupported per-model offload minimum batch option. Amp-Thread-ID: https://ampcode.com/threads/T-01a169a1-9771-71c8-a7ed-cf942193f399 Co-authored-by: Amp <amp@ampcode.com>
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Squash-merging #51 collapsed the v0.40.0 sync into bb10946, so upstream's history is not in coder_2_33's ancestry and the merge base with charmbracelet/fantasy is still v0.31.0. This records the real merge (d37f122, whose tree matches bb10946) as a parent with no file changes, so the next upstream merge only surfaces commits after v0.40.0.
Merges charmbracelet/fantasy main at 28d60cb (v0.45.5 plus a kronk bump). Conflict resolutions: - providers/openai, providers/openaicompat: take upstream's ToolRunBuffer and ToolMessages (charmbracelet#366, charmbracelet#368), which replace the fork's pendingToolMedia (#64), and upstream's reasoning_content replay. - providers/openai: newResponsesLanguageModel takes both the fork's reasoning-model override (#57) and upstream's header hook (charmbracelet#353). Keep reasoningGenerationPattern. - providers/anthropic: keep the fork's effort switch (#47); emit upstream's still-open tool blocks before the fork's per-request usage (#50). - go.mod, go.sum: take upstream's, keep the fork's SDK replaces. The next commits restore the coder SDK forks and Go 1.26.
coder/coder ships the coder forks of anthropic-sdk-go and openai-go and builds with Go 1.26, so keep both after the upstream sync: - Import github.com/charmbracelet/anthropic-sdk-go and github.com/openai/openai-go/v3 again instead of upstream's github.com/anthropics/anthropic-sdk-go v1.75 (charmbracelet#336) and github.com/charmbracelet/openai-go (charmbracelet#381). The existing replaces point both at the coder forks. - anthropic: adapt to the older SDK API (anthropic.Model conversion, NewThinkingConfigAdaptiveParam) and read the error type from the raw error envelope, since the SDK has no Error.Type accessor. - openai: revert 111ec83 (openai-go v3.54 API adaptation). - go.mod: go 1.26.5. Pin kronk v1.31.5, the last release that builds with Go 1.26, and its jinja v1.8.0 and yzma v1.23.0. Revert 28d60cb's kronk provider adaptation (typed NUMA strategy, string model type), which needs kronk v1.33. - examples/go.mod: same Go and kronk pins.
…ing and thinking display - Forward message_start and message_delta as keepalives. Upstream forwards every content-free event as a keepalive (ca3b510), but the fork handles both events itself for per-request usage (#50) and refusal metadata (#41), so they never reached the catch-all. - Claude 5 models keep adaptive thinking from the fork's version rule (#47) and now also get upstream's summarized display default (02d13f0). Update both tests to expect that. - The coder SDK fork reports a mid-stream error event as an untyped error, so drop the upstream test's assertion that it carries status 200. The title and retry assertions still hold through wrapStreamError.
73e8de2 to
bedfd1e
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bedfd1eb11
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Go 1.26.6 has standard library vulnerabilities that Go 1.26.9 and 1.26.10 fix (GO-2026-6603, -6605, -6607, -6608, -6610, -6611, -6612, -6613, -6617 and -6809), so govulncheck fails on every PR.
|
@codex review re: Return synchronous Kronk error finishes as errors Both of these come from upstream, not from the sync. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eea77ce78f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review re: Map valid streamed stop tool calls to tool-calls re: Buffer provider tool results with their calls Both of these come from upstream, not from the sync: |
|
@codex review re: Map valid streamed stop tool calls to tool-calls re: Buffer provider tool results with their calls Both of these come from upstream, not from the sync: re: Return synchronous Kronk error finishes as errors Both of these come from upstream, not from the sync. |
|
Codex Review: Didn't find any major issues. 👍 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Moves the fantasy pin to the tip of `coder_2_33` (`85ffbbe`). That commit is coder/fantasy#72, which merges 87 upstream charmbracelet/fantasy commits, v0.40.0 to v0.45.5. Between the two pins 117 files change. Upstream's own v0.40.0 to v0.45.5 change, without tests, testdata, examples, `go.sum` and the kronk provider, is 43 files, +2271/−928. ## What reaches chatd chatd builds only the `anthropic`, `openai` and `openaicompat` fantasy clients (`chatprovider.ModelFromConfig`); other vendors reach it through the AI Gateway on one of those. So the upstream changes to the Google, Vercel, OpenRouter, Bedrock, Azure and kronk providers, and to the `fantasy.Agent` loop and its retries, do not run in chatd. These do: - **Chat Completions and openaicompat streams** keep reasoning on batched and DeepSeek-shaped chunks, keep `finish_reason: length` when tool calls are truncated, and stop sending empty reasoning fields. openaicompat drops assistant turns that hold only reasoning. - **Token usage.** When an OpenAI-shaped backend reports reasoning tokens apart from completion tokens (reasoning larger than output), output tokens now include them, so that backend's reported output tokens and cost rise. OpenAI's own shape, where reasoning is a subset, is unchanged. - **Responses.** A content-filtered turn no longer reads as a tool-call turn. - **Context overflow.** Baseten, Fireworks and Parasail prompt-length errors set `ContextTooLargeErr`, which compaction acts on. - **Anthropic.** Tool calls whose content block never closes are reported. For Claude 5 models, thinking defaults to `display: "summarized"` when the chat config sets none; a configured display still wins. `TestThinkingDropBlockModel_RetriesWithEffort` now expects the field in the retry body. - **Anthropic keepalives.** Fantasy forwards `message_start`, `message_delta` and unknown events as content-free `keepalive` parts. The first one arrives before any model output, so this PR makes `ttft_seconds` and the `time_to_first_token` stage skip them, as they skip warnings. They still reset the stream silence guard. `processStepStream` ignores them, and the debug recorder counts them in its part count but records no content. - **Tool-result media** now goes through upstream's shared `ToolRunBuffer`, which replaces coder/fantasy#64 and does the same thing. #72 keeps coder's anthropic-sdk-go and openai-go forks, Go 1.26 and kronk v1.31.5, so upstream's SDK and Go moves do not come along. `go mod tidy` raises the modules fantasy v0.45.5 requires, among them otel exporters v1.47, the AWS SDK, `google.golang.org/api` v0.307 and go-openapi v1. All are upgrades. The `go.mod` comment now names #72 as the upstream sync. #29861 stacks on this PR to pin coder/fantasy#62. <details> <summary>Verification</summary> - `go build ./...`. - `go test` passes on every package that imports fantasy (`coderd/x/chatd/...`), and `go test ./coderd -run 'TestChat|TestExpChat|TestMCP|TestAIBridge'` passes. - `TestGuardedStreamTTFTStage/WarningsAndKeepalivesThenContentObservesOnce` fails without the TTFT change (TTFT observed 0s instead of 1s) and passes with it. - `make pre-commit` passes. The generated Prometheus docs pick up the metric help change. Not verified against live backends in this PR: the stream fixes, the token usage change and the context-overflow patterns have no coder test against a real provider. coder/fantasy#72 reports a local chatd run against the AI Gateway on Anthropic, Responses, OpenAI Chat and openaicompat. </details> > 🤖 This PR was created with the help of Coder Agents, and _will be_ reviewed by a human. 🏂🏻
This syncs
coder_2_33with upstream charmbracelet/fantasymainat 28d60cb (v0.45.5 plus a kronk bump), which is 85 upstream commits since the last sync in #51. It replaces what this PR used to be, a cherry-pick of charmbracelet#366 and charmbracelet#368, as both are upstream now.Please merge this with "Create a merge commit", not squash. #51 was squash-merged, same as my sync in #42 (which I then had to fix with #43), so none of the upstream commits it brought in are ancestors of
coder_2_33, and git still thinks we last synced at v0.31.0. The first commit is just a-s oursmerge of #51's head (d37f122) to put that history back with no file changes. Once this lands, the next sync only has to deal with new upstream commits.The conflict resolutions are in the merge commit message. The main ones are that upstream's
ToolRunBufferreplaces ourpendingToolMediafrom #64, andnewResponsesLanguageModeltakes both our reasoning model override (#57) and upstream's header hook (charmbracelet#353).Upstream has also moved to the official
github.com/anthropics/anthropic-sdk-gov1.75 (charmbracelet#336), togithub.com/charmbracelet/openai-go(charmbracelet#381) and to Go 1.27.3. The commit after the merge keeps us on what coder/coder ships instead:github.com/charmbracelet/anthropic-sdk-goandgithub.com/openai/openai-go/v3, which our replaces point at the coder forks. coder/coder replacesgithub.com/anthropics/anthropic-sdk-gov1.19.0 for aibridge, so that replace would stop applying if fantasy required v1.75. charmbracelet/openai-go only adds an error body fix (fix: return api error instead of decode failure for non-object error bodies openai/openai-go#914), whereas ours has the deferred request serialisation. So I've reverted 111ec83 (the openai-go v3.54 API changes) and adapted the Anthropic provider to the older SDK, e.g. reading the error type from the raw error JSON, as there's noError.Type().gostays at 1.26.5, as coder/coder is on 1.26.9. kronk v1.31.5 is the last release that builds with Go 1.26, so I've pinned it and reverted 28d60cb's kronk provider changes, which need v1.33.The last commit fixes a few spots where our Anthropic patches clashed with upstream's. Our
message_startandmessage_deltacases (#50, #41) were swallowing the events upstream now forwards as keepalives, so they forward them too. Claude 5 models get upstream's summarized thinking display on top of our adaptive thinking (#47). Our Anthropic SDK reports a mid-stream error as an untyped error, so upstream's test that it carries a 200 status doesn't apply.I've also bumped the Go that
govulncheckruns with from 1.26.6 to 1.26.10, as it's been failing on every PR since mid-October on standard library vulnerabilities that 1.26.9 and 1.26.10 fix.When coder/coder picks this up,
go mod tidybumps a few dependencies (otel v1.47, the AWS SDK,google.golang.org/api, etc.). Anthropic streams will also start sending keepalive parts, whichchatloopcurrently counts as the first token for TTFT, so the bump needs to skip those.I've pointed coder/coder at this PR, and at the top of the stack (#74), and the chatd, aibridge, MCP and chat API tests pass on both, as does a repo-wide
go build. The generated swagger docs are also unchanged despite the go-openapi bump. I then ran chatd on a local coderd against our AI gateway on Anthropic, Responses, openai Chat and openaicompat, with parallel tool calls, Anthropic thinking, Responses reasoning and a user-attached PDF, and it all worked.Part of CODAGT-1430