@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,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The witness a native Codex write is coordinated by.
|
|
3
|
+
*
|
|
4
|
+
* NOT an `AdmissionSnapshot`, and the difference is the whole reason this file
|
|
5
|
+
* exists. `admitCodexWrite` refuses before it constructs a snapshot unless
|
|
6
|
+
* ownership is `owned` (`admission.ts`), so every snapshot it produces carries
|
|
7
|
+
* `owned` — the field cannot hold `unknown` at all. Reusing that type here would
|
|
8
|
+
* have meant one of two untruths: either the call becomes gated on ownership,
|
|
9
|
+
* which refuses Codex injection on every Windows machine and on Linux without a
|
|
10
|
+
* reachable user bus, or a hand-built snapshot claims an admission that never
|
|
11
|
+
* happened.
|
|
12
|
+
*
|
|
13
|
+
* So this type authorizes THE WRITE, not the DECISION to write. Deciding whether
|
|
14
|
+
* a write should happen at all is admission's job and belongs to its own phase,
|
|
15
|
+
* behind the Windows definition-chain walk.
|
|
16
|
+
*
|
|
17
|
+
* What the id covers, and why it is the OUTPUT rather than the inputs: the bytes
|
|
18
|
+
* `injectCodexConfig` emits depend on the port, the resolved catalog path, the
|
|
19
|
+
* hostname, websocket mode, legacy mode and the managed sub-agent defaults. An
|
|
20
|
+
* enumeration of those was already incomplete once. Hashing the computed
|
|
21
|
+
* candidate bytes closes the class instead of the instance — an input that
|
|
22
|
+
* changes the output changes the id whether or not anyone remembered to list it.
|
|
23
|
+
*/
|
|
24
|
+
import { createHash } from "node:crypto";
|
|
25
|
+
|
|
26
|
+
export interface CodexWriteCandidate {
|
|
27
|
+
/** The exact string about to replace `config.toml`. */
|
|
28
|
+
readonly configBytes: string;
|
|
29
|
+
/** The exact string about to replace the profile. */
|
|
30
|
+
readonly profileBytes: string;
|
|
31
|
+
/** The RESOLVED catalog path, never the raw option. */
|
|
32
|
+
readonly catalogPath: string | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface CodexWriteEvidence {
|
|
36
|
+
/** sha256 of the `config.toml` bytes this operation read as its input. */
|
|
37
|
+
readonly nativeInputIdentity: string;
|
|
38
|
+
/** Digest of the persisted Remodex config these bytes were derived from. */
|
|
39
|
+
readonly persistedIdentity: string;
|
|
40
|
+
/** Generation as observed before the lock; `present:false` means no coordinator yet. */
|
|
41
|
+
readonly generation: Readonly<{ present: boolean; value: number }>;
|
|
42
|
+
/** Content identity of the journal, or a stable marker for absence. */
|
|
43
|
+
readonly journalIdentity: string;
|
|
44
|
+
readonly canonicalTargets: Readonly<{
|
|
45
|
+
config: string;
|
|
46
|
+
profile: string;
|
|
47
|
+
journal: string;
|
|
48
|
+
}>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface CodexWriteCoordination {
|
|
52
|
+
readonly candidate: CodexWriteCandidate;
|
|
53
|
+
readonly evidence: CodexWriteEvidence;
|
|
54
|
+
/**
|
|
55
|
+
* Recorded context, deliberately OUTSIDE `comparisonId`.
|
|
56
|
+
*
|
|
57
|
+
* The lock compares one id and nothing else, so a field that is copied rather
|
|
58
|
+
* than re-observed detects no drift by being in it — it would only match
|
|
59
|
+
* itself. Ownership is not re-observed under the lock (that would mean running
|
|
60
|
+
* a service-manager subprocess while N and C are held), so it travels as
|
|
61
|
+
* something the operation SAW, not as something the comparison PROVES.
|
|
62
|
+
*/
|
|
63
|
+
readonly observedOwnership: "owned" | "foreign" | "unknown";
|
|
64
|
+
readonly comparisonId: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Collapse a generation to one token.
|
|
69
|
+
*
|
|
70
|
+
* Absent and present-zero are the same authority — no cooperating write has
|
|
71
|
+
* committed — and they cannot be observed the same way: before the lock only
|
|
72
|
+
* absence is visible, and inside it only the committed zero is. Without this
|
|
73
|
+
* they never match and every first write refuses.
|
|
74
|
+
*/
|
|
75
|
+
function generationToken(generation: CodexWriteEvidence["generation"]): string {
|
|
76
|
+
const { present, value } = generation;
|
|
77
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
78
|
+
throw new TypeError(`A config generation must be a non-negative safe integer, got ${String(value)}.`);
|
|
79
|
+
}
|
|
80
|
+
return present && value > 0 ? `gen:${value}` : "gen:0";
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function hashCodexWriteCoordination(
|
|
84
|
+
candidate: CodexWriteCandidate,
|
|
85
|
+
evidence: CodexWriteEvidence,
|
|
86
|
+
): string {
|
|
87
|
+
return createHash("sha256")
|
|
88
|
+
.update(JSON.stringify([
|
|
89
|
+
// The output, hashed directly. Two operations that intend different bytes
|
|
90
|
+
// cannot share an id, however they came to differ.
|
|
91
|
+
createHash("sha256").update(candidate.configBytes).digest("hex"),
|
|
92
|
+
createHash("sha256").update(candidate.profileBytes).digest("hex"),
|
|
93
|
+
candidate.catalogPath,
|
|
94
|
+
evidence.nativeInputIdentity,
|
|
95
|
+
evidence.persistedIdentity,
|
|
96
|
+
generationToken(evidence.generation),
|
|
97
|
+
evidence.journalIdentity,
|
|
98
|
+
evidence.canonicalTargets,
|
|
99
|
+
]))
|
|
100
|
+
.digest("hex");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function codexWriteCoordination(
|
|
104
|
+
candidate: CodexWriteCandidate,
|
|
105
|
+
evidence: CodexWriteEvidence,
|
|
106
|
+
observedOwnership: CodexWriteCoordination["observedOwnership"],
|
|
107
|
+
): CodexWriteCoordination {
|
|
108
|
+
return {
|
|
109
|
+
candidate,
|
|
110
|
+
evidence,
|
|
111
|
+
observedOwnership,
|
|
112
|
+
comparisonId: hashCodexWriteCoordination(candidate, evidence),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { classifyError, isCyberPolicyCode } from "../lib/errors";
|
|
2
|
+
import type { OcxComboTarget } from "../types";
|
|
3
|
+
import { targetKey } from "./types";
|
|
4
|
+
import {
|
|
5
|
+
captureConfigGeneration,
|
|
6
|
+
sweepExpiredOnWrite,
|
|
7
|
+
type GenerationContext,
|
|
8
|
+
} from "../lib/state-store-sweeper";
|
|
9
|
+
|
|
10
|
+
interface TargetCooldown {
|
|
11
|
+
cooldownUntil: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const DEFAULT_COOLDOWN_MS = 60_000;
|
|
15
|
+
const MAX_COOLDOWN_MS = 10 * 60_000;
|
|
16
|
+
|
|
17
|
+
/** Map<`${comboId}\0${provider/model}`, TargetCooldown> */
|
|
18
|
+
const targetCooldowns = new Map<string, TargetCooldown>();
|
|
19
|
+
let lastReconciledGeneration = 0;
|
|
20
|
+
let liveComboTargets = new Set<string>();
|
|
21
|
+
|
|
22
|
+
function cooldownMapKey(
|
|
23
|
+
comboId: string,
|
|
24
|
+
target: Pick<OcxComboTarget, "provider" | "model">,
|
|
25
|
+
): string {
|
|
26
|
+
return `${comboId}\0${targetKey(target)}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function parseRetryAfterMs(
|
|
30
|
+
value: string | null | undefined,
|
|
31
|
+
now = Date.now(),
|
|
32
|
+
): number | undefined {
|
|
33
|
+
const text = value?.trim();
|
|
34
|
+
if (!text) return undefined;
|
|
35
|
+
if (/^\d+(?:\.\d+)?$/.test(text)) {
|
|
36
|
+
const seconds = Number(text);
|
|
37
|
+
if (Number.isFinite(seconds) && seconds > 0) {
|
|
38
|
+
return Math.min(Math.max(Math.ceil(seconds * 1000), 1), MAX_COOLDOWN_MS);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const timestamp = Date.parse(text);
|
|
42
|
+
if (!Number.isFinite(timestamp)) return undefined;
|
|
43
|
+
const delay = timestamp - now;
|
|
44
|
+
return delay > 0 ? Math.min(delay, MAX_COOLDOWN_MS) : undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function isComboTargetInCooldown(
|
|
48
|
+
comboId: string,
|
|
49
|
+
target: Pick<OcxComboTarget, "provider" | "model">,
|
|
50
|
+
now = Date.now(),
|
|
51
|
+
): boolean {
|
|
52
|
+
const key = cooldownMapKey(comboId, target);
|
|
53
|
+
const entry = targetCooldowns.get(key);
|
|
54
|
+
if (!entry) return false;
|
|
55
|
+
if (entry.cooldownUntil <= now) {
|
|
56
|
+
targetCooldowns.delete(key);
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function coolComboTarget(
|
|
63
|
+
comboId: string,
|
|
64
|
+
target: Pick<OcxComboTarget, "provider" | "model">,
|
|
65
|
+
options?: { retryAfter?: string | null; now?: number; cooldownMs?: number; writerGeneration?: number },
|
|
66
|
+
): void {
|
|
67
|
+
const now = options?.now ?? Date.now();
|
|
68
|
+
const writerGeneration = options?.writerGeneration ?? captureConfigGeneration();
|
|
69
|
+
const ownerKey = `${comboId}::${targetKey(target)}`;
|
|
70
|
+
if (writerGeneration < lastReconciledGeneration && !liveComboTargets.has(ownerKey)) return;
|
|
71
|
+
const cooldownMs = options?.cooldownMs
|
|
72
|
+
?? parseRetryAfterMs(options?.retryAfter, now)
|
|
73
|
+
?? DEFAULT_COOLDOWN_MS;
|
|
74
|
+
targetCooldowns.set(cooldownMapKey(comboId, target), {
|
|
75
|
+
cooldownUntil: now + Math.min(Math.max(cooldownMs, 1), MAX_COOLDOWN_MS),
|
|
76
|
+
});
|
|
77
|
+
sweepExpiredOnWrite(now);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function reconcileComboTargetCooldowns(context: GenerationContext): number {
|
|
81
|
+
if (context.generation <= lastReconciledGeneration) return 0;
|
|
82
|
+
liveComboTargets = new Set(context.comboTargets);
|
|
83
|
+
lastReconciledGeneration = context.generation;
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function sweepExpiredComboTargetCooldowns(now = Date.now()): number {
|
|
88
|
+
let removed = 0;
|
|
89
|
+
for (const [key, cooldown] of targetCooldowns) {
|
|
90
|
+
if (cooldown.cooldownUntil > now) continue;
|
|
91
|
+
targetCooldowns.delete(key);
|
|
92
|
+
removed += 1;
|
|
93
|
+
}
|
|
94
|
+
return removed;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function clearComboTargetCooldowns(comboId?: string): void {
|
|
98
|
+
if (comboId === undefined) {
|
|
99
|
+
targetCooldowns.clear();
|
|
100
|
+
liveComboTargets.clear();
|
|
101
|
+
lastReconciledGeneration = 0;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const prefix = `${comboId}\0`;
|
|
105
|
+
for (const key of targetCooldowns.keys()) {
|
|
106
|
+
if (key.startsWith(prefix)) targetCooldowns.delete(key);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export type ComboFailureDecision = "hop" | "stop";
|
|
111
|
+
|
|
112
|
+
export function comboFailureDecision(
|
|
113
|
+
status: number,
|
|
114
|
+
message: string,
|
|
115
|
+
options?: { code?: string | null },
|
|
116
|
+
): ComboFailureDecision {
|
|
117
|
+
if (status === 499) return "stop";
|
|
118
|
+
if (message.toLowerCase().includes("origin_rejected")) return "stop";
|
|
119
|
+
// Cyber policy is a hard non-retryable refusal — honor structured code even when
|
|
120
|
+
// classificationText was truncated before the JSON code field.
|
|
121
|
+
if (isCyberPolicyCode(options?.code)) return "stop";
|
|
122
|
+
const error = classifyError(status, "upstream_error", message);
|
|
123
|
+
if (isCyberPolicyCode(error.code)) return "stop";
|
|
124
|
+
if (["origin_rejected", "context_length_exceeded", "invalid_request_error"].includes(error.code ?? "")) {
|
|
125
|
+
return "stop";
|
|
126
|
+
}
|
|
127
|
+
if ([401, 403, 404, 408, 429].includes(status) || status >= 500) return "hop";
|
|
128
|
+
if ([
|
|
129
|
+
"permission_denied",
|
|
130
|
+
"subscription_required",
|
|
131
|
+
"invalid_api_key",
|
|
132
|
+
"insufficient_quota",
|
|
133
|
+
"rate_limit_exceeded",
|
|
134
|
+
"server_is_overloaded",
|
|
135
|
+
"upstream_server_error",
|
|
136
|
+
].includes(error.code ?? "")) {
|
|
137
|
+
return "hop";
|
|
138
|
+
}
|
|
139
|
+
return "stop";
|
|
140
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export {
|
|
2
|
+
COMBO_NAMESPACE,
|
|
3
|
+
comboAliasIssues,
|
|
4
|
+
comboConfigError,
|
|
5
|
+
comboConfigIssues,
|
|
6
|
+
comboDefaultEffort,
|
|
7
|
+
comboDisabledModelId,
|
|
8
|
+
comboDisabledModelSelectors,
|
|
9
|
+
comboModelId,
|
|
10
|
+
comboPublicModelId,
|
|
11
|
+
getCombo,
|
|
12
|
+
isNativeAliasCombo,
|
|
13
|
+
isValidComboId,
|
|
14
|
+
listComboIds,
|
|
15
|
+
normalizeComboConfig,
|
|
16
|
+
parseComboModelId,
|
|
17
|
+
preservesPhysicalComboProvider,
|
|
18
|
+
resolveComboId,
|
|
19
|
+
targetKey,
|
|
20
|
+
} from "./types";
|
|
21
|
+
export {
|
|
22
|
+
advanceComboAfterFailure,
|
|
23
|
+
clearComboSelectionState,
|
|
24
|
+
NoAvailableComboTargetsError,
|
|
25
|
+
noteComboFailure,
|
|
26
|
+
noteComboSuccess,
|
|
27
|
+
pickComboTarget,
|
|
28
|
+
tryPickComboModel,
|
|
29
|
+
UnknownComboError,
|
|
30
|
+
type ComboPick,
|
|
31
|
+
} from "./resolve";
|
|
32
|
+
export {
|
|
33
|
+
clearComboTargetCooldowns,
|
|
34
|
+
coolComboTarget,
|
|
35
|
+
isComboTargetInCooldown,
|
|
36
|
+
parseRetryAfterMs,
|
|
37
|
+
comboFailureDecision,
|
|
38
|
+
type ComboFailureDecision,
|
|
39
|
+
} from "./failover";
|
|
40
|
+
export {
|
|
41
|
+
comboIdFromRawBody,
|
|
42
|
+
concreteComboRequestBody,
|
|
43
|
+
resetComboEffortWarningStateForTests,
|
|
44
|
+
} from "./request";
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { OcxComboDefaultEffort, OcxComboTarget, OcxConfig } from "../types";
|
|
2
|
+
import { resolveComboId } from "./types";
|
|
3
|
+
|
|
4
|
+
const warnedUnsupportedDefaults = new Set<string>();
|
|
5
|
+
let lastWarningReconciledGeneration = 0;
|
|
6
|
+
|
|
7
|
+
export function reconcileComboWarningMemos(generation: number): number {
|
|
8
|
+
if (generation <= lastWarningReconciledGeneration) return 0;
|
|
9
|
+
const removed = warnedUnsupportedDefaults.size;
|
|
10
|
+
warnedUnsupportedDefaults.clear();
|
|
11
|
+
lastWarningReconciledGeneration = generation;
|
|
12
|
+
return removed;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function resetComboEffortWarningStateForTests(): void {
|
|
16
|
+
warnedUnsupportedDefaults.clear();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function comboIdFromRawBody(body: unknown, config: OcxConfig): string | null {
|
|
20
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return null;
|
|
21
|
+
const model = (body as { model?: unknown }).model;
|
|
22
|
+
if (typeof model !== "string") return null;
|
|
23
|
+
return resolveComboId(config, model);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function concreteComboRequestBody(
|
|
27
|
+
body: unknown,
|
|
28
|
+
target: Pick<OcxComboTarget, "provider" | "model">,
|
|
29
|
+
defaultEffort: OcxComboDefaultEffort | null,
|
|
30
|
+
targetReasoningEfforts: readonly string[] | undefined,
|
|
31
|
+
): Record<string, unknown> {
|
|
32
|
+
const clone = structuredClone(body) as Record<string, unknown>;
|
|
33
|
+
clone.model = `${target.provider}/${target.model}`;
|
|
34
|
+
if (!defaultEffort) return clone;
|
|
35
|
+
const reasoning = clone.reasoning;
|
|
36
|
+
const needsDefault = reasoning === undefined || (
|
|
37
|
+
reasoning
|
|
38
|
+
&& typeof reasoning === "object"
|
|
39
|
+
&& !Array.isArray(reasoning)
|
|
40
|
+
&& !Object.prototype.hasOwnProperty.call(reasoning, "effort")
|
|
41
|
+
);
|
|
42
|
+
if (!needsDefault) return clone;
|
|
43
|
+
// Both picker availability and runtime injection stay fail-closed until this concrete target
|
|
44
|
+
// advertises support. Keep the request guard even if an older dashboard saved a stale default.
|
|
45
|
+
if (!targetReasoningEfforts?.includes(defaultEffort)) {
|
|
46
|
+
const key = `${target.provider}/${target.model}:${defaultEffort}`;
|
|
47
|
+
if (!warnedUnsupportedDefaults.has(key)) {
|
|
48
|
+
warnedUnsupportedDefaults.add(key);
|
|
49
|
+
console.debug("[Remodex] combo default effort omitted", {
|
|
50
|
+
provider: target.provider,
|
|
51
|
+
model: target.model,
|
|
52
|
+
requestedEffort: defaultEffort,
|
|
53
|
+
capability: targetReasoningEfforts === undefined ? "unknown" : "unsupported",
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return clone;
|
|
57
|
+
}
|
|
58
|
+
if (reasoning === undefined) {
|
|
59
|
+
clone.reasoning = { effort: defaultEffort };
|
|
60
|
+
} else {
|
|
61
|
+
clone.reasoning = { ...(reasoning as Record<string, unknown>), effort: defaultEffort };
|
|
62
|
+
}
|
|
63
|
+
return clone;
|
|
64
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import type { OcxComboTarget, OcxConfig } from "../types";
|
|
2
|
+
import { coolComboTarget, isComboTargetInCooldown } from "./failover";
|
|
3
|
+
import { getCombo, resolveComboId, targetKey } from "./types";
|
|
4
|
+
import type { NormalizedComboConfig } from "./types";
|
|
5
|
+
import {
|
|
6
|
+
captureConfigGeneration,
|
|
7
|
+
type GenerationContext,
|
|
8
|
+
} from "../lib/state-store-sweeper";
|
|
9
|
+
|
|
10
|
+
export interface ComboPick {
|
|
11
|
+
comboId: string;
|
|
12
|
+
target: Required<OcxComboTarget>;
|
|
13
|
+
targetIndex: number;
|
|
14
|
+
attempted: string[];
|
|
15
|
+
writerGeneration: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface SelectionState {
|
|
19
|
+
activeKey?: string;
|
|
20
|
+
successes: number;
|
|
21
|
+
currentWeights: Map<string, number>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const selectionState = new Map<string, SelectionState>();
|
|
25
|
+
let lastReconciledGeneration = 0;
|
|
26
|
+
let liveComboTargets = new Set<string>();
|
|
27
|
+
|
|
28
|
+
function comboTargetOwnerKey(comboId: string, key: string): string {
|
|
29
|
+
return `${comboId}::${key}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function mayCommitComboState(comboId: string, key: string, writerGeneration: number): boolean {
|
|
33
|
+
return writerGeneration >= lastReconciledGeneration
|
|
34
|
+
|| liveComboTargets.has(comboTargetOwnerKey(comboId, key));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class UnknownComboError extends Error {
|
|
38
|
+
constructor(readonly comboId: string) {
|
|
39
|
+
super(`Unknown combo: ${comboId}`);
|
|
40
|
+
this.name = "UnknownComboError";
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class NoAvailableComboTargetsError extends Error {
|
|
45
|
+
readonly code = "combo_unavailable";
|
|
46
|
+
|
|
47
|
+
constructor(readonly comboId: string) {
|
|
48
|
+
super(`No available targets for combo: ${comboId}`);
|
|
49
|
+
this.name = "NoAvailableComboTargetsError";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function targetProviderIsUsable(config: OcxConfig, target: OcxComboTarget): boolean {
|
|
54
|
+
return Object.hasOwn(config.providers, target.provider)
|
|
55
|
+
&& config.providers[target.provider]?.disabled !== true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function smoothWeightedIndex(
|
|
59
|
+
targets: Required<OcxComboTarget>[],
|
|
60
|
+
state: SelectionState,
|
|
61
|
+
eligible: (target: Required<OcxComboTarget>) => boolean,
|
|
62
|
+
): number {
|
|
63
|
+
let best = -1;
|
|
64
|
+
let bestScore = Number.NEGATIVE_INFINITY;
|
|
65
|
+
let total = 0;
|
|
66
|
+
for (let i = 0; i < targets.length; i++) {
|
|
67
|
+
const target = targets[i]!;
|
|
68
|
+
if (!eligible(target)) continue;
|
|
69
|
+
const key = targetKey(target);
|
|
70
|
+
const score = (state.currentWeights.get(key) ?? 0) + target.weight;
|
|
71
|
+
state.currentWeights.set(key, score);
|
|
72
|
+
total += target.weight;
|
|
73
|
+
if (score > bestScore) {
|
|
74
|
+
best = i;
|
|
75
|
+
bestScore = score;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (best >= 0) {
|
|
79
|
+
const key = targetKey(targets[best]!);
|
|
80
|
+
state.currentWeights.set(key, (state.currentWeights.get(key) ?? 0) - total);
|
|
81
|
+
}
|
|
82
|
+
return best;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function pickComboTarget(
|
|
86
|
+
config: OcxConfig,
|
|
87
|
+
comboId: string,
|
|
88
|
+
options: {
|
|
89
|
+
exclude?: Iterable<string>;
|
|
90
|
+
eligible?: (target: Required<OcxComboTarget>) => boolean;
|
|
91
|
+
} = {},
|
|
92
|
+
): ComboPick | null {
|
|
93
|
+
const writerGeneration = captureConfigGeneration();
|
|
94
|
+
const combo = getCombo(config, comboId);
|
|
95
|
+
if (!combo) throw new UnknownComboError(comboId);
|
|
96
|
+
const excluded = new Set(options.exclude ?? []);
|
|
97
|
+
const eligible = (target: Required<OcxComboTarget>): boolean =>
|
|
98
|
+
targetProviderIsUsable(config, target)
|
|
99
|
+
&& !excluded.has(targetKey(target))
|
|
100
|
+
&& (options.eligible?.(target) ?? true);
|
|
101
|
+
|
|
102
|
+
let targetIndex = -1;
|
|
103
|
+
if (combo.strategy === "round-robin") {
|
|
104
|
+
let state = selectionState.get(comboId);
|
|
105
|
+
if (!state) {
|
|
106
|
+
state = { successes: 0, currentWeights: new Map() };
|
|
107
|
+
selectionState.set(comboId, state);
|
|
108
|
+
}
|
|
109
|
+
if (state.activeKey) {
|
|
110
|
+
targetIndex = combo.targets.findIndex(target => targetKey(target) === state.activeKey && eligible(target));
|
|
111
|
+
if (targetIndex < 0) {
|
|
112
|
+
delete state.activeKey;
|
|
113
|
+
state.successes = 0;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (targetIndex < 0) {
|
|
117
|
+
targetIndex = smoothWeightedIndex(combo.targets, state, eligible);
|
|
118
|
+
if (targetIndex >= 0) {
|
|
119
|
+
state.activeKey = targetKey(combo.targets[targetIndex]!);
|
|
120
|
+
state.successes = 0;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
targetIndex = combo.targets.findIndex(eligible);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (targetIndex < 0) return null;
|
|
128
|
+
const target = combo.targets[targetIndex]!;
|
|
129
|
+
return {
|
|
130
|
+
comboId,
|
|
131
|
+
target,
|
|
132
|
+
targetIndex,
|
|
133
|
+
attempted: [...excluded, targetKey(target)],
|
|
134
|
+
writerGeneration,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function noteComboSuccess(
|
|
139
|
+
comboId: string,
|
|
140
|
+
combo: NormalizedComboConfig,
|
|
141
|
+
target: Required<OcxComboTarget>,
|
|
142
|
+
writerGeneration = captureConfigGeneration(),
|
|
143
|
+
): void {
|
|
144
|
+
if (combo.strategy !== "round-robin") return;
|
|
145
|
+
const key = targetKey(target);
|
|
146
|
+
if (!mayCommitComboState(comboId, key, writerGeneration)) return;
|
|
147
|
+
const state = selectionState.get(comboId);
|
|
148
|
+
if (!state || state.activeKey !== key) return;
|
|
149
|
+
state.successes += 1;
|
|
150
|
+
if (state.successes >= combo.stickyLimit) {
|
|
151
|
+
delete state.activeKey;
|
|
152
|
+
state.successes = 0;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function noteComboFailure(
|
|
157
|
+
comboId: string,
|
|
158
|
+
target: OcxComboTarget,
|
|
159
|
+
writerGeneration = captureConfigGeneration(),
|
|
160
|
+
): void {
|
|
161
|
+
if (!mayCommitComboState(comboId, targetKey(target), writerGeneration)) return;
|
|
162
|
+
const state = selectionState.get(comboId);
|
|
163
|
+
if (state?.activeKey === targetKey(target)) {
|
|
164
|
+
delete state.activeKey;
|
|
165
|
+
state.successes = 0;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function advanceComboAfterFailure(
|
|
170
|
+
config: OcxConfig,
|
|
171
|
+
pick: ComboPick,
|
|
172
|
+
options: {
|
|
173
|
+
retryAfter?: string | null;
|
|
174
|
+
now?: number;
|
|
175
|
+
eligible?: (target: Required<OcxComboTarget>) => boolean;
|
|
176
|
+
} = {},
|
|
177
|
+
): ComboPick | null {
|
|
178
|
+
noteComboFailure(pick.comboId, pick.target, pick.writerGeneration);
|
|
179
|
+
coolComboTarget(pick.comboId, pick.target, {
|
|
180
|
+
...options,
|
|
181
|
+
writerGeneration: pick.writerGeneration,
|
|
182
|
+
});
|
|
183
|
+
return pickComboTarget(config, pick.comboId, {
|
|
184
|
+
exclude: pick.attempted,
|
|
185
|
+
eligible: target => !isComboTargetInCooldown(pick.comboId, target, options.now)
|
|
186
|
+
&& (options.eligible?.(target) ?? true),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function reconcileComboRotationState(context: GenerationContext): number {
|
|
191
|
+
if (context.generation <= lastReconciledGeneration) return 0;
|
|
192
|
+
let removed = 0;
|
|
193
|
+
for (const [comboId, state] of selectionState) {
|
|
194
|
+
if (!context.comboIds.has(comboId)) {
|
|
195
|
+
selectionState.delete(comboId);
|
|
196
|
+
removed += 1;
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
if (state.activeKey && !context.comboTargets.has(comboTargetOwnerKey(comboId, state.activeKey))) {
|
|
200
|
+
delete state.activeKey;
|
|
201
|
+
state.successes = 0;
|
|
202
|
+
removed += 1;
|
|
203
|
+
}
|
|
204
|
+
for (const key of state.currentWeights.keys()) {
|
|
205
|
+
if (context.comboTargets.has(comboTargetOwnerKey(comboId, key))) continue;
|
|
206
|
+
state.currentWeights.delete(key);
|
|
207
|
+
removed += 1;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
liveComboTargets = new Set(context.comboTargets);
|
|
211
|
+
lastReconciledGeneration = context.generation;
|
|
212
|
+
return removed;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function clearComboSelectionState(comboId?: string): void {
|
|
216
|
+
if (comboId === undefined) {
|
|
217
|
+
selectionState.clear();
|
|
218
|
+
liveComboTargets.clear();
|
|
219
|
+
lastReconciledGeneration = 0;
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
selectionState.delete(comboId);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function tryPickComboModel(config: OcxConfig, modelId: string): ComboPick | null {
|
|
226
|
+
const comboId = resolveComboId(config, modelId);
|
|
227
|
+
if (!comboId) return null;
|
|
228
|
+
if (!getCombo(config, comboId)) throw new UnknownComboError(comboId);
|
|
229
|
+
const picked = pickComboTarget(config, comboId);
|
|
230
|
+
if (!picked) throw new NoAvailableComboTargetsError(comboId);
|
|
231
|
+
return picked;
|
|
232
|
+
}
|