Skip to content

agent: pass adaptive thinking config to SDK query()#104

Merged
mcheemaa merged 3 commits intomainfrom
agent-thinking-adaptive
Apr 29, 2026
Merged

agent: pass adaptive thinking config to SDK query()#104
mcheemaa merged 3 commits intomainfrom
agent-thinking-adaptive

Conversation

@mcheemaa
Copy link
Copy Markdown
Member

Summary

Opus 4.7 (and likely future models) reject the legacy thinking.type: enabled shape in API requests. Without an explicit thinking option on the SDK query(), the bundled CLI falls back to that legacy shape and the API returns a 400:

invalid_request_error: "thinking.type.enabled" is not supported for this model. Use "thinking.type.adaptive" and "output_config.effort" to control thinking behavior.

This patch passes thinking: { type: "adaptive" } explicitly from both SDK call sites (chat agent and judge subprocess) so the supported request shape is forwarded on every call regardless of which model variant is configured. The existing effort option continues to control thinking depth under the adaptive contract.

Changes

  • src/agent/chat-query.ts: add thinking: { type: "adaptive" as const } to query() options.
  • src/agent/judge-query.ts: same in the judge subprocess query() options.

Test plan

  • bun run lint clean
  • bun run typecheck clean
  • bun test src/agent/ 90/90 pass
  • Post-merge: rebuild Phantom Cloud rootfs against this commit, redeploy, re-onboard a tenant, send a real DM, confirm Opus 4.7 returns a Claude-generated reply (no 400 invalid_request_error).

Why this is small

The SDK already accepts adaptive thinking; the API already requires it for newer models. The only change is making the request shape explicit instead of relying on a CLI default that's no longer correct for Opus 4.7.

Opus 4.7 (and likely future models) reject the legacy
`thinking.type: enabled` shape in API requests. Without an explicit
`thinking` option on the SDK query(), the bundled CLI falls back to
that legacy shape and the API returns a 400:

  invalid_request_error: "thinking.type.enabled" is not supported
  for this model. Use "thinking.type.adaptive" and
  "output_config.effort" to control thinking behavior.

Pass `thinking: { type: "adaptive" }` from chat-query.ts and
judge-query.ts so the SDK forwards the supported shape on every
query, regardless of which Opus or Sonnet variant is configured.
The existing `effort` option continues to control thinking depth
under the adaptive contract.
@mcheemaa
Copy link
Copy Markdown
Member Author

@codex please review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4bdc5698dd

ℹ️ 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".

Comment thread src/agent/chat-query.ts Outdated
},
persistSession: true,
effort: deps.config.effort,
thinking: { type: "adaptive" as const },
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Pass adaptive thinking in handleMessage SDK query

This patch adds thinking: { type: "adaptive" } for runForChat, but the primary AgentRuntime.handleMessage() path still calls query() without a thinking option in src/agent/runtime.ts (the call used by Slack/trigger/scheduler/MCP entry points). For deployments on claude-opus-4-7, those requests will continue to use the SDK's legacy default shape and still fail with the same 400 error this commit is trying to eliminate, so the fix is incomplete for production channels.

Useful? React with 👍 / 👎.

Round 1 of #104 review caught the runtime.ts handleMessage call site
was untouched, leaving inbound Slack/trigger/scheduler/MCP requests
on Opus 4.7 still defaulting to the legacy thinking.type.enabled
shape that returns 400 invalid_request_error. Mirror the explicit
adaptive shape on this third call site so every entry point that
reaches the SDK query() forwards the supported request shape.

Also patch reflection-subprocess.ts, the fourth query() site, which
runs on the same Opus tier during memory drains and would 400 the
same way without the adaptive thinking option.
@mcheemaa
Copy link
Copy Markdown
Member Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 81cbfb4c0b

ℹ️ 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".

Comment thread src/evolution/reflection-subprocess.ts Outdated
permissionMode: "bypassPermissions",
allowDangerouslySkipPermissions: true,
tools: ["Read", "Write", "Edit", "Glob", "Grep"],
thinking: { type: "adaptive" as const },
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid forcing adaptive thinking on Haiku 4.5 tier

The reflection subprocess now unconditionally sends thinking: { type: "adaptive" }, but this path defaults to the haiku tier (TIER_MODELS.haiku maps to claude-haiku-4-5 in src/evolution/judge-models.ts), and 4.5-era models require manual thinking (enabled + budget_tokens) rather than adaptive mode. In that configuration, the query will fail with a 400 and the drain is marked as a skipped transient failure, so memory reflection can silently stop working until escalation. Please gate the thinking config by model capability (or move the haiku tier to an adaptive-capable model).

Useful? React with 👍 / 👎.

Round 2 found unconditional adaptive thinking breaks Haiku 4.5 in the
reflection subprocess (and any future haiku-tier callsite). Adaptive is
supported on Sonnet 4.6 and Opus 4.7; Haiku 4.5 needs the legacy enabled
+ budget_tokens shape. The fix replaces the four scattered adaptive-stamp
lines with a single-source-of-truth getThinkingConfig(model) helper so
every call site picks the right shape based on its model.

Verified end-to-end against the live Anthropic API on opus-4-7,
sonnet-4-6, and haiku-4-5: opus rejects enabled (400), haiku rejects
adaptive (400), sonnet accepts both. The helper maps each model family
to the shape the API actually accepts, defaulting unknown models to
adaptive because every model since Opus 4.7 has been adaptive-only.

Helper is covered by 12 new unit tests against the full matrix; chat,
judge, runtime, and reflection callsites now spread it instead of
hard-coding a literal.
@mcheemaa
Copy link
Copy Markdown
Member Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8c9c335619

ℹ️ 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".

Comment on lines +30 to +33
"claude-haiku-4",
"claude-haiku-3",
"claude-sonnet-3",
"claude-sonnet-4-5",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Match Claude 3.x IDs when selecting manual thinking

getThinkingConfig only checks claude-haiku-3* / claude-sonnet-3* prefixes, but Anthropic’s actual 3.x IDs are claude-3-5-haiku-* and claude-3-7-sonnet-*; those values currently fall through to the adaptive default and will send thinking: { type: "adaptive" } to models that require manual thinking (enabled + budget), causing runtime 400s for valid legacy model configurations. This regression is easy to trigger by setting model to a real 3.x ID (e.g. claude-3-5-haiku-20241022).

Useful? React with 👍 / 👎.

@mcheemaa mcheemaa merged commit 24e8da5 into main Apr 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant