@united-workforce/cli 0.7.0 → 0.8.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/README.md +32 -5
- package/dist/.build-fingerprint +1 -0
- package/dist/__tests__/broker-step-active-turns.test.d.ts +20 -0
- package/dist/__tests__/broker-step-active-turns.test.d.ts.map +1 -0
- package/dist/__tests__/broker-step-active-turns.test.js +428 -0
- package/dist/__tests__/broker-step-active-turns.test.js.map +1 -0
- package/dist/__tests__/broker-step-turn-chain-phase2.test.d.ts +13 -0
- package/dist/__tests__/broker-step-turn-chain-phase2.test.d.ts.map +1 -0
- package/dist/__tests__/broker-step-turn-chain-phase2.test.js +429 -0
- package/dist/__tests__/broker-step-turn-chain-phase2.test.js.map +1 -0
- package/dist/__tests__/e2e-broker-step-suspend.test.d.ts +18 -0
- package/dist/__tests__/e2e-broker-step-suspend.test.d.ts.map +1 -0
- package/dist/__tests__/e2e-broker-step-suspend.test.js +313 -0
- package/dist/__tests__/e2e-broker-step-suspend.test.js.map +1 -0
- package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.d.ts +28 -0
- package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.d.ts.map +1 -0
- package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.js +322 -0
- package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.js.map +1 -0
- package/dist/__tests__/log-tag-validity.test.d.ts +2 -0
- package/dist/__tests__/log-tag-validity.test.d.ts.map +1 -0
- package/dist/__tests__/log-tag-validity.test.js +110 -0
- package/dist/__tests__/log-tag-validity.test.js.map +1 -0
- package/dist/__tests__/setup-agent-discovery.test.js +23 -23
- package/dist/__tests__/setup-agent-discovery.test.js.map +1 -1
- package/dist/__tests__/step-show-json.test.js +5 -5
- package/dist/__tests__/step-show-json.test.js.map +1 -1
- package/dist/__tests__/step-show-text.test.d.ts +2 -0
- package/dist/__tests__/step-show-text.test.d.ts.map +1 -0
- package/dist/__tests__/step-show-text.test.js +192 -0
- package/dist/__tests__/step-show-text.test.js.map +1 -0
- package/dist/__tests__/step-turns-cli-subprocess.test.d.ts +21 -0
- package/dist/__tests__/step-turns-cli-subprocess.test.d.ts.map +1 -0
- package/dist/__tests__/step-turns-cli-subprocess.test.js +356 -0
- package/dist/__tests__/step-turns-cli-subprocess.test.js.map +1 -0
- package/dist/__tests__/step-turns-panorama-phase3.test.d.ts +21 -0
- package/dist/__tests__/step-turns-panorama-phase3.test.d.ts.map +1 -0
- package/dist/__tests__/step-turns-panorama-phase3.test.js +476 -0
- package/dist/__tests__/step-turns-panorama-phase3.test.js.map +1 -0
- package/dist/__tests__/step-turns.test.d.ts +24 -0
- package/dist/__tests__/step-turns.test.d.ts.map +1 -0
- package/dist/__tests__/step-turns.test.js +646 -0
- package/dist/__tests__/step-turns.test.js.map +1 -0
- package/dist/__tests__/store-turn-chain.test.d.ts +2 -0
- package/dist/__tests__/store-turn-chain.test.d.ts.map +1 -0
- package/dist/__tests__/store-turn-chain.test.js +341 -0
- package/dist/__tests__/store-turn-chain.test.js.map +1 -0
- package/dist/__tests__/thread-list-limit-offset.test.d.ts +24 -0
- package/dist/__tests__/thread-list-limit-offset.test.d.ts.map +1 -0
- package/dist/__tests__/thread-list-limit-offset.test.js +254 -0
- package/dist/__tests__/thread-list-limit-offset.test.js.map +1 -0
- package/dist/__tests__/thread-list-template-ms-date.test.js +7 -2
- package/dist/__tests__/thread-list-template-ms-date.test.js.map +1 -1
- package/dist/__tests__/thread.test.js +28 -14
- package/dist/__tests__/thread.test.js.map +1 -1
- package/dist/cli.js +910 -344
- package/dist/cli.js.map +1 -1
- package/dist/commands/broker-step.d.ts +10 -3
- package/dist/commands/broker-step.d.ts.map +1 -1
- package/dist/commands/broker-step.js +231 -27
- package/dist/commands/broker-step.js.map +1 -1
- package/dist/commands/prompt.d.ts.map +1 -1
- package/dist/commands/prompt.js +42 -50
- package/dist/commands/prompt.js.map +1 -1
- package/dist/commands/setup.d.ts +6 -4
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +16 -26
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/step.d.ts +48 -1
- package/dist/commands/step.d.ts.map +1 -1
- package/dist/commands/step.js +496 -3
- package/dist/commands/step.js.map +1 -1
- package/dist/output-mappers.d.ts +8 -0
- package/dist/output-mappers.d.ts.map +1 -1
- package/dist/output-mappers.js +72 -18
- package/dist/output-mappers.js.map +1 -1
- package/dist/schemas.d.ts +3 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +17 -3
- package/dist/schemas.js.map +1 -1
- package/dist/store.d.ts +147 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +254 -1
- package/dist/store.js.map +1 -1
- package/dist/text-renderers.d.ts.map +1 -1
- package/dist/text-renderers.js +27 -2
- package/dist/text-renderers.js.map +1 -1
- package/package.json +7 -6
- package/src/__tests__/broker-step-active-turns.test.ts +509 -0
- package/src/__tests__/broker-step-turn-chain-phase2.test.ts +525 -0
- package/src/__tests__/e2e-broker-step-suspend.test.ts +351 -0
- package/src/__tests__/e2e-thread-resume-timeout-suspend.test.ts +360 -0
- package/src/__tests__/log-tag-validity.test.ts +124 -0
- package/src/__tests__/setup-agent-discovery.test.ts +23 -23
- package/src/__tests__/step-show-json.test.ts +5 -5
- package/src/__tests__/step-show-text.test.ts +236 -0
- package/src/__tests__/step-turns-cli-subprocess.test.ts +411 -0
- package/src/__tests__/step-turns-panorama-phase3.test.ts +579 -0
- package/src/__tests__/step-turns.test.ts +734 -0
- package/src/__tests__/store-turn-chain.test.ts +386 -0
- package/src/__tests__/thread-list-limit-offset.test.ts +305 -0
- package/src/__tests__/thread-list-template-ms-date.test.ts +7 -2
- package/src/__tests__/thread.test.ts +29 -15
- package/src/cli.ts +1056 -483
- package/src/commands/broker-step.ts +315 -38
- package/src/commands/prompt.ts +42 -50
- package/src/commands/setup.ts +16 -28
- package/src/commands/step.ts +655 -3
- package/src/output-mappers.ts +99 -21
- package/src/schemas.ts +32 -2
- package/src/store.ts +297 -2
- package/src/text-renderers.ts +35 -2
package/README.md
CHANGED
|
@@ -16,11 +16,11 @@ workflow → thread → step → turn
|
|
|
16
16
|
- **Workflow** (layer 1): YAML template with roles and routing graph
|
|
17
17
|
- **Thread** (layer 2): Single workflow execution instance
|
|
18
18
|
- **Step** (layer 3): One moderator→agent→extract cycle
|
|
19
|
-
- **Turn** (layer 4): Agent-internal interactions (use `step
|
|
19
|
+
- **Turn** (layer 4): Agent-internal interactions (use `step turns` to see the whole-thread turn panorama — every step's turns, with the in-flight step marked 进行中 — or `step show` / CAS to inspect)
|
|
20
20
|
|
|
21
21
|
This package has no library `src/index.ts` — it is consumed as a CLI binary only.
|
|
22
22
|
|
|
23
|
-
**Dependencies:** `@ocas/core`, `@ocas/fs`, `@united-workforce/util-agent`, `@united-workforce/protocol`, `@united-workforce/util`, `
|
|
23
|
+
**Dependencies:** `@ocas/core`, `@ocas/cli-kit`, `@ocas/fs`, `@united-workforce/util-agent`, `@united-workforce/protocol`, `@united-workforce/util`, `dotenv`, `mustache`, `yaml`
|
|
24
24
|
|
|
25
25
|
## Installation
|
|
26
26
|
|
|
@@ -63,7 +63,7 @@ The `json` and `yaml` envelopes carry the schema hash on the `type` field so con
|
|
|
63
63
|
| `uwf thread start <workflow> -p <prompt>` | Create a thread without executing |
|
|
64
64
|
| `uwf thread exec <thread-id> [--agent <cmd>] [-c <count>] [--background]` | Execute one or more moderator→agent→extract cycles |
|
|
65
65
|
| `uwf thread show <thread-id>` | Show thread head pointer |
|
|
66
|
-
| `uwf thread list [--status <status>] [--all] [--after <date>] [--before <date>] [--
|
|
66
|
+
| `uwf thread list [--status <status>] [--all] [--after <date>] [--before <date>] [--limit <n>] [--offset <m>]` | List threads (defaults to active: idle + running). Use `--all` to include end/cancelled/suspended, or `--status` to filter explicitly (idle, running, suspended, end, cancelled, active, or comma-separated). Supports time range and pagination (`--limit`/`--offset`; `--take`/`--skip` are accepted as aliases). |
|
|
67
67
|
| `uwf thread read <thread-id> [--quota N] [--before <hash>] [--start]` | Render thread as readable markdown |
|
|
68
68
|
|
|
69
69
|
`thread read`, `step list`, and `step show` work on both active and ended threads.
|
|
@@ -74,7 +74,12 @@ The `json` and `yaml` envelopes carry the schema hash on the `type` field so con
|
|
|
74
74
|
|
|
75
75
|
### Suspend / Resume
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
A thread enters `suspended` status from **two sources**, both landing at the same `$status: "$SUSPEND"` exit:
|
|
78
|
+
|
|
79
|
+
1. **Voluntary** — an agent emits `$status: "$SUSPEND"` in its frontmatter (it hits a token budget, needs human input, etc.).
|
|
80
|
+
2. **Timeout checkpoint** — the agent's `send` exceeds the adapter timeout. Instead of killing the step as an error, the broker reports a `kind: "suspended"` result and the step is written as a `$SUSPEND` node carrying the timeout `reason` (and the `nativeId` needed to resume). A timeout is a **checkpoint, not a death** — work already produced is preserved and the thread can be continued.
|
|
81
|
+
|
|
82
|
+
A suspended thread **cannot be advanced with `exec`** — `exec` detects the suspended head and returns immediately without running any agent.
|
|
78
83
|
|
|
79
84
|
To continue a suspended thread, use `resume`:
|
|
80
85
|
|
|
@@ -83,6 +88,8 @@ uwf thread resume <thread-id> # resume with workflow's defaul
|
|
|
83
88
|
uwf thread resume <thread-id> -p "version 1.2.0" # resume with supplementary context
|
|
84
89
|
```
|
|
85
90
|
|
|
91
|
+
`resume` issues a **fresh `send`** on the same cached `(threadId, role)` session; the underlying agent adapter resumes by its native session id (`--resume <nativeId>`), so the agent continues from its own history rather than starting over. For a timeout-suspended thread, `-p` supplies a short continuation prompt (e.g. `"continue"`) — the original prompt is not re-sent.
|
|
92
|
+
|
|
86
93
|
> ⚠️ `exec` does not advance suspended threads — you **must** use `resume` to provide context and continue.
|
|
87
94
|
|
|
88
95
|
Examples:
|
|
@@ -97,7 +104,8 @@ uwf thread list --all
|
|
|
97
104
|
uwf thread list --status running
|
|
98
105
|
uwf thread list --status active
|
|
99
106
|
uwf thread list --status idle,end
|
|
100
|
-
uwf thread list --after 7d --
|
|
107
|
+
uwf thread list --after 7d --limit 10
|
|
108
|
+
uwf thread list --limit 5 --offset 10
|
|
101
109
|
uwf thread read 01ARZ3NDEKTSV4RRFFQ69G5FAV --quota 8000
|
|
102
110
|
uwf thread stop 01ARZ3NDEKTSV4RRFFQ69G5FAV
|
|
103
111
|
```
|
|
@@ -109,6 +117,7 @@ uwf thread stop 01ARZ3NDEKTSV4RRFFQ69G5FAV
|
|
|
109
117
|
| `uwf step list <thread-id>` | List all steps in a thread chronologically |
|
|
110
118
|
| `uwf step show <step-hash>` | Show step metadata and frontmatter |
|
|
111
119
|
| `uwf step read <step-hash> [--quota <chars>]` | Read a step's turns as human-readable markdown |
|
|
120
|
+
| `uwf step turns <thread-id> [--role <r>] [--live] [--limit <n>] [--offset <m>]` | Show **all** turns across a thread's steps (whole-chain panorama): each completed step from its `detail.turns` (`✓`), the in-flight step from its active var (`🔄 进行中`) |
|
|
112
121
|
| `uwf step fork <step-hash>` | Fork a thread from a specific step |
|
|
113
122
|
| `uwf step ask <step-hash> -p <prompt> [--agent <cmd>] [--no-fork]` | Ask a follow-up question to a historical step's agent (read-only; no thread mutation) |
|
|
114
123
|
|
|
@@ -118,11 +127,29 @@ Examples:
|
|
|
118
127
|
uwf step list 01ARZ3NDEKTSV4RRFFQ69G5FAV
|
|
119
128
|
uwf step show 32GCDE899RRQ3
|
|
120
129
|
uwf step read 32GCDE899RRQ3 --quota 2000
|
|
130
|
+
uwf step turns 01ARZ3NDEKTSV4RRFFQ69G5FAV # whole-thread panorama
|
|
131
|
+
uwf step turns 01ARZ3NDEKTSV4RRFFQ69G5FAV --role coder # filter to one role's steps
|
|
132
|
+
uwf step turns 01ARZ3NDEKTSV4RRFFQ69G5FAV --limit 20 --offset 40 # paginate the flat sequence
|
|
133
|
+
uwf step turns 01ARZ3NDEKTSV4RRFFQ69G5FAV --role coder --live # follow the in-flight step
|
|
121
134
|
uwf step fork 32GCDE899RRQ3
|
|
122
135
|
uwf step ask 32GCDE899RRQ3 -p "Why did you choose this approach?"
|
|
123
136
|
uwf step ask 32GCDE899RRQ3 -p "Summarise the key findings" --no-fork
|
|
124
137
|
```
|
|
125
138
|
|
|
139
|
+
`step turns` is the turn-layer (layer 4) query keyed by `<thread-id>`. Unlike
|
|
140
|
+
`step read` — which renders a *single* completed step's `detail.turns` by step
|
|
141
|
+
hash, quota-bounded — `step turns` renders the **whole-thread turn panorama**: it
|
|
142
|
+
walks the entire thread chain and shows **every** step's turns in chronological
|
|
143
|
+
order, each turn attributed to its owning role/step. Completed steps are read from
|
|
144
|
+
their immutable `detail.turns` and marked `✓`; the in-flight step is read live from
|
|
145
|
+
its `@uwf/active-turns/<thread-id>/<role>` var and marked `🔄 进行中`. **All turns
|
|
146
|
+
show by default** (no truncation); `--limit`/`--offset` paginate the flattened
|
|
147
|
+
cross-step turn sequence. `--role <r>` filters the panorama to one role's steps
|
|
148
|
+
across the whole chain (e.g. on a multi-step thread whose head is a different role,
|
|
149
|
+
`--role developer` still returns the developer step's turns). With `--live` it polls
|
|
150
|
+
the SQLite-backed active var (not SSE) and prints each new turn as it arrives,
|
|
151
|
+
exiting when the in-flight step completes.
|
|
152
|
+
|
|
126
153
|
### Workflow (Layer 1: Templates)
|
|
127
154
|
|
|
128
155
|
| Command | Description |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"hash":"5705b01e563b540d0df2cfb3d50a0ddab22afcd05b62b89bded9a14c0b14e27a","outputs":["__tests__/agent-resolution-llm-free.test.d.ts","__tests__/agent-resolution-llm-free.test.d.ts.map","__tests__/agent-resolution-llm-free.test.js","__tests__/agent-resolution-llm-free.test.js.map","__tests__/broker-prompt.test.d.ts","__tests__/broker-prompt.test.d.ts.map","__tests__/broker-prompt.test.js","__tests__/broker-prompt.test.js.map","__tests__/broker-step-active-turns.test.d.ts","__tests__/broker-step-active-turns.test.d.ts.map","__tests__/broker-step-active-turns.test.js","__tests__/broker-step-active-turns.test.js.map","__tests__/broker-step-turn-chain-phase2.test.d.ts","__tests__/broker-step-turn-chain-phase2.test.d.ts.map","__tests__/broker-step-turn-chain-phase2.test.js","__tests__/broker-step-turn-chain-phase2.test.js.map","__tests__/build-step-entry.test.d.ts","__tests__/build-step-entry.test.d.ts.map","__tests__/build-step-entry.test.js","__tests__/build-step-entry.test.js.map","__tests__/clear-thread-failed-attempts.test.d.ts","__tests__/clear-thread-failed-attempts.test.d.ts.map","__tests__/clear-thread-failed-attempts.test.js","__tests__/clear-thread-failed-attempts.test.js.map","__tests__/concurrency.test.d.ts","__tests__/concurrency.test.d.ts.map","__tests__/concurrency.test.js","__tests__/concurrency.test.js.map","__tests__/config-text-renderer.test.d.ts","__tests__/config-text-renderer.test.d.ts.map","__tests__/config-text-renderer.test.js","__tests__/config-text-renderer.test.js.map","__tests__/config.test.d.ts","__tests__/config.test.d.ts.map","__tests__/config.test.js","__tests__/config.test.js.map","__tests__/current-role.test.d.ts","__tests__/current-role.test.d.ts.map","__tests__/current-role.test.js","__tests__/current-role.test.js.map","__tests__/e2e-broker-step-suspend.test.d.ts","__tests__/e2e-broker-step-suspend.test.d.ts.map","__tests__/e2e-broker-step-suspend.test.js","__tests__/e2e-broker-step-suspend.test.js.map","__tests__/e2e-broker-step.test.d.ts","__tests__/e2e-broker-step.test.d.ts.map","__tests__/e2e-broker-step.test.js","__tests__/e2e-broker-step.test.js.map","__tests__/e2e-mock-agent.test.d.ts","__tests__/e2e-mock-agent.test.d.ts.map","__tests__/e2e-mock-agent.test.js","__tests__/e2e-mock-agent.test.js.map","__tests__/e2e-thread-resume-timeout-suspend.test.d.ts","__tests__/e2e-thread-resume-timeout-suspend.test.d.ts.map","__tests__/e2e-thread-resume-timeout-suspend.test.js","__tests__/e2e-thread-resume-timeout-suspend.test.js.map","__tests__/format-text-default.test.d.ts","__tests__/format-text-default.test.d.ts.map","__tests__/format-text-default.test.js","__tests__/format-text-default.test.js.map","__tests__/format-text-registry.test.d.ts","__tests__/format-text-registry.test.d.ts.map","__tests__/format-text-registry.test.js","__tests__/format-text-registry.test.js.map","__tests__/include-tag.test.d.ts","__tests__/include-tag.test.d.ts.map","__tests__/include-tag.test.js","__tests__/include-tag.test.js.map","__tests__/issue-180-workflow-ref-removed.test.d.ts","__tests__/issue-180-workflow-ref-removed.test.d.ts.map","__tests__/issue-180-workflow-ref-removed.test.js","__tests__/issue-180-workflow-ref-removed.test.js.map","__tests__/log-tag-validity.test.d.ts","__tests__/log-tag-validity.test.d.ts.map","__tests__/log-tag-validity.test.js","__tests__/log-tag-validity.test.js.map","__tests__/log-text-renderer.test.d.ts","__tests__/log-text-renderer.test.d.ts.map","__tests__/log-text-renderer.test.js","__tests__/log-text-renderer.test.js.map","__tests__/log.test.d.ts","__tests__/log.test.d.ts.map","__tests__/log.test.js","__tests__/log.test.js.map","__tests__/moderator-evaluate.test.d.ts","__tests__/moderator-evaluate.test.d.ts.map","__tests__/moderator-evaluate.test.js","__tests__/moderator-evaluate.test.js.map","__tests__/output-mapper-thread-list-startedat.test.d.ts","__tests__/output-mapper-thread-list-startedat.test.d.ts.map","__tests__/output-mapper-thread-list-startedat.test.js","__tests__/output-mapper-thread-list-startedat.test.js.map","__tests__/output-mapper-workflow-add.test.d.ts","__tests__/output-mapper-workflow-add.test.d.ts.map","__tests__/output-mapper-workflow-add.test.js","__tests__/output-mapper-workflow-add.test.js.map","__tests__/pid-recycling.test.d.ts","__tests__/pid-recycling.test.d.ts.map","__tests__/pid-recycling.test.js","__tests__/pid-recycling.test.js.map","__tests__/preload.d.ts","__tests__/preload.d.ts.map","__tests__/preload.js","__tests__/preload.js.map","__tests__/prompt.test.d.ts","__tests__/prompt.test.d.ts.map","__tests__/prompt.test.js","__tests__/prompt.test.js.map","__tests__/resolve-head-hash.test.d.ts","__tests__/resolve-head-hash.test.d.ts.map","__tests__/resolve-head-hash.test.js","__tests__/resolve-head-hash.test.js.map","__tests__/setup-agent-discovery.test.d.ts","__tests__/setup-agent-discovery.test.d.ts.map","__tests__/setup-agent-discovery.test.js","__tests__/setup-agent-discovery.test.js.map","__tests__/setup-complexity.test.d.ts","__tests__/setup-complexity.test.d.ts.map","__tests__/setup-complexity.test.js","__tests__/setup-complexity.test.js.map","__tests__/setup-no-llm.test.d.ts","__tests__/setup-no-llm.test.d.ts.map","__tests__/setup-no-llm.test.js","__tests__/setup-no-llm.test.js.map","__tests__/solve-issue-tea-worktree.test.d.ts","__tests__/solve-issue-tea-worktree.test.d.ts.map","__tests__/solve-issue-tea-worktree.test.js","__tests__/solve-issue-tea-worktree.test.js.map","__tests__/step-ask.test.d.ts","__tests__/step-ask.test.d.ts.map","__tests__/step-ask.test.js","__tests__/step-ask.test.js.map","__tests__/step-read.test.d.ts","__tests__/step-read.test.d.ts.map","__tests__/step-read.test.js","__tests__/step-read.test.js.map","__tests__/step-show-json.test.d.ts","__tests__/step-show-json.test.d.ts.map","__tests__/step-show-json.test.js","__tests__/step-show-json.test.js.map","__tests__/step-show-text.test.d.ts","__tests__/step-show-text.test.d.ts.map","__tests__/step-show-text.test.js","__tests__/step-show-text.test.js.map","__tests__/step-timing.test.d.ts","__tests__/step-timing.test.d.ts.map","__tests__/step-timing.test.js","__tests__/step-timing.test.js.map","__tests__/step-turns-cli-subprocess.test.d.ts","__tests__/step-turns-cli-subprocess.test.d.ts.map","__tests__/step-turns-cli-subprocess.test.js","__tests__/step-turns-cli-subprocess.test.js.map","__tests__/step-turns-panorama-phase3.test.d.ts","__tests__/step-turns-panorama-phase3.test.d.ts.map","__tests__/step-turns-panorama-phase3.test.js","__tests__/step-turns-panorama-phase3.test.js.map","__tests__/step-turns.test.d.ts","__tests__/step-turns.test.d.ts.map","__tests__/step-turns.test.js","__tests__/step-turns.test.js.map","__tests__/store-global-cas.test.d.ts","__tests__/store-global-cas.test.d.ts.map","__tests__/store-global-cas.test.js","__tests__/store-global-cas.test.js.map","__tests__/store-storage-root.test.d.ts","__tests__/store-storage-root.test.d.ts.map","__tests__/store-storage-root.test.js","__tests__/store-storage-root.test.js.map","__tests__/store-turn-chain.test.d.ts","__tests__/store-turn-chain.test.d.ts.map","__tests__/store-turn-chain.test.js","__tests__/store-turn-chain.test.js.map","__tests__/store-unified-threads.test.d.ts","__tests__/store-unified-threads.test.d.ts.map","__tests__/store-unified-threads.test.js","__tests__/store-unified-threads.test.js.map","__tests__/thread-agent-failure-suspended.test.d.ts","__tests__/thread-agent-failure-suspended.test.d.ts.map","__tests__/thread-agent-failure-suspended.test.js","__tests__/thread-agent-failure-suspended.test.js.map","__tests__/thread-cancel-status.test.d.ts","__tests__/thread-cancel-status.test.d.ts.map","__tests__/thread-cancel-status.test.js","__tests__/thread-cancel-status.test.js.map","__tests__/thread-cancel-text-renderer.test.d.ts","__tests__/thread-cancel-text-renderer.test.d.ts.map","__tests__/thread-cancel-text-renderer.test.js","__tests__/thread-cancel-text-renderer.test.js.map","__tests__/thread-join.test.d.ts","__tests__/thread-join.test.d.ts.map","__tests__/thread-join.test.js","__tests__/thread-join.test.js.map","__tests__/thread-list-filters.test.d.ts","__tests__/thread-list-filters.test.d.ts.map","__tests__/thread-list-filters.test.js","__tests__/thread-list-filters.test.js.map","__tests__/thread-list-limit-offset.test.d.ts","__tests__/thread-list-limit-offset.test.d.ts.map","__tests__/thread-list-limit-offset.test.js","__tests__/thread-list-limit-offset.test.js.map","__tests__/thread-list-template-ms-date.test.d.ts","__tests__/thread-list-template-ms-date.test.d.ts.map","__tests__/thread-list-template-ms-date.test.js","__tests__/thread-list-template-ms-date.test.js.map","__tests__/thread-list-workflow-corrupt.test.d.ts","__tests__/thread-list-workflow-corrupt.test.d.ts.map","__tests__/thread-list-workflow-corrupt.test.js","__tests__/thread-list-workflow-corrupt.test.js.map","__tests__/thread-location.test.d.ts","__tests__/thread-location.test.d.ts.map","__tests__/thread-location.test.js","__tests__/thread-location.test.js.map","__tests__/thread-poke.test.d.ts","__tests__/thread-poke.test.d.ts.map","__tests__/thread-poke.test.js","__tests__/thread-poke.test.js.map","__tests__/thread-read-quota.test.d.ts","__tests__/thread-read-quota.test.d.ts.map","__tests__/thread-read-quota.test.js","__tests__/thread-read-quota.test.js.map","__tests__/thread-read-xml-tags.test.d.ts","__tests__/thread-read-xml-tags.test.d.ts.map","__tests__/thread-read-xml-tags.test.js","__tests__/thread-read-xml-tags.test.js.map","__tests__/thread-resume.test.d.ts","__tests__/thread-resume.test.d.ts.map","__tests__/thread-resume.test.js","__tests__/thread-resume.test.js.map","__tests__/thread-show-status.test.d.ts","__tests__/thread-show-status.test.d.ts.map","__tests__/thread-show-status.test.js","__tests__/thread-show-status.test.js.map","__tests__/thread-start-cwd-cli.test.d.ts","__tests__/thread-start-cwd-cli.test.d.ts.map","__tests__/thread-start-cwd-cli.test.js","__tests__/thread-start-cwd-cli.test.js.map","__tests__/thread-step-count.test.d.ts","__tests__/thread-step-count.test.d.ts.map","__tests__/thread-step-count.test.js","__tests__/thread-step-count.test.js.map","__tests__/thread-stop-text-renderer.test.d.ts","__tests__/thread-stop-text-renderer.test.d.ts.map","__tests__/thread-stop-text-renderer.test.js","__tests__/thread-stop-text-renderer.test.js.map","__tests__/thread-suspend-step.test.d.ts","__tests__/thread-suspend-step.test.d.ts.map","__tests__/thread-suspend-step.test.js","__tests__/thread-suspend-step.test.js.map","__tests__/thread-suspended-display.test.d.ts","__tests__/thread-suspended-display.test.d.ts.map","__tests__/thread-suspended-display.test.js","__tests__/thread-suspended-display.test.js.map","__tests__/thread-test-helpers.d.ts","__tests__/thread-test-helpers.d.ts.map","__tests__/thread-test-helpers.js","__tests__/thread-test-helpers.js.map","__tests__/thread.test.d.ts","__tests__/thread.test.d.ts.map","__tests__/thread.test.js","__tests__/thread.test.js.map","__tests__/validate-semantic.test.d.ts","__tests__/validate-semantic.test.d.ts.map","__tests__/validate-semantic.test.js","__tests__/validate-semantic.test.js.map","__tests__/workflow-list-recursive.test.d.ts","__tests__/workflow-list-recursive.test.d.ts.map","__tests__/workflow-list-recursive.test.js","__tests__/workflow-list-recursive.test.js.map","__tests__/workflow-paths.test.d.ts","__tests__/workflow-paths.test.d.ts.map","__tests__/workflow-paths.test.js","__tests__/workflow-paths.test.js.map","__tests__/workflow-resolution.test.d.ts","__tests__/workflow-resolution.test.d.ts.map","__tests__/workflow-resolution.test.js","__tests__/workflow-resolution.test.js.map","__tests__/workflow-show-resolution.test.d.ts","__tests__/workflow-show-resolution.test.d.ts.map","__tests__/workflow-show-resolution.test.js","__tests__/workflow-show-resolution.test.js.map","__tests__/workflow-validate.test.d.ts","__tests__/workflow-validate.test.d.ts.map","__tests__/workflow-validate.test.js","__tests__/workflow-validate.test.js.map","__tests__/write-envelope.test.d.ts","__tests__/write-envelope.test.d.ts.map","__tests__/write-envelope.test.js","__tests__/write-envelope.test.js.map","background/background.d.ts","background/background.d.ts.map","background/background.js","background/background.js.map","background/index.d.ts","background/index.d.ts.map","background/index.js","background/index.js.map","background/types.d.ts","background/types.d.ts.map","background/types.js","background/types.js.map","cli.d.ts","cli.d.ts.map","cli.js","cli.js.map","commands/broker-step.d.ts","commands/broker-step.d.ts.map","commands/broker-step.js","commands/broker-step.js.map","commands/config.d.ts","commands/config.d.ts.map","commands/config.js","commands/config.js.map","commands/log.d.ts","commands/log.d.ts.map","commands/log.js","commands/log.js.map","commands/prompt.d.ts","commands/prompt.d.ts.map","commands/prompt.js","commands/prompt.js.map","commands/setup.d.ts","commands/setup.d.ts.map","commands/setup.js","commands/setup.js.map","commands/shared.d.ts","commands/shared.d.ts.map","commands/shared.js","commands/shared.js.map","commands/step.d.ts","commands/step.d.ts.map","commands/step.js","commands/step.js.map","commands/thread-time-parser.d.ts","commands/thread-time-parser.d.ts.map","commands/thread-time-parser.js","commands/thread-time-parser.js.map","commands/thread.d.ts","commands/thread.d.ts.map","commands/thread.js","commands/thread.js.map","commands/workflow.d.ts","commands/workflow.d.ts.map","commands/workflow.js","commands/workflow.js.map","concurrency/concurrency.d.ts","concurrency/concurrency.d.ts.map","concurrency/concurrency.js","concurrency/concurrency.js.map","concurrency/index.d.ts","concurrency/index.d.ts.map","concurrency/index.js","concurrency/index.js.map","concurrency/types.d.ts","concurrency/types.d.ts.map","concurrency/types.js","concurrency/types.js.map","format.d.ts","format.d.ts.map","format.js","format.js.map","include.d.ts","include.d.ts.map","include.js","include.js.map","moderator/__tests__/evaluate.test.d.ts","moderator/__tests__/evaluate.test.d.ts.map","moderator/__tests__/evaluate.test.js","moderator/__tests__/evaluate.test.js.map","moderator/evaluate.d.ts","moderator/evaluate.d.ts.map","moderator/evaluate.js","moderator/evaluate.js.map","moderator/index.d.ts","moderator/index.d.ts.map","moderator/index.js","moderator/index.js.map","moderator/types.d.ts","moderator/types.d.ts.map","moderator/types.js","moderator/types.js.map","output-mappers.d.ts","output-mappers.d.ts.map","output-mappers.js","output-mappers.js.map","schemas.d.ts","schemas.d.ts.map","schemas.js","schemas.js.map","store.d.ts","store.d.ts.map","store.js","store.js.map","text-renderers.d.ts","text-renderers.d.ts.map","text-renderers.js","text-renderers.js.map","validate-semantic.d.ts","validate-semantic.d.ts.map","validate-semantic.js","validate-semantic.js.map","validate.d.ts","validate.d.ts.map","validate.js","validate.js.map"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 2 (#398 + #419) — realtime turn persistence in `executeBrokerStep`.
|
|
3
|
+
*
|
|
4
|
+
* Updated for Phase 2 (#419):
|
|
5
|
+
* - Turns are now written with `prev`+`owner` chain instead of accumulating in
|
|
6
|
+
* `@uwf/active-turns/<tid>/<role>` array var
|
|
7
|
+
* - Detail node no longer contains `turns` array — use `turnsOfStep()` to retrieve
|
|
8
|
+
* - Thread-keyed active vars (`@uwf/active-step/<tid>`, `@uwf/active-turn-head/<tid>`)
|
|
9
|
+
*
|
|
10
|
+
* Covers the acceptance steps:
|
|
11
|
+
* Step 1 — broker-step's `onTurn` writes each turn with `prev`+`owner` chain;
|
|
12
|
+
* the turn chain grows 1→2→3.
|
|
13
|
+
* Step 2 — on completion, detail has `turnCount===3` (no `turns` array);
|
|
14
|
+
* turns are accessible via `turnsOfStep()`.
|
|
15
|
+
* Step 3 — a crash-rerun is a fresh attempt: new step-start isolates old turns
|
|
16
|
+
* via different `owner` reference.
|
|
17
|
+
* Step 4 — cross-process visibility: thread-keyed turn head var is observable.
|
|
18
|
+
*/
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=broker-step-active-turns.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broker-step-active-turns.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/broker-step-active-turns.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG"}
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 2 (#398 + #419) — realtime turn persistence in `executeBrokerStep`.
|
|
3
|
+
*
|
|
4
|
+
* Updated for Phase 2 (#419):
|
|
5
|
+
* - Turns are now written with `prev`+`owner` chain instead of accumulating in
|
|
6
|
+
* `@uwf/active-turns/<tid>/<role>` array var
|
|
7
|
+
* - Detail node no longer contains `turns` array — use `turnsOfStep()` to retrieve
|
|
8
|
+
* - Thread-keyed active vars (`@uwf/active-step/<tid>`, `@uwf/active-turn-head/<tid>`)
|
|
9
|
+
*
|
|
10
|
+
* Covers the acceptance steps:
|
|
11
|
+
* Step 1 — broker-step's `onTurn` writes each turn with `prev`+`owner` chain;
|
|
12
|
+
* the turn chain grows 1→2→3.
|
|
13
|
+
* Step 2 — on completion, detail has `turnCount===3` (no `turns` array);
|
|
14
|
+
* turns are accessible via `turnsOfStep()`.
|
|
15
|
+
* Step 3 — a crash-rerun is a fresh attempt: new step-start isolates old turns
|
|
16
|
+
* via different `owner` reference.
|
|
17
|
+
* Step 4 — cross-process visibility: thread-keyed turn head var is observable.
|
|
18
|
+
*/
|
|
19
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
20
|
+
import { tmpdir } from "node:os";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { putSchema } from "@ocas/core";
|
|
23
|
+
import { createFsStore, createSqliteVarStore } from "@ocas/fs";
|
|
24
|
+
import { createProcessLogger } from "@united-workforce/util";
|
|
25
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
26
|
+
import { executeBrokerStep } from "../commands/broker-step.js";
|
|
27
|
+
import { ACTIVE_TURNS_VAR_PREFIX, activeTurnsVarName, appendActiveTurn, createUwfStore, getActiveTurnHead, readActiveTurns, turnsOfStep, walkTurnChain, } from "../store.js";
|
|
28
|
+
// ── SSE plumbing ─────────────────────────────────────────────────────────────
|
|
29
|
+
function sseFrame(id, event, data) {
|
|
30
|
+
return `id: ${id}\nevent: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
31
|
+
}
|
|
32
|
+
function turnFrame(id, index, content) {
|
|
33
|
+
return sseFrame(id, "turn", {
|
|
34
|
+
type: "@sumeru/turn",
|
|
35
|
+
value: { index, role: "assistant", content, timestamp: "", toolCalls: null },
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function doneFrame(id, turnCount) {
|
|
39
|
+
return sseFrame(id, "done", {
|
|
40
|
+
type: "@sumeru/summary",
|
|
41
|
+
value: { turnCount, tokens: { in: 9, out: 4 }, durationMs: 42 },
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function delay(ms) {
|
|
45
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
46
|
+
}
|
|
47
|
+
/** How long each assistant turn is held back, so readers can sample between them. */
|
|
48
|
+
const PER_TURN_MS = 40;
|
|
49
|
+
/**
|
|
50
|
+
* Build a paced SSE Response: each frame is enqueued `PER_TURN_MS` after the
|
|
51
|
+
* previous, so the broker's reader loop fires `onTurn` one turn at a time and a
|
|
52
|
+
* concurrent reader can observe the active var growing. Robust to consumer
|
|
53
|
+
* cancellation (the broker cancels its reader in a `finally`), so a late
|
|
54
|
+
* `enqueue`/`close` after cancel is swallowed rather than surfacing as an
|
|
55
|
+
* unhandled rejection.
|
|
56
|
+
*/
|
|
57
|
+
function buildPacedSseResponse(frames) {
|
|
58
|
+
const encoder = new TextEncoder();
|
|
59
|
+
let cancelled = false;
|
|
60
|
+
const stream = new ReadableStream({
|
|
61
|
+
start(controller) {
|
|
62
|
+
void (async () => {
|
|
63
|
+
try {
|
|
64
|
+
for (const frame of frames) {
|
|
65
|
+
if (cancelled)
|
|
66
|
+
return;
|
|
67
|
+
controller.enqueue(encoder.encode(frame));
|
|
68
|
+
await delay(PER_TURN_MS);
|
|
69
|
+
}
|
|
70
|
+
if (!cancelled)
|
|
71
|
+
controller.close();
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Consumer closed/cancelled the stream first — nothing to do.
|
|
75
|
+
}
|
|
76
|
+
})();
|
|
77
|
+
},
|
|
78
|
+
cancel() {
|
|
79
|
+
cancelled = true;
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
return new Response(stream, {
|
|
83
|
+
status: 200,
|
|
84
|
+
headers: { "Content-Type": "text/event-stream; charset=utf-8" },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function buildJsonResponse(status, body) {
|
|
88
|
+
return new Response(JSON.stringify(body), {
|
|
89
|
+
status,
|
|
90
|
+
headers: { "Content-Type": "application/json" },
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// ── Fixture: role schema + workflow ──────────────────────────────────────────
|
|
94
|
+
const ROLE_OUTPUT_SCHEMA = {
|
|
95
|
+
title: "coder-output",
|
|
96
|
+
type: "object",
|
|
97
|
+
required: ["$status"],
|
|
98
|
+
properties: {
|
|
99
|
+
$status: { type: "string", enum: ["done", "failed"] },
|
|
100
|
+
summary: { type: "string" },
|
|
101
|
+
},
|
|
102
|
+
additionalProperties: false,
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* The final assistant turn carries valid frontmatter so extraction succeeds on
|
|
106
|
+
* the primary send (no retries → exactly one onTurn per emitted turn). Its
|
|
107
|
+
* stored content is this whole block (byte-for-byte), which is what the
|
|
108
|
+
* solidified `detail.turns[last]` holds.
|
|
109
|
+
*/
|
|
110
|
+
const FINAL_TURN = `---
|
|
111
|
+
$status: done
|
|
112
|
+
summary: shipped
|
|
113
|
+
---
|
|
114
|
+
the final answer`;
|
|
115
|
+
const HOST = "http://127.0.0.1:7900";
|
|
116
|
+
const GATEWAY = "coder-gw";
|
|
117
|
+
const ALIAS = "coder-agent";
|
|
118
|
+
const SESSION_ID = "ses_active_turns";
|
|
119
|
+
const THREAD_ID = "06FCACTIVETURNSPHASE2A001";
|
|
120
|
+
const ROLE = "coder";
|
|
121
|
+
function buildConfig() {
|
|
122
|
+
return {
|
|
123
|
+
agents: { [ALIAS]: { host: HOST, gateway: GATEWAY } },
|
|
124
|
+
defaultAgent: ALIAS,
|
|
125
|
+
agentOverrides: null,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
async function buildWorkflow(uwf) {
|
|
129
|
+
const frontmatterHash = (await putSchema(uwf.store, ROLE_OUTPUT_SCHEMA));
|
|
130
|
+
const workflow = {
|
|
131
|
+
version: 1,
|
|
132
|
+
name: "active-turns-wf",
|
|
133
|
+
description: "phase2 realtime turns",
|
|
134
|
+
roles: {
|
|
135
|
+
[ROLE]: {
|
|
136
|
+
description: "writes code",
|
|
137
|
+
goal: "produce a change",
|
|
138
|
+
capabilities: [],
|
|
139
|
+
procedure: "do the work",
|
|
140
|
+
output: "frontmatter+body",
|
|
141
|
+
frontmatter: frontmatterHash,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
graph: {
|
|
145
|
+
[ROLE]: {
|
|
146
|
+
done: { role: "$END", prompt: "", location: null },
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
const startHash = (await uwf.store.cas.put(uwf.schemas.startNode, {
|
|
151
|
+
workflow: await uwf.store.cas.put(uwf.schemas.workflow, workflow),
|
|
152
|
+
prompt: "task",
|
|
153
|
+
cwd: "/tmp/work",
|
|
154
|
+
}));
|
|
155
|
+
return { workflow, startHash };
|
|
156
|
+
}
|
|
157
|
+
function resolveFetchUrl(input) {
|
|
158
|
+
if (typeof input === "string")
|
|
159
|
+
return input;
|
|
160
|
+
if (input instanceof URL)
|
|
161
|
+
return input.href;
|
|
162
|
+
return input.url;
|
|
163
|
+
}
|
|
164
|
+
/** Drive one broker step end-to-end with the configured fixture. */
|
|
165
|
+
function runStep(uwf, workflow, startHash, tmpDir) {
|
|
166
|
+
return executeBrokerStep({
|
|
167
|
+
storageRoot: tmpDir,
|
|
168
|
+
uwf,
|
|
169
|
+
config: buildConfig(),
|
|
170
|
+
workflow,
|
|
171
|
+
threadId: THREAD_ID,
|
|
172
|
+
role: ROLE,
|
|
173
|
+
edgePrompt: "go",
|
|
174
|
+
effectiveCwd: "/tmp/work",
|
|
175
|
+
startHash,
|
|
176
|
+
prevHash: null,
|
|
177
|
+
agentOverride: null,
|
|
178
|
+
previousAttempts: null,
|
|
179
|
+
plog: createProcessLogger({
|
|
180
|
+
storageRoot: tmpDir,
|
|
181
|
+
context: { thread: THREAD_ID, workflow: "active-turns-wf" },
|
|
182
|
+
}),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/** Resolve the `content` of a turn node hash, or `null`. */
|
|
186
|
+
function turnContent(store, hash) {
|
|
187
|
+
const node = store.cas.get(hash);
|
|
188
|
+
if (node === null)
|
|
189
|
+
return null;
|
|
190
|
+
const payload = node.payload;
|
|
191
|
+
return typeof payload.content === "string" ? payload.content : null;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* An *independent* reader of the shared on-disk store — a fresh CAS (its own
|
|
195
|
+
* hash-set scan) and a fresh SQLite connection — simulating "process B" reading
|
|
196
|
+
* the WAL-committed active var while "process A" runs the step.
|
|
197
|
+
*/
|
|
198
|
+
function openReader(casDir) {
|
|
199
|
+
const cas = createFsStore(casDir);
|
|
200
|
+
const { var: varStore, tag, close } = createSqliteVarStore(join(casDir, "vars"), cas);
|
|
201
|
+
return { store: { cas, var: varStore, tag }, close };
|
|
202
|
+
}
|
|
203
|
+
// ── Tests ────────────────────────────────────────────────────────────────────
|
|
204
|
+
describe("active-turns realtime persistence (#398)", () => {
|
|
205
|
+
let tmpDir;
|
|
206
|
+
let casDir;
|
|
207
|
+
let savedOcasHome;
|
|
208
|
+
let messageBodies;
|
|
209
|
+
beforeEach(async () => {
|
|
210
|
+
savedOcasHome = process.env.OCAS_HOME;
|
|
211
|
+
tmpDir = await mkdtemp(join(tmpdir(), "active-turns-"));
|
|
212
|
+
casDir = join(tmpDir, "cas");
|
|
213
|
+
process.env.OCAS_HOME = casDir;
|
|
214
|
+
messageBodies = [];
|
|
215
|
+
vi.stubGlobal("fetch", async (input, init) => {
|
|
216
|
+
const url = resolveFetchUrl(input);
|
|
217
|
+
if (url.endsWith(`/gateways/${GATEWAY}/sessions`)) {
|
|
218
|
+
return buildJsonResponse(201, {
|
|
219
|
+
type: "@sumeru/session",
|
|
220
|
+
value: { id: SESSION_ID, gateway: GATEWAY },
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (url.endsWith(`/sessions/${SESSION_ID}/messages`)) {
|
|
224
|
+
messageBodies.push(typeof init?.body === "string" ? init.body : "");
|
|
225
|
+
return buildPacedSseResponse([
|
|
226
|
+
turnFrame(1, 0, "t1"),
|
|
227
|
+
turnFrame(2, 1, "t2"),
|
|
228
|
+
turnFrame(3, 2, FINAL_TURN),
|
|
229
|
+
doneFrame(4, 3),
|
|
230
|
+
]);
|
|
231
|
+
}
|
|
232
|
+
return buildJsonResponse(500, { error: "unexpected url", url });
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
afterEach(async () => {
|
|
236
|
+
vi.unstubAllGlobals();
|
|
237
|
+
if (savedOcasHome === undefined)
|
|
238
|
+
delete process.env.OCAS_HOME;
|
|
239
|
+
else
|
|
240
|
+
process.env.OCAS_HOME = savedOcasHome;
|
|
241
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
242
|
+
});
|
|
243
|
+
// Step 1 — the turn chain grows 1 → 2 → 3 as onTurn fires (Phase 2: via turn chain, not role-keyed var).
|
|
244
|
+
test("turn chain grows 1 -> 2 -> 3 via prev+owner chain as turns stream", async () => {
|
|
245
|
+
const uwf = await createUwfStore(tmpDir);
|
|
246
|
+
const { workflow, startHash } = await buildWorkflow(uwf);
|
|
247
|
+
const p = runStep(uwf, workflow, startHash, tmpDir);
|
|
248
|
+
// Sample the turn chain head while the step is in flight.
|
|
249
|
+
const chainLengths = [];
|
|
250
|
+
let finished = false;
|
|
251
|
+
void p.finally(() => {
|
|
252
|
+
finished = true;
|
|
253
|
+
});
|
|
254
|
+
while (!finished) {
|
|
255
|
+
const head = getActiveTurnHead(uwf.store, THREAD_ID);
|
|
256
|
+
const len = head !== null ? walkTurnChain(uwf, head).length : 0;
|
|
257
|
+
chainLengths.push(len);
|
|
258
|
+
await delay(PER_TURN_MS / 4);
|
|
259
|
+
}
|
|
260
|
+
const result = await p;
|
|
261
|
+
// Monotonic growth: first occurrences of 1, 2, 3 appear in order.
|
|
262
|
+
const firstIndexOf = (n) => chainLengths.indexOf(n);
|
|
263
|
+
expect(firstIndexOf(1)).toBeGreaterThanOrEqual(0);
|
|
264
|
+
expect(firstIndexOf(2)).toBeGreaterThan(firstIndexOf(1));
|
|
265
|
+
expect(firstIndexOf(3)).toBeGreaterThan(firstIndexOf(2));
|
|
266
|
+
// The chain never shrinks while accumulating.
|
|
267
|
+
const beforeFinal = chainLengths.slice(0, chainLengths.indexOf(3) + 1);
|
|
268
|
+
for (let i = 1; i < beforeFinal.length; i++) {
|
|
269
|
+
expect(beforeFinal[i]).toBeGreaterThanOrEqual(beforeFinal[i - 1]);
|
|
270
|
+
}
|
|
271
|
+
// Verify turns via turn chain (Phase 2: no detail.turns array)
|
|
272
|
+
expect(result.isError).toBe(false);
|
|
273
|
+
const turnHead = getActiveTurnHead(uwf.store, THREAD_ID);
|
|
274
|
+
expect(turnHead).not.toBeNull();
|
|
275
|
+
const chain = walkTurnChain(uwf, turnHead);
|
|
276
|
+
expect(chain).toHaveLength(3);
|
|
277
|
+
const contents = chain.map((h) => turnContent(uwf.store, h));
|
|
278
|
+
expect(contents).toEqual(["t1", "t2", FINAL_TURN]);
|
|
279
|
+
for (const h of chain) {
|
|
280
|
+
const node = uwf.store.cas.get(h);
|
|
281
|
+
expect((node?.payload).role).toBe("assistant");
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
// Step 2 — completion: detail has turnCount===3 (no turns array); turns via turnsOfStep.
|
|
285
|
+
test("detail has turnCount===3 (no turns array); turns accessible via turnsOfStep", async () => {
|
|
286
|
+
const uwf = await createUwfStore(tmpDir);
|
|
287
|
+
const { workflow, startHash } = await buildWorkflow(uwf);
|
|
288
|
+
const result = await runStep(uwf, workflow, startHash, tmpDir);
|
|
289
|
+
expect(result.isError).toBe(false);
|
|
290
|
+
const detail = uwf.store.cas.get(result.detailHash)?.payload;
|
|
291
|
+
expect(detail.turnCount).toBe(3);
|
|
292
|
+
expect(detail.turns).toBeUndefined(); // Phase 2: no turns array
|
|
293
|
+
expect(detail.sessionId).toBe(SESSION_ID);
|
|
294
|
+
expect(detail.duration).toBeGreaterThanOrEqual(0);
|
|
295
|
+
// Get turns via turn chain
|
|
296
|
+
const turnHead = getActiveTurnHead(uwf.store, THREAD_ID);
|
|
297
|
+
expect(turnHead).not.toBeNull();
|
|
298
|
+
// Get the step-start owner from first turn
|
|
299
|
+
const firstTurn = uwf.store.cas.get(walkTurnChain(uwf, turnHead)[0])
|
|
300
|
+
?.payload;
|
|
301
|
+
const stepStartHash = firstTurn.owner;
|
|
302
|
+
const stepTurns = turnsOfStep(uwf, turnHead, stepStartHash);
|
|
303
|
+
expect(stepTurns).toHaveLength(3);
|
|
304
|
+
expect(stepTurns.map((h) => turnContent(uwf.store, h))).toEqual(["t1", "t2", FINAL_TURN]);
|
|
305
|
+
// Role-keyed var is cleared (backward compat)
|
|
306
|
+
const vars = uwf.varStore.list({ exactName: activeTurnsVarName(THREAD_ID, ROLE) });
|
|
307
|
+
expect(vars).toEqual([]);
|
|
308
|
+
// Backward-compat: frontmatter extraction still works
|
|
309
|
+
expect(result.frontmatter).toEqual({ $status: "done", summary: "shipped" });
|
|
310
|
+
});
|
|
311
|
+
// Step 3 — crash-rerun: new step-start isolates old turns via different owner.
|
|
312
|
+
test("crash-rerun: new step-start isolates old turns via different owner", async () => {
|
|
313
|
+
const uwf = await createUwfStore(tmpDir);
|
|
314
|
+
const { workflow, startHash } = await buildWorkflow(uwf);
|
|
315
|
+
// Seed a residual active var (two stale turns) from a "crashed" prior attempt.
|
|
316
|
+
// Phase 2: these will be ignored because the new step gets a new step-start
|
|
317
|
+
// with different owner hash.
|
|
318
|
+
const turnSchemaHash = putSchema(uwf.store, {
|
|
319
|
+
title: "broker-turn",
|
|
320
|
+
type: "object",
|
|
321
|
+
required: ["role", "content"],
|
|
322
|
+
properties: {
|
|
323
|
+
role: { type: "string", enum: ["assistant", "tool"] },
|
|
324
|
+
content: { type: "string" },
|
|
325
|
+
},
|
|
326
|
+
additionalProperties: false,
|
|
327
|
+
});
|
|
328
|
+
for (const stale of ["old1", "old2"]) {
|
|
329
|
+
const h = uwf.store.cas.put(turnSchemaHash, { role: "assistant", content: stale });
|
|
330
|
+
appendActiveTurn(uwf.store, THREAD_ID, ROLE, h);
|
|
331
|
+
}
|
|
332
|
+
expect(readActiveTurns(uwf.store, THREAD_ID, ROLE)).toHaveLength(2);
|
|
333
|
+
const result = await runStep(uwf, workflow, startHash, tmpDir);
|
|
334
|
+
expect(result.isError).toBe(false);
|
|
335
|
+
const detail = uwf.store.cas.get(result.detailHash)?.payload;
|
|
336
|
+
// Only the new attempt's 3 turns counted
|
|
337
|
+
expect(detail.turnCount).toBe(3);
|
|
338
|
+
// Get the new step's turns via turnsOfStep
|
|
339
|
+
const turnHead = getActiveTurnHead(uwf.store, THREAD_ID);
|
|
340
|
+
expect(turnHead).not.toBeNull();
|
|
341
|
+
// Get the step-start owner from the first new turn (will be the new step-start)
|
|
342
|
+
const chain = walkTurnChain(uwf, turnHead);
|
|
343
|
+
// The chain includes ALL turns (old + new), but filtered by owner gives only new ones
|
|
344
|
+
expect(chain.length).toBeGreaterThanOrEqual(3);
|
|
345
|
+
// Find the new step-start (the one that owns the turns with content "t1", "t2", etc.)
|
|
346
|
+
const newTurns = chain.filter((h) => {
|
|
347
|
+
const c = turnContent(uwf.store, h);
|
|
348
|
+
return c === "t1" || c === "t2" || c === FINAL_TURN;
|
|
349
|
+
});
|
|
350
|
+
expect(newTurns).toHaveLength(3);
|
|
351
|
+
const newStepOwner = (uwf.store.cas.get(newTurns[0])?.payload).owner;
|
|
352
|
+
const filteredTurns = turnsOfStep(uwf, turnHead, newStepOwner);
|
|
353
|
+
expect(filteredTurns).toHaveLength(3);
|
|
354
|
+
const contents = filteredTurns.map((h) => turnContent(uwf.store, h));
|
|
355
|
+
expect(contents).toEqual(["t1", "t2", FINAL_TURN]);
|
|
356
|
+
expect(contents).not.toContain("old1");
|
|
357
|
+
expect(contents).not.toContain("old2");
|
|
358
|
+
// Role-keyed active var deleted after step.
|
|
359
|
+
expect(uwf.varStore.list({ exactName: activeTurnsVarName(THREAD_ID, ROLE) })).toEqual([]);
|
|
360
|
+
});
|
|
361
|
+
// Step 4 — cross-process visibility via the thread-keyed turn head var.
|
|
362
|
+
test("an independent reader sees the growing turn chain mid-flight", async () => {
|
|
363
|
+
const uwf = await createUwfStore(tmpDir);
|
|
364
|
+
const { workflow, startHash } = await buildWorkflow(uwf);
|
|
365
|
+
const p = runStep(uwf, workflow, startHash, tmpDir);
|
|
366
|
+
// Sample turn chain from independent reader while step runs
|
|
367
|
+
const { counts, contents } = await sampleTurnChainWhileRunning(casDir, uwf, tmpDir, p);
|
|
368
|
+
// Progress was visible before completion: a non-empty, growing chain.
|
|
369
|
+
const maxObserved = Math.max(...counts);
|
|
370
|
+
expect(maxObserved).toBeGreaterThanOrEqual(2);
|
|
371
|
+
expect(counts.some((n) => n > 0 && n < 3)).toBe(true);
|
|
372
|
+
expect(contents.has("t1")).toBe(true);
|
|
373
|
+
// After completion the role-keyed var is gone
|
|
374
|
+
const after = openReader(casDir);
|
|
375
|
+
try {
|
|
376
|
+
expect(after.store.var.list({ namePrefix: `${ACTIVE_TURNS_VAR_PREFIX}${THREAD_ID}/` })).toEqual([]);
|
|
377
|
+
}
|
|
378
|
+
finally {
|
|
379
|
+
after.close();
|
|
380
|
+
}
|
|
381
|
+
// Thread-keyed turn head var still points to the chain
|
|
382
|
+
const finalHead = getActiveTurnHead(uwf.store, THREAD_ID);
|
|
383
|
+
expect(finalHead).not.toBeNull();
|
|
384
|
+
expect(walkTurnChain(uwf, finalHead)).toHaveLength(3);
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
/**
|
|
388
|
+
* Sample the turn chain from an independent reader while a step runs.
|
|
389
|
+
* Returns observed chain lengths and contents.
|
|
390
|
+
*/
|
|
391
|
+
async function sampleTurnChainWhileRunning(casDir, uwf, tmpDir, stepPromise) {
|
|
392
|
+
const counts = [];
|
|
393
|
+
const contents = new Set();
|
|
394
|
+
let finished = false;
|
|
395
|
+
void stepPromise.finally(() => {
|
|
396
|
+
finished = true;
|
|
397
|
+
});
|
|
398
|
+
while (!finished) {
|
|
399
|
+
const reader = openReader(casDir);
|
|
400
|
+
try {
|
|
401
|
+
const head = getActiveTurnHead(reader.store, THREAD_ID);
|
|
402
|
+
if (head !== null) {
|
|
403
|
+
const chain = walkTurnChain({
|
|
404
|
+
store: reader.store,
|
|
405
|
+
schemas: uwf.schemas,
|
|
406
|
+
storageRoot: tmpDir,
|
|
407
|
+
varStore: uwf.varStore,
|
|
408
|
+
}, head);
|
|
409
|
+
counts.push(chain.length);
|
|
410
|
+
for (const h of chain) {
|
|
411
|
+
const c = turnContent(reader.store, h);
|
|
412
|
+
if (c !== null)
|
|
413
|
+
contents.add(c);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
counts.push(0);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
finally {
|
|
421
|
+
reader.close();
|
|
422
|
+
}
|
|
423
|
+
await delay(PER_TURN_MS / 3);
|
|
424
|
+
}
|
|
425
|
+
await stepPromise;
|
|
426
|
+
return { counts, contents, finished };
|
|
427
|
+
}
|
|
428
|
+
//# sourceMappingURL=broker-step-active-turns.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broker-step-active-turns.test.js","sourceRoot":"","sources":["../../src/__tests__/broker-step-active-turns.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 2 (#419) — Turn chain with prev+owner fields and thread-keyed active vars.
|
|
3
|
+
*
|
|
4
|
+
* Covers the spec acceptance scenarios:
|
|
5
|
+
* 1. onTurn writes each turn with prev pointer and owner reference
|
|
6
|
+
* 2. Step-start/step-complete dual node lifecycle
|
|
7
|
+
* 3. Same role multi-round ownership (#412 regression test)
|
|
8
|
+
* 4. Thread-keyed active vars (not role-keyed)
|
|
9
|
+
* 5. Crash recovery isolation (new attempt gets new step-start)
|
|
10
|
+
* 6. Detail node has no turns array (turns self-contained via chain)
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=broker-step-turn-chain-phase2.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broker-step-turn-chain-phase2.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/broker-step-turn-chain-phase2.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|