@iislee/opencodex 2.11.0 → 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/README.md +114 -19
- package/bin/ocx.mjs +164 -36
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-BF38heuV.js +104 -0
- package/gui/dist/assets/index-DMiI18Kv.css +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +19 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +376 -52
- package/src/adapters/base.ts +54 -7
- package/src/adapters/client-fingerprint.ts +18 -12
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +129 -6
- package/src/adapters/cursor/discovery.ts +61 -4
- package/src/adapters/cursor/effort-map.ts +27 -3
- package/src/adapters/cursor/framing.ts +39 -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/live-models.ts +174 -58
- package/src/adapters/cursor/live-transport.ts +609 -170
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-fs.ts +10 -7
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +0 -1
- package/src/adapters/cursor/native-exec.ts +101 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +383 -65
- package/src/adapters/cursor/request-builder.ts +237 -31
- package/src/adapters/cursor/tool-definitions.ts +242 -12
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +28 -1
- package/src/adapters/cursor.ts +133 -7
- package/src/adapters/google-antigravity-replay.ts +558 -34
- package/src/adapters/google-antigravity-wire.ts +43 -10
- package/src/adapters/google-http.ts +38 -10
- package/src/adapters/google-tool-schema.ts +80 -15
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +618 -74
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +18 -2
- package/src/adapters/kiro-tools.ts +10 -1
- package/src/adapters/kiro.ts +92 -54
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1311 -336
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +830 -56
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +104 -21
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +428 -61
- package/src/chat/inbound.ts +43 -19
- package/src/chat/outbound.ts +82 -26
- package/src/claude/agents-inject.ts +32 -9
- package/src/claude/context-windows.ts +21 -5
- package/src/claude/desktop-3p.ts +243 -9
- package/src/claude/gateway-cache.ts +41 -4
- package/src/claude/inbound.ts +72 -3
- package/src/claude/model-info.ts +38 -15
- package/src/claude/outbound.ts +70 -16
- package/src/cli/account-api.ts +35 -1
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +389 -2
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +30 -6
- package/src/cli/agent.ts +45 -1
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +29 -4
- package/src/cli/claude.ts +103 -34
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +2 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +8 -0
- package/src/cli/config-command.ts +74 -10
- package/src/cli/dispatch.ts +593 -0
- package/src/cli/doctor.ts +315 -43
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +20 -271
- package/src/cli/index.ts +378 -519
- package/src/cli/init.ts +4 -17
- package/src/cli/integrations.ts +120 -2
- 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 +35 -2
- package/src/cli/models.ts +100 -14
- package/src/cli/observe.ts +92 -3
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/provider.ts +24 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +437 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +10 -3
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/v2.ts +105 -10
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1358 -21
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-store.ts +29 -2
- package/src/codex/account-usability.ts +25 -2
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/app-server-processes.ts +493 -106
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +849 -242
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +345 -32
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +68 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +121 -30
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +529 -45
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +224 -30
- package/src/codex/catalog/provider-fetch.ts +1460 -134
- package/src/codex/catalog/sync.ts +1449 -186
- 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 +6 -3
- 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/desired-state.ts +230 -0
- package/src/codex/features.ts +636 -39
- 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 +26 -20
- package/src/codex/history-provider.ts +231 -28
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1073 -152
- package/src/codex/injected-marker.ts +37 -3
- 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 +66 -4
- 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 +24 -0
- package/src/codex/main-account.ts +29 -1
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +56 -10
- 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 +80 -1
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +1 -1
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/project-config-warnings.ts +20 -6
- 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 +175 -13
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +505 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1009 -28
- package/src/codex/subagent-model-fallback.ts +350 -35
- package/src/codex/sync.ts +191 -2
- 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 +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +20 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +81 -9
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +1762 -140
- package/src/generated/compatibility-version.json +3164 -0
- package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
- package/src/grok/inject.ts +16 -5
- package/src/grok/inspect.ts +45 -0
- package/src/grok/sync.ts +2 -2
- package/src/images/loop.ts +152 -29
- package/src/images/plan.ts +23 -13
- 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/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +153 -9
- package/src/lib/bun-runtime.ts +125 -12
- package/src/lib/bun-stream-caps.ts +13 -9
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +6 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +44 -2
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -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/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +4 -1
- package/src/lib/provider-outbound.ts +49 -9
- package/src/lib/redact.ts +419 -3
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/shadow-call.ts +35 -4
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/state-store-registrations.ts +10 -2
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/token-estimate.ts +19 -2
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +44 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +156 -3
- package/src/lib/windows-atomic-replace.ts +155 -0
- package/src/lib/windows-elevation.ts +70 -2
- package/src/lib/windows-secret-acl.ts +409 -69
- 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 +33 -5
- 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.ts +12 -1
- package/src/oauth/callback-server.ts +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +398 -66
- package/src/oauth/key-providers.ts +16 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/local-token-detect.ts +11 -2
- package/src/oauth/log.ts +3 -1
- package/src/oauth/login-cli.ts +88 -28
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/store.ts +119 -21
- package/src/oauth/token-guardian.ts +9 -3
- package/src/pi/models.ts +2 -2
- package/src/providers/alibaba-region-migration.ts +1 -1
- package/src/providers/antigravity-models.ts +521 -31
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +22 -5
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +253 -6
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +10 -7
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/label.ts +1 -1
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +72 -4
- package/src/providers/openai-tier-startup.ts +31 -2
- package/src/providers/openai-tiers.ts +119 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +29 -0
- package/src/providers/quota.ts +1319 -38
- package/src/providers/registry.ts +1429 -111
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +42 -6
- 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 +11 -4
- package/src/reasoning-effort.ts +49 -1
- package/src/responses/compaction.ts +26 -1
- 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 +220 -38
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +7 -1
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +565 -27
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +366 -30
- 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 +2 -29
- package/src/server/auth-cors.ts +267 -46
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +130 -56
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +159 -43
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +18 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +94 -12
- package/src/server/index.ts +865 -181
- package/src/server/lifecycle.ts +284 -13
- package/src/server/live.ts +136 -17
- 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 +398 -103
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/combo-routes.ts +62 -24
- package/src/server/management/config-routes.ts +464 -51
- package/src/server/management/context.ts +80 -2
- 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 +101 -32
- package/src/server/management/model-routes.ts +189 -131
- 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 +80 -4
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +764 -157
- 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 +380 -0
- package/src/server/management/shared.ts +27 -11
- package/src/server/management/sidebar-routes.ts +47 -31
- 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 +288 -32
- package/src/server/management/system-routes.ts +77 -0
- package/src/server/management/usage-summary-cache.ts +9 -1
- 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 +115 -14
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +132 -5
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +236 -76
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log.ts +235 -22
- 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 +204 -35
- package/src/server/responses/compact.ts +442 -55
- package/src/server/responses/core.ts +2872 -331
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +79 -4
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -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 +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-item-id-repair.ts +54 -6
- 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 +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +110 -22
- package/src/server/startup-action-control.ts +8 -1
- package/src/server/startup-health-cache.ts +19 -1
- package/src/server/system-env.ts +80 -9
- package/src/server/ws-bridge.ts +39 -38
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1111 -90
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/scanner.ts +1 -1
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +83 -9
- package/src/tray/windows.ts +43 -16
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +845 -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 +104 -1236
- package/src/update/index.ts +32 -19
- package/src/update/job.ts +442 -67
- package/src/update/notify.ts +12 -6
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +268 -16
- package/src/usage/log.ts +606 -41
- package/src/usage/summary.ts +177 -9
- 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 +10 -6
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +9 -3
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +238 -24
- 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 +13 -7
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +11 -3
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +279 -50
- package/src/web-search/parse.ts +125 -30
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/xai-executor.ts +219 -0
- package/gui/dist/assets/index-DTpMHS4F.js +0 -67
- package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
- package/src/cli/internal-dispatch.ts +0 -20
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derived request-history index (RI-02).
|
|
3
|
+
*
|
|
4
|
+
* `usage.jsonl` stays canonical; this module maintains a rebuildable SQLite
|
|
5
|
+
* projection (ADR-1, ADR-8). On every open/query it verifies schema version,
|
|
6
|
+
* file identity, integrity, and byte offset, then appends whatever complete
|
|
7
|
+
* JSONL rows arrived since the last index. Missing/corrupt/stale index or a
|
|
8
|
+
* replaced/truncated source triggers an automatic full rebuild; canonical
|
|
9
|
+
* history is never touched.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { Database } from "bun:sqlite";
|
|
13
|
+
import {
|
|
14
|
+
closeSync,
|
|
15
|
+
existsSync,
|
|
16
|
+
fstatSync,
|
|
17
|
+
openSync,
|
|
18
|
+
readSync,
|
|
19
|
+
unlinkSync,
|
|
20
|
+
} from "node:fs";
|
|
21
|
+
import { getConfigDir } from "../../config";
|
|
22
|
+
import { recordOwnedConfigPath } from "../../lib/config-ownership";
|
|
23
|
+
import {
|
|
24
|
+
currentUsageLogRevision,
|
|
25
|
+
normalizeUsageEntryForTest,
|
|
26
|
+
usageLogPath,
|
|
27
|
+
type PersistedUsageEntry,
|
|
28
|
+
type UsageLogRevision,
|
|
29
|
+
} from "../../usage/log";
|
|
30
|
+
import {
|
|
31
|
+
HISTORY_DDL,
|
|
32
|
+
HISTORY_META_KEYS,
|
|
33
|
+
HISTORY_SCHEMA_VERSION,
|
|
34
|
+
historyIndexPath,
|
|
35
|
+
} from "./schema";
|
|
36
|
+
import {
|
|
37
|
+
decodeHistoryCursor,
|
|
38
|
+
encodeHistoryCursor,
|
|
39
|
+
InvalidCursorError,
|
|
40
|
+
type HistoryCursor,
|
|
41
|
+
} from "./cursor";
|
|
42
|
+
|
|
43
|
+
export interface RequestHistoryIndexMeta {
|
|
44
|
+
schemaVersion: number;
|
|
45
|
+
dbPath: string;
|
|
46
|
+
sourceSize: number;
|
|
47
|
+
sourceMtimeMs: number;
|
|
48
|
+
indexedOffset: number;
|
|
49
|
+
indexedRows: number;
|
|
50
|
+
builtAtMs: number;
|
|
51
|
+
lastError: string | null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface RequestHistoryFilters {
|
|
55
|
+
provider?: string;
|
|
56
|
+
model?: string;
|
|
57
|
+
requestedModel?: string;
|
|
58
|
+
status?: number;
|
|
59
|
+
conversationId?: string;
|
|
60
|
+
surface?: string;
|
|
61
|
+
inboundProtocol?: string;
|
|
62
|
+
apiKeyId?: string;
|
|
63
|
+
profileId?: string;
|
|
64
|
+
fallback?: boolean;
|
|
65
|
+
from?: number;
|
|
66
|
+
to?: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface RequestHistoryPage {
|
|
70
|
+
rows: PersistedUsageEntry[];
|
|
71
|
+
nextCursor?: string;
|
|
72
|
+
hasMore: boolean;
|
|
73
|
+
meta: RequestHistoryIndexMeta;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const REQUEST_HISTORY_MAX_PAGE_SIZE = 100;
|
|
77
|
+
export const REQUEST_HISTORY_DEFAULT_PAGE_SIZE = 50;
|
|
78
|
+
export const REQUEST_HISTORY_INSERT_BATCH = 500;
|
|
79
|
+
export const REQUEST_HISTORY_READ_CHUNK_BYTES = 64 * 1024;
|
|
80
|
+
// The SQLite index is a disposable projection. Complete JSONL records above
|
|
81
|
+
// this bound are omitted from the projection; the canonical usage.jsonl is
|
|
82
|
+
// never truncated or rewritten by the indexer.
|
|
83
|
+
export const REQUEST_HISTORY_MAX_RECORD_BYTES = 1024 * 1024;
|
|
84
|
+
|
|
85
|
+
let db: Database | null = null;
|
|
86
|
+
let dbPath = "";
|
|
87
|
+
let openPromise: Promise<RequestHistoryIndexMeta> | null = null;
|
|
88
|
+
|
|
89
|
+
function indexDbPath(): string {
|
|
90
|
+
const dir = getConfigDir();
|
|
91
|
+
const path = historyIndexPath(dir);
|
|
92
|
+
recordOwnedConfigPath(dir, path);
|
|
93
|
+
return path;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function metaValue(dbHandle: Database, key: string): string | null {
|
|
97
|
+
const row = dbHandle.query("SELECT value FROM schema_meta WHERE key = ?").get(key) as
|
|
98
|
+
| { value: string }
|
|
99
|
+
| undefined;
|
|
100
|
+
return row?.value ?? null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function setMeta(dbHandle: Database, key: string, value: string | number): void {
|
|
104
|
+
dbHandle.query(
|
|
105
|
+
"INSERT INTO schema_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value",
|
|
106
|
+
).run(key, String(value));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function readIndexedMeta(dbHandle: Database): Omit<RequestHistoryIndexMeta, "dbPath"> {
|
|
110
|
+
const asNumber = (key: string): number => {
|
|
111
|
+
const value = metaValue(dbHandle, key);
|
|
112
|
+
const parsed = value === null ? NaN : Number(value);
|
|
113
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
114
|
+
};
|
|
115
|
+
return {
|
|
116
|
+
schemaVersion: asNumber(HISTORY_META_KEYS.schemaVersion) || HISTORY_SCHEMA_VERSION,
|
|
117
|
+
sourceSize: asNumber(HISTORY_META_KEYS.sourceSize),
|
|
118
|
+
sourceMtimeMs: asNumber(HISTORY_META_KEYS.sourceMtimeMs),
|
|
119
|
+
indexedOffset: asNumber(HISTORY_META_KEYS.indexedOffset),
|
|
120
|
+
indexedRows: asNumber(HISTORY_META_KEYS.indexedRows),
|
|
121
|
+
builtAtMs: asNumber(HISTORY_META_KEYS.builtAtMs),
|
|
122
|
+
lastError: metaValue(dbHandle, HISTORY_META_KEYS.lastError),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function metaFor(dbHandle: Database): RequestHistoryIndexMeta {
|
|
127
|
+
return { dbPath, ...readIndexedMeta(dbHandle) };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function sourceIdentity(): UsageLogRevision | null {
|
|
131
|
+
return currentUsageLogRevision();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function readStoredMetaField(dbHandle: Database, key: string): string {
|
|
135
|
+
return metaValue(dbHandle, key) ?? "";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function sourceIdentityMatches(dbHandle: Database, revision: UsageLogRevision | null): boolean {
|
|
139
|
+
const stored = readIndexedMeta(dbHandle);
|
|
140
|
+
if (revision === null) return stored.sourceSize === 0;
|
|
141
|
+
const storedPath = readStoredMetaField(dbHandle, HISTORY_META_KEYS.sourcePath);
|
|
142
|
+
if (!storedPath) return false;
|
|
143
|
+
const storedDev = Number(readStoredMetaField(dbHandle, HISTORY_META_KEYS.sourceDev));
|
|
144
|
+
const storedIno = Number(readStoredMetaField(dbHandle, HISTORY_META_KEYS.sourceIno));
|
|
145
|
+
const storedBirthtimeMs = Number(readStoredMetaField(dbHandle, HISTORY_META_KEYS.sourceBirthtimeMs));
|
|
146
|
+
return storedPath === revision.path
|
|
147
|
+
&& storedDev === Number(revision.dev)
|
|
148
|
+
&& storedIno === Number(revision.ino)
|
|
149
|
+
&& storedBirthtimeMs === Number(revision.birthtimeMs);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Extract the `requests` row columns from a canonical persisted entry. */
|
|
153
|
+
function extractRow(entry: PersistedUsageEntry): Array<string | number | null> {
|
|
154
|
+
const attempts = entry.attempts;
|
|
155
|
+
return [
|
|
156
|
+
entry.requestId,
|
|
157
|
+
entry.timestamp,
|
|
158
|
+
entry.provider,
|
|
159
|
+
entry.model,
|
|
160
|
+
entry.requestedModel ?? null,
|
|
161
|
+
entry.status,
|
|
162
|
+
entry.surface ?? null,
|
|
163
|
+
entry.inboundProtocol ?? null,
|
|
164
|
+
entry.apiKeyId ?? null,
|
|
165
|
+
entry.conversationId ?? null,
|
|
166
|
+
entry.routeDecision?.routeKind ?? null,
|
|
167
|
+
entry.routeDecision?.profile?.id ?? null,
|
|
168
|
+
entry.routeDecision?.profile?.revision ?? null,
|
|
169
|
+
(attempts?.length ?? 0) > 1 ? 1 : 0,
|
|
170
|
+
entry.durationMs,
|
|
171
|
+
entry.firstOutputMs ?? null,
|
|
172
|
+
entry.usageStatus,
|
|
173
|
+
entry.usage ? JSON.stringify(entry.usage) : null,
|
|
174
|
+
entry.totalTokens ?? null,
|
|
175
|
+
entry.errorCode ?? null,
|
|
176
|
+
entry.terminalStatus ?? null,
|
|
177
|
+
entry.closeReason ?? null,
|
|
178
|
+
attempts?.length ?? 1,
|
|
179
|
+
entry.routeDecision ? JSON.stringify(entry.routeDecision) : null,
|
|
180
|
+
JSON.stringify(entry),
|
|
181
|
+
];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const ROW_INSERT = `
|
|
185
|
+
INSERT OR IGNORE INTO requests (
|
|
186
|
+
request_id, timestamp, provider, model, requested_model, status, surface,
|
|
187
|
+
inbound_protocol, api_key_id, conversation_id, route_kind, profile_id,
|
|
188
|
+
profile_revision, fallback, duration_ms, first_output_ms, usage_status,
|
|
189
|
+
usage_json, total_tokens, error_code, terminal_status, close_reason,
|
|
190
|
+
attempt_count, decision_json, row_json
|
|
191
|
+
) VALUES (
|
|
192
|
+
?, ?, ?, ?, ?, ?, ?,
|
|
193
|
+
?, ?, ?, ?, ?, ?,
|
|
194
|
+
?, ?, ?, ?, ?, ?, ?,
|
|
195
|
+
?, ?, ?, ?, ?
|
|
196
|
+
)`;
|
|
197
|
+
|
|
198
|
+
function parsedEntryFromLine(line: string): PersistedUsageEntry | null {
|
|
199
|
+
if (!line.trim()) return null;
|
|
200
|
+
try {
|
|
201
|
+
const parsed = JSON.parse(line) as PersistedUsageEntry;
|
|
202
|
+
if (parsed && typeof parsed === "object"
|
|
203
|
+
&& typeof parsed.requestId === "string"
|
|
204
|
+
&& typeof parsed.timestamp === "number"
|
|
205
|
+
&& typeof parsed.provider === "string"
|
|
206
|
+
&& typeof parsed.model === "string"
|
|
207
|
+
&& typeof parsed.status === "number"
|
|
208
|
+
&& typeof parsed.durationMs === "number") {
|
|
209
|
+
return parsed;
|
|
210
|
+
}
|
|
211
|
+
} catch {
|
|
212
|
+
/* skip partial / hand-edited lines, same as every other reader */
|
|
213
|
+
}
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function ingestSourceTail(dbHandle: Database, path: string, fromOffset: number): number {
|
|
218
|
+
let inserted = 0;
|
|
219
|
+
let pending: Array<Array<string | number | null>> = [];
|
|
220
|
+
const insert = dbHandle.prepare(ROW_INSERT);
|
|
221
|
+
let fd: number | undefined;
|
|
222
|
+
try {
|
|
223
|
+
const commitBatch = () => {
|
|
224
|
+
dbHandle.transaction((rows: Array<Array<string | number | null>>) => {
|
|
225
|
+
for (const row of rows) {
|
|
226
|
+
// `changes` counts real inserts only; INSERT OR IGNORE replays add 0.
|
|
227
|
+
inserted += insert.run(...row).changes;
|
|
228
|
+
}
|
|
229
|
+
})(pending);
|
|
230
|
+
pending = [];
|
|
231
|
+
};
|
|
232
|
+
const ingestLine = (line: Buffer) => {
|
|
233
|
+
const entry = parsedEntryFromLine(line.toString("utf-8"));
|
|
234
|
+
if (!entry) return;
|
|
235
|
+
pending.push(extractRow(entry));
|
|
236
|
+
if (pending.length >= REQUEST_HISTORY_INSERT_BATCH) commitBatch();
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
fd = openSync(path, "r");
|
|
240
|
+
const stat = fstatSync(fd);
|
|
241
|
+
const size = Number(stat.size);
|
|
242
|
+
const readBuffer = Buffer.allocUnsafe(REQUEST_HISTORY_READ_CHUNK_BYTES);
|
|
243
|
+
let position = fromOffset;
|
|
244
|
+
let nextOffset = fromOffset;
|
|
245
|
+
let fragments: Buffer[] = [];
|
|
246
|
+
let fragmentBytes = 0;
|
|
247
|
+
let oversized = false;
|
|
248
|
+
while (position < size) {
|
|
249
|
+
const requested = Math.min(readBuffer.length, size - position);
|
|
250
|
+
const bytesRead = readSync(fd, readBuffer, 0, requested, position);
|
|
251
|
+
if (bytesRead === 0) throw new Error("usage log changed while indexing");
|
|
252
|
+
let lineStart = 0;
|
|
253
|
+
for (let index = 0; index < bytesRead; index++) {
|
|
254
|
+
if (readBuffer[index] !== 0x0a) continue;
|
|
255
|
+
const segment = readBuffer.subarray(lineStart, index);
|
|
256
|
+
if (!oversized && fragmentBytes + segment.length <= REQUEST_HISTORY_MAX_RECORD_BYTES) {
|
|
257
|
+
const line = fragments.length === 0
|
|
258
|
+
? segment
|
|
259
|
+
: Buffer.concat([...fragments, segment], fragmentBytes + segment.length);
|
|
260
|
+
ingestLine(line);
|
|
261
|
+
}
|
|
262
|
+
fragments = [];
|
|
263
|
+
fragmentBytes = 0;
|
|
264
|
+
oversized = false;
|
|
265
|
+
lineStart = index + 1;
|
|
266
|
+
nextOffset = position + index + 1;
|
|
267
|
+
}
|
|
268
|
+
const remainder = readBuffer.subarray(lineStart, bytesRead);
|
|
269
|
+
if (!oversized && fragmentBytes + remainder.length <= REQUEST_HISTORY_MAX_RECORD_BYTES) {
|
|
270
|
+
// Copy because readBuffer is reused on the next iteration.
|
|
271
|
+
fragments.push(Buffer.from(remainder));
|
|
272
|
+
fragmentBytes += remainder.length;
|
|
273
|
+
} else if (remainder.length > 0) {
|
|
274
|
+
fragments = [];
|
|
275
|
+
fragmentBytes = 0;
|
|
276
|
+
oversized = true;
|
|
277
|
+
}
|
|
278
|
+
position += bytesRead;
|
|
279
|
+
}
|
|
280
|
+
if (pending.length > 0) commitBatch();
|
|
281
|
+
const current = readIndexedMeta(dbHandle);
|
|
282
|
+
setMeta(dbHandle, HISTORY_META_KEYS.indexedOffset, nextOffset);
|
|
283
|
+
setMeta(dbHandle, HISTORY_META_KEYS.indexedRows, current.indexedRows + inserted);
|
|
284
|
+
setMeta(dbHandle, HISTORY_META_KEYS.sourceSize, Number(stat.size));
|
|
285
|
+
setMeta(dbHandle, HISTORY_META_KEYS.sourceMtimeMs, Number(stat.mtimeMs));
|
|
286
|
+
setMeta(dbHandle, HISTORY_META_KEYS.builtAtMs, Date.now());
|
|
287
|
+
return inserted;
|
|
288
|
+
} finally {
|
|
289
|
+
if (fd !== undefined) closeSync(fd);
|
|
290
|
+
// Windows file locks: an unterminated prepared statement keeps the DB
|
|
291
|
+
// file busy after close (verified on Bun 1.3.14). Finalize always.
|
|
292
|
+
insert.finalize();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function resetAndCreateSchema(dbHandle: Database): void {
|
|
297
|
+
dbHandle.exec("DROP TABLE IF EXISTS requests");
|
|
298
|
+
dbHandle.exec("DROP TABLE IF EXISTS schema_meta");
|
|
299
|
+
dbHandle.exec(HISTORY_DDL);
|
|
300
|
+
setMeta(dbHandle, HISTORY_META_KEYS.schemaVersion, HISTORY_SCHEMA_VERSION);
|
|
301
|
+
setMeta(dbHandle, HISTORY_META_KEYS.indexedOffset, 0);
|
|
302
|
+
setMeta(dbHandle, HISTORY_META_KEYS.indexedRows, 0);
|
|
303
|
+
setMeta(dbHandle, HISTORY_META_KEYS.builtAtMs, Date.now());
|
|
304
|
+
setMeta(dbHandle, HISTORY_META_KEYS.lastError, "rebuilt");
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function recordSourceMeta(dbHandle: Database, revision: UsageLogRevision | null): void {
|
|
308
|
+
setMeta(dbHandle, HISTORY_META_KEYS.sourcePath, revision?.path ?? "");
|
|
309
|
+
setMeta(dbHandle, HISTORY_META_KEYS.sourceDev, revision?.dev ?? 0);
|
|
310
|
+
setMeta(dbHandle, HISTORY_META_KEYS.sourceIno, revision?.ino ?? 0);
|
|
311
|
+
setMeta(dbHandle, HISTORY_META_KEYS.sourceBirthtimeMs, revision?.birthtimeMs ?? 0);
|
|
312
|
+
setMeta(dbHandle, HISTORY_META_KEYS.sourceSize, revision?.size ?? 0);
|
|
313
|
+
setMeta(dbHandle, HISTORY_META_KEYS.sourceMtimeMs, revision?.mtimeMs ?? 0);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function isHealthy(dbHandle: Database): boolean {
|
|
317
|
+
try {
|
|
318
|
+
const row = dbHandle.query("PRAGMA quick_check").get() as { quick_check?: string } | undefined;
|
|
319
|
+
return row?.quick_check === "ok";
|
|
320
|
+
} catch {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function destroyAndRecreate(path: string, reason: string): Database {
|
|
326
|
+
if (db) {
|
|
327
|
+
try { db.close(); } catch { /* already closed */ }
|
|
328
|
+
db = null;
|
|
329
|
+
}
|
|
330
|
+
// Windows: a partially-opened handle from a failed `new Database` can hold
|
|
331
|
+
// the file briefly after the throw. Retry the unlink before recreating.
|
|
332
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
333
|
+
try {
|
|
334
|
+
for (const suffix of ["-wal", "-shm"] as const) {
|
|
335
|
+
try { unlinkSync(`${path}${suffix}`); } catch { /* sidecar may not exist */ }
|
|
336
|
+
}
|
|
337
|
+
unlinkSync(path);
|
|
338
|
+
break;
|
|
339
|
+
} catch {
|
|
340
|
+
if (attempt === 4) break;
|
|
341
|
+
Bun.sleepSync(50);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
const fresh = new Database(path, { create: true });
|
|
345
|
+
fresh.exec("PRAGMA journal_mode = WAL");
|
|
346
|
+
fresh.exec("PRAGMA busy_timeout = 5000");
|
|
347
|
+
resetAndCreateSchema(fresh);
|
|
348
|
+
setMeta(fresh, HISTORY_META_KEYS.lastError, reason);
|
|
349
|
+
db = fresh;
|
|
350
|
+
return fresh;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function openIndexDb(): Database {
|
|
354
|
+
const path = indexDbPath();
|
|
355
|
+
if (db) return db;
|
|
356
|
+
let handle: Database | undefined;
|
|
357
|
+
try {
|
|
358
|
+
handle = new Database(path, { create: true });
|
|
359
|
+
handle.exec("PRAGMA journal_mode = WAL");
|
|
360
|
+
handle.exec("PRAGMA busy_timeout = 5000");
|
|
361
|
+
handle.exec(HISTORY_DDL);
|
|
362
|
+
if (metaValue(handle, HISTORY_META_KEYS.schemaVersion) === null) {
|
|
363
|
+
// Fresh database: record the schema version so the next refresh treats
|
|
364
|
+
// it as current instead of destroying the file we just created.
|
|
365
|
+
setMeta(handle, HISTORY_META_KEYS.schemaVersion, HISTORY_SCHEMA_VERSION);
|
|
366
|
+
setMeta(handle, HISTORY_META_KEYS.indexedOffset, 0);
|
|
367
|
+
setMeta(handle, HISTORY_META_KEYS.indexedRows, 0);
|
|
368
|
+
setMeta(handle, HISTORY_META_KEYS.builtAtMs, Date.now());
|
|
369
|
+
setMeta(handle, HISTORY_META_KEYS.lastError, "created");
|
|
370
|
+
}
|
|
371
|
+
} catch {
|
|
372
|
+
// A partially-opened handle on a corrupt file can hold the OS lock on
|
|
373
|
+
// Windows; close it before the destructive recreate.
|
|
374
|
+
if (handle) {
|
|
375
|
+
try { handle.close(); } catch { /* already unusable */ }
|
|
376
|
+
}
|
|
377
|
+
handle = destroyAndRecreate(path, "unreadable database recreated");
|
|
378
|
+
}
|
|
379
|
+
dbPath = path;
|
|
380
|
+
db = handle;
|
|
381
|
+
return handle;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function ensureSchemaAndIdentity(dbHandle: Database): "ready" | "rebuilt" {
|
|
385
|
+
try {
|
|
386
|
+
const storedVersion = metaValue(dbHandle, HISTORY_META_KEYS.schemaVersion);
|
|
387
|
+
if (storedVersion !== String(HISTORY_SCHEMA_VERSION)) {
|
|
388
|
+
destroyAndRecreate(dbPath, `schema version ${storedVersion ?? "missing"} -> ${HISTORY_SCHEMA_VERSION}`);
|
|
389
|
+
return "rebuilt";
|
|
390
|
+
}
|
|
391
|
+
if (!isHealthy(dbHandle)) {
|
|
392
|
+
destroyAndRecreate(dbPath, "integrity check failed; index rebuilt");
|
|
393
|
+
return "rebuilt";
|
|
394
|
+
}
|
|
395
|
+
const revision = sourceIdentity();
|
|
396
|
+
if (!sourceIdentityMatches(dbHandle, revision)) {
|
|
397
|
+
destroyAndRecreate(dbPath, "source identity changed; index rebuilt");
|
|
398
|
+
return "rebuilt";
|
|
399
|
+
}
|
|
400
|
+
return "ready";
|
|
401
|
+
} catch {
|
|
402
|
+
// A file that opens but is not actually SQLite (or is mid-corruption)
|
|
403
|
+
// throws on the first statement; treat it as corrupt and rebuild.
|
|
404
|
+
destroyAndRecreate(dbPath, "index unreadable; rebuilt");
|
|
405
|
+
return "rebuilt";
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function fullRebuild(dbHandle: Database, reason: string): void {
|
|
410
|
+
resetAndCreateSchema(dbHandle);
|
|
411
|
+
setMeta(dbHandle, HISTORY_META_KEYS.lastError, reason);
|
|
412
|
+
const path = usageLogPath();
|
|
413
|
+
const revision = sourceIdentity();
|
|
414
|
+
recordSourceMeta(dbHandle, revision);
|
|
415
|
+
if (!existsSync(path)) {
|
|
416
|
+
setMeta(dbHandle, HISTORY_META_KEYS.sourceSize, 0);
|
|
417
|
+
setMeta(dbHandle, HISTORY_META_KEYS.indexedOffset, 0);
|
|
418
|
+
setMeta(dbHandle, HISTORY_META_KEYS.indexedRows, 0);
|
|
419
|
+
setMeta(dbHandle, HISTORY_META_KEYS.builtAtMs, Date.now());
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const inserted = ingestSourceTail(dbHandle, path, 0);
|
|
423
|
+
const current = readIndexedMeta(dbHandle);
|
|
424
|
+
setMeta(dbHandle, HISTORY_META_KEYS.indexedRows, inserted);
|
|
425
|
+
setMeta(dbHandle, HISTORY_META_KEYS.indexedOffset, Math.max(current.indexedOffset, 0));
|
|
426
|
+
setMeta(dbHandle, HISTORY_META_KEYS.builtAtMs, Date.now());
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function refreshLockedSync(): RequestHistoryIndexMeta {
|
|
430
|
+
openIndexDb();
|
|
431
|
+
const state = ensureSchemaAndIdentity(db!);
|
|
432
|
+
const handle = db!;
|
|
433
|
+
const revision = sourceIdentity();
|
|
434
|
+
if (state === "rebuilt") {
|
|
435
|
+
fullRebuild(db!, "rebuilt after identity/schema mismatch");
|
|
436
|
+
return metaFor(db!);
|
|
437
|
+
}
|
|
438
|
+
const current = readIndexedMeta(handle);
|
|
439
|
+
if (revision === null) {
|
|
440
|
+
// Source gone: the derived index must not outlive its canonical ledger.
|
|
441
|
+
if (current.indexedRows > 0) fullRebuild(handle, "source ledger missing; index reset");
|
|
442
|
+
return metaFor(handle);
|
|
443
|
+
}
|
|
444
|
+
const tailNextOffset = current.indexedOffset;
|
|
445
|
+
if (Number(revision.size) < tailNextOffset) {
|
|
446
|
+
// Truncated source: offsets no longer make sense.
|
|
447
|
+
fullRebuild(handle, "source truncated; index rebuilt");
|
|
448
|
+
return metaFor(handle);
|
|
449
|
+
}
|
|
450
|
+
if (tailNextOffset < Number(revision.size)) {
|
|
451
|
+
const inserted = ingestSourceTail(handle, revision.path, tailNextOffset);
|
|
452
|
+
// A clean tail ingest proves the index is healthy: clear any earlier
|
|
453
|
+
// rebuild marker so status readers can distinguish rebuilds from tails.
|
|
454
|
+
if (inserted > 0) setMeta(handle, HISTORY_META_KEYS.lastError, "");
|
|
455
|
+
}
|
|
456
|
+
return metaFor(handle);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/** Synchronous refresh for routing-time evidence reads (RI-06+). */
|
|
460
|
+
export function openRequestHistoryIndexSync(): RequestHistoryIndexMeta {
|
|
461
|
+
return refreshLockedSync();
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Open (and refresh) the index. Single-flight: concurrent callers share one
|
|
466
|
+
* refresh. Never throws for missing/corrupt index or ledger state; those are
|
|
467
|
+
* repaired or reflected in the returned meta.
|
|
468
|
+
*/
|
|
469
|
+
export function openRequestHistoryIndex(): Promise<RequestHistoryIndexMeta> {
|
|
470
|
+
if (!openPromise) {
|
|
471
|
+
openPromise = Promise.resolve(refreshLockedSync()).finally(() => {
|
|
472
|
+
openPromise = null;
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
return openPromise;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
export function closeRequestHistoryIndex(): void {
|
|
479
|
+
if (db) {
|
|
480
|
+
try { db.close(); } catch { /* ignore */ }
|
|
481
|
+
db = null;
|
|
482
|
+
}
|
|
483
|
+
openPromise = null;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/** Force a full rebuild from the canonical ledger (CLI / tests). */
|
|
487
|
+
export async function rebuildRequestHistoryIndex(): Promise<RequestHistoryIndexMeta> {
|
|
488
|
+
const handle = openIndexDb();
|
|
489
|
+
fullRebuild(handle, "manual rebuild requested");
|
|
490
|
+
return metaFor(handle);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
type HistoryQueryRow = {
|
|
494
|
+
row_json: string;
|
|
495
|
+
timestamp?: number;
|
|
496
|
+
request_id?: string;
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
function queryRows(
|
|
500
|
+
handle: Database,
|
|
501
|
+
filters: RequestHistoryFilters,
|
|
502
|
+
cursor: HistoryCursor | null,
|
|
503
|
+
limit: number,
|
|
504
|
+
): { rows: Array<HistoryQueryRow>; fetched: number } {
|
|
505
|
+
const where: string[] = [];
|
|
506
|
+
const values: Array<string | number> = [];
|
|
507
|
+
const add = (clause: string, value: string | number) => {
|
|
508
|
+
where.push(clause);
|
|
509
|
+
values.push(value);
|
|
510
|
+
};
|
|
511
|
+
if (filters.provider !== undefined) add("provider = ?", filters.provider);
|
|
512
|
+
if (filters.model !== undefined) add("model = ?", filters.model);
|
|
513
|
+
if (filters.requestedModel !== undefined) add("requested_model = ?", filters.requestedModel);
|
|
514
|
+
if (filters.status !== undefined) add("status = ?", filters.status);
|
|
515
|
+
if (filters.conversationId !== undefined) add("conversation_id = ?", filters.conversationId);
|
|
516
|
+
if (filters.surface !== undefined) add("surface = ?", filters.surface);
|
|
517
|
+
if (filters.inboundProtocol !== undefined) add("inbound_protocol = ?", filters.inboundProtocol);
|
|
518
|
+
if (filters.apiKeyId !== undefined) add("api_key_id = ?", filters.apiKeyId);
|
|
519
|
+
if (filters.profileId !== undefined) add("profile_id = ?", filters.profileId);
|
|
520
|
+
if (filters.fallback !== undefined) add("fallback = ?", filters.fallback ? 1 : 0);
|
|
521
|
+
if (filters.from !== undefined) add("timestamp >= ?", filters.from);
|
|
522
|
+
if (filters.to !== undefined) add("timestamp <= ?", filters.to);
|
|
523
|
+
if (cursor) {
|
|
524
|
+
where.push("(timestamp < ? OR (timestamp = ? AND request_id < ?))");
|
|
525
|
+
values.push(cursor.t, cursor.t, cursor.i);
|
|
526
|
+
}
|
|
527
|
+
const whereSql = where.length > 0 ? ` WHERE ${where.join(" AND ")}` : "";
|
|
528
|
+
const rows = handle.query(
|
|
529
|
+
`SELECT row_json, timestamp, request_id FROM requests${whereSql} ORDER BY timestamp DESC, request_id DESC LIMIT ?`,
|
|
530
|
+
).all(...values, limit + 1) as Array<HistoryQueryRow>;
|
|
531
|
+
return { rows, fetched: rows.length };
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function requireDb(): Database {
|
|
535
|
+
const handle = db;
|
|
536
|
+
if (!handle) throw new Error("request-history index is not open");
|
|
537
|
+
return handle;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
function hydrateRow(row: HistoryQueryRow | undefined): PersistedUsageEntry | null {
|
|
541
|
+
if (!row) return null;
|
|
542
|
+
try {
|
|
543
|
+
const parsed = JSON.parse(row.row_json) as PersistedUsageEntry;
|
|
544
|
+
if (parsed && typeof parsed === "object" && typeof parsed.requestId === "string") {
|
|
545
|
+
return normalizeUsageEntryForTest(parsed);
|
|
546
|
+
}
|
|
547
|
+
} catch {
|
|
548
|
+
/* defensive: a damaged row is skipped, canonical ledger unaffected */
|
|
549
|
+
}
|
|
550
|
+
return null;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
export async function queryRequestHistory(
|
|
554
|
+
filters: RequestHistoryFilters,
|
|
555
|
+
rawCursor: string | null | undefined,
|
|
556
|
+
pageSize: number | undefined,
|
|
557
|
+
): Promise<RequestHistoryPage> {
|
|
558
|
+
const meta = await openRequestHistoryIndex();
|
|
559
|
+
const cursor = decodeHistoryCursor(rawCursor);
|
|
560
|
+
if (rawCursor !== null && rawCursor !== undefined && cursor === null) {
|
|
561
|
+
throw new InvalidCursorError();
|
|
562
|
+
}
|
|
563
|
+
const limit = Math.min(
|
|
564
|
+
Math.max(1, Math.trunc(pageSize ?? REQUEST_HISTORY_DEFAULT_PAGE_SIZE)),
|
|
565
|
+
REQUEST_HISTORY_MAX_PAGE_SIZE,
|
|
566
|
+
);
|
|
567
|
+
const handle = requireDb();
|
|
568
|
+
const { rows, fetched } = queryRows(handle, filters, cursor, limit);
|
|
569
|
+
const hasMore = fetched > limit;
|
|
570
|
+
const pageRows = rows.slice(0, limit);
|
|
571
|
+
const entries: PersistedUsageEntry[] = [];
|
|
572
|
+
for (const row of pageRows) {
|
|
573
|
+
const entry = hydrateRow(row);
|
|
574
|
+
if (entry) entries.push(entry);
|
|
575
|
+
}
|
|
576
|
+
let nextCursor: string | undefined;
|
|
577
|
+
if (hasMore && pageRows.length > 0) {
|
|
578
|
+
const last = pageRows[pageRows.length - 1]!;
|
|
579
|
+
nextCursor = encodeHistoryCursor({ t: last.timestamp!, i: last.request_id! });
|
|
580
|
+
}
|
|
581
|
+
return { rows: entries, ...(nextCursor ? { nextCursor } : {}), hasMore, meta };
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
export async function requestHistoryRowById(requestId: string): Promise<PersistedUsageEntry | null> {
|
|
585
|
+
await openRequestHistoryIndex();
|
|
586
|
+
const handle = requireDb();
|
|
587
|
+
const row = handle.query("SELECT row_json FROM requests WHERE request_id = ?").get(requestId) as
|
|
588
|
+
| { row_json: string }
|
|
589
|
+
| undefined;
|
|
590
|
+
return hydrateRow(row);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
export async function requestHistoryIndexStatus(): Promise<RequestHistoryIndexMeta> {
|
|
594
|
+
return openRequestHistoryIndex();
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Raw handle for analytics-style queries. Callers must await
|
|
599
|
+
* `openRequestHistoryIndex()` first; the handle is valid until
|
|
600
|
+
* `closeRequestHistoryIndex()`.
|
|
601
|
+
*/
|
|
602
|
+
export function requestHistoryDb(): Database {
|
|
603
|
+
if (!db) throw new Error("request-history index is not open");
|
|
604
|
+
return db;
|
|
605
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema contract for the derived request-history index (RI-02).
|
|
3
|
+
*
|
|
4
|
+
* `usage.jsonl` remains the canonical append-only evidence ledger;
|
|
5
|
+
* `routing-history.sqlite` is a disposable, rebuildable query projection
|
|
6
|
+
* (ADR-1/ADR-8 in devlog/_fin/260804_router_intelligence/000_master_plan.md).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export const HISTORY_SCHEMA_VERSION = 1;
|
|
10
|
+
export const HISTORY_DB_FILENAME = "routing-history.sqlite";
|
|
11
|
+
|
|
12
|
+
export const HISTORY_META_KEYS = {
|
|
13
|
+
schemaVersion: "schema_version",
|
|
14
|
+
sourcePath: "source_path",
|
|
15
|
+
sourceDev: "source_dev",
|
|
16
|
+
sourceIno: "source_ino",
|
|
17
|
+
sourceBirthtimeMs: "source_birthtime_ms",
|
|
18
|
+
sourceSize: "source_size",
|
|
19
|
+
sourceMtimeMs: "source_mtime_ms",
|
|
20
|
+
indexedOffset: "indexed_offset",
|
|
21
|
+
indexedRows: "indexed_rows",
|
|
22
|
+
builtAtMs: "built_at_ms",
|
|
23
|
+
lastError: "last_error",
|
|
24
|
+
} as const;
|
|
25
|
+
|
|
26
|
+
export const HISTORY_DDL = `
|
|
27
|
+
CREATE TABLE IF NOT EXISTS schema_meta (
|
|
28
|
+
key TEXT PRIMARY KEY,
|
|
29
|
+
value TEXT NOT NULL
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
CREATE TABLE IF NOT EXISTS requests (
|
|
33
|
+
request_id TEXT PRIMARY KEY,
|
|
34
|
+
timestamp INTEGER NOT NULL,
|
|
35
|
+
provider TEXT NOT NULL,
|
|
36
|
+
model TEXT NOT NULL,
|
|
37
|
+
requested_model TEXT,
|
|
38
|
+
status INTEGER NOT NULL,
|
|
39
|
+
surface TEXT,
|
|
40
|
+
inbound_protocol TEXT,
|
|
41
|
+
api_key_id TEXT,
|
|
42
|
+
conversation_id TEXT,
|
|
43
|
+
route_kind TEXT,
|
|
44
|
+
profile_id TEXT,
|
|
45
|
+
profile_revision TEXT,
|
|
46
|
+
fallback INTEGER NOT NULL DEFAULT 0,
|
|
47
|
+
duration_ms INTEGER NOT NULL,
|
|
48
|
+
first_output_ms INTEGER,
|
|
49
|
+
usage_status TEXT,
|
|
50
|
+
usage_json TEXT,
|
|
51
|
+
total_tokens INTEGER,
|
|
52
|
+
error_code TEXT,
|
|
53
|
+
terminal_status TEXT,
|
|
54
|
+
close_reason TEXT,
|
|
55
|
+
attempt_count INTEGER NOT NULL DEFAULT 1,
|
|
56
|
+
decision_json TEXT,
|
|
57
|
+
row_json TEXT NOT NULL
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
CREATE INDEX IF NOT EXISTS idx_requests_ts ON requests(timestamp DESC, request_id DESC);
|
|
61
|
+
CREATE INDEX IF NOT EXISTS idx_requests_provider ON requests(provider);
|
|
62
|
+
CREATE INDEX IF NOT EXISTS idx_requests_model ON requests(model);
|
|
63
|
+
CREATE INDEX IF NOT EXISTS idx_requests_requested_model ON requests(requested_model);
|
|
64
|
+
CREATE INDEX IF NOT EXISTS idx_requests_status ON requests(status);
|
|
65
|
+
CREATE INDEX IF NOT EXISTS idx_requests_conversation ON requests(conversation_id);
|
|
66
|
+
CREATE INDEX IF NOT EXISTS idx_requests_api_key ON requests(api_key_id);
|
|
67
|
+
CREATE INDEX IF NOT EXISTS idx_requests_profile ON requests(profile_id);
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
export function historyIndexPath(configDir: string): string {
|
|
71
|
+
return `${configDir.replace(/[\\/]+$/, "")}/${HISTORY_DB_FILENAME}`;
|
|
72
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { OcxRoutingProfileConfig } from "../types";
|
|
2
|
+
|
|
3
|
+
/** Canonical public namespace reserved for routing-policy model ids. */
|
|
4
|
+
export const POLICY_NAMESPACE = "policy";
|
|
5
|
+
|
|
6
|
+
/** Public namespace prefixes claimed by slash-qualified routing-profile aliases. */
|
|
7
|
+
export function routingProfileAliasNamespacePrefixes(
|
|
8
|
+
config: { routingProfiles?: Record<string, OcxRoutingProfileConfig> },
|
|
9
|
+
): string[] {
|
|
10
|
+
return Object.values(config.routingProfiles ?? {}).flatMap((profile) => {
|
|
11
|
+
const alias = typeof profile?.alias === "string" ? profile.alias.trim() : "";
|
|
12
|
+
const slash = alias.indexOf("/");
|
|
13
|
+
return slash > 0 ? [alias.slice(0, slash)] : [];
|
|
14
|
+
});
|
|
15
|
+
}
|