zidane 1.2.0 → 1.3.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 +71 -9
- package/dist/{agent-DvZm8U14.d.ts → agent-DxIUxou4.d.ts} +10 -4
- package/dist/{chunk-LMSOIIAT.js → chunk-IC2WAUBZ.js} +153 -11
- package/dist/{chunk-34KXKPNN.js → chunk-N523NBO2.js} +1 -1
- package/dist/{chunk-27EP7HB3.js → chunk-SWS5624X.js} +137 -35
- package/dist/harnesses.d.ts +2 -2
- package/dist/harnesses.js +2 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -3
- package/dist/mcp.d.ts +2 -2
- package/dist/providers.d.ts +1 -1
- package/dist/session.d.ts +46 -20
- package/dist/session.js +1 -1
- package/dist/{spawn-pP2grsVp.d.ts → spawn-bEqlGUVT.d.ts} +2 -2
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +1 -1
- package/dist/{types-4CFQ-6Qu.d.ts → types-CLRMCak3.d.ts} +11 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -290,24 +290,40 @@ MCP connections are made lazily on the first `run()` call and reused across subs
|
|
|
290
290
|
|
|
291
291
|
## Sessions
|
|
292
292
|
|
|
293
|
-
Sessions give an agent persistent identity,
|
|
293
|
+
Sessions give an agent persistent identity, turn history, and run metadata across multiple calls or restarts. Each message exchange is a `SessionTurn` with its own UUID, enabling real-time multiplayer streaming.
|
|
294
|
+
|
|
295
|
+
### SessionTurn
|
|
296
|
+
|
|
297
|
+
Every message in a session is a turn:
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
interface SessionTurn {
|
|
301
|
+
id: string // UUID — generated by store or crypto.randomUUID()
|
|
302
|
+
role: 'user' | 'assistant' | 'system'
|
|
303
|
+
content: SessionContentBlock[] // same format used by providers
|
|
304
|
+
usage?: TurnUsage // token usage (assistant turns only)
|
|
305
|
+
createdAt: number // timestamp
|
|
306
|
+
}
|
|
307
|
+
```
|
|
294
308
|
|
|
295
309
|
### Creating a session
|
|
296
310
|
|
|
311
|
+
`createSession` is async — stores can generate IDs server-side (e.g. Supabase).
|
|
312
|
+
|
|
297
313
|
```ts
|
|
298
314
|
import { createSession, createMemoryStore } from 'zidane/session'
|
|
299
315
|
|
|
300
316
|
// In-memory (default, no persistence)
|
|
301
|
-
const session = createSession({ id: 'my-session', agentId: 'my-agent' })
|
|
317
|
+
const session = await createSession({ id: 'my-session', agentId: 'my-agent' })
|
|
302
318
|
|
|
303
319
|
// With a store for persistence
|
|
304
320
|
const store = createMemoryStore()
|
|
305
|
-
const session = createSession({ id: 'my-session', store })
|
|
321
|
+
const session = await createSession({ id: 'my-session', store })
|
|
306
322
|
```
|
|
307
323
|
|
|
308
324
|
### Storage backends
|
|
309
325
|
|
|
310
|
-
Three built-in stores are available
|
|
326
|
+
Three built-in stores are available. All implement the full `SessionStore` interface including incremental operations.
|
|
311
327
|
|
|
312
328
|
```ts
|
|
313
329
|
import { createMemoryStore, createSqliteStore, createRemoteStore } from 'zidane/session'
|
|
@@ -322,6 +338,38 @@ const sqliteStore = createSqliteStore({ path: './sessions.db' })
|
|
|
322
338
|
const remoteStore = createRemoteStore({ url: 'https://api.example.com/sessions' })
|
|
323
339
|
```
|
|
324
340
|
|
|
341
|
+
### SessionStore interface
|
|
342
|
+
|
|
343
|
+
```ts
|
|
344
|
+
interface SessionStore {
|
|
345
|
+
// Optional: server-side ID generation
|
|
346
|
+
generateSessionId?: () => string | Promise<string>
|
|
347
|
+
generateTurnId?: () => string | Promise<string>
|
|
348
|
+
|
|
349
|
+
// Core CRUD
|
|
350
|
+
load: (sessionId: string) => Promise<SessionData | null>
|
|
351
|
+
save: (session: SessionData) => Promise<void>
|
|
352
|
+
delete: (sessionId: string) => Promise<void>
|
|
353
|
+
list: (filter?) => Promise<string[]>
|
|
354
|
+
|
|
355
|
+
// Incremental operations (avoids full re-save)
|
|
356
|
+
appendTurns: (sessionId: string, turns: SessionTurn[]) => Promise<void>
|
|
357
|
+
getTurns: (sessionId: string, from?: number, limit?: number) => Promise<SessionTurn[]>
|
|
358
|
+
updateRun: (sessionId: string, run: SessionRun) => Promise<void>
|
|
359
|
+
updateStatus: (sessionId: string, status: SessionStatus) => Promise<void>
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Custom ID generation lets external databases (e.g. Supabase) provide UUIDs server-side, keeping IDs in sync:
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
const store = createRemoteStore({ url: '...' })
|
|
367
|
+
store.generateTurnId = async () => {
|
|
368
|
+
const { data } = await supabase.rpc('gen_random_uuid')
|
|
369
|
+
return data
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
325
373
|
### Agent integration
|
|
326
374
|
|
|
327
375
|
```ts
|
|
@@ -335,6 +383,18 @@ await agent.run({ prompt: 'hello' })
|
|
|
335
383
|
await session.save() // persist to store
|
|
336
384
|
```
|
|
337
385
|
|
|
386
|
+
Turns are persisted incrementally after each agent turn via `appendTurns` — not as a full document save. If the agent crashes mid-run, you still have turns up to the last completed turn.
|
|
387
|
+
|
|
388
|
+
### Session status
|
|
389
|
+
|
|
390
|
+
Sessions track their status: `'idle' | 'running' | 'completed' | 'error'`. The agent updates it automatically during runs.
|
|
391
|
+
|
|
392
|
+
```ts
|
|
393
|
+
session.status // 'idle'
|
|
394
|
+
await agent.run({ prompt: 'go' })
|
|
395
|
+
// idle → running → completed (or error)
|
|
396
|
+
```
|
|
397
|
+
|
|
338
398
|
### Session hooks
|
|
339
399
|
|
|
340
400
|
```ts
|
|
@@ -347,9 +407,9 @@ agent.hooks.hook('session:end', (ctx) => {
|
|
|
347
407
|
// ctx.status: 'completed' | 'aborted' | 'error'
|
|
348
408
|
})
|
|
349
409
|
|
|
350
|
-
agent.hooks.hook('session:
|
|
410
|
+
agent.hooks.hook('session:turns', (ctx) => {
|
|
351
411
|
// ctx.sessionId, ctx.count
|
|
352
|
-
// fired after each turn (
|
|
412
|
+
// fired after each turn (incremental sync)
|
|
353
413
|
})
|
|
354
414
|
|
|
355
415
|
agent.hooks.hook('session:save', (ctx) => {
|
|
@@ -363,8 +423,6 @@ agent.hooks.hook('session:meta', (ctx) => {
|
|
|
363
423
|
})
|
|
364
424
|
```
|
|
365
425
|
|
|
366
|
-
Messages are synced to the session after every turn, not just at run start/end. If the agent crashes mid-run, you still have messages up to the last completed turn.
|
|
367
|
-
|
|
368
426
|
### Restoring a session
|
|
369
427
|
|
|
370
428
|
```ts
|
|
@@ -390,11 +448,12 @@ agent.hooks.hook('system:before', (ctx) => {
|
|
|
390
448
|
|
|
391
449
|
agent.hooks.hook('turn:before', (ctx) => {
|
|
392
450
|
// ctx.turn: turn number
|
|
451
|
+
// ctx.turnId: UUID for this turn (generated before LLM call)
|
|
393
452
|
// ctx.options: StreamOptions being sent to provider
|
|
394
453
|
})
|
|
395
454
|
|
|
396
455
|
agent.hooks.hook('turn:after', (ctx) => {
|
|
397
|
-
// ctx.turn, ctx.usage { input, output }
|
|
456
|
+
// ctx.turn, ctx.turnId, ctx.usage { input, output }
|
|
398
457
|
})
|
|
399
458
|
|
|
400
459
|
agent.hooks.hook('agent:done', (ctx) => {
|
|
@@ -412,10 +471,13 @@ agent.hooks.hook('agent:abort', () => {
|
|
|
412
471
|
agent.hooks.hook('stream:text', (ctx) => {
|
|
413
472
|
// ctx.delta: new text chunk
|
|
414
473
|
// ctx.text: accumulated text so far
|
|
474
|
+
// ctx.turnId: UUID of the turn being streamed
|
|
475
|
+
// ctx.blockIndex: content block index within the turn
|
|
415
476
|
})
|
|
416
477
|
|
|
417
478
|
agent.hooks.hook('stream:end', (ctx) => {
|
|
418
479
|
// ctx.text: final complete text
|
|
480
|
+
// ctx.turnId, ctx.blockIndex
|
|
419
481
|
})
|
|
420
482
|
```
|
|
421
483
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Hookable } from 'hookable';
|
|
2
2
|
import Anthropic from '@anthropic-ai/sdk';
|
|
3
|
-
import { M as McpServerConfig,
|
|
3
|
+
import { M as McpServerConfig, e as TurnUsage, b as SessionMessage, C as ChildRunStats, a as AgentStats, A as AgentRunOptions, c as SessionTurn, d as ToolExecutionMode } from './types-CLRMCak3.js';
|
|
4
4
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
5
5
|
import { Provider, StreamOptions } from './providers.js';
|
|
6
6
|
import { Session } from './session.js';
|
|
@@ -168,18 +168,24 @@ interface AgentHooks {
|
|
|
168
168
|
}) => void;
|
|
169
169
|
'turn:before': (ctx: {
|
|
170
170
|
turn: number;
|
|
171
|
+
turnId: string;
|
|
171
172
|
options: StreamOptions;
|
|
172
173
|
}) => void;
|
|
173
174
|
'turn:after': (ctx: {
|
|
174
175
|
turn: number;
|
|
176
|
+
turnId: string;
|
|
175
177
|
usage: TurnUsage;
|
|
176
178
|
}) => void;
|
|
177
179
|
'stream:text': (ctx: {
|
|
178
180
|
delta: string;
|
|
179
181
|
text: string;
|
|
182
|
+
turnId: string;
|
|
183
|
+
blockIndex: number;
|
|
180
184
|
}) => void;
|
|
181
185
|
'stream:end': (ctx: {
|
|
182
186
|
text: string;
|
|
187
|
+
turnId: string;
|
|
188
|
+
blockIndex: number;
|
|
183
189
|
}) => void;
|
|
184
190
|
'tool:before': (ctx: {
|
|
185
191
|
name: string;
|
|
@@ -264,7 +270,7 @@ interface AgentHooks {
|
|
|
264
270
|
runId: string;
|
|
265
271
|
status: 'completed' | 'aborted' | 'error';
|
|
266
272
|
}) => void;
|
|
267
|
-
'session:
|
|
273
|
+
'session:turns': (ctx: {
|
|
268
274
|
sessionId: string;
|
|
269
275
|
count: number;
|
|
270
276
|
}) => void;
|
|
@@ -286,7 +292,7 @@ interface AgentOptions {
|
|
|
286
292
|
execution?: ExecutionContext;
|
|
287
293
|
/** MCP servers to connect and expose as tools */
|
|
288
294
|
mcpServers?: McpServerConfig[];
|
|
289
|
-
/** Session for identity,
|
|
295
|
+
/** Session for identity, turn persistence, and run tracking */
|
|
290
296
|
session?: Session;
|
|
291
297
|
/** @internal */
|
|
292
298
|
_mcpConnector?: (configs: McpServerConfig[]) => Promise<McpConnection>;
|
|
@@ -302,7 +308,7 @@ interface Agent {
|
|
|
302
308
|
/** Destroy the execution context and clean up resources */
|
|
303
309
|
destroy: () => Promise<void>;
|
|
304
310
|
readonly isRunning: boolean;
|
|
305
|
-
readonly
|
|
311
|
+
readonly turns: SessionTurn[];
|
|
306
312
|
readonly execution: ExecutionContext;
|
|
307
313
|
readonly handle: ExecutionHandle | null;
|
|
308
314
|
readonly session: Session | null;
|
|
@@ -21,6 +21,37 @@ function createMemoryStore() {
|
|
|
21
21
|
ids = ids.slice(0, filter.limit);
|
|
22
22
|
}
|
|
23
23
|
return ids;
|
|
24
|
+
},
|
|
25
|
+
async appendTurns(sessionId, turns) {
|
|
26
|
+
const data = sessions.get(sessionId);
|
|
27
|
+
if (data) {
|
|
28
|
+
data.turns.push(...JSON.parse(JSON.stringify(turns)));
|
|
29
|
+
data.updatedAt = Date.now();
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
async getTurns(sessionId, from = 0, limit) {
|
|
33
|
+
const data = sessions.get(sessionId);
|
|
34
|
+
if (!data)
|
|
35
|
+
return [];
|
|
36
|
+
const sliced = data.turns.slice(from, limit !== void 0 ? from + limit : void 0);
|
|
37
|
+
return JSON.parse(JSON.stringify(sliced));
|
|
38
|
+
},
|
|
39
|
+
async updateRun(sessionId, run) {
|
|
40
|
+
const data = sessions.get(sessionId);
|
|
41
|
+
if (data) {
|
|
42
|
+
const idx = data.runs.findIndex((r) => r.id === run.id);
|
|
43
|
+
if (idx >= 0) {
|
|
44
|
+
data.runs[idx] = JSON.parse(JSON.stringify(run));
|
|
45
|
+
}
|
|
46
|
+
data.updatedAt = Date.now();
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
async updateStatus(sessionId, status) {
|
|
50
|
+
const data = sessions.get(sessionId);
|
|
51
|
+
if (data) {
|
|
52
|
+
data.status = status;
|
|
53
|
+
data.updatedAt = Date.now();
|
|
54
|
+
}
|
|
24
55
|
}
|
|
25
56
|
};
|
|
26
57
|
}
|
|
@@ -82,6 +113,50 @@ function createRemoteStore(options) {
|
|
|
82
113
|
}
|
|
83
114
|
const body = await res.json();
|
|
84
115
|
return body.ids;
|
|
116
|
+
},
|
|
117
|
+
async appendTurns(sessionId, turns) {
|
|
118
|
+
const res = await request(`/sessions/${encodeURIComponent(sessionId)}/turns`, {
|
|
119
|
+
method: "POST",
|
|
120
|
+
body: JSON.stringify(turns)
|
|
121
|
+
});
|
|
122
|
+
if (!res.ok) {
|
|
123
|
+
throw new Error(`Remote appendTurns failed: ${res.status} ${res.statusText}`);
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
async getTurns(sessionId, from = 0, limit) {
|
|
127
|
+
const params = new URLSearchParams();
|
|
128
|
+
if (from)
|
|
129
|
+
params.set("from", String(from));
|
|
130
|
+
if (limit !== void 0)
|
|
131
|
+
params.set("limit", String(limit));
|
|
132
|
+
const query = params.toString();
|
|
133
|
+
const path = `/sessions/${encodeURIComponent(sessionId)}/turns${query ? `?${query}` : ""}`;
|
|
134
|
+
const res = await request(path);
|
|
135
|
+
if (!res.ok) {
|
|
136
|
+
throw new Error(`Remote getTurns failed: ${res.status} ${res.statusText}`);
|
|
137
|
+
}
|
|
138
|
+
return await res.json();
|
|
139
|
+
},
|
|
140
|
+
async updateRun(sessionId, run) {
|
|
141
|
+
const res = await request(
|
|
142
|
+
`/sessions/${encodeURIComponent(sessionId)}/runs/${encodeURIComponent(run.id)}`,
|
|
143
|
+
{
|
|
144
|
+
method: "PUT",
|
|
145
|
+
body: JSON.stringify(run)
|
|
146
|
+
}
|
|
147
|
+
);
|
|
148
|
+
if (!res.ok) {
|
|
149
|
+
throw new Error(`Remote updateRun failed: ${res.status} ${res.statusText}`);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
async updateStatus(sessionId, status) {
|
|
153
|
+
const res = await request(`/sessions/${encodeURIComponent(sessionId)}`, {
|
|
154
|
+
method: "PATCH",
|
|
155
|
+
body: JSON.stringify({ status })
|
|
156
|
+
});
|
|
157
|
+
if (!res.ok) {
|
|
158
|
+
throw new Error(`Remote updateStatus failed: ${res.status} ${res.statusText}`);
|
|
159
|
+
}
|
|
85
160
|
}
|
|
86
161
|
};
|
|
87
162
|
}
|
|
@@ -113,7 +188,7 @@ function createSqliteStore(options) {
|
|
|
113
188
|
const stmtDelete = db.prepare("DELETE FROM sessions WHERE id = ?");
|
|
114
189
|
const stmtList = db.prepare("SELECT id FROM sessions ORDER BY updated_at DESC");
|
|
115
190
|
const stmtListByAgent = db.prepare("SELECT id FROM sessions WHERE agent_id = ? ORDER BY updated_at DESC");
|
|
116
|
-
|
|
191
|
+
const store = {
|
|
117
192
|
async load(sessionId) {
|
|
118
193
|
const row = stmtLoad.get(sessionId);
|
|
119
194
|
if (!row)
|
|
@@ -144,19 +219,61 @@ function createSqliteStore(options) {
|
|
|
144
219
|
return ids.slice(0, filter.limit);
|
|
145
220
|
}
|
|
146
221
|
return ids;
|
|
222
|
+
},
|
|
223
|
+
async appendTurns(sessionId, turns) {
|
|
224
|
+
const data = await store.load(sessionId);
|
|
225
|
+
if (data) {
|
|
226
|
+
data.turns.push(...turns);
|
|
227
|
+
data.updatedAt = Date.now();
|
|
228
|
+
await store.save(data);
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
async getTurns(sessionId, from = 0, limit) {
|
|
232
|
+
const data = await store.load(sessionId);
|
|
233
|
+
if (!data)
|
|
234
|
+
return [];
|
|
235
|
+
return data.turns.slice(from, limit !== void 0 ? from + limit : void 0);
|
|
236
|
+
},
|
|
237
|
+
async updateRun(sessionId, run) {
|
|
238
|
+
const data = await store.load(sessionId);
|
|
239
|
+
if (data) {
|
|
240
|
+
const idx = data.runs.findIndex((r) => r.id === run.id);
|
|
241
|
+
if (idx >= 0) {
|
|
242
|
+
data.runs[idx] = run;
|
|
243
|
+
}
|
|
244
|
+
data.updatedAt = Date.now();
|
|
245
|
+
await store.save(data);
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
async updateStatus(sessionId, status) {
|
|
249
|
+
const data = await store.load(sessionId);
|
|
250
|
+
if (data) {
|
|
251
|
+
data.status = status;
|
|
252
|
+
data.updatedAt = Date.now();
|
|
253
|
+
await store.save(data);
|
|
254
|
+
}
|
|
147
255
|
}
|
|
148
256
|
};
|
|
257
|
+
return store;
|
|
149
258
|
}
|
|
150
259
|
|
|
151
260
|
// src/session/index.ts
|
|
152
|
-
function createSession(options = {}) {
|
|
261
|
+
async function createSession(options = {}) {
|
|
153
262
|
const store = options.store;
|
|
154
263
|
const now = Date.now();
|
|
264
|
+
let sessionId = options.id;
|
|
265
|
+
if (!sessionId && store?.generateSessionId) {
|
|
266
|
+
sessionId = await store.generateSessionId();
|
|
267
|
+
}
|
|
268
|
+
if (!sessionId) {
|
|
269
|
+
sessionId = generateId();
|
|
270
|
+
}
|
|
155
271
|
const data = options._data ?? {
|
|
156
|
-
id:
|
|
272
|
+
id: sessionId,
|
|
157
273
|
agentId: options.agentId,
|
|
158
|
-
|
|
274
|
+
turns: [],
|
|
159
275
|
runs: [],
|
|
276
|
+
status: "idle",
|
|
160
277
|
metadata: options.metadata ?? {},
|
|
161
278
|
createdAt: now,
|
|
162
279
|
updatedAt: now
|
|
@@ -167,15 +284,18 @@ function createSession(options = {}) {
|
|
|
167
284
|
function findRun(runId) {
|
|
168
285
|
return data.runs.find((r) => r.id === runId);
|
|
169
286
|
}
|
|
170
|
-
|
|
287
|
+
const session = {
|
|
171
288
|
get id() {
|
|
172
289
|
return data.id;
|
|
173
290
|
},
|
|
174
291
|
get agentId() {
|
|
175
292
|
return data.agentId;
|
|
176
293
|
},
|
|
177
|
-
get
|
|
178
|
-
return data.
|
|
294
|
+
get turns() {
|
|
295
|
+
return data.turns;
|
|
296
|
+
},
|
|
297
|
+
get status() {
|
|
298
|
+
return data.status;
|
|
179
299
|
},
|
|
180
300
|
get runs() {
|
|
181
301
|
return data.runs;
|
|
@@ -232,14 +352,35 @@ function createSession(options = {}) {
|
|
|
232
352
|
}
|
|
233
353
|
touch();
|
|
234
354
|
},
|
|
235
|
-
|
|
236
|
-
data.
|
|
355
|
+
async appendTurns(turns) {
|
|
356
|
+
data.turns.push(...turns);
|
|
237
357
|
touch();
|
|
358
|
+
if (store) {
|
|
359
|
+
await store.appendTurns(data.id, turns);
|
|
360
|
+
}
|
|
238
361
|
},
|
|
239
|
-
|
|
240
|
-
data.
|
|
362
|
+
setTurns(turns) {
|
|
363
|
+
data.turns = turns;
|
|
241
364
|
touch();
|
|
242
365
|
},
|
|
366
|
+
async updateStatus(status) {
|
|
367
|
+
data.status = status;
|
|
368
|
+
touch();
|
|
369
|
+
if (store) {
|
|
370
|
+
await store.updateStatus(data.id, status);
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
async updateRun(run) {
|
|
374
|
+
if (store) {
|
|
375
|
+
await store.updateRun(data.id, run);
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
generateTurnId() {
|
|
379
|
+
if (store?.generateTurnId) {
|
|
380
|
+
return store.generateTurnId();
|
|
381
|
+
}
|
|
382
|
+
return crypto.randomUUID();
|
|
383
|
+
},
|
|
243
384
|
setMeta(key, value) {
|
|
244
385
|
data.metadata[key] = value;
|
|
245
386
|
touch();
|
|
@@ -254,6 +395,7 @@ function createSession(options = {}) {
|
|
|
254
395
|
return JSON.parse(JSON.stringify(data));
|
|
255
396
|
}
|
|
256
397
|
};
|
|
398
|
+
return session;
|
|
257
399
|
}
|
|
258
400
|
async function loadSession(store, sessionId) {
|
|
259
401
|
const loaded = await store.load(sessionId);
|
|
@@ -287,6 +287,9 @@ var init_validation = __esm({
|
|
|
287
287
|
});
|
|
288
288
|
|
|
289
289
|
// src/loop.ts
|
|
290
|
+
function turnsToMessages(turns) {
|
|
291
|
+
return turns.map((t) => ({ role: t.role, content: t.content }));
|
|
292
|
+
}
|
|
290
293
|
async function runLoop(ctx) {
|
|
291
294
|
let totalIn = 0;
|
|
292
295
|
let totalOut = 0;
|
|
@@ -309,14 +312,26 @@ async function runLoop(ctx) {
|
|
|
309
312
|
if (ctx.steeringQueue.length > 0) {
|
|
310
313
|
const steerMsg = ctx.steeringQueue.shift();
|
|
311
314
|
await ctx.hooks.callHook("steer:inject", { message: steerMsg });
|
|
312
|
-
ctx.
|
|
315
|
+
const steerUserMsg = ctx.provider.userMessage(steerMsg);
|
|
316
|
+
ctx.turns.push({
|
|
317
|
+
id: await ctx.generateTurnId(),
|
|
318
|
+
role: steerUserMsg.role,
|
|
319
|
+
content: steerUserMsg.content,
|
|
320
|
+
createdAt: Date.now()
|
|
321
|
+
});
|
|
313
322
|
continue;
|
|
314
323
|
}
|
|
315
324
|
if (result.ended) {
|
|
316
325
|
if (ctx.followUpQueue.length > 0) {
|
|
317
326
|
const followUp = ctx.followUpQueue.shift();
|
|
318
327
|
await ctx.hooks.callHook("steer:inject", { message: followUp });
|
|
319
|
-
ctx.
|
|
328
|
+
const followUpMsg = ctx.provider.userMessage(followUp);
|
|
329
|
+
ctx.turns.push({
|
|
330
|
+
id: await ctx.generateTurnId(),
|
|
331
|
+
role: followUpMsg.role,
|
|
332
|
+
content: followUpMsg.content,
|
|
333
|
+
createdAt: Date.now()
|
|
334
|
+
});
|
|
320
335
|
continue;
|
|
321
336
|
}
|
|
322
337
|
return { totalIn, totalOut, turns: turn + 1, elapsed: Date.now() - startTime, turnUsage: turnUsages };
|
|
@@ -327,37 +342,59 @@ async function runLoop(ctx) {
|
|
|
327
342
|
return stats;
|
|
328
343
|
}
|
|
329
344
|
async function executeTurn(ctx, turn) {
|
|
345
|
+
const turnId = await ctx.generateTurnId();
|
|
346
|
+
const messages = turnsToMessages(ctx.turns);
|
|
330
347
|
const streamOptions = {
|
|
331
348
|
model: ctx.model,
|
|
332
349
|
system: ctx.system,
|
|
333
350
|
tools: ctx.formattedTools,
|
|
334
|
-
messages
|
|
351
|
+
messages,
|
|
335
352
|
maxTokens: 16384,
|
|
336
353
|
thinking: ctx.thinking,
|
|
337
354
|
signal: ctx.signal
|
|
338
355
|
};
|
|
339
|
-
await ctx.hooks.callHook("context:transform", { messages
|
|
340
|
-
await ctx.hooks.callHook("turn:before", { turn, options: streamOptions });
|
|
356
|
+
await ctx.hooks.callHook("context:transform", { messages });
|
|
357
|
+
await ctx.hooks.callHook("turn:before", { turn, turnId, options: streamOptions });
|
|
341
358
|
let currentText = "";
|
|
359
|
+
const blockIndex = 0;
|
|
342
360
|
const result = await ctx.provider.stream(
|
|
343
361
|
streamOptions,
|
|
344
362
|
{
|
|
345
363
|
onText(delta) {
|
|
346
364
|
currentText += delta;
|
|
347
|
-
ctx.hooks.callHook("stream:text", { delta, text: currentText });
|
|
365
|
+
ctx.hooks.callHook("stream:text", { delta, text: currentText, turnId, blockIndex });
|
|
348
366
|
}
|
|
349
367
|
}
|
|
350
368
|
);
|
|
351
369
|
if (currentText) {
|
|
352
|
-
await ctx.hooks.callHook("stream:end", { text: currentText });
|
|
370
|
+
await ctx.hooks.callHook("stream:end", { text: currentText, turnId, blockIndex });
|
|
353
371
|
}
|
|
354
|
-
await ctx.hooks.callHook("turn:after", { turn, usage: result.usage });
|
|
372
|
+
await ctx.hooks.callHook("turn:after", { turn, turnId, usage: result.usage });
|
|
355
373
|
if (result.done) {
|
|
374
|
+
ctx.turns.push({
|
|
375
|
+
id: turnId,
|
|
376
|
+
role: "assistant",
|
|
377
|
+
content: result.assistantMessage?.content ?? [{ type: "text", text: currentText }],
|
|
378
|
+
usage: result.usage,
|
|
379
|
+
createdAt: Date.now()
|
|
380
|
+
});
|
|
356
381
|
return { ended: true, usage: result.usage };
|
|
357
382
|
}
|
|
358
|
-
ctx.
|
|
383
|
+
ctx.turns.push({
|
|
384
|
+
id: turnId,
|
|
385
|
+
role: "assistant",
|
|
386
|
+
content: result.assistantMessage.content,
|
|
387
|
+
usage: result.usage,
|
|
388
|
+
createdAt: Date.now()
|
|
389
|
+
});
|
|
359
390
|
const toolResults = ctx.toolExecution === "parallel" ? await executeToolsParallel(ctx, result.toolCalls) : await executeToolsSequential(ctx, result.toolCalls);
|
|
360
|
-
ctx.
|
|
391
|
+
const toolResultMsg = ctx.provider.toolResultsMessage(toolResults);
|
|
392
|
+
ctx.turns.push({
|
|
393
|
+
id: await ctx.generateTurnId(),
|
|
394
|
+
role: toolResultMsg.role,
|
|
395
|
+
content: toolResultMsg.content,
|
|
396
|
+
createdAt: Date.now()
|
|
397
|
+
});
|
|
361
398
|
return { ended: false, usage: result.usage };
|
|
362
399
|
}
|
|
363
400
|
async function executeSingleTool(ctx, call) {
|
|
@@ -412,8 +449,20 @@ async function executeToolsSequential(ctx, toolCalls) {
|
|
|
412
449
|
for (const skipped of toolCalls.slice(toolCalls.indexOf(call))) {
|
|
413
450
|
results.push({ id: skipped.id, content: "Skipped: steering message received" });
|
|
414
451
|
}
|
|
415
|
-
ctx.
|
|
416
|
-
ctx.
|
|
452
|
+
const toolResultMsg = ctx.provider.toolResultsMessage(results);
|
|
453
|
+
ctx.turns.push({
|
|
454
|
+
id: await ctx.generateTurnId(),
|
|
455
|
+
role: toolResultMsg.role,
|
|
456
|
+
content: toolResultMsg.content,
|
|
457
|
+
createdAt: Date.now()
|
|
458
|
+
});
|
|
459
|
+
const steerUserMsg = ctx.provider.userMessage(steerMsg);
|
|
460
|
+
ctx.turns.push({
|
|
461
|
+
id: await ctx.generateTurnId(),
|
|
462
|
+
role: steerUserMsg.role,
|
|
463
|
+
content: steerUserMsg.content,
|
|
464
|
+
createdAt: Date.now()
|
|
465
|
+
});
|
|
417
466
|
return [];
|
|
418
467
|
}
|
|
419
468
|
const { result } = await executeSingleTool(ctx, call);
|
|
@@ -447,8 +496,8 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
447
496
|
const allMcpServers = [...harness.mcpServers ?? [], ...mcpServers ?? []];
|
|
448
497
|
const steeringQueue = [];
|
|
449
498
|
const followUpQueue = [];
|
|
450
|
-
let
|
|
451
|
-
let runCounter = 0;
|
|
499
|
+
let conversationTurns = session?.turns.slice() ?? [];
|
|
500
|
+
let runCounter = session?.runs.length ?? 0;
|
|
452
501
|
async function run(options) {
|
|
453
502
|
if (running) {
|
|
454
503
|
throw new Error("Agent is already running. Use steer() or followUp() to queue messages, or waitForIdle().");
|
|
@@ -457,8 +506,10 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
457
506
|
abortController = new AbortController();
|
|
458
507
|
const runId = `run_${++runCounter}`;
|
|
459
508
|
session?.startRun(runId, options.prompt);
|
|
460
|
-
if (session)
|
|
509
|
+
if (session) {
|
|
510
|
+
await session.updateStatus("running");
|
|
461
511
|
await hooks.callHook("session:start", { sessionId: session.id, runId, prompt: options.prompt });
|
|
512
|
+
}
|
|
462
513
|
if (options.signal) {
|
|
463
514
|
if (options.signal.aborted) {
|
|
464
515
|
abortController.abort();
|
|
@@ -496,18 +547,44 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
496
547
|
})
|
|
497
548
|
);
|
|
498
549
|
const formattedTools = provider.formatTools(toolSpecs);
|
|
499
|
-
const
|
|
550
|
+
const turns = [];
|
|
551
|
+
const isResume = session && session.turns.length > 0 && session.runs.length > 0;
|
|
552
|
+
if (isResume) {
|
|
553
|
+
turns.push(...session.turns);
|
|
554
|
+
}
|
|
500
555
|
if (options.system) {
|
|
501
556
|
await hooks.callHook("system:before", { system: options.system });
|
|
502
|
-
|
|
503
|
-
|
|
557
|
+
const systemUserMsg = provider.userMessage(options.system);
|
|
558
|
+
turns.push({
|
|
559
|
+
id: crypto.randomUUID(),
|
|
560
|
+
role: systemUserMsg.role,
|
|
561
|
+
content: systemUserMsg.content,
|
|
562
|
+
createdAt: Date.now()
|
|
563
|
+
});
|
|
564
|
+
const systemAckMsg = provider.assistantMessage("Understood. I will proceed with these instructions above the rest of my system prompt.");
|
|
565
|
+
turns.push({
|
|
566
|
+
id: crypto.randomUUID(),
|
|
567
|
+
role: systemAckMsg.role,
|
|
568
|
+
content: systemAckMsg.content,
|
|
569
|
+
createdAt: Date.now()
|
|
570
|
+
});
|
|
504
571
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
572
|
+
const promptMsg = provider.userMessage(options.prompt, options.images);
|
|
573
|
+
turns.push({
|
|
574
|
+
id: crypto.randomUUID(),
|
|
575
|
+
role: promptMsg.role,
|
|
576
|
+
content: promptMsg.content,
|
|
577
|
+
createdAt: Date.now()
|
|
578
|
+
});
|
|
579
|
+
conversationTurns = turns;
|
|
580
|
+
let lastPersistedTurnCount = isResume ? session.turns.length : 0;
|
|
581
|
+
const unregisterSessionSync = session ? hooks.hook("turn:after", async () => {
|
|
582
|
+
const newTurns = turns.slice(lastPersistedTurnCount);
|
|
583
|
+
if (newTurns.length > 0) {
|
|
584
|
+
await session.appendTurns(newTurns);
|
|
585
|
+
lastPersistedTurnCount = turns.length;
|
|
586
|
+
hooks.callHook("session:turns", { sessionId: session.id, count: turns.length });
|
|
587
|
+
}
|
|
511
588
|
}) : void 0;
|
|
512
589
|
try {
|
|
513
590
|
const stats = await runLoop({
|
|
@@ -526,7 +603,8 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
526
603
|
handle: executionHandle,
|
|
527
604
|
steeringQueue,
|
|
528
605
|
followUpQueue,
|
|
529
|
-
|
|
606
|
+
turns,
|
|
607
|
+
generateTurnId: () => session?.generateTurnId() ?? crypto.randomUUID()
|
|
530
608
|
});
|
|
531
609
|
const finalStats = {
|
|
532
610
|
...stats,
|
|
@@ -534,15 +612,24 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
534
612
|
};
|
|
535
613
|
if (abortController.signal.aborted) {
|
|
536
614
|
session?.abortRun(runId);
|
|
537
|
-
if (session)
|
|
615
|
+
if (session) {
|
|
616
|
+
const run2 = session.runs.find((r) => r.id === runId);
|
|
617
|
+
if (run2)
|
|
618
|
+
await session.updateRun(run2);
|
|
619
|
+
await session.updateStatus("idle");
|
|
538
620
|
await hooks.callHook("session:end", { sessionId: session.id, runId, status: "aborted" });
|
|
621
|
+
}
|
|
539
622
|
await hooks.callHook("agent:done", finalStats);
|
|
540
623
|
return finalStats;
|
|
541
624
|
}
|
|
542
625
|
const totalCost = finalStats.turnUsage?.reduce((sum, t) => sum + (t.cost ?? 0), 0) || void 0;
|
|
543
626
|
if (totalCost)
|
|
544
627
|
finalStats.cost = totalCost;
|
|
545
|
-
|
|
628
|
+
const finalNewTurns = turns.slice(lastPersistedTurnCount);
|
|
629
|
+
if (session && finalNewTurns.length > 0) {
|
|
630
|
+
await session.appendTurns(finalNewTurns);
|
|
631
|
+
lastPersistedTurnCount = turns.length;
|
|
632
|
+
}
|
|
546
633
|
session?.completeRun(runId, {
|
|
547
634
|
turns: finalStats.turns,
|
|
548
635
|
tokensIn: finalStats.totalIn,
|
|
@@ -550,22 +637,37 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
550
637
|
turnUsage: finalStats.turnUsage,
|
|
551
638
|
cost: totalCost
|
|
552
639
|
});
|
|
553
|
-
if (session)
|
|
640
|
+
if (session) {
|
|
641
|
+
const run2 = session.runs.find((r) => r.id === runId);
|
|
642
|
+
if (run2)
|
|
643
|
+
await session.updateRun(run2);
|
|
644
|
+
await session.updateStatus("completed");
|
|
554
645
|
await hooks.callHook("session:end", { sessionId: session.id, runId, status: "completed" });
|
|
646
|
+
}
|
|
555
647
|
await hooks.callHook("agent:done", finalStats);
|
|
556
648
|
return finalStats;
|
|
557
649
|
} catch (err) {
|
|
558
650
|
if (abortController.signal.aborted) {
|
|
559
651
|
session?.abortRun(runId);
|
|
560
|
-
if (session)
|
|
652
|
+
if (session) {
|
|
653
|
+
const run2 = session.runs.find((r) => r.id === runId);
|
|
654
|
+
if (run2)
|
|
655
|
+
await session.updateRun(run2);
|
|
656
|
+
await session.updateStatus("idle");
|
|
561
657
|
await hooks.callHook("session:end", { sessionId: session.id, runId, status: "aborted" });
|
|
658
|
+
}
|
|
562
659
|
const stats = { totalIn: 0, totalOut: 0, turns: 0, elapsed: 0 };
|
|
563
660
|
await hooks.callHook("agent:done", stats);
|
|
564
661
|
return stats;
|
|
565
662
|
}
|
|
566
663
|
session?.errorRun(runId, err.message);
|
|
567
|
-
if (session)
|
|
664
|
+
if (session) {
|
|
665
|
+
const run2 = session.runs.find((r) => r.id === runId);
|
|
666
|
+
if (run2)
|
|
667
|
+
await session.updateRun(run2);
|
|
668
|
+
await session.updateStatus("error");
|
|
568
669
|
await hooks.callHook("session:end", { sessionId: session.id, runId, status: "error" });
|
|
670
|
+
}
|
|
569
671
|
throw err;
|
|
570
672
|
} finally {
|
|
571
673
|
unregisterSpawnHook();
|
|
@@ -592,7 +694,7 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
592
694
|
return idlePromise ?? Promise.resolve();
|
|
593
695
|
}
|
|
594
696
|
function reset() {
|
|
595
|
-
|
|
697
|
+
conversationTurns = [];
|
|
596
698
|
steeringQueue.length = 0;
|
|
597
699
|
followUpQueue.length = 0;
|
|
598
700
|
}
|
|
@@ -630,8 +732,8 @@ function createAgent({ harness, provider, toolExecution = "sequential", executio
|
|
|
630
732
|
get isRunning() {
|
|
631
733
|
return running;
|
|
632
734
|
},
|
|
633
|
-
get
|
|
634
|
-
return
|
|
735
|
+
get turns() {
|
|
736
|
+
return conversationTurns;
|
|
635
737
|
},
|
|
636
738
|
get execution() {
|
|
637
739
|
return executionContext;
|
|
@@ -731,7 +833,7 @@ function createSpawnTool(options = {}) {
|
|
|
731
833
|
task,
|
|
732
834
|
stats
|
|
733
835
|
});
|
|
734
|
-
const response = extractText(agent.
|
|
836
|
+
const response = extractText(agent.turns.at(-1));
|
|
735
837
|
return [
|
|
736
838
|
`[sub-agent ${id}] Completed in ${stats.turns} turns (${stats.elapsed}ms)`,
|
|
737
839
|
`Tokens: ${stats.totalIn} in / ${stats.totalOut} out`,
|
|
@@ -831,7 +933,7 @@ var init_spawn = __esm({
|
|
|
831
933
|
task,
|
|
832
934
|
stats
|
|
833
935
|
});
|
|
834
|
-
const response = extractText(agent.
|
|
936
|
+
const response = extractText(agent.turns.at(-1));
|
|
835
937
|
return [
|
|
836
938
|
`[sub-agent ${id}] Completed in ${stats.turns} turns (${stats.elapsed}ms)`,
|
|
837
939
|
`Tokens: ${stats.totalIn} in / ${stats.totalOut} out`,
|
package/dist/harnesses.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import '@anthropic-ai/sdk';
|
|
2
2
|
import 'hookable';
|
|
3
|
-
export { H as Harness, f as HarnessConfig, T as ToolContext, g as ToolDef, h as ToolMap, _ as basic, l as basicTools, k as defineHarness } from './agent-
|
|
3
|
+
export { H as Harness, f as HarnessConfig, T as ToolContext, g as ToolDef, h as ToolMap, _ as basic, l as basicTools, k as defineHarness } from './agent-DxIUxou4.js';
|
|
4
4
|
import './providers.js';
|
|
5
|
-
import './types-
|
|
5
|
+
import './types-CLRMCak3.js';
|
|
6
6
|
import '@modelcontextprotocol/sdk/client/index.js';
|
|
7
7
|
import './session.js';
|
package/dist/harnesses.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { S as SpawnConfig, E as ExecutionContext, a as ExecResult } from './agent-
|
|
2
|
-
export { A as Agent, b as AgentHooks, c as AgentOptions, C as ContextCapabilities, d as ContextType, e as ExecutionHandle, H as Harness, f as HarnessConfig, M as McpConnection, T as ToolContext, g as ToolDef, h as ToolMap, i as connectMcpServers, j as createAgent, k as defineHarness } from './agent-
|
|
1
|
+
import { S as SpawnConfig, E as ExecutionContext, a as ExecResult } from './agent-DxIUxou4.js';
|
|
2
|
+
export { A as Agent, b as AgentHooks, c as AgentOptions, C as ContextCapabilities, d as ContextType, e as ExecutionHandle, H as Harness, f as HarnessConfig, M as McpConnection, T as ToolContext, g as ToolDef, h as ToolMap, i as connectMcpServers, j as createAgent, k as defineHarness } from './agent-DxIUxou4.js';
|
|
3
3
|
export { CreateSessionOptions, RemoteStoreOptions, Session, SessionData, SessionRun, SessionStore, SqliteStoreOptions, autoDetectAndConvert, createMemoryStore, createRemoteStore, createSession, createSqliteStore, fromAnthropic, fromOpenAI, loadSession, toAnthropic, toOpenAI } from './session.js';
|
|
4
|
-
export { C as ChildAgent, S as SpawnToolOptions, a as SpawnToolState, c as createSpawnTool, s as spawn } from './spawn-
|
|
5
|
-
export { A as AgentRunOptions, a as AgentStats, I as ImageContent, M as McpServerConfig, S as SessionContentBlock, b as SessionMessage, T as ThinkingLevel,
|
|
4
|
+
export { C as ChildAgent, S as SpawnToolOptions, a as SpawnToolState, c as createSpawnTool, s as spawn } from './spawn-bEqlGUVT.js';
|
|
5
|
+
export { A as AgentRunOptions, a as AgentStats, I as ImageContent, M as McpServerConfig, S as SessionContentBlock, b as SessionMessage, c as SessionTurn, T as ThinkingLevel, d as ToolExecutionMode, e as TurnUsage } from './types-CLRMCak3.js';
|
|
6
6
|
import 'hookable';
|
|
7
7
|
import '@anthropic-ai/sdk';
|
|
8
8
|
import '@modelcontextprotocol/sdk/client/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
defineHarness
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-N523NBO2.js";
|
|
4
4
|
import {
|
|
5
5
|
createAgent,
|
|
6
6
|
createDockerContext,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
init_agent,
|
|
11
11
|
init_contexts,
|
|
12
12
|
spawn
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-SWS5624X.js";
|
|
14
14
|
import {
|
|
15
15
|
connectMcpServers,
|
|
16
16
|
init_mcp
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
createSession,
|
|
22
22
|
createSqliteStore,
|
|
23
23
|
loadSession
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-IC2WAUBZ.js";
|
|
25
25
|
import {
|
|
26
26
|
autoDetectAndConvert,
|
|
27
27
|
fromAnthropic,
|
package/dist/mcp.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import 'hookable';
|
|
2
|
-
export { M as McpConnection, i as connectMcpServers, r as resultToString } from './agent-
|
|
3
|
-
export { M as McpServerConfig } from './types-
|
|
2
|
+
export { M as McpConnection, i as connectMcpServers, r as resultToString } from './agent-DxIUxou4.js';
|
|
3
|
+
export { M as McpServerConfig } from './types-CLRMCak3.js';
|
|
4
4
|
import '@modelcontextprotocol/sdk/client/index.js';
|
|
5
5
|
import '@anthropic-ai/sdk';
|
|
6
6
|
import './providers.js';
|
package/dist/providers.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as SessionMessage, T as ThinkingLevel, I as ImageContent,
|
|
1
|
+
import { b as SessionMessage, T as ThinkingLevel, I as ImageContent, e as TurnUsage } from './types-CLRMCak3.js';
|
|
2
2
|
|
|
3
3
|
declare function anthropic(): Provider;
|
|
4
4
|
|
package/dist/session.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { b as SessionMessage,
|
|
2
|
-
export { S as SessionContentBlock } from './types-
|
|
1
|
+
import { b as SessionMessage, c as SessionTurn, e as TurnUsage } from './types-CLRMCak3.js';
|
|
2
|
+
export { S as SessionContentBlock } from './types-CLRMCak3.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* In-memory session store.
|
|
@@ -37,10 +37,14 @@ declare function autoDetectAndConvert(msg: {
|
|
|
37
37
|
* Remote session store via HTTP API.
|
|
38
38
|
*
|
|
39
39
|
* Expects a REST API with:
|
|
40
|
-
* GET {url}/sessions/{id}
|
|
41
|
-
* PUT {url}/sessions/{id}
|
|
42
|
-
* DELETE {url}/sessions/{id}
|
|
43
|
-
* GET {url}/sessions?agentId=&limit=
|
|
40
|
+
* GET {url}/sessions/{id} -> SessionData | 404
|
|
41
|
+
* PUT {url}/sessions/{id} -> save SessionData
|
|
42
|
+
* DELETE {url}/sessions/{id} -> delete
|
|
43
|
+
* GET {url}/sessions?agentId=&limit= -> { ids: string[] }
|
|
44
|
+
* POST {url}/sessions/{id}/turns -> append turns
|
|
45
|
+
* GET {url}/sessions/{id}/turns?from=&limit= -> SessionTurn[]
|
|
46
|
+
* PUT {url}/sessions/{id}/runs/{runId} -> update run
|
|
47
|
+
* PATCH {url}/sessions/{id} -> { status }
|
|
44
48
|
*/
|
|
45
49
|
|
|
46
50
|
interface RemoteStoreOptions {
|
|
@@ -64,7 +68,7 @@ declare function createSqliteStore(options: SqliteStoreOptions): SessionStore;
|
|
|
64
68
|
/**
|
|
65
69
|
* Session management for agents.
|
|
66
70
|
*
|
|
67
|
-
* A session tracks identity,
|
|
71
|
+
* A session tracks identity, turn history, and run metadata.
|
|
68
72
|
* Plug in any storage backend by implementing the SessionStore interface,
|
|
69
73
|
* or use one of the built-in stores: memory, sqlite, remote.
|
|
70
74
|
*/
|
|
@@ -89,32 +93,47 @@ interface SessionRun {
|
|
|
89
93
|
interface SessionData {
|
|
90
94
|
id: string;
|
|
91
95
|
agentId?: string;
|
|
92
|
-
|
|
96
|
+
turns: SessionTurn[];
|
|
93
97
|
runs: SessionRun[];
|
|
98
|
+
status: 'idle' | 'running' | 'completed' | 'error';
|
|
94
99
|
metadata: Record<string, unknown>;
|
|
95
100
|
createdAt: number;
|
|
96
101
|
updatedAt: number;
|
|
97
102
|
}
|
|
98
103
|
interface SessionStore {
|
|
104
|
+
/** Optional: generate a session ID server-side (e.g. Supabase UUID). */
|
|
105
|
+
generateSessionId?: () => string | Promise<string>;
|
|
106
|
+
/** Optional: generate a turn ID server-side. */
|
|
107
|
+
generateTurnId?: () => string | Promise<string>;
|
|
99
108
|
/** Load a session by ID. Returns null if not found. */
|
|
100
109
|
load: (sessionId: string) => Promise<SessionData | null>;
|
|
101
|
-
/** Save a session (create or update). */
|
|
110
|
+
/** Save a session (create or update, full document). */
|
|
102
111
|
save: (session: SessionData) => Promise<void>;
|
|
103
112
|
/** Delete a session. */
|
|
104
113
|
delete: (sessionId: string) => Promise<void>;
|
|
105
|
-
/** List session IDs, optionally filtered
|
|
114
|
+
/** List session IDs, optionally filtered. */
|
|
106
115
|
list: (filter?: {
|
|
107
116
|
agentId?: string;
|
|
108
117
|
limit?: number;
|
|
109
118
|
}) => Promise<string[]>;
|
|
119
|
+
/** Append new turns to a session (incremental, avoids full re-save). */
|
|
120
|
+
appendTurns: (sessionId: string, turns: SessionTurn[]) => Promise<void>;
|
|
121
|
+
/** Return a slice of turns for a session. */
|
|
122
|
+
getTurns: (sessionId: string, from?: number, limit?: number) => Promise<SessionTurn[]>;
|
|
123
|
+
/** Persist an updated run record (called after completeRun / abortRun / errorRun). */
|
|
124
|
+
updateRun: (sessionId: string, run: SessionRun) => Promise<void>;
|
|
125
|
+
/** Update the top-level status of a session. */
|
|
126
|
+
updateStatus: (sessionId: string, status: SessionData['status']) => Promise<void>;
|
|
110
127
|
}
|
|
111
128
|
interface Session {
|
|
112
129
|
/** Session ID */
|
|
113
130
|
readonly id: string;
|
|
114
131
|
/** Agent ID (optional label) */
|
|
115
132
|
readonly agentId?: string;
|
|
116
|
-
/** Current
|
|
117
|
-
readonly
|
|
133
|
+
/** Current turn history */
|
|
134
|
+
readonly turns: SessionTurn[];
|
|
135
|
+
/** Top-level session status */
|
|
136
|
+
readonly status: SessionData['status'];
|
|
118
137
|
/** All runs in this session */
|
|
119
138
|
readonly runs: SessionRun[];
|
|
120
139
|
/** Arbitrary metadata */
|
|
@@ -133,19 +152,25 @@ interface Session {
|
|
|
133
152
|
abortRun: (runId: string) => void;
|
|
134
153
|
/** Mark a run as errored */
|
|
135
154
|
errorRun: (runId: string, error: string) => void;
|
|
136
|
-
/** Append
|
|
137
|
-
|
|
138
|
-
/** Replace all
|
|
139
|
-
|
|
155
|
+
/** Append turns to in-memory history AND persist via store.appendTurns (if store present) */
|
|
156
|
+
appendTurns: (turns: SessionTurn[]) => Promise<void>;
|
|
157
|
+
/** Replace all turns in-memory (does not persist — use save() for that) */
|
|
158
|
+
setTurns: (turns: SessionTurn[]) => void;
|
|
159
|
+
/** Update the session status in memory AND via store.updateStatus (if store present) */
|
|
160
|
+
updateStatus: (status: SessionData['status']) => Promise<void>;
|
|
161
|
+
/** Persist an updated run record via store.updateRun (if store present) */
|
|
162
|
+
updateRun: (run: SessionRun) => Promise<void>;
|
|
163
|
+
/** Generate a turn ID using store.generateTurnId if available, else crypto.randomUUID() */
|
|
164
|
+
generateTurnId: () => string | Promise<string>;
|
|
140
165
|
/** Set metadata key */
|
|
141
166
|
setMeta: (key: string, value: unknown) => void;
|
|
142
|
-
/** Persist the session to the store */
|
|
167
|
+
/** Persist the full session document to the store */
|
|
143
168
|
save: () => Promise<void>;
|
|
144
169
|
/** Serialize to SessionData */
|
|
145
170
|
toJSON: () => SessionData;
|
|
146
171
|
}
|
|
147
172
|
interface CreateSessionOptions {
|
|
148
|
-
/** Session ID
|
|
173
|
+
/** Session ID. If omitted and store provides generateSessionId, that is used. */
|
|
149
174
|
id?: string;
|
|
150
175
|
/** Agent ID label */
|
|
151
176
|
agentId?: string;
|
|
@@ -157,11 +182,12 @@ interface CreateSessionOptions {
|
|
|
157
182
|
}
|
|
158
183
|
/**
|
|
159
184
|
* Create a new session.
|
|
185
|
+
* Async so stores that generate IDs server-side (e.g. Supabase) can be supported.
|
|
160
186
|
*/
|
|
161
|
-
declare function createSession(options?: CreateSessionOptions): Session
|
|
187
|
+
declare function createSession(options?: CreateSessionOptions): Promise<Session>;
|
|
162
188
|
/**
|
|
163
189
|
* Load an existing session from a store.
|
|
164
190
|
*/
|
|
165
191
|
declare function loadSession(store: SessionStore, sessionId: string): Promise<Session | null>;
|
|
166
192
|
|
|
167
|
-
export { type CreateSessionOptions, type RemoteStoreOptions, type Session, type SessionData, SessionMessage, type SessionRun, type SessionStore, type SqliteStoreOptions, autoDetectAndConvert, createMemoryStore, createRemoteStore, createSession, createSqliteStore, fromAnthropic, fromOpenAI, loadSession, toAnthropic, toOpenAI };
|
|
193
|
+
export { type CreateSessionOptions, type RemoteStoreOptions, type Session, type SessionData, SessionMessage, type SessionRun, type SessionStore, SessionTurn, type SqliteStoreOptions, autoDetectAndConvert, createMemoryStore, createRemoteStore, createSession, createSqliteStore, fromAnthropic, fromOpenAI, loadSession, toAnthropic, toOpenAI };
|
package/dist/session.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { f as HarnessConfig, g as ToolDef } from './agent-
|
|
2
|
-
import { a as AgentStats } from './types-
|
|
1
|
+
import { f as HarnessConfig, g as ToolDef } from './agent-DxIUxou4.js';
|
|
2
|
+
import { a as AgentStats } from './types-CLRMCak3.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Spawn tool — create sub-agents from a parent agent.
|
package/dist/tools.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { g as ToolDef } from './agent-
|
|
2
|
-
export { C as ChildAgent, S as SpawnToolOptions, a as SpawnToolState, c as createSpawnTool, s as spawn } from './spawn-
|
|
1
|
+
import { g as ToolDef } from './agent-DxIUxou4.js';
|
|
2
|
+
export { C as ChildAgent, S as SpawnToolOptions, a as SpawnToolState, c as createSpawnTool, s as spawn } from './spawn-bEqlGUVT.js';
|
|
3
3
|
import 'hookable';
|
|
4
4
|
import '@anthropic-ai/sdk';
|
|
5
|
-
import './types-
|
|
5
|
+
import './types-CLRMCak3.js';
|
|
6
6
|
import '@modelcontextprotocol/sdk/client/index.js';
|
|
7
7
|
import './providers.js';
|
|
8
8
|
import './session.js';
|
package/dist/tools.js
CHANGED
|
@@ -52,6 +52,16 @@ interface SessionMessage {
|
|
|
52
52
|
role: 'user' | 'assistant';
|
|
53
53
|
content: SessionContentBlock[];
|
|
54
54
|
}
|
|
55
|
+
interface SessionTurn {
|
|
56
|
+
/** UUID — generated by the store if it provides generateTurnId, else crypto.randomUUID() */
|
|
57
|
+
id: string;
|
|
58
|
+
role: 'user' | 'assistant' | 'system';
|
|
59
|
+
content: SessionContentBlock[];
|
|
60
|
+
/** Token usage — only present on assistant turns */
|
|
61
|
+
usage?: TurnUsage;
|
|
62
|
+
/** Unix timestamp (Date.now()) when the turn was created */
|
|
63
|
+
createdAt: number;
|
|
64
|
+
}
|
|
55
65
|
interface AgentRunOptions {
|
|
56
66
|
model?: string;
|
|
57
67
|
prompt: string;
|
|
@@ -91,4 +101,4 @@ interface ChildRunStats {
|
|
|
91
101
|
stats: AgentStats;
|
|
92
102
|
}
|
|
93
103
|
|
|
94
|
-
export type { AgentRunOptions as A, ChildRunStats as C, ImageContent as I, McpServerConfig as M, SessionContentBlock as S, ThinkingLevel as T, AgentStats as a, SessionMessage as b,
|
|
104
|
+
export type { AgentRunOptions as A, ChildRunStats as C, ImageContent as I, McpServerConfig as M, SessionContentBlock as S, ThinkingLevel as T, AgentStats as a, SessionMessage as b, SessionTurn as c, ToolExecutionMode as d, TurnUsage as e };
|