zelari-code 0.7.9 → 0.7.11
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/LICENSE +37 -37
- package/README.md +320 -295
- package/bin/zelari-code.js +62 -62
- package/dist/cli/app.js +33 -3
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/components/LiveRegion.js +7 -3
- package/dist/cli/components/LiveRegion.js.map +1 -1
- package/dist/cli/components/SelectList.js +67 -0
- package/dist/cli/components/SelectList.js.map +1 -0
- package/dist/cli/components/Spinner.js +51 -0
- package/dist/cli/components/Spinner.js.map +1 -0
- package/dist/cli/components/SplashScreen.js +85 -85
- package/dist/cli/components/StatusBar.js +42 -34
- package/dist/cli/components/StatusBar.js.map +1 -1
- package/dist/cli/headless.js +10 -10
- package/dist/cli/hooks/useSlashDispatch.js +11 -1
- package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
- package/dist/cli/keyStore.js +2 -2
- package/dist/cli/keyStore.js.map +1 -1
- package/dist/cli/main.bundled.js +15146 -14919
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +1 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/modelDiscovery.js +42 -5
- package/dist/cli/modelDiscovery.js.map +1 -1
- package/dist/cli/provider/openai-compatible.js +4 -2
- package/dist/cli/provider/openai-compatible.js.map +1 -1
- package/dist/cli/slashCommands.js +22 -5
- package/dist/cli/slashCommands.js.map +1 -1
- package/dist/cli/slashHandlers/provider.js +102 -5
- package/dist/cli/slashHandlers/provider.js.map +1 -1
- package/package.json +2 -2
- package/dist/agents/advancedTools.js +0 -115
- package/dist/agents/advancedTools.js.map +0 -1
- package/dist/agents/councilApi.js +0 -375
- package/dist/agents/councilApi.js.map +0 -1
- package/dist/agents/councilDirectives.js +0 -100
- package/dist/agents/councilDirectives.js.map +0 -1
- package/dist/agents/promoteMember.js +0 -210
- package/dist/agents/promoteMember.js.map +0 -1
- package/dist/agents/promptModules.js +0 -139
- package/dist/agents/promptModules.js.map +0 -1
- package/dist/agents/roles.js +0 -299
- package/dist/agents/roles.js.map +0 -1
- package/dist/agents/skills/builtin/debugging.js +0 -248
- package/dist/agents/skills/builtin/debugging.js.map +0 -1
- package/dist/agents/skills/builtin/docs.js +0 -301
- package/dist/agents/skills/builtin/docs.js.map +0 -1
- package/dist/agents/skills/builtin/git-ops.js +0 -301
- package/dist/agents/skills/builtin/git-ops.js.map +0 -1
- package/dist/agents/skills/builtin/planning.js +0 -335
- package/dist/agents/skills/builtin/planning.js.map +0 -1
- package/dist/agents/skills/builtin/refactoring.js +0 -261
- package/dist/agents/skills/builtin/refactoring.js.map +0 -1
- package/dist/agents/skills/builtin/review.js +0 -302
- package/dist/agents/skills/builtin/review.js.map +0 -1
- package/dist/agents/skills/builtin/testing.js +0 -245
- package/dist/agents/skills/builtin/testing.js.map +0 -1
- package/dist/agents/skills.js +0 -272
- package/dist/agents/skills.js.map +0 -1
- package/dist/agents/systemPromptBuilder.js +0 -151
- package/dist/agents/systemPromptBuilder.js.map +0 -1
- package/dist/agents/toolSchemas.js +0 -249
- package/dist/agents/toolSchemas.js.map +0 -1
- package/dist/agents/tools.js +0 -196
- package/dist/agents/tools.js.map +0 -1
- package/dist/agents/vaultTools.js +0 -134
- package/dist/agents/vaultTools.js.map +0 -1
- package/dist/cli/components/CollapsibleToolOutput.js +0 -43
- package/dist/cli/components/CollapsibleToolOutput.js.map +0 -1
- package/dist/cli/components/Header.js +0 -38
- package/dist/cli/components/Header.js.map +0 -1
- package/dist/main/core/AgentHarness.js +0 -467
- package/dist/main/core/AgentHarness.js.map +0 -1
- package/dist/main/core/providerStream.js +0 -99
- package/dist/main/core/providerStream.js.map +0 -1
- package/dist/main/core/sessionJsonl.js +0 -99
- package/dist/main/core/sessionJsonl.js.map +0 -1
- package/dist/main/core/tools/auditLog.js +0 -26
- package/dist/main/core/tools/auditLog.js.map +0 -1
- package/dist/main/core/tools/builtin/filesystem.js +0 -110
- package/dist/main/core/tools/builtin/filesystem.js.map +0 -1
- package/dist/main/core/tools/builtin/listFiles.js +0 -86
- package/dist/main/core/tools/builtin/listFiles.js.map +0 -1
- package/dist/main/core/tools/builtin/search.js +0 -56
- package/dist/main/core/tools/builtin/search.js.map +0 -1
- package/dist/main/core/tools/builtin/shell.js +0 -51
- package/dist/main/core/tools/builtin/shell.js.map +0 -1
- package/dist/main/core/tools/registry.js +0 -71
- package/dist/main/core/tools/registry.js.map +0 -1
- package/dist/main/core/tools/toolTypes.js +0 -8
- package/dist/main/core/tools/toolTypes.js.map +0 -1
- package/dist/main/core/tools/zodBridge.js +0 -56
- package/dist/main/core/tools/zodBridge.js.map +0 -1
- package/dist/shared/eventBus.js +0 -104
- package/dist/shared/eventBus.js.map +0 -1
- package/dist/shared/events.js +0 -73
- package/dist/shared/events.js.map +0 -1
- package/dist/shared/index.js +0 -8
- package/dist/shared/index.js.map +0 -1
- package/dist/types/context.js +0 -3
- package/dist/types/context.js.map +0 -1
- package/dist/types/index.js +0 -2
- package/dist/types/index.js.map +0 -1
- package/dist/types/knowledge.js +0 -2
- package/dist/types/knowledge.js.map +0 -1
- package/dist/types/systemTypes.js +0 -10
- package/dist/types/systemTypes.js.map +0 -1
|
@@ -1,467 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AgentHarness — provider-neutral agent loop.
|
|
3
|
-
*
|
|
4
|
-
* Encapsulates a single agent turn: given a (model, provider, messages, tools)
|
|
5
|
-
* configuration and a provider streaming function, it drives the stream and
|
|
6
|
-
* yields the full {@link BrainEvent} lifecycle as an `AsyncIterable<BrainEvent>`.
|
|
7
|
-
*
|
|
8
|
-
* Electron-free: this module imports ONLY from `electron/shared/` (the event
|
|
9
|
-
* contract + bus) and `electron/main/core/tools/` (the tool registry). It has
|
|
10
|
-
* zero coupling to `llm.ts` or any main-process IPC, so it can run in the
|
|
11
|
-
* Electron main process today and be reused from the Ink CLI in Phase 14.
|
|
12
|
-
*
|
|
13
|
-
* When `toolRegistry` is provided, tool_call deltas trigger real tool
|
|
14
|
-
* execution and emit a matching `tool_execution_end` event. Without it, the
|
|
15
|
-
* harness only emits `tool_execution_start` (legacy behavior, useful for
|
|
16
|
-
* streaming-only consumers).
|
|
17
|
-
*
|
|
18
|
-
* @see docs/plans/2026-06-28-zelari-code.md (Task 12.1 + 14.8)
|
|
19
|
-
*/
|
|
20
|
-
import { createBrainEvent, } from '../../shared/events.js';
|
|
21
|
-
// --- Harness ----------------------------------------------------------------
|
|
22
|
-
/**
|
|
23
|
-
* The agent loop's primary output is the async generator returned by
|
|
24
|
-
* `run()`: every BrainEvent is yielded exactly once, in order. The
|
|
25
|
-
* optional `eventBus` config field is a SIDE-CAR for listeners that
|
|
26
|
-
* want to observe events without consuming the generator — e.g.
|
|
27
|
-
* a metrics collector, a logging sink, or an external UI.
|
|
28
|
-
*
|
|
29
|
-
* **B18 contract**: consumers should EITHER iterate the `run()`
|
|
30
|
-
* generator OR subscribe to the event bus, not both. The same
|
|
31
|
-
* event would otherwise be processed twice (once by the iterator
|
|
32
|
-
* consumer, once by the listener). Today only `app.tsx` iterates
|
|
33
|
-
* `run()`, so no double-processing occurs — but adding a bus
|
|
34
|
-
* listener in the future requires care.
|
|
35
|
-
*/
|
|
36
|
-
export class AgentHarness {
|
|
37
|
-
config;
|
|
38
|
-
eventBus;
|
|
39
|
-
sessionId;
|
|
40
|
-
maxQueuedIterations;
|
|
41
|
-
cancelled = false;
|
|
42
|
-
activeController = null;
|
|
43
|
-
queue = [];
|
|
44
|
-
constructor(config) {
|
|
45
|
-
this.config = config;
|
|
46
|
-
this.eventBus = config.eventBus;
|
|
47
|
-
this.sessionId = config.sessionId ?? crypto.randomUUID();
|
|
48
|
-
this.maxQueuedIterations = config.maxQueuedIterations ?? 3;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Cancel the in-flight run. Events drain until end of stream.
|
|
52
|
-
*
|
|
53
|
-
* Idempotent: calling cancel() multiple times is safe — the cancelled
|
|
54
|
-
* flag stays true and AbortController.abort() is itself a no-op on
|
|
55
|
-
* already-aborted controllers. If no turn is running, this is a
|
|
56
|
-
* no-op (the next run() invocation will check the cancelled flag
|
|
57
|
-
* and emit `agent_end` with `reason: 'cancelled'` before any work).
|
|
58
|
-
*
|
|
59
|
-
* After cancel() returns, the harness should be discarded by the
|
|
60
|
-
* caller (the run() generator finishes after the current turn ends).
|
|
61
|
-
* For mid-stream interrupt + new-prompt injection, see Task C.3.2.
|
|
62
|
-
*/
|
|
63
|
-
cancel() {
|
|
64
|
-
if (this.cancelled)
|
|
65
|
-
return; // idempotent — don't re-abort
|
|
66
|
-
this.cancelled = true;
|
|
67
|
-
this.activeController?.abort();
|
|
68
|
-
}
|
|
69
|
-
/** Current size of the queued user-prompt buffer. */
|
|
70
|
-
get queueLength() {
|
|
71
|
-
return this.queue.length;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Enqueue a user prompt to be processed at the next opportunity.
|
|
75
|
-
* The next prompt in the queue will be appended to the conversation
|
|
76
|
-
* transcript and re-enter the provider stream loop after the current
|
|
77
|
-
* turn finishes. Emits a `queue_update` event so UIs can refresh
|
|
78
|
-
* the displayed counter.
|
|
79
|
-
*
|
|
80
|
-
* If `run()` has already returned (no active loop), the queued
|
|
81
|
-
* prompt will be picked up on the *next* run() call — note this
|
|
82
|
-
* helper does NOT itself trigger a run. Callers wire the
|
|
83
|
-
* dequeue step inside `run()` (Task 18.1).
|
|
84
|
-
*/
|
|
85
|
-
enqueue(userText) {
|
|
86
|
-
this.queue.push(userText);
|
|
87
|
-
const queueEvent = createBrainEvent('queue_update', this.sessionId, {
|
|
88
|
-
queuedCount: this.queue.length,
|
|
89
|
-
});
|
|
90
|
-
this.emit(queueEvent);
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Dequeue the next queued prompt, or `null` if the queue is empty.
|
|
94
|
-
* Emits a `queue_update` event with the new length so UIs can
|
|
95
|
-
* decrement the counter.
|
|
96
|
-
*/
|
|
97
|
-
dequeueNext() {
|
|
98
|
-
const next = this.queue.shift() ?? null;
|
|
99
|
-
const queueEvent = createBrainEvent('queue_update', this.sessionId, {
|
|
100
|
-
queuedCount: this.queue.length,
|
|
101
|
-
});
|
|
102
|
-
this.emit(queueEvent);
|
|
103
|
-
return next;
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Run a single agent turn and yield provider-neutral BrainEvents.
|
|
107
|
-
* The returned AsyncIterable emits all BrainEvents for the run, then completes.
|
|
108
|
-
* Callers can subscribe via eventBus AND iterate the returned iterable.
|
|
109
|
-
*/
|
|
110
|
-
async *run() {
|
|
111
|
-
const startTime = Date.now();
|
|
112
|
-
this.activeController = new AbortController();
|
|
113
|
-
// Emit agent_start
|
|
114
|
-
const startEvent = createBrainEvent('agent_start', this.sessionId, {
|
|
115
|
-
model: this.config.model,
|
|
116
|
-
provider: this.config.provider,
|
|
117
|
-
});
|
|
118
|
-
this.emit(startEvent);
|
|
119
|
-
yield startEvent;
|
|
120
|
-
// === Initial turn (always runs to preserve Phase 12.x behavior) ===
|
|
121
|
-
// The harness processes the messages buffer that was provided in
|
|
122
|
-
// the config. Backward compat: existing callers expect a single
|
|
123
|
-
// provider call here even when the queue is empty.
|
|
124
|
-
const initialMessageId = crypto.randomUUID();
|
|
125
|
-
let totalLength = 0;
|
|
126
|
-
let hadError = false;
|
|
127
|
-
const initialMsgStart = createBrainEvent('message_start', this.sessionId, { messageId: initialMessageId, role: 'assistant' });
|
|
128
|
-
this.emit(initialMsgStart);
|
|
129
|
-
yield initialMsgStart;
|
|
130
|
-
let initialTurnLength = 0;
|
|
131
|
-
const initialFinishRef = { value: 'stop' };
|
|
132
|
-
// Task G.4.3 — capture real provider usage for this turn. The ref
|
|
133
|
-
// is read after runSingleTurn returns and attached to message_end.
|
|
134
|
-
const initialUsageRef = { value: null };
|
|
135
|
-
for await (const ev of this.runSingleTurn(initialMessageId, initialFinishRef, initialUsageRef)) {
|
|
136
|
-
if (ev.type === 'message_delta') {
|
|
137
|
-
initialTurnLength += ev.delta.length;
|
|
138
|
-
}
|
|
139
|
-
else if (ev.type === 'error') {
|
|
140
|
-
// Cancellations are emitted as error events with severity='cancelled'
|
|
141
|
-
// (Task C.3.1) — they must NOT set hadError, otherwise the final
|
|
142
|
-
// agent_end would emit reason='error' instead of 'cancelled'.
|
|
143
|
-
if (ev.severity !== 'cancelled') {
|
|
144
|
-
hadError = true;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
yield ev;
|
|
148
|
-
}
|
|
149
|
-
totalLength += initialTurnLength;
|
|
150
|
-
const initialMsgEnd = createBrainEvent('message_end', this.sessionId, {
|
|
151
|
-
messageId: initialMessageId,
|
|
152
|
-
totalLength: initialTurnLength,
|
|
153
|
-
finishReason: initialFinishRef.value,
|
|
154
|
-
...(initialUsageRef.value ? { usage: initialUsageRef.value } : {}),
|
|
155
|
-
});
|
|
156
|
-
this.emit(initialMsgEnd);
|
|
157
|
-
yield initialMsgEnd;
|
|
158
|
-
// === Agentic tool-call loop ===
|
|
159
|
-
// When the model's finish reason is 'tool_calls', the turn produced tool
|
|
160
|
-
// invocations whose results are now in the transcript (appended by
|
|
161
|
-
// runSingleTurn). Re-enter the provider so the model can consume those
|
|
162
|
-
// results and continue — this is the core agent loop (reason → act →
|
|
163
|
-
// observe → reason). Bounded by MAX_TOOL_LOOP_ITERATIONS to prevent runaway.
|
|
164
|
-
const MAX_TOOL_LOOP_ITERATIONS = 12;
|
|
165
|
-
let toolLoopTurns = 0;
|
|
166
|
-
while (!this.cancelled &&
|
|
167
|
-
!hadError &&
|
|
168
|
-
toolLoopTurns < MAX_TOOL_LOOP_ITERATIONS &&
|
|
169
|
-
initialFinishRef.value === 'tool_calls') {
|
|
170
|
-
toolLoopTurns++;
|
|
171
|
-
const turnMessageId = crypto.randomUUID();
|
|
172
|
-
const msgStart = createBrainEvent('message_start', this.sessionId, { messageId: turnMessageId, role: 'assistant' });
|
|
173
|
-
this.emit(msgStart);
|
|
174
|
-
yield msgStart;
|
|
175
|
-
let turnLength = 0;
|
|
176
|
-
const turnFinishRef = { value: 'stop' };
|
|
177
|
-
const turnUsageRef = { value: null };
|
|
178
|
-
for await (const ev of this.runSingleTurn(turnMessageId, turnFinishRef, turnUsageRef)) {
|
|
179
|
-
if (ev.type === 'message_delta') {
|
|
180
|
-
turnLength += ev.delta.length;
|
|
181
|
-
}
|
|
182
|
-
else if (ev.type === 'error') {
|
|
183
|
-
if (ev.severity !== 'cancelled')
|
|
184
|
-
hadError = true;
|
|
185
|
-
}
|
|
186
|
-
yield ev;
|
|
187
|
-
}
|
|
188
|
-
totalLength += turnLength;
|
|
189
|
-
const msgEnd = createBrainEvent('message_end', this.sessionId, {
|
|
190
|
-
messageId: turnMessageId,
|
|
191
|
-
totalLength: turnLength,
|
|
192
|
-
finishReason: turnFinishRef.value,
|
|
193
|
-
...(turnUsageRef.value ? { usage: turnUsageRef.value } : {}),
|
|
194
|
-
});
|
|
195
|
-
this.emit(msgEnd);
|
|
196
|
-
yield msgEnd;
|
|
197
|
-
// Drive the loop: keep going only if this turn again requested tool calls.
|
|
198
|
-
initialFinishRef.value = turnFinishRef.value;
|
|
199
|
-
if (hadError || this.cancelled)
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
// === Queue drain (Task 18.1) ===
|
|
203
|
-
// After the initial turn, drain queued user prompts up to
|
|
204
|
-
// maxQueuedIterations. Each iteration appends the next dequeued
|
|
205
|
-
// user prompt to messages, then re-enters the provider stream.
|
|
206
|
-
// Loop terminates on cancel, error, empty queue, or max iterations.
|
|
207
|
-
let turns = 0;
|
|
208
|
-
while (turns < this.maxQueuedIterations) {
|
|
209
|
-
if (this.cancelled)
|
|
210
|
-
break;
|
|
211
|
-
if (this.queue.length === 0)
|
|
212
|
-
break;
|
|
213
|
-
const queuedPrompt = this.dequeueNext();
|
|
214
|
-
if (queuedPrompt === null)
|
|
215
|
-
break;
|
|
216
|
-
// Append to conversation transcript for this turn
|
|
217
|
-
this.config.messages.push({ role: 'user', content: queuedPrompt });
|
|
218
|
-
const turnMessageId = crypto.randomUUID();
|
|
219
|
-
const msgStart = createBrainEvent('message_start', this.sessionId, {
|
|
220
|
-
messageId: turnMessageId,
|
|
221
|
-
role: 'assistant',
|
|
222
|
-
});
|
|
223
|
-
this.emit(msgStart);
|
|
224
|
-
yield msgStart;
|
|
225
|
-
let turnLength = 0;
|
|
226
|
-
const turnFinishRef = { value: 'stop' };
|
|
227
|
-
const turnUsageRef = { value: null };
|
|
228
|
-
for await (const ev of this.runSingleTurn(turnMessageId, turnFinishRef, turnUsageRef)) {
|
|
229
|
-
if (ev.type === 'message_delta') {
|
|
230
|
-
turnLength += ev.delta.length;
|
|
231
|
-
}
|
|
232
|
-
else if (ev.type === 'error') {
|
|
233
|
-
hadError = true;
|
|
234
|
-
}
|
|
235
|
-
yield ev;
|
|
236
|
-
}
|
|
237
|
-
totalLength += turnLength;
|
|
238
|
-
const msgEnd = createBrainEvent('message_end', this.sessionId, {
|
|
239
|
-
messageId: turnMessageId,
|
|
240
|
-
totalLength: turnLength,
|
|
241
|
-
finishReason: turnFinishRef.value,
|
|
242
|
-
...(turnUsageRef.value ? { usage: turnUsageRef.value } : {}),
|
|
243
|
-
});
|
|
244
|
-
this.emit(msgEnd);
|
|
245
|
-
yield msgEnd;
|
|
246
|
-
turns++;
|
|
247
|
-
}
|
|
248
|
-
// Emit agent_end
|
|
249
|
-
const agentEnd = createBrainEvent('agent_end', this.sessionId, {
|
|
250
|
-
reason: hadError ? 'error' : this.cancelled ? 'cancelled' : 'completed',
|
|
251
|
-
durationMs: Date.now() - startTime,
|
|
252
|
-
});
|
|
253
|
-
this.emit(agentEnd);
|
|
254
|
-
yield agentEnd;
|
|
255
|
-
this.activeController = null;
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* Run a single provider turn for the current message buffer.
|
|
259
|
-
* Streams from the provider, dispatches deltas to events, executes
|
|
260
|
-
* any tool calls (if a registry was provided). Yields each
|
|
261
|
-
* `BrainEvent` it produces so the caller can re-emit them in
|
|
262
|
-
* the outer generator.
|
|
263
|
-
*
|
|
264
|
-
* Does NOT emit `message_start` / `message_end` — those are the
|
|
265
|
-
* caller's responsibility (so the outer generator can wrap them
|
|
266
|
-
* around the yielded event stream and compute the right
|
|
267
|
-
* `totalLength` from observed deltas).
|
|
268
|
-
*
|
|
269
|
-
* Extracted from the original monolithic `run()` body to enable
|
|
270
|
-
* the queue-draining loop in Task 18.1.
|
|
271
|
-
*/
|
|
272
|
-
async *runSingleTurn(messageId, finishRef, usageRef) {
|
|
273
|
-
try {
|
|
274
|
-
const stream = this.config.providerStream({
|
|
275
|
-
messages: this.config.messages,
|
|
276
|
-
model: this.config.model,
|
|
277
|
-
provider: this.config.provider,
|
|
278
|
-
tools: this.config.tools,
|
|
279
|
-
signal: this.activeController?.signal,
|
|
280
|
-
});
|
|
281
|
-
// Per-turn tool call counter (Task G.2). Reset on every turn so
|
|
282
|
-
// queue-drained turns don't accumulate across prompts.
|
|
283
|
-
let toolCallsThisTurn = 0;
|
|
284
|
-
const maxToolCalls = this.config.maxToolCallsPerTurn;
|
|
285
|
-
// Accumulate this turn's text + tool calls so we can append an assistant
|
|
286
|
-
// message (with tool_calls) to the transcript before re-entering the
|
|
287
|
-
// provider. Without this, tool results would arrive at the API with no
|
|
288
|
-
// preceding assistant tool_calls message → HTTP 400.
|
|
289
|
-
let turnText = '';
|
|
290
|
-
const turnToolCalls = [];
|
|
291
|
-
for await (const delta of stream) {
|
|
292
|
-
if (this.cancelled) {
|
|
293
|
-
// Emit a cancellation error event so consumers (CLI, tests) can
|
|
294
|
-
// observe the mid-stream interrupt (Task C.3.1).
|
|
295
|
-
const cancelEvent = createBrainEvent('error', this.sessionId, {
|
|
296
|
-
severity: 'cancelled',
|
|
297
|
-
message: 'Run cancelled by user.',
|
|
298
|
-
code: 'cancelled',
|
|
299
|
-
});
|
|
300
|
-
this.emit(cancelEvent);
|
|
301
|
-
yield cancelEvent;
|
|
302
|
-
break;
|
|
303
|
-
}
|
|
304
|
-
if (delta.kind === 'text') {
|
|
305
|
-
turnText += delta.delta;
|
|
306
|
-
const deltaEvent = createBrainEvent('message_delta', this.sessionId, { messageId, delta: delta.delta });
|
|
307
|
-
this.emit(deltaEvent);
|
|
308
|
-
yield deltaEvent;
|
|
309
|
-
}
|
|
310
|
-
else if (delta.kind === 'thinking') {
|
|
311
|
-
const thinkEvent = createBrainEvent('thinking_delta', this.sessionId, {
|
|
312
|
-
messageId,
|
|
313
|
-
delta: delta.delta,
|
|
314
|
-
});
|
|
315
|
-
this.emit(thinkEvent);
|
|
316
|
-
yield thinkEvent;
|
|
317
|
-
}
|
|
318
|
-
else if (delta.kind === 'tool_call') {
|
|
319
|
-
toolCallsThisTurn++;
|
|
320
|
-
// Record this tool call so the assistant message (appended after the
|
|
321
|
-
// turn) carries the full tool_calls list the model emitted.
|
|
322
|
-
turnToolCalls.push({ id: delta.toolCallId, name: delta.toolName, args: delta.args });
|
|
323
|
-
const toolStartEvent = createBrainEvent('tool_execution_start', this.sessionId, {
|
|
324
|
-
toolCallId: delta.toolCallId,
|
|
325
|
-
toolName: delta.toolName,
|
|
326
|
-
args: delta.args,
|
|
327
|
-
});
|
|
328
|
-
this.emit(toolStartEvent);
|
|
329
|
-
yield toolStartEvent;
|
|
330
|
-
// Skip registry execution if we've exceeded the per-turn limit
|
|
331
|
-
// (Task G.2, carryover from v3-C C.1.5). Emit a synthetic
|
|
332
|
-
// `tool_execution_end` so the UI can still render the attempt
|
|
333
|
-
// and downstream consumers (e.g. the LLM context) see a clean
|
|
334
|
-
// closure. Without this guard, a council member could fire 50
|
|
335
|
-
// read_file calls in one turn and blow the message context.
|
|
336
|
-
const skipped = typeof maxToolCalls === 'number' && toolCallsThisTurn > maxToolCalls;
|
|
337
|
-
if (this.config.toolRegistry && !skipped) {
|
|
338
|
-
const startMs = Date.now();
|
|
339
|
-
const result = await this.config.toolRegistry.invoke(delta.toolName, delta.args, {
|
|
340
|
-
cwd: this.config.cwd,
|
|
341
|
-
sessionId: this.sessionId,
|
|
342
|
-
signal: this.activeController?.signal,
|
|
343
|
-
});
|
|
344
|
-
let resultStr = '';
|
|
345
|
-
if (result.ok) {
|
|
346
|
-
if (typeof result.value === 'string') {
|
|
347
|
-
resultStr = result.value;
|
|
348
|
-
}
|
|
349
|
-
else if (typeof result.value === 'object' && result.value !== null) {
|
|
350
|
-
resultStr = JSON.stringify(result.value, null, 2);
|
|
351
|
-
}
|
|
352
|
-
else {
|
|
353
|
-
resultStr = String(result.value);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
else {
|
|
357
|
-
resultStr = result.error;
|
|
358
|
-
}
|
|
359
|
-
const endEvent = createBrainEvent('tool_execution_end', this.sessionId, {
|
|
360
|
-
toolCallId: delta.toolCallId,
|
|
361
|
-
result: resultStr,
|
|
362
|
-
isError: !result.ok,
|
|
363
|
-
durationMs: Date.now() - startMs,
|
|
364
|
-
});
|
|
365
|
-
this.emit(endEvent);
|
|
366
|
-
yield endEvent;
|
|
367
|
-
// Append the tool result to the transcript so the next provider
|
|
368
|
-
// turn can see what the tool returned (OpenAI role:'tool' message).
|
|
369
|
-
this.config.messages.push({
|
|
370
|
-
role: 'tool',
|
|
371
|
-
toolCallId: delta.toolCallId,
|
|
372
|
-
content: resultStr,
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
else if (skipped) {
|
|
376
|
-
// Synthetic end event — no registry call, just close out the
|
|
377
|
-
// tool_execution_start with an explicit skip reason. The LLM
|
|
378
|
-
// can see in the next provider turn that this tool didn't run.
|
|
379
|
-
const endEvent = createBrainEvent('tool_execution_end', this.sessionId, {
|
|
380
|
-
toolCallId: delta.toolCallId,
|
|
381
|
-
result: `[skipped] maxToolCallsPerTurn reached (limit=${maxToolCalls})`,
|
|
382
|
-
isError: true,
|
|
383
|
-
durationMs: 0,
|
|
384
|
-
});
|
|
385
|
-
this.emit(endEvent);
|
|
386
|
-
yield endEvent;
|
|
387
|
-
this.config.messages.push({
|
|
388
|
-
role: 'tool',
|
|
389
|
-
toolCallId: delta.toolCallId,
|
|
390
|
-
content: `[skipped] maxToolCallsPerTurn reached (limit=${maxToolCalls})`,
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
else if (delta.kind === 'finish') {
|
|
395
|
-
// Capture the finish reason via the shared ref so the caller
|
|
396
|
-
// can synthesize the matching `message_end`.
|
|
397
|
-
finishRef.value = delta.reason;
|
|
398
|
-
// Append the assistant turn (text + any tool_calls) to the transcript.
|
|
399
|
-
// This MUST happen before the loop re-enters the provider (either via
|
|
400
|
-
// queue drain or a follow-up tool-result turn) so the conversation
|
|
401
|
-
// history stays valid: every role:'tool' message needs a preceding
|
|
402
|
-
// assistant message that declared the matching tool_calls.
|
|
403
|
-
if (turnToolCalls.length > 0 || turnText.length > 0) {
|
|
404
|
-
this.config.messages.push({
|
|
405
|
-
role: 'assistant',
|
|
406
|
-
content: turnText,
|
|
407
|
-
...(turnToolCalls.length > 0 ? { toolCalls: turnToolCalls } : {}),
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
break;
|
|
411
|
-
}
|
|
412
|
-
else if (delta.kind === 'error') {
|
|
413
|
-
const errEvent = createBrainEvent('error', this.sessionId, {
|
|
414
|
-
severity: 'recoverable',
|
|
415
|
-
message: delta.message,
|
|
416
|
-
});
|
|
417
|
-
this.emit(errEvent);
|
|
418
|
-
yield errEvent;
|
|
419
|
-
}
|
|
420
|
-
else if (delta.kind === 'usage') {
|
|
421
|
-
// Provider-reported token usage (Task G.4). The breakdown is
|
|
422
|
-
// captured in the shared ref so the caller's `message_end`
|
|
423
|
-
// synthesis can attach it. The delta itself does not become a
|
|
424
|
-
// standalone BrainEvent (it would be noise in the chat stream);
|
|
425
|
-
// consumers wanting real-time token counts hook the message_end
|
|
426
|
-
// and read `event.usage`.
|
|
427
|
-
usageRef.value = delta.usage;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
catch (err) {
|
|
432
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
433
|
-
const errEvent = createBrainEvent('error', this.sessionId, {
|
|
434
|
-
severity: 'recoverable',
|
|
435
|
-
message: errorMessage,
|
|
436
|
-
});
|
|
437
|
-
this.emit(errEvent);
|
|
438
|
-
yield errEvent;
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
emit(event) {
|
|
442
|
-
if (!this.eventBus)
|
|
443
|
-
return;
|
|
444
|
-
// B24 fix — surface listener errors instead of silently swallowing
|
|
445
|
-
// them. Previously a misbehaving listener would log to console.error
|
|
446
|
-
// (invisible in the Ink UI) and the run would continue, leaving the
|
|
447
|
-
// user with a hung tool or missing UI update. We still don't crash
|
|
448
|
-
// the agent loop, but the failure is observable: each listener error
|
|
449
|
-
// is yielded as a synthetic `error` BrainEvent so the UI can show it.
|
|
450
|
-
try {
|
|
451
|
-
this.eventBus.emit(event);
|
|
452
|
-
}
|
|
453
|
-
catch (err) {
|
|
454
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
455
|
-
// Use console.error as last resort so it's visible even when no
|
|
456
|
-
// consumer is iterating run() (e.g. test harnesses that only listen
|
|
457
|
-
// to the bus).
|
|
458
|
-
console.error('[AgentHarness] eventBus listener threw:', message);
|
|
459
|
-
// We don't yield here (emit is sync, run() is the yield path).
|
|
460
|
-
// Document the contract: callers iterating run() will see the
|
|
461
|
-
// original event; the bus-listener error is logged but does not
|
|
462
|
-
// crash the run. For caller-side visibility, callers should still
|
|
463
|
-
// catch errors inside their own listeners.
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
//# sourceMappingURL=AgentHarness.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AgentHarness.js","sourceRoot":"","sources":["../../../src/main/core/AgentHarness.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Convert AgentHarness AgentMessage[] → legacy {role, content}[].
|
|
3
|
-
* Tool messages pass through their content (renderer fills these).
|
|
4
|
-
*/
|
|
5
|
-
function toLegacyMessages(messages) {
|
|
6
|
-
return messages.map((m) => ({ role: m.role, content: m.content }));
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Convert AgentHarness AgentToolSpec[] → legacy OpenAI-shaped tool descriptors.
|
|
10
|
-
*/
|
|
11
|
-
function toLegacyTools(tools) {
|
|
12
|
-
return tools.map((t) => ({
|
|
13
|
-
type: 'function',
|
|
14
|
-
function: { name: t.name, description: t.description, parameters: t.parameters },
|
|
15
|
-
}));
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Wrap a legacy stream function into a ProviderStreamFn that yields
|
|
19
|
-
* provider-neutral deltas. Text chunks are forwarded; finish/end is detected
|
|
20
|
-
* by the legacy function's resolved result (content length is the sum of deltas).
|
|
21
|
-
*
|
|
22
|
-
* NOTE: This adapter does NOT yield tool_call deltas yet — it treats tool calls
|
|
23
|
-
* as a single 'finish' + tools-in-result pattern. Full tool-call streaming lands
|
|
24
|
-
* in a later task.
|
|
25
|
-
*/
|
|
26
|
-
export function wrapLegacyStream(legacyStream, params, _messages, _tools) {
|
|
27
|
-
return async function* (providerParams) {
|
|
28
|
-
const accumulatedChunks = [];
|
|
29
|
-
const legacyParams = {
|
|
30
|
-
apiKey: params.apiKey,
|
|
31
|
-
model: providerParams.model,
|
|
32
|
-
provider: providerParams.provider,
|
|
33
|
-
messages: toLegacyMessages(providerParams.messages),
|
|
34
|
-
tools: toLegacyTools(providerParams.tools),
|
|
35
|
-
temperature: 0.7,
|
|
36
|
-
stream: true,
|
|
37
|
-
customBaseUrl: params.customBaseUrl,
|
|
38
|
-
customAuthStyle: params.customAuthStyle,
|
|
39
|
-
onChunk: (chunk) => {
|
|
40
|
-
accumulatedChunks.push(chunk);
|
|
41
|
-
},
|
|
42
|
-
onRequestId: undefined,
|
|
43
|
-
signal: providerParams.signal,
|
|
44
|
-
};
|
|
45
|
-
// Fire the legacy stream and yield chunks as they arrive.
|
|
46
|
-
// We can't await the whole result before yielding — we need to yield
|
|
47
|
-
// chunks incrementally. Use a small async queue.
|
|
48
|
-
const queue = [];
|
|
49
|
-
let resolveNext = null;
|
|
50
|
-
let done = false;
|
|
51
|
-
let error = null;
|
|
52
|
-
const promise = legacyStream(legacyParams)
|
|
53
|
-
.then((result) => {
|
|
54
|
-
// After legacy stream completes, emit a tool_call event for each tool
|
|
55
|
-
// it returned (AgentHarness will then schedule tool execution in 12.6).
|
|
56
|
-
for (const tc of result.toolCalls) {
|
|
57
|
-
queue.push({ kind: 'tool_call', toolCallId: tc.id, toolName: tc.name, args: tc.args });
|
|
58
|
-
}
|
|
59
|
-
queue.push({ kind: 'finish', reason: 'stop' });
|
|
60
|
-
})
|
|
61
|
-
.catch((err) => {
|
|
62
|
-
error = err;
|
|
63
|
-
})
|
|
64
|
-
.finally(() => {
|
|
65
|
-
done = true;
|
|
66
|
-
if (resolveNext) {
|
|
67
|
-
resolveNext();
|
|
68
|
-
resolveNext = null;
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
// Pump chunks from accumulatedChunks every microtask
|
|
72
|
-
let lastEmittedIndex = 0;
|
|
73
|
-
while (!done || queue.length > 0 || lastEmittedIndex < accumulatedChunks.length) {
|
|
74
|
-
// Emit any new chunks
|
|
75
|
-
while (lastEmittedIndex < accumulatedChunks.length) {
|
|
76
|
-
yield { kind: 'text', delta: accumulatedChunks[lastEmittedIndex] };
|
|
77
|
-
lastEmittedIndex++;
|
|
78
|
-
}
|
|
79
|
-
// Emit any queued deltas
|
|
80
|
-
while (queue.length > 0) {
|
|
81
|
-
const d = queue.shift();
|
|
82
|
-
yield d;
|
|
83
|
-
}
|
|
84
|
-
// If error, throw
|
|
85
|
-
if (error) {
|
|
86
|
-
throw error;
|
|
87
|
-
}
|
|
88
|
-
// If done but nothing left, exit
|
|
89
|
-
if (done)
|
|
90
|
-
break;
|
|
91
|
-
// Wait for next microtask
|
|
92
|
-
await new Promise((resolve) => {
|
|
93
|
-
resolveNext = resolve;
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
await promise; // Ensure the legacy promise resolves (catches final errors)
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
//# sourceMappingURL=providerStream.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"providerStream.js","sourceRoot":"","sources":["../../../src/main/core/providerStream.ts"],"names":[],"mappings":"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"}
|