fix: opencode zen gateway compat (muse-spark 1.3 via opencode-go sub) - #46
Conversation
- openai responses: don't duplicate /v1 when base URL already has version segment - openai responses: dedupe repeated call_ids across turns (relay mints per-request call_1..) - anthropic: same no-dup-version-segment handling for /messages endpoint - compatible: share base_url_has_version_segment helper from providers/mod - catalog extensions: skip patch-fragments for unknown models instead of fabricating hollow entries
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Deploying crabcode with
|
| Latest commit: |
b8a552d
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://bbc13d59.crabcode.pages.dev |
| Branch Preview URL: | https://fix-opencode-zen-gateway-com.crabcode.pages.dev |
PR Review —
|
Makes muse-spark-1.3-contributor usable on crabcode through the opencode-go subscription gateway (
https://opencode.ai/zen/go/v1). Three request-path bugs, all gateway-specific — no behavior change for first-party providers (OpenAI/Anthropic/xAI mint unique ids and versionless base URLs, so the new code paths are no-ops for them).What broke
Session
xcx605ghifzhcdkqvil5wwwydied on step 1 with:plus two latent gateway issues found while pairing on the session: a
/v1/v1/responses404 and a hollow catalog entry from theFailed to deserialize catalog extension model {provider_id}/{model_id}log line.Changes
call_ids (src/aisdk/providers/openai.rs): the zen relay mints sequential per-request ids (call_1,call_2, … restarting every request), so after two tool turns the replayed history repeats ids and the Responses validator 400s. Newdedupe_responses_call_idspass inbuild_openai_messages(single choke point for HTTP + websocket bodies) rewrites repeats to{id}_dupNon both thefunction_calland its matching output (occurrence-indexed pairing), dropping stale responseitem.ids on rewritten calls. First occurrence untouched.src/aisdk/providers/{mod,openai,anthropic,compatible}.rs): sharedbase_url_has_version_segmenthelper; default Responses path becomes/responses(not/v1/responses) and Anthropic/messages(not/v1/messages) when the base URL already carries/vN.compatible.rsnow reuses the helper instead of its local copy.src/model/extensions/mod.rs): a{"attachment": true}-style fragment for a model absent from models.dev no longer fabricates a hollow entry with wrong defaults (tool_call=false, no limits/cost); it's skipped with a descriptive log (also fixes the unformatted{provider_id}/{model_id}log line) until models.dev carries the model or the spec is completed.Verification
dedupes_repeated_call_ids_across_turns_for_responses_input,default_responses_path_does_not_duplicate_v1_in_base_url,messages_url_does_not_duplicate_version_segment,detects_version_segment_in_base_url,catalog_extensions_patch_fragment_for_unknown_model_is_skippedcargo test --bin crabcode aisdk::providers→ 88 passed;model::extensions→ 19 passedcargo fmtclean,scripts/check-aisdk-boundary.shok.devrefs: neither opencode (packages/llm/src/protocols/openai-responses.ts) nor grok-build (xai-grok-sampling-types/.../responses.rs) needs this because first-party backends mint globally-unique ids — this is purely a relay-compat shim.Follow-ups (not in scope)
src/llm/client.rshas_call) drops the 2ndcall_1. Consider uniquifying on ingest.