@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
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
StageSnapshot,
|
|
8
8
|
StageStatus,
|
|
9
9
|
ToolNodeSnapshot,
|
|
10
|
+
WorkflowActor,
|
|
10
11
|
WorkflowFailureCode,
|
|
11
12
|
WorkflowFailureDisposition,
|
|
12
13
|
WorkflowFailureKind,
|
|
@@ -406,6 +407,7 @@ export function restoreTerminalRuns(entries: readonly SessionEntry[], store: Sto
|
|
|
406
407
|
...(runMeta.rootRunId !== undefined ? { rootRunId: runMeta.rootRunId } : {}),
|
|
407
408
|
...(runMeta.resumedFromRunId !== undefined ? { resumedFromRunId: runMeta.resumedFromRunId } : {}),
|
|
408
409
|
...(runMeta.resumeFromStageId !== undefined ? { resumeFromStageId: runMeta.resumeFromStageId } : {}),
|
|
410
|
+
...(runMeta.origin !== undefined ? { origin: runMeta.origin } : {}),
|
|
409
411
|
...(runMeta.accumulatedDurationMs !== undefined
|
|
410
412
|
? { accumulatedDurationMs: runMeta.accumulatedDurationMs }
|
|
411
413
|
: {}),
|
|
@@ -481,6 +483,7 @@ export function findRunStartMetadata(
|
|
|
481
483
|
readonly resumedFromRunId?: string;
|
|
482
484
|
readonly resumeFromStageId?: string;
|
|
483
485
|
readonly accumulatedDurationMs?: number;
|
|
486
|
+
readonly origin?: WorkflowActor;
|
|
484
487
|
} {
|
|
485
488
|
for (const entry of entries) {
|
|
486
489
|
if (entry.type !== "workflow.run.start" || entry.payload.runId !== runId) continue;
|
|
@@ -490,6 +493,7 @@ export function findRunStartMetadata(
|
|
|
490
493
|
const resumedFromRunId = entry.payload.resumedFromRunId;
|
|
491
494
|
const resumeFromStageId = entry.payload.resumeFromStageId;
|
|
492
495
|
const accumulatedDurationMs = entry.payload.accumulatedDurationMs;
|
|
496
|
+
const origin = entry.payload.origin;
|
|
493
497
|
return {
|
|
494
498
|
...(typeof parentRunId === "string" ? { parentRunId } : {}),
|
|
495
499
|
...(typeof parentStageId === "string" ? { parentStageId } : {}),
|
|
@@ -501,6 +505,7 @@ export function findRunStartMetadata(
|
|
|
501
505
|
accumulatedDurationMs > 0
|
|
502
506
|
? { accumulatedDurationMs }
|
|
503
507
|
: {}),
|
|
508
|
+
...(origin === "user" || origin === "agent" ? { origin } : {}),
|
|
504
509
|
};
|
|
505
510
|
}
|
|
506
511
|
return {};
|
|
@@ -209,6 +209,7 @@ export function restoreOnSessionStart(
|
|
|
209
209
|
...(runMeta.parentStageId !== undefined ? { parentStageId: runMeta.parentStageId } : {}),
|
|
210
210
|
...(runMeta.rootRunId !== undefined ? { rootRunId: runMeta.rootRunId } : {}),
|
|
211
211
|
...(runMeta.resumedFromRunId !== undefined ? { resumedFromRunId: runMeta.resumedFromRunId } : {}),
|
|
212
|
+
...(runMeta.origin !== undefined ? { origin: runMeta.origin } : {}),
|
|
212
213
|
...(runMeta.resumeFromStageId !== undefined ? { resumeFromStageId: runMeta.resumeFromStageId } : {}),
|
|
213
214
|
...(runMeta.accumulatedDurationMs !== undefined
|
|
214
215
|
? { accumulatedDurationMs: runMeta.accumulatedDurationMs }
|
|
@@ -244,6 +245,7 @@ export function restoreOnSessionStart(
|
|
|
244
245
|
...(runMeta.parentStageId !== undefined ? { parentStageId: runMeta.parentStageId } : {}),
|
|
245
246
|
...(runMeta.rootRunId !== undefined ? { rootRunId: runMeta.rootRunId } : {}),
|
|
246
247
|
...(runMeta.resumedFromRunId !== undefined ? { resumedFromRunId: runMeta.resumedFromRunId } : {}),
|
|
248
|
+
...(runMeta.origin !== undefined ? { origin: runMeta.origin } : {}),
|
|
247
249
|
...(runMeta.resumeFromStageId !== undefined ? { resumeFromStageId: runMeta.resumeFromStageId } : {}),
|
|
248
250
|
...(runMeta.accumulatedDurationMs !== undefined
|
|
249
251
|
? { accumulatedDurationMs: runMeta.accumulatedDurationMs }
|
|
@@ -268,6 +270,7 @@ export function restoreOnSessionStart(
|
|
|
268
270
|
...(runMeta.parentStageId !== undefined ? { parentStageId: runMeta.parentStageId } : {}),
|
|
269
271
|
...(runMeta.rootRunId !== undefined ? { rootRunId: runMeta.rootRunId } : {}),
|
|
270
272
|
...(runMeta.resumedFromRunId !== undefined ? { resumedFromRunId: runMeta.resumedFromRunId } : {}),
|
|
273
|
+
...(runMeta.origin !== undefined ? { origin: runMeta.origin } : {}),
|
|
271
274
|
...(runMeta.resumeFromStageId !== undefined ? { resumeFromStageId: runMeta.resumeFromStageId } : {}),
|
|
272
275
|
...(runMeta.accumulatedDurationMs !== undefined
|
|
273
276
|
? { accumulatedDurationMs: runMeta.accumulatedDurationMs }
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type {
|
|
10
10
|
ToolNodeSnapshot,
|
|
11
|
+
WorkflowActor,
|
|
11
12
|
WorkflowFailureCode,
|
|
12
13
|
WorkflowFailureDisposition,
|
|
13
14
|
WorkflowFailureKind,
|
|
@@ -40,6 +41,8 @@ export interface RunStartPayload {
|
|
|
40
41
|
readonly parentStageId?: string;
|
|
41
42
|
readonly rootRunId?: string;
|
|
42
43
|
readonly resumedFromRunId?: string;
|
|
44
|
+
/** Who launched this run, when the launcher was attributable. */
|
|
45
|
+
readonly origin?: WorkflowActor;
|
|
43
46
|
readonly resumeFromStageId?: string;
|
|
44
47
|
/** Elapsed ms inherited from prior sessions of a resumed run. */
|
|
45
48
|
readonly accumulatedDurationMs?: number;
|
|
@@ -151,6 +154,7 @@ export function appendRunStart(api: PersistenceAPI, payload: RunStartPayload): v
|
|
|
151
154
|
...(payload.parentStageId !== undefined ? { parentStageId: payload.parentStageId } : {}),
|
|
152
155
|
...(payload.rootRunId !== undefined ? { rootRunId: payload.rootRunId } : {}),
|
|
153
156
|
...(payload.resumedFromRunId !== undefined ? { resumedFromRunId: payload.resumedFromRunId } : {}),
|
|
157
|
+
...(payload.origin !== undefined ? { origin: payload.origin } : {}),
|
|
154
158
|
...(payload.resumeFromStageId !== undefined ? { resumeFromStageId: payload.resumeFromStageId } : {}),
|
|
155
159
|
...(payload.accumulatedDurationMs !== undefined ? { accumulatedDurationMs: payload.accumulatedDurationMs } : {}),
|
|
156
160
|
ts: payload.ts,
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { effectiveRunStatus } from "./returned-run-status.js";
|
|
2
|
+
import type { RunSnapshot, RunStatus } from "./store-types.js";
|
|
3
|
+
|
|
4
|
+
/** The status represented by a run's primary indicator. */
|
|
5
|
+
export type RunIndicatorStatus = RunStatus | "awaiting_input";
|
|
6
|
+
|
|
7
|
+
const TERMINAL_OR_BLOCKED = new Set<RunStatus>(["completed", "failed", "killed", "cancelled", "skipped", "blocked"]);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the status represented by a run's primary indicator.
|
|
11
|
+
*
|
|
12
|
+
* A live run with a pending run/stage prompt is awaiting input. When the
|
|
13
|
+
* caller supplies the complete run collection, pending prompts in hidden
|
|
14
|
+
* nested descendants are attributed to the visible ancestor by following
|
|
15
|
+
* `rootRunId` and `parentRunId`. Effective terminal and blocked statuses are
|
|
16
|
+
* authoritative, even when a stale prompt marker remains in a snapshot.
|
|
17
|
+
*/
|
|
18
|
+
export function runIndicatorStatus(run: RunSnapshot, allRuns: readonly RunSnapshot[] = [run]): RunIndicatorStatus {
|
|
19
|
+
const status = effectiveRunStatus(run);
|
|
20
|
+
if (TERMINAL_OR_BLOCKED.has(status)) return status;
|
|
21
|
+
if (runHasPendingInput(run)) return "awaiting_input";
|
|
22
|
+
|
|
23
|
+
const runsById = new Map(allRuns.map((candidate) => [candidate.id, candidate]));
|
|
24
|
+
for (const candidate of allRuns) {
|
|
25
|
+
if (candidate.id === run.id || !runBelongsTo(candidate, run, runsById)) continue;
|
|
26
|
+
const candidateStatus = effectiveRunStatus(candidate);
|
|
27
|
+
if (!TERMINAL_OR_BLOCKED.has(candidateStatus) && runHasPendingInput(candidate)) return "awaiting_input";
|
|
28
|
+
}
|
|
29
|
+
return status;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Precompute the indicator status of each listed run against the complete
|
|
34
|
+
* run collection. The result is plain serializable data, so a surface whose
|
|
35
|
+
* payload is persisted and re-rendered after a session restore (e.g. the
|
|
36
|
+
* `/workflow status` chat entry) keeps hidden-descendant prompt attribution
|
|
37
|
+
* without serializing the hidden run snapshots themselves.
|
|
38
|
+
*/
|
|
39
|
+
export function resolveRunIndicatorStatuses(
|
|
40
|
+
runs: readonly RunSnapshot[],
|
|
41
|
+
allRuns: readonly RunSnapshot[],
|
|
42
|
+
): Readonly<Record<string, RunIndicatorStatus>> {
|
|
43
|
+
const statuses: Record<string, RunIndicatorStatus> = {};
|
|
44
|
+
for (const run of runs) statuses[run.id] = runIndicatorStatus(run, allRuns);
|
|
45
|
+
return statuses;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function runHasPendingInput(run: RunSnapshot): boolean {
|
|
49
|
+
if (run.pendingPrompt !== undefined) return true;
|
|
50
|
+
return run.stages.some(
|
|
51
|
+
(stage) =>
|
|
52
|
+
stage.status === "awaiting_input" ||
|
|
53
|
+
stage.awaitingInputSince !== undefined ||
|
|
54
|
+
stage.pendingPrompt !== undefined ||
|
|
55
|
+
stage.inputRequest !== undefined,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function runBelongsTo(
|
|
60
|
+
candidate: RunSnapshot,
|
|
61
|
+
ancestor: RunSnapshot,
|
|
62
|
+
runsById: ReadonlyMap<string, RunSnapshot>,
|
|
63
|
+
): boolean {
|
|
64
|
+
if (candidate.rootRunId === ancestor.id) return true;
|
|
65
|
+
|
|
66
|
+
const visited = new Set<string>();
|
|
67
|
+
let current: RunSnapshot | undefined = candidate;
|
|
68
|
+
while (current !== undefined && current.parentRunId !== undefined) {
|
|
69
|
+
if (current.parentRunId === ancestor.id) return true;
|
|
70
|
+
if (visited.has(current.id)) return false;
|
|
71
|
+
visited.add(current.id);
|
|
72
|
+
current = runsById.get(current.parentRunId);
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
PendingPrompt,
|
|
3
3
|
PromptKind,
|
|
4
|
+
RunResumeSource,
|
|
4
5
|
RunSnapshot,
|
|
5
6
|
RunStatus,
|
|
6
7
|
StageInputRequest,
|
|
@@ -9,6 +10,7 @@ import type {
|
|
|
9
10
|
StoreSnapshot,
|
|
10
11
|
ToolEvent,
|
|
11
12
|
ToolNodeSnapshot,
|
|
13
|
+
WorkflowActor,
|
|
12
14
|
WorkflowChildRunRef,
|
|
13
15
|
WorkflowFailureCode,
|
|
14
16
|
WorkflowFailureDisposition,
|
|
@@ -33,10 +35,30 @@ export interface RunEndMetadata {
|
|
|
33
35
|
readonly exitReason?: string;
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
export type { RunResumeSource, WorkflowActor } from "./store-types.js";
|
|
39
|
+
|
|
36
40
|
export interface RunPauseMetadata {
|
|
37
41
|
readonly resumable?: boolean;
|
|
38
42
|
readonly exitReason?: string;
|
|
43
|
+
/** Who paused or quit this run. Omitted for internal engine pauses. */
|
|
44
|
+
readonly actor?: WorkflowActor;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface RunResumeMetadata {
|
|
48
|
+
/** Who resumed this run. Omitted for internal engine resumes. */
|
|
49
|
+
readonly actor?: WorkflowActor;
|
|
50
|
+
/**
|
|
51
|
+
* Required so a new call site cannot silently start notifying: every caller
|
|
52
|
+
* states its own path, and only `run_control` is user-visible.
|
|
53
|
+
*/
|
|
54
|
+
readonly source: RunResumeSource;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Attribution for a stage-scoped pause or resume. */
|
|
58
|
+
export interface StageControlMetadata {
|
|
59
|
+
readonly actor?: WorkflowActor;
|
|
39
60
|
}
|
|
61
|
+
|
|
40
62
|
export interface RunBlockedMetadata extends RunEndMetadata {
|
|
41
63
|
readonly failureRecoverability: "recoverable";
|
|
42
64
|
readonly failedStageId: string;
|
|
@@ -214,17 +236,31 @@ export interface Store {
|
|
|
214
236
|
recordStageInputRequest(runId: string, stageId: string, request: StageInputRequest): boolean;
|
|
215
237
|
/** Clear a stage's brokered structured-prompt descriptor. */
|
|
216
238
|
clearStageInputRequest(runId: string, stageId: string): boolean;
|
|
217
|
-
/**
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
239
|
+
/**
|
|
240
|
+
* Mark a stage as `paused` and record `pausedAt`. Metadata on an already-paused
|
|
241
|
+
* stage records attribution alone, so a control path can claim a pause the
|
|
242
|
+
* engine already published.
|
|
243
|
+
*/
|
|
244
|
+
recordStagePaused(runId: string, stageId: string, pausedAt?: number, metadata?: StageControlMetadata): boolean;
|
|
245
|
+
/**
|
|
246
|
+
* Clear `paused`/`blocked` state on a stage and record `resumedAt`. Metadata on
|
|
247
|
+
* an already-running stage records attribution alone.
|
|
248
|
+
*/
|
|
249
|
+
recordStageResumed(runId: string, stageId: string, resumedAt?: number, metadata?: StageControlMetadata): boolean;
|
|
221
250
|
recordStageBlocked(runId: string, stageId: string, blockedBy: string): boolean;
|
|
222
251
|
recordStageUnblocked(runId: string, stageId: string): boolean;
|
|
223
252
|
recordStageNotice(runId: string, stageId: string, notice: StageNotice): boolean;
|
|
224
|
-
/** Mark a run as `paused`. Optional metadata can annotate resumable quit/detach state. */
|
|
253
|
+
/** Mark a run as `paused`. Optional metadata can annotate resumable quit/detach state and attribution. */
|
|
225
254
|
recordRunPaused(runId: string, pausedAt?: number, metadata?: RunPauseMetadata): boolean;
|
|
226
|
-
/**
|
|
227
|
-
|
|
255
|
+
/**
|
|
256
|
+
* Restore a run from `paused` back to `running`.
|
|
257
|
+
*
|
|
258
|
+
* Metadata states which path resumed the run. A run-control resume records its
|
|
259
|
+
* attribution even when an inner engine path already flipped the status, which
|
|
260
|
+
* is the normal order: stage control and the acknowledgement pass both resume
|
|
261
|
+
* the run before public run control returns.
|
|
262
|
+
*/
|
|
263
|
+
recordRunResumed(runId: string, resumedAt?: number, metadata?: RunResumeMetadata): boolean;
|
|
228
264
|
/** Drop every run and notice. */
|
|
229
265
|
clear(): void;
|
|
230
266
|
snapshot(): StoreSnapshot;
|
|
@@ -6,9 +6,15 @@ import {
|
|
|
6
6
|
type StoreContext,
|
|
7
7
|
TERMINAL_STATUSES,
|
|
8
8
|
} from "./store-internal.js";
|
|
9
|
-
import type {
|
|
9
|
+
import type {
|
|
10
|
+
RunBlockedMetadata,
|
|
11
|
+
RunEndMetadata,
|
|
12
|
+
RunPauseMetadata,
|
|
13
|
+
RunResumeMetadata,
|
|
14
|
+
Store,
|
|
15
|
+
} from "./store-public-types.js";
|
|
10
16
|
import type { RunSnapshot, RunStatus, StoreSnapshot, WorkflowNotice } from "./store-types.js";
|
|
11
|
-
import { accumulatePausedDurationMs, elapsedRunMs } from "./timing.js";
|
|
17
|
+
import { accumulatePausedDurationMs, elapsedRunMs, nextControlTimestamp } from "./timing.js";
|
|
12
18
|
import type { WorkflowOutputValues } from "./types.js";
|
|
13
19
|
|
|
14
20
|
type RunStoreMethods = Pick<
|
|
@@ -181,32 +187,60 @@ export function createRunStoreMethods(context: StoreContext): RunStoreMethods {
|
|
|
181
187
|
if (!run) return false;
|
|
182
188
|
if (TERMINAL_STATUSES.has(run.status)) return false;
|
|
183
189
|
const wasPaused = run.status === "paused";
|
|
184
|
-
const enteringQuit = metadata?.exitReason === "quit" && run.exitReason !== "quit";
|
|
185
190
|
if (!wasPaused) {
|
|
186
191
|
run.status = "paused";
|
|
187
|
-
run.pausedAt = pausedAt
|
|
192
|
+
run.pausedAt = nextControlTimestamp(pausedAt, run.resumedAt);
|
|
188
193
|
run.resumedAt = undefined;
|
|
194
|
+
delete run.pauseActor;
|
|
195
|
+
delete run.resumeActor;
|
|
196
|
+
delete run.resumeSource;
|
|
189
197
|
}
|
|
190
198
|
if (metadata?.resumable !== undefined) run.resumable = metadata.resumable;
|
|
191
199
|
if (metadata?.exitReason !== undefined) run.exitReason = metadata.exitReason;
|
|
192
|
-
if (
|
|
200
|
+
if (metadata?.exitReason === "quit" && run.quitAt === undefined)
|
|
201
|
+
run.quitAt = nextControlTimestamp(undefined, run.pausedAt);
|
|
202
|
+
// A control path claims the stop it just performed, even when the engine
|
|
203
|
+
// already published the paused state on its way there.
|
|
204
|
+
if (metadata?.actor !== undefined) run.pauseActor = metadata.actor;
|
|
193
205
|
if (wasPaused && metadata === undefined) return false;
|
|
194
206
|
context.bumpAndNotify();
|
|
195
207
|
return true;
|
|
196
208
|
},
|
|
197
209
|
|
|
198
|
-
recordRunResumed(runId: string, resumedAt?: number): boolean {
|
|
210
|
+
recordRunResumed(runId: string, resumedAt?: number, metadata?: RunResumeMetadata): boolean {
|
|
199
211
|
const run = context.findRun(runId);
|
|
200
212
|
if (!run) return false;
|
|
201
213
|
if (TERMINAL_STATUSES.has(run.status)) return false;
|
|
202
|
-
|
|
203
|
-
|
|
214
|
+
// Run control is the last step of a resume, by which point stage control
|
|
215
|
+
// or the acknowledgement pass has usually flipped the status already.
|
|
216
|
+
// Recording its attribution anyway is what distinguishes a deliberate
|
|
217
|
+
// resume from the engine continuing work on its own.
|
|
218
|
+
const claimsRunControl = metadata?.source === "run_control";
|
|
219
|
+
if (run.status !== "paused") {
|
|
220
|
+
if (!claimsRunControl || run.status !== "running" || run.resumedAt === undefined) return false;
|
|
221
|
+
if (run.resumeSource === "run_control" && run.resumeActor === metadata?.actor) return false;
|
|
222
|
+
run.resumeSource = "run_control";
|
|
223
|
+
if (metadata?.actor === undefined) delete run.resumeActor;
|
|
224
|
+
else run.resumeActor = metadata.actor;
|
|
225
|
+
context.bumpAndNotify();
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
const resumedTs = nextControlTimestamp(resumedAt, run.pausedAt);
|
|
204
229
|
run.status = "running";
|
|
205
230
|
run.pausedDurationMs = accumulatePausedDurationMs(run.pausedDurationMs, run.pausedAt, resumedTs);
|
|
206
231
|
run.resumedAt = resumedTs;
|
|
207
232
|
run.pausedAt = undefined;
|
|
208
233
|
delete run.quitAt;
|
|
209
234
|
delete run.exitReason;
|
|
235
|
+
delete run.pauseActor;
|
|
236
|
+
if (metadata === undefined) {
|
|
237
|
+
delete run.resumeActor;
|
|
238
|
+
delete run.resumeSource;
|
|
239
|
+
} else {
|
|
240
|
+
run.resumeSource = metadata.source;
|
|
241
|
+
if (metadata.actor === undefined) delete run.resumeActor;
|
|
242
|
+
else run.resumeActor = metadata.actor;
|
|
243
|
+
}
|
|
210
244
|
context.bumpAndNotify();
|
|
211
245
|
return true;
|
|
212
246
|
},
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
type StoreContext,
|
|
7
7
|
TERMINAL_STATUSES,
|
|
8
8
|
} from "./store-internal.js";
|
|
9
|
-
import type { Store } from "./store-public-types.js";
|
|
9
|
+
import type { StageControlMetadata, Store } from "./store-public-types.js";
|
|
10
10
|
import { nextExecutionOrder } from "./store-tool-node-methods.js";
|
|
11
11
|
import type { StageInputRequest, StageNotice, StageSnapshot, ToolEvent, WorkflowChildRunRef } from "./store-types.js";
|
|
12
|
-
import { accumulatePausedDurationMs } from "./timing.js";
|
|
12
|
+
import { accumulatePausedDurationMs, nextControlTimestamp } from "./timing.js";
|
|
13
13
|
|
|
14
14
|
type StageStoreMethods = Pick<
|
|
15
15
|
Store,
|
|
@@ -269,29 +269,49 @@ export function createStageStoreMethods(context: StoreContext): StageStoreMethod
|
|
|
269
269
|
return true;
|
|
270
270
|
},
|
|
271
271
|
|
|
272
|
-
recordStagePaused(runId: string, stageId: string, pausedAt?: number): boolean {
|
|
272
|
+
recordStagePaused(runId: string, stageId: string, pausedAt?: number, metadata?: StageControlMetadata): boolean {
|
|
273
273
|
const run = context.findRun(runId);
|
|
274
274
|
if (!run) return false;
|
|
275
275
|
if (TERMINAL_STATUSES.has(run.status)) return false;
|
|
276
276
|
const stage = context.findStage(run, stageId);
|
|
277
277
|
if (!stage) return false;
|
|
278
|
-
if (cannotPause(stage.status))
|
|
278
|
+
if (cannotPause(stage.status)) {
|
|
279
|
+
// Attribution-only claim: the control path paused this stage through
|
|
280
|
+
// the engine and is naming itself afterwards.
|
|
281
|
+
if (stage.status !== "paused" || metadata?.actor === undefined) return false;
|
|
282
|
+
if (stage.pauseActor === metadata.actor) return false;
|
|
283
|
+
stage.pauseActor = metadata.actor;
|
|
284
|
+
context.bumpAndNotify();
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
279
287
|
stage.status = "paused";
|
|
280
|
-
stage.pausedAt = pausedAt
|
|
288
|
+
stage.pausedAt = nextControlTimestamp(pausedAt, stage.resumedAt);
|
|
281
289
|
stage.resumedAt = undefined;
|
|
282
290
|
delete stage.awaitingInputSince;
|
|
291
|
+
delete stage.resumeActor;
|
|
292
|
+
if (metadata?.actor === undefined) delete stage.pauseActor;
|
|
293
|
+
else stage.pauseActor = metadata.actor;
|
|
283
294
|
context.bumpAndNotify();
|
|
284
295
|
return true;
|
|
285
296
|
},
|
|
286
297
|
|
|
287
|
-
recordStageResumed(runId: string, stageId: string, resumedAt?: number): boolean {
|
|
298
|
+
recordStageResumed(runId: string, stageId: string, resumedAt?: number, metadata?: StageControlMetadata): boolean {
|
|
288
299
|
const run = context.findRun(runId);
|
|
289
300
|
if (!run) return false;
|
|
290
301
|
if (TERMINAL_STATUSES.has(run.status)) return false;
|
|
291
302
|
const stage = context.findStage(run, stageId);
|
|
292
303
|
if (!stage) return false;
|
|
293
|
-
if (stage.status !== "paused" && stage.status !== "blocked")
|
|
294
|
-
|
|
304
|
+
if (stage.status !== "paused" && stage.status !== "blocked") {
|
|
305
|
+
// Attribution-only claim, mirroring the paused path above.
|
|
306
|
+
if (stage.status !== "running" || stage.resumedAt === undefined || metadata?.actor === undefined) {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
if (stage.resumeActor === metadata.actor) return false;
|
|
310
|
+
stage.resumeActor = metadata.actor;
|
|
311
|
+
context.bumpAndNotify();
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
const resumedTs = nextControlTimestamp(resumedAt, stage.pausedAt);
|
|
295
315
|
stage.status = "running";
|
|
296
316
|
if (stage.startedAt !== undefined) {
|
|
297
317
|
stage.pausedDurationMs = accumulatePausedDurationMs(stage.pausedDurationMs, stage.pausedAt, resumedTs);
|
|
@@ -300,6 +320,9 @@ export function createStageStoreMethods(context: StoreContext): StageStoreMethod
|
|
|
300
320
|
stage.pausedAt = undefined;
|
|
301
321
|
delete stage.blockedByStageId;
|
|
302
322
|
delete stage.awaitingInputSince;
|
|
323
|
+
delete stage.pauseActor;
|
|
324
|
+
if (metadata?.actor === undefined) delete stage.resumeActor;
|
|
325
|
+
else stage.resumeActor = metadata.actor;
|
|
303
326
|
context.bumpAndNotify();
|
|
304
327
|
return true;
|
|
305
328
|
},
|
|
@@ -261,8 +261,27 @@ export interface StageSnapshot {
|
|
|
261
261
|
pausedAt?: number;
|
|
262
262
|
/** Timestamp recorded on the most recent resume from a paused state. */
|
|
263
263
|
resumedAt?: number;
|
|
264
|
+
/** Who paused this stage. Set only by a deliberate control action. */
|
|
265
|
+
pauseActor?: WorkflowActor;
|
|
266
|
+
/** Who resumed this stage. Set only by a deliberate control action. */
|
|
267
|
+
resumeActor?: WorkflowActor;
|
|
264
268
|
}
|
|
265
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Who performed a workflow lifecycle action. A run's `origin` answers "who
|
|
272
|
+
* launched it"; an actor on a pause, quit, or resume answers "who did this one
|
|
273
|
+
* thing". They differ routinely — the agent starts a run and the user quits it.
|
|
274
|
+
*/
|
|
275
|
+
export type WorkflowActor = "user" | "agent";
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Which code path resumed a run. Only `run_control` is a deliberate control
|
|
279
|
+
* action; the rest continue work already in progress — answering a
|
|
280
|
+
* human-in-the-loop prompt, per-stage control, and the acknowledgement pass —
|
|
281
|
+
* and must never be reported as a lifecycle event of their own.
|
|
282
|
+
*/
|
|
283
|
+
export type RunResumeSource = "run_control" | "prompt_answer" | "stage_control" | "acknowledgement";
|
|
284
|
+
|
|
266
285
|
export interface RunSnapshot {
|
|
267
286
|
readonly id: string;
|
|
268
287
|
readonly name: string;
|
|
@@ -286,6 +305,21 @@ export interface RunSnapshot {
|
|
|
286
305
|
pausedAt?: number;
|
|
287
306
|
/** Timestamp when the run entered resumable quit state; display-only expiry marker. */
|
|
288
307
|
quitAt?: number;
|
|
308
|
+
/**
|
|
309
|
+
* Who paused or quit this run, and who resumed it. A control path records
|
|
310
|
+
* these; the engine's own pauses and resumes leave them unset, which is what
|
|
311
|
+
* keeps an internal continuation from being reported as a user action.
|
|
312
|
+
*/
|
|
313
|
+
pauseActor?: WorkflowActor;
|
|
314
|
+
resumeActor?: WorkflowActor;
|
|
315
|
+
/** Which path performed the most recent resume. */
|
|
316
|
+
resumeSource?: RunResumeSource;
|
|
317
|
+
/**
|
|
318
|
+
* Who launched this run. Set once at dispatch and inherited by a continuation
|
|
319
|
+
* from the run it continues. Absent on legacy and restored runs that never
|
|
320
|
+
* recorded it, in which case attribution is omitted rather than guessed.
|
|
321
|
+
*/
|
|
322
|
+
origin?: WorkflowActor;
|
|
289
323
|
/** Timestamp recorded on the most recent resume from a paused state. */
|
|
290
324
|
resumedAt?: number;
|
|
291
325
|
result?: WorkflowOutputValues;
|
|
@@ -19,6 +19,16 @@ interface RunTimerSnapshot {
|
|
|
19
19
|
function nonNegative(ms: number): number {
|
|
20
20
|
return Math.max(0, ms);
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Return an occurrence timestamp that remains ordered when a clock tick is
|
|
24
|
+
* shared by two deliberate control transitions. Lifecycle notice keys use
|
|
25
|
+
* these timestamps as occurrence identities, so a later transition must not
|
|
26
|
+
* reuse the prior transition's key.
|
|
27
|
+
*/
|
|
28
|
+
export function nextControlTimestamp(requestedAt: number | undefined, previousAt: number | undefined): number {
|
|
29
|
+
const candidate = requestedAt ?? Date.now();
|
|
30
|
+
return previousAt === undefined || candidate > previousAt ? candidate : previousAt + 1;
|
|
31
|
+
}
|
|
22
32
|
|
|
23
33
|
export function rebasedStageStartedAt(accumulatedDurationMs: number | undefined, resumedAt: number): number {
|
|
24
34
|
return resumedAt - nonNegative(accumulatedDurationMs ?? 0);
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
import type { ExtensionAPI } from "../extension/index.js";
|
|
29
29
|
import type { RunDetail } from "../runs/background/status.js";
|
|
30
|
+
import type { RunIndicatorStatus } from "../shared/run-indicator-status.js";
|
|
30
31
|
import type { RunSnapshot } from "../shared/store-types.js";
|
|
31
32
|
import type { WorkflowInputValues } from "../shared/types.js";
|
|
32
33
|
import { renderDispatchConfirm } from "./dispatch-confirm.js";
|
|
@@ -67,6 +68,15 @@ export interface DispatchPayload {
|
|
|
67
68
|
export interface StatusPayload {
|
|
68
69
|
kind: "status";
|
|
69
70
|
runs: readonly RunSnapshot[];
|
|
71
|
+
/**
|
|
72
|
+
* Emit-time indicator status per visible run id, resolved against the
|
|
73
|
+
* complete point-in-time run collection (including hidden nested
|
|
74
|
+
* descendants). Persisted with the payload because chat entries are
|
|
75
|
+
* re-rendered from `details` after a session restore, where the full
|
|
76
|
+
* collection is gone; storing only the derived statuses keeps hidden
|
|
77
|
+
* run snapshots out of the serialized message.
|
|
78
|
+
*/
|
|
79
|
+
indicatorStatuses?: Readonly<Record<string, RunIndicatorStatus>>;
|
|
70
80
|
}
|
|
71
81
|
|
|
72
82
|
/** Workflow catalogue after `/workflow list`. */
|
|
@@ -164,7 +174,12 @@ export function renderChatSurfacePlainText(
|
|
|
164
174
|
return [rendered, `run id: ${payload.runId}`, `inputs: ${formatPlainRecord(payload.inputs)}`].join("\n");
|
|
165
175
|
}
|
|
166
176
|
case "status": {
|
|
167
|
-
const rendered = renderStatusList(payload.runs, {
|
|
177
|
+
const rendered = renderStatusList(payload.runs, {
|
|
178
|
+
width,
|
|
179
|
+
now,
|
|
180
|
+
...themed,
|
|
181
|
+
indicatorStatuses: payload.indicatorStatuses,
|
|
182
|
+
});
|
|
168
183
|
if (payload.runs.length === 0) return rendered;
|
|
169
184
|
return [
|
|
170
185
|
rendered,
|
|
@@ -288,7 +303,12 @@ function renderPayload(payload: ChatSurfacePayload, theme: GraphTheme, width: nu
|
|
|
288
303
|
width,
|
|
289
304
|
});
|
|
290
305
|
case "status":
|
|
291
|
-
return renderStatusList(payload.runs, {
|
|
306
|
+
return renderStatusList(payload.runs, {
|
|
307
|
+
theme,
|
|
308
|
+
width,
|
|
309
|
+
now,
|
|
310
|
+
indicatorStatuses: payload.indicatorStatuses,
|
|
311
|
+
});
|
|
292
312
|
case "list":
|
|
293
313
|
return renderWorkflowList(payload.entries, { theme, width });
|
|
294
314
|
case "detail":
|
|
@@ -34,5 +34,5 @@ export function renderSessionList(runs: readonly RunSnapshot[], opts: SessionLis
|
|
|
34
34
|
toolNodes: graph.tools.map((tool) => structuredClone(tool)),
|
|
35
35
|
};
|
|
36
36
|
});
|
|
37
|
-
return renderStatusList(filtered, { theme: opts.theme, now });
|
|
37
|
+
return renderStatusList(filtered, { theme: opts.theme, now, allRuns: runs });
|
|
38
38
|
}
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
import type { PiCustomComponent, PiCustomOverlayFactoryTui, PiCustomOverlayFunction } from "../extension/wiring.js";
|
|
27
27
|
import type { Store } from "../shared/store.js";
|
|
28
|
-
import {
|
|
28
|
+
import { subscribeStoreInvalidation } from "../shared/store-observation.js";
|
|
29
29
|
import type { GraphTheme } from "./graph-theme.js";
|
|
30
30
|
import {
|
|
31
31
|
createSessionPickerResumeCandidateCache,
|
|
@@ -81,6 +81,7 @@ export function openSessionPicker(
|
|
|
81
81
|
const state = createSessionPickerState();
|
|
82
82
|
let settled = false;
|
|
83
83
|
let unsubscribe: (() => void) | null = null;
|
|
84
|
+
let pickerRevision = 0;
|
|
84
85
|
|
|
85
86
|
const resumeCandidateCache = createSessionPickerResumeCandidateCache();
|
|
86
87
|
|
|
@@ -100,16 +101,16 @@ export function openSessionPicker(
|
|
|
100
101
|
};
|
|
101
102
|
// Re-render on store changes so newly-started runs appear and
|
|
102
103
|
// status icons refresh without the user having to press a key.
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
// invalidation channel carries no snapshot, so a cached one would
|
|
106
|
-
// go stale and newly-started runs would never appear.
|
|
104
|
+
// The picker only needs live run references for rendering; a small local
|
|
105
|
+
// revision keeps resume-probe caching coherent without cloning the store.
|
|
107
106
|
const selectRows = (): ReturnType<typeof selectRunsForPicker> => {
|
|
108
|
-
const
|
|
107
|
+
const liveRuns = store.runs();
|
|
109
108
|
const resumeCandidateLookup =
|
|
110
|
-
intent === "resume"
|
|
109
|
+
intent === "resume"
|
|
110
|
+
? resumeCandidateCache({ runs: liveRuns, notices: store.notices(), version: pickerRevision })
|
|
111
|
+
: undefined;
|
|
111
112
|
return selectRunsForPicker(
|
|
112
|
-
|
|
113
|
+
liveRuns,
|
|
113
114
|
state.query,
|
|
114
115
|
state.includeAll,
|
|
115
116
|
Date.now(),
|
|
@@ -117,11 +118,14 @@ export function openSessionPicker(
|
|
|
117
118
|
resumeCandidateLookup,
|
|
118
119
|
);
|
|
119
120
|
};
|
|
120
|
-
unsubscribe = subscribeStoreInvalidation(store, () =>
|
|
121
|
+
unsubscribe = subscribeStoreInvalidation(store, () => {
|
|
122
|
+
pickerRevision++;
|
|
123
|
+
tui.requestRender?.();
|
|
124
|
+
});
|
|
121
125
|
return {
|
|
122
126
|
render: (width: number) => {
|
|
123
127
|
const rows = selectRows();
|
|
124
|
-
return renderSessionPicker({ width, theme, rows, state });
|
|
128
|
+
return renderSessionPicker({ width, theme, rows, state, allRuns: store.runs() });
|
|
125
129
|
},
|
|
126
130
|
handleInput: (data: string) => {
|
|
127
131
|
const rows = selectRows();
|