kernl 0.11.4 → 0.12.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +59 -0
- package/dist/agent/__tests__/run.test.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lifecycle/__tests__/hooks.test.js +6 -6
- package/dist/storage/__tests__/in-memory.test.js +1 -1
- package/dist/thread/__tests__/fixtures/mock-model.js +3 -3
- package/dist/thread/__tests__/mock.d.ts +2 -3
- package/dist/thread/__tests__/mock.d.ts.map +1 -1
- package/dist/thread/__tests__/thread-persistence.test.js +6 -6
- package/dist/thread/__tests__/thread.test.js +22 -22
- package/dist/thread/thread.d.ts +4 -0
- package/dist/thread/thread.d.ts.map +1 -1
- package/dist/thread/thread.js +47 -79
- package/dist/thread/types.d.ts +18 -3
- package/dist/thread/types.d.ts.map +1 -1
- package/dist/thread/utils.d.ts +7 -7
- package/dist/thread/utils.d.ts.map +1 -1
- package/dist/thread/utils.js +6 -6
- package/package.json +5 -7
- package/src/agent/__tests__/run.test.ts +2 -2
- package/src/index.ts +1 -0
- package/src/lifecycle/__tests__/hooks.test.ts +6 -6
- package/src/storage/__tests__/in-memory.test.ts +1 -1
- package/src/thread/__tests__/fixtures/mock-model.ts +3 -3
- package/src/thread/__tests__/mock.ts +2 -2
- package/src/thread/__tests__/thread-persistence.test.ts +6 -6
- package/src/thread/__tests__/thread.test.ts +22 -22
- package/src/thread/thread.ts +51 -82
- package/src/thread/types.ts +49 -3
- package/src/thread/utils.ts +19 -12
- package/dist/thread/__tests__/integration.test.d.ts +0 -2
- package/dist/thread/__tests__/integration.test.d.ts.map +0 -1
- package/dist/thread/__tests__/integration.test.js +0 -320
- package/src/thread/__tests__/integration.test.ts +0 -434
package/dist/thread/thread.js
CHANGED
|
@@ -120,33 +120,14 @@ export class Thread {
|
|
|
120
120
|
this.abort = new AbortController();
|
|
121
121
|
this.tickres = undefined; // reset for this run
|
|
122
122
|
await this.checkpoint(); /* c1: persist RUNNING state + initial input */
|
|
123
|
-
this.
|
|
124
|
-
|
|
125
|
-
threadId: this.tid,
|
|
126
|
-
agentId: this.agent.id,
|
|
127
|
-
namespace: this.namespace,
|
|
128
|
-
context: this.context,
|
|
129
|
-
});
|
|
130
|
-
yield { kind: "stream-start" }; // always yield start immediately
|
|
123
|
+
this.emit("thread.start");
|
|
124
|
+
yield { kind: "stream.start" }; // always yield start immediately
|
|
131
125
|
try {
|
|
132
126
|
yield* this._execute();
|
|
133
|
-
this.
|
|
134
|
-
kind: "thread.stop",
|
|
135
|
-
threadId: this.tid,
|
|
136
|
-
agentId: this.agent.id,
|
|
137
|
-
namespace: this.namespace,
|
|
138
|
-
context: this.context,
|
|
139
|
-
state: STOPPED,
|
|
140
|
-
result: this.tickres,
|
|
141
|
-
});
|
|
127
|
+
this.emit("thread.stop", { state: STOPPED, result: this.tickres });
|
|
142
128
|
}
|
|
143
129
|
catch (err) {
|
|
144
|
-
this.
|
|
145
|
-
kind: "thread.stop",
|
|
146
|
-
threadId: this.tid,
|
|
147
|
-
agentId: this.agent.id,
|
|
148
|
-
namespace: this.namespace,
|
|
149
|
-
context: this.context,
|
|
130
|
+
this.emit("thread.stop", {
|
|
150
131
|
state: STOPPED,
|
|
151
132
|
error: err instanceof Error ? err.message : String(err),
|
|
152
133
|
});
|
|
@@ -176,12 +157,15 @@ export class Thread {
|
|
|
176
157
|
err = e.error;
|
|
177
158
|
logger.error(e.error); // (TODO): onError callback in options
|
|
178
159
|
}
|
|
179
|
-
//
|
|
160
|
+
// complete items get persisted with seq, deltas are ephemeral
|
|
180
161
|
if (notDelta(e)) {
|
|
181
|
-
|
|
182
|
-
|
|
162
|
+
const [seqd] = this.append(e);
|
|
163
|
+
events.push(seqd);
|
|
164
|
+
yield seqd;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
yield e;
|
|
183
168
|
}
|
|
184
|
-
yield e;
|
|
185
169
|
}
|
|
186
170
|
// if an error event occurred → throw it
|
|
187
171
|
if (err) {
|
|
@@ -201,10 +185,10 @@ export class Thread {
|
|
|
201
185
|
}
|
|
202
186
|
// perform intended actions
|
|
203
187
|
const { actions, pendingApprovals } = await this.performActions(intentions);
|
|
204
|
-
// append + yield action events
|
|
188
|
+
// append + yield action events (sequenced)
|
|
205
189
|
for (const a of actions) {
|
|
206
|
-
this.append(a);
|
|
207
|
-
yield
|
|
190
|
+
const [seqd] = this.append(a);
|
|
191
|
+
yield seqd;
|
|
208
192
|
}
|
|
209
193
|
await this.checkpoint(); /* c3: tick complete */
|
|
210
194
|
if (pendingApprovals.length > 0) {
|
|
@@ -228,16 +212,9 @@ export class Thread {
|
|
|
228
212
|
this._tick++;
|
|
229
213
|
// (TODO): check limits (if this._tick > this.limits.maxTicks)
|
|
230
214
|
// (TODO): run input guardrails on first tick (if this._tick === 1)
|
|
215
|
+
// (TODO): compaction if necessary
|
|
231
216
|
const req = await this.prepareModelRequest(this.history);
|
|
232
|
-
this.
|
|
233
|
-
kind: "model.call.start",
|
|
234
|
-
provider: this.model.provider,
|
|
235
|
-
modelId: this.model.modelId,
|
|
236
|
-
settings: req.settings ?? {},
|
|
237
|
-
threadId: this.tid,
|
|
238
|
-
agentId: this.agent.id,
|
|
239
|
-
context: this.context,
|
|
240
|
-
});
|
|
217
|
+
this.emit("model.call.start", { settings: req.settings ?? {} });
|
|
241
218
|
let usage;
|
|
242
219
|
let finishReason = "unknown";
|
|
243
220
|
try {
|
|
@@ -259,27 +236,10 @@ export class Thread {
|
|
|
259
236
|
yield event;
|
|
260
237
|
}
|
|
261
238
|
}
|
|
262
|
-
this.
|
|
263
|
-
kind: "model.call.end",
|
|
264
|
-
provider: this.model.provider,
|
|
265
|
-
modelId: this.model.modelId,
|
|
266
|
-
finishReason,
|
|
267
|
-
usage,
|
|
268
|
-
threadId: this.tid,
|
|
269
|
-
agentId: this.agent.id,
|
|
270
|
-
context: this.context,
|
|
271
|
-
});
|
|
239
|
+
this.emit("model.call.end", { finishReason, usage });
|
|
272
240
|
}
|
|
273
241
|
catch (error) {
|
|
274
|
-
this.
|
|
275
|
-
kind: "model.call.end",
|
|
276
|
-
provider: this.model.provider,
|
|
277
|
-
modelId: this.model.modelId,
|
|
278
|
-
finishReason: "error",
|
|
279
|
-
threadId: this.tid,
|
|
280
|
-
agentId: this.agent.id,
|
|
281
|
-
context: this.context,
|
|
282
|
-
});
|
|
242
|
+
this.emit("model.call.end", { finishReason: "error" });
|
|
283
243
|
yield {
|
|
284
244
|
kind: "error",
|
|
285
245
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
@@ -356,9 +316,29 @@ export class Thread {
|
|
|
356
316
|
cancel() {
|
|
357
317
|
this.abort?.abort();
|
|
358
318
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
319
|
+
/**
|
|
320
|
+
* Emit an agent event with common fields auto-filled.
|
|
321
|
+
*/
|
|
322
|
+
emit(kind, payload) {
|
|
323
|
+
const base = {
|
|
324
|
+
kind,
|
|
325
|
+
threadId: this.tid,
|
|
326
|
+
agentId: this.agent.id,
|
|
327
|
+
context: this.context,
|
|
328
|
+
};
|
|
329
|
+
let auto = {};
|
|
330
|
+
switch (kind) {
|
|
331
|
+
case "thread.start":
|
|
332
|
+
case "thread.stop":
|
|
333
|
+
auto = { namespace: this.namespace };
|
|
334
|
+
break;
|
|
335
|
+
case "model.call.start":
|
|
336
|
+
case "model.call.end":
|
|
337
|
+
auto = { provider: this.model.provider, modelId: this.model.modelId };
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
this.agent.emit(kind, { ...base, ...auto, ...payload });
|
|
341
|
+
}
|
|
362
342
|
/**
|
|
363
343
|
* Perform the actions returned by the model
|
|
364
344
|
*/
|
|
@@ -380,7 +360,7 @@ export class Thread {
|
|
|
380
360
|
const pendingApprovals = [];
|
|
381
361
|
// (TODO): clean this - approval tracking should be handled differently
|
|
382
362
|
for (const e of toolEvents) {
|
|
383
|
-
if (e.kind === "tool
|
|
363
|
+
if (e.kind === "tool.result" &&
|
|
384
364
|
e.state === "requires_approval" // (TODO): fix this
|
|
385
365
|
) {
|
|
386
366
|
// find the original tool call for this pending approval
|
|
@@ -404,11 +384,7 @@ export class Thread {
|
|
|
404
384
|
async executeTools(calls) {
|
|
405
385
|
return await Promise.all(calls.map(async (call) => {
|
|
406
386
|
const parsedArgs = JSON.parse(call.arguments || "{}");
|
|
407
|
-
this.
|
|
408
|
-
kind: "tool.call.start",
|
|
409
|
-
threadId: this.tid,
|
|
410
|
-
agentId: this.agent.id,
|
|
411
|
-
context: this.context,
|
|
387
|
+
this.emit("tool.call.start", {
|
|
412
388
|
toolId: call.toolId,
|
|
413
389
|
callId: call.callId,
|
|
414
390
|
args: parsedArgs,
|
|
@@ -426,11 +402,7 @@ export class Thread {
|
|
|
426
402
|
ctx.agent = this.agent;
|
|
427
403
|
ctx.approve(call.callId); // mark this call as approved
|
|
428
404
|
const res = await tool.invoke(ctx, call.arguments, call.callId);
|
|
429
|
-
this.
|
|
430
|
-
kind: "tool.call.end",
|
|
431
|
-
threadId: this.tid,
|
|
432
|
-
agentId: this.agent.id,
|
|
433
|
-
context: this.context,
|
|
405
|
+
this.emit("tool.call.end", {
|
|
434
406
|
toolId: call.toolId,
|
|
435
407
|
callId: call.callId,
|
|
436
408
|
state: res.state,
|
|
@@ -440,7 +412,7 @@ export class Thread {
|
|
|
440
412
|
error: res.error,
|
|
441
413
|
});
|
|
442
414
|
return {
|
|
443
|
-
kind: "tool
|
|
415
|
+
kind: "tool.result",
|
|
444
416
|
callId: call.callId,
|
|
445
417
|
toolId: call.toolId,
|
|
446
418
|
state: res.state,
|
|
@@ -449,18 +421,14 @@ export class Thread {
|
|
|
449
421
|
};
|
|
450
422
|
}
|
|
451
423
|
catch (error) {
|
|
452
|
-
this.
|
|
453
|
-
kind: "tool.call.end",
|
|
454
|
-
threadId: this.tid,
|
|
455
|
-
agentId: this.agent.id,
|
|
456
|
-
context: this.context,
|
|
424
|
+
this.emit("tool.call.end", {
|
|
457
425
|
toolId: call.toolId,
|
|
458
426
|
callId: call.callId,
|
|
459
427
|
state: FAILED,
|
|
460
428
|
error: error instanceof Error ? error.message : String(error),
|
|
461
429
|
});
|
|
462
430
|
return {
|
|
463
|
-
kind: "tool
|
|
431
|
+
kind: "tool.result",
|
|
464
432
|
callId: call.callId,
|
|
465
433
|
toolId: call.toolId,
|
|
466
434
|
state: FAILED,
|
package/dist/thread/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ToolCall, LanguageModel, LanguageModelItem,
|
|
1
|
+
import { ToolCall, LanguageModel, LanguageModelItem, RUNNING, STOPPED, INTERRUPTIBLE, UNINTERRUPTIBLE, ZOMBIE, DEAD, TextStartEvent, TextEndEvent, TextDeltaEvent, ReasoningStartEvent, ReasoningEndEvent, ReasoningDeltaEvent, ToolInputStartEvent, ToolInputEndEvent, ToolInputDeltaEvent, StartEvent, FinishEvent, AbortEvent, ErrorEvent, RawEvent } from "@kernl-sdk/protocol";
|
|
2
2
|
import { Task } from "../task.js";
|
|
3
3
|
import { Context } from "../context.js";
|
|
4
4
|
import { Agent } from "../agent.js";
|
|
@@ -79,9 +79,24 @@ export interface ThreadSystemEvent extends ThreadEventBase {
|
|
|
79
79
|
*/
|
|
80
80
|
export type ThreadEvent = (LanguageModelItem & ThreadEventBase) | ThreadSystemEvent;
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
82
|
+
* Incremental content chunks (ephemeral, not persisted).
|
|
83
83
|
*/
|
|
84
|
-
export type
|
|
84
|
+
export type StreamDeltaEvent = TextDeltaEvent | ReasoningDeltaEvent | ToolInputDeltaEvent;
|
|
85
|
+
/**
|
|
86
|
+
* Boundary markers + control flow (ephemeral, not persisted).
|
|
87
|
+
*/
|
|
88
|
+
export type StreamControlEvent = TextStartEvent | TextEndEvent | ReasoningStartEvent | ReasoningEndEvent | ToolInputStartEvent | ToolInputEndEvent | StartEvent | FinishEvent | AbortEvent | ErrorEvent | RawEvent;
|
|
89
|
+
/**
|
|
90
|
+
* All ephemeral stream types (not persisted to history).
|
|
91
|
+
*/
|
|
92
|
+
export type StreamEvent = StreamDeltaEvent | StreamControlEvent;
|
|
93
|
+
/**
|
|
94
|
+
* Thread stream events = sequenced ThreadEvents + ephemeral StreamEvents.
|
|
95
|
+
*
|
|
96
|
+
* Complete items (Message, ToolCall, etc.) are yielded as ThreadEvents with seq.
|
|
97
|
+
* Deltas and control events are yielded as StreamEvents without seq.
|
|
98
|
+
*/
|
|
99
|
+
export type ThreadStreamEvent = ThreadEvent | StreamEvent;
|
|
85
100
|
/**
|
|
86
101
|
* Result of thread execution
|
|
87
102
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/thread/types.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,aAAa,EACb,iBAAiB,EACjB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/thread/types.ts"],"names":[],"mappings":"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"}
|
package/dist/thread/utils.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { ResolvedAgentResponse } from "../guardrail.js";
|
|
2
|
-
import { ToolCall, LanguageModelItem } from "@kernl-sdk/protocol";
|
|
2
|
+
import { ToolCall, LanguageModelItem, LanguageModelStreamEvent } from "@kernl-sdk/protocol";
|
|
3
3
|
import type { AgentOutputType } from "../agent/types.js";
|
|
4
|
-
import type { ThreadEvent,
|
|
4
|
+
import type { ThreadEvent, ThreadEventBase, ActionSet, PublicThreadEvent } from "./types.js";
|
|
5
5
|
/**
|
|
6
6
|
* Create a ThreadEvent from a LanguageModelItem with thread metadata.
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
|
-
* ```
|
|
9
|
+
* ```ts
|
|
10
10
|
* tevent({
|
|
11
11
|
* kind: "message",
|
|
12
12
|
* seq: 0,
|
|
@@ -28,17 +28,17 @@ export declare function tevent(event: {
|
|
|
28
28
|
/**
|
|
29
29
|
* Check if an event is a tool call
|
|
30
30
|
*/
|
|
31
|
-
export declare function isActionIntention(event:
|
|
31
|
+
export declare function isActionIntention(event: ThreadEvent): event is ToolCall & ThreadEventBase;
|
|
32
32
|
/**
|
|
33
33
|
* Extract action intentions from a list of events.
|
|
34
34
|
* Returns ActionSet if there are any tool calls, null otherwise.
|
|
35
35
|
*/
|
|
36
|
-
export declare function getIntentions(events:
|
|
36
|
+
export declare function getIntentions(events: ThreadEvent[]): ActionSet | null;
|
|
37
37
|
/**
|
|
38
38
|
* Check if an event is NOT a delta/start/end event (i.e., a complete item).
|
|
39
39
|
* Returns true for complete items: Message, Reasoning, ToolCall, ToolResult
|
|
40
40
|
*/
|
|
41
|
-
export declare function notDelta(event:
|
|
41
|
+
export declare function notDelta(event: LanguageModelStreamEvent): event is LanguageModelItem;
|
|
42
42
|
/**
|
|
43
43
|
* Check if an event is public/client-facing (not internal).
|
|
44
44
|
* Filters out internal system events that clients don't need.
|
|
@@ -48,7 +48,7 @@ export declare function isPublicEvent(event: ThreadEvent): event is PublicThread
|
|
|
48
48
|
* Extract the final text response from a list of items.
|
|
49
49
|
* Returns null if no assistant message with text content is found.
|
|
50
50
|
*/
|
|
51
|
-
export declare function getFinalResponse(items:
|
|
51
|
+
export declare function getFinalResponse(items: ThreadEvent[]): string | null;
|
|
52
52
|
/**
|
|
53
53
|
* Parse the final response according to the output type schema.
|
|
54
54
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/thread/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAIzD,OAAO,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/thread/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAIzD,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,SAAS,EACT,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,GAAG,WAAW,CAad;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,WAAW,GACjB,KAAK,IAAI,QAAQ,GAAG,eAAe,CAErC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,GAAG,IAAI,CAGrE;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,wBAAwB,GAC9B,KAAK,IAAI,iBAAiB,CAY5B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,KAAK,IAAI,iBAAiB,CAc5E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,GAAG,IAAI,CAapE;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,SAAS,eAAe,EAChE,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,OAAO,GACd,qBAAqB,CAAC,OAAO,CAAC,CAsBhC"}
|
package/dist/thread/utils.js
CHANGED
|
@@ -5,7 +5,7 @@ import { ModelBehaviorError } from "../lib/error.js";
|
|
|
5
5
|
* Create a ThreadEvent from a LanguageModelItem with thread metadata.
|
|
6
6
|
*
|
|
7
7
|
* @example
|
|
8
|
-
* ```
|
|
8
|
+
* ```ts
|
|
9
9
|
* tevent({
|
|
10
10
|
* kind: "message",
|
|
11
11
|
* seq: 0,
|
|
@@ -32,7 +32,7 @@ export function tevent(event) {
|
|
|
32
32
|
* Check if an event is a tool call
|
|
33
33
|
*/
|
|
34
34
|
export function isActionIntention(event) {
|
|
35
|
-
return event.kind === "tool
|
|
35
|
+
return event.kind === "tool.call";
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
38
|
* Extract action intentions from a list of events.
|
|
@@ -50,8 +50,8 @@ export function notDelta(event) {
|
|
|
50
50
|
switch (event.kind) {
|
|
51
51
|
case "message":
|
|
52
52
|
case "reasoning":
|
|
53
|
-
case "tool
|
|
54
|
-
case "tool
|
|
53
|
+
case "tool.call":
|
|
54
|
+
case "tool.result":
|
|
55
55
|
return true;
|
|
56
56
|
// all other events are streaming deltas/control events
|
|
57
57
|
default:
|
|
@@ -66,8 +66,8 @@ export function isPublicEvent(event) {
|
|
|
66
66
|
switch (event.kind) {
|
|
67
67
|
case "message":
|
|
68
68
|
case "reasoning":
|
|
69
|
-
case "tool
|
|
70
|
-
case "tool
|
|
69
|
+
case "tool.call":
|
|
70
|
+
case "tool.result":
|
|
71
71
|
return true;
|
|
72
72
|
case "system":
|
|
73
73
|
return false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kernl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "A modern AI agent framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kernl",
|
|
@@ -34,21 +34,19 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@modelcontextprotocol/sdk": "^1.20.2",
|
|
36
36
|
"yaml": "^2.8.2",
|
|
37
|
-
"@kernl-sdk/protocol": "0.
|
|
38
|
-
"@kernl-sdk/
|
|
39
|
-
"@kernl-sdk/
|
|
37
|
+
"@kernl-sdk/protocol": "0.5.0",
|
|
38
|
+
"@kernl-sdk/retrieval": "0.1.9",
|
|
39
|
+
"@kernl-sdk/shared": "^0.4.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"zod": "^4.1.8"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@ai-sdk/openai": "3.0.0-beta.57",
|
|
46
45
|
"@types/node": "^24.10.0",
|
|
47
46
|
"tsc-alias": "^1.8.10",
|
|
48
47
|
"typescript": "5.9.2",
|
|
49
48
|
"vitest": "^4.0.8",
|
|
50
|
-
"zod": "^4.1.8"
|
|
51
|
-
"@kernl-sdk/ai": "0.3.5"
|
|
49
|
+
"zod": "^4.1.8"
|
|
52
50
|
},
|
|
53
51
|
"scripts": {
|
|
54
52
|
"clean": "rm -rf dist",
|
|
@@ -268,7 +268,7 @@ describe("Agent.stream() lifecycle", () => {
|
|
|
268
268
|
events.push(event);
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
-
expect(events[0]).toEqual({ kind: "stream
|
|
271
|
+
expect(events[0]).toEqual({ kind: "stream.start" });
|
|
272
272
|
});
|
|
273
273
|
|
|
274
274
|
it("should have same persistence behavior as run()", async () => {
|
|
@@ -305,7 +305,7 @@ describe("Agent.stream() lifecycle", () => {
|
|
|
305
305
|
// Should have streamed events
|
|
306
306
|
expect(events).toEqual(
|
|
307
307
|
expect.arrayContaining([
|
|
308
|
-
{ kind: "stream
|
|
308
|
+
{ kind: "stream.start" },
|
|
309
309
|
expect.objectContaining({ kind: "message" }),
|
|
310
310
|
]),
|
|
311
311
|
);
|
package/src/index.ts
CHANGED
|
@@ -308,7 +308,7 @@ describe("Lifecycle Hooks", () => {
|
|
|
308
308
|
content: [
|
|
309
309
|
message({ role: "assistant", text: "" }),
|
|
310
310
|
{
|
|
311
|
-
kind: "tool
|
|
311
|
+
kind: "tool.call" as const,
|
|
312
312
|
toolId: "echo",
|
|
313
313
|
state: IN_PROGRESS,
|
|
314
314
|
callId: "call_1",
|
|
@@ -381,7 +381,7 @@ describe("Lifecycle Hooks", () => {
|
|
|
381
381
|
content: [
|
|
382
382
|
message({ role: "assistant", text: "" }),
|
|
383
383
|
{
|
|
384
|
-
kind: "tool
|
|
384
|
+
kind: "tool.call" as const,
|
|
385
385
|
toolId: "add",
|
|
386
386
|
state: IN_PROGRESS,
|
|
387
387
|
callId: "call_1",
|
|
@@ -446,7 +446,7 @@ describe("Lifecycle Hooks", () => {
|
|
|
446
446
|
content: [
|
|
447
447
|
message({ role: "assistant", text: "" }),
|
|
448
448
|
{
|
|
449
|
-
kind: "tool
|
|
449
|
+
kind: "tool.call" as const,
|
|
450
450
|
toolId: "add",
|
|
451
451
|
state: IN_PROGRESS,
|
|
452
452
|
callId: "call_1",
|
|
@@ -510,7 +510,7 @@ describe("Lifecycle Hooks", () => {
|
|
|
510
510
|
content: [
|
|
511
511
|
message({ role: "assistant", text: "" }),
|
|
512
512
|
{
|
|
513
|
-
kind: "tool
|
|
513
|
+
kind: "tool.call" as const,
|
|
514
514
|
toolId: "failing",
|
|
515
515
|
state: IN_PROGRESS,
|
|
516
516
|
callId: "call_1",
|
|
@@ -576,14 +576,14 @@ describe("Lifecycle Hooks", () => {
|
|
|
576
576
|
content: [
|
|
577
577
|
message({ role: "assistant", text: "" }),
|
|
578
578
|
{
|
|
579
|
-
kind: "tool
|
|
579
|
+
kind: "tool.call" as const,
|
|
580
580
|
toolId: "tool1",
|
|
581
581
|
state: IN_PROGRESS,
|
|
582
582
|
callId: "call_1",
|
|
583
583
|
arguments: JSON.stringify({ value: "a" }),
|
|
584
584
|
},
|
|
585
585
|
{
|
|
586
|
-
kind: "tool
|
|
586
|
+
kind: "tool.call" as const,
|
|
587
587
|
toolId: "tool2",
|
|
588
588
|
state: IN_PROGRESS,
|
|
589
589
|
callId: "call_2",
|
|
@@ -20,18 +20,18 @@ async function* streamFromResponse(
|
|
|
20
20
|
if (contentItem.kind === "text") {
|
|
21
21
|
// Yield text-start
|
|
22
22
|
yield {
|
|
23
|
-
kind: "text
|
|
23
|
+
kind: "text.start" as const,
|
|
24
24
|
id: item.id,
|
|
25
25
|
};
|
|
26
26
|
// Yield text-delta
|
|
27
27
|
yield {
|
|
28
|
-
kind: "text
|
|
28
|
+
kind: "text.delta" as const,
|
|
29
29
|
id: item.id,
|
|
30
30
|
text: contentItem.text,
|
|
31
31
|
};
|
|
32
32
|
// Yield text-end
|
|
33
33
|
yield {
|
|
34
|
-
kind: "text
|
|
34
|
+
kind: "text.end" as const,
|
|
35
35
|
id: item.id,
|
|
36
36
|
};
|
|
37
37
|
}
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
LanguageModelResponse,
|
|
5
5
|
LanguageModelResponseItem,
|
|
6
6
|
LanguageModelItem,
|
|
7
|
+
LanguageModelStreamEvent,
|
|
7
8
|
} from "@kernl-sdk/protocol";
|
|
8
|
-
import type { ThreadStreamEvent } from "@/thread/types";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* A mock language model that echoes the user input back as an assistant message.
|
|
@@ -54,7 +54,7 @@ export class MockLanguageModel implements LanguageModel {
|
|
|
54
54
|
|
|
55
55
|
async *stream(
|
|
56
56
|
request: LanguageModelRequest,
|
|
57
|
-
): AsyncIterable<
|
|
57
|
+
): AsyncIterable<LanguageModelStreamEvent> {
|
|
58
58
|
// TODO: Implement streaming (not needed for hello world)
|
|
59
59
|
throw new Error("MockLanguageModel.stream() not implemented yet");
|
|
60
60
|
}
|
|
@@ -77,7 +77,7 @@ describe("Thread Persistence", () => {
|
|
|
77
77
|
// return {
|
|
78
78
|
// content: [
|
|
79
79
|
// message({ role: "assistant", text: "" }),
|
|
80
|
-
// { kind: "tool
|
|
80
|
+
// { kind: "tool.call", toolId: "test", callId: "call_1", state: IN_PROGRESS, arguments: "{}" },
|
|
81
81
|
// ],
|
|
82
82
|
// finishReason: "stop",
|
|
83
83
|
// usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
@@ -138,7 +138,7 @@ describe("Thread Persistence", () => {
|
|
|
138
138
|
// return {
|
|
139
139
|
// content: [
|
|
140
140
|
// message({ role: "assistant", text: "" }),
|
|
141
|
-
// { kind: "tool
|
|
141
|
+
// { kind: "tool.call", toolId: "echo", callId: "call_1", state: IN_PROGRESS, arguments: '{"text":"test"}' },
|
|
142
142
|
// ],
|
|
143
143
|
// finishReason: "stop",
|
|
144
144
|
// usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
@@ -178,7 +178,7 @@ describe("Thread Persistence", () => {
|
|
|
178
178
|
//
|
|
179
179
|
// // Find the append call for tick 1 (should include model message, tool-call, and tool-result)
|
|
180
180
|
// const tick1Events = storage.calls.append.find(batch =>
|
|
181
|
-
// batch.some(e => e.kind === "tool
|
|
181
|
+
// batch.some(e => e.kind === "tool.result")
|
|
182
182
|
// );
|
|
183
183
|
//
|
|
184
184
|
// expect(tick1Events).toBeDefined();
|
|
@@ -188,8 +188,8 @@ describe("Thread Persistence", () => {
|
|
|
188
188
|
// expect(tick1Events).toEqual(
|
|
189
189
|
// expect.arrayContaining([
|
|
190
190
|
// expect.objectContaining({ kind: "message", role: "assistant" }),
|
|
191
|
-
// expect.objectContaining({ kind: "tool
|
|
192
|
-
// expect.objectContaining({ kind: "tool
|
|
191
|
+
// expect.objectContaining({ kind: "tool.call", toolId: "echo" }),
|
|
192
|
+
// expect.objectContaining({ kind: "tool.result", toolId: "echo", result: "Echo: test" }),
|
|
193
193
|
// ])
|
|
194
194
|
// );
|
|
195
195
|
});
|
|
@@ -232,7 +232,7 @@ describe("Thread Persistence", () => {
|
|
|
232
232
|
// expect(lastUpdate.patch.state).toBe(STOPPED);
|
|
233
233
|
//
|
|
234
234
|
// // Verify stream-start event
|
|
235
|
-
// expect(events[0]).toEqual({ kind: "stream
|
|
235
|
+
// expect(events[0]).toEqual({ kind: "stream.start" });
|
|
236
236
|
});
|
|
237
237
|
|
|
238
238
|
it.skip("should persist STOPPED state even on model error", async () => {
|