@evolvingmachines/evolve 0.0.55-project-sable.20260916.db0bc0bb → 0.0.56
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/dist/cli/index.cjs +32 -32
- package/dist/cli/index.js +27 -27
- package/package.json +4 -6
- package/skills/evolve/SKILL.md +4 -3
- package/skills/evolve-evals/SKILL.md +112 -0
- package/{docs-evals → skills/evolve-evals/references}/cli-reference/run.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/cli-reference/skills.mdx +4 -4
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/agents.mdx +2 -2
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/analyze.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/jobs.mdx +3 -3
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/models.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/sandboxes.mdx +2 -2
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/secrets.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/trial-outputs.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/getting-started/quick-start.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/index.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/sdk/python.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/sdk/typescript.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/sdk-reference/errors.mdx +2 -2
- package/{docs-evals → skills/evolve-evals/references}/sdk-reference/jobs.mdx +2 -2
- package/docs-agents/SKILL.md +0 -138
- package/docs-agents/index.md +0 -81
- package/docs-agents/python/01-getting-started.md +0 -511
- package/docs-agents/python/02-configuration.md +0 -855
- package/docs-agents/python/03-runtime.md +0 -899
- package/docs-agents/python/04-streaming.md +0 -451
- package/docs-agents/python/05-swarm-pipeline.md +0 -953
- package/docs-agents/python/index.md +0 -122
- package/docs-agents/typescript/01-getting-started.md +0 -494
- package/docs-agents/typescript/02-configuration.md +0 -841
- package/docs-agents/typescript/03-runtime.md +0 -864
- package/docs-agents/typescript/04-streaming.md +0 -478
- package/docs-agents/typescript/05-swarm-pipeline.md +0 -957
- package/docs-agents/typescript/index.md +0 -121
- package/docs-evals/SKILL.md +0 -112
- package/docs-evals/docs.json +0 -180
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/agent.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/analysis.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/analyze.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/auth.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/check.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/dataset.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/index.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/job.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/secrets.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/skill.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/trial.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/upload.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/check.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/datasets.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/index.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/skills.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/tasks.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/trials.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/upload.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/dashboard/checks.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/dashboard/datasets.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/dashboard/jobs.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/dashboard/traces.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/dashboard/trial-viewer.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/getting-started/installation.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/agents.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/analyses.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/auth.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/checks.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/datasets.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/index.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/meta.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/skills.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/trials.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/types.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/snippets/global-options.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/snippets/list-flags.mdx +0 -0
|
@@ -1,478 +0,0 @@
|
|
|
1
|
-
# Streaming Events
|
|
2
|
-
|
|
3
|
-
Real-time output from `run()` and `executeCommand()`. For basic usage, see [Getting Started](./01-getting-started.md#streaming).
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Event Listeners
|
|
8
|
-
|
|
9
|
-
`Evolve` extends Node's `EventEmitter`. Subscribe to real-time output from `run()` and `executeCommand()`:
|
|
10
|
-
|
|
11
|
-
```typescript
|
|
12
|
-
import { Evolve } from "@evolvingmachines/evolve";
|
|
13
|
-
import type { OutputEvent, LifecycleEvent } from "@evolvingmachines/evolve";
|
|
14
|
-
|
|
15
|
-
const evolve = new Evolve().withAgent({ type: "claude" });
|
|
16
|
-
|
|
17
|
-
// Parsed events (recommended)
|
|
18
|
-
evolve.on("content", (event: OutputEvent) => {
|
|
19
|
-
console.log(event.update.sessionUpdate, event.update);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
// Lifecycle events (sandbox + agent state transitions)
|
|
23
|
-
evolve.on("lifecycle", (event: LifecycleEvent) => {
|
|
24
|
-
console.log(event.reason, event.sandbox, event.agent);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// Raw output (debugging)
|
|
28
|
-
evolve.on("stdout", (chunk: string) => process.stdout.write(chunk));
|
|
29
|
-
evolve.on("stderr", (chunk: string) => process.stderr.write(chunk));
|
|
30
|
-
|
|
31
|
-
await evolve.run({ prompt: "Hello" });
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
| Event | Type | Description |
|
|
35
|
-
|-------|------|-------------|
|
|
36
|
-
| `content` | `OutputEvent` | Parsed ACP-style events (recommended) |
|
|
37
|
-
| `lifecycle` | `LifecycleEvent` | Sandbox and agent state transitions |
|
|
38
|
-
| `stdout` | `string` | Raw JSONL output |
|
|
39
|
-
| `stderr` | `string` | Error output |
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## LifecycleEvent
|
|
44
|
-
|
|
45
|
-
```typescript
|
|
46
|
-
evolve.on("lifecycle", (event: LifecycleEvent) => {
|
|
47
|
-
console.log(event.reason, event.sandboxId);
|
|
48
|
-
});
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
```typescript
|
|
52
|
-
interface LifecycleEvent {
|
|
53
|
-
sandboxId: string | null;
|
|
54
|
-
sandbox: SandboxLifecycleState; // "booting" | "error" | "ready" | "running" | "paused" | "stopped"
|
|
55
|
-
agent: AgentRuntimeState; // "idle" | "running" | "interrupted" | "error"
|
|
56
|
-
timestamp: string; // ISO 8601
|
|
57
|
-
reason: LifecycleReason;
|
|
58
|
-
browser?: {
|
|
59
|
-
liveUrl: string; // Live browser view URL
|
|
60
|
-
sessionId?: string; // Use with sessions().browserReplay()
|
|
61
|
-
sessionTag?: string; // Use to correlate checkpoints
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
type LifecycleReason =
|
|
66
|
-
| "browser_ready" // Managed browser live view is available
|
|
67
|
-
| "sandbox_boot" // Sandbox is being created
|
|
68
|
-
| "sandbox_ready" // Sandbox is ready for commands
|
|
69
|
-
| "sandbox_connected" // Reconnected to existing sandbox
|
|
70
|
-
| "sandbox_pause" // Sandbox suspended
|
|
71
|
-
| "sandbox_resume" // Sandbox resumed
|
|
72
|
-
| "sandbox_killed" // Sandbox destroyed
|
|
73
|
-
| "sandbox_error" // Sandbox setup failed
|
|
74
|
-
| "run_start" // Agent run started
|
|
75
|
-
| "run_complete" // Agent run finished successfully
|
|
76
|
-
| "run_interrupted" // Agent run was interrupted
|
|
77
|
-
| "run_failed" // Agent run failed (non-zero exit or error)
|
|
78
|
-
| "run_background_complete" // Background run finished successfully
|
|
79
|
-
| "run_background_failed" // Background run failed
|
|
80
|
-
| "command_start" // Shell command started
|
|
81
|
-
| "command_complete" // Shell command finished successfully
|
|
82
|
-
| "command_failed" // Shell command failed (non-zero exit)
|
|
83
|
-
| "command_interrupted" // Shell command was interrupted
|
|
84
|
-
| "command_background_complete" // Background command finished successfully
|
|
85
|
-
| "command_background_failed"; // Background command failed
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
---
|
|
89
|
-
|
|
90
|
-
## OutputEvent
|
|
91
|
-
|
|
92
|
-
Top-level event structure:
|
|
93
|
-
|
|
94
|
-
```typescript
|
|
95
|
-
interface OutputEvent {
|
|
96
|
-
sessionId?: string;
|
|
97
|
-
update: SessionUpdate;
|
|
98
|
-
/** The harness's own clock for this line, ISO 8601 (absent when the wire line has none). */
|
|
99
|
-
timestamp?: string;
|
|
100
|
-
/** The model the harness named for this line. */
|
|
101
|
-
model?: string;
|
|
102
|
-
/** The harness's id for the LLM message this line belongs to (claude, qwen). */
|
|
103
|
-
messageId?: string;
|
|
104
|
-
/** On a SUBAGENT's line: the parent's tool call that delegated to it. */
|
|
105
|
-
parentToolCallId?: string;
|
|
106
|
-
/** Other facts of the line under the harness's own key names (e.g. stop_reason). */
|
|
107
|
-
extra?: Record<string, unknown>;
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
Everything beyond `update` is optional and comes straight from the wire line the update was parsed
|
|
112
|
-
from — a field the harness did not print is absent, never guessed. `timestamp` is the harness's
|
|
113
|
-
clock (claude, gemini, opencode and droid stamp every line; qwen and kimi stamp none); `model` is
|
|
114
|
-
the model named on the line, or on the harness's init line for gemini and droid; `messageId` lets you
|
|
115
|
-
tell which lines belong to one LLM message (claude prints one line per content block, all with the
|
|
116
|
-
same `message.id`); `parentToolCallId` is set only on a subagent's lines and names the `toolCallId`
|
|
117
|
-
of the `Task`/`agent` call that spawned it.
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
## SessionUpdate Types
|
|
122
|
-
|
|
123
|
-
Discriminated union on `sessionUpdate` field:
|
|
124
|
-
|
|
125
|
-
```typescript
|
|
126
|
-
type SessionUpdate =
|
|
127
|
-
| AgentMessageChunk
|
|
128
|
-
| AgentThoughtChunk
|
|
129
|
-
| UserMessageChunk
|
|
130
|
-
| ToolCall
|
|
131
|
-
| ToolCallUpdate
|
|
132
|
-
| Plan
|
|
133
|
-
| AgentError
|
|
134
|
-
| AgentUsage;
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### Message Events
|
|
138
|
-
|
|
139
|
-
| Type | `sessionUpdate` | Description |
|
|
140
|
-
|------|-----------------|-------------|
|
|
141
|
-
| `AgentMessageChunk` | `"agent_message_chunk"` | Text/image streaming from agent |
|
|
142
|
-
| `AgentThoughtChunk` | `"agent_thought_chunk"` | Reasoning (Codex) or thinking (Claude) |
|
|
143
|
-
| `UserMessageChunk` | `"user_message_chunk"` | User message echo (Gemini) |
|
|
144
|
-
|
|
145
|
-
```typescript
|
|
146
|
-
interface AgentMessageChunk {
|
|
147
|
-
sessionUpdate: "agent_message_chunk";
|
|
148
|
-
content: ContentBlock;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
interface AgentThoughtChunk {
|
|
152
|
-
sessionUpdate: "agent_thought_chunk";
|
|
153
|
-
content: ContentBlock;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
interface UserMessageChunk {
|
|
157
|
-
sessionUpdate: "user_message_chunk";
|
|
158
|
-
content: ContentBlock;
|
|
159
|
-
}
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### Tool Events
|
|
163
|
-
|
|
164
|
-
| Type | `sessionUpdate` | Description |
|
|
165
|
-
|------|-----------------|-------------|
|
|
166
|
-
| `ToolCall` | `"tool_call"` | Tool execution started |
|
|
167
|
-
| `ToolCallUpdate` | `"tool_call_update"` | Tool execution finished |
|
|
168
|
-
|
|
169
|
-
```typescript
|
|
170
|
-
interface ToolCall {
|
|
171
|
-
sessionUpdate: "tool_call";
|
|
172
|
-
toolCallId: string;
|
|
173
|
-
title: string;
|
|
174
|
-
toolName?: string;
|
|
175
|
-
kind: ToolKind;
|
|
176
|
-
status: ToolCallStatus;
|
|
177
|
-
rawInput?: unknown;
|
|
178
|
-
content?: ToolCallContent[];
|
|
179
|
-
locations?: ToolCallLocation[];
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
interface ToolCallUpdate {
|
|
183
|
-
sessionUpdate: "tool_call_update";
|
|
184
|
-
toolCallId: string;
|
|
185
|
-
status?: ToolCallStatus;
|
|
186
|
-
title?: string;
|
|
187
|
-
content?: ToolCallContent[];
|
|
188
|
-
locations?: ToolCallLocation[];
|
|
189
|
-
/** The harness's own structured record of the result, verbatim (ACP's rawOutput). */
|
|
190
|
-
rawOutput?: unknown;
|
|
191
|
-
}
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
`toolName` is the harness-native tool name, verbatim — `Bash`, `Read`, or the joined `mcp__<server>__<tool>` an MCP call carries. Prefer it over parsing `title`, which is formatted per tool for people to read and is not round-trippable; `toolName` is the identifier the model actually called. It is a deliberate addition to the ACP shape, which names no tool and whose `kind` collapses every MCP tool to `other`, and it is optional — absent on traces recorded before the SDK carried it, and on the occasional call a harness cannot name, so fall back to `kind` there.
|
|
195
|
-
|
|
196
|
-
`content` is the result text exactly as the harness sent it — a failed call's error text is not
|
|
197
|
-
wrapped in a code fence or prefixed; frame it in your own UI. `rawOutput` is the harness's
|
|
198
|
-
structured record of the same result when it prints one beyond the text: claude's
|
|
199
|
-
`tool_use_result` (`stdout`, `stderr`, `exitCode`, `interrupted`, or the file it wrote), codex's
|
|
200
|
-
completed item (`aggregated_output`, `exit_code`, `status`), opencode's tool state (`output`,
|
|
201
|
-
`metadata` with the exit code, `time`). Read an exit code from there rather than from prose.
|
|
202
|
-
|
|
203
|
-
### Plan Event
|
|
204
|
-
|
|
205
|
-
| Type | `sessionUpdate` | Description |
|
|
206
|
-
|------|-----------------|-------------|
|
|
207
|
-
| `Plan` | `"plan"` | TodoWrite updates (replaces entire list) |
|
|
208
|
-
| `AgentError` | `"error"` | A failure the HARNESS reported. **Not agent work** — see below |
|
|
209
|
-
| `AgentUsage` | `"usage"` | Token accounting the HARNESS reported. **Not agent work** — see below |
|
|
210
|
-
|
|
211
|
-
```typescript
|
|
212
|
-
interface Plan {
|
|
213
|
-
sessionUpdate: "plan";
|
|
214
|
-
entries: PlanEntry[];
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
interface PlanEntry {
|
|
218
|
-
content: string;
|
|
219
|
-
status: "pending" | "in_progress" | "completed";
|
|
220
|
-
priority: "high" | "medium" | "low";
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
---
|
|
225
|
-
|
|
226
|
-
## Content Types
|
|
227
|
-
|
|
228
|
-
```typescript
|
|
229
|
-
type ContentBlock = TextContent | ImageContent;
|
|
230
|
-
|
|
231
|
-
interface TextContent {
|
|
232
|
-
type: "text";
|
|
233
|
-
text: string;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
interface ImageContent {
|
|
237
|
-
type: "image";
|
|
238
|
-
data: string; // Base64-encoded
|
|
239
|
-
mimeType: string; // "image/png", "image/jpeg"
|
|
240
|
-
uri?: string;
|
|
241
|
-
}
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
---
|
|
245
|
-
|
|
246
|
-
## Tool Metadata Types
|
|
247
|
-
|
|
248
|
-
### ToolKind
|
|
249
|
-
|
|
250
|
-
Tool category for UI icons:
|
|
251
|
-
|
|
252
|
-
```typescript
|
|
253
|
-
type ToolKind =
|
|
254
|
-
| "read" // Read, NotebookRead
|
|
255
|
-
| "edit" // Edit, Write, NotebookEdit
|
|
256
|
-
| "delete" // (future)
|
|
257
|
-
| "move" // (future)
|
|
258
|
-
| "search" // Glob, Grep, LS
|
|
259
|
-
| "execute" // Bash, BashOutput, KillShell
|
|
260
|
-
| "think" // Task (subagent)
|
|
261
|
-
| "fetch" // WebFetch, WebSearch
|
|
262
|
-
| "switch_mode" // ExitPlanMode
|
|
263
|
-
| "other"; // Unknown or third-party MCP tools
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
### ToolCallStatus
|
|
267
|
-
|
|
268
|
-
```typescript
|
|
269
|
-
type ToolCallStatus = "pending" | "in_progress" | "completed" | "failed";
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
### ToolCallLocation
|
|
273
|
-
|
|
274
|
-
```typescript
|
|
275
|
-
interface ToolCallLocation {
|
|
276
|
-
path: string;
|
|
277
|
-
line?: number;
|
|
278
|
-
}
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
### ToolCallContent
|
|
282
|
-
|
|
283
|
-
```typescript
|
|
284
|
-
type ToolCallContent =
|
|
285
|
-
| { type: "content"; content: ContentBlock }
|
|
286
|
-
| DiffContent;
|
|
287
|
-
|
|
288
|
-
interface DiffContent {
|
|
289
|
-
type: "diff";
|
|
290
|
-
path: string;
|
|
291
|
-
oldText: string | null;
|
|
292
|
-
newText: string;
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
---
|
|
297
|
-
|
|
298
|
-
## Browser Automation Streaming
|
|
299
|
-
|
|
300
|
-
The full browser guide is [Configuration → Browser Automation](./02-configuration.md#browser-automation).
|
|
301
|
-
This section only documents the streaming fields for browser live view.
|
|
302
|
-
|
|
303
|
-
| Need | API | Use |
|
|
304
|
-
|------|-----|-----|
|
|
305
|
-
| Show live browser during a run | `lifecycle` event with `reason === "browser_ready"` | `event.browser.liveUrl` |
|
|
306
|
-
| Save the browser/session id | same lifecycle event | `event.browser.sessionId` |
|
|
307
|
-
|
|
308
|
-
### Managed Browser
|
|
309
|
-
|
|
310
|
-
Managed browser sessions emit the live-view URL as soon as the browser is ready:
|
|
311
|
-
|
|
312
|
-
```typescript
|
|
313
|
-
evolve.on("lifecycle", (event) => {
|
|
314
|
-
if (event.reason === "browser_ready" && event.browser) {
|
|
315
|
-
openLiveView(event.browser.liveUrl);
|
|
316
|
-
rememberSessionId(event.browser.sessionId);
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
const result = await evolve.run({ prompt: "QA the checkout flow" });
|
|
321
|
-
openLiveView(result.browser?.liveUrl);
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
The same URL is also stored in trace metadata for replay or embedding after the trace exists:
|
|
325
|
-
|
|
326
|
-
```typescript
|
|
327
|
-
type TraceMetadata = {
|
|
328
|
-
browser_session_id?: string;
|
|
329
|
-
dashboard_session_id?: string;
|
|
330
|
-
browser_session_tag?: string;
|
|
331
|
-
browser_live_url?: string;
|
|
332
|
-
};
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
Use `event.browser.liveUrl` or `result.browser?.liveUrl` for immediate UI display.
|
|
336
|
-
For replay after cleanup, use the `sessionId` with `sessions().browserReplay()`;
|
|
337
|
-
the full example lives in [Configuration → Browser Automation](./02-configuration.md#browser-automation).
|
|
338
|
-
|
|
339
|
-
---
|
|
340
|
-
|
|
341
|
-
## UI Integration Example
|
|
342
|
-
|
|
343
|
-
```typescript
|
|
344
|
-
import type { OutputEvent } from "@evolvingmachines/evolve";
|
|
345
|
-
|
|
346
|
-
function handleEvent(event: OutputEvent): void {
|
|
347
|
-
const { update } = event;
|
|
348
|
-
|
|
349
|
-
switch (update.sessionUpdate) {
|
|
350
|
-
case "agent_message_chunk":
|
|
351
|
-
if (update.content.type === "text") {
|
|
352
|
-
ui.appendMessage(update.content.text);
|
|
353
|
-
} else {
|
|
354
|
-
ui.appendImage(update.content.data, update.content.mimeType);
|
|
355
|
-
}
|
|
356
|
-
break;
|
|
357
|
-
|
|
358
|
-
case "agent_thought_chunk":
|
|
359
|
-
ui.appendThought(update.content);
|
|
360
|
-
break;
|
|
361
|
-
|
|
362
|
-
case "user_message_chunk":
|
|
363
|
-
// Gemini echo - typically ignored
|
|
364
|
-
break;
|
|
365
|
-
|
|
366
|
-
case "tool_call":
|
|
367
|
-
ui.addTool({
|
|
368
|
-
id: update.toolCallId,
|
|
369
|
-
title: update.title,
|
|
370
|
-
kind: update.kind,
|
|
371
|
-
status: update.status,
|
|
372
|
-
locations: update.locations,
|
|
373
|
-
});
|
|
374
|
-
break;
|
|
375
|
-
|
|
376
|
-
case "tool_call_update":
|
|
377
|
-
ui.updateTool(update.toolCallId, {
|
|
378
|
-
status: update.status,
|
|
379
|
-
content: update.content,
|
|
380
|
-
});
|
|
381
|
-
break;
|
|
382
|
-
|
|
383
|
-
case "plan":
|
|
384
|
-
ui.renderPlan(update.entries);
|
|
385
|
-
break;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
evolve.on("content", handleEvent);
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
---
|
|
393
|
-
|
|
394
|
-
## Key Patterns
|
|
395
|
-
|
|
396
|
-
1. **Handle all 6 event types** — Don't silently drop unknown events
|
|
397
|
-
2. **Match tools by ID** — `tool_call` and `tool_call_update` share `toolCallId`
|
|
398
|
-
3. **Handle out-of-order** — `tool_call_update` may arrive before `tool_call`
|
|
399
|
-
4. **Concatenate chunks** — Message text arrives incrementally
|
|
400
|
-
5. **Support images** — `ContentBlock` includes `ImageContent`
|
|
401
|
-
6. **Use `kind` for icons** — Categorize tools visually (read, edit, execute, etc.)
|
|
402
|
-
7. **Identify tools by `toolName`** — The harness-native name, not the human-readable `title`; fall back to `kind` when it is absent
|
|
403
|
-
8. **Track `locations`** — Show affected file paths in UI
|
|
404
|
-
|
|
405
|
-
---
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
## Harness-reported failures (`error`)
|
|
409
|
-
|
|
410
|
-
A harness can fail without the process dying, and it reports that on the same stream it uses for
|
|
411
|
-
output. Codex, for example, writes `{"type":"error"}` while it retries and `{"type":"turn.failed"}`
|
|
412
|
-
when a turn gives up — on **stdout**, while stderr says only `Reading prompt from stdin...`. Those
|
|
413
|
-
are surfaced as their own update so a transcript shows what actually happened:
|
|
414
|
-
|
|
415
|
-
```typescript
|
|
416
|
-
interface AgentError {
|
|
417
|
-
sessionUpdate: "error";
|
|
418
|
-
/** The harness's own message, verbatim. */
|
|
419
|
-
message: string;
|
|
420
|
-
/** True when the harness treated it as terminal for the turn. */
|
|
421
|
-
fatal: boolean;
|
|
422
|
-
}
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
**It is deliberately not a message chunk.** If you are counting "did the agent do any work",
|
|
426
|
-
an error must not count — otherwise a run that never reached the model looks like a run that
|
|
427
|
-
produced output. Use the exported predicate rather than writing the check yourself:
|
|
428
|
-
|
|
429
|
-
```typescript
|
|
430
|
-
import { isAgentWorkUpdate } from "@evolvingmachines/evolve";
|
|
431
|
-
|
|
432
|
-
const didWork = events.some((e) => isAgentWorkUpdate(e.update));
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
## Harness-reported usage (`usage`)
|
|
436
|
-
|
|
437
|
-
Every harness prints its own token accounting on the stream, and it arrives as its own update so
|
|
438
|
-
you can meter a run without reading the raw JSON: claude and qwen print each LLM message's usage,
|
|
439
|
-
opencode prints each step's tokens and cost, and codex, gemini, claude, qwen and droid print a
|
|
440
|
-
whole-run total on their terminal line. Kimi's stream-json prints no usage at all, so a kimi run
|
|
441
|
-
simply has no `usage` events.
|
|
442
|
-
|
|
443
|
-
```typescript
|
|
444
|
-
interface AgentUsage {
|
|
445
|
-
sessionUpdate: "usage";
|
|
446
|
-
/** "call": one LLM inference. "run": the harness's total for the whole run. */
|
|
447
|
-
scope: "call" | "run";
|
|
448
|
-
usage: TokenUsage;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
interface TokenUsage {
|
|
452
|
-
promptTokens?: number; // input INCLUDING the cached and cache-written shares
|
|
453
|
-
completionTokens?: number;
|
|
454
|
-
cachedTokens?: number; // the cache-read share of promptTokens
|
|
455
|
-
costUsd?: number; // only when the harness priced it (claude's total_cost_usd)
|
|
456
|
-
extra?: Record<string, unknown>; // the harness's other counters, its own key names verbatim
|
|
457
|
-
}
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
The names are Harbor's ATIF `Metrics` fields, so a trajectory copies them without renaming. A
|
|
461
|
-
counter the harness did not print is absent, never `0`. Two things to know when you sum:
|
|
462
|
-
|
|
463
|
-
- A `"call"` event repeats for every line of the same `messageId` (claude prints one line per
|
|
464
|
-
content block, each with the message's running usage) — keep the **last** one per `messageId`,
|
|
465
|
-
then add across messages.
|
|
466
|
-
- A `"run"` event is the harness's own total, reported once at the end; it is not another call.
|
|
467
|
-
|
|
468
|
-
```typescript
|
|
469
|
-
const perMessage = new Map<string, TokenUsage>();
|
|
470
|
-
for (const e of events) {
|
|
471
|
-
if (e.update.sessionUpdate !== "usage" || e.update.scope !== "call") continue;
|
|
472
|
-
perMessage.set(e.messageId ?? `line-${perMessage.size}`, e.update.usage);
|
|
473
|
-
}
|
|
474
|
-
const promptTokens = [...perMessage.values()].reduce((n, u) => n + (u.promptTokens ?? 0), 0);
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
Like `error`, `usage` is **not agent work**: `isAgentWorkUpdate` answers `false` for it, so a
|
|
478
|
-
stream that carries only accounting still counts as a run that did nothing.
|