kernl 0.11.0 → 0.11.2
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 +16 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/kernl/kernl.d.ts.map +1 -1
- package/dist/kernl/kernl.js +1 -61
- package/dist/lifecycle/__tests__/hooks.test.js +37 -4
- package/dist/lifecycle.d.ts +2 -6
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/thread/thread.d.ts +8 -0
- package/dist/thread/thread.d.ts.map +1 -1
- package/dist/thread/thread.js +37 -11
- package/dist/thread/utils.d.ts.map +1 -1
- package/dist/thread/utils.js +2 -3
- package/package.json +3 -3
- package/src/index.ts +12 -0
- package/src/kernl/kernl.ts +1 -66
- package/src/lifecycle/__tests__/hooks.test.ts +45 -4
- package/src/lifecycle.ts +2 -7
- package/src/thread/thread.ts +39 -14
- package/src/thread/utils.ts +2 -3
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @kernl/core
|
|
2
2
|
|
|
3
|
+
## 0.11.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 47e44c0: Fix lifecycle event architecture: Thread now owns all lifecycle events and emits via agent for uniform observability
|
|
8
|
+
- Move thread.start/stop emissions from Kernl to Thread.stream()
|
|
9
|
+
- Both agent.on() and kernl.on() now receive all lifecycle events
|
|
10
|
+
- Remove redundant outcome field from ThreadStopEvent (use result/error instead)
|
|
11
|
+
- Fix: schedule() was missing thread events, agent.on("thread.\*") never fired
|
|
12
|
+
|
|
13
|
+
## 0.11.1
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- e1a7848: Export lifecycle event types from package root
|
|
18
|
+
|
|
3
19
|
## 0.11.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { Kernl } from "./kernl/index.js";
|
|
|
2
2
|
export type { KernlOptions, StorageOptions, AgentRegistry, ModelRegistry, } from "./kernl/index.js";
|
|
3
3
|
export { Agent } from "./agent.js";
|
|
4
4
|
export { Context } from "./context.js";
|
|
5
|
+
export type { LifecycleEvent, ThreadStartEvent, ThreadStopEvent, ModelCallStartEvent, ModelCallEndEvent, ToolCallStartEvent, ToolCallEndEvent, } from "./lifecycle.js";
|
|
5
6
|
export { RealtimeAgent, RealtimeSession, WebSocketTransport } from "./realtime/index.js";
|
|
6
7
|
export type { RealtimeAgentConfig, RealtimeAgentVoiceConfig, RealtimeSessionOptions, WebSocketTransportOptions, } from "./realtime/index.js";
|
|
7
8
|
export { tool, Toolkit, FunctionToolkit, MCPToolkit } from "./tool/index.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChF,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAIrD,YAAY,EACV,OAAO,IAAI,MAAM,EACjB,YAAY,IAAI,WAAW,EAC3B,gBAAgB,IAAI,eAAe,GACpC,MAAM,cAAc,CAAC;AAEtB,YAAY,EACV,kBAAkB,IAAI,iBAAiB,EACvC,iBAAiB,IAAI,gBAAgB,EACrC,oBAAoB,IAAI,mBAAmB,EAC3C,mBAAmB,IAAI,kBAAkB,EACzC,mBAAmB,IAAI,kBAAkB,GAC1C,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,aAAa,EACb,KAAK,WAAW,EAChB,KAAK,iBAAiB,GACvB,MAAM,gBAAgB,CAAC;AAIxB,YAAY,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,oBAAoB,EACpB,aAAa,EACb,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,WAAW,GACZ,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACrD,YAAY,EACV,WAAW,EACX,WAAW,EACX,SAAS,EACT,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,UAAU,EACV,eAAe,GAChB,MAAM,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChF,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAIrD,YAAY,EACV,OAAO,IAAI,MAAM,EACjB,YAAY,IAAI,WAAW,EAC3B,gBAAgB,IAAI,eAAe,GACpC,MAAM,cAAc,CAAC;AAEtB,YAAY,EACV,kBAAkB,IAAI,iBAAiB,EACvC,iBAAiB,IAAI,gBAAgB,EACrC,oBAAoB,IAAI,mBAAmB,EAC3C,mBAAmB,IAAI,kBAAkB,EACzC,mBAAmB,IAAI,kBAAkB,GAC1C,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,aAAa,EACb,KAAK,WAAW,EAChB,KAAK,iBAAiB,GACvB,MAAM,gBAAgB,CAAC;AAIxB,YAAY,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,oBAAoB,EACpB,aAAa,EACb,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,WAAW,GACZ,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACrD,YAAY,EACV,WAAW,EACX,WAAW,EACX,SAAS,EACT,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,UAAU,EACV,eAAe,GAChB,MAAM,UAAU,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kernl.d.ts","sourceRoot":"","sources":["../../src/kernl/kernl.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EACL,MAAM,EAIP,MAAM,UAAU,CAAC;AAIlB,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAiC,MAAM,SAAS,CAAC;AAE3E;;;;;GAKG;AACH,qBAAa,KAAM,SAAQ,UAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;IAEjE,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAa;IAEpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IACrD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6B;IAEvD,OAAO,CAAC,QAAQ,CAGd;IAGF,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,OAAO,GAAE,YAAiB;IAatC;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAgChC;;OAEG;IACG,KAAK,CAAC,QAAQ,EAAE,OAAO,SAAS,eAAe,EACnD,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"kernl.d.ts","sourceRoot":"","sources":["../../src/kernl/kernl.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EACL,MAAM,EAIP,MAAM,UAAU,CAAC;AAIlB,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAiC,MAAM,SAAS,CAAC;AAE3E;;;;;GAKG;AACH,qBAAa,KAAM,SAAQ,UAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;IAEjE,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAa;IAEpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IACrD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6B;IAEvD,OAAO,CAAC,QAAQ,CAGd;IAGF,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,OAAO,GAAE,YAAiB;IAatC;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAgChC;;OAEG;IACG,KAAK,CAAC,QAAQ,EAAE,OAAO,SAAS,eAAe,EACnD,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IAS/D;;;;OAIG;IACG,QAAQ,CAAC,QAAQ,EAAE,OAAO,SAAS,eAAe,EACtD,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IAS/D;;;;OAIG;IACI,WAAW,CAAC,QAAQ,EAAE,OAAO,SAAS,eAAe,EAC1D,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAChC,aAAa,CAAC,iBAAiB,CAAC;IASnC;;;;OAIG;IACI,cAAc,CAAC,QAAQ,EAAE,OAAO,SAAS,eAAe,EAC7D,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAChC,aAAa,CAAC,iBAAiB,CAAC;IAWnC;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;CA6BzB"}
|
package/dist/kernl/kernl.js
CHANGED
|
@@ -68,39 +68,8 @@ export class Kernl extends KernlHooks {
|
|
|
68
68
|
*/
|
|
69
69
|
async spawn(thread) {
|
|
70
70
|
this.athreads.set(thread.tid, thread);
|
|
71
|
-
this.emit("thread.start", {
|
|
72
|
-
kind: "thread.start",
|
|
73
|
-
threadId: thread.tid,
|
|
74
|
-
agentId: thread.agent.id,
|
|
75
|
-
namespace: thread.namespace,
|
|
76
|
-
context: thread.context,
|
|
77
|
-
});
|
|
78
71
|
try {
|
|
79
|
-
|
|
80
|
-
this.emit("thread.stop", {
|
|
81
|
-
kind: "thread.stop",
|
|
82
|
-
threadId: thread.tid,
|
|
83
|
-
agentId: thread.agent.id,
|
|
84
|
-
namespace: thread.namespace,
|
|
85
|
-
context: thread.context,
|
|
86
|
-
state: thread.state,
|
|
87
|
-
outcome: "success",
|
|
88
|
-
result: result.response,
|
|
89
|
-
});
|
|
90
|
-
return result;
|
|
91
|
-
}
|
|
92
|
-
catch (err) {
|
|
93
|
-
this.emit("thread.stop", {
|
|
94
|
-
kind: "thread.stop",
|
|
95
|
-
threadId: thread.tid,
|
|
96
|
-
agentId: thread.agent.id,
|
|
97
|
-
namespace: thread.namespace,
|
|
98
|
-
context: thread.context,
|
|
99
|
-
state: thread.state,
|
|
100
|
-
outcome: "error",
|
|
101
|
-
error: err instanceof Error ? err.message : String(err),
|
|
102
|
-
});
|
|
103
|
-
throw err;
|
|
72
|
+
return await thread.execute();
|
|
104
73
|
}
|
|
105
74
|
finally {
|
|
106
75
|
this.athreads.delete(thread.tid);
|
|
@@ -127,37 +96,8 @@ export class Kernl extends KernlHooks {
|
|
|
127
96
|
*/
|
|
128
97
|
async *spawnStream(thread) {
|
|
129
98
|
this.athreads.set(thread.tid, thread);
|
|
130
|
-
this.emit("thread.start", {
|
|
131
|
-
kind: "thread.start",
|
|
132
|
-
threadId: thread.tid,
|
|
133
|
-
agentId: thread.agent.id,
|
|
134
|
-
namespace: thread.namespace,
|
|
135
|
-
context: thread.context,
|
|
136
|
-
});
|
|
137
99
|
try {
|
|
138
100
|
yield* thread.stream();
|
|
139
|
-
this.emit("thread.stop", {
|
|
140
|
-
kind: "thread.stop",
|
|
141
|
-
threadId: thread.tid,
|
|
142
|
-
agentId: thread.agent.id,
|
|
143
|
-
namespace: thread.namespace,
|
|
144
|
-
context: thread.context,
|
|
145
|
-
state: thread.state,
|
|
146
|
-
outcome: "success",
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
catch (err) {
|
|
150
|
-
this.emit("thread.stop", {
|
|
151
|
-
kind: "thread.stop",
|
|
152
|
-
threadId: thread.tid,
|
|
153
|
-
agentId: thread.agent.id,
|
|
154
|
-
namespace: thread.namespace,
|
|
155
|
-
context: thread.context,
|
|
156
|
-
state: thread.state,
|
|
157
|
-
outcome: "error",
|
|
158
|
-
error: err instanceof Error ? err.message : String(err),
|
|
159
|
-
});
|
|
160
|
-
throw err;
|
|
161
101
|
}
|
|
162
102
|
finally {
|
|
163
103
|
this.athreads.delete(thread.tid);
|
|
@@ -35,7 +35,7 @@ describe("Lifecycle Hooks", () => {
|
|
|
35
35
|
expect(events[0].threadId).toBeDefined();
|
|
36
36
|
expect(events[0].context).toBeDefined();
|
|
37
37
|
});
|
|
38
|
-
it("emits thread.stop with
|
|
38
|
+
it("emits thread.stop with result on successful run", async () => {
|
|
39
39
|
const events = [];
|
|
40
40
|
const model = createMockModel(async () => ({
|
|
41
41
|
content: [message({ role: "assistant", text: "Done" })],
|
|
@@ -58,12 +58,11 @@ describe("Lifecycle Hooks", () => {
|
|
|
58
58
|
kind: "thread.stop",
|
|
59
59
|
agentId: "test-agent",
|
|
60
60
|
namespace: "kernl",
|
|
61
|
-
outcome: "success",
|
|
62
61
|
state: "stopped",
|
|
63
62
|
result: "Done",
|
|
64
63
|
});
|
|
65
64
|
});
|
|
66
|
-
it("emits thread.stop with
|
|
65
|
+
it("emits thread.stop with error on failure", async () => {
|
|
67
66
|
const events = [];
|
|
68
67
|
const model = createMockModel(async () => {
|
|
69
68
|
throw new Error("Model exploded");
|
|
@@ -82,7 +81,6 @@ describe("Lifecycle Hooks", () => {
|
|
|
82
81
|
expect(events[0]).toMatchObject({
|
|
83
82
|
kind: "thread.stop",
|
|
84
83
|
agentId: "test-agent",
|
|
85
|
-
outcome: "error",
|
|
86
84
|
error: "Model exploded",
|
|
87
85
|
});
|
|
88
86
|
});
|
|
@@ -112,6 +110,41 @@ describe("Lifecycle Hooks", () => {
|
|
|
112
110
|
expect(kernlEvents).toHaveLength(1);
|
|
113
111
|
expect(agentEvents[0].threadId).toBe(kernlEvents[0].threadId);
|
|
114
112
|
});
|
|
113
|
+
it("agent.on receives thread events (emitted by Thread via agent.emit)", async () => {
|
|
114
|
+
const agentStartEvents = [];
|
|
115
|
+
const agentStopEvents = [];
|
|
116
|
+
const kernlStartEvents = [];
|
|
117
|
+
const kernlStopEvents = [];
|
|
118
|
+
const model = createMockModel(async () => ({
|
|
119
|
+
content: [message({ role: "assistant", text: "Done" })],
|
|
120
|
+
finishReason: "stop",
|
|
121
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
122
|
+
warnings: [],
|
|
123
|
+
}));
|
|
124
|
+
const agent = new Agent({
|
|
125
|
+
id: "test-agent",
|
|
126
|
+
name: "Test",
|
|
127
|
+
instructions: "Test",
|
|
128
|
+
model,
|
|
129
|
+
});
|
|
130
|
+
const kernl = new Kernl();
|
|
131
|
+
kernl.register(agent);
|
|
132
|
+
// Thread events should be receivable via both agent.on and kernl.on
|
|
133
|
+
agent.on("thread.start", (e) => agentStartEvents.push(e));
|
|
134
|
+
agent.on("thread.stop", (e) => agentStopEvents.push(e));
|
|
135
|
+
kernl.on("thread.start", (e) => kernlStartEvents.push(e));
|
|
136
|
+
kernl.on("thread.stop", (e) => kernlStopEvents.push(e));
|
|
137
|
+
await agent.run("Hello");
|
|
138
|
+
// Both agent and kernl should receive thread events
|
|
139
|
+
expect(agentStartEvents).toHaveLength(1);
|
|
140
|
+
expect(agentStopEvents).toHaveLength(1);
|
|
141
|
+
expect(kernlStartEvents).toHaveLength(1);
|
|
142
|
+
expect(kernlStopEvents).toHaveLength(1);
|
|
143
|
+
// Same event data
|
|
144
|
+
expect(agentStartEvents[0].threadId).toBe(kernlStartEvents[0].threadId);
|
|
145
|
+
expect(agentStopEvents[0].threadId).toBe(kernlStopEvents[0].threadId);
|
|
146
|
+
expect(agentStopEvents[0].result).toBeDefined();
|
|
147
|
+
});
|
|
115
148
|
});
|
|
116
149
|
describe("Model events", () => {
|
|
117
150
|
it("emits model.call.start before generation", async () => {
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -54,15 +54,11 @@ export interface ThreadStopEvent<TContext = unknown, TOutput = unknown> {
|
|
|
54
54
|
*/
|
|
55
55
|
state: ThreadState;
|
|
56
56
|
/**
|
|
57
|
-
* The
|
|
58
|
-
*/
|
|
59
|
-
outcome: "success" | "error" | "cancelled";
|
|
60
|
-
/**
|
|
61
|
-
* The result if outcome is "success".
|
|
57
|
+
* The result of execution (present on success).
|
|
62
58
|
*/
|
|
63
59
|
result?: TOutput;
|
|
64
60
|
/**
|
|
65
|
-
* Error message
|
|
61
|
+
* Error message (present on error).
|
|
66
62
|
*/
|
|
67
63
|
error?: string;
|
|
68
64
|
}
|
package/dist/lifecycle.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C,OAAO,KAAK,EACV,kBAAkB,EAClB,yBAAyB,EACzB,4BAA4B,EAC5B,aAAa,EACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAIlD;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,QAAQ,GAAG,OAAO;IAClD,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAE9B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,QAAQ,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO;IACpE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAE7B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE3B;;OAEG;IACH,KAAK,EAAE,WAAW,CAAC;IAEnB;;OAEG;IACH,
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"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"}
|
package/dist/thread/thread.d.ts
CHANGED
|
@@ -61,6 +61,7 @@ export declare class Thread<TContext = unknown, TOutput extends AgentOutputType
|
|
|
61
61
|
private cpbuf;
|
|
62
62
|
private persisted;
|
|
63
63
|
private history;
|
|
64
|
+
private tickres?;
|
|
64
65
|
private abort?;
|
|
65
66
|
private storage?;
|
|
66
67
|
constructor(options: ThreadOptions<TContext, TOutput>);
|
|
@@ -70,6 +71,11 @@ export declare class Thread<TContext = unknown, TOutput extends AgentOutputType
|
|
|
70
71
|
execute(): Promise<ThreadExecuteResult<ResolvedAgentResponse<TOutput>>>;
|
|
71
72
|
/**
|
|
72
73
|
* Streaming execution - returns async iterator of events
|
|
74
|
+
*
|
|
75
|
+
* All runs (new or resumed) emit:
|
|
76
|
+
* - Exactly one thread.start
|
|
77
|
+
* - Zero or more model.call.* and tool.call.*
|
|
78
|
+
* - Exactly one thread.stop (with result on success, error on failure)
|
|
73
79
|
*/
|
|
74
80
|
stream(): AsyncIterable<ThreadStreamEvent>;
|
|
75
81
|
/**
|
|
@@ -103,6 +109,8 @@ export declare class Thread<TContext = unknown, TOutput extends AgentOutputType
|
|
|
103
109
|
append(...items: ThreadEventInner[]): ThreadEvent[];
|
|
104
110
|
/**
|
|
105
111
|
* Cancel the running thread
|
|
112
|
+
*
|
|
113
|
+
* TODO: Emit thread.stop when cancelled (neither result nor error set)
|
|
106
114
|
*/
|
|
107
115
|
cancel(): void;
|
|
108
116
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../../src/thread/thread.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAKzD,OAAO,EAML,aAAa,EAKd,MAAM,qBAAqB,CAAC;AAG7B,OAAO,KAAK,EAEV,WAAW,EACX,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EAEpB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAWrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBAAa,MAAM,CACjB,QAAQ,GAAG,OAAO,EAClB,OAAO,SAAS,eAAe,GAAG,MAAM;IAExC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACzC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAIlD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,OAAO,CAAwE;
|
|
1
|
+
{"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../../src/thread/thread.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAKzD,OAAO,EAML,aAAa,EAKd,MAAM,qBAAqB,CAAC;AAG7B,OAAO,KAAK,EAEV,WAAW,EACX,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EAEpB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAWrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBAAa,MAAM,CACjB,QAAQ,GAAG,OAAO,EAClB,OAAO,SAAS,eAAe,GAAG,MAAM;IAExC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACzC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAIlD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,OAAO,CAAwE;IACvF,OAAO,CAAC,OAAO,CAAC,CAAiC;IAEjD,OAAO,CAAC,KAAK,CAAC,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAC,CAAc;gBAElB,OAAO,EAAE,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC;IAgCrD;;OAEG;IACG,OAAO,IAAI,OAAO,CACtB,mBAAmB,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CACpD;IAQD;;;;;;;OAOG;IACI,MAAM,IAAI,aAAa,CAAC,iBAAiB,CAAC;IAmDjD;;;;;OAKG;YACY,QAAQ;IAiEvB;;;;;OAKG;YACY,IAAI;IAoEnB;;;;;OAKG;YACW,UAAU;IAuCxB;;;;;;OAMG;IACH,MAAM,CAAC,GAAG,KAAK,EAAE,gBAAgB,EAAE,GAAG,WAAW,EAAE;IAiBnD;;;;OAIG;IACH,MAAM;IAQN;;OAEG;YACW,cAAc;IAyC5B;;;;OAIG;YACW,YAAY;IAkF1B;;OAEG;YACW,mBAAmB;CAsDlC"}
|
package/dist/thread/thread.js
CHANGED
|
@@ -63,6 +63,7 @@ export class Thread {
|
|
|
63
63
|
cpbuf; /* checkpoint buffer - events pending persistence */
|
|
64
64
|
persisted; /* indicates thread was hydrated from storage */
|
|
65
65
|
history;
|
|
66
|
+
tickres; /* final result from terminal tick */
|
|
66
67
|
abort;
|
|
67
68
|
storage;
|
|
68
69
|
constructor(options) {
|
|
@@ -100,20 +101,16 @@ export class Thread {
|
|
|
100
101
|
for await (const _event of this.stream()) {
|
|
101
102
|
// just consume the stream (already in history in _execute())
|
|
102
103
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
.filter((e) => e.kind !== "system")
|
|
106
|
-
.map((e) => {
|
|
107
|
-
const { tid, seq, timestamp, metadata, ...item } = e;
|
|
108
|
-
return item;
|
|
109
|
-
});
|
|
110
|
-
const text = getFinalResponse(items);
|
|
111
|
-
assert(text, "_execute continues until text !== null"); // (TODO): consider preventing infinite loops here
|
|
112
|
-
const parsed = parseFinalResponse(text, this.agent.output);
|
|
113
|
-
return { response: parsed, state: this.state };
|
|
104
|
+
assert(this.tickres, "_execute continues until tickres is set");
|
|
105
|
+
return { response: this.tickres, state: this.state };
|
|
114
106
|
}
|
|
115
107
|
/**
|
|
116
108
|
* Streaming execution - returns async iterator of events
|
|
109
|
+
*
|
|
110
|
+
* All runs (new or resumed) emit:
|
|
111
|
+
* - Exactly one thread.start
|
|
112
|
+
* - Zero or more model.call.* and tool.call.*
|
|
113
|
+
* - Exactly one thread.stop (with result on success, error on failure)
|
|
117
114
|
*/
|
|
118
115
|
async *stream() {
|
|
119
116
|
if (this.state === RUNNING && this.abort) {
|
|
@@ -121,12 +118,38 @@ export class Thread {
|
|
|
121
118
|
}
|
|
122
119
|
this.state = RUNNING;
|
|
123
120
|
this.abort = new AbortController();
|
|
121
|
+
this.tickres = undefined; // reset for this run
|
|
124
122
|
await this.checkpoint(); /* c1: persist RUNNING state + initial input */
|
|
123
|
+
this.agent.emit("thread.start", {
|
|
124
|
+
kind: "thread.start",
|
|
125
|
+
threadId: this.tid,
|
|
126
|
+
agentId: this.agent.id,
|
|
127
|
+
namespace: this.namespace,
|
|
128
|
+
context: this.context,
|
|
129
|
+
});
|
|
125
130
|
yield { kind: "stream-start" }; // always yield start immediately
|
|
126
131
|
try {
|
|
127
132
|
yield* this._execute();
|
|
133
|
+
this.agent.emit("thread.stop", {
|
|
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
|
+
});
|
|
128
142
|
}
|
|
129
143
|
catch (err) {
|
|
144
|
+
this.agent.emit("thread.stop", {
|
|
145
|
+
kind: "thread.stop",
|
|
146
|
+
threadId: this.tid,
|
|
147
|
+
agentId: this.agent.id,
|
|
148
|
+
namespace: this.namespace,
|
|
149
|
+
context: this.context,
|
|
150
|
+
state: STOPPED,
|
|
151
|
+
error: err instanceof Error ? err.message : String(err),
|
|
152
|
+
});
|
|
130
153
|
throw err;
|
|
131
154
|
}
|
|
132
155
|
finally {
|
|
@@ -170,6 +193,7 @@ export class Thread {
|
|
|
170
193
|
const text = getFinalResponse(events);
|
|
171
194
|
if (!text)
|
|
172
195
|
continue; // run again, policy-dependent? (how to ensure no infinite loop here?)
|
|
196
|
+
this.tickres = parseFinalResponse(text, this.agent.output);
|
|
173
197
|
await this.checkpoint(); /* c2: terminal tick - no tool calls */
|
|
174
198
|
// await this.agent.runOutputGuardails(context, state);
|
|
175
199
|
// this.kernl.emit("thread.terminated", context, output);
|
|
@@ -326,6 +350,8 @@ export class Thread {
|
|
|
326
350
|
}
|
|
327
351
|
/**
|
|
328
352
|
* Cancel the running thread
|
|
353
|
+
*
|
|
354
|
+
* TODO: Emit thread.stop when cancelled (neither result nor error set)
|
|
329
355
|
*/
|
|
330
356
|
cancel() {
|
|
331
357
|
this.abort?.abort();
|
|
@@ -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,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAIlE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EACV,WAAW,EAEX,iBAAiB,EACjB,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,CAAC,KAAK,EAAE,iBAAiB,GAAG,KAAK,IAAI,QAAQ,CAE7E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,SAAS,GAAG,IAAI,CAG3E;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,KAAK,IAAI,iBAAiB,CAY7E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,KAAK,IAAI,iBAAiB,CAc5E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,MAAM,GAAG,IAAI,
|
|
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,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAIlE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EACV,WAAW,EAEX,iBAAiB,EACjB,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,CAAC,KAAK,EAAE,iBAAiB,GAAG,KAAK,IAAI,QAAQ,CAE7E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,SAAS,GAAG,IAAI,CAG3E;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,KAAK,IAAI,iBAAiB,CAY7E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,KAAK,IAAI,iBAAiB,CAc5E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,MAAM,GAAG,IAAI,CAa1E;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
|
@@ -80,11 +80,10 @@ export function isPublicEvent(event) {
|
|
|
80
80
|
* Returns null if no assistant message with text content is found.
|
|
81
81
|
*/
|
|
82
82
|
export function getFinalResponse(items) {
|
|
83
|
-
//
|
|
83
|
+
// scan backwards for the last assistant message
|
|
84
84
|
for (let i = items.length - 1; i >= 0; i--) {
|
|
85
85
|
const item = items[i];
|
|
86
86
|
if (item.kind === "message" && item.role === "assistant") {
|
|
87
|
-
// Extract text from content parts
|
|
88
87
|
for (const part of item.content) {
|
|
89
88
|
if (part.kind === "text") {
|
|
90
89
|
return part.text;
|
|
@@ -120,6 +119,6 @@ export function parseFinalResponse(text, output) {
|
|
|
120
119
|
throw new ModelBehaviorError(`Failed to parse structured output: ${error instanceof Error ? error.message : String(error)}`);
|
|
121
120
|
}
|
|
122
121
|
}
|
|
123
|
-
//
|
|
122
|
+
// fallback - should not reach here
|
|
124
123
|
return text;
|
|
125
124
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kernl",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.2",
|
|
4
4
|
"description": "A modern AI agent framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kernl",
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@modelcontextprotocol/sdk": "^1.20.2",
|
|
36
36
|
"yaml": "^2.8.2",
|
|
37
|
-
"@kernl-sdk/protocol": "0.4.1",
|
|
38
37
|
"@kernl-sdk/retrieval": "0.1.7",
|
|
39
|
-
"@kernl-sdk/shared": "^0.3.1"
|
|
38
|
+
"@kernl-sdk/shared": "^0.3.1",
|
|
39
|
+
"@kernl-sdk/protocol": "0.4.1"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"zod": "^4.1.8"
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,18 @@ export type {
|
|
|
8
8
|
export { Agent } from "./agent";
|
|
9
9
|
export { Context } from "./context";
|
|
10
10
|
|
|
11
|
+
// --- lifecycle hooks ---
|
|
12
|
+
|
|
13
|
+
export type {
|
|
14
|
+
LifecycleEvent,
|
|
15
|
+
ThreadStartEvent,
|
|
16
|
+
ThreadStopEvent,
|
|
17
|
+
ModelCallStartEvent,
|
|
18
|
+
ModelCallEndEvent,
|
|
19
|
+
ToolCallStartEvent,
|
|
20
|
+
ToolCallEndEvent,
|
|
21
|
+
} from "./lifecycle";
|
|
22
|
+
|
|
11
23
|
// --- realtime ---
|
|
12
24
|
|
|
13
25
|
export { RealtimeAgent, RealtimeSession, WebSocketTransport } from "./realtime";
|
package/src/kernl/kernl.ts
CHANGED
|
@@ -102,42 +102,8 @@ export class Kernl extends KernlHooks {
|
|
|
102
102
|
thread: Thread<TContext, TOutput>,
|
|
103
103
|
): Promise<ThreadExecuteResult<ResolvedAgentResponse<TOutput>>> {
|
|
104
104
|
this.athreads.set(thread.tid, thread);
|
|
105
|
-
|
|
106
|
-
this.emit("thread.start", {
|
|
107
|
-
kind: "thread.start",
|
|
108
|
-
threadId: thread.tid,
|
|
109
|
-
agentId: thread.agent.id,
|
|
110
|
-
namespace: thread.namespace,
|
|
111
|
-
context: thread.context,
|
|
112
|
-
});
|
|
113
|
-
|
|
114
105
|
try {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
this.emit("thread.stop", {
|
|
118
|
-
kind: "thread.stop",
|
|
119
|
-
threadId: thread.tid,
|
|
120
|
-
agentId: thread.agent.id,
|
|
121
|
-
namespace: thread.namespace,
|
|
122
|
-
context: thread.context,
|
|
123
|
-
state: thread.state,
|
|
124
|
-
outcome: "success",
|
|
125
|
-
result: result.response,
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
return result;
|
|
129
|
-
} catch (err) {
|
|
130
|
-
this.emit("thread.stop", {
|
|
131
|
-
kind: "thread.stop",
|
|
132
|
-
threadId: thread.tid,
|
|
133
|
-
agentId: thread.agent.id,
|
|
134
|
-
namespace: thread.namespace,
|
|
135
|
-
context: thread.context,
|
|
136
|
-
state: thread.state,
|
|
137
|
-
outcome: "error",
|
|
138
|
-
error: err instanceof Error ? err.message : String(err),
|
|
139
|
-
});
|
|
140
|
-
throw err;
|
|
106
|
+
return await thread.execute();
|
|
141
107
|
} finally {
|
|
142
108
|
this.athreads.delete(thread.tid);
|
|
143
109
|
}
|
|
@@ -168,39 +134,8 @@ export class Kernl extends KernlHooks {
|
|
|
168
134
|
thread: Thread<TContext, TOutput>,
|
|
169
135
|
): AsyncIterable<ThreadStreamEvent> {
|
|
170
136
|
this.athreads.set(thread.tid, thread);
|
|
171
|
-
|
|
172
|
-
this.emit("thread.start", {
|
|
173
|
-
kind: "thread.start",
|
|
174
|
-
threadId: thread.tid,
|
|
175
|
-
agentId: thread.agent.id,
|
|
176
|
-
namespace: thread.namespace,
|
|
177
|
-
context: thread.context,
|
|
178
|
-
});
|
|
179
|
-
|
|
180
137
|
try {
|
|
181
138
|
yield* thread.stream();
|
|
182
|
-
|
|
183
|
-
this.emit("thread.stop", {
|
|
184
|
-
kind: "thread.stop",
|
|
185
|
-
threadId: thread.tid,
|
|
186
|
-
agentId: thread.agent.id,
|
|
187
|
-
namespace: thread.namespace,
|
|
188
|
-
context: thread.context,
|
|
189
|
-
state: thread.state,
|
|
190
|
-
outcome: "success",
|
|
191
|
-
});
|
|
192
|
-
} catch (err) {
|
|
193
|
-
this.emit("thread.stop", {
|
|
194
|
-
kind: "thread.stop",
|
|
195
|
-
threadId: thread.tid,
|
|
196
|
-
agentId: thread.agent.id,
|
|
197
|
-
namespace: thread.namespace,
|
|
198
|
-
context: thread.context,
|
|
199
|
-
state: thread.state,
|
|
200
|
-
outcome: "error",
|
|
201
|
-
error: err instanceof Error ? err.message : String(err),
|
|
202
|
-
});
|
|
203
|
-
throw err;
|
|
204
139
|
} finally {
|
|
205
140
|
this.athreads.delete(thread.tid);
|
|
206
141
|
}
|
|
@@ -54,7 +54,7 @@ describe("Lifecycle Hooks", () => {
|
|
|
54
54
|
expect(events[0].context).toBeDefined();
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
it("emits thread.stop with
|
|
57
|
+
it("emits thread.stop with result on successful run", async () => {
|
|
58
58
|
const events: ThreadStopEvent[] = [];
|
|
59
59
|
|
|
60
60
|
const model = createMockModel(async () => ({
|
|
@@ -83,13 +83,12 @@ describe("Lifecycle Hooks", () => {
|
|
|
83
83
|
kind: "thread.stop",
|
|
84
84
|
agentId: "test-agent",
|
|
85
85
|
namespace: "kernl",
|
|
86
|
-
outcome: "success",
|
|
87
86
|
state: "stopped",
|
|
88
87
|
result: "Done",
|
|
89
88
|
});
|
|
90
89
|
});
|
|
91
90
|
|
|
92
|
-
it("emits thread.stop with
|
|
91
|
+
it("emits thread.stop with error on failure", async () => {
|
|
93
92
|
const events: ThreadStopEvent[] = [];
|
|
94
93
|
|
|
95
94
|
const model = createMockModel(async () => {
|
|
@@ -114,7 +113,6 @@ describe("Lifecycle Hooks", () => {
|
|
|
114
113
|
expect(events[0]).toMatchObject({
|
|
115
114
|
kind: "thread.stop",
|
|
116
115
|
agentId: "test-agent",
|
|
117
|
-
outcome: "error",
|
|
118
116
|
error: "Model exploded",
|
|
119
117
|
});
|
|
120
118
|
});
|
|
@@ -151,6 +149,49 @@ describe("Lifecycle Hooks", () => {
|
|
|
151
149
|
expect(kernlEvents).toHaveLength(1);
|
|
152
150
|
expect(agentEvents[0].threadId).toBe(kernlEvents[0].threadId);
|
|
153
151
|
});
|
|
152
|
+
|
|
153
|
+
it("agent.on receives thread events (emitted by Thread via agent.emit)", async () => {
|
|
154
|
+
const agentStartEvents: ThreadStartEvent[] = [];
|
|
155
|
+
const agentStopEvents: ThreadStopEvent[] = [];
|
|
156
|
+
const kernlStartEvents: ThreadStartEvent[] = [];
|
|
157
|
+
const kernlStopEvents: ThreadStopEvent[] = [];
|
|
158
|
+
|
|
159
|
+
const model = createMockModel(async () => ({
|
|
160
|
+
content: [message({ role: "assistant", text: "Done" })],
|
|
161
|
+
finishReason: "stop",
|
|
162
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
163
|
+
warnings: [],
|
|
164
|
+
}));
|
|
165
|
+
|
|
166
|
+
const agent = new Agent({
|
|
167
|
+
id: "test-agent",
|
|
168
|
+
name: "Test",
|
|
169
|
+
instructions: "Test",
|
|
170
|
+
model,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const kernl = new Kernl();
|
|
174
|
+
kernl.register(agent);
|
|
175
|
+
|
|
176
|
+
// Thread events should be receivable via both agent.on and kernl.on
|
|
177
|
+
agent.on("thread.start", (e) => agentStartEvents.push(e));
|
|
178
|
+
agent.on("thread.stop", (e) => agentStopEvents.push(e));
|
|
179
|
+
kernl.on("thread.start", (e) => kernlStartEvents.push(e));
|
|
180
|
+
kernl.on("thread.stop", (e) => kernlStopEvents.push(e));
|
|
181
|
+
|
|
182
|
+
await agent.run("Hello");
|
|
183
|
+
|
|
184
|
+
// Both agent and kernl should receive thread events
|
|
185
|
+
expect(agentStartEvents).toHaveLength(1);
|
|
186
|
+
expect(agentStopEvents).toHaveLength(1);
|
|
187
|
+
expect(kernlStartEvents).toHaveLength(1);
|
|
188
|
+
expect(kernlStopEvents).toHaveLength(1);
|
|
189
|
+
|
|
190
|
+
// Same event data
|
|
191
|
+
expect(agentStartEvents[0].threadId).toBe(kernlStartEvents[0].threadId);
|
|
192
|
+
expect(agentStopEvents[0].threadId).toBe(kernlStopEvents[0].threadId);
|
|
193
|
+
expect(agentStopEvents[0].result).toBeDefined();
|
|
194
|
+
});
|
|
154
195
|
});
|
|
155
196
|
|
|
156
197
|
describe("Model events", () => {
|
package/src/lifecycle.ts
CHANGED
|
@@ -74,17 +74,12 @@ export interface ThreadStopEvent<TContext = unknown, TOutput = unknown> {
|
|
|
74
74
|
state: ThreadState;
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
|
-
* The
|
|
78
|
-
*/
|
|
79
|
-
outcome: "success" | "error" | "cancelled";
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* The result if outcome is "success".
|
|
77
|
+
* The result of execution (present on success).
|
|
83
78
|
*/
|
|
84
79
|
result?: TOutput;
|
|
85
80
|
|
|
86
81
|
/**
|
|
87
|
-
* Error message
|
|
82
|
+
* Error message (present on error).
|
|
88
83
|
*/
|
|
89
84
|
error?: string;
|
|
90
85
|
}
|
package/src/thread/thread.ts
CHANGED
|
@@ -107,6 +107,7 @@ export class Thread<
|
|
|
107
107
|
private cpbuf: ThreadEvent[]; /* checkpoint buffer - events pending persistence */
|
|
108
108
|
private persisted: boolean; /* indicates thread was hydrated from storage */
|
|
109
109
|
private history: ThreadEvent[] /* history representing the event log for the thread */;
|
|
110
|
+
private tickres?: ResolvedAgentResponse<TOutput>; /* final result from terminal tick */
|
|
110
111
|
|
|
111
112
|
private abort?: AbortController;
|
|
112
113
|
private storage?: ThreadStore;
|
|
@@ -152,24 +153,17 @@ export class Thread<
|
|
|
152
153
|
for await (const _event of this.stream()) {
|
|
153
154
|
// just consume the stream (already in history in _execute())
|
|
154
155
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const items = this.history
|
|
158
|
-
.filter((e) => e.kind !== "system")
|
|
159
|
-
.map((e) => {
|
|
160
|
-
const { tid, seq, timestamp, metadata, ...item } = e;
|
|
161
|
-
return item as LanguageModelItem;
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
const text = getFinalResponse(items);
|
|
165
|
-
assert(text, "_execute continues until text !== null"); // (TODO): consider preventing infinite loops here
|
|
166
|
-
const parsed = parseFinalResponse(text, this.agent.output);
|
|
167
|
-
|
|
168
|
-
return { response: parsed, state: this.state };
|
|
156
|
+
assert(this.tickres, "_execute continues until tickres is set");
|
|
157
|
+
return { response: this.tickres, state: this.state };
|
|
169
158
|
}
|
|
170
159
|
|
|
171
160
|
/**
|
|
172
161
|
* Streaming execution - returns async iterator of events
|
|
162
|
+
*
|
|
163
|
+
* All runs (new or resumed) emit:
|
|
164
|
+
* - Exactly one thread.start
|
|
165
|
+
* - Zero or more model.call.* and tool.call.*
|
|
166
|
+
* - Exactly one thread.stop (with result on success, error on failure)
|
|
173
167
|
*/
|
|
174
168
|
async *stream(): AsyncIterable<ThreadStreamEvent> {
|
|
175
169
|
if (this.state === RUNNING && this.abort) {
|
|
@@ -178,14 +172,42 @@ export class Thread<
|
|
|
178
172
|
|
|
179
173
|
this.state = RUNNING;
|
|
180
174
|
this.abort = new AbortController();
|
|
175
|
+
this.tickres = undefined; // reset for this run
|
|
181
176
|
|
|
182
177
|
await this.checkpoint(); /* c1: persist RUNNING state + initial input */
|
|
183
178
|
|
|
179
|
+
this.agent.emit("thread.start", {
|
|
180
|
+
kind: "thread.start",
|
|
181
|
+
threadId: this.tid,
|
|
182
|
+
agentId: this.agent.id,
|
|
183
|
+
namespace: this.namespace,
|
|
184
|
+
context: this.context,
|
|
185
|
+
});
|
|
186
|
+
|
|
184
187
|
yield { kind: "stream-start" }; // always yield start immediately
|
|
185
188
|
|
|
186
189
|
try {
|
|
187
190
|
yield* this._execute();
|
|
191
|
+
|
|
192
|
+
this.agent.emit("thread.stop", {
|
|
193
|
+
kind: "thread.stop",
|
|
194
|
+
threadId: this.tid,
|
|
195
|
+
agentId: this.agent.id,
|
|
196
|
+
namespace: this.namespace,
|
|
197
|
+
context: this.context,
|
|
198
|
+
state: STOPPED,
|
|
199
|
+
result: this.tickres,
|
|
200
|
+
});
|
|
188
201
|
} catch (err) {
|
|
202
|
+
this.agent.emit("thread.stop", {
|
|
203
|
+
kind: "thread.stop",
|
|
204
|
+
threadId: this.tid,
|
|
205
|
+
agentId: this.agent.id,
|
|
206
|
+
namespace: this.namespace,
|
|
207
|
+
context: this.context,
|
|
208
|
+
state: STOPPED,
|
|
209
|
+
error: err instanceof Error ? err.message : String(err),
|
|
210
|
+
});
|
|
189
211
|
throw err;
|
|
190
212
|
} finally {
|
|
191
213
|
this.state = STOPPED;
|
|
@@ -233,6 +255,7 @@ export class Thread<
|
|
|
233
255
|
const text = getFinalResponse(events);
|
|
234
256
|
if (!text) continue; // run again, policy-dependent? (how to ensure no infinite loop here?)
|
|
235
257
|
|
|
258
|
+
this.tickres = parseFinalResponse(text, this.agent.output);
|
|
236
259
|
await this.checkpoint(); /* c2: terminal tick - no tool calls */
|
|
237
260
|
|
|
238
261
|
// await this.agent.runOutputGuardails(context, state);
|
|
@@ -409,6 +432,8 @@ export class Thread<
|
|
|
409
432
|
|
|
410
433
|
/**
|
|
411
434
|
* Cancel the running thread
|
|
435
|
+
*
|
|
436
|
+
* TODO: Emit thread.stop when cancelled (neither result nor error set)
|
|
412
437
|
*/
|
|
413
438
|
cancel() {
|
|
414
439
|
this.abort?.abort();
|
package/src/thread/utils.ts
CHANGED
|
@@ -113,11 +113,10 @@ export function isPublicEvent(event: ThreadEvent): event is PublicThreadEvent {
|
|
|
113
113
|
* Returns null if no assistant message with text content is found.
|
|
114
114
|
*/
|
|
115
115
|
export function getFinalResponse(items: LanguageModelItem[]): string | null {
|
|
116
|
-
//
|
|
116
|
+
// scan backwards for the last assistant message
|
|
117
117
|
for (let i = items.length - 1; i >= 0; i--) {
|
|
118
118
|
const item = items[i];
|
|
119
119
|
if (item.kind === "message" && item.role === "assistant") {
|
|
120
|
-
// Extract text from content parts
|
|
121
120
|
for (const part of item.content) {
|
|
122
121
|
if (part.kind === "text") {
|
|
123
122
|
return part.text;
|
|
@@ -161,6 +160,6 @@ export function parseFinalResponse<TOutput extends AgentOutputType>(
|
|
|
161
160
|
}
|
|
162
161
|
}
|
|
163
162
|
|
|
164
|
-
//
|
|
163
|
+
// fallback - should not reach here
|
|
165
164
|
return text as ResolvedAgentResponse<TOutput>;
|
|
166
165
|
}
|