@bitkyc08/opencodex 2.80.0 → 2.82.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/README.md +3 -3
- package/bin/ocx.mjs +166 -73
- package/gui/dist/assets/App-Ds_qL7o8.js +54 -0
- package/gui/dist/assets/Tray-BqHF5Trd.js +1 -0
- package/gui/dist/assets/{index-Brk6F3fn.css → index-BAbcj51J.css} +1 -1
- package/gui/dist/assets/index-D3FBCNiP.js +94 -0
- package/gui/dist/assets/quota-summary-DTBC8n7-.js +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/claude-green.svg +1 -0
- package/package.json +3 -2
- package/src/adapters/anthropic-model-contract.ts +8 -2
- package/src/adapters/anthropic.ts +8 -3
- package/src/adapters/codebuddy/mcp-server.ts +2 -25
- package/src/adapters/codebuddy/tool-bridge.ts +1 -7
- package/src/adapters/coding-agent/mcp-server.ts +33 -0
- package/src/adapters/coding-agent/protocol.ts +122 -17
- package/src/adapters/coding-agent/tool-catalog.ts +75 -0
- package/src/adapters/coding-agent/turn.ts +101 -44
- package/src/adapters/cursor/catalog.ts +8 -0
- package/src/adapters/cursor/effort-map.ts +2 -0
- package/src/adapters/devin/live-models.ts +2 -0
- package/src/adapters/kiro-retry.ts +9 -4
- package/src/adapters/openai-chat/messages.ts +7 -6
- package/src/adapters/openai-responses/compaction-search-history.ts +109 -0
- package/src/adapters/openai-responses/passthrough.ts +9 -4
- package/src/adapters/openai-responses/tool-output-recovery.ts +20 -0
- package/src/adapters/physical-send.ts +8 -5
- package/src/adapters/qoder/adapter.ts +41 -6
- package/src/adapters/qoder/scaffold-guard.ts +2 -3
- package/src/adapters/zed.ts +16 -1
- package/src/claude/agents-inject.ts +14 -3
- package/src/claude/context-windows.ts +19 -17
- package/src/claude/desktop-3p.ts +88 -12
- package/src/claude/desktop-profile.ts +2 -1
- package/src/claude/gateway-cache.ts +18 -1
- package/src/claude/inbound-cache-stabilize.ts +4 -9
- package/src/claude/inbound.ts +78 -3
- package/src/claude/intercept/cli-catalog.ts +3 -0
- package/src/claude/intercept/model-bindings.ts +1 -0
- package/src/claude/intercept/picker-ca-persistence.ts +7 -6
- package/src/claude/intercept/picker-listener.ts +71 -4
- package/src/claude/intercept/picker-models.ts +14 -6
- package/src/claude/intercept/settings.ts +3 -0
- package/src/claude/long-context.ts +66 -0
- package/src/claude/model-info.ts +19 -16
- package/src/claude/outbound.ts +94 -9
- package/src/claude/subagent-model.ts +40 -11
- package/src/cli/account-anthropic-threshold.ts +14 -5
- package/src/cli/account-api.ts +3 -1
- package/src/cli/account-extended.ts +13 -9
- package/src/cli/account-policy-dto.ts +1 -1
- package/src/cli/account-policy.ts +13 -4
- package/src/cli/account.ts +3 -3
- package/src/cli/agent.ts +9 -5
- package/src/cli/aside-profile-recovery.ts +33 -0
- package/src/cli/capabilities-accounts.ts +2 -2
- package/src/cli/capabilities-agents-routing.ts +24 -0
- package/src/cli/capabilities-base.ts +5 -5
- package/src/cli/capabilities-integrations.ts +18 -2
- package/src/cli/cli-path-diagnostics.ts +132 -0
- package/src/cli/codex-shim-autorestore.ts +3 -0
- package/src/cli/desktop-runtime-guidance.ts +65 -0
- package/src/cli/dispatch.ts +15 -1
- package/src/cli/doctor.ts +16 -3
- package/src/cli/help.ts +4 -1
- package/src/cli/index.ts +25 -14
- package/src/cli/integration-aside-sync.ts +2 -1
- package/src/cli/integration-plan-dto.ts +1 -0
- package/src/cli/integration-preview.ts +8 -1
- package/src/cli/integrations.ts +48 -6
- package/src/cli/message-args.ts +34 -0
- package/src/cli/message-command.ts +43 -0
- package/src/cli/message-runtime.ts +6 -0
- package/src/cli/observe.ts +3 -1
- package/src/cli/provider.ts +29 -6
- package/src/cli/registry.ts +24 -2
- package/src/cli/resolve.ts +25 -2
- package/src/cli/root.ts +4 -2
- package/src/cli/status.ts +64 -12
- package/src/cli/update-restart-child.ts +4 -2
- package/src/cli/update-restart-home.ts +28 -10
- package/src/cli/update-restart-service-record.ts +116 -0
- package/src/cli/update-restart-supervision.ts +96 -0
- package/src/cli/update-restart.ts +59 -13
- package/src/cli/v2.ts +27 -20
- package/src/cli/version-skew-notice.ts +77 -0
- package/src/clients/config-export/commandcode.ts +131 -0
- package/src/clients/config-export/contracts.ts +12 -0
- package/src/clients/config-export.ts +64 -1
- package/src/clients/lazycodex.ts +1 -1
- package/src/clients/omo-role-models.ts +32 -7
- package/src/codex/auth-api/account-list.ts +11 -3
- package/src/codex/auth-api/account-selection.ts +107 -0
- package/src/codex/auth-api/main-account-probe.ts +25 -8
- package/src/codex/auth-api/pool-mode-gate.ts +33 -9
- package/src/codex/auth-api/pool-quota-probe.ts +15 -1
- package/src/codex/auth-api/routes.ts +11 -49
- package/src/codex/auth-context.ts +20 -1
- package/src/codex/autostart-health.ts +12 -3
- package/src/codex/catalog/auto-review.ts +13 -6
- package/src/codex/catalog/build-entries.ts +33 -7
- package/src/codex/catalog/bundled.ts +155 -26
- package/src/codex/catalog/combo-member.ts +3 -2
- package/src/codex/catalog/control-plane.ts +45 -0
- package/src/codex/catalog/effort.ts +37 -6
- package/src/codex/catalog/gather-capture.ts +10 -3
- package/src/codex/catalog/model-hints.ts +15 -8
- package/src/codex/catalog/model-visibility.ts +3 -1
- package/src/codex/catalog/operator-tiers.ts +38 -0
- package/src/codex/catalog/parsing.ts +2 -1
- package/src/codex/catalog/provider-models.ts +58 -44
- package/src/codex/catalog/retained-sync.ts +7 -5
- package/src/codex/catalog/routed-gather.ts +15 -1
- package/src/codex/catalog-auto-refresh-sources.ts +3 -4
- package/src/codex/catalog-auto-refresh.ts +19 -0
- package/src/codex/catalog.ts +1 -1
- package/src/codex/codex-home-owner.ts +3 -0
- package/src/codex/config-write-lock.ts +333 -0
- package/src/codex/control-plane-models.ts +6 -0
- package/src/codex/convergence.ts +2 -1
- package/src/codex/features.ts +257 -200
- package/src/codex/inject/config-write-section.ts +34 -0
- package/src/codex/inject/multi-agent-v2.ts +14 -6
- package/src/codex/inject/remove.ts +36 -11
- package/src/codex/inject/restore.ts +85 -20
- package/src/codex/inject-coordination.ts +15 -6
- package/src/codex/inject.ts +62 -20
- package/src/codex/journal.ts +62 -17
- package/src/codex/main-account-cache.ts +43 -0
- package/src/codex/paths.ts +2 -0
- package/src/codex/prepared-home.ts +18 -0
- package/src/codex/prompt-journal.ts +25 -12
- package/src/codex/prompt-layers.ts +49 -26
- package/src/codex/prompt-lock-claim.ts +134 -0
- package/src/codex/prompt-lock-evidence.ts +26 -0
- package/src/codex/prompt-lock-io.ts +16 -0
- package/src/codex/prompt-lock-owner.ts +130 -0
- package/src/codex/prompt-lock.ts +84 -53
- package/src/codex/routing/failure-window.ts +146 -0
- package/src/codex/routing/selection.ts +4 -1
- package/src/codex/routing.ts +13 -17
- package/src/codex/runtime.ts +106 -18
- package/src/codex/shim.ts +45 -19
- package/src/combos/jev-decision-contract.ts +25 -2
- package/src/combos/jev-service-exchange.ts +281 -0
- package/src/combos/jev.ts +34 -219
- package/src/combos/types.ts +1 -1
- package/src/config/atomic-write.ts +1 -1
- package/src/config/codex-ws-reuse-setting.ts +10 -0
- package/src/config/diagnostics.ts +27 -16
- package/src/config/live-reconcile.ts +17 -0
- package/src/config/load-degrade.ts +42 -0
- package/src/config/rebase-provenance.ts +11 -0
- package/src/config/schema/anthropic-account-pool.ts +143 -0
- package/src/config/schema/config-schema.ts +11 -1
- package/src/config/schema/leaf-validators.ts +4 -0
- package/src/config.ts +2 -0
- package/src/generated/compatibility-version.json +566 -298
- package/src/generated/model-metadata.ts +7 -6
- package/src/grok/inject.ts +50 -4
- package/src/grok/sync.ts +2 -1
- package/src/images/loop.ts +30 -11
- package/src/integrations/aside-profiles.ts +10 -3
- package/src/integrations/catalog-refresh.ts +19 -3
- package/src/integrations/mutation-plan.ts +7 -0
- package/src/integrations/registry.ts +8 -0
- package/src/integrations/state.ts +9 -2
- package/src/integrations/writer.ts +17 -5
- package/src/lib/bun-path-runtime.d.mts +32 -0
- package/src/lib/bun-path-runtime.mjs +95 -0
- package/src/lib/bun-runtime-preflight.ts +140 -0
- package/src/lib/desktop-cli-handoff.d.mts +20 -0
- package/src/lib/desktop-cli-handoff.mjs +92 -0
- package/src/lib/desktop-cli-record.d.mts +29 -0
- package/src/lib/desktop-cli-record.mjs +102 -0
- package/src/lib/lab-live-route-production.ts +9 -1
- package/src/lib/request-execution-budget.ts +244 -58
- package/src/lib/spend-pool-alias-validation.ts +79 -0
- package/src/lib/spend-pool-continuity.ts +34 -0
- package/src/lib/spend-reservation-ledger.ts +412 -50
- package/src/lib/state-store-registrations.ts +20 -3
- package/src/lib/synced-state-location.ts +46 -6
- package/src/lib/test-home-guard.ts +87 -1
- package/src/lib/translator-budget.ts +17 -4
- package/src/lib/upstream-retry.ts +17 -5
- package/src/lib/windows-atomic-replace.ts +38 -16
- package/src/lib/windows-elevation.ts +6 -0
- package/src/lib/windows-secret-acl.ts +92 -25
- package/src/lib/winsw.ts +2 -3
- package/src/lib/workflow-budget.ts +53 -11
- package/src/messaging/budget.ts +45 -0
- package/src/messaging/discovery.ts +57 -0
- package/src/messaging/envelope.ts +49 -0
- package/src/messaging/input.ts +37 -0
- package/src/messaging/rpc.ts +196 -0
- package/src/messaging/send.ts +58 -0
- package/src/messaging/socket.ts +72 -0
- package/src/messaging/types.ts +29 -0
- package/src/oauth/anthropic-account-refusal.ts +90 -18
- package/src/oauth/anthropic-account-threshold.ts +8 -2
- package/src/oauth/anthropic-continuity.ts +15 -1
- package/src/oauth/anthropic-model-quota.ts +120 -48
- package/src/oauth/anthropic-model-routes.ts +11 -3
- package/src/oauth/anthropic-oauth-definitions.ts +98 -0
- package/src/oauth/anthropic-pool-config.ts +30 -0
- package/src/oauth/anthropic-rate-limit-policy.ts +64 -9
- package/src/oauth/anthropic-routing.ts +1202 -866
- package/src/oauth/anthropic-send-ownership.ts +41 -0
- package/src/oauth/anthropic.ts +4 -1
- package/src/oauth/chatgpt.ts +113 -41
- package/src/oauth/generic-account-failover.ts +3 -1
- package/src/oauth/health.ts +8 -6
- package/src/oauth/index.ts +96 -175
- package/src/oauth/kiro.ts +22 -9
- package/src/oauth/login-cli.ts +2 -0
- package/src/oauth/model-discovery-auth.ts +43 -0
- package/src/oauth/pool-kernel.ts +11 -5
- package/src/oauth/pool-settings-capability.ts +5 -3
- package/src/oauth/store-anthropic-instance.ts +87 -0
- package/src/oauth/store.ts +68 -10
- package/src/oauth/token-guardian.ts +2 -0
- package/src/oauth/types.ts +2 -0
- package/src/protocols/plan-snapshot.ts +5 -0
- package/src/protocols/settings.ts +20 -5
- package/src/providers/anthropic-instance-id.ts +47 -0
- package/src/providers/anthropic-instance.ts +48 -0
- package/src/providers/anthropic-reset-grant-ledger.ts +11 -1
- package/src/providers/azure-model-metadata.ts +115 -0
- package/src/providers/derive.ts +23 -0
- package/src/providers/kiro-models.ts +3 -0
- package/src/providers/label.ts +1 -1
- package/src/providers/model-rename-fields.ts +2 -0
- package/src/providers/quota/account-cache.ts +37 -11
- package/src/providers/quota/anthropic-account-quota.ts +93 -0
- package/src/providers/quota/anthropic-cooldown-recovery.ts +222 -111
- package/src/providers/quota/report-cache.ts +24 -1
- package/src/providers/quota/vendor-probes-key.ts +127 -17
- package/src/providers/quota/vendor-probes-oauth.ts +46 -14
- package/src/providers/quota.ts +23 -33
- package/src/providers/registry/entries-core.ts +35 -30
- package/src/providers/registry/model-ids.ts +1 -0
- package/src/providers/registry/model-seeds.ts +7 -4
- package/src/providers/registry/types.ts +3 -0
- package/src/providers/registry.ts +3 -3
- package/src/responses/reasoning-envelope.ts +29 -1
- package/src/responses/reasoning-replay-cache.ts +17 -1
- package/src/responses/spill-store.ts +20 -3
- package/src/responses/state/metrics.ts +95 -0
- package/src/responses/state/snapshot-codec.ts +6 -0
- package/src/responses/state/spill-failure.ts +12 -0
- package/src/responses/state/spill-queue.ts +13 -5
- package/src/responses/state/unforced-store-false.ts +55 -0
- package/src/responses/state.ts +68 -76
- package/src/responses/task-input.ts +17 -0
- package/src/router.ts +28 -4
- package/src/routing/compatibility/assemble.ts +1 -1
- package/src/routing/quota.ts +7 -3
- package/src/server/auth-cors.ts +5 -0
- package/src/server/background-lifecycle.ts +27 -0
- package/src/server/chat-completions.ts +7 -1
- package/src/server/chat-native.ts +64 -28
- package/src/server/claude-messages.ts +59 -8
- package/src/server/gui-static.ts +38 -4
- package/src/server/inbound-body-admission.ts +1 -0
- package/src/server/index/claude-intercept-lifecycle.ts +3 -1
- package/src/server/index/serve-options.ts +10 -2
- package/src/server/index/spend-ledger-lifecycle.ts +12 -5
- package/src/server/index/startup-warnings.ts +19 -0
- package/src/server/index.ts +5 -2
- package/src/server/inference/context.ts +1 -1
- package/src/server/lifecycle.ts +1 -1
- package/src/server/management/agent-settings-routes.ts +123 -38
- package/src/server/management/anthropic-account-threshold.ts +12 -9
- package/src/server/management/anthropic-pool-settings.ts +72 -0
- package/src/server/management/anthropic-reset-grant-routes.ts +98 -39
- package/src/server/management/codex-agent-role-routes.ts +4 -2
- package/src/server/management/codex-prompt-routes.ts +1 -0
- package/src/server/management/codex-role-auto-assign.ts +13 -2
- package/src/server/management/config-routes.ts +85 -14
- package/src/server/management/context.ts +2 -2
- package/src/server/management/decision-routes.ts +2 -1
- package/src/server/management/integration-routes.ts +25 -2
- package/src/server/management/oauth-account-routes.ts +79 -98
- package/src/server/management/provider-instance-ownership.ts +44 -0
- package/src/server/management/provider-routes.ts +21 -28
- package/src/server/management/route-registry.ts +3 -1
- package/src/server/management/routing-profile-routes.ts +4 -4
- package/src/server/management/shared.ts +3 -3
- package/src/server/management/system-restart.ts +44 -14
- package/src/server/management/system-routes.ts +24 -2
- package/src/server/management/vision-sidecar-options.ts +9 -6
- package/src/server/management/web-search-sidecar-options.ts +51 -2
- package/src/server/management-auth.ts +6 -0
- package/src/server/messages-native-eligibility.ts +3 -2
- package/src/server/messages-native-oauth.ts +91 -45
- package/src/server/messages-native-selector.ts +39 -0
- package/src/server/messages-native.ts +133 -38
- package/src/server/messages-response-headers.ts +14 -0
- package/src/server/request-log-conversation.ts +48 -5
- package/src/server/request-log.ts +36 -2
- package/src/server/responses/adapter-continuation.ts +31 -19
- package/src/server/responses/adapter-dispatch.ts +75 -24
- package/src/server/responses/antigravity-validation-refusal.ts +20 -6
- package/src/server/responses/codex-ws-exchange.ts +17 -2
- package/src/server/responses/codex-ws-pool.ts +100 -13
- package/src/server/responses/codex-ws-wire.ts +9 -0
- package/src/server/responses/combo-requested-effort.ts +3 -1
- package/src/server/responses/compact.ts +25 -8
- package/src/server/responses/compaction-recovery.ts +1 -1
- package/src/server/responses/core-codex-account.ts +22 -1
- package/src/server/responses/core-combo-native.ts +24 -4
- package/src/server/responses/core-combo.ts +38 -25
- package/src/server/responses/core-lifetime.ts +3 -36
- package/src/server/responses/core-normalize.ts +1 -0
- package/src/server/responses/core-options.ts +8 -1
- package/src/server/responses/core-replay.ts +78 -0
- package/src/server/responses/core.ts +3 -3
- package/src/server/responses/fetch-helpers.ts +26 -3
- package/src/server/responses/passthrough-delivery.ts +30 -4
- package/src/server/responses/passthrough-dispatch.ts +39 -9
- package/src/server/responses/request-prepare.ts +41 -5
- package/src/server/responses/request-send-budget.ts +150 -50
- package/src/server/responses/request-spend.ts +325 -33
- package/src/server/responses/request-transport.ts +132 -52
- package/src/server/responses/response-effects.ts +1 -0
- package/src/server/responses/run-turn-execution.ts +13 -3
- package/src/server/responses/sidecar-execution.ts +113 -22
- package/src/server/responses/sidecar-send-budget.ts +58 -0
- package/src/server/responses/ws-upstream.ts +19 -6
- package/src/server/responses-undeclared-tool-guard.ts +5 -1
- package/src/server/startup-health-cache.ts +2 -1
- package/src/server/workflow-refusal.ts +33 -0
- package/src/service/cli.ts +20 -4
- package/src/service/desktop-command-guard.ts +32 -0
- package/src/service/desktop-startup.ts +66 -40
- package/src/service/desktop-supervision.d.mts +26 -0
- package/src/service/desktop-supervision.mjs +140 -0
- package/src/service/managing-cli.ts +1 -0
- package/src/service/orchestration.ts +46 -20
- package/src/service/ownership-mutation-lease.d.mts +1 -1
- package/src/service/ownership-mutation-lease.mjs +5 -7
- package/src/service/repair.ts +25 -9
- package/src/service/state.ts +4 -3
- package/src/service/systemd.ts +17 -8
- package/src/service/windows-ops.ts +61 -22
- package/src/sidecar/anthropic-binding.ts +79 -0
- package/src/sidecar/auth.ts +76 -2
- package/src/storage/policy-job.ts +5 -1
- package/src/storage/policy-worker.ts +3 -1
- package/src/storage/policy.ts +9 -0
- package/src/types/anthropic-account-pool.ts +33 -0
- package/src/types/config.ts +33 -28
- package/src/types/provider.ts +5 -0
- package/src/types/request.ts +5 -0
- package/src/types/tools.ts +7 -0
- package/src/types/wire.ts +1 -0
- package/src/types.ts +4 -0
- package/src/update/index.ts +57 -9
- package/src/update/restart-ownership.ts +10 -3
- package/src/update/runtime-ownership.d.mts +6 -0
- package/src/update/runtime-ownership.mjs +23 -7
- package/src/usage/cost.ts +3 -2
- package/src/usage/expected-prices.ts +66 -14
- package/src/vision/anthropic-describe.ts +16 -3
- package/src/vision/index.ts +3 -0
- package/src/vision/plan.ts +19 -6
- package/src/web-search/alpha-search.ts +7 -1
- package/src/web-search/anthropic-executor.ts +16 -4
- package/src/web-search/index.ts +7 -3
- package/src/web-search/loop.ts +32 -7
- package/src/web-search/passthrough-bridge.ts +4 -1
- package/src/web-search/sidecar-providers.ts +4 -3
- package/gui/dist/assets/App-MbDVfUeC.js +0 -54
- package/gui/dist/assets/Tray-CzkxK82A.js +0 -1
- package/gui/dist/assets/index-UJt6npXk.js +0 -94
- package/gui/dist/assets/quota-summary-DU3sD6Z-.js +0 -1
|
@@ -72,6 +72,7 @@ export interface ResponseSpillPayload {
|
|
|
72
72
|
*/
|
|
73
73
|
providerOutputStart?: number;
|
|
74
74
|
providers?: OcxProviderContinuationState;
|
|
75
|
+
unforcedStoreFalse?: boolean;
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
export interface ResponseSpillRef {
|
|
@@ -496,6 +497,7 @@ function serializedSpill(
|
|
|
496
497
|
items: state.items,
|
|
497
498
|
...(state.providerOutputStart !== undefined ? { providerOutputStart: state.providerOutputStart } : {}),
|
|
498
499
|
...(state.providers ? { providers: state.providers } : {}),
|
|
500
|
+
...(state.unforcedStoreFalse ? { unforcedStoreFalse: state.unforcedStoreFalse } : {}),
|
|
499
501
|
};
|
|
500
502
|
const serialized = JSON.stringify(payload);
|
|
501
503
|
if (serialized === undefined) throw new Error("Response spill serialization failed");
|
|
@@ -549,12 +551,14 @@ function validPayload(value: unknown, responseId: string): value is ResponseSpil
|
|
|
549
551
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
550
552
|
const payload = value as Record<string, unknown>;
|
|
551
553
|
const keys = Object.keys(payload);
|
|
552
|
-
if (keys.some(key => !["version", "responseId", "createdAt", "clientThreadId", "items", "providerOutputStart", "providers"].includes(key))) return false;
|
|
554
|
+
if (keys.some(key => !["version", "responseId", "createdAt", "clientThreadId", "items", "providerOutputStart", "providers", "unforcedStoreFalse"].includes(key))) return false;
|
|
553
555
|
if (payload.version !== 1 || payload.responseId !== responseId) return false;
|
|
554
556
|
if (typeof payload.createdAt !== "number" || !Number.isFinite(payload.createdAt)) return false;
|
|
555
557
|
if (payload.clientThreadId !== undefined
|
|
556
558
|
&& (typeof payload.clientThreadId !== "string" || payload.clientThreadId.trim().length === 0)) return false;
|
|
559
|
+
if (payload.unforcedStoreFalse !== undefined && typeof payload.unforcedStoreFalse !== "boolean") return false;
|
|
557
560
|
if (!Array.isArray(payload.items)) return false;
|
|
561
|
+
if (payload.unforcedStoreFalse === true && payload.providerOutputStart === undefined) return false;
|
|
558
562
|
// A malformed boundary must degrade to "never skip", never to a bad index: reject the
|
|
559
563
|
// payload outright so materialization treats it as corrupt rather than trusting it.
|
|
560
564
|
if (payload.providerOutputStart !== undefined) {
|
|
@@ -761,10 +765,23 @@ export function readResponseSpill(responseId: string, ref: ResponseSpillRef): Re
|
|
|
761
765
|
export function deleteResponseSpill(ref: ResponseSpillRef): void {
|
|
762
766
|
if (!validSpillRef(ref)) return;
|
|
763
767
|
const dir = responseSpillDirectory();
|
|
768
|
+
const path = join(dir, ref.fileName);
|
|
764
769
|
try {
|
|
765
|
-
unlink(
|
|
770
|
+
unlink(path);
|
|
766
771
|
fsyncDirectoryBestEffort(dir);
|
|
767
|
-
} catch {
|
|
772
|
+
} catch (error) {
|
|
773
|
+
// Still best effort, but no longer invisible: a file a failed unlink left behind occupies
|
|
774
|
+
// the volume, so the accounting owner keeps pricing it until the path is gone (#6747).
|
|
775
|
+
if (!isErrno(error, "ENOENT")) spillUnlinkFailureObserver?.(path, ref.payloadBytes);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
type SpillUnlinkFailureObserver = (path: string, bytes: number) => void;
|
|
780
|
+
let spillUnlinkFailureObserver: SpillUnlinkFailureObserver | null = null;
|
|
781
|
+
|
|
782
|
+
/** The owner of spill accounting registers here so a failed unlink cannot under-report disk use. */
|
|
783
|
+
export function setResponseSpillUnlinkFailureObserver(next: SpillUnlinkFailureObserver | null): void {
|
|
784
|
+
spillUnlinkFailureObserver = next;
|
|
768
785
|
}
|
|
769
786
|
|
|
770
787
|
type SpillDirNameKind = "spill" | "temp";
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { StoredResponseState } from "../state";
|
|
2
|
+
import type { ResponseSpillWriteStatus, ResponseSpillWriteFailureCode, ResponseSpillWriteFailureOrigin } from "./spill-failure";
|
|
3
|
+
|
|
4
|
+
export interface ResponseStateMetrics {
|
|
5
|
+
count: number;
|
|
6
|
+
residentCount: number;
|
|
7
|
+
spillStubCount: number;
|
|
8
|
+
tombstoneCount: number;
|
|
9
|
+
totalBytes: number;
|
|
10
|
+
spillPayloadBytes: number;
|
|
11
|
+
largestBytes: number;
|
|
12
|
+
oldestAgeMs: number;
|
|
13
|
+
spillWrites: number;
|
|
14
|
+
spillWriteFailures: number;
|
|
15
|
+
spillWriteStatus: ResponseSpillWriteStatus;
|
|
16
|
+
spillWriteConsecutiveFailures: number;
|
|
17
|
+
spillLastWriteFailureCode: ResponseSpillWriteFailureCode | null;
|
|
18
|
+
spillLastWriteFailureOrigin: ResponseSpillWriteFailureOrigin | null;
|
|
19
|
+
spillAclRetryReturnedTimeouts: number;
|
|
20
|
+
spillAclTimeoutMemoRefusals: number;
|
|
21
|
+
/** Publications refused because the durable spill cap could not make room (cumulative). */
|
|
22
|
+
spillCapacityRefusals: number;
|
|
23
|
+
/** Spills evicted by admission to make room for a newer publication (cumulative). */
|
|
24
|
+
spillHeadroomEvictions: number;
|
|
25
|
+
spillLastWriteFailureAt: number | null;
|
|
26
|
+
spillLastWriteSuccessAt: number | null;
|
|
27
|
+
spillReadFailures: number;
|
|
28
|
+
replayScopeMismatchDrops: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function computeResponseStateMetrics(params: {
|
|
32
|
+
states: Iterable<StoredResponseState>;
|
|
33
|
+
stateCount: number;
|
|
34
|
+
now: number;
|
|
35
|
+
totalBytes: number;
|
|
36
|
+
spillWrites: number;
|
|
37
|
+
spillWriteFailures: number;
|
|
38
|
+
spillWriteConsecutiveFailures: number;
|
|
39
|
+
spillLastFailureCode: ResponseSpillWriteFailureCode | null;
|
|
40
|
+
spillLastFailureOrigin: ResponseSpillWriteFailureOrigin | null;
|
|
41
|
+
spillLastSuccessAt: number | null;
|
|
42
|
+
spillAclRetryReturnedTimeouts: number;
|
|
43
|
+
spillAclTimeoutMemoRefusals: number;
|
|
44
|
+
spillCapacityRefusals: number;
|
|
45
|
+
spillHeadroomEvictions: number;
|
|
46
|
+
spillLastFailureAt: number | null;
|
|
47
|
+
spillReadFailures: number;
|
|
48
|
+
replayScopeMismatchDrops: number;
|
|
49
|
+
}): ResponseStateMetrics {
|
|
50
|
+
let largestBytes = 0;
|
|
51
|
+
let oldestCreatedAt = params.now;
|
|
52
|
+
let residentCount = 0;
|
|
53
|
+
let spillStubCount = 0;
|
|
54
|
+
let tombstoneCount = 0;
|
|
55
|
+
let spillPayloadBytes = 0;
|
|
56
|
+
for (const state of params.states) {
|
|
57
|
+
const bytes = state.sizeBytes;
|
|
58
|
+
if (bytes > largestBytes) largestBytes = bytes;
|
|
59
|
+
if (state.createdAt < oldestCreatedAt) oldestCreatedAt = state.createdAt;
|
|
60
|
+
if (state.kind === "resident") {
|
|
61
|
+
residentCount += 1;
|
|
62
|
+
} else if (state.kind === "spill") {
|
|
63
|
+
spillStubCount += 1;
|
|
64
|
+
spillPayloadBytes += state.spill.payloadBytes;
|
|
65
|
+
} else tombstoneCount += 1;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
count: params.stateCount,
|
|
69
|
+
residentCount,
|
|
70
|
+
spillStubCount,
|
|
71
|
+
tombstoneCount,
|
|
72
|
+
totalBytes: params.totalBytes,
|
|
73
|
+
spillPayloadBytes,
|
|
74
|
+
largestBytes,
|
|
75
|
+
oldestAgeMs: params.stateCount > 0 ? params.now - oldestCreatedAt : 0,
|
|
76
|
+
spillWrites: params.spillWrites,
|
|
77
|
+
spillWriteFailures: params.spillWriteFailures,
|
|
78
|
+
spillWriteStatus: params.spillWriteConsecutiveFailures > 0
|
|
79
|
+
? "degraded"
|
|
80
|
+
: params.spillLastSuccessAt !== null
|
|
81
|
+
? "healthy"
|
|
82
|
+
: "initial",
|
|
83
|
+
spillWriteConsecutiveFailures: params.spillWriteConsecutiveFailures,
|
|
84
|
+
spillLastWriteFailureCode: params.spillLastFailureCode,
|
|
85
|
+
spillLastWriteFailureOrigin: params.spillLastFailureOrigin,
|
|
86
|
+
spillAclRetryReturnedTimeouts: params.spillAclRetryReturnedTimeouts,
|
|
87
|
+
spillAclTimeoutMemoRefusals: params.spillAclTimeoutMemoRefusals,
|
|
88
|
+
spillCapacityRefusals: params.spillCapacityRefusals,
|
|
89
|
+
spillHeadroomEvictions: params.spillHeadroomEvictions,
|
|
90
|
+
spillLastWriteFailureAt: params.spillLastFailureAt,
|
|
91
|
+
spillLastWriteSuccessAt: params.spillLastSuccessAt,
|
|
92
|
+
spillReadFailures: params.spillReadFailures,
|
|
93
|
+
replayScopeMismatchDrops: params.replayScopeMismatchDrops,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -24,6 +24,7 @@ interface LegacySnapshotState {
|
|
|
24
24
|
providers?: OcxProviderContinuationState;
|
|
25
25
|
conversationId?: unknown;
|
|
26
26
|
cursorCheckpointUsable?: unknown;
|
|
27
|
+
unforcedStoreFalse?: unknown;
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
function isSpillRef(value: unknown): value is ResponseSpillRef {
|
|
@@ -51,6 +52,9 @@ export function loadSnapshotEntry(id: string, value: unknown, store: SnapshotLoa
|
|
|
51
52
|
? raw as number
|
|
52
53
|
: undefined;
|
|
53
54
|
};
|
|
55
|
+
// Restricted retention requires proven provider output; legacy unrestricted rows stay readable.
|
|
56
|
+
if (rec.unforcedStoreFalse === true
|
|
57
|
+
&& anchorFor(rec.kind === "spill" ? Number.MAX_SAFE_INTEGER : Array.isArray(rec.items) ? rec.items.length : 0) === undefined) return;
|
|
54
58
|
if (rec.kind === "spill") {
|
|
55
59
|
if (!isSpillRef(rec.spill)) return;
|
|
56
60
|
const base: Omit<SpilledResponseState, "sizeBytes"> = {
|
|
@@ -61,6 +65,7 @@ export function loadSnapshotEntry(id: string, value: unknown, store: SnapshotLoa
|
|
|
61
65
|
// here; the spill payload validator re-checks it against the real array.
|
|
62
66
|
...(anchorFor(Number.MAX_SAFE_INTEGER) !== undefined ? { providerOutputStart: anchorFor(Number.MAX_SAFE_INTEGER) } : {}),
|
|
63
67
|
...(rec.providers ? { providers: rec.providers } : {}),
|
|
68
|
+
...(rec.unforcedStoreFalse === true ? { unforcedStoreFalse: true } : {}),
|
|
64
69
|
spill: rec.spill,
|
|
65
70
|
};
|
|
66
71
|
store.replaceMapEntry(id, { ...base, sizeBytes: store.stubSize(id, base) });
|
|
@@ -88,6 +93,7 @@ export function loadSnapshotEntry(id: string, value: unknown, store: SnapshotLoa
|
|
|
88
93
|
items: rec.items,
|
|
89
94
|
...(anchorFor(rec.items.length) !== undefined ? { providerOutputStart: anchorFor(rec.items.length) } : {}),
|
|
90
95
|
...(providers ? { providers } : {}),
|
|
96
|
+
...(rec.unforcedStoreFalse === true ? { unforcedStoreFalse: true } : {}),
|
|
91
97
|
});
|
|
92
98
|
if (!resident) {
|
|
93
99
|
store.replaceMapEntry(id, store.tombstone(id, rec.createdAt));
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
export const spillCounters = {
|
|
2
2
|
writes: 0, writeFailures: 0, readFailures: 0,
|
|
3
3
|
aclRetryReturnedTimeouts: 0, aclTimeoutMemoRefusals: 0,
|
|
4
|
+
capacityRefusals: 0, headroomEvictions: 0,
|
|
4
5
|
};
|
|
5
6
|
|
|
7
|
+
/** Test-only: zero every spill counter, including ones added later. */
|
|
8
|
+
export function resetSpillCountersForTests(): void {
|
|
9
|
+
for (const key of Object.keys(spillCounters) as Array<keyof typeof spillCounters>) spillCounters[key] = 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
export type ResponseSpillWriteFailureCode =
|
|
7
13
|
| "EACLRETRYEXHAUSTED"
|
|
8
14
|
| "ETIMEDOUT"
|
|
@@ -102,6 +108,12 @@ export function noteSpillWriteFailure(
|
|
|
102
108
|
if (origin === "retry_returned_timeout") spillCounters.aclRetryReturnedTimeouts += 1;
|
|
103
109
|
else if (origin === "timeout_memo_refusal") spillCounters.aclTimeoutMemoRefusals += 1;
|
|
104
110
|
}
|
|
111
|
+
|
|
112
|
+
/** A publication refused because the durable spill cap could not make room for it (#6747). */
|
|
113
|
+
export function noteSpillCapacityRefusal(): void {
|
|
114
|
+
spillCounters.capacityRefusals += 1;
|
|
115
|
+
noteSpillWriteFailure(null, "ECAPACITY");
|
|
116
|
+
}
|
|
105
117
|
/**
|
|
106
118
|
* Admission-boundary observability (test-visible). directSpills: oversized
|
|
107
119
|
* candidates routed straight to durable spill without a resident stay or
|
|
@@ -11,12 +11,14 @@ import {
|
|
|
11
11
|
responseSpillNow,
|
|
12
12
|
type ResponseSpillPublicationControl,
|
|
13
13
|
type ResponseSpillRef,
|
|
14
|
+
setResponseSpillUnlinkFailureObserver,
|
|
14
15
|
writeResponseSpillDurably,
|
|
15
16
|
writeResponseSpillDurablyAsync,
|
|
16
17
|
} from "../spill-store";
|
|
17
18
|
import { enforceAppOwnedMemoryBudget } from "../../lib/app-owned-memory";
|
|
18
19
|
import {
|
|
19
20
|
admissionCounters,
|
|
21
|
+
noteSpillCapacityRefusal,
|
|
20
22
|
noteSpillWriteFailure,
|
|
21
23
|
noteSpillWriteSuccess,
|
|
22
24
|
spillAclMemoRefusalOrigin,
|
|
@@ -42,7 +44,8 @@ export interface SpillQueueStore {
|
|
|
42
44
|
pruneResponses(): void;
|
|
43
45
|
accountedResponseSpillBytes(): number;
|
|
44
46
|
spillByteCap(): number;
|
|
45
|
-
|
|
47
|
+
/** No argument: plain cap pruning. A number (0 included): admission reclaim of that headroom. */
|
|
48
|
+
enforceSpilledResponseBudget(requiredHeadroomBytes?: number): number;
|
|
46
49
|
terminalizationMaxPasses(): number;
|
|
47
50
|
}
|
|
48
51
|
|
|
@@ -122,6 +125,8 @@ function chargeUnreclaimableSpillPath(path: string | null | undefined, bytes: nu
|
|
|
122
125
|
if (!path || bytes <= 0) return;
|
|
123
126
|
unreclaimableSpillPaths.set(path, bytes);
|
|
124
127
|
}
|
|
128
|
+
// A failed unlink of an installed or deferred spill leaves a real file too; price it the same way.
|
|
129
|
+
setResponseSpillUnlinkFailureObserver(chargeUnreclaimableSpillPath);
|
|
125
130
|
|
|
126
131
|
/** Drop charges for paths that have since disappeared; returns the surviving total. */
|
|
127
132
|
function reconcileUnreclaimableSpillPaths(): number {
|
|
@@ -191,6 +196,7 @@ function spillPayloadForResident(candidate: ResidentResponseState): Parameters<t
|
|
|
191
196
|
items: candidate.items,
|
|
192
197
|
...(candidate.providerOutputStart !== undefined ? { providerOutputStart: candidate.providerOutputStart } : {}),
|
|
193
198
|
...(candidate.providers ? { providers: candidate.providers } : {}),
|
|
199
|
+
...(candidate.unforcedStoreFalse ? { unforcedStoreFalse: candidate.unforcedStoreFalse } : {}),
|
|
194
200
|
};
|
|
195
201
|
}
|
|
196
202
|
|
|
@@ -285,9 +291,10 @@ export function queuePendingResponseSpill(
|
|
|
285
291
|
// against a total that is short by a whole envelope.
|
|
286
292
|
const inheritedBytes = inheritedSpill?.payloadBytes ?? 0;
|
|
287
293
|
if (requireStore().accountedResponseSpillBytes() + footprint + inheritedBytes > requireStore().spillByteCap()) {
|
|
288
|
-
|
|
294
|
+
// An envelope over the replay ceiling ends in EFBIG anyway; never evict a continuation for it.
|
|
295
|
+
if (footprint / 2 <= responseSpillPayloadCap()) requireStore().enforceSpilledResponseBudget(footprint + inheritedBytes);
|
|
289
296
|
if (requireStore().accountedResponseSpillBytes() + footprint + inheritedBytes > requireStore().spillByteCap()) {
|
|
290
|
-
|
|
297
|
+
noteSpillCapacityRefusal();
|
|
291
298
|
requireStore().replaceWithSpillFailure(id, candidate);
|
|
292
299
|
requireStore().deferSupersededSpill(inheritedSpill);
|
|
293
300
|
return;
|
|
@@ -420,10 +427,11 @@ function installShutdownFallbackSpill(
|
|
|
420
427
|
// over budget. `replaceWithSpillFailure` is the same fail-closed ending the budget
|
|
421
428
|
// exhaustion path uses, so replay reports `spill_failed` and the client resends.
|
|
422
429
|
if (requireStore().accountedResponseSpillBytes() + supersededBytes > requireStore().spillByteCap()) {
|
|
423
|
-
|
|
430
|
+
// The footprint is already reserved above, so only the superseded generation is extra room.
|
|
431
|
+
if (footprint / 2 <= responseSpillPayloadCap()) requireStore().enforceSpilledResponseBudget(supersededBytes);
|
|
424
432
|
if (requireStore().accountedResponseSpillBytes() + supersededBytes > requireStore().spillByteCap()) {
|
|
425
433
|
if (requireStore().currentEntry(job.id) === candidate) {
|
|
426
|
-
|
|
434
|
+
noteSpillCapacityRefusal();
|
|
427
435
|
requireStore().replaceWithSpillFailure(job.id, candidate);
|
|
428
436
|
requireStore().deferSupersededSpill(job.supersededSpill);
|
|
429
437
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Closed provenance and replay gating for unforced store:false client tool call responses.
|
|
3
|
+
*
|
|
4
|
+
* An unforced store:false response is cached exclusively to allow the client to send a matching
|
|
5
|
+
* function/custom tool output continuation on the next turn. Normal replay, text continuation, or
|
|
6
|
+
* mismatched output without a matching pending call fails replay and requires the client to
|
|
7
|
+
* supply the full conversation.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export function hasPendingClientToolCall(output: readonly unknown[]): boolean {
|
|
11
|
+
return output.some(item =>
|
|
12
|
+
!!item && typeof item === "object" && clientToolOutputType((item as { type?: unknown }).type) !== undefined,
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function allowsUnforcedStoreFalseReplay(
|
|
17
|
+
stored: readonly unknown[],
|
|
18
|
+
providerOutputStart: number | undefined,
|
|
19
|
+
clientInput: readonly unknown[],
|
|
20
|
+
carried: number,
|
|
21
|
+
): boolean {
|
|
22
|
+
if (typeof providerOutputStart !== "number" || !Number.isSafeInteger(providerOutputStart)
|
|
23
|
+
|| providerOutputStart < 0 || providerOutputStart > stored.length) return false;
|
|
24
|
+
const anchor = providerOutputStart;
|
|
25
|
+
const pendingCallIds = new Map<string, string>();
|
|
26
|
+
for (const item of stored.slice(anchor)) {
|
|
27
|
+
if (item && typeof item === "object") {
|
|
28
|
+
const outputType = clientToolOutputType((item as { type?: unknown }).type);
|
|
29
|
+
const callId = (item as { call_id?: unknown }).call_id;
|
|
30
|
+
if (outputType && typeof callId === "string" && callId) pendingCallIds.set(callId, outputType);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for (let i = 0; i < carried; i++) {
|
|
34
|
+
const item = clientInput[i];
|
|
35
|
+
if (item && typeof item === "object") {
|
|
36
|
+
const callId = (item as { call_id?: unknown }).call_id;
|
|
37
|
+
if (typeof callId === "string" && pendingCallIds.get(callId) === (item as { type?: unknown }).type) pendingCallIds.delete(callId);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return clientInput.slice(carried).some(item => {
|
|
41
|
+
if (item && typeof item === "object") {
|
|
42
|
+
const callId = (item as { call_id?: unknown }).call_id;
|
|
43
|
+
return typeof callId === "string" && pendingCallIds.has(callId)
|
|
44
|
+
&& pendingCallIds.get(callId) === (item as { type?: unknown }).type;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Closed call/output pairs supported by the client-owned continuation path. */
|
|
51
|
+
function clientToolOutputType(type: unknown): string | undefined {
|
|
52
|
+
if (type === "function_call") return "function_call_output";
|
|
53
|
+
if (type === "custom_tool_call") return "custom_tool_call_output";
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|