Compare commits

..
Author SHA1 Message Date
Aiden Cline b710ac1c27 feat(core): route Cohere models through the native provider (#52663) 2026-10-01 23:20:24 -05:00
Aiden Cline a2c51d74f9 fix(ai): fit Cohere thinking budgets under max tokens 2026-10-01 22:46:35 -05:00
Aiden Cline d0db34e244 fix(ai): keep Cohere output limit errors out of context overflow 2026-10-01 22:21:13 -05:00
Aiden Cline 6c11dc125d refactor(ai): simplify Cohere chat protocol 2026-10-01 22:11:48 -05:00
Aiden Cline 52f1aaf8eb feat(ai): add native Cohere chat provider 2026-10-01 21:42:29 -05:00
Aiden Cline e41756cfc4 fix(ai): isolate Groq and Vertex metadata keys (#52598) 2026-10-01 19:24:08 -05:00
Shoubhit Dash 8b24fc8c2a feat(app): show last turn changes in review panel (#51640) 2026-10-02 06:39:33 +08:00
Filip 0f9f0a9ae3 fix(core): ignore directories named AGENTS.md during instruction discovery (#52576) 2026-10-01 23:12:26 +02:00
Aiden Cline f9e61fd9a3 fix(core): drop legacy catalog context pricing (#52582) 2026-10-01 16:09:38 -05:00
James Long 5256112bac feat(cli): check for updates every 10 minutes (#52552) 2026-10-01 16:29:04 -04:00
Filip afc5d1e21f test(core): test Azure plugin behavior instead of fakes (#52570) 2026-10-01 21:42:39 +02:00
opencode-agent[bot] 80ecb3fc89 chore: update nix node_modules hashes 2026-10-01 19:19:55 +00:00
Shoubhit Dash 31a683f5ca chore(acp): bump @agentclientprotocol/sdk to 1.6.0 (#52559) 2026-10-02 00:38:00 +05:30
Aiden Cline 5d707f1a2b fix(ai): classify Together input token rejections as context overflow (#52133) 2026-10-01 14:07:15 -05:00
Aiden Cline e2948f5a51 fix(core): skip automatic copies of directly read instructions (#52382) 2026-10-01 13:59:02 -05:00
Filip fbe8a9f7b4 feat(core): discover Azure deployments (#50053) 2026-10-01 20:42:12 +02:00
Aiden Cline 033b9ea560 fix(ai): make Claude capability defaults forward-compatible (#52535) 2026-10-01 13:20:54 -05:00
Shoubhit Dash 7bb3fbf095 feat(acp): support additional workspace directories (#52524) 2026-10-01 23:47:00 +05:30
Shoubhit Dash 507e117466 chore(ci): remove unused ffmpeg install (#52547) 2026-10-01 23:38:06 +05:30
Shoubhit Dash 1549712761 fix(acp): fall back to a reference for unreadable resource links (#52520) 2026-10-01 23:03:39 +05:30
opencode-agent[bot]andrekram1-node 4f37be6265 fix(ai): place Bedrock tool images by model family (#52528)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-10-01 11:58:36 -05:00
Rémy SanchezandAiden Cline 7b04288099 fix(ai): support prompt caching for DigitalOcean inference (#51559)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2026-10-01 11:56:04 -05:00
Shoubhit Dash 96339544bf feat(acp): answer V2 forms through ACP elicitation (#52511) 2026-10-01 22:17:50 +05:30
Adam b03d760f43 feat(core): explain why the provider blocked a response (#52518) 2026-10-01 11:23:40 -05:00
Shoubhit Dash b73e75fb6a test(tui): isolate app fixture state (#52512) 2026-10-01 21:49:07 +05:30
Shoubhit Dash 08c15ec1cd fix(acp): send available commands after the session response (#52522) 2026-10-01 21:42:35 +05:30
Shoubhit Dash 48f3c2e923 fix(acp): map invalid requests to invalid params (#52521) 2026-10-01 21:34:24 +05:30
Shoubhit Dash 3d94a90978 refactor(acp): run permission requests as effects (#52510) 2026-10-01 20:59:05 +05:30
Shoubhit Dash 2c33922412 refactor(acp): run ACP turns as interruptible effects (#52503) 2026-10-01 19:31:40 +05:30
Shoubhit Dash 7e42a897bc feat(acp): follow model and agent changes from other clients (#52499) 2026-10-01 18:45:52 +05:30
Shoubhit Dash d8663e1fe8 chore(ci): cancel superseded check runs (#52498) 2026-10-01 18:43:55 +05:30
Shoubhit Dash a6b10e3e87 fix(ci): stabilize bun cache keys (#52495) 2026-10-01 18:36:05 +05:30
Shoubhit Dash 3400375fb3 refactor(acp): split the promise turn from the session lifecycle (#52493) 2026-10-01 18:06:09 +05:30
opencode-agent[bot] ffb51318f6 chore(core): refresh bundled models.dev snapshot 2026-10-01 12:22:44 +00:00
Shoubhit Dash b1157ebb04 feat(acp): mark compactions for ACP clients (#52485) 2026-10-01 17:33:45 +05:30
Shoubhit Dash 3e4cdcd180 refactor(acp): move ACP sessions into a scoped effect registry (#52488) 2026-10-01 17:33:08 +05:30
Shoubhit Dash 0a6f380db7 fix(acp): report locations for native file tools (#52469) 2026-10-01 16:59:46 +05:30
Shoubhit Dash 44336e8b84 refactor(acp): run the catalog as an effect service (#52471) 2026-10-01 16:53:10 +05:30
Shoubhit Dash 20cf09752d fix(acp): report usage for the whole turn (#52467) 2026-10-01 16:21:26 +05:30
Shoubhit Dash 966e718b31 fix(acp): stop echoing edited files to the client (#52466) 2026-10-01 16:20:16 +05:30
opencode-agent[bot]andnexxeln cf0c9fb914 docs(plugin): use path in skill transform examples (#52470)
Co-authored-by: nexxeln <95541290+nexxeln@users.noreply.github.com>
2026-10-01 16:09:33 +05:30
Shoubhit Dash bebc3640f4 refactor(acp): run ACP requests as effects and exit when the server dies (#52336) 2026-10-01 15:44:35 +05:30
Aiden Cline aa6a4f93bd fix(ai): keep system updates after pending tool results (#52426) 2026-10-01 02:46:37 -05:00
opencode-agent[bot] 8433dd732f chore: update nix node_modules hashes 2026-10-01 07:06:42 +00:00
Jérôme BenoitandTest User c34d09fe97 fix(nix): drop x86_64-darwin target and unblock flake eval on nixpkgs 26.11 (#52129)
Co-authored-by: Test User <test@test.com>
2026-10-01 01:55:00 -05:00
Aiden Cline 2fb7985bb7 fix(core): make MCP errors self-describing (#52418) 2026-10-01 01:46:55 -05:00
Aiden Cline a931e8a9fd fix(ai): classify Z.ai provider errors (#52104) 2026-10-01 01:30:53 -05:00
Aiden Cline 149acd7141 fix(plugin): forward session update metadata (#52434) 2026-10-01 00:52:45 -05:00
Aiden Cline adf4b023d8 fix(ai): classify xAI invalid API keys as authentication errors (#52112) 2026-10-01 00:29:49 -05:00
Luke Parker f406d93a66 refactor(app): move GUI features into built-in extensions (#52369) 2026-10-01 15:17:55 +10:00
Aiden Cline 9faf99a4ab fix(ai): add missing results for trailing tool calls (#52421) 2026-09-30 23:29:50 -05:00
19f203837e feat(plugin): support parent session creation (#52359)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
Co-authored-by: dbpolito <347400+dbpolito@users.noreply.github.com>
2026-09-30 22:50:09 -05:00
Aiden Cline f0f4c94c0a fix(ai): classify Novita context length rejections as context overflow (#52134) 2026-09-30 22:40:07 -05:00
Aiden Cline 9c4c5870b6 fix(ai): classify DeepInfra input length rejections as context overflow (#52132) 2026-09-30 22:39:24 -05:00
Aiden Cline 924c12b291 feat(plugin): expose session compaction (#52385) 2026-09-30 22:26:10 -05:00
Aiden Cline 155bc7df75 fix(core): terminate legacy MCP sessions on close (#52414) 2026-09-30 22:17:08 -05:00
opencode-agent[bot]andrekram1-node d280eaf961 fix(ci): extend issue and PR compliance grace to 72 hours (#52416)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-09-30 21:40:04 -05:00
Aiden Cline 5556ad563d fix(ai): stop retrying Z.ai Responses model and permission rejections (#52135) 2026-09-30 18:19:33 -05:00
opencode-agent[bot]andiamdavidhill 629e7aaa31 fix(session-ui): increase markdown bold weight (#52389)
Co-authored-by: iamdavidhill <1879069+iamdavidhill@users.noreply.github.com>
2026-10-01 09:04:36 +10:00
opencode dd2af0e5fc sync release versions for v2.0.21 2026-09-30 23:02:16 +00:00
Aiden Cline a923596ee7 feat(plugin): expose session removal (#52387) 2026-09-30 17:51:36 -05:00
Aiden Cline 91b9bc52a4 fix(ai): make model capability defaults forward-compatible (#52388) 2026-09-30 17:50:40 -05:00
Aiden Cline f46fa72a92 fix(core): add namespaced session identity headers (#52368) 2026-09-30 15:14:20 -05:00
Aiden Cline 14636b9900 fix(core): avoid reinjecting ancestor instructions (#52364) 2026-09-30 15:01:58 -05:00
Aiden Cline b020f1018b fix(ai): route Cloudflare AI Gateway Claude and OpenAI through native passthroughs (#52222) 2026-09-30 14:01:56 -05:00
Shoubhit Dash 7878744505 test(acp): drive ACP tests through the wire protocol (#52307) 2026-09-30 22:09:51 +05:30
Aiden Cline 599bdc982e fix(ai): classify Amazon Nova input token rejections as context overflow (#52131) 2026-09-30 11:13:34 -05:00
James Long 82bb5ff88a fix(browser): hide browser tools unless a desktop is attached (#52309) 2026-09-30 11:42:23 -04:00
Simon Klee 0159356be6 tui: upgrade OpenTUI to 0.5.14 (#52316) 2026-09-30 15:16:51 +00:00
OpeOginni 9388b94a97 fix(tui): tighten expanded instruction group spacing (#52311) 2026-09-30 15:08:01 +00:00
James Long 02c3891d9b feat(core): let form cancellation carry a message (#52137) 2026-09-30 09:20:26 -04:00
Shoubhit Dash 1844c11104 fix(acp): follow server defaults and refresh the session catalog (#52286) 2026-09-30 18:36:56 +05:30
opencode-agent[bot] c0285b457a chore(core): refresh bundled models.dev snapshot 2026-09-30 12:25:26 +00:00
opencode-agent[bot]andBrendonovich ffa4c4c730 feat(app): open referenced session IDs from markdown (#52231)
Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
2026-09-30 15:39:30 +08:00
Luke Parker 01efd22b2a feat(desktop): comment on page elements from the in-app browser (#52217) 2026-09-30 16:52:42 +10:00
opencode-agent[bot]andBrendonovich dd68d6eb79 fix(app): select new-session project by resolved ID (#52230)
Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
2026-09-30 14:34:05 +08:00
Simon Klee 1243d09dbc tui: update OpenTUI to 0.5.13 (#52233) 2026-09-30 06:13:28 +00:00
Aiden Cline a80a00011d fix(ai): classify Workers AI context window rejections as context overflow (#52128) 2026-09-29 23:49:03 -05:00
opencode-agent[bot]andBrendonovich bf97a0443f fix(app): alert only for open session tabs (#52204)
Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
2026-09-30 03:55:01 +00:00
Luke Parker 67b14e9191 feat(session-ui): keep open Used group header sticky (#52210) 2026-09-30 13:46:40 +10:00
Luke Parker 1b02abcfab feat(session-ui): group adjacent reads into one row (#52207) 2026-09-30 12:54:40 +10:00
Aiden Cline 74dbc509d7 fix(ai): place prompt cache breakpoints on OpenRouter Anthropic and Qwen requests (#52110) 2026-09-29 18:07:49 -05:00
Aiden Cline 760f87fab1 fix(core): pass through Copilot Responses settings (#52182) 2026-09-29 17:52:53 -05:00
opencode-agent[bot]andrekram1-node df51166711 fix(ci): run V2 Discord notification after skipped build jobs (#52012)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-09-29 16:22:16 -05:00
opencode 8d8a7bc844 sync release versions for v2.0.20 2026-09-29 21:08:02 +00:00
opencode-agent[bot] a2fc1968be fix(stats): match document background to page theme (#52169) 2026-09-29 15:59:22 -05:00
Aiden Cline c2a39ac592 fix(core): stop promising a ChatGPT usage reset (#52168) 2026-09-29 15:50:09 -05:00
Aiden Cline 4deda18037 fix(app): align ChatGPT usage copy and links (#52163) 2026-09-29 15:18:45 -05:00
Aiden Cline 0f83038253 fix(core): align ChatGPT token sharing with updated partner guide (#52162) 2026-09-29 15:11:58 -05:00
Dax 4c33a253aa feat(cli): add auth export and auth import commands (#52139) 2026-09-29 16:09:01 -04:00
135995d4fc test: stabilize V2 CI test suites (#52159)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
Co-authored-by: jlongster <17031+jlongster@users.noreply.github.com>
2026-09-29 14:54:11 -05:00
Aiden Cline 4d9090790b feat(core): add separate ChatGPT token-sharing OAuth method (#52147) 2026-09-29 14:48:51 -05:00
Aiden Cline 621a5b0706 feat(app): show ChatGPT token-sharing guidance (#52160) 2026-09-29 14:45:59 -05:00
Aiden Cline 16ef62c851 feat(app): show ChatGPT usage limit dialog (#52153) 2026-09-29 14:38:48 -05:00
Aiden Cline b694d2bf26 fix(core): explain ChatGPT token-sharing errors (#52158) 2026-09-29 14:25:01 -05:00
Aiden Cline 89d37a0f6d fix(core): restrict database files to their owner (#52150) 2026-09-29 14:18:40 -05:00
James Long bc5ff1cfd9 fix(cli): answer subagent asks in run and keep parallel rejections continuing (#52146) 2026-09-29 15:03:06 -04:00
Aiden Cline c14a1f5acf feat(core): preserve provider response body in session errors (#52136) 2026-09-29 13:32:09 -05:00
Frank 7db941a892 docs(console): add GPT 6.1 Sol to model list 2026-09-29 14:28:47 -04:00
James Long 83fafda63a feat(cli): continue run after rejecting a permission ask (#51968) 2026-09-29 14:26:20 -04:00
opencode-agent[bot]andjlongster a565ea8c74 feat(cli): allow disabling the background service (#52107)
Co-authored-by: jlongster <17031+jlongster@users.noreply.github.com>
2026-09-29 13:32:38 -04:00
Aiden Cline 3126808e0e fix(ai): defer Mistral thinking metadata until block end (#52008) 2026-09-29 11:38:06 -05:00
opencode-agent[bot]andthdxr 948047a8ca fix(tui): use disclosure icon for low activity errors (#52097)
Co-authored-by: thdxr <826656+thdxr@users.noreply.github.com>
2026-09-29 11:10:32 -04:00
opencode-agent[bot] 0f931d3939 chore(core): refresh bundled models.dev snapshot 2026-09-29 12:22:53 +00:00
Kit Langton 7ef4a1a56e feat(tui): show recently closed tabs in new session menu 2026-09-29 03:35:31 -07:00
Victor Navarro b29dab3231 fix(core): drop SSO link from Console sign-in error (#52062) 2026-09-29 12:04:27 +02:00
Victor Navarro d76f968c60 feat(core): tell users how to sign back in to OpenCode Console (#51847) 2026-09-29 10:58:45 +02:00
opencode-agent[bot]andrekram1-node b30c4d00d1 fix(ai): enable explicit caching on more message protocol routes (#51981)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-09-29 00:50:08 -05:00
Aiden Cline 6712cc4c2c fix(core): turn off Workers AI thinking through the chat template (#52017) 2026-09-29 00:45:17 -05:00
Aiden Cline 2aaa265cdc fix(ai): read provider error messages from common body layouts (#52014) 2026-09-29 00:19:20 -05:00
Luke Parker ff72659a47 fix(desktop): give isolated dev service a fixed port (#52013) 2026-09-29 15:09:50 +10:00
Aiden Cline 14af33d53d fix(ai): show provider error bodies when no message is recognized (#51978) 2026-09-29 00:06:52 -05:00
Luke Parker a604b7f773 fix(ui): calm diff word highlights with @pierre/diffs 1.5.1 (#51236) 2026-09-29 14:58:24 +10:00
Luke Parker 41d4a9c45c fix(session-ui): render moved notice as a timeline divider (#52009) 2026-09-29 14:58:13 +10:00
Luke Parker 293d60a89f chore(desktop): bump electron to 44.4.5 (#52005) 2026-09-29 14:50:04 +10:00
Aiden Cline 34a8938dc7 fix(ai): bind Bedrock Claude thinking blocks by default (#51959) 2026-09-28 23:38:20 -05:00
Aiden Cline 36ef6cc216 fix(ai): finalize Bedrock redacted reasoning at block end (#51999) 2026-09-28 23:37:51 -05:00
opencode f02c30eb55 sync release versions for v2.0.19 2026-09-29 04:31:02 +00:00
Aiden Cline ca084b2430 fix(ai): give provider routes distinct IDs (#51976) 2026-09-28 19:55:06 -05:00
Aiden Cline 3740ec311b feat(core): align shell tool environment with agent conventions (#51975) 2026-09-28 19:53:53 -05:00
opencode-agent[bot]andrekram1-node 35bd8ac442 test(core): update xAI variant expectations for Responses (#51977)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-09-28 19:48:35 -05:00
Aiden Cline 1fc05ca590 fix(core): share affinity in provider session headers (#51931) 2026-09-28 19:30:24 -05:00
Aiden Cline bda798b167 fix(core): drop session ID and order instructions for prompt-cache reuse (#51960) 2026-09-28 19:29:28 -05:00
Aiden Cline 3babae35c0 fix(core): fall back to Cloudflare environment IDs when not configured (#51963) 2026-09-28 19:28:03 -05:00
Aiden Cline 3ab5c1433c fix(core): request xAI reasoning summaries on Responses variants (#51964) 2026-09-28 19:11:48 -05:00
Aiden Cline 49437a25b1 fix(ai): classify invalid Google API keys as authentication errors (#51950) 2026-09-28 18:49:29 -05:00
Aiden Cline 49403a554f feat(core): cap requested output tokens at 256k (#51962) 2026-09-28 18:49:05 -05:00
opencode-agent[bot]andrekram1-node 87d6f93409 test(cli): isolate run exit codes between tests (#51955)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-09-28 19:16:01 -04:00
Frank 97d4eaa2ba zen: jev privacy policy 2026-09-28 19:01:46 -04:00
Kit Langton 7827dbe396 fix(tui): deduplicate projects in the open picker (#51924) 2026-09-28 18:13:00 -04:00
James Long 5f9ced439b fix(cli): drop misleading interruption errors after declined prompts in run (#51948) 2026-09-28 17:58:04 -04:00
Aiden Cline 8c1ce954d0 fix(tui): wait for agent and model before auto-submitting --prompt (#51938) 2026-09-28 15:41:14 -05:00
07338c5d48 feat(cli): create the session when --session names one that does not exist (#51405)
Co-authored-by: Alireza Haghdoost <haghdoost@uber.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2026-09-28 15:09:03 -05:00
James Long 46e53e3f2b fix(ai): expose evaluation confidence (#51930) 2026-09-28 15:24:21 -04:00
Aiden Cline 6cf442b545 fix(core): share child session affinity headers (#51923) 2026-09-28 13:31:17 -05:00
opencode-agent[bot]andrekram1-node f20f5b68ee chore(release): announce V2 releases in Discord (#51880)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-09-28 12:30:55 -05:00
SebastianandOpenCode Agent 96dd9f77a9 fix(core): attribute one-shot generation requests (#48358)
Co-authored-by: OpenCode Agent <opencode-agent[bot]@users.noreply.github.com>
2026-09-28 11:55:14 -05:00
opencode-agent[bot] dd786c62af chore(core): refresh bundled models.dev snapshot 2026-09-28 12:23:50 +00:00
Frank 87c402a124 docs(go): simplify v2 usage limit explanation 2026-09-28 07:39:42 -04:00
Frank 7076a878a4 docs(www): document Go Plus (#51834) 2026-09-28 07:25:37 -04:00
Frank 45b91eed82 docs(go): sync v2 model list with v1 (#51837) 2026-09-28 11:23:40 +00:00
Niels Kootstra 39e1ce55bc fix(core): reject relative path segments in repository hosts (#51577) 2026-09-28 10:14:35 +05:30
opencode-agent[bot]andrekram1-node d9f54392ba fix(tui): distinguish background shell from interrupted command (#51769)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-09-27 23:01:00 -05:00
Aiden Cline d73396ab3d fix(ai): preserve Gemini thought signatures on OpenAI Chat tool calls (#51768) 2026-09-27 22:57:22 -05:00
Jérôme BenoitandTest User 0caae608a2 chore(nix): update nixpkgs for Bun 1.4 (#50221)
Co-authored-by: Test User <test@test.com>
2026-09-27 21:34:52 -05:00
Kit Langton 96f23508be refactor(core): remove unused project discovery option (#51729) 2026-09-27 15:05:46 -07:00
Kit Langton 28bb0a7158 refactor(core): drop forwarding shim modules (#51670) 2026-09-27 14:47:19 -07:00
DS 3d109828ff fix(tui): truncate btw question preview (#51713) 2026-09-27 21:05:20 +02:00
Shoubhit Dash c0d49f101c feat(ai): retry transient failures on queued generation reads (#51635) 2026-09-27 19:47:25 +05:30
Shoubhit Dash be2446e188 feat(ai): add ElevenLabs Scribe transcription route (#51641) 2026-09-27 19:34:36 +05:30
Shoubhit Dash 107966eddd fix(ai): reject and throw with signal.reason on abort (#51633) 2026-09-27 19:24:45 +05:30
Kit Langton f5e580cde1 chore(core): remove dead modules and exports (#51667) 2026-09-27 06:38:43 -07:00
Shoubhit Dash 4428a77acd fix(ai): classify terminal generation failures by provider error code (#51632) 2026-09-27 18:44:21 +05:30
2058 changed files with 81732 additions and 91406 deletions

No files matched your search

-5
View File
@@ -1,5 +0,0 @@
---
"@opencode/core": patch
---
Correct directory page headings when the read offset is zero.
+5 -3
View File
@@ -45,14 +45,16 @@ runs:
- name: Get cache directory
id: cache
shell: bash
run: echo "dir=$(bun pm cache)" >> "$GITHUB_OUTPUT"
run: |
echo "dir=$(bun pm cache)" >> "$GITHUB_OUTPUT"
echo "version=$(bun --version)" >> "$GITHUB_OUTPUT"
- name: Restore Bun dependencies
id: bun-cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ steps.cache.outputs.dir }}
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ steps.cache.outputs.version }}-${{ hashFiles('bun.lock', 'patches/**') }}
- name: Install setuptools for distutils compatibility
run: python3 -m pip install setuptools || pip install setuptools || true
@@ -75,4 +77,4 @@ runs:
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ steps.cache.outputs.dir }}
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
key: ${{ steps.bun-cache.outputs.cache-primary-key }}
+4
View File
@@ -7,6 +7,10 @@ on:
branches: [dev, v2]
workflow_dispatch:
concurrency:
group: ${{ case(github.ref == 'refs/heads/dev', format('{0}-{1}', github.workflow, github.run_id), format('{0}-{1}', github.workflow, github.event.pull_request.number || github.ref)) }}
cancel-in-progress: true
jobs:
check:
name: typecheck
+7 -7
View File
@@ -15,7 +15,7 @@ jobs:
close-non-compliant:
runs-on: ubuntu-latest
steps:
- name: Close non-compliant issues and PRs after 2 hours
- name: Close non-compliant issues and PRs after 72 hours
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
@@ -33,7 +33,7 @@ jobs:
}
const now = Date.now();
const twoHours = 2 * 60 * 60 * 1000;
const seventyTwoHours = 72 * 60 * 60 * 1000;
const orgMemberAssociations = new Set(['OWNER', 'MEMBER']);
const agentLogin = 'opencode-agent[bot]';
const { data: file } = await github.rest.repos.getContent({
@@ -87,14 +87,14 @@ jobs:
if (!complianceComment) continue;
const commentAge = now - new Date(complianceComment.created_at).getTime();
if (commentAge < twoHours) {
core.info(`${kind} #${item.number} still within 2-hour window (${Math.round(commentAge / 60000)}m elapsed)`);
if (commentAge < seventyTwoHours) {
core.info(`${kind} #${item.number} still within 72-hour window (${Math.round(commentAge / 60000)}m elapsed)`);
continue;
}
const closeMessage = isPR
? 'This pull request has been automatically closed because it was not updated to meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md) within the 2-hour window.\n\nFeel free to open a new pull request that follows our guidelines.'
: 'This issue has been automatically closed because it was not updated to meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md) within the 2-hour window.\n\nFeel free to open a new issue that follows our issue templates.';
? 'This pull request has been automatically closed because it was not updated to meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md) within the 72-hour window.\n\nFeel free to open a new pull request that follows our guidelines.'
: 'This issue has been automatically closed because it was not updated to meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md) within the 72-hour window.\n\nFeel free to open a new issue that follows our issue templates.';
await github.rest.issues.createComment({
owner: context.repo.owner,
@@ -129,5 +129,5 @@ jobs:
});
}
core.info(`Closed non-compliant ${kind} #${item.number} after 2-hour window`);
core.info(`Closed non-compliant ${kind} #${item.number} after 72-hour window`);
}
+2 -2
View File
@@ -107,7 +107,7 @@ jobs:
If the issue is NOT compliant and the author association is not OWNER or MEMBER, start the comment with:
<!-- issue-compliance -->
Then explain what needs to be fixed and that they have 2 hours to edit the issue before it is automatically closed. Also add the label needs:compliance to the issue using: gh issue edit ${{ github.event.issue.number }} --add-label needs:compliance
Then explain what needs to be fixed and that they have 72 hours to edit the issue before it is automatically closed. Also add the label needs:compliance to the issue using: gh issue edit ${{ github.event.issue.number }} --add-label needs:compliance
If duplicates were found, include a section about potential duplicates with links.
@@ -124,7 +124,7 @@ jobs:
**What needs to be fixed:**
- [specific reasons]
Please edit this issue to address the above within **2 hours**, or it will be automatically closed.
Please edit this issue to address the above within **72 hours**, or it will be automatically closed.
[If duplicates found, add:]
---
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
echo "=== Flake structure ==="
nix flake show --all-systems
SYSTEMS="x86_64-linux aarch64-linux x86_64-darwin aarch64-darwin"
SYSTEMS="x86_64-linux aarch64-linux aarch64-darwin"
PACKAGES="opencode"
# TODO: move 'desktop' to PACKAGES when #11755 is fixed
OPTIONAL_PACKAGES="desktop"
+1 -3
View File
@@ -34,8 +34,6 @@ jobs:
runner: blacksmith-4vcpu-ubuntu-2404
- system: aarch64-linux
runner: blacksmith-4vcpu-ubuntu-2404-arm
- system: x86_64-darwin
runner: macos-15-intel
- system: aarch64-darwin
runner: macos-latest
runs-on: ${{ matrix.runner }}
@@ -126,7 +124,7 @@ jobs:
[ -f "$HASH_FILE" ] || echo '{"nodeModules":{}}' > "$HASH_FILE"
for SYSTEM in x86_64-linux aarch64-linux x86_64-darwin aarch64-darwin; do
for SYSTEM in x86_64-linux aarch64-linux aarch64-darwin; do
FILE="hashes/hash-${SYSTEM}/hash.txt"
if [ -f "$FILE" ]; then
HASH="$(tr -d '[:space:]' < "$FILE")"
+1 -1
View File
@@ -307,7 +307,7 @@ jobs:
**What needs to be fixed:**
${issues.map(i => `- ${i}`).join('\n')}
Please edit this PR description to address the above within **2 hours**, or it will be automatically closed.
Please edit this PR description to address the above within **72 hours**, or it will be automatically closed.
If you believe this was flagged incorrectly, please let a maintainer know.`;
+20
View File
@@ -24,6 +24,10 @@ on:
description: "Override version (optional)"
required: false
type: string
release_notes:
description: "Reviewed V2 release notes for the Discord announcement (optional)"
required: false
type: string
concurrency: ${{ github.workflow }}-${{ github.ref }}-${{ (github.ref_name == 'v2' && (inputs.version || inputs.bump) && 'release') || inputs.version || inputs.bump }}
@@ -653,3 +657,19 @@ jobs:
OPENCODE_DESKTOP_DIST: /tmp/desktop
CLOUDFLARE_ACCOUNT_ID: 15d29c8639fd3733b1b5486a2acfd968
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
notify-discord-v2:
needs:
- version
- publish
if: ${{ !cancelled() && github.repository == 'anomalyco/opencode' && github.ref_name == 'v2' && needs.version.outputs.release && needs.publish.result == 'success' }}
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
# Unlike dev, V2 publishes a tag rather than a GitHub Release event.
- name: Announce V2 release in Discord
uses: SethCohen/github-releases-to-discord@24d166886aee4646d448c8a389ff9e1ebcab3682 # v1.20.0
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK }}
release_name: OpenCode V2 ${{ needs.version.outputs.tag }}
release_body: ${{ inputs.release_notes }}
release_html_url: https://github.com/${{ github.repository }}/tree/${{ needs.version.outputs.tag }}
+9 -6
View File
@@ -94,12 +94,6 @@ jobs:
git config --global user.email "bot@opencode.ai"
git config --global user.name "opencode"
- name: Install ffmpeg
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install --yes ffmpeg
- name: Cache Turbo
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
@@ -251,6 +245,13 @@ jobs:
run: bunx playwright test --config e2e/service-worker/playwright.config.ts
timeout-minutes: 5
- name: Run session UI component tests
if: ${{ !cancelled() && env.E2E_ENABLED == 'true' }}
run: bun --cwd packages/session-ui test:components
env:
CI: true
timeout-minutes: 15
- name: Upload Playwright artifacts
if: always() && env.E2E_ENABLED == 'true'
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
@@ -261,3 +262,5 @@ jobs:
path: |
packages/app/e2e/test-results
packages/app/e2e/playwright-report
packages/session-ui/component-tests/test-results
packages/session-ui/component-tests/playwright-report
+94 -1
View File
@@ -1,5 +1,9 @@
{
"$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/oxc-project.github.io/refs/heads/json-schema/src/public/.oxlintrc.schema.json",
"jsPlugins": [
{ "name": "anti-slop", "specifier": "./script/oxlint/anti-slop/index.ts" },
{ "name": "anti-slop-effect", "specifier": "./script/oxlint/anti-slop/effect/index.ts" }
],
"categories": {
"correctness": "off",
"suspicious": "off",
@@ -18,5 +22,94 @@
}
]
},
"ignorePatterns": ["**/node_modules", "**/dist", "**/.build", "**/.sst", "**/*.d.ts", "**/sdk.gen.ts"]
"overrides": [
{
"files": [
"packages/app/**",
"packages/desktop/**",
"packages/gui-extensions/**",
"packages/ui/**",
"packages/session-ui/**"
],
"rules": {
"oxc/no-accumulating-spread": "warn",
"anti-slop/no-array-filter-map": "warn",
"anti-slop/no-reduce-accumulator-copy": "warn",
"anti-slop/no-chained-type-assertions": "warn",
"anti-slop/no-conditional-empty-object-spread": "warn",
"anti-slop/no-known-value-widening": "warn",
"anti-slop/no-module-mocking": "warn",
"anti-slop/no-object-parameters": "warn",
"anti-slop/no-reflect-apply": "warn",
"anti-slop/no-reflect-get": "warn",
"anti-slop/no-runtime-typeof": "warn",
"anti-slop/no-shape-in-symbol-names": "warn",
"anti-slop/no-unknown-parameters": "warn",
"anti-slop/no-unknown-returns": "warn",
"anti-slop/no-unknown-type-aliases": "warn",
"anti-slop/no-unsafe-dictionary-type": "warn",
"anti-slop/no-widen-then-assert": "warn",
"anti-slop/require-readable-spacing": "warn",
"anti-slop/require-safety-comment-for-type-assertion": "warn"
}
},
{
"files": ["packages/app/**", "packages/desktop/**", "packages/gui-extensions/**", "packages/session-ui/**"],
"rules": {
"anti-slop-effect/no-manual-effect-error-tag": "warn",
"anti-slop-effect/no-manual-tag-comparison": "warn",
"anti-slop-effect/no-manual-tagged-construction": "warn",
"anti-slop-effect/no-service-constructor-imports": "warn",
"anti-slop-effect/prefer-effect-match": "warn"
}
},
{
"files": ["packages/gui-extensions/src/*/**"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"regex": "^@opencode/(app|desktop)(/|$)",
"message": "GUI extensions never import the app or desktop packages. Use the SDK."
},
{
"regex": "^@/",
"message": "GUI extensions never import app internals. Use the SDK."
},
{
"group": ["../*/*", "!../*/contract", "!../sdk/*"],
"message": "Import another extension only through its contract.ts."
},
{
"regex": "\\.css$",
"message": "Import CSS with ?inline and contribute it with ctx.add(Style, css)."
}
]
}
]
}
}
],
"ignorePatterns": [
"**/node_modules",
"**/dist",
"**/.build",
"**/.sst",
"**/*.d.ts",
"**/sdk.gen.ts",
".agent/**",
".agents/**",
".claude/**",
".codex/**",
".continue/**",
".cursor/**",
".gemini/**",
".opencode/**",
".pi/**",
".roo/**",
".windsurf/**",
"script/oxlint/anti-slop/**"
]
}
+150 -92
View File
@@ -15,6 +15,7 @@
"@actions/artifact": "5.0.1",
"@ast-grep/cli": "0.44.0",
"@opencode/client": "workspace:*",
"@oxlint/plugins": "1.60.0",
"@tsconfig/bun": "catalog:",
"@types/mime-types": "3.0.1",
"@types/react": "19.2.17",
@@ -32,7 +33,7 @@
},
"packages/ai": {
"name": "@opencode/ai",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@aws-sdk/credential-providers": "3.1057.0",
"@opencode/schema": "workspace:*",
@@ -54,7 +55,7 @@
},
"packages/app": {
"name": "@opencode/app",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@corvu/drawer": "catalog:",
"@dnd-kit/abstract": "0.5.0",
@@ -64,7 +65,7 @@
"@ibm/plex": "6.4.1",
"@kobalte/core": "catalog:",
"@opencode/client": "workspace:*",
"@opencode/plugin-browser": "workspace:*",
"@opencode/gui-extensions": "workspace:*",
"@opencode/schema": "workspace:*",
"@opencode/session-ui": "workspace:*",
"@opencode/ui": "workspace:*",
@@ -86,13 +87,11 @@
"core-js": "3.50.0",
"effect": "catalog:",
"fuzzysort": "catalog:",
"ghostty-web": "github:anomalyco/ghostty-web#83c0a07b8628b748aed073b232cb4b52a6ca11c1",
"qr-scanner": "1.4.2",
"remeda": "catalog:",
"solid-js": "catalog:",
"solid-presence": "0.2.0",
"tailwindcss": "4.3.3",
"uqr": "0.1.3",
},
"devDependencies": {
"@happy-dom/global-registrator": "20.0.11",
@@ -103,6 +102,7 @@
"@types/node": "catalog:",
"@typescript/native-preview": "catalog:",
"diff": "catalog:",
"ghostty-web": "github:anomalyco/ghostty-web#83c0a07b8628b748aed073b232cb4b52a6ca11c1",
"happy-dom": "20.11.1",
"tw-animate-css": "1.4.0",
"vite": "8.2.2",
@@ -112,13 +112,13 @@
},
"packages/cli": {
"name": "@opencode/cli",
"version": "2.0.18",
"version": "2.0.21",
"bin": {
"opencode": "./bin/opencode.cjs",
"opencode2": "./bin/opencode2.cjs",
},
"dependencies": {
"@agentclientprotocol/sdk": "1.2.1",
"@agentclientprotocol/sdk": "1.6.0",
"@clack/core": "1.0.0-alpha.1",
"@clack/prompts": "1.0.0-alpha.1",
"@effect/platform-node": "catalog:",
@@ -178,7 +178,7 @@
},
"packages/client": {
"name": "@opencode/client",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@opencode/protocol": "workspace:*",
"@opencode/schema": "workspace:*",
@@ -194,7 +194,7 @@
"zod": "catalog:",
},
"peerDependencies": {
"effect": "4.0.0-rc.117",
"effect": "4.0.0-rc.112",
"solid-js": ">=1.9.0",
},
"optionalPeers": [
@@ -204,7 +204,7 @@
},
"packages/codemode": {
"name": "@opencode/codemode",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"acorn": "8.15.0",
"effect": "catalog:",
@@ -217,7 +217,7 @@
},
"packages/console/app": {
"name": "@opencode/console-app",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@@ -253,7 +253,7 @@
},
"packages/console/core": {
"name": "@opencode/console-core",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@@ -280,7 +280,7 @@
},
"packages/console/function": {
"name": "@opencode/console-function",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@openauthjs/openauth": "0.0.0-20250322224806",
"@opencode/console-core": "workspace:*",
@@ -297,7 +297,7 @@
},
"packages/console/mail": {
"name": "@opencode/console-mail",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@@ -321,7 +321,7 @@
},
"packages/console/support": {
"name": "@opencode/console-support",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@opencode/console-core": "workspace:*",
@@ -341,7 +341,7 @@
},
"packages/core": {
"name": "@opencode/core",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@ai-sdk/cohere": "3.0.27",
"@ai-sdk/gateway": "3.0.104",
@@ -377,6 +377,7 @@
"https-proxy-agent": "7.0.6",
"ignore": "7.0.5",
"immer": "11.1.4",
"jose": "6.0.11",
"jsonc-parser": "3.3.1",
"mime-types": "3.0.2",
"tree-sitter-bash": "0.25.0",
@@ -405,12 +406,11 @@
"@types/node": "catalog:",
"@types/which": "3.0.4",
"drizzle-kit": "catalog:",
"fast-check": "catalog:",
},
},
"packages/desktop": {
"name": "@opencode/desktop",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@zip.js/zip.js": "2.7.62",
"electron-context-menu": "5.0.0",
@@ -424,26 +424,22 @@
"@lydell/node-pty": "catalog:",
"@opencode/app": "workspace:*",
"@opencode/client": "workspace:*",
"@opencode/plugin-browser": "workspace:*",
"@opencode/gui-extensions": "workspace:*",
"@opencode/schema": "workspace:*",
"@opencode/ui": "workspace:*",
"@sentry/solid": "catalog:",
"@sentry/vite-plugin": "catalog:",
"@solid-primitives/storage": "catalog:",
"@solidjs/meta": "catalog:",
"@solidjs/router": "catalog:",
"@types/bun": "catalog:",
"@types/node": "catalog:",
"@typescript/native-preview": "catalog:",
"app-builder-lib": "26.15.7",
"devtools-protocol": "0.0.1687809",
"drizzle-kit": "catalog:",
"drizzle-orm": "catalog:",
"effect": "catalog:",
"electron": "44.4.3",
"electron": "44.4.5",
"electron-builder": "26.15.7",
"electron-vite": "6.0.0-beta.1",
"puppeteer-core": "25.9.0",
"solid-js": "catalog:",
"typescript": "~5.6.2",
"vite": "8.2.2",
@@ -459,7 +455,7 @@
},
"packages/enterprise": {
"name": "@opencode/enterprise",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@hono/standard-validator": "catalog:",
"@opencode-ai/sdk": "1.18.21",
@@ -496,7 +492,7 @@
},
"packages/function": {
"name": "@opencode/function",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@@ -510,11 +506,56 @@
"typescript": "catalog:",
},
},
"packages/gui-extensions": {
"name": "@opencode/gui-extensions",
"version": "2.0.20",
"dependencies": {
"@dnd-kit/abstract": "0.5.0",
"@dnd-kit/dom": "0.5.0",
"@dnd-kit/solid": "0.5.0",
"@effect/platform-node": "catalog:",
"@kobalte/core": "catalog:",
"@opencode/client": "workspace:*",
"@opencode/plugin-browser": "workspace:*",
"@opencode/schema": "workspace:*",
"@opencode/session-ui": "workspace:*",
"@opencode/ui": "workspace:*",
"@opencode/util": "workspace:*",
"@pierre/trees": "1.0.0-beta.4",
"@solid-primitives/event-listener": "catalog:",
"@solid-primitives/keyed": "1.5.3",
"@solid-primitives/media": "catalog:",
"@solid-primitives/resize-observer": "catalog:",
"@solid-primitives/scheduled": "1.5.3",
"@tanstack/solid-query": "5.91.4",
"@tanstack/solid-virtual": "catalog:",
"effect": "catalog:",
"fuzzysort": "catalog:",
"ghostty-web": "github:anomalyco/ghostty-web#83c0a07b8628b748aed073b232cb4b52a6ca11c1",
"remeda": "catalog:",
"solid-js": "catalog:",
"solid-presence": "0.2.0",
"uqr": "0.1.3",
},
"devDependencies": {
"@happy-dom/global-registrator": "20.0.11",
"@lydell/node-pty": "catalog:",
"@tsconfig/node22": "catalog:",
"@types/bun": "catalog:",
"@types/node": "catalog:",
"@typescript/native-preview": "catalog:",
"devtools-protocol": "0.0.1687809",
"electron": "44.4.5",
"electron-updater": "6.8.9",
"lighthouse": "13.4.1",
"vite": "catalog:",
},
},
"packages/http-recorder": {
"name": "@opencode/http-recorder",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@effect/platform-node-shared": "4.0.0-rc.117",
"@effect/platform-node-shared": "4.0.0-rc.112",
},
"devDependencies": {
"@effect/platform-node": "catalog:",
@@ -531,7 +572,7 @@
},
"packages/httpapi-codegen": {
"name": "@opencode/httpapi-codegen",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"effect": "catalog:",
"prettier": "3.6.2",
@@ -544,7 +585,7 @@
},
"packages/latex": {
"name": "@opencode/latex",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@opencode/plugin": "workspace:*",
"@opentui/core": "catalog:",
@@ -558,7 +599,7 @@
},
"packages/merman": {
"name": "@opencode/merman",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@opencode/plugin": "workspace:*",
"@opentui/core": "catalog:",
@@ -573,7 +614,7 @@
},
"packages/plugin": {
"name": "@opencode/plugin",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@ai-sdk/provider": "3.0.8",
"@opencode/ai": "workspace:*",
@@ -599,8 +640,8 @@
},
"peerDependencies": {
"@opencode/theme": "workspace:*",
"@opentui/core": ">=0.5.12",
"@opentui/solid": ">=0.5.12",
"@opentui/core": ">=0.5.14",
"@opentui/solid": ">=0.5.14",
"solid-js": ">=1.9.0",
},
"optionalPeers": [
@@ -612,7 +653,7 @@
},
"packages/plugin-browser": {
"name": "@opencode/plugin-browser",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@opencode/plugin": "workspace:*",
"@opencode/schema": "workspace:*",
@@ -642,7 +683,7 @@
},
"packages/protocol": {
"name": "@opencode/protocol",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@opencode/schema": "workspace:*",
"effect": "catalog:",
@@ -657,7 +698,7 @@
},
"packages/schema": {
"name": "@opencode/schema",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@standard-schema/spec": "catalog:",
"effect": "catalog:",
@@ -681,7 +722,7 @@
},
"packages/sdk": {
"name": "@opencode/sdk",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@opencode/client": "workspace:*",
"@opencode/core": "workspace:*",
@@ -702,7 +743,7 @@
},
"packages/server": {
"name": "@opencode/server",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@effect/platform-node": "catalog:",
"@effect/platform-node-shared": "catalog:",
@@ -724,7 +765,7 @@
},
"packages/session-ui": {
"name": "@opencode/session-ui",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode/client": "workspace:*",
@@ -759,7 +800,7 @@
},
"packages/simulation": {
"name": "@opencode/simulation",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@opencode/ai": "workspace:*",
"@opencode/core": "workspace:*",
@@ -779,7 +820,7 @@
},
"packages/stats/app": {
"name": "@opencode/stats-app",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@ibm/plex": "6.4.1",
"@kobalte/core": "catalog:",
@@ -813,7 +854,7 @@
},
"packages/stats/core": {
"name": "@opencode/stats-core",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@aws-sdk/client-athena": "3.933.0",
"@planetscale/database": "1.19.0",
@@ -832,7 +873,7 @@
},
"packages/stats/server": {
"name": "@opencode/stats-server",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@aws-sdk/client-firehose": "3.933.0",
"@effect/platform-node": "catalog:",
@@ -878,7 +919,7 @@
},
"packages/theme": {
"name": "@opencode/theme",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@opentui/core": "catalog:",
"effect": "catalog:",
@@ -892,7 +933,7 @@
},
"packages/tui": {
"name": "@opencode/tui",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@opencode/client": "workspace:*",
"@opencode/core": "workspace:*",
@@ -926,7 +967,7 @@
},
"packages/ui": {
"name": "@opencode/ui",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@kobalte/core": "catalog:",
"@pierre/diffs": "catalog:",
@@ -961,7 +1002,7 @@
},
"packages/util": {
"name": "@opencode/util",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@effect/opentelemetry": "catalog:",
"@effect/platform-node": "catalog:",
@@ -999,7 +1040,7 @@
},
"packages/web": {
"name": "@opencode/web",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
@@ -1040,7 +1081,7 @@
},
"services/update": {
"name": "@opencode/update",
"version": "2.0.18",
"version": "2.0.21",
"dependencies": {
"jose": "6.0.11",
"semver": "catalog:",
@@ -1106,10 +1147,10 @@
"catalog": {
"@cloudflare/workers-types": "4.20251008.0",
"@corvu/drawer": "0.2.4",
"@effect/opentelemetry": "4.0.0-rc.117",
"@effect/platform-node": "4.0.0-rc.117",
"@effect/platform-node-shared": "4.0.0-rc.117",
"@effect/sql-sqlite-bun": "4.0.0-rc.117",
"@effect/opentelemetry": "4.0.0-rc.112",
"@effect/platform-node": "4.0.0-rc.112",
"@effect/platform-node-shared": "4.0.0-rc.112",
"@effect/sql-sqlite-bun": "4.0.0-rc.112",
"@hono/standard-validator": "0.2.0",
"@hono/zod-validator": "0.4.2",
"@kobalte/core": "0.13.13",
@@ -1117,10 +1158,10 @@
"@npmcli/arborist": "9.4.0",
"@octokit/rest": "22.0.0",
"@openauthjs/openauth": "0.0.0-20250322224806",
"@opentui/core": "0.5.12",
"@opentui/keymap": "0.5.12",
"@opentui/solid": "0.5.12",
"@pierre/diffs": "1.2.10",
"@opentui/core": "0.5.14",
"@opentui/keymap": "0.5.14",
"@opentui/solid": "0.5.14",
"@pierre/diffs": "1.5.1",
"@playwright/test": "1.59.1",
"@sentry/solid": "10.71.0",
"@sentry/vite-plugin": "5.4.0",
@@ -1149,8 +1190,7 @@
"dompurify": "3.4.14",
"drizzle-kit": "1.0.0-rc.5-ab785fc",
"drizzle-orm": "1.0.0-rc.5-169397b",
"effect": "4.0.0-rc.117",
"fast-check": "4.9.0",
"effect": "4.0.0-rc.112",
"fuzzysort": "3.1.0",
"get-east-asian-width": "1.6.0",
"hono": "4.10.7",
@@ -1190,7 +1230,7 @@
"@adobe/css-tools": ["@adobe/css-tools@4.5.0", "", {}, "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q=="],
"@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@1.2.1", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-jwYUdOQR7tc+Zfch53VL4JJyUNK/46q03uUTYb+PjECsmnNl94XFXOfYLJ8RBpMNidXd1rpOAVgb0vqD98xImA=="],
"@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@1.6.0", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-XxXrmX7aZkDgOB0Rg9cu+ZFyiUUc5lF2n9seO3Gc4OR+MTdfZOwIqF6m3LvsmmM8K3qgPmXkDH8/IFM2u9vdcQ=="],
"@ai-sdk/cohere": ["@ai-sdk/cohere@3.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-OqcCq2PiFY1dbK/0Ck45KuvE8jfdxRuuAE9Y5w46dAk6U+9vPOeg1CDcmR+ncqmrYrhRl3nmyDttyDahyjCzAw=="],
@@ -1682,13 +1722,13 @@
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.12.0", "", {}, "sha512-mlUE+rZ8CatQekLhnaiN91Iemdd+e2gFKooGlnRB3oPTL3VghLfX24dx7HrzMNeC1JrIB/0kpsfyty3f5HNfxQ=="],
"@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-rc.117", "", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-base": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-node": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-web": ">=2.0.0 <3.0.0", "@opentelemetry/semantic-conventions": ">=1.33.0 <2.0.0", "effect": "^4.0.0-rc.117" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-IWAn2rU/RZLStkXfcdF1nGxcKQ7kbHct7N98T/5yOmSYiXvD8ZIxsGZhuAcRPPjc0NbNU2Ay8DZLPesyhJhUgA=="],
"@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-rc.112", "", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-base": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-node": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-web": ">=2.0.0 <3.0.0", "@opentelemetry/semantic-conventions": ">=1.33.0 <2.0.0", "effect": "^4.0.0-rc.112" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-OTRv1DxTHUmnakgJ6XVM8wVgF1KgZH4UXnOemwSLUwUjXO+RCikzF8oR/rlVmOGq81KtQzj1URM4M4nchlQOuQ=="],
"@effect/platform-node": ["@effect/platform-node@4.0.0-rc.117", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.117", "undici": "^8.10.2" }, "peerDependencies": { "effect": "^4.0.0-rc.117", "redis": ">=5.0.0 <7.0.0" } }, "sha512-WbPcvQDkqXFnCeG6LohJ9eVNapCDhZbCpezhYKxm0IsZEk7swakRh7RkC1t2CXzd3hGmszTv2k9e/pXyZuL+wQ=="],
"@effect/platform-node": ["@effect/platform-node@4.0.0-rc.112", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.112", "mime": "^4.1.0", "undici": "^8.10.0" }, "peerDependencies": { "effect": "^4.0.0-rc.112", "redis": ">=5.0.0 <7.0.0" } }, "sha512-/BMAcdNGQQskLmI0Zoa95KfTZkr9HV9N4NSxaSrusG6GeW6Ulp9KvZ+Rlaiw8lnOt43CXjFLdfll5/k5rxL4hQ=="],
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.117", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.3" }, "peerDependencies": { "effect": "^4.0.0-rc.117" } }, "sha512-GyRkEfLBG49MwJe+/XDPiXYcQ44RA9p2z0AurlsWhR1cd1PqOUMEZU1pORL+/R5hR8aH6ZuqoJYD8lAc6h+wlA=="],
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.112", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.3" }, "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-ttjz0xKamFN7vL8pNDYVwddJLjZvqKePc05djlz2VcdaKbLsnYbtMnL1rbOfHgEnIUSHGh7FkjaN4DM1Ov81sQ=="],
"@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.0-rc.117", "", { "peerDependencies": { "effect": "^4.0.0-rc.117" } }, "sha512-UjgkEmR+s5Rc870sDsDzu/8AA5KQqcBeq5qgH6AFe5OYfv3GCMfoQTkIvnl+Q3M5KaZosYgwwEy9uij/J2HOJw=="],
"@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.0-rc.112", "", { "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-EqR8pWZo3VzedRvP6qo5HcfqNmFvSa+sQLWQl3oBMx2KY1FCc8NYjep79wYjNkW0qABnffrPUXCMTOncd1A+5g=="],
"@electron-internal/extract-zip": ["@electron-internal/extract-zip@1.0.5", "", {}, "sha512-+bqFCP98pLI0Tt0XQo1TmlXtwjWchISndDOxCkEcIuUgXWpBnLyRI+2DU+mesvnMMX6L1XDqYNA0lXNDHd/yiA=="],
@@ -2022,6 +2062,18 @@
"@motionone/utils": ["@motionone/utils@10.18.0", "", { "dependencies": { "@motionone/types": "^10.17.1", "hey-listen": "^1.0.8", "tslib": "^2.3.1" } }, "sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw=="],
"@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ=="],
"@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w=="],
"@msgpackr-extract/msgpackr-extract-linux-arm": ["@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4", "", { "os": "linux", "cpu": "arm" }, "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw=="],
"@msgpackr-extract/msgpackr-extract-linux-arm64": ["@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw=="],
"@msgpackr-extract/msgpackr-extract-linux-x64": ["@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ=="],
"@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4", "", { "os": "win32", "cpu": "x64" }, "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ=="],
"@napi-rs/lzma-linux-x64-gnu": ["@napi-rs/lzma-linux-x64-gnu@1.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ=="],
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.2.3", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, "sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q=="],
@@ -2164,6 +2216,8 @@
"@opencode/function": ["@opencode/function@workspace:packages/function"],
"@opencode/gui-extensions": ["@opencode/gui-extensions@workspace:packages/gui-extensions"],
"@opencode/http-recorder": ["@opencode/http-recorder@workspace:packages/http-recorder"],
"@opencode/httpapi-codegen": ["@opencode/httpapi-codegen@workspace:packages/httpapi-codegen"],
@@ -2244,27 +2298,27 @@
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="],
"@opentui/core": ["@opentui/core@0.5.12", "", { "dependencies": { "bun-ffi-structs": "0.3.1", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.5.12", "@opentui/core-darwin-x64": "0.5.12", "@opentui/core-linux-arm64": "0.5.12", "@opentui/core-linux-arm64-musl": "0.5.12", "@opentui/core-linux-x64": "0.5.12", "@opentui/core-linux-x64-musl": "0.5.12", "@opentui/core-win32-arm64": "0.5.12", "@opentui/core-win32-x64": "0.5.12" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-ZXBE5gmvdovmV8zJQrOQf6E44v1tJRDEgrM2MYhEglzgXZ+smIUp95O8zeRYGsuIzQIiMPMgQqKtTJuzvAb7BQ=="],
"@opentui/core": ["@opentui/core@0.5.14", "", { "dependencies": { "bun-ffi-structs": "0.3.1", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.5.14", "@opentui/core-darwin-x64": "0.5.14", "@opentui/core-linux-arm64": "0.5.14", "@opentui/core-linux-arm64-musl": "0.5.14", "@opentui/core-linux-x64": "0.5.14", "@opentui/core-linux-x64-musl": "0.5.14", "@opentui/core-win32-arm64": "0.5.14", "@opentui/core-win32-x64": "0.5.14" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-tfQ+PWQyeBnYloB3diEcPqbILv14xemH5jjAEICfPuyNDtGBqrjhUtThrhbvFRuPMcj6IEeXrAk6VE8e91h0kg=="],
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.5.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-YdVnP0tAyerBNl0mIcmQEOotPeZzW1VnSXKBl5cyZ5e6nDd2Y+ui/8eRPpn1oqcamf1NCnzS4ohMgejOvna8Zg=="],
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.5.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wWmw41wRMBoI0lN9mgyzGRwYujwwfNkBP6jYM99k4Bx2XkeSZ3sCeu5bwX9vEJPYqjiBShbDhc0NnVSP7NwzVg=="],
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.5.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-uRrQJdHmLUSj3PV23QPi3WSimYTTxcXnVouxF6U4xMXlOv4N3SxnHfVwMRQkPqbGOfvVWHeLE6FdK4C+ubU0sQ=="],
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.5.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-7smHKDH8IhUaBsgYuAClMl2mHWu+yjpMrtdw3wEvBVtCzKMrHi/TJ5PtydO+IfUzR3BXpVubdbR1irD8BTcR/w=="],
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.5.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-XeKhuIaEtgipvuPHbl4qPOBj+Ut+2zObmsxMVM1jDcjz/FatG9PGeGQPx1G1SnvH2AgpT4K+eCu7DUF0+yIqoQ=="],
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.5.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-xH1hP+NaLySEJeZkl21NlkZBMddMfQ1jU8NeX1AEBc2GNBOvDXU4Ud/xw87SrAvU1xG9K7/9C4oy4AmIMEpVGg=="],
"@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.5.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-VZ2sNMw1d/r1SLPjUbOP9LKscKz1CQjID8adTL6gG8Lrrq+mYcIUxutyB+P/eG0J/7oRZLPR6OMt7dUOap6RTg=="],
"@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.5.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-mnBBAuTb92NiRLAjOD755tS8/tNQemDztbg9tMvoCT90G52FtVrRb31Ge6OrYqfm0c9DkZGhEBOhunsId/4zSA=="],
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.5.12", "", { "os": "linux", "cpu": "x64" }, "sha512-eZiCjEzwbb6qClPPfk32Nha9xmr9obt69Xj0+9SKsXxWLBKkjQEGOMRoh/R9ObaQF4aq8If1xV3VEY0sD9W9vg=="],
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.5.14", "", { "os": "linux", "cpu": "x64" }, "sha512-Hkk4kaDGMcn9bmJFJPW3/QOGGbPuWe3sCFV/CkiVb4+bCvcTm7EXQr4QTAA63BYy2dKE5bUFUi1zZlyeMkWpnA=="],
"@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.5.12", "", { "os": "linux", "cpu": "x64" }, "sha512-WWW0hVBoSYZ3D6AgZ4u2Y5/u/IyIq2pDb+4yI3WgJ70Wyt6ofHy+6kRGRgbXFn1p+rPInAHjCXD2v6C7iEKSrA=="],
"@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.5.14", "", { "os": "linux", "cpu": "x64" }, "sha512-ngJ+U2grOGEteeQvZdAJNqn09M+At5mfWInauK5aS427bea1yLo+e6hor/CRmbn9SxEEF+SwoyekaOrLPWyU7w=="],
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.5.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-aLbm6870Ybls6CYL4zMOCImTBPLZHZMUXJFGqMI44lIWxitkAtT6zg5lYA4oRqFRzzryDclxr29+hDgT3p3Blw=="],
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.5.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-T9kNqKXg2jysmTsyyZ1A8LBQotFBM+iPjzyRslxyexqrs8a1UcmxbApEo+COtxQuqukMTbvwyqEdAT8vcmxEkQ=="],
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.5.12", "", { "os": "win32", "cpu": "x64" }, "sha512-KTwtwpfd2zF9opVh3SyRJYDd1o3Xv4XL8OZb8Zi+CqWUel6Y2IDCiVivCv8fGJt3J7wOIXXtuZI9ZUkLyKJCiQ=="],
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.5.14", "", { "os": "win32", "cpu": "x64" }, "sha512-mqKSkab8VdMLSmMdocna7+BTyMoIutkVXOV9lfmPrBO2g7Np5c6c4SJ4QIVZqPvast11XyT0/7FfXOYLKAS72w=="],
"@opentui/keymap": ["@opentui/keymap@0.5.12", "", { "dependencies": { "@opentui/core": "0.5.12" }, "peerDependencies": { "@opentui/react": "0.5.12", "@opentui/solid": "0.5.12", "react": ">=19.2.0", "solid-js": "1.9.12" }, "optionalPeers": ["@opentui/react", "@opentui/solid", "react", "solid-js"] }, "sha512-yWPvJjRhJTRoRSUucQq9Ua8ZW7n/2YQ/j6JxWq5Qekm4WuFiTplEkebR/Aj2/xA8tX68NOE5qv1LrY0Jk3NLNQ=="],
"@opentui/keymap": ["@opentui/keymap@0.5.14", "", { "dependencies": { "@opentui/core": "0.5.14" }, "peerDependencies": { "@opentui/react": "0.5.14", "@opentui/solid": "0.5.14", "react": ">=19.2.0", "solid-js": "1.9.12" }, "optionalPeers": ["@opentui/react", "@opentui/solid", "react", "solid-js"] }, "sha512-YGTAvRrpQTbRNV7GH0UxRuCSPxwnSooVdB+qPHHP+3ywc93+lhekljgP8dRivl32f3CiMqqm96Uj2PgwKxkC0Q=="],
"@opentui/solid": ["@opentui/solid@0.5.12", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.5.12", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-hAiVlVMtT7AkHGblKwcW1YAuXtxkSy1XSf/RRc4j3IlG3mTNX0bhJdnGOo3Xw14EqeZMp41Mcp5WzHAzMm/DzA=="],
"@opentui/solid": ["@opentui/solid@0.5.14", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.5.14", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-bBRl34mZ0wFGhjHX6y1VNiZmJ3DSm2DVPm0PNSVDpvq9qxRHuywEPTCn/Lgte0C9450tgf11cDqcE3pR9cZwVA=="],
"@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
@@ -2466,6 +2520,8 @@
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.60.0", "", { "os": "win32", "cpu": "x64" }, "sha512-JOro4ZcfBLamJCyfURQmOQByoorgOdx3ZjAkSqnb/CyG/i+lN3KoV5LAgk5ZAW6DPq7/Cx7n23f8DuTWXTWgyQ=="],
"@oxlint/plugins": ["@oxlint/plugins@1.60.0", "", {}, "sha512-wxEoVVAS5FQAXiA8jPY+NWTOTKTzbSViMfW7yU5OQ7+f34W0KYfy2iuSLC9o1fiYn5xt3LQLxZBREFJtDlQLRw=="],
"@pagefind/darwin-arm64": ["@pagefind/darwin-arm64@1.5.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ=="],
"@pagefind/darwin-x64": ["@pagefind/darwin-x64@1.5.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw=="],
@@ -2520,11 +2576,11 @@
"@peculiar/webcrypto": ["@peculiar/webcrypto@1.7.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.7.0", "@peculiar/json-schema": "^1.1.12", "@peculiar/utils": "^2.0.2", "tslib": "^2.8.1", "webcrypto-core": "^1.9.2" } }, "sha512-ODOov0sGMJMf3jPonOkgGqPknTsu+DdQ7kD++gz8aI+aFMOMHFbWAA2taqXXVTdP+OTOQR/znGvSpmkeI0WTYQ=="],
"@pierre/diffs": ["@pierre/diffs@1.2.10", "", { "dependencies": { "@pierre/theme": "1.0.3", "@pierre/theming": "0.0.1", "@shikijs/transformers": "^3.0.0 || ^4.0.0", "diff": "8.0.3", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "^3.0.0 || ^4.0.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-rPeAmDWarxFVTQpaf4y6wTxjZxU44xKJKoJti2zU21P06DVd9nRHZX+xSIObLB307Qjpaesyb1x/j0z94t7vLw=="],
"@pierre/diffs": ["@pierre/diffs@1.5.1", "", { "dependencies": { "@pierre/theme": "2.0.0", "@pierre/theming": "1.0.1", "@shikijs/transformers": "^3.0.0 || ^4.0.0", "diff": "9.0.0", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "^3.0.0 || ^4.0.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-+EXNfz4ZXI6FHr7P6ToWEORwyYiPVfAmzhA70xF+0y/oNvj7gbNTLJJ6jNzkBjuMbRlu564TAmgYZLc5OyHURA=="],
"@pierre/theme": ["@pierre/theme@1.0.3", "", {}, "sha512-sWHv11TMoqKxKDgTIk5VbhQjdPhs8DCcBxbjh3mRlS3YOM/OcrWoGX6MM8eBGn9cUu3M46Py0JnxsG2nJaFTuA=="],
"@pierre/theme": ["@pierre/theme@2.0.0", "", {}, "sha512-yNDd9GYLQl1mEUJR8AneJ5e4ohLIHQd/wZLWr4fagt78vS2RwwZNW530vVgHqXFAyFVcFlRmGUD5ramXH46OXw=="],
"@pierre/theming": ["@pierre/theming@0.0.1", "", { "peerDependencies": { "@pierre/theme": "^1.0.0", "@shikijs/themes": "^3.0.0 || ^4.0.0", "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0", "shiki": "^3.0.0 || ^4.0.0" }, "optionalPeers": ["@pierre/theme", "@shikijs/themes", "react", "react-dom", "shiki"] }, "sha512-1thlEtJbqdyLzc1ZS2KQa1q7FzDGHT4dTEdKHoyQjOMeWWOmbVG5/ndEfOKfAb5Fzkz8cNJrOjFLiZoDH/A03A=="],
"@pierre/theming": ["@pierre/theming@1.0.1", "", { "peerDependencies": { "@pierre/theme": "^1.1.0 || ^2.0.0", "@shikijs/themes": "^3.0.0 || ^4.0.0", "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0", "shiki": "^3.0.0 || ^4.0.0" }, "optionalPeers": ["@pierre/theme", "@shikijs/themes", "react", "react-dom", "shiki"] }, "sha512-WCI5Qd7iprDpISL9fBYOLe8RV53+b7mFNA3bPzl60/2CKCSrsKN8zEcep6Y3BAzvARlmca50zGjDodqPGiTUKA=="],
"@pierre/trees": ["@pierre/trees@1.0.0-beta.4", "", { "dependencies": { "preact": "11.0.0-beta.0", "preact-render-to-string": "6.6.5" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-OfT1yk9ne8Te5+GB5zUY8yqE6B8BqjBHQJleH4lu8ltwNpoocZl4vXt1AzlEExpxI/pp+AFX5QG+lR3JjtTEag=="],
@@ -3856,11 +3912,11 @@
"editorconfig": ["editorconfig@1.0.7", "", { "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", "minimatch": "^9.0.1", "semver": "^7.5.3" }, "bin": { "editorconfig": "bin/editorconfig" } }, "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw=="],
"effect": ["effect@4.0.0-rc.117", "", {}, "sha512-UUyi9QiOW4nySFIBM3KnYbNMd9EZliOdKfBcyLD0mPMPheO2fkuXS5y0opjWc9oqzlJxPQICEGm8gGw3kh9j/w=="],
"effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="],
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
"electron": ["electron@44.4.3", "", { "dependencies": { "@electron-internal/extract-zip": "^1.0.1", "@electron/get": "^5.0.0", "@types/node": "^24.9.0" }, "bin": { "electron": "cli.js", "install-electron": "install.js" } }, "sha512-LTpSFTB40qVCXIX5xMo+cgHI/Jjkbjw7VpB26PccEbroqOn72LBukeaDwPVo1fBYzSzs0c9iPuAucFCO7Tw81Q=="],
"electron": ["electron@44.4.5", "", { "dependencies": { "@electron-internal/extract-zip": "^1.0.1", "@electron/get": "^5.0.0", "@types/node": "^24.9.0" }, "bin": { "electron": "cli.js", "install-electron": "install.js" } }, "sha512-SjgoaeYsSWZfJzubgQU7juvuXMTvn6/e1gAHdGFA/yuMbpF+I+skYqIJ6DdXBXHeWbkbpNpmwZCTpiivtlWZSw=="],
"electron-builder": ["electron-builder@26.15.7", "", { "dependencies": { "app-builder-lib": "26.15.7", "builder-util": "26.15.3", "builder-util-runtime": "9.7.0", "chalk": "^4.1.2", "ci-info": "^4.2.0", "dmg-builder": "26.15.7", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "./cli.js", "install-app-deps": "./install-app-deps.js" } }, "sha512-DBpaNzxsPs1BvEblzFoNriSbzsBqDCy/gseIngeEhYzQG1IxfB7Hvc2tBBVmpWE2BTQGP9J1RrAvDT+Vc/uAxg=="],
@@ -4694,7 +4750,7 @@
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
"mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
"mime": ["mime@4.1.0", "", { "bin": { "mime": "bin/cli.js" } }, "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw=="],
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
@@ -4742,6 +4798,10 @@
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"msgpackr": ["msgpackr@2.0.5", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-cef05H/dSYpLpqp3sj/qyZh5vhUYCalnaLO7j1yOmpsR0y/XwLVtK7r5gn+U/F7CTEfMowcGhlUQJDLcLf7jcA=="],
"msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="],
"muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="],
"mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="],
@@ -4784,6 +4844,8 @@
"node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="],
"node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="],
"node-html-parser": ["node-html-parser@7.1.0", "", { "dependencies": { "css-select": "^5.1.0", "he": "1.2.0" } }, "sha512-iJo8b2uYGT40Y8BTyy5ufL6IVbN8rbm/1QK2xffXU/1a/v3AAa0d1YAoqBNYqaS4R/HajkWIpIfdE6KcyFh1AQ=="],
"node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="],
@@ -5580,7 +5642,7 @@
"uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
"undici": ["undici@8.10.2", "", {}, "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ=="],
"undici": ["undici@8.10.0", "", {}, "sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ=="],
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
@@ -6032,6 +6094,8 @@
"@bufbuild/protoplugin/typescript": ["typescript@5.4.5", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ=="],
"@cloudflare/kv-asset-handler/mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
"@cloudflare/vite-plugin/vite": ["vite@7.3.6", "", { "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg=="],
"@cloudflare/vite-plugin/ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
@@ -6180,6 +6244,8 @@
"@opencode/files/wrangler": ["wrangler@4.110.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.5.0", "@cloudflare/unenv-preset": "2.16.1", "blake3-wasm": "2.1.5", "esbuild": "0.28.1", "miniflare": "4.20260708.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20260708.1" }, "optionalDependencies": { "fsevents": "2.3.3" }, "peerDependencies": { "@cloudflare/workers-types": "^5.20260708.1" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js", "cf-wrangler": "bin/cf-wrangler.js" } }, "sha512-xZeXKYi7hxQRF5anL+v77RkufJNpF9f3Eqeyqq2QBsETpLZgh0Agj0jJ6JPtkbgn6ukZdh8OK5egsGPWIditgg=="],
"@opencode/gui-extensions/vite": ["vite@7.3.6", "", { "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg=="],
"@opencode/posts/wrangler": ["wrangler@4.110.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.5.0", "@cloudflare/unenv-preset": "2.16.1", "blake3-wasm": "2.1.5", "esbuild": "0.28.1", "miniflare": "4.20260708.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20260708.1" }, "optionalDependencies": { "fsevents": "2.3.3" }, "peerDependencies": { "@cloudflare/workers-types": "^5.20260708.1" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js", "cf-wrangler": "bin/cf-wrangler.js" } }, "sha512-xZeXKYi7hxQRF5anL+v77RkufJNpF9f3Eqeyqq2QBsETpLZgh0Agj0jJ6JPtkbgn6ukZdh8OK5egsGPWIditgg=="],
"@opencode/session-ui/vite": ["vite@7.3.6", "", { "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg=="],
@@ -6240,11 +6306,7 @@
"@parcel/watcher/detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="],
"@pierre/diffs/diff": ["diff@8.0.3", "", {}, "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ=="],
"@pierre/diffs/react": ["react@19.2.8", "", {}, "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw=="],
"@pierre/diffs/react-dom": ["react-dom@19.2.8", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.8" } }, "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ=="],
"@pierre/diffs/diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="],
"@pierre/trees/react": ["react@19.2.8", "", {}, "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw=="],
@@ -6632,8 +6694,6 @@
"tw-to-css/tailwindcss": ["tailwindcss@3.3.2", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.18.2", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", "postcss": "^8.4.23", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w=="],
"unifont/undici": ["undici@8.10.0", "", {}, "sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ=="],
"unplugin/acorn": ["acorn@8.18.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ=="],
"unused-filename/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
@@ -7144,8 +7204,6 @@
"@oxc-resolver/binding-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
"@pierre/diffs/react-dom/scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
"@pierre/trees/react-dom/scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
"@puppeteer/browsers/yargs/cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="],
Generated
+3 -3
View File
@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1776683584,
"narHash": "sha256-NuTLMrr10Tng72hurYG8jYQ4XKK8wnpJmOGcPiis96g=",
"lastModified": 1790510107,
"narHash": "sha256-EVMNYv7hYDDD9TGVT/hIyTYgpiXA8y3m5xIEIxuGNU0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9dd5558b06dbdacbf635a3dd36dce1b1a7ee3a89",
"rev": "3181085bfd08663b6b9e60bc7a8395c2aaa741bd",
"type": "github"
},
"original": {
+1 -2
View File
@@ -12,7 +12,6 @@
"aarch64-linux"
"x86_64-linux"
"aarch64-darwin"
"x86_64-darwin"
];
forEachSystem = f: nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
rev = self.shortRev or self.dirtyShortRev or "dirty";
@@ -22,7 +21,7 @@
default = pkgs.mkShell {
packages = with pkgs; [
bun
nodejs_20
nodejs
pkg-config
openssl
git
-1
View File
@@ -7,7 +7,6 @@ in
aarch64-linux = "20e68d6c4e47f3ebf59de7c6b1f8b8bec6a6ebda6a451132f9b465f3f13ce467";
x86_64-linux = "2452b27112d92387471fa2488aafac85d79ea3f2ee1216c0abd5150d6c12362b";
aarch64-darwin = "ac7194a3dfd81930ba35355c01620262c1254752859b42dcb8f4b9e4d174a871";
x86_64-darwin = "4489aba55477a0082266cb690db1c829503ba3338048599d8fd243953df37dab";
# fetchzip hashes the unpacked headers, not the release tarball.
headers = "sha256-4eUy3BZVvxTl7KUOsxio7769lL6ag/ecbeK+qLURWMI=";
}
+3 -4
View File
@@ -1,8 +1,7 @@
{
"nodeModules": {
"x86_64-linux": "sha256-7DgxTpKv6ITKTom0mhlJNPQfdEjtEHK5P8uyCr26HZw=",
"aarch64-linux": "sha256-PJxW1Ibfx6oS1neWPSHqzP1Pm1HT9my1TrrHmOb6/no=",
"aarch64-darwin": "sha256-VIme5VHfM8JxNiDSOykkr5FytghDLI0FxkhiOXUSyQw=",
"x86_64-darwin": "sha256-rQ/j0QkR1vxAq4jgUbr0nY4RDyiLTJqN8q1AfoiEqVQ="
"x86_64-linux": "sha256-g3k0cAFGqzmRYlcIkg1NDvlx1WxHYhnYPL0/a8E+qTg=",
"aarch64-linux": "sha256-a+3ymqdxOONGe2Tpq4GUccl1b+Dwzxlb9LFXgE1gZ+0=",
"aarch64-darwin": "sha256-h8xIzuMmaWfJqjHCO74xUDCWNKQLFrIGoKYZ+2TauYc="
}
}
-1
View File
@@ -81,6 +81,5 @@ stdenvNoCC.mkDerivation {
"aarch64-linux"
"x86_64-linux"
"aarch64-darwin"
"x86_64-darwin"
];
}
+14 -14
View File
@@ -2,7 +2,7 @@
"$schema": "https://json.schemastore.org/package.json",
"name": "opencode",
"description": "AI-powered development tool",
"version": "2.0.18",
"version": "2.0.21",
"private": true,
"type": "module",
"packageManager": "bun@1.4.2",
@@ -18,7 +18,7 @@
"dev:www": "bun run --cwd services/www dev",
"dev:storybook": "bun --cwd packages/storybook storybook",
"bench:devex": "bun run --cwd packages/app test:bench:devex",
"lint": "oxlint",
"lint": "oxlint && ast-grep scan -c script/ast-grep/gui-extensions/sgconfig.yml",
"lint:effect-patterns": "ast-grep scan -c script/ast-grep/sgconfig.yml packages/util/src packages/core/src packages/server/src packages/protocol/src packages/cli/src",
"lint:effect-simplifications": "ast-grep scan -c script/ast-grep/effect-simplifications/sgconfig.yml --off=unused-suppression packages",
"test:lint-rules": "ast-grep test -c script/ast-grep/sgconfig.yml",
@@ -42,19 +42,19 @@
"packages/stats/*"
],
"catalog": {
"@effect/opentelemetry": "4.0.0-rc.117",
"@effect/platform-node": "4.0.0-rc.117",
"@effect/platform-node-shared": "4.0.0-rc.117",
"@effect/sql-sqlite-bun": "4.0.0-rc.117",
"@effect/opentelemetry": "4.0.0-rc.112",
"@effect/platform-node": "4.0.0-rc.112",
"@effect/platform-node-shared": "4.0.0-rc.112",
"@effect/sql-sqlite-bun": "4.0.0-rc.112",
"@npmcli/arborist": "9.4.0",
"@types/bun": "1.4.0",
"@types/cross-spawn": "6.0.6",
"@octokit/rest": "22.0.0",
"@hono/standard-validator": "0.2.0",
"@hono/zod-validator": "0.4.2",
"@opentui/core": "0.5.12",
"@opentui/keymap": "0.5.12",
"@opentui/solid": "0.5.12",
"@opentui/core": "0.5.14",
"@opentui/keymap": "0.5.14",
"@opentui/solid": "0.5.14",
"@tanstack/solid-virtual": "3.13.37",
"@shikijs/stream": "4.4.3",
"@standard-schema/spec": "1.1.0",
@@ -68,7 +68,7 @@
"@tsconfig/bun": "1.0.9",
"@cloudflare/workers-types": "4.20251008.0",
"@openauthjs/openauth": "0.0.0-20250322224806",
"@pierre/diffs": "1.2.10",
"@pierre/diffs": "1.5.1",
"opentui-spinner": "0.0.7",
"@solid-primitives/event-listener": "2.4.6",
"@solid-primitives/media": "2.3.6",
@@ -79,8 +79,7 @@
"dompurify": "3.4.14",
"drizzle-kit": "1.0.0-rc.5-ab785fc",
"drizzle-orm": "1.0.0-rc.5-169397b",
"effect": "4.0.0-rc.117",
"fast-check": "4.9.0",
"effect": "4.0.0-rc.112",
"ai": "6.0.168",
"cross-spawn": "7.0.6",
"hono": "4.10.7",
@@ -118,10 +117,11 @@
"@actions/artifact": "5.0.1",
"@ast-grep/cli": "0.44.0",
"@opencode/client": "workspace:*",
"@types/react": "19.2.17",
"@types/react-dom": "19.2.3",
"@oxlint/plugins": "1.60.0",
"@tsconfig/bun": "catalog:",
"@types/mime-types": "3.0.1",
"@types/react": "19.2.17",
"@types/react-dom": "19.2.3",
"@typescript/native-preview": "catalog:",
"glob": "13.0.5",
"husky": "9.1.7",
+2 -2
View File
@@ -98,11 +98,11 @@ When a provider supports multiple physical transports, selection remains executi
Media does not fit the SSE-frames-to-event-state-machine LLM route. `MediaRoute.inline(...)` / `queued(...)` / `stream(...)` (`src/route/media.ts`) compose a `MediaProtocol` kind with `Endpoint` and `Auth` and own the transport plumbing: `http` option merging, URL/query rendering, auth headers, JSON vs multipart encoding, and handing the response back to the protocol. `MediaProtocol.inline` (`src/route/media-protocol.ts`) is `body.from(request)` plus `response.decode(response, context)`; each protocol declares `const route = MediaProtocol.identity({ id, name, provider })` once and decodes through `route.decodeJson` / `route.text` / `route.decodeStarted` so decode failures retain the raw body and HTTP context, raising `route.unsupported(operation, message)` for requests it cannot lower, and passes `route` as the first argument to `MediaProtocol.inline` / `queued` / `stream`. `Generation` (`src/generation.ts`) is the provider-neutral handle for a queued generation over a `GenerationRoute` (`status`, `result`, `cancel`). Image protocol files follow the same section order as LLM protocols and declare unsupported common fields once through the protocol's `unsupported` list.
`MediaProtocol.queued` is the submit-then-poll kind every video route uses: `start` (body + decode into `{ token, snapshot }`), `status`, `result`, and optional `cancel` (with `activeOnly` when the provider's cancel endpoint deletes finished work, as Runway's does: the route refreshes status first and skips terminal generations), each addressed by a route-owned `token` whose `Schema.Codec` makes it serializable. `MediaRoute.inline` and `MediaRoute.queued` compose the two kinds with `Endpoint` and `Auth`; the queued route decodes the token once at the boundary (`start` output or `resume` input) and closes over it in a token-free `GenerationRoute` (`status`/`result`/`cancel` are plain Effects), so `Generation` never sees the token's shape and only carries the encoded JSON for persistence. Polls reuse the route's auth and deployment headers plus the request's `http` overlay after `start`, and resolve relative paths against the route base URL (provider-issued absolute URLs such as fal's `status_url` pass through). `result` is always its own GET even when the provider returns output inside the status document, so `Generation.await` behaves the same after `start` and after `resume`. `PollContext.auth` carries only what `Auth` added or changed so protocols can hand download credentials to output assets as transient `Media.Asset.headers` (Veo) — never part of `source` or JSON. Status strings map through a per-protocol `STATUS` table via `MediaProtocol.status`; terminal generations without output fail through `output.ended` / `output.contentPolicy` with the provider document on `reason.body`. `GenerationAwaitOptions` (`AwaitOptions` in `src/generation.ts`, `{ poll?: Poll }`) is the one options type for `await`, `events`, `Video.generate`, and `Video.stream`.
`MediaProtocol.queued` is the submit-then-poll kind every video route uses: `start` (body + decode into `{ token, snapshot }`), `status`, `result`, and optional `cancel` (with `activeOnly` when the provider's cancel endpoint deletes finished work, as Runway's does: the route refreshes status first and skips terminal generations), each addressed by a route-owned `token` whose `Schema.Codec` makes it serializable. `MediaRoute.inline` and `MediaRoute.queued` compose the two kinds with `Endpoint` and `Auth`; the queued route decodes the token once at the boundary (`start` output or `resume` input) and closes over it in a token-free `GenerationRoute` (`status`/`result`/`cancel` are plain Effects), so `Generation` never sees the token's shape and only carries the encoded JSON for persistence. Polls reuse the route's auth and deployment headers plus the request's `http` overlay after `start`, and resolve relative paths against the route base URL (provider-issued absolute URLs such as fal's `status_url` pass through). `result` is always its own GET even when the provider returns output inside the status document, so `Generation.await` behaves the same after `start` and after `resume`. `PollContext.auth` carries only what `Auth` added or changed so protocols can hand download credentials to output assets as transient `Media.Asset.headers` (Veo) — never part of `source` or JSON. Status strings map through a per-protocol `STATUS` table via `MediaProtocol.status`; terminal generations without output fail through `output.ended` / `output.contentPolicy` with the provider document on `reason.body`; a `failed` generation maps the provider's error code through a per-protocol `FAILURE` table via `MediaProtocol.failure` so rejected inputs are not reported as retryable `ProviderInternal`. `GenerationAwaitOptions` (`AwaitOptions` in `src/generation.ts`, `{ poll?: Poll }`) is the one options type for `await`, `events`, `Video.generate`, and `Video.stream`.
`MediaProtocol.stream` is the incremental kind every speech route uses, with the same discipline as LLM protocols. `MediaRoute.stream` submits the caller's request as `MediaProtocol.Addressed<Request>` (`{ ...request, mode }`, `mode: "generate" | "stream"`), so one provider stays one protocol: `body.from`, the endpoint path, and `frames` read `request.mode` to pick the body, path, and framing. `frames(bytes, context)` returns frames — `Framing.sse`, `Framing.lines`, `Framing.document` (a single-document response shaped like a streamed record), or the raw `bytes` for chunked audio. `initial()` is fresh per-response parser state; `step` folds each frame into it and emits modality events; `finish(state, context)` runs once after the last frame with the request, body, and observed `http` (header-only usage lives there) and emits exactly one terminal event or fails with `route.incomplete()`. Keep parser state to real accumulators and derive anything the request or body determines in `finish`. `generate` runs the same stream and folds it with the modality's `collect`. Request-derived URL parameters go on the body's `query` (array values repeat the parameter), applied before route and caller `http.query`. Decode frames with `route.decodeFrame` and raise stream-time failures with `route.frameError` (the frame stays on `reason.body`); protocols never thread HTTP context, because the route fills `reason.http` on stream errors that lack it. Speech protocols share `protocols/utils/speech-stream.ts` for deltas, timestamps, voice ids, PCM and container descriptions, and the terminal asset.
Every modality route is the inline | stream | queued union (transcription uses all three: OpenAI and Gemini stream, Deepgram is inline, AssemblyAI is queued), every client is `MediaClient.make(Service, { modality, responseEvents })` (`src/media-client.ts`), which dispatches on the route's `kind`, and every model composes through `composeRoute`. fal queue protocols come from `protocols/utils/fal-queue.ts`, bodies are `json`, `multipart`, or `binary` (a raw upload), and a queued protocol that must upload media before submitting implements `start.prepare` (`MediaProtocol.Prepare`; AssemblyAI `/v2/upload`).
Every modality route is the inline | stream | queued union (transcription uses all three: OpenAI and Gemini stream, Deepgram and ElevenLabs are inline, AssemblyAI is queued), every client is `MediaClient.make(Service, { modality, responseEvents })` (`src/media-client.ts`), which dispatches on the route's `kind`, and every model composes through `composeRoute`. fal queue protocols come from `protocols/utils/fal-queue.ts`, bodies are `json`, `multipart`, or `binary` (a raw upload), and a queued protocol that must upload media before submitting implements `start.prepare` (`MediaProtocol.Prepare`; AssemblyAI `/v2/upload`).
### URL Construction
+25 -13
View File
@@ -129,8 +129,9 @@ VercelAIGateway.configure().experimental.evaluation("typesafe-ai/jev")
OpenRouter reads `OPENROUTER_API_KEY`. Vercel reads `AI_GATEWAY_API_KEY`, then `VERCEL_OIDC_TOKEN`.
The common API uses `boolean`; System One routes lower it to native `noul`.
Choice and score confidence plus score legends remain available in provider metadata, and the
provider's rounded probabilities are returned unchanged.
Choice and score answers include `confidence` when the provider returns it, such as
`response.answers.department.confidence`. Score legends remain available in provider metadata, and
the provider's rounded probabilities are returned unchanged.
## Alibaba Cloud Model Studio
@@ -752,7 +753,10 @@ const events = Video.stream({ model: Runway.configure({ apiKey }).video("gen4.5"
Status polls, result fetches, cancels, and asset downloads all run through the same request executor with the route's
auth. `Generation.await` and `Generation.events` fail with a
`Timeout` reason when `poll.timeout` (default 10 minutes) elapses. Failed,
`Timeout` reason when `poll.timeout` (default 10 minutes) elapses. Status polls and result fetches retry transient
failures (rate limits, provider 5xx, network errors) with backoff that honors `retry-after`, always within
`poll.timeout`; submits and cancels never retry. Interrupting a wait (or aborting its `signal`) does not cancel the
provider job, which keeps running and billing: call `cancel()` to stop it. Failed,
cancelled, and expired generations fail typed with the provider's terminal document on `reason.body`; moderation
outcomes (Veo `raiMediaFilteredReasons`, xAI `respect_moderation`, Runway `SAFETY.*` codes) surface as `notices` when
a video is still returned and as a `ContentPolicy` reason when nothing is.
@@ -773,7 +777,9 @@ Provider notes:
The promise client exposes the same surface: `ai.video.start(...)` resolves to a handle with `await`, `events`,
`result`, `refresh`, `cancel`, and `token`; `ai.video.generate`, `ai.video.resume(model, token)`, and
`ai.video.stream` mirror the Effect API. The handle's `status` and `progress` are a snapshot from when it was
created; `refresh()` resolves to a new handle.
created; `refresh()` resolves to a new handle. Every promise method and stream accepts `{ signal }`: like `fetch`,
aborting rejects the Promise or throws from the `for await` loop with `signal.reason` (an `AbortError` `DOMException`
unless `abort(reason)` passed one), while `break` stops a stream without throwing.
```ts
import { ai } from "@opencode/ai/promise"
@@ -871,11 +877,12 @@ for await (const event of ai.speech.stream({ model, text: "Hello from OpenCode."
## Transcription
Transcription (speech-to-text) is the one modality whose providers use every route kind: OpenAI and Gemini stream,
Deepgram answers inline, and AssemblyAI is queued. `Transcription.generate` and `Transcription.stream` work on all of
them; `Transcription.start` / `resume` return a `Generation` on queued routes and fail with `UnsupportedOperation`
elsewhere. Models come from `.transcription(...)` selectors on the `OpenAI`, `Google`, `Deepgram`, and `AssemblyAI`
facades. Common fields (`language`, `prompt`, `timestamps: "none" | "segment" | "word"`, `diarize`, `speakers`) lower
natively or fail with a typed `AIError` before any network call; a route may return more than asked.
Deepgram and ElevenLabs answer inline, and AssemblyAI is queued. `Transcription.generate` and `Transcription.stream`
work on all of them; `Transcription.start` / `resume` return a `Generation` on queued routes and fail with
`UnsupportedOperation` elsewhere. Models come from `.transcription(...)` selectors on the `OpenAI`, `Google`,
`Deepgram`, `ElevenLabs`, and `AssemblyAI` facades. Common fields (`language`, `prompt`,
`timestamps: "none" | "segment" | "word"`, `diarize`, `speakers`) lower natively or fail with a typed `AIError` before
any network call; a route may return more than asked.
```ts
import { Console, Effect, Stream } from "effect"
@@ -887,7 +894,7 @@ const openai = OpenAI.configure({ apiKey: process.env.OPENAI_API_KEY })
const program = Effect.gen(function* () {
const audio = yield* Media.file("./call.mp3")
// Speaker-labelled segments; labels are provider-native strings ("A", "0", "spk:0").
// Speaker-labelled segments; labels are provider-native strings ("A", "0", "spk:0", "speaker_0").
const response = yield* Transcription.generate({
model: Deepgram.configure({ apiKey }).transcription("nova-3"),
audio,
@@ -897,7 +904,7 @@ const program = Effect.gen(function* () {
response.text // "Hello from OpenCode."
response.segments // [{ text, startSeconds, endSeconds, speaker: "0" }]
response.words // [{ text, startSeconds, endSeconds, speaker, confidence }]
response.language // the provider's own value, lowercased ("en", "english", "en_us")
response.language // the provider's own value, lowercased ("en", "eng", "english", "en_us")
// Text deltas as the model transcribes, then one finish carrying the whole transcript.
yield* Transcription.stream({ model: openai.transcription("gpt-4o-mini-transcribe"), audio }).pipe(
@@ -921,7 +928,12 @@ Provider notes:
- **OpenAI** takes inline audio only; `diarize` needs `gpt-4o-transcribe-diarize`, timestamps need `whisper-1`, and `whisper-1` does not stream.
- **Gemini** needs a transcribe model (`gemini-3.5-transcribe`); `prompt` and `speakers` fail typed.
- **Deepgram** detects the language unless `language` is set; vocabulary goes in `providerOptions.keyterm`.
- **AssemblyAI** uploads inline audio before submitting and is the only route that accepts `speakers`.
- **ElevenLabs** (`scribe_v2`) uploads inline audio as the multipart `file` and sends a URL as `source_url`. Words
always carry timestamps, and segments are speaker turns, so `diarize`, `timestamps: "segment"`, or `speakers` turns
on diarization. `speakers` is an upper bound (`num_speakers`); `prompt` fails typed (vocabulary goes in
`providerOptions.keyterms`), as do webhook delivery and per-channel output (`use_multi_channel` without
`multichannel_output_style: "combined"`).
- **AssemblyAI** uploads inline audio before submitting and treats `speakers` as the exact speaker count.
The promise client mirrors the Effect API:
@@ -1211,7 +1223,7 @@ const gateway = CloudflareAIGateway.configure({
}).model("workers-ai/@cf/meta/llama-3.1-8b-instruct")
```
Included LLM providers: OpenAI, Anthropic, Google (Gemini), Google Vertex, Amazon Bedrock, Azure OpenAI, Baseten, Cerebras, Cloudflare AI Gateway, Cloudflare Workers AI, DeepInfra, DeepSeek, Fireworks, Groq, Mistral, OpenRouter, TogetherAI, and xAI. Z.ai currently exposes image generation. Generic Chat Completions, Responses, and Anthropic Messages-compatible entrypoints support custom endpoints.
Included LLM providers: OpenAI, Anthropic, Google (Gemini), Google Vertex, Amazon Bedrock, Azure OpenAI, Baseten, Cerebras, Cohere, Cloudflare AI Gateway, Cloudflare Workers AI, DeepInfra, DeepSeek, Fireworks, Groq, Mistral, OpenRouter, TogetherAI, and xAI. Z.ai currently exposes image generation. Generic Chat Completions, Responses, and Anthropic Messages-compatible entrypoints support custom endpoints.
Each named provider owns its module, endpoint, authentication, and route setup. Providers with the same wire format compose the shared protocol directly:
+27 -17
View File
@@ -1,7 +1,6 @@
# Media generation in `@opencode/ai` — public API direction
Status: phases 1–4 implemented (through Image queued routes and partial images; ElevenLabs Scribe transcription
pending); phase 5 proposal.
Status: phases 1–4 implemented (through Image queued routes and partial images); phase 5 proposal.
## Goal
@@ -271,8 +270,8 @@ Deferred: `Speech.session(...)` — input-streaming TTS where text arrives incre
#### Transcription (STT)
Shipped as the second half of phase 3 (`src/transcription.ts`, `src/transcription-client.ts`, protocols
`openai-transcription`, `google-transcription`, `deepgram-transcription`, `assemblyai-transcription`; new `AssemblyAI`
facade).
`openai-transcription`, `google-transcription`, `deepgram-transcription`, `elevenlabs-transcription`,
`assemblyai-transcription`; new `AssemblyAI` facade).
```ts
const request = Transcription.request({
@@ -281,7 +280,7 @@ const request = Transcription.request({
language: "en", // provider-native passthrough
timestamps: "segment", // none | segment | word
diarize: true,
speakers: 2, // exact speaker count (AssemblyAI only)
speakers: 2, // speaker count (AssemblyAI exact, ElevenLabs maximum)
providerOptions: { known_speaker_names: ["agent"] },
})
@@ -309,17 +308,23 @@ upload); `packages/ai/AGENTS.md` (Media Routes) describes both.
Settled rules:
- **Timestamps.** A granularity the selected route or model cannot produce fails as `UnsupportedOperation`
(`media.timestamps`), following Speech; a route that returns more than asked (Deepgram and AssemblyAI always return
words) is not stripped. Segments always carry start and end times: Gemini times each transcription part from its
(`media.timestamps`), following Speech; a route that returns more than asked (Deepgram, ElevenLabs, and AssemblyAI
always return words) is not stripped. Segments always carry start and end times: Gemini times each transcription part from its
word offsets, so segment timestamps and diarization also request word offsets there.
- **Diarization.** `diarize` means segments (and words, where the provider labels them) carry `speaker`. Labels are
provider-native strings — OpenAI `A` or a known speaker name, Deepgram `0`, Gemini `spk:0`, AssemblyAI `A` — with no
cross-provider speaker model. `speakers` is the exact number of speakers to label, which AssemblyAI (`speakers_expected`, the only route that
accepts it) treats as a constraint rather than a hint.
provider-native strings — OpenAI `A` or a known speaker name, Deepgram `0`, Gemini `spk:0`, AssemblyAI `A`,
ElevenLabs `speaker_0` — with no cross-provider speaker model. `speakers` is the number of speakers to label:
AssemblyAI (`speakers_expected`) treats it as an exact constraint rather than a hint, and ElevenLabs
(`num_speakers`) as the maximum. Both turn on diarization for it; the other routes reject it.
- **Segments from words.** ElevenLabs returns only a token list (`word`, `spacing`, `audio_event`), so its segments
are speaker turns: consecutive words and spacing with one `speaker_id`, text joined from the provider's own spacing
tokens. `words` drops spacing and audio events. Segments therefore need diarization, which `timestamps: "segment"`
turns on, as AssemblyAI's utterances need speaker labels.
- **Language** is passed through (`language`, OpenAI `gpt-transcribe` `languages[]`, Gemini `languageCodes`,
AssemblyAI `language_code`). `response.language` is the provider's own value, lowercased but not normalized: an
ISO code on most routes (AssemblyAI's detection returns `en`), `english` from whisper-1. Deepgram and AssemblyAI
assume English unless asked to detect, so a missing `language` enables their detection.
AssemblyAI and ElevenLabs `language_code`). `response.language` is the provider's own value, lowercased but not
normalized: an ISO code on most routes (AssemblyAI's detection returns `en`, ElevenLabs ISO 639-3 `eng`), `english`
from whisper-1. Deepgram and AssemblyAI assume English unless asked to detect, so a missing `language` enables their
detection.
- **Gemini** requires a transcribe model; other model ids fail with `UnsupportedOperation` before the call, because
general models ignore `audioTranscriptionConfig` and answer conversationally. Streamed chunks carry whole speaker
turns (one part per turn), which join with a space.
@@ -332,11 +337,12 @@ Settled rules:
| OpenAI | stream (`stream: true` in `stream` mode; `whisper-1` ignores `stream`, so it emits only `finish`) | multipart `file` (inline only) | `whisper-1` (`verbose_json`); diarize model: `segment` | `gpt-4o-transcribe-diarize` (`diarized_json`) | `speakers`; `prompt` on the diarize model | `tokens` or `seconds` |
| Gemini | stream (`generateContent` / `streamGenerateContent`) | `inlineData` or Gemini Files `fileData` | `audioTranscriptionConfig.wordTimestamp` | `audioTranscriptionConfig.diarization` | `prompt`, `speakers` | `tokens` |
| Deepgram | inline | raw body, or JSON `{ url }` | words always; `segment` → `utterances` | `diarize_model=latest` + `utterances` | `prompt`, `speakers` | `seconds` (`metadata.duration`) |
| ElevenLabs | inline | multipart `file`, or `source_url` | words always; `segment` → `diarize` (speaker turns) | `diarize` | `prompt`; `webhook`, per-channel `use_multi_channel` | `seconds` (`audio_duration_secs`) |
| AssemblyAI | queued (upload → submit → poll) | `/v2/upload` then `audio_url`, or a URL | words always; `segment` → `speaker_labels` | `speaker_labels` | — | `seconds` (`audio_duration`) |
Deferred: `Transcription.session(...)` — realtime STT over WebSocket (Deepgram live, AssemblyAI streaming, ElevenLabs
realtime, OpenAI realtime transcription) — is the same future scoped `session` shape as input-streaming TTS and ships
with the realtime work in phase 5. ElevenLabs Scribe is not implemented yet.
with the realtime work in phase 5.
### `Generation` — shared async execution
@@ -361,6 +367,10 @@ Poll = { interval?: Duration; timeout?: Duration }
`Generation` is not video-specific. Image routes on BFL, fal, Replicate, and Stability `upscale()` are queued; `Image.start` exists for them. A route declares itself `inline` or `queued`; `generate` on a queued route is `start` then `await`.
Status polls and result reads retry transient failures (rate limits, provider 5xx, and transport errors, classified by the same `isRetryable` the Session runner uses) inside `MediaRoute.queued`. Only the HTTP exchange retries, never the decoded document: a terminal `failed` generation also surfaces as `ProviderInternal` and must not be re-read. Gaps grow exponentially from 1s with jitter, up to 30s each, honoring a provider `retry-after` up to that cap, for at most 8 retries. `await`, `events`, and `Video.stream` cut retries off at `poll.timeout` and fail with `Timeout`, so retries never extend the caller's deadline; a direct `result()` or `resume` read is bounded by the retry cap alone. `start` and `cancel` never retry: a repeated submit can start and bill a second job. The policy is internal; there is no option for it.
Interrupting `await`, `events`, or `Video.stream` (or aborting the promise API's `signal`) stops waiting only. The provider job keeps running and billing; call `cancel()` explicitly to stop it.
### Usage
```ts
@@ -402,7 +412,7 @@ for await (const event of ai.llm.stream(request)) { … }
await ai.dispose()
```
Streams become `AsyncIterable` via `Stream.toAsyncIterable`. `AIError` is thrown as-is. `AbortSignal` maps to interruption. Nothing in `src/*` except this entrypoint knows about promises.
Streams become `AsyncIterable` via `Stream.toAsyncIterable`. `AIError` is thrown as-is. Aborting an `AbortSignal` interrupts the work and, like `fetch`, rejects the Promise or throws from the stream with `signal.reason` instead of ending the stream as if complete. Nothing in `src/*` except this entrypoint knows about promises.
### Providers
@@ -414,7 +424,7 @@ implemented):
| `OpenAI` | responses (default), chat | Images API (stream) | *Sora skipped (decision 8)* | ✓ | ✓ | |
| `Google` | Gemini | Gemini-native | Veo | Gemini TTS | `gemini-3.5-transcribe` | |
| `XAI` | ✓ | ✓ | ✓ | | | |
| `ElevenLabs` | | | | ✓ | *Scribe (pending)* | *soundEffect, music (phase 5)* |
| `ElevenLabs` | | | | ✓ | Scribe | *soundEffect, music (phase 5)* |
| `Cartesia` | | | | ✓ | | |
| `Deepgram` | | | | Aura | ✓ | |
| `Fal` | | ✓ (queued) | ✓ | | | |
@@ -467,7 +477,7 @@ Foundation + Image ship together as the reference implementation, serially. Vide
1. **Foundation** — per-modality selectors, `Media`, `Generation`, `Poll`, `Usage` union, `MediaProtocol` kinds, `@opencode/ai/promise` with `llm` + `image`. Port the five existing image protocols onto it. Unify `MediaPart` and add the `media` LLM event (fixes Gemini image output being dropped).
2. **Video** — ✅ Veo, xAI, fal, Runway shipped (`MediaProtocol.queued`, `Video.start/generate/resume/stream`, promise `ai.video`). Deferred: `Video.complete` (webhooks), Luma, Kling, MiniMax, Replicate.
3. **Speech + Transcription** — ✅ Speech: OpenAI, Gemini TTS, ElevenLabs, Cartesia, Deepgram shipped (`MediaProtocol.stream`, `Speech.generate/stream`, promise `ai.speech`). ✅ Transcription: OpenAI, Gemini, Deepgram, AssemblyAI shipped across all three route kinds (`Transcription.generate/stream/start/resume`, promise `ai.transcription`). Pending: ElevenLabs Scribe. Deferred: `Speech.session` and `Transcription.session` (WebSocket streaming).
3. **Speech + Transcription** — ✅ Speech: OpenAI, Gemini TTS, ElevenLabs, Cartesia, Deepgram shipped (`MediaProtocol.stream`, `Speech.generate/stream`, promise `ai.speech`). ✅ Transcription: OpenAI, Gemini, Deepgram, ElevenLabs Scribe, AssemblyAI shipped across all three route kinds (`Transcription.generate/stream/start/resume`, promise `ai.transcription`). Deferred: `Speech.session` and `Transcription.session` (WebSocket streaming).
4. **Image queued routes and partials** — ✅ BFL, fal, Replicate, and Stability creative upscale queued; Stability generate inline; OpenAI `partial_images` streaming (`image-partial` restored). Imagen dropped: shut down on the Gemini API and discontinued on Vertex (2026-06-30). Deferred: Stability's synchronous edit and fast/conservative upscale endpoints.
5. **Later** — ElevenLabs music/SFX, Lyria, `Speech.session` / `Transcription.session`, realtime.
+1 -1
View File
@@ -15,7 +15,7 @@ import { OpenAI } from "@opencode/ai/providers"
* hover imports and local values to see how the public API is typed.
*/
const apiKey = Config.Redacted("OPENAI_API_KEY")
const apiKey = Config.redacted("OPENAI_API_KEY")
// 1. Configure a provider. The configured facade records provider identity,
// deployment options, authentication, and defaults. Per-modality selectors pick
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "2.0.18",
"version": "2.0.21",
"name": "@opencode/ai",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -383,7 +383,7 @@ const readEnvFile = Effect.fn("RecordingEnv.readFile")(function* () {
})
const readConfigString = (provider: ConfigProvider.ConfigProvider, name: string) =>
Config.String(name)
Config.string(name)
.parse(provider)
.pipe(
Effect.match({
+23 -3
View File
@@ -38,12 +38,31 @@ const resolve = (policy: CachePolicy | undefined): CachePolicyObject => {
// prefix caching, Gemini's implicit + out-of-band CachedContent). Skip the
// whole policy pass for these — emitting hints would be harmless but pointless.
const RESPECTS_INLINE_HINTS = new Set([
"alibaba-messages",
"anthropic-messages",
"anthropic-compatible-messages",
"cloudflare-ai-gateway-messages",
"google-vertex-messages",
"meta-messages",
"minimax-messages",
"moonshot-messages",
"zai-coding-messages",
"bedrock-converse",
"openrouter",
"digitalocean",
])
// OpenRouter upstreams other than Anthropic and Alibaba Qwen cache without breakpoints. Gemini uses only the last
// breakpoint, so a conversation-tail breakpoint writes a new cache every step and costs more than none. Qwen ignores
// breakpoints on tool definitions and caches tools with the system prompt.
const openRouterPolicy = (modelID: string): CachePolicyObject => {
// `~anthropic/claude-sonnet-latest` style IDs are OpenRouter aliases for the latest model in a family.
const id = modelID.replace(/^~/, "")
if (id.startsWith("anthropic/")) return AUTO
if (id.startsWith("qwen/")) return { system: true, messages: { tail: 1 } }
return NONE
}
const makeHint = (ttlSeconds: number | undefined): CacheHint =>
ttlSeconds !== undefined ? new CacheHint({ type: "ephemeral", ttlSeconds }) : new CacheHint({ type: "ephemeral" })
@@ -149,9 +168,10 @@ const countHints = (request: LLMRequest) =>
export const applyCachePolicy = (request: LLMRequest): LLMRequest => {
if (!RESPECTS_INLINE_HINTS.has(request.model.route.id)) return request
if (request.model.route.id === "openrouter" && (request.cache === undefined || request.cache === "auto"))
return request
const policy = resolve(request.cache)
const policy =
request.model.route.id === "openrouter" && (request.cache === undefined || request.cache === "auto")
? openRouterPolicy(request.model.id)
: resolve(request.cache)
if (!policy.tools && !policy.system && !policy.messages) return request
const hint = makeHint(policy.ttlSeconds)
@@ -63,6 +63,7 @@ export const ChoiceAnswer = Schema.Struct({
type: Schema.Literal("choice"),
choice: Schema.String,
probabilities: Schema.optional(Schema.Record(Schema.String, Probability)),
confidence: Schema.optional(Probability),
})
export type ChoiceAnswer = Schema.Schema.Type<typeof ChoiceAnswer>
@@ -70,6 +71,7 @@ export const ScoreAnswer = Schema.Struct({
type: Schema.Literal("score"),
score: Schema.Number,
probabilities: Schema.optional(Schema.Record(Schema.String, Probability)),
confidence: Schema.optional(Probability),
})
export type ScoreAnswer = Schema.Schema.Type<typeof ScoreAnswer>
@@ -92,6 +94,7 @@ export type AnswerFor<Question extends EvaluationQuestion> = Question extends {
readonly type: "choice"
readonly choice: Extract<keyof Criteria, string>
readonly probabilities?: Readonly<Record<Extract<keyof Criteria, string>, number>>
readonly confidence?: number
}
: Question extends { readonly type: "score" }
? ScoreAnswer
+10 -5
View File
@@ -142,32 +142,37 @@ export const model = <Options extends EvaluationOptions = EvaluationOptions>(cfg
Effect.mapError((cause) => fail("System One returned an invalid response", cause, text)),
)
const confidence: Record<string, number> = {}
const legend: Record<string, Record<string, Schema.Json>> = {}
const answers = Object.fromEntries(
Object.entries(data.answers).map(([id, answer]): [string, EvaluationAnswer] => {
if (answer.type === "noul") return [id, { type: "boolean", probability: answer.noul }]
if (answer.type === "choice") {
if (answer.confidence !== undefined) confidence[id] = answer.confidence
return [
id,
{
type: "choice",
choice: answer.choice,
probabilities: answer.probabilities,
...(answer.confidence === undefined ? {} : { confidence: answer.confidence }),
},
]
}
if (answer.confidence !== undefined) confidence[id] = answer.confidence
if (answer.legend !== undefined) legend[id] = answer.legend
return [id, { type: "score", score: answer.score, probabilities: answer.probabilities }]
return [
id,
{
type: "score",
score: answer.score,
probabilities: answer.probabilities,
...(answer.confidence === undefined ? {} : { confidence: answer.confidence }),
},
]
}),
)
const meta = {
...(data.id === undefined ? {} : { responseId: data.id }),
...(data.provider === undefined ? {} : { provider: data.provider }),
...data.provider_metadata?.[cfg.providerMetadataKey],
...(Object.keys(confidence).length === 0 ? {} : { confidence }),
...(Object.keys(legend).length === 0 ? {} : { legend }),
}
return new EvaluationResponse({
+47 -28
View File
@@ -102,7 +102,7 @@ export class Generation<Response> {
return settled.pipe(
// Non-completed terminal states also go through `result` so the route can surface its provider failure body.
Effect.flatMap((generation) => generation.result()),
Effect.timeoutOrElse({ duration: timeout, orElse: () => this.timeoutError(timeout) }),
Effect.timeoutOrElse({ duration: timeout, orElse: () => timeoutError(this.id, timeout) }),
)
}
@@ -123,20 +123,7 @@ export class Generation<Response> {
Clock.currentTimeMillis.pipe(
Effect.map((start) => {
const deadline = start + Duration.toMillis(timeout)
// Fail before polling once the deadline has passed: a fast status request could otherwise win the zero-budget
// race and schedule another zero-delay poll.
const refresh = Clock.currentTimeMillis.pipe(
Effect.flatMap((now) =>
now >= deadline
? this.timeoutError(timeout)
: this.refresh().pipe(
Effect.timeoutOrElse({
duration: Duration.millis(deadline - now),
orElse: () => this.timeoutError(timeout),
}),
),
),
)
const refresh = within(this.refresh(), this.id, timeout, deadline)
const schedule = this.schedule(options?.poll).pipe(
Schedule.modifyDelay((meta) =>
Effect.succeed(Duration.min(meta.duration, Duration.millis(Math.max(0, deadline - meta.now)))),
@@ -157,15 +144,6 @@ export class Generation<Response> {
return { type: "generation-progress", id: this.id, progress: this.progress }
}
private timeoutError(timeout: Duration.Duration) {
return new AIError({
reason: new TimeoutError({
message: `Generation ${this.id} did not finish within ${Duration.format(timeout)}`,
timeoutMs: Duration.toMillis(timeout),
}),
})
}
private poll(poll: Poll | undefined) {
return this.refresh().pipe(
Effect.repeat({ schedule: this.schedule(poll), until: (generation) => generation.terminal }),
@@ -177,12 +155,53 @@ export class Generation<Response> {
}
}
/** `events` followed by the expanded result, with the result fetch bounded by the same `poll.timeout` deadline. */
export const resultEvents = <Response, A>(
generation: Generation<Response>,
expand: (response: Response) => ReadonlyArray<A>,
options?: AwaitOptions,
): Stream.Stream<Observation | A, AIError> =>
generation.events(options).pipe(
Stream.filter((event): event is Observation => event.type !== "generation-finished"),
Stream.concat(Stream.fromIterableEffect(Effect.map(generation.result(), expand))),
): Stream.Stream<Observation | A, AIError> => {
const timeout = Duration.fromInputUnsafe(options?.poll?.timeout ?? DEFAULT_POLL_TIMEOUT)
return Stream.unwrap(
Clock.currentTimeMillis.pipe(
Effect.map((start) =>
generation.events(options).pipe(
Stream.filter((event): event is Observation => event.type !== "generation-finished"),
Stream.concat(
Stream.fromIterableEffect(
within(generation.result(), generation.id, timeout, start + Duration.toMillis(timeout)).pipe(
Effect.map(expand),
),
),
),
),
),
),
)
}
/**
* Run `effect` within the time left until `deadline`. Fails before starting once the deadline has passed: a fast
* request could otherwise win the zero-budget race and schedule another zero-delay poll.
*/
const within = <A>(effect: Effect.Effect<A, AIError>, id: string, timeout: Duration.Duration, deadline: number) =>
Clock.currentTimeMillis.pipe(
Effect.flatMap((now) =>
now >= deadline
? Effect.fail(timeoutError(id, timeout))
: effect.pipe(
Effect.timeoutOrElse({
duration: Duration.millis(deadline - now),
orElse: () => Effect.fail(timeoutError(id, timeout)),
}),
),
),
)
const timeoutError = (id: string, timeout: Duration.Duration) =>
new AIError({
reason: new TimeoutError({
message: `Generation ${id} did not finish within ${Duration.format(timeout)}`,
timeoutMs: Duration.toMillis(timeout),
}),
})
+1 -1
View File
@@ -4,7 +4,7 @@ export { ImageClient } from "./image-client.js"
export { Auth } from "./route/auth.js"
export { Provider } from "./provider.js"
export { ProviderPackage } from "./provider-package.js"
export { isContextOverflow, isContextOverflowFailure } from "./provider-error.js"
export { isContextOverflow, isContextOverflowFailure, isRetryable } from "./provider-error.js"
export type {
RouteLanguageModelInput,
RouteRoutedLanguageModelInput,
+7 -6
View File
@@ -42,7 +42,7 @@ export type GenerationHandle<Response> = Snapshot & {
/** Serializable JSON; pass it back to `resume` from another process. */
readonly token: unknown
readonly await: (options?: AwaitOptions & RunOptions) => Promise<Response>
/** Status observations until the first terminal one, polling like `await`; abort ends iteration without throwing. */
/** Status observations until the first terminal one, polling like `await`; abort throws `signal.reason`. */
readonly events: (options?: AwaitOptions & RunOptions) => AsyncIterable<Event>
/** The result without polling; fails when the generation has not completed. */
readonly result: (options?: RunOptions) => Promise<Response>
@@ -50,15 +50,16 @@ export type GenerationHandle<Response> = Snapshot & {
readonly cancel: (options?: RunOptions) => Promise<void>
}
// Fails with `signal.reason` so aborted calls reject and aborted streams throw like `fetch`: an `AbortError` by default.
const abortEffect = (signal: AbortSignal | undefined) =>
signal === undefined
? Effect.never
: Effect.callback<void>((resume) => {
: Effect.callback<never, unknown>((resume) => {
if (signal.aborted) {
resume(Effect.void)
resume(Effect.fail(signal.reason))
return
}
const onAbort = () => resume(Effect.void)
const onAbort = () => resume(Effect.fail(signal.reason))
signal.addEventListener("abort", onAbort, { once: true })
return Effect.sync(() => signal.removeEventListener("abort", onAbort))
})
@@ -68,14 +69,14 @@ export const make = (options: Options = {}) => {
/** Run any package Effect (for example `LLMClient.compact(...)`) inside this runtime. */
const run = <A, E>(effect: Effect.Effect<A, E, Services>, options?: RunOptions) =>
runtime.runPromise(effect, { signal: options?.signal })
runtime.runPromise(Effect.raceFirst(effect, abortEffect(options?.signal)))
const iterate = <A, E>(stream: Stream.Stream<A, E, Services>, options?: RunOptions): AsyncIterable<A> =>
Stream.toAsyncIterable(
Stream.unwrap(
runtime.contextEffect.pipe(
Effect.map(
(context): Stream.Stream<A, E> =>
(context): Stream.Stream<A, unknown> =>
stream.pipe(Stream.interruptWhen(abortEffect(options?.signal)), Stream.provideContext(context)),
),
),
+16 -28
View File
@@ -29,6 +29,7 @@ import { JsonObject, knownString, optionalArray, optionalNull, ProviderShared }
import { classifyProviderFailure } from "../provider-error.js"
import { effortUpdate, resolveEffortUpdates } from "../effort-updates.js"
import * as Cache from "./utils/cache.js"
import { claudeVersion, supportsThinkingBlockBinding, THINKING_BINDING_BETA } from "./utils/claude-model.js"
import { Lifecycle } from "./utils/lifecycle.js"
import { ToolStream } from "./utils/tool-stream.js"
@@ -450,6 +451,9 @@ const AnthropicStreamDelta = Schema.Struct({
signature: Schema.optional(Schema.String),
stop_reason: optionalNull(Schema.String),
stop_sequence: optionalNull(Schema.String),
stop_details: optionalNull(
Schema.Struct({ category: optionalNull(Schema.String), explanation: optionalNull(Schema.String) }),
),
})
type AnthropicStreamDelta = Schema.Schema.Type<typeof AnthropicStreamDelta>
const decodeAnthropicStreamDelta = Schema.decodeUnknownOption(AnthropicStreamDelta)
@@ -803,15 +807,12 @@ const requireThinkingSignature = (request: LLMRequest) => {
// Mid-conversation system messages became available with Opus 4.8 and version
// 5 of the other supported Claude families. Treat later family versions as
// compatible without assuming that every Anthropic Messages model is Claude.
// Opus 4.8 and every Claude 5 model accept mid-conversation system messages; later versions inherit support.
const supportsNativeSystemUpdates = (request: LLMRequest) => {
const match = /(?:^|[./])claude-(fable|haiku|mythos|opus|sonnet)-(\d+)(?:[.-](\d+))?/.exec(
String(request.model.id).toLowerCase(),
)
if (!match) return false
const major = Number(match[2])
if (match[1] !== "opus") return major >= 5
if (major !== 4) return major >= 5
return match[3] !== undefined && match[3].length <= 2 && Number(match[3]) >= 8
const version = claudeVersion(String(request.model.id))
if (version === undefined) return false
if (version.family === "opus" && version.major === 4) return version.minor >= 8
return version.major >= 5
}
const endsInServerToolUse = (message: LLMRequest["messages"][number]) => {
@@ -988,29 +989,13 @@ const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* (
return messages
})
// Accept gateway namespaces and Vertex suffixes without treating a snapshot date as a minor version.
const claudeVersion = (id: string) => {
const match = /(?:^|[./])claude-(?<family>[a-z]+)-(?<major>\d+)(?:[.-](?<minor>\d{1,2}))?(?:$|[-:@])/.exec(
id.toLowerCase(),
)?.groups
if (!match) return undefined
return { family: match.family, major: Number(match.major), minor: Number(match.minor ?? 0) }
}
const supportsThinkingBlockBinding = (model: LLMRequest["model"]) => {
const override = model.compatibility?.supportsThinkingBlockBinding
if (override !== undefined) return override
const version = claudeVersion(model.id)
return version !== undefined && (version.major > 5 || (version.major === 5 && version.minor >= 1))
}
// Per-turn effort started with Claude Opus 5 and every Claude 5.1 model; later versions of any family inherit it.
const supportsEffortUpdates = (model: LLMRequest["model"]) => {
const override = model.compatibility?.supportsEffortUpdates
if (override !== undefined) return override
const version = claudeVersion(model.id)
if (version === undefined) return false
if (version.family === "opus") return version.major >= 5
if (version.family !== "fable" && version.family !== "mythos") return false
if (version.family === "opus" && version.major >= 5) return true
return version.major > 5 || (version.major === 5 && version.minor >= 1)
}
@@ -1432,10 +1417,14 @@ const onMessageDelta = (
stopSequence === null || stopSequence === undefined
? state.pendingFinish?.providerMetadata
: providerMetadata(state.providerMetadataKey, { stopSequence })
const category = event.delta?.stop_details?.category
const explanation = event.delta?.stop_details?.explanation
return {
reason: {
normalized: mapFinishReason(stopReason),
raw: stopReason,
...(category ? { category } : {}),
...(explanation ? { explanation } : {}),
},
providerMetadata: finishMetadata,
}
@@ -1652,8 +1641,7 @@ function requiredBetaHeaders(body: Pick<AnthropicMessagesBody, "messages" | "con
betas.push("mid-conversation-output-config-2026-07-01")
const thinking = body.thinking
if (thinking && thinking.type !== "disabled" && thinking.block_binding)
betas.push("thinking-binding-controls-2026-08-01")
if (thinking && thinking.type !== "disabled" && thinking.block_binding) betas.push(THINKING_BINDING_BETA)
return betas
}
+79 -12
View File
@@ -23,6 +23,7 @@ import { JsonObject, optionalArray, ProviderShared } from "./shared.js"
import { BedrockAuth } from "./utils/bedrock-auth.js"
import { BedrockCache } from "./utils/bedrock-cache.js"
import { BedrockMedia } from "./utils/bedrock-media.js"
import { supportsThinkingBlockBinding, THINKING_BINDING_BETA } from "./utils/claude-model.js"
import { Lifecycle } from "./utils/lifecycle.js"
import { MistralToolID } from "./utils/mistral-tool-id.js"
import { ToolStream } from "./utils/tool-stream.js"
@@ -318,6 +319,9 @@ const lowerToolResult = Effect.fn("BedrockConverse.lowerToolResult")(function* (
} satisfies BedrockToolResultBlock
})
// Keep Claude and Nova tool-result images inline; put other models' images beside the result.
const keepToolImagesInline = (id: string) => id.includes("anthropic.claude-") || id.includes("amazon.nova-")
const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (
request: LLMRequest,
breakpoints: BedrockCache.Breakpoints,
@@ -327,8 +331,19 @@ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (
// Mistral can reject replay IDs even when they satisfy Converse's broader ID syntax.
const normalizeID = request.model.id.includes("mistral.") ? MistralToolID.normalizer(request) : (id: string) => id
const providerMetadataKey = request.model.route.providerMetadataKey ?? String(request.model.provider)
const hoistImages = !keepToolImagesInline(request.model.id)
// Bedrock expects parallel tool results before any images hoisted beside them.
const pendingImages: BedrockMedia.ImageBlock[] = []
const flushImages = () => {
if (pendingImages.length === 0) return
const previous = messages.at(-1)
if (previous?.role === "user")
messages[messages.length - 1] = { role: "user", content: [...previous.content, ...pendingImages] }
pendingImages.length = 0
}
for (const message of request.messages) {
if (message.role !== "tool") flushImages()
if (message.role === "system") {
const part = yield* ProviderShared.wrappedSystemUpdate("Bedrock Converse", message)
const content = textWithCache(breakpoints, part.text, part.cache)
@@ -402,7 +417,22 @@ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (
for (const part of message.content) {
if (!ProviderShared.supportsContent(part, ["tool-result"]))
return yield* ProviderShared.unsupportedContent("Bedrock Converse", "tool", ["tool-result"])
content.push(yield* lowerToolResult(part, documentNames, normalizeID))
const result = yield* lowerToolResult(part, documentNames, normalizeID)
const images: BedrockMedia.ImageBlock[] = hoistImages
? result.toolResult.content.filter((item) => "image" in item)
: []
const nonImageContent = result.toolResult.content.filter((item) => !("image" in item))
content.push(
images.length === 0
? result
: {
toolResult: {
...result.toolResult,
content: nonImageContent.length > 0 ? nonImageContent : [{ text: "See attached image." }],
},
},
)
pendingImages.push(...images)
const cachePoint = BedrockCache.block(breakpoints, part.cache)
if (cachePoint) content.push(cachePoint)
}
@@ -412,6 +442,7 @@ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (
else messages.push({ role: "user", content })
}
flushImages()
return messages
})
@@ -443,6 +474,23 @@ const decodeOptions = ProviderShared.validateWith(Schema.decodeUnknownEffect(Opt
// Claude on Bedrock requires the thinking budget below `maxTokens`, with a minimum of 1,024.
const MIN_THINKING_BUDGET = 1_024
const isThinkingDisabled = Schema.is(
Schema.Struct({
additionalModelRequestFields: Schema.Struct({ thinking: Schema.Struct({ type: Schema.Literal("disabled") }) }),
}),
)
// Claude 5.1+ binds each thinking signature to the prefix above it. Ask Bedrock to drop the affected blocks instead of
// failing when that prefix changes. `http.body` overlays this field by field, so callers can still override it.
const applyThinkingBindingDefault = (request: LLMRequest, thinking: Readonly<Record<string, unknown>> | undefined) => {
if (isThinkingDisabled(request.http?.body)) return thinking
if (!supportsThinkingBlockBinding(request.model)) return thinking
return {
...(thinking ?? { type: "adaptive" as const }),
block_binding: { prefix_mismatch_behavior: "drop_block" },
}
}
const fromRequest = Effect.fn("BedrockConverse.fromRequest")(function* (request: LLMRequest) {
const toolChoice = request.toolChoice ? yield* lowerToolChoice(request.toolChoice) : undefined
const flattened = ProviderShared.flattenToolRequest(request)
@@ -450,7 +498,8 @@ const fromRequest = Effect.fn("BedrockConverse.fromRequest")(function* (request:
const options = yield* decodeOptions(request.providerOptions ?? {})
const maxTokens =
isNova2(request.model) && isHighReasoningEffort(request.http?.body) ? undefined : generation?.maxTokens
const thinking =
const thinking = applyThinkingBindingDefault(
request,
options.thinking === undefined
? undefined
: {
@@ -460,7 +509,8 @@ const fromRequest = Effect.fn("BedrockConverse.fromRequest")(function* (request:
maxTokens,
MIN_THINKING_BUDGET,
),
}
},
)
// Bedrock-Claude shares Anthropic's 4-breakpoint cap. Spend the budget in
// tools → system → messages order to favour the highest-impact prefixes.
const breakpoints = BedrockCache.breakpoints(request.model.id)
@@ -509,6 +559,8 @@ const fromRequest = Effect.fn("BedrockConverse.fromRequest")(function* (request:
: {
...(generation?.topK === undefined ? {} : { top_k: generation.topK }),
...(thinking === undefined ? {} : { thinking }),
// Converse takes Anthropic betas in the body, and Bedrock rejects `block_binding` without this one.
...(thinking?.block_binding === undefined ? {} : { anthropic_beta: [THINKING_BINDING_BETA] }),
},
}
})
@@ -555,7 +607,7 @@ interface ParserState {
readonly hasToolCalls: boolean
readonly lifecycle: Lifecycle.State
readonly reasoningSignatures: Readonly<Record<number, string>>
readonly reasoningRedactedContent: Readonly<Record<number, ReadonlyArray<Uint8Array>>>
readonly reasoningRedactedContent: Readonly<Record<number, Uint8Array[]>>
}
const encodeRedactedContent = (chunks: ReadonlyArray<Uint8Array>) => Encoding.encodeBase64(concatBytes(chunks))
@@ -605,10 +657,9 @@ const step = (state: ParserState, event: BedrockEvent) =>
const index = event.contentBlockDelta.contentBlockIndex
const reasoning = event.contentBlockDelta.delta.reasoningContent
const events: LLMEvent[] = []
const redactedChunks = yield* (() => {
const redactedChunk = yield* (() => {
if (reasoning.redactedContent === undefined) return Effect.succeed(undefined)
return Effect.fromResult(Encoding.decodeBase64(reasoning.redactedContent)).pipe(
Effect.map((chunk) => [...(state.reasoningRedactedContent[index] ?? []), chunk]),
Effect.mapError((cause) =>
ProviderShared.eventError(
ADAPTER,
@@ -619,17 +670,21 @@ const step = (state: ParserState, event: BedrockEvent) =>
),
)
})()
const redactedData = redactedChunks === undefined ? reasoning.data : encodeRedactedContent(redactedChunks)
const redactedChunks = state.reasoningRedactedContent[index] ?? []
if (redactedChunk !== undefined) redactedChunks.push(redactedChunk)
const metadata = (() => {
if (reasoning.signature) return providerMetadata(state.providerMetadataKey, { signature: reasoning.signature })
if (redactedData !== undefined) return providerMetadata(state.providerMetadataKey, { redactedData })
if (redactedChunk === undefined && reasoning.data !== undefined)
return providerMetadata(state.providerMetadataKey, { redactedData: reasoning.data })
})()
const lifecycle = (() => {
if (reasoning.text === undefined && metadata === undefined) return state.lifecycle
return Lifecycle.reasoningDelta(state.lifecycle, events, `reasoning-${index}`, reasoning.text ?? "", metadata)
if (reasoning.text !== undefined || metadata !== undefined)
return Lifecycle.reasoningDelta(state.lifecycle, events, `reasoning-${index}`, reasoning.text ?? "", metadata)
if (redactedChunk !== undefined) return Lifecycle.reasoningStart(state.lifecycle, events, `reasoning-${index}`)
return state.lifecycle
})()
const reasoningRedactedContent = (() => {
if (redactedChunks !== undefined) return { ...state.reasoningRedactedContent, [index]: redactedChunks }
if (redactedChunk !== undefined) return { ...state.reasoningRedactedContent, [index]: redactedChunks }
if (reasoning.data === undefined) return state.reasoningRedactedContent
return Object.fromEntries(
Object.entries(state.reasoningRedactedContent).filter(([key]) => key !== String(index)),
@@ -765,7 +820,19 @@ const onHalt = (state: ParserState): ReadonlyArray<LLMEvent> => {
return state.finishReason.normalized
})()
const events: LLMEvent[] = []
Lifecycle.finish(state.lifecycle, events, {
const lifecycle = Object.entries(state.reasoningRedactedContent).reduce((current, [index, chunks]) => {
const signature = state.reasoningSignatures[Number(index)]
return Lifecycle.reasoningEnd(
current,
events,
`reasoning-${index}`,
providerMetadata(
state.providerMetadataKey,
signature ? { signature } : { redactedData: encodeRedactedContent(chunks) },
),
)
}, state.lifecycle)
Lifecycle.finish(lifecycle, events, {
reason: {
...state.finishReason,
normalized,
+326
View File
@@ -0,0 +1,326 @@
import { Effect, Schema } from "effect"
import { Route } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { Framing } from "../route/framing.js"
import { Protocol } from "../route/protocol.js"
import { LLMEvent, Usage, type FinishReasonDetails, type LLMRequest } from "../schema/index.js"
import { ProviderShared } from "./shared.js"
import { Lifecycle } from "./utils/lifecycle.js"
import { ToolStream } from "./utils/tool-stream.js"
const ADAPTER = "cohere-chat"
export const DEFAULT_BASE_URL = "https://api.cohere.com/v2"
const Options = Schema.Struct({
thinking: Schema.optional(
Schema.Struct({
type: Schema.optional(Schema.Literals(["enabled", "disabled"])),
tokenBudget: Schema.optional(Schema.Int.check(Schema.isGreaterThan(0))),
}),
),
})
export type ProviderOptionsInput = Schema.Schema.Type<typeof Options>
const Content = Schema.Union([
Schema.Struct({ type: Schema.Literal("text"), text: Schema.String }),
Schema.Struct({ type: Schema.Literal("thinking"), thinking: Schema.String }),
Schema.Struct({ type: Schema.Literal("image_url"), image_url: Schema.Struct({ url: Schema.String }) }),
])
const ToolCall = Schema.Struct({
id: Schema.String,
type: Schema.Literal("function"),
function: Schema.Struct({ name: Schema.String, arguments: Schema.String }),
})
const Message = Schema.Struct({
role: Schema.Literals(["system", "user", "assistant", "tool"]),
content: Schema.optional(Schema.Union([Schema.String, Schema.Array(Content)])),
tool_calls: Schema.optional(Schema.Array(ToolCall)),
tool_call_id: Schema.optional(Schema.String),
tool_plan: Schema.optional(Schema.String),
})
const Body = Schema.Struct({
model: Schema.String,
messages: Schema.Array(Message),
stream: Schema.Literal(true),
tools: Schema.optional(
Schema.Array(
Schema.Struct({
type: Schema.Literal("function"),
function: Schema.Struct({
name: Schema.String,
description: Schema.optional(Schema.String),
parameters: Schema.Unknown,
}),
}),
),
),
tool_choice: Schema.optional(Schema.Literals(["NONE", "REQUIRED"])),
thinking: Schema.optional(Schema.Struct({ type: Schema.String, token_budget: Schema.optional(Schema.Number) })),
max_tokens: Schema.optional(Schema.Number),
temperature: Schema.optional(Schema.Number),
p: Schema.optional(Schema.Number),
k: Schema.optional(Schema.Number),
seed: Schema.optional(Schema.Number),
stop_sequences: Schema.optional(Schema.Array(Schema.String)),
frequency_penalty: Schema.optional(Schema.Number),
presence_penalty: Schema.optional(Schema.Number),
})
const TokenCounts = Schema.Struct({
input_tokens: Schema.optional(Schema.Number),
output_tokens: Schema.optional(Schema.Number),
reasoning_tokens: Schema.optional(Schema.Number),
})
const NativeUsage = Schema.Struct({
tokens: Schema.optional(TokenCounts),
billed_units: Schema.optional(TokenCounts),
cached_tokens: Schema.optional(Schema.Number),
})
const Event = Schema.Union([
Schema.Struct({ type: Schema.Literal("message-start") }),
Schema.Struct({
type: Schema.Literals(["content-start", "content-delta"]),
index: Schema.Number,
delta: Schema.Struct({
message: Schema.Struct({
content: Schema.Struct({ text: Schema.optional(Schema.String), thinking: Schema.optional(Schema.String) }),
}),
}),
}),
Schema.Struct({ type: Schema.Literal("content-end"), index: Schema.Number }),
Schema.Struct({
type: Schema.Literal("tool-plan-delta"),
delta: Schema.Struct({ message: Schema.Struct({ tool_plan: Schema.String }) }),
}),
Schema.Struct({
type: Schema.Literals(["tool-call-start", "tool-call-delta"]),
index: Schema.Number,
delta: Schema.Struct({
message: Schema.Struct({
tool_calls: Schema.Struct({
id: Schema.optional(Schema.String),
function: Schema.Struct({ name: Schema.optional(Schema.String), arguments: Schema.optional(Schema.String) }),
}),
}),
}),
}),
Schema.Struct({ type: Schema.Literal("tool-call-end"), index: Schema.Number }),
Schema.Struct({
type: Schema.Literal("message-end"),
delta: Schema.Struct({ finish_reason: Schema.String, usage: Schema.optional(NativeUsage) }),
}),
// Citation output is outside this basic chat surface.
Schema.Struct({ type: Schema.Literals(["citation-start", "citation-end"]) }),
])
type Event = typeof Event.Type
type State = {
readonly lifecycle: Lifecycle.State
readonly tools: ToolStream.State<number>
readonly finished: boolean
}
const TOOL_CHOICE = { auto: undefined, none: "NONE", required: "REQUIRED", tool: "REQUIRED" } as const
const fromRequest = Effect.fn("CohereChat.fromRequest")(function* (request: LLMRequest) {
const options = yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(Options))(request.providerOptions ?? {})
const flattened = ProviderShared.flattenToolRequest(request)
const messages: (typeof Message.Type)[] = request.system.length
? [{ role: "system", content: ProviderShared.joinText(request.system) }]
: []
for (const message of flattened.request.messages) {
if (message.role === "system") {
messages.push({ role: "user", content: (yield* ProviderShared.wrappedSystemUpdate("Cohere Chat", message)).text })
continue
}
if (message.role === "tool") {
for (const part of message.content) {
if (part.type !== "tool-result")
return yield* ProviderShared.unsupportedContent("Cohere Chat", "tool", ["tool-result"])
if (part.result.type === "content" && part.result.value.some((item) => item.type === "file"))
return yield* ProviderShared.invalidRequest("Cohere Chat does not support file content in tool results")
messages.push({ role: "tool", tool_call_id: part.id, content: ProviderShared.toolResultText(part) })
}
continue
}
const content: (typeof Content.Type)[] = []
const calls: (typeof ToolCall.Type)[] = []
const plans: string[] = []
for (const part of message.content) {
if (part.type === "text") {
content.push({ type: "text", text: part.text })
continue
}
if (message.role === "assistant" && part.type === "reasoning") {
if (part.providerMetadata?.cohere?.toolPlan === true) plans.push(part.text)
else content.push({ type: "thinking", thinking: part.text })
continue
}
if (message.role === "assistant" && part.type === "tool-call") {
const args = ProviderShared.encodeJson(part.input)
calls.push({ id: part.id, type: "function", function: { name: part.name, arguments: args } })
continue
}
if (message.role === "user" && part.type === "media" && part.media.mediaType.startsWith("image/")) {
const url =
ProviderShared.mediaUrl(part.media) ??
(yield* ProviderShared.requireInlineMedia("Cohere Chat", part.media)).dataUrl
content.push({ type: "image_url", image_url: { url } })
continue
}
return yield* ProviderShared.unsupportedContent(
"Cohere Chat",
message.role,
message.role === "user" ? ["text", "media"] : ["text", "reasoning", "tool-call"],
)
}
messages.push({
role: message.role,
content: content.length ? content : undefined,
tool_calls: calls.length ? calls : undefined,
tool_plan: plans.length ? plans.join("") : undefined,
})
}
const selected = request.toolChoice?.type === "tool" ? request.toolChoice.name : undefined
const tools = selected === undefined ? flattened.tools : flattened.tools.filter((tool) => tool.name === selected)
if (selected !== undefined && tools.length === 0)
return yield* ProviderShared.invalidRequest("Cohere Chat tool choice must name an available tool")
if (tools.some((tool) => tool.native !== undefined))
return yield* ProviderShared.invalidRequest("Cohere Chat does not support provider-defined tools")
return {
model: request.model.id,
messages,
stream: true as const,
tools: tools.length
? tools.map((tool) => ({
type: "function" as const,
function: { name: tool.name, description: tool.description, parameters: tool.inputSchema },
}))
: undefined,
tool_choice: TOOL_CHOICE[request.toolChoice?.type ?? "auto"],
thinking: options.thinking && {
type: options.thinking.type ?? "enabled",
// Cohere rejects budgets above max_tokens; fitting also leaves room for the answer.
token_budget:
options.thinking.tokenBudget === undefined
? undefined
: ProviderShared.fitThinkingBudget(options.thinking.tokenBudget, request.generation?.maxTokens),
},
max_tokens: request.generation?.maxTokens,
temperature: request.generation?.temperature,
p: request.generation?.topP,
k: request.generation?.topK,
seed: request.generation?.seed,
stop_sequences: request.generation?.stop,
frequency_penalty: request.generation?.frequencyPenalty,
presence_penalty: request.generation?.presencePenalty,
}
})
const finishReason = (raw: string): FinishReasonDetails => {
switch (raw) {
case "COMPLETE":
case "STOP_SEQUENCE":
return { normalized: "stop", raw }
case "MAX_TOKENS":
return { normalized: "length", raw }
case "TOOL_CALL":
return { normalized: "tool-calls", raw }
case "ERROR":
case "TIMEOUT":
return { normalized: "error", raw }
default:
return { normalized: "unknown", raw }
}
}
const mapUsage = (usage: typeof NativeUsage.Type) =>
new Usage({
inputTokens: usage.tokens?.input_tokens,
outputTokens: usage.tokens?.output_tokens,
nonCachedInputTokens: ProviderShared.subtractTokens(usage.tokens?.input_tokens, usage.cached_tokens),
cacheReadInputTokens: usage.cached_tokens,
reasoningTokens: usage.tokens?.reasoning_tokens,
totalTokens: ProviderShared.totalTokens(usage.tokens?.input_tokens, usage.tokens?.output_tokens, undefined),
providerMetadata: { cohere: usage },
})
// Lifecycle deltas open blocks on demand and ends are no-ops for closed blocks, so content-start needs no handling.
const step = Effect.fn("CohereChat.step")(function* (state: State, event: Event) {
const events: LLMEvent[] = []
switch (event.type) {
case "message-start":
return [{ ...state, lifecycle: Lifecycle.stepStart(state.lifecycle, events) }, events] as const
case "content-delta": {
const id = String(event.index)
const content = event.delta.message.content
const lifecycle =
content.thinking !== undefined
? Lifecycle.reasoningDelta(state.lifecycle, events, id, content.thinking)
: Lifecycle.textDelta(state.lifecycle, events, id, content.text ?? "")
return [{ ...state, lifecycle }, events] as const
}
case "content-end": {
const id = String(event.index)
const lifecycle = Lifecycle.textEnd(Lifecycle.reasoningEnd(state.lifecycle, events, id), events, id)
return [{ ...state, lifecycle }, events] as const
}
case "tool-plan-delta": {
const plan = event.delta.message.tool_plan
const lifecycle = Lifecycle.reasoningDelta(state.lifecycle, events, "tool-plan", plan, {
cohere: { toolPlan: true },
})
return [{ ...state, lifecycle }, events] as const
}
case "tool-call-start":
case "tool-call-delta": {
const call = event.delta.message.tool_calls
const result = ToolStream.appendOrStart(
ADAPTER,
state.tools,
event.index,
{ id: call.id, name: call.function.name, text: call.function.arguments ?? "" },
"Cohere tool call is missing id or name",
)
if (ToolStream.isError(result)) return yield* result
return [{ ...state, tools: result.tools }, result.events] as const
}
case "tool-call-end": {
const result = yield* ToolStream.finish(ADAPTER, state.tools, event.index)
return [{ ...state, tools: result.tools }, result.events ?? []] as const
}
case "message-end": {
const pending = yield* ToolStream.finishAll(ADAPTER, state.tools)
events.push(...pending.events)
const lifecycle = Lifecycle.finish(state.lifecycle, events, {
reason: finishReason(event.delta.finish_reason),
usage: event.delta.usage && mapUsage(event.delta.usage),
})
return [{ tools: pending.tools, lifecycle, finished: true }, events] as const
}
default:
return [state, events] as const
}
})
export const protocol = Protocol.make({
id: ADAPTER,
body: { schema: Body, from: fromRequest },
stream: {
event: Protocol.jsonEvent(Event),
initial: (): State => ({ lifecycle: Lifecycle.initial(), tools: ToolStream.empty(), finished: false }),
step,
terminal: (event) => event.type === "message-end",
onHalt: (state) =>
state.finished
? Effect.succeed([])
: Effect.fail(ProviderShared.eventError(ADAPTER, "Cohere stream ended without message-end")),
},
})
export const route = Route.make({
id: ADAPTER,
provider: "cohere",
providerMetadataKey: "cohere",
protocol,
endpoint: Endpoint.path("/chat", { baseURL: DEFAULT_BASE_URL }),
framing: Framing.sse,
})
export * as CohereChat from "./cohere-chat.js"
@@ -6,6 +6,7 @@ import { mergeJsonRecords, type OpenString } from "../schema/index.js"
import { TranscriptionModel, TranscriptionResponse, type TranscriptionRequestFor } from "../transcription.js"
import { ProviderShared } from "./shared.js"
import { MediaInput } from "./utils/media-input.js"
import { SpeakerTurns } from "./utils/speaker-turns.js"
const route = MediaProtocol.identity({ id: "deepgram-transcription", name: "Deepgram", provider: "deepgram" })
export const DEFAULT_BASE_URL = "https://api.deepgram.com"
@@ -115,16 +116,6 @@ const speaker = (value: number | undefined) => (value === undefined ? undefined
const wordText = (word: typeof Word.Type) => word.punctuated_word ?? word.word
// Utterances split on pauses, not speakers: the v2 diarizer labels a whole utterance with one speaker even when its
// words change speaker, so segments split each utterance at speaker changes.
const speakerTurns = (words: ReadonlyArray<typeof Word.Type>) =>
words.reduce<Array<Array<typeof Word.Type>>>((turns, word) => {
const last = turns.at(-1)
if (last === undefined || last[0].speaker !== word.speaker) return [...turns, [word]]
last.push(word)
return turns
}, [])
const decodeResponse = Effect.fn("DeepgramTranscription.decodeResponse")(function* (
response: HttpClientResponse.HttpClientResponse,
) {
@@ -136,6 +127,8 @@ const decodeResponse = Effect.fn("DeepgramTranscription.decodeResponse")(functio
const requestID = output.value.metadata?.request_id
return new TranscriptionResponse({
text: alternative.transcript,
// Utterances split on pauses, not speakers: the v2 diarizer labels a whole utterance with one speaker even when
// its words change speaker, so segments split each utterance at speaker changes.
segments: output.value.results.utterances?.flatMap((utterance) =>
utterance.words === undefined || utterance.words.length === 0
? [
@@ -146,7 +139,7 @@ const decodeResponse = Effect.fn("DeepgramTranscription.decodeResponse")(functio
speaker: speaker(utterance.speaker),
},
]
: speakerTurns(utterance.words).map((turn) => ({
: SpeakerTurns.group(utterance.words, (word) => word.speaker).map((turn) => ({
text: turn.map(wordText).join(" "),
startSeconds: turn[0].start,
endSeconds: turn[turn.length - 1].end,
@@ -0,0 +1,211 @@
import { Effect, Schema } from "effect"
import type { HttpClientResponse } from "effect/unstable/http"
import { MediaProtocol } from "../route/media-protocol.js"
import { MediaRoute } from "../route/media.js"
import { mergeJsonRecords, type OpenString } from "../schema/index.js"
import { TranscriptionModel, TranscriptionResponse, type TranscriptionRequestFor } from "../transcription.js"
import { mediaTypeExtension } from "../utils/media-type.js"
import { ProviderShared, optionalNull } from "./shared.js"
import { MediaInput } from "./utils/media-input.js"
import { SpeakerTurns } from "./utils/speaker-turns.js"
const route = MediaProtocol.identity({
id: "elevenlabs-transcription",
name: "ElevenLabs Transcription",
provider: "elevenlabs",
})
export const DEFAULT_BASE_URL = "https://api.elevenlabs.io"
export const PATH = "/v1/speech-to-text"
// ---------------------------------------------------------------------------
// 1. Public model input
// ---------------------------------------------------------------------------
export type ElevenLabsTranscriptionOptions = {
readonly tag_audio_events?: boolean
readonly timestamps_granularity?: OpenString<"none" | "word" | "character">
readonly diarization_threshold?: number
readonly file_format?: OpenString<"pcm_s16le_16" | "other">
readonly temperature?: number
readonly seed?: number
readonly keyterms?: ReadonlyArray<string>
readonly no_verbatim?: boolean
readonly detect_speaker_roles?: boolean
readonly use_speaker_library?: boolean
readonly entity_detection?: string | ReadonlyArray<string>
readonly entity_redaction?: string | ReadonlyArray<string>
readonly entity_redaction_mode?: OpenString<"redacted" | "entity_type" | "enumerated_entity_type">
} & Record<string, unknown>
export type Request = TranscriptionRequestFor<ElevenLabsTranscriptionOptions>
// ---------------------------------------------------------------------------
// 2. Response schema
// ---------------------------------------------------------------------------
/** `type` is `word`, `spacing` (the whitespace between words), or `audio_event` (`(laughter)`). */
const Token = Schema.Struct({
text: Schema.String,
type: Schema.String,
start: optionalNull(Schema.Number),
end: optionalNull(Schema.Number),
speaker_id: optionalNull(Schema.String),
logprob: optionalNull(Schema.Number),
})
type Token = Schema.Schema.Type<typeof Token>
const Transcript = Schema.Struct({
language_code: optionalNull(Schema.String),
text: Schema.String,
words: optionalNull(Schema.Array(Token)),
transcription_id: optionalNull(Schema.String),
audio_duration_secs: optionalNull(Schema.Number),
})
// ---------------------------------------------------------------------------
// 5. Request body construction
// ---------------------------------------------------------------------------
/** Speaker turns are the only segments ElevenLabs can produce, and `num_speakers` only applies to diarization. */
const diarizes = (request: Request) =>
request.diarize === true || request.timestamps === "segment" || request.speakers !== undefined
const RESERVED_FORM_FIELDS = new Set([
"file",
"cloud_storage_url",
"source_url",
"model_id",
"language_code",
"diarize",
"num_speakers",
])
const validate = (request: Request, overlay: Record<string, unknown>) => {
// Webhook requests return 202 with no transcript; the result arrives at a configured webhook instead.
if (overlay.webhook === true)
return Effect.fail(route.unsupported("transcription.webhook", `${route.name} does not deliver to webhooks`))
// Separate multichannel output replaces the transcript with one transcript per channel.
if (overlay.use_multi_channel === true && overlay.multichannel_output_style !== "combined")
return Effect.fail(
route.unsupported(
"transcription.multichannel",
`${route.name} returns a single transcript; set multichannel_output_style: "combined" to merge channels`,
),
)
if (overlay.timestamps_granularity === "none" && (request.timestamps === "word" || diarizes(request)))
return Effect.fail(
route.unsupported(
"media.timestamps",
`${route.name} cannot return word timestamps or speaker turns with timestamps_granularity: "none"`,
),
)
return Effect.void
}
const fromRequest = Effect.fn("ElevenLabsTranscription.fromRequest")(function* (request: Request) {
const overlay = mergeJsonRecords(request.providerOptions, request.http?.body) ?? {}
yield* validate(request, overlay)
const form = new FormData()
const url = ProviderShared.mediaUrl(request.audio)
if (url === undefined) {
const extension = mediaTypeExtension(request.audio.mediaType)
const audio = yield* MediaInput.inlineBytes(route.id, request.audio)
form.append(
"file",
MediaInput.blob(audio, request.audio.mediaType),
extension === undefined ? "audio" : `audio.${extension}`,
)
}
MediaInput.appendFields(
form,
{
model_id: request.model.id,
// `cloud_storage_url` is deprecated in favor of `source_url`, which accepts any hosted audio or video URL.
source_url: url,
language_code: request.language,
diarize: diarizes(request) ? true : undefined,
num_speakers: request.speakers,
},
{ overlay, reserved: RESERVED_FORM_FIELDS, repeatArrays: "key" },
)
return MediaProtocol.multipart(form)
})
// ---------------------------------------------------------------------------
// 6. Response decoding
// ---------------------------------------------------------------------------
const decodeTranscript = route.decodeJson(Transcript)
type TimedWord = Token & { readonly start: number; readonly end: number }
const isTimedWord = (token: Token): token is TimedWord =>
token.type === "word" && typeof token.start === "number" && typeof token.end === "number"
/** Turn text keeps the provider's own spacing tokens, so languages written without spaces are not re-spaced. */
const speakerTurns = (tokens: ReadonlyArray<Token>) =>
SpeakerTurns.group(
tokens.filter((token) => token.type === "word" || token.type === "spacing"),
(token) => token.speaker_id,
).flatMap((turn) => {
const words = turn.filter(isTimedWord)
if (words.length === 0) return []
return [
{
text: turn
.map((token) => token.text)
.join("")
.trim(),
startSeconds: words[0].start,
endSeconds: words[words.length - 1].end,
speaker: turn[0].speaker_id ?? undefined,
},
]
})
const decodeResponse = Effect.fn("ElevenLabsTranscription.decodeResponse")(function* (
response: HttpClientResponse.HttpClientResponse,
context: MediaProtocol.DecodeContext<Request>,
) {
const output = yield* decodeTranscript(response)
const transcript = output.value
const tokens = transcript.words ?? []
const duration = transcript.audio_duration_secs ?? undefined
const transcriptionID = transcript.transcription_id ?? undefined
return new TranscriptionResponse({
text: transcript.text,
segments: diarizes(context.request) ? speakerTurns(tokens) : undefined,
words: tokens.filter(isTimedWord).map((word) => ({
text: word.text,
startSeconds: word.start,
endSeconds: word.end,
speaker: word.speaker_id ?? undefined,
confidence: typeof word.logprob === "number" ? Math.exp(word.logprob) : undefined,
})),
language: transcript.language_code?.toLowerCase(),
durationSeconds: duration,
usage: duration === undefined ? undefined : { type: "seconds", seconds: duration },
providerMetadata: transcriptionID === undefined ? undefined : { elevenlabs: { transcriptionId: transcriptionID } },
})
})
// ---------------------------------------------------------------------------
// 7. Protocol and route
// ---------------------------------------------------------------------------
export const protocol = MediaProtocol.inline<Request, TranscriptionResponse>(route, {
unsupported: ["prompt"],
body: { from: fromRequest },
response: { decode: decodeResponse },
})
export const model = (input: MediaRoute.ModelInput) =>
TranscriptionModel.fromRoute<ElevenLabsTranscriptionOptions>(
{ protocol, baseURL: DEFAULT_BASE_URL, path: PATH },
input,
)
export const ElevenLabsTranscription = {
protocol,
model,
} as const
+14 -1
View File
@@ -36,7 +36,9 @@ const StartResponse = Schema.Struct({ name: Schema.String })
const Operation = Schema.Struct({
done: Schema.optional(Schema.Boolean),
error: Schema.optional(Schema.Struct({ message: Schema.optional(Schema.String) })),
error: Schema.optional(
Schema.Struct({ code: Schema.optional(Schema.Number), message: Schema.optional(Schema.String) }),
),
response: Schema.optional(
Schema.Struct({
generateVideoResponse: Schema.optional(
@@ -60,6 +62,16 @@ const Operation = Schema.Struct({
metadata: Schema.optional(Schema.Unknown),
})
// Operation errors are `google.rpc.Status`; unlisted codes (INTERNAL, UNAVAILABLE, ...) are provider-side.
const FAILURE = {
3: "InvalidRequest", // INVALID_ARGUMENT
7: "Authentication", // PERMISSION_DENIED
8: "RateLimit", // RESOURCE_EXHAUSTED
9: "InvalidRequest", // FAILED_PRECONDITION
11: "InvalidRequest", // OUT_OF_RANGE
16: "Authentication", // UNAUTHENTICATED
} as const satisfies Record<number, MediaProtocol.Failure>
// ---------------------------------------------------------------------------
// 5. Request body construction
// ---------------------------------------------------------------------------
@@ -154,6 +166,7 @@ const decodeResult = Effect.fn("GoogleVideo.decodeResult")(function* (
return yield* output.ended(
"failed",
`${route.name} operation failed${operation.error?.message === undefined ? "" : `: ${operation.error.message}`}`,
MediaProtocol.failure(FAILURE, operation.error?.code),
)
const generated = operation.response?.generateVideoResponse
// Downloads require the same API key as the poll; the asset carries it transiently and follows the redirect.
+1
View File
@@ -1,5 +1,6 @@
export * as AnthropicMessages from "./anthropic-messages.js"
export * as BedrockConverse from "./bedrock-converse.js"
export * as CohereChat from "./cohere-chat.js"
export * as Gemini from "./gemini.js"
export * as MistralChat from "./mistral-chat.js"
export * as OpenAIChat from "./openai-chat.js"
+11 -6
View File
@@ -10,14 +10,19 @@ const WebSearch = Schema.Struct({
name: Schema.Literal("web_search"),
user_location: MetaResponses.WebSearch.fields.user_location,
})
const MetaCacheControl = Schema.Struct({
type: Schema.tag("ephemeral"),
ttl: Schema.optional(Schema.Literals(["5m", "1h"])),
})
const FunctionTool = Schema.Struct({
name: Schema.String,
description: Schema.String,
input_schema: JsonObject,
cache_control: Schema.optional(MetaCacheControl),
})
const Body = Schema.Struct({
...AnthropicMessages.AnthropicMessagesBody.fields,
tools: optionalArray(
Schema.Union([
Schema.Struct({ name: Schema.String, description: Schema.String, input_schema: JsonObject }),
WebSearch,
]),
),
tools: optionalArray(Schema.Union([FunctionTool, WebSearch])),
})
const fromRequest = Effect.fn("MetaMessages.fromRequest")(function* (request: LLMRequest) {
+10 -6
View File
@@ -426,6 +426,7 @@ interface ActiveContent {
readonly type: "text" | "reasoning"
readonly id: string
readonly thinking?: MistralThinkingContent
readonly thinkingUnits?: MistralThinkingUnit[]
}
export interface ParserState {
@@ -502,8 +503,8 @@ const closeActive = (state: ParserState, events: LLMEvent[]) => {
state.lifecycle,
events,
state.active.id,
thinkingMetadata(state.active.thinking ?? { type: "thinking", thinking: [] }),
thinkingText(state.active.thinking?.thinking ?? []),
thinkingMetadata({ ...state.active.thinking, type: "thinking", thinking: state.active.thinkingUnits ?? [] }),
thinkingText(state.active.thinkingUnits ?? []),
)
return { ...state, lifecycle, active: undefined }
}
@@ -524,20 +525,23 @@ const appendThinking = (state: ParserState, events: LLMEvent[], part: MistralOut
const current = state.active?.type === "reasoning" ? state : closeActive(state, events)
const units = thinkingUnits(part.thinking)
const active = current.active ?? { type: "reasoning" as const, id: `reasoning-${current.nextContent}` }
// Keep native units out of streamed events until the block is complete.
const accumulated = active.thinkingUnits ?? []
accumulated.push(...units)
const thinking = {
...active.thinking,
...part,
type: "thinking" as const,
thinking: [...(active.thinking?.thinking ?? []), ...units],
thinking: [],
}
const text = thinkingText(units)
return {
...current,
lifecycle:
text.length > 0
? Lifecycle.reasoningDelta(current.lifecycle, events, active.id, text, thinkingMetadata(thinking))
: Lifecycle.reasoningStart(current.lifecycle, events, active.id, thinkingMetadata(thinking)),
active: { ...active, thinking },
? Lifecycle.reasoningDelta(current.lifecycle, events, active.id, text)
: Lifecycle.reasoningStart(current.lifecycle, events, active.id),
active: { ...active, thinking, thinkingUnits: accumulated },
nextContent: current.active ? current.nextContent : current.nextContent + 1,
}
}
+84 -55
View File
@@ -20,7 +20,6 @@ import {
type LLMRequest,
type MediaPart,
type ReasoningPart,
type TextPart,
type ToolCallPart,
type ToolDefinition,
} from "../schema/index.js"
@@ -45,6 +44,7 @@ const OpenAIChatCacheControl = Schema.Struct({
type: Schema.Literal("ephemeral"),
ttl: Schema.optional(Schema.String),
})
type OpenAIChatCacheControl = Schema.Schema.Type<typeof OpenAIChatCacheControl>
const OpenAIChatFunction = Schema.Struct({
name: Schema.String,
@@ -64,6 +64,14 @@ const OpenAIChatTool = Schema.Struct({
})
type OpenAIChatTool = Schema.Schema.Type<typeof OpenAIChatTool>
// Gemini's OpenAI-compatible surface carries thought signatures in tool call
// `extra_content` and rejects replayed parallel calls without them:
// https://ai.google.dev/gemini-api/docs/thinking#signatures
const ExtraContent = Schema.Struct({
google: Schema.Struct({ thought_signature: Schema.String }),
})
const decodeExtraContent = (value: unknown) => Option.getOrUndefined(Schema.decodeUnknownOption(ExtraContent)(value))
const OpenAIChatAssistantToolCall = Schema.Struct({
id: Schema.String,
type: Schema.tag("function"),
@@ -71,6 +79,7 @@ const OpenAIChatAssistantToolCall = Schema.Struct({
name: Schema.String,
arguments: Schema.String,
}),
extra_content: Schema.optional(ExtraContent),
})
type OpenAIChatAssistantToolCall = Schema.Schema.Type<typeof OpenAIChatAssistantToolCall>
@@ -112,18 +121,15 @@ const decodeReasoningDetail = Schema.decodeUnknownOption(ReasoningDetail)
const knownReasoningDetails = (details: ReadonlyArray<unknown>) =>
details.flatMap((detail) => Option.toArray(decodeReasoningDetail(detail)))
// Intentionally omit Gemini's provider-specific `extra_content.google.thought_signature`
// extension until direct Google OpenAI-compatible routing is supported here:
// https://github.com/vercel/ai/issues/11590
// https://github.com/vercel/ai/pull/11745
// https://ai.google.dev/gemini-api/docs/thought-signatures#openai
const OpenAIChatTextContent = Schema.Struct({
type: Schema.Literal("text"),
text: Schema.String,
cache_control: Schema.optional(OpenAIChatCacheControl),
})
type OpenAIChatTextContent = Schema.Schema.Type<typeof OpenAIChatTextContent>
const OpenAIChatUserContent = Schema.Union([
Schema.Struct({
type: Schema.Literal("text"),
text: Schema.String,
cache_control: Schema.optional(OpenAIChatCacheControl),
}),
OpenAIChatTextContent,
Schema.Struct({
type: Schema.Literal("image_url"),
image_url: Schema.Struct({ url: Schema.String }),
@@ -133,6 +139,7 @@ const OpenAIChatUserContent = Schema.Union([
file: Schema.Struct({ filename: Schema.String, file_data: Schema.String }),
}),
])
type OpenAIChatUserContent = Schema.Schema.Type<typeof OpenAIChatUserContent>
const OpenAIChatMessage = Schema.Union([
Schema.Struct({
@@ -146,21 +153,19 @@ const OpenAIChatMessage = Schema.Union([
Schema.StructWithRest(
Schema.Struct({
role: Schema.Literal("assistant"),
content: Schema.NullOr(Schema.String),
content: Schema.NullOr(Schema.Union([Schema.String, Schema.Array(OpenAIChatTextContent)])),
tool_calls: optionalArray(OpenAIChatAssistantToolCall),
reasoning_content: Schema.optional(Schema.String),
reasoning: Schema.optional(Schema.String),
reasoning_text: Schema.optional(Schema.String),
reasoning_details: Schema.optional(Schema.Unknown),
cache_control: Schema.optional(OpenAIChatCacheControl),
}),
[Schema.Record(Schema.String, Schema.Unknown)],
),
Schema.Struct({
role: Schema.Literal("tool"),
tool_call_id: Schema.String,
content: Schema.String,
cache_control: Schema.optional(OpenAIChatCacheControl),
content: Schema.Union([Schema.String, Schema.Array(OpenAIChatTextContent)]),
}),
]).pipe(Schema.toTaggedUnion("role"))
type OpenAIChatMessage = Schema.Schema.Type<typeof OpenAIChatMessage>
@@ -207,9 +212,11 @@ const OpenAIChatUsage = Schema.StructWithRest(
prompt_tokens: optionalNull(Schema.Number),
completion_tokens: optionalNull(Schema.Number),
total_tokens: optionalNull(Schema.Number),
// Zai reports cache hits as top-level `cached_tokens`; DeepSeek uses `prompt_cache_hit_tokens`.
// Provider-specific cache accounting fields.
cached_tokens: optionalNull(Schema.Number),
prompt_cache_hit_tokens: optionalNull(Schema.Number),
cache_read_input_tokens: optionalNull(Schema.Number),
cache_created_input_tokens: optionalNull(Schema.Number),
prompt_tokens_details: optionalNull(
Schema.StructWithRest(
Schema.Struct({
@@ -242,6 +249,7 @@ const OpenAIChatToolCallDelta = Schema.Struct({
index: optionalNull(Schema.Number),
id: optionalNull(Schema.String),
function: optionalNull(OpenAIChatToolCallDeltaFunction),
extra_content: optionalNull(Schema.Unknown),
})
type OpenAIChatToolCallDelta = Schema.Schema.Type<typeof OpenAIChatToolCallDelta>
@@ -294,6 +302,7 @@ interface PendingToolDelta {
readonly id?: string
readonly name?: string
readonly input: string
readonly extraContent?: Schema.Schema.Type<typeof ExtraContent>
}
export interface ParserState {
@@ -322,9 +331,7 @@ export interface ParserState {
// OpenAI Chat wire format. Keep provider quirks here instead of leaking native
// fields into `LLMRequest`.
interface LoweringOptions {
readonly cacheControl?: (
cache: CacheHint | undefined,
) => Schema.Schema.Type<typeof OpenAIChatCacheControl> | undefined
readonly cacheControl?: (cache: CacheHint | undefined) => OpenAIChatCacheControl | undefined
readonly toolCallID?: (id: string) => string
}
@@ -347,13 +354,17 @@ const lowerToolChoice = (toolChoice: NonNullable<LLMRequest["toolChoice"]>) =>
tool: (name) => ({ type: "function" as const, function: { name } }),
})
const lowerToolCall = (part: ToolCallPart, options: LoweringOptions): OpenAIChatAssistantToolCall => ({
const lowerToolCall = (
part: ToolCallPart,
options: LoweringOptions & { readonly providerMetadataKey: string },
): OpenAIChatAssistantToolCall => ({
id: options.toolCallID?.(part.id) ?? part.id,
type: "function",
function: {
name: part.name,
arguments: ProviderShared.encodeJson(part.input === undefined ? {} : part.input),
},
extra_content: decodeExtraContent(part.providerMetadata?.[options.providerMetadataKey]?.extraContent),
})
const lowerMedia = Effect.fn("OpenAIChat.lowerMedia")(function* (part: MediaPart) {
@@ -406,7 +417,7 @@ const lowerUserMessage = Effect.fn("OpenAIChat.lowerUserMessage")(function* (
message: OpenAIChatRequestMessage,
options: LoweringOptions,
) {
const content: Array<Schema.Schema.Type<typeof OpenAIChatUserContent>> = []
const content: OpenAIChatUserContent[] = []
for (const part of message.content) {
if (part.type === "text") {
content.push({ type: "text", text: part.text, cache_control: options.cacheControl?.(part.cache) })
@@ -432,14 +443,14 @@ const lowerAssistantMessage = Effect.fn("OpenAIChat.lowerAssistantMessage")(func
requireReasoning: boolean,
options: LoweringOptions & { readonly providerMetadataKey: string },
) {
const content: TextPart[] = []
const content: OpenAIChatTextContent[] = []
const reasoning: ReasoningPart[] = []
const toolCalls: OpenAIChatAssistantToolCall[] = []
for (const part of message.content) {
if (!ProviderShared.supportsContent(part, ["text", "reasoning", "tool-call"]))
return yield* ProviderShared.unsupportedContent("OpenAI Chat", "assistant", ["text", "reasoning", "tool-call"])
if (part.type === "text") {
content.push(part)
content.push({ type: "text", text: part.text, cache_control: options.cacheControl?.(part.cache) })
continue
}
if (part.type === "reasoning") {
@@ -477,14 +488,15 @@ const lowerAssistantMessage = Effect.fn("OpenAIChat.lowerAssistantMessage")(func
if (reasoning.length === 0) return nativeReasoning ?? (requireReasoning ? "" : undefined)
return text
})()
const cached = message.content.findLast((part) => "cache" in part && part.cache !== undefined)
const cacheControl = options.cacheControl?.(cached && "cache" in cached ? cached.cache : undefined)
const result = {
role: "assistant" as const,
content: content.length > 0 ? content.map((part) => part.text).join("") : toolCalls.length > 0 ? null : "",
content: (() => {
if (content.some((part) => part.cache_control !== undefined)) return content
if (content.length === 0 && toolCalls.length > 0) return null
return content.map((part) => part.text).join("")
})(),
...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),
...(details !== undefined ? { reasoning_details: details } : {}),
...(cacheControl !== undefined ? { cache_control: cacheControl } : {}),
}
if (field === undefined || reasoningText === undefined) return result
return { ...result, [field]: reasoningText }
@@ -495,33 +507,38 @@ const lowerToolMessages = Effect.fn("OpenAIChat.lowerToolMessages")(function* (
options: LoweringOptions,
) {
const messages: OpenAIChatMessage[] = []
const attachments: Array<Schema.Schema.Type<typeof OpenAIChatUserContent>> = []
const attachments: OpenAIChatUserContent[] = []
for (const part of message.content) {
if (!ProviderShared.supportsContent(part, ["tool-result"]))
return yield* ProviderShared.unsupportedContent("OpenAI Chat", "tool", ["tool-result"])
if (part.result.type !== "content") {
messages.push({
role: "tool",
tool_call_id: options.toolCallID?.(part.id) ?? part.id,
content: ProviderShared.toolResultText(part),
cache_control: options.cacheControl?.(part.cache),
})
messages.push(
toolMessage(
options.toolCallID?.(part.id) ?? part.id,
ProviderShared.toolResultText(part),
options.cacheControl?.(part.cache),
),
)
continue
}
const content: ReadonlyArray<Tool.Content> = part.result.value
const text = content.filter((item) => item.type === "text").map((item) => item.text)
messages.push({
role: "tool",
tool_call_id: options.toolCallID?.(part.id) ?? part.id,
content: text.join("\n"),
cache_control: options.cacheControl?.(part.cache),
})
messages.push(
toolMessage(options.toolCallID?.(part.id) ?? part.id, text.join("\n"), options.cacheControl?.(part.cache)),
)
const files = content.filter((item) => item.type === "file")
attachments.push(...(yield* Effect.forEach(files, (item) => lowerMedia(ProviderShared.toolFileMedia(item)))))
}
return { messages, attachments }
})
// Chat cache breakpoints belong on text content parts, not on the message itself.
const toolMessage = (toolCallID: string, text: string, cacheControl: OpenAIChatCacheControl | undefined) => ({
role: "tool" as const,
tool_call_id: toolCallID,
content: cacheControl === undefined ? text : [{ type: "text" as const, text, cache_control: cacheControl }],
})
const lowerMessage = Effect.fn("OpenAIChat.lowerMessage")(function* (
message: OpenAIChatRequestMessage,
reasoningField: string | undefined,
@@ -580,7 +597,7 @@ const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request:
if (requireAssistantAfterTool && messages.at(-1)?.role === "tool")
messages.push({ role: "assistant", content: "Done." })
}
const pendingAttachments: Array<Schema.Schema.Type<typeof OpenAIChatUserContent>> = []
const pendingAttachments: OpenAIChatUserContent[] = []
const flushAttachments = () => {
if (pendingAttachments.length === 0) return
bridgeTools()
@@ -590,24 +607,25 @@ const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request:
if (message.role === "user") bridgeTools()
if (message.role === "system") {
const part = yield* ProviderShared.wrappedSystemUpdate("OpenAI Chat", message)
const cacheControl = options.cacheControl?.(part.cache)
if (pendingAttachments.length > 0) {
messages.push({
role: "user",
content: [
...pendingAttachments.splice(0),
{ type: "text", text: part.text, cache_control: options.cacheControl?.(part.cache) },
{ type: "text", text: part.text, cache_control: cacheControl },
],
})
continue
}
const previous = messages.at(-1)
if (previous?.role === "user" && typeof previous.content === "string")
messages[messages.length - 1] = options.cacheControl?.(part.cache)
messages[messages.length - 1] = cacheControl
? {
role: "user",
content: [
{ type: "text", text: previous.content },
{ type: "text", text: part.text, cache_control: options.cacheControl(part.cache) },
{ type: "text", text: part.text, cache_control: cacheControl },
],
}
: { role: "user", content: `${previous.content}\n${part.text}` }
@@ -616,15 +634,15 @@ const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request:
role: "user",
content: [
...previous.content,
{ type: "text", text: part.text, cache_control: options.cacheControl?.(part.cache) },
{ type: "text", text: part.text, cache_control: cacheControl },
],
}
else
messages.push(
options.cacheControl?.(part.cache)
cacheControl
? {
role: "user",
content: [{ type: "text", text: part.text, cache_control: options.cacheControl(part.cache) }],
content: [{ type: "text", text: part.text, cache_control: cacheControl }],
}
: { role: "user", content: part.text },
)
@@ -721,7 +739,9 @@ const detectSupportsStore = (provider: string, baseURL: string | undefined): boo
p === "vercel-ai-gateway" || url.includes("ai-gateway.vercel.sh") || url.includes("vercel.sh")
const isAntLing = p === "ant-ling" || url.includes("api.ant-ling.com")
const isOpencode = p === "opencode" || url.includes("opencode.ai")
const isGemini = url.includes("generativelanguage.googleapis.com")
const isNonStandard =
isGemini ||
isNvidia ||
isCerebras ||
isXai ||
@@ -885,16 +905,19 @@ const mapFinishReason = Effect.fn("OpenAIChat.mapFinishReason")(function* (event
// satisfied on both sides.
// Providers differ on cache-hit location: OpenAI uses
// `prompt_tokens_details.cached_tokens`, DeepSeek uses
// `prompt_cache_hit_tokens`, and Zai uses top-level `cached_tokens`.
// `prompt_cache_hit_tokens`, Zai uses top-level `cached_tokens`, and
// DigitalOcean uses top-level `cache_read_input_tokens` / `cache_created_input_tokens`.
const mapUsage = (usage: OpenAIChatEvent["usage"], providerMetadataKey: string): Usage | undefined => {
if (!usage) return undefined
const input = usage.prompt_tokens ?? undefined
const output = usage.completion_tokens ?? undefined
const cached = (usage.prompt_tokens_details?.cached_tokens ??
(usage as { prompt_cache_hit_tokens?: number | null }).prompt_cache_hit_tokens ??
(usage as { cached_tokens?: number | null }).cached_tokens ??
undefined) as number | undefined
const cacheWrite = usage.prompt_tokens_details?.cache_write_tokens ?? undefined
const cached =
usage.prompt_tokens_details?.cached_tokens ??
usage.prompt_cache_hit_tokens ??
usage.cached_tokens ??
usage.cache_read_input_tokens ??
undefined
const cacheWrite = usage.prompt_tokens_details?.cache_write_tokens ?? usage.cache_created_input_tokens ?? undefined
const reasoning = usage.completion_tokens_details?.reasoning_tokens ?? undefined
const nonCached = ProviderShared.subtractTokens(input, ProviderShared.sumTokens(cached, cacheWrite))
return new Usage({
@@ -1114,12 +1137,13 @@ const step = (state: ParserState, event: OpenAIChatEvent) =>
const id = current?.id ?? pending?.id ?? (tool.id || undefined)
const name = current?.name ?? pending?.name ?? (tool.function?.name || undefined)
const text = `${pending?.input ?? ""}${tool.function?.arguments ?? ""}`
const extraContent = pending?.extraContent ?? decodeExtraContent(tool.extra_content)
latestToolIndex = index
nextToolIndex = Math.max(nextToolIndex, index + 1)
if (!current && (!id || !name)) {
pendingTools = {
...pendingTools,
[index]: { id: id || undefined, name: name || undefined, input: text },
[index]: { id: id || undefined, name: name || undefined, input: text, extraContent },
}
continue
}
@@ -1131,7 +1155,12 @@ const step = (state: ParserState, event: OpenAIChatEvent) =>
ADAPTER,
tools,
index,
{ id: id || undefined, name: name || undefined, text },
{
id: id || undefined,
name: name || undefined,
text,
providerMetadata: extraContent && { [state.providerMetadataKey]: { extraContent } },
},
"OpenAI Chat tool call delta is missing id or name",
)
if (ToolStream.isError(result))
@@ -143,14 +143,15 @@ const adapter = {
restoreHostedToolItem: (item: unknown) => (Schema.is(OpenAIResponsesHostedToolItem)(item) ? item : undefined),
} satisfies OpenResponses.ProviderAdapter
// GPT-6 Astra, Sol, and Luna accept `configuration_update` only in standard mode (not `reasoning.mode: "pro"` or
// `-pro` slugs), and never alongside automatic `context_management` compaction.
// GPT-6 and later default to `configuration_update` support, except in `reasoning.mode: "pro"`
// or alongside automatic `context_management` compaction.
const supportsEffortUpdates = (request: LLMRequest) => {
if (request.providerOptions?.contextManagement !== undefined) return false
if (Schema.is(Schema.Struct({ mode: Schema.Literal("pro") }))(request.http?.body?.reasoning)) return false
const override = request.model.compatibility?.supportsEffortUpdates
if (override !== undefined) return override
return /(?:^|\/)gpt-6-(?:astra|sol|luna)$/i.test(request.model.id)
const match = /(?:^|\/)gpt-(\d+)(?:\.\d+)?(?:-|$)/i.exec(request.model.id)
return match !== null && Number(match[1]) >= 6
}
const nativeImageToolInput = (tool: ToolDefinition) => {
@@ -193,7 +193,7 @@ const fromRequest = Effect.fn("OpenAITranscription.fromRequest")(function* (requ
{
overlay: mergeJsonRecords(request.providerOptions, request.http?.body),
reserved: RESERVED_FORM_FIELDS,
repeatArrays: true,
repeatArrays: "key[]",
},
)
return MediaProtocol.multipart(form)
+6 -1
View File
@@ -137,7 +137,12 @@ const decodeResult = Effect.fn("RunwayVideo.decodeResult")(function* (
const message = `${route.name} task failed${code === undefined ? "" : ` (${code})`}${task.failure ? `: ${task.failure}` : ""}`
// Runway failure codes are dotted paths; every moderation outcome carries a SAFETY segment.
if (code !== undefined && /(^|\.)SAFETY(\.|$)/.test(code)) return yield* output.contentPolicy(message)
return yield* output.ended("failed", message)
// ASSET.INVALID rejects the caller's input media; Runway documents it as not retryable.
return yield* output.ended(
"failed",
message,
code !== undefined && /^ASSET\.INVALID(\.|$)/.test(code) ? "InvalidRequest" : "ProviderInternal",
)
}
if (status === "cancelled")
return yield* output.ended("cancelled", `${route.name} task ${context.token.taskID} was cancelled`)
+10
View File
@@ -1,4 +1,5 @@
// Shared counter and TTL mapping for provider cache-marker lowering.
import type { CacheHint } from "../../schema/index.js"
export interface Breakpoints {
remaining: number
@@ -11,3 +12,12 @@ export const newBreakpoints = (cap: number): Breakpoints => ({ remaining: cap, d
// requests omit the wire TTL and use the provider default.
export const ttlBucket = (ttlSeconds: number | undefined): "1h" | undefined =>
ttlSeconds !== undefined && ttlSeconds >= 3600 ? "1h" : undefined
export const cacheControl = () => {
const breakpoints = newBreakpoints(4)
return (cache: CacheHint | undefined) => {
if (cache === undefined || breakpoints.remaining === 0) return undefined
breakpoints.remaining -= 1
return { type: "ephemeral" as const, ttl: ttlBucket(cache.ttlSeconds) }
}
}
@@ -0,0 +1,19 @@
import type { LLMRequest } from "../../schema/index.js"
export const THINKING_BINDING_BETA = "thinking-binding-controls-2026-08-01"
// Accept gateway namespaces and Vertex suffixes without treating a snapshot date as a minor version.
export const claudeVersion = (id: string) => {
const match = /(?:^|[./])claude-(?<family>[a-z]+)-(?<major>\d+)(?:[.-](?<minor>\d{1,2}))?(?:$|[-:@])/.exec(
id.toLowerCase(),
)?.groups
if (!match) return undefined
return { family: match.family, major: Number(match.major), minor: Number(match.minor ?? 0) }
}
export const supportsThinkingBlockBinding = (model: LLMRequest["model"]) => {
const override = model.compatibility?.supportsThinkingBlockBinding
if (override !== undefined) return override
const version = claudeVersion(model.id)
return version !== undefined && (version.major > 5 || (version.major === 5 && version.minor >= 1))
}
@@ -71,8 +71,9 @@ export const imageOutput = (
}
/**
* Append multipart text fields: strings as-is, other values as JSON, or arrays as repeated `key[]` parts with
* `repeatArrays`. `overlay` keys in `reserved` are dropped so `http.body` cannot replace route-owned fields.
* Append multipart text fields: strings as-is, other values as JSON, or scalar arrays as one part per item with
* `repeatArrays`, named `key[]` or `key`. `overlay` keys in `reserved` are dropped so `http.body` cannot replace
* route-owned fields.
*/
export const appendFields = (
form: FormData,
@@ -80,13 +81,13 @@ export const appendFields = (
options: {
readonly overlay?: Record<string, unknown>
readonly reserved: ReadonlySet<string>
readonly repeatArrays?: true
readonly repeatArrays?: "key[]" | "key"
},
) => {
const overlay = Object.entries(options.overlay ?? {}).filter(([key]) => !options.reserved.has(key))
Object.entries(mergeJsonRecords(fields, Object.fromEntries(overlay)) ?? {}).forEach(([key, value]) => {
if (Array.isArray(value) && options.repeatArrays)
return value.forEach((item) => form.append(`${key}[]`, String(item)))
if (Array.isArray(value) && value.every(isScalar) && options.repeatArrays !== undefined)
return value.forEach((item) => form.append(options.repeatArrays === "key[]" ? `${key}[]` : key, String(item)))
form.append(key, typeof value === "string" ? value : encodeJson(value))
})
}
@@ -0,0 +1,10 @@
/** Split an ordered token list into runs of consecutive tokens with the same speaker. */
export const group = <Item>(items: ReadonlyArray<Item>, speaker: (item: Item) => unknown) =>
items.reduce<Array<Array<Item>>>((turns, item) => {
const last = turns.at(-1)
if (last === undefined || speaker(last[0]) !== speaker(item)) return [...turns, [item]]
last.push(item)
return turns
}, [])
export * as SpeakerTurns from "./speaker-turns.js"
@@ -147,7 +147,12 @@ export const appendOrStart = <K extends StreamKey>(
route: string,
tools: State<K>,
key: K,
delta: { readonly id?: string; readonly name?: string; readonly text: string },
delta: {
readonly id?: string
readonly name?: string
readonly text: string
readonly providerMetadata?: ProviderMetadata
},
missingToolMessage: string,
): AppendOutcome<K> | AIError => {
const current = tools[key]
@@ -161,7 +166,7 @@ export const appendOrStart = <K extends StreamKey>(
namespace: current?.namespace,
input: `${current?.input ?? ""}${delta.text}`,
providerExecuted: current?.providerExecuted,
providerMetadata: current?.providerMetadata,
providerMetadata: current?.providerMetadata ?? delta.providerMetadata,
}
if (current && delta.text.length === 0 && current.id === id && current.name === name)
return { tools, tool: current, events: [] }
+8
View File
@@ -65,6 +65,13 @@ const STATUS = {
expired: "expired",
} as const satisfies Record<string, Status>
// Documented video error codes; `service_unavailable`, `internal_error`, and unknown codes are provider-side.
const FAILURE = {
invalid_argument: "InvalidRequest",
failed_precondition: "InvalidRequest",
permission_denied: "Authentication",
} as const satisfies Record<string, MediaProtocol.Failure>
// ---------------------------------------------------------------------------
// 5. Request body construction
// ---------------------------------------------------------------------------
@@ -143,6 +150,7 @@ const decodeResult = Effect.fn("XAIVideo.decodeResult")(function* (
return yield* output.ended(
"failed",
`${route.name} generation failed${code === undefined ? "" : ` (${code})`}${message === undefined ? "" : `: ${message}`}`,
MediaProtocol.failure(FAILURE, code),
)
}
if (status !== "completed")
+7 -3
View File
@@ -41,16 +41,20 @@ const Body = Schema.Struct({
user_id: Options.fields.userID,
})
// Tool streaming was introduced in GLM-4.6; later versions inherit support.
const supportsToolStreaming = (modelID: string) => {
const match = /(?:^|\/)glm-(\d+)(?:\.(\d+))?(?:-|$)/i.exec(modelID)
return match !== null && (Number(match[1]) > 4 || (Number(match[1]) === 4 && Number(match[2] ?? 0) >= 6))
}
const fromRequest = Effect.fn("ZAIChat.fromRequest")(function* (request: LLMRequest) {
const options = yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(Options))(request.providerOptions ?? {})
const body = yield* OpenAIChat.protocol.body.from(request)
return {
...body,
thinking: options.thinking,
// Tool streaming was introduced in GLM-4.6; older models must not receive the opt-in.
tool_stream:
options.toolStream ??
(body.tools?.length && /^glm-(?:4\.[67]|5(?:[.-]|$))/i.test(request.model.id) ? true : undefined),
options.toolStream ?? (body.tools?.length && supportsToolStreaming(request.model.id) ? true : undefined),
do_sample: options.doSample,
response_format: options.responseFormat,
request_id: options.requestID,
+116 -8
View File
@@ -1,4 +1,4 @@
import { Option, Schema } from "effect"
import { Option, Schema, SchemaGetter } from "effect"
import {
AuthenticationError,
ContentPolicyError,
@@ -16,24 +16,34 @@ import {
const patterns = [
/prompt is too long/i,
/input is too long for requested model/i,
// Cloudflare Workers AI reports this as HTTP 413.
/exceeded this model context window limit/i,
/exceeds the context window/i,
/exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\d,]+ tokens?|\s*\([\d,]+\))/i,
/input token count.*exceeds the maximum/i,
// Amazon Nova on Bedrock reports this as a mid-stream validationException.
/number of input tokens exceeds maximum length/i,
/tokens in request more than max tokens allowed/i,
/maximum prompt length is \d+/i,
/reduce the length of the messages/i,
// DeepInfra
/requested input length \d+ exceeds maximum input length/i,
/maximum context length is \d+ tokens/i,
/exceeds (?:the )?maximum allowed input length of [\d,]+ tokens?/i,
/input \(\d+ tokens\) is longer than the model'?s context length \(\d+ tokens\)/i,
// Novita omits the token counts.
/input(?: \(\d+ tokens\))? is longer than the model'?s context length/i,
/exceeds the limit of \d+/i,
/exceeds the available context size/i,
/greater than the context length/i,
// Hugging Face Text Generation Inference, e.g. Together
/`inputs` tokens \+ `max_new_tokens` must be <= \d+/i,
/context window exceeds limit/i,
/exceeded model token limit/i,
/context[_ ]length[_ ]exceeded/i,
/context length is only \d+ tokens/i,
/input length.*exceeds.*context length/i,
/prompt too long; exceeded (?:max )?context length/i,
// Z.ai code 1261 arrives as `Prompt too long` or `Prompt 超长`.
/prompt (?:too long|超长)/i,
/too large for model with \d+ maximum context length/i,
/prompt has [\d,]+ tokens?, but the configured context size is [\d,]+ tokens?/i,
/model_context_window_exceeded/i,
@@ -45,7 +55,13 @@ const patterns = [
const payloadPatterns = [/request entity too large/i, /payload too large/i, /request too large/i]
const exclusions = [/^(throttling error|service unavailable):/i, /rate limit/i, /too many requests/i]
const exclusions = [
/^(throttling error|service unavailable):/i,
/rate limit/i,
/too many requests/i,
// Cohere reports an output limit above the model maximum as "too many tokens"; compaction cannot fix it.
/max[_ ]tokens must be less than/i,
]
export const isContextOverflow = (message: string) =>
!exclusions.some((pattern) => pattern.test(message)) &&
@@ -58,6 +74,47 @@ export const isContextOverflowFailure = (failure: unknown) =>
? failure.reason._tag === "InvalidRequest" && failure.reason.classification === "context-overflow"
: Schema.is(ProviderErrorEvent)(failure) && failure.classification === "context-overflow"
/**
* Whether a failed call may succeed when sent again: rate limits, provider-side failures, transport failures that did
* not deliver an accepted write, and unrecognized failures. Callers decide which calls are safe to repeat.
*/
export const isRetryable = (error: AIError) => {
const override = error.reason.http?.headers["x-should-retry"]
if (override === "true") return true
if (override === "false") return false
switch (error.reason._tag) {
case "RateLimit":
case "ProviderInternal":
return true
// A WebSocket acknowledgment marks delivery accepted before model output may exist.
// Read failures can still recover; the caller chooses retry versus continuation from durable output.
case "Transport":
return (
error.reason.delivery !== "rejected" &&
(error.reason.delivery !== "accepted" || error.reason.operation === "read")
)
case "InvalidProviderOutput":
return error.reason.classification === "incomplete-stream"
// Unrecognized failures retry: classification records affirmative
// deterministic evidence, and transient failures are exactly the ones
// that arrive in shapes no classifier anticipates.
case "UnknownProvider":
return true
case "Authentication":
case "QuotaExceeded":
case "ContentPolicy":
case "InvalidRequest":
case "UnsupportedOperation":
case "NoRoute":
case "Timeout":
return false
default: {
const exhaustive: never = error.reason
return exhaustive
}
}
}
const decodeJson = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Unknown))
// OpenCode Zen reports account caps as typed 429/402 errors that are not throttles.
const QUOTA_CODES = new Set([
@@ -68,7 +125,9 @@ const QUOTA_CODES = new Set([
"freeusagelimiterror",
"creditlimitexceeded",
])
const AUTH_CODES = new Set(["authentication_error", "permission_error"])
// Google reports an invalid API key as HTTP 400 INVALID_ARGUMENT with this `details[].reason`.
// Z.ai's Responses API reports account and plan rejections mid-stream as `permission_denied`.
const AUTH_CODES = new Set(["authentication_error", "permission_error", "permission_denied", "api_key_invalid"])
const SERVER_CODES = new Set([
"api_error",
"internal_error",
@@ -82,6 +141,7 @@ const SERVER_CODES = new Set([
])
// `invalid_request` is the Vercel AI Gateway's code for an upstream request rejection.
const INVALID_REQUEST_CODES = new Set([
"model_not_found",
"invalid_prompt",
"invalid_request",
"invalid_request_error",
@@ -101,18 +161,57 @@ const CONTENT_POLICY_CODES = new Set([
// OpenCode Zen replaces upstream codes outside its allow-list but keeps the original
// as a `[code]` label at the start of the rewritten message.
const GATEWAY_CODE_LABEL = /^[^:\n]+: \[([A-Za-z0-9_.-]+)\]/
// xAI reports an invalid API key as HTTP 400 with the generic `invalid-argument` code.
const AUTH_TEXT = /incorrect api key provided/i
const RATE_LIMIT_TEXT = /rate increased too quickly|rate[-_\s]?limit|too[_\s]?many[_\s]?requests/i
// Only consulted on 429, where throttles and account caps share a status.
const QUOTA_TEXT = /insufficient[-_\s]?quota|quota[-_\s]?exceeded|budget exceeded|usage limit/i
// Z.ai reports balance, plan expiry, plan limits, and plan model access on 429.
const QUOTA_TEXT =
/insufficient[-_\s]?(?:quota|balance)|quota[-_\s]?exceeded|budget exceeded|usage limit|limit exhausted|package has expired|plan does not yet include/i
// Policy rejections without a dedicated code, matched against the provider's own
// explanation only. OpenAI reuses `invalid_prompt` for usage-policy rejections while
// Bedrock Mantle reuses it for schema validation; Anthropic reports blocked output
// under `invalid_request_error`.
const CONTENT_POLICY_TEXT =
/violating our usage policy|blocked by content filtering policy|content[-_\s]?policy|rejected as a result of our safety system/i
/violating our usage policy|blocked by content filtering policy|content[-_\s]?policy|rejected as a result of our safety system|detected potentially unsafe or sensitive content/i
const SERVER_ERROR_TEXT =
/\b(?:try again|(?:please |you can )?retry (?:the |this |your )?request|try (?:the |this |your )?request again|(?:currently |temporarily )?at capacity|overloaded|temporarily unavailable|service[-_\s]?unavailable|(?:server|internal)[-_\s]?error|server (?:is )?busy|provider returned (?:an )?error|resource[-_\s]?exhausted|upstream (?:connect|connection|request)|request buffer limit while retrying upstream)\b/i
const Message = Schema.String.check(Schema.isPattern(/\S/))
const messageAt = <Fields extends Schema.Struct.Fields>(
fields: Fields,
message: (body: Schema.Struct<Fields>["Type"]) => string,
) =>
Schema.Struct(fields).pipe(
Schema.decodeTo(Schema.String, {
decode: SchemaGetter.transform(message),
encode: SchemaGetter.forbidden(() => "Provider error messages are decode-only"),
}),
)
// Common error body layouts that carry a human-readable message, in priority order.
// Provider-specific layouts belong in their protocol.
const decodeMessage = Schema.decodeUnknownOption(
Schema.fromJsonString(
Schema.Union([
messageAt({ error: Schema.Struct({ message: Message }) }, (body) => body.error.message),
messageAt({ error: Message }, (body) => body.error),
messageAt({ message: Message }, (body) => body.message),
// AWS services
messageAt({ Message: Message }, (body) => body.Message),
// RFC 9457 problem details
messageAt({ detail: Message }, (body) => body.detail),
messageAt(
{ errors: Schema.NonEmptyArray(Schema.Struct({ message: Message })) },
(body) => body.errors[0].message,
),
]),
),
)
export const providerErrorMessage = (body: string) => Option.getOrUndefined(decodeMessage(body))
export interface ProviderFailure {
readonly message: string
readonly status?: number | undefined
@@ -165,7 +264,12 @@ export function classifyProviderFailure(input: ProviderFailure): AIError["reason
(input.status === 429 && QUOTA_TEXT.test(text))
)
return new QuotaExceededError(details)
if (input.status === 401 || input.status === 403 || codes.some((code) => AUTH_CODES.has(code)))
if (
input.status === 401 ||
input.status === 403 ||
codes.some((code) => AUTH_CODES.has(code)) ||
(input.status === 400 && AUTH_TEXT.test(text))
)
return new AuthenticationError(details)
if (
input.status === 429 ||
@@ -218,6 +322,10 @@ function providerCodes(value: unknown) {
error?.type,
error?.status,
error?.error_type,
// Google `google.rpc.ErrorInfo` details carry the specific reason.
...(Array.isArray(error?.details)
? error.details.map((detail) => (isRecord(detail) ? detail.reason : undefined))
: []),
inner?.code,
metadata?.error_type,
responseError?.code,
@@ -28,7 +28,8 @@ export type Settings = ProviderPackage.Settings &
readonly provider?: string
}
export const routes = [AnthropicMessages.route]
const compatibleRoute = AnthropicMessages.route.with({ id: "anthropic-compatible-messages", provider: id })
export const routes = [compatibleRoute]
const auth = (input: ProviderAuthOption<"optional">) => {
if ("auth" in input && input.auth) return input.auth
@@ -43,7 +44,7 @@ export const configure = (input: Config) => {
message: "Anthropic-compatible providers require a baseURL",
})
const { provider: _, baseURL, apiKey: _apiKey, auth: _auth, ...rest } = input
const route = AnthropicMessages.route.with({
const route = (provider === "anthropic" ? AnthropicMessages.route : compatibleRoute).with({
...rest,
provider,
endpoint: { baseURL },
@@ -42,14 +42,24 @@ export type Settings = ProviderPackage.Settings &
export const baseURL = (input: GatewayURL) => {
if (input.baseURL) return input.baseURL
if (!input.accountId)
throw new ProviderConfigurationError({
provider: id,
message: "CloudflareAIGateway.configure requires accountId unless baseURL is supplied",
})
return `https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(input.accountId)}/ai/v1`
return `https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(requireAccountId(input))}/ai/v1`
}
// Cloudflare's REST API rejects parts of the Anthropic Messages and OpenAI Responses request shapes, such as
// system prompt blocks and `minimal` reasoning effort, so these models use the provider-native gateway endpoints.
const passthroughURL = (input: GatewayURL & GatewayOptions, provider: "anthropic/v1" | "openai") =>
`https://gateway.ai.cloudflare.com/v1/${encodeURIComponent(requireAccountId(input))}/${encodeURIComponent(gatewayId(input))}/${provider}`
const requireAccountId = (input: GatewayURL) => {
if (input.accountId) return input.accountId
throw new ProviderConfigurationError({
provider: id,
message: "CloudflareAIGateway.configure requires accountId unless baseURL is supplied",
})
}
const gatewayId = (input: GatewayOptions) => input.gatewayId?.trim() || "default"
export const responsesRoute = OpenAIResponses.route.with({
id: "cloudflare-ai-gateway-responses",
provider: id,
@@ -70,16 +80,12 @@ export const route = OpenAIChat.route.with({
export const routes = [responsesRoute, messagesRoute, route]
const auth = (input: LanguageModelOptions) => {
if ("auth" in input && input.auth) return input.auth
return Auth.optional(input.gatewayApiKey ?? ("apiKey" in input ? input.apiKey : undefined), "apiKey")
const credential = (input: LanguageModelOptions) =>
Auth.optional(input.gatewayApiKey ?? ("apiKey" in input ? input.apiKey : undefined), "apiKey")
.orElse(Auth.config(authEnvVars[0]))
.orElse(Auth.config(authEnvVars[1]))
.bearer()
}
const headers = (input: LanguageModelOptions) => ({
...(input.gatewayId === undefined ? {} : { "cf-aig-gateway-id": input.gatewayId.trim() || "default" }),
...(input.metadata === undefined
? {}
: { "cf-aig-metadata": Schema.encodeSync(Schema.fromJsonString(Schema.Unknown))(input.metadata) }),
@@ -90,31 +96,42 @@ const headers = (input: LanguageModelOptions) => ({
...input.headers,
})
const modelID = (input: string | ModelID) => {
const value = String(input)
if (value.startsWith("workers-ai/")) return value.slice("workers-ai/".length)
if (value.startsWith("anthropic/")) return `anthropic/${value.slice("anthropic/".length).replaceAll(".", "-")}`
return value
}
export const configure = (input: LanguageModelOptions) => {
const defaults = {
const custom = "auth" in input && input.auth ? input.auth : undefined
const rest = {
endpoint: { baseURL: baseURL(input) },
auth: auth(input),
headers: headers(input),
auth: custom ?? credential(input).bearer(),
headers: { "cf-aig-gateway-id": gatewayId(input), ...headers(input) },
http: input.http,
providerOptions: input.providerOptions,
}
const responses = responsesRoute.with(defaults)
const messages = messagesRoute.with(defaults)
const chat = route.with(defaults)
// A custom baseURL stands in for the REST API, so every model keeps using it with gateway model IDs.
const native = input.baseURL === undefined
const passthrough = (provider: "anthropic/v1" | "openai") =>
native
? {
...rest,
endpoint: { baseURL: passthroughURL(input, provider) },
auth: custom ?? Auth.bearerHeader("cf-aig-authorization", credential(input)),
headers: headers(input),
}
: rest
const responses = responsesRoute.with(passthrough("openai"))
const messages = messagesRoute.with(passthrough("anthropic/v1"))
const chat = route.with(rest)
return {
id,
model: (input: string | ModelID) => {
const wire = modelID(input)
if (String(input).startsWith("openai/")) return responses.model<OpenAIProviderOptionsInput>({ id: wire })
if (String(input).startsWith("anthropic/")) return messages.model<OpenAIProviderOptionsInput>({ id: wire })
return chat.model<OpenAIProviderOptionsInput>({ id: wire })
const value = String(input)
if (value.startsWith("openai/"))
return responses.model<OpenAIProviderOptionsInput>({ id: native ? value.slice("openai/".length) : value })
if (value.startsWith("anthropic/"))
return messages.model<OpenAIProviderOptionsInput>({
id: native ? value.slice("anthropic/".length).replaceAll(".", "-") : value,
})
if (value.startsWith("workers-ai/"))
return chat.model<OpenAIProviderOptionsInput>({ id: value.slice("workers-ai/".length) })
return chat.model<OpenAIProviderOptionsInput>({ id: value })
},
configure,
}
+66
View File
@@ -0,0 +1,66 @@
import { CohereChat } from "../protocols/cohere-chat.js"
import { OpenAIChat } from "../protocols/openai-chat.js"
import { Route, type RouteDefaultsInput } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options.js"
import { ProviderID, type ModelID, type OpenString } from "../schema/index.js"
import type { ProviderPackage } from "../provider-package.js"
export const id = ProviderID.make("cohere")
const COMPATIBILITY_BASE_URL = "https://api.cohere.ai/compatibility/v1"
export type ChatOptionsInput = { readonly reasoningEffort?: OpenString<"none" | "high"> }
export type ProviderOptions = CohereChat.ProviderOptionsInput & ChatOptionsInput
export type LanguageModelOptions = Omit<RouteDefaultsInput, "providerOptions"> &
ProviderAuthOption<"optional"> & {
readonly baseURL?: string
readonly providerOptions?: ProviderOptions
}
export type Settings<Options = CohereChat.ProviderOptionsInput> = ProviderPackage.Settings &
Options & { readonly apiKey?: string; readonly baseURL?: string }
export const route = CohereChat.route
export const chatRoute = Route.make({
id: "cohere-chat-completions",
provider: id,
providerMetadataKey: "cohere",
protocol: OpenAIChat.protocol,
endpoint: Endpoint.path("/chat/completions", { baseURL: COMPATIBILITY_BASE_URL }),
framing: OpenAIChat.framing,
})
export const routes = [route, chatRoute]
export const configure = (input: LanguageModelOptions = {}) => {
const { apiKey: _apiKey, auth: _auth, baseURL, ...defaults } = input
const auth = AuthOptions.bearer(input, "COHERE_API_KEY")
const native = route.with({ ...defaults, auth, endpoint: { baseURL: baseURL ?? CohereChat.DEFAULT_BASE_URL } })
const chat = chatRoute.with({ ...defaults, auth, endpoint: { baseURL: baseURL ?? COMPATIBILITY_BASE_URL } })
return {
id,
model: (modelID: string | ModelID) => native.model<CohereChat.ProviderOptionsInput>({ id: modelID }),
chat: (modelID: string | ModelID) =>
chat.model<ChatOptionsInput>({
id: modelID,
compatibility: {
maxTokensField: "max_tokens",
supportsStore: false,
supportsUsageInStreaming: true,
reasoningField: "reasoning_content",
supportsStrictMode: false,
},
}),
configure,
}
}
export const provider = configure()
export const model: ProviderPackage.Definition<Settings, CohereChat.ProviderOptionsInput>["model"] = (
modelID,
{ apiKey, baseURL, body, headers, ...providerOptions },
) =>
configure({
apiKey,
baseURL,
headers,
http: body === undefined ? undefined : { body: { ...body } },
providerOptions,
}).model(modelID)
export * as Cohere from "./cohere.js"
+16
View File
@@ -0,0 +1,16 @@
import type { ProviderPackage } from "../../provider-package.js"
import { Cohere } from "../cohere.js"
export type Settings = Cohere.Settings<Cohere.ChatOptionsInput>
export const model: ProviderPackage.Definition<Settings, Cohere.ChatOptionsInput>["model"] = (
modelID,
{ apiKey, baseURL, body, headers, ...providerOptions },
) =>
Cohere.configure({
apiKey,
baseURL,
headers,
http: body === undefined ? undefined : { body: { ...body } },
providerOptions,
}).chat(modelID)
+76
View File
@@ -0,0 +1,76 @@
import type { ProviderPackage } from "../provider-package.js"
import { OpenAIChat } from "../protocols/openai-chat.js"
import { cacheControl } from "../protocols/utils/cache.js"
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options.js"
import { Route, type RouteDefaultsInput } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { Protocol } from "../route/protocol.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import type { OpenAIProviderOptionsInput } from "./openai-options.js"
export const id = ProviderID.make("digitalocean")
const baseURL = "https://inference.do-ai.run/v1"
export type LanguageModelOptions = Omit<RouteDefaultsInput, "providerOptions"> &
ProviderAuthOption<"optional"> & {
readonly baseURL?: string
readonly providerOptions?: OpenAIProviderOptionsInput
}
export type Settings = ProviderPackage.Settings & OpenAIProviderOptionsInput & { readonly apiKey?: string }
export const protocol = Protocol.make({
id: "digitalocean-chat",
body: {
schema: OpenAIChat.protocol.body.schema,
from: (request) => OpenAIChat.fromRequest(request, { cacheControl: cacheControl() }),
},
stream: OpenAIChat.protocol.stream,
})
export const route = Route.make({
id: "digitalocean",
provider: id,
providerMetadataKey: "digitalocean",
protocol,
endpoint: Endpoint.path("/chat/completions", { baseURL }),
framing: OpenAIChat.framing,
})
export const routes = [route]
export const configure = (input: LanguageModelOptions = {}) => {
const { apiKey: _apiKey, auth: _auth, baseURL: endpoint, ...defaults } = input
const configured = route.with({
...defaults,
endpoint: { baseURL: endpoint ?? baseURL },
auth: AuthOptions.bearer(input, ["DIGITALOCEAN_ACCESS_TOKEN", "DIGITALOCEAN_API_KEY", "DO_INFERENCE_API_KEY"]),
})
return {
id,
model: (modelID: string | ModelID) =>
configured.model<OpenAIProviderOptionsInput>({
id: modelID,
compatibility: {
supportsPromptCacheKey: true,
},
}),
configure,
}
}
export const provider = configure()
export const model: ProviderPackage.Definition<Settings, OpenAIProviderOptionsInput>["model"] = (
modelID,
{ apiKey, baseURL, body, headers, ...providerOptions },
) =>
configure({
apiKey,
baseURL,
headers,
http: { body },
providerOptions,
}).model(modelID)
export * as DigitalOcean from "./digitalocean.js"
+5
View File
@@ -3,8 +3,10 @@ import type { ProviderAuthOption } from "../route/auth-options.js"
import { MediaRoute } from "../route/media.js"
import { type HttpOptions, ProviderID, type ModelID } from "../schema/index.js"
import { ElevenLabsSpeech } from "../protocols/elevenlabs-speech.js"
import { ElevenLabsTranscription } from "../protocols/elevenlabs-transcription.js"
export type { ElevenLabsOutputFormat, ElevenLabsSpeechOptions } from "../protocols/elevenlabs-speech.js"
export type { ElevenLabsTranscriptionOptions } from "../protocols/elevenlabs-transcription.js"
export const id = ProviderID.make("elevenlabs")
@@ -24,12 +26,15 @@ const auth = (options: ProviderAuthOption<"optional">) => {
export const configure = (input: Config = {}) => {
const media = MediaRoute.deployment(input, auth(input))
const speech = (modelID: string | ModelID) => ElevenLabsSpeech.model({ ...media, id: modelID })
const transcription = (modelID: string | ModelID) => ElevenLabsTranscription.model({ ...media, id: modelID })
return {
id,
speech,
transcription,
configure,
}
}
export const provider = configure()
export const speech = provider.speech
export const transcription = provider.transcription
@@ -37,7 +37,7 @@ export type Settings = ProviderPackage.Settings &
const route = Route.make({
id: "google-vertex-messages",
provider: id,
providerMetadataKey: "anthropic",
providerMetadataKey: "vertex",
protocol: Protocol.make({
id: AnthropicMessages.protocol.id,
body: {
+1 -1
View File
@@ -71,7 +71,7 @@ export const protocol = Protocol.make({
export const route = Route.make({
id: "groq-chat",
provider: id,
providerMetadataKey: "openai",
providerMetadataKey: "groq",
protocol,
endpoint: Endpoint.path("/chat/completions", { baseURL }),
framing: OpenAIChat.framing,
+2
View File
@@ -9,11 +9,13 @@ export * as Baseten from "./baseten.js"
export * as BlackForestLabs from "./black-forest-labs.js"
export * as Cartesia from "./cartesia.js"
export * as Cerebras from "./cerebras.js"
export * as Cohere from "./cohere.js"
export * as CloudflareAIGateway from "./cloudflare-ai-gateway.js"
export * as CloudflareWorkersAI from "./cloudflare-workers-ai.js"
export * as DeepInfra from "./deepinfra.js"
export * as Deepgram from "./deepgram.js"
export * as DeepSeek from "./deepseek.js"
export * as DigitalOcean from "./digitalocean.js"
export * as ElevenLabs from "./elevenlabs.js"
export * as Fal from "./fal.js"
export * as Fireworks from "./fireworks.js"
+2 -14
View File
@@ -3,11 +3,11 @@ import { Route, type RouteDefaultsInput } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { Protocol } from "../route/protocol.js"
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options.js"
import { HttpOptions, ProviderID, type CacheHint, type ModelID, type OpenString } from "../schema/index.js"
import { HttpOptions, ProviderID, type ModelID, type OpenString } from "../schema/index.js"
import type { ProviderPackage } from "../provider-package.js"
import { SystemOne } from "../experimental/system-one.js"
import { OpenAIChat } from "../protocols/openai-chat.js"
import { newBreakpoints, ttlBucket } from "../protocols/utils/cache.js"
import { cacheControl } from "../protocols/utils/cache.js"
import { isRecord, ProviderShared } from "../protocols/shared.js"
export const id = ProviderID.make("openrouter")
@@ -131,18 +131,6 @@ export const protocol = Protocol.make({
stream: OpenAIChat.protocol.stream,
})
const cacheControl = () => {
const breakpoints = newBreakpoints(4)
return (cache: CacheHint | undefined) => {
if (cache === undefined || breakpoints.remaining === 0) return undefined
breakpoints.remaining -= 1
return {
type: "ephemeral" as const,
...(ttlBucket(cache.ttlSeconds) === "1h" ? { ttl: "1h" } : {}),
}
}
}
// OpenRouter forwards `reasoning.max_tokens` as the upstream thinking budget. Upstreams such as Anthropic and Alibaba
// reject one that is not below the output limit; 1,024 is Anthropic's minimum budget.
const fitReasoning = (reasoning: Record<string, unknown>, maxTokens: number | undefined) =>
+3 -3
View File
@@ -35,13 +35,13 @@ const RESPONSES_WEBSOCKET_ROTATE_AFTER_MS = 24 * 60 * 1000
const responsesRoute = Route.make({
compact: { endpoint: XAIResponses.compact },
id: "openai-responses",
id: "xai-responses",
provider: id,
providerMetadataKey: "xai",
protocol: XAIResponses.protocol,
endpoint: Endpoint.path("/responses", { baseURL }),
transport: OpenResponsesChannel.transport({
id: "openai-responses",
id: "xai-responses",
name: "xAI Responses",
rotateAfterMs: RESPONSES_WEBSOCKET_ROTATE_AFTER_MS,
// xAI continues a chain only from stored responses: with `store: false` (the route default) `previous_response_id`
@@ -53,7 +53,7 @@ const responsesRoute = Route.make({
})
const chatRoute = Route.make({
id: "openai-compatible-chat",
id: "xai-chat",
provider: id,
providerMetadataKey: "xai",
protocol: OpenAIChat.protocol,
+1 -1
View File
@@ -95,7 +95,7 @@ export const optional = (secret: Secret | undefined, source = "optional value")
export const config = (name: string) =>
credential(
Effect.gen(function* () {
const secret = yield* Config.option(Config.Redacted(name))
const secret = yield* Config.option(Config.redacted(name))
if (Option.isSome(secret) && Redacted.value(secret.value) !== "") return secret.value
return yield* Effect.fail(new MissingCredentialError(name, `${name} is not set`))
}),
+10 -14
View File
@@ -8,7 +8,7 @@ import {
HttpClientResponse,
} from "effect/unstable/http"
import { HttpContext, HttpRateLimitDetails, AIError, TransportError } from "../schema/index.js"
import { classifyProviderFailure } from "../provider-error.js"
import { classifyProviderFailure, providerErrorMessage } from "../provider-error.js"
import { Service, type HttpMiddleware, type Interface } from "./executor-service.js"
export { Service } from "./executor-service.js"
@@ -84,21 +84,17 @@ export const responseHttp = (response: HttpClientResponse.HttpClientResponse) =>
headers: headerDetails(response.headers),
})
const decodeProviderBody = Schema.decodeUnknownOption(
Schema.fromJsonString(
Schema.Struct({
message: Schema.optionalKey(Schema.String),
error: Schema.optionalKey(Schema.Struct({ message: Schema.optionalKey(Schema.String) })),
}),
),
)
const MAX_BODY_CHARS = 2000
// Without a recognized message, show the raw body so the provider's explanation is never dropped.
const providerMessage = (status: number, body: string | void) => {
const decoded = body === undefined ? undefined : Option.getOrUndefined(decodeProviderBody(body))
return (
[decoded?.error?.message, decoded?.message].find((message) => message?.trim()) ??
`Provider request failed with HTTP ${status}`
)
const fallback = `Provider request failed with HTTP ${status}`
const text = body?.trim() ?? ""
const message = providerErrorMessage(text)
if (message) return message
// Gateway and proxy HTML error pages are markup, not an explanation.
if (!text || /^<(?:!doctype|html)/i.test(text)) return fallback
return `${fallback}: ${text.length > MAX_BODY_CHARS ? `${text.slice(0, MAX_BODY_CHARS)}…` : text}`
}
const statusError = (response: HttpClientResponse.HttpClientResponse) =>
+26 -5
View File
@@ -5,12 +5,14 @@ import { Media } from "../media.js"
import type { AuthInput } from "./auth.js"
import {
AIError,
AuthenticationError,
ContentPolicyError,
HttpContext,
InvalidProviderOutputError,
InvalidRequestError,
ProviderID,
ProviderInternalError,
RateLimitError,
UnsupportedOperationError,
} from "../schema/index.js"
@@ -188,6 +190,16 @@ export const stream = <Request, Event, Frame, State>(
// Response helpers
// ---------------------------------------------------------------------------
/** Reasons a provider can report for a `failed` generation; anything it does not classify is `ProviderInternal`. */
const FAILURES = {
InvalidRequest: InvalidRequestError,
Authentication: AuthenticationError,
RateLimit: RateLimitError,
ProviderInternal: ProviderInternalError,
}
export type Failure = keyof typeof FAILURES
const context = (response: HttpClientResponse.HttpClientResponse) =>
new HttpContext({ url: response.request.url, status: response.status, headers: response.headers })
@@ -199,9 +211,10 @@ export const identity = (input: { readonly id: string; readonly name: string; re
/**
* Read a text body while retaining the original payload and HTTP context on every downstream error. `invalid` is a
* malformed provider document; `ended` is a generation that reached a terminal status without output (`failed` is
* provider-side, `cancelled`/`expired` mean the result will never exist); `pending` is a `result()` read before the
* generation finished, which is caller misuse; `contentPolicy` is a moderated result.
* malformed provider document; `ended` is a generation that reached a terminal status without output (`failed`
* carries the provider's classification, defaulting to `ProviderInternal`; `cancelled`/`expired` mean the result
* will never exist); `pending` is a `result()` read before the generation finished, which is caller misuse;
* `contentPolicy` is a moderated result.
*/
const text = Effect.fn("MediaProtocol.text")(function* (response: HttpClientResponse.HttpClientResponse) {
const http = context(response)
@@ -223,11 +236,15 @@ export const identity = (input: { readonly id: string; readonly name: string; re
http,
invalid: (message: string, cause?: unknown) =>
new AIError({ reason: new InvalidProviderOutputError({ route: input.id, message, body, http, cause }) }),
ended: (status: Exclude<Status, "queued" | "running" | "completed">, message: string) =>
ended: (
status: Exclude<Status, "queued" | "running" | "completed">,
message: string,
failure: Failure = "ProviderInternal",
) =>
new AIError({
reason:
status === "failed"
? new ProviderInternalError({ message, body, http })
? new FAILURES[failure]({ message, body, http })
: new InvalidRequestError({ message, body, http }),
}),
pending: (id: string) =>
@@ -303,6 +320,10 @@ export const status = <Table extends Record<string, Status>>(
return Effect.succeed(table[raw])
}
/** Map a provider error code through the protocol's table; missing or unmapped codes are `ProviderInternal`. */
export const failure = (table: Readonly<Record<string, Failure>>, code: string | number | undefined): Failure =>
code !== undefined && Object.hasOwn(table, code) ? table[code] : "ProviderInternal"
/** A `url` asset whose provider-declared retention window starts now. */
export const expiringUrl = (url: string, retention: Duration.Duration, options?: Parameters<typeof Media.url>[1]) =>
Clock.currentTimeMillis.pipe(
+34 -4
View File
@@ -1,4 +1,4 @@
import { Effect, Schema, Stream } from "effect"
import { Duration, Effect, Schedule, Schema, Stream } from "effect"
import { Headers, HttpClientRequest, type HttpClientResponse } from "effect/unstable/http"
import { Auth, type AuthInput } from "./auth.js"
import { Endpoint } from "./endpoint.js"
@@ -7,6 +7,7 @@ import { RequestExecutor } from "./executor.js"
import { MediaProtocol } from "./media-protocol.js"
import { Generation, isTerminal } from "../generation.js"
import type { Media } from "../media.js"
import { isRetryable } from "../provider-error.js"
import {
AIError,
AIErrorReason,
@@ -137,6 +138,32 @@ export const inline = <Request extends MediaRequest, Response>(
}
}
const READ_RETRY_MAX_DELAY = Duration.seconds(30)
/**
* Status and result reads retry transient failures; `start` and `cancel` never do. Gaps grow exponentially from 1s,
* jittered, up to 30s each, for at most 8 retries (about two minutes when every attempt fails), so a direct
* `Generation.result()` stays bounded; `await` and `events` also cut retries off at `poll.timeout`. A provider
* `retryAfterMs` raises the gap, still capped at 30s.
*/
const READ_RETRY = Schedule.max([
Schedule.min([Schedule.exponential("1 second"), Schedule.spaced(READ_RETRY_MAX_DELAY)]),
Schedule.recurs(8),
]).pipe(
Schedule.jittered,
Schedule.setInputType<AIError>(),
Schedule.modifyDelay(({ input, duration }) =>
Effect.succeed(
Duration.min(
input.reason._tag === "RateLimit" || input.reason._tag === "ProviderInternal"
? Duration.max(duration, Duration.millis(input.reason.retryAfterMs ?? 0))
: duration,
READ_RETRY_MAX_DELAY,
),
),
),
)
/**
* Compose a queued media protocol the same way, adding `start`/`resume` handles whose polls reuse the route's auth,
* deployment headers, and (for `start`) the request's `http` overlay. The token is decoded once at the boundary and
@@ -154,6 +181,8 @@ export const queued = <Request extends MediaRequest, Response, Token>(
const generationRoute = (token: Token, http: HttpOptions | undefined, execute: Execute) => {
const materialize = (asset: Media.Asset) =>
asset.materialize().pipe(Effect.provideService(RequestExecutorService, { execute }))
// Only the GET exchange retries: a decoded terminal failure (`output.ended`) can be a `ProviderInternal` too, and
// re-reading it would spin until the caller's deadline.
const poll = <A>(operation: {
readonly path: (token: Token) => string
readonly decode: (
@@ -161,9 +190,10 @@ export const queued = <Request extends MediaRequest, Response, Token>(
context: MediaProtocol.PollContext<Token>,
) => Effect.Effect<A, AIError>
}) =>
transport
.call("GET", operation.path(token), http, execute)
.pipe(Effect.flatMap((sent) => operation.decode(sent.response, { token, auth: sent.auth, materialize })))
transport.call("GET", operation.path(token), http, execute).pipe(
Effect.retry({ schedule: READ_RETRY, while: isRetryable }),
Effect.flatMap((sent) => operation.decode(sent.response, { token, auth: sent.auth, materialize })),
)
const status = poll(protocol.status)
const cancel = protocol.cancel
const send =
+4
View File
@@ -264,6 +264,10 @@ export type ToolError = Schema.Schema.Type<typeof ToolError>
export const FinishReasonDetails = Schema.Struct({
normalized: FinishReason,
raw: Schema.optional(Schema.String),
/** The provider's policy area for a content-filter finish, such as `cyber`. */
category: Schema.optional(Schema.String),
/** The provider's human-readable reason for a content-filter finish. */
explanation: Schema.optional(Schema.String),
}).annotate({ identifier: "LLM.FinishReasonDetails" })
export type FinishReasonDetails = Schema.Schema.Type<typeof FinishReasonDetails>
+16 -2
View File
@@ -6,10 +6,17 @@ const MISSING_TOOL_RESULT = "Tool result missing"
export function normalizeToolHistory(messages: ReadonlyArray<Message>) {
const normalized: Message[] = []
const pending = new Map<string, ToolCallPart>()
// System updates cannot sit between a tool call and its results, so they wait until every pending call is answered.
const held: Message[] = []
const releaseHeld = () => {
if (pending.size > 0) return
normalized.push(...held)
held.length = 0
}
const appendMissingResults = () => {
if (pending.size === 0) return
normalized.push(missingToolResults(pending.values()))
if (pending.size > 0) normalized.push(missingToolResults(pending.values()))
pending.clear()
releaseHeld()
}
for (const message of messages) {
@@ -18,6 +25,12 @@ export function normalizeToolHistory(messages: ReadonlyArray<Message>) {
if (message.role === "tool") {
const tool = normalizeToolMessage(message, pending)
if (tool) normalized.push(tool)
releaseHeld()
continue
}
if (message.role === "system" && pending.size > 0) {
held.push(message)
continue
}
@@ -27,6 +40,7 @@ export function normalizeToolHistory(messages: ReadonlyArray<Message>) {
if (part.type === "tool-call" && part.providerExecuted !== true) pending.set(part.id, part)
}
}
appendMissingResults()
return normalized.length === messages.length && normalized.every((message, index) => message === messages[index])
? messages
+2 -28
View File
@@ -6,7 +6,6 @@ import type {
ToolOutput as ToolOutputType,
} from "./schema/index.js"
import { ToolDefinition, ToolFailure, ToolOutput } from "./schema/index.js"
import { isRecord } from "./utils/record.js"
/**
* Schema constraint for tool parameters / success values: no decoding or
@@ -201,7 +200,7 @@ export function make(config: TypedToolConfig | DynamicToolConfig): AnyTool {
_definition: new ToolDefinition({
name: "",
description: config.description,
inputSchema: toInputJsonSchema(config.parameters),
inputSchema: toJsonSchema(config.parameters),
outputSchema: toJsonSchema(config.success),
}),
}
@@ -231,33 +230,8 @@ export const toDefinitions = (tools: Tools): ReadonlyArray<ToolDefinitionClass>
}),
)
const toInputJsonSchema = (schema: Schema.Top): JsonSchema.JsonSchema => {
// Effect represents Struct({}) as any non-null value; tool parameters must
// instead describe an object. Inline named empty inputs so providers such as
// Gemini can recognize a no-argument tool, while retaining schema annotations.
if (
schema.ast._tag !== "Objects" ||
schema.ast.propertySignatures.length !== 0 ||
schema.ast.indexSignatures.length !== 0 ||
schema.ast.encoding !== undefined ||
schema.ast.checks !== undefined
)
return toJsonSchema(schema)
const json = Schema.toJsonSchemaDocument(schema, {
onExcessProperty: "error",
referencePolicy: () => undefined,
}).schema
if (isRecord(json.not) && json.not.type === "null" && Object.keys(json.not).length === 1) {
const normalized: JsonSchema.JsonSchema = { type: "object", properties: {}, additionalProperties: false, ...json }
delete normalized.not
return normalized
}
return toJsonSchema(schema)
}
const toJsonSchema = (schema: Schema.Top): JsonSchema.JsonSchema => {
const document = Schema.toJsonSchemaDocument(schema, { onExcessProperty: "error" })
const document = Schema.toJsonSchemaDocument(schema)
if (Object.keys(document.definitions).length === 0) return document.schema
return { ...document.schema, $defs: document.definitions }
}
+1 -1
View File
@@ -103,7 +103,7 @@ export type TranscriptionRequestInput<Model extends TranscriptionModel = Transcr
// Response and events
// ---------------------------------------------------------------------------
/** Speaker labels are provider-native (`A`, `0`, `spk:0`, or a known speaker name). */
/** Speaker labels are provider-native (`A`, `0`, `spk:0`, `speaker_0`, or a known speaker name). */
export const TranscriptionSegment = Schema.Struct({
text: Schema.String,
startSeconds: Schema.Number,
+1 -1
View File
@@ -30,7 +30,7 @@ type LanguageModel = {
declare const auth: Auth.Definition
declare const optionalAuthModel: LanguageModelFactory<BaseOptions, "optional", LanguageModel>
declare const requiredAuthModel: LanguageModelFactory<BaseOptions, "required", LanguageModel>
const configApiKey = Config.Redacted("OPENAI_API_KEY")
const configApiKey = Config.redacted("OPENAI_API_KEY")
OpenAIChat.route.model({ id: "gpt-4.1-mini" })
+87 -1
View File
@@ -3,7 +3,18 @@ import { Effect } from "effect"
import { CacheHint, LLM, Message } from "../src/index.js"
import { Auth } from "../src/route.js"
import { compileRequest } from "../src/route/client.js"
import { AmazonBedrock, GoogleVertexMessages } from "../src/providers.js"
import {
Alibaba,
AmazonBedrock,
AnthropicCompatible,
CloudflareAIGateway,
DigitalOcean,
GoogleVertexMessages,
Meta,
MiniMax,
Moonshot,
ZAICodingPlan,
} from "../src/providers.js"
import * as AnthropicMessages from "../src/protocols/anthropic-messages.js"
import * as Gemini from "../src/protocols/gemini.js"
import * as OpenAIChat from "../src/protocols/openai-chat.js"
@@ -107,6 +118,81 @@ describe("applyCachePolicy", () => {
}),
)
it.effect("'auto' emits cache_control markers on DigitalOcean", () =>
Effect.gen(function* () {
const prepared = yield* compileRequest(
LLM.request({
model: DigitalOcean.configure({ apiKey: "test" }).model("anthropic-claude-fable-5.1"),
system: "You are concise.",
tools: [{ name: "lookup", description: "Look up a value", inputSchema: { type: "object", properties: {} } }],
prompt: "hi",
}),
)
expect(prepared.body).toMatchObject({
tools: [{ type: "function", function: { name: "lookup" }, cache_control: { type: "ephemeral" } }],
messages: [
{
role: "system",
content: [{ text: "You are concise.", cache_control: { type: "ephemeral" } }],
},
{
role: "user",
content: [{ text: "hi", cache_control: { type: "ephemeral" } }],
},
],
})
}),
)
it.effect("'auto' emits Anthropic cache markers on Anthropic-compatible routes", () =>
Effect.gen(function* () {
const prepared = yield* compileRequest(
LLM.request({
model: AnthropicCompatible.configure({ apiKey: "test", baseURL: "https://messages.example.test/v1" }).model(
"compatible",
),
system: "You are concise.",
prompt: "hi",
}),
)
expect(prepared.route).toBe("anthropic-compatible-messages")
expect(prepared.body).toMatchObject({
system: [{ type: "text", text: "You are concise.", cache_control: { type: "ephemeral" } }],
messages: [{ role: "user", content: [{ type: "text", text: "hi", cache_control: { type: "ephemeral" } }] }],
})
}),
)
const messagesModels = [
["alibaba-messages", Alibaba.configure({ region: "ap-southeast-1", apiKey: "test" }).messages("qwen3.8-max")],
[
"cloudflare-ai-gateway-messages",
CloudflareAIGateway.configure({ accountId: "test", gatewayId: "test", apiKey: "test" }).model(
"anthropic/claude-sonnet-4-6",
),
],
["meta-messages", Meta.configure({ apiKey: "test" }).messages("muse-spark-1.3")],
["minimax-messages", MiniMax.configure({ apiKey: "test" }).model("MiniMax-M3")],
["moonshot-messages", Moonshot.configure({ apiKey: "test" }).messages("kimi-k3")],
["zai-coding-messages", ZAICodingPlan.configure({ apiKey: "test" }).messages("glm-5.3")],
] as const
messagesModels.forEach(([route, model]) =>
it.effect(`'auto' emits cache markers on ${route}`, () =>
Effect.gen(function* () {
const prepared = yield* compileRequest(LLM.request({ model, system: "Sys", prompt: "hi" }))
expect(prepared.route).toBe(route)
expect(prepared.body).toMatchObject({
system: [{ type: "text", text: "Sys", cache_control: { type: "ephemeral" } }],
messages: [{ role: "user", content: [{ type: "text", text: "hi", cache_control: { type: "ephemeral" } }] }],
})
}),
),
)
it.effect("'auto' is a no-op on OpenAI (implicit caching protocol)", () =>
Effect.gen(function* () {
const prepared = yield* compileRequest(
+25 -6
View File
@@ -147,7 +147,7 @@ describe("Anthropic Messages effort updates", () => {
}),
)
it.effect("accepts a marker between a tool call and its result", () =>
it.effect("moves a marker between a tool call and its result after the result", () =>
Effect.gen(function* () {
const prepared = yield* compileRequest(
LLM.request({
@@ -166,8 +166,8 @@ describe("Anthropic Messages effort updates", () => {
expect(prepared.body.messages).toEqual([
{ role: "user", content: [{ type: "text", text: "Weather?" }] },
{ role: "assistant", content: [{ type: "tool_use", id: "call_1", name: "lookup", input: {} }] },
{ role: "system", content: [], output_config: { effort: "low" } },
{ role: "user", content: [{ type: "tool_result", tool_use_id: "call_1", content: '{"temp":72}' }] },
{ role: "system", content: [], output_config: { effort: "low" } },
])
}),
)
@@ -197,9 +197,15 @@ describe("Anthropic Messages effort updates", () => {
["anthropic/claude-opus-5", true],
["claude-fable-5-1", true],
["claude-mythos-5-1", true],
["claude-opus-5-5", true],
["claude-sonnet-5-5", true],
["anthropic/claude-sonnet-5-5", true],
["claude-sonnet-6", true],
["claude-haiku-6", true],
["claude-fable-5", false],
["claude-opus-4-8", false],
["claude-sonnet-5", false],
["claude-sonnet-5-20260801", false],
["kimi-k2.5", false],
] as const) {
it.effect(`${supported ? "lowers" : "strips"} markers for ${id}`, () =>
@@ -375,11 +381,24 @@ describe("OpenAI Responses effort updates", () => {
["openai/gpt-6-sol", true],
["gpt-6-luna", true],
["openai/gpt-6-luna", true],
["gpt-6-astra-2026-09-01", false],
["gpt-6-sol-pro", false],
["gpt-6-luna-pro", false],
["gpt-6-sol-fast", false],
["gpt-6", true],
["gpt-6.1-sol", true],
["openai/gpt-6.1-sol", true],
["GPT-6.1-SOL", true],
["gpt-6-astra-2026-09-01", true],
["gpt-6-sol-pro", true],
["gpt-6-luna-pro", true],
["gpt-6-sol-fast", true],
["gpt-7", true],
["openai/gpt-7.2-new-family", true],
["gpt-10.1", true],
["gpt-5", false],
["gpt-5.6-sol", false],
["gpt-5.10", false],
["not-gpt-6-sol", false],
["gpt-6foo", false],
["gpt-6.x-sol", false],
["future-model", false],
] as const) {
it.effect(`${supported ? "lowers" : "strips"} markers for ${id}`, () =>
Effect.gen(function* () {
+2 -1
View File
@@ -39,17 +39,18 @@ describe("experimental Evaluation", () => {
type: "choice",
choice: "billing",
probabilities: { billing: 0.9, technical: 0.1 },
confidence: 0.8,
})
expect(response.answers.urgency).toEqual({
type: "score",
score: 1.2,
probabilities: { "0": 0, "1": 0.8, "2": 0.2 },
confidence: 0.6,
})
expect(response.answers.refund).toEqual({ type: "boolean", probability: 0.97 })
expect(response.usage?.totalTokens).toBe(36)
expect(response.providerMetadata).toEqual({
typesafe: {
confidence: { department: 0.8, urgency: 0.6 },
legend: { urgency: { "0": "Can wait", "1": "Needs attention", "2": "Blocking" } },
},
})
+2
View File
@@ -26,8 +26,10 @@ const request = Evaluation.request({
const result = EvaluationClient.evaluate(request)
type Result = Success<typeof result>
type Choice = Assert<Equal<Result["answers"]["topic"]["choice"], "billing" | "support">>
type Confidence = Assert<Equal<Result["answers"]["topic"]["confidence"], number | undefined>>
type ClientRequirements = Assert<Equal<Requirements<typeof result>, Service>>
void (true satisfies Choice)
void (true satisfies Confidence)
void (true satisfies ClientRequirements)
Effect.gen(function* () {
+49 -3
View File
@@ -273,10 +273,56 @@ describe("RequestExecutor", () => {
expectAIError(error)
expect(error.reason).toMatchObject({ _tag: "InvalidRequest" })
expect("classification" in error.reason ? error.reason.classification : undefined).toBeUndefined()
expect(error.message).toBe("Provider request failed with HTTP 400")
expect(error.message).toBe("Provider request failed with HTTP 400: invalid parameter")
}).pipe(Effect.provide(fixedResponse("invalid parameter", { status: 400 }))),
)
it.effect("shows unrecognized provider error bodies", () =>
Effect.gen(function* () {
const executor = yield* RequestExecutor.Service
const error = yield* executor.execute(request).pipe(Effect.flip)
expect(error.message).toBe(
'Provider request failed with HTTP 422: {"object":"error","message":{"detail":[{"msg":"Input should be less than or equal to 1.5"}]}}',
)
}).pipe(
Effect.provide(
fixedResponse('{"object":"error","message":{"detail":[{"msg":"Input should be less than or equal to 1.5"}]}}', {
status: 422,
}),
),
),
)
it.effect("shows messages from common provider error layouts", () =>
Effect.gen(function* () {
const executor = yield* RequestExecutor.Service
const error = yield* executor.execute(request).pipe(Effect.flip)
expect(error.message).toBe("Invalid API Key")
}).pipe(Effect.provide(fixedResponse('{"detail":"Invalid API Key"}', { status: 401 }))),
)
it.effect("truncates long unrecognized provider error bodies", () =>
Effect.gen(function* () {
const executor = yield* RequestExecutor.Service
const error = yield* executor.execute(request).pipe(Effect.flip)
expect(error.message).toBe(`Provider request failed with HTTP 400: ${"x".repeat(2000)}…`)
expect(error.reason.body).toHaveLength(5000)
}).pipe(Effect.provide(fixedResponse("x".repeat(5000), { status: 400 }))),
)
it.effect("does not show HTML error pages", () =>
Effect.gen(function* () {
const executor = yield* RequestExecutor.Service
const error = yield* executor.execute(request).pipe(Effect.flip)
expect(error.message).toBe("Provider request failed with HTTP 502")
expect(error.reason.body).toContain("Bad Gateway")
}).pipe(Effect.provide(fixedResponse("<!DOCTYPE html><html><body>Bad Gateway</body></html>", { status: 502 }))),
)
it.effect("preserves structured provider messages from large error bodies", () =>
Effect.gen(function* () {
const executor = yield* RequestExecutor.Service
@@ -299,7 +345,7 @@ describe("RequestExecutor", () => {
),
)
it.effect("falls back when structured provider messages are empty", () =>
it.effect("shows the body when structured provider messages are empty", () =>
Effect.gen(function* () {
const executor = yield* RequestExecutor.Service
const error = yield* executor.execute(request).pipe(Effect.flip)
@@ -308,7 +354,7 @@ describe("RequestExecutor", () => {
expect(error.reason).toMatchObject({
_tag: "InvalidRequest",
})
expect(error.message).toBe("Provider request failed with HTTP 400")
expect(error.message).toBe('Provider request failed with HTTP 400: {"error":{"message":" "}}')
}).pipe(Effect.provide(fixedResponse('{"error":{"message":" "}}', { status: 400 }))),
)
+7 -2
View File
@@ -154,8 +154,8 @@ describe("public exports", () => {
expect(XAI.model).toBeFunction()
expect(XAI.provider.responses).toBe(XAI.responses)
expect(XAI.provider.chat).toBe(XAI.chat)
expect(XAI.configure({ apiKey: "fixture" }).responses("grok-4.3").route.id).toBe("openai-responses")
expect(XAI.configure({ apiKey: "fixture" }).chat("grok-4.3").route.id).toBe("openai-compatible-chat")
expect(XAI.configure({ apiKey: "fixture" }).responses("grok-4.3").route.id).toBe("xai-responses")
expect(XAI.configure({ apiKey: "fixture" }).chat("grok-4.3").route.id).toBe("xai-chat")
expect(OpenAI.configure({ apiKey: "fixture" }).image("gpt-image-2").route.id).toBe("openai-images")
expect(OpenAI.provider.image).toBe(OpenAI.image)
expect(Google.configure({ apiKey: "fixture" }).image("imagen-4.0-generate-001").route.id).toBe("google-images")
@@ -197,6 +197,11 @@ describe("public exports", () => {
expect(Google.configure({ apiKey: "fixture" }).transcription("gemini-3.5-transcribe").route.kind).toBe("stream")
expect(Deepgram.configure({ apiKey: "fixture" }).transcription("nova-3").route.kind).toBe("inline")
expect(AssemblyAI.configure({ apiKey: "fixture" }).transcription("universal-3-5-pro").route.kind).toBe("queued")
expect(ElevenLabs.configure({ apiKey: "fixture" }).transcription("scribe_v2").route.id).toBe(
"elevenlabs-transcription",
)
expect(ElevenLabs.configure({ apiKey: "fixture" }).transcription("scribe_v2").route.kind).toBe("inline")
expect(ElevenLabs.provider.transcription).toBe(ElevenLabs.transcription)
})
test("protocol barrels expose supported low-level routes", () => {
@@ -10,7 +10,7 @@
"usage"
],
"name": "alibaba-messages/qwen-3-7-plus-streams-thinking-disabled",
"recordedAt": "2026-09-08T03:10:57.819Z"
"recordedAt": "2026-09-29T05:26:24.450Z"
},
"interactions": [
{
@@ -21,14 +21,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.7-plus\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"stream\":true,\"max_tokens\":4096,\"thinking\":{\"type\":\"disabled\"}}"
"body": "{\"model\":\"qwen3.7-plus\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"stream\":true,\"max_tokens\":4096,\"thinking\":{\"type\":\"disabled\"}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.7-plus\",\"id\":\"msg_c4d58b4f-a61d-9d0c-a9e4-cb45d34b1120\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"7887\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"output_tokens\":5,\"cache_creation_input_tokens\":0,\"input_tokens\":32,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.7-plus\",\"id\":\"msg_39067759-5f01-9b3a-b2c1-09111797f7b5\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"788\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"7\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"cache_creation\":{\"ephemeral_5m_input_tokens\":0},\"output_tokens\":5,\"cache_creation_input_tokens\":0,\"input_tokens\":32,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
}
}
]
@@ -10,7 +10,7 @@
"usage"
],
"name": "alibaba-messages/qwen-3-7-plus-streams-thinking-enabled",
"recordedAt": "2026-09-08T03:11:03.999Z"
"recordedAt": "2026-09-29T05:26:35.745Z"
},
"interactions": [
{
@@ -21,14 +21,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.7-plus\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"stream\":true,\"max_tokens\":4096,\"thinking\":{\"type\":\"enabled\",\"budget_tokens\":1024}}"
"body": "{\"model\":\"qwen3.7-plus\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"stream\":true,\"max_tokens\":4096,\"thinking\":{\"type\":\"enabled\",\"budget_tokens\":1024}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.7-plus\",\"id\":\"msg_9243d346-7958-94f1-b81a-72a33c12b5e2\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"Thinking\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" Process:\\n\\n1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Identify\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" the core request\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\": Calculate 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73 *\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 219\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" and return *only\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"* the final\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" integer.\\n2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Perform the\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" multiplication:\\n\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" * \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173 *\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 219\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"\\n * \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" * 20\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0 = 3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"4600\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"\\n \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" * 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73 * \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"10 = \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"1730\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"\\n * \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" * 9 =\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 155\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"7\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thLine truncated
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.7-plus\",\"id\":\"msg_1d2b3b1a-cb68-970b-89cc-5bc4074b845a\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"Thinking\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" Process:\\n\\n1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". **Ident\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"ify the core question\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\":** The user wants\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" to know the product\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" of \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173 and\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 219\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\".\\n2.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" **Identify\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" the constraint:** Reply\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" with *only*\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" the final\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" integer.\\n3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". **Perform\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" the calculation:**\\n\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" * \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173 *\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 219\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"\\n * \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" * 20\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0 = 3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"4600\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"\\n \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" * 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73 * \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"10 = \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"1730\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndaLine truncated
}
}
]
@@ -9,7 +9,7 @@
"image"
],
"name": "alibaba-messages/qwen-3-8-flash-reads-image-bytes",
"recordedAt": "2026-09-08T03:11:05.331Z"
"recordedAt": "2026-09-29T05:26:39.160Z"
},
"interactions": [
{
@@ -20,14 +20,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.8-flash\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"Read the three words in this image. Reply with only the words in order.\"},{\"type\":\"image\",\"source\":{\"type\":\"base64\",\"media_type\":\"image/png\",\"data\":\"iVBORw0KGgoAAAANSUhEUgAAAnYAAACKCAYAAAAnmweyAAACKWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iCiAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgZXhpZjpQaXhlbFhEaW1lbnNpb249IjYzMCIKICAgZXhpZjpVc2VyQ29tbWVudD0iU2NyZWVuc2hvdCIKICAgZXhpZjpQaXhlbFlEaW1lbnNpb249IjEzOCIKICAgdGlmZjpZUmVzb2x1dGlvbj0iMTQ0LzEiCiAgIHRpZmY6WFJlc29sdXRpb249IjE0NC8xIgogICB0aWZmOlJlc29sdXRpb25Vbml0PSIyIi8+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo8P3hwYWNrZXQgZW5kPSJyIj8+at0SpgAACrhpQ0NQSUNDIFByb2ZpbGUAAEiJlZcHUFNZF8fvey+dhJYQASmh994CSAmhBVCQDjZCEiAQQkxBwa4sruBaUBHBsqKrIgo2qg0RxbYo9r4gi4iyLhZsqHwPGMLufvN933xn5s75zXnn/u+5d959cx4AFFOuRCKC1QHIFsul0SEBjMSkZAb+JcACTUACnoDK5ckkrKioCIDahP+7fbgLoFF/y25U69+f/1fT4AtkPACgKJRT+TJeNsonAIABTyKVA4CgDEwWyCWjfB9lmhQtEOWBUU4fY8yoDi11nGljObHRbJQtASCQuVxpOgBkVzTOyOWlozrkWJQdxXyhGOUClH2zs3P4KLehbInmSFAe1Wem/kUn/W+aqUpNLjddyeN7GTNCoFAmEXHz/s/j+N+WLVJMrGGBDnKGNDQa9Xrouf2elROuZHHqjMgJFvLH8sc4QxEaN8E8GTt5gmWiGM4E87mB4Uod0YyICU4TBitzhHJO7AQLZEExEyzNiVaumyZlsyaYK52sQZEVp4xnCDhK/fyM2IQJzhXGz1DWlhUTPpnDVsalimjlXgTikIDJdYOV55At+8vehRzlXHlGbKjyHLiT9QvErElNWaKyNr4gMGgyJ06ZL5EHKNeSiKKU+QJRiDIuy41RzpWjL+fk3CjlGWZyw6ImGMQAOVAAPhCCHMAAgaiXAQkQAS7IkwsWykc3xM6R5EmF6RlyBgu9dQIGR8yzt2U4Ozq7AzB6h8dfkXf0sbsJ0a9MxlZVAeDTNDIycnIyFnYDgKMpAJDqJmOWcwBQ7wPg0imeQpo7Hhu7a1j0y6AGaEAHGAATYAnsgDNwB97AHwSBMBAJYkESmAt4IANkAylYABaDFaAQFIMNYAsoB7vAHnAAHAbHQAM4Bc6Bi+AquAHugEegC/SCV2AQfADDEAThIQpEhXQgQ8gMsoGcISbkCwVBEVA0lASlQOmQGFJAi6FVUDFUApVDu6Eq6CjUBJ2DLkOd0AOoG+qH3kJfYAQmwzRYHzaHHWAmzILD4Vh4DpwOz4fz4QJ4HVwGV8KH4Hr4HHwVvgN3wa/gIQQgKggdMULsECbCRiKRZCQNkSJLkSKkFKlEapBmpB25hXQhA8hnDA5DxTAwdhhvTCgmDsPDzMcsxazFlGMOYOoxbZhbmG7MIOY7loLVw9pgvbAcbCI2HbsAW4gtxe7D1mEvYO9ge7EfcDgcHWeB88CF4pJwmbhFuLW4HbhaXAuuE9eDG8Lj8Tp4G7wPPhLPxcvxhfht+EP4s/ib+F78J4IKwZDgTAgmJBPEhJWEUsJBwhnCTUIfYZioTjQjehEjiXxiHnE9cS+xmXid2EscJmmQLEg+pFhSJmkFqYxUQ7pAekx6p6KiYqziqTJTRaiyXKVM5YjKJZVulc9kTbI1mU2eTVaQ15H3k1vID8jvKBSKOcWfkkyRU9ZRqijnKU8pn1SpqvaqHFW+6jLVCtV61Zuqr9WIamZqLLW5avlqpWrH1a6rDagT1c3V2epc9aXqFepN6vfUhzSoGk4akRrZGms1Dmpc1nihidc01wzS5GsWaO7RPK/ZQ0WoJlQ2lUddRd1LvUDtpeFoFjQOLZNWTDtM66ANamlquWrFay3UqtA6rdVFR+jmdA5dRF9PP0a/S/8yRX8Ka4pgypopNVNuTvmoPVXbX1ugXaRdq31H+4sOQydIJ0tno06DzhNdjK617kzdBbo7dS/oDkylTfWeyptaNPXY1Id6sJ61XrTeIr09etf0hvQN9EP0Jfrb9M/rDxjQDfwNMg02G5wx6DekGvoaCg03G541fMnQYrAYIkYZo40xaKRnFGqkMNpt1GE0bGxhHGe80rjW+IkJyYRpkmay2aTVZNDU0HS66WLTatOHZkQzplmG2VazdrOP5hbmCearzRvMX1hoW3As8i2qLR5bUiz9LOdbVlretsJZMa2yrHZY3bCGrd2sM6wrrK/bwDbuNkKbHTadtlhbT1uxbaXtPTuyHcsu167artuebh9hv9K+wf61g6lDssNGh3aH745ujiLHvY6PnDSdwpxWOjU7vXW2duY5VzjfdqG4BLssc2l0eeNq4ypw3el6343qNt1ttVur2zd3D3epe417v4epR4rHdo97TBozirmWeckT6xnguczzlOdnL3cvudcxrz+97byzvA96v5hmMU0wbe+0Hh9jH67Pbp8uX4Zviu/Pvl1+Rn5cv0q/Z/4m/nz/ff59LCtWJusQ63WAY4A0oC7gI9uLvYTdEogEhgQWBXYEaQbFBZUHPQ02Dk4Prg4eDHELWRTSEooNDQ/dGHqPo8/hcao4g2EeYUvC2sLJ4THh5eHPIqwjpBHN0+HpYdM3TX88w2yGeEZDJIjkRG6KfBJlETU/6uRM3MyomRUzn0c7RS+Obo+hxsyLORjzITYgdn3sozjLOEVca7xa/Oz4qviPCYEJJQldiQ6JSxKvJukmCZMak/HJ8cn7kodmBc3aMqt3ttvswtl351jMWTjn8lzduaK5p+epzePOO56CTUlIOZjylRvJreQOpXJSt6cO8ti8rbxXfH/+Zn6/wEdQIuhL80krSXuR7pO+Kb0/wy+jNGNAyBaWC99khmbuyvyYFZm1P2tElCCqzSZkp2Q3iTXFWeK2HIOchTmdEhtJoaRrvtf8LfMHpeHSfTJINkfWKKehzdI1haXiB0V3rm9uRe6nBfELji/UWCheeC3POm9NXl9+cP4vizCLeItaFxstXrG4ewlrye6l0NLUpa3LTJYVLOtdHrL8wArSiqwVv650XFmy8v2qhFXNBfoFywt6fgj5obpQtVBaeG+19+pdP2J+FP7YscZlzbY134v4RVeKHYtLi7+u5a298pPTT2U/jaxLW9ex3n39zg24DeINdzf6bTxQolGSX9Kzafqm+s2MzUWb32+Zt+VyqWvprq2krYqtXWURZY3bTLdt2Pa1PKP8TkVARe12ve1rtn/cwd9xc6f/zppd+ruKd335Wfjz/d0hu+srzStL9+D25O55vjd+b/svzF+q9unuK973bb94f9eB6ANtVR5VVQf1Dq6vhqsV1f2HZh+6cTjwcGONXc3uWnpt8RFwRHHk5dGUo3ePhR9rPc48XnPC7MT2OmpdUT1Un1c/2JDR0NWY1NjZFNbU2uzdXHfS/uT+U0anKk5rnV5/hnSm4MzI2fyzQy2SloFz6ed6Wue1PjqfeP5228y2jgvhFy5dDL54vp3VfvaSz6VTl70uN11hXmm46n61/prbtbpf3X6t63DvqL/ucb3xhueN5s5pnWdu+t08dyvw1sXbnNtX78y403k37u79e7Pvdd3n33/xQPTgzcPch8OPlj/GPi56ov6k9Kne08rfrH6r7XLvOt0d2H3tWcyzRz28nle/y37/2lvwnPK8tM+wr+qF84tT/cH9N17Oetn7SvJqeKDwD40/tr+2fH3iT/8/rw0mDva+kb4Zebv2nc67/e9d37cORQ09/ZD9Yfhj0SedTwc+Mz+3f0n40je84Cv+a9k3q2/N38O/Px7JHhmRcKXcsVYAQQeclgbA2/0AUJIAoKI9BGnWeI89ZtD4f8EYgf/E4334mKGdSw3qRtsjdgsAR9BhvhwANX8ARlujWH8Au7gox0Q/PNa7jxoO/Yup8UK0Vjk9ta0C/7Txvv4vdf/TA6Xq3/y/AOOhDyne6KAWAAAAimVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kABAAAAAEAAABOAAAAAAAAAJAAAAABAAAAkAAAAAEAA5KGAAcAAAASAAAAeKACAAQAAAABAAACdqADAAQAAAABAAAAigAAAABBU0NJSQAAAFNjAAAAAAAAAADxh4F4AAAAHGlET1QAAAACAAAAAAAAAEUAAAAoAAAARQLine truncated
"body": "{\"model\":\"qwen3.8-flash\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"Read the three words in this image. Reply with only the words in order.\",\"cache_control\":{\"type\":\"ephemeral\"}},{\"type\":\"image\",\"source\":{\"type\":\"base64\",\"media_type\":\"image/png\",\"data\":\"iVBORw0KGgoAAAANSUhEUgAAAnYAAACKCAYAAAAnmweyAAACKWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iCiAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgZXhpZjpQaXhlbFhEaW1lbnNpb249IjYzMCIKICAgZXhpZjpVc2VyQ29tbWVudD0iU2NyZWVuc2hvdCIKICAgZXhpZjpQaXhlbFlEaW1lbnNpb249IjEzOCIKICAgdGlmZjpZUmVzb2x1dGlvbj0iMTQ0LzEiCiAgIHRpZmY6WFJlc29sdXRpb249IjE0NC8xIgogICB0aWZmOlJlc29sdXRpb25Vbml0PSIyIi8+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo8P3hwYWNrZXQgZW5kPSJyIj8+at0SpgAACrhpQ0NQSUNDIFByb2ZpbGUAAEiJlZcHUFNZF8fvey+dhJYQASmh994CSAmhBVCQDjZCEiAQQkxBwa4sruBaUBHBsqKrIgo2qg0RxbYo9r4gi4iyLhZsqHwPGMLufvN933xn5s75zXnn/u+5d959cx4AFFOuRCKC1QHIFsul0SEBjMSkZAb+JcACTUACnoDK5ckkrKioCIDahP+7fbgLoFF/y25U69+f/1fT4AtkPACgKJRT+TJeNsonAIABTyKVA4CgDEwWyCWjfB9lmhQtEOWBUU4fY8yoDi11nGljObHRbJQtASCQuVxpOgBkVzTOyOWlozrkWJQdxXyhGOUClH2zs3P4KLehbInmSFAe1Wem/kUn/W+aqUpNLjddyeN7GTNCoFAmEXHz/s/j+N+WLVJMrGGBDnKGNDQa9Xrouf2elROuZHHqjMgJFvLH8sc4QxEaN8E8GTt5gmWiGM4E87mB4Uod0YyICU4TBitzhHJO7AQLZEExEyzNiVaumyZlsyaYK52sQZEVp4xnCDhK/fyM2IQJzhXGz1DWlhUTPpnDVsalimjlXgTikIDJdYOV55At+8vehRzlXHlGbKjyHLiT9QvErElNWaKyNr4gMGgyJ06ZL5EHKNeSiKKU+QJRiDIuy41RzpWjL+fk3CjlGWZyw6ImGMQAOVAAPhCCHMAAgaiXAQkQAS7IkwsWykc3xM6R5EmF6RlyBgu9dQIGR8yzt2U4Ozq7AzB6h8dfkXf0sbsJ0a9MxlZVAeDTNDIycnIyFnYDgKMpAJDqJmOWcwBQ7wPg0imeQpo7Hhu7a1j0y6AGaEAHGAATYAnsgDNwB97AHwSBMBAJYkESmAt4IANkAylYABaDFaAQFIMNYAsoB7vAHnAAHAbHQAM4Bc6Bi+AquAHugEegC/SCV2AQfADDEAThIQpEhXQgQ8gMsoGcISbkCwVBEVA0lASlQOmQGFJAi6FVUDFUApVDu6Eq6CjUBJ2DLkOd0AOoG+qH3kJfYAQmwzRYHzaHHWAmzILD4Vh4DpwOz4fz4QJ4HVwGV8KH4Hr4HHwVvgN3wa/gIQQgKggdMULsECbCRiKRZCQNkSJLkSKkFKlEapBmpB25hXQhA8hnDA5DxTAwdhhvTCgmDsPDzMcsxazFlGMOYOoxbZhbmG7MIOY7loLVw9pgvbAcbCI2HbsAW4gtxe7D1mEvYO9ge7EfcDgcHWeB88CF4pJwmbhFuLW4HbhaXAuuE9eDG8Lj8Tp4G7wPPhLPxcvxhfht+EP4s/ib+F78J4IKwZDgTAgmJBPEhJWEUsJBwhnCTUIfYZioTjQjehEjiXxiHnE9cS+xmXid2EscJmmQLEg+pFhSJmkFqYxUQ7pAekx6p6KiYqziqTJTRaiyXKVM5YjKJZVulc9kTbI1mU2eTVaQ15H3k1vID8jvKBSKOcWfkkyRU9ZRqijnKU8pn1SpqvaqHFW+6jLVCtV61Zuqr9WIamZqLLW5avlqpWrH1a6rDagT1c3V2epc9aXqFepN6vfUhzSoGk4akRrZGms1Dmpc1nihidc01wzS5GsWaO7RPK/ZQ0WoJlQ2lUddRd1LvUDtpeFoFjQOLZNWTDtM66ANamlquWrFay3UqtA6rdVFR+jmdA5dRF9PP0a/S/8yRX8Ka4pgypopNVNuTvmoPVXbX1ugXaRdq31H+4sOQydIJ0tno06DzhNdjK617kzdBbo7dS/oDkylTfWeyptaNPXY1Id6sJ61XrTeIr09etf0hvQN9EP0Jfrb9M/rDxjQDfwNMg02G5wx6DekGvoaCg03G541fMnQYrAYIkYZo40xaKRnFGqkMNpt1GE0bGxhHGe80rjW+IkJyYRpkmay2aTVZNDU0HS66WLTatOHZkQzplmG2VazdrOP5hbmCearzRvMX1hoW3As8i2qLR5bUiz9LOdbVlretsJZMa2yrHZY3bCGrd2sM6wrrK/bwDbuNkKbHTadtlhbT1uxbaXtPTuyHcsu167artuebh9hv9K+wf61g6lDssNGh3aH745ujiLHvY6PnDSdwpxWOjU7vXW2duY5VzjfdqG4BLssc2l0eeNq4ypw3el6343qNt1ttVur2zd3D3epe417v4epR4rHdo97TBozirmWeckT6xnguczzlOdnL3cvudcxrz+97byzvA96v5hmMU0wbe+0Hh9jH67Pbp8uX4Zviu/Pvl1+Rn5cv0q/Z/4m/nz/ff59LCtWJusQ63WAY4A0oC7gI9uLvYTdEogEhgQWBXYEaQbFBZUHPQ02Dk4Prg4eDHELWRTSEooNDQ/dGHqPo8/hcao4g2EeYUvC2sLJ4THh5eHPIqwjpBHN0+HpYdM3TX88w2yGeEZDJIjkRG6KfBJlETU/6uRM3MyomRUzn0c7RS+Obo+hxsyLORjzITYgdn3sozjLOEVca7xa/Oz4qviPCYEJJQldiQ6JSxKvJukmCZMak/HJ8cn7kodmBc3aMqt3ttvswtl351jMWTjn8lzduaK5p+epzePOO56CTUlIOZjylRvJreQOpXJSt6cO8ti8rbxXfH/+Zn6/wEdQIuhL80krSXuR7pO+Kb0/wy+jNGNAyBaWC99khmbuyvyYFZm1P2tElCCqzSZkp2Q3iTXFWeK2HIOchTmdEhtJoaRrvtf8LfMHpeHSfTJINkfWKKehzdI1haXiB0V3rm9uRe6nBfELji/UWCheeC3POm9NXl9+cP4vizCLeItaFxstXrG4ewlrye6l0NLUpa3LTJYVLOtdHrL8wArSiqwVv650XFmy8v2qhFXNBfoFywt6fgj5obpQtVBaeG+19+pdP2J+FP7YscZlzbY134v4RVeKHYtLi7+u5a298pPTT2U/jaxLW9ex3n39zg24DeINdzf6bTxQolGSX9Kzafqm+s2MzUWb32+Zt+VyqWvprq2krYqtXWURZY3bTLdt2Pa1PKP8TkVARe12ve1rtn/cwd9xc6f/zppd+ruKd335Wfjz/d0hu+srzStL9+D25O55vjd+b/svzF+q9unuK973bb94f9eB6ANtVR5VVQf1Dq6vhqsV1f2HZh+6cTjwcGONXc3uWnpt8RFwRHHk5dGUo3ePhR9rPc48XnPC7MT2OmpdUT1Un1c/2JDR0NWY1NjZFNbU2uzdXHfS/uT+U0anKk5rnV5/hnSm4MzI2fyzQy2SloFz6ed6Wue1PjqfeP5228y2jgvhFy5dDL54vp3VfvaSz6VTl70uN11hXmm46n61/prbtbpf3X6t63DvqL/ucb3xhueN5s5pnWdu+t08dyvw1sXbnNtX78y403k37u79e7Pvdd3n33/xQPTgzcPch8OPlj/GPi56ov6k9Kne08rfrH6r7XLvOt0d2H3tWcyzRz28nle/y37/2lvwnPK8tM+wr+qF84tT/cH9N17Oetn7SvJqeKDwD40/tr+2fH3iT/8/rw0mDva+kb4Zebv2nc67/e9d37cORQ09/ZD9Yfhj0SedTwc+Mz+3f0n40je84Cv+a9k3q2/N38O/Px7JHhmRcKXcsVYAQQeclgbA2/0AUJIAoKI9BGnWeI89ZtD4f8EYgf/E4334mKGdSw3qRtsjdgsAR9BhvhwANX8ARlujWH8Au7gox0Q/PNa7jxoO/Yup8UK0Vjk9ta0C/7Txvv4vdf/TA6Xq3/y/AOOhDyne6KAWAAAAimVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kABAAAAAEAAABOAAAAAAAAAJAAAAABAAAAkAAAAAEAA5KGAAcAAAASAAAAeKACAAQAAAABAAACdqADAAQAAAABAAAAigAAAABBU0NJSQAAAFNjAAAAAAAAAADLine truncated
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-flash\",\"id\":\"msg_84fa8c1d-57b1-9645-be64-fa27c790cdff\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":16,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"j\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"iggling restroom prison\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"output_tokens\":6,\"cache_creation_input_tokens\":0,\"input_tokens\":110,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-flash\",\"id\":\"msg_64a9e119-56aa-9556-b522-a030e231d980\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":16,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"j\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"iggling restroom prison\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"output_tokens\":6,\"cache_creation_input_tokens\":0,\"input_tokens\":110,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
}
}
]
@@ -9,7 +9,7 @@
"structured-output"
],
"name": "alibaba-messages/qwen-3-8-max-follows-a-json-schema",
"recordedAt": "2026-09-08T03:11:30.530Z"
"recordedAt": "2026-09-29T05:26:41.466Z"
},
"interactions": [
{
@@ -20,14 +20,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"Return a JSON object with one key \\\"city\\\" set to the capital city of France.\"}]}],\"stream\":true,\"max_tokens\":1024,\"thinking\":{\"type\":\"disabled\"},\"output_config\":{\"format\":{\"type\":\"json_schema\",\"schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"],\"additionalProperties\":false}}}}"
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"Return a JSON object with one key \\\"city\\\" set to the capital city of France.\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"stream\":true,\"max_tokens\":1024,\"thinking\":{\"type\":\"disabled\"},\"output_config\":{\"format\":{\"type\":\"json_schema\",\"schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"],\"additionalProperties\":false}}}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_16e067c1-984b-94d3-9abb-11792d794271\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":18,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"{\\\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"city\\\":\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\" \\\"Paris\\\"}\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"output_tokens\":6,\"cache_creation_input_tokens\":0,\"input_tokens\":32,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_61ee9b9d-a224-9b69-98f7-9f9ea3937b41\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":18,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"{\\\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"city\\\":\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\" \\\"Paris\\\"}\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"cache_creation\":{\"ephemeral_5m_input_tokens\":0},\"output_tokens\":6,\"cache_creation_input_tokens\":0,\"input_tokens\":32,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
}
}
]
@@ -10,7 +10,7 @@
"tool-choice"
],
"name": "alibaba-messages/qwen-3-8-max-obeys-named-tool-choice",
"recordedAt": "2026-09-08T03:11:06.590Z"
"recordedAt": "2026-09-29T05:26:40.212Z"
},
"interactions": [
{
@@ -21,14 +21,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"Find the current weather in Paris.\"}]}],\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get weather in a city\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"]}}],\"tool_choice\":{\"type\":\"tool\",\"name\":\"get_weather\"},\"stream\":true,\"max_tokens\":4096,\"thinking\":{\"type\":\"disabled\"}}"
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"Find the current weather in Paris.\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get weather in a city\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"]},\"cache_control\":{\"type\":\"ephemeral\"}}],\"tool_choice\":{\"type\":\"tool\",\"name\":\"get_weather\"},\"stream\":true,\"max_tokens\":4096,\"thinking\":{\"type\":\"disabled\"}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_0e8f1abf-f2bc-9a86-a6a7-14804ac17eac\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":45,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"name\":\"get_weather\",\"input\":{},\"id\":\"toolu_cf9cab33261f4709ae096d8a\",\"type\":\"tool_use\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"{\\\"city\\\": \\\"Paris\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"\\\"\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"}\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"output_tokens\":19,\"cache_creation_input_tokens\":0,\"input_tokens\":288,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_dab3e1c5-e75e-978d-902e-1b0a82918cff\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":45,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"name\":\"get_weather\",\"input\":{},\"id\":\"toolu_9a1c3c06a04744cc97df33a2\",\"type\":\"tool_use\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"{\\\"city\\\": \\\"Paris\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"\\\"\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"}\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"cache_creation\":{\"ephemeral_5m_input_tokens\":0},\"output_tokens\":19,\"cache_creation_input_tokens\":0,\"input_tokens\":288,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
}
}
]
@@ -12,7 +12,7 @@
"continuation"
],
"name": "alibaba-messages/qwen-3-8-max-replays-reasoning-through-a-tool-loop-and-follow-up",
"recordedAt": "2026-09-08T03:10:15.259Z"
"recordedAt": "2026-09-29T05:27:12.635Z"
},
"interactions": [
{
@@ -23,14 +23,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"We have a budget of 38000 dollars for 219 trips costing 173 dollars each. Calculate whether that is affordable. If it is, use get_weather to look up the current weather in Paris. After receiving the result, report the weather in one short sentence.\"}]}],\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get the current weather in a city\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"],\"additionalProperties\":false}}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"medium\"}}"
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"We have a budget of 38000 dollars for 219 trips costing 173 dollars each. Calculate whether that is affordable. If it is, use get_weather to look up the current weather in Paris. After receiving the result, report the weather in one short sentence.\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get the current weather in a city\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"],\"additionalProperties\":false},\"cache_control\":{\"type\":\"ephemeral\"}}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"medium\"}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_0f315bca-1ce8-94cb-bd3a-acb325ff2ee5\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":107,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"I\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" need\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" to investigate\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" this further. Let\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" me check the details\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\".\\n\\n\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"219 ×\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" = 37\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\",887\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Budget is \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"38,\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"000.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" Since 37\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\",\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"887 ≤\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 38,\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"000,\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" it can be covered\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Call get_weather\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" for\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" Paris.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"signature_delta\",\"signature\":\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"name\":\"get_weather\",\"input\":{},\"id\":\"toolu_5d1ba8ca72bd49889ca838f2\",\"type\":\"tool_use\"},\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"{\\\"city\\\": \\\"Paris\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"\\\"\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"}\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":1}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"tool_use\"},\"type\":\"message_delta\",\"usage\":{\"output_tokens\":97,\"cache_creationLine truncated
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_91737fe2-1513-9c19-9477-fda7f3bb52b4\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":107,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19 ×\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" = 37\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"887.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" ≤\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 380\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"00, affordable\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Then call get\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"_weather Paris\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\".\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"signature_delta\",\"signature\":\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"name\":\"get_weather\",\"input\":{},\"id\":\"toolu_4b23422a5a214d5897e91ff2\",\"type\":\"tool_use\"},\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"{\\\"city\\\": \\\"Paris\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"\\\"\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"partial_json\":\"}\",\"type\":\"input_json_delta\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":1}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"tool_use\"},\"type\":\"message_delta\",\"usage\":{\"cache_creation\":{\"ephemeral_5m_input_tokens\":0},\"output_tokens\":60,\"cache_creation_input_tokens\":0,\"input_tokens\":351,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
}
},
{
@@ -41,14 +41,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"We have a budget of 38000 dollars for 219 trips costing 173 dollars each. Calculate whether that is affordable. If it is, use get_weather to look up the current weather in Paris. After receiving the result, report the weather in one short sentence.\"}]},{\"role\":\"assistant\",\"content\":[{\"type\":\"thinking\",\"thinking\":\"I need to investigate this further. Let me check the details.\\n\\n219 × 173 = 37,887. Budget is 38,000. Since 37,887 ≤ 38,000, it can be covered. Call get_weather for Paris.\",\"signature\":\"\"},{\"type\":\"tool_use\",\"id\":\"toolu_5d1ba8ca72bd49889ca838f2\",\"name\":\"get_weather\",\"input\":{\"city\":\"Paris\"}}]},{\"role\":\"user\",\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"toolu_5d1ba8ca72bd49889ca838f2\",\"content\":\"{\\\"condition\\\":\\\"sunny\\\",\\\"temperature\\\":\\\"18C\\\"}\"}]}],\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get the current weather in a city\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"],\"additionalProperties\":false}}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"medium\"}}"
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"We have a budget of 38000 dollars for 219 trips costing 173 dollars each. Calculate whether that is affordable. If it is, use get_weather to look up the current weather in Paris. After receiving the result, report the weather in one short sentence.\"}]},{\"role\":\"assistant\",\"content\":[{\"type\":\"thinking\",\"thinking\":\"219 × 173 = 37887. ≤ 38000, affordable. Then call get_weather Paris.\",\"signature\":\"\"},{\"type\":\"tool_use\",\"id\":\"toolu_4b23422a5a214d5897e91ff2\",\"name\":\"get_weather\",\"input\":{\"city\":\"Paris\"}}]},{\"role\":\"user\",\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"toolu_4b23422a5a214d5897e91ff2\",\"content\":\"{\\\"condition\\\":\\\"sunny\\\",\\\"temperature\\\":\\\"18C\\\"}\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get the current weather in a city\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"],\"additionalProperties\":false},\"cache_control\":{\"type\":\"ephemeral\"}}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"medium\"}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_07dd2003-5458-9d30-89d2-841489626cc7\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":107,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"Wait\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\", I\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" should have calculated\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" it\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" first, but the\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" call was made anyway\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Calculation: \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"21\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"9 × 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73 = \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"37,8\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"87 ≤ \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"38,0\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"00, so\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" it can be covered\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". I\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"'ll report the weather\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" briefly.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"signature_delta\",\"signature\":\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"Yes, it's\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\" affordable\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\": 21\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"9 trips × $\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"173 =\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\" $37,\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"887,\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\" which fits within the\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\" $38,\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"000 budget\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\Line truncated
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_0621b485-def4-9a5f-b285-e78a8fbec8fe\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":107,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"Calc\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"ulation: 2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19 × \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173 =\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 37,\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"887 dollars\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" ≤ 38\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\",000\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" dollars, so it\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"'s purch\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"asable.\\n\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"signature_delta\",\"signature\":\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"Yes,\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\" it's affordable\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\": 21\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"9 trips × $\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"173 =\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\" $37,\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"887,\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\" which is within the\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\" $38,\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"000 budget\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\" (leaving $\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"1\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"13 to spare\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"). Paris is currently\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\" sunny at\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\" 18°C\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\".\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":1}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"Line truncated
}
},
{
@@ -59,14 +59,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"We have a budget of 38000 dollars for 219 trips costing 173 dollars each. Calculate whether that is affordable. If it is, use get_weather to look up the current weather in Paris. After receiving the result, report the weather in one short sentence.\"}]},{\"role\":\"assistant\",\"content\":[{\"type\":\"thinking\",\"thinking\":\"I need to investigate this further. Let me check the details.\\n\\n219 × 173 = 37,887. Budget is 38,000. Since 37,887 ≤ 38,000, it can be covered. Call get_weather for Paris.\",\"signature\":\"\"},{\"type\":\"tool_use\",\"id\":\"toolu_5d1ba8ca72bd49889ca838f2\",\"name\":\"get_weather\",\"input\":{\"city\":\"Paris\"}}]},{\"role\":\"user\",\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"toolu_5d1ba8ca72bd49889ca838f2\",\"content\":\"{\\\"condition\\\":\\\"sunny\\\",\\\"temperature\\\":\\\"18C\\\"}\"}]},{\"role\":\"assistant\",\"content\":[{\"type\":\"thinking\",\"thinking\":\"Wait, I should have calculated it first, but the call was made anyway. Calculation: 219 × 173 = 37,887 ≤ 38,000, so it can be covered. I'll report the weather briefly.\",\"signature\":\"\"},{\"type\":\"text\",\"text\":\"Yes, it's affordable: 219 trips × $173 = $37,887, which fits within the $38,000 budget (leaving $113 to spare).\\n\\nIt's currently sunny in Paris at 18°C.\"}]},{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What temperature did the tool report? Reply with only the temperature.\"}]}],\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get the current weather in a city\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"],\"additionalProperties\":false}}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"medium\"}}"
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"We have a budget of 38000 dollars for 219 trips costing 173 dollars each. Calculate whether that is affordable. If it is, use get_weather to look up the current weather in Paris. After receiving the result, report the weather in one short sentence.\"}]},{\"role\":\"assistant\",\"content\":[{\"type\":\"thinking\",\"thinking\":\"219 × 173 = 37887. ≤ 38000, affordable. Then call get_weather Paris.\",\"signature\":\"\"},{\"type\":\"tool_use\",\"id\":\"toolu_4b23422a5a214d5897e91ff2\",\"name\":\"get_weather\",\"input\":{\"city\":\"Paris\"}}]},{\"role\":\"user\",\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"toolu_4b23422a5a214d5897e91ff2\",\"content\":\"{\\\"condition\\\":\\\"sunny\\\",\\\"temperature\\\":\\\"18C\\\"}\"}]},{\"role\":\"assistant\",\"content\":[{\"type\":\"thinking\",\"thinking\":\"Calculation: 219 × 173 = 37,887 dollars ≤ 38,000 dollars, so it's purchasable.\\n\",\"signature\":\"\"},{\"type\":\"text\",\"text\":\"Yes, it's affordable: 219 trips × $173 = $37,887, which is within the $38,000 budget (leaving $113 to spare). Paris is currently sunny at 18°C.\"}]},{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What temperature did the tool report? Reply with only the temperature.\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get the current weather in a city\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"],\"additionalProperties\":false},\"cache_control\":{\"type\":\"ephemeral\"}}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"medium\"}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_c3875213-1faa-93af-9c86-7cb715f98b68\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":180,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"The\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" user\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" wants\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" to\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" know the temperature reported\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" by the tool.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" Let me think about\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" it\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". The tool said\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" \\\"18C\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"\\\". I just need\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" to answer\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" with the temperature only\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\".\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"signature_delta\",\"signature\":\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"18C\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":1}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"output_tokens\":42,\"cache_creation_input_tokens\":0,\"input_tokens\":621,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_810c014d-d6e0-9241-9a30-dfdbc122757c\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":177,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"The\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" tool reported the\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" temperature as \\\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"18C\\\".\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"signature_delta\",\"signature\":\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"1\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"8C\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":1}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"cache_creation\":{\"ephemeral_5m_input_tokens\":0},\"output_tokens\":17,\"cache_creation_input_tokens\":0,\"input_tokens\":562,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
}
}
]
@@ -11,7 +11,7 @@
"usage"
],
"name": "alibaba-messages/qwen-3-8-max-streams-default-effort",
"recordedAt": "2026-09-08T03:08:06.284Z"
"recordedAt": "2026-09-29T05:26:45.747Z"
},
"interactions": [
{
@@ -22,14 +22,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"stream\":true,\"max_tokens\":4096}"
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"stream\":true,\"max_tokens\":4096}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_192fee9c-dc58-9dc5-9b32-a2bc427c431d\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"We\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" need answer user's\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" simple arithmetic\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\": 17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3 * 2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Need final only\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" integer. Compute:\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"*200\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"=346\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"00;\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"*\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19=3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"287 (\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173*\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"20=3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"460-\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3287\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"); sum 3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"788\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"7. Ensure final\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" only integer.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"signature_delta\",\"signature\":\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"3\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"7887\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":1}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"output_tokens\":95,\"cache_creatiLine truncated
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_0e234266-2d6a-9113-a9b8-63884a430002\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"We\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" need answer user's\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" simple arithmetic\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\": 17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3 * 2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Need final only\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" integer. Compute:\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"*200\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"=346\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"00;\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" *19=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173*\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"20-1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3460\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"-173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"=328\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"7; sum \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3788\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"7. Check alternative\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\": 21\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"9*17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3 = 2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19*(1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"70+3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\")=372\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"30+\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"657=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3788\"},\"type\":\"content_block_delta\"Line truncated
}
}
]
@@ -11,7 +11,7 @@
"usage"
],
"name": "alibaba-messages/qwen-3-8-max-streams-high-effort",
"recordedAt": "2026-09-08T03:12:33.729Z"
"recordedAt": "2026-09-29T05:26:56.565Z"
},
"interactions": [
{
@@ -22,14 +22,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"high\"}}"
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"high\"}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_76b8cb12-452d-996f-817b-c5886f318ecb\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"We\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" need answer user\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" asks\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" simple\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" multiplication, final integer\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" only.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" Need compute 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73*2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19. \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173*\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"200=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3460\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0; *1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"9=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3287\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"?\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"*20=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"34\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"60 minus1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73=3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"287.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" Sum 37\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"88\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"7. Final only\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" integer.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"signature_delta\",\"signature\":\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"37\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"887\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":1}\n\neveLine truncated
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_794e5a53-2dca-9826-9937-6b1a25f95aed\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"We\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" need answer user\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"'s simple arithmetic\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\": 17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3 * 2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Need final integer\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" only. Compute:\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"*200\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"=346\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"00;\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"*\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19=1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73*2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0-17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3=34\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"60-1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73=3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"287;\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" sum=37\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"887.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" Alternatively 21\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"9*1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73. Final\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" only.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" Ensure no extra.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"signature_delta\",\"signature\":\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"tyLine truncated
}
}
]
@@ -11,7 +11,7 @@
"usage"
],
"name": "alibaba-messages/qwen-3-8-max-streams-low-effort",
"recordedAt": "2026-09-08T03:09:58.770Z"
"recordedAt": "2026-09-29T05:26:48.756Z"
},
"interactions": [
{
@@ -22,14 +22,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"low\"}}"
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"low\"}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_67452056-d120-9ed5-96c6-869ece329616\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"The\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" user wants me to\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" calculate 17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3 × 2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19.\\n\\n\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"Let me compute this\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\":\\n17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3 × 2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19\\n=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" × (20\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0 + 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"9)\\n=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" × 20\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0 + 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73 × \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19\\n=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 34,\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"600 +\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 3,2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"87\\n=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 37,\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"887\\n\\n\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"Let me verify:\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" ×\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 19 =\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" × 20\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" - 17\"},\"type\":\"content_bloLine truncated
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_c16fec02-5f94-9041-8c5d-e3341df18395\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"Let\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" me calculate 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73 × \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"219.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"\\n\\n173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" × 21\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"9 = 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73 × (\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"200 +\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 19)\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"\\n= 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73 × \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"200 +\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" × 19\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"\\n= 3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"4,60\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0 +\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 3,2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"87\\n=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 37,\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"887\\n\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"signature_delta\",\"signature\":\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"37\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"887\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":1}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"cache_creation\":{\"ephemeral_5m_input_tokens\":0},\"output_tokens\":90,\"cache_creation_input_tokens\":0,\"input_tokens\":69,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
}
}
]
@@ -11,7 +11,7 @@
"usage"
],
"name": "alibaba-messages/qwen-3-8-max-streams-max-effort",
"recordedAt": "2026-09-08T03:12:36.479Z"
"recordedAt": "2026-09-29T05:27:03.676Z"
},
"interactions": [
{
@@ -22,14 +22,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"max\"}}"
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"max\"}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_7952446b-0176-9526-ad7d-b1f0184bc106\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"We\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" need answer user\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"'s simple multiplication with\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" only final integer.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" Need compute 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73*2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19. \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173*\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"200=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3460\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0; 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73*1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"9=32\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"87 (\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173*\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"20=3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"460-\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3287\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"); sum=3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"7887\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Final only integer\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\".\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"signature_delta\",\"signature\":\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"37\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"887\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":1}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"output_tokens\":92,\"cache_creation_input_tokens\":0,\"input_tokens\":81,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_3a74a19e-d977-9868-9393-39d66092bf96\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"We\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" need answer user\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"'s arithmetic\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\": 17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3 * 2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Need final integer\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" only. Compute:\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"*200\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"=34\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"600;\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"*19=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173*\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"20-1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3460\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"-173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"=328\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"7; sum=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"378\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"87. Check\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" alternative: 2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"9*17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3 = 2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19*(1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"70+3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\")=372\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"30+\"},\"type\":\"content_block_delta\",\"index\":0Line truncated
}
}
]
@@ -11,7 +11,7 @@
"usage"
],
"name": "alibaba-messages/qwen-3-8-max-streams-medium-effort",
"recordedAt": "2026-09-08T03:10:01.981Z"
"recordedAt": "2026-09-29T05:26:52.626Z"
},
"interactions": [
{
@@ -22,14 +22,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"medium\"}}"
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"medium\"}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_1798c2a7-1f8d-9f9a-8d57-8fb1121762e4\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"The\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" user wants me to\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" calculate 17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3 × 2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19 and reply\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" with only the final\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" integer.\\n\\n1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73 × \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"219:\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"\\n173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" × 20\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0 = 3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"4,60\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0\\n17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3 × 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"9 = 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73 × \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"20 - \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173 =\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 3,4\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"60 - \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173 =\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 3,2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"87\\n3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"4,60\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0 + 3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\",287\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" = 37\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\",887\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"\\n\\nSo the answer\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" is 3\"},\"type\"Line truncated
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_b64044fb-ade1-9788-a3b8-3535093bc1f3\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"The\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" user wants me to\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" calculate 17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3 × 2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19 and reply\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" with only the final\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" integer.\\n\\n1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73 × \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"219:\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"\\n173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" × 20\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0 = 3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"4,60\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0\\n17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3 × 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"9 = 1\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"73 × \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"20 - \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173 =\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 3,4\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"60 - \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173 =\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 3,2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"87\\n3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"4,60\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"0 + 3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\",287\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" = 37\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\",887\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"\\n\\nSo the answer\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" is 3\"},\"type\"Line truncated
}
}
]
@@ -11,7 +11,7 @@
"usage"
],
"name": "alibaba-messages/qwen-3-8-max-streams-xhigh-effort",
"recordedAt": "2026-09-08T03:10:04.633Z"
"recordedAt": "2026-09-29T05:26:59.822Z"
},
"interactions": [
{
@@ -22,14 +22,14 @@
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"xhigh\"}}"
"body": "{\"model\":\"qwen3.8-max\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"stream\":true,\"max_tokens\":4096,\"output_config\":{\"effort\":\"xhigh\"}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_a57b8563-71fb-9248-a31e-c49d6ba38717\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"We\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" need answer simple multiplication\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". We\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" already call\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Need compute \"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173*\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"219.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"*200\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"=346\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"00; *\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19=3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"287;\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" sum 37\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"88\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"7. Final only\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" integer. Ensure\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" no extra.\\n\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"signature_delta\",\"signature\":\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"378\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"87\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":1}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"output_tokens\":69,\"cache_creation_input_tokens\":0,\"input_tokens\":81,\"cache_read_input_tokens\":0,\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\nevent:message_stop\ndata:{\"type\":\"message_stop\"}\n\n"
"body": "event:ping\ndata:{\"type\":\"ping\"}\n\nevent:message_start\ndata:{\"message\":{\"model\":\"qwen3.8-max\",\"id\":\"msg_f5e89325-7eb3-922c-9e58-2d2d7ea44ced\",\"role\":\"assistant\",\"type\":\"message\",\"content\":[],\"usage\":{\"input_tokens\":20,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"thinking\",\"signature\":\"\",\"thinking\":\"\"},\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"We\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" need answer user\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"'s simple arithmetic\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\": 17\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3 * 2\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Need final only\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" integer. Compute:\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"*200\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"=346\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"00;\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 173\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"*\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"19=3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"287 (\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173*\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"20=3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"460-\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173=\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3287\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"); sum 3\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"788\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"7. Final only\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" integer.\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"signature_delta\",\"signature\":\"\"},\"type\":\"content_block_delta\",\"index\":0}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":0}\n\nevent:content_block_start\ndata:{\"type\":\"content_block_start\",\"content_block\":{\"type\":\"text\",\"text\":\"\"},\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"37\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_delta\ndata:{\"delta\":{\"type\":\"text_delta\",\"text\":\"887\"},\"type\":\"content_block_delta\",\"index\":1}\n\nevent:content_block_stop\ndata:{\"type\":\"content_block_stop\",\"index\":1}\n\nevent:message_delta\ndata:{\"delta\":{\"stop_reason\":\"end_turn\"},\"type\":\"message_delta\",\"usage\":{\"cache_creation\":{\"ephemeral_5m_input_tLine truncated
}
}
]
@@ -0,0 +1,34 @@
{
"version": 1,
"metadata": {
"tags": [
"prefix:bedrock-converse-thinking-binding",
"provider:amazon-bedrock",
"protocol:bedrock-converse",
"reasoning"
],
"name": "bedrock-converse-thinking-binding/accepts-the-default-binding-with-no-thinking-configured",
"recordedAt": "2026-09-28T23:09:14.527Z"
},
"interactions": [
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://bedrock-runtime.us-east-1.amazonaws.com/model/global.anthropic.claude-opus-5-5/converse-stream",
"headers": {
"content-type": "application/json"
},
"body": "{\"modelId\":\"global.anthropic.claude-opus-5-5\",\"messages\":[{\"role\":\"user\",\"content\":[{\"text\":\"Say hello.\"}]}],\"system\":[{\"text\":\"Reply with the single word 'Hello'.\"}],\"inferenceConfig\":{\"maxTokens\":1024},\"additionalModelRequestFields\":{\"thinking\":{\"type\":\"adaptive\",\"block_binding\":{\"prefix_mismatch_behavior\":\"drop_block\"}},\"anthropic_beta\":[\"thinking-binding-controls-2026-08-01\"]}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "application/vnd.amazon.eventstream"
},
"body": "AAAAoQAAAFKtAFmXCzpldmVudC10eXBlBwAMbWVzc2FnZVN0YXJ0DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSiIsInJvbGUiOiJhc3Npc3RhbnQifUMJiXoAAAC8AAAAV0Ua/isLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJ0ZXh0IjoiSGVsbG8ifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDRCJ91Ic6iwAAALQAAABWAm2FfAs6ZXZlbnQtdHlwZQcAEGNvbnRlbnRCbG9ja1N0b3ANOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVViJ9qr7BagAAAIYAAABRR+j7OQs6ZXZlbnQtdHlwZQcAC21lc3NhZ2VTdG9wDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsicCI6ImFiY2RlIiwic3RvcFJlYXNvbiI6ImVuZF90dXJuIn0pJ2GhAAABCAAAAE4PaiuaCzpldmVudC10eXBlBwAIbWV0YWRhdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJtZXRyaWNzIjp7ImxhdGVuY3lNcyI6MTI0OX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFkiLCJ1c2FnZSI6eyJpbnB1dFRva2VucyI6MjgsIm91dHB1dFRva2VucyI6NSwic2VydmVyVG9vbFVzYWdlIjp7fSwidG90YWxUb2tlbnMiOjMzfX2s2SiQ",
"bodyEncoding": "base64"
}
}
]
}
@@ -0,0 +1,71 @@
{
"version": 1,
"metadata": {
"tags": [
"prefix:bedrock-converse-thinking-binding",
"provider:amazon-bedrock",
"protocol:bedrock-converse",
"reasoning"
],
"name": "bedrock-converse-thinking-binding/keeps-a-session-working-after-the-system-prompt-changes",
"recordedAt": "2026-09-28T23:10:11.738Z"
},
"interactions": [
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://bedrock-runtime.us-east-1.amazonaws.com/model/global.anthropic.claude-opus-5-5/converse-stream",
"headers": {
"content-type": "application/json"
},
"body": "{\"modelId\":\"global.anthropic.claude-opus-5-5\",\"messages\":[{\"role\":\"user\",\"content\":[{\"text\":\"How many positive integers below 5000 have exactly 12 positive divisors? Reply with the number only.\"}]}],\"system\":[{\"text\":\"You are a concise assistant.\"}],\"inferenceConfig\":{\"maxTokens\":12000},\"additionalModelRequestFields\":{\"thinking\":{\"type\":\"adaptive\",\"block_binding\":{\"prefix_mismatch_behavior\":\"drop_block\"},\"display\":\"summarized\"},\"output_config\":{\"effort\":\"high\"},\"anthropic_beta\":[\"thinking-binding-controls-2026-08-01\"]}}"
},
"response": {
"status": 200,
"headers": {
"content-type": "application/vnd.amazon.eventstream"
},
"body": "AAAAfwAAAFKbxZivCzpldmVudC10eXBlBwAMbWVzc2FnZVN0YXJ0DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsicCI6ImFiIiwicm9sZSI6ImFzc2lzdGFudCJ9NixsGAAAAOYAAABXN7kpQQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IkkgbmVlZCBudW0ifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUIn1D+gHXAAAA7AAAAFd9CTHgCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiYmVycyB1bmRlciJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVoifbkKWVMAAAC6AAAAV8paC4sLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgNSJ9fSwicCI6ImFiY2RlZmdoaWoifcnjI7YAAADtAAAAV0BpGFALOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIwMDAgd2l0aCBleGFjdGx5IDEyIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVIifZKiTlgAAADeAAAAV6bo2gYLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgZGl2aXNvcnMsIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0wifRIaXcAAAAEGAAAAV9QxPTsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgYmFzZWQgb24gdGhlIGZhY3Rvcml6YXRpb24gcGF0In19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0In02t0irAAAAuAAAAFewmljrCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoidGVybnMgIn19LCJwIjoiYWJjZCJ9eN43wAAAAMoAAABXM4jrRAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IjEyPSJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHkifaFkWvQAAADPAAAAV/toZDQLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIxMiwgNiJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUIifZm96ekAAADaAAAAV1NofMYLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiLCtyJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUCJ9iH+n3AAAAMcAAABXyxgv9Qs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IjIsIDTCtzMsICJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3AifWl7oSQAAADlAAAAV3AZU5ELOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIzwrcywrcifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXIn0JazM8AAAA2AAAAFcpqC+mCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiMiwifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OIn2UHVG5AAAA9QAAAFcQ+cQTCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGdpdmluZyBmb3JtcyBwXjExIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAifSNGFeQAAAC/AAAAVwK6hPsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIsIHBeNcK3cSwgcCJ9fSwicCI6ImFiY2RlZiJ9ZLcKxwAAAMYAAABX9ngGRQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6Il4zwrdxXiJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxciJ9vlaYoQAAAPAAAABX2BlLYws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnLine truncated
"bodyEncoding": "base64"
}
},
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://bedrock-runtime.us-east-1.amazonaws.com/model/global.anthropic.claude-opus-5-5/converse-stream",
"headers": {
"content-type": "application/json"
},
"body": "{\"modelId\":\"global.anthropic.claude-opus-5-5\",\"messages\":[{\"role\":\"user\",\"content\":[{\"text\":\"How many positive integers below 5000 have exactly 12 positive divisors? Reply with the number only.\"}]},{\"role\":\"assistant\",\"content\":[{\"reasoningContent\":{\"reasoningText\":{\"text\":\"I need numbers under 5000 with exactly 12 divisors, based on the factorization patterns 12=12, 6·2, 4·3, 3·2·2, giving forms p^11, p^5·q, p^3·q^2, and p^2·q·r. Checking p^11, only 2^11=2048 works since 3^11 is too large, giving one solution; now I'm working through the p^5·q case starting with p=2.\\n\\nFor p^5·q, p=2 gives 35 valid q values, p=3 gives 7, p=5 gives none, totaling 42.\\n\\nFor p^3·q^2, checking each base p=2,3,5,7,11 against the bound, I get 8+5+2+2+0=17 solutions total.\\n\\nNow I'm setting up the p^2·q·r case where p, q, r are distinct primes with q<r, working through the bound qr<1250 for p=2, then qr≤555 for p=3 excluding 3, and starting the p=5 case.\\n\\nContinuing with q=11: r<113.5, giving π(113)=30, minus 5 primes ≤11 leaves 25. Then q=13: r<96.08...\\n\\nq=13: r≤96, π(96)=24, exclude 6 → 18. q=17: r≤73, π=21, exclude 7 → 14. q=19: r≤65, π=18, exclude 8 → 10. q=23: r≤54, π=16, exclude 9 → 7. q=29: r≤43, π=14, exclude 10 → 4. q=31: r≤40, π=12, exclude 11 → 1. q=37: none left since r must exceed 37. Running total after adding these: 78+50+36+25+18+14+10+7+4+1 = 221, matching my tally so far.\\n\\nNow moving to p=3, requiring q<r, both distinct from 3, with qr≤555. I work through q=2 giving 57 valid r, q=5 giving 26, q=7 giving 18, q=11 giving 10, q=13 giving 7, q=17 giving 4, q=19 giving 2, and I'm now checking q=23 where r≤24 limits things further.\\n\\nContinuing q=3 gives 8, q=5 gives 4, q=11 none, so p=7 sums to 25.\\n\\nFor p=11: q=2 gives 6, q=3 gives 3, q=5 gives 1.\\n\\nMoving to p=13: q=2 gives 4, q=3 gives 2, q=5 gives none, totaling 6. Then p=17 sums to 4, p=19 gives 2, p=23 gives 1, so the p²qr total is 460.\\n\\nAdding everything up: 1+42+17+460 = 520. Let me double-check the p=2, q=3 case where 12r<5000 means r<416.67.\\n\\n\",\"signature\":\"CAQSgCAKEggSEAEYAjgBQgh0aGlua2luZxIMQjiVuilwjCMPIok3GgzYxByPuaSFe5bJk+kiMLehuAI4ZqG5YI0Mn1+6bHyjsHvrAmNP/3+qOaKAePGNHYDMHEiXdiri3EPqXeWPtyqbH1MJpdPij9cl4Ppd+c2sizrrPSRLX15i09KiQpyVMb3kgLTceDfuuhqlv2RpZfx0YCuf0m9vbZ6tThvNAHsdW63ElQiMwCQlDcjGN0Iz4ahiJ4D9JMXR86yV7findKZn8gGkXc9uDgGjPhmmqFXAzkwKRYGT1Qt00LDfsdR9xnmrcclw2OZA2Rr2QJ9qX8+d5wKxJbrhTyU41tvE9uPdL/0syQDfB1HNSOnGkzN0kxbCkwEGGsopAbq+m5yDazQlAg4oDD+gbF9wPCTeuPnyKBmhauG3dq8TrZvrd6hbD7mgjBm6iETE+gLSsU56hMlpfBiESAUplybA6nfGFmTz0MJtuYpdxFuCi9D1gLm073ivpVi4pS3Dw+e7jCk8RelmS61laCh0nPLx+zn5ORGMCbMKZ+Bbr1IEvRzb8GyBIYcldu6z/Swv46+jc5OWixPPAqFeXPyCxBcST546upay/O+Bp4FS3u8PLN/rdbSkMSGHjcjDDY2nzuzWj2MRdH6zcfKFSKOQ/6Lxs6YXt/YszzIDAPLMLhq8vZLsURxgvevgX4GPU0NQupxQZnhX1xfzv2++X7xWdJiCS0V8UaRREdpyOAKhisQvJf9vo5AgoF4C2HV7sHL9PLtuvJ+aE+jnaPd3cTYnRqpyqKEjnJcc0uR1DUL7QIV/2N3EMuUb76ToxHNaAW9jRGC8dKDa+iQDqqWSCXKGC8zThiYhJLq8IxoTQDctqYvoUwgaq45uG7Hp+HGIzb8zU/9sr+XeprqZLaE/KfrTScFrbyKOWX3nnkNO3hmzIFWwfE2Yp0JfXz2IpoFygMPRNW5IJ/XX0ngtM1TTpO5XUbeCDvm8EhdwmxuL2KTxKkybVNYr+gDdSxOmTqeaCVrt+jtC0w/lJOva9u/tZJDR0OQWmZ2DOUq74boxeW7oFfJ9DvXr4loJpaAZkZHWXDXkJEfxhA51k0Nw5f4FtmEoG6zDj0aV9UBWmG7u4Asrxdwz/gKHJ9xmfuqv3GpMyxYJLKTDPkcCaGUrQrfOT05NIMN9QhhtNPZ0c1PoI7TNlFVyKG0hm1Wu+2mMrJ4I+W98IlRQmDHKoS/G+NTbpTz7EMElNoxRnucrwB8KFVTV0wahuL61r0MTbNjlmOERB/NkJUWGGldCjGhtOlWc5SIK6ivko16negNM2m1v+DruxNV87+34NvVH7M/i7VwpCjUDgM81ZmBV3xt1BtNHxXajIenmQo0rIjPmCmyShQApHMb50zHxuO53UFsRSDEhYaTc7pnjtdY403h3leMp9LhgmF9hVkCyYB0GN5QK31J02rW5Fy4LTpVbRdgRflPzlaL29Cf/9HHm9jf4NAREuwCgk3LA+WnjA5IIWxh1LomT2f7tedmN8Bz/mbjIhALP9AeypC/g1Xc0ICoePm2LJqAjFPyGLtrJgJJ+TlGyB0G9MhcSWHtOKabuZlRFYp2QBW5yVCPGgSc5MQOJMQKGUXgC3FIZ06/KykP7HIk9RHdzkTtcOMQJhgUhcdQ9K9pvf8ro+BYKxP9v4qQ8Gb62R6W3q+Saw/rgA5s4wPrE9dkHFQRzZcVjdRmTR5iyYSurOafgZePUhzS9gCbgLdgkgNi9cdvMB5GeasXET3vmbvi4xjQ0yiOQLdLc7aRDFIuOT/nn6Fzh+iOQ6Qlr+3hQEdb+UXymt5NUl5F3j8mdl0iHw56DdYNC/s7qXSkCtgO/djjXvr4CWCEqzQ5x36lejPC0E8T3g1TcS1xmutQQkKcyK48ehYDjpPPNZ7oSCtHxKv9ekrTIe8jKqyRzcWOsdcO06GnjMXvu5zaEG8at1T1XzhuJrRCm3alU28bfmJOGSR8kJa5c5Xb2gzCcoe9MMZ1LWijAifWdQ+oOBVw0SRb3cQGZGqoaKmJBj7KCAduUrHokx4DjYpJOKqhPtgYfJw9jV//yl/iF9rQnFM0P7xa4r2mrGakVPZYZ/v9BJDaTrRTd7gXBGUuktk91FOCUHmYm5fw+VqCync+joXtDY2T76O7AHu8XEQtvJkjEIQ21c0bgC/ruYvJxR7yfFz0fmWpKJEL/ebL4cnrJkVedLUla9FUa7YWr3C7VHzjKPbA9gwbDTL42htNw3U71L6oM1nOIvcEbulE36kW82PwM9fVLLkLNh55djJgipiROuH44m4tMlWmKof+JK5DjVcW1SlXxKGAr0LP17kveAWq/lcsCAMRmw5z5ZL9xv+8AcxXhzJJkwDDy1XzBn8JVxP4IZqW+Np8G4z6DKwUhKaCe50PgPiASaKUDRCFi+xPv85+fxbd9TePSiXIFU4Y9fe3AgL43aRskBqxfwRpEnOJfAJibbwOoFRQU/GAuwiiIZUO3j9SFWF5rZHocIif1OnQQUsxw8mrRD3ee5hmBbwQaCM7YGDNhsoREyE/CVoSJ1faJMiAWxBXUzIfhxLzE++dPyoQGojA4s/4hlimsMT3dwiSfOjj//jXJQopSKbTRGGvlL8cRlvNKeqMPzfIE9ZpKhStdbOMGD9ETsiuLCDfc8FpHZK6njZA9Pcuq7IJoAzrY9bpQgmoIe3Vk8SSgDHQmSy+rBYan38IQMA65+z0NDNx6qRB0ewViBeOfhSrLG5cPrPW7VJDyNzyQXZsEtGNKIWS6Z7Nm5MuVvhsovWVXYWIuaTNVChfr+3pSvXoYn6OSsLXLine truncated
},
"response": {
"status": 200,
"headers": {
"content-type": "application/vnd.amazon.eventstream"
},
"body": "AAAAoQAAAFKtAFmXCzpldmVudC10eXBlBwAMbWVzc2FnZVN0YXJ0DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSiIsInJvbGUiOiJhc3Npc3RhbnQifUMJiXoAAADkAAAAV015eiELOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiJJIG5lZWQgdG8gZG91YmxlIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0wiff0W1SkAAAC8AAAAV0Ua/isLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiItIn19LCJwIjoiYWJjZGVmZ2hpamtsbSJ9L62pVQAAALsAAABX9zoiOws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6ImNoZWNrIHRoYXQifX0sInAiOiJhYmMifXMTCCkAAADXAAAAV6v4uHcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgNTIwIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKSyJ91ktj4wAAAMMAAABXPpiJNQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiB3YXMgYWN0dWFsbHkgcmlnaHQifX0sInAiOiJhYiJ9GC2umgAAANEAAABXJLhN1ws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBiZWZvcmUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCIn3AaUHEAAAAwQAAAFdEWNpVCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGRvIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcCJ9ALX4WQAAAMgAAABXSUi4JAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6InVibGluZyBpdCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxIn32XUj3AAAA4AAAAFe4+dzhCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiLCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVlcifSOIB4IAAADDAAAAVz6YiTULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgc28gSSdtIn19LCJwIjoiYWJjZGVmZ2hpamtsbW4ifWxC0z8AAAC3AAAAVzLKzzoLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgcmUtZGUifX0sInAiOiJhYmMifRWn2MQAAAC+AAAAVz/arUsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiJyaXZpbmcgdGhlIGRpdiJ9fSwicCI6ImFiIn3fe8wrAAAAyQAAAFd0KJGUCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiaXNvci0ifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2In3df/xuAAAAzAAAAFe8yB7kCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiY291bnQifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5In3YkNsnAAAA1wAAAFer+Lh3CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGZvciJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSksifU6mgYEAAADZAAAAVxTIBhYLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiJtcyBmb3IgMTI6In19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHIn3pvCBtAAAAuQAAAFeN+nFbCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHAifX0sInAiOiJhYmNkZWZnaGkifTi7PKIAAADDAAAAVz6YiTULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZWLine truncated
"bodyEncoding": "base64"
}
},
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://bedrock-runtime.us-east-1.amazonaws.com/model/global.anthropic.claude-opus-5-5/converse-stream",
"headers": {
"content-type": "application/json"
},
"body": "{\"modelId\":\"global.anthropic.claude-opus-5-5\",\"messages\":[{\"role\":\"user\",\"content\":[{\"text\":\"How many positive integers below 5000 have exactly 12 positive divisors? Reply with the number only.\"}]},{\"role\":\"assistant\",\"content\":[{\"reasoningContent\":{\"reasoningText\":{\"text\":\"I need numbers under 5000 with exactly 12 divisors, based on the factorization patterns 12=12, 6·2, 4·3, 3·2·2, giving forms p^11, p^5·q, p^3·q^2, and p^2·q·r. Checking p^11, only 2^11=2048 works since 3^11 is too large, giving one solution; now I'm working through the p^5·q case starting with p=2.\\n\\nFor p^5·q, p=2 gives 35 valid q values, p=3 gives 7, p=5 gives none, totaling 42.\\n\\nFor p^3·q^2, checking each base p=2,3,5,7,11 against the bound, I get 8+5+2+2+0=17 solutions total.\\n\\nNow I'm setting up the p^2·q·r case where p, q, r are distinct primes with q<r, working through the bound qr<1250 for p=2, then qr≤555 for p=3 excluding 3, and starting the p=5 case.\\n\\nContinuing with q=11: r<113.5, giving π(113)=30, minus 5 primes ≤11 leaves 25. Then q=13: r<96.08...\\n\\nq=13: r≤96, π(96)=24, exclude 6 → 18. q=17: r≤73, π=21, exclude 7 → 14. q=19: r≤65, π=18, exclude 8 → 10. q=23: r≤54, π=16, exclude 9 → 7. q=29: r≤43, π=14, exclude 10 → 4. q=31: r≤40, π=12, exclude 11 → 1. q=37: none left since r must exceed 37. Running total after adding these: 78+50+36+25+18+14+10+7+4+1 = 221, matching my tally so far.\\n\\nNow moving to p=3, requiring q<r, both distinct from 3, with qr≤555. I work through q=2 giving 57 valid r, q=5 giving 26, q=7 giving 18, q=11 giving 10, q=13 giving 7, q=17 giving 4, q=19 giving 2, and I'm now checking q=23 where r≤24 limits things further.\\n\\nContinuing q=3 gives 8, q=5 gives 4, q=11 none, so p=7 sums to 25.\\n\\nFor p=11: q=2 gives 6, q=3 gives 3, q=5 gives 1.\\n\\nMoving to p=13: q=2 gives 4, q=3 gives 2, q=5 gives none, totaling 6. Then p=17 sums to 4, p=19 gives 2, p=23 gives 1, so the p²qr total is 460.\\n\\nAdding everything up: 1+42+17+460 = 520. Let me double-check the p=2, q=3 case where 12r<5000 means r<416.67.\\n\\n\",\"signature\":\"CAQSgCAKEggSEAEYAjgBQgh0aGlua2luZxIMQjiVuilwjCMPIok3GgzYxByPuaSFe5bJk+kiMLehuAI4ZqG5YI0Mn1+6bHyjsHvrAmNP/3+qOaKAePGNHYDMHEiXdiri3EPqXeWPtyqbH1MJpdPij9cl4Ppd+c2sizrrPSRLX15i09KiQpyVMb3kgLTceDfuuhqlv2RpZfx0YCuf0m9vbZ6tThvNAHsdW63ElQiMwCQlDcjGN0Iz4ahiJ4D9JMXR86yV7findKZn8gGkXc9uDgGjPhmmqFXAzkwKRYGT1Qt00LDfsdR9xnmrcclw2OZA2Rr2QJ9qX8+d5wKxJbrhTyU41tvE9uPdL/0syQDfB1HNSOnGkzN0kxbCkwEGGsopAbq+m5yDazQlAg4oDD+gbF9wPCTeuPnyKBmhauG3dq8TrZvrd6hbD7mgjBm6iETE+gLSsU56hMlpfBiESAUplybA6nfGFmTz0MJtuYpdxFuCi9D1gLm073ivpVi4pS3Dw+e7jCk8RelmS61laCh0nPLx+zn5ORGMCbMKZ+Bbr1IEvRzb8GyBIYcldu6z/Swv46+jc5OWixPPAqFeXPyCxBcST546upay/O+Bp4FS3u8PLN/rdbSkMSGHjcjDDY2nzuzWj2MRdH6zcfKFSKOQ/6Lxs6YXt/YszzIDAPLMLhq8vZLsURxgvevgX4GPU0NQupxQZnhX1xfzv2++X7xWdJiCS0V8UaRREdpyOAKhisQvJf9vo5AgoF4C2HV7sHL9PLtuvJ+aE+jnaPd3cTYnRqpyqKEjnJcc0uR1DUL7QIV/2N3EMuUb76ToxHNaAW9jRGC8dKDa+iQDqqWSCXKGC8zThiYhJLq8IxoTQDctqYvoUwgaq45uG7Hp+HGIzb8zU/9sr+XeprqZLaE/KfrTScFrbyKOWX3nnkNO3hmzIFWwfE2Yp0JfXz2IpoFygMPRNW5IJ/XX0ngtM1TTpO5XUbeCDvm8EhdwmxuL2KTxKkybVNYr+gDdSxOmTqeaCVrt+jtC0w/lJOva9u/tZJDR0OQWmZ2DOUq74boxeW7oFfJ9DvXr4loJpaAZkZHWXDXkJEfxhA51k0Nw5f4FtmEoG6zDj0aV9UBWmG7u4Asrxdwz/gKHJ9xmfuqv3GpMyxYJLKTDPkcCaGUrQrfOT05NIMN9QhhtNPZ0c1PoI7TNlFVyKG0hm1Wu+2mMrJ4I+W98IlRQmDHKoS/G+NTbpTz7EMElNoxRnucrwB8KFVTV0wahuL61r0MTbNjlmOERB/NkJUWGGldCjGhtOlWc5SIK6ivko16negNM2m1v+DruxNV87+34NvVH7M/i7VwpCjUDgM81ZmBV3xt1BtNHxXajIenmQo0rIjPmCmyShQApHMb50zHxuO53UFsRSDEhYaTc7pnjtdY403h3leMp9LhgmF9hVkCyYB0GN5QK31J02rW5Fy4LTpVbRdgRflPzlaL29Cf/9HHm9jf4NAREuwCgk3LA+WnjA5IIWxh1LomT2f7tedmN8Bz/mbjIhALP9AeypC/g1Xc0ICoePm2LJqAjFPyGLtrJgJJ+TlGyB0G9MhcSWHtOKabuZlRFYp2QBW5yVCPGgSc5MQOJMQKGUXgC3FIZ06/KykP7HIk9RHdzkTtcOMQJhgUhcdQ9K9pvf8ro+BYKxP9v4qQ8Gb62R6W3q+Saw/rgA5s4wPrE9dkHFQRzZcVjdRmTR5iyYSurOafgZePUhzS9gCbgLdgkgNi9cdvMB5GeasXET3vmbvi4xjQ0yiOQLdLc7aRDFIuOT/nn6Fzh+iOQ6Qlr+3hQEdb+UXymt5NUl5F3j8mdl0iHw56DdYNC/s7qXSkCtgO/djjXvr4CWCEqzQ5x36lejPC0E8T3g1TcS1xmutQQkKcyK48ehYDjpPPNZ7oSCtHxKv9ekrTIe8jKqyRzcWOsdcO06GnjMXvu5zaEG8at1T1XzhuJrRCm3alU28bfmJOGSR8kJa5c5Xb2gzCcoe9MMZ1LWijAifWdQ+oOBVw0SRb3cQGZGqoaKmJBj7KCAduUrHokx4DjYpJOKqhPtgYfJw9jV//yl/iF9rQnFM0P7xa4r2mrGakVPZYZ/v9BJDaTrRTd7gXBGUuktk91FOCUHmYm5fw+VqCync+joXtDY2T76O7AHu8XEQtvJkjEIQ21c0bgC/ruYvJxR7yfFz0fmWpKJEL/ebL4cnrJkVedLUla9FUa7YWr3C7VHzjKPbA9gwbDTL42htNw3U71L6oM1nOIvcEbulE36kW82PwM9fVLLkLNh55djJgipiROuH44m4tMlWmKof+JK5DjVcW1SlXxKGAr0LP17kveAWq/lcsCAMRmw5z5ZL9xv+8AcxXhzJJkwDDy1XzBn8JVxP4IZqW+Np8G4z6DKwUhKaCe50PgPiASaKUDRCFi+xPv85+fxbd9TePSiXIFU4Y9fe3AgL43aRskBqxfwRpEnOJfAJibbwOoFRQU/GAuwiiIZUO3j9SFWF5rZHocIif1OnQQUsxw8mrRD3ee5hmBbwQaCM7YGDNhsoREyE/CVoSJ1faJMiAWxBXUzIfhxLzE++dPyoQGojA4s/4hlimsMT3dwiSfOjj//jXJQopSKbTRGGvlL8cRlvNKeqMPzfIE9ZpKhStdbOMGD9ETsiuLCDfc8FpHZK6njZA9Pcuq7IJoAzrY9bpQgmoIe3Vk8SSgDHQmSy+rBYan38IQMA65+z0NDNx6qRB0ewViBeOfhSrLG5cPrPW7VJDyNzyQXZsEtGNKIWS6Z7Nm5MuVvhsovWVXYWIuaTNVChfr+3pSvXoYn6OSsLXLine truncated
},
"response": {
"status": 400,
"headers": {
"content-type": "application/json"
},
"body": "{\"message\":\"The model returned the following errors: messages.1.content.0: Invalid `signature` in `thinking` block. The block is bound to a different conversation. Remove the block, or set `thinking.block_binding.prefix_mismatch_behavior` to \\\"drop_block\\\". The `system` prompt differs from the one this block was created with.\"}"
}
}
]
}
@@ -0,0 +1,38 @@
{
"version": 1,
"metadata": {
"provider": "cloudflare-ai-gateway",
"route": "cloudflare-ai-gateway-messages",
"transport": "http",
"model": "claude-haiku-4-5",
"tags": [
"prefix:cloudflare-ai-gateway",
"provider:cloudflare-ai-gateway",
"text",
"golden"
],
"name": "cloudflare-ai-gateway/cloudflare-ai-gateway-claude-haiku-4-5-text",
"recordedAt": "2026-09-30T04:35:43.657Z"
},
"interactions": [
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/anthropic/v1/messages",
"headers": {
"anthropic-version": "2023-06-01",
"content-type": "application/json"
},
"body": "{\"model\":\"claude-haiku-4-5\",\"system\":[{\"type\":\"text\",\"text\":\"You are concise.\"}],\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"Reply exactly with: Hello!\"}]}],\"stream\":true,\"max_tokens\":40,\"temperature\":0}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream; charset=utf-8"
},
"body": "event: message_start\ndata: {\"p\": \"6247a7b95b5e3f\", \"type\":\"message_start\",\"message\":{\"model\":\"claude-haiku-4-5-20251001\",\"id\":\"msg_011CfZ16hXSVRfaXBDtUBKis\",\"type\":\"message\",\"role\":\"assistant\",\"content\":[],\"container\":null,\"stop_reason\":null,\"stop_sequence\":null,\"stop_details\":null,\"usage\":{\"input_tokens\":18,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"cache_creation\":{\"ephemeral_5m_input_tokens\":0,\"ephemeral_1h_input_tokens\":0},\"output_tokens\":2,\"service_tier\":\"standard\",\"inference_geo\":\"not_available\"},\"diagnostics\":null}}\n\nevent: content_block_start\ndata: {\"p\": \"f9b\", \"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"text\",\"text\":\"\"} }\n\nevent: ping\ndata: {\"p\": \"cc76aa8\", \"type\": \"ping\"}\n\nevent: content_block_delta\ndata: {\"p\": \"94f\", \"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"Hello!\"} }\n\nevent: content_block_stop\ndata: {\"p\": \"1a9d8\", \"type\":\"content_block_stop\",\"index\":0 }\n\nevent: message_delta\ndata: {\"p\": \"0cb3c23\", \"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"end_turn\",\"stop_sequence\":null,\"stop_details\":null,\"container\":null},\"usage\":{\"input_tokens\":18,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"output_tokens\":5} }\n\nevent: message_stop\ndata: {\"p\": \"6ef9de29973ed\", \"type\":\"message_stop\" }\n\n"
}
}
]
}
@@ -0,0 +1,58 @@
{
"version": 1,
"metadata": {
"provider": "cloudflare-ai-gateway",
"route": "cloudflare-ai-gateway-messages",
"transport": "http",
"model": "claude-haiku-4-5",
"tags": [
"prefix:cloudflare-ai-gateway",
"provider:cloudflare-ai-gateway",
"tool",
"tool-loop",
"golden"
],
"name": "cloudflare-ai-gateway/cloudflare-ai-gateway-claude-haiku-4-5-tool-loop",
"recordedAt": "2026-09-30T04:35:45.222Z"
},
"interactions": [
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/anthropic/v1/messages",
"headers": {
"anthropic-version": "2023-06-01",
"content-type": "application/json"
},
"body": "{\"model\":\"claude-haiku-4-5\",\"system\":[{\"type\":\"text\",\"text\":\"Use the get_weather tool exactly once. After the tool result, reply exactly: Paris is sunny.\"}],\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is the weather in Paris?\"}]}],\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get current weather for a city.\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"],\"additionalProperties\":false}}],\"stream\":true,\"max_tokens\":80,\"temperature\":0}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream; charset=utf-8"
},
"body": "event: message_start\ndata: {\"p\": \"f2f6a212\", \"type\":\"message_start\",\"message\":{\"model\":\"claude-haiku-4-5-20251001\",\"id\":\"msg_011CfZ16jzmxrCrHLxeCxrL8\",\"type\":\"message\",\"role\":\"assistant\",\"content\":[],\"container\":null,\"stop_reason\":null,\"stop_sequence\":null,\"stop_details\":null,\"usage\":{\"input_tokens\":593,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"cache_creation\":{\"ephemeral_5m_input_tokens\":0,\"ephemeral_1h_input_tokens\":0},\"output_tokens\":26,\"service_tier\":\"standard\",\"inference_geo\":\"not_available\"},\"diagnostics\":null} }\n\nevent: content_block_start\ndata: {\"p\": \"7\", \"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"tool_use\",\"id\":\"toolu_019hb1DDwKBNMMeaKjZf1CpS\",\"name\":\"get_weather\",\"input\":{},\"caller\":{\"type\":\"direct\"}} }\n\nevent: ping\ndata: {\"p\": \"e112b39d9a4869\", \"type\": \"ping\"}\n\nevent: content_block_delta\ndata: {\"p\": \"12d\", \"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"input_json_delta\",\"partial_json\":\"\"} }\n\nevent: content_block_delta\ndata: {\"p\": \"2\", \"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"input_json_delta\",\"partial_json\":\"{\\\"city\\\"\"} }\n\nevent: content_block_delta\ndata: {\"p\": \"f6bb01e5ae5c1c7\", \"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"input_json_delta\",\"partial_json\":\": \\\"Pari\"} }\n\nevent: content_block_delta\ndata: {\"p\": \"c26aa17\", \"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"input_json_delta\",\"partial_json\":\"s\\\"}\"} }\n\nevent: content_block_stop\ndata: {\"p\": \"16f665\", \"type\":\"content_block_stop\",\"index\":0 }\n\nevent: message_delta\ndata: {\"p\": \"e00cc845875\", \"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"tool_use\",\"stop_sequence\":null,\"stop_details\":null,\"container\":null},\"usage\":{\"input_tokens\":593,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"output_tokens\":54} }\n\nevent: message_stop\ndata: {\"p\": \"5082e73ce8055a\", \"type\":\"message_stop\" }\n\n"
}
},
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/anthropic/v1/messages",
"headers": {
"anthropic-version": "2023-06-01",
"content-type": "application/json"
},
"body": "{\"model\":\"claude-haiku-4-5\",\"system\":[{\"type\":\"text\",\"text\":\"Use the get_weather tool exactly once. After the tool result, reply exactly: Paris is sunny.\"}],\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is the weather in Paris?\"}]},{\"role\":\"assistant\",\"content\":[{\"type\":\"tool_use\",\"id\":\"toolu_019hb1DDwKBNMMeaKjZf1CpS\",\"name\":\"get_weather\",\"input\":{\"city\":\"Paris\"}}]},{\"role\":\"user\",\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"toolu_019hb1DDwKBNMMeaKjZf1CpS\",\"content\":\"{\\\"temperature\\\":22,\\\"condition\\\":\\\"sunny\\\"}\"}]}],\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get current weather for a city.\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"],\"additionalProperties\":false}}],\"stream\":true,\"max_tokens\":80,\"temperature\":0}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream; charset=utf-8"
},
"body": "event: message_start\ndata: {\"p\": \"ff048fa113d17ffc\", \"type\":\"message_start\",\"message\":{\"model\":\"claude-haiku-4-5-20251001\",\"id\":\"msg_011CfZ16ooU6seiMzxt69doW\",\"type\":\"message\",\"role\":\"assistant\",\"content\":[],\"container\":null,\"stop_reason\":null,\"stop_sequence\":null,\"stop_details\":null,\"usage\":{\"input_tokens\":668,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"cache_creation\":{\"ephemeral_5m_input_tokens\":0,\"ephemeral_1h_input_tokens\":0},\"output_tokens\":1,\"service_tier\":\"standard\",\"inference_geo\":\"not_available\"},\"diagnostics\":null} }\n\nevent: content_block_start\ndata: {\"p\": \"5172b1\", \"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"text\",\"text\":\"\"} }\n\nevent: ping\ndata: {\"p\": \"d\", \"type\": \"ping\"}\n\nevent: content_block_delta\ndata: {\"p\": \"7f847273c\", \"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"Paris\"} }\n\nevent: content_block_delta\ndata: {\"p\": \"1de4\", \"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" is sunny\"}}\n\nevent: content_block_delta\ndata: {\"p\": \"d61\", \"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\".\"}}\n\nevent: content_block_stop\ndata: {\"p\": \"29638a9b46e21ecd\", \"type\":\"content_block_stop\",\"index\":0 }\n\nevent: message_delta\ndata: {\"p\": \"8e5f9442b03f76\", \"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"end_turn\",\"stop_sequence\":null,\"stop_details\":null,\"container\":null},\"usage\":{\"input_tokens\":668,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"output_tokens\":7} }\n\nevent: message_stop\ndata: {\"p\": \"97d9afcead79c7a\", \"type\":\"message_stop\" }\n\n"
}
}
]
}
@@ -0,0 +1,37 @@
{
"version": 1,
"metadata": {
"provider": "cloudflare-ai-gateway",
"route": "cloudflare-ai-gateway-responses",
"transport": "http",
"model": "gpt-5-nano",
"tags": [
"prefix:cloudflare-ai-gateway",
"provider:cloudflare-ai-gateway",
"text",
"golden"
],
"name": "cloudflare-ai-gateway/cloudflare-ai-gateway-openai-gpt-5-nano-text",
"recordedAt": "2026-09-30T04:36:07.656Z"
},
"interactions": [
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/openai/responses",
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"gpt-5-nano\",\"input\":[{\"type\":\"message\",\"role\":\"user\",\"content\":[{\"type\":\"input_text\",\"text\":\"Reply exactly with: Hello!\"}]}],\"instructions\":\"You are concise.\",\"store\":false,\"include\":[\"reasoning.encrypted_content\"],\"max_output_tokens\":2000,\"stream\":true}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream; charset=utf-8"
},
"body": "event: response.created\ndata: {\"p\": \"6e564fc3bf3\", \"type\":\"response.created\",\"response\":{\"id\":\"resp_0137cf30a4752bdf016abc91b6263487d19ea9f96c7605459a\",\"object\":\"response\",\"created_at\":1790742966,\"status\":\"in_progress\",\"access_programs\":null,\"background\":false,\"completed_at\":null,\"error\":null,\"frequency_penalty\":0.0,\"incomplete_details\":null,\"instructions\":\"You are concise.\",\"max_output_tokens\":2000,\"max_tool_calls\":null,\"model\":\"gpt-5-nano-2025-08-07\",\"moderation\":null,\"output\":[],\"parallel_tool_calls\":true,\"presence_penalty\":0.0,\"previous_response_id\":null,\"prompt_cache_key\":null,\"prompt_cache_retention\":\"in_memory\",\"reasoning\":{\"context\":\"current_turn\",\"effort\":\"medium\",\"mode\":\"standard\",\"summary\":null},\"safety_identifier\":null,\"service_tier\":\"auto\",\"store\":false,\"temperature\":1.0,\"text\":{\"format\":{\"type\":\"text\"},\"verbosity\":\"medium\"},\"tool_choice\":\"auto\",\"tool_usage\":{\"image_gen\":{\"input_tokens\":0,\"input_tokens_details\":{\"image_tokens\":0,\"text_tokens\":0},\"output_tokens\":0,\"output_tokens_details\":{\"image_tokens\":0,\"text_tokens\":0},\"total_tokens\":0},\"web_search\":{\"num_requests\":0}},\"tools\":[],\"top_logprobs\":0,\"top_p\":1.0,\"truncation\":\"disabled\",\"usage\":null,\"user\":null,\"metadata\":{}},\"sequence_number\":0}\n\nevent: response.in_progress\ndata: {\"p\": \"f61c4ed2a9768\", \"type\":\"response.in_progress\",\"response\":{\"id\":\"resp_0137cf30a4752bdf016abc91b6263487d19ea9f96c7605459a\",\"object\":\"response\",\"created_at\":1790742966,\"status\":\"in_progress\",\"access_programs\":null,\"background\":false,\"completed_at\":null,\"error\":null,\"frequency_penalty\":0.0,\"incomplete_details\":null,\"instructions\":\"You are concise.\",\"max_output_tokens\":2000,\"max_tool_calls\":null,\"model\":\"gpt-5-nano-2025-08-07\",\"moderation\":null,\"output\":[],\"parallel_tool_calls\":true,\"presence_penalty\":0.0,\"previous_response_id\":null,\"prompt_cache_key\":null,\"prompt_cache_retention\":\"in_memory\",\"reasoning\":{\"context\":\"current_turn\",\"effort\":\"medium\",\"mode\":\"standard\",\"summary\":null},\"safety_identifier\":null,\"service_tier\":\"auto\",\"store\":false,\"temperature\":1.0,\"text\":{\"format\":{\"type\":\"text\"},\"verbosity\":\"medium\"},\"tool_choice\":\"auto\",\"tool_usage\":{\"image_gen\":{\"input_tokens\":0,\"input_tokens_details\":{\"image_tokens\":0,\"text_tokens\":0},\"output_tokens\":0,\"output_tokens_details\":{\"image_tokens\":0,\"text_tokens\":0},\"total_tokens\":0},\"web_search\":{\"num_requests\":0}},\"tools\":[],\"top_logprobs\":0,\"top_p\":1.0,\"truncation\":\"disabled\",\"usage\":null,\"user\":null,\"metadata\":{}},\"sequence_number\":1}\n\nevent: response.output_item.added\ndata: {\"p\": \"01\", \"type\":\"response.output_item.added\",\"item\":{\"id\":\"rs_0137cf30a4752bdf016abc91b69ae887d1af96950defb06f97\",\"type\":\"reasoning\",\"content\":[],\"encrypted_content\":\"gAAAAABqvJG2MoCXBYbRlRsokydYprE0lt8iLr1a1iUQbNLeerXyd1MY4Fm9MfjJLFaGzGPJy6wwZUZmm6nsZ7LP1VprwIAnv2kfNTBoO57je5cZ78dkzJzOOLYnQyaiSPrbXTXKG8JQfKrrt0qN7x5-eiXD-SIcQa8E9Or_ZugNqIYn7UfiS3YC5Xupjij5eCgl43kmMzNLNoQgBOv5sTQkj4saT7b0NltrY_coexW7o7HA3YJU02_aKqV6YSKKKMzZkVUw8Qt71Jwbg28x-Udpk9Wk6uzqqMSFRchkQJ4oT8HGsFO6MfHo-eLUNqGI24ZJlYcHI_CVW8IkjcpGWtv7dHzoOIAbQ3tTx09taixBP3PvaIcD9Qn5YsUV7dE3NncXID-eAnjgs0WmP9Tz8vvLXZrYiV4Ry0S_gIAUPFKC-3Z9e7yQ395JWPeWk7K1eT9y0FmTGHNZ6MVfzqBahukSbogL1Q1izblwxu6dTVMfQbo0n7IEi6HhfDYIzsHNbpYDDL54yG0ncHNy4fSu4dnYjuZrokgqThIOCrpeYcJq7xTN9cTU5L-AQz9_EEraVt2swKnl-4sJ1V8k6j0eJIZMK8yTAgOAUiI3jFBLscCRGjmmWLft2UDMt8h6SoKFXyDmTyRZJ2Mbm0wBIvKmH-EZM5-xc2T_57XV9vI-BaPZYrbxT7jtOuK8oqnpZRtLGyDKiUYxibnU1J2AUh3HbXz-nMrnjA6WxU9NXCVf-1WnVQyJfFAIRD0Kpbt6c6rXOJw7aMGLHATOFFG4716vVg79CvT-ll9_AsUNQwyby8sRUYi-Y05x4vxPnkegilDuhnytDt6uYqNRFertTCaSCIg-u96yHrg3r8T9zBpy3UqogKq2pkG-WrkNxIwEa0LMOqlwQwrnIDf72eV9wFpg9M67ezVptNFTkCLi3BOB4Gfi4SFkmOBBE4tfjymktfUWGk9g1uAa3VAsRRSBcbMqwbnSS9s1flwOp7NkHffGHdDP6bo66Y-YcsryokhHWi1s3ikK7cvp5n6BdpypWLRQq4za25PGf3uj7c17XKM6YoiV36wuu4AKp6XAX2iJ1cIDIqLETLmPJowSL7bj-Nodly_VatRK8h4yjbCExGdk6WURCo93KaEc1h9lbFKuRWeYGNPIByblnILU4JSoOm40K1aP0DT_KKJ6Gg==\",\"summary\":[]},\"output_index\":0,\"sequence_number\":2}\n\nevent: response.output_item.done\ndata: {\"p\": \"2fe6743f311de\", \"type\":\"response.output_item.done\",\"item\":{\"id\":\"rs_0137cf30a4752bdf016abc91b69ae887d1af96950defb06f97\",\"type\":\"reasoning\",\"content\":[],\"encrypted_content\":\"gAAAAABqvJG3gRV3VHJfHPkeyz8hrmbpzFNdsSUxXsSgIJAc7Z5rVjrK-eBH6uM3cuwf6oFRHDk5gl3tjbkubNIsNuX9QWS5qKZmni4YyzHa00eDWaF0mdEB41BiwcO085Ef-zgU9dsblogPVbaAkCx9AG01rLpeJvmEZrG3ZceeHDer7iebUpvoFSeBLRnuUn192MSKUTF0602CdbtQvzI39HuCijTVGiEh4dWgs5BoAvnD0tfNeWrXZBOueaf_CFInJPuoR4eyAORHV5pTn8fbAEiv8mVqKvHI0OL7GvA0E1Yg7c5rlrLgJj0Ey6P5POAYCL7KOkT3kw1LKbA4glCNOiZC54XWY2V7jI1bgquxOgj0FG3Gstl9B7IMncSTuNgKZONEJ9LWWVWOtLl6kMRq0gLZqhpKUoNqkgKpiS7noUkEQJJ7n-tv1djLIfrHdwWDO2XJhb0ouXC6qgn-TKnu1eBKCaGcWvKLine truncated
}
}
]
}
@@ -0,0 +1,56 @@
{
"version": 1,
"metadata": {
"provider": "cloudflare-ai-gateway",
"route": "cloudflare-ai-gateway-responses",
"transport": "http",
"model": "gpt-5-nano",
"tags": [
"prefix:cloudflare-ai-gateway",
"provider:cloudflare-ai-gateway",
"tool",
"tool-loop",
"golden"
],
"name": "cloudflare-ai-gateway/cloudflare-ai-gateway-openai-gpt-5-nano-tool-loop",
"recordedAt": "2026-09-30T04:36:34.984Z"
},
"interactions": [
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/openai/responses",
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"gpt-5-nano\",\"input\":[{\"type\":\"message\",\"role\":\"user\",\"content\":[{\"type\":\"input_text\",\"text\":\"What is the weather in Paris?\"}]}],\"instructions\":\"Use the get_weather tool exactly once. After the tool result, reply exactly: Paris is sunny.\",\"tools\":[{\"type\":\"function\",\"name\":\"get_weather\",\"description\":\"Get current weather for a city.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"],\"additionalProperties\":false},\"strict\":false}],\"store\":false,\"include\":[\"reasoning.encrypted_content\"],\"max_output_tokens\":2000,\"stream\":true}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream; charset=utf-8"
},
"body": "event: response.created\ndata: {\"p\": \"d82f1d10b60\", \"type\":\"response.created\",\"response\":{\"id\":\"resp_06bc195765a8c9c7016abc91ce40f887d189169a2d89f2ee42\",\"object\":\"response\",\"created_at\":1790742990,\"status\":\"in_progress\",\"access_programs\":null,\"background\":false,\"completed_at\":null,\"error\":null,\"frequency_penalty\":0.0,\"incomplete_details\":null,\"instructions\":\"Use the get_weather tool exactly once. After the tool result, reply exactly: Paris is sunny.\",\"max_output_tokens\":2000,\"max_tool_calls\":null,\"model\":\"gpt-5-nano-2025-08-07\",\"moderation\":null,\"output\":[],\"parallel_tool_calls\":true,\"presence_penalty\":0.0,\"previous_response_id\":null,\"prompt_cache_key\":null,\"prompt_cache_retention\":\"in_memory\",\"reasoning\":{\"context\":\"current_turn\",\"effort\":\"medium\",\"mode\":\"standard\",\"summary\":null},\"safety_identifier\":null,\"service_tier\":\"auto\",\"store\":false,\"temperature\":1.0,\"text\":{\"format\":{\"type\":\"text\"},\"verbosity\":\"medium\"},\"tool_choice\":\"auto\",\"tool_usage\":{\"image_gen\":{\"input_tokens\":0,\"input_tokens_details\":{\"image_tokens\":0,\"text_tokens\":0},\"output_tokens\":0,\"output_tokens_details\":{\"image_tokens\":0,\"text_tokens\":0},\"total_tokens\":0},\"web_search\":{\"num_requests\":0}},\"tools\":[{\"type\":\"function\",\"description\":\"Get current weather for a city.\",\"name\":\"get_weather\",\"output_schema\":null,\"parameters\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"],\"additionalProperties\":false},\"strict\":false}],\"top_logprobs\":0,\"top_p\":1.0,\"truncation\":\"disabled\",\"usage\":null,\"user\":null,\"metadata\":{}},\"sequence_number\":0}\n\nevent: response.in_progress\ndata: {\"p\": \"0b0cb44c44\", \"type\":\"response.in_progress\",\"response\":{\"id\":\"resp_06bc195765a8c9c7016abc91ce40f887d189169a2d89f2ee42\",\"object\":\"response\",\"created_at\":1790742990,\"status\":\"in_progress\",\"access_programs\":null,\"background\":false,\"completed_at\":null,\"error\":null,\"frequency_penalty\":0.0,\"incomplete_details\":null,\"instructions\":\"Use the get_weather tool exactly once. After the tool result, reply exactly: Paris is sunny.\",\"max_output_tokens\":2000,\"max_tool_calls\":null,\"model\":\"gpt-5-nano-2025-08-07\",\"moderation\":null,\"output\":[],\"parallel_tool_calls\":true,\"presence_penalty\":0.0,\"previous_response_id\":null,\"prompt_cache_key\":null,\"prompt_cache_retention\":\"in_memory\",\"reasoning\":{\"context\":\"current_turn\",\"effort\":\"medium\",\"mode\":\"standard\",\"summary\":null},\"safety_identifier\":null,\"service_tier\":\"auto\",\"store\":false,\"temperature\":1.0,\"text\":{\"format\":{\"type\":\"text\"},\"verbosity\":\"medium\"},\"tool_choice\":\"auto\",\"tool_usage\":{\"image_gen\":{\"input_tokens\":0,\"input_tokens_details\":{\"image_tokens\":0,\"text_tokens\":0},\"output_tokens\":0,\"output_tokens_details\":{\"image_tokens\":0,\"text_tokens\":0},\"total_tokens\":0},\"web_search\":{\"num_requests\":0}},\"tools\":[{\"type\":\"function\",\"description\":\"Get current weather for a city.\",\"name\":\"get_weather\",\"output_schema\":null,\"parameters\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"],\"additionalProperties\":false},\"strict\":false}],\"top_logprobs\":0,\"top_p\":1.0,\"truncation\":\"disabled\",\"usage\":null,\"user\":null,\"metadata\":{}},\"sequence_number\":1}\n\nevent: response.output_item.added\ndata: {\"p\": \"608c6368a0c703ea\", \"type\":\"response.output_item.added\",\"item\":{\"id\":\"rs_06bc195765a8c9c7016abc91ce881c87d18e71310b9a21b3ca\",\"type\":\"reasoning\",\"content\":[],\"encrypted_content\":\"gAAAAABqvJHOLa_CYgj0Ynl-_tBncVpCPOfdueKV7-3xsbVVIXhZFUdhtEfjPYHW85-TecrFUmkr7jMw4OsT2Zckq7xkxVfZ8kXNObzjU6N6t35hp8hIJ9CbGmJBsxZBQceHHtZgQrOVWCKJ7z1B1k5zsJ8lbSRkLVAahsCEwg-tYDzQAkYUcqlK7VS62sKLLfDMYpSMCvv-y-5v9I4S74P0D2Zr7znJBap72RK0tHjN-d3vdjOaxMMkLP8JlK6-HlOWabzVEPWmsdXFPFzjWuRjAOn5ILrcQzu5T8kPLjon2kW4XuwwcXeI_7UvFmt9yRfkTlVFVr-hRcSad9AjBHHYx3nmvlhM2nVuKggGolqpwdKLR87sccTmbo0kzYp8Av1yHPJ6xKxAIJYZO_XDdvXGK1vu6WFqxe37LXpWIAvJ1BbXo7yMdV2tZshqP2WBiYdILkMiZFV4VDuzuOYEx3_56QyL4sdh0p3_mxXfgjEiLNzloBrq9VtPL1YLucqzAZwCDuhtwKLC3zZ1awSC_exx7thmBbULObOBfOhWN9oIG53MrLbpJVN4MlENvtLoq7l_92k0VbPcOGDgJcmJjYOy-p7P_YDQ_Y9WR0oNpCNRFfarqGBOzegO7_UPRVUEKJeb3xx2e6-9HnrjC9jyAFs4MI54uNfKMbF7a6p55NWaEtvbTn3124XDaUD2qeSChCoAv2KFXxTIIyQeOVgVBQbHW8IamL9Eh0RvjEpg5WZqgRK4QdRZ8fiFL3lLV5stsqVvNz_1LAnGs4bnH69pmmlfO0E2C8LLhLhRVh9hcEXnKwpA6URICdn58uEPKVr9tDmTyaJbiZx_4lPbVSQ_T2ncKL8pL8gK4odQDdhe_XjdqF9i5N_t29H8A3XUDkXOgd5zyMepV1GCfKm7DaJHYXIIIjr_q4xheZFzxMl1KMQX_a9xbc-KRvOj2apHphqo5TsmYOFl5QYyt3wWllpmUZ6c9oSVOg159RFyR7UUdjGJDN8aN9pXlDjxYjR76Q9Xvmun2duw37Abi7TXl2BzJ2Bq9VFLGW_7CB_kv0vxNijP2K2XuD0Ge8tfM7HfU_gFXN-WXym5GdN6DMCxAg7whaBAj9su1wEaI11VQBTF0s41glo-V4DTcLyKTNFjScck_6a_vEnmFE57IEToGK_akhdx_SzKS9rHrA==\",\"summary\":[]},\"output_index\":0,\"sequence_number\":2}\n\neveLine truncated
}
},
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/openai/responses",
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"gpt-5-nano\",\"input\":[{\"type\":\"message\",\"role\":\"user\",\"content\":[{\"type\":\"input_text\",\"text\":\"What is the weather in Paris?\"}]},{\"type\":\"reasoning\",\"id\":\"rs_06bc195765a8c9c7016abc91ce881c87d18e71310b9a21b3ca\",\"summary\":[],\"encrypted_content\":\"gAAAAABqvJHSN68IWwhWq9YTPxs-e-OeLdOqfdkkIEP_1hc9f7k6yH9tGZKLUC2OPF0avZ7xaJQp8iOR_gPt3z0TGQ1T0e4M9OR6boMFOA_C4TwinAF1POgbZLI-0SUDkAm1PZSaO0Ic7DBh1rRT6biled_-iWs0ke3FP3nFZit5Ve16AI1TdL4c9QERNCcZFsD5neV8eBeABWarZ8SMFfxcYJ5y8QkpDOL1ShqenD22Df7fDy8cdkYWybEEZcAfgXWSfQK2hRwSNYN_BDV9CfKj-cUTePwf0D2vLm-2xd9LGt-KiLPbsp9EpGXP41ra6-qHRLeu7MO64XWIu2vsf9qAflOjp7MOSuTJ3ZvDQoTNRs-pEam8-kRYRC07Hj9IzC0sjreE1NPVzz-Yuw79gqaQokfVmuznok8XoBFKLjQ1Sa9-i8Ano4lXOKz6APnXXBdbbSUBvNV3jlmqvtxhyZ2u901SuIxZcSmPY5aAEsaHiSm2lTIuHXr6f1WZcKOsR88U4ymlI-wSGKMKJT5hh9xxvSw4VQxcbjfMBllDpH6dg3X_AUwmN6JFVWZsl1QFyaTAt3LsbUY6xfuh_IbuO30tPnG5tlUrluJdXGloRCH11NFB7wjLQ3aR1DTSxjlfce9xxfX0OdZsrIeL0Z03kveHI5ZkIjp4xQo_VAGkU-tiQ8Dyx5DYiAR-sCYaOqNwzxKWVc5YYohZKpHjpCBel0pzDgUADDWyube45tOIDVyeefNjIfmRuDnJ9ZZhi45JY4E8kRviu00sFlfVxDdKLwnykuYBEeU6RCQSx6yVr5zxErvtqEbcrz3XvNJhOiNL6n_I8D6dd4muE7j43BrQgI_ae5dakGyvy83JLyeylqZKak5GIwq7KjymQQIWMVdQIfTuF4n6HbaYLcoYZthe9WdGjo3nnBkyn08Voor8OFycbUxS6qm-siAYU_0CgG29fDgorAb9F4DmFEM_Lg0ymYyBAEXsnm9EilD0rndz-tKthJN1e53CvZZlCfhbBKxjU-hTeiBeE49YIsM7KueWdCTNetU_gSeGipB-UU-sDJMvHUR0sclIenUIMC0MSNPuUBGdzTDjQBVKmJZvKUy8NJBghXHYEzCxZRdO_qnn-FIq731ZhqA-G58_48T-tovQF3JlygWW8d-XH4PzjgSR0YK4Ucpo-d8AcY0u-2HsEv6TaxgUvBnot_kPBxFhCpdLj6nbesLCAZkvmM1erBl-ew6ztD1FSt2MIg2Nr9vqOL-cQeH9zGX0OqXrbWWqCrOJkLSoq7ST-Fq6cQhvM_6KUw_mhgWHHuYy-68EgzyzZ7K7lQAx379F2Fiv2U3SR9JCWvtja5YigRBqM7PwxIyYs_o0y4p19UZg5jTx0TyR-pVXw1_CcknqmrGginPv2zKvbRlnRm-cIEO0mWsfwUgN7DzGSKa06zoEStd-aVprHolQ4_l3oFtTUVhymo4SO5VMAWVZLrGuZNn2PRifFZlvYl00Dt1RAMG0FguNGMcLn0-0hzxio-5psReiIguJfurRHnsk3tPyYwYqILmCng1OW5ytJvRUkWYgZ_esuD_9gnHyL58mYyW5MsqFmWeMoOGeDPde9ggHqf1uAZ6NxGbpco7njgxOhPKEKkr0bMXWmn31C1wh7VM2TkwhD2M9apFLQ1eX4wHl6hZsbknl1LdZrY3pLIL_SkAL6xnfxfCcA7hGli6fnlOVhLQC4WEIR-h7zJqeK60SF9-AZt6l3LwnQru5e5aIwKWv0xqS5VLf6mOmCRC0HVAJBdYRKU2CImoih7pey6HV7-JP1nxOTiK2teo5uI2PUrMLTV_oAh-O3SFkvX8eZ0LgGDF3s-AgEq3G-Hs5qNEeX7rcyUWeTZ63HZ2w7e4R1STF0pulnJW91So2vjF9aEBFY2AkpM-rSx2kKl-xYG3UMX-57Gbw0PPTNgnhwbP1AjAlPfG3TAt6Df8ouxUYsCsnA5tZna5e4QOQW1ZcEoesgJxy24QeaJN4OUHRBlmzEQ4d20rtNJL2wsed0HXdLSU427NicPdioL1lYVHXxlnU0tQEbQbLFQzIsh2WJaFqkDsBOTrN6HXTgUfY85cDo39Rm5u6gAEnJpef8NXpeqTim5oBASsqra5hZEjYi5PkFHNcLI663eNzFLlYix73_pVIcMch6YsHg6Z8JWLo7Xhz5vN4IqxEH8Qya_odYAkNpYN_kT1oTeo4MDqs0IpvPmj6tIylYRoW3txAnatsxge0l6HGa4_tG4dP_t91rsTJTzR8wsOsQZpnrKtuYEv5WlfuvpgeITrloDcWQOxq9VeqdYFdNEJPevIwvmEIA-udNoo-Ho31ZxhbODdI9p9nOLQ9lRxBVA__VOCNJisDFVLt_PyDevENtme1qJTe-RvsCuQBhTVffUPTpc4ez7V9V8CiTN37yb2VkMtHcmxcyNYiGdwIaMe3WKS_W9bM7Fqil1LX6mVu-49CnWp7SNRHXlvCeNfFWo_DvKiu8g6aMy-th-kdRSrMjKJ_6R_5ph0GKyGkF5sirhUf6W-S5s2WnV-3yj9Y0IbNWUr8xHK6SXgOXhSLfdLcJbedHNdIXIggd-jzLcAi5F_qkRV67g1W9IKQGwTzIFvoJrlq3gChxHzyrD3gOPYiAirj_6Kh2tO8iyEtEzXPNaIWHqxPnoHC2f79AA6S1rzzt1e0IPLyo0KrCeNWPb1lUsKDKOuxPB8_v6mp1LbSxAw-qWDcgHpHrM6Hve90fw-xSyRY1ZOJ14NsJE85vw2rqSo7AJtBQC2SrIsyKy5Q7rKC2lkQeyWdpCJOEslvHPTbNTftWXs9qZKSGhHXhY2_MCR5_jetBl33KKpIqOvJZs4nkaz2tmyCbFAmfQgcreiOYA1qGNWvPNJWUifd8GZHvDiemO37ZvLew3WCloB2bsn1urkN8OGmK2-NcL3jtVr0T7fRSvGG8BETDPUDtLvg2wAQeV0kGfM6dH37ED8auPcWxygz8cDD1ni8QoPpdlHsH55kL38rEerrgI_fEcAsAGqXacW8-07vKLDt_dJ4cmSVq-DVTIw-EQIrhBOf3gW8W5LP2_sVA2mjchwWP2mZ-v-zEeYVtkzCWznJCqFbeatyxHv5Q2phnWkxj2d-lsELVDHHRXPlB-MqUBsYLAhhPJzRC9n76EoOVdgr5bsfP1XQlYj_WdPdZ13HpGZyj7ZfIPRazmYlw-EBURIYzOHlilo0Hk7pLZ5Im7E5XtLXjb0r4MaUZltViFS7Za7lm1yeVmrA0k-X4T8lgTqaBpr5BnnVVTPUNB2701N4_Z3tPxFxO3Bi_wGVVqB19D1hZGyNCXHqxlvvvPozHi3gV6Oh5ElPb4_wWTJeXJTqPI_gcnExs8Z-AnwTST6Dbw1u4EBUapdXDNcC3PD6YHlQ2Cn0lUD3TMFjGZiTL3UQADwKHEtH8R45QIEadT7O8p1pVWhzFsdOZbNdc160iViD3A920MHSRcJ_pLhxwuyndMEfzJEInv3s7lIxcJtc_VVruYr-ce24eD57jf23TsXgBEkFBsGFvORSUtds_eviuK4_wjijz33Aeydm3SqMi_DfFoy0CDSLe7qnvWBda9IF4MRlvcR-N8qgZW_vjx3OkfiUUF2PDlw1tmXhSuiF1IoPusUWZQ7QD2aEEBD_RXaipdCy_Lh7yDEw9CtdEb332MLvzFgUPBLSWWyrA6gYQwpEiJHFrQMDetsaFFL-A5188dSPLjtXi9KkxGsA5wEbA1FcvABrHOBo_Ws8V3wzIuHl7uo7PO6FGIZB-d0RZiAw7AP5cVjG0udCWmQPpS0WVF5slSNmKgZjr9WD20w9yaliZOiPN_2A2w9Zx_ca4YBceORZ69irPy0xCKQJBlq0HMeZV_WzQATzbV0n8oyfx3CB12oF9JYn_4C5vqC_QnlGmUMFno3F1ZP94Tv7XqyDTt_JTAK_xppfVJEX7018apcF2w40aM5kp6_Clv0lb7AOkGWFKOAI7qOoraTldZh6ik_1DuJqKno7k0Qtc8RnRdQjNRhXJDfb1oqRBYvBfNQkROULiOoNx2yJdp7wvMjqah7WYE1wnKbftTPLjPDQDoc=\"},{\"type\":\"function_call\",\"id\":\"fc_06bc195765a8c9c7016abc91d247ec87d19e4f16354641a20f\",\"call_id\":\"call_RN4tTgQaJ61I5FoTePK9mpHu\",\"name\":\"get_weather\",\"arguments\":\"{\\\"city\\\":\\\"Paris\\\"}\"},{\"type\":\"function_call_output\",\"call_id\":\"call_RN4tTgQaJ61I5FoTePK9mpHu\",\"output\":\"{\\\"temperature\\\":22,\\\"condition\\\":\\\"sunny\\\"}\"}],\"instructions\":\"Use the get_weather tool exactly once. After the tool result, reply exactly: Paris is sunny.\",\"tools\":[{\"type\":\"function\",\"name\":\"get_weather\",\"description\":\"Get current weather for a city.\",\"parametLine truncated
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream; charset=utf-8"
},
"body": "event: response.created\ndata: {\"p\": \"aa3530\", \"type\":\"response.created\",\"response\":{\"id\":\"resp_06bc195765a8c9c7016abc91d296d887d1bb460e087f742d90\",\"object\":\"response\",\"created_at\":1790742994,\"status\":\"in_progress\",\"access_programs\":null,\"background\":false,\"completed_at\":null,\"error\":null,\"frequency_penalty\":0.0,\"incomplete_details\":null,\"instructions\":\"Use the get_weather tool exactly once. After the tool result, reply exactly: Paris is sunny.\",\"max_output_tokens\":2000,\"max_tool_calls\":null,\"model\":\"gpt-5-nano-2025-08-07\",\"moderation\":null,\"output\":[],\"parallel_tool_calls\":true,\"presence_penalty\":0.0,\"previous_response_id\":null,\"prompt_cache_key\":null,\"prompt_cache_retention\":\"in_memory\",\"reasoning\":{\"context\":\"current_turn\",\"effort\":\"medium\",\"mode\":\"standard\",\"summary\":null},\"safety_identifier\":null,\"service_tier\":\"auto\",\"store\":false,\"temperature\":1.0,\"text\":{\"format\":{\"type\":\"text\"},\"verbosity\":\"medium\"},\"tool_choice\":\"auto\",\"tool_usage\":{\"image_gen\":{\"input_tokens\":0,\"input_tokens_details\":{\"image_tokens\":0,\"text_tokens\":0},\"output_tokens\":0,\"output_tokens_details\":{\"image_tokens\":0,\"text_tokens\":0},\"total_tokens\":0},\"web_search\":{\"num_requests\":0}},\"tools\":[{\"type\":\"function\",\"description\":\"Get current weather for a city.\",\"name\":\"get_weather\",\"output_schema\":null,\"parameters\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"],\"additionalProperties\":false},\"strict\":false}],\"top_logprobs\":0,\"top_p\":1.0,\"truncation\":\"disabled\",\"usage\":null,\"user\":null,\"metadata\":{}},\"sequence_number\":0}\n\nevent: response.in_progress\ndata: {\"p\": \"a6b66d35bc20b2b\", \"type\":\"response.in_progress\",\"response\":{\"id\":\"resp_06bc195765a8c9c7016abc91d296d887d1bb460e087f742d90\",\"object\":\"response\",\"created_at\":1790742994,\"status\":\"in_progress\",\"access_programs\":null,\"background\":false,\"completed_at\":null,\"error\":null,\"frequency_penalty\":0.0,\"incomplete_details\":null,\"instructions\":\"Use the get_weather tool exactly once. After the tool result, reply exactly: Paris is sunny.\",\"max_output_tokens\":2000,\"max_tool_calls\":null,\"model\":\"gpt-5-nano-2025-08-07\",\"moderation\":null,\"output\":[],\"parallel_tool_calls\":true,\"presence_penalty\":0.0,\"previous_response_id\":null,\"prompt_cache_key\":null,\"prompt_cache_retention\":\"in_memory\",\"reasoning\":{\"context\":\"current_turn\",\"effort\":\"medium\",\"mode\":\"standard\",\"summary\":null},\"safety_identifier\":null,\"service_tier\":\"auto\",\"store\":false,\"temperature\":1.0,\"text\":{\"format\":{\"type\":\"text\"},\"verbosity\":\"medium\"},\"tool_choice\":\"auto\",\"tool_usage\":{\"image_gen\":{\"input_tokens\":0,\"input_tokens_details\":{\"image_tokens\":0,\"text_tokens\":0},\"output_tokens\":0,\"output_tokens_details\":{\"image_tokens\":0,\"text_tokens\":0},\"total_tokens\":0},\"web_search\":{\"num_requests\":0}},\"tools\":[{\"type\":\"function\",\"description\":\"Get current weather for a city.\",\"name\":\"get_weather\",\"output_schema\":null,\"parameters\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"],\"additionalProperties\":false},\"strict\":false}],\"top_logprobs\":0,\"top_p\":1.0,\"truncation\":\"disabled\",\"usage\":null,\"user\":null,\"metadata\":{}},\"sequence_number\":1}\n\nevent: response.output_item.added\ndata: {\"p\": \"169cd8bd840\", \"type\":\"response.output_item.added\",\"item\":{\"id\":\"msg_06bc195765a8c9c7016abc91d2e9dc87d1bc4d4524c7f3037d\",\"type\":\"message\",\"status\":\"in_progress\",\"content\":[],\"role\":\"assistant\"},\"output_index\":0,\"sequence_number\":2}\n\nevent: response.content_part.added\ndata: {\"p\": \"045e323978cf3\", \"type\":\"response.content_part.added\",\"content_index\":0,\"item_id\":\"msg_06bc195765a8c9c7016abc91d2e9dc87d1bc4d4524c7f3037d\",\"output_index\":0,\"part\":{\"type\":\"output_text\",\"annotations\":[],\"logprobs\":[],\"text\":\"\"},\"sequence_number\":3}\n\nevent: response.output_text.delta\ndata: {\"p\": \"42af845ab126d6\", \"type\":\"response.output_text.delta\",\"content_index\":0,\"delta\":\"Paris\",\"item_id\":\"msg_06bc195765a8c9c7016abc91d2e9dc87d1bc4d4524c7f3037d\",\"logprobs\":[],\"obfuscation\":\"WAn5iJo53hF\",\"output_index\":0,\"sequence_number\":4}\n\nevent: response.output_text.delta\ndata: {\"p\": \"aa473d2c7c859\", \"type\":\"response.output_text.delta\",\"content_index\":0,\"delta\":\" is\",\"item_id\":\"msg_06bc195765a8c9c7016abc91d2e9dc87d1bc4d4524c7f3037d\",\"logprobs\":[],\"obfuscation\":\"uH1AD585J0MVU\",\"output_index\":0,\"sequence_number\":5}\n\nevent: response.output_text.delta\ndata: {\"p\": \"8\", \"type\":\"response.output_text.delta\",\"content_index\":0,\"delta\":\" sunny\",\"item_id\":\"msg_06bc195765a8c9c7016abc91d2e9dc87d1bc4d4524c7f3037d\",\"logprobs\":[],\"obfuscaLine truncated
}
}
]
}
@@ -0,0 +1,49 @@
{
"version": 1,
"metadata": {
"tags": [
"prefix:cohere",
"provider:cohere"
],
"name": "cohere/continues-a-native-tool-call",
"recordedAt": "2026-10-02T02:36:16.143Z"
},
"interactions": [
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://api.cohere.com/v2/chat",
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"command-a-plus-05-2026\",\"messages\":[{\"role\":\"system\",\"content\":\"Use the get_weather tool exactly once. After the tool result, reply exactly: Paris is sunny.\"},{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is the weather in Paris?\"}]}],\"stream\":true,\"tools\":[{\"type\":\"function\",\"function\":{\"name\":\"get_weather\",\"description\":\"Get current weather for a city.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"],\"additionalProperties\":false}}}],\"max_tokens\":2048}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event: message-start\ndata: {\"id\":\"a57af21c-0496-4123-8e83-bcc6abb9bcae\",\"type\":\"message-start\",\"delta\":{\"message\":{\"role\":\"assistant\",\"content\":[],\"tool_plan\":\"\",\"tool_calls\":[],\"citations\":[]}}}\n\nevent: content-start\ndata: {\"type\":\"content-start\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"type\":\"thinking\",\"thinking\":\"\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\"The\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" user\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" is\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" asking\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" about\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" the\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" weather\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" in\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" Paris\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\".\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" I\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" have\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" access\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" to\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" a\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" get\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\"_weather\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" function\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" that\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" takes\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" a\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" city\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" parameter\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\".\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" The\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" instructions\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" say\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" to\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" use\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" the\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" get\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\"_weather\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" tool\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" exactly\"}}}}\n\nevent: conteLine truncated
}
},
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://api.cohere.com/v2/chat",
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"command-a-plus-05-2026\",\"messages\":[{\"role\":\"system\",\"content\":\"Use the get_weather tool exactly once. After the tool result, reply exactly: Paris is sunny.\"},{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is the weather in Paris?\"}]},{\"role\":\"assistant\",\"content\":[{\"type\":\"thinking\",\"thinking\":\"The user is asking about the weather in Paris. I have access to a get_weather function that takes a city parameter. The instructions say to use the get_weather tool exactly once, and then reply exactly \\\"Paris is sunny\\\" after getting the tool result.\\n\\nLet me call the get_weather function with \\\"Paris\\\" as the city parameter.\"}],\"tool_calls\":[{\"id\":\"get_weather_mdhvw7kbf1e3\",\"type\":\"function\",\"function\":{\"name\":\"get_weather\",\"arguments\":\"{\\\"city\\\":\\\"Paris\\\"}\"}}]},{\"role\":\"tool\",\"content\":\"{\\\"temperature\\\":22,\\\"condition\\\":\\\"sunny\\\"}\",\"tool_call_id\":\"get_weather_mdhvw7kbf1e3\"}],\"stream\":true,\"tools\":[{\"type\":\"function\",\"function\":{\"name\":\"get_weather\",\"description\":\"Get current weather for a city.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"],\"additionalProperties\":false}}}],\"max_tokens\":2048}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event: message-start\ndata: {\"id\":\"fd1ac100-b2c5-42f4-ae1c-6de65aa5ef6a\",\"type\":\"message-start\",\"delta\":{\"message\":{\"role\":\"assistant\",\"content\":[],\"tool_plan\":\"\",\"tool_calls\":[],\"citations\":[]}}}\n\nevent: content-start\ndata: {\"type\":\"content-start\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"type\":\"thinking\",\"thinking\":\"\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\"The\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" tool\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" result\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" shows\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" that\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" Paris\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" has\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" sunny\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" weather\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" with\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" a\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" temperature\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" of\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" 22\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" degrees\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\".\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" According\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" to\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" the\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" instructions\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\",\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" after\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" getting\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" the\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" tool\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" result\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\",\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" I\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" need\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" to\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" reply\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" exactly\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\":\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" \\\"\"}}}}\n\nevent: cLine truncated
}
}
]
}
@@ -0,0 +1,31 @@
{
"version": 1,
"metadata": {
"tags": [
"prefix:cohere",
"provider:cohere"
],
"name": "cohere/streams-compatible-chat-reasoning",
"recordedAt": "2026-10-02T02:39:47.406Z"
},
"interactions": [
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://api.cohere.ai/compatibility/v1/chat/completions",
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"command-a-reasoning-08-2025\",\"messages\":[{\"role\":\"user\",\"content\":\"What is 17 times 23? Answer briefly.\"}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"reasoning_effort\":\"high\",\"max_tokens\":2048}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "data: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\"\",\"role\":\"assistant\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\"Okay\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\",\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\" so\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\" I\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\" need\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\" to\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\" figure\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\" out\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\" what\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\" 1\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\"7\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\" multiplied\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\" by\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\" 2\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\"3\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"index\":0,\"finish_reason\":null,\"delta\":{\"reasoning_content\":\" is\"},\"logprobs\":null}],\"created\":1790908779,\"model\":\"command-a-reasoning-08-2025\",\"object\":\"chat.completion.chunk\",\"usage\":null}\n\ndata: {\"id\":\"52b1dec0-5396-46a4-9897-9e0adf56038b\",\"choices\":[{\"indLine truncated
}
}
]
}
@@ -0,0 +1,31 @@
{
"version": 1,
"metadata": {
"tags": [
"prefix:cohere",
"provider:cohere"
],
"name": "cohere/streams-native-text-and-usage",
"recordedAt": "2026-10-02T02:36:12.967Z"
},
"interactions": [
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://api.cohere.com/v2/chat",
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"command-a-03-2025\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"Reply exactly: OK\"}]}],\"stream\":true,\"max_tokens\":64}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event: message-start\ndata: {\"id\":\"a171b3a5-db11-4445-a645-5221fb466ab8\",\"type\":\"message-start\",\"delta\":{\"message\":{\"role\":\"assistant\",\"content\":[],\"tool_plan\":\"\",\"tool_calls\":[],\"citations\":[]}}}\n\nevent: content-start\ndata: {\"type\":\"content-start\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"type\":\"text\",\"text\":\"\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"text\":\"OK\"}}}}\n\nevent: content-end\ndata: {\"type\":\"content-end\",\"index\":0}\n\nevent: message-end\ndata: {\"type\":\"message-end\",\"delta\":{\"finish_reason\":\"COMPLETE\",\"usage\":{\"billed_units\":{\"input_tokens\":4,\"output_tokens\":1},\"tokens\":{\"input_tokens\":499,\"output_tokens\":4},\"cached_tokens\":464}}}\n\ndata: [DONE]\n\n"
}
}
]
}
@@ -0,0 +1,31 @@
{
"version": 1,
"metadata": {
"tags": [
"prefix:cohere",
"provider:cohere"
],
"name": "cohere/streams-native-thinking-with-a-budget",
"recordedAt": "2026-10-02T02:36:14.669Z"
},
"interactions": [
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://api.cohere.com/v2/chat",
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"command-a-reasoning-08-2025\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 17 times 23? Answer briefly.\"}]}],\"stream\":true,\"thinking\":{\"type\":\"enabled\",\"token_budget\":128},\"max_tokens\":2048}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "event: message-start\ndata: {\"id\":\"305edbbe-9f86-4bc0-9490-7766b168a453\",\"type\":\"message-start\",\"delta\":{\"message\":{\"role\":\"assistant\",\"content\":[],\"tool_plan\":\"\",\"tool_calls\":[],\"citations\":[]}}}\n\nevent: content-start\ndata: {\"type\":\"content-start\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"type\":\"thinking\",\"thinking\":\"\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\"Okay\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\",\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" let\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\"'s\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" see\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\".\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" I\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" need\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" to\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" figure\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" out\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" what\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" 1\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\"7\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" multiplied\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" by\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" 2\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\"3\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" is\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\".\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" H\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\"mm\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\",\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" how\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" do\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" I\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" do\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" this\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\"?\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" I\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" remember\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" some\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" multiplication\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",\"index\":0,\"delta\":{\"message\":{\"content\":{\"thinking\":\" methods\"}}}}\n\nevent: content-delta\ndata: {\"type\":\"content-delta\",Line truncated
}
}
]
}
@@ -0,0 +1,54 @@
{
"version": 1,
"metadata": {
"model": "openai-gpt-5-nano",
"tags": [
"prefix:digitalocean-chat",
"provider:digitalocean",
"protocol:digitalocean-chat",
"cache",
"tool",
"tool-loop"
],
"name": "digitalocean-chat/gpt-nano-continues-a-tool-call-with-cache-markers",
"recordedAt": "2026-10-01T07:36:41.717Z"
},
"interactions": [
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://inference.do-ai.run/v1/chat/completions",
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"openai-gpt-5-nano\",\"messages\":[{\"role\":\"system\",\"content\":[{\"type\":\"text\",\"text\":\"Use the get_weather tool exactly once. After the tool result, reply exactly: Paris is sunny.\",\"cache_control\":{\"type\":\"ephemeral\"}}]},{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is the weather in Paris?\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"tools\":[{\"type\":\"function\",\"function\":{\"name\":\"get_weather\",\"description\":\"Get current weather for a city.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"],\"additionalProperties\":false},\"strict\":false},\"cache_control\":{\"type\":\"ephemeral\"}}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"store\":false,\"reasoning_effort\":\"minimal\",\"max_completion_tokens\":1024}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "data: {\"choices\":[{\"delta\":{\"content\":\"\",\"role\":\"assistant\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1790840200,\"id\":\"chatcmpl-EU5dIREwFebLDdrnmX7ftaDIK4qrZ\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[{\"delta\":{\"tool_calls\":[{\"function\":{\"arguments\":\"\",\"name\":\"get_weather\"},\"id\":\"call_zPwN7xhG4uXQINkufgtjVJ7L\",\"index\":0,\"type\":\"function\"}]},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1790840200,\"id\":\"chatcmpl-EU5dIREwFebLDdrnmX7ftaDIK4qrZ\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[{\"delta\":{\"tool_calls\":[{\"function\":{\"arguments\":\"{\\\"\"},\"index\":0,\"type\":\"function\"}]},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1790840200,\"id\":\"chatcmpl-EU5dIREwFebLDdrnmX7ftaDIK4qrZ\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[{\"delta\":{\"tool_calls\":[{\"function\":{\"arguments\":\"city\"},\"index\":0,\"type\":\"function\"}]},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1790840200,\"id\":\"chatcmpl-EU5dIREwFebLDdrnmX7ftaDIK4qrZ\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[{\"delta\":{\"tool_calls\":[{\"function\":{\"arguments\":\"\\\":\\\"\"},\"index\":0,\"type\":\"function\"}]},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1790840200,\"id\":\"chatcmpl-EU5dIREwFebLDdrnmX7ftaDIK4qrZ\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[{\"delta\":{\"tool_calls\":[{\"function\":{\"arguments\":\"Paris\"},\"index\":0,\"type\":\"function\"}]},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1790840200,\"id\":\"chatcmpl-EU5dIREwFebLDdrnmX7ftaDIK4qrZ\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[{\"delta\":{\"tool_calls\":[{\"function\":{\"arguments\":\"\\\"}\"},\"index\":0,\"type\":\"function\"}]},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1790840200,\"id\":\"chatcmpl-EU5dIREwFebLDdrnmX7ftaDIK4qrZ\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[{\"delta\":{},\"finish_reason\":\"tool_calls\",\"index\":0,\"logprobs\":null}],\"created\":1790840200,\"id\":\"chatcmpl-EU5dIREwFebLDdrnmX7ftaDIK4qrZ\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[],\"created\":1790840200,\"id\":\"chatcmpl-EU5dIREwFebLDdrnmX7ftaDIK4qrZ\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\",\"usage\":{\"cache_created_input_tokens\":0,\"cache_creation\":{\"ephemeral_1h_input_tokens\":0,\"ephemeral_5m_input_tokens\":0},\"cache_read_input_tokens\":0,\"completion_tokens\":23,\"completion_tokens_details\":{\"reasoning_tokens\":0},\"prompt_tokens\":155,\"prompt_tokens_details\":{\"cached_tokens\":0},\"speed\":null,\"total_tokens\":178}}\n\ndata: [DONE]\n\n"
}
},
{
"transport": "http",
"request": {
"method": "POST",
"url": "https://inference.do-ai.run/v1/chat/completions",
"headers": {
"content-type": "application/json"
},
"body": "{\"model\":\"openai-gpt-5-nano\",\"messages\":[{\"role\":\"system\",\"content\":[{\"type\":\"text\",\"text\":\"Use the get_weather tool exactly once. After the tool result, reply exactly: Paris is sunny.\",\"cache_control\":{\"type\":\"ephemeral\"}}]},{\"role\":\"user\",\"content\":\"What is the weather in Paris?\"},{\"role\":\"assistant\",\"content\":null,\"tool_calls\":[{\"id\":\"call_zPwN7xhG4uXQINkufgtjVJ7L\",\"type\":\"function\",\"function\":{\"name\":\"get_weather\",\"arguments\":\"{\\\"city\\\":\\\"Paris\\\"}\"}}]},{\"role\":\"tool\",\"tool_call_id\":\"call_zPwN7xhG4uXQINkufgtjVJ7L\",\"content\":[{\"type\":\"text\",\"text\":\"{\\\"temperature\\\":22,\\\"condition\\\":\\\"sunny\\\"}\",\"cache_control\":{\"type\":\"ephemeral\"}}]}],\"tools\":[{\"type\":\"function\",\"function\":{\"name\":\"get_weather\",\"description\":\"Get current weather for a city.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"],\"additionalProperties\":false},\"strict\":false},\"cache_control\":{\"type\":\"ephemeral\"}}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"store\":false,\"reasoning_effort\":\"minimal\",\"max_completion_tokens\":1024}"
},
"response": {
"status": 200,
"headers": {
"content-type": "text/event-stream"
},
"body": "data: {\"choices\":[{\"delta\":{\"content\":\"\",\"role\":\"assistant\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1790840201,\"id\":\"chatcmpl-EU5dJprTkE7OHEKnmvot7rR0LSo5L\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[{\"delta\":{\"content\":\"Paris\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1790840201,\"id\":\"chatcmpl-EU5dJprTkE7OHEKnmvot7rR0LSo5L\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[{\"delta\":{\"content\":\" is\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1790840201,\"id\":\"chatcmpl-EU5dJprTkE7OHEKnmvot7rR0LSo5L\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[{\"delta\":{\"content\":\" sunny\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1790840201,\"id\":\"chatcmpl-EU5dJprTkE7OHEKnmvot7rR0LSo5L\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[{\"delta\":{\"content\":\".\"},\"finish_reason\":null,\"index\":0,\"logprobs\":null}],\"created\":1790840201,\"id\":\"chatcmpl-EU5dJprTkE7OHEKnmvot7rR0LSo5L\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\",\"index\":0,\"logprobs\":null}],\"created\":1790840201,\"id\":\"chatcmpl-EU5dJprTkE7OHEKnmvot7rR0LSo5L\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"choices\":[],\"created\":1790840201,\"id\":\"chatcmpl-EU5dJprTkE7OHEKnmvot7rR0LSo5L\",\"model\":\"openai-gpt-5-nano\",\"object\":\"chat.completion.chunk\",\"usage\":{\"cache_created_input_tokens\":0,\"cache_creation\":{\"ephemeral_1h_input_tokens\":0,\"ephemeral_5m_input_tokens\":0},\"cache_read_input_tokens\":0,\"completion_tokens\":13,\"completion_tokens_details\":{\"reasoning_tokens\":0},\"prompt_tokens\":193,\"prompt_tokens_details\":{\"cached_tokens\":0},\"speed\":null,\"total_tokens\":206}}\n\ndata: [DONE]\n\n"
}
}
]
}
Loaded 100 of 2058 files, more files were not shown because too many files have changed in this diff. Show more