kernl 0.2.1 → 0.6.0
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/.turbo/turbo-check-types.log +4 -0
- package/CHANGELOG.md +138 -0
- package/LICENSE +1 -1
- package/dist/agent/__tests__/concurrency.test.d.ts +2 -0
- package/dist/agent/__tests__/concurrency.test.d.ts.map +1 -0
- package/dist/agent/__tests__/concurrency.test.js +152 -0
- package/dist/agent/__tests__/run.test.d.ts +2 -0
- package/dist/agent/__tests__/run.test.d.ts.map +1 -0
- package/dist/agent/__tests__/run.test.js +357 -0
- package/dist/agent/index.d.ts +1 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent.d.ts +32 -9
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +101 -14
- package/dist/api/__tests__/cursor-page.test.d.ts +2 -0
- package/dist/api/__tests__/cursor-page.test.d.ts.map +1 -0
- package/dist/api/__tests__/cursor-page.test.js +414 -0
- package/dist/api/__tests__/offset-page.test.d.ts +2 -0
- package/dist/api/__tests__/offset-page.test.d.ts.map +1 -0
- package/dist/api/__tests__/offset-page.test.js +510 -0
- package/dist/api/__tests__/threads.test.d.ts +2 -0
- package/dist/api/__tests__/threads.test.d.ts.map +1 -0
- package/dist/api/__tests__/threads.test.js +338 -0
- package/dist/api/models/index.d.ts +2 -0
- package/dist/api/models/index.d.ts.map +1 -0
- package/dist/api/models/thread.d.ts +120 -0
- package/dist/api/models/thread.d.ts.map +1 -0
- package/dist/api/pagination/base.d.ts +48 -0
- package/dist/api/pagination/base.d.ts.map +1 -0
- package/dist/api/pagination/base.js +45 -0
- package/dist/api/pagination/cursor.d.ts +44 -0
- package/dist/api/pagination/cursor.d.ts.map +1 -0
- package/dist/api/pagination/cursor.js +52 -0
- package/dist/api/pagination/offset.d.ts +42 -0
- package/dist/api/pagination/offset.d.ts.map +1 -0
- package/dist/api/pagination/offset.js +55 -0
- package/dist/api/resources/threads/events.d.ts +21 -0
- package/dist/api/resources/threads/events.d.ts.map +1 -0
- package/dist/api/resources/threads/events.js +24 -0
- package/dist/api/resources/threads/index.d.ts +4 -0
- package/dist/api/resources/threads/index.d.ts.map +1 -0
- package/dist/api/resources/threads/index.js +2 -0
- package/dist/api/resources/threads/threads.d.ts +57 -0
- package/dist/api/resources/threads/threads.d.ts.map +1 -0
- package/dist/api/resources/threads/threads.js +199 -0
- package/dist/api/resources/threads/types.d.ts +123 -0
- package/dist/api/resources/threads/types.d.ts.map +1 -0
- package/dist/api/resources/threads/utils.d.ts +18 -0
- package/dist/api/resources/threads/utils.d.ts.map +1 -0
- package/dist/api/resources/threads/utils.js +78 -0
- package/dist/context.d.ts +5 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +6 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/internal.d.ts +4 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +2 -0
- package/dist/kernl/index.d.ts +3 -0
- package/dist/kernl/index.d.ts.map +1 -0
- package/dist/kernl/index.js +2 -0
- package/dist/kernl/kernl.d.ts +64 -0
- package/dist/kernl/kernl.d.ts.map +1 -0
- package/dist/kernl/kernl.js +116 -0
- package/dist/kernl/threads.d.ts +110 -0
- package/dist/kernl/threads.d.ts.map +1 -0
- package/dist/kernl/threads.js +126 -0
- package/dist/kernl.d.ts +22 -6
- package/dist/kernl.d.ts.map +1 -1
- package/dist/kernl.js +73 -10
- package/dist/lib/env.d.ts +3 -3
- package/dist/lib/env.js +1 -1
- package/dist/mcp/__tests__/integration.test.js +8 -8
- package/dist/mcp/__tests__/utils.test.js +6 -6
- package/dist/mcp/http.d.ts +1 -1
- package/dist/mcp/http.d.ts.map +1 -1
- package/dist/mcp/http.js +9 -9
- package/dist/mcp/sse.d.ts +1 -1
- package/dist/mcp/sse.d.ts.map +1 -1
- package/dist/mcp/sse.js +7 -7
- package/dist/mcp/utils.d.ts +1 -1
- package/dist/mcp/utils.d.ts.map +1 -1
- package/dist/mcp/utils.js +4 -5
- package/dist/storage/__tests__/in-memory.test.d.ts +2 -0
- package/dist/storage/__tests__/in-memory.test.d.ts.map +1 -0
- package/dist/storage/__tests__/in-memory.test.js +455 -0
- package/dist/storage/base.d.ts +64 -0
- package/dist/storage/base.d.ts.map +1 -0
- package/dist/storage/base.js +4 -0
- package/dist/storage/in-memory.d.ts +62 -0
- package/dist/storage/in-memory.d.ts.map +1 -0
- package/dist/storage/in-memory.js +283 -0
- package/dist/storage/index.d.ts +10 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +7 -0
- package/dist/storage/thread.d.ts +123 -0
- package/dist/storage/thread.d.ts.map +1 -0
- package/dist/storage/thread.js +4 -0
- package/dist/task.d.ts +5 -3
- package/dist/task.d.ts.map +1 -1
- package/dist/task.js +10 -8
- package/dist/thread/__tests__/fixtures/mock-model.d.ts +1 -2
- package/dist/thread/__tests__/fixtures/mock-model.d.ts.map +1 -1
- package/dist/thread/__tests__/integration.test.js +6 -6
- package/dist/thread/__tests__/namespace.test.d.ts +2 -0
- package/dist/thread/__tests__/namespace.test.d.ts.map +1 -0
- package/dist/thread/__tests__/namespace.test.js +131 -0
- package/dist/thread/__tests__/thread-persistence.test.d.ts +2 -0
- package/dist/thread/__tests__/thread-persistence.test.d.ts.map +1 -0
- package/dist/thread/__tests__/thread-persistence.test.js +351 -0
- package/dist/thread/__tests__/thread.test.js +49 -51
- package/dist/thread/thread.d.ts +70 -18
- package/dist/thread/thread.d.ts.map +1 -1
- package/dist/thread/thread.js +211 -73
- package/dist/thread/utils.d.ts +36 -8
- package/dist/thread/utils.d.ts.map +1 -1
- package/dist/thread/utils.js +52 -8
- package/dist/tool/__tests__/fixtures.js +1 -1
- package/dist/tool/__tests__/toolkit.test.js +15 -12
- package/dist/tool/tool.js +3 -3
- package/dist/types/kernl.d.ts +42 -0
- package/dist/types/kernl.d.ts.map +1 -0
- package/dist/types/thread.d.ts +108 -22
- package/dist/types/thread.d.ts.map +1 -1
- package/dist/types/thread.js +12 -0
- package/package.json +11 -7
- package/src/agent/__tests__/concurrency.test.ts +194 -0
- package/src/agent/__tests__/run.test.ts +441 -0
- package/src/agent/index.ts +0 -0
- package/src/agent.ts +139 -24
- package/src/api/__tests__/cursor-page.test.ts +512 -0
- package/src/api/__tests__/offset-page.test.ts +624 -0
- package/src/api/__tests__/threads.test.ts +415 -0
- package/src/api/models/index.ts +6 -0
- package/src/api/models/thread.ts +138 -0
- package/src/api/pagination/base.ts +79 -0
- package/src/api/pagination/cursor.ts +86 -0
- package/src/api/pagination/offset.ts +89 -0
- package/src/api/resources/threads/events.ts +26 -0
- package/src/api/resources/threads/index.ts +9 -0
- package/src/api/resources/threads/threads.ts +256 -0
- package/src/api/resources/threads/types.ts +143 -0
- package/src/api/resources/threads/utils.ts +104 -0
- package/src/context.ts +10 -1
- package/src/index.ts +49 -1
- package/src/internal.ts +15 -0
- package/src/kernl.ts +86 -17
- package/src/mcp/__tests__/integration.test.ts +8 -9
- package/src/mcp/__tests__/utils.test.ts +6 -6
- package/src/mcp/http.ts +9 -9
- package/src/mcp/sse.ts +7 -7
- package/src/mcp/utils.ts +6 -5
- package/src/storage/__tests__/in-memory.test.ts +534 -0
- package/src/storage/base.ts +77 -0
- package/src/storage/in-memory.ts +372 -0
- package/src/storage/index.ts +21 -0
- package/src/storage/thread.ts +141 -0
- package/src/task.ts +12 -10
- package/src/thread/__tests__/fixtures/mock-model.ts +2 -4
- package/src/thread/__tests__/integration.test.ts +13 -12
- package/src/thread/__tests__/namespace.test.ts +158 -0
- package/src/thread/__tests__/thread-persistence.test.ts +367 -0
- package/src/thread/__tests__/thread.test.ts +52 -54
- package/src/thread/thread.ts +247 -96
- package/src/thread/utils.ts +76 -13
- package/src/tool/__tests__/fixtures.ts +1 -1
- package/src/tool/__tests__/toolkit.test.ts +15 -12
- package/src/tool/tool.ts +3 -3
- package/src/types/kernl.ts +51 -0
- package/src/types/thread.ts +139 -25
- package/vitest.config.ts +1 -0
- package/dist/env.d.ts +0 -45
- package/dist/env.d.ts.map +0 -1
- package/dist/env.js +0 -31
- package/dist/error.d.ts +0 -1
- package/dist/error.d.ts.map +0 -1
- package/dist/kernel.d.ts +0 -7
- package/dist/kernel.d.ts.map +0 -1
- package/dist/kernel.js +0 -7
- package/dist/lib/serde/__tests__/codec.test.d.ts +0 -2
- package/dist/lib/serde/__tests__/codec.test.d.ts.map +0 -1
- package/dist/lib/serde/__tests__/codec.test.js +0 -75
- package/dist/lib/serde/codec.d.ts +0 -12
- package/dist/lib/serde/codec.d.ts.map +0 -1
- package/dist/lib/serde/codec.js +0 -54
- package/dist/lib/serde/thread.d.ts +0 -1
- package/dist/lib/serde/thread.d.ts.map +0 -1
- package/dist/lib/serde/thread.js +0 -172
- package/dist/lib/serde/tool.d.ts +0 -36
- package/dist/lib/serde/tool.d.ts.map +0 -1
- package/dist/lib/utils.d.ts +0 -19
- package/dist/lib/utils.d.ts.map +0 -1
- package/dist/lib/utils.js +0 -41
- package/dist/logger.d.ts +0 -36
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -43
- package/dist/mcp/__tests__/fixtures/echo-server.d.ts +0 -3
- package/dist/mcp/__tests__/fixtures/echo-server.d.ts.map +0 -1
- package/dist/mcp/__tests__/fixtures/echo-server.js +0 -92
- package/dist/mcp/__tests__/fixtures/math-server.d.ts +0 -3
- package/dist/mcp/__tests__/fixtures/math-server.d.ts.map +0 -1
- package/dist/mcp/__tests__/fixtures/math-server.js +0 -98
- package/dist/mcp/__tests__/fixtures/test-server.d.ts +0 -3
- package/dist/mcp/__tests__/fixtures/test-server.d.ts.map +0 -1
- package/dist/mcp/__tests__/fixtures/test-server.js +0 -163
- package/dist/mcp/__tests__/test-utils.d.ts +0 -17
- package/dist/mcp/__tests__/test-utils.d.ts.map +0 -1
- package/dist/mcp/__tests__/test-utils.js +0 -42
- package/dist/mcp/node.d.ts +0 -60
- package/dist/mcp/node.d.ts.map +0 -1
- package/dist/mcp/node.js +0 -297
- package/dist/model.d.ts +0 -175
- package/dist/model.d.ts.map +0 -1
- package/dist/providers/ai.d.ts +0 -1
- package/dist/providers/ai.d.ts.map +0 -1
- package/dist/providers/ai.js +0 -1
- package/dist/providers/default.d.ts +0 -16
- package/dist/providers/default.d.ts.map +0 -1
- package/dist/providers/default.js +0 -17
- package/dist/providers/registry.d.ts +0 -1
- package/dist/providers/registry.d.ts.map +0 -1
- package/dist/providers/registry.js +0 -1
- package/dist/sched/scheduler.d.ts +0 -20
- package/dist/sched/scheduler.d.ts.map +0 -1
- package/dist/sched/task.d.ts +0 -92
- package/dist/sched/task.d.ts.map +0 -1
- package/dist/sched/task.js +0 -102
- package/dist/serde/__tests__/codec.test.d.ts +0 -2
- package/dist/serde/__tests__/codec.test.d.ts.map +0 -1
- package/dist/serde/__tests__/codec.test.js +0 -75
- package/dist/serde/codec.d.ts +0 -12
- package/dist/serde/codec.d.ts.map +0 -1
- package/dist/serde/codec.js +0 -54
- package/dist/serde/json.d.ts +0 -8
- package/dist/serde/json.d.ts.map +0 -1
- package/dist/serde/json.js +0 -13
- package/dist/serde/thread.d.ts +0 -687
- package/dist/serde/thread.d.ts.map +0 -1
- package/dist/serde/thread.js +0 -158
- package/dist/serde/tool.d.ts +0 -36
- package/dist/serde/tool.d.ts.map +0 -1
- package/dist/session.d.ts +0 -1
- package/dist/session.d.ts.map +0 -1
- package/dist/session.js +0 -1
- package/dist/thread/__tests__/stream.test.d.ts +0 -2
- package/dist/thread/__tests__/stream.test.d.ts.map +0 -1
- package/dist/thread/__tests__/stream.test.js +0 -244
- package/dist/tool/mcp.d.ts +0 -75
- package/dist/tool/mcp.d.ts.map +0 -1
- package/dist/tool/mcp.js +0 -111
- package/dist/tools.d.ts +0 -362
- package/dist/tools.d.ts.map +0 -1
- package/dist/tools.js +0 -220
- package/dist/types/proto.d.ts +0 -1551
- package/dist/types/proto.d.ts.map +0 -1
- package/dist/types/proto.js +0 -531
- package/dist/usage.d.ts +0 -43
- package/dist/usage.d.ts.map +0 -1
- package/dist/usage.js +0 -61
- package/src/lib/serde/thread.ts +0 -188
- /package/dist/{error.js → agent/index.js} +0 -0
- /package/dist/{lib/serde/tool.js → api/models/index.js} +0 -0
- /package/dist/{model.js → api/models/thread.js} +0 -0
- /package/dist/{sched/scheduler.js → api/resources/threads/types.js} +0 -0
- /package/dist/{serde/tool.js → types/kernl.js} +0 -0
|
@@ -47,23 +47,21 @@ describe("Thread", () => {
|
|
|
47
47
|
model,
|
|
48
48
|
});
|
|
49
49
|
const kernl = new Kernl();
|
|
50
|
-
const thread = new Thread(
|
|
50
|
+
const thread = new Thread({ agent, input: userMessage("Hello world") });
|
|
51
51
|
const result = await thread.execute();
|
|
52
52
|
// Access private history via type assertion for testing
|
|
53
53
|
const history = thread.history;
|
|
54
54
|
expect(history).toEqual([
|
|
55
|
-
{
|
|
55
|
+
expect.objectContaining({
|
|
56
56
|
kind: "message",
|
|
57
|
-
id: expect.any(String),
|
|
58
57
|
role: "user",
|
|
59
58
|
content: [{ kind: "text", text: "Hello world" }],
|
|
60
|
-
},
|
|
61
|
-
{
|
|
59
|
+
}),
|
|
60
|
+
expect.objectContaining({
|
|
62
61
|
kind: "message",
|
|
63
|
-
id: "msg_1",
|
|
64
62
|
role: "assistant",
|
|
65
63
|
content: [{ kind: "text", text: "Hello world" }],
|
|
66
|
-
},
|
|
64
|
+
}),
|
|
67
65
|
]);
|
|
68
66
|
expect(thread._tick).toBe(1);
|
|
69
67
|
});
|
|
@@ -94,16 +92,15 @@ describe("Thread", () => {
|
|
|
94
92
|
model,
|
|
95
93
|
});
|
|
96
94
|
const kernl = new Kernl();
|
|
97
|
-
const thread = new Thread(
|
|
95
|
+
const thread = new Thread({ agent, input: userMessage("Test input") });
|
|
98
96
|
await thread.execute();
|
|
99
97
|
const history = thread.history;
|
|
100
98
|
const firstMessage = history[0];
|
|
101
|
-
expect(firstMessage).toEqual({
|
|
99
|
+
expect(firstMessage).toEqual(expect.objectContaining({
|
|
102
100
|
kind: "message",
|
|
103
|
-
id: expect.any(String),
|
|
104
101
|
role: "user",
|
|
105
102
|
content: [{ kind: "text", text: "Test input" }],
|
|
106
|
-
});
|
|
103
|
+
}));
|
|
107
104
|
});
|
|
108
105
|
it("should use array input as-is", async () => {
|
|
109
106
|
const model = createMockModel(async (req) => {
|
|
@@ -140,11 +137,15 @@ describe("Thread", () => {
|
|
|
140
137
|
},
|
|
141
138
|
];
|
|
142
139
|
const kernl = new Kernl();
|
|
143
|
-
const thread = new Thread(
|
|
140
|
+
const thread = new Thread({ agent, input: events });
|
|
144
141
|
await thread.execute();
|
|
145
142
|
const history = thread.history;
|
|
146
143
|
const firstMessage = history[0];
|
|
147
|
-
expect(firstMessage).toEqual(
|
|
144
|
+
expect(firstMessage).toEqual(expect.objectContaining({
|
|
145
|
+
kind: events[0].kind,
|
|
146
|
+
role: events[0].role,
|
|
147
|
+
content: events[0].content,
|
|
148
|
+
}));
|
|
148
149
|
});
|
|
149
150
|
});
|
|
150
151
|
describe("Multi-Turn Execution", () => {
|
|
@@ -214,48 +215,45 @@ describe("Thread", () => {
|
|
|
214
215
|
],
|
|
215
216
|
});
|
|
216
217
|
const kernl = new Kernl();
|
|
217
|
-
const thread = new Thread(
|
|
218
|
+
const thread = new Thread({ agent, input: userMessage("Use the echo tool") });
|
|
218
219
|
const result = await thread.execute();
|
|
219
220
|
const history = thread.history;
|
|
220
221
|
expect(history).toEqual([
|
|
221
222
|
// Initial user message
|
|
222
|
-
{
|
|
223
|
+
expect.objectContaining({
|
|
223
224
|
kind: "message",
|
|
224
|
-
id: expect.any(String),
|
|
225
225
|
role: "user",
|
|
226
226
|
content: [{ kind: "text", text: "Use the echo tool" }],
|
|
227
|
-
},
|
|
227
|
+
}),
|
|
228
228
|
// Assistant message (tick 1)
|
|
229
|
-
{
|
|
229
|
+
expect.objectContaining({
|
|
230
230
|
kind: "message",
|
|
231
|
-
id: "msg_1",
|
|
232
231
|
role: "assistant",
|
|
233
232
|
content: [],
|
|
234
|
-
},
|
|
233
|
+
}),
|
|
235
234
|
// Tool call (tick 1)
|
|
236
|
-
{
|
|
235
|
+
expect.objectContaining({
|
|
237
236
|
kind: "tool-call",
|
|
238
237
|
toolId: "echo",
|
|
239
238
|
callId: "call_1",
|
|
240
239
|
state: IN_PROGRESS,
|
|
241
240
|
arguments: JSON.stringify({ text: "test" }),
|
|
242
|
-
},
|
|
241
|
+
}),
|
|
243
242
|
// Tool result (executed after tick 1)
|
|
244
|
-
{
|
|
243
|
+
expect.objectContaining({
|
|
245
244
|
kind: "tool-result",
|
|
246
245
|
callId: "call_1",
|
|
247
246
|
toolId: "echo",
|
|
248
247
|
state: COMPLETED,
|
|
249
248
|
result: "Echo: test",
|
|
250
249
|
error: null,
|
|
251
|
-
},
|
|
250
|
+
}),
|
|
252
251
|
// Final assistant message (tick 2)
|
|
253
|
-
{
|
|
252
|
+
expect.objectContaining({
|
|
254
253
|
kind: "message",
|
|
255
|
-
id: "msg_2",
|
|
256
254
|
role: "assistant",
|
|
257
255
|
content: [{ kind: "text", text: "Done!" }],
|
|
258
|
-
},
|
|
256
|
+
}),
|
|
259
257
|
]);
|
|
260
258
|
expect(thread._tick).toBe(2);
|
|
261
259
|
});
|
|
@@ -349,7 +347,7 @@ describe("Thread", () => {
|
|
|
349
347
|
],
|
|
350
348
|
});
|
|
351
349
|
const kernl = new Kernl();
|
|
352
|
-
const thread = new Thread(
|
|
350
|
+
const thread = new Thread({ agent, input: userMessage("Start") });
|
|
353
351
|
const result = await thread.execute();
|
|
354
352
|
const history = thread.history;
|
|
355
353
|
// Should have: 1 user msg + 3 assistant msgs + 2 tool calls + 2 tool results = 8 events
|
|
@@ -416,19 +414,19 @@ describe("Thread", () => {
|
|
|
416
414
|
toolkits: [], // No tools available
|
|
417
415
|
});
|
|
418
416
|
const kernl = new Kernl();
|
|
419
|
-
const thread = new Thread(
|
|
417
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
420
418
|
await thread.execute();
|
|
421
419
|
const history = thread.history;
|
|
422
420
|
// Check that the tool result is an error
|
|
423
421
|
const toolResult = history.find((e) => e.kind === "tool-result");
|
|
424
|
-
expect(toolResult).toEqual({
|
|
422
|
+
expect(toolResult).toEqual(expect.objectContaining({
|
|
425
423
|
kind: "tool-result",
|
|
426
424
|
callId: "call_1",
|
|
427
425
|
toolId: "nonexistent",
|
|
428
426
|
state: FAILED,
|
|
429
427
|
result: undefined,
|
|
430
428
|
error: "Tool nonexistent not found",
|
|
431
|
-
});
|
|
429
|
+
}));
|
|
432
430
|
});
|
|
433
431
|
it("should handle tool execution error", async () => {
|
|
434
432
|
let callCount = 0;
|
|
@@ -498,7 +496,7 @@ describe("Thread", () => {
|
|
|
498
496
|
],
|
|
499
497
|
});
|
|
500
498
|
const kernl = new Kernl();
|
|
501
|
-
const thread = new Thread(
|
|
499
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
502
500
|
await thread.execute();
|
|
503
501
|
const history = thread.history;
|
|
504
502
|
const toolResult = history.find((e) => e.kind === "tool-result");
|
|
@@ -575,19 +573,19 @@ describe("Thread", () => {
|
|
|
575
573
|
toolkits: [new FunctionToolkit({ id: "test-tools", tools: [addTool] })],
|
|
576
574
|
});
|
|
577
575
|
const kernl = new Kernl();
|
|
578
|
-
const thread = new Thread(
|
|
576
|
+
const thread = new Thread({ agent, input: userMessage("Add 5 and 3") });
|
|
579
577
|
await thread.execute();
|
|
580
578
|
// @ts-expect-error
|
|
581
579
|
const history = thread.history;
|
|
582
580
|
const toolResult = history.find((e) => e.kind === "tool-result");
|
|
583
|
-
expect(toolResult).toEqual({
|
|
581
|
+
expect(toolResult).toEqual(expect.objectContaining({
|
|
584
582
|
kind: "tool-result",
|
|
585
583
|
callId: "call_1",
|
|
586
584
|
toolId: "add",
|
|
587
585
|
state: COMPLETED,
|
|
588
586
|
result: 8,
|
|
589
587
|
error: null,
|
|
590
|
-
});
|
|
588
|
+
}));
|
|
591
589
|
});
|
|
592
590
|
});
|
|
593
591
|
describe("Parallel Tool Execution", () => {
|
|
@@ -670,29 +668,29 @@ describe("Thread", () => {
|
|
|
670
668
|
],
|
|
671
669
|
});
|
|
672
670
|
const kernl = new Kernl();
|
|
673
|
-
const thread = new Thread(
|
|
671
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
674
672
|
await thread.execute();
|
|
675
673
|
const history = thread.history;
|
|
676
674
|
// Should have both tool results in history
|
|
677
675
|
const toolResults = history.filter((e) => e.kind === "tool-result");
|
|
678
676
|
expect(toolResults).toHaveLength(2);
|
|
679
677
|
expect(toolResults).toEqual(expect.arrayContaining([
|
|
680
|
-
{
|
|
678
|
+
expect.objectContaining({
|
|
681
679
|
kind: "tool-result",
|
|
682
680
|
callId: "call_1",
|
|
683
681
|
toolId: "tool1",
|
|
684
682
|
state: COMPLETED,
|
|
685
683
|
result: "Tool1: a",
|
|
686
684
|
error: null,
|
|
687
|
-
},
|
|
688
|
-
{
|
|
685
|
+
}),
|
|
686
|
+
expect.objectContaining({
|
|
689
687
|
kind: "tool-result",
|
|
690
688
|
callId: "call_2",
|
|
691
689
|
toolId: "tool2",
|
|
692
690
|
state: COMPLETED,
|
|
693
691
|
result: "Tool2: b",
|
|
694
692
|
error: null,
|
|
695
|
-
},
|
|
693
|
+
}),
|
|
696
694
|
]));
|
|
697
695
|
});
|
|
698
696
|
});
|
|
@@ -761,7 +759,7 @@ describe("Thread", () => {
|
|
|
761
759
|
],
|
|
762
760
|
});
|
|
763
761
|
const kernl = new Kernl();
|
|
764
|
-
const thread = new Thread(
|
|
762
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
765
763
|
const result = await thread.execute();
|
|
766
764
|
expect(thread._tick).toBe(3);
|
|
767
765
|
});
|
|
@@ -829,7 +827,7 @@ describe("Thread", () => {
|
|
|
829
827
|
],
|
|
830
828
|
});
|
|
831
829
|
const kernl = new Kernl();
|
|
832
|
-
const thread = new Thread(
|
|
830
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
833
831
|
const result = await thread.execute();
|
|
834
832
|
// Verify the thread executed both turns
|
|
835
833
|
expect(thread._tick).toBe(2);
|
|
@@ -864,7 +862,7 @@ describe("Thread", () => {
|
|
|
864
862
|
model,
|
|
865
863
|
});
|
|
866
864
|
const kernl = new Kernl();
|
|
867
|
-
const thread = new Thread(
|
|
865
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
868
866
|
const result = await thread.execute();
|
|
869
867
|
expect(thread._tick).toBe(1);
|
|
870
868
|
});
|
|
@@ -932,7 +930,7 @@ describe("Thread", () => {
|
|
|
932
930
|
],
|
|
933
931
|
});
|
|
934
932
|
const kernl = new Kernl();
|
|
935
|
-
const thread = new Thread(
|
|
933
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
936
934
|
const result = await thread.execute();
|
|
937
935
|
// Should have made 2 calls - first with tool, second without
|
|
938
936
|
expect(thread._tick).toBe(2);
|
|
@@ -967,7 +965,7 @@ describe("Thread", () => {
|
|
|
967
965
|
responseType: "text",
|
|
968
966
|
});
|
|
969
967
|
const kernl = new Kernl();
|
|
970
|
-
const thread = new Thread(
|
|
968
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
971
969
|
const result = await thread.execute();
|
|
972
970
|
expect(result.response).toBe("Hello, world!");
|
|
973
971
|
expect(thread._tick).toBe(1);
|
|
@@ -1010,7 +1008,7 @@ describe("Thread", () => {
|
|
|
1010
1008
|
responseType: responseSchema,
|
|
1011
1009
|
});
|
|
1012
1010
|
const kernl = new Kernl();
|
|
1013
|
-
const thread = new Thread(
|
|
1011
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1014
1012
|
const result = await thread.execute();
|
|
1015
1013
|
expect(result.response).toEqual({
|
|
1016
1014
|
name: "Alice",
|
|
@@ -1054,7 +1052,7 @@ describe("Thread", () => {
|
|
|
1054
1052
|
responseType: responseSchema,
|
|
1055
1053
|
});
|
|
1056
1054
|
const kernl = new Kernl();
|
|
1057
|
-
const thread = new Thread(
|
|
1055
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1058
1056
|
await expect(thread.execute()).rejects.toThrow(ModelBehaviorError);
|
|
1059
1057
|
});
|
|
1060
1058
|
it("should throw ModelBehaviorError when JSON doesn't match schema", async () => {
|
|
@@ -1094,7 +1092,7 @@ describe("Thread", () => {
|
|
|
1094
1092
|
responseType: responseSchema,
|
|
1095
1093
|
});
|
|
1096
1094
|
const kernl = new Kernl();
|
|
1097
|
-
const thread = new Thread(
|
|
1095
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1098
1096
|
await expect(thread.execute()).rejects.toThrow(ModelBehaviorError);
|
|
1099
1097
|
});
|
|
1100
1098
|
it("should throw ModelBehaviorError when required fields are missing", async () => {
|
|
@@ -1135,7 +1133,7 @@ describe("Thread", () => {
|
|
|
1135
1133
|
responseType: responseSchema,
|
|
1136
1134
|
});
|
|
1137
1135
|
const kernl = new Kernl();
|
|
1138
|
-
const thread = new Thread(
|
|
1136
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1139
1137
|
await expect(thread.execute()).rejects.toThrow(ModelBehaviorError);
|
|
1140
1138
|
});
|
|
1141
1139
|
it("should handle nested structured output", async () => {
|
|
@@ -1189,7 +1187,7 @@ describe("Thread", () => {
|
|
|
1189
1187
|
responseType: responseSchema,
|
|
1190
1188
|
});
|
|
1191
1189
|
const kernl = new Kernl();
|
|
1192
|
-
const thread = new Thread(
|
|
1190
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1193
1191
|
const result = await thread.execute();
|
|
1194
1192
|
expect(result.response).toEqual({
|
|
1195
1193
|
user: {
|
|
@@ -1250,7 +1248,7 @@ describe("Thread", () => {
|
|
|
1250
1248
|
responseType: "text",
|
|
1251
1249
|
});
|
|
1252
1250
|
const kernl = new Kernl();
|
|
1253
|
-
const thread = new Thread(
|
|
1251
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1254
1252
|
const result = await thread.execute();
|
|
1255
1253
|
// Should have made 2 calls
|
|
1256
1254
|
expect(callCount).toBe(2);
|
package/dist/thread/thread.d.ts
CHANGED
|
@@ -1,30 +1,71 @@
|
|
|
1
|
-
import { Kernl } from "../kernl";
|
|
2
1
|
import { Agent } from "../agent";
|
|
3
2
|
import { Context } from "../context";
|
|
4
3
|
import type { Task } from "../task";
|
|
4
|
+
import type { ResolvedAgentResponse } from "../guardrail";
|
|
5
5
|
import { LanguageModel } from "@kernl-sdk/protocol";
|
|
6
|
-
import type { ThreadEvent,
|
|
6
|
+
import type { ThreadEvent, ThreadState, ThreadOptions, ThreadEventInner, ThreadStreamEvent, ThreadExecuteResult } from "../types/thread";
|
|
7
7
|
import type { AgentResponseType } from "../types/agent";
|
|
8
|
-
import type { ResolvedAgentResponse } from "../guardrail";
|
|
9
8
|
/**
|
|
10
9
|
* A thread drives the execution loop for an agent.
|
|
10
|
+
*
|
|
11
|
+
* Ground principles:
|
|
12
|
+
*
|
|
13
|
+
* 1) Event log is source of truth.
|
|
14
|
+
* - Persistent storage (e.g. Postgres) is treated as an append-only per-thread log of `ThreadEvent`s:
|
|
15
|
+
* monotonic `seq`, no gaps, no updates/deletes.
|
|
16
|
+
* - `Thread.state`, `tick`, etc. are projections of that log, not an alternative source of truth.
|
|
17
|
+
*
|
|
18
|
+
* 2) Single writer per thread.
|
|
19
|
+
* - At most one executor is allowed for a given `tid` at a time.
|
|
20
|
+
* - Callers are responsible for enforcing this (e.g. locking/versioning) so two processes cannot
|
|
21
|
+
* interleave or race on `seq` or state.
|
|
22
|
+
*
|
|
23
|
+
* 3) Persist before use / observation.
|
|
24
|
+
* - Before an event can:
|
|
25
|
+
* - influence a future tick (i.e. be part of `history` fed back into the model), or
|
|
26
|
+
* - be considered “delivered” to a client,
|
|
27
|
+
* it SHOULD be durably written to storage when storage is configured.
|
|
28
|
+
*
|
|
29
|
+
* 4) Transaction boundaries match semantic steps.
|
|
30
|
+
* - The intended strategy is to buffer within a tick, then atomically persist all new events + state
|
|
31
|
+
* at the end of `tick()`.
|
|
32
|
+
* - After a crash, you only ever see whole ticks or none, never half a tick, from the store’s
|
|
33
|
+
* point of view.
|
|
34
|
+
*
|
|
35
|
+
* 5) Recovery is replay.
|
|
36
|
+
* - On restart, callers rebuild a `Thread` from the stored event log (plus optional snapshots).
|
|
37
|
+
* - Any incomplete tick or pending tool call is handled by a clear, deterministic policy at a
|
|
38
|
+
* higher layer (e.g. re-run, mark failed, or require manual intervention).
|
|
39
|
+
*
|
|
40
|
+
* On storage failures:
|
|
41
|
+
*
|
|
42
|
+
* “If storage is configured, it is authoritative” → fail hard on persist errors rather than
|
|
43
|
+
* treating persistence as best-effort.
|
|
44
|
+
*
|
|
45
|
+
* If a storage implementation is present, `persist(...)` is expected to throw on failure, and
|
|
46
|
+
* that error should bubble out of `_execute()` / `stream()` and stop the thread.
|
|
11
47
|
*/
|
|
12
48
|
export declare class Thread<TContext = unknown, TResponse extends AgentResponseType = "text"> {
|
|
13
|
-
|
|
14
|
-
readonly
|
|
49
|
+
readonly tid: string;
|
|
50
|
+
readonly namespace: string;
|
|
15
51
|
readonly agent: Agent<TContext, TResponse>;
|
|
16
52
|
readonly context: Context<TContext>;
|
|
17
53
|
readonly model: LanguageModel;
|
|
18
54
|
readonly parent: Task<TContext> | null;
|
|
19
|
-
readonly
|
|
20
|
-
readonly
|
|
55
|
+
readonly createdAt: Date;
|
|
56
|
+
readonly updatedAt: Date;
|
|
57
|
+
readonly metadata: Record<string, unknown> | null;
|
|
21
58
|
_tick: number;
|
|
59
|
+
_seq: number;
|
|
22
60
|
state: ThreadState;
|
|
61
|
+
private cpbuf;
|
|
62
|
+
private persisted;
|
|
23
63
|
private history;
|
|
24
64
|
private abort?;
|
|
25
|
-
|
|
65
|
+
private storage?;
|
|
66
|
+
constructor(options: ThreadOptions<TContext, TResponse>);
|
|
26
67
|
/**
|
|
27
|
-
* Blocking execution
|
|
68
|
+
* Blocking execution - runs until terminal state or interruption
|
|
28
69
|
*/
|
|
29
70
|
execute(): Promise<ThreadExecuteResult<ResolvedAgentResponse<TResponse>>>;
|
|
30
71
|
/**
|
|
@@ -32,15 +73,7 @@ export declare class Thread<TContext = unknown, TResponse extends AgentResponseT
|
|
|
32
73
|
*/
|
|
33
74
|
stream(): AsyncIterable<ThreadStreamEvent>;
|
|
34
75
|
/**
|
|
35
|
-
*
|
|
36
|
-
*/
|
|
37
|
-
cancel(): void;
|
|
38
|
-
/**
|
|
39
|
-
* Append a new event to the thread history
|
|
40
|
-
*/
|
|
41
|
-
append(event: ThreadEvent): void;
|
|
42
|
-
/**
|
|
43
|
-
* Main execution loop - always yields events, callers can propagate or discard (as in execute())
|
|
76
|
+
* Main execution loop - always yields events, callers can propagate or discard.
|
|
44
77
|
*
|
|
45
78
|
* NOTE: Streaming structured output deferred for now. Prioritizing correctness + simplicity,
|
|
46
79
|
* and unclear what use cases there would actually be for streaming a structured output (other than maybe gen UI).
|
|
@@ -53,6 +86,25 @@ export declare class Thread<TContext = unknown, TResponse extends AgentResponseT
|
|
|
53
86
|
* For now, we stream text-delta and tool events, final validation happens in _execute().
|
|
54
87
|
*/
|
|
55
88
|
private tick;
|
|
89
|
+
/**
|
|
90
|
+
* Persist current thread state to storage.
|
|
91
|
+
*
|
|
92
|
+
* - If storage is configured, it is authoritative - failures throw and halt execution.
|
|
93
|
+
* - No-op if storage is not configured.
|
|
94
|
+
*/
|
|
95
|
+
private checkpoint;
|
|
96
|
+
/**
|
|
97
|
+
* Append one or more items to history + enrich w/ runtime headers.
|
|
98
|
+
*
|
|
99
|
+
* Core rule:
|
|
100
|
+
*
|
|
101
|
+
* > An event becomes a ThreadEvent (and gets seq/timestamp) exactly when it is appended to history. <
|
|
102
|
+
*/
|
|
103
|
+
append(...items: ThreadEventInner[]): ThreadEvent[];
|
|
104
|
+
/**
|
|
105
|
+
* Cancel the running thread
|
|
106
|
+
*/
|
|
107
|
+
cancel(): void;
|
|
56
108
|
/**
|
|
57
109
|
* Perform the actions returned by the model
|
|
58
110
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../../src/thread/thread.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../../src/thread/thread.ts"],"names":[],"mappings":"AAEA,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,EAGd,MAAM,qBAAqB,CAAC;AAG7B,OAAO,KAAK,EAEV,WAAW,EACX,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EAEpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAUvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBAAa,MAAM,CACjB,QAAQ,GAAG,OAAO,EAClB,SAAS,SAAS,iBAAiB,GAAG,MAAM;IAE5C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,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;IAEvF,OAAO,CAAC,KAAK,CAAC,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAC,CAAc;gBAElB,OAAO,EAAE,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC;IA+BvD;;OAEG;IACG,OAAO,IAAI,OAAO,CACtB,mBAAmB,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC,CACtD;IAoBD;;OAEG;IACI,MAAM,IAAI,aAAa,CAAC,iBAAiB,CAAC;IAuBjD;;;;;OAKG;YACY,QAAQ;IAgEvB;;;;;OAKG;YACY,IAAI;IA8BnB;;;;;OAKG;YACW,UAAU;IAuCxB;;;;;;OAMG;IACH,MAAM,CAAC,GAAG,KAAK,EAAE,gBAAgB,EAAE,GAAG,WAAW,EAAE;IAiBnD;;OAEG;IACH,MAAM;IAQN;;OAEG;YACW,cAAc;IAyC5B;;;;OAIG;YACW,YAAY;IA2C1B;;OAEG;YACW,mBAAmB;CA2ClC"}
|