@bitkyc08/opencodex 2.60.0 → 2.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_INSTALL.md +64 -0
- package/README.md +28 -1
- package/bin/ocx.mjs +382 -209
- package/gui/dist/assets/App-CH6C5H7x.js +50 -0
- package/gui/dist/assets/Tray-CLZh48fM.js +1 -0
- package/gui/dist/assets/index-_bpvxJu0.css +1 -0
- package/gui/dist/assets/index-wpTOyepx.js +86 -0
- package/gui/dist/assets/usage-companion-chart-a0N58rRI.js +1 -0
- package/gui/dist/favicon.png +0 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/stepfun-color.svg +1 -0
- package/package.json +5 -1
- package/src/adapters/anthropic.ts +16 -0
- package/src/adapters/coding-agent/protocol.ts +36 -6
- package/src/adapters/coding-agent/turn.ts +10 -2
- package/src/adapters/command-code.ts +2 -1
- package/src/adapters/cursor/catalog.ts +51 -7
- package/src/adapters/cursor/protobuf-request.ts +6 -3
- package/src/adapters/cursor/request-builder.ts +13 -3
- package/src/adapters/cursor.ts +11 -2
- package/src/adapters/declaration-carrier.ts +45 -0
- package/src/adapters/devin.ts +75 -23
- package/src/adapters/google-antigravity-wire.ts +5 -2
- package/src/adapters/google-errors.ts +7 -1
- package/src/adapters/google.ts +29 -5
- package/src/adapters/image.ts +4 -1
- package/src/adapters/input-media-guard.ts +21 -9
- package/src/adapters/kiro/usage.ts +3 -2
- package/src/adapters/kiro-tool-fallback.ts +1 -1
- package/src/adapters/ollama-native.ts +6 -0
- package/src/adapters/openai-chat/developer-role.ts +61 -0
- package/src/adapters/openai-chat/messages.ts +46 -27
- package/src/adapters/openai-chat/parallel-tool-calls.ts +32 -0
- package/src/adapters/openai-chat/passthrough.ts +33 -9
- package/src/adapters/openai-chat/reasoning-wire.ts +89 -0
- package/src/adapters/openai-chat.ts +18 -57
- package/src/adapters/openai-responses/passthrough.ts +2 -0
- package/src/adapters/registry.ts +3 -2
- package/src/adapters/run-turn-queue.ts +178 -29
- package/src/adapters/xai-web-search.ts +16 -1
- package/src/bridge/errors.ts +8 -2
- package/src/bridge/response-json.ts +9 -1
- package/src/bridge/sse.ts +10 -0
- package/src/chat/inbound.ts +141 -5
- package/src/claude/desktop-3p.ts +7 -1
- package/src/claude/desktop-first-party.ts +183 -0
- package/src/claude/desktop-gateway-state.ts +41 -0
- package/src/claude/inbound-content-options.ts +6 -0
- package/src/claude/inbound.ts +32 -6
- package/src/claude/intercept/connect-proxy.ts +179 -0
- package/src/claude/intercept/listener.ts +122 -0
- package/src/claude/intercept/local-ca.ts +298 -0
- package/src/claude/intercept/runtime.ts +98 -0
- package/src/claude/intercept/settings.ts +189 -0
- package/src/cli/access.ts +87 -0
- package/src/cli/account-auth.ts +19 -0
- package/src/cli/capabilities.ts +31 -0
- package/src/cli/claude-desktop.ts +206 -16
- package/src/cli/codex-shim-autorestore.ts +3 -0
- package/src/cli/companion.ts +56 -0
- package/src/cli/dispatch.ts +43 -4
- package/src/cli/ensure-desired-integrations.ts +43 -5
- package/src/cli/help.ts +7 -9
- package/src/cli/index.ts +200 -61
- package/src/cli/init.ts +8 -0
- package/src/cli/integrations.ts +7 -1
- package/src/cli/registry.ts +41 -2
- package/src/cli/resolve.ts +230 -0
- package/src/cli/root.ts +24 -1
- package/src/cli/start-ownership-publication.ts +56 -0
- package/src/cli/status-probes.ts +2 -18
- package/src/cli/status.ts +62 -0
- package/src/cli/stop-report.ts +143 -0
- package/src/cli/uninstall-plan.ts +9 -0
- package/src/client/machine-listener.ts +2 -5
- package/src/clients/aside-profiles.ts +4 -0
- package/src/clients/config-export/zcode-store.ts +157 -0
- package/src/clients/config-export.ts +36 -0
- package/src/codex/app-server-processes.ts +72 -40
- package/src/codex/auth-api/login-flow.ts +6 -1
- package/src/codex/autostart-health.ts +28 -0
- package/src/codex/catalog/build-entries.ts +2 -2
- package/src/codex/catalog/effort.ts +3 -3
- package/src/codex/catalog/provider-models.ts +24 -15
- package/src/codex/catalog/retained-sync.ts +2 -2
- package/src/codex/convergence.ts +2 -2
- package/src/codex/history-provider.ts +12 -1
- package/src/codex/inject/config-toml.ts +41 -6
- package/src/codex/inject/paginated-openai-compat.ts +90 -0
- package/src/codex/inject.ts +18 -15
- package/src/codex/injected-marker.ts +18 -0
- package/src/codex/main-account.ts +6 -0
- package/src/codex/model-cache.ts +52 -6
- package/src/codex/model-entitlement-admission.ts +59 -0
- package/src/codex/model-entitlements.ts +87 -44
- package/src/codex/native-main-admission.ts +83 -0
- package/src/codex/routing/health-store.ts +39 -0
- package/src/codex/routing/selection.ts +37 -1
- package/src/codex/routing.ts +5 -41
- package/src/codex/shim-templates.ts +29 -3
- package/src/companion/settings.ts +132 -0
- package/src/config/atomic-write.ts +117 -5
- package/src/config/load-degrade.ts +34 -7
- package/src/config/process-state.ts +1 -1
- package/src/config/schema/config-schema.ts +27 -1
- package/src/config/schema/leaf-validators.ts +47 -0
- package/src/config.ts +1 -1
- package/src/generated/compatibility-version.json +418 -174
- package/src/integrations/config-io.ts +44 -10
- package/src/integrations/merge.ts +120 -13
- package/src/integrations/mutation-plan.ts +124 -18
- package/src/integrations/registry.ts +38 -0
- package/src/integrations/state.ts +78 -45
- package/src/integrations/target.ts +208 -0
- package/src/integrations/writer.ts +49 -11
- package/src/lab/conformance/fixture-provider.ts +5 -0
- package/src/lib/browser-launch-notice.ts +59 -0
- package/src/lib/bun-runtime.ts +6 -2
- package/src/lib/debug.ts +40 -0
- package/src/lib/open-url.ts +51 -7
- package/src/lib/package-tree-integrity.ts +2 -1
- package/src/lib/package-version.ts +8 -0
- package/src/lib/provider-egress.ts +310 -0
- package/src/lib/provider-outbound.ts +59 -14
- package/src/lib/proxy-env.ts +82 -7
- package/src/lib/request-execution-budget.ts +72 -0
- package/src/lib/request-failure-attribution.ts +183 -0
- package/src/lib/request-failure-model.ts +236 -0
- package/src/lib/request-resend-gate.ts +138 -0
- package/src/lib/standalone.ts +16 -0
- package/src/lib/upstream-retry.ts +167 -16
- package/src/lib/winsw.ts +2 -2
- package/src/oauth/index.ts +24 -1
- package/src/oauth/login-cli.ts +80 -29
- package/src/providers/api-key-resolve.ts +133 -0
- package/src/providers/api-key-selection.ts +5 -1
- package/src/providers/key-failover.ts +31 -1
- package/src/providers/key-store.ts +34 -110
- package/src/providers/model-rename-fields.ts +147 -0
- package/src/providers/model-rename-migration.ts +124 -37
- package/src/providers/quota/vendor-probes-key.ts +37 -22
- package/src/providers/reasoning-metadata.ts +43 -18
- package/src/providers/registry/entries-core.ts +9 -4
- package/src/providers/registry/entries-extended.ts +29 -4
- package/src/providers/registry/model-seeds.ts +47 -10
- package/src/providers/xai-transport.ts +12 -1
- package/src/reasoning-effort.ts +8 -0
- package/src/responses/function-call-compat.ts +38 -1
- package/src/responses/inline-document.ts +65 -0
- package/src/responses/input-media.ts +42 -8
- package/src/responses/muse-tool-name-alias.ts +19 -0
- package/src/responses/parser-content.ts +8 -2
- package/src/responses/parser-tools.ts +3 -0
- package/src/responses/parser.ts +3 -1
- package/src/responses/schema.ts +3 -0
- package/src/router.ts +17 -2
- package/src/server/admission-model-scope.ts +219 -0
- package/src/server/audio-live.ts +9 -3
- package/src/server/audio-upstream.ts +18 -0
- package/src/server/auth-cors.ts +26 -0
- package/src/server/chat-completions.ts +55 -2
- package/src/server/chat-native.ts +19 -4
- package/src/server/claude-messages.ts +55 -17
- package/src/server/grok-responses-snapshot-repair.ts +113 -11
- package/src/server/gui-freshness.ts +103 -0
- package/src/server/gui-static.ts +7 -9
- package/src/server/images.ts +59 -6
- package/src/server/index/claude-intercept-lifecycle.ts +49 -0
- package/src/server/index/serve-options.ts +56 -10
- package/src/server/index/spend-ledger-lifecycle.ts +34 -8
- package/src/server/index/startup-warnings.ts +24 -0
- package/src/server/index.ts +21 -28
- package/src/server/lifecycle.ts +4 -4
- package/src/server/live-call-bindings.ts +6 -0
- package/src/server/live.ts +88 -3
- package/src/server/management/agent-settings-routes.ts +121 -36
- package/src/server/management/companion-routes.ts +77 -0
- package/src/server/management/logs-usage-routes.ts +19 -0
- package/src/server/management/native-integration-routes.ts +103 -6
- package/src/server/management/oauth-account-routes.ts +45 -7
- package/src/server/management/route-registry.ts +6 -0
- package/src/server/management/shared.ts +18 -1
- package/src/server/management/usage-timeline-routes.ts +44 -0
- package/src/server/management-api.ts +8 -9
- package/src/server/proxy-liveness.ts +75 -0
- package/src/server/relay.ts +19 -2
- package/src/server/request-log-failure-attribution.ts +99 -0
- package/src/server/request-log.ts +114 -0
- package/src/server/request-metrics.ts +92 -30
- package/src/server/responses/codex-ws-wire.ts +34 -8
- package/src/server/responses/combo-stream-preflight.ts +168 -6
- package/src/server/responses/compact.ts +11 -0
- package/src/server/responses/core-opaque-recovery.ts +90 -0
- package/src/server/responses/fetch-helpers.ts +124 -8
- package/src/server/responses/input-admission.ts +10 -0
- package/src/server/responses/passthrough-delivery.ts +14 -1
- package/src/server/responses/passthrough-dispatch.ts +179 -35
- package/src/server/responses/passthrough-error.ts +27 -8
- package/src/server/responses/request-prepare.ts +42 -1
- package/src/server/responses/request-send-budget.ts +12 -0
- package/src/server/responses/request-transport.ts +24 -4
- package/src/server/responses/reset-replay.ts +108 -0
- package/src/server/responses-request-tool-scope.ts +214 -0
- package/src/server/responses-undeclared-tool-guard.ts +4 -1
- package/src/server/search.ts +25 -1
- package/src/server/usage-ledger-retention.ts +73 -0
- package/src/service/cli.ts +48 -2
- package/src/service/health.ts +3 -2
- package/src/service/install-state-contract.d.mts +27 -0
- package/src/service/install-state-contract.mjs +34 -0
- package/src/service/launchd.ts +1 -1
- package/src/service/orchestration.ts +2 -4
- package/src/service/ownership-compatibility.ts +164 -0
- package/src/service/ownership-mutation-lease.d.mts +32 -0
- package/src/service/ownership-mutation-lease.mjs +211 -0
- package/src/service/repair.ts +45 -1
- package/src/service/state-lock.ts +269 -0
- package/src/service/state-record.d.mts +36 -0
- package/src/service/state-record.mjs +138 -0
- package/src/service/state.ts +582 -68
- package/src/service/windows-taskxml.ts +11 -10
- package/src/service.ts +7 -3
- package/src/tray/windows-tray.ps1 +1 -1
- package/src/types/config.ts +37 -0
- package/src/types/provider.ts +73 -0
- package/src/types/request.ts +28 -2
- package/src/types/tools.ts +19 -0
- package/src/types.ts +3 -0
- package/src/update/index.ts +207 -63
- package/src/update/job.ts +9 -5
- package/src/update/ownership-transaction.ts +47 -0
- package/src/update/restart-ownership.ts +54 -0
- package/src/update/runtime-ownership.d.mts +40 -0
- package/src/update/runtime-ownership.mjs +122 -0
- package/src/usage/attempt-delivery.ts +198 -0
- package/src/usage/cache-diagnostic.ts +305 -0
- package/src/usage/failure-fingerprint.ts +118 -0
- package/src/usage/failure-projection-cache.ts +174 -0
- package/src/usage/failure-projection.ts +174 -0
- package/src/usage/ledger-retention.ts +165 -0
- package/src/usage/log.ts +126 -79
- package/src/usage/request-outcome.ts +150 -0
- package/src/usage/retention-contract.ts +28 -0
- package/src/usage/summary.ts +2 -2
- package/src/usage/telemetry-contract.ts +237 -0
- package/src/usage/timeline.ts +236 -0
- package/src/web-search/alpha-search.ts +21 -1
- package/gui/dist/assets/index-BTuCbqQd.css +0 -1
- package/gui/dist/assets/index-DoBVdPHP.js +0 -134
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e}from"./index-wpTOyepx.js";var t={anthropic:`claude-color.svg`,"anthropic-apikey":`claude-color.svg`,"azure-openai":`openai.svg`,chatgpt:`openai.svg`,"cloudflare-ai-gateway":`cloudflare-ai-gateway-color.svg`,"cloudflare-workers-ai":`cloudflare-ai-gateway-color.svg`,cline:`cline-color.svg`,"cline-pass":`cline-color.svg`,"command-code":`commandcode-color.svg`,commandcode:`commandcode-color.svg`,cursor:`cursor-color.svg`,deepseek:`deepseek-color.svg`,devin:`devin.svg`,firepass:`firepass-color.svg`,fireworks:`fireworks-color.svg`,github:`github-copilot-color.svg`,"github-copilot":`copilot-color.svg`,"gitlab-duo":`gitlab-duo-color.svg`,google:`gemini-color.svg`,"google-antigravity":`antigravity-color.svg`,"google-vertex":`gemini-color.svg`,groq:`groq-color.svg`,huggingface:`huggingface-color.svg`,kimi:`kimi-color.svg`,"kimi-code":`kimi-color.svg`,kiro:`kiro-color.svg`,"lm-studio":`lm-studio-color.svg`,"meta-model":`meta.svg`,"meta-muse":`meta.svg`,mistral:`mistral-color.svg`,minimax:`minimax.svg`,"minimax-cn":`minimax.svg`,moonshot:`moonshot-color.svg`,nvidia:`nvidia-color.svg`,ollama:`ollama-color.svg`,"ollama-cloud":`ollama-color.svg`,openai:`openai.svg`,"openai-apikey":`openai.svg`,"opencode-free":`opencode.svg`,"opencode-go":`opencode.svg`,"opencode-zen":`opencode.svg`,openrouter:`openrouter-color.svg`,opper:`opper.svg`,qianfan:`qianfan-color.svg`,qoder:`qoder.svg`,"qoder-cn":`qoder.svg`,alibaba:`alibaba-color.svg`,"alibaba-token-plan":`alibaba-color.svg`,"alibaba-token-plan-intl":`alibaba-color.svg`,baseten:`baseten.svg`,bizrouter:`bizrouter.svg`,cerebras:`cerebras.svg`,crusoe:`crusoe.svg`,deepinfra:`deepinfra.svg`,digitalocean:`digitalocean.svg`,featherless:`featherless.svg`,hyperbolic:`hyperbolic.svg`,kilo:`kilo.svg`,nanogpt:`nanogpt.svg`,nebius:`nebius.svg`,neuralwatt:`neuralwatt.svg`,nous:`nous.svg`,novita:`novita.svg`,orcarouter:`orcarouter.svg`,"orcarouter-oauth":`orcarouter.svg`,packycode:`packycode.svg`,parallel:`parallel.svg`,sambanova:`sambanova.svg`,scaleway:`scaleway.svg`,stepfun:`stepfun-color.svg`,siliconflow:`siliconflow.svg`,synthetic:`synthetic.svg`,together:`together.svg`,umans:`umans.svg`,venice:`venice.svg`,vultr:`vultr.svg`,litellm:`litellm.svg`,zenmux:`zenmux.svg`,zai:`zai.svg`,"zhipu-bigmodel":`zai.svg`,"zhipu-bigmodel-coding":`zai.svg`,"qwen-cloud":`qwen-portal-color.svg`,"vercel-ai-gateway":`vercel-ai-gateway-color.svg`,vllm:`vllm-color.svg`,xai:`grok.svg`,"mimo-free":`xiaomi-color.svg`,mimo:`xiaomi-color.svg`,xiaomi:`xiaomi-color.svg`,"xiaomi-mimo":`xiaomi-color.svg`},n={anthropic:`Anthropic Claude`,"anthropic-apikey":`Anthropic Claude`,chatgpt:`ChatGPT`,openai:`OpenAI (Codex login)`,"openai-apikey":`OpenAI API`,"azure-openai":`Azure OpenAI`,"cloudflare-ai-gateway":`Cloudflare AI Gateway`,"cloudflare-workers-ai":`Cloudflare Workers AI`,cline:`Cline`,"cline-pass":`ClinePass`,nvidia:`NVIDIA NIM`,ollama:`Ollama`,"ollama-cloud":`Ollama Cloud`,xai:`xAI Grok`,"mimo-free":`MiMo Free`,xiaomi:`Xiaomi`,cursor:`Cursor`,deepseek:`DeepSeek`,devin:`Devin`,github:`GitHub`,"github-copilot":`GitHub Copilot`,"gitlab-duo":`GitLab Duo`,openrouter:`OpenRouter`,opper:`Opper`,"opencode-go":`OpenCode Go`,"opencode-free":`OpenCode Free`,"opencode-zen":`OpenCode Zen`,orcarouter:`OrcaRouter - API`,"orcarouter-oauth":`OrcaRouter - Auth`,packycode:`PackyCode`,mistral:`Mistral`,groq:`Groq`,"meta-model":`Meta Model API`,"meta-muse":`Muse Code`,alibaba:`Alibaba Coding Plan`,"alibaba-token-plan":`Alibaba Token Plan`,"alibaba-token-plan-intl":`Alibaba Token Plan (Intl)`,kimi:`Kimi`,"kimi-code":`Kimi`,moonshot:`Moonshot`,google:`Google`,"google-vertex":`Google Vertex`,"lm-studio":`LM Studio`,huggingface:`Hugging Face`,"qwen-cloud":`Qwen Cloud`,siliconflow:`SiliconFlow`,stepfun:`StepFun`,"tencent-coding-plan":`Tencent Cloud Coding Plan`,codebuddy:`CodeBuddy`,"codebuddy-cn":`CodeBuddy CN`,qoder:`Qoder`,"qoder-cn":`Qoder CN`,"vercel-ai-gateway":`Vercel AI Gateway`,vllm:`vLLM`,litellm:`LiteLLM`},r={"command-code":`provider.name.commandCodeAuth`,commandcode:`provider.name.commandCodeApi`,orcarouter:`provider.name.orcaRouterApi`,"orcarouter-oauth":`provider.name.orcaRouterAuth`,volcengine:`provider.name.volcengine`,"volcengine-coding-plan":`provider.name.volcengineCodingPlan`,"volcengine-agent-plan":`provider.name.volcengineAgentPlan`},i=new Set([...Object.keys(n),...Object.keys(r)]);function a(e){let n=e.toLowerCase();return Object.hasOwn(t,n)?t[n]:void 0}function o(e,t){let n=a(e);return n?`/provider-icons/${n}`:void 0}var s=new Set([`cerebras.svg`,`deepinfra.svg`,`neuralwatt.svg`,`nous.svg`,`novita.svg`,`packycode.svg`,`opper.svg`,`siliconflow.svg`,`synthetic.svg`,`zenmux.svg`,`grok.svg`,`kimi-color.svg`,`ollama-color.svg`,`opencode.svg`,`vercel-ai-gateway-color.svg`]),c=new Set([`baseten.svg`,`kilo.svg`,`sambanova.svg`,`venice.svg`,`zai.svg`]),l=new Set([`bizrouter.svg`,`featherless.svg`,`hyperbolic.svg`,`nebius.svg`,`parallel.svg`,`umans.svg`]);function u(e){if(!e)return`image`;let t=e.split(`/`).pop()??``;return s.has(t)?`mask`:c.has(t)?`plate`:l.has(t)?`dark-plate`:`image`}function d(e,t){let i=e.toLowerCase(),a=Object.hasOwn(r,i)?r[i]:void 0;return a?t(a):(Object.hasOwn(n,i)?n[i]:void 0)||(e===i&&/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(e)?e.split(`-`).map(e=>e&&e[0].toUpperCase()+e.slice(1)).join(` `):e)}function f(e){return i.has(e.toLowerCase())}function p(e){return e===`command-code`?`commandcode-auth`:e===`commandcode`?`commandcode-api`:e}function m(e,t){let n=e.indexOf(`/`);if(n<=0)return e;let r=e.slice(0,n),i=e.slice(n+1);if(r===`command-code`||r===`commandcode`){let e=i.match(/^([a-z0-9]+)-([a-z0-9]+(?:-[a-z0-9]+)+)$/i);return e&&i.startsWith(`${e[1]}-${e[1]}-`)&&(i=i.slice(e[1].length+1)),`${r===`command-code`?`commandcode-auth`:`commandcode-api`}/${i}`}return e}var h={ko:[{v:0x2386f26fc10000,s:`경`},{v:0xe8d4a51000,s:`조`},{v:1e8,s:`억`},{v:1e4,s:`만`}],zh:[{v:0x2386f26fc10000,s:`京`},{v:0xe8d4a51000,s:`兆`},{v:1e8,s:`亿`},{v:1e4,s:`万`}],"zh-TW":[{v:0x2386f26fc10000,s:`京`},{v:0xe8d4a51000,s:`兆`},{v:1e8,s:`億`},{v:1e4,s:`萬`}]};function g(e){return e.replace(/\.0+$/,``).replace(/(\.\d*?)0+$/,`$1`)}function _(e,t){let n=h[t];if(n){for(let t of n)if(e>=t.v)return`${g((e/t.v).toFixed(1))}${t.s}`;return String(e)}return e<1e4?String(e):e<1e6?`${g((e/1e3).toFixed(1))}K`:e<1e9?`${g((e/1e6).toFixed(1))}M`:e<0xe8d4a51000?`${g((e/1e9).toFixed(1))}B`:`${g((e/0xe8d4a51000).toFixed(1))}T`}var v=1e10;function y(e){return e<v?e*1e3:e}function b(e,t){let n=e=>typeof e==`number`&&Number.isFinite(e);if(!n(e.shortPercent)||e.shortPercent<100)return!1;let r=e.shortResetAt;if(!n(r)||r<=0){let r=e.shortObservedAt;if(!n(r))return!1;let i=t-r;return i>=0&&i<=3e5}return y(r)>t}function x(e){return{fiveHourAvailable:e?.shortWindowSeconds===18e3&&typeof e.shortResetAt==`number`,weeklyAvailable:typeof e?.weeklyResetAt==`number`}}function S(e){let t=e?.trim().toLowerCase();return t===`go`||t===`free`}function C(e,t){if(!e)return null;let n=e.shortPercent===void 0&&e.shortResetAt===void 0?e:{...e,fiveHourPercent:e.fiveHourPercent??e.shortPercent,fiveHourResetAt:e.fiveHourResetAt??e.shortResetAt};return S(t)?{...n.monthlyPercent===void 0?{}:{monthlyPercent:n.monthlyPercent},...n.monthlyResetAt===void 0?{}:{monthlyResetAt:n.monthlyResetAt},...n.creditsUsd===void 0?{}:{creditsUsd:n.creditsUsd},...n.resetCredits===void 0?{}:{resetCredits:n.resetCredits},updatedAt:n.updatedAt}:n}function w(e,t,n=Date.now()){if(!e)return null;let r=e=>typeof e==`number`&&Number.isFinite(e),i=r(e.fiveHourPercent)?e.fiveHourPercent:r(e.shortPercent)?e.shortPercent:void 0,a=(S(t)?[e.monthlyPercent]:[e.weeklyPercent,e.monthlyPercent]).filter(r);if(a.length===0)return b({...r(i)?{shortPercent:i}:{},...r(e.fiveHourResetAt??e.shortResetAt)?{shortResetAt:e.fiveHourResetAt??e.shortResetAt}:{},...r(e.shortObservedAt)?{shortObservedAt:e.shortObservedAt}:{}},n)?100:null;let o=r(i)?[...a,i]:a;return o.length?Math.max(...o):null}function T(e){let t=new URLSearchParams({hours:String(e.chartHours),bucketMinutes:String(e.bucketMinutes),metric:e.tokenMetric,aggregation:e.aggregation,grouping:e.chartGrouping});e.models?.length&&t.set(`models`,e.models.join(`,`));for(let n of e.hiddenProviders)t.append(`hiddenProvider`,n);return t}function E(e){return Array.isArray(e)&&e.length<=100&&e.every(e=>typeof e==`string`)?JSON.stringify([...new Set(e)].sort()):void 0}function D(e,t){let n=new Set(t.hiddenProviders),r=e.availableModels.filter(e=>!n.has(e.slice(0,e.indexOf(`/`))));if(t.models?.length===0)return{...e,series:[],availableModels:r};let i=t.models===null?null:new Set(t.models),a=i!==null||n.size>0,o=e.appliedFilters,s=!!o&&E(o.hiddenProviders)===E(t.hiddenProviders)&&(t.models===null?o.models===null:E(o.models)===E(t.models)),c=e.series.filter(e=>e.id===`other`&&e.provider===``?!a||s:!n.has(e.provider)&&(i===null||i.has(`${e.provider}/${e.model}`)||i.has(e.model)));return{...e,series:c,availableModels:r,truncated:e.truncated||(a||o!==void 0)&&!s}}var O={6:15,24:60,72:180,168:360};function k(e){return O[e]}function A(e){if(e<1e3)return String(Math.round(e));let t=[[0xe8d4a51000,`T`],[1e9,`B`],[1e6,`M`],[1e3,`K`]];for(let n=0;n<t.length;n+=1){let[r,i]=t[n];if(e>=r){let a=Math.round(e/r);if(a>=1e3&&n>0){let[r,i]=t[n-1];return`${Math.round(e/r)}${i}`}return`${a}${i}`}}return String(Math.round(e))}function j(e,t){let n=new Map;for(let r of e){let e=r.includes(`/`)?r.slice(0,r.indexOf(`/`)):r,i=n.get(e)??{provider:e,models:[],total:0},a=t.get(r)??0;i.models.push({id:r,total:a}),i.total+=a,n.set(e,i)}return Array.from(n.values()).map(e=>({...e,models:e.models.toSorted((e,t)=>t.total-e.total||e.id.localeCompare(t.id))})).toSorted((e,t)=>t.total-e.total||e.provider.localeCompare(t.provider))}function M(e,t,n,r){let i=new Set(t),a=new Set((e??t).filter(e=>i.has(e)));for(let e of n)r?a.add(e):a.delete(e);return t.length>0&&t.every(e=>a.has(e))?null:t.filter(e=>a.has(e))}function N(e,t=[]){let n={...e};if(typeof n.menuBarTemplate==`string`&&n.menuBarTemplate.trim()===``&&(n.menuBarTemplate=null),n.models!==void 0&&t.length>0){let e=n.models??[],r=new Set(e);e.length===t.length&&t.every(e=>r.has(e))&&(n.models=null)}return n}function P(e,t,n,r,i=8){let a=Math.max(0,t-i*2),o=Math.max(0,n-i*2),s=Math.max(r,1),c=Math.max(e.length-1,1);return e.map((e,t)=>`${i+a*t/c},${i+o*(1-Math.max(0,e)/s)}`).join(` `)}function F(e,t,n,r,i=8){let a=e[0]?.points.length??0;if(a===0)return[];let o=Math.max(0,t-i*2),s=Math.max(0,n-i*2),c=Math.max(r,1),l=Math.min(3,o/Math.max(a*8,1)),u=Math.max(0,o/a-l),d=[];for(let t=0;t<a;t+=1){let n=0;for(let r=0;r<e.length;r+=1){let f=s*Math.max(0,e[r]?.points[t]??0)/c;f>0&&d.push({x:i+o/a*t+l/2,y:i+s-n-f,width:u,height:f,seriesIndex:r,bucketIndex:t}),n+=f}}return d}var I=e(),L=[`#0A84FF`,`#FF9F0A`,`#30D158`,`#BF5AF2`,`#FF453A`,`#64D2FF`],R=640,z=160,B=28;function V(e,t){return Math.max(...t===`stackedBar`?Array.from({length:e.buckets},(t,n)=>e.series.reduce((e,t)=>e+(t.points[n]??0),0)):e.series.flatMap(e=>e.points),0)}function H(e,t){let n=new Intl.DateTimeFormat(t,{month:`short`,day:`numeric`}),r=Math.max(1,Math.floor((e.buckets-1)/3));return[0,1,2,3].map(t=>{let i=Math.min(e.buckets-1,t*r);return n.format(new Date((e.start+i*e.bucketSeconds)*1e3))})}function U({timeline:e,chartStyle:t,hours:n,loading:r,error:i,onRetry:a,locale:o,t:s}){if(r)return(0,I.jsx)(`div`,{className:`usage-companion-chart-skeleton`,"aria-busy":`true`,"aria-label":s(`usage.companion.loading`)});if(i)return(0,I.jsxs)(`div`,{className:`usage-companion-chart-state`,role:`alert`,children:[(0,I.jsx)(`span`,{children:s(`usage.companion.timelineUnavailable`)}),(0,I.jsx)(`button`,{type:`button`,className:`btn btn-ghost btn-sm`,onClick:a,children:s(`common.retry`)})]});if(!e||e.series.length===0)return(0,I.jsx)(`div`,{className:`usage-companion-chart-state`,children:s(`usage.companion.empty`,{hours:e?.buckets?Math.round(e.buckets*e.bucketSeconds/3600):n})});let c=V(e,t),l=H(e,o),u=B,d=l.map((e,t)=>(0,I.jsx)(`text`,{x:B+584*t/3,y:156,textAnchor:t===0?`start`:t===3?`end`:`middle`,className:`usage-companion-axis-label`,children:e},`${e}-${t}`)),f=t===`line`?e.series.map((e,t)=>(0,I.jsx)(`polyline`,{points:P(e.points,584,104,c,0),transform:`translate(${B},${B})`,fill:`none`,stroke:L[t%L.length],strokeWidth:`2`,strokeLinejoin:`round`,strokeLinecap:`round`},e.id)):F(e.series,584,104,c,0).map(e=>(0,I.jsx)(`rect`,{x:B+e.x,y:B+e.y,width:e.width,height:e.height,fill:L[e.seriesIndex%L.length],rx:`1`},`${e.bucketIndex}-${e.seriesIndex}`));return(0,I.jsxs)(`div`,{className:`usage-companion-chart`,children:[(0,I.jsxs)(`svg`,{viewBox:`0 0 ${R} ${z}`,role:`img`,"aria-label":s(`usage.companion.chartLabel`),children:[(0,I.jsx)(`line`,{x1:B,y1:u,x2:B,y2:132,className:`usage-companion-axis`}),(0,I.jsx)(`line`,{x1:B,y1:132,x2:612,y2:132,className:`usage-companion-axis`}),(0,I.jsx)(`text`,{x:24,y:32,textAnchor:`end`,className:`usage-companion-axis-label`,children:A(c)}),f,d]}),(0,I.jsx)(`div`,{className:`usage-companion-legend`,children:e.series.map((e,t)=>(0,I.jsxs)(`span`,{className:`usage-companion-legend-item`,children:[(0,I.jsx)(`span`,{className:`usage-companion-swatch`,style:{background:L[t%L.length]},"aria-hidden":`true`}),(0,I.jsx)(`span`,{children:e.id})]},e.id))}),e.truncated&&(0,I.jsx)(`p`,{className:`muted text-caption`,children:s(`usage.companion.olderRecordsSkipped`)})]})}export{u as _,T as a,M as c,x as d,_ as f,p as g,f as h,D as i,w as l,d as m,k as n,A as o,m as p,N as r,j as s,U as t,C as u,o as v};
|
package/gui/dist/favicon.png
CHANGED
|
Binary file
|
package/gui/dist/index.html
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
} catch (e) {}
|
|
17
17
|
})();
|
|
18
18
|
</script>
|
|
19
|
-
<script type="module" crossorigin src="/assets/index-
|
|
20
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
19
|
+
<script type="module" crossorigin src="/assets/index-wpTOyepx.js"></script>
|
|
20
|
+
<link rel="stylesheet" crossorigin href="/assets/index-_bpvxJu0.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
23
23
|
<div id="root"></div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>Stepfun</title><path d="M22.012 0h1.032v.927H24v.968h-.956V3.78h-1.032V1.896h-1.878v-.97h1.878V0zM2.6 12.371V1.87h.969v10.502h-.97zm10.423.66h10.95v.918h-6.208v9.579h-4.742V13.03zM5.629 3.333v12.356H0v4.51h10.386V8L20.859 8l-.003-4.668-15.227.001z" fill="url(#stepfun-gradient)" fill-rule="evenodd"/><defs><linearGradient id="stepfun-gradient" x1="1.646" y1="1.916" x2="18.342" y2="22.091" gradientUnits="userSpaceOnUse"><stop stop-color="#01A9FF"/><stop offset="1" stop-color="#0160FF"/></linearGradient></defs></svg>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitkyc08/opencodex",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.61.0",
|
|
4
4
|
"description": "Universal provider proxy for OpenAI Codex & Claude Code — use any LLM with Codex CLI/App/SDK and Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./bin/package-main.mjs",
|
|
@@ -49,6 +49,8 @@
|
|
|
49
49
|
"typecheck": "bun x tsc --noEmit",
|
|
50
50
|
"audit:high": "bun audit --audit-level=high && cd gui && bun audit --audit-level=high",
|
|
51
51
|
"privacy:scan": "bun scripts/privacy-scan.ts",
|
|
52
|
+
"favicons": "bun scripts/brand-favicons.ts",
|
|
53
|
+
"favicons:check": "bun scripts/brand-favicons.ts --check",
|
|
52
54
|
"skill:surface": "bun scripts/generate-ocx-skill-surface.ts",
|
|
53
55
|
"skill:surface:check": "bun scripts/generate-ocx-skill-surface.ts --check",
|
|
54
56
|
"structure:index": "bun scripts/structure-ssot.ts --fix",
|
|
@@ -58,6 +60,8 @@
|
|
|
58
60
|
"build:gui": "cd gui && bun install --frozen-lockfile && bun run build && cd .. && bun run prepare:package",
|
|
59
61
|
"build:remote-workspace-helper": "cargo build --release --locked --manifest-path native/remote-workspace-helper/Cargo.toml",
|
|
60
62
|
"test:remote-workspace-helper": "cargo test --locked --manifest-path native/remote-workspace-helper/Cargo.toml",
|
|
63
|
+
"build:standalone": "bun scripts/build-standalone.ts",
|
|
64
|
+
"test:macos": "swift run --package-path app MenuBarCoreTests",
|
|
61
65
|
"prepare:package": "bun scripts/prepare-package.ts",
|
|
62
66
|
"prepack": "bun run prepare:package",
|
|
63
67
|
"prepublishOnly": "bun run audit:high && bun run typecheck && bun run build:gui",
|
|
@@ -39,6 +39,16 @@ function toAnthropicContentPart(p: OcxContentPart): unknown {
|
|
|
39
39
|
: { type: "image", source: { type: "url", url: p.imageUrl } };
|
|
40
40
|
}
|
|
41
41
|
if (p.type === "video") return { type: "text", text: "[video]" };
|
|
42
|
+
// The block the caller sent, rebuilt. A Messages-to-Messages route used to reduce it to its
|
|
43
|
+
// title before any adapter ran, so the model was told a document existed rather than given
|
|
44
|
+
// one, and the answer came back looking the same (#5212).
|
|
45
|
+
if (p.type === "document") {
|
|
46
|
+
return {
|
|
47
|
+
type: "document",
|
|
48
|
+
source: { type: "base64", media_type: p.mediaType, data: p.data },
|
|
49
|
+
...(p.filename !== undefined ? { title: p.filename } : {}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
42
52
|
return { type: "text", text: p.text };
|
|
43
53
|
}
|
|
44
54
|
|
|
@@ -857,6 +867,12 @@ function toolsToAnthropicFormat(parsed: OcxParsedRequest, toolNames: { toWire: (
|
|
|
857
867
|
name: toolNames.toWire(namespacedToolName(t.namespace, t.name)),
|
|
858
868
|
description: t.description,
|
|
859
869
|
input_schema: normalizeAnthropicInputSchema(t.parameters),
|
|
870
|
+
// Anthropic is the target that DEFINES both of these, and both were dropped while the
|
|
871
|
+
// OpenAI Chat adapter already forwarded strict (#5210). Only an explicit `true` is
|
|
872
|
+
// emitted: the Messages inbound records an absent strict as `false`, so a false here
|
|
873
|
+
// cannot be distinguished from silence and must not become an opt-out on the wire.
|
|
874
|
+
...(t.strict === true ? { strict: true } : {}),
|
|
875
|
+
...(t.allowedCallers !== undefined ? { allowed_callers: [...t.allowedCallers] } : {}),
|
|
860
876
|
}));
|
|
861
877
|
return converted;
|
|
862
878
|
}
|
|
@@ -21,6 +21,30 @@ export const MAX_STREAM_LINE_BYTES = 8 * 1024 * 1024;
|
|
|
21
21
|
export const MAX_STREAM_TOTAL_BYTES = 64 * 1024 * 1024;
|
|
22
22
|
/** Hard ceiling on projected conversation history text (characters) to prevent runaway memory. */
|
|
23
23
|
export const MAX_PROJECTED_HISTORY_CHARS = 200_000;
|
|
24
|
+
/**
|
|
25
|
+
* Chars-per-token ratio for deriving the projected-history ceiling from the model context
|
|
26
|
+
* window. Sits between the English/code (~4 chars per token) and CJK (~1.5) extremes: the
|
|
27
|
+
* ceiling is a runaway-memory bound and a coarse guard against cutting history the window can
|
|
28
|
+
* hold, not a token accounting - the caller-side compaction line stays the token authority.
|
|
29
|
+
*/
|
|
30
|
+
const PROJECTED_HISTORY_CHARS_PER_TOKEN = 3;
|
|
31
|
+
/** Absolute ceiling on a window-derived history cap, so runaway metadata cannot unbound stdin. */
|
|
32
|
+
const MAX_PROJECTED_HISTORY_DERIVED_CHARS = 4_000_000;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Projected-history character ceiling for a turn, derived from the declared model context
|
|
36
|
+
* window. A missing or non-finite window keeps the legacy flat cap, and the derivation never
|
|
37
|
+
* lowers the cap below it: small windows change nothing, while large windows scale (a 1M-token
|
|
38
|
+
* model keeps 3M characters) until the hard ceiling. The flat 200k cap predates window
|
|
39
|
+
* metadata and cut long replays to roughly 50k-130k tokens of content regardless of the model.
|
|
40
|
+
*/
|
|
41
|
+
export function projectedHistoryCharLimit(contextWindowTokens: number | undefined): number {
|
|
42
|
+
if (typeof contextWindowTokens !== "number" || !Number.isFinite(contextWindowTokens) || contextWindowTokens <= 0) {
|
|
43
|
+
return MAX_PROJECTED_HISTORY_CHARS;
|
|
44
|
+
}
|
|
45
|
+
const derived = contextWindowTokens * PROJECTED_HISTORY_CHARS_PER_TOKEN;
|
|
46
|
+
return Math.min(Math.max(derived, MAX_PROJECTED_HISTORY_CHARS), MAX_PROJECTED_HISTORY_DERIVED_CHARS);
|
|
47
|
+
}
|
|
24
48
|
|
|
25
49
|
export class CodingAgentStreamLimitError extends Error {
|
|
26
50
|
constructor(message: string) {
|
|
@@ -308,7 +332,7 @@ function formatMessageForHistory(message: OcxMessage): string {
|
|
|
308
332
|
if (message.role === "user") {
|
|
309
333
|
const text = typeof message.content === "string"
|
|
310
334
|
? message.content
|
|
311
|
-
: message.content.map(p => (p.type === "text" ? p.text : `[${p.type}]`)).join("\n");
|
|
335
|
+
: message.content.map(p => (p.type === "text" || p.type === "document" ? p.text : `[${p.type}]`)).join("\n");
|
|
312
336
|
return `USER:\n${text}`;
|
|
313
337
|
}
|
|
314
338
|
if (message.role === "assistant") {
|
|
@@ -328,7 +352,7 @@ function formatMessageForHistory(message: OcxMessage): string {
|
|
|
328
352
|
if (message.role === "toolResult") {
|
|
329
353
|
const text = typeof message.content === "string"
|
|
330
354
|
? message.content
|
|
331
|
-
: message.content.map(p => (p.type === "text" ? p.text : "[image]")).join("");
|
|
355
|
+
: message.content.map(p => (p.type === "text" || p.type === "document" ? p.text : "[image]")).join("");
|
|
332
356
|
const status = message.isError ? " (error)" : "";
|
|
333
357
|
return `TOOL RESULT (call_id: ${message.toolCallId})${status}:\n${text}`;
|
|
334
358
|
}
|
|
@@ -355,6 +379,8 @@ export function buildInputLines(message: OcxMessage): string[] {
|
|
|
355
379
|
else if (part.type === "image") {
|
|
356
380
|
const image = imagePart(part.imageUrl);
|
|
357
381
|
if (image) content.push(image);
|
|
382
|
+
} else if (part.type === "document") {
|
|
383
|
+
content.push(textPart(part.text));
|
|
358
384
|
} else {
|
|
359
385
|
content.push(textPart("[video]"));
|
|
360
386
|
}
|
|
@@ -378,7 +404,7 @@ export function buildSystemPrompt(parsed: OcxParsedRequest): string | undefined
|
|
|
378
404
|
if (message.role !== "developer") continue;
|
|
379
405
|
const text = typeof message.content === "string"
|
|
380
406
|
? message.content
|
|
381
|
-
: message.content.map(part => (part.type === "text" ? part.text : "")).join("");
|
|
407
|
+
: message.content.map(part => (part.type === "text" || part.type === "document" ? part.text : "")).join("");
|
|
382
408
|
if (text.trim()) parts.push(text);
|
|
383
409
|
}
|
|
384
410
|
return parts.length > 0 ? parts.join("\n\n") : undefined;
|
|
@@ -395,7 +421,7 @@ export function buildSystemPrompt(parsed: OcxParsedRequest): string | undefined
|
|
|
395
421
|
* prior conversation turns are structured as bounded context text with tool results as text,
|
|
396
422
|
* clearly demarcated from the current user request. Codex retains tool control; vendor tools are never invoked.
|
|
397
423
|
*/
|
|
398
|
-
export function buildConversationInput(parsed: OcxParsedRequest): string[] {
|
|
424
|
+
export function buildConversationInput(parsed: OcxParsedRequest, options: { maxHistoryChars?: number } = {}): string[] {
|
|
399
425
|
const nonDev = parsed.context.messages.filter(m => m.role !== "developer");
|
|
400
426
|
if (nonDev.length === 0) {
|
|
401
427
|
return [JSON.stringify({ type: "user", message: { role: "user", content: [{ type: "text", text: "" }] } })];
|
|
@@ -440,6 +466,8 @@ export function buildConversationInput(parsed: OcxParsedRequest): string[] {
|
|
|
440
466
|
const image = imagePart(part.imageUrl);
|
|
441
467
|
if (image) currentImageBlocks.push(image);
|
|
442
468
|
else textParts.push("[image omitted: unsupported reference]");
|
|
469
|
+
} else if (part.type === "document") {
|
|
470
|
+
textParts.push(part.text);
|
|
443
471
|
} else {
|
|
444
472
|
textParts.push("[video]");
|
|
445
473
|
}
|
|
@@ -463,6 +491,7 @@ export function buildConversationInput(parsed: OcxParsedRequest): string[] {
|
|
|
463
491
|
else segments.push("[image omitted: unsupported reference]");
|
|
464
492
|
continue;
|
|
465
493
|
}
|
|
494
|
+
if (part.type === "document") { segments.push(part.text); continue; }
|
|
466
495
|
segments.push("[video]");
|
|
467
496
|
}
|
|
468
497
|
text = segments.join("");
|
|
@@ -475,10 +504,11 @@ export function buildConversationInput(parsed: OcxParsedRequest): string[] {
|
|
|
475
504
|
|
|
476
505
|
const imageBlocks: WireContentPart[] = [...historyImageBlocks, ...currentImageBlocks];
|
|
477
506
|
|
|
507
|
+
const maxHistoryChars = options.maxHistoryChars ?? MAX_PROJECTED_HISTORY_CHARS;
|
|
478
508
|
let historyText = historyMessages.map(formatMessageForHistory).filter(Boolean).join("\n\n");
|
|
479
|
-
if (historyText.length >
|
|
509
|
+
if (historyText.length > maxHistoryChars) {
|
|
480
510
|
historyText = `[Earlier conversation history truncated for length...]\n\n` +
|
|
481
|
-
historyText.slice(historyText.length -
|
|
511
|
+
historyText.slice(historyText.length - maxHistoryChars);
|
|
482
512
|
}
|
|
483
513
|
|
|
484
514
|
const combinedText = `Prior conversation context:\n\n${historyText}\n\nCurrent user request:\n\n${currentRequestText}`;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { execFileSync, spawn as nodeSpawn, type ChildProcess, type SpawnOptions } from "node:child_process";
|
|
2
2
|
import type { AdapterEvent, OcxParsedRequest, OcxProviderConfig } from "../../types";
|
|
3
3
|
import { commandInvocation } from "../../lib/win-exec";
|
|
4
|
+
import { modelRecordValue } from "../../reasoning-effort";
|
|
4
5
|
import type { IncomingMeta } from "../base";
|
|
5
|
-
import { buildConversationInput, CodingAgentProtocolError, mapStreamMessageToEvents, readJsonLines, type StreamParseState } from "./protocol";
|
|
6
|
+
import { buildConversationInput, CodingAgentProtocolError, mapStreamMessageToEvents, projectedHistoryCharLimit, readJsonLines, type StreamParseState } from "./protocol";
|
|
6
7
|
import { resolveCodingAgentBinary, resolveProfileByBaseUrl, type CodingAgentProviderProfile, type WhichFn } from "./profile";
|
|
7
8
|
|
|
8
9
|
/** Injectable spawn for tests; production uses node:child_process. */
|
|
@@ -264,7 +265,14 @@ export async function runCodingAgentTurn(input: CodingAgentTurnInput): Promise<v
|
|
|
264
265
|
const stdin = child.stdin;
|
|
265
266
|
if (stdin) {
|
|
266
267
|
stdin.on("error", () => { /* EPIPE if the CLI exits early; surfaced via close/stderr */ });
|
|
267
|
-
|
|
268
|
+
// The projected history scales with the model context window on the routed provider row
|
|
269
|
+
// (catalog and config metadata merged): a 1M-token model keeps 3M characters of replay
|
|
270
|
+
// where the flat cap cut it near 50k-130k tokens of content. Absent metadata keeps the
|
|
271
|
+
// flat cap.
|
|
272
|
+
const historyCharLimit = projectedHistoryCharLimit(
|
|
273
|
+
modelRecordValue(provider.modelContextWindows, parsed.modelId) ?? provider.contextWindow,
|
|
274
|
+
);
|
|
275
|
+
for (const line of buildConversationInput(parsed, { maxHistoryChars: historyCharLimit })) stdin.write(`${line}\n`);
|
|
268
276
|
stdin.end();
|
|
269
277
|
}
|
|
270
278
|
const stdout = child.stdout;
|
|
@@ -32,7 +32,7 @@ function canonicalCommandCodeModelId(modelId: string): string {
|
|
|
32
32
|
/** Flatten tool-result content for the text-only wire output, keeping an `[image]` marker per image part in content order. */
|
|
33
33
|
function toolResultText(content: string | OcxContentPart[]): string {
|
|
34
34
|
if (typeof content === "string") return content;
|
|
35
|
-
return content.map(part => (part.type === "text" ? part.text : "[image]")).join("");
|
|
35
|
+
return content.map(part => (part.type === "text" || part.type === "document" ? part.text : "[image]")).join("");
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/** Best-effort media type from a remote https URL extension, e.g. image/png. */
|
|
@@ -149,6 +149,7 @@ function wireMessages(messages: OcxMessage[]): Array<Record<string, unknown>> {
|
|
|
149
149
|
else for (const part of message.content) {
|
|
150
150
|
if (part.type === "text") content.push({ type: "text", text: part.text });
|
|
151
151
|
else if (part.type === "image") content.push(wireImagePart(part.imageUrl));
|
|
152
|
+
else if (part.type === "document") content.push({ type: "text", text: part.text });
|
|
152
153
|
else content.push({ type: "text", text: "[video]" });
|
|
153
154
|
}
|
|
154
155
|
out.push({ role: "user", content });
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
normalizeCursorClaudeId,
|
|
4
4
|
type NormalizedCursorClaudeId,
|
|
5
5
|
} from "./claude-id";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Cursor umbrella catalog — the single source of truth for cursor model
|
|
@@ -599,7 +600,7 @@ export function resolveCursorSelection(
|
|
|
599
600
|
pickedId: string,
|
|
600
601
|
reasoning: string | undefined,
|
|
601
602
|
liveMaxModeIds?: ReadonlySet<string>,
|
|
602
|
-
options: { fast?: boolean } = {},
|
|
603
|
+
options: { fast?: boolean; liveRosterScope?: string } = {},
|
|
603
604
|
): CursorResolvedSelection {
|
|
604
605
|
const parsed = parseCursorVariantId(pickedId);
|
|
605
606
|
if (!parsed.known) {
|
|
@@ -617,7 +618,10 @@ export function resolveCursorSelection(
|
|
|
617
618
|
const requested = parsed.level ?? reasoning;
|
|
618
619
|
const effort = cursorVariantEffort(spec, requested);
|
|
619
620
|
const requestedClaude = normalizeCursorClaudeId(pickedId);
|
|
620
|
-
const
|
|
621
|
+
const scopedClaudeIdentities = options.liveRosterScope
|
|
622
|
+
? liveCursorClaudeWireIdentitiesByScope.get(options.liveRosterScope)
|
|
623
|
+
: liveCursorClaudeWireIdentities;
|
|
624
|
+
const claudeIdentity = scopedClaudeIdentities?.get(parsed.baseId)
|
|
621
625
|
?? (requestedClaude
|
|
622
626
|
? { sourceBaseId: requestedClaude.sourceBaseId, spelling: requestedClaude.spelling }
|
|
623
627
|
: undefined);
|
|
@@ -626,7 +630,9 @@ export function resolveCursorSelection(
|
|
|
626
630
|
? `${capability.wirePrefix}${canonicalId}`
|
|
627
631
|
: canonicalId;
|
|
628
632
|
const ultraRequested = parsed.ultra || reasoning?.toLowerCase() === "ultra";
|
|
629
|
-
const evidence = liveMaxModeIds
|
|
633
|
+
const evidence = liveMaxModeIds
|
|
634
|
+
?? (options.liveRosterScope ? liveCursorMaxModeBasesByScope.get(options.liveRosterScope) : undefined)
|
|
635
|
+
?? liveCursorMaxModeBases;
|
|
630
636
|
const maxModeArmed = capability.maxModeVerified === true || evidence.has(parsed.baseId);
|
|
631
637
|
return { wireId, canonicalId, maxMode: ultraRequested && maxModeArmed, known: true };
|
|
632
638
|
}
|
|
@@ -639,15 +645,36 @@ export function resolveCursorSelection(
|
|
|
639
645
|
*/
|
|
640
646
|
let liveCursorMaxModeBases: ReadonlySet<string> = new Set();
|
|
641
647
|
let liveCursorClaudeWireIdentities: ReadonlyMap<string, CursorLiveClaudeWireIdentity> = new Map();
|
|
648
|
+
const liveCursorMaxModeBasesByScope = new Map<string, ReadonlySet<string>>();
|
|
649
|
+
const liveCursorClaudeWireIdentitiesByScope = new Map<string, ReadonlyMap<string, CursorLiveClaudeWireIdentity>>();
|
|
650
|
+
const liveCursorRosterScopesByProvider = new Map<string, Set<string>>();
|
|
651
|
+
|
|
652
|
+
/** Non-secret key binding live roster evidence to one upstream destination and credential. */
|
|
653
|
+
export function cursorLiveRosterScope(baseUrl: string | undefined, credential: string): string {
|
|
654
|
+
const destination = (baseUrl?.trim().replace(/\/+$/, "") || "https://api2.cursor.sh");
|
|
655
|
+
return createHash("sha256")
|
|
656
|
+
.update("ocx:cursor:live-roster\0")
|
|
657
|
+
.update(destination)
|
|
658
|
+
.update("\0")
|
|
659
|
+
.update(credential)
|
|
660
|
+
.digest("hex");
|
|
661
|
+
}
|
|
642
662
|
|
|
643
|
-
export function recordLiveCursorClaudeModels(liveIds: readonly string[]): void {
|
|
663
|
+
export function recordLiveCursorClaudeModels(liveIds: readonly string[], scope?: { provider: string; key: string }): void {
|
|
644
664
|
const next = new Map<string, CursorLiveClaudeWireIdentity>();
|
|
645
665
|
for (const rawId of liveIds) {
|
|
646
666
|
const n = normalizeCursorClaudeId(rawId.startsWith("cursor-") ? rawId.slice(7) : rawId);
|
|
647
667
|
if (!n || !CURSOR_CAPABILITIES[n.canonicalBaseId]) continue;
|
|
648
668
|
if (!next.has(n.canonicalBaseId)) next.set(n.canonicalBaseId, { sourceBaseId: n.sourceBaseId, spelling: n.spelling });
|
|
649
669
|
}
|
|
650
|
-
|
|
670
|
+
if (scope) {
|
|
671
|
+
liveCursorClaudeWireIdentitiesByScope.set(scope.key, next);
|
|
672
|
+
const scopes = liveCursorRosterScopesByProvider.get(scope.provider) ?? new Set<string>();
|
|
673
|
+
scopes.add(scope.key);
|
|
674
|
+
liveCursorRosterScopesByProvider.set(scope.provider, scopes);
|
|
675
|
+
} else {
|
|
676
|
+
liveCursorClaudeWireIdentities = next;
|
|
677
|
+
}
|
|
651
678
|
}
|
|
652
679
|
|
|
653
680
|
export function liveCursorClaudeWireIdentitiesForTests(): ReadonlyMap<string, CursorLiveClaudeWireIdentity> {
|
|
@@ -656,15 +683,32 @@ export function liveCursorClaudeWireIdentitiesForTests(): ReadonlyMap<string, Cu
|
|
|
656
683
|
|
|
657
684
|
export function resetLiveCursorClaudeWireIdentitiesForTests(): void {
|
|
658
685
|
liveCursorClaudeWireIdentities = new Map();
|
|
686
|
+
liveCursorClaudeWireIdentitiesByScope.clear();
|
|
687
|
+
liveCursorRosterScopesByProvider.clear();
|
|
659
688
|
}
|
|
660
689
|
|
|
661
|
-
export function recordLiveCursorMaxModeModels(liveIds: readonly string[]): void {
|
|
690
|
+
export function recordLiveCursorMaxModeModels(liveIds: readonly string[], scope?: { provider: string; key: string }): void {
|
|
662
691
|
const bases = new Set<string>();
|
|
663
692
|
for (const id of liveIds) {
|
|
664
693
|
const parsed = parseCursorVariantId(id);
|
|
665
694
|
if (parsed.known) bases.add(parsed.baseId);
|
|
666
695
|
}
|
|
667
|
-
|
|
696
|
+
if (scope) liveCursorMaxModeBasesByScope.set(scope.key, bases);
|
|
697
|
+
else liveCursorMaxModeBases = bases;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
export function clearLiveCursorRosterState(provider?: string): void {
|
|
701
|
+
if (!provider) {
|
|
702
|
+
liveCursorClaudeWireIdentitiesByScope.clear();
|
|
703
|
+
liveCursorMaxModeBasesByScope.clear();
|
|
704
|
+
liveCursorRosterScopesByProvider.clear();
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
for (const scope of liveCursorRosterScopesByProvider.get(provider) ?? []) {
|
|
708
|
+
liveCursorClaudeWireIdentitiesByScope.delete(scope);
|
|
709
|
+
liveCursorMaxModeBasesByScope.delete(scope);
|
|
710
|
+
}
|
|
711
|
+
liveCursorRosterScopesByProvider.delete(provider);
|
|
668
712
|
}
|
|
669
713
|
|
|
670
714
|
export function liveCursorMaxModeBasesForTests(): ReadonlySet<string> {
|
|
@@ -741,7 +741,7 @@ function contentText(message: OcxMessage): string {
|
|
|
741
741
|
if (typeof message.content === "string") return message.content;
|
|
742
742
|
return message.content
|
|
743
743
|
.map(part => {
|
|
744
|
-
if (part.type === "text") return part.text;
|
|
744
|
+
if (part.type === "text" || part.type === "document") return part.text;
|
|
745
745
|
if (part.type === "thinking") return part.thinking;
|
|
746
746
|
if (part.type === "image") return undefined;
|
|
747
747
|
return undefined;
|
|
@@ -754,7 +754,7 @@ function contentToText(content: OcxToolResultMessage["content"]): string {
|
|
|
754
754
|
if (typeof content === "string") return content;
|
|
755
755
|
return content
|
|
756
756
|
.map(part => {
|
|
757
|
-
if (part.type === "text") return part.text;
|
|
757
|
+
if (part.type === "text" || part.type === "document") return part.text;
|
|
758
758
|
if (part.type === "image") return CURSOR_VISION_IMAGE_HISTORY_MARKER;
|
|
759
759
|
return undefined;
|
|
760
760
|
})
|
|
@@ -767,7 +767,7 @@ function historyContentText(message: OcxMessage): string {
|
|
|
767
767
|
if (message.role === "toolResult" || typeof message.content === "string") return contentText(message);
|
|
768
768
|
return message.content
|
|
769
769
|
.map(part => {
|
|
770
|
-
if (part.type === "text") return part.text;
|
|
770
|
+
if (part.type === "text" || part.type === "document") return part.text;
|
|
771
771
|
if (part.type === "thinking") return part.thinking;
|
|
772
772
|
if (part.type === "image") return CURSOR_VISION_IMAGE_HISTORY_MARKER;
|
|
773
773
|
return undefined;
|
|
@@ -836,6 +836,9 @@ function decodeResultParts(message: OcxToolResultMessage): DecodedResultPart[] |
|
|
|
836
836
|
return content.map((part): DecodedResultPart => {
|
|
837
837
|
if (part.type === "text") return { kind: "text", text: part.text };
|
|
838
838
|
if (part.type === "video") return { kind: "text", text: "[video]" };
|
|
839
|
+
// Without this the document falls through to decodeInlineImage(part.imageUrl) below and is
|
|
840
|
+
// treated as an image it is not.
|
|
841
|
+
if (part.type === "document") return { kind: "text", text: part.text };
|
|
839
842
|
const decoded = decodeInlineImage(part.imageUrl);
|
|
840
843
|
return decoded ? { kind: "image", ...decoded } : { kind: "undecodable" };
|
|
841
844
|
});
|
|
@@ -213,7 +213,7 @@ export function cursorRequestEmitsFastVariant(parsed: OcxParsedRequest): boolean
|
|
|
213
213
|
* instead: current Cursor clients send the matching Grok base id plus `effort` and `fast` parameters.
|
|
214
214
|
* A fully-qualified id (one that is not a known effort base) passes through unchanged.
|
|
215
215
|
*/
|
|
216
|
-
function normalizeCursorModelId(modelId: string, reasoning?: string, fast?: boolean): {
|
|
216
|
+
function normalizeCursorModelId(modelId: string, reasoning?: string, fast?: boolean, liveRosterScope?: string): {
|
|
217
217
|
modelId: string;
|
|
218
218
|
requestedModelParameters?: readonly CursorRequestedModelParameter[];
|
|
219
219
|
routingLevel?: CursorRoutingLevel;
|
|
@@ -239,7 +239,7 @@ function normalizeCursorModelId(modelId: string, reasoning?: string, fast?: bool
|
|
|
239
239
|
],
|
|
240
240
|
};
|
|
241
241
|
}
|
|
242
|
-
const resolved = resolveCursorSelection(id, reasoning, undefined, { fast });
|
|
242
|
+
const resolved = resolveCursorSelection(id, reasoning, undefined, { fast, liveRosterScope });
|
|
243
243
|
return {
|
|
244
244
|
...selection,
|
|
245
245
|
...(resolved.maxMode ? { maxMode: true } : {}),
|
|
@@ -251,6 +251,9 @@ function contentPartToText(part: OcxContentPart | OcxAssistantContentPart): stri
|
|
|
251
251
|
switch (part.type) {
|
|
252
252
|
case "text":
|
|
253
253
|
return part.text;
|
|
254
|
+
case "document":
|
|
255
|
+
// Cursor has no document carrier; the marker keeps the turn from serializing to nothing.
|
|
256
|
+
return part.text;
|
|
254
257
|
case "thinking":
|
|
255
258
|
return part.thinking;
|
|
256
259
|
case "image":
|
|
@@ -407,6 +410,8 @@ export function cursorCoveredPrefixDigest(parsed: OcxParsedRequest, coveredMessa
|
|
|
407
410
|
export interface CreateCursorRequestOptions {
|
|
408
411
|
/** Force a brand-new Cursor conversation id even when remembered state exists. */
|
|
409
412
|
forceFreshConversation?: boolean;
|
|
413
|
+
/** Credential-bound scope for live Cursor model spelling and Max-Mode evidence. */
|
|
414
|
+
liveRosterScope?: string;
|
|
410
415
|
}
|
|
411
416
|
|
|
412
417
|
function lookupPrefixSnapshot(
|
|
@@ -499,7 +504,12 @@ export function createCursorRequest(
|
|
|
499
504
|
const visibleTools = cursorToolsForActivePrompt(parsed.context.tools, activeText, parsed.options.toolChoice);
|
|
500
505
|
const budget = applyCursorToolBudget(visibleTools, parsed.options.toolChoice);
|
|
501
506
|
const limitNote = catalogLimitNote(budget.tools, budget.omitted);
|
|
502
|
-
const model = normalizeCursorModelId(
|
|
507
|
+
const model = normalizeCursorModelId(
|
|
508
|
+
parsed.modelId,
|
|
509
|
+
parsed.options.reasoning,
|
|
510
|
+
cursorFastRequested(parsed),
|
|
511
|
+
options.liveRosterScope,
|
|
512
|
+
);
|
|
503
513
|
const request: CursorRunRequest = {
|
|
504
514
|
modelId: model.modelId,
|
|
505
515
|
...(model.requestedModelParameters ? { requestedModelParameters: model.requestedModelParameters } : {}),
|
package/src/adapters/cursor.ts
CHANGED
|
@@ -61,6 +61,7 @@ import {
|
|
|
61
61
|
CursorTransportDisabledError,
|
|
62
62
|
type CursorTransportFactory,
|
|
63
63
|
} from "./cursor/transport";
|
|
64
|
+
import { cursorLiveRosterScope } from "./cursor/catalog";
|
|
64
65
|
|
|
65
66
|
export const CURSOR_API_URL = "https://api2.cursor.sh";
|
|
66
67
|
|
|
@@ -172,9 +173,11 @@ export function createCursorAdapter(provider: OcxProviderConfig, deps: CursorAda
|
|
|
172
173
|
// Namespace thread→conversation derivation by the authenticated Cursor credential so
|
|
173
174
|
// shared-proxy tenants with different Cursor accounts cannot collide on a parent thread id.
|
|
174
175
|
// Prefer an already-set auth scope (e.g. Codex pool account) when present.
|
|
176
|
+
let liveRosterScope: string | undefined;
|
|
175
177
|
if (!_parsed._cursorIdentityScope) {
|
|
176
178
|
try {
|
|
177
179
|
const token = resolveCursorToken(provider, incoming.headers);
|
|
180
|
+
liveRosterScope = cursorLiveRosterScope(provider.baseUrl, token);
|
|
178
181
|
_parsed._cursorIdentityScope = createHash("sha256")
|
|
179
182
|
.update("ocx:cursor:acct:")
|
|
180
183
|
.update(token)
|
|
@@ -183,11 +186,17 @@ export function createCursorAdapter(provider: OcxProviderConfig, deps: CursorAda
|
|
|
183
186
|
} catch {
|
|
184
187
|
/* Missing credential is handled by the live transport path below. */
|
|
185
188
|
}
|
|
189
|
+
} else {
|
|
190
|
+
try {
|
|
191
|
+
liveRosterScope = cursorLiveRosterScope(provider.baseUrl, resolveCursorToken(provider, incoming.headers));
|
|
192
|
+
} catch {
|
|
193
|
+
/* Missing credential is handled by the live transport path below. */
|
|
194
|
+
}
|
|
186
195
|
}
|
|
187
196
|
const inheritedCheckpointRef = _parsed._providerContinuation?.cursor?.checkpointRef;
|
|
188
197
|
const previousConversationId = _parsed._cursorConversationId;
|
|
189
198
|
let request = {
|
|
190
|
-
...createCursorRequest(_parsed),
|
|
199
|
+
...createCursorRequest(_parsed, { liveRosterScope }),
|
|
191
200
|
_cursorIdentityScope: _parsed._cursorIdentityScope?.trim() || "local",
|
|
192
201
|
};
|
|
193
202
|
requestSizeContext = cursorRequestSizeContext(request);
|
|
@@ -441,7 +450,7 @@ export function createCursorAdapter(provider: OcxProviderConfig, deps: CursorAda
|
|
|
441
450
|
lastTransport = undefined;
|
|
442
451
|
_parsed._cursorConversationId = undefined;
|
|
443
452
|
const next = {
|
|
444
|
-
...createCursorRequest(_parsed, { forceFreshConversation: true }),
|
|
453
|
+
...createCursorRequest(_parsed, { forceFreshConversation: true, liveRosterScope }),
|
|
445
454
|
_cursorIdentityScope: _parsed._cursorIdentityScope?.trim() || "local",
|
|
446
455
|
};
|
|
447
456
|
rekeyContextUsage(failedConversationId, next.conversationId);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Type-only: erased at compile time, so this does not create an import cycle with the registry.
|
|
2
|
+
import type { AdapterWire } from "./registry";
|
|
3
|
+
import type { OcxMessage, OcxParsedRequest } from "../types";
|
|
4
|
+
import { toolRestrictsCallers } from "../types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Wires that can actually carry a constraint, as a default-deny allowlist.
|
|
8
|
+
*
|
|
9
|
+
* A per-adapter opt-in is the wrong shape for this: an adapter that never learned about a
|
|
10
|
+
* carrier rebuilds the declaration or the message without it and returns a normal completion,
|
|
11
|
+
* which is exactly the silent widening this batch exists to remove. Listing the wires that CAN
|
|
12
|
+
* carry it means a new wire refuses until someone teaches it, and adding a member to
|
|
13
|
+
* `AdapterWire` makes the omission visible here rather than at a customer's upstream.
|
|
14
|
+
*/
|
|
15
|
+
const CALLER_RESTRICTION_WIRES: ReadonlySet<AdapterWire> = new Set<AdapterWire>(["anthropic"]);
|
|
16
|
+
const INLINE_DOCUMENT_WIRES: ReadonlySet<AdapterWire> = new Set<AdapterWire>([
|
|
17
|
+
"anthropic",
|
|
18
|
+
"openai-chat",
|
|
19
|
+
"google",
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
/** A fixed-vocabulary refusal, or `undefined` when this wire can hold everything the request carries. */
|
|
23
|
+
export function unrepresentableDeclaration(parsed: OcxParsedRequest, wire: AdapterWire): string | undefined {
|
|
24
|
+
if (!CALLER_RESTRICTION_WIRES.has(wire) && parsed.context.tools?.some(toolRestrictsCallers)) {
|
|
25
|
+
// The name is deliberately absent: it is caller-controlled and would put client metadata
|
|
26
|
+
// into an error body.
|
|
27
|
+
return "OpenCodex cannot express tools[].allowed_callers on this route. "
|
|
28
|
+
+ "Route the request to an Anthropic-protocol provider, or remove the caller restriction.";
|
|
29
|
+
}
|
|
30
|
+
if (!INLINE_DOCUMENT_WIRES.has(wire) && parsed.context.messages.some(carriesDocument)) {
|
|
31
|
+
return "OpenCodex cannot translate document input on this route. "
|
|
32
|
+
+ "Use a native input wire that supports the attachment, or convert it to text first.";
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Typed structurally rather than as `OcxContentPart[]`: an assistant turn's content is
|
|
39
|
+
* `OcxAssistantContentPart[]`, which carries thinking and tool-call members and is not
|
|
40
|
+
* assignable to the user-content union. Only the discriminant is read here.
|
|
41
|
+
*/
|
|
42
|
+
function carriesDocument(message: OcxMessage): boolean {
|
|
43
|
+
const content: unknown = message.content;
|
|
44
|
+
return Array.isArray(content) && (content as ReadonlyArray<{ type: string }>).some(part => part.type === "document");
|
|
45
|
+
}
|