@remodex/rmx 1.0.2
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 +91 -0
- package/LICENSE +21 -0
- package/README.md +242 -0
- package/assets/architecture.png +0 -0
- package/assets/banner.png +0 -0
- package/assets/claude-code-models.gif +0 -0
- package/assets/codex-app-picker.png +0 -0
- package/bin/ocx.mjs +584 -0
- package/bin/package-main.mjs +9 -0
- package/gui/dist/assets/index-CZqebSPQ.css +1 -0
- package/gui/dist/assets/index-CkETtt7P.js +71 -0
- package/gui/dist/favicon.png +0 -0
- package/gui/dist/fonts/google-sans-cyrillic.woff2 +0 -0
- package/gui/dist/fonts/google-sans-latin.woff2 +0 -0
- package/gui/dist/icons.svg +24 -0
- package/gui/dist/index.html +25 -0
- package/gui/dist/logo.png +0 -0
- package/gui/dist/provider-icons/alibaba-color.svg +1 -0
- package/gui/dist/provider-icons/antigravity-color.svg +1 -0
- package/gui/dist/provider-icons/claude-color.svg +1 -0
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -0
- package/gui/dist/provider-icons/cursor-color.svg +2 -0
- package/gui/dist/provider-icons/deepseek-color.svg +1 -0
- package/gui/dist/provider-icons/discord.svg +1 -0
- package/gui/dist/provider-icons/firepass-color.svg +1 -0
- package/gui/dist/provider-icons/fireworks-color.svg +1 -0
- package/gui/dist/provider-icons/gemini-color.svg +1 -0
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
- package/gui/dist/provider-icons/grok.svg +1 -0
- package/gui/dist/provider-icons/groq-color.svg +1 -0
- package/gui/dist/provider-icons/huggingface-color.svg +1 -0
- package/gui/dist/provider-icons/kimi-color.svg +1 -0
- package/gui/dist/provider-icons/kiro-color.svg +15 -0
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
- package/gui/dist/provider-icons/mistral-color.svg +1 -0
- package/gui/dist/provider-icons/moonshot-color.svg +1 -0
- package/gui/dist/provider-icons/nvidia-color.svg +1 -0
- package/gui/dist/provider-icons/ollama-color.svg +1 -0
- package/gui/dist/provider-icons/openai.svg +1 -0
- package/gui/dist/provider-icons/opencode.svg +2 -0
- package/gui/dist/provider-icons/openrouter-color.svg +1 -0
- package/gui/dist/provider-icons/pi.svg +21 -0
- package/gui/dist/provider-icons/qianfan-color.svg +1 -0
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
- package/gui/dist/provider-icons/telegram.svg +1 -0
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/vllm-color.svg +1 -0
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
- package/package.json +118 -0
- package/src/AGENTS.md +28 -0
- package/src/adapters/anthropic-image-guard.ts +251 -0
- package/src/adapters/anthropic-image-normalize.ts +518 -0
- package/src/adapters/anthropic.ts +1205 -0
- package/src/adapters/azure.ts +36 -0
- package/src/adapters/base.ts +83 -0
- package/src/adapters/client-fingerprint.ts +59 -0
- package/src/adapters/command-code.ts +453 -0
- package/src/adapters/cursor/arg-codec.ts +38 -0
- package/src/adapters/cursor/arg-normalize.ts +104 -0
- package/src/adapters/cursor/cursor-errors.ts +165 -0
- package/src/adapters/cursor/discovery.ts +276 -0
- package/src/adapters/cursor/effort-map.ts +139 -0
- package/src/adapters/cursor/exec-policy.ts +88 -0
- package/src/adapters/cursor/framing.ts +250 -0
- package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
- package/src/adapters/cursor/kv-store.ts +52 -0
- package/src/adapters/cursor/live-models.ts +153 -0
- package/src/adapters/cursor/live-smoke-gate.ts +41 -0
- package/src/adapters/cursor/live-transport.ts +1235 -0
- package/src/adapters/cursor/mcp-config.ts +42 -0
- package/src/adapters/cursor/mcp-manager.ts +333 -0
- package/src/adapters/cursor/message-mapper.ts +49 -0
- package/src/adapters/cursor/native-exec-common.ts +59 -0
- package/src/adapters/cursor/native-exec-desktop.ts +184 -0
- package/src/adapters/cursor/native-exec-fs.ts +332 -0
- package/src/adapters/cursor/native-exec-mcp.ts +153 -0
- package/src/adapters/cursor/native-exec-network.ts +43 -0
- package/src/adapters/cursor/native-exec-shell.ts +548 -0
- package/src/adapters/cursor/native-exec-tools.ts +118 -0
- package/src/adapters/cursor/native-exec.ts +604 -0
- package/src/adapters/cursor/protobuf-events.ts +735 -0
- package/src/adapters/cursor/protobuf-request.ts +719 -0
- package/src/adapters/cursor/request-builder.ts +280 -0
- package/src/adapters/cursor/thread-continuity.ts +67 -0
- package/src/adapters/cursor/tool-definitions.ts +621 -0
- package/src/adapters/cursor/transport-retry.ts +132 -0
- package/src/adapters/cursor/transport.ts +57 -0
- package/src/adapters/cursor/types.ts +59 -0
- package/src/adapters/cursor.ts +196 -0
- package/src/adapters/google-antigravity-replay.ts +520 -0
- package/src/adapters/google-antigravity-wire.ts +140 -0
- package/src/adapters/google-errors.ts +85 -0
- package/src/adapters/google-http.ts +100 -0
- package/src/adapters/google-tool-schema.ts +173 -0
- package/src/adapters/google-truncation.ts +24 -0
- package/src/adapters/google-wire-compiler.ts +232 -0
- package/src/adapters/google.ts +859 -0
- package/src/adapters/identity.ts +77 -0
- package/src/adapters/image.ts +23 -0
- package/src/adapters/kiro-constants.ts +16 -0
- package/src/adapters/kiro-errors.ts +208 -0
- package/src/adapters/kiro-events.ts +197 -0
- package/src/adapters/kiro-images.ts +129 -0
- package/src/adapters/kiro-retry.ts +312 -0
- package/src/adapters/kiro-thinking.ts +104 -0
- package/src/adapters/kiro-tool-fallback.ts +36 -0
- package/src/adapters/kiro-tools.ts +224 -0
- package/src/adapters/kiro-truncation.ts +33 -0
- package/src/adapters/kiro-wire.ts +129 -0
- package/src/adapters/kiro.ts +1924 -0
- package/src/adapters/mimo-free.ts +263 -0
- package/src/adapters/openai-chat.ts +1265 -0
- package/src/adapters/openai-responses.ts +1309 -0
- package/src/adapters/run-turn-queue.ts +114 -0
- package/src/adapters/tool-catalog-nudge.ts +71 -0
- package/src/adapters/upstream-http-error.ts +48 -0
- package/src/android-remote/assets.ts +218 -0
- package/src/android-remote/attachments.ts +168 -0
- package/src/android-remote/auth.ts +237 -0
- package/src/android-remote/cloudflare-provisioning.ts +409 -0
- package/src/android-remote/cloudflare-secret.ts +106 -0
- package/src/android-remote/cloudflare-tunnel.ts +488 -0
- package/src/android-remote/cloudflared.ts +286 -0
- package/src/android-remote/codex-app-server.ts +565 -0
- package/src/android-remote/desktop-history-page.ts +936 -0
- package/src/android-remote/desktop-ipc.ts +3643 -0
- package/src/android-remote/desktop-ownership-store.ts +98 -0
- package/src/android-remote/desktop-project-registration.ts +129 -0
- package/src/android-remote/desktop-session-stream.ts +1110 -0
- package/src/android-remote/desktop-workspace-state.ts +443 -0
- package/src/android-remote/file-change-parser.ts +112 -0
- package/src/android-remote/gateway.ts +9108 -0
- package/src/android-remote/mutation-store.ts +299 -0
- package/src/android-remote/projection.ts +1780 -0
- package/src/android-remote/queued-turn-store.ts +248 -0
- package/src/android-remote/session-command-recovery.ts +1384 -0
- package/src/android-remote/store.ts +466 -0
- package/src/android-remote/thread-reconciliation.ts +133 -0
- package/src/android-remote/thread-source-paths.ts +307 -0
- package/src/android-remote/thread-stream.ts +546 -0
- package/src/android-remote/turn-activity.ts +235 -0
- package/src/android-remote/user-message-identity.ts +94 -0
- package/src/bridge.ts +1793 -0
- package/src/chat/inbound.ts +295 -0
- package/src/chat/outbound.ts +821 -0
- package/src/claude/agents-inject.ts +267 -0
- package/src/claude/alias.ts +149 -0
- package/src/claude/auth-detect.ts +229 -0
- package/src/claude/auth-mode-migration.ts +32 -0
- package/src/claude/auth-mode.ts +62 -0
- package/src/claude/context-windows.ts +189 -0
- package/src/claude/desktop-3p-guard.ts +35 -0
- package/src/claude/desktop-3p-paths.ts +84 -0
- package/src/claude/desktop-3p.ts +601 -0
- package/src/claude/desktop-health.ts +26 -0
- package/src/claude/desktop-profile.ts +263 -0
- package/src/claude/gateway-cache.ts +70 -0
- package/src/claude/inbound-debug.ts +163 -0
- package/src/claude/inbound.ts +519 -0
- package/src/claude/model-info.ts +154 -0
- package/src/claude/outbound.ts +898 -0
- package/src/cli/access.ts +108 -0
- package/src/cli/account-api.ts +296 -0
- package/src/cli/account-auth.ts +250 -0
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +476 -0
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +297 -0
- package/src/cli/agent-driven.ts +70 -0
- package/src/cli/agent.ts +184 -0
- package/src/cli/catalog-prewarm.ts +27 -0
- package/src/cli/claude-desktop.ts +211 -0
- package/src/cli/claude.ts +302 -0
- package/src/cli/codex-shim-autorestore.ts +45 -0
- package/src/cli/codex-shim-readiness.ts +69 -0
- package/src/cli/combo.ts +124 -0
- package/src/cli/config-command.ts +183 -0
- package/src/cli/debug.ts +228 -0
- package/src/cli/desktop-first-run.ts +25 -0
- package/src/cli/doctor.ts +1022 -0
- package/src/cli/export-command.ts +201 -0
- package/src/cli/help.ts +370 -0
- package/src/cli/index.ts +1565 -0
- package/src/cli/init.ts +224 -0
- package/src/cli/integrations.ts +225 -0
- package/src/cli/interactive-confirm.ts +133 -0
- package/src/cli/internal-dispatch.ts +35 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/models-runtime.ts +224 -0
- package/src/cli/models.ts +340 -0
- package/src/cli/observe.ts +170 -0
- package/src/cli/opencode.ts +587 -0
- package/src/cli/provider-runtime.ts +179 -0
- package/src/cli/provider.ts +476 -0
- package/src/cli/ready.ts +301 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +328 -0
- package/src/cli/star-prompt.ts +211 -0
- package/src/cli/status-oauth.ts +78 -0
- package/src/cli/status.ts +321 -0
- package/src/cli/system-command.ts +196 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +205 -0
- package/src/cli/v2.ts +200 -0
- package/src/cli.ts +10 -0
- package/src/clients/config-export.ts +1109 -0
- package/src/codex/account-id.ts +34 -0
- package/src/codex/account-label.ts +34 -0
- package/src/codex/account-lifecycle.ts +172 -0
- package/src/codex/account-namespace-match.ts +63 -0
- package/src/codex/account-namespaces.ts +195 -0
- package/src/codex/account-pause.ts +20 -0
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-runtime-state.ts +31 -0
- package/src/codex/account-store.ts +517 -0
- package/src/codex/account-usability.ts +40 -0
- package/src/codex/admission.ts +263 -0
- package/src/codex/app-server-processes.ts +799 -0
- package/src/codex/auth-api.ts +2098 -0
- package/src/codex/auth-collision.ts +107 -0
- package/src/codex/auth-context.ts +480 -0
- package/src/codex/autostart-health.ts +156 -0
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +471 -0
- package/src/codex/catalog/bundled.ts +533 -0
- package/src/codex/catalog/effort.ts +432 -0
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +287 -0
- package/src/codex/catalog/native-models.ts +7 -0
- package/src/codex/catalog/parsing.ts +503 -0
- package/src/codex/catalog/provider-fetch.ts +2267 -0
- package/src/codex/catalog/sync.ts +1606 -0
- package/src/codex/catalog-admission.ts +197 -0
- package/src/codex/catalog-refresh-status.ts +87 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +15 -0
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +593 -0
- package/src/codex/convergence.ts +580 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/data/upstream-models.json +830 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/desktop-client-processes.ts +521 -0
- package/src/codex/exec-invocation.ts +22 -0
- package/src/codex/features.ts +1091 -0
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +347 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +115 -0
- package/src/codex/history-provider.ts +1075 -0
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +204 -0
- package/src/codex/home.ts +206 -0
- package/src/codex/inject-coordination.ts +257 -0
- package/src/codex/inject.ts +1857 -0
- package/src/codex/injected-marker.ts +79 -0
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +105 -0
- package/src/codex/journal.ts +172 -0
- package/src/codex/main-account-cache.ts +56 -0
- package/src/codex/main-account.ts +40 -0
- package/src/codex/management-convergence.ts +114 -0
- package/src/codex/model-cache.ts +267 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +167 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +348 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +691 -0
- package/src/codex/paths.ts +78 -0
- package/src/codex/plugins-doctor.ts +242 -0
- package/src/codex/pool-rotation.ts +295 -0
- package/src/codex/project-config-warnings.ts +426 -0
- package/src/codex/prompt-journal.ts +311 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/provider-adoption.ts +242 -0
- package/src/codex/quota-rejection.ts +224 -0
- package/src/codex/quota.ts +494 -0
- package/src/codex/refresh.ts +60 -0
- package/src/codex/routing.ts +1855 -0
- package/src/codex/runtime.ts +659 -0
- package/src/codex/shim.ts +1215 -0
- package/src/codex/subagent-defaults.ts +557 -0
- package/src/codex/subagent-model-fallback.ts +560 -0
- package/src/codex/sync.ts +238 -0
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +374 -0
- package/src/codex/warmup.ts +192 -0
- package/src/codex/websocket-registry.ts +100 -0
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +140 -0
- package/src/combos/index.ts +44 -0
- package/src/combos/request.ts +64 -0
- package/src/combos/resolve.ts +232 -0
- package/src/combos/types.ts +392 -0
- package/src/config.ts +3270 -0
- package/src/generated/model-metadata.ts +144 -0
- package/src/github/star-state.ts +203 -0
- package/src/grok/inject.ts +540 -0
- package/src/grok/inspect.ts +45 -0
- package/src/grok/status.ts +127 -0
- package/src/grok/sync.ts +66 -0
- package/src/images/artifacts.ts +516 -0
- package/src/images/fulfill-video.ts +163 -0
- package/src/images/fulfill.ts +149 -0
- package/src/images/index.ts +4 -0
- package/src/images/loop.ts +922 -0
- package/src/images/plan.ts +133 -0
- package/src/images/synthetic-tool.ts +133 -0
- package/src/images/types.ts +41 -0
- package/src/images/xai-client.ts +141 -0
- package/src/images/xai-video-client.ts +163 -0
- package/src/index.ts +22 -0
- package/src/integrations/config-io.ts +151 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +108 -0
- package/src/integrations/serialize.ts +235 -0
- package/src/integrations/state.ts +290 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer.ts +492 -0
- package/src/lib/abort.ts +146 -0
- package/src/lib/admin-secrets.ts +25 -0
- package/src/lib/admission.ts +83 -0
- package/src/lib/app-owned-memory-stores.ts +173 -0
- package/src/lib/app-owned-memory.ts +265 -0
- package/src/lib/bounded-body.ts +242 -0
- package/src/lib/bun-binary-validator.d.mts +3 -0
- package/src/lib/bun-binary-validator.mjs +18 -0
- package/src/lib/bun-runtime.ts +184 -0
- package/src/lib/bun-stream-caps.ts +127 -0
- package/src/lib/config-ownership.ts +438 -0
- package/src/lib/crash-guard.ts +344 -0
- package/src/lib/debug-log-buffer.ts +83 -0
- package/src/lib/debug-settings.ts +108 -0
- package/src/lib/debug.ts +31 -0
- package/src/lib/destination-policy.ts +316 -0
- package/src/lib/errors.ts +364 -0
- package/src/lib/eventstream-decoder.ts +253 -0
- package/src/lib/gcp-adc.ts +341 -0
- package/src/lib/injection-debug-log.ts +58 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/open-url.ts +25 -0
- package/src/lib/pinned-http.ts +182 -0
- package/src/lib/privacy.ts +20 -0
- package/src/lib/process-control.ts +168 -0
- package/src/lib/provider-environment.ts +470 -0
- package/src/lib/provider-outbound.ts +203 -0
- package/src/lib/provider-url.ts +14 -0
- package/src/lib/proxy-env.ts +18 -0
- package/src/lib/redact.ts +510 -0
- package/src/lib/remodex-home.ts +616 -0
- package/src/lib/retry-after.ts +55 -0
- package/src/lib/service-secrets.ts +178 -0
- package/src/lib/shadow-call.ts +54 -0
- package/src/lib/sidecar-tracker.ts +52 -0
- package/src/lib/sse-decoder.ts +364 -0
- package/src/lib/state-store-registrations.ts +109 -0
- package/src/lib/state-store-sweeper.ts +184 -0
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/test-home-guard.ts +98 -0
- package/src/lib/token-estimate.ts +69 -0
- package/src/lib/translator-budget.ts +366 -0
- package/src/lib/upstream-reachability.ts +91 -0
- package/src/lib/upstream-retry.ts +508 -0
- package/src/lib/win-exec.ts +115 -0
- package/src/lib/win-paths.ts +68 -0
- package/src/lib/windows-elevation.ts +705 -0
- package/src/lib/windows-secret-acl.ts +817 -0
- package/src/lib/windows-user-principal.ts +283 -0
- package/src/lib/winsw.ts +402 -0
- package/src/model-sources.ts +73 -0
- package/src/oauth/anthropic-routing.ts +594 -0
- package/src/oauth/anthropic.ts +177 -0
- package/src/oauth/callback-server.ts +294 -0
- package/src/oauth/chatgpt.ts +150 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +231 -0
- package/src/oauth/github-copilot.ts +428 -0
- package/src/oauth/google-antigravity.ts +230 -0
- package/src/oauth/health.ts +443 -0
- package/src/oauth/index.ts +1280 -0
- package/src/oauth/key-providers.ts +128 -0
- package/src/oauth/kimi.ts +213 -0
- package/src/oauth/kiro-credentials.ts +726 -0
- package/src/oauth/kiro.ts +621 -0
- package/src/oauth/local-token-detect.ts +121 -0
- package/src/oauth/log.ts +48 -0
- package/src/oauth/login-cli.ts +163 -0
- package/src/oauth/pkce.ts +15 -0
- package/src/oauth/store.ts +655 -0
- package/src/oauth/token-guardian.ts +309 -0
- package/src/oauth/types.ts +62 -0
- package/src/oauth/xai.ts +241 -0
- package/src/providers/alibaba-region-backup.ts +75 -0
- package/src/providers/alibaba-region-migration.ts +156 -0
- package/src/providers/alibaba-region-startup.ts +36 -0
- package/src/providers/antigravity-models.ts +317 -0
- package/src/providers/api-keys.ts +140 -0
- package/src/providers/base-url-choices.ts +64 -0
- package/src/providers/codex-capacity.ts +288 -0
- package/src/providers/command-code-efforts.ts +85 -0
- package/src/providers/context-cap.ts +73 -0
- package/src/providers/derive.ts +451 -0
- package/src/providers/free-directory.ts +187 -0
- package/src/providers/github-copilot-transport.ts +56 -0
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +271 -0
- package/src/providers/kiro-models.ts +67 -0
- package/src/providers/label.ts +19 -0
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +361 -0
- package/src/providers/openai-sidecar.ts +235 -0
- package/src/providers/openai-tier-startup.ts +27 -0
- package/src/providers/openai-tiers.ts +301 -0
- package/src/providers/openai-virtual-models.ts +83 -0
- package/src/providers/openrouter-routing.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +179 -0
- package/src/providers/quota.ts +1942 -0
- package/src/providers/reasoning-capabilities.ts +336 -0
- package/src/providers/registry.ts +2375 -0
- package/src/providers/slug-codec.ts +74 -0
- package/src/providers/xai-transport.ts +149 -0
- package/src/reasoning-effort.ts +243 -0
- package/src/responses/compaction.ts +124 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/parser.ts +714 -0
- package/src/responses/reasoning-envelope.ts +60 -0
- package/src/responses/reasoning-replay-cache.ts +106 -0
- package/src/responses/schema.ts +159 -0
- package/src/responses/spill-store.ts +431 -0
- package/src/responses/state.ts +1039 -0
- package/src/responses/tool-groups.ts +19 -0
- package/src/router.ts +802 -0
- package/src/routing/analytics.ts +377 -0
- package/src/routing/capability.ts +205 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +444 -0
- package/src/routing/health.ts +401 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +424 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +686 -0
- package/src/server/adapter-resolve.ts +83 -0
- package/src/server/auth-cors.ts +606 -0
- package/src/server/chat-completions.ts +379 -0
- package/src/server/claude-messages.ts +980 -0
- package/src/server/effort-policy.ts +251 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +152 -0
- package/src/server/image-retry.ts +42 -0
- package/src/server/images.ts +485 -0
- package/src/server/index.ts +1633 -0
- package/src/server/lifecycle.ts +482 -0
- package/src/server/live.ts +609 -0
- package/src/server/management/agent-settings-routes.ts +1180 -0
- package/src/server/management/android-remote-routes.ts +390 -0
- package/src/server/management/api-access.ts +141 -0
- package/src/server/management/api-key-usage.ts +167 -0
- package/src/server/management/body.ts +35 -0
- package/src/server/management/combo-routes.ts +244 -0
- package/src/server/management/config-routes.ts +602 -0
- package/src/server/management/context.ts +88 -0
- package/src/server/management/integration-routes.ts +538 -0
- package/src/server/management/logs-usage-routes.ts +516 -0
- package/src/server/management/model-routes.ts +519 -0
- package/src/server/management/model-rows.ts +143 -0
- package/src/server/management/native-integration-routes.ts +781 -0
- package/src/server/management/oauth-account-routes.ts +573 -0
- package/src/server/management/provider-routes.ts +781 -0
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +384 -0
- package/src/server/management/shared.ts +277 -0
- package/src/server/management/sidebar-routes.ts +106 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +433 -0
- package/src/server/management/system-routes.ts +141 -0
- package/src/server/management/usage-summary-cache.ts +86 -0
- package/src/server/management-api.ts +269 -0
- package/src/server/management-auth.ts +353 -0
- package/src/server/memory-watchdog.ts +156 -0
- package/src/server/port-reclaim.ts +307 -0
- package/src/server/ports.ts +156 -0
- package/src/server/proxy-liveness.ts +326 -0
- package/src/server/proxy-stop.ts +92 -0
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +353 -0
- package/src/server/relay.ts +1179 -0
- package/src/server/request-decompress.ts +132 -0
- package/src/server/request-log-conversation.ts +168 -0
- package/src/server/request-log.ts +1072 -0
- package/src/server/responses/collaboration.ts +409 -0
- package/src/server/responses/compact.ts +710 -0
- package/src/server/responses/core.ts +3561 -0
- package/src/server/responses/encrypted-payload.ts +308 -0
- package/src/server/responses/fetch-helpers.ts +171 -0
- package/src/server/responses/passthrough-error.ts +78 -0
- package/src/server/responses/policy-fallback.ts +152 -0
- package/src/server/responses/terminal-guard.ts +230 -0
- package/src/server/responses/upstream-error.ts +48 -0
- package/src/server/responses-image-gen-repair.ts +132 -0
- package/src/server/responses-item-id-repair.ts +272 -0
- package/src/server/responses-json-events.ts +52 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses.ts +10 -0
- package/src/server/search.ts +181 -0
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +263 -0
- package/src/server/startup-action-control.ts +308 -0
- package/src/server/startup-health-cache.ts +119 -0
- package/src/server/system-env.ts +418 -0
- package/src/server/windows-tcp-drop.ts +184 -0
- package/src/server/windows-tray-control.ts +41 -0
- package/src/server/ws-bridge.ts +470 -0
- package/src/service-manager-probe.ts +824 -0
- package/src/service.ts +3011 -0
- package/src/stall-timeout.ts +20 -0
- package/src/storage/cleanup-job.ts +57 -0
- package/src/storage/cleanup.ts +3085 -0
- package/src/storage/policy-job.ts +457 -0
- package/src/storage/policy-scheduler.ts +40 -0
- package/src/storage/policy-worker.ts +59 -0
- package/src/storage/policy.ts +527 -0
- package/src/storage/restore-job.ts +299 -0
- package/src/storage/restore-worker.ts +58 -0
- package/src/storage/scanner.ts +238 -0
- package/src/storage/storage-mutation-coordinator.ts +139 -0
- package/src/storage/worker-lifecycle.ts +215 -0
- package/src/tray/assets/opencodex-tray-offline.ico +0 -0
- package/src/tray/assets/opencodex-tray-online.ico +0 -0
- package/src/tray/assets/opencodex-tray-warning.ico +0 -0
- package/src/tray/assets/opencodex-tray.png +0 -0
- package/src/tray/windows-tray.ps1 +364 -0
- package/src/tray/windows.ts +738 -0
- package/src/types.ts +1531 -0
- package/src/update/badge.ts +72 -0
- package/src/update/desktop-release.ts +1620 -0
- package/src/update/index.ts +402 -0
- package/src/update/job.ts +1906 -0
- package/src/update/notify.ts +261 -0
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/npm-invocation.d.mts +23 -0
- package/src/update/npm-invocation.mjs +94 -0
- package/src/update/tray-update-plan.d.mts +18 -0
- package/src/update/tray-update-plan.mjs +38 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/debug.ts +97 -0
- package/src/usage/expected-prices.ts +283 -0
- package/src/usage/log.ts +695 -0
- package/src/usage/summary.ts +585 -0
- package/src/usage/totals.ts +14 -0
- package/src/vision/anthropic-describe.ts +185 -0
- package/src/vision/describe.ts +127 -0
- package/src/vision/index.ts +558 -0
- package/src/vision/reasoning.ts +55 -0
- package/src/web-search/anthropic-executor.ts +189 -0
- package/src/web-search/executor.ts +105 -0
- package/src/web-search/format-result.ts +89 -0
- package/src/web-search/index.ts +196 -0
- package/src/web-search/loop.ts +791 -0
- package/src/web-search/parse.ts +235 -0
- package/src/web-search/progress-stream.ts +342 -0
- package/src/web-search/synthetic-tool.ts +47 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { comboFailureDecision } from "../../combos/failover";
|
|
2
|
+
import { readBoundedResponseBody } from "../../lib/bounded-body";
|
|
3
|
+
import { readJsonRequestBody } from "../request-decompress";
|
|
4
|
+
import { finishRequestAttempt, type RequestLogContext } from "../request-log";
|
|
5
|
+
import type { OcxConfig } from "../../types";
|
|
6
|
+
import type { RouteCandidateTrace, RouteDecisionTraceV1 } from "../../routing/trace";
|
|
7
|
+
import { handleResponses as handleResponsesCore } from "./core";
|
|
8
|
+
|
|
9
|
+
type CoreHandler = typeof handleResponsesCore;
|
|
10
|
+
type CoreOptions = Parameters<CoreHandler>[3];
|
|
11
|
+
|
|
12
|
+
export interface PolicyFallbackDeps {
|
|
13
|
+
runCore?: CoreHandler;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function candidateKey(candidate: Pick<RouteCandidateTrace, "provider" | "model">): string {
|
|
17
|
+
return `${candidate.provider}\u0000${candidate.model}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Rank the remaining candidates from the ORIGINAL policy trace. The initial
|
|
22
|
+
* decision stays immutable; fallback execution belongs in attempts[], not in a
|
|
23
|
+
* rewritten decision trace.
|
|
24
|
+
*/
|
|
25
|
+
export function rankPolicyFallbackCandidates(
|
|
26
|
+
trace: RouteDecisionTraceV1,
|
|
27
|
+
tried: ReadonlySet<string>,
|
|
28
|
+
): RouteCandidateTrace[] {
|
|
29
|
+
return trace.candidates
|
|
30
|
+
.map((candidate, index) => ({ candidate, index }))
|
|
31
|
+
.filter(({ candidate }) =>
|
|
32
|
+
candidate.eligible
|
|
33
|
+
&& candidate.exclusions.length === 0
|
|
34
|
+
&& !tried.has(candidateKey(candidate)))
|
|
35
|
+
.sort((left, right) => {
|
|
36
|
+
const scoreDelta = (right.candidate.score?.total ?? Number.NEGATIVE_INFINITY)
|
|
37
|
+
- (left.candidate.score?.total ?? Number.NEGATIVE_INFINITY);
|
|
38
|
+
return scoreDelta || left.index - right.index;
|
|
39
|
+
})
|
|
40
|
+
.map(({ candidate }) => candidate);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function requestWithCandidate(
|
|
44
|
+
req: Request,
|
|
45
|
+
rawBody: Record<string, unknown>,
|
|
46
|
+
candidate: Pick<RouteCandidateTrace, "provider" | "model">,
|
|
47
|
+
): Request {
|
|
48
|
+
const headers = new Headers(req.headers);
|
|
49
|
+
headers.delete("content-encoding");
|
|
50
|
+
headers.delete("content-length");
|
|
51
|
+
headers.set("content-type", "application/json");
|
|
52
|
+
return new Request(req.url, {
|
|
53
|
+
method: req.method,
|
|
54
|
+
headers,
|
|
55
|
+
body: JSON.stringify({ ...rawBody, model: `${candidate.provider}/${candidate.model}` }),
|
|
56
|
+
signal: req.signal,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function errorCodeFromText(text: string): string | undefined {
|
|
61
|
+
if (!text) return undefined;
|
|
62
|
+
try {
|
|
63
|
+
const payload = JSON.parse(text) as { error?: { code?: unknown; type?: unknown }; code?: unknown };
|
|
64
|
+
const candidate = payload.error?.code ?? payload.error?.type ?? payload.code;
|
|
65
|
+
return typeof candidate === "string" ? candidate : undefined;
|
|
66
|
+
} catch {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function shouldHopPolicyCandidate(response: Response, signal?: AbortSignal): Promise<boolean> {
|
|
72
|
+
if (response.status < 400 || signal?.aborted) return false;
|
|
73
|
+
try {
|
|
74
|
+
const inspected = await readBoundedResponseBody(response.clone(), { signal });
|
|
75
|
+
const text = inspected.displaySafe ? inspected.text : "";
|
|
76
|
+
return comboFailureDecision(response.status, text, { code: errorCodeFromText(text) }) === "hop";
|
|
77
|
+
} catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function isPolicyDecision(trace: RouteDecisionTraceV1 | undefined): trace is RouteDecisionTraceV1 {
|
|
83
|
+
return trace?.routeKind === "policy" && !!trace.profile;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Finalize the failed physical attempt so the retry receives a fresh attempt row. */
|
|
87
|
+
function finishFailedPolicyAttempt(logCtx: RequestLogContext, status: number): void {
|
|
88
|
+
const attempt = logCtx.activeAttempt;
|
|
89
|
+
if (attempt) {
|
|
90
|
+
const startedAt = logCtx.activeAttemptStartedAt ?? Date.now();
|
|
91
|
+
finishRequestAttempt(attempt, status, Math.max(0, Date.now() - startedAt), attempt.usage ?? logCtx.usage);
|
|
92
|
+
}
|
|
93
|
+
delete logCtx.activeAttempt;
|
|
94
|
+
delete logCtx.activeAttemptStartedAt;
|
|
95
|
+
delete logCtx.usage;
|
|
96
|
+
delete logCtx.usageFromBridge;
|
|
97
|
+
delete logCtx.upstreamError;
|
|
98
|
+
delete logCtx.terminalHttpStatus;
|
|
99
|
+
delete logCtx.terminalIncompleteReason;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Run a Responses request and, only for an explicitly selected policy profile,
|
|
104
|
+
* hop to the next eligible policy candidate after a retryable pre-success
|
|
105
|
+
* failure. The initial policy trace remains the canonical selection evidence;
|
|
106
|
+
* physical retries continue to accumulate in the existing request attempts.
|
|
107
|
+
*/
|
|
108
|
+
export async function handleResponsesWithPolicyFallback(
|
|
109
|
+
req: Request,
|
|
110
|
+
config: OcxConfig,
|
|
111
|
+
logCtx: RequestLogContext,
|
|
112
|
+
options: CoreOptions = {},
|
|
113
|
+
deps: PolicyFallbackDeps = {},
|
|
114
|
+
): Promise<Response> {
|
|
115
|
+
const runCore = deps.runCore ?? handleResponsesCore;
|
|
116
|
+
let rawBody: Record<string, unknown> | null = null;
|
|
117
|
+
try {
|
|
118
|
+
const parsed = await readJsonRequestBody(req.clone());
|
|
119
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) rawBody = parsed as Record<string, unknown>;
|
|
120
|
+
} catch {
|
|
121
|
+
// Core owns the client-facing parse/decompression error.
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let response = await runCore(req, config, logCtx, options);
|
|
125
|
+
const initialTrace = logCtx.routeDecision;
|
|
126
|
+
const initialRequestedModel = logCtx.requestedModel;
|
|
127
|
+
if (!rawBody || !isPolicyDecision(initialTrace)) return response;
|
|
128
|
+
|
|
129
|
+
const tried = new Set<string>([
|
|
130
|
+
candidateKey({ provider: initialTrace.selected.provider, model: initialTrace.selected.model }),
|
|
131
|
+
]);
|
|
132
|
+
|
|
133
|
+
while (await shouldHopPolicyCandidate(response, req.signal)) {
|
|
134
|
+
if (req.signal.aborted) return response;
|
|
135
|
+
const next = rankPolicyFallbackCandidates(initialTrace, tried)[0];
|
|
136
|
+
if (!next) return response;
|
|
137
|
+
tried.add(candidateKey(next));
|
|
138
|
+
|
|
139
|
+
finishFailedPolicyAttempt(logCtx, response.status);
|
|
140
|
+
const retryRequest = requestWithCandidate(req, rawBody, next);
|
|
141
|
+
try {
|
|
142
|
+
response = await runCore(retryRequest, config, logCtx, options);
|
|
143
|
+
} finally {
|
|
144
|
+
logCtx.requestedModel = initialRequestedModel;
|
|
145
|
+
logCtx.routeDecision = initialTrace;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return response;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export const handleResponses = handleResponsesWithPolicyFallback;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AdapterEvent,
|
|
3
|
+
OcxAssistantContentPart,
|
|
4
|
+
OcxAssistantMessage,
|
|
5
|
+
OcxParsedRequest,
|
|
6
|
+
OcxUsage,
|
|
7
|
+
} from "../../types";
|
|
8
|
+
|
|
9
|
+
const ACTIONABLE_REQUEST_RE = /(?:\b(?:add|change|check|continue|create|debug|delete|deploy|edit|execute|fix|implement|inspect|keep going|modify|patch|proceed|refactor|remove|review|run|test|update|write)\b|继续|接着|往下|升级|修改|改(?:一下|下)?|修复|实现|添加|新增|删除|重构|更新|运行|执行|检查|查看|排查|调试|创建|写入|提交|推送|部署|看下|改成|修一下)/iu;
|
|
10
|
+
const PLAN_ONLY_REQUEST_RE = /(?:暂时不要(?:调用|使用)工具|不要调用工具|不用执行|只回复(?:计划|方案)|(?:只|先|给|说|写|出|来)(?:我)?(?:一个|个|一下|份)?[^。!?\n]{0,8}?(?:计划|方案|草案|提案|思路)|(?:计划|方案|草案|提案|思路)(?:就(?:行|好|可以)|即可)|\b(?:just give|provide)\s+(?:me\s+)?(?:a\s+)?plan\b|\b(?:do not|don't)\s+(?:use|call)\s+tools?\b|\b(?:write|draft|outline|propose|give|provide|create|make|share|suggest|sketch)\s+(?:me\s+)?(?:a\s+|an\s+|the\s+|your\s+)?(?:(?:brief|concise|short|detailed|high[-\s]?level|rough|quick|step[-\s]?by[-\s]?step|implementation|migration|refactor(?:ing)?|design|technical)\s+)*(?:plan|proposal|draft|outline|approach|strategy|design\s+doc)\b)/iu;
|
|
11
|
+
const PLAN_INTENT_RE = /(?:\b(?:i(?:'|’)m going to|i will|i(?:'|’)ll|let me|next i)\b|我(?:先|会|将|接下来)|下一步)/iu;
|
|
12
|
+
const PLAN_OR_COMPLETION_RE = /(?:\b(?:i(?:'|’)m going to|i will|i(?:'|’)ll|let me|next i|i(?:'|’)ve (?:already )?(?:added|applied|changed|completed|fixed|implemented|modified|updated))\b|\b(?:done|completed|fixed|implemented|updated|applied)\b|我(?:先|会|将|接下来)|下一步|已(?:经)?(?:修改|修复|完成|应用|更新|实现|处理)|完成了|已经好了)/iu;
|
|
13
|
+
const WAITING_FOR_USER_RE = /(?:[??]\s*$|需要我|请(?:确认|选择|提供)|是否|要不要|可以吗|\b(?:do you want|should i|which file|please confirm|please provide)\b)/iu;
|
|
14
|
+
const EXPLICIT_CONTINUE_RE = /^(?:继续|接着|往下|go on|continue|proceed|keep going)\s*[.!。!]?$/iu;
|
|
15
|
+
const MAX_ANNOUNCEMENT_CHARS = 280;
|
|
16
|
+
|
|
17
|
+
export const TERMINAL_GUARD_NUDGE =
|
|
18
|
+
"你刚才只描述了计划,没有执行任何工具。不要再次解释计划,现在立即调用必要工具执行用户任务。" +
|
|
19
|
+
"只有工具返回后才总结;如果确实无法执行,请明确说明阻塞原因。";
|
|
20
|
+
|
|
21
|
+
export type TerminalGuardDecision = "pass" | "continue" | "ambiguous";
|
|
22
|
+
|
|
23
|
+
export interface TerminalTurnAnalysis {
|
|
24
|
+
decision: TerminalGuardDecision;
|
|
25
|
+
reason: "normal" | "waiting_for_user" | "no_tools" | "no_actionable_request" | "no_execution_claim" | "recent_tool_activity" | "substantive_answer" | "suspicious_no_tool";
|
|
26
|
+
assistantText: string;
|
|
27
|
+
userText: string;
|
|
28
|
+
hasToolCall: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function messageText(value: unknown): string {
|
|
32
|
+
if (typeof value === "string") return value;
|
|
33
|
+
if (!Array.isArray(value)) return "";
|
|
34
|
+
return value
|
|
35
|
+
.filter((part): part is { type?: unknown; text?: unknown } => !!part && typeof part === "object")
|
|
36
|
+
.filter(part => part.type === "text" && typeof part.text === "string")
|
|
37
|
+
.map(part => part.text as string)
|
|
38
|
+
.join("");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function latestUserText(parsed: OcxParsedRequest): string {
|
|
42
|
+
for (let i = parsed.context.messages.length - 1; i >= 0; i -= 1) {
|
|
43
|
+
const message = parsed.context.messages[i];
|
|
44
|
+
if (message.role === "user") return messageText(message.content);
|
|
45
|
+
}
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function recentTurnHasToolActivity(parsed: OcxParsedRequest): boolean {
|
|
50
|
+
let latestUserIndex = -1;
|
|
51
|
+
for (let i = parsed.context.messages.length - 1; i >= 0; i -= 1) {
|
|
52
|
+
if (parsed.context.messages[i]?.role === "user") {
|
|
53
|
+
latestUserIndex = i;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (latestUserIndex < 0) return false;
|
|
58
|
+
let lastAssistant: OcxAssistantMessage | undefined;
|
|
59
|
+
for (let i = latestUserIndex - 1; i >= 0; i -= 1) {
|
|
60
|
+
const message = parsed.context.messages[i];
|
|
61
|
+
if (message.role === "assistant") {
|
|
62
|
+
lastAssistant = message;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (lastAssistant?.role === "assistant") {
|
|
67
|
+
const hasToolCall = lastAssistant.content.some(part => part.type === "toolCall");
|
|
68
|
+
const text = lastAssistant.content
|
|
69
|
+
.filter(part => part.type === "text")
|
|
70
|
+
.map(part => part.text)
|
|
71
|
+
.join("");
|
|
72
|
+
if (!hasToolCall && PLAN_INTENT_RE.test(text)) return false;
|
|
73
|
+
}
|
|
74
|
+
for (let i = latestUserIndex - 1; i >= 0 && parsed.context.messages[i]?.role !== "user"; i -= 1) {
|
|
75
|
+
const message = parsed.context.messages[i];
|
|
76
|
+
if (message.role === "toolResult") return true;
|
|
77
|
+
if (message.role === "assistant" && message.content.some(part => part.type === "toolCall")) return true;
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function assistantText(events: readonly AdapterEvent[]): string {
|
|
83
|
+
return events
|
|
84
|
+
.filter((event): event is Extract<AdapterEvent, { type: "text_delta" }> => event.type === "text_delta")
|
|
85
|
+
.map(event => event.text)
|
|
86
|
+
.join("");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function analyzeTerminalTurn(parsed: OcxParsedRequest, events: readonly AdapterEvent[]): TerminalTurnAnalysis {
|
|
90
|
+
const userText = latestUserText(parsed);
|
|
91
|
+
const text = assistantText(events);
|
|
92
|
+
const hasToolCall = events.some(event => event.type === "tool_call_start");
|
|
93
|
+
if (hasToolCall) {
|
|
94
|
+
return { decision: "pass", reason: "normal", assistantText: text, userText, hasToolCall };
|
|
95
|
+
}
|
|
96
|
+
if (!parsed.context.tools || parsed.context.tools.length === 0 || parsed.options.toolChoice === "none") {
|
|
97
|
+
return { decision: "pass", reason: "no_tools", assistantText: text, userText, hasToolCall };
|
|
98
|
+
}
|
|
99
|
+
if (!ACTIONABLE_REQUEST_RE.test(userText)) {
|
|
100
|
+
return { decision: "pass", reason: "no_actionable_request", assistantText: text, userText, hasToolCall };
|
|
101
|
+
}
|
|
102
|
+
if (PLAN_ONLY_REQUEST_RE.test(userText)) {
|
|
103
|
+
return { decision: "pass", reason: "no_actionable_request", assistantText: text, userText, hasToolCall };
|
|
104
|
+
}
|
|
105
|
+
if (EXPLICIT_CONTINUE_RE.test(userText) && recentTurnHasToolActivity(parsed)) {
|
|
106
|
+
return { decision: "pass", reason: "recent_tool_activity", assistantText: text, userText, hasToolCall };
|
|
107
|
+
}
|
|
108
|
+
if (WAITING_FOR_USER_RE.test(text)) {
|
|
109
|
+
return { decision: "pass", reason: "waiting_for_user", assistantText: text, userText, hasToolCall };
|
|
110
|
+
}
|
|
111
|
+
if (text.trim().length > MAX_ANNOUNCEMENT_CHARS) {
|
|
112
|
+
return { decision: "pass", reason: "substantive_answer", assistantText: text, userText, hasToolCall };
|
|
113
|
+
}
|
|
114
|
+
if (!PLAN_OR_COMPLETION_RE.test(text)) {
|
|
115
|
+
return { decision: "ambiguous", reason: "no_execution_claim", assistantText: text, userText, hasToolCall };
|
|
116
|
+
}
|
|
117
|
+
return { decision: "continue", reason: "suspicious_no_tool", assistantText: text, userText, hasToolCall };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function assistantMessageFromEvents(events: readonly AdapterEvent[]): OcxAssistantMessage | undefined {
|
|
121
|
+
let text = "";
|
|
122
|
+
let thinking = "";
|
|
123
|
+
let signature: string | undefined;
|
|
124
|
+
const redacted: string[] = [];
|
|
125
|
+
for (const event of events) {
|
|
126
|
+
if (event.type === "text_delta") text += event.text;
|
|
127
|
+
else if (event.type === "thinking_delta") thinking += event.thinking;
|
|
128
|
+
else if (event.type === "thinking_signature") signature = event.signature;
|
|
129
|
+
else if (event.type === "redacted_thinking") redacted.push(event.data);
|
|
130
|
+
}
|
|
131
|
+
const content: OcxAssistantContentPart[] = [];
|
|
132
|
+
if (thinking || signature || redacted.length > 0) {
|
|
133
|
+
content.push({ type: "thinking", thinking, ...(signature ? { signature } : {}), ...(redacted.length > 0 ? { redacted } : {}) });
|
|
134
|
+
}
|
|
135
|
+
if (text) content.push({ type: "text", text });
|
|
136
|
+
if (content.length === 0) return undefined;
|
|
137
|
+
return { role: "assistant", content, timestamp: Date.now() };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function buildContinuationRequest(parsed: OcxParsedRequest, events: readonly AdapterEvent[]): OcxParsedRequest {
|
|
141
|
+
const messages = [...parsed.context.messages];
|
|
142
|
+
const assistant = assistantMessageFromEvents(events);
|
|
143
|
+
if (assistant) messages.push(assistant);
|
|
144
|
+
messages.push({ role: "developer", content: TERMINAL_GUARD_NUDGE, timestamp: Date.now() });
|
|
145
|
+
return { ...parsed, context: { ...parsed.context, messages } };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface GuardedEventStreamOptions {
|
|
149
|
+
parsed: OcxParsedRequest;
|
|
150
|
+
firstEvents: AsyncIterable<AdapterEvent>;
|
|
151
|
+
continuation: (parsed: OcxParsedRequest) => AsyncIterable<AdapterEvent> | Promise<AsyncIterable<AdapterEvent>>;
|
|
152
|
+
adapterName?: string;
|
|
153
|
+
maxAutoContinuations?: number;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function mergeUsage(first: OcxUsage | undefined, second: OcxUsage | undefined): OcxUsage | undefined {
|
|
157
|
+
if (!first) return second;
|
|
158
|
+
if (!second) return first;
|
|
159
|
+
const sumOptional = (key: keyof OcxUsage): number | undefined => {
|
|
160
|
+
const left = first[key];
|
|
161
|
+
const right = second[key];
|
|
162
|
+
return typeof left === "number" || typeof right === "number"
|
|
163
|
+
? (typeof left === "number" ? left : 0) + (typeof right === "number" ? right : 0)
|
|
164
|
+
: undefined;
|
|
165
|
+
};
|
|
166
|
+
const cachedInputTokens = sumOptional("cachedInputTokens");
|
|
167
|
+
const cacheReadInputTokens = sumOptional("cacheReadInputTokens");
|
|
168
|
+
const cacheCreationInputTokens = sumOptional("cacheCreationInputTokens");
|
|
169
|
+
const reasoningOutputTokens = sumOptional("reasoningOutputTokens");
|
|
170
|
+
const inputTokens = first.inputTokens + second.inputTokens;
|
|
171
|
+
const outputTokens = first.outputTokens + second.outputTokens;
|
|
172
|
+
return {
|
|
173
|
+
inputTokens,
|
|
174
|
+
outputTokens,
|
|
175
|
+
totalTokens: inputTokens + outputTokens,
|
|
176
|
+
...(cachedInputTokens !== undefined ? { cachedInputTokens } : {}),
|
|
177
|
+
...(cacheReadInputTokens !== undefined ? { cacheReadInputTokens } : {}),
|
|
178
|
+
...(cacheCreationInputTokens !== undefined ? { cacheCreationInputTokens } : {}),
|
|
179
|
+
...(reasoningOutputTokens !== undefined ? { reasoningOutputTokens } : {}),
|
|
180
|
+
...(first.estimated || second.estimated ? { estimated: true } : {}),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Preserve normal terminals, but withhold one suspicious no-tool terminal for a bounded re-ask. */
|
|
185
|
+
export async function* guardTerminalEventStream(options: GuardedEventStreamOptions): AsyncGenerator<AdapterEvent> {
|
|
186
|
+
const maxContinuations = Math.max(0, Math.min(2, Math.floor(options.maxAutoContinuations ?? 1)));
|
|
187
|
+
let parsed = options.parsed;
|
|
188
|
+
let continuations = 0;
|
|
189
|
+
let accumulatedUsage: OcxUsage | undefined;
|
|
190
|
+
let source: AsyncIterable<AdapterEvent> = options.firstEvents;
|
|
191
|
+
|
|
192
|
+
while (true) {
|
|
193
|
+
const seen: AdapterEvent[] = [];
|
|
194
|
+
let terminalSeen = false;
|
|
195
|
+
for await (const event of source) {
|
|
196
|
+
if (event.type === "done") {
|
|
197
|
+
terminalSeen = true;
|
|
198
|
+
const analysis = options.adapterName === "anthropic"
|
|
199
|
+
? analyzeTerminalTurn(parsed, seen)
|
|
200
|
+
: { decision: "pass" as const };
|
|
201
|
+
const normalStop = event.stopReason !== "max_tokens" && event.stopReason !== "content_filter";
|
|
202
|
+
if (normalStop && analysis.decision === "continue" && continuations < maxContinuations) {
|
|
203
|
+
accumulatedUsage = mergeUsage(accumulatedUsage, event.usage);
|
|
204
|
+
continuations += 1;
|
|
205
|
+
parsed = buildContinuationRequest(parsed, seen);
|
|
206
|
+
yield { type: "assistant_boundary" };
|
|
207
|
+
try {
|
|
208
|
+
source = await options.continuation(parsed);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
yield { type: "error", message: error instanceof Error ? error.message : String(error) };
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
const usage = mergeUsage(accumulatedUsage, event.usage);
|
|
216
|
+
yield usage ? { ...event, usage } : event;
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (event.type === "incomplete" || event.type === "error") {
|
|
220
|
+
terminalSeen = true;
|
|
221
|
+
const usage = mergeUsage(accumulatedUsage, event.usage);
|
|
222
|
+
yield usage ? { ...event, usage } : event;
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
seen.push(event);
|
|
226
|
+
yield event;
|
|
227
|
+
}
|
|
228
|
+
if (!terminalSeen) return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upstream connection failures share one message shape across the three catch sites in
|
|
3
|
+
* core.ts. A TLS certificate/hostname mismatch deserves its own wording: the generic
|
|
4
|
+
* "Provider unreachable" reads as if Remodex built a wrong endpoint, which sent issue
|
|
5
|
+
* #553 looking for an adapter URL bug that does not exist. Name the likely cause and the
|
|
6
|
+
* command that settles it.
|
|
7
|
+
*/
|
|
8
|
+
export function describeUpstreamConnectFailure(err: unknown, connectMs: number): string {
|
|
9
|
+
if (err instanceof Error && err.name === "TimeoutError") {
|
|
10
|
+
return `Provider connect timeout after ${connectMs}ms`;
|
|
11
|
+
}
|
|
12
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
13
|
+
const code = err instanceof Error ? (err as { code?: unknown }).code : undefined;
|
|
14
|
+
// `code` is the reliable signal. The message fallback is anchored to the head because Bun
|
|
15
|
+
// renders this rejection as `ERR_TLS_CERT_ALTNAME_INVALID fetching "<url>"`; matching the
|
|
16
|
+
// bare substring anywhere would also fire on text that merely quotes the code back at us.
|
|
17
|
+
// Only transport failures reach these call sites, so that is defensive rather than load-bearing.
|
|
18
|
+
if (code === "ERR_TLS_CERT_ALTNAME_INVALID" || detail.startsWith("ERR_TLS_CERT_ALTNAME_INVALID")) {
|
|
19
|
+
const host = extractHostname(detail);
|
|
20
|
+
const target = host ?? "the provider host";
|
|
21
|
+
const probe = host ?? "<host>";
|
|
22
|
+
return `Provider TLS certificate does not match ${target}: ${redactUrlUserinfo(detail)}. `
|
|
23
|
+
+ "Remodex did not rewrite this hostname — a certificate that does not cover it normally "
|
|
24
|
+
+ "means TLS interception (corporate proxy, VPN, or local MITM tooling) or a poisoned DNS "
|
|
25
|
+
+ `answer. Check with: openssl s_client -connect ${probe}:443 -servername ${probe} `
|
|
26
|
+
+ "</dev/null | openssl x509 -noout -subject -ext subjectAltName";
|
|
27
|
+
}
|
|
28
|
+
return `Provider unreachable: ${redactUrlUserinfo(detail)}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A provider base URL may carry credentials as userinfo (`https://user:token@host/`), and the
|
|
33
|
+
* runtime error echoes the URL it was fetching. Strip it before the message reaches a client
|
|
34
|
+
* or a log line.
|
|
35
|
+
*/
|
|
36
|
+
function redactUrlUserinfo(detail: string): string {
|
|
37
|
+
return detail.replace(/(https?:\/\/)[^/\s"'@]*@/g, "$1<redacted>@");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function extractHostname(detail: string): string | null {
|
|
41
|
+
const match = detail.match(/https?:\/\/([^/\s"']+)/);
|
|
42
|
+
if (!match?.[1]) return null;
|
|
43
|
+
try {
|
|
44
|
+
return new URL(`https://${match[1]}`).hostname || null;
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { collectResponsesToolGroups } from "../responses/tool-groups";
|
|
2
|
+
import { relaySseWithPayloadRewrite, type SsePayloadRewrite } from "./sse-payload-rewrite";
|
|
3
|
+
import type { TranslatorBudget } from "../lib/translator-budget";
|
|
4
|
+
|
|
5
|
+
interface NamespacedTool {
|
|
6
|
+
namespace: string;
|
|
7
|
+
name: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const IMAGE_GEN_NAMESPACE = "image_gen";
|
|
11
|
+
const IMAGE_GEN_DOTTED_PREFIX = `${IMAGE_GEN_NAMESPACE}.`;
|
|
12
|
+
|
|
13
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
14
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Restrict the generic bridge map to Codex's standalone image namespace and accept the dotted
|
|
19
|
+
* alias emitted by earlier compatibility attempts. Legacy flat dotted declarations are recovered
|
|
20
|
+
* from the raw request because the generic parser does not assign them a namespace. Exact declared
|
|
21
|
+
* names avoid splitting arbitrary double-underscore function names that belong to unrelated tools.
|
|
22
|
+
*/
|
|
23
|
+
export function imageGenToolCallAliases(
|
|
24
|
+
toolNsMap: ReadonlyMap<string, NamespacedTool>,
|
|
25
|
+
requestBody?: unknown,
|
|
26
|
+
translatorBudget?: TranslatorBudget,
|
|
27
|
+
): Map<string, NamespacedTool> {
|
|
28
|
+
const aliases = new Map<string, NamespacedTool>();
|
|
29
|
+
const retainAlias = (key: string, tool: NamespacedTool) => {
|
|
30
|
+
if (aliases.has(key)) {
|
|
31
|
+
aliases.set(key, tool);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
translatorBudget?.chargeRetained(
|
|
35
|
+
Buffer.byteLength(key) + Buffer.byteLength(tool.namespace) + Buffer.byteLength(tool.name),
|
|
36
|
+
{ kind: "request_copies" },
|
|
37
|
+
);
|
|
38
|
+
aliases.set(key, tool);
|
|
39
|
+
};
|
|
40
|
+
for (const [wireName, tool] of toolNsMap) {
|
|
41
|
+
if (tool.namespace !== IMAGE_GEN_NAMESPACE) continue;
|
|
42
|
+
retainAlias(wireName, tool);
|
|
43
|
+
retainAlias(`${tool.namespace}.${tool.name}`, tool);
|
|
44
|
+
}
|
|
45
|
+
for (const group of collectResponsesToolGroups(requestBody)) {
|
|
46
|
+
for (const tool of group) {
|
|
47
|
+
if (
|
|
48
|
+
!isPlainObject(tool)
|
|
49
|
+
|| tool.type !== "function"
|
|
50
|
+
|| typeof tool.name !== "string"
|
|
51
|
+
|| !tool.name.startsWith(IMAGE_GEN_DOTTED_PREFIX)
|
|
52
|
+
|| tool.name.length === IMAGE_GEN_DOTTED_PREFIX.length
|
|
53
|
+
) continue;
|
|
54
|
+
const localName = tool.name.slice(IMAGE_GEN_DOTTED_PREFIX.length);
|
|
55
|
+
const target = { namespace: IMAGE_GEN_NAMESPACE, name: localName };
|
|
56
|
+
retainAlias(`${IMAGE_GEN_NAMESPACE}__${localName}`, target);
|
|
57
|
+
retainAlias(tool.name, target);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return aliases;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Recursively restore only exact image-gen function-call aliases in a parsed Responses payload. */
|
|
64
|
+
function restoreImageGenCalls(
|
|
65
|
+
value: unknown,
|
|
66
|
+
aliases: ReadonlyMap<string, NamespacedTool>,
|
|
67
|
+
): { value: unknown; changed: boolean } {
|
|
68
|
+
if (Array.isArray(value)) {
|
|
69
|
+
let changed = false;
|
|
70
|
+
const restored = value.map(entry => {
|
|
71
|
+
const result = restoreImageGenCalls(entry, aliases);
|
|
72
|
+
changed ||= result.changed;
|
|
73
|
+
return result.value;
|
|
74
|
+
});
|
|
75
|
+
return changed ? { value: restored, changed: true } : { value, changed: false };
|
|
76
|
+
}
|
|
77
|
+
if (!isPlainObject(value)) return { value, changed: false };
|
|
78
|
+
|
|
79
|
+
let changed = false;
|
|
80
|
+
const restored: Record<string, unknown> = {};
|
|
81
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
82
|
+
const result = restoreImageGenCalls(entry, aliases);
|
|
83
|
+
restored[key] = result.value;
|
|
84
|
+
changed ||= result.changed;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const name = typeof value.name === "string" ? value.name : undefined;
|
|
88
|
+
const target = value.type === "function_call" && name ? aliases.get(name) : undefined;
|
|
89
|
+
if (target) {
|
|
90
|
+
restored.name = target.name;
|
|
91
|
+
restored.namespace = target.namespace;
|
|
92
|
+
changed = true;
|
|
93
|
+
}
|
|
94
|
+
return changed ? { value: restored, changed: true } : { value, changed: false };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Restore image-gen function calls in a non-streaming Responses JSON document. */
|
|
98
|
+
export function restoreImageGenCallsInJson(
|
|
99
|
+
text: string,
|
|
100
|
+
aliases: ReadonlyMap<string, NamespacedTool>,
|
|
101
|
+
): string {
|
|
102
|
+
if (aliases.size === 0) return text;
|
|
103
|
+
let payload: unknown;
|
|
104
|
+
try {
|
|
105
|
+
payload = JSON.parse(text);
|
|
106
|
+
} catch {
|
|
107
|
+
return text;
|
|
108
|
+
}
|
|
109
|
+
const restored = restoreImageGenCalls(payload, aliases);
|
|
110
|
+
return restored.changed ? JSON.stringify(restored.value) : text;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Payload rewrite for composition with other client-facing SSE transforms. */
|
|
114
|
+
export function createImageGenCallRestoreRewrite(
|
|
115
|
+
aliases: ReadonlyMap<string, NamespacedTool>,
|
|
116
|
+
): SsePayloadRewrite | undefined {
|
|
117
|
+
if (aliases.size === 0) return undefined;
|
|
118
|
+
return (payload) => restoreImageGenCallsInJson(payload, aliases);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Restore upstream-safe image-gen aliases only on the client-facing SSE branch. The inspection and
|
|
123
|
+
* continuation-cache branch must retain raw upstream names so a replay can be sent back unchanged.
|
|
124
|
+
*/
|
|
125
|
+
export function relaySseWithImageGenCallRestore(
|
|
126
|
+
body: ReadableStream<Uint8Array>,
|
|
127
|
+
aliases: ReadonlyMap<string, NamespacedTool>,
|
|
128
|
+
translatorBudget: TranslatorBudget,
|
|
129
|
+
): ReadableStream<Uint8Array> {
|
|
130
|
+
const rewrite = createImageGenCallRestoreRewrite(aliases);
|
|
131
|
+
return rewrite ? relaySseWithPayloadRewrite(body, rewrite, translatorBudget) : body;
|
|
132
|
+
}
|