@bitkyc08/opencodex 2.86.0 → 2.88.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/gui/dist/assets/App-CHC89EXQ.js +58 -0
- package/gui/dist/assets/App-wT3mXqFz.css +1 -0
- package/gui/dist/assets/{Tray-DyR9yBee.js → Tray-B5bC7AWL.js} +1 -1
- package/gui/dist/assets/index-B5bsvxor.js +94 -0
- package/gui/dist/assets/index-DPeB9HpV.css +1 -0
- package/gui/dist/assets/quota-summary-D8y2wTsB.js +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/adapters/anthropic/beta-allowlist.ts +9 -8
- package/src/adapters/anthropic/beta-body-pairs.ts +93 -0
- package/src/adapters/anthropic/passthrough.ts +7 -23
- package/src/adapters/anthropic-progress.ts +84 -0
- package/src/adapters/anthropic-rejection-memo.ts +71 -0
- package/src/adapters/anthropic-replay.ts +135 -0
- package/src/adapters/anthropic-tool-catalog.ts +11 -0
- package/src/adapters/anthropic.ts +151 -33
- package/src/adapters/base.ts +2 -0
- package/src/adapters/claude-cli/adapter.ts +111 -23
- package/src/adapters/claude-cli/profiles.ts +2 -1
- package/src/adapters/claude-cli/stable-replay.ts +108 -0
- package/src/adapters/claude-cli/usage-admission.ts +230 -0
- package/src/adapters/coding-agent/protocol.ts +1 -1
- package/src/adapters/coding-agent/turn.ts +18 -2
- package/src/adapters/dsh-account.ts +97 -0
- package/src/adapters/google-progress-history.ts +53 -0
- package/src/adapters/google.ts +52 -9
- package/src/adapters/openai-chat/messages.ts +4 -3
- package/src/adapters/openai-chat/passthrough.ts +8 -2
- package/src/adapters/openai-chat/reasoning-replay.ts +52 -0
- package/src/adapters/openai-responses/compaction-search-history.ts +14 -7
- package/src/adapters/openai-responses/passthrough.ts +57 -125
- package/src/adapters/openai-responses/request-strips.ts +25 -3
- package/src/adapters/openai-responses/transport.ts +81 -0
- package/src/adapters/qoder/adapter.ts +4 -2
- package/src/adapters/registry.ts +5 -0
- package/src/adapters/zed.ts +26 -1
- package/src/advisor/activity.ts +55 -0
- package/src/advisor/budget.ts +62 -0
- package/src/advisor/consult.ts +4 -1
- package/src/advisor/context.ts +16 -4
- package/src/advisor/evidence-tool.ts +21 -0
- package/src/advisor/evidence.ts +117 -0
- package/src/advisor/runtime.ts +79 -31
- package/src/advisor/settings.ts +11 -2
- package/src/bridge/errors.ts +19 -1
- package/src/bridge/internal.ts +7 -1
- package/src/bridge/response-json.ts +18 -3
- package/src/bridge/sse.ts +59 -8
- package/src/bridge/terminal-refusal.ts +59 -0
- package/src/claude/desktop-3p-library.ts +32 -7
- package/src/claude/desktop-3p.ts +55 -13
- package/src/claude/desktop-first-party.ts +1 -1
- package/src/claude/desktop-picker-platform.ts +4 -0
- package/src/claude/desktop-picker.ts +15 -8
- package/src/claude/desktop-system-proxy.ts +50 -4
- package/src/claude/inbound-content-options.ts +77 -0
- package/src/claude/inbound.ts +33 -0
- package/src/claude/intercept/picker-ca-startup.ts +2 -1
- package/src/claude/intercept/picker-runtime.ts +6 -5
- package/src/claude/intercept/picker-trust-windows.ts +338 -0
- package/src/claude/intercept/picker-trust.ts +19 -0
- package/src/claude/intercept/port-policy.ts +30 -0
- package/src/claude/intercept/runtime.ts +97 -94
- package/src/claude/outbound.ts +46 -13
- package/src/cli/account-api.ts +1 -0
- package/src/cli/account-policy-dto.ts +6 -0
- package/src/cli/account-policy.ts +34 -5
- package/src/cli/account-preservation.ts +44 -0
- package/src/cli/account.ts +8 -2
- package/src/cli/advisor.ts +17 -3
- package/src/cli/capabilities-accounts.ts +20 -1
- package/src/cli/capabilities-agents-routing.ts +5 -2
- package/src/cli/capabilities-base.ts +38 -10
- package/src/cli/capabilities-observe-system.ts +63 -3
- package/src/cli/capabilities-provider-models.ts +11 -0
- package/src/cli/codex-cli-update.ts +151 -41
- package/src/cli/codex-provider.ts +44 -0
- package/src/cli/combo-input.ts +10 -1
- package/src/cli/combo-result.ts +1 -1
- package/src/cli/combo.ts +2 -1
- package/src/cli/cross-home-owner.ts +33 -16
- package/src/cli/dispatch.ts +25 -4
- package/src/cli/doctor.ts +6 -1
- package/src/cli/ensure-desktop-cold-start.ts +60 -7
- package/src/cli/help.ts +3 -2
- package/src/cli/index.ts +1 -1
- package/src/cli/integration-plan-dto.ts +1 -0
- package/src/cli/log-history.ts +172 -0
- package/src/cli/loopback-family.ts +31 -0
- package/src/cli/models-runtime-subcommands.ts +1 -0
- package/src/cli/models-runtime.ts +72 -8
- package/src/cli/observe-stream.ts +2 -0
- package/src/cli/observe.ts +16 -4
- package/src/cli/provider.ts +27 -5
- package/src/cli/registry.ts +28 -8
- package/src/cli/runtime-api.ts +5 -3
- package/src/cli/system-command.ts +40 -8
- package/src/cli/uninstall-client-state.ts +32 -0
- package/src/cli/usage-compare.ts +309 -0
- package/src/cli/usage-model-search.ts +4 -4
- package/src/cli/usage-report.ts +2 -2
- package/src/cli/v2.ts +1 -1
- package/src/client/machine-listener.ts +1 -3
- package/src/client/runtime.ts +1 -0
- package/src/clients/client-path.ts +51 -0
- package/src/clients/config-export/contracts.ts +2 -1
- package/src/clients/config-export.ts +18 -44
- package/src/clients/gentle-shell-path.ts +87 -0
- package/src/codex/account-auto-switch.ts +2 -0
- package/src/codex/account-identity.ts +29 -0
- package/src/codex/account-label.ts +1 -1
- package/src/codex/account-lifecycle.ts +21 -5
- package/src/codex/account-preservation.ts +28 -0
- package/src/codex/account-use-remaining.ts +23 -0
- package/src/codex/app-server-processes.ts +97 -7
- package/src/codex/app-server-restart-service.ts +55 -4
- package/src/codex/auth-api/account-list.ts +4 -0
- package/src/codex/auth-api/account-pause-group.ts +6 -50
- package/src/codex/auth-api/account-preservation.ts +57 -0
- package/src/codex/auth-api/routes.ts +8 -0
- package/src/codex/auth-api/use-remaining-route.ts +36 -0
- package/src/codex/auth-api.ts +0 -1
- package/src/codex/auth-context.ts +2 -2
- package/src/codex/catalog/auto-review.ts +20 -3
- package/src/codex/catalog/build-entries.ts +9 -1
- package/src/codex/catalog/combo-member.ts +14 -5
- package/src/codex/catalog/configured-tiers.ts +1 -1
- package/src/codex/catalog/gather-capture.ts +2 -0
- package/src/codex/catalog/metadata.ts +11 -9
- package/src/codex/catalog/model-hints.ts +21 -16
- package/src/codex/catalog/model-visibility.ts +3 -1
- package/src/codex/catalog/parsing.ts +30 -86
- package/src/codex/catalog/provider-models.ts +36 -34
- package/src/codex/catalog/routed-gather.ts +14 -13
- package/src/codex/cli-install-provenance.ts +105 -17
- package/src/codex/cli-update-plan.ts +545 -0
- package/src/codex/config-write-lock.ts +23 -2
- package/src/codex/desktop-app/picker-freshness.ts +96 -0
- package/src/codex/desktop-app-restart.ts +21 -0
- package/src/codex/desktop-compatibility/installed-build.ts +24 -6
- package/src/codex/desktop-compatibility/routing-preflight.ts +1 -1
- package/src/codex/desktop-compatibility/runtime.ts +12 -3
- package/src/codex/desktop-compatibility/windows-key-protection.ts +115 -9
- package/src/codex/features.ts +85 -45
- package/src/codex/inject/history-failure.ts +27 -0
- package/src/codex/inject/restore.ts +24 -2
- package/src/codex/inject/routing-classify.ts +4 -3
- package/src/codex/inject.ts +18 -27
- package/src/codex/main-account-hard-lock.ts +30 -1
- package/src/codex/native-profile-startup.ts +1 -1
- package/src/codex/ocx-compaction-history.ts +12 -10
- package/src/codex/paths.ts +86 -1
- package/src/codex/provider-routing.ts +174 -0
- package/src/codex/refresh.ts +2 -2
- package/src/codex/routing/health-store.ts +1 -1
- package/src/codex/routing/selection.ts +4 -3
- package/src/codex/routing/thread-affinity.ts +1 -1
- package/src/codex/signed-in-identity.ts +43 -0
- package/src/codex/subagent-model-fallback.ts +1 -1
- package/src/codex/sync.ts +6 -1
- package/src/codex/user-identity.ts +16 -5
- package/src/codex/websocket-activity.ts +161 -0
- package/src/codex/websocket-registry.ts +25 -1
- package/src/codex/windows-local-appdata.ts +84 -0
- package/src/combos/failover.ts +6 -1
- package/src/combos/index.ts +1 -0
- package/src/combos/resolve.ts +46 -10
- package/src/combos/types.ts +15 -0
- package/src/config/diagnostics.ts +33 -6
- package/src/config/live-reconcile.ts +38 -2
- package/src/config/load-degrade.ts +17 -0
- package/src/config/opencode-wire-upgrade.ts +54 -0
- package/src/config/opencode-zen-upgrade.ts +53 -0
- package/src/config/owner-registry.ts +22 -17
- package/src/config/provider-validation.ts +45 -2
- package/src/config/schema/config-schema.ts +22 -0
- package/src/config/schema/leaf-validators.ts +38 -9
- package/src/config/schema/main-account-hard-lock-fallback.ts +26 -0
- package/src/config/schema/native-reasoning-retention.ts +26 -0
- package/src/config.ts +2 -0
- package/src/generated/compatibility-version.json +657 -297
- package/src/grok/sync.ts +1 -1
- package/src/images/loop.ts +116 -27
- package/src/integrations/catalog-refresh.ts +1 -1
- package/src/integrations/mutation-plan.ts +1 -0
- package/src/integrations/registry.ts +8 -0
- package/src/lib/codex-restart-contract.ts +15 -0
- package/src/lib/desktop-upstream-tunnel.ts +18 -53
- package/src/lib/empty-tool-catalog.ts +62 -0
- package/src/lib/errors.ts +19 -3
- package/src/lib/gcp-adc.ts +96 -9
- package/src/lib/gcp-credential-input.ts +12 -0
- package/src/lib/lab-live-route-production.ts +5 -0
- package/src/lib/opaque-proxy-tunnel.ts +217 -0
- package/src/lib/redact.ts +2 -2
- package/src/lib/request-failure-model.ts +2 -0
- package/src/oauth/account-quota-rank.ts +69 -2
- package/src/oauth/anthropic-account-refusal.ts +20 -2
- package/src/oauth/anthropic-oauth-definitions.ts +3 -1
- package/src/oauth/anthropic-routing.ts +1 -21
- package/src/oauth/anthropic.ts +38 -7
- package/src/oauth/callback-server.ts +27 -1
- package/src/oauth/chatgpt-device.ts +1 -1
- package/src/oauth/chatgpt-shared.ts +83 -0
- package/src/oauth/chatgpt.ts +8 -72
- package/src/oauth/dsh.ts +203 -0
- package/src/oauth/generic-account-failover.ts +40 -11
- package/src/oauth/generic-session-affinity.ts +125 -0
- package/src/oauth/index.ts +184 -109
- package/src/oauth/local-token-detect.ts +21 -1
- package/src/oauth/login-cli-errors.ts +44 -0
- package/src/oauth/login-cli.ts +69 -7
- package/src/oauth/login-flow-state.ts +371 -23
- package/src/oauth/meta-muse-errors.ts +41 -0
- package/src/oauth/meta-muse-keychain.ts +52 -0
- package/src/oauth/meta-muse.ts +51 -84
- package/src/oauth/model-discovery-auth.ts +3 -0
- package/src/oauth/pool-settings-capability.ts +4 -2
- package/src/oauth/refresh-flight-retirement.ts +48 -0
- package/src/oauth/session-affinity-key.ts +23 -0
- package/src/oauth/store-anthropic-instance.ts +9 -2
- package/src/oauth/store.ts +12 -5
- package/src/protocols/encoders/adapter-events.ts +6 -5
- package/src/protocols/encoders/messages.ts +9 -6
- package/src/protocols/provider-summary.ts +2 -1
- package/src/providers/api-key-cooldowns.ts +49 -0
- package/src/providers/api-key-resolve.ts +11 -6
- package/src/providers/api-key-response-ownership.ts +57 -0
- package/src/providers/api-key-selection.ts +31 -6
- package/src/providers/api-keys.ts +214 -3
- package/src/providers/claude-cli-usage.ts +96 -0
- package/src/providers/dsh-account-destination.ts +31 -0
- package/src/providers/dsh-account-models.ts +41 -0
- package/src/providers/gcp-credential-cleanup.ts +59 -0
- package/src/providers/key-failover.ts +54 -50
- package/src/providers/key-store.ts +7 -2
- package/src/providers/model-rename-fields.ts +3 -0
- package/src/providers/model-rename-migration.ts +2 -2
- package/src/providers/openai-tiers-destination.ts +11 -2
- package/src/providers/openai-tiers.ts +5 -12
- package/src/providers/opencode-go-transport.ts +3 -1
- package/src/providers/opencode-zen-rate-limit.ts +7 -2
- package/src/providers/quota/account-cache.ts +6 -5
- package/src/providers/quota/account-row.ts +34 -0
- package/src/providers/quota/antigravity.ts +28 -7
- package/src/providers/quota/dsh-account.ts +70 -0
- package/src/providers/quota/vendor-probes-oauth.ts +1 -93
- package/src/providers/quota-types.ts +2 -0
- package/src/providers/quota.ts +14 -20
- package/src/providers/registry/entries-core.ts +37 -8
- package/src/providers/registry/types.ts +1 -1
- package/src/providers/request-pacing.ts +77 -19
- package/src/providers/routed-config.ts +339 -0
- package/src/providers/service-tier.ts +2 -1
- package/src/quota/window-mapping.ts +5 -2
- package/src/responses/anthropic-progress.ts +34 -0
- package/src/responses/assistant-replay.ts +35 -0
- package/src/responses/compaction-history-framing.ts +65 -0
- package/src/responses/compaction.ts +6 -1
- package/src/responses/incomplete-reason.ts +31 -0
- package/src/responses/parser.ts +50 -5
- package/src/responses/reasoning-envelope.ts +4 -0
- package/src/responses/reasoning-replay-cache.ts +74 -6
- package/src/responses/reasoning-retention.ts +173 -0
- package/src/responses/retained-compaction.ts +46 -0
- package/src/responses/schema.ts +23 -0
- package/src/router.ts +8 -321
- package/src/routing/analytics.ts +7 -15
- package/src/routing/health.ts +37 -22
- package/src/routing/history/indexer.ts +6 -5
- package/src/routing/history/ingest.ts +6 -2
- package/src/routing/profile.ts +1 -1
- package/src/server/admission-model-scope.ts +17 -0
- package/src/server/auth-cors.ts +11 -0
- package/src/server/chat-completions.ts +7 -1
- package/src/server/chat-native-reasoning.ts +123 -0
- package/src/server/chat-native-sse.ts +110 -7
- package/src/server/chat-native.ts +76 -17
- package/src/server/claude-messages.ts +56 -414
- package/src/server/effort-policy.ts +1 -1
- package/src/server/images.ts +15 -2
- package/src/server/index/live-sideband.ts +3 -2
- package/src/server/index/model-alias-id.ts +36 -0
- package/src/server/index/optional-listeners.ts +2 -0
- package/src/server/index/serve-options.ts +20 -6
- package/src/server/index/startup-warnings.ts +2 -0
- package/src/server/index/websocket-handler.ts +18 -4
- package/src/server/index.ts +8 -8
- package/src/server/inference/advisor-diagnostics.ts +31 -0
- package/src/server/lifecycle.ts +13 -1
- package/src/server/management/advisor-routes.ts +15 -4
- package/src/server/management/claude-desktop-picker-routes.ts +1 -1
- package/src/server/management/combo-routes.ts +176 -50
- package/src/server/management/companion-routes.ts +1 -1
- package/src/server/management/config-routes.ts +75 -4
- package/src/server/management/cursor-integration-routes.ts +1 -1
- package/src/server/management/model-routes.ts +11 -6
- package/src/server/management/model-rows.ts +14 -0
- package/src/server/management/native-integration-routes.ts +2 -7
- package/src/server/management/native-reasoning-retention-routes.ts +41 -0
- package/src/server/management/oauth-account-routes.ts +87 -14
- package/src/server/management/provider-gcp-credential-routes.ts +29 -0
- package/src/server/management/provider-key-pacing-routes.ts +31 -0
- package/src/server/management/provider-overwrite-carry.ts +7 -0
- package/src/server/management/provider-routes.ts +25 -30
- package/src/server/management/route-registry.ts +10 -1
- package/src/server/management-api.ts +3 -1
- package/src/server/messages-native-tool-guard.ts +185 -0
- package/src/server/messages-native.ts +117 -24
- package/src/server/messages-shared.ts +431 -0
- package/src/server/relay.ts +1 -1
- package/src/server/request-log-terminal-status.ts +1 -1
- package/src/server/request-log.ts +6 -1
- package/src/server/responses/account-change-state.ts +8 -2
- package/src/server/responses/adapter-continuation.ts +47 -19
- package/src/server/responses/adapter-delivery.ts +72 -12
- package/src/server/responses/adapter-dispatch.ts +46 -3
- package/src/server/responses/advisor-retention.ts +117 -0
- package/src/server/responses/advisor-slot.ts +73 -41
- package/src/server/responses/anthropic-thinking-recovery.ts +153 -0
- package/src/server/responses/codex-ws-wire.ts +15 -8
- package/src/server/responses/combo-stream-preflight.ts +3 -2
- package/src/server/responses/compact.ts +303 -125
- package/src/server/responses/compaction-recovery.ts +20 -10
- package/src/server/responses/compaction-retention.ts +61 -0
- package/src/server/responses/context-overflow.ts +11 -6
- package/src/server/responses/core-auth.ts +6 -0
- package/src/server/responses/core-codex-account.ts +11 -1
- package/src/server/responses/core-combo-failure.ts +2 -0
- package/src/server/responses/core-combo.ts +121 -36
- package/src/server/responses/core-errors.ts +3 -3
- package/src/server/responses/core-lifetime.ts +8 -4
- package/src/server/responses/core-opaque-recovery.ts +35 -0
- package/src/server/responses/core-options.ts +7 -0
- package/src/server/responses/core-pipeline.ts +141 -0
- package/src/server/responses/core-replay.ts +23 -3
- package/src/server/responses/core.ts +2 -115
- package/src/server/responses/fetch-helpers.ts +73 -19
- package/src/server/responses/main-hard-lock-routing.ts +109 -0
- package/src/server/responses/native-response-control.ts +4 -2
- package/src/server/responses/passthrough-delivery.ts +3 -1
- package/src/server/responses/passthrough-dispatch.ts +15 -13
- package/src/server/responses/passthrough-execution.ts +3 -2
- package/src/server/responses/request-prepare.ts +77 -12
- package/src/server/responses/request-sidecar-auth.ts +2 -2
- package/src/server/responses/request-transport.ts +104 -27
- package/src/server/responses/response-effects.ts +2 -0
- package/src/server/responses/response-tool-ownership.ts +21 -0
- package/src/server/responses/run-turn-execution.ts +96 -30
- package/src/server/responses/sidecar-execution.ts +63 -9
- package/src/server/responses/sidecar-send-budget.ts +2 -2
- package/src/server/responses/terminal-guard.ts +2 -16
- package/src/server/responses-undeclared-tool-guard.ts +1 -1
- package/src/server/ws-bridge.ts +2 -0
- package/src/service/auth-preflight.ts +71 -0
- package/src/service/cli.ts +4 -2
- package/src/service/definition.ts +97 -0
- package/src/service/guards.ts +1 -61
- package/src/service/health-sentinel-linux.ts +112 -0
- package/src/service/health-sentinel-main.ts +76 -57
- package/src/service/health.ts +5 -89
- package/src/service/launchd.ts +27 -7
- package/src/service/logging.ts +72 -9
- package/src/service/repair.ts +2 -1
- package/src/service/state.ts +7 -8
- package/src/service/systemd.ts +1 -1
- package/src/service/windows-guarded-manager.ts +2 -1
- package/src/service/windows-ops.ts +1 -1
- package/src/service/windows-scheduler.ts +2 -7
- package/src/service/windows-taskxml.ts +2 -2
- package/src/service/windows-wscript.ts +14 -0
- package/src/service.ts +4 -2
- package/src/sidecar/auth.ts +2 -0
- package/src/types/config.ts +64 -3
- package/src/types/opencode-go.ts +61 -0
- package/src/types/opencode-zen.ts +35 -0
- package/src/types/provider.ts +32 -6
- package/src/types/request.ts +31 -2
- package/src/types/wire.ts +31 -37
- package/src/types.ts +2 -0
- package/src/update/npm-invocation.mjs +12 -2
- package/src/usage/cost.ts +48 -12
- package/src/usage/expected-prices.ts +3 -0
- package/src/usage/ledger-retention.ts +2 -1
- package/src/usage/ledger-scanner.ts +6 -5
- package/src/usage/log.ts +17 -8
- package/src/usage/summary.ts +30 -11
- package/src/usage/telemetry-contract.ts +1 -0
- package/src/usage/user-cost-overlays.ts +14 -19
- package/src/usage/user-cost-validation.ts +38 -0
- package/src/vision/eligibility.ts +13 -0
- package/src/web-search/anthropic-history.ts +59 -0
- package/src/web-search/loop.ts +236 -73
- package/src/web-search/progress-stream.ts +15 -2
- package/src/web-search/run-turn-loop.ts +9 -1
- package/gui/dist/assets/App-BjlttVLy.js +0 -58
- package/gui/dist/assets/App-CSJvmjNs.css +0 -1
- package/gui/dist/assets/index-BB6uK6tU.css +0 -1
- package/gui/dist/assets/index-BMssP4k3.js +0 -94
- package/gui/dist/assets/quota-summary-D8M1bc_R.js +0 -1
package/src/usage/summary.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
type PersistedUsageEntry,
|
|
11
11
|
type UsageStatus,
|
|
12
12
|
} from "./log";
|
|
13
|
-
import { type AttemptCostEstimate, type CostEstimate, estimateAttemptCost, estimateRequestCost, serviceTierContext, type ServiceTierContext, tokensPerSecond } from "./cost";
|
|
13
|
+
import { type AttemptCostEstimate, type CostEstimate, estimateAttemptCost, estimateRequestCost, isMeasuredStatus, serviceTierContext, type ServiceTierContext, tokensPerSecond } from "./cost";
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Canonical range members. The warm-up loop in the management usage route
|
|
@@ -303,7 +303,10 @@ export function computeEntryCost(entry: PersistedUsageEntry): EntryCostInfo {
|
|
|
303
303
|
isPriced = true;
|
|
304
304
|
}
|
|
305
305
|
}
|
|
306
|
-
|
|
306
|
+
// An unmeasured leg that may have generated billed tokens leaves the total unknown, not short.
|
|
307
|
+
const unknownCost = entry.attempts.some((attempt, index) =>
|
|
308
|
+
!attemptEstimates[index] && (!attempt.usage || !isMeasuredStatus(attempt.usageStatus)) && !spentNothing(attempt));
|
|
309
|
+
return { tier, estimate: null, attemptEstimates, costTotal, isPriced: isPriced && !unknownCost };
|
|
307
310
|
}
|
|
308
311
|
const estimate = estimateRequestCost({
|
|
309
312
|
...usageModelPriceOptions(entry, entry),
|
|
@@ -428,10 +431,6 @@ function blankTotals(): UsageSummaryTotals {
|
|
|
428
431
|
};
|
|
429
432
|
}
|
|
430
433
|
|
|
431
|
-
function isMeasuredStatus(status: UsageStatus): boolean {
|
|
432
|
-
return status === "reported" || status === "estimated";
|
|
433
|
-
}
|
|
434
|
-
|
|
435
434
|
export interface UsageAttribution {
|
|
436
435
|
requestId: string;
|
|
437
436
|
provider: string;
|
|
@@ -666,8 +665,12 @@ function addEstimatedCost(
|
|
|
666
665
|
entry: Pick<PersistedUsageEntry, "usageStatus" | "usage" | "attempts">,
|
|
667
666
|
costInfo: EntryCostInfo,
|
|
668
667
|
): void {
|
|
669
|
-
|
|
670
|
-
|
|
668
|
+
// A row of attempts reads `unreported` when any leg lacks usage. Once one leg is measured the row
|
|
669
|
+
// is metered and the attempt-level pricing decides, matching the model and provider breakdowns.
|
|
670
|
+
const measuredAttempt = entry.attempts?.some(attempt => attempt.usage && isMeasuredStatus(attempt.usageStatus));
|
|
671
|
+
if (!measuredAttempt
|
|
672
|
+
&& (entry.usageStatus === "unreported" || entry.usageStatus === "unsupported"
|
|
673
|
+
|| (!entry.usage && !entry.attempts?.length))) {
|
|
671
674
|
totals.unmeteredRequests += 1;
|
|
672
675
|
return;
|
|
673
676
|
}
|
|
@@ -814,14 +817,30 @@ function blankRequestCounts(): UsageRequestCounts {
|
|
|
814
817
|
};
|
|
815
818
|
}
|
|
816
819
|
|
|
820
|
+
/**
|
|
821
|
+
* A usage-less attempt that provably cost nothing: it never reached upstream, or upstream refused it
|
|
822
|
+
* with an HTTP error before any output (providers do not bill a pre-generation 429/401/5xx). One
|
|
823
|
+
* whose stream began, aborted, or ended without a status may have generated billed tokens, so it
|
|
824
|
+
* stays an unknown cost. A request made only of such zeros carries neither fact and counts unpriced.
|
|
825
|
+
*/
|
|
826
|
+
function spentNothing(attempt: NonNullable<PersistedUsageEntry["attempts"]>[number] | undefined): boolean {
|
|
827
|
+
if (!attempt || attempt.usage) return false;
|
|
828
|
+
if (attempt.sendCount === 0 || attempt.locallyAnswered === true) return true;
|
|
829
|
+
// A 499 is the client hanging up on a send upstream may already be generating for.
|
|
830
|
+
return attempt.status >= 400 && attempt.status !== 499
|
|
831
|
+
&& attempt.streamAborted !== true && attempt.firstOutputMs === undefined;
|
|
832
|
+
}
|
|
833
|
+
|
|
817
834
|
function bumpRequestCounts(counts: UsageRequestCounts, facts: number, amount = 1): void {
|
|
818
835
|
counts.requests += amount;
|
|
819
836
|
const status = statusFromRequestFacts(facts);
|
|
820
837
|
if (isMeasuredStatus(status)) counts.measuredRequests += amount;
|
|
821
838
|
if (status === "reported") counts.reportedRequests += amount;
|
|
822
839
|
else if (status === "estimated") counts.estimatedRequests += amount;
|
|
823
|
-
|
|
824
|
-
|
|
840
|
+
// Unpriced dominates: one unpriceable part makes the request's cost unknown, and counting it
|
|
841
|
+
// on both sides overstated price coverage.
|
|
842
|
+
if ((facts & REQUEST_PRICED) !== 0 && (facts & REQUEST_UNPRICED) === 0) counts.pricedRequests += amount;
|
|
843
|
+
else counts.unpricedRequests += amount;
|
|
825
844
|
}
|
|
826
845
|
|
|
827
846
|
function mergeRequestCounts(target: UsageRequestCounts, source: UsageRequestCounts): void {
|
|
@@ -1557,7 +1576,7 @@ class StreamingUsageSummaryAccumulator implements UsageSummaryAccumulator {
|
|
|
1557
1576
|
: costInfo.estimate;
|
|
1558
1577
|
const ordinal = this.nextOrdinal++;
|
|
1559
1578
|
const facts = requestStatusFact(attribution.usageStatus)
|
|
1560
|
-
| (estimate ? REQUEST_PRICED : REQUEST_UNPRICED);
|
|
1579
|
+
| (estimate ? REQUEST_PRICED : spentNothing(entry.attempts?.[index]) ? 0 : REQUEST_UNPRICED);
|
|
1561
1580
|
const modelKey = this.addModelAttribution(partition, attribution, estimate, ordinal);
|
|
1562
1581
|
modelFacts.set(modelKey, (modelFacts.get(modelKey) ?? 0) | facts);
|
|
1563
1582
|
if (this.mode === "row-unique") {
|
|
@@ -18,8 +18,10 @@
|
|
|
18
18
|
*
|
|
19
19
|
* Display-time estimation only — these rows never affect billing.
|
|
20
20
|
*/
|
|
21
|
-
import type { OcxConfig, OcxProviderConfig, ProviderCostOverlay } from "../types";
|
|
22
|
-
import {
|
|
21
|
+
import type { OcxConfig, OcxProviderConfig, ProviderCostOverlay, PromptLengthPricing } from "../types";
|
|
22
|
+
import type { ExpectedPriceOverlay } from "./expected-prices";
|
|
23
|
+
import { validCost4 } from "./user-cost-validation";
|
|
24
|
+
export { COST4_RATE_KEYS, isValidCost4Rate, validCost4, isValidPromptLengthPricing } from "./user-cost-validation";
|
|
23
25
|
import { redactSecretString } from "../lib/redact";
|
|
24
26
|
import { isSelectableCodexPoolAccount, MAIN_CODEX_ACCOUNT_ID } from "../codex/account-id";
|
|
25
27
|
import { codexAccountLogLabel } from "../codex/account-label";
|
|
@@ -236,22 +238,13 @@ export function resetPreservedDiskOnlyProvidersForTests(): void {
|
|
|
236
238
|
preservationOwnerStates.clear();
|
|
237
239
|
}
|
|
238
240
|
|
|
239
|
-
/**
|
|
240
|
-
export
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
return
|
|
245
|
-
|
|
246
|
-
&& rate >= 0
|
|
247
|
-
&& rate <= MAX_COST4_RATE;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/** True when `value` is a complete cost entry: all four rates are non-negative finite numbers. */
|
|
251
|
-
function validCost4(value: unknown): value is ProviderCostOverlay {
|
|
252
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
253
|
-
const entry = value as Record<string, unknown>;
|
|
254
|
-
return COST4_RATE_KEYS.every(key => isValidCost4Rate(entry[key]));
|
|
241
|
+
/** Copy a validated override; automatic is represented by absence. */
|
|
242
|
+
export function copyPromptLengthPricing(policy: PromptLengthPricing): PromptLengthPricing | undefined {
|
|
243
|
+
if (policy.mode === "automatic") return undefined;
|
|
244
|
+
if (policy.mode !== "custom") return { mode: policy.mode };
|
|
245
|
+
const { input, output, cacheRead, cacheWrite } = policy.rates;
|
|
246
|
+
return { mode: "custom", thresholdTokens: policy.thresholdTokens, comparison: policy.comparison,
|
|
247
|
+
rates: { input, output, cacheRead, cacheWrite } };
|
|
255
248
|
}
|
|
256
249
|
|
|
257
250
|
/**
|
|
@@ -273,10 +266,11 @@ export function refreshUserCostOverlays(config: OcxConfig): void {
|
|
|
273
266
|
if (!costs || typeof costs !== "object" || Array.isArray(costs)) continue;
|
|
274
267
|
for (const [modelId, cost4] of Object.entries(costs)) {
|
|
275
268
|
if (!modelId.trim() || !validCost4(cost4)) continue;
|
|
269
|
+
const policy = cost4.promptLengthPricing && copyPromptLengthPricing(cost4.promptLengthPricing);
|
|
276
270
|
rows.push({
|
|
277
271
|
provider: providerName,
|
|
278
272
|
modelId,
|
|
279
|
-
// Copy
|
|
273
|
+
// Copy only validated rates and policy: a hand-edited row may
|
|
280
274
|
// carry extra properties (e.g. a misplaced apiKey) that must never
|
|
281
275
|
// reach display estimates or /api/logs through the registry.
|
|
282
276
|
cost4: {
|
|
@@ -285,6 +279,7 @@ export function refreshUserCostOverlays(config: OcxConfig): void {
|
|
|
285
279
|
cacheRead: cost4.cacheRead,
|
|
286
280
|
cacheWrite: cost4.cacheWrite,
|
|
287
281
|
},
|
|
282
|
+
...(policy ? { promptLengthPricing: policy } : {}),
|
|
288
283
|
// Display provenance only: redact token-shaped provider/model ids so
|
|
289
284
|
// the source string can never echo a pasted key. Matching still uses
|
|
290
285
|
// the raw fields, and the change-detection signature below MUST keep
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Pure model-cost validation shared by config, migration, and display lifting. */
|
|
2
|
+
import type { ProviderCostOverlay, PromptLengthPricing } from "../types";
|
|
3
|
+
import { MAX_COST4_RATE } from "./expected-prices";
|
|
4
|
+
|
|
5
|
+
/** Exact four fields accepted for a user-configured cost tuple. */
|
|
6
|
+
export const COST4_RATE_KEYS = ["input", "output", "cacheRead", "cacheWrite"] as const;
|
|
7
|
+
|
|
8
|
+
/** Shared per-rate predicate used by config validation, display sanitization, and runtime lifting. */
|
|
9
|
+
export function isValidCost4Rate(rate: unknown): rate is number {
|
|
10
|
+
return typeof rate === "number"
|
|
11
|
+
&& Number.isFinite(rate)
|
|
12
|
+
&& rate >= 0
|
|
13
|
+
&& rate <= MAX_COST4_RATE;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Complete base rates with a valid optional policy; extra top-level fields are never copied. */
|
|
17
|
+
export function validCost4(value: unknown): value is ProviderCostOverlay {
|
|
18
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
19
|
+
const entry = value as Record<string, unknown>;
|
|
20
|
+
return COST4_RATE_KEYS.every(key => Object.hasOwn(entry, key) && isValidCost4Rate(entry[key]))
|
|
21
|
+
&& (!Object.hasOwn(entry, "promptLengthPricing") || isValidPromptLengthPricing(entry.promptLengthPricing));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Strict nested policy boundary; diagnostics never echo untrusted policy fields. */
|
|
25
|
+
export function isValidPromptLengthPricing(value: unknown): value is PromptLengthPricing {
|
|
26
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
27
|
+
const policy = value as Record<string, unknown>;
|
|
28
|
+
if (!Object.hasOwn(policy, "mode")) return false;
|
|
29
|
+
if (policy.mode === "automatic" || policy.mode === "flat") return Object.keys(policy).length === 1;
|
|
30
|
+
if (policy.mode !== "custom" || Object.keys(policy).length !== 4
|
|
31
|
+
|| !["mode", "thresholdTokens", "comparison", "rates"].every(key => Object.hasOwn(policy, key))
|
|
32
|
+
|| typeof policy.thresholdTokens !== "number" || !Number.isSafeInteger(policy.thresholdTokens)
|
|
33
|
+
|| policy.thresholdTokens <= 0 || (policy.comparison !== "gt" && policy.comparison !== "gte")) return false;
|
|
34
|
+
const rates = policy.rates;
|
|
35
|
+
return !!rates && typeof rates === "object" && !Array.isArray(rates)
|
|
36
|
+
&& Object.keys(rates).length === COST4_RATE_KEYS.length
|
|
37
|
+
&& COST4_RATE_KEYS.every(key => Object.hasOwn(rates, key) && isValidCost4Rate((rates as Record<string, unknown>)[key]));
|
|
38
|
+
}
|
|
@@ -226,6 +226,19 @@ export function isVisionSidecarConsumer(config: VisionCapabilityConfig, provider
|
|
|
226
226
|
return isVisionSidecarConsumerWithCache(config, providerName, modelId, new Map());
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
/**
|
|
230
|
+
* `isVisionSidecarConsumer` for many rows of one config. Rows of the same provider share one
|
|
231
|
+
* registry enrichment instead of rebuilding it per row, which matters for `/api/models`
|
|
232
|
+
* listings with thousands of rows. Bind it to a single config snapshot; it does not observe
|
|
233
|
+
* provider changes made after the first lookup.
|
|
234
|
+
*/
|
|
235
|
+
export function visionSidecarConsumerClassifier(
|
|
236
|
+
config: VisionCapabilityConfig,
|
|
237
|
+
): (providerName: string, modelId: string) => boolean {
|
|
238
|
+
const cache: EnrichedProviderCache = new Map();
|
|
239
|
+
return (providerName, modelId) => isVisionSidecarConsumerWithCache(config, providerName, modelId, cache);
|
|
240
|
+
}
|
|
241
|
+
|
|
229
242
|
/**
|
|
230
243
|
* Can this model accept an image on the wire? Sources are consulted in descending
|
|
231
244
|
* trustworthiness; the first that speaks wins. `undefined` means nothing knows,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { AdapterEvent, OcxAssistantContentPart, OcxThinkingContent, OcxToolCall } from "../types";
|
|
2
|
+
|
|
3
|
+
/** Rebuild one validated Anthropic model response without changing its search arguments or order. */
|
|
4
|
+
export function anthropicSearchAssistantContent(events: readonly AdapterEvent[]): OcxAssistantContentPart[] {
|
|
5
|
+
const content: OcxAssistantContentPart[] = [];
|
|
6
|
+
let thinking: OcxThinkingContent | undefined;
|
|
7
|
+
let text: Extract<OcxAssistantContentPart, { type: "text" }> | undefined;
|
|
8
|
+
let call: OcxToolCall | undefined;
|
|
9
|
+
let argumentsText = "";
|
|
10
|
+
for (const event of events) {
|
|
11
|
+
if (event.type === "heartbeat") continue;
|
|
12
|
+
// A signature is a replacement snapshot until the next semantic block starts.
|
|
13
|
+
if (thinking?.signature !== undefined && event.type !== "thinking_signature") thinking = undefined;
|
|
14
|
+
if (event.type !== "text_delta") text = undefined;
|
|
15
|
+
switch (event.type) {
|
|
16
|
+
case "thinking_delta":
|
|
17
|
+
if (!thinking) { thinking = { type: "thinking", thinking: "" }; content.push(thinking); }
|
|
18
|
+
thinking.thinking += event.thinking;
|
|
19
|
+
break;
|
|
20
|
+
case "thinking_signature":
|
|
21
|
+
if (!thinking) { thinking = { type: "thinking", thinking: "" }; content.push(thinking); }
|
|
22
|
+
thinking.signature = event.signature;
|
|
23
|
+
break;
|
|
24
|
+
case "redacted_thinking":
|
|
25
|
+
thinking = undefined;
|
|
26
|
+
content.push({ type: "thinking", thinking: "", redacted: [event.data] });
|
|
27
|
+
break;
|
|
28
|
+
case "text_delta":
|
|
29
|
+
thinking = undefined;
|
|
30
|
+
if (event.anthropicThinkingSignature) {
|
|
31
|
+
text = undefined;
|
|
32
|
+
content.push({ type: "thinking", thinking: event.text, signature: event.anthropicThinkingSignature });
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
if (!text) { text = { type: "text", text: "" }; content.push(text); }
|
|
36
|
+
text.text += event.text;
|
|
37
|
+
break;
|
|
38
|
+
case "tool_call_start":
|
|
39
|
+
thinking = undefined;
|
|
40
|
+
call = { type: "toolCall", id: event.id, name: event.name, arguments: {},
|
|
41
|
+
...(event.providerMetadata ? { providerMetadata: event.providerMetadata } : {}) };
|
|
42
|
+
content.push(call);
|
|
43
|
+
argumentsText = "";
|
|
44
|
+
break;
|
|
45
|
+
case "tool_call_delta":
|
|
46
|
+
argumentsText += event.arguments;
|
|
47
|
+
break;
|
|
48
|
+
case "tool_call_end": {
|
|
49
|
+
if (!call) throw new Error("search history has an unpaired tool call");
|
|
50
|
+
const args: unknown = JSON.parse(argumentsText || "{}");
|
|
51
|
+
if (!args || typeof args !== "object" || Array.isArray(args)) throw new Error("search history tool input is not an object");
|
|
52
|
+
call.arguments = args as Record<string, unknown>;
|
|
53
|
+
call = undefined;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return content;
|
|
59
|
+
}
|