@parallel-cli/parallel 0.4.6 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +58 -11
- package/dist/agents/agent.js +98 -14
- package/dist/agents/tools.js +218 -20
- package/dist/commands.js +52 -0
- package/dist/controller.js +23 -13
- package/dist/coordination/blackboard.js +37 -1
- package/dist/i18n.js +69 -13
- package/dist/index.js +1 -0
- package/dist/ui/AgentPanel.js +87 -25
- package/dist/ui/App.js +11 -6
- package/dist/ui/AttachApp.js +99 -14
- package/dist/ui/CommandInput.js +12 -2
- package/dist/ui/Timeline.js +5 -0
- package/dist/ui/events.js +20 -17
- package/dist/ui/tokens.js +2 -2
- package/dist/ui/views.js +17 -5
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Parallel are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.4.7 - 2026-06-24
|
|
6
|
+
|
|
7
|
+
### 0.4.7 Added
|
|
8
|
+
|
|
9
|
+
- Added file revision safety for shared-tree co-editing so stale `write_file` retries and `edit_file` calls must re-read and merge concurrent work before mutating.
|
|
10
|
+
- Added immediate agent-to-agent note nudging with duplicate-note suppression, active-agent checks, and rate-limit safeguards.
|
|
11
|
+
- Added visible coordination signals in the Hub, `/board`, `/diff`, and timelines for claims, work-map warnings, notes, approvals, and questions.
|
|
12
|
+
- Added `/review [agent|all] [prompt]`, a lightweight ask-mode reviewer that returns `APPROVE`, `REVISE`, or `BLOCK` with risks, tests to run, and files to inspect.
|
|
13
|
+
- Added Cursor-style per-agent progress steps through `update_steps`, visible in the Hub and attached terminals.
|
|
14
|
+
- Added batched read-only inspection tools (`read_many`, `inspect_project`) plus lightweight performance counters for model turns, tool calls, shell commands, and context usage.
|
|
15
|
+
|
|
16
|
+
### 0.4.7 Changed
|
|
17
|
+
|
|
18
|
+
- Reworked `/board` into a coordination surface with Work map warnings first, agent/path/time metadata, and suggestions to inspect `/focus` or `/diff`.
|
|
19
|
+
- Prioritized incoming notes and work-map context in agent live context so coordination updates are handled before ordinary activity.
|
|
20
|
+
- Updated product messaging around shared awareness: agents work like a live team on one working tree, not isolated background jobs.
|
|
21
|
+
- Reworked agent rows to keep the Hub compact with cropped summaries, cream bullet recaps capped at four lines, mode badges, and visible `full /focus aN` plus `term /attach aN` shortcuts.
|
|
22
|
+
- Reworked dedicated agent terminals with a launch header, hidden raw launch noise in normal mode, append-only final results, and a small live status region so native scrollback remains usable.
|
|
23
|
+
- Tuned agent prompts by mode so `/ask`, `/task`, `/plan`, and `/review` use clearer contracts, early progress steps, batched inspection, and less redundant shell micro-commanding.
|
|
24
|
+
|
|
25
|
+
### 0.4.7 Fixed
|
|
26
|
+
|
|
27
|
+
- Fixed the previous collision retry weakness where a stale writer could receive an adaptation diff and then overwrite without a real re-read.
|
|
28
|
+
- Fixed `edit_file` allowing targeted edits on a stale file as long as `old_string` still existed.
|
|
29
|
+
- Fixed timeline narration being hardcoded in French by routing narration through i18n.
|
|
30
|
+
- Fixed `claim_files` appearing as generic file activity instead of coordination activity.
|
|
31
|
+
- Fixed completed attached terminals repainting large dynamic result panels that could trap mouse-wheel scroll at the top.
|
|
32
|
+
|
|
5
33
|
## 0.4.6 - 2026-06-24
|
|
6
34
|
|
|
7
35
|
### 0.4.6 Added
|
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Parallel
|
|
2
2
|
|
|
3
|
-
Real-time
|
|
3
|
+
Real-time coding agents that work like a live team, not isolated background jobs.
|
|
4
4
|
|
|
5
|
-
Parallel lets
|
|
5
|
+
Parallel lets several AI coding agents co-edit the same repository at the same time with shared awareness injected before every model action. Each agent has its own task, mode, live activity timeline, model, and visible coordination context. The TUI stays keyboard-first so you can launch work, inspect progress, answer approvals, steer agents, review risks, and reconcile changes without leaving the terminal.
|
|
6
6
|
|
|
7
|
-
> One
|
|
7
|
+
> One working tree. Many agents. Shared awareness. Human in control.
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/@parallel-cli/parallel)
|
|
10
10
|

