open-multi-agent-kit 0.96.2 → 0.98.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/CHANGELOG.md +51 -0
- package/README.md +43 -9
- package/dist/cli/args.d.ts +2 -3
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +13 -189
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/help.d.ts +3 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +194 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/initial-message.d.ts.map +1 -1
- package/dist/cli/initial-message.js +2 -1
- package/dist/cli/initial-message.js.map +1 -1
- package/dist/cli/resource-paths.d.ts +4 -0
- package/dist/cli/resource-paths.d.ts.map +1 -0
- package/dist/cli/resource-paths.js +59 -0
- package/dist/cli/resource-paths.js.map +1 -0
- package/dist/commands/adaptorch-doctor-cli.d.ts +13 -0
- package/dist/commands/adaptorch-doctor-cli.d.ts.map +1 -0
- package/dist/commands/adaptorch-doctor-cli.js +115 -0
- package/dist/commands/adaptorch-doctor-cli.js.map +1 -0
- package/dist/commands/resource-doctor-cli.d.ts +4 -0
- package/dist/commands/resource-doctor-cli.d.ts.map +1 -1
- package/dist/commands/resource-doctor-cli.js +35 -5
- package/dist/commands/resource-doctor-cli.js.map +1 -1
- package/dist/core/adaptorch-bridge.d.ts +11 -13
- package/dist/core/adaptorch-bridge.d.ts.map +1 -1
- package/dist/core/adaptorch-bridge.js +11 -13
- package/dist/core/adaptorch-bridge.js.map +1 -1
- package/dist/core/agent-session-snapshot.d.ts +16 -0
- package/dist/core/agent-session-snapshot.d.ts.map +1 -0
- package/dist/core/agent-session-snapshot.js +111 -0
- package/dist/core/agent-session-snapshot.js.map +1 -0
- package/dist/core/agent-session.d.ts +14 -10
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +102 -217
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/agent-tool-settings.d.ts +10 -0
- package/dist/core/agent-tool-settings.d.ts.map +1 -1
- package/dist/core/agent-tool-settings.js +10 -1
- package/dist/core/agent-tool-settings.js.map +1 -1
- package/dist/core/attachment-store.d.ts +39 -0
- package/dist/core/attachment-store.d.ts.map +1 -0
- package/dist/core/attachment-store.js +81 -0
- package/dist/core/attachment-store.js.map +1 -0
- package/dist/core/command-safety.d.ts +8 -0
- package/dist/core/command-safety.d.ts.map +1 -1
- package/dist/core/command-safety.js +140 -14
- package/dist/core/command-safety.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +13 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +60 -62
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/index.d.ts +1 -0
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +1 -0
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/compaction/knowledge-triage-format.d.ts +9 -0
- package/dist/core/compaction/knowledge-triage-format.d.ts.map +1 -0
- package/dist/core/compaction/knowledge-triage-format.js +71 -0
- package/dist/core/compaction/knowledge-triage-format.js.map +1 -0
- package/dist/core/compaction/knowledge-triage-types.d.ts +7 -0
- package/dist/core/compaction/knowledge-triage-types.d.ts.map +1 -0
- package/dist/core/compaction/knowledge-triage-types.js +2 -0
- package/dist/core/compaction/knowledge-triage-types.js.map +1 -0
- package/dist/core/compaction/knowledge-triage.d.ts +29 -0
- package/dist/core/compaction/knowledge-triage.d.ts.map +1 -0
- package/dist/core/compaction/knowledge-triage.js +189 -0
- package/dist/core/compaction/knowledge-triage.js.map +1 -0
- package/dist/core/compaction/transaction.d.ts.map +1 -1
- package/dist/core/compaction/transaction.js +1 -1
- package/dist/core/compaction/transaction.js.map +1 -1
- package/dist/core/compaction/utils.d.ts +4 -0
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +37 -0
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/completion-sound-io.d.ts +14 -0
- package/dist/core/completion-sound-io.d.ts.map +1 -0
- package/dist/core/completion-sound-io.js +64 -0
- package/dist/core/completion-sound-io.js.map +1 -0
- package/dist/core/completion-sound.d.ts +4 -10
- package/dist/core/completion-sound.d.ts.map +1 -1
- package/dist/core/completion-sound.js +28 -58
- package/dist/core/completion-sound.js.map +1 -1
- package/dist/core/context-budget-governor-v2.d.ts +1 -1
- package/dist/core/context-budget-governor-v2.d.ts.map +1 -1
- package/dist/core/context-budget-governor-v2.js +1 -1
- package/dist/core/context-budget-governor-v2.js.map +1 -1
- package/dist/core/context-budget-relevance.d.ts +15 -2
- package/dist/core/context-budget-relevance.d.ts.map +1 -1
- package/dist/core/context-budget-relevance.js +21 -9
- package/dist/core/context-budget-relevance.js.map +1 -1
- package/dist/core/context-budget-system-prompt-items.d.ts +1 -1
- package/dist/core/context-budget-system-prompt-items.d.ts.map +1 -1
- package/dist/core/context-budget-system-prompt-items.js.map +1 -1
- package/dist/core/context-budget-system-prompt.d.ts +1 -1
- package/dist/core/context-budget-system-prompt.d.ts.map +1 -1
- package/dist/core/context-budget-system-prompt.js.map +1 -1
- package/dist/core/context-budget-v2-cache-keys.d.ts +3 -0
- package/dist/core/context-budget-v2-cache-keys.d.ts.map +1 -1
- package/dist/core/context-budget-v2-cache-keys.js +2 -0
- package/dist/core/context-budget-v2-cache-keys.js.map +1 -1
- package/dist/core/context-budget-v2-plan-cache-keys.d.ts.map +1 -1
- package/dist/core/context-budget-v2-plan-cache-keys.js +3 -0
- package/dist/core/context-budget-v2-plan-cache-keys.js.map +1 -1
- package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planner.js +2 -1
- package/dist/core/context-budget-v2-planner.js.map +1 -1
- package/dist/core/context-budget-v2-scoring.d.ts +17 -0
- package/dist/core/context-budget-v2-scoring.d.ts.map +1 -1
- package/dist/core/context-budget-v2-scoring.js +25 -8
- package/dist/core/context-budget-v2-scoring.js.map +1 -1
- package/dist/core/context-budget-v2-selection.d.ts +2 -2
- package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
- package/dist/core/context-budget-v2-selection.js +18 -1
- package/dist/core/context-budget-v2-selection.js.map +1 -1
- package/dist/core/context-budget-v2-types.d.ts +17 -0
- package/dist/core/context-budget-v2-types.d.ts.map +1 -1
- package/dist/core/context-budget-v2-types.js +15 -0
- package/dist/core/context-budget-v2-types.js.map +1 -1
- package/dist/core/context-file.d.ts +23 -0
- package/dist/core/context-file.d.ts.map +1 -0
- package/dist/core/context-file.js +17 -0
- package/dist/core/context-file.js.map +1 -0
- package/dist/core/extensions/builtin/command-safety-gate.d.ts +3 -1
- package/dist/core/extensions/builtin/command-safety-gate.d.ts.map +1 -1
- package/dist/core/extensions/builtin/command-safety-gate.js +7 -0
- package/dist/core/extensions/builtin/command-safety-gate.js.map +1 -1
- package/dist/core/extensions/types.d.ts +12 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/keybindings.d.ts +1 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +6 -1
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-prompt-policy.d.ts +1 -1
- package/dist/core/model-prompt-policy.d.ts.map +1 -1
- package/dist/core/model-prompt-policy.js.map +1 -1
- package/dist/core/model-registry.d.ts +8 -3
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +71 -1
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/package-doctor-source-scan.d.ts +9 -0
- package/dist/core/package-doctor-source-scan.d.ts.map +1 -1
- package/dist/core/package-doctor-source-scan.js +77 -4
- package/dist/core/package-doctor-source-scan.js.map +1 -1
- package/dist/core/prompt-attachment.d.ts +51 -0
- package/dist/core/prompt-attachment.d.ts.map +1 -0
- package/dist/core/prompt-attachment.js +186 -0
- package/dist/core/prompt-attachment.js.map +1 -0
- package/dist/core/prompt-settlement.d.ts +6 -3
- package/dist/core/prompt-settlement.d.ts.map +1 -1
- package/dist/core/prompt-settlement.js +10 -14
- package/dist/core/prompt-settlement.js.map +1 -1
- package/dist/core/provider-resilience.d.ts +28 -0
- package/dist/core/provider-resilience.d.ts.map +1 -1
- package/dist/core/provider-resilience.js +50 -0
- package/dist/core/provider-resilience.js.map +1 -1
- package/dist/core/provider-retry.d.ts +1 -1
- package/dist/core/provider-retry.d.ts.map +1 -1
- package/dist/core/provider-retry.js +1 -1
- package/dist/core/provider-retry.js.map +1 -1
- package/dist/core/provider-usage.d.ts.map +1 -1
- package/dist/core/provider-usage.js +68 -2
- package/dist/core/provider-usage.js.map +1 -1
- package/dist/core/reasoning-router-promotion.d.ts +124 -0
- package/dist/core/reasoning-router-promotion.d.ts.map +1 -0
- package/dist/core/reasoning-router-promotion.js +121 -0
- package/dist/core/reasoning-router-promotion.js.map +1 -0
- package/dist/core/reasoning-router-replay-stability.d.ts +65 -0
- package/dist/core/reasoning-router-replay-stability.d.ts.map +1 -0
- package/dist/core/reasoning-router-replay-stability.js +67 -0
- package/dist/core/reasoning-router-replay-stability.js.map +1 -0
- package/dist/core/reasoning-router-v4-weights.d.ts +6 -6
- package/dist/core/reasoning-router-v4-weights.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4-weights.js +3 -3
- package/dist/core/reasoning-router-v4-weights.js.map +1 -1
- package/dist/core/reasoning-router-v4.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4.js +6 -6
- package/dist/core/reasoning-router-v4.js.map +1 -1
- package/dist/core/redaction.d.ts.map +1 -1
- package/dist/core/redaction.js +1 -1
- package/dist/core/redaction.js.map +1 -1
- package/dist/core/resource-admission.d.ts +2 -1
- package/dist/core/resource-admission.d.ts.map +1 -1
- package/dist/core/resource-admission.js +11 -0
- package/dist/core/resource-admission.js.map +1 -1
- package/dist/core/resource-governor-format.d.ts +1 -1
- package/dist/core/resource-governor-format.d.ts.map +1 -1
- package/dist/core/resource-governor-format.js.map +1 -1
- package/dist/core/resource-governor-settings.d.ts +6 -12
- package/dist/core/resource-governor-settings.d.ts.map +1 -1
- package/dist/core/resource-governor-settings.js.map +1 -1
- package/dist/core/resource-governor-types.d.ts +24 -0
- package/dist/core/resource-governor-types.d.ts.map +1 -0
- package/dist/core/resource-governor-types.js +15 -0
- package/dist/core/resource-governor-types.js.map +1 -0
- package/dist/core/resource-loader.d.ts +1 -7
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/resource-observation-journal.d.ts +2 -1
- package/dist/core/resource-observation-journal.d.ts.map +1 -1
- package/dist/core/resource-observation-journal.js +4 -3
- package/dist/core/resource-observation-journal.js.map +1 -1
- package/dist/core/resource-observation-report-reader.d.ts +7 -0
- package/dist/core/resource-observation-report-reader.d.ts.map +1 -0
- package/dist/core/resource-observation-report-reader.js +157 -0
- package/dist/core/resource-observation-report-reader.js.map +1 -0
- package/dist/core/resource-observation-report.d.ts +24 -0
- package/dist/core/resource-observation-report.d.ts.map +1 -0
- package/dist/core/resource-observation-report.js +101 -0
- package/dist/core/resource-observation-report.js.map +1 -0
- package/dist/core/router-feedback-collector.d.ts +1 -1
- package/dist/core/router-feedback-collector.d.ts.map +1 -1
- package/dist/core/router-feedback-collector.js.map +1 -1
- package/dist/core/session-bash-service.d.ts.map +1 -1
- package/dist/core/session-bash-service.js +4 -3
- package/dist/core/session-bash-service.js.map +1 -1
- package/dist/core/session-failure-cause.d.ts +33 -0
- package/dist/core/session-failure-cause.d.ts.map +1 -0
- package/dist/core/session-failure-cause.js +141 -0
- package/dist/core/session-failure-cause.js.map +1 -0
- package/dist/core/session-system-prompt.d.ts +1 -1
- package/dist/core/session-system-prompt.d.ts.map +1 -1
- package/dist/core/session-system-prompt.js.map +1 -1
- package/dist/core/session-termination.d.ts +1 -1
- package/dist/core/session-termination.d.ts.map +1 -1
- package/dist/core/session-termination.js +11 -2
- package/dist/core/session-termination.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +10 -14
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +13 -48
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +1 -34
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/workload-classifier.d.ts +2 -10
- package/dist/core/workload-classifier.d.ts.map +1 -1
- package/dist/core/workload-classifier.js +17 -0
- package/dist/core/workload-classifier.js.map +1 -1
- package/dist/core/workload-family-matcher.d.ts +1 -1
- package/dist/core/workload-family-matcher.d.ts.map +1 -1
- package/dist/core/workload-family-matcher.js.map +1 -1
- package/dist/core/workload-shard-execution-types.d.ts +40 -0
- package/dist/core/workload-shard-execution-types.d.ts.map +1 -0
- package/dist/core/workload-shard-execution-types.js +14 -0
- package/dist/core/workload-shard-execution-types.js.map +1 -0
- package/dist/core/workload-shard-executor.d.ts +3 -27
- package/dist/core/workload-shard-executor.d.ts.map +1 -1
- package/dist/core/workload-shard-executor.js.map +1 -1
- package/dist/core/workload-shard-runner.d.ts +1 -1
- package/dist/core/workload-shard-runner.d.ts.map +1 -1
- package/dist/core/workload-shard-runner.js.map +1 -1
- package/dist/core/workload-types.d.ts +24 -0
- package/dist/core/workload-types.d.ts.map +1 -0
- package/dist/core/workload-types.js +15 -0
- package/dist/core/workload-types.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +27 -47
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/attachment-strip.d.ts +21 -0
- package/dist/modes/interactive/components/attachment-strip.d.ts.map +1 -0
- package/dist/modes/interactive/components/attachment-strip.js +136 -0
- package/dist/modes/interactive/components/attachment-strip.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +6 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +26 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/status-sidebar.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-sidebar.js +12 -1
- package/dist/modes/interactive/components/status-sidebar.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +23 -4
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +174 -53
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/omk-control-panel.json +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +42 -33
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +14 -2
- package/dist/utils/clipboard.js.map +1 -1
- package/docs/adaptorch-preview-spec.md +20 -18
- package/docs/adaptorch-preview.md +9 -9
- package/docs/compaction.md +25 -4
- package/docs/correctness-wall.md +10 -10
- package/docs/docs.json +12 -0
- package/docs/environment-variables.md +9 -2
- package/docs/extensions.md +12 -3
- package/docs/index.md +7 -1
- package/docs/metrics.md +74 -2
- package/docs/provider-resilience.md +11 -0
- package/docs/runtime-algorithms.md +359 -0
- package/docs/sdk.md +2 -2
- package/docs/settings.md +11 -10
- package/docs/usage.md +19 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +18 -18
- package/package.json +7 -7
- package/dist/core/context-budget-governor.d.ts +0 -67
- package/dist/core/context-budget-governor.d.ts.map +0 -1
- package/dist/core/context-budget-governor.js +0 -224
- package/dist/core/context-budget-governor.js.map +0 -1
- package/dist/core/lean-ctx.d.ts +0 -99
- package/dist/core/lean-ctx.d.ts.map +0 -1
- package/dist/core/lean-ctx.js +0 -225
- package/dist/core/lean-ctx.js.map +0 -1
- package/dist/core/read-anchors.d.ts +0 -110
- package/dist/core/read-anchors.d.ts.map +0 -1
- package/dist/core/read-anchors.js +0 -193
- package/dist/core/read-anchors.js.map +0 -1
- package/dist/core/recovery-checkpoint.d.ts +0 -196
- package/dist/core/recovery-checkpoint.d.ts.map +0 -1
- package/dist/core/recovery-checkpoint.js +0 -382
- package/dist/core/recovery-checkpoint.js.map +0 -1
- package/dist/core/sandbox-policy-v2.d.ts +0 -49
- package/dist/core/sandbox-policy-v2.d.ts.map +0 -1
- package/dist/core/sandbox-policy-v2.js +0 -368
- package/dist/core/sandbox-policy-v2.js.map +0 -1
- package/dist/core/tools/omp-pure-seams.d.ts +0 -41
- package/dist/core/tools/omp-pure-seams.d.ts.map +0 -1
- package/dist/core/tools/omp-pure-seams.js +0 -142
- package/dist/core/tools/omp-pure-seams.js.map +0 -1
- package/dist/core/tools/omp-seam-runtime.d.ts +0 -100
- package/dist/core/tools/omp-seam-runtime.d.ts.map +0 -1
- package/dist/core/tools/omp-seam-runtime.js +0 -40
- package/dist/core/tools/omp-seam-runtime.js.map +0 -1
- package/dist/guardrails/audit-logger.d.ts +0 -4
- package/dist/guardrails/audit-logger.d.ts.map +0 -1
- package/dist/guardrails/audit-logger.js +0 -28
- package/dist/guardrails/audit-logger.js.map +0 -1
- package/dist/guardrails/freedomd-adapter.d.ts +0 -16
- package/dist/guardrails/freedomd-adapter.d.ts.map +0 -1
- package/dist/guardrails/freedomd-adapter.js +0 -87
- package/dist/guardrails/freedomd-adapter.js.map +0 -1
- package/dist/orchestration/lane-grant-auditor.d.ts +0 -4
- package/dist/orchestration/lane-grant-auditor.d.ts.map +0 -1
- package/dist/orchestration/lane-grant-auditor.js +0 -87
- package/dist/orchestration/lane-grant-auditor.js.map +0 -1
- package/dist/types/guardrails.d.ts +0 -61
- package/dist/types/guardrails.d.ts.map +0 -1
- package/dist/types/guardrails.js +0 -9
- package/dist/types/guardrails.js.map +0 -1
- package/dist/types/lane-grant.d.ts +0 -58
- package/dist/types/lane-grant.d.ts.map +0 -1
- package/dist/types/lane-grant.js +0 -9
- package/dist/types/lane-grant.js.map +0 -1
|
@@ -17,7 +17,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
17
17
|
import { basename, dirname, join as joinPath } from "node:path";
|
|
18
18
|
import { isDeepStrictEqual } from "node:util";
|
|
19
19
|
import { getVisionRouteModel } from "omk-agent-core";
|
|
20
|
-
import { clampThinkingLevel, cleanupSessionResources, deriveContextPromptCacheKey, getSupportedThinkingLevels,
|
|
20
|
+
import { clampThinkingLevel, cleanupSessionResources, deriveContextPromptCacheKey, getSupportedThinkingLevels, isBuiltinStreamFn, modelsAreEqual, resetApiProviders, } from "omk-ai";
|
|
21
21
|
import { APP_NAME, VERSION } from "../config.js";
|
|
22
22
|
import { theme } from "../modes/interactive/theme/theme.js";
|
|
23
23
|
import { stripFrontmatter } from "../utils/frontmatter.js";
|
|
@@ -72,14 +72,15 @@ function firstTextContent(result) {
|
|
|
72
72
|
}
|
|
73
73
|
return undefined;
|
|
74
74
|
}
|
|
75
|
+
import { createImmutableMessageSnapshot } from "./agent-session-snapshot.js";
|
|
75
76
|
import { redactCredentialShapedContent } from "./compaction/transaction.js";
|
|
76
77
|
import { selectContextFilesForModel } from "./model-prompt-policy.js";
|
|
77
78
|
import { findExactModelReferenceMatch } from "./model-resolver.js";
|
|
78
79
|
import { computePromptTokenBudget } from "./prompt-budget.js";
|
|
79
80
|
import { classifyPromptCacheTransition } from "./prompt-cache.js";
|
|
80
|
-
import
|
|
81
|
+
import * as promptSettlement from "./prompt-settlement.js";
|
|
81
82
|
import { expandPromptTemplate } from "./prompt-templates.js";
|
|
82
|
-
import { isQuotaExhaustionMessage, isStickySafetyModel, pickFailoverCandidate, resolveProviderResilience, shouldEjectStickySafetyModel, shouldHonorSafetyFailover, stickySafetyBlockMessage, } from "./provider-resilience.js";
|
|
83
|
+
import { isQuotaExhaustionMessage, isStickySafetyModel, isUpstreamUnavailableMessage, pickFailoverCandidate, resolveFailoverCandidates, resolveProviderResilience, sameModelRouteCandidates, shouldEjectStickySafetyModel, shouldHonorSafetyFailover, stickySafetyBlockMessage, } from "./provider-resilience.js";
|
|
83
84
|
import { computeRetryDelayMs, failoverModelKey, isFailoverTriggerError, isRetryableAssistantError, nextRetryAttempt, retryBudgetForAssistantError, } from "./provider-retry.js";
|
|
84
85
|
import { getBiasStepsForCell, parseRouterBiasSnapshot } from "./reasoning-router-bias.js";
|
|
85
86
|
import { classifyTaskV4, deriveRouterFeedbackFeaturesV4, resolveThinkingLevelV4WithUncertainty, TASK_CLASS_THINKING_LEVELS_V4, } from "./reasoning-router-v4.js";
|
|
@@ -95,6 +96,7 @@ import { RunResourceLeaseController } from "./run-resource-lease.js";
|
|
|
95
96
|
import { SessionBashRuntime } from "./session-bash-runtime.js";
|
|
96
97
|
import { SessionBashService } from "./session-bash-service.js";
|
|
97
98
|
import { SessionCompactionService } from "./session-compaction-service.js";
|
|
99
|
+
import { preflightFailureCause, providerFailureCause, runtimeFailureCause, terminationMessage, } from "./session-failure-cause.js";
|
|
98
100
|
import { CURRENT_SESSION_VERSION, getLatestCompactionEntry } from "./session-manager.js";
|
|
99
101
|
import { acquireSessionOwnerLeaseSync } from "./session-owner-lease.js";
|
|
100
102
|
import { assembleSessionSystemPrompt } from "./session-system-prompt.js";
|
|
@@ -171,103 +173,6 @@ function toolNameSetsEqual(left, right) {
|
|
|
171
173
|
return (normalizedLeft.length === normalizedRight.length &&
|
|
172
174
|
normalizedLeft.every((toolName, index) => toolName === normalizedRight[index]));
|
|
173
175
|
}
|
|
174
|
-
function snapshotContractError(reason) {
|
|
175
|
-
return new Error(`Finalized message replacement must be a plain serializable snapshot: ${reason}`);
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Clone a finalized message replacement into the JSON-compatible snapshot
|
|
179
|
-
* persisted by SessionManager. Undefined remains allowed as ordinary optional
|
|
180
|
-
* message data: JSON omits object properties with undefined values and writes
|
|
181
|
-
* undefined array elements as null.
|
|
182
|
-
*/
|
|
183
|
-
function clonePlainSnapshot(value, ancestors = new WeakSet(), copies = new WeakMap()) {
|
|
184
|
-
if (value === null)
|
|
185
|
-
return value;
|
|
186
|
-
switch (typeof value) {
|
|
187
|
-
case "string":
|
|
188
|
-
case "boolean":
|
|
189
|
-
case "undefined":
|
|
190
|
-
return value;
|
|
191
|
-
case "number":
|
|
192
|
-
if (!Number.isFinite(value)) {
|
|
193
|
-
throw snapshotContractError("non-finite number values are not allowed");
|
|
194
|
-
}
|
|
195
|
-
return value;
|
|
196
|
-
case "bigint":
|
|
197
|
-
throw snapshotContractError("bigint values are not allowed");
|
|
198
|
-
case "function":
|
|
199
|
-
case "symbol":
|
|
200
|
-
throw snapshotContractError(`${typeof value} values are not allowed`);
|
|
201
|
-
case "object":
|
|
202
|
-
break;
|
|
203
|
-
default:
|
|
204
|
-
throw snapshotContractError(`${typeof value} values are not allowed`);
|
|
205
|
-
}
|
|
206
|
-
if (ancestors.has(value)) {
|
|
207
|
-
throw snapshotContractError("cyclic values are not allowed");
|
|
208
|
-
}
|
|
209
|
-
if (copies.has(value)) {
|
|
210
|
-
return copies.get(value);
|
|
211
|
-
}
|
|
212
|
-
ancestors.add(value);
|
|
213
|
-
try {
|
|
214
|
-
if (Array.isArray(value)) {
|
|
215
|
-
const copy = [];
|
|
216
|
-
copy.length = value.length;
|
|
217
|
-
copies.set(value, copy);
|
|
218
|
-
for (const key of Reflect.ownKeys(value)) {
|
|
219
|
-
if (key === "length")
|
|
220
|
-
continue;
|
|
221
|
-
if (typeof key !== "string" || !/^(0|[1-9]\d*)$/.test(key) || Number(key) >= value.length) {
|
|
222
|
-
throw snapshotContractError("arrays may only contain indexed values");
|
|
223
|
-
}
|
|
224
|
-
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
225
|
-
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) {
|
|
226
|
-
throw snapshotContractError("accessor or non-enumerable properties are not allowed");
|
|
227
|
-
}
|
|
228
|
-
copy[Number(key)] = clonePlainSnapshot(descriptor.value, ancestors, copies);
|
|
229
|
-
}
|
|
230
|
-
return copy;
|
|
231
|
-
}
|
|
232
|
-
const prototype = Object.getPrototypeOf(value);
|
|
233
|
-
if (prototype !== Object.prototype && prototype !== null) {
|
|
234
|
-
throw snapshotContractError("non-plain objects are not allowed");
|
|
235
|
-
}
|
|
236
|
-
const copy = Object.create(prototype);
|
|
237
|
-
copies.set(value, copy);
|
|
238
|
-
for (const key of Reflect.ownKeys(value)) {
|
|
239
|
-
if (typeof key !== "string") {
|
|
240
|
-
throw snapshotContractError("symbol-keyed properties are not allowed");
|
|
241
|
-
}
|
|
242
|
-
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
243
|
-
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) {
|
|
244
|
-
throw snapshotContractError("accessor or non-enumerable properties are not allowed");
|
|
245
|
-
}
|
|
246
|
-
Object.defineProperty(copy, key, {
|
|
247
|
-
value: clonePlainSnapshot(descriptor.value, ancestors, copies),
|
|
248
|
-
enumerable: true,
|
|
249
|
-
configurable: true,
|
|
250
|
-
writable: true,
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
return copy;
|
|
254
|
-
}
|
|
255
|
-
finally {
|
|
256
|
-
ancestors.delete(value);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
function freezeSnapshot(value, seen = new WeakSet()) {
|
|
260
|
-
if (value === null || typeof value !== "object" || seen.has(value))
|
|
261
|
-
return value;
|
|
262
|
-
seen.add(value);
|
|
263
|
-
for (const child of Object.values(value)) {
|
|
264
|
-
freezeSnapshot(child, seen);
|
|
265
|
-
}
|
|
266
|
-
return Object.freeze(value);
|
|
267
|
-
}
|
|
268
|
-
function createImmutableMessageSnapshot(message) {
|
|
269
|
-
return freezeSnapshot(clonePlainSnapshot(message));
|
|
270
|
-
}
|
|
271
176
|
// ============================================================================
|
|
272
177
|
// AgentSession Class
|
|
273
178
|
// ============================================================================
|
|
@@ -387,7 +292,7 @@ export class AgentSession {
|
|
|
387
292
|
_workspaceMutationCount = 0;
|
|
388
293
|
// Model registry for API key resolution
|
|
389
294
|
_modelRegistry;
|
|
390
|
-
/** Lazy
|
|
295
|
+
/** Lazy provider: representations persist per workspace by default; plans stay session-memory-only. */
|
|
391
296
|
_contextBudgetCacheProvider;
|
|
392
297
|
_contextCacheInvalidationSnapshot;
|
|
393
298
|
// Tool registry for extension getTools/setTools
|
|
@@ -599,78 +504,6 @@ export class AgentSession {
|
|
|
599
504
|
});
|
|
600
505
|
this._appendReplayEvent(event, details);
|
|
601
506
|
}
|
|
602
|
-
_terminationMessage(value, fallback) {
|
|
603
|
-
const redacted = redactSensitiveText(value?.trim() || fallback)
|
|
604
|
-
.replace(/\0/g, "")
|
|
605
|
-
.slice(0, 512);
|
|
606
|
-
return redacted || fallback;
|
|
607
|
-
}
|
|
608
|
-
_providerFailureCause(message) {
|
|
609
|
-
const text = message.errorMessage ?? "";
|
|
610
|
-
if (isContextOverflow(message, this.model?.contextWindow ?? 0)) {
|
|
611
|
-
return { area: "provider", code: "context_overflow" };
|
|
612
|
-
}
|
|
613
|
-
// Fable/Claude often emit stop_reason=refusal on benign turns (false positive).
|
|
614
|
-
// Match broadly so we never mislabel these as provider.protocol.
|
|
615
|
-
if (/stop_reason\s*=\s*(refusal|sensitive)|content\/safety stop|safety stop|provider\.refusal|kind=provider_refusal/i.test(text)) {
|
|
616
|
-
return { area: "provider", code: "refusal" };
|
|
617
|
-
}
|
|
618
|
-
// Quota/billing exhaustion is checked BEFORE the generic 401/403 auth
|
|
619
|
-
// patterns: "403 ... usage limit for this billing cycle" is transient per
|
|
620
|
-
// cycle and must fail over, not terminate the turn as an auth error.
|
|
621
|
-
if (isQuotaExhaustionMessage(text) || /rate.?limit|too many requests|429/i.test(text)) {
|
|
622
|
-
return { area: "provider", code: "rate_limit" };
|
|
623
|
-
}
|
|
624
|
-
if (/auth|unauthori[sz]ed|forbidden|invalid.?api.?key|no api key|401|403|\/login/i.test(text)) {
|
|
625
|
-
return { area: "provider", code: "auth" };
|
|
626
|
-
}
|
|
627
|
-
// Kimi/K3 + OpenAI-compat: orphan tool results after dropped error assistants.
|
|
628
|
-
// Sanitize-and-retry (transform-messages drops orphans), not a hard tool fatal.
|
|
629
|
-
if (/tool_call_id\s+is\s+not\s+found|tool_call_id\s+not\s+found|unknown\s+tool_call_id/i.test(text)) {
|
|
630
|
-
return { area: "provider", code: "protocol" };
|
|
631
|
-
}
|
|
632
|
-
if (/tool.+timed? out|tool.+timeout/i.test(text))
|
|
633
|
-
return { area: "tool", code: "timeout" };
|
|
634
|
-
if (/\btool\b/i.test(text) && !/tool_call_id/i.test(text))
|
|
635
|
-
return { area: "tool", code: "fatal" };
|
|
636
|
-
if (/network|fetch failed|connection|socket|websocket|timed? out|timeout|dns|econn|^terminated$/i.test(text)) {
|
|
637
|
-
return { area: "provider", code: "network" };
|
|
638
|
-
}
|
|
639
|
-
return { area: "provider", code: "protocol" };
|
|
640
|
-
}
|
|
641
|
-
_classifyPreflightCause(message) {
|
|
642
|
-
if (!this.model || /no model|model selected|model is required/i.test(message)) {
|
|
643
|
-
return { area: "configuration", code: "invalid" };
|
|
644
|
-
}
|
|
645
|
-
if (isQuotaExhaustionMessage(message)) {
|
|
646
|
-
return { area: "provider", code: "rate_limit" };
|
|
647
|
-
}
|
|
648
|
-
if (/auth|api key|unauthori[sz]ed|forbidden|401|403|\/login/i.test(message)) {
|
|
649
|
-
return { area: "provider", code: "auth" };
|
|
650
|
-
}
|
|
651
|
-
if (/context.+overflow|context window|too many tokens/i.test(message)) {
|
|
652
|
-
return { area: "provider", code: "context_overflow" };
|
|
653
|
-
}
|
|
654
|
-
if (/duplicate.?result/i.test(message))
|
|
655
|
-
return { area: "transcript", code: "duplicate_result" };
|
|
656
|
-
if (/orphan.?result/i.test(message))
|
|
657
|
-
return { area: "transcript", code: "orphan_result" };
|
|
658
|
-
if (/duplicate.?call/i.test(message))
|
|
659
|
-
return { area: "transcript", code: "duplicate_call_id" };
|
|
660
|
-
if (/transcript|missing.?result/i.test(message))
|
|
661
|
-
return { area: "transcript", code: "missing_result" };
|
|
662
|
-
if (/compaction/i.test(message))
|
|
663
|
-
return { area: "compaction", code: "failed" };
|
|
664
|
-
if (/fsync/i.test(message))
|
|
665
|
-
return { area: "persistence", code: "fsync_failed" };
|
|
666
|
-
if (/lock/i.test(message))
|
|
667
|
-
return { area: "persistence", code: "lock_failed" };
|
|
668
|
-
if (/append|persist|write/i.test(message))
|
|
669
|
-
return { area: "persistence", code: "append_failed" };
|
|
670
|
-
if (/tool/i.test(message))
|
|
671
|
-
return { area: "tool", code: "fatal" };
|
|
672
|
-
return { area: "internal", code: "unclassified" };
|
|
673
|
-
}
|
|
674
507
|
_classifyRunTermination(runId, event) {
|
|
675
508
|
const timestamp = new Date().toISOString();
|
|
676
509
|
let assistant;
|
|
@@ -699,11 +532,11 @@ export class AgentSession {
|
|
|
699
532
|
}
|
|
700
533
|
else if (assistant.stopReason === "aborted") {
|
|
701
534
|
cause = this._userAbortRequested ? { area: "user", code: "abort" } : { area: "provider", code: "abort" };
|
|
702
|
-
message =
|
|
535
|
+
message = terminationMessage(assistant.errorMessage, this._userAbortRequested ? "The user aborted the run." : "The provider aborted the run.");
|
|
703
536
|
}
|
|
704
537
|
else if (assistant.stopReason === "error") {
|
|
705
|
-
cause = this.
|
|
706
|
-
message =
|
|
538
|
+
cause = providerFailureCause(assistant, this.model?.contextWindow ?? 0);
|
|
539
|
+
message = terminationMessage(assistant.errorMessage, "The provider request failed.");
|
|
707
540
|
}
|
|
708
541
|
else {
|
|
709
542
|
cause = { area: "completed" };
|
|
@@ -733,24 +566,8 @@ export class AgentSession {
|
|
|
733
566
|
this._lastTermination = termination;
|
|
734
567
|
this._emit({ type: "session_termination", termination });
|
|
735
568
|
}
|
|
736
|
-
_runtimeFailureCause(error) {
|
|
737
|
-
if (this._pendingRuntimeTerminationCause)
|
|
738
|
-
return this._pendingRuntimeTerminationCause;
|
|
739
|
-
const code = typeof error === "object" && error !== null && "code" in error ? Reflect.get(error, "code") : undefined;
|
|
740
|
-
if (typeof code === "string" &&
|
|
741
|
-
new Set(["EACCES", "EDQUOT", "EFBIG", "EIO", "EISDIR", "EMFILE", "ENFILE", "ENOSPC", "EPERM", "EROFS"]).has(code)) {
|
|
742
|
-
return { area: "persistence", code: "append_failed" };
|
|
743
|
-
}
|
|
744
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
745
|
-
if (/compaction.+stale|session changed during compaction/i.test(message)) {
|
|
746
|
-
return { area: "compaction", code: "stale" };
|
|
747
|
-
}
|
|
748
|
-
if (/compaction/i.test(message))
|
|
749
|
-
return { area: "compaction", code: "failed" };
|
|
750
|
-
return { area: "internal", code: "unclassified" };
|
|
751
|
-
}
|
|
752
569
|
_publishRuntimeFailure(error) {
|
|
753
|
-
const cause = this.
|
|
570
|
+
const cause = this._pendingRuntimeTerminationCause ?? runtimeFailureCause(error);
|
|
754
571
|
const runId = this._activeRunId ?? `runtime-${randomUUID()}`;
|
|
755
572
|
const timestamp = new Date().toISOString();
|
|
756
573
|
let message = "The AgentSession runtime failed before completing the run.";
|
|
@@ -915,7 +732,7 @@ export class AgentSession {
|
|
|
915
732
|
throw new Error(formatNoApiKeyFoundMessage(model.provider));
|
|
916
733
|
}
|
|
917
734
|
async _getCompactionRequestAuth(model) {
|
|
918
|
-
if (this.agent.streamFn
|
|
735
|
+
if (isBuiltinStreamFn(this.agent.streamFn)) {
|
|
919
736
|
return this._getRequiredRequestAuth(model);
|
|
920
737
|
}
|
|
921
738
|
const result = await this._modelRegistry.getApiKeyAndHeaders(model);
|
|
@@ -1130,6 +947,11 @@ export class AgentSession {
|
|
|
1130
947
|
}
|
|
1131
948
|
else if (event.type === "agent_end") {
|
|
1132
949
|
await this._extensionRunner.emit({ type: "agent_end", messages: event.messages });
|
|
950
|
+
// `agent_end` fires once per attempt. Extensions that release per-run
|
|
951
|
+
// state need the boundary no retry follows, so mark it explicitly.
|
|
952
|
+
if (!this._willRetryAfterAgentEnd(event)) {
|
|
953
|
+
await this._extensionRunner.emit({ type: "agent_settled", messages: event.messages });
|
|
954
|
+
}
|
|
1133
955
|
}
|
|
1134
956
|
else if (event.type === "turn_start") {
|
|
1135
957
|
this._turnMetricsState = {
|
|
@@ -1694,12 +1516,12 @@ export class AgentSession {
|
|
|
1694
1516
|
}
|
|
1695
1517
|
}
|
|
1696
1518
|
catch (error) {
|
|
1697
|
-
outcome =
|
|
1698
|
-
this._userAbortRequested || (error instanceof Error && /abort/i.test(error.message)) ? "aborted" : "failed";
|
|
1519
|
+
outcome = "failed";
|
|
1699
1520
|
this._publishRuntimeFailure(error);
|
|
1700
1521
|
throw error;
|
|
1701
1522
|
}
|
|
1702
1523
|
finally {
|
|
1524
|
+
outcome = promptSettlement.resolvePromptSettlementOutcome(outcome, this._lastTermination?.kind);
|
|
1703
1525
|
if (resourceLease !== null) {
|
|
1704
1526
|
// Generation-safe: a stale release after another run acquired the
|
|
1705
1527
|
// lease is a no-op instead of clobbering the newer cap (§8.1).
|
|
@@ -1720,15 +1542,15 @@ export class AgentSession {
|
|
|
1720
1542
|
*/
|
|
1721
1543
|
_emitPromptSettledIfReady(input) {
|
|
1722
1544
|
try {
|
|
1723
|
-
let state = createPromptSettlementState(input.promptRunId, input.startedAtEpochMs);
|
|
1724
|
-
state = reducePromptSettlement(state, { kind: "terminal", outcome: input.outcome });
|
|
1545
|
+
let state = promptSettlement.createPromptSettlementState(input.promptRunId, input.startedAtEpochMs);
|
|
1546
|
+
state = promptSettlement.reducePromptSettlement(state, { kind: "terminal", outcome: input.outcome });
|
|
1725
1547
|
if (this.isStreaming) {
|
|
1726
|
-
state = reducePromptSettlement(state, { kind: "tool", delta: 1 });
|
|
1548
|
+
state = promptSettlement.reducePromptSettlement(state, { kind: "tool", delta: 1 });
|
|
1727
1549
|
}
|
|
1728
1550
|
if (this.agent.hasQueuedMessages()) {
|
|
1729
|
-
state = reducePromptSettlement(state, { kind: "continuation", delta: 1 });
|
|
1551
|
+
state = promptSettlement.reducePromptSettlement(state, { kind: "continuation", delta: 1 });
|
|
1730
1552
|
}
|
|
1731
|
-
const settled = settlePromptIfReady(state, Date.now());
|
|
1553
|
+
const settled = promptSettlement.settlePromptIfReady(state, Date.now());
|
|
1732
1554
|
if (settled.event !== null) {
|
|
1733
1555
|
input.resourceObservations?.record("prompt_settled_v1", settledObservationFacts(settled.event));
|
|
1734
1556
|
this._emit(settled.event);
|
|
@@ -2017,7 +1839,7 @@ export class AgentSession {
|
|
|
2017
1839
|
// Emit input event for extension interception (before skill/template expansion)
|
|
2018
1840
|
let currentImages = options?.images;
|
|
2019
1841
|
if (this._extensionRunner.hasHandlers("input")) {
|
|
2020
|
-
const inputResult = await this._extensionRunner.emitInput(currentText, currentImages, options?.source ?? "interactive", this.isStreaming ? options?.streamingBehavior : undefined);
|
|
1842
|
+
const inputResult = await this._extensionRunner.emitInput(currentText, currentImages, options?.source ?? "interactive", this.isStreaming || this.isRetrying ? options?.streamingBehavior : undefined);
|
|
2021
1843
|
if (inputResult.action === "handled") {
|
|
2022
1844
|
preflightResult?.(true);
|
|
2023
1845
|
return;
|
|
@@ -2034,8 +1856,8 @@ export class AgentSession {
|
|
|
2034
1856
|
expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);
|
|
2035
1857
|
}
|
|
2036
1858
|
expandedText = redactSensitiveText(expandedText);
|
|
2037
|
-
//
|
|
2038
|
-
if (this.isStreaming) {
|
|
1859
|
+
// While a run or its retry backoff owns the session, queue instead of starting a competing top-level prompt.
|
|
1860
|
+
if (this.isStreaming || this.isRetrying) {
|
|
2039
1861
|
if (!options?.streamingBehavior) {
|
|
2040
1862
|
throw new Error("Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message.");
|
|
2041
1863
|
}
|
|
@@ -2143,14 +1965,14 @@ export class AgentSession {
|
|
|
2143
1965
|
catch (error) {
|
|
2144
1966
|
preflightResult?.(false);
|
|
2145
1967
|
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
2146
|
-
const cause = this.
|
|
1968
|
+
const cause = preflightFailureCause(rawMessage, Boolean(this.model));
|
|
2147
1969
|
const timestamp = new Date().toISOString();
|
|
2148
1970
|
this._publishTermination(classifySessionTermination({
|
|
2149
1971
|
sessionId: this.sessionId,
|
|
2150
1972
|
runId: `preflight-${randomUUID()}`,
|
|
2151
1973
|
timestamp,
|
|
2152
1974
|
source: "observed",
|
|
2153
|
-
message:
|
|
1975
|
+
message: terminationMessage(rawMessage, "Prompt preflight failed."),
|
|
2154
1976
|
cause,
|
|
2155
1977
|
sideEffects: "none",
|
|
2156
1978
|
...(this.model ? { provider: this.model.provider, model: this.model.id } : {}),
|
|
@@ -2532,7 +2354,7 @@ export class AgentSession {
|
|
|
2532
2354
|
}
|
|
2533
2355
|
async _cycleAvailableModel(direction) {
|
|
2534
2356
|
const resilience = resolveProviderResilience(this.settingsManager.getProviderResilienceSettings());
|
|
2535
|
-
const raw =
|
|
2357
|
+
const raw = this._modelRegistry.getAvailable();
|
|
2536
2358
|
// Hard-kill sticky safety models from the cycle list (Fable must not re-enter via hotkey).
|
|
2537
2359
|
const availableModels = resilience.blockStickySafetyModels
|
|
2538
2360
|
? raw.filter((m) => !isStickySafetyModel(m.id, m.provider))
|
|
@@ -2736,8 +2558,8 @@ export class AgentSession {
|
|
|
2736
2558
|
/**
|
|
2737
2559
|
* Context-pressure band 0..3 from the projected token estimate over the
|
|
2738
2560
|
* model context window (reuses estimateProjectedContextTokens). 0..<0.5,
|
|
2739
|
-
* 1..<0.75, 2..<0.9, 3..>=0.9.
|
|
2740
|
-
*
|
|
2561
|
+
* 1..<0.75, 2..<0.9, 3..>=0.9. The released default pressure coefficient
|
|
2562
|
+
* is 1 and participates only after the classifier has prompt evidence.
|
|
2741
2563
|
*/
|
|
2742
2564
|
_computePressureBucket() {
|
|
2743
2565
|
const contextWindow = this.model?.contextWindow ?? 0;
|
|
@@ -2986,6 +2808,25 @@ export class AgentSession {
|
|
|
2986
2808
|
});
|
|
2987
2809
|
return model;
|
|
2988
2810
|
}
|
|
2811
|
+
/**
|
|
2812
|
+
* Authenticated failover candidates for compaction summarization, in
|
|
2813
|
+
* resilience-chain order, excluding the primary compaction model itself.
|
|
2814
|
+
* Used when the primary model's quota is exhausted (same-model retry is
|
|
2815
|
+
* useless until reset; another provider can still save the compaction).
|
|
2816
|
+
*/
|
|
2817
|
+
_compactionFailoverModels(primary) {
|
|
2818
|
+
const candidates = resolveFailoverCandidates(this.settingsManager.getProviderResilienceSettings());
|
|
2819
|
+
const available = this._modelRegistry.getAvailable();
|
|
2820
|
+
const models = [];
|
|
2821
|
+
for (const candidate of candidates) {
|
|
2822
|
+
if (candidate.provider === primary.provider && candidate.id === primary.id)
|
|
2823
|
+
continue;
|
|
2824
|
+
const resolved = available.find((m) => m.provider === candidate.provider && m.id === candidate.id);
|
|
2825
|
+
if (resolved)
|
|
2826
|
+
models.push(resolved);
|
|
2827
|
+
}
|
|
2828
|
+
return models;
|
|
2829
|
+
}
|
|
2989
2830
|
/**
|
|
2990
2831
|
* Manually compact the session context.
|
|
2991
2832
|
* Aborts current agent operation first.
|
|
@@ -3046,7 +2887,7 @@ export class AgentSession {
|
|
|
3046
2887
|
}
|
|
3047
2888
|
else {
|
|
3048
2889
|
// Generate compaction result
|
|
3049
|
-
const result = await compact(preparation, compactionModel, apiKey, headers, customInstructions, this._compactionAbortController.signal, this.thinkingLevel, this.agent.streamFn, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason: "manual" }));
|
|
2890
|
+
const result = await compact(preparation, compactionModel, apiKey, headers, customInstructions, this._compactionAbortController.signal, this.thinkingLevel, this.agent.streamFn, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason: "manual" }), this._compactionFailoverModels(compactionModel));
|
|
3050
2891
|
summary = result.summary;
|
|
3051
2892
|
firstKeptEntryId = result.firstKeptEntryId;
|
|
3052
2893
|
tokensBefore = result.tokensBefore;
|
|
@@ -3089,13 +2930,15 @@ export class AgentSession {
|
|
|
3089
2930
|
compactionCode = "aborted";
|
|
3090
2931
|
else if (stale)
|
|
3091
2932
|
compactionCode = "stale";
|
|
2933
|
+
else if (isQuotaExhaustionMessage(message))
|
|
2934
|
+
compactionCode = "quota_exhausted";
|
|
3092
2935
|
const timestamp = new Date().toISOString();
|
|
3093
2936
|
this._publishTermination(classifySessionTermination({
|
|
3094
2937
|
sessionId: this.sessionId,
|
|
3095
2938
|
runId: `compaction-${randomUUID()}`,
|
|
3096
2939
|
timestamp,
|
|
3097
2940
|
source: "observed",
|
|
3098
|
-
message:
|
|
2941
|
+
message: terminationMessage(message, "Manual compaction failed."),
|
|
3099
2942
|
cause: { area: "compaction", code: compactionCode },
|
|
3100
2943
|
sideEffects: committedCompaction ? "confirmed" : "none",
|
|
3101
2944
|
...(this.model ? { provider: this.model.provider, model: this.model.id } : {}),
|
|
@@ -3142,7 +2985,7 @@ export class AgentSession {
|
|
|
3142
2985
|
/**
|
|
3143
2986
|
* Effective context window for the upcoming turn.
|
|
3144
2987
|
* Image-bearing turns with a text-only session model are auto-routed to the
|
|
3145
|
-
* vision model (gpt-5.6-luna,
|
|
2988
|
+
* vision model (gpt-5.6-luna, 1M) — that window is the real limit. Text-only
|
|
3146
2989
|
* turns keep the session model's (typically much larger) window.
|
|
3147
2990
|
*/
|
|
3148
2991
|
_effectiveTurnContextWindow(pendingMessages, sessionWindow) {
|
|
@@ -3305,7 +3148,7 @@ export class AgentSession {
|
|
|
3305
3148
|
const compactionModel = this._resolveCompactionModel(this.model);
|
|
3306
3149
|
let apiKey;
|
|
3307
3150
|
let headers;
|
|
3308
|
-
if (this.agent.streamFn
|
|
3151
|
+
if (isBuiltinStreamFn(this.agent.streamFn)) {
|
|
3309
3152
|
const authResult = await this._modelRegistry.getApiKeyAndHeaders(compactionModel);
|
|
3310
3153
|
if (!authResult.ok || !authResult.apiKey) {
|
|
3311
3154
|
const providerLabel = compactionModel.provider;
|
|
@@ -3377,7 +3220,7 @@ export class AgentSession {
|
|
|
3377
3220
|
}
|
|
3378
3221
|
else {
|
|
3379
3222
|
// Generate compaction result
|
|
3380
|
-
const compactResult = await compact(preparation, compactionModel, apiKey, headers, undefined, this._autoCompactionAbortController.signal, this.thinkingLevel, this.agent.streamFn, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason }));
|
|
3223
|
+
const compactResult = await compact(preparation, compactionModel, apiKey, headers, undefined, this._autoCompactionAbortController.signal, this.thinkingLevel, this.agent.streamFn, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason }), this._compactionFailoverModels(compactionModel));
|
|
3381
3224
|
summary = compactResult.summary;
|
|
3382
3225
|
firstKeptEntryId = compactResult.firstKeptEntryId;
|
|
3383
3226
|
tokensBefore = compactResult.tokensBefore;
|
|
@@ -3992,6 +3835,41 @@ export class AgentSession {
|
|
|
3992
3835
|
// setModel itself blocks sticky targets, not sources — safe.
|
|
3993
3836
|
await this.setModel(next);
|
|
3994
3837
|
}
|
|
3838
|
+
/**
|
|
3839
|
+
* Rotate to another authenticated provider route serving the SAME model
|
|
3840
|
+
* family (e.g. openrouter/stealth/ox-alpha ↔ opencode-go/ox-alpha-free ↔
|
|
3841
|
+
* opencode/x-preview-f-free). Used when the current route fails with an
|
|
3842
|
+
* upstream availability error — same-model retry would hammer a dead
|
|
3843
|
+
* endpoint while the identical model is one route away. Visited and
|
|
3844
|
+
* unauthenticated routes are marked in {@link _refusedModels} so repeat
|
|
3845
|
+
* failures advance the rotation within the turn.
|
|
3846
|
+
*/
|
|
3847
|
+
async _maybeRotateModelRoutes() {
|
|
3848
|
+
const current = this.model;
|
|
3849
|
+
if (!current)
|
|
3850
|
+
return undefined;
|
|
3851
|
+
const candidates = sameModelRouteCandidates(current, this._modelRegistry.getAvailable());
|
|
3852
|
+
for (const candidate of candidates) {
|
|
3853
|
+
const key = failoverModelKey(candidate.provider, candidate.id);
|
|
3854
|
+
if (this._refusedModels.has(key))
|
|
3855
|
+
continue;
|
|
3856
|
+
const next = this._modelRegistry.find(candidate.provider, candidate.id);
|
|
3857
|
+
if (!next || !this._modelRegistry.hasConfiguredAuth(next)) {
|
|
3858
|
+
this._refusedModels.add(key);
|
|
3859
|
+
continue;
|
|
3860
|
+
}
|
|
3861
|
+
try {
|
|
3862
|
+
await this.setModel(next);
|
|
3863
|
+
// The old route just failed upstream — keep it out of this turn's retries.
|
|
3864
|
+
this._refusedModels.add(failoverModelKey(current.provider, current.id));
|
|
3865
|
+
return `${next.provider}/${next.id}`;
|
|
3866
|
+
}
|
|
3867
|
+
catch {
|
|
3868
|
+
this._refusedModels.add(key);
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3871
|
+
return undefined;
|
|
3872
|
+
}
|
|
3995
3873
|
/**
|
|
3996
3874
|
* Content/safety stops (stop_reason=refusal) are often false positives on coding turns
|
|
3997
3875
|
* for Fable AND Claude Opus/Sonnet. Retrying the same model usually reprints the refusal —
|
|
@@ -4053,12 +3931,19 @@ export class AgentSession {
|
|
|
4053
3931
|
if (attempt === undefined)
|
|
4054
3932
|
return false;
|
|
4055
3933
|
this._retryAttempt = attempt;
|
|
3934
|
+
// Upstream-unavailable (gateway 5xx / dropped stream): rotate to another
|
|
3935
|
+
// authenticated route of the SAME model family so the retry lands on a
|
|
3936
|
+
// live endpoint instead of hammering the dead one.
|
|
3937
|
+
const rotatedTo = isUpstreamUnavailableMessage(message.errorMessage)
|
|
3938
|
+
? await this._maybeRotateModelRoutes()
|
|
3939
|
+
: undefined;
|
|
4056
3940
|
// Content/safety stop (Fable/Opus/Sonnet): switch model BEFORE delay so retry is not same-model refusal.
|
|
4057
3941
|
const failoverTo = await this._maybeFailoverFromSafetyStop(message);
|
|
3942
|
+
const switchedVia = failoverTo ? `failover ${failoverTo}` : rotatedTo ? `route ${rotatedTo}` : undefined;
|
|
4058
3943
|
// Safety stops are usually immediate false positives — short delay after failover, full backoff otherwise.
|
|
4059
|
-
const delayMs = computeRetryDelayMs(settings.baseDelayMs, attempt,
|
|
4060
|
-
const errorMessage =
|
|
4061
|
-
? `${message.errorMessage || "content/safety stop"} →
|
|
3944
|
+
const delayMs = computeRetryDelayMs(settings.baseDelayMs, attempt, switchedVia !== undefined);
|
|
3945
|
+
const errorMessage = switchedVia
|
|
3946
|
+
? `${message.errorMessage || "content/safety stop"} → ${switchedVia}`
|
|
4062
3947
|
: message.errorMessage || "Unknown error";
|
|
4063
3948
|
this._emit({
|
|
4064
3949
|
type: "auto_retry_start",
|