@yansigit/opencodex 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_INSTALL.md +109 -0
- package/LICENSE +21 -0
- package/README.md +303 -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 +587 -0
- package/bin/package-main.mjs +9 -0
- package/gui/dist/assets/index-BNJ7r4Gd.js +102 -0
- package/gui/dist/assets/index-CGoDO3uO.css +1 -0
- package/gui/dist/favicon.png +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 +108 -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-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +1327 -0
- package/src/adapters/azure.ts +36 -0
- package/src/adapters/base.ts +121 -0
- package/src/adapters/client-fingerprint.ts +65 -0
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/arg-codec.ts +38 -0
- package/src/adapters/cursor/arg-normalize.ts +104 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +288 -0
- package/src/adapters/cursor/discovery.ts +333 -0
- package/src/adapters/cursor/effort-map.ts +151 -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/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/kv-store.ts +52 -0
- package/src/adapters/cursor/live-models.ts +269 -0
- package/src/adapters/cursor/live-smoke-gate.ts +41 -0
- package/src/adapters/cursor/live-transport.ts +1653 -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 +76 -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 +547 -0
- package/src/adapters/cursor/native-exec-tools.ts +118 -0
- package/src/adapters/cursor/native-exec.ts +663 -0
- package/src/adapters/cursor/protobuf-events.ts +1381 -0
- package/src/adapters/cursor/protobuf-request.ts +1032 -0
- package/src/adapters/cursor/request-builder.ts +461 -0
- package/src/adapters/cursor/thread-continuity.ts +67 -0
- package/src/adapters/cursor/tool-definitions.ts +735 -0
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport-retry.ts +132 -0
- package/src/adapters/cursor/transport.ts +79 -0
- package/src/adapters/cursor/types.ts +79 -0
- package/src/adapters/cursor.ts +322 -0
- package/src/adapters/google-antigravity-hosts.ts +48 -0
- package/src/adapters/google-antigravity-replay.ts +827 -0
- package/src/adapters/google-antigravity-tools.ts +105 -0
- package/src/adapters/google-antigravity-wire.ts +141 -0
- package/src/adapters/google-errors.ts +92 -0
- package/src/adapters/google-http.ts +460 -0
- package/src/adapters/google-tool-schema.ts +238 -0
- package/src/adapters/google-truncation.ts +24 -0
- package/src/adapters/google-wire-compiler.ts +232 -0
- package/src/adapters/google.ts +1377 -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 +112 -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 +1936 -0
- package/src/adapters/mimo-free.ts +280 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1980 -0
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +1911 -0
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/run-turn-queue.ts +114 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +154 -0
- package/src/adapters/upstream-http-error.ts +48 -0
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +1986 -0
- package/src/chat/inbound.ts +319 -0
- package/src/chat/outbound.ts +821 -0
- package/src/claude/agents-inject.ts +266 -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 +205 -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 +615 -0
- package/src/claude/desktop-health.ts +26 -0
- package/src/claude/desktop-profile.ts +263 -0
- package/src/claude/gateway-cache.ts +107 -0
- package/src/claude/inbound-debug.ts +163 -0
- package/src/claude/inbound.ts +578 -0
- package/src/claude/model-info.ts +174 -0
- package/src/claude/outbound.ts +926 -0
- package/src/cli/access.ts +108 -0
- package/src/cli/account-api.ts +302 -0
- package/src/cli/account-auth.ts +250 -0
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +737 -0
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +299 -0
- package/src/cli/agent-driven.ts +70 -0
- package/src/cli/agent.ts +290 -0
- package/src/cli/catalog-prewarm.ts +27 -0
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +213 -0
- package/src/cli/claude.ts +355 -0
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +47 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +127 -0
- package/src/cli/config-command.ts +209 -0
- package/src/cli/debug.ts +228 -0
- package/src/cli/dispatch.ts +585 -0
- package/src/cli/doctor.ts +1202 -0
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +213 -0
- package/src/cli/help.ts +101 -0
- package/src/cli/index.ts +973 -0
- package/src/cli/init.ts +211 -0
- package/src/cli/integrations.ts +260 -0
- package/src/cli/interactive-confirm.ts +133 -0
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +245 -0
- package/src/cli/models.ts +422 -0
- package/src/cli/observe.ts +206 -0
- package/src/cli/opencode.ts +588 -0
- package/src/cli/provider-replit.ts +232 -0
- package/src/cli/provider-runtime.ts +179 -0
- package/src/cli/provider.ts +492 -0
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +422 -0
- package/src/cli/replit-gateway-key-input.ts +138 -0
- package/src/cli/root.ts +86 -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 +328 -0
- package/src/cli/system-command.ts +112 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +199 -0
- package/src/cli/v2.ts +268 -0
- package/src/cli.ts +10 -0
- package/src/clients/config-export.ts +1704 -0
- package/src/codex/account-id.ts +34 -0
- package/src/codex/account-label.ts +47 -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 +544 -0
- package/src/codex/account-usability.ts +43 -0
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/agent-roles-sync.ts +225 -0
- package/src/codex/agent-roles.ts +238 -0
- package/src/codex/app-server-processes.ts +1143 -0
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +2147 -0
- package/src/codex/auth-collision.ts +109 -0
- package/src/codex/auth-context.ts +665 -0
- package/src/codex/autostart-health.ts +156 -0
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +436 -0
- package/src/codex/catalog/bundled.ts +549 -0
- package/src/codex/catalog/effort.ts +446 -0
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +664 -0
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +650 -0
- package/src/codex/catalog/provider-fetch.ts +2064 -0
- package/src/codex/catalog/sync.ts +1883 -0
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +14 -0
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +651 -0
- package/src/codex/coordinator-doctor.ts +332 -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/exec-invocation.ts +22 -0
- package/src/codex/features.ts +1566 -0
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +407 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +108 -0
- package/src/codex/history-provider.ts +979 -0
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/home.ts +206 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1733 -0
- package/src/codex/injected-marker.ts +106 -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 +80 -0
- package/src/codex/journal.ts +225 -0
- package/src/codex/log-guard/inspect.ts +506 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +56 -0
- package/src/codex/main-account.ts +68 -0
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +273 -0
- package/src/codex/model-entitlements.ts +353 -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 +178 -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 +492 -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 +682 -0
- package/src/codex/paths.ts +144 -0
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +242 -0
- package/src/codex/pool-rotation.ts +295 -0
- package/src/codex/project-config-warnings.ts +425 -0
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +573 -0
- package/src/codex/refresh.ts +62 -0
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +1888 -0
- package/src/codex/runtime.ts +659 -0
- package/src/codex/shim.ts +2170 -0
- package/src/codex/subagent-defaults.ts +550 -0
- package/src/codex/subagent-model-fallback.ts +784 -0
- package/src/codex/sync.ts +319 -0
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +298 -0
- package/src/codex/websocket-registry.ts +100 -0
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +160 -0
- package/src/combos/index.ts +45 -0
- package/src/combos/request.ts +94 -0
- package/src/combos/resolve.ts +232 -0
- package/src/combos/types.ts +398 -0
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +4041 -0
- package/src/fork/register.ts +3 -0
- package/src/generated/compatibility-version.json +3116 -0
- package/src/generated/model-metadata.ts +106 -0
- package/src/github/star-state.ts +203 -0
- package/src/grok/inject.ts +530 -0
- package/src/grok/inspect.ts +45 -0
- package/src/grok/status.ts +121 -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 +955 -0
- package/src/images/plan.ts +143 -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 +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +159 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +361 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +691 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -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 +195 -0
- package/src/lib/app-owned-memory.ts +265 -0
- package/src/lib/bounded-body.ts +346 -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 +130 -0
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +364 -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 +380 -0
- package/src/lib/errors.ts +406 -0
- package/src/lib/eventstream-decoder.ts +253 -0
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/gcp-adc.ts +341 -0
- package/src/lib/injection-debug-log.ts +58 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/open-url.ts +25 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +270 -0
- package/src/lib/privacy.ts +20 -0
- package/src/lib/process-control.ts +168 -0
- package/src/lib/provider-outbound.ts +210 -0
- package/src/lib/provider-url.ts +14 -0
- package/src/lib/proxy-env.ts +18 -0
- package/src/lib/redact.ts +521 -0
- package/src/lib/retry-after.ts +55 -0
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/service-secrets.ts +25 -0
- package/src/lib/shadow-call.ts +61 -0
- package/src/lib/sidecar-tracker.ts +52 -0
- package/src/lib/sse-decoder.ts +364 -0
- package/src/lib/state-store-registrations.ts +119 -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 +90 -0
- package/src/lib/token-estimate.ts +86 -0
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +400 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +392 -0
- package/src/lib/win-exec.ts +115 -0
- package/src/lib/win-paths.ts +68 -0
- package/src/lib/windows-atomic-replace.ts +156 -0
- package/src/lib/windows-elevation.ts +773 -0
- package/src/lib/windows-secret-acl.ts +854 -0
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +403 -0
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic-routing.ts +594 -0
- package/src/oauth/anthropic.ts +188 -0
- package/src/oauth/antigravity-routing.ts +151 -0
- package/src/oauth/callback-server.ts +300 -0
- package/src/oauth/chatgpt.ts +161 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +252 -0
- package/src/oauth/github-copilot.ts +428 -0
- package/src/oauth/google-antigravity.ts +262 -0
- package/src/oauth/health.ts +407 -0
- package/src/oauth/index.ts +1504 -0
- package/src/oauth/key-providers.ts +124 -0
- package/src/oauth/kimi.ts +227 -0
- package/src/oauth/kiro-credentials.ts +726 -0
- package/src/oauth/kiro.ts +621 -0
- package/src/oauth/local-token-detect.ts +130 -0
- package/src/oauth/log.ts +50 -0
- package/src/oauth/login-cli.ts +223 -0
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/pkce.ts +15 -0
- package/src/oauth/store.ts +728 -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 +695 -0
- package/src/providers/antigravity-quota.ts +216 -0
- package/src/providers/api-keys.ts +140 -0
- package/src/providers/base-url-choices.ts +74 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +82 -0
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +586 -0
- package/src/providers/fastwire.ts +501 -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 +449 -0
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +243 -0
- package/src/providers/openai-tier-startup.ts +56 -0
- package/src/providers/openai-tiers.ts +423 -0
- package/src/providers/openai-virtual-models.ts +83 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/openrouter-routing.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +185 -0
- package/src/providers/quota.ts +2345 -0
- package/src/providers/registry.ts +2918 -0
- package/src/providers/replit/constants.ts +27 -0
- package/src/providers/replit/derive.ts +85 -0
- package/src/providers/replit/headers.ts +28 -0
- package/src/providers/replit/origin.ts +55 -0
- package/src/providers/replit/pair-install-response.ts +72 -0
- package/src/providers/replit/probe.ts +199 -0
- package/src/providers/replit/setup.ts +350 -0
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +103 -0
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +148 -0
- package/src/reasoning-effort.ts +183 -0
- package/src/responses/compaction.ts +142 -0
- package/src/responses/custom-tool-compat.ts +266 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +355 -0
- package/src/responses/parser.ts +838 -0
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +60 -0
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +165 -0
- package/src/responses/spill-store.ts +459 -0
- package/src/responses/state.ts +1433 -0
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-groups.ts +19 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +761 -0
- package/src/routing/analytics.ts +378 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -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 +547 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +53 -0
- package/src/server/auth-cors.ts +751 -0
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +442 -0
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +1030 -0
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +190 -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 +568 -0
- package/src/server/index.ts +1813 -0
- package/src/server/lifecycle.ts +498 -0
- package/src/server/live.ts +717 -0
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +1433 -0
- package/src/server/management/api-access.ts +141 -0
- package/src/server/management/api-key-usage.ts +193 -0
- package/src/server/management/body.ts +41 -0
- package/src/server/management/combo-routes.ts +263 -0
- package/src/server/management/config-routes.ts +835 -0
- package/src/server/management/context.ts +113 -0
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +586 -0
- package/src/server/management/model-routes.ts +560 -0
- package/src/server/management/model-rows.ts +163 -0
- package/src/server/management/native-integration-routes.ts +769 -0
- package/src/server/management/oauth-account-routes.ts +637 -0
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +1033 -0
- package/src/server/management/replit-provider-routes.ts +86 -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 +385 -0
- package/src/server/management/shared.ts +286 -0
- package/src/server/management/sidebar-routes.ts +106 -0
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +435 -0
- package/src/server/management/system-routes.ts +194 -0
- package/src/server/management/usage-summary-cache.ts +94 -0
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +314 -0
- package/src/server/management-auth.ts +482 -0
- package/src/server/memory-watchdog.ts +156 -0
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/port-reclaim.ts +307 -0
- package/src/server/ports.ts +156 -0
- package/src/server/proxy-liveness.ts +328 -0
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +353 -0
- package/src/server/relay.ts +1209 -0
- package/src/server/request-decompress.ts +239 -0
- package/src/server/request-log-conversation.ts +168 -0
- package/src/server/request-log.ts +1259 -0
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/collaboration.ts +551 -0
- package/src/server/responses/compact.ts +771 -0
- package/src/server/responses/core.ts +5389 -0
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +331 -0
- package/src/server/responses/fetch-helpers.ts +232 -0
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/passthrough-error.ts +78 -0
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +251 -0
- package/src/server/responses/terminal-guard.ts +251 -0
- package/src/server/responses/upstream-error.ts +53 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -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 +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +153 -0
- package/src/server/responses.ts +25 -0
- package/src/server/search.ts +201 -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 +315 -0
- package/src/server/startup-health-cache.ts +131 -0
- package/src/server/system-env.ts +484 -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 +472 -0
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +3575 -0
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -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 +757 -0
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +876 -0
- package/src/types/provider.ts +545 -0
- package/src/types/request.ts +384 -0
- package/src/types/tools.ts +131 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +106 -0
- package/src/update/badge.ts +72 -0
- package/src/update/index.ts +415 -0
- package/src/update/job.ts +1887 -0
- package/src/update/notify.ts +263 -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/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -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 +625 -0
- package/src/usage/debug.ts +97 -0
- package/src/usage/expected-prices.ts +416 -0
- package/src/usage/log.ts +1223 -0
- package/src/usage/summary.ts +753 -0
- package/src/usage/totals.ts +14 -0
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +189 -0
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +131 -0
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +681 -0
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +195 -0
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +113 -0
- package/src/web-search/format-result.ts +89 -0
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +331 -0
- package/src/web-search/loop.ts +896 -0
- package/src/web-search/parse.ts +315 -0
- package/src/web-search/progress-stream.ts +342 -0
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/synthetic-tool.ts +47 -0
- package/src/web-search/xai-executor.ts +219 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Hard process-wide limits shared by all live model-discovery parsers. */
|
|
2
|
+
export const MODEL_DISCOVERY_MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
|
|
3
|
+
export const MODEL_DISCOVERY_MAX_MODELS = 2_000;
|
|
4
|
+
export const MODEL_DISCOVERY_MAX_MODEL_ID_LENGTH = 1_024;
|
|
5
|
+
|
|
6
|
+
const MODEL_DISCOVERY_MODEL_ID_CONTROL_CHARS = /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;
|
|
7
|
+
|
|
8
|
+
/** Reject model IDs that cannot safely be published as callable catalog selectors. */
|
|
9
|
+
export function isValidModelDiscoveryModelId(value: unknown): value is string {
|
|
10
|
+
if (typeof value !== "string") return false;
|
|
11
|
+
const normalized = value.trim();
|
|
12
|
+
return Boolean(normalized)
|
|
13
|
+
&& normalized === value
|
|
14
|
+
&& normalized.length <= MODEL_DISCOVERY_MAX_MODEL_ID_LENGTH
|
|
15
|
+
&& !MODEL_DISCOVERY_MODEL_ID_CONTROL_CHARS.test(normalized);
|
|
16
|
+
}
|
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
import type { OcxProviderConfig } from "../types";
|
|
2
|
+
import {
|
|
3
|
+
isValidModelDiscoveryModelId,
|
|
4
|
+
MODEL_DISCOVERY_MAX_MODEL_ID_LENGTH,
|
|
5
|
+
MODEL_DISCOVERY_MAX_MODELS,
|
|
6
|
+
MODEL_DISCOVERY_MAX_RESPONSE_BYTES,
|
|
7
|
+
} from "./model-discovery-limits";
|
|
8
|
+
export {
|
|
9
|
+
isValidModelDiscoveryModelId,
|
|
10
|
+
MODEL_DISCOVERY_MAX_MODEL_ID_LENGTH,
|
|
11
|
+
MODEL_DISCOVERY_MAX_MODELS,
|
|
12
|
+
MODEL_DISCOVERY_MAX_RESPONSE_BYTES,
|
|
13
|
+
} from "./model-discovery-limits";
|
|
14
|
+
import {
|
|
15
|
+
getProviderRegistryEntry,
|
|
16
|
+
providerMatchesRegistryTransport,
|
|
17
|
+
registryEntryForProviderDestination,
|
|
18
|
+
type ProviderModelDiscoveryFilter,
|
|
19
|
+
type ProviderModelDiscoveryPredicate,
|
|
20
|
+
type ProviderModelDiscoveryScalar,
|
|
21
|
+
type ProviderModelDiscoverySpec,
|
|
22
|
+
} from "./registry";
|
|
23
|
+
|
|
24
|
+
const MODEL_DISCOVERY_MAX_FILTER_VALUES = 256;
|
|
25
|
+
const MODEL_DISCOVERY_MAX_FILTER_STRING_LENGTH = 1_024;
|
|
26
|
+
|
|
27
|
+
export interface ResolvedProviderModelDiscovery {
|
|
28
|
+
spec?: ProviderModelDiscoverySpec;
|
|
29
|
+
maxResponseBytes: number;
|
|
30
|
+
maxModels: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type ProviderModelsApiItem = Record<string, unknown> & { id: string };
|
|
34
|
+
|
|
35
|
+
export type ModelDiscoveryResponseFailure =
|
|
36
|
+
| "response_too_large"
|
|
37
|
+
| "invalid_json"
|
|
38
|
+
| "invalid_shape"
|
|
39
|
+
| "too_many_models";
|
|
40
|
+
|
|
41
|
+
export type BoundedDiscoveryJsonResult =
|
|
42
|
+
| { ok: true; value: unknown }
|
|
43
|
+
| { ok: false; reason: "response_too_large" | "invalid_json" };
|
|
44
|
+
|
|
45
|
+
export type ProviderModelItemsResult =
|
|
46
|
+
| { ok: true; items: ProviderModelsApiItem[]; rawCount: number }
|
|
47
|
+
| { ok: false; reason: "invalid_shape" | "too_many_models" };
|
|
48
|
+
|
|
49
|
+
export type ModelEnvelopeRowsResult =
|
|
50
|
+
| { ok: true; rows: unknown[] }
|
|
51
|
+
| { ok: false; reason: "invalid_shape" | "too_many_models" };
|
|
52
|
+
|
|
53
|
+
function positiveIntegerAtMost(value: number | undefined, hardLimit: number): number {
|
|
54
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return hardLimit;
|
|
55
|
+
return Math.min(Math.floor(value), hardLimit);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function discoveryPredicateError(predicate: ProviderModelDiscoveryPredicate): string | null {
|
|
59
|
+
if (!Array.isArray(predicate.path) || predicate.path.length === 0 || predicate.path.length > 8) {
|
|
60
|
+
return "predicate path must contain 1-8 segments";
|
|
61
|
+
}
|
|
62
|
+
if (predicate.path.some(segment => typeof segment !== "string" || !segment.trim() || segment.length > 64)) {
|
|
63
|
+
return "predicate path segments must be nonblank strings up to 64 characters";
|
|
64
|
+
}
|
|
65
|
+
const values = "equalsAny" in predicate
|
|
66
|
+
? predicate.equalsAny
|
|
67
|
+
: "containsAny" in predicate
|
|
68
|
+
? predicate.containsAny
|
|
69
|
+
: predicate.containsAll;
|
|
70
|
+
if (!Array.isArray(values) || values.length === 0 || values.length > 32) {
|
|
71
|
+
return "predicate values must contain 1-32 scalars";
|
|
72
|
+
}
|
|
73
|
+
if (values.some(value => (
|
|
74
|
+
(typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean")
|
|
75
|
+
|| (typeof value === "string" && (!value.trim() || value.length > 128))
|
|
76
|
+
|| (typeof value === "number" && !Number.isFinite(value))
|
|
77
|
+
))) {
|
|
78
|
+
return "predicate values must be finite booleans/numbers or nonblank strings up to 128 characters";
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Static registry validation used by parity tests; discovery metadata never comes from config. */
|
|
84
|
+
export function providerModelDiscoverySpecError(spec: ProviderModelDiscoverySpec): string | null {
|
|
85
|
+
if (spec.url && spec.path) return "url and path are mutually exclusive";
|
|
86
|
+
if (spec.url !== undefined) {
|
|
87
|
+
try {
|
|
88
|
+
const parsed = new URL(spec.url);
|
|
89
|
+
if (parsed.protocol !== "https:") return "absolute discovery url must use https";
|
|
90
|
+
if (parsed.username || parsed.password || parsed.hash) return "absolute discovery url must not contain credentials or a fragment";
|
|
91
|
+
} catch {
|
|
92
|
+
return "absolute discovery url must be valid";
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (spec.path !== undefined) {
|
|
96
|
+
const path = spec.path.trim();
|
|
97
|
+
if (!path || path.length > 512) return "discovery path must be 1-512 characters";
|
|
98
|
+
if (/^[a-z][a-z\d+.-]*:/i.test(path) || path.startsWith("//") || path.includes("?") || path.includes("#")) {
|
|
99
|
+
return "discovery path must be a query-free relative/origin path";
|
|
100
|
+
}
|
|
101
|
+
if (path.includes("\\")) return "discovery path must use forward slashes";
|
|
102
|
+
const segments = path.split("/");
|
|
103
|
+
if (segments.some((segment, index) => {
|
|
104
|
+
const decoded = segment.replace(/%2e/gi, ".");
|
|
105
|
+
if (decoded !== "..") return false;
|
|
106
|
+
return index !== 0 || segments.filter(s => s.replace(/%2e/gi, ".") === "..").length !== 1;
|
|
107
|
+
})) {
|
|
108
|
+
return "discovery path must not contain parent-directory segments";
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const queryEntries = Object.entries(spec.query ?? {});
|
|
112
|
+
if (queryEntries.length > 32) return "discovery query may contain at most 32 entries";
|
|
113
|
+
if (queryEntries.some(([key, value]) => !key.trim() || key.length > 128 || typeof value !== "string" || value.length > 512)) {
|
|
114
|
+
return "discovery query keys/values exceed their bounds";
|
|
115
|
+
}
|
|
116
|
+
for (const [field, value, hardLimit] of [
|
|
117
|
+
["maxResponseBytes", spec.maxResponseBytes, MODEL_DISCOVERY_MAX_RESPONSE_BYTES],
|
|
118
|
+
["maxModels", spec.maxModels, MODEL_DISCOVERY_MAX_MODELS],
|
|
119
|
+
] as const) {
|
|
120
|
+
if (value !== undefined && (!Number.isInteger(value) || value <= 0 || value > hardLimit)) {
|
|
121
|
+
return `${field} must be a positive integer no greater than ${hardLimit}`;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
for (const [group, predicates] of Object.entries(spec.filter ?? {})) {
|
|
125
|
+
if (!Array.isArray(predicates) || predicates.length === 0 || predicates.length > 32) {
|
|
126
|
+
return `${group} must contain 1-32 predicates`;
|
|
127
|
+
}
|
|
128
|
+
for (const predicate of predicates) {
|
|
129
|
+
const error = discoveryPredicateError(predicate);
|
|
130
|
+
if (error) return `${group}: ${error}`;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function resolveProviderModelDiscovery(
|
|
137
|
+
providerName: string,
|
|
138
|
+
provider: Pick<OcxProviderConfig, "baseUrl" | "adapter"> & Partial<Pick<OcxProviderConfig, "authMode">>,
|
|
139
|
+
): ResolvedProviderModelDiscovery {
|
|
140
|
+
// The dashboard permits a canonical preset to be saved under a different name. Recover its
|
|
141
|
+
// registry-owned discovery policy by transport in that case. The destination helper is limited
|
|
142
|
+
// to exact fixed-key baseUrl + adapter matches, so custom endpoints, OAuth rows, templates, and
|
|
143
|
+
// overridable destinations cannot acquire another provider's discovery URL or filter.
|
|
144
|
+
const namedEntry = getProviderRegistryEntry(providerName);
|
|
145
|
+
const entry = namedEntry
|
|
146
|
+
? (providerMatchesRegistryTransport(providerName, provider) ? namedEntry : undefined)
|
|
147
|
+
: registryEntryForProviderDestination(provider);
|
|
148
|
+
const spec = entry?.modelDiscovery;
|
|
149
|
+
return {
|
|
150
|
+
...(spec ? { spec } : {}),
|
|
151
|
+
maxResponseBytes: positiveIntegerAtMost(spec?.maxResponseBytes, MODEL_DISCOVERY_MAX_RESPONSE_BYTES),
|
|
152
|
+
maxModels: positiveIntegerAtMost(spec?.maxModels, MODEL_DISCOVERY_MAX_MODELS),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function appendDiscoveryQuery(url: URL, query: Readonly<Record<string, string>> | undefined): URL {
|
|
157
|
+
for (const [key, value] of Object.entries(query ?? {})) url.searchParams.set(key, value);
|
|
158
|
+
return url;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Apply a registry-owned URL/path/query policy to the adapter's normal discovery endpoint. */
|
|
162
|
+
export function resolveProviderModelDiscoveryUrl(
|
|
163
|
+
providerName: string,
|
|
164
|
+
configuredProvider: Pick<OcxProviderConfig, "baseUrl" | "adapter"> & Partial<Pick<OcxProviderConfig, "authMode">>,
|
|
165
|
+
effectiveBaseUrl: string,
|
|
166
|
+
defaultUrl: string,
|
|
167
|
+
): string {
|
|
168
|
+
const { spec } = resolveProviderModelDiscovery(providerName, configuredProvider);
|
|
169
|
+
if (!spec) return defaultUrl;
|
|
170
|
+
|
|
171
|
+
let resolved: URL;
|
|
172
|
+
if (spec.url) {
|
|
173
|
+
resolved = new URL(spec.url);
|
|
174
|
+
} else if (spec.path) {
|
|
175
|
+
const base = new URL(effectiveBaseUrl.endsWith("/") ? effectiveBaseUrl : `${effectiveBaseUrl}/`);
|
|
176
|
+
resolved = spec.path.startsWith("/")
|
|
177
|
+
? new URL(spec.path, base.origin)
|
|
178
|
+
: new URL(spec.path, base);
|
|
179
|
+
} else {
|
|
180
|
+
resolved = new URL(defaultUrl);
|
|
181
|
+
}
|
|
182
|
+
return appendDiscoveryQuery(resolved, spec.query).toString();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function cancelWithoutWaiting(reader: ReadableStreamDefaultReader<Uint8Array>, reason: unknown): void {
|
|
186
|
+
try {
|
|
187
|
+
void reader.cancel(reason).catch(() => undefined);
|
|
188
|
+
} catch {
|
|
189
|
+
// A non-conforming stream may throw synchronously from cancel().
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Read a discovery response under a strict byte ceiling before JSON.parse can allocate freely. */
|
|
194
|
+
export async function readBoundedDiscoveryJson(
|
|
195
|
+
response: Response,
|
|
196
|
+
maxResponseBytes: number,
|
|
197
|
+
): Promise<BoundedDiscoveryJsonResult> {
|
|
198
|
+
const limit = positiveIntegerAtMost(maxResponseBytes, MODEL_DISCOVERY_MAX_RESPONSE_BYTES);
|
|
199
|
+
const declaredLength = Number(response.headers.get("content-length"));
|
|
200
|
+
if (Number.isFinite(declaredLength) && declaredLength > limit) {
|
|
201
|
+
try {
|
|
202
|
+
void response.body?.cancel(new DOMException("Model discovery response is too large", "QuotaExceededError"))
|
|
203
|
+
.catch(() => undefined);
|
|
204
|
+
} catch {
|
|
205
|
+
// Best-effort cancellation only.
|
|
206
|
+
}
|
|
207
|
+
return { ok: false, reason: "response_too_large" };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (!response.body) return { ok: false, reason: "invalid_json" };
|
|
211
|
+
const reader = response.body.getReader();
|
|
212
|
+
const chunks: Uint8Array[] = [];
|
|
213
|
+
let total = 0;
|
|
214
|
+
try {
|
|
215
|
+
while (true) {
|
|
216
|
+
const { value, done } = await reader.read();
|
|
217
|
+
if (done) break;
|
|
218
|
+
if (!value || value.byteLength === 0) continue;
|
|
219
|
+
if (value.byteLength > limit - total) {
|
|
220
|
+
cancelWithoutWaiting(
|
|
221
|
+
reader,
|
|
222
|
+
new DOMException("Model discovery response is too large", "QuotaExceededError"),
|
|
223
|
+
);
|
|
224
|
+
return { ok: false, reason: "response_too_large" };
|
|
225
|
+
}
|
|
226
|
+
chunks.push(value);
|
|
227
|
+
total += value.byteLength;
|
|
228
|
+
}
|
|
229
|
+
} finally {
|
|
230
|
+
try {
|
|
231
|
+
reader.releaseLock();
|
|
232
|
+
} catch {
|
|
233
|
+
// Cancellation may keep the lock briefly.
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const bytes = new Uint8Array(total);
|
|
238
|
+
let offset = 0;
|
|
239
|
+
for (const chunk of chunks) {
|
|
240
|
+
bytes.set(chunk, offset);
|
|
241
|
+
offset += chunk.byteLength;
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
245
|
+
return { ok: true, value: JSON.parse(text) as unknown };
|
|
246
|
+
} catch {
|
|
247
|
+
return { ok: false, reason: "invalid_json" };
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function valueAtPath(item: Record<string, unknown>, path: readonly string[]): unknown {
|
|
252
|
+
let current: unknown = item;
|
|
253
|
+
for (const segment of path) {
|
|
254
|
+
if (current === null || typeof current !== "object" || Array.isArray(current)) return undefined;
|
|
255
|
+
current = (current as Record<string, unknown>)[segment];
|
|
256
|
+
}
|
|
257
|
+
return current;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function comparableScalar(value: unknown, caseInsensitive: boolean): ProviderModelDiscoveryScalar | undefined {
|
|
261
|
+
if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") return undefined;
|
|
262
|
+
if (typeof value === "string" && value.length > MODEL_DISCOVERY_MAX_FILTER_STRING_LENGTH) return undefined;
|
|
263
|
+
return caseInsensitive && typeof value === "string" ? value.toLowerCase() : value;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function comparableNeedles(
|
|
267
|
+
values: readonly ProviderModelDiscoveryScalar[],
|
|
268
|
+
caseInsensitive: boolean,
|
|
269
|
+
): ProviderModelDiscoveryScalar[] {
|
|
270
|
+
return values.map(value => caseInsensitive && typeof value === "string" ? value.toLowerCase() : value);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function predicateMatches(item: ProviderModelsApiItem, predicate: ProviderModelDiscoveryPredicate): boolean {
|
|
274
|
+
const caseInsensitive = predicate.caseInsensitive === true;
|
|
275
|
+
const raw = valueAtPath(item, predicate.path);
|
|
276
|
+
if ("equalsAny" in predicate) {
|
|
277
|
+
const value = comparableScalar(raw, caseInsensitive);
|
|
278
|
+
return value !== undefined && comparableNeedles(predicate.equalsAny, caseInsensitive).includes(value);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const collection = Array.isArray(raw);
|
|
282
|
+
const values: ProviderModelDiscoveryScalar[] = [];
|
|
283
|
+
if (collection) {
|
|
284
|
+
for (let i = 0; i < raw.length && i < MODEL_DISCOVERY_MAX_FILTER_VALUES; i += 1) {
|
|
285
|
+
const value = comparableScalar(raw[i], caseInsensitive);
|
|
286
|
+
if (value !== undefined) values.push(value);
|
|
287
|
+
}
|
|
288
|
+
} else if (typeof raw === "string") {
|
|
289
|
+
values.push(caseInsensitive ? raw.toLowerCase() : raw);
|
|
290
|
+
}
|
|
291
|
+
const needles = comparableNeedles(
|
|
292
|
+
"containsAny" in predicate ? predicate.containsAny : predicate.containsAll,
|
|
293
|
+
caseInsensitive,
|
|
294
|
+
);
|
|
295
|
+
if ("containsAny" in predicate) {
|
|
296
|
+
return needles.some(needle => values.some(value => (
|
|
297
|
+
!collection && typeof value === "string" && typeof needle === "string" ? value.includes(needle) : value === needle
|
|
298
|
+
)));
|
|
299
|
+
}
|
|
300
|
+
return needles.every(needle => values.some(value => (
|
|
301
|
+
!collection && typeof value === "string" && typeof needle === "string" ? value.includes(needle) : value === needle
|
|
302
|
+
)));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export function providerModelMatchesDiscoveryFilter(
|
|
306
|
+
item: ProviderModelsApiItem,
|
|
307
|
+
filter: ProviderModelDiscoveryFilter | undefined,
|
|
308
|
+
): boolean {
|
|
309
|
+
if (!filter) return true;
|
|
310
|
+
if (filter.allOf && !filter.allOf.every(predicate => predicateMatches(item, predicate))) return false;
|
|
311
|
+
if (filter.anyOf && filter.anyOf.length > 0 && !filter.anyOf.some(predicate => predicateMatches(item, predicate))) return false;
|
|
312
|
+
if (filter.noneOf?.some(predicate => predicateMatches(item, predicate))) return false;
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** Extract one allowlisted array envelope while enforcing the raw-row ceiling. */
|
|
317
|
+
export function extractModelEnvelopeRows(
|
|
318
|
+
value: unknown,
|
|
319
|
+
maxModels: number,
|
|
320
|
+
envelopeKeys: readonly string[],
|
|
321
|
+
): ModelEnvelopeRowsResult {
|
|
322
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
323
|
+
return { ok: false, reason: "invalid_shape" };
|
|
324
|
+
}
|
|
325
|
+
const record = value as Record<string, unknown>;
|
|
326
|
+
const rows = envelopeKeys.map(key => record[key]).find(Array.isArray);
|
|
327
|
+
if (!rows) return { ok: false, reason: "invalid_shape" };
|
|
328
|
+
const limit = positiveIntegerAtMost(maxModels, MODEL_DISCOVERY_MAX_MODELS);
|
|
329
|
+
if (rows.length > limit) return { ok: false, reason: "too_many_models" };
|
|
330
|
+
return { ok: true, rows };
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** Validate, bound, deduplicate, and declaratively filter OpenAI `{data:[...]}` or top-level arrays (Together `#617`). */
|
|
334
|
+
/**
|
|
335
|
+
* Metadata a sibling `models[]` array may contribute to an ALREADY-ADMITTED
|
|
336
|
+
* `data[]` row (#1797).
|
|
337
|
+
*
|
|
338
|
+
* llama.cpp serves a dual-envelope body: an Ollama-style `models[]` array
|
|
339
|
+
* carrying `capabilities` alongside the OpenAI-style `data[]` array carrying
|
|
340
|
+
* `meta`, so the two halves of one model's metadata never meet and a server
|
|
341
|
+
* that truthfully advertises "multimodal" produced an image-blind row.
|
|
342
|
+
*
|
|
343
|
+
* Two boundaries make this safe, and both were added after review found the
|
|
344
|
+
* first attempt unsound:
|
|
345
|
+
*
|
|
346
|
+
* 1. It runs AFTER admission filtering. Enriching first let a sibling supply
|
|
347
|
+
* the exact field a provider filter requires — reproduced against the real
|
|
348
|
+
* Chutes policy, where a row lacking `supported_features: ["tools"]` was
|
|
349
|
+
* admitted once a same-id sibling provided it. Enrichment may change what is
|
|
350
|
+
* KNOWN about a model, never WHICH models are published.
|
|
351
|
+
* 2. Only the capability keys #1797 needs are copied. A blanket "fill every
|
|
352
|
+
* absent key" made the untrusted `models[]` array a way into any field the
|
|
353
|
+
* pipeline consumes.
|
|
354
|
+
*
|
|
355
|
+
* The list deliberately EXCLUDES `supported_features` and `features`, even
|
|
356
|
+
* though both are capability-shaped: they are the two keys real provider
|
|
357
|
+
* filters test (`registry.ts:1591` requires `supported_features` to contain
|
|
358
|
+
* "tools"; `registry.ts:1883` tests `features.tool_use`). Ordering already
|
|
359
|
+
* prevents a sibling from flipping an admission verdict, but a key that is
|
|
360
|
+
* both enrichable and filter-relevant is one refactor away from becoming a
|
|
361
|
+
* bypass again. #1797 does not need them.
|
|
362
|
+
*/
|
|
363
|
+
const SIBLING_ENRICHABLE_KEYS = new Set(["capabilities", "modalities", "input_modalities"]);
|
|
364
|
+
|
|
365
|
+
type SiblingIndex = Map<string, Record<string, unknown> | null>;
|
|
366
|
+
|
|
367
|
+
function buildSiblingIndex(value: unknown, limit: number): SiblingIndex | null {
|
|
368
|
+
const record = plainObject(value);
|
|
369
|
+
const sibling = record?.models;
|
|
370
|
+
if (!Array.isArray(sibling) || sibling.length === 0 || sibling.length > limit) return null;
|
|
371
|
+
|
|
372
|
+
const byId: SiblingIndex = new Map();
|
|
373
|
+
for (const raw of sibling) {
|
|
374
|
+
const entry = plainObject(raw);
|
|
375
|
+
if (!entry) continue;
|
|
376
|
+
for (const key of ["id", "model", "name"]) {
|
|
377
|
+
const id = entry[key];
|
|
378
|
+
if (typeof id !== "string" || id.length === 0) continue;
|
|
379
|
+
// `null` marks an ambiguous id: two sibling entries claim it, so neither
|
|
380
|
+
// can be attributed with confidence and both are ignored.
|
|
381
|
+
byId.set(id, byId.has(id) && byId.get(id) !== entry ? null : entry);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return byId.size > 0 ? byId : null;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function enrichAdmittedModel(item: ProviderModelsApiItem, siblings: SiblingIndex): ProviderModelsApiItem {
|
|
388
|
+
const extra = siblings.get(item.id);
|
|
389
|
+
if (!extra) return item;
|
|
390
|
+
let merged: Record<string, unknown> | null = null;
|
|
391
|
+
for (const key of SIBLING_ENRICHABLE_KEYS) {
|
|
392
|
+
if (!(key in extra) || key in item) continue;
|
|
393
|
+
merged ??= { ...(item as Record<string, unknown>) };
|
|
394
|
+
merged[key] = extra[key];
|
|
395
|
+
}
|
|
396
|
+
return (merged ?? item) as ProviderModelsApiItem;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function plainObject(value: unknown): Record<string, unknown> | null {
|
|
400
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
401
|
+
? value as Record<string, unknown>
|
|
402
|
+
: null;
|
|
403
|
+
}
|
|
404
|
+
export function extractProviderModelItems(
|
|
405
|
+
value: unknown,
|
|
406
|
+
discovery: ResolvedProviderModelDiscovery,
|
|
407
|
+
): ProviderModelItemsResult {
|
|
408
|
+
const limit = positiveIntegerAtMost(discovery.maxModels, MODEL_DISCOVERY_MAX_MODELS);
|
|
409
|
+
let data: unknown[];
|
|
410
|
+
let siblings: SiblingIndex | null = null;
|
|
411
|
+
if (Array.isArray(value)) {
|
|
412
|
+
// Together-style top-level /models arrays. Catalog discovery must not treat a stray
|
|
413
|
+
// `models` key on openai-chat responses as valid — only `data` envelopes or top-level arrays.
|
|
414
|
+
if (value.length > limit) return { ok: false, reason: "too_many_models" };
|
|
415
|
+
data = value;
|
|
416
|
+
} else {
|
|
417
|
+
const envelope = extractModelEnvelopeRows(value, discovery.maxModels, ["data"]);
|
|
418
|
+
if (!envelope.ok) return envelope;
|
|
419
|
+
data = envelope.rows;
|
|
420
|
+
siblings = buildSiblingIndex(value, limit);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const items: ProviderModelsApiItem[] = [];
|
|
424
|
+
const seen = new Set<string>();
|
|
425
|
+
for (const raw of data) {
|
|
426
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
427
|
+
return { ok: false, reason: "invalid_shape" };
|
|
428
|
+
}
|
|
429
|
+
const id = (raw as { id?: unknown }).id;
|
|
430
|
+
if (!isValidModelDiscoveryModelId(id)) return { ok: false, reason: "invalid_shape" };
|
|
431
|
+
const prefix = discovery.spec?.stripIdPrefix;
|
|
432
|
+
let finalId = id;
|
|
433
|
+
if (prefix && finalId.startsWith(prefix)) {
|
|
434
|
+
finalId = finalId.slice(prefix.length);
|
|
435
|
+
if (!isValidModelDiscoveryModelId(finalId)) continue;
|
|
436
|
+
}
|
|
437
|
+
const item = finalId === id ? raw as ProviderModelsApiItem : { ...(raw as ProviderModelsApiItem), id: finalId };
|
|
438
|
+
// Admission is decided on the ORIGINAL `data[]` row, before any sibling
|
|
439
|
+
// enrichment. Merging first let a `models[]` entry supply the very field a
|
|
440
|
+
// provider filter requires — reproduced against the real Chutes policy,
|
|
441
|
+
// where a row lacking `supported_features: ["tools"]` was admitted once a
|
|
442
|
+
// same-id sibling provided it. Enrichment must never change WHICH models
|
|
443
|
+
// are published, only what is known about an already-admitted one.
|
|
444
|
+
if (!providerModelMatchesDiscoveryFilter(item, discovery.spec?.filter) || seen.has(finalId)) continue;
|
|
445
|
+
seen.add(finalId);
|
|
446
|
+
items.push(siblings ? enrichAdmittedModel(item, siblings) : item);
|
|
447
|
+
}
|
|
448
|
+
return { ok: true, items, rawCount: data.length };
|
|
449
|
+
}
|