|
|
@@ -13,14 +13,18 @@ Parallel lets you run several AI coding agents on the same repository at the sam
|
|
|
13
13
|
|
|
14
14
|
## Highlights
|
|
15
15
|
|
|
16
|
-
- Run multiple agents
|
|
17
|
-
- Choose explicit modes: `/ask`, `/task`, and `/
|
|
16
|
+
- Run multiple agents as a live team on one shared working tree.
|
|
17
|
+
- Choose explicit modes: `/ask`, `/task`, `/plan`, and `/review`.
|
|
18
18
|
- Type plain text to launch a task agent immediately.
|
|
19
19
|
- Use context-aware input in the hub, focus view, and attached agent terminals.
|
|
20
20
|
- Steer one agent with `@a1 ...` or broadcast with `@all ...`.
|
|
21
21
|
- Open dedicated agent terminals with native scrollback.
|
|
22
22
|
- Use a cleaner Codex-like hub with a framed header, focused prompt bar, and quieter empty state.
|
|
23
23
|
- Review agents, notes, file activity, diffs, cost, skills, specialists, and saved sessions from the TUI.
|
|
24
|
+
- Use `/review [agent|all]` to spawn a lightweight ask-mode reviewer with verdict, risks, tests, and files to inspect.
|
|
25
|
+
- Avoid lost work with file revision safety: stale `write_file` and `edit_file` calls must re-read and merge before retrying.
|
|
26
|
+
- Nudge agents immediately when another agent posts a targeted note, with dedupe and rate-limit safeguards.
|
|
27
|
+
- See overlapping claims and repeated co-edit conflicts in the Hub, `/board`, `/diff`, and agent timelines.
|
|
24
28
|
- Track shell-created file mutations in the same live diff feed as agent edits.
|
|
25
29
|
- Configure OpenAI-compatible providers through a guided wizard and settings panel.
|
|
26
30
|
- Use 29 provider presets across Western, Chinese, Gateway, Inference, and Local categories.
|
|
@@ -86,6 +90,7 @@ Use explicit modes when intent matters:
|
|
|
86
90
|
/ask Reviewer: should we split the CLI parser?
|
|
87
91
|
/plan Migration: propose the safest rollout for the config change
|
|
88
92
|
/task Builder: implement the approved plan
|
|
93
|
+
/review all before we commit
|
|
89
94
|
```
|
|
90
95
|
|
|
91
96
|
Steer a running agent:
|
|
@@ -102,11 +107,36 @@ Broadcast to every agent:
|
|
|
102
107
|
|
|
103
108
|
`@all` steers active agents in real time. Finished, stopped, or errored agents are not relaunched by a broadcast.
|
|
104
109
|
|
|
110
|
+
## Best Use Case: Coupled Work
|
|
111
|
+
|
|
112
|
+
Parallel is strongest when the work is too coupled for isolated fan-out and too large for one agent.
|
|
113
|
+
|
|
114
|
+
Example live-team flow:
|
|
115
|
+
|
|
116
|
+
```text
|
|
117
|
+
/task API: define the new billing quote contract in src/api/quotes.ts
|
|
118
|
+
/task Client: build the UI client against the quote contract
|
|
119
|
+
/task Tests: write integration coverage for quote creation and validation
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The API agent can claim `src/api`, post a note with the proposed signature, and update the contract. The client agent sees that note and the diff before its next model action, re-reads the file, and adapts without inventing a second interface. The tests agent watches both sides, adds coverage, and can ask for clarification before the three agents collide.
|
|
123
|
+
|
|
124
|
+
Before committing:
|
|
125
|
+
|
|
126
|
+
```text
|
|
127
|
+
/review all verify the API contract, client usage, and tests agree
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The reviewer is ask-only: it does not edit, does not gate the session globally, and returns a structured verdict with risks and validation steps.
|
|
131
|
+
|
|
105
132
|
## Agent Modes
|
|
106
133
|
|
|
107
134
|
- `/ask`: questions, reviews, audits, and tradeoffs. The agent answers and advises; mutating tools and shell commands are blocked.
|
|
108
|
-
- `/task`: implementation work. The agent can execute, edit, validate, and summarize.
|
|
135
|
+
- `/task`: implementation work. The agent can execute, edit, validate, and summarize. It may also conclude that no file change is needed when the task is a verification.
|
|
109
136
|
- `/plan`: risky or unclear work. The agent inspects first, presents a plan, then edits only after explicit approval. A timeout does not approve the plan.
|
|
137
|
+
- `/review`: lightweight reviewer around `/ask`. It inspects the current shared-tree work and returns `APPROVE`, `REVISE`, or `BLOCK` with risks, tests to run, and files to inspect.
|
|
138
|
+
|
|
139
|
+
Task and plan agents maintain a small Cursor-style checklist with one active step at a time. The runtime also encourages batched inspection through `read_many` and `inspect_project` so agents avoid slow chains of tiny read-only shell commands.
|
|
110
140
|
|
|
111
141
|
Aliases:
|
|
112
142
|
|
|
@@ -118,7 +148,7 @@ Plain text is equivalent to `/task`.
|
|
|
118
148
|
|
|
119
149
|
## Control Room
|
|
120
150
|
|
|
121
|
-
The main TUI is the Parallel hub. The default view stays intentionally quiet: a Codex-like framed header, cream-toned accents, a focused prompt block, and detailed status moved into explicit views.
|
|
151
|
+
The main TUI is the Parallel hub. The default view stays intentionally quiet: a Codex-like framed header, cream-toned accents, a focused prompt block, compact cropped agent rows, and detailed status moved into explicit views.
|
|
122
152
|
|
|
123
153
|
It is designed to answer:
|
|
124
154
|
|
|
@@ -128,6 +158,11 @@ It is designed to answer:
|
|
|
128
158
|
- what changed in the project
|
|
129
159
|
- what model, provider, shell mode, and cost are active
|
|
130
160
|
|
|
161
|
+
Agent rows stay compact even when summaries are long. Use the row shortcuts to expand the right level of detail:
|
|
162
|
+
|
|
163
|
+
- `full /focus a1`: open the full in-Hub transcript and result for one agent.
|
|
164
|
+
- `term /attach a1`: reopen that agent's dedicated terminal.
|
|
165
|
+
|
|
131
166
|
Input has three explicit contexts:
|
|
132
167
|
|
|
133
168
|
- Hub: plain text launches a new `/task` agent. Slash suggestions show hub commands and agent arguments autocomplete for `/focus`, `/send`, `/attach`, `/pause`, `/resume`, `/stop`, `/restore`, and `/commit`.
|
|
@@ -146,6 +181,8 @@ Common hub commands:
|
|
|
146
181
|
- `/agents`: agent overview.
|
|
147
182
|
- `/focus a1`: inspect and steer one agent.
|
|
148
183
|
- `/raw`: toggle raw detail in focus view.
|
|
184
|
+
- `/attach a1`: open or reopen an agent's dedicated terminal.
|
|
185
|
+
- `/review all`: ask-mode reviewer with verdict, risks, tests, and files to inspect.
|
|
149
186
|
- `/board`: shared blackboard, claims, notes, and file activity.
|
|
150
187
|
- `/diff`: live diff history.
|
|
151
188
|
- `/cost`: token and cost breakdown.
|
|
@@ -180,8 +217,10 @@ parallel attach a1 --root .
|
|
|
180
217
|
|
|
181
218
|
Attached terminals show:
|
|
182
219
|
|
|
220
|
+
- a launch header with agent, mode, model, and task
|
|
183
221
|
- the selected agent's live timeline
|
|
184
222
|
- native terminal scrollback
|
|
223
|
+
- append-only final results after `done`, `error`, or `stopped`
|
|
185
224
|
- model, elapsed time, context, and cost
|
|
186
225
|
- other agents' current state
|
|
187
226
|
- approval and question prompts for that agent
|
|
@@ -197,6 +236,7 @@ plain text sends a message to this agent
|
|
|
197
236
|
/task Tests: write parser regression tests
|
|
198
237
|
/ask Reviewer: is this result safe to merge?
|
|
199
238
|
/plan Migration: prepare a migration plan
|
|
239
|
+
/review all before commit
|
|
200
240
|
/raw
|
|
201
241
|
/quit
|
|
202
242
|
```
|
|
@@ -265,6 +305,7 @@ If the update succeeds, restart Parallel to run the new version. Use `parallel -
|
|
|
265
305
|
- `/ask [Name:] <question> [--model=m]`: launch an ask-only agent.
|
|
266
306
|
- `/task [Name:] <task> [--model=m] [#skill]`: launch a task agent. Plain text does the same.
|
|
267
307
|
- `/plan [Name:] <task> [--model=m]`: launch a plan-first agent. It cannot mutate files or run risky shell commands until you manually approve the plan.
|
|
308
|
+
- `/review [agent|all] [prompt]`: launch a lightweight ask-mode reviewer for one agent or the whole shared tree.
|
|
268
309
|
- `/issue <n>`: spawn a task from a GitHub issue. Requires the `gh` CLI, a GitHub repository, and `gh auth login`.
|
|
269
310
|
- `/specialist <name> <task>`: spawn with a specialist persona.
|
|
270
311
|
- `/specialist new <name> [global]`: create a specialist template.
|
|
@@ -293,7 +334,7 @@ If the update succeeds, restart Parallel to run the new version. Use `parallel -
|
|
|
293
334
|
### Views And Sessions
|
|
294
335
|
|
|
295
336
|
- `/agents`: agent overview.
|
|
296
|
-
- `/board`: shared blackboard,
|
|
337
|
+
- `/board`: shared blackboard, work-map warnings, claims, file activity, and notes.
|
|
297
338
|
- `/notes`: full notes history.
|
|
298
339
|
- `/diff`: live diff history.
|
|
299
340
|
- `/cost`: token and cost breakdown.
|
|
@@ -375,15 +416,21 @@ When an agent writes a file:
|
|
|
375
416
|
|
|
376
417
|
1. Parallel checks whether the file changed since that agent last read it.
|
|
377
418
|
2. If the file is unchanged, the write proceeds.
|
|
378
|
-
3. If another agent changed it, the write is rejected
|
|
379
|
-
4. The
|
|
419
|
+
3. If another agent or shell command changed it, the write is rejected with an adaptation diff.
|
|
420
|
+
4. The stale baseline is not silently synchronized. The agent must call `read_file`, merge both intentions on top of the current revision, and retry.
|
|
380
421
|
|
|
381
|
-
This keeps agents moving without allowing silent overwrites.
|
|
422
|
+
The same stale-read guard applies to `edit_file`, even when `old_string` still exists. This keeps agents moving without allowing silent overwrites.
|
|
382
423
|
|
|
383
424
|
Commands run through `run_command` are also snapshotted before and after execution. If a shell command edits, creates, or deletes tracked project files, Parallel records those mutations in `/diff`, `/board`, and `/commit` ownership just like tool-based edits.
|
|
384
425
|
|
|
385
426
|
The work map is advisory, not a lock. Agents can declare claims with `claim_files`; Parallel detects overlapping claims and repeated conflicts, then shows non-blocking warnings in `/board` and injects them into agent context so agents can coordinate before collisions become expensive.
|
|
386
427
|
|
|
428
|
+
## Shared-Tree Vs Isolated Agents
|
|
429
|
+
|
|
430
|
+
Use Parallel's shared-tree mode when agents need to negotiate live contracts: API and client, schema and tests, parser and docs, or any change where one agent's edit should affect another agent's next step.
|
|
431
|
+
|
|
432
|
+
Use isolated agents or separate worktrees for embarrassingly parallel work: unrelated files, independent chores, or experiments you only want to merge after review. Parallel's identity is the shared-tree team workflow; isolation is a future complement, not the default.
|
|
433
|
+
|
|
387
434
|
## Headless Mode
|
|
388
435
|
|
|
389
436
|
For CI and scripts, run without the TUI:
|
package/dist/agents/agent.js
CHANGED
|
@@ -19,12 +19,14 @@ AGENT MODE: ${mode}
|
|
|
19
19
|
${mode === 'ask'
|
|
20
20
|
? `ASK MODE:
|
|
21
21
|
- You are advisory only. Do not modify files.
|
|
22
|
-
-
|
|
22
|
+
- Prefer search/read_file/read_many/inspect_project over shell. Use safe read-only commands only when internal tools are insufficient.
|
|
23
|
+
- Keep the investigation short and targeted. Do not run heavy validation loops unless the user explicitly asks.
|
|
23
24
|
- Do not run mutating commands, write files, edit files, claim files, or commit.
|
|
24
25
|
- Finish with task_complete using this user-facing structure in ${userLang}: "Réponse courte", "Recommandation", "Pourquoi", "Prochaines étapes".`
|
|
25
26
|
: mode === 'plan'
|
|
26
27
|
? `PLAN MODE:
|
|
27
28
|
- Explore first with read-only tools.
|
|
29
|
+
- Batch independent reads/searches with read_many or inspect_project. Keep exploration broad enough to be correct but bounded.
|
|
28
30
|
- Before modifying any file or running mutating commands, call ask_user with a concrete implementation plan.
|
|
29
31
|
- The plan must include steps, files you expect to touch, risks, and validation.
|
|
30
32
|
- Use options ["Approve", "Revise"], recommended "Revise" so timeout never approves changes.
|
|
@@ -32,7 +34,8 @@ ${mode === 'ask'
|
|
|
32
34
|
- Finish with task_complete using this user-facing structure in ${userLang}: "Plan appliqué", "Ce que j’ai modifié", "Validation", "Risques restants".`
|
|
33
35
|
: `TASK MODE:
|
|
34
36
|
- Execute the user's objective end-to-end.
|
|
35
|
-
-
|
|
37
|
+
- Use this loop: create visible steps, batch inspect, act, batch validate, summarize.
|
|
38
|
+
- If the task is a verification/audit and the correct outcome is no file changes, that is valid task work. Say explicitly in task_complete that no modification was necessary and why.
|
|
36
39
|
- Ask the user only when blocked or when a risky product decision cannot be inferred.
|
|
37
40
|
- Finish with task_complete using this user-facing structure in ${userLang}: "Ce que j’ai fait", "Ce que j’ai vérifié", "Résultat", "Détails techniques".`}
|
|
38
41
|
${skillsList
|
|
@@ -59,13 +62,16 @@ PARALLEL'S PHILOSOPHY — REAL-TIME CO-EDITING, NEVER ANY BLOCKING:
|
|
|
59
62
|
8. MAKE THE SHARED AWARENESS VISIBLE: when another agent's work influenced a decision of yours (you reused their function, adapted to their diff, avoided their work area), SAY IT explicitly — in a post_note to them ("I saw you changed X, so I did Y") and in your task_complete summary (name the agent and what you built on). The user must be able to SEE that you worked as a team, not as isolated bots.
|
|
60
63
|
|
|
61
64
|
WORK METHOD:
|
|
62
|
-
-
|
|
65
|
+
- For non-trivial work, call update_steps early with 3-6 concrete steps. Keep exactly one step active and mark steps done as you complete them.
|
|
66
|
+
- Explore first before modifying. Decide all independent reads/searches you need, then batch them with read_many or inspect_project instead of calling tools one by one.
|
|
67
|
+
- Use run_command for builds/tests/validation and genuinely useful shell scripts. Do NOT spend many turns running grep/head/tail/wc/awk cascades; batch independent shell checks into one labelled command or use inspect_project.
|
|
63
68
|
- Declare your work area with claim_files when you start (and when it changes): it prevents collisions without ever locking anything.
|
|
64
69
|
- If you discover a durable, non-obvious fact about the project (convention, decision, pitfall), save it with remember(fact) for future agents.
|
|
65
70
|
- wait_for_agent exists for hard dependencies only — prefer progressing on another part of your task over waiting.
|
|
66
71
|
- Prefer edit_file (targeted changes) over write_file (full rewrite): targeted edits coexist better in parallel.
|
|
67
72
|
- Make minimal changes; do not rewrite what already works.
|
|
68
73
|
- Verify your work when relevant (run_command for tests/build), then finish with task_complete.
|
|
74
|
+
- Performance discipline: minimize model turns. If multiple tool calls are independent, make them in the same assistant turn. If several shell checks are independent, run one labelled command.
|
|
69
75
|
- The task_complete summary is user-facing. Make it structured and specific in ${userLang}, not just "done":
|
|
70
76
|
1. What I did — concrete outcome in 1-2 sentences.
|
|
71
77
|
2. Files changed or inspected — mention paths when relevant.
|
|
@@ -76,6 +82,29 @@ WORK METHOD:
|
|
|
76
82
|
LANGUAGE: write notes addressed to "user" and your task_complete summary in ${userLang}. Notes to other agents and code stay in English.`;
|
|
77
83
|
/** Assumed context window (tokens) when the provider does not advertise one. */
|
|
78
84
|
const CONTEXT_WINDOW = 128_000;
|
|
85
|
+
const EMPTY_PERF = {
|
|
86
|
+
modelTurns: 0,
|
|
87
|
+
toolCalls: 0,
|
|
88
|
+
shellCommands: 0,
|
|
89
|
+
shellMs: 0,
|
|
90
|
+
readOnlyShellCommands: 0,
|
|
91
|
+
};
|
|
92
|
+
function noChangeTaskLine() {
|
|
93
|
+
switch (getLang()) {
|
|
94
|
+
case 'fr':
|
|
95
|
+
return 'Mode task: vérification sans changement de fichier nécessaire.';
|
|
96
|
+
case 'es':
|
|
97
|
+
return 'Modo task: verificación sin cambios de archivos necesarios.';
|
|
98
|
+
case 'zh':
|
|
99
|
+
return 'Task 模式:已完成验证,无需修改文件。';
|
|
100
|
+
case 'en':
|
|
101
|
+
default:
|
|
102
|
+
return 'Task mode: verification completed with no file changes needed.';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function isReadOnlyShell(command) {
|
|
106
|
+
return /\b(grep|rg|head|tail|wc|awk|sed|cat|ls|find)\b/.test(command) && !/[>|;]/.test(command);
|
|
107
|
+
}
|
|
79
108
|
export class Agent {
|
|
80
109
|
opts;
|
|
81
110
|
id;
|
|
@@ -90,6 +119,7 @@ export class Agent {
|
|
|
90
119
|
stopped = false;
|
|
91
120
|
lastNoteId = 0;
|
|
92
121
|
lastChangeId = 0;
|
|
122
|
+
readOnlyShellStreak = 0;
|
|
93
123
|
constructor(opts) {
|
|
94
124
|
this.opts = opts;
|
|
95
125
|
this.id = opts.id;
|
|
@@ -114,6 +144,8 @@ export class Agent {
|
|
|
114
144
|
cost: opts.price ? 0 : null,
|
|
115
145
|
startedAt: Date.now(),
|
|
116
146
|
specialist: opts.specialist?.name,
|
|
147
|
+
progressSteps: [],
|
|
148
|
+
perf: { ...EMPTY_PERF },
|
|
117
149
|
};
|
|
118
150
|
this.board.registerAgent(info);
|
|
119
151
|
// Skip notes/changes that existed before this agent was born
|
|
@@ -165,9 +197,13 @@ export class Agent {
|
|
|
165
197
|
* A note addressed to this agent just arrived: interrupt the current model
|
|
166
198
|
* call so the next turn (which injects unread notes) starts immediately.
|
|
167
199
|
*/
|
|
168
|
-
nudge() {
|
|
200
|
+
nudge(reason = 'reading team update') {
|
|
201
|
+
if (this.finished || this.stopped || this.paused)
|
|
202
|
+
return false;
|
|
169
203
|
this.steered = true;
|
|
204
|
+
this.board.setAgentState(this.id, 'listening', reason);
|
|
170
205
|
this.llmAbort?.abort();
|
|
206
|
+
return true;
|
|
171
207
|
}
|
|
172
208
|
/**
|
|
173
209
|
* Append a message to the in-memory history AND to the conversation file
|
|
@@ -189,6 +225,18 @@ export class Agent {
|
|
|
189
225
|
await new Promise((r) => setTimeout(r, 300));
|
|
190
226
|
}
|
|
191
227
|
}
|
|
228
|
+
updatePerf(delta) {
|
|
229
|
+
const current = this.board.agents.get(this.id)?.perf ?? EMPTY_PERF;
|
|
230
|
+
this.board.updateAgent(this.id, {
|
|
231
|
+
perf: {
|
|
232
|
+
modelTurns: current.modelTurns + (delta.modelTurns ?? 0),
|
|
233
|
+
toolCalls: current.toolCalls + (delta.toolCalls ?? 0),
|
|
234
|
+
shellCommands: current.shellCommands + (delta.shellCommands ?? 0),
|
|
235
|
+
shellMs: current.shellMs + (delta.shellMs ?? 0),
|
|
236
|
+
readOnlyShellCommands: current.readOnlyShellCommands + (delta.readOnlyShellCommands ?? 0),
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
}
|
|
192
240
|
/**
|
|
193
241
|
* Build the live context injected before EVERY model call:
|
|
194
242
|
* other agents' status + their fresh diffs + unread notes.
|
|
@@ -197,6 +245,15 @@ export class Agent {
|
|
|
197
245
|
liveContext() {
|
|
198
246
|
let hasNews = false;
|
|
199
247
|
const parts = ['[REAL TIME]', this.board.snapshotFor(this.id)];
|
|
248
|
+
const notes = this.board.notesFor(this.name, this.lastNoteId);
|
|
249
|
+
if (notes.length > 0) {
|
|
250
|
+
this.lastNoteId = notes[notes.length - 1].id;
|
|
251
|
+
hasNews = true;
|
|
252
|
+
parts.push('\n[PRIORITY NOTES RECEIVED — take them into account now]');
|
|
253
|
+
for (const n of notes) {
|
|
254
|
+
parts.push(` • from ${n.from}: ${n.content}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
200
257
|
const changes = this.board.changesSince(this.id, this.lastChangeId);
|
|
201
258
|
if (changes.length > 0) {
|
|
202
259
|
this.lastChangeId = changes[changes.length - 1].id;
|
|
@@ -219,15 +276,6 @@ export class Agent {
|
|
|
219
276
|
}
|
|
220
277
|
parts.push('Analyze these diffs: if any of them touches your work area, re-read the affected file and adapt. NEVER undo these changes.');
|
|
221
278
|
}
|
|
222
|
-
const notes = this.board.notesFor(this.name, this.lastNoteId);
|
|
223
|
-
if (notes.length > 0) {
|
|
224
|
-
this.lastNoteId = notes[notes.length - 1].id;
|
|
225
|
-
hasNews = true;
|
|
226
|
-
parts.push('\n[NOTES RECEIVED — take them into account now]');
|
|
227
|
-
for (const n of notes) {
|
|
228
|
-
parts.push(` • from ${n.from}: ${n.content}`);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
279
|
parts.push('\nContinue your task taking the above into account. Use tools, or task_complete if finished.');
|
|
232
280
|
return { text: parts.join('\n'), hasNews };
|
|
233
281
|
}
|
|
@@ -322,6 +370,7 @@ export class Agent {
|
|
|
322
370
|
this.llmAbort = null;
|
|
323
371
|
}
|
|
324
372
|
this.steered = false;
|
|
373
|
+
this.updatePerf({ modelTurns: 1 });
|
|
325
374
|
const a = this.board.agents.get(this.id);
|
|
326
375
|
if (a) {
|
|
327
376
|
// Real-time financial view: accrue the cost of this round immediately.
|
|
@@ -378,11 +427,40 @@ export class Agent {
|
|
|
378
427
|
this.board.log(this.id, 'tool', label);
|
|
379
428
|
}
|
|
380
429
|
this.board.updateAgent(this.id, { currentAction: label.slice(0, 80) });
|
|
430
|
+
const shellStartedAt = tc.function.name === 'run_command' ? Date.now() : 0;
|
|
381
431
|
const result = await this.executor.execute(tc.function.name, args);
|
|
432
|
+
const shellMs = shellStartedAt ? Date.now() - shellStartedAt : 0;
|
|
433
|
+
const readOnlyShell = tc.function.name === 'run_command' && isReadOnlyShell(String(args.command ?? ''));
|
|
434
|
+
this.updatePerf({
|
|
435
|
+
toolCalls: 1,
|
|
436
|
+
shellCommands: tc.function.name === 'run_command' ? 1 : 0,
|
|
437
|
+
shellMs,
|
|
438
|
+
readOnlyShellCommands: readOnlyShell ? 1 : 0,
|
|
439
|
+
});
|
|
440
|
+
if (readOnlyShell) {
|
|
441
|
+
this.readOnlyShellStreak++;
|
|
442
|
+
if (this.readOnlyShellStreak >= 3) {
|
|
443
|
+
this.record({
|
|
444
|
+
role: 'user',
|
|
445
|
+
content: '[PERFORMANCE CORRECTION] You are using several read-only shell micro-commands. Batch the next inspection with read_many/inspect_project or a single labelled shell command, then continue.',
|
|
446
|
+
});
|
|
447
|
+
this.readOnlyShellStreak = 0;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
else if (tc.function.name !== 'update_status' && tc.function.name !== 'update_steps') {
|
|
451
|
+
this.readOnlyShellStreak = 0;
|
|
452
|
+
}
|
|
382
453
|
if (result === '__TASK_COMPLETE__') {
|
|
383
454
|
completed = true;
|
|
384
455
|
const summary = String(args.summary ?? 'Task complete.');
|
|
385
|
-
this.board.
|
|
456
|
+
const changedByThisAgent = this.board.changes.filter((c) => c.agentId === this.id).length;
|
|
457
|
+
const noChangePrefix = this.opts.mode === 'task' && changedByThisAgent === 0
|
|
458
|
+
? `${noChangeTaskLine()}\n\n`
|
|
459
|
+
: '';
|
|
460
|
+
this.board.updateAgent(this.id, {
|
|
461
|
+
lastResult: `${noChangePrefix}${summary}`,
|
|
462
|
+
progressSteps: (this.board.agents.get(this.id)?.progressSteps ?? []).map((s) => ({ ...s, status: 'done' })),
|
|
463
|
+
});
|
|
386
464
|
// ONE short headline note (the full summary lives in lastResult and
|
|
387
465
|
// is rendered as the agent's recap) — no duplicated walls of text.
|
|
388
466
|
const headline = summary.split('\n').find((l) => l.trim())?.trim() ?? 'Task complete.';
|
|
@@ -419,6 +497,8 @@ export class Agent {
|
|
|
419
497
|
switch (name) {
|
|
420
498
|
case 'read_file':
|
|
421
499
|
return `📖 read ${args.path}`;
|
|
500
|
+
case 'read_many':
|
|
501
|
+
return `📚 read ${Array.isArray(args.paths) ? args.paths.slice(0, 3).join(', ') : 'files'}`;
|
|
422
502
|
case 'write_file':
|
|
423
503
|
return `✏ write ${args.path}`;
|
|
424
504
|
case 'edit_file':
|
|
@@ -427,12 +507,16 @@ export class Agent {
|
|
|
427
507
|
return `📁 ls ${args.path ?? '.'}`;
|
|
428
508
|
case 'search':
|
|
429
509
|
return `🔍 search /${args.pattern}/`;
|
|
510
|
+
case 'inspect_project':
|
|
511
|
+
return `🔎 inspect project`;
|
|
430
512
|
case 'run_command':
|
|
431
513
|
return `$ ${args.command}`;
|
|
432
514
|
case 'post_note':
|
|
433
515
|
return `✉ note → ${args.to}`;
|
|
434
516
|
case 'update_status':
|
|
435
517
|
return `📢 ${args.status}`;
|
|
518
|
+
case 'update_steps':
|
|
519
|
+
return `☑ update steps`;
|
|
436
520
|
case 'ask_user':
|
|
437
521
|
return `❓ ${String(args.question ?? '').slice(0, 60)}`;
|
|
438
522
|
case 'load_skill':
|