kernl 0.7.4 → 0.8.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/CHANGELOG.md +19 -1
- package/dist/agent/types.d.ts +20 -12
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent.d.ts +7 -7
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +3 -14
- package/dist/api/resources/agents/agents.d.ts +5 -5
- package/dist/api/resources/agents/agents.d.ts.map +1 -1
- package/dist/api/resources/agents/agents.js +1 -1
- package/dist/guardrail.d.ts +19 -19
- package/dist/guardrail.d.ts.map +1 -1
- package/dist/kernl/kernl.d.ts +6 -6
- package/dist/kernl/kernl.d.ts.map +1 -1
- package/dist/lib/error.d.ts +3 -3
- package/dist/lib/error.d.ts.map +1 -1
- package/dist/lifecycle.d.ts +6 -6
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/memory/__tests__/encoder.test.d.ts +2 -0
- package/dist/memory/__tests__/encoder.test.d.ts.map +1 -0
- package/dist/memory/__tests__/encoder.test.js +120 -0
- package/dist/memory/codecs/domain.d.ts +5 -0
- package/dist/memory/codecs/domain.d.ts.map +1 -1
- package/dist/memory/codecs/domain.js +6 -0
- package/dist/memory/encoder.d.ts +25 -2
- package/dist/memory/encoder.d.ts.map +1 -1
- package/dist/memory/encoder.js +46 -5
- package/dist/memory/index.d.ts +1 -1
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +1 -1
- package/dist/memory/schema.d.ts.map +1 -1
- package/dist/memory/schema.js +5 -0
- package/dist/memory/types.d.ts +1 -0
- package/dist/memory/types.d.ts.map +1 -1
- package/dist/thread/__tests__/integration.test.js +1 -1
- package/dist/thread/__tests__/thread.test.js +8 -8
- package/dist/thread/thread.d.ts +5 -5
- package/dist/thread/thread.d.ts.map +1 -1
- package/dist/thread/thread.js +13 -2
- package/dist/thread/types.d.ts +9 -6
- package/dist/thread/types.d.ts.map +1 -1
- package/dist/thread/utils.d.ts +7 -6
- package/dist/thread/utils.d.ts.map +1 -1
- package/dist/thread/utils.js +9 -8
- package/package.json +5 -4
- package/src/agent/types.ts +25 -29
- package/src/agent.ts +15 -28
- package/src/api/resources/agents/agents.ts +8 -8
- package/src/guardrail.ts +28 -28
- package/src/kernl/kernl.ts +12 -12
- package/src/lib/error.ts +3 -3
- package/src/lifecycle.ts +6 -6
- package/src/memory/__tests__/encoder.test.ts +153 -0
- package/src/memory/codecs/domain.ts +6 -0
- package/src/memory/encoder.ts +51 -6
- package/src/memory/index.ts +1 -1
- package/src/memory/schema.ts +5 -0
- package/src/memory/types.ts +1 -0
- package/src/thread/__tests__/integration.test.ts +130 -146
- package/src/thread/__tests__/thread.test.ts +8 -8
- package/src/thread/thread.ts +21 -7
- package/src/thread/types.ts +9 -6
- package/src/thread/utils.ts +15 -14
|
@@ -1061,7 +1061,7 @@ describe("Thread", () => {
|
|
|
1061
1061
|
});
|
|
1062
1062
|
|
|
1063
1063
|
describe("Final Output Parsing", () => {
|
|
1064
|
-
it("should return text output when
|
|
1064
|
+
it("should return text output when output is 'text'", async () => {
|
|
1065
1065
|
const model = createMockModel(async (req: LanguageModelRequest) => {
|
|
1066
1066
|
return {
|
|
1067
1067
|
content: [
|
|
@@ -1087,7 +1087,7 @@ describe("Thread", () => {
|
|
|
1087
1087
|
name: "Test",
|
|
1088
1088
|
instructions: "Test agent",
|
|
1089
1089
|
model,
|
|
1090
|
-
|
|
1090
|
+
output: "text",
|
|
1091
1091
|
});
|
|
1092
1092
|
|
|
1093
1093
|
const kernl = new Kernl();
|
|
@@ -1136,7 +1136,7 @@ describe("Thread", () => {
|
|
|
1136
1136
|
name: "Test",
|
|
1137
1137
|
instructions: "Test agent",
|
|
1138
1138
|
model,
|
|
1139
|
-
|
|
1139
|
+
output: responseSchema,
|
|
1140
1140
|
});
|
|
1141
1141
|
|
|
1142
1142
|
const kernl = new Kernl();
|
|
@@ -1186,7 +1186,7 @@ describe("Thread", () => {
|
|
|
1186
1186
|
name: "Test",
|
|
1187
1187
|
instructions: "Test agent",
|
|
1188
1188
|
model,
|
|
1189
|
-
|
|
1189
|
+
output: responseSchema,
|
|
1190
1190
|
});
|
|
1191
1191
|
|
|
1192
1192
|
const kernl = new Kernl();
|
|
@@ -1231,7 +1231,7 @@ describe("Thread", () => {
|
|
|
1231
1231
|
name: "Test",
|
|
1232
1232
|
instructions: "Test agent",
|
|
1233
1233
|
model,
|
|
1234
|
-
|
|
1234
|
+
output: responseSchema,
|
|
1235
1235
|
});
|
|
1236
1236
|
|
|
1237
1237
|
const kernl = new Kernl();
|
|
@@ -1277,7 +1277,7 @@ describe("Thread", () => {
|
|
|
1277
1277
|
name: "Test",
|
|
1278
1278
|
instructions: "Test agent",
|
|
1279
1279
|
model,
|
|
1280
|
-
|
|
1280
|
+
output: responseSchema,
|
|
1281
1281
|
});
|
|
1282
1282
|
|
|
1283
1283
|
const kernl = new Kernl();
|
|
@@ -1336,7 +1336,7 @@ describe("Thread", () => {
|
|
|
1336
1336
|
name: "Test",
|
|
1337
1337
|
instructions: "Test agent",
|
|
1338
1338
|
model,
|
|
1339
|
-
|
|
1339
|
+
output: responseSchema,
|
|
1340
1340
|
});
|
|
1341
1341
|
|
|
1342
1342
|
const kernl = new Kernl();
|
|
@@ -1405,7 +1405,7 @@ describe("Thread", () => {
|
|
|
1405
1405
|
name: "Test",
|
|
1406
1406
|
instructions: "Test agent",
|
|
1407
1407
|
model,
|
|
1408
|
-
|
|
1408
|
+
output: "text",
|
|
1409
1409
|
});
|
|
1410
1410
|
|
|
1411
1411
|
const kernl = new Kernl();
|
package/src/thread/thread.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import assert from "assert";
|
|
2
|
+
import { ZodType } from "zod";
|
|
3
|
+
import * as z from "zod";
|
|
2
4
|
|
|
3
5
|
import { Agent } from "@/agent";
|
|
4
6
|
import { Context } from "@/context";
|
|
@@ -30,7 +32,8 @@ import type {
|
|
|
30
32
|
ThreadExecuteResult,
|
|
31
33
|
PerformActionsResult,
|
|
32
34
|
} from "./types";
|
|
33
|
-
import type {
|
|
35
|
+
import type { AgentOutputType } from "@/agent/types";
|
|
36
|
+
import type { LanguageModelResponseType } from "@kernl-sdk/protocol";
|
|
34
37
|
|
|
35
38
|
import {
|
|
36
39
|
tevent,
|
|
@@ -82,11 +85,11 @@ import {
|
|
|
82
85
|
*/
|
|
83
86
|
export class Thread<
|
|
84
87
|
TContext = unknown,
|
|
85
|
-
|
|
88
|
+
TOutput extends AgentOutputType = "text",
|
|
86
89
|
> {
|
|
87
90
|
readonly tid: string;
|
|
88
91
|
readonly namespace: string;
|
|
89
|
-
readonly agent: Agent<TContext,
|
|
92
|
+
readonly agent: Agent<TContext, TOutput>;
|
|
90
93
|
readonly context: Context<TContext>;
|
|
91
94
|
readonly model: LanguageModel; /* inherited from the agent unless specified */
|
|
92
95
|
readonly parent: Task<TContext> | null; /* parent task which spawned this thread */
|
|
@@ -106,7 +109,7 @@ export class Thread<
|
|
|
106
109
|
private abort?: AbortController;
|
|
107
110
|
private storage?: ThreadStore;
|
|
108
111
|
|
|
109
|
-
constructor(options: ThreadOptions<TContext,
|
|
112
|
+
constructor(options: ThreadOptions<TContext, TOutput>) {
|
|
110
113
|
this.tid = options.tid ?? `tid_${randomID()}`;
|
|
111
114
|
this.namespace = options.namespace ?? "kernl";
|
|
112
115
|
this.agent = options.agent;
|
|
@@ -142,7 +145,7 @@ export class Thread<
|
|
|
142
145
|
* Blocking execution - runs until terminal state or interruption
|
|
143
146
|
*/
|
|
144
147
|
async execute(): Promise<
|
|
145
|
-
ThreadExecuteResult<ResolvedAgentResponse<
|
|
148
|
+
ThreadExecuteResult<ResolvedAgentResponse<TOutput>>
|
|
146
149
|
> {
|
|
147
150
|
for await (const _event of this.stream()) {
|
|
148
151
|
// just consume the stream (already in history in _execute())
|
|
@@ -158,7 +161,7 @@ export class Thread<
|
|
|
158
161
|
|
|
159
162
|
const text = getFinalResponse(items);
|
|
160
163
|
assert(text, "_execute continues until text !== null"); // (TODO): consider preventing infinite loops here
|
|
161
|
-
const parsed = parseFinalResponse(text, this.agent.
|
|
164
|
+
const parsed = parseFinalResponse(text, this.agent.output);
|
|
162
165
|
|
|
163
166
|
return { response: parsed, state: this.state };
|
|
164
167
|
}
|
|
@@ -405,7 +408,7 @@ export class Thread<
|
|
|
405
408
|
e.kind === "tool-result" &&
|
|
406
409
|
(e.state as any) === "requires_approval" // (TODO): fix this
|
|
407
410
|
) {
|
|
408
|
-
//
|
|
411
|
+
// find the original tool call for this pending approval
|
|
409
412
|
const call = intentions.toolCalls.find((c) => c.callId === e.callId);
|
|
410
413
|
call && pendingApprovals.push(call);
|
|
411
414
|
} else {
|
|
@@ -508,10 +511,21 @@ export class Thread<
|
|
|
508
511
|
);
|
|
509
512
|
const tools = enabled.map((tool) => tool.serialize());
|
|
510
513
|
|
|
514
|
+
// derive responseType from agent.output
|
|
515
|
+
let responseType: LanguageModelResponseType | undefined;
|
|
516
|
+
if (this.agent.output && this.agent.output !== "text") {
|
|
517
|
+
const schema = this.agent.output as ZodType;
|
|
518
|
+
responseType = {
|
|
519
|
+
kind: "json",
|
|
520
|
+
schema: z.toJSONSchema(schema, { target: "draft-7" }) as any,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
511
524
|
return {
|
|
512
525
|
input: filtered,
|
|
513
526
|
settings,
|
|
514
527
|
tools,
|
|
528
|
+
responseType,
|
|
515
529
|
};
|
|
516
530
|
}
|
|
517
531
|
}
|
package/src/thread/types.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { Task } from "@/task";
|
|
|
15
15
|
import { Context } from "@/context";
|
|
16
16
|
import { Agent } from "@/agent";
|
|
17
17
|
|
|
18
|
-
import type {
|
|
18
|
+
import type { AgentOutputType } from "@/agent/types";
|
|
19
19
|
import type { ThreadStore } from "@/storage";
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -23,7 +23,10 @@ import type { ThreadStore } from "@/storage";
|
|
|
23
23
|
*/
|
|
24
24
|
export type PublicThreadEvent = LanguageModelItem & ThreadEventBase;
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Text output type - indicates the agent returns a plain string.
|
|
28
|
+
*/
|
|
29
|
+
export type TextOutput = "text";
|
|
27
30
|
|
|
28
31
|
/**
|
|
29
32
|
* Thread state values as a const array (for zod schemas).
|
|
@@ -61,10 +64,10 @@ export const REQUIRES_APPROVAL = "requires_approval";
|
|
|
61
64
|
*/
|
|
62
65
|
export interface IThread<
|
|
63
66
|
TContext = unknown,
|
|
64
|
-
|
|
67
|
+
TOutput extends AgentOutputType = "text",
|
|
65
68
|
> {
|
|
66
69
|
tid: string;
|
|
67
|
-
agent: Agent<TContext,
|
|
70
|
+
agent: Agent<TContext, TOutput>;
|
|
68
71
|
model: LanguageModel;
|
|
69
72
|
|
|
70
73
|
context: Context<TContext>;
|
|
@@ -148,9 +151,9 @@ export interface ThreadExecuteResult<TResponse = unknown> {
|
|
|
148
151
|
*/
|
|
149
152
|
export interface ThreadOptions<
|
|
150
153
|
TContext = unknown,
|
|
151
|
-
|
|
154
|
+
TOutput extends AgentOutputType = "text",
|
|
152
155
|
> {
|
|
153
|
-
agent: Agent<TContext,
|
|
156
|
+
agent: Agent<TContext, TOutput>;
|
|
154
157
|
input?: LanguageModelItem[];
|
|
155
158
|
history?: ThreadEvent[];
|
|
156
159
|
context?: Context<TContext>;
|
package/src/thread/utils.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { ToolCall, LanguageModelItem } from "@kernl-sdk/protocol";
|
|
|
8
8
|
import { ModelBehaviorError } from "@/lib/error";
|
|
9
9
|
|
|
10
10
|
/* types */
|
|
11
|
-
import type {
|
|
11
|
+
import type { AgentOutputType } from "@/agent/types";
|
|
12
12
|
import type {
|
|
13
13
|
ThreadEvent,
|
|
14
14
|
ThreadEventBase,
|
|
@@ -129,30 +129,31 @@ export function getFinalResponse(items: LanguageModelItem[]): string | null {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
/**
|
|
132
|
-
*
|
|
132
|
+
* Parse the final response according to the output type schema.
|
|
133
133
|
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* - If
|
|
134
|
+
* This serves as a safety net validation after native structured output from the provider.
|
|
135
|
+
*
|
|
136
|
+
* - If output is "text", returns the text as-is
|
|
137
|
+
* - If output is a ZodType, parses and validates the text as JSON
|
|
137
138
|
*
|
|
138
139
|
* @throws {ModelBehaviorError} if structured output validation fails
|
|
139
140
|
*/
|
|
140
|
-
export function parseFinalResponse<
|
|
141
|
+
export function parseFinalResponse<TOutput extends AgentOutputType>(
|
|
141
142
|
text: string,
|
|
142
|
-
|
|
143
|
-
): ResolvedAgentResponse<
|
|
144
|
-
if (
|
|
145
|
-
return text as ResolvedAgentResponse<
|
|
143
|
+
output: TOutput,
|
|
144
|
+
): ResolvedAgentResponse<TOutput> {
|
|
145
|
+
if (output === "text") {
|
|
146
|
+
return text as ResolvedAgentResponse<TOutput>; // text output - return as-is
|
|
146
147
|
}
|
|
147
148
|
|
|
148
149
|
// structured output - decode JSON and validate with schema
|
|
149
|
-
if (
|
|
150
|
+
if (output && typeof output === "object") {
|
|
150
151
|
// (TODO): prob better way of checking this here
|
|
151
|
-
const schema =
|
|
152
|
+
const schema = output as ZodType;
|
|
152
153
|
|
|
153
154
|
try {
|
|
154
155
|
const validated = json(schema).decode(text); // (TODO): it would be nice if we could use `decodeSafe` here
|
|
155
|
-
return validated as ResolvedAgentResponse<
|
|
156
|
+
return validated as ResolvedAgentResponse<TOutput>;
|
|
156
157
|
} catch (error) {
|
|
157
158
|
throw new ModelBehaviorError(
|
|
158
159
|
`Failed to parse structured output: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -161,5 +162,5 @@ export function parseFinalResponse<TResponse extends AgentResponseType>(
|
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
// Fallback - should not reach here
|
|
164
|
-
return text as ResolvedAgentResponse<
|
|
165
|
+
return text as ResolvedAgentResponse<TOutput>;
|
|
165
166
|
}
|