From d3c2b3e642fc16eb99405d336ec34aa4e37e57f7 Mon Sep 17 00:00:00 2001 From: Turtle Date: Sat, 3 Oct 2026 10:16:11 +0800 Subject: [PATCH] fix(workflow-run): infer interruption only from crash or fork closers Replace the persisted background marker with a client-only rule. A foreground run writes run-end before its Tool Step ends and a background run outlives that Step, so only a Turn closed after a crash or at a fork boundary shows a run without run-end as interrupted. --- docs/persistence-catalog.i18n.yaml | 44 +++++----- docs/persistence-catalog.md | 29 +++---- docs/persistence-catalog.zh.md | 29 +++---- ...26-10-03-workflow-run-background.i18n.yaml | 28 ------ .../2026-10-03-workflow-run-background.md | 48 ----------- ...-10-03-workflow-run-background.schema.json | 86 ------------------- .../2026-10-03-workflow-run-background.zh.md | 48 ----------- docs/persistence-schema.json | 55 ++++++------ .../client/ui-workflow-run/README.i18n.yaml | 8 +- packages/client/ui-workflow-run/README.md | 5 +- packages/client/ui-workflow-run/README.zh.md | 5 +- .../src/client/workflow-definition.ts | 22 ++--- .../tests/workflow-run.client.spec.tsx | 45 +++++----- .../workflow/tool-workflow/README.i18n.yaml | 4 +- packages/workflow/tool-workflow/README.md | 2 +- packages/workflow/tool-workflow/README.zh.md | 2 +- packages/workflow/tool-workflow/src/index.ts | 15 ++-- packages/workflow/tool-workflow/src/types.ts | 4 +- .../tool-workflow/tests/tool-workflow.spec.ts | 1 - 19 files changed, 129 insertions(+), 351 deletions(-) delete mode 100644 docs/persistence-changes/2026-10-03-workflow-run-background.i18n.yaml delete mode 100644 docs/persistence-changes/2026-10-03-workflow-run-background.md delete mode 100644 docs/persistence-changes/2026-10-03-workflow-run-background.schema.json delete mode 100644 docs/persistence-changes/2026-10-03-workflow-run-background.zh.md diff --git a/docs/persistence-catalog.i18n.yaml b/docs/persistence-catalog.i18n.yaml index 9c8f98adfd..0797c29333 100644 --- a/docs/persistence-catalog.i18n.yaml +++ b/docs/persistence-catalog.i18n.yaml @@ -9,8 +9,8 @@ en: e7c80d1de4d328b4 zh: d9f368c27fd9f998 /session-persistence-event-catalog/persistence-type-fingerprints: - en: 8501cdd466c329a3 - zh: 1fecdaa5349ce427 + en: 33dd28b1c768cd8b + zh: 7256442baf2faed1 /session-persistence-event-catalog/event-envelope: en: 7ebb1a2e0dd1f916 zh: 8946f415dda5c1b8 @@ -252,17 +252,17 @@ en: 1eac7deac6af15f3 zh: 1eac7deac6af15f3 /session-persistence-event-catalog/events/tool-workflow/tool-workflow-agent-end-log-only: - en: 24d01a19ee065fdf - zh: c433d504c2b5d830 + en: 77bc3650fec776c4 + zh: 423c11a52cb11e1a /session-persistence-event-catalog/events/tool-workflow/tool-workflow-agent-start-log-only: - en: a96412f6e5621c77 - zh: 9bd265eb39e18428 + en: 8e131e9c8210d334 + zh: 65059ec0c2f5dc95 /session-persistence-event-catalog/events/tool-workflow/tool-workflow-run-end-log-only: - en: 1d6bcf016a6af399 - zh: 710a56368a33c717 + en: 7d4f9675b83814d3 + zh: 5bfd2fdd82b2f85d /session-persistence-event-catalog/events/tool-workflow/tool-workflow-run-start-log-only: - en: b510118291f55b51 - zh: 26e9b29ed0c0114b + en: b96c096b5ff3e03c + zh: ec6b06357cbc3398 /session-persistence-event-catalog/events/turn: en: d7e8c999a0851a0c zh: d7e8c999a0851a0c @@ -1236,17 +1236,17 @@ en: 12c14727bb7834e2 zh: b0f3c877873c36db /session-persistence-event-catalog/resolved-persistence-types/toolworkflowagentenddata: - en: 8f327cc1f9f2474c - zh: 812e74404c278beb + en: ac394442db02e075 + zh: 3782191860f095f1 /session-persistence-event-catalog/resolved-persistence-types/toolworkflowagentstartdata: - en: debf65304f3ef434 - zh: a3e3d46bdbbf5bca + en: b30d7b45639c4d48 + zh: 97cca691e6952c88 /session-persistence-event-catalog/resolved-persistence-types/toolworkflowrunenddata: - en: 586c57bf172e73d1 - zh: 5d02fcf3992a7011 + en: 4905fd20255fab76 + zh: 46ebc17868537607 /session-persistence-event-catalog/resolved-persistence-types/toolworkflowrunstartdata: - en: 727900992b451c68 - zh: 3c977315869a0a51 + en: 54090e169899c573 + zh: 530ea8d0d0f8cf68 /session-persistence-event-catalog/resolved-persistence-types/turnendcancelcause: en: 544292eddeff5faa zh: 4e36e575a5030fb2 @@ -2019,11 +2019,11 @@ en: 557cbf925d0d118a zh: cdea625fa2ad1c33 /session-persistence-event-catalog/resolved-persistence-types/type-tool-workflow-run-end: - en: 5ed112e5ea7334c4 - zh: 15d0b1188a96fdda + en: bb5da0ee7d289b9c + zh: 2e6703d11142f065 /session-persistence-event-catalog/resolved-persistence-types/type-tool-workflow-run-start: - en: dbaeaf21e1d3cd05 - zh: e7c6da48921f3dad + en: 939c100f8a590003 + zh: b372827fffc17b1c /session-persistence-event-catalog/resolved-persistence-types/type-tool-call: en: 2dc168f9f2bd25d6 zh: d75bd24319468403 diff --git a/docs/persistence-catalog.md b/docs/persistence-catalog.md index 2f6dbfd966..989987d5df 100644 --- a/docs/persistence-catalog.md +++ b/docs/persistence-catalog.md @@ -69,7 +69,7 @@ The [format references](persistence-changes/historical-formats/README.md) cover | `event:tool-workflow/agent-end` | event | `babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7` | [`{ type: "tool-workflow/agent-end" }`](#persistence-type-sha256-babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7) | | `event:tool-workflow/agent-start` | event | `5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627` | [`{ type: "tool-workflow/agent-start" }`](#persistence-type-sha256-5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627) | | `event:tool-workflow/run-end` | event | `42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f` | [`{ type: "tool-workflow/run-end" }`](#persistence-type-sha256-42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f) | -| `event:tool-workflow/run-start` | event | `0dea366b90e202fdbb1a8d79aef14ffc6716b31000e5116309af6ae65d67cecc` | [`{ type: "tool-workflow/run-start" }`](#persistence-type-sha256-0dea366b90e202fdbb1a8d79aef14ffc6716b31000e5116309af6ae65d67cecc) | +| `event:tool-workflow/run-start` | event | `c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058` | [`{ type: "tool-workflow/run-start" }`](#persistence-type-sha256-c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058) | | `event:tool/call` | event | `3b1be838223869fe0a08210db85bf773796ed3f2373ac16555dff227cade0c48` | [`{ type: "tool/call" }`](#persistence-type-sha256-3b1be838223869fe0a08210db85bf773796ed3f2373ac16555dff227cade0c48) | | `event:tool/ptc-dispatch` | event | `100f6dca1468538239522cde3533e5bd721d0f1a7b50bea8b0eb533ea6c96163` | [`{ type: "tool/ptc-dispatch" }`](#persistence-type-sha256-100f6dca1468538239522cde3533e5bd721d0f1a7b50bea8b0eb533ea6c96163) | | `event:tool/ptc-dispatch-start` | event | `ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93` | [`{ type: "tool/ptc-dispatch-start" }`](#persistence-type-sha256-ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93) | @@ -1150,7 +1150,7 @@ Source: [`packages/core/session/src/types.ts:375`](../packages/core/session/src/ 'tool-workflow/agent-end': ToolWorkflowAgentEndData ``` -Source: [`packages/workflow/tool-workflow/src/types.ts:59`](../packages/workflow/tool-workflow/src/types.ts) +Source: [`packages/workflow/tool-workflow/src/types.ts:57`](../packages/workflow/tool-workflow/src/types.ts) @@ -1164,7 +1164,7 @@ Source: [`packages/workflow/tool-workflow/src/types.ts:59`](../packages/workflow 'tool-workflow/agent-start': ToolWorkflowAgentStartData ``` -Source: [`packages/workflow/tool-workflow/src/types.ts:54`](../packages/workflow/tool-workflow/src/types.ts) +Source: [`packages/workflow/tool-workflow/src/types.ts:52`](../packages/workflow/tool-workflow/src/types.ts) @@ -1178,7 +1178,7 @@ Source: [`packages/workflow/tool-workflow/src/types.ts:54`](../packages/workflow 'tool-workflow/run-end': ToolWorkflowRunEndData ``` -Source: [`packages/workflow/tool-workflow/src/types.ts:64`](../packages/workflow/tool-workflow/src/types.ts) +Source: [`packages/workflow/tool-workflow/src/types.ts:62`](../packages/workflow/tool-workflow/src/types.ts) @@ -1187,12 +1187,12 @@ Source: [`packages/workflow/tool-workflow/src/types.ts:64`](../packages/workflow ```ts persistence-catalog /** * Opens one top-level workflow record. - * @param data - stable run identity, display name, and background marker. + * @param data - stable run identity and display name. */ 'tool-workflow/run-start': ToolWorkflowRunStartData ``` -Source: [`packages/workflow/tool-workflow/src/types.ts:49`](../packages/workflow/tool-workflow/src/types.ts) +Source: [`packages/workflow/tool-workflow/src/types.ts:47`](../packages/workflow/tool-workflow/src/types.ts) ### `turn/*` @@ -5014,7 +5014,7 @@ Array of [`ToolSchema`](#persistence-type-sha256-66ba70f6f068da443f969a0b947a013 SHA-256: `c0ea97bc89dfc46fa94eab956f5c3ee6af2f964aa7db6327cb18b451f207bef7` -Sources: [`packages/workflow/tool-workflow/src/types.ts:31`](../packages/workflow/tool-workflow/src/types.ts) +Sources: [`packages/workflow/tool-workflow/src/types.ts:29`](../packages/workflow/tool-workflow/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -5032,7 +5032,7 @@ Sources: [`packages/workflow/tool-workflow/src/types.ts:31`](../packages/workflo SHA-256: `9a410ddf56792b2b7cd4a224a2e54dc4dee30a8e8e6b1c2b9a1d19992b217adc` -Sources: [`packages/workflow/tool-workflow/src/types.ts:22`](../packages/workflow/tool-workflow/src/types.ts) +Sources: [`packages/workflow/tool-workflow/src/types.ts:20`](../packages/workflow/tool-workflow/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -5052,14 +5052,14 @@ Sources: [`packages/workflow/tool-workflow/src/types.ts:22`](../packages/workflo SHA-256: `7f9365bae9fcb73e1e34061a1acfe0422c1a5fd351848cace9bebbe806f28462` -Sources: [`packages/workflow/tool-workflow/src/types.ts:38`](../packages/workflow/tool-workflow/src/types.ts) +Sources: [`packages/workflow/tool-workflow/src/types.ts:36`](../packages/workflow/tool-workflow/src/types.ts) | Property | Presence | Type | |---|---|---| | `runId` | required | `string` | | `stopReason` | required | [`WorkflowStopReason`](#persistence-type-sha256-8465ece5e9d9007c038b357015d849c15262cb0bc25abc59e47692d87ee01a15) | - + @@ -5067,13 +5067,12 @@ Sources: [`packages/workflow/tool-workflow/src/types.ts:38`](../packages/workflo ### `ToolWorkflowRunStartData` -SHA-256: `3cc643a957d3f0b1ecb0db5dcb5326939cdb35afe6a98b3261415b7d3c72e376` +SHA-256: `a6da9ad5d42ae83a6833a8288b076688e8e0801633ea36cbdd8a30a6d9f3160c` Sources: [`packages/workflow/tool-workflow/src/types.ts:14`](../packages/workflow/tool-workflow/src/types.ts) | Property | Presence | Type | |---|---|---| -| `background` | optional | `true` | | `name` | required | `string` | | `runId` | required | `string` | @@ -8567,17 +8566,17 @@ SHA-256: `42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f` | `time` | required | `number` | | `type` | required | `"tool-workflow/run-end"` | - + ### `{ type: "tool-workflow/run-start" }` -SHA-256: `0dea366b90e202fdbb1a8d79aef14ffc6716b31000e5116309af6ae65d67cecc` +SHA-256: `c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058` | Property | Presence | Type | |---|---|---| -| `data` | required | [`ToolWorkflowRunStartData`](#persistence-type-sha256-3cc643a957d3f0b1ecb0db5dcb5326939cdb35afe6a98b3261415b7d3c72e376) | +| `data` | required | [`ToolWorkflowRunStartData`](#persistence-type-sha256-a6da9ad5d42ae83a6833a8288b076688e8e0801633ea36cbdd8a30a6d9f3160c) | | `ignorable` | optional | `true` | | `seq` | required | `number` | | `time` | required | `number` | diff --git a/docs/persistence-catalog.zh.md b/docs/persistence-catalog.zh.md index 75ea865720..295160c5d0 100644 --- a/docs/persistence-catalog.zh.md +++ b/docs/persistence-catalog.zh.md @@ -71,7 +71,7 @@ | `event:tool-workflow/agent-end` | event | `babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7` | [`{ type: "tool-workflow/agent-end" }`](#persistence-type-sha256-babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7) | | `event:tool-workflow/agent-start` | event | `5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627` | [`{ type: "tool-workflow/agent-start" }`](#persistence-type-sha256-5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627) | | `event:tool-workflow/run-end` | event | `42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f` | [`{ type: "tool-workflow/run-end" }`](#persistence-type-sha256-42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f) | -| `event:tool-workflow/run-start` | event | `0dea366b90e202fdbb1a8d79aef14ffc6716b31000e5116309af6ae65d67cecc` | [`{ type: "tool-workflow/run-start" }`](#persistence-type-sha256-0dea366b90e202fdbb1a8d79aef14ffc6716b31000e5116309af6ae65d67cecc) | +| `event:tool-workflow/run-start` | event | `c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058` | [`{ type: "tool-workflow/run-start" }`](#persistence-type-sha256-c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058) | | `event:tool/call` | event | `3b1be838223869fe0a08210db85bf773796ed3f2373ac16555dff227cade0c48` | [`{ type: "tool/call" }`](#persistence-type-sha256-3b1be838223869fe0a08210db85bf773796ed3f2373ac16555dff227cade0c48) | | `event:tool/ptc-dispatch` | event | `100f6dca1468538239522cde3533e5bd721d0f1a7b50bea8b0eb533ea6c96163` | [`{ type: "tool/ptc-dispatch" }`](#persistence-type-sha256-100f6dca1468538239522cde3533e5bd721d0f1a7b50bea8b0eb533ea6c96163) | | `event:tool/ptc-dispatch-start` | event | `ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93` | [`{ type: "tool/ptc-dispatch-start" }`](#persistence-type-sha256-ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93) | @@ -1152,7 +1152,7 @@ export type SessionEvent = { 'tool-workflow/agent-end': ToolWorkflowAgentEndData ``` -来源:[`packages/workflow/tool-workflow/src/types.ts:59`](../packages/workflow/tool-workflow/src/types.ts) +来源:[`packages/workflow/tool-workflow/src/types.ts:57`](../packages/workflow/tool-workflow/src/types.ts) @@ -1166,7 +1166,7 @@ export type SessionEvent = { 'tool-workflow/agent-start': ToolWorkflowAgentStartData ``` -来源:[`packages/workflow/tool-workflow/src/types.ts:54`](../packages/workflow/tool-workflow/src/types.ts) +来源:[`packages/workflow/tool-workflow/src/types.ts:52`](../packages/workflow/tool-workflow/src/types.ts) @@ -1180,7 +1180,7 @@ export type SessionEvent = { 'tool-workflow/run-end': ToolWorkflowRunEndData ``` -来源:[`packages/workflow/tool-workflow/src/types.ts:64`](../packages/workflow/tool-workflow/src/types.ts) +来源:[`packages/workflow/tool-workflow/src/types.ts:62`](../packages/workflow/tool-workflow/src/types.ts) @@ -1189,12 +1189,12 @@ export type SessionEvent = { ```ts persistence-catalog /** * Opens one top-level workflow record. - * @param data - stable run identity, display name, and background marker. + * @param data - stable run identity and display name. */ 'tool-workflow/run-start': ToolWorkflowRunStartData ``` -来源:[`packages/workflow/tool-workflow/src/types.ts:49`](../packages/workflow/tool-workflow/src/types.ts) +来源:[`packages/workflow/tool-workflow/src/types.ts:47`](../packages/workflow/tool-workflow/src/types.ts) ### `turn/*` @@ -5016,7 +5016,7 @@ SHA-256: `a0baff42eb900561f91032b6950a3925cf19c5c8d9ba33948ac69e4ac7dee573` SHA-256: `c0ea97bc89dfc46fa94eab956f5c3ee6af2f964aa7db6327cb18b451f207bef7` -来源:[`packages/workflow/tool-workflow/src/types.ts:31`](../packages/workflow/tool-workflow/src/types.ts) +来源:[`packages/workflow/tool-workflow/src/types.ts:29`](../packages/workflow/tool-workflow/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -5034,7 +5034,7 @@ SHA-256: `c0ea97bc89dfc46fa94eab956f5c3ee6af2f964aa7db6327cb18b451f207bef7` SHA-256: `9a410ddf56792b2b7cd4a224a2e54dc4dee30a8e8e6b1c2b9a1d19992b217adc` -来源:[`packages/workflow/tool-workflow/src/types.ts:22`](../packages/workflow/tool-workflow/src/types.ts) +来源:[`packages/workflow/tool-workflow/src/types.ts:20`](../packages/workflow/tool-workflow/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -5054,14 +5054,14 @@ SHA-256: `9a410ddf56792b2b7cd4a224a2e54dc4dee30a8e8e6b1c2b9a1d19992b217adc` SHA-256: `7f9365bae9fcb73e1e34061a1acfe0422c1a5fd351848cace9bebbe806f28462` -来源:[`packages/workflow/tool-workflow/src/types.ts:38`](../packages/workflow/tool-workflow/src/types.ts) +来源:[`packages/workflow/tool-workflow/src/types.ts:36`](../packages/workflow/tool-workflow/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| | `runId` | 必需 | `string` | | `stopReason` | 必需 | [`WorkflowStopReason`](#persistence-type-sha256-8465ece5e9d9007c038b357015d849c15262cb0bc25abc59e47692d87ee01a15) | - + @@ -5069,13 +5069,12 @@ SHA-256: `7f9365bae9fcb73e1e34061a1acfe0422c1a5fd351848cace9bebbe806f28462` ### `ToolWorkflowRunStartData` -SHA-256: `3cc643a957d3f0b1ecb0db5dcb5326939cdb35afe6a98b3261415b7d3c72e376` +SHA-256: `a6da9ad5d42ae83a6833a8288b076688e8e0801633ea36cbdd8a30a6d9f3160c` 来源:[`packages/workflow/tool-workflow/src/types.ts:14`](../packages/workflow/tool-workflow/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| -| `background` | 可选 | `true` | | `name` | 必需 | `string` | | `runId` | 必需 | `string` | @@ -8569,17 +8568,17 @@ SHA-256: `42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f` | `time` | 必需 | `number` | | `type` | 必需 | `"tool-workflow/run-end"` | - + ### `{ type: "tool-workflow/run-start" }` -SHA-256: `0dea366b90e202fdbb1a8d79aef14ffc6716b31000e5116309af6ae65d67cecc` +SHA-256: `c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058` | 属性 | 存在性 | 类型 | |---|---|---| -| `data` | 必需 | [`ToolWorkflowRunStartData`](#persistence-type-sha256-3cc643a957d3f0b1ecb0db5dcb5326939cdb35afe6a98b3261415b7d3c72e376) | +| `data` | 必需 | [`ToolWorkflowRunStartData`](#persistence-type-sha256-a6da9ad5d42ae83a6833a8288b076688e8e0801633ea36cbdd8a30a6d9f3160c) | | `ignorable` | 可选 | `true` | | `seq` | 必需 | `number` | | `time` | 必需 | `number` | diff --git a/docs/persistence-changes/2026-10-03-workflow-run-background.i18n.yaml b/docs/persistence-changes/2026-10-03-workflow-run-background.i18n.yaml deleted file mode 100644 index a8a2816af3..0000000000 --- a/docs/persistence-changes/2026-10-03-workflow-run-background.i18n.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# Bilingual-pair consistency record for 2026-10-03-workflow-run-background.md (docs/i18n/README.md): per heading -# section, a hash of its English and Chinese blocks outside code blocks and generated regions. -# After editing either side, bring the other along and re-record with: -# pnpm run verify-translation-pairing --write docs/persistence-changes/2026-10-03-workflow-run-background.md -/: - en: 3d5a424ae7d7e46b - zh: c22a8e4a62d8cc1a -/2026-10-03-workflow-run-background: - en: 990aebebf4796f71 - zh: 9ae52c345e6c5537 -/2026-10-03-workflow-run-background/summary: - en: bffd445af628f905 - zh: 6207efcc06c2768d -/2026-10-03-workflow-run-background/table-of-contents: - en: 6cf314a069ceb451 - zh: 9adff678e9ecab3b -/2026-10-03-workflow-run-background/declaration: - en: 6907136f28e48c90 - zh: 02f8298485f3d8e7 -/2026-10-03-workflow-run-background/compatibility: - en: cdcfa251bd45ee28 - zh: 593c290c4ee9b868 -/2026-10-03-workflow-run-background/verification: - en: 0539b2ac90f058bf - zh: 6ead6a707c3b3121 -/2026-10-03-workflow-run-background/dev-note: - en: b75c8458928b72b9 - zh: 003ba4e17b4b5269 diff --git a/docs/persistence-changes/2026-10-03-workflow-run-background.md b/docs/persistence-changes/2026-10-03-workflow-run-background.md deleted file mode 100644 index 7800ebbb7c..0000000000 --- a/docs/persistence-changes/2026-10-03-workflow-run-background.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -description: "Records a persistence type transition and its compatibility acknowledgement." -kind: persistence-change ---- - -# 2026-10-03-workflow-run-background - -English | [中文](2026-10-03-workflow-run-background.zh.md) - -## Summary - -Adds an optional background marker to tool-workflow/run-start. - -## Table of Contents - -- [Declaration](#declaration) -- [Compatibility](#compatibility) -- [Verification](#verification) -- [Dev Note](#dev-note) - - -## Declaration - -```yaml persistence-change -schemaVersion: 1 -id: 2026-10-03-workflow-run-background -baseline: false -changes: - - root: "event:tool-workflow/run-start" - previous: "2026-09-11-initial" - after: "0dea366b90e202fdbb1a8d79aef14ffc6716b31000e5116309af6ae65d67cecc" - decision: same-version -``` - - -## Compatibility - -Existing records remain valid. Writers add the marker only from this change onward: in new records, absence means a foreground run, while background runs recorded earlier also lack it and keep their interrupted presentation after the Tool Step closes. The Web workflow node uses the marker to stop inferring interruption from the closed Tool Step of a run that belongs to a background job. - - -## Verification - -pnpm exec vitest run packages/workflow/tool-workflow/tests packages/client/ui-workflow-run/tests: 70 tests passed. - - -## Dev Note - -None. diff --git a/docs/persistence-changes/2026-10-03-workflow-run-background.schema.json b/docs/persistence-changes/2026-10-03-workflow-run-background.schema.json deleted file mode 100644 index 31699b93a7..0000000000 --- a/docs/persistence-changes/2026-10-03-workflow-run-background.schema.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "formatVersion": 2, - "roots": [ - { - "key": "event:tool-workflow/run-start", - "kind": "event", - "event": "tool-workflow/run-start", - "surface": false, - "digest": "0dea366b90e202fdbb1a8d79aef14ffc6716b31000e5116309af6ae65d67cecc", - "schema": { - "root": 0, - "nodes": [ - { - "kind": "object", - "properties": [ - { - "name": "data", - "type": 1, - "optional": false - }, - { - "name": "ignorable", - "type": 2, - "optional": true - }, - { - "name": "seq", - "type": 4, - "optional": false - }, - { - "name": "time", - "type": 4, - "optional": false - }, - { - "name": "type", - "type": 5, - "optional": false - } - ], - "indices": [] - }, - { - "kind": "object", - "properties": [ - { - "name": "background", - "type": 2, - "optional": true - }, - { - "name": "name", - "type": 3, - "optional": false - }, - { - "name": "runId", - "type": 3, - "optional": false - } - ], - "indices": [] - }, - { - "kind": "literal", - "value": true - }, - { - "kind": "primitive", - "type": "string" - }, - { - "kind": "primitive", - "type": "number" - }, - { - "kind": "literal", - "value": "tool-workflow/run-start" - } - ] - } - } - ], - "types": [] -} diff --git a/docs/persistence-changes/2026-10-03-workflow-run-background.zh.md b/docs/persistence-changes/2026-10-03-workflow-run-background.zh.md deleted file mode 100644 index 131a087b45..0000000000 --- a/docs/persistence-changes/2026-10-03-workflow-run-background.zh.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -description: "记录持久化类型更改及其兼容性确认。" -kind: persistence-change ---- - -# 2026-10-03-workflow-run-background - -[English](2026-10-03-workflow-run-background.md) | 中文 - -## 概述 - -为 tool-workflow/run-start 增加可选的后台标记。 - -## 目录 - -- [声明](#declaration) -- [兼容性](#compatibility) -- [验证](#verification) -- [开发备注](#dev-note) - - -## 声明 - -```yaml persistence-change -schemaVersion: 1 -id: 2026-10-03-workflow-run-background -baseline: false -changes: - - root: "event:tool-workflow/run-start" - previous: "2026-09-11-initial" - after: "0dea366b90e202fdbb1a8d79aef14ffc6716b31000e5116309af6ae65d67cecc" - decision: same-version -``` - - -## 兼容性 - -已有记录仍然有效。写入方从本变更起才写入该标记:新记录中缺失表示前台运行;此前记录的后台运行同样缺少该标记,工具 Step 关闭后仍显示为已中断。Web 工作流节点使用该标记,不再根据已关闭的工具 Step 推断后台作业所属运行已中断。 - - -## 验证 - -pnpm exec vitest run packages/workflow/tool-workflow/tests packages/client/ui-workflow-run/tests:70 个测试通过。 - - -## 开发备注 - -无。 diff --git a/docs/persistence-schema.json b/docs/persistence-schema.json index fd2c22b524..f29dde8245 100644 --- a/docs/persistence-schema.json +++ b/docs/persistence-schema.json @@ -17123,7 +17123,7 @@ "kind": "event", "event": "tool-workflow/run-start", "surface": false, - "digest": "0dea366b90e202fdbb1a8d79aef14ffc6716b31000e5116309af6ae65d67cecc", + "digest": "c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058", "schema": { "root": 0, "nodes": [ @@ -17137,7 +17137,7 @@ }, { "name": "ignorable", - "type": 2, + "type": 3, "optional": true }, { @@ -17161,32 +17161,27 @@ { "kind": "object", "properties": [ - { - "name": "background", - "type": 2, - "optional": true - }, { "name": "name", - "type": 3, + "type": 2, "optional": false }, { "name": "runId", - "type": 3, + "type": 2, "optional": false } ], "indices": [] }, - { - "kind": "literal", - "value": true - }, { "kind": "primitive", "type": "string" }, + { + "kind": "literal", + "value": true + }, { "kind": "primitive", "type": "number" @@ -21959,11 +21954,6 @@ "packages/subagent/tool-subagent/src/model-selection-state.ts:17" ] }, - { - "digest": "0dea366b90e202fdbb1a8d79aef14ffc6716b31000e5116309af6ae65d67cecc", - "names": [], - "sources": [] - }, { "digest": "0e10d7c096b47e61defe372a5fc8bd37d835199410eac44367f95c45082498bd", "names": [], @@ -22712,15 +22702,6 @@ "names": [], "sources": [] }, - { - "digest": "3cc643a957d3f0b1ecb0db5dcb5326939cdb35afe6a98b3261415b7d3c72e376", - "names": [ - "packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunStartData" - ], - "sources": [ - "packages/workflow/tool-workflow/src/types.ts:14" - ] - }, { "digest": "3cfc3a56502da1f8c6153c2c56657bab4b749056968634dd0991d325ec1c919f", "names": [ @@ -23669,7 +23650,7 @@ "packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunEndData" ], "sources": [ - "packages/workflow/tool-workflow/src/types.ts:38" + "packages/workflow/tool-workflow/src/types.ts:36" ] }, { @@ -24070,7 +24051,7 @@ "packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentStartData" ], "sources": [ - "packages/workflow/tool-workflow/src/types.ts:22" + "packages/workflow/tool-workflow/src/types.ts:20" ] }, { @@ -24232,6 +24213,15 @@ "packages/hooks/hook-protocol/src/types.ts:48" ] }, + { + "digest": "a6da9ad5d42ae83a6833a8288b076688e8e0801633ea36cbdd8a30a6d9f3160c", + "names": [ + "packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunStartData" + ], + "sources": [ + "packages/workflow/tool-workflow/src/types.ts:14" + ] + }, { "digest": "a720757f704a2512e9d2f20da4a093e582472176236a75ab8b8eb7aaff17d85a", "names": [], @@ -24679,7 +24669,7 @@ "packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentEndData" ], "sources": [ - "packages/workflow/tool-workflow/src/types.ts:31" + "packages/workflow/tool-workflow/src/types.ts:29" ] }, { @@ -24700,6 +24690,11 @@ "packages/llm/llm/src/types.ts:105" ] }, + { + "digest": "c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058", + "names": [], + "sources": [] + }, { "digest": "c219efbdfd53b836786202ab4532913d555798f0a8615a4e9629736e3799fb70", "names": [], diff --git a/packages/client/ui-workflow-run/README.i18n.yaml b/packages/client/ui-workflow-run/README.i18n.yaml index 923d4a48a7..498bd598e9 100644 --- a/packages/client/ui-workflow-run/README.i18n.yaml +++ b/packages/client/ui-workflow-run/README.i18n.yaml @@ -21,8 +21,8 @@ en: 99b67c86b6cf2031 zh: b3c5e998600525cb /deepseek-ai-dsh-client-ui-workflow-run/use-this-package/state-and-completion: - en: d7b7c401ea53e2ca - zh: 8d3cdbff168d796d + en: de2dbff7df2294ed + zh: 97a03787caf02e2b /deepseek-ai-dsh-client-ui-workflow-run/understand-the-implementation: en: d41b996f3fb6727b zh: 6b40fdf1db894fff @@ -42,8 +42,8 @@ en: ca75c51c89c2c9b0 zh: de54f3467ef3b9be /deepseek-ai-dsh-client-ui-workflow-run/known-limitations-and-deferred-work: - en: c7346285846dd51a - zh: 56d8171fcc6b1d80 + en: d89a3727cfdc9db9 + zh: 42ad9b22bb0c356e /deepseek-ai-dsh-client-ui-workflow-run/known-limitations-and-deferred-work/dev-note: en: e67f633dc6fe7773 zh: 3bb0c20c93f16f98 diff --git a/packages/client/ui-workflow-run/README.md b/packages/client/ui-workflow-run/README.md index 1e14c011f7..0ef9f12cd3 100644 --- a/packages/client/ui-workflow-run/README.md +++ b/packages/client/ui-workflow-run/README.md @@ -33,7 +33,7 @@ Run and phase headers keep 6px gaps between their title, count, and status field ### State and completion -Completion updates the visible status immediately but delays its automatic close while focus remains inside the content. For a foreground run, a closed Turn or Step with missing terminal events presents the affected run or members as interrupted without changing the tool result. A background run outlives its Tool Step, so it stays running until its terminal events arrive. +Completion updates the visible status immediately but delays its automatic close while focus remains inside the content. A run or member without terminal events stays running after its Turn or Step ends normally, because a background run outlives its Tool Step. It is presented as interrupted, without changing the tool result, once its Turn is closed after a crash or at a fork boundary. ----- @@ -86,8 +86,7 @@ None; this package neither assembles nor sends a provider request. These limits define which runs produce records and what the node exposes; they are current package constraints. - **Only top-level calls through `dsh-tool-workflow` produce these records** — nested PTC mode calls and direct `WorkflowEngine` consumers do not. -- **A background run lost without terminal events stays running** — its Step closure carries no liveness fact, and the session log records no job loss after a process crash or after a failed append disables recording for that run. -- **Background runs recorded before the background marker still show as interrupted** — their `tool-workflow/run-start` lacks the marker, so the node treats them as foreground runs. +- **A run lost without terminal events in a normally ended Turn stays running** — for example a background run whose process crashed during a later Turn, or a run whose recording stopped after a failed append; the session log carries no fact that marks it stopped. - **Navigation is intentionally live-only** — terminal members remain visible for review but never expose a cold-session opener from this node. - **The node shows run, phase, member identity, and status only** — scripts, outputs, errors, logs, usage, static topology, and controls remain outside this surface. diff --git a/packages/client/ui-workflow-run/README.zh.md b/packages/client/ui-workflow-run/README.zh.md index 46385ecfee..5c14fe12ad 100644 --- a/packages/client/ui-workflow-run/README.zh.md +++ b/packages/client/ui-workflow-run/README.zh.md @@ -33,7 +33,7 @@ kind: "package-reference" ### 状态与完成 -完成状态会立即更新,但只要焦点仍位于展开内容内,自动折叠就会等待焦点离开。对前台运行,若所属轮次或步骤已关闭但终点事件缺失,界面把相应运行或成员显示为已中断,而不改写工具结果。后台运行的生命周期长于其工具 Step,因此在终点事件到达前保持运行中。 +完成状态会立即更新,但只要焦点仍位于展开内容内,自动折叠就会等待焦点离开。缺少终点事件的运行或成员在所属轮次或步骤正常结束后仍显示为运行中,因为后台运行的生命周期长于其工具 Step。只有当所属轮次在崩溃后或于分叉边界被关闭时,界面才把它们显示为已中断,且不改写工具结果。 ----- @@ -86,8 +86,7 @@ kind: "package-reference" 这些限制定义哪些运行会产生记录、节点暴露什么;它们是当前包约束。 - **只有经 `dsh-tool-workflow` 发起的顶层调用会生成这些记录**:嵌套 PTC mode 调用和直接 `WorkflowEngine` 消费方不会生成。 -- **未写终点事件就丢失的后台运行保持运行中**:其 Step 关闭不表示存活状态,进程崩溃或追加失败停止该运行的记录后,会话日志也不记录作业丢失。 -- **后台标记出现之前记录的后台运行仍显示为已中断**:其 `tool-workflow/run-start` 缺少该标记,节点把它们视为前台运行。 +- **在正常结束的轮次中未写终点事件就丢失的运行保持运行中**:例如进程在之后的轮次中崩溃的后台运行,或追加失败后停止记录的运行;会话日志中没有标记其已停止的事实。 - **导航刻意只面向实时运行**:终态成员继续保留供复盘,但本节点永不为其提供冷会话入口。 - **节点只显示运行、阶段、成员身份与状态**:脚本、输出、错误、日志、用量、静态拓扑与控制操作都不属于本界面。 diff --git a/packages/client/ui-workflow-run/src/client/workflow-definition.ts b/packages/client/ui-workflow-run/src/client/workflow-definition.ts index 2f7adb6ee5..f842cba937 100644 --- a/packages/client/ui-workflow-run/src/client/workflow-definition.ts +++ b/packages/client/ui-workflow-run/src/client/workflow-definition.ts @@ -47,8 +47,6 @@ interface WorkflowMemberState extends Omit interface WorkflowState { readonly name: string - /** A background run outlives its Tool Step, so a closed Location does not imply interruption. */ - readonly background: boolean readonly stopReason?: WorkflowStopReason readonly members: readonly WorkflowMemberState[] } @@ -82,11 +80,16 @@ function statusFromOutcome(outcome: WorkflowAgentOutcome): WorkflowRunStatus { } } -function locationClosed(location: ConversationLocation): boolean { - if (location.kind === 'step') { - return location.step.status === 'closed' || location.turn.status === 'closed' - } - return location.kind === 'turn' && location.turn.status === 'closed' +/** + * A foreground run writes its run-end before its Tool Step ends, and a + * background run outlives that Step, so an ordinary Step or Turn closure says + * nothing about liveness. Only a Turn closed after a crash or at a fork + * boundary proves that a run without run-end stopped. + */ +function turnAbandoned(location: ConversationLocation): boolean { + if (location.kind !== 'step' && location.kind !== 'turn') return false + const reason = location.turn.end?.data.reason.kind + return reason === 'interrupted' || reason === 'forked' } function projectWorkflow( @@ -95,8 +98,7 @@ function projectWorkflow( ): WorkflowRunChatData { const state = context.state as WorkflowState const interrupted = state.stopReason === undefined - && !state.background - && locationClosed(location) + && turnAbandoned(location) const phases = new Map() for (const member of state.members) { const phase = member.phase === undefined ? null : member.phase @@ -165,7 +167,7 @@ export const workflowRunDefinition: ConversationNodeDefinition = if (match.event.type !== 'tool-workflow/run-start') { throw new Error('workflow-run start requires tool-workflow/run-start') } - return { name: match.event.data.name, background: match.event.data.background === true, members: [] } + return { name: match.event.data.name, members: [] } }, update: (context, match) => { if (match.event.type === 'tool-workflow/agent-start') { diff --git a/packages/client/ui-workflow-run/tests/workflow-run.client.spec.tsx b/packages/client/ui-workflow-run/tests/workflow-run.client.spec.tsx index fb27171502..2c13b66721 100644 --- a/packages/client/ui-workflow-run/tests/workflow-run.client.spec.tsx +++ b/packages/client/ui-workflow-run/tests/workflow-run.client.spec.tsx @@ -174,31 +174,13 @@ describe('workflow-run Conversation Definition', () => { expect(workflowData(value)).toEqual(workflowData(assembler(events))) }) - it('shows missing terminal facts as interrupted only after the owning Location closes', () => { + it('keeps a background run running after its Tool Step and Turn end normally', () => { const value = assembler([ at(1, 'turn/start', { turn: 1 }), at(2, 'step/start', { turn: 1, step: 1 }), at(3, 'tool-workflow/run-start', { runId: 'run-1', name: 'audit' }), - at(4, 'tool-workflow/agent-start', { - runId: 'run-1', seq: 1, label: 'worker', childId: 'child-1', - }), - ]) - expect(workflowData(value)?.status).toBe('running') - value.append(at(5, 'step/end', { turn: 1, step: 1 })) - value.flush() - expect(workflowData(value)).toMatchObject({ - status: 'interrupted', - phases: [{ members: [{ status: 'interrupted' }] }], - }) - }) - - it('keeps a background run running after its Tool Step and Turn close', () => { - const value = assembler([ - at(1, 'turn/start', { turn: 1 }), - at(2, 'step/start', { turn: 1, step: 1 }), - at(3, 'tool-workflow/run-start', { runId: 'run-1', name: 'audit', background: true }), at(4, 'step/end', { turn: 1, step: 1 }), - at(5, 'turn/end', { turn: 1, reason: { kind: 'completed' } }), + at(5, 'turn/end', { turn: 1, reason: { kind: 'aborted', reason: { kind: 'user' } } }), at(6, 'tool-workflow/agent-start', { runId: 'run-1', seq: 1, label: 'worker', childId: 'child-1', }), @@ -213,6 +195,27 @@ describe('workflow-run Conversation Definition', () => { expect(workflowData(value)?.status).toBe('completed') }) + it.each(['interrupted', 'forked'] as const)( + 'shows missing terminal facts as interrupted once a %s closer ends the owning Turn', + (kind) => { + const value = assembler([ + at(1, 'turn/start', { turn: 1 }), + at(2, 'step/start', { turn: 1, step: 1 }), + at(3, 'tool-workflow/run-start', { runId: 'run-1', name: 'audit' }), + at(4, 'tool-workflow/agent-start', { + runId: 'run-1', seq: 1, label: 'worker', childId: 'child-1', + }), + ]) + expect(workflowData(value)?.status).toBe('running') + value.append(at(5, 'turn/end', { turn: 1, reason: { kind } })) + value.flush() + expect(workflowData(value)).toMatchObject({ + status: 'interrupted', + phases: [{ members: [{ status: 'interrupted' }] }], + }) + }, + ) + it('retains a zero-member run as its own completed node', () => { const value = assembler([ at(1, 'turn/start', { turn: 1 }), @@ -250,7 +253,7 @@ describe('workflow-run Conversation Definition', () => { at(3, 'tool-workflow/agent-start', { runId: 'turn', seq: 1, label: 'open', childId: 'child-1', }), - at(4, 'turn/end', { turn: 1, reason: { kind: 'completed' } }), + at(4, 'turn/end', { turn: 1, reason: { kind: 'interrupted' } }), ]) expect(workflowData(interruptedTurn)?.status).toBe('interrupted') }) diff --git a/packages/workflow/tool-workflow/README.i18n.yaml b/packages/workflow/tool-workflow/README.i18n.yaml index b75bc93863..8f307582b3 100644 --- a/packages/workflow/tool-workflow/README.i18n.yaml +++ b/packages/workflow/tool-workflow/README.i18n.yaml @@ -42,8 +42,8 @@ en: 35950b2015800ec5 zh: 5ae6f5a5e53dc585 /deepseek-ai-dsh-tool-workflow/understand-the-implementation/durable-session-records: - en: f067ab6fc9a052cd - zh: a5087dc3cd44aae9 + en: e5bbbb7788d6dcdf + zh: aa035f074f7ac021 /deepseek-ai-dsh-tool-workflow/understand-the-implementation/render-intent: en: 389b3740ec1f5ac2 zh: 78430014f5e270e2 diff --git a/packages/workflow/tool-workflow/README.md b/packages/workflow/tool-workflow/README.md index abeb6411dc..5cdadb9ab5 100644 --- a/packages/workflow/tool-workflow/README.md +++ b/packages/workflow/tool-workflow/README.md @@ -75,7 +75,7 @@ A background call registers the run through `jobs.start` inside the job starter, ### Durable session records -For a root transport execution (`exec.parent` absent), the tool projects the run into the calling Agent's Session with four log-only events: run-start after `start()` returns, carrying `background: true` for a background run, member starts and endings filtered by `run.id`, then run-end only after the result is available and disposal reaches quiescence. Nested transport calls execute normally but write no record. The first failed Session append disables later recording for that run with one warning, leaving either no record or a legal continuous prefix without changing the tool result or cleanup. +For a root transport execution (`exec.parent` absent), the tool projects the run into the calling Agent's Session with four log-only events: run-start after `start()` returns, member starts and endings filtered by `run.id`, then run-end only after the result is available and disposal reaches quiescence. Nested transport calls execute normally but write no record. The first failed Session append disables later recording for that run with one warning, leaving either no record or a legal continuous prefix without changing the tool result or cleanup. The engine's `workflow/phase` and `workflow/log` events have no per-line durable surface from this tool: the session log deliberately records run and member lifecycle only, and the Web transcript derives from those records. A background run's lines reach a human through the job observation record instead, which is transient by design. diff --git a/packages/workflow/tool-workflow/README.zh.md b/packages/workflow/tool-workflow/README.zh.md index f73cff56c6..dcc92b352c 100644 --- a/packages/workflow/tool-workflow/README.zh.md +++ b/packages/workflow/tool-workflow/README.zh.md @@ -75,7 +75,7 @@ kind: "package-reference" ### 持久会话记录 -对于根 transport 执行(`exec.parent` 缺省),工具会用四个 log-only 事件把运行投影到调用方 agent 的会话:`start()` 返回后写 run-start(后台运行带 `background: true`),只记录 `run.id` 匹配的成员开始与结束,并且只在结果可用且 dispose 完全停稳后写 run-end。嵌套 transport 调用照常执行,但不写任何记录。会话追加操作首次失败后,本运行会停止后续记录并只告警一次,留下空记录或合法连续前缀,同时不改变工具结果和清理。 +对于根 transport 执行(`exec.parent` 缺省),工具会用四个 log-only 事件把运行投影到调用方 agent 的会话:`start()` 返回后写 run-start,只记录 `run.id` 匹配的成员开始与结束,并且只在结果可用且 dispose 完全停稳后写 run-end。嵌套 transport 调用照常执行,但不写任何记录。会话追加操作首次失败后,本运行会停止后续记录并只告警一次,留下空记录或合法连续前缀,同时不改变工具结果和清理。 引擎的 `workflow/phase` 与 `workflow/log` 事件在本工具没有逐行的持久面:会话日志刻意只记录 run 与成员生命周期,Web transcript 由这些记录派生。后台运行的这些行改经任务观察 record 抵达人类,而 record 的瞬态是设计使然。 diff --git a/packages/workflow/tool-workflow/src/index.ts b/packages/workflow/tool-workflow/src/index.ts index 40df3ea61e..d6ca7140ec 100644 --- a/packages/workflow/tool-workflow/src/index.ts +++ b/packages/workflow/tool-workflow/src/index.ts @@ -65,7 +65,7 @@ export const Config: z = z.object({ type ResolvedConfig = Required interface WorkflowRecorder { - start(session: Session, run: WorkflowRun, background: boolean): void + start(session: Session, run: WorkflowRun): void finish(runId: WorkflowRunId, stopReason: WorkflowStopReason): void abandon(runId: WorkflowRunId): void } @@ -136,13 +136,8 @@ function createWorkflowRecorder(ctx: Context): WorkflowRecorder { }) return { - start(session, run, background) { - const data: ToolWorkflowRunStartData = { - runId: run.id, - name: run.meta.name, - ...background ? { background: true } : {}, - } - if (append(session, 'tool-workflow/run-start', data)) { + start(session, run) { + if (append(session, 'tool-workflow/run-start', { runId: run.id, name: run.meta.name })) { active.set(run.id, session) } }, @@ -291,7 +286,7 @@ function startBackgroundRun( parent, }) deps.mirror.start(run.id, job) - if (recordsRun) deps.recorder.start(parent.session, run, true) + if (recordsRun) deps.recorder.start(parent.session, run) const done = run.result.then(async (result): Promise => { try { // Keep member listeners alive through disposal: an engine may @@ -444,7 +439,7 @@ export function apply(ctx: Context, config: Config): void { }) const recordsRun = exec.parent === undefined // The engine publishes member events after start() returns and this run record is active. - if (recordsRun) recorder.start(parent.session, run, false) + if (recordsRun) recorder.start(parent.session, run) // Bridge the tool's abort signal to the run: if the parent step is aborted while the // script is in flight, cancel the whole run. The signal also enters the engine directly, but diff --git a/packages/workflow/tool-workflow/src/types.ts b/packages/workflow/tool-workflow/src/types.ts index 723bdc2906..c184404939 100644 --- a/packages/workflow/tool-workflow/src/types.ts +++ b/packages/workflow/tool-workflow/src/types.ts @@ -14,8 +14,6 @@ import type { export interface ToolWorkflowRunStartData { readonly runId: WorkflowRunId readonly name: string - /** Present when the run belongs to a background job and outlives its Tool Step. */ - readonly background?: true } /** Records one workflow member after its child Session is published. */ @@ -44,7 +42,7 @@ declare module '@deepseek-ai/dsh-session/types' { interface SessionEventMap { /** * Opens one top-level workflow record. - * @param data - stable run identity, display name, and background marker. + * @param data - stable run identity and display name. */ 'tool-workflow/run-start': ToolWorkflowRunStartData /** diff --git a/packages/workflow/tool-workflow/tests/tool-workflow.spec.ts b/packages/workflow/tool-workflow/tests/tool-workflow.spec.ts index de6a38aaf9..a0fbed76df 100644 --- a/packages/workflow/tool-workflow/tests/tool-workflow.spec.ts +++ b/packages/workflow/tool-workflow/tests/tool-workflow.spec.ts @@ -517,7 +517,6 @@ describe('dsh-tool-workflow', () => { expect(session.snapshotEvents().map(event => event.type)).toEqual([ 'tool-workflow/run-start', 'tool-workflow/agent-start', 'tool-workflow/agent-end', 'tool-workflow/run-end', ]) - expect(session.snapshotEvents()[0]!.data).toEqual({ runId: 'run-1', name: 'audit', background: true }) // A straggling event after settlement finds no tracked run and is dropped. engine.phase(runId, 'Late') expect(retained(ctx, job.id, parent)).not.toContain('Late')