@bastani/atomic 0.9.12 → 0.9.13-alpha.1
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 +20 -0
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/README.md +5 -12
- package/dist/builtin/intercom/broker/client.ts +11 -2
- package/dist/builtin/intercom/contact-supervisor-tool.ts +13 -3
- package/dist/builtin/intercom/index-heavy.ts +13 -3
- package/dist/builtin/intercom/index.ts +43 -19
- package/dist/builtin/intercom/intercom-utils.ts +15 -29
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/source-ownership.ts +9 -12
- package/dist/builtin/mcp/CHANGELOG.md +6 -0
- package/dist/builtin/mcp/README.md +3 -1
- package/dist/builtin/mcp/index.ts +10 -16
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/mcp/startup-warmup.ts +20 -8
- package/dist/builtin/subagents/CHANGELOG.md +30 -0
- package/dist/builtin/subagents/README.md +22 -30
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/doctor.ts +1 -1
- package/dist/builtin/subagents/src/extension/fanout-child.ts +76 -56
- package/dist/builtin/subagents/src/extension/index.ts +23 -32
- package/dist/builtin/subagents/src/extension/startup-maintenance.ts +25 -44
- package/dist/builtin/subagents/src/intercom/result-intercom.ts +7 -7
- package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +166 -434
- package/dist/builtin/subagents/src/runs/background/notify.ts +29 -8
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-dynamic-step.ts +2 -2
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +4 -4
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-step.ts +2 -2
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +2 -2
- package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +1 -281
- package/dist/builtin/subagents/src/runs/foreground/execution-structured-retries.ts +11 -75
- package/dist/builtin/subagents/src/runs/foreground/inprocess-run-sync.ts +457 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +119 -246
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-chain.ts +1 -1
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +18 -9
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +1 -1
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +4 -4
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +1 -646
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +2 -7
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +5 -5
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +7 -8
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +14 -5
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +158 -93
- package/dist/builtin/subagents/src/runs/inprocess/background-single.ts +179 -0
- package/dist/builtin/subagents/src/runs/inprocess/background.ts +89 -0
- package/dist/builtin/subagents/src/runs/inprocess/child-policy.ts +27 -0
- package/dist/builtin/subagents/src/runs/inprocess/control-registry.ts +55 -0
- package/dist/builtin/subagents/src/runs/inprocess/control-status.ts +106 -0
- package/dist/builtin/subagents/src/runs/inprocess/index.ts +50 -0
- package/dist/builtin/subagents/src/runs/inprocess/nested-routing.ts +218 -0
- package/dist/builtin/subagents/src/runs/{shared/subagent-prompt-runtime.ts → inprocess/prompt-behavior.ts} +37 -75
- package/dist/builtin/subagents/src/runs/inprocess/runner.ts +1138 -0
- package/dist/builtin/subagents/src/runs/{shared/nested-events.ts → inprocess/runtime-support/nested-api.ts} +13 -7
- package/dist/builtin/subagents/src/runs/{shared/nested-events-control.ts → inprocess/runtime-support/nested-control.ts} +18 -17
- package/dist/builtin/subagents/src/runs/{shared/nested-events-core.ts → inprocess/runtime-support/nested-core.ts} +14 -61
- package/dist/builtin/subagents/src/runs/{shared/nested-events-projection.ts → inprocess/runtime-support/nested-projection.ts} +4 -10
- package/dist/builtin/subagents/src/runs/{shared/nested-events-registry.ts → inprocess/runtime-support/nested-registry.ts} +19 -4
- package/dist/builtin/subagents/src/runs/{shared/nested-render.ts → inprocess/runtime-support/nested-rendering.ts} +3 -3
- package/dist/builtin/subagents/src/runs/{shared/nested-events-sanitize.ts → inprocess/runtime-support/nested-sanitize.ts} +3 -3
- package/dist/builtin/subagents/src/runs/inprocess.ts +1 -0
- package/dist/builtin/subagents/src/runs/shared/dynamic-fanout.ts +10 -4
- package/dist/builtin/subagents/src/runs/shared/model-candidate-filter.ts +0 -1
- package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +15 -492
- package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +13 -11
- package/dist/builtin/subagents/src/runs/shared/run-history.ts +3 -5
- package/dist/builtin/subagents/src/runs/shared/single-output.ts +4 -4
- package/dist/builtin/subagents/src/runs/shared/workflow-graph.ts +5 -5
- package/dist/builtin/subagents/src/shared/types-async.ts +0 -1
- package/dist/builtin/subagents/src/shared/types-config.ts +18 -0
- package/dist/builtin/subagents/src/shared/types-results.ts +9 -2
- package/dist/builtin/subagents/src/slash/prompt-template-bridge.ts +2 -3
- package/dist/builtin/subagents/src/slash/slash-live-state.ts +2 -2
- package/dist/builtin/subagents/src/tui/render-chain-graph.ts +10 -4
- package/dist/builtin/subagents/src/tui/render-event-formatting.ts +12 -11
- package/dist/builtin/subagents/src/tui/render-result-compact.ts +49 -12
- package/dist/builtin/subagents/src/tui/render-result.ts +46 -17
- package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -1
- package/dist/builtin/subagents/src/tui/render-status-progress.ts +8 -5
- package/dist/builtin/subagents/src/tui/render-widget-graph.ts +0 -8
- package/dist/builtin/subagents/src/tui/render-widget.ts +0 -24
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +25 -0
- package/dist/builtin/workflows/README.md +13 -3
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/durable/backend.ts +7 -0
- package/dist/builtin/workflows/src/durable/dbos-metadata.ts +11 -1
- package/dist/builtin/workflows/src/durable/resume-runtime.ts +1 -0
- package/dist/builtin/workflows/src/durable/tool-primitive.ts +4 -28
- package/dist/builtin/workflows/src/durable/types.ts +5 -0
- package/dist/builtin/workflows/src/engine/run.ts +17 -1
- package/dist/builtin/workflows/src/extension/atomic-stage-session.ts +12 -39
- package/dist/builtin/workflows/src/extension/config-file-loader.ts +10 -1
- package/dist/builtin/workflows/src/extension/config-loader.ts +1 -1
- package/dist/builtin/workflows/src/extension/dispatcher.ts +4 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +1151 -737
- package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +303 -38
- package/dist/builtin/workflows/src/extension/render-result.ts +4 -0
- package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +6 -3
- package/dist/builtin/workflows/src/extension/runtime.ts +7 -1
- package/dist/builtin/workflows/src/extension/wiring.ts +53 -11
- package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +12 -3
- package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +5 -2
- package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +9 -7
- package/dist/builtin/workflows/src/extension/workflow-status-summary.ts +11 -0
- package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +18 -1
- package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +10 -8
- package/dist/builtin/workflows/src/extension/workflow-tool.ts +9 -4
- package/dist/builtin/workflows/src/runs/background/quit.ts +28 -4
- package/dist/builtin/workflows/src/runs/background/resume-acknowledgements.ts +2 -1
- package/dist/builtin/workflows/src/runs/background/status.ts +55 -8
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +4 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts +3 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +688 -38
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +3 -1
- package/dist/builtin/workflows/src/runs/shared/model-fallback-failures.ts +19 -514
- package/dist/builtin/workflows/src/runs/shared/retry.ts +44 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +5 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +6 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +5 -1
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +5 -0
- package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +5 -0
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +3 -0
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
- package/dist/builtin/workflows/src/shared/run-indicator-status.ts +75 -0
- package/dist/builtin/workflows/src/shared/store-public-types.ts +43 -7
- package/dist/builtin/workflows/src/shared/store-run-methods.ts +42 -8
- package/dist/builtin/workflows/src/shared/store-stage-methods.ts +31 -8
- package/dist/builtin/workflows/src/shared/store-types.ts +34 -0
- package/dist/builtin/workflows/src/shared/timing.ts +10 -0
- package/dist/builtin/workflows/src/tui/chat-surface-message.ts +22 -2
- package/dist/builtin/workflows/src/tui/session-list.ts +1 -1
- package/dist/builtin/workflows/src/tui/session-overlays.ts +14 -10
- package/dist/builtin/workflows/src/tui/session-picker.ts +20 -4
- package/dist/builtin/workflows/src/tui/status-list.ts +31 -47
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +9 -1
- package/dist/builtin/workflows/src/tui/widget.ts +16 -46
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +54 -11
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +49 -14
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +13 -0
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-models.d.ts.map +1 -1
- package/dist/core/agent-session-models.js +12 -1
- package/dist/core/agent-session-models.js.map +1 -1
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +4 -0
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-retry.d.ts +21 -4
- package/dist/core/agent-session-retry.d.ts.map +1 -1
- package/dist/core/agent-session-retry.js +232 -106
- package/dist/core/agent-session-retry.js.map +1 -1
- package/dist/core/agent-session-state.d.ts.map +1 -1
- package/dist/core/agent-session-state.js +2 -1
- package/dist/core/agent-session-state.js.map +1 -1
- package/dist/core/agent-session-tool-hooks.d.ts.map +1 -1
- package/dist/core/agent-session-tool-hooks.js +12 -0
- package/dist/core/agent-session-tool-hooks.js.map +1 -1
- package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
- package/dist/core/agent-session-tool-registry.js +1 -1
- package/dist/core/agent-session-tool-registry.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +3 -1
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts +12 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +7 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +25 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner-context.d.ts +2 -1
- package/dist/core/extensions/runner-context.d.ts.map +1 -1
- package/dist/core/extensions/runner-context.js +4 -0
- package/dist/core/extensions/runner-context.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -2
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +3 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/model-fallback-failures.d.ts +30 -0
- package/dist/core/model-fallback-failures.d.ts.map +1 -0
- package/dist/core/model-fallback-failures.js +610 -0
- package/dist/core/model-fallback-failures.js.map +1 -0
- package/dist/core/retry-policy.d.ts +30 -0
- package/dist/core/retry-policy.d.ts.map +1 -0
- package/dist/core/retry-policy.js +25 -0
- package/dist/core/retry-policy.js.map +1 -0
- package/dist/core/sdk-types.d.ts +8 -2
- package/dist/core/sdk-types.d.ts.map +1 -1
- package/dist/core/sdk-types.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +6 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-core.d.ts +2 -0
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +7 -0
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/index-extensions.d.ts +1 -1
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/docs/intercom.md +5 -10
- package/docs/settings.md +7 -1
- package/docs/subagents.md +19 -19
- package/docs/workflows.md +21 -5
- package/examples/extensions/gondolin/package-lock.json +3 -3
- package/npm-shrinkwrap.json +29 -29
- package/package.json +2 -2
- package/dist/builtin/subagents/src/runs/background/async-event-journal.ts +0 -112
- package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +0 -543
- package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +0 -140
- package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +0 -279
- package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +0 -99
- package/dist/builtin/subagents/src/runs/background/async-execution.ts +0 -17
- package/dist/builtin/subagents/src/runs/background/async-resume.ts +0 -402
- package/dist/builtin/subagents/src/runs/background/async-status.ts +0 -411
- package/dist/builtin/subagents/src/runs/background/completion-claims.ts +0 -196
- package/dist/builtin/subagents/src/runs/background/completion-dedupe.ts +0 -102
- package/dist/builtin/subagents/src/runs/background/parallel-groups.ts +0 -59
- package/dist/builtin/subagents/src/runs/background/result-delivery-processor.ts +0 -300
- package/dist/builtin/subagents/src/runs/background/result-file-claims.ts +0 -166
- package/dist/builtin/subagents/src/runs/background/result-quarantine.ts +0 -77
- package/dist/builtin/subagents/src/runs/background/result-retry-scheduler.ts +0 -48
- package/dist/builtin/subagents/src/runs/background/result-status.ts +0 -87
- package/dist/builtin/subagents/src/runs/background/result-watcher-data.ts +0 -72
- package/dist/builtin/subagents/src/runs/background/result-watcher.ts +0 -320
- package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +0 -105
- package/dist/builtin/subagents/src/runs/background/run-status.ts +0 -358
- package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +0 -457
- package/dist/builtin/subagents/src/runs/background/subagent-runner-dynamic.ts +0 -376
- package/dist/builtin/subagents/src/runs/background/subagent-runner-finalize.ts +0 -150
- package/dist/builtin/subagents/src/runs/background/subagent-runner-output.ts +0 -109
- package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel-helpers.ts +0 -128
- package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel.ts +0 -309
- package/dist/builtin/subagents/src/runs/background/subagent-runner-sequential.ts +0 -173
- package/dist/builtin/subagents/src/runs/background/subagent-runner-state.ts +0 -578
- package/dist/builtin/subagents/src/runs/background/subagent-runner-step.ts +0 -330
- package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +0 -330
- package/dist/builtin/subagents/src/runs/background/subagent-runner-types.ts +0 -210
- package/dist/builtin/subagents/src/runs/background/subagent-runner-utils.ts +0 -69
- package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +0 -90
- package/dist/builtin/subagents/src/runs/background/top-level-async.ts +0 -12
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt-control.ts +0 -140
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +0 -108
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt-types.ts +0 -17
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +0 -558
- package/dist/builtin/subagents/src/runs/shared/attempt-watchdog.ts +0 -126
- package/dist/builtin/subagents/src/runs/shared/final-drain.ts +0 -39
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +0 -339
- package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +0 -165
- package/dist/builtin/subagents/src/runs/shared/spawn-env.ts +0 -21
- package/dist/builtin/subagents/src/shared/post-exit-stdio-guard.ts +0 -86
- /package/dist/builtin/subagents/src/runs/{shared/nested-path.ts → inprocess/runtime-support/nested-paths.ts} +0 -0
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import type { ModelFallbackFailureKind, ModelFallbackFailureSignal, ModelFallbackFailureSource } from "@bastani/atomic";
|
|
2
|
+
import {
|
|
3
|
+
errorMessage,
|
|
4
|
+
isRetryableModelFailure,
|
|
5
|
+
modelFailureMessage,
|
|
6
|
+
normalizeModelFailureSignal,
|
|
7
|
+
} from "@bastani/atomic";
|
|
1
8
|
import {
|
|
2
9
|
type ModelInfo as AvailableModelInfo,
|
|
3
10
|
splitKnownThinkingSuffix,
|
|
@@ -5,12 +12,12 @@ import {
|
|
|
5
12
|
} from "../../shared/model-info.ts";
|
|
6
13
|
import type { Usage } from "../../shared/types.ts";
|
|
7
14
|
|
|
8
|
-
export type { AvailableModelInfo };
|
|
15
|
+
export type { AvailableModelInfo, ModelFallbackFailureKind, ModelFallbackFailureSignal, ModelFallbackFailureSource };
|
|
16
|
+
export { errorMessage, isRetryableModelFailure, modelFailureMessage, normalizeModelFailureSignal };
|
|
9
17
|
|
|
10
18
|
interface ModelAttemptSummary {
|
|
11
19
|
model: string;
|
|
12
20
|
success: boolean;
|
|
13
|
-
exitCode?: number | null;
|
|
14
21
|
error?: string;
|
|
15
22
|
usage?: Usage;
|
|
16
23
|
}
|
|
@@ -21,6 +28,11 @@ function applyFallbackThinkingLevel(model: string, thinkingLevel: string | undef
|
|
|
21
28
|
return thinkingSuffix ? model : `${model}:${thinkingLevel}`;
|
|
22
29
|
}
|
|
23
30
|
|
|
31
|
+
export function applyThinkingSuffix(model: string | undefined, thinking: string | undefined): string | undefined {
|
|
32
|
+
if (!model || !thinking || thinking === "off") return model;
|
|
33
|
+
return applyFallbackThinkingLevel(model, thinking);
|
|
34
|
+
}
|
|
35
|
+
|
|
24
36
|
export function resolveModelCandidate(
|
|
25
37
|
model: string | undefined,
|
|
26
38
|
availableModels: AvailableModelInfo[] | undefined,
|
|
@@ -68,497 +80,8 @@ export function currentModelFullId(model: { provider: string; id: string } | und
|
|
|
68
80
|
return `${String(model.provider)}/${model.id}`;
|
|
69
81
|
}
|
|
70
82
|
|
|
71
|
-
const RETRYABLE_MODEL_FAILURE_PATTERNS: readonly RegExp[] = [
|
|
72
|
-
/rate\s*limit/i,
|
|
73
|
-
/too many requests/i,
|
|
74
|
-
/\b429\b/,
|
|
75
|
-
/quota/i,
|
|
76
|
-
/usage[\s_-]*limit/i, // usage-limit exhaustion is a quota condition (accept space/underscore/hyphen/joined forms); next candidate may have headroom
|
|
77
|
-
/billing/i,
|
|
78
|
-
/credit/i,
|
|
79
|
-
/auth(?:entication)?/i,
|
|
80
|
-
/unauthori[sz]ed/i,
|
|
81
|
-
/\b40[13]\b/,
|
|
82
|
-
/forbidden/i,
|
|
83
|
-
/api key/i,
|
|
84
|
-
/token expired/i,
|
|
85
|
-
/invalid key/i,
|
|
86
|
-
/provider.*unavailable/i,
|
|
87
|
-
/model.*unavailable/i,
|
|
88
|
-
/model.*disabled/i,
|
|
89
|
-
/model.*not found/i,
|
|
90
|
-
/unknown model/i,
|
|
91
|
-
/overloaded/i,
|
|
92
|
-
/service unavailable/i,
|
|
93
|
-
/temporar(?:ily)? unavailable/i,
|
|
94
|
-
/connection refused/i,
|
|
95
|
-
/fetch failed/i,
|
|
96
|
-
/network error/i,
|
|
97
|
-
/socket hang up/i,
|
|
98
|
-
/upstream/i,
|
|
99
|
-
/timed? out/i,
|
|
100
|
-
/timeout/i,
|
|
101
|
-
/\b50[0-4]\b/,
|
|
102
|
-
];
|
|
103
|
-
|
|
104
|
-
const NON_RETRYABLE_FAILURE_PATTERNS: readonly RegExp[] = [
|
|
105
|
-
/command failed/i,
|
|
106
|
-
/tests? failed/i,
|
|
107
|
-
/shell/i,
|
|
108
|
-
/missing file/i,
|
|
109
|
-
/no such file/i,
|
|
110
|
-
/cancel/i,
|
|
111
|
-
/abort/i,
|
|
112
|
-
/interrupted/i,
|
|
113
|
-
];
|
|
114
|
-
|
|
115
|
-
const CANCELLED_FAILURE_PATTERNS: readonly RegExp[] = [/cancel/i, /abort/i, /interrupted/i];
|
|
116
|
-
|
|
117
|
-
export type ModelFallbackFailureKind =
|
|
118
|
-
| "auth_on_candidate_provider"
|
|
119
|
-
| "rate_limit"
|
|
120
|
-
| "provider_unavailable"
|
|
121
|
-
| "network_timeout"
|
|
122
|
-
| "model_unavailable"
|
|
123
|
-
| "request_incompatible"
|
|
124
|
-
| "cancelled"
|
|
125
|
-
| "task_failure"
|
|
126
|
-
| "unknown";
|
|
127
|
-
|
|
128
|
-
export type ModelFallbackFailureSource =
|
|
129
|
-
| "assistant_message"
|
|
130
|
-
| "diagnostic"
|
|
131
|
-
| "throw"
|
|
132
|
-
| "structured"
|
|
133
|
-
| "string_fallback";
|
|
134
|
-
|
|
135
|
-
export interface ModelFallbackFailureSignal {
|
|
136
|
-
readonly kind: ModelFallbackFailureKind;
|
|
137
|
-
readonly message: string;
|
|
138
|
-
readonly source: ModelFallbackFailureSource;
|
|
139
|
-
readonly stopReason?: string;
|
|
140
|
-
readonly status?: number;
|
|
141
|
-
readonly code?: string | number;
|
|
142
|
-
readonly name?: string;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const FALLBACKABLE_FAILURE_KINDS: ReadonlySet<ModelFallbackFailureKind> = new Set([
|
|
146
|
-
"auth_on_candidate_provider",
|
|
147
|
-
"rate_limit",
|
|
148
|
-
"provider_unavailable",
|
|
149
|
-
"network_timeout",
|
|
150
|
-
"model_unavailable",
|
|
151
|
-
"request_incompatible",
|
|
152
|
-
]);
|
|
153
|
-
|
|
154
|
-
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
|
155
|
-
return value !== null && typeof value === "object" ? (value as Record<string, unknown>) : undefined;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function field(value: unknown, key: string): unknown {
|
|
159
|
-
return asRecord(value)?.[key];
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function stringField(value: unknown, key: string): string | undefined {
|
|
163
|
-
const raw = field(value, key);
|
|
164
|
-
return typeof raw === "string" && raw.trim().length > 0 ? raw : undefined;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function errorName(value: unknown): string | undefined {
|
|
168
|
-
return value instanceof Error ? value.name : stringField(value, "name");
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function directMessageFrom(value: unknown): string | undefined {
|
|
172
|
-
return stringField(value, "errorMessage") ?? stringField(value, "message") ?? stringField(value, "statusText");
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function integerFrom(value: unknown): number | undefined {
|
|
176
|
-
if (typeof value === "number" && Number.isInteger(value)) return value;
|
|
177
|
-
if (typeof value !== "string" || value.trim().length === 0) return undefined;
|
|
178
|
-
const parsed = Number(value.trim());
|
|
179
|
-
return Number.isInteger(parsed) ? parsed : undefined;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function statusFrom(value: unknown): number | undefined {
|
|
183
|
-
return (
|
|
184
|
-
integerFrom(field(value, "status")) ??
|
|
185
|
-
integerFrom(field(value, "statusCode")) ??
|
|
186
|
-
integerFrom(field(value, "httpStatus"))
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function codeFrom(value: unknown): string | number | undefined {
|
|
191
|
-
const rawCode = field(value, "code");
|
|
192
|
-
return typeof rawCode === "string" || typeof rawCode === "number" ? rawCode : undefined;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function stopReasonFrom(value: unknown): string | undefined {
|
|
196
|
-
return stringField(value, "stopReason");
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function finishReasonFrom(value: unknown): string | undefined {
|
|
200
|
-
return stringField(value, "finish_reason") ?? stringField(value, "finishReason");
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
function causeOf(value: unknown): unknown {
|
|
204
|
-
return value instanceof Error ? value.cause : field(value, "cause");
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function diagnosticErrors(value: unknown): readonly unknown[] {
|
|
208
|
-
const diagnostics = field(value, "diagnostics");
|
|
209
|
-
if (!Array.isArray(diagnostics)) return [];
|
|
210
|
-
const errors: unknown[] = [];
|
|
211
|
-
for (const diagnostic of diagnostics) {
|
|
212
|
-
const diagnosticError = field(diagnostic, "error");
|
|
213
|
-
errors.push(diagnosticError ?? diagnostic);
|
|
214
|
-
}
|
|
215
|
-
return errors;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
function normalizeCode(value: string | number | undefined): string | undefined {
|
|
219
|
-
if (value === undefined) return undefined;
|
|
220
|
-
const normalized = String(value)
|
|
221
|
-
.trim()
|
|
222
|
-
.toLowerCase()
|
|
223
|
-
.replace(/[^a-z0-9]+/g, "_")
|
|
224
|
-
.replace(/^_+|_+$/g, "");
|
|
225
|
-
return normalized.length > 0 ? normalized : undefined;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function kindFromStatus(status: number | undefined): ModelFallbackFailureKind | undefined {
|
|
229
|
-
switch (status) {
|
|
230
|
-
case 400:
|
|
231
|
-
case 413:
|
|
232
|
-
case 422:
|
|
233
|
-
return "request_incompatible";
|
|
234
|
-
case 401:
|
|
235
|
-
case 403:
|
|
236
|
-
return "auth_on_candidate_provider";
|
|
237
|
-
case 408:
|
|
238
|
-
return "network_timeout";
|
|
239
|
-
case 404:
|
|
240
|
-
return "model_unavailable";
|
|
241
|
-
case 429:
|
|
242
|
-
return "rate_limit";
|
|
243
|
-
default:
|
|
244
|
-
if (status !== undefined && status >= 500 && status <= 599) return "provider_unavailable";
|
|
245
|
-
return undefined;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const REQUEST_INCOMPATIBLE_CODES: ReadonlySet<string> = new Set([
|
|
250
|
-
"invalid_request",
|
|
251
|
-
"invalid_request_error",
|
|
252
|
-
"bad_request",
|
|
253
|
-
"context_length_exceeded",
|
|
254
|
-
"request_too_large",
|
|
255
|
-
"too_large",
|
|
256
|
-
"request_entity_too_large",
|
|
257
|
-
"max_tokens",
|
|
258
|
-
"max_context_length",
|
|
259
|
-
"context_window_exceeded",
|
|
260
|
-
]);
|
|
261
|
-
function requestIncompatibleKindFromCode(code: string | number | undefined): ModelFallbackFailureKind | undefined {
|
|
262
|
-
const normalizedCode = normalizeCode(code);
|
|
263
|
-
return normalizedCode !== undefined && REQUEST_INCOMPATIBLE_CODES.has(normalizedCode)
|
|
264
|
-
? "request_incompatible"
|
|
265
|
-
: undefined;
|
|
266
|
-
}
|
|
267
|
-
function refusalKindFromCode(code: string | number | undefined): ModelFallbackFailureKind | undefined {
|
|
268
|
-
const normalizedCode = normalizeCode(code);
|
|
269
|
-
if (normalizedCode === undefined) return undefined;
|
|
270
|
-
if (normalizedCode.includes("content_filter") || normalizedCode.includes("contentfilter")) return "task_failure";
|
|
271
|
-
if (normalizedCode.includes("safety") || normalizedCode.includes("policy")) return "task_failure";
|
|
272
|
-
switch (normalizedCode) {
|
|
273
|
-
case "blocked":
|
|
274
|
-
case "blocked_by_provider":
|
|
275
|
-
case "blocked_by_safety":
|
|
276
|
-
case "blocked_by_policy":
|
|
277
|
-
case "provider_refusal":
|
|
278
|
-
case "refusal":
|
|
279
|
-
case "tool_refusal":
|
|
280
|
-
case "tool_call_refusal":
|
|
281
|
-
case "tool_use_refusal":
|
|
282
|
-
return "task_failure";
|
|
283
|
-
default:
|
|
284
|
-
return undefined;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const CODE_KINDS_BY_KIND: ReadonlyArray<readonly [ModelFallbackFailureKind, ReadonlySet<string>]> = [
|
|
289
|
-
[
|
|
290
|
-
"auth_on_candidate_provider",
|
|
291
|
-
new Set([
|
|
292
|
-
"auth",
|
|
293
|
-
"auth_required",
|
|
294
|
-
"authentication_required",
|
|
295
|
-
"unauthorized",
|
|
296
|
-
"forbidden",
|
|
297
|
-
"invalid_api_key",
|
|
298
|
-
"missing_api_key",
|
|
299
|
-
"invalid_key",
|
|
300
|
-
]),
|
|
301
|
-
],
|
|
302
|
-
[
|
|
303
|
-
"network_timeout",
|
|
304
|
-
new Set([
|
|
305
|
-
"etimedout",
|
|
306
|
-
"econnreset",
|
|
307
|
-
"econnrefused",
|
|
308
|
-
"enotfound",
|
|
309
|
-
"eai_again",
|
|
310
|
-
"fetch_failed",
|
|
311
|
-
"network_error",
|
|
312
|
-
"timeout",
|
|
313
|
-
"timeout_error",
|
|
314
|
-
"und_err_connect_timeout",
|
|
315
|
-
]),
|
|
316
|
-
],
|
|
317
|
-
[
|
|
318
|
-
"rate_limit",
|
|
319
|
-
new Set([
|
|
320
|
-
"rate_limit",
|
|
321
|
-
"rate_limit_exceeded",
|
|
322
|
-
"too_many_requests",
|
|
323
|
-
"quota_exceeded",
|
|
324
|
-
"insufficient_quota",
|
|
325
|
-
"usage_limit",
|
|
326
|
-
"usage_limit_reached",
|
|
327
|
-
"usage_limit_exceeded",
|
|
328
|
-
]),
|
|
329
|
-
],
|
|
330
|
-
["cancelled", new Set(["aborterror", "aborted", "cancelled", "canceled"])],
|
|
331
|
-
["model_unavailable", new Set(["model_not_found", "model_unavailable", "model_disabled", "unknown_model"])],
|
|
332
|
-
[
|
|
333
|
-
"provider_unavailable",
|
|
334
|
-
new Set(["provider_error", "api_error", "service_unavailable", "temporarily_unavailable", "overloaded"]),
|
|
335
|
-
],
|
|
336
|
-
];
|
|
337
|
-
function kindFromCode(code: string | number | undefined): ModelFallbackFailureKind | undefined {
|
|
338
|
-
const normalizedCode = normalizeCode(code);
|
|
339
|
-
if (normalizedCode === undefined) return undefined;
|
|
340
|
-
const refusalKind = refusalKindFromCode(code);
|
|
341
|
-
if (refusalKind !== undefined) return refusalKind;
|
|
342
|
-
const httpStatusKind = kindFromStatus(integerFrom(code));
|
|
343
|
-
if (httpStatusKind !== undefined) return httpStatusKind;
|
|
344
|
-
const requestIncompatibleKind = requestIncompatibleKindFromCode(code);
|
|
345
|
-
if (requestIncompatibleKind !== undefined) return requestIncompatibleKind;
|
|
346
|
-
return CODE_KINDS_BY_KIND.find(([_, codes]) => codes.has(normalizedCode))?.[0];
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const REQUEST_INCOMPATIBLE_FAILURE_PATTERNS: readonly RegExp[] = [
|
|
350
|
-
/\bcontext[_\s-]?(?:length|window)(?:[_\s-]?exceeded)?\b/i,
|
|
351
|
-
/\bmax[_\s-]?(?:context|tokens?)\b/i,
|
|
352
|
-
/\b(?:request(?:[_\s-]?entity)?[_\s-]?too|too)[_\s-]?large\b/i,
|
|
353
|
-
/\b(?:unsupported|unknown|invalid)\s+(?:tool|parameter|function)\b/i,
|
|
354
|
-
/\b(?:tool|parameter|function)\s+(?:not\s+(?:supported|found|allowed)|unknown|invalid)\b/i,
|
|
355
|
-
/\b(?:invalid[_\s-]?request(?:[_\s-]?error)?|bad[_\s-]?request)\b/i,
|
|
356
|
-
];
|
|
357
|
-
const PROVIDER_REFUSAL_FAILURE_PATTERNS: readonly RegExp[] = [
|
|
358
|
-
/\bfinish[_\s-]?reason\b[^\n]*\bcontent[_\s-]?filter\b/i,
|
|
359
|
-
/\bcontent[_\s-]?filter(?:ed|ing)?\b/i,
|
|
360
|
-
/\b(?:safety|policy)\b[^\n]*\b(?:refus(?:e|al|ed|es|ing)?|block(?:ed|ing)?|filter(?:ed|ing)?|violat(?:e|ion|ed|ing)?|disallow(?:ed|ing)?|reject(?:ed|ion|ing)?)\b/i,
|
|
361
|
-
/\b(?:refus(?:e|al|ed|es|ing)?|block(?:ed|ing)?|filter(?:ed|ing)?|violat(?:e|ion|ed|ing)?|disallow(?:ed|ing)?|reject(?:ed|ion|ing)?)\b[^\n]*\b(?:safety|policy)\b/i,
|
|
362
|
-
/\btool[_\s-]?(?:call|use)?[_\s-]?refus(?:e|al|ed|es|ing)?\b/i,
|
|
363
|
-
/\btool(?:\s+call|\s+use)?\b[^\n]*\brefus(?:e|al|ed|es|ing)?\b/i,
|
|
364
|
-
/\brefus(?:e|al|ed|es|ing)?\b[^\n]*\btool(?:\s+call|\s+use)?\b/i,
|
|
365
|
-
/\bprovider[_\s-]?refus(?:e|al|ed|es|ing)?\b/i,
|
|
366
|
-
/\bprovider\b[^\n]*\brefus(?:e|al|ed|es|ing)?\b[^\n]*\b(?:prompt|request|content|policy|safety)\b/i,
|
|
367
|
-
];
|
|
368
|
-
|
|
369
|
-
function refusalKindFromMessage(message: string): ModelFallbackFailureKind | undefined {
|
|
370
|
-
if (CANCELLED_FAILURE_PATTERNS.some((pattern) => pattern.test(message))) return "cancelled";
|
|
371
|
-
if (NON_RETRYABLE_FAILURE_PATTERNS.some((pattern) => pattern.test(message))) return "task_failure";
|
|
372
|
-
if (PROVIDER_REFUSAL_FAILURE_PATTERNS.some((pattern) => pattern.test(message))) return "task_failure";
|
|
373
|
-
return undefined;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
function fallbackKindFromMessage(message: string, name: string | undefined): ModelFallbackFailureKind | undefined {
|
|
377
|
-
const refusalKind = refusalKindFromMessage(message);
|
|
378
|
-
if (refusalKind !== undefined) return refusalKind;
|
|
379
|
-
if (REQUEST_INCOMPATIBLE_FAILURE_PATTERNS.some((pattern) => pattern.test(message))) return "request_incompatible";
|
|
380
|
-
const nameKind = kindFromCode(name);
|
|
381
|
-
if (nameKind !== undefined) return nameKind;
|
|
382
|
-
if (!RETRYABLE_MODEL_FAILURE_PATTERNS.some((pattern) => pattern.test(message))) return undefined;
|
|
383
|
-
if (/rate\s*limit|too many requests|\b429\b|quota|usage[\s_-]*limit|billing|credit/i.test(message))
|
|
384
|
-
return "rate_limit";
|
|
385
|
-
if (/auth|unauthori[sz]ed|\b40[13]\b|api key|token expired|forbidden|invalid key/i.test(message))
|
|
386
|
-
return "auth_on_candidate_provider";
|
|
387
|
-
if (
|
|
388
|
-
/model.*(?:unavailable|disabled|not found|unknown)|(?:unavailable|disabled|not found|unknown).*model/i.test(
|
|
389
|
-
message,
|
|
390
|
-
)
|
|
391
|
-
)
|
|
392
|
-
return "model_unavailable";
|
|
393
|
-
if (/network|fetch failed|socket|connection refused|timeout|timed? out/i.test(message)) return "network_timeout";
|
|
394
|
-
return "provider_unavailable";
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
function signalSource(value: unknown, fallback: ModelFallbackFailureSource | undefined): ModelFallbackFailureSource {
|
|
398
|
-
if (fallback !== undefined) return fallback;
|
|
399
|
-
if (stopReasonFrom(value) !== undefined || diagnosticErrors(value).length > 0) return "assistant_message";
|
|
400
|
-
if (value instanceof Error) return "throw";
|
|
401
|
-
return "structured";
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
function makeSignal(
|
|
405
|
-
kind: ModelFallbackFailureKind,
|
|
406
|
-
value: unknown,
|
|
407
|
-
source: ModelFallbackFailureSource | undefined,
|
|
408
|
-
): ModelFallbackFailureSignal {
|
|
409
|
-
const status = statusFrom(value);
|
|
410
|
-
const code = codeFrom(value);
|
|
411
|
-
const name = errorName(value);
|
|
412
|
-
const stopReason = stopReasonFrom(value);
|
|
413
|
-
return {
|
|
414
|
-
kind,
|
|
415
|
-
message: modelFailureMessage(value),
|
|
416
|
-
source: signalSource(value, source),
|
|
417
|
-
...(stopReason !== undefined ? { stopReason } : {}),
|
|
418
|
-
...(status !== undefined ? { status } : {}),
|
|
419
|
-
...(code !== undefined ? { code } : {}),
|
|
420
|
-
...(name !== undefined ? { name } : {}),
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
function fallbackSignalForMessage(
|
|
425
|
-
message: string | undefined,
|
|
426
|
-
value: unknown,
|
|
427
|
-
source: ModelFallbackFailureSource | undefined,
|
|
428
|
-
): ModelFallbackFailureSignal | undefined {
|
|
429
|
-
if (message === undefined || message.trim().length === 0) return undefined;
|
|
430
|
-
const kind = fallbackKindFromMessage(message, errorName(value));
|
|
431
|
-
return kind === undefined ? undefined : makeSignal(kind, value, source);
|
|
432
|
-
}
|
|
433
|
-
function fallbackSignalFromMessage(
|
|
434
|
-
value: unknown,
|
|
435
|
-
source: ModelFallbackFailureSource | undefined,
|
|
436
|
-
): ModelFallbackFailureSignal | undefined {
|
|
437
|
-
return fallbackSignalForMessage(modelFailureMessage(value), value, source);
|
|
438
|
-
}
|
|
439
|
-
function fallbackSignalFromDirectMessage(
|
|
440
|
-
value: unknown,
|
|
441
|
-
source: ModelFallbackFailureSource | undefined,
|
|
442
|
-
): ModelFallbackFailureSignal | undefined {
|
|
443
|
-
return fallbackSignalForMessage(directMessageFrom(value), value, source);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
function classifyAssistantRefusalSignal(
|
|
447
|
-
value: unknown,
|
|
448
|
-
source: ModelFallbackFailureSource | undefined,
|
|
449
|
-
): ModelFallbackFailureSignal | undefined {
|
|
450
|
-
const codeRefusalKind =
|
|
451
|
-
refusalKindFromCode(codeFrom(value)) ??
|
|
452
|
-
refusalKindFromCode(errorName(value)) ??
|
|
453
|
-
refusalKindFromCode(finishReasonFrom(value));
|
|
454
|
-
if (codeRefusalKind !== undefined) return makeSignal(codeRefusalKind, value, source);
|
|
455
|
-
|
|
456
|
-
const messageRefusalKind = refusalKindFromMessage(directMessageFrom(value) ?? "");
|
|
457
|
-
return messageRefusalKind === undefined ? undefined : makeSignal(messageRefusalKind, value, source);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
function isRefusalSignal(signal: ModelFallbackFailureSignal): boolean {
|
|
461
|
-
return signal.kind === "cancelled" || signal.kind === "task_failure";
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
function structuredSignal(
|
|
465
|
-
value: unknown,
|
|
466
|
-
seen: Set<unknown>,
|
|
467
|
-
source?: ModelFallbackFailureSource,
|
|
468
|
-
): ModelFallbackFailureSignal | undefined {
|
|
469
|
-
if (value === undefined || value === null || seen.has(value)) return undefined;
|
|
470
|
-
if (typeof value === "object") seen.add(value);
|
|
471
|
-
|
|
472
|
-
const stopReason = stopReasonFrom(value)?.toLowerCase();
|
|
473
|
-
if (stopReason === "aborted") return makeSignal("cancelled", value, source);
|
|
474
|
-
|
|
475
|
-
const directRefusalSignal = classifyAssistantRefusalSignal(value, source);
|
|
476
|
-
if (directRefusalSignal !== undefined) return directRefusalSignal;
|
|
477
|
-
|
|
478
|
-
const codeKind = kindFromCode(codeFrom(value));
|
|
479
|
-
const nameKind = kindFromCode(errorName(value));
|
|
480
|
-
if (codeKind === "cancelled" || nameKind === "cancelled") return makeSignal("cancelled", value, source);
|
|
481
|
-
|
|
482
|
-
let firstNestedFallbackSignal: ModelFallbackFailureSignal | undefined;
|
|
483
|
-
const nestedSeen = new Set(seen);
|
|
484
|
-
for (const diagnosticError of diagnosticErrors(value)) {
|
|
485
|
-
const diagnosticSignal =
|
|
486
|
-
structuredSignal(diagnosticError, nestedSeen, "diagnostic") ??
|
|
487
|
-
fallbackSignalFromMessage(diagnosticError, "diagnostic");
|
|
488
|
-
if (diagnosticSignal === undefined) continue;
|
|
489
|
-
if (isRefusalSignal(diagnosticSignal)) return diagnosticSignal;
|
|
490
|
-
firstNestedFallbackSignal ??= diagnosticSignal;
|
|
491
|
-
}
|
|
492
|
-
const cause = causeOf(value);
|
|
493
|
-
const causeSignal = structuredSignal(cause, nestedSeen, source) ?? fallbackSignalFromMessage(cause, source);
|
|
494
|
-
if (causeSignal !== undefined) {
|
|
495
|
-
if (isRefusalSignal(causeSignal)) return causeSignal;
|
|
496
|
-
firstNestedFallbackSignal ??= causeSignal;
|
|
497
|
-
}
|
|
498
|
-
// Direct-message classification runs after nested traversal so a generic wrapper
|
|
499
|
-
// ("invalid request"/"400 bad request") cannot mask a non-retryable nested signal.
|
|
500
|
-
// Kept in the same position as the workflows classifier so the two copies stay
|
|
501
|
-
// behaviorally parallel (see test/unit/model-fallback-classifier-conformance.test.ts).
|
|
502
|
-
const directMessageSignal = fallbackSignalFromDirectMessage(value, source);
|
|
503
|
-
if (directMessageSignal !== undefined) return directMessageSignal;
|
|
504
|
-
const statusKind = kindFromStatus(statusFrom(value));
|
|
505
|
-
if (statusKind !== undefined) return makeSignal(statusKind, value, source);
|
|
506
|
-
if (codeKind !== undefined) return makeSignal(codeKind, value, source);
|
|
507
|
-
if (nameKind !== undefined) return makeSignal(nameKind, value, source);
|
|
508
|
-
if (firstNestedFallbackSignal !== undefined) return firstNestedFallbackSignal;
|
|
509
|
-
if (stopReason === "error") return makeSignal("provider_unavailable", value, source);
|
|
510
|
-
return undefined;
|
|
511
|
-
}
|
|
512
|
-
function messageFromUnknown(value: unknown, seen: Set<unknown>): string | undefined {
|
|
513
|
-
if (value === undefined || value === null || seen.has(value)) return undefined;
|
|
514
|
-
if (typeof value === "string") return value.trim().length > 0 ? value : undefined;
|
|
515
|
-
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
|
|
516
|
-
if (typeof value === "symbol" || typeof value === "function") return undefined;
|
|
517
|
-
seen.add(value);
|
|
518
|
-
if (value instanceof Error && value.message.trim().length > 0) return value.message;
|
|
519
|
-
const directMessage = directMessageFrom(value);
|
|
520
|
-
if (directMessage !== undefined) return directMessage;
|
|
521
|
-
for (const diagnosticError of diagnosticErrors(value)) {
|
|
522
|
-
const diagnosticMessage = messageFromUnknown(diagnosticError, seen);
|
|
523
|
-
if (diagnosticMessage !== undefined) return diagnosticMessage;
|
|
524
|
-
}
|
|
525
|
-
const causeMessage = messageFromUnknown(causeOf(value), seen);
|
|
526
|
-
if (causeMessage !== undefined) return causeMessage;
|
|
527
|
-
const stopReason = stopReasonFrom(value);
|
|
528
|
-
if (stopReason !== undefined) return `Assistant message ended with stopReason:${stopReason}`;
|
|
529
|
-
const finishReason = finishReasonFrom(value);
|
|
530
|
-
if (finishReason !== undefined) return `Model request finished with finish_reason:${finishReason}`;
|
|
531
|
-
const status = statusFrom(value);
|
|
532
|
-
if (status !== undefined) return `Model request failed with status ${status}`;
|
|
533
|
-
const code = codeFrom(value);
|
|
534
|
-
return code !== undefined ? `Model request failed with code ${String(code)}` : undefined;
|
|
535
|
-
}
|
|
536
|
-
export function modelFailureMessage(error: unknown): string {
|
|
537
|
-
const structuredMessage = messageFromUnknown(error, new Set());
|
|
538
|
-
if (structuredMessage !== undefined) return structuredMessage;
|
|
539
|
-
const rendered = String(error);
|
|
540
|
-
return rendered === "[object Object]" ? "Model request failed" : rendered;
|
|
541
|
-
}
|
|
542
|
-
export function normalizeModelFailureSignal(error: unknown): ModelFallbackFailureSignal {
|
|
543
|
-
const structured = structuredSignal(error, new Set());
|
|
544
|
-
if (structured !== undefined) return structured;
|
|
545
|
-
const message = modelFailureMessage(error);
|
|
546
|
-
const name = errorName(error);
|
|
547
|
-
const fallbackKind = message.trim().length > 0 ? fallbackKindFromMessage(message, name) : undefined;
|
|
548
|
-
return {
|
|
549
|
-
kind: fallbackKind ?? "unknown",
|
|
550
|
-
message,
|
|
551
|
-
source: "string_fallback",
|
|
552
|
-
...(name !== undefined ? { name } : {}),
|
|
553
|
-
};
|
|
554
|
-
}
|
|
555
|
-
export function isRetryableModelFailure(error: unknown): boolean {
|
|
556
|
-
if (error === undefined) return false;
|
|
557
|
-
const signal = normalizeModelFailureSignal(error);
|
|
558
|
-
return FALLBACKABLE_FAILURE_KINDS.has(signal.kind);
|
|
559
|
-
}
|
|
560
83
|
export function formatModelAttemptNote(attempt: ModelAttemptSummary, nextModel?: string): string {
|
|
561
|
-
const failure = attempt.error?.trim() ||
|
|
84
|
+
const failure = attempt.error?.trim() || "model failure";
|
|
562
85
|
return nextModel
|
|
563
86
|
? `[fallback] ${attempt.model} failed: ${failure}. Retrying with ${nextModel}.`
|
|
564
87
|
: `[fallback] ${attempt.model} failed: ${failure}.`;
|
|
@@ -108,7 +108,7 @@ export interface ParallelTaskResult {
|
|
|
108
108
|
agent: string;
|
|
109
109
|
taskIndex?: number;
|
|
110
110
|
output: string;
|
|
111
|
-
|
|
111
|
+
status: import("../../shared/types.ts").SubagentAttemptStatus;
|
|
112
112
|
error?: string;
|
|
113
113
|
model?: string;
|
|
114
114
|
fastMode?: boolean;
|
|
@@ -126,17 +126,19 @@ export function aggregateParallelOutputs(
|
|
|
126
126
|
const header = headerFormat(r.taskIndex ?? i, r.agent);
|
|
127
127
|
const hasOutput = Boolean(r.output?.trim());
|
|
128
128
|
const status =
|
|
129
|
-
r.
|
|
129
|
+
r.status === "skipped"
|
|
130
130
|
? "SKIPPED"
|
|
131
|
-
: r.
|
|
132
|
-
?
|
|
133
|
-
: r.error
|
|
134
|
-
? `
|
|
135
|
-
:
|
|
136
|
-
? `
|
|
137
|
-
: !hasOutput &&
|
|
138
|
-
?
|
|
139
|
-
:
|
|
131
|
+
: r.status === "continued"
|
|
132
|
+
? "CONTINUED"
|
|
133
|
+
: r.status === "error"
|
|
134
|
+
? `FAILED${r.error ? `: ${r.error}` : ""}`
|
|
135
|
+
: r.error
|
|
136
|
+
? `WARNING: ${r.error}`
|
|
137
|
+
: !hasOutput && r.outputTargetPath && r.outputTargetExists === false
|
|
138
|
+
? `EMPTY OUTPUT (expected output file missing: ${r.outputTargetPath})`
|
|
139
|
+
: !hasOutput && !r.outputTargetPath
|
|
140
|
+
? "EMPTY OUTPUT (no textual response returned)"
|
|
141
|
+
: "";
|
|
140
142
|
const body = status ? (hasOutput ? `${status}\n${r.output}` : status) : r.output;
|
|
141
143
|
return `${header}\n${body}`;
|
|
142
144
|
})
|
|
@@ -7,9 +7,8 @@ export interface RunEntry {
|
|
|
7
7
|
agent: string;
|
|
8
8
|
task: string;
|
|
9
9
|
ts: number;
|
|
10
|
-
status: "ok" | "error";
|
|
10
|
+
status: "ok" | "error" | "skipped" | "interrupted" | "continued";
|
|
11
11
|
duration: number;
|
|
12
|
-
exit?: number;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
const HISTORY_PATH =
|
|
@@ -18,15 +17,14 @@ const HISTORY_READ_PATHS = getAgentConfigPaths("run-history.jsonl");
|
|
|
18
17
|
const ROTATE_READ_THRESHOLD = 1200;
|
|
19
18
|
const ROTATE_KEEP = 1000;
|
|
20
19
|
|
|
21
|
-
export function recordRun(agent: string, task: string,
|
|
20
|
+
export function recordRun(agent: string, task: string, status: RunEntry["status"], durationMs: number): void {
|
|
22
21
|
try {
|
|
23
22
|
const entry: RunEntry = {
|
|
24
23
|
agent,
|
|
25
24
|
task: task.slice(0, 200),
|
|
26
25
|
ts: Math.floor(Date.now() / 1000),
|
|
27
|
-
status
|
|
26
|
+
status,
|
|
28
27
|
duration: durationMs,
|
|
29
|
-
...(exitCode !== 0 ? { exit: exitCode } : {}),
|
|
30
28
|
};
|
|
31
29
|
fs.mkdirSync(path.dirname(HISTORY_PATH), { recursive: true });
|
|
32
30
|
fs.appendFileSync(HISTORY_PATH, `${JSON.stringify(entry)}\n`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import type { OutputMode, SavedOutputReference } from "../../shared/types.ts";
|
|
3
|
+
import type { OutputMode, SavedOutputReference, SubagentAttemptStatus } from "../../shared/types.ts";
|
|
4
4
|
|
|
5
5
|
export interface SingleOutputSnapshot {
|
|
6
6
|
exists: boolean;
|
|
@@ -147,13 +147,13 @@ export function finalizeSingleOutput(params: {
|
|
|
147
147
|
truncatedOutput?: string;
|
|
148
148
|
outputPath?: string;
|
|
149
149
|
outputMode?: OutputMode;
|
|
150
|
-
|
|
150
|
+
status: SubagentAttemptStatus;
|
|
151
151
|
savedPath?: string;
|
|
152
152
|
outputReference?: SavedOutputReference;
|
|
153
153
|
saveError?: string;
|
|
154
154
|
}): { displayOutput: string; savedPath?: string; outputReference?: SavedOutputReference; saveError?: string } {
|
|
155
155
|
let displayOutput = params.truncatedOutput || params.fullOutput;
|
|
156
|
-
if (params.
|
|
156
|
+
if (params.status === "ok" && params.savedPath) {
|
|
157
157
|
const outputReference = params.outputReference ?? formatSavedOutputReference(params.savedPath, params.fullOutput);
|
|
158
158
|
if (params.outputMode === "file-only") {
|
|
159
159
|
return { displayOutput: outputReference.message, savedPath: params.savedPath, outputReference };
|
|
@@ -161,7 +161,7 @@ export function finalizeSingleOutput(params: {
|
|
|
161
161
|
displayOutput += `\n\n${outputReference.message}`;
|
|
162
162
|
return { displayOutput, savedPath: params.savedPath, outputReference };
|
|
163
163
|
}
|
|
164
|
-
if (params.
|
|
164
|
+
if (params.status === "ok" && params.saveError && params.outputPath) {
|
|
165
165
|
displayOutput += `\n\nOutput file error: ${params.outputPath}\n${params.saveError}`;
|
|
166
166
|
return { displayOutput, saveError: params.saveError };
|
|
167
167
|
}
|
|
@@ -11,7 +11,7 @@ export interface WorkflowGraphBuildInput {
|
|
|
11
11
|
runId: string;
|
|
12
12
|
mode?: SubagentRunMode;
|
|
13
13
|
steps: ChainStep[];
|
|
14
|
-
results?: Array<Pick<SingleResult, "
|
|
14
|
+
results?: Array<Pick<SingleResult, "status" | "detached" | "interrupted" | "error">>;
|
|
15
15
|
currentFlatIndex?: number;
|
|
16
16
|
currentStepIndex?: number;
|
|
17
17
|
stepStatuses?: Array<{ status?: string; error?: string }>;
|
|
@@ -51,12 +51,12 @@ function normalizeStatus(status: string | undefined): WorkflowNodeStatus | undef
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
function resultStatus(
|
|
54
|
-
result: Pick<SingleResult, "
|
|
54
|
+
result: Pick<SingleResult, "status" | "detached" | "interrupted"> | undefined,
|
|
55
55
|
): WorkflowNodeStatus | undefined {
|
|
56
56
|
if (!result) return undefined;
|
|
57
|
-
if (result.detached) return "detached";
|
|
58
|
-
if (result.interrupted) return "paused";
|
|
59
|
-
return result.
|
|
57
|
+
if (result.detached || result.status === "continued") return "detached";
|
|
58
|
+
if (result.interrupted || result.status === "interrupted") return "paused";
|
|
59
|
+
return result.status === "ok" ? "completed" : "failed";
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function nodeStatus(input: WorkflowGraphBuildInput, flatIndex: number): WorkflowNodeStatus {
|