kernl 0.12.3 → 0.12.4
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
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -936,6 +936,247 @@ describe("Thread", () => {
|
|
|
936
936
|
expect(thread._tick).toBe(2);
|
|
937
937
|
});
|
|
938
938
|
});
|
|
939
|
+
describe("Event Sequencing", () => {
|
|
940
|
+
it("should assign incrementing seq values to all persisted events", async () => {
|
|
941
|
+
let callCount = 0;
|
|
942
|
+
const model = createMockModel(async (req) => {
|
|
943
|
+
callCount++;
|
|
944
|
+
if (callCount === 1) {
|
|
945
|
+
return {
|
|
946
|
+
content: [
|
|
947
|
+
{
|
|
948
|
+
kind: "message",
|
|
949
|
+
id: "msg_1",
|
|
950
|
+
role: "assistant",
|
|
951
|
+
content: [],
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
kind: "tool.call",
|
|
955
|
+
toolId: "echo",
|
|
956
|
+
state: IN_PROGRESS,
|
|
957
|
+
callId: "call_1",
|
|
958
|
+
arguments: JSON.stringify({ text: "test" }),
|
|
959
|
+
},
|
|
960
|
+
],
|
|
961
|
+
finishReason: "stop",
|
|
962
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
963
|
+
warnings: [],
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
return {
|
|
967
|
+
content: [
|
|
968
|
+
{
|
|
969
|
+
kind: "message",
|
|
970
|
+
id: "msg_2",
|
|
971
|
+
role: "assistant",
|
|
972
|
+
content: [{ kind: "text", text: "Done!" }],
|
|
973
|
+
},
|
|
974
|
+
],
|
|
975
|
+
finishReason: "stop",
|
|
976
|
+
usage: { inputTokens: 4, outputTokens: 2, totalTokens: 6 },
|
|
977
|
+
warnings: [],
|
|
978
|
+
};
|
|
979
|
+
});
|
|
980
|
+
const echoTool = tool({
|
|
981
|
+
id: "echo",
|
|
982
|
+
description: "Echoes input",
|
|
983
|
+
parameters: z.object({ text: z.string() }),
|
|
984
|
+
execute: async (ctx, { text }) => `Echo: ${text}`,
|
|
985
|
+
});
|
|
986
|
+
const agent = new Agent({
|
|
987
|
+
id: "test",
|
|
988
|
+
name: "Test",
|
|
989
|
+
instructions: "Test agent",
|
|
990
|
+
model,
|
|
991
|
+
toolkits: [
|
|
992
|
+
new FunctionToolkit({ id: "test-tools", tools: [echoTool] }),
|
|
993
|
+
],
|
|
994
|
+
});
|
|
995
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
996
|
+
await thread.execute();
|
|
997
|
+
const history = thread.history;
|
|
998
|
+
// Verify all events have seq values
|
|
999
|
+
for (const event of history) {
|
|
1000
|
+
expect(event).toHaveProperty("seq");
|
|
1001
|
+
expect(typeof event.seq).toBe("number");
|
|
1002
|
+
}
|
|
1003
|
+
// Verify seq values increment: 0, 1, 2, 3, 4
|
|
1004
|
+
const seqValues = history.map((e) => e.seq);
|
|
1005
|
+
expect(seqValues).toEqual([0, 1, 2, 3, 4]);
|
|
1006
|
+
});
|
|
1007
|
+
it("should assign consistent tid to all events in a thread", async () => {
|
|
1008
|
+
const model = createMockModel(async (req) => {
|
|
1009
|
+
return {
|
|
1010
|
+
content: [
|
|
1011
|
+
{
|
|
1012
|
+
kind: "message",
|
|
1013
|
+
id: "msg_1",
|
|
1014
|
+
role: "assistant",
|
|
1015
|
+
content: [{ kind: "text", text: "Hello" }],
|
|
1016
|
+
},
|
|
1017
|
+
],
|
|
1018
|
+
finishReason: "stop",
|
|
1019
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
1020
|
+
warnings: [],
|
|
1021
|
+
};
|
|
1022
|
+
});
|
|
1023
|
+
const agent = new Agent({
|
|
1024
|
+
id: "test",
|
|
1025
|
+
name: "Test",
|
|
1026
|
+
instructions: "Test agent",
|
|
1027
|
+
model,
|
|
1028
|
+
});
|
|
1029
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1030
|
+
await thread.execute();
|
|
1031
|
+
const history = thread.history;
|
|
1032
|
+
const threadId = thread.tid;
|
|
1033
|
+
// All events should have the same tid as the thread
|
|
1034
|
+
for (const event of history) {
|
|
1035
|
+
expect(event).toHaveProperty("tid");
|
|
1036
|
+
expect(event.tid).toBe(threadId);
|
|
1037
|
+
}
|
|
1038
|
+
});
|
|
1039
|
+
it("should assign timestamps to all events", async () => {
|
|
1040
|
+
const model = createMockModel(async (req) => {
|
|
1041
|
+
return {
|
|
1042
|
+
content: [
|
|
1043
|
+
{
|
|
1044
|
+
kind: "message",
|
|
1045
|
+
id: "msg_1",
|
|
1046
|
+
role: "assistant",
|
|
1047
|
+
content: [{ kind: "text", text: "Hello" }],
|
|
1048
|
+
},
|
|
1049
|
+
],
|
|
1050
|
+
finishReason: "stop",
|
|
1051
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
1052
|
+
warnings: [],
|
|
1053
|
+
};
|
|
1054
|
+
});
|
|
1055
|
+
const agent = new Agent({
|
|
1056
|
+
id: "test",
|
|
1057
|
+
name: "Test",
|
|
1058
|
+
instructions: "Test agent",
|
|
1059
|
+
model,
|
|
1060
|
+
});
|
|
1061
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1062
|
+
await thread.execute();
|
|
1063
|
+
const history = thread.history;
|
|
1064
|
+
for (const event of history) {
|
|
1065
|
+
expect(event).toHaveProperty("timestamp");
|
|
1066
|
+
expect(event.timestamp).toBeInstanceOf(Date);
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1069
|
+
it("should generate event ids in expected format", async () => {
|
|
1070
|
+
let callCount = 0;
|
|
1071
|
+
const model = createMockModel(async (req) => {
|
|
1072
|
+
callCount++;
|
|
1073
|
+
if (callCount === 1) {
|
|
1074
|
+
return {
|
|
1075
|
+
content: [
|
|
1076
|
+
{
|
|
1077
|
+
kind: "message",
|
|
1078
|
+
id: "msg_1",
|
|
1079
|
+
role: "assistant",
|
|
1080
|
+
content: [],
|
|
1081
|
+
},
|
|
1082
|
+
{
|
|
1083
|
+
kind: "tool.call",
|
|
1084
|
+
toolId: "simple",
|
|
1085
|
+
state: IN_PROGRESS,
|
|
1086
|
+
callId: "call_1",
|
|
1087
|
+
arguments: "{}",
|
|
1088
|
+
},
|
|
1089
|
+
],
|
|
1090
|
+
finishReason: "stop",
|
|
1091
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
1092
|
+
warnings: [],
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
return {
|
|
1096
|
+
content: [
|
|
1097
|
+
{
|
|
1098
|
+
kind: "message",
|
|
1099
|
+
id: "msg_2",
|
|
1100
|
+
role: "assistant",
|
|
1101
|
+
content: [{ kind: "text", text: "Done" }],
|
|
1102
|
+
},
|
|
1103
|
+
],
|
|
1104
|
+
finishReason: "stop",
|
|
1105
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
1106
|
+
warnings: [],
|
|
1107
|
+
};
|
|
1108
|
+
});
|
|
1109
|
+
const simpleTool = tool({
|
|
1110
|
+
id: "simple",
|
|
1111
|
+
description: "Simple tool",
|
|
1112
|
+
parameters: undefined,
|
|
1113
|
+
execute: async () => "result",
|
|
1114
|
+
});
|
|
1115
|
+
const agent = new Agent({
|
|
1116
|
+
id: "test",
|
|
1117
|
+
name: "Test",
|
|
1118
|
+
instructions: "Test agent",
|
|
1119
|
+
model,
|
|
1120
|
+
toolkits: [
|
|
1121
|
+
new FunctionToolkit({ id: "test-tools", tools: [simpleTool] }),
|
|
1122
|
+
],
|
|
1123
|
+
});
|
|
1124
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1125
|
+
await thread.execute();
|
|
1126
|
+
const history = thread.history;
|
|
1127
|
+
// Messages should have id format "message:{original_id}"
|
|
1128
|
+
const messages = history.filter((e) => e.kind === "message");
|
|
1129
|
+
for (const msg of messages) {
|
|
1130
|
+
expect(msg.id).toMatch(/^message:/);
|
|
1131
|
+
}
|
|
1132
|
+
// Tool calls use callId (not id), so tevent falls back to randomID()
|
|
1133
|
+
const toolCalls = history.filter((e) => e.kind === "tool.call");
|
|
1134
|
+
for (const tc of toolCalls) {
|
|
1135
|
+
expect(tc.id).toBeDefined();
|
|
1136
|
+
expect(typeof tc.id).toBe("string");
|
|
1137
|
+
}
|
|
1138
|
+
// Tool results also use callId, so tevent falls back to randomID()
|
|
1139
|
+
const toolResults = history.filter((e) => e.kind === "tool.result");
|
|
1140
|
+
for (const tr of toolResults) {
|
|
1141
|
+
expect(tr.id).toBeDefined();
|
|
1142
|
+
expect(typeof tr.id).toBe("string");
|
|
1143
|
+
}
|
|
1144
|
+
});
|
|
1145
|
+
it("should yield sequenced events during streaming", async () => {
|
|
1146
|
+
const model = createMockModel(async (req) => {
|
|
1147
|
+
return {
|
|
1148
|
+
content: [
|
|
1149
|
+
{
|
|
1150
|
+
kind: "message",
|
|
1151
|
+
id: "msg_1",
|
|
1152
|
+
role: "assistant",
|
|
1153
|
+
content: [{ kind: "text", text: "Hello" }],
|
|
1154
|
+
},
|
|
1155
|
+
],
|
|
1156
|
+
finishReason: "stop",
|
|
1157
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
1158
|
+
warnings: [],
|
|
1159
|
+
};
|
|
1160
|
+
});
|
|
1161
|
+
const agent = new Agent({
|
|
1162
|
+
id: "test",
|
|
1163
|
+
name: "Test",
|
|
1164
|
+
instructions: "Test agent",
|
|
1165
|
+
model,
|
|
1166
|
+
});
|
|
1167
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1168
|
+
const events = [];
|
|
1169
|
+
for await (const event of thread.stream()) {
|
|
1170
|
+
events.push(event);
|
|
1171
|
+
}
|
|
1172
|
+
// Find the complete message event (not deltas)
|
|
1173
|
+
const messageEvent = events.find((e) => e.kind === "message" && e.role === "assistant");
|
|
1174
|
+
expect(messageEvent).toBeDefined();
|
|
1175
|
+
expect(messageEvent).toHaveProperty("seq");
|
|
1176
|
+
expect(messageEvent).toHaveProperty("tid");
|
|
1177
|
+
expect(messageEvent).toHaveProperty("timestamp");
|
|
1178
|
+
});
|
|
1179
|
+
});
|
|
939
1180
|
describe("Final Output Parsing", () => {
|
|
940
1181
|
it("should return text output when output is 'text'", async () => {
|
|
941
1182
|
const model = createMockModel(async (req) => {
|
package/dist/tool/tool.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Context, UnknownContext } from "../context.js";
|
|
2
2
|
import { type LanguageModelTool } from "@kernl-sdk/protocol";
|
|
3
|
-
import type { ToolConfig, ToolApprovalFunction, ToolEnabledFunction, ToolErrorFunction, ToolInputParameters, ToolResult } from "./types.js";
|
|
3
|
+
import type { ToolConfig, ToolApprovalFunction, ToolEnabledFunction, ToolErrorFunction, ToolExecuteFunction, ToolInputParameters, ToolResult } from "./types.js";
|
|
4
4
|
/**
|
|
5
5
|
* Exposes a function to the agent as a tool to be called
|
|
6
6
|
*
|
|
@@ -42,7 +42,7 @@ export declare class FunctionTool<TContext = UnknownContext, TParameters extends
|
|
|
42
42
|
readonly description: string;
|
|
43
43
|
readonly parameters?: TParameters;
|
|
44
44
|
readonly mode: "blocking" | "async";
|
|
45
|
-
|
|
45
|
+
execute: ToolExecuteFunction<TContext, TParameters, TResult>;
|
|
46
46
|
errorfn: ToolErrorFunction | null;
|
|
47
47
|
requiresApproval: ToolApprovalFunction<TParameters>;
|
|
48
48
|
isEnabled: ToolEnabledFunction<TContext>;
|
package/dist/tool/tool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/tool/tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAMpD,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,KAAK,EACV,UAAU,EACV,oBAAoB,EACpB,mBAAmB,EAEnB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/tool/tool.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kernl",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.4",
|
|
4
4
|
"description": "A modern AI agent framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kernl",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
35
|
+
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
36
36
|
"yaml": "^2.8.2",
|
|
37
37
|
"@kernl-sdk/protocol": "0.5.1",
|
|
38
38
|
"@kernl-sdk/retrieval": "0.1.10",
|
|
@@ -1060,6 +1060,286 @@ describe("Thread", () => {
|
|
|
1060
1060
|
});
|
|
1061
1061
|
});
|
|
1062
1062
|
|
|
1063
|
+
describe("Event Sequencing", () => {
|
|
1064
|
+
it("should assign incrementing seq values to all persisted events", async () => {
|
|
1065
|
+
let callCount = 0;
|
|
1066
|
+
|
|
1067
|
+
const model = createMockModel(async (req: LanguageModelRequest) => {
|
|
1068
|
+
callCount++;
|
|
1069
|
+
|
|
1070
|
+
if (callCount === 1) {
|
|
1071
|
+
return {
|
|
1072
|
+
content: [
|
|
1073
|
+
{
|
|
1074
|
+
kind: "message" as const,
|
|
1075
|
+
id: "msg_1",
|
|
1076
|
+
role: "assistant" as const,
|
|
1077
|
+
content: [],
|
|
1078
|
+
},
|
|
1079
|
+
{
|
|
1080
|
+
kind: "tool.call" as const,
|
|
1081
|
+
toolId: "echo",
|
|
1082
|
+
state: IN_PROGRESS,
|
|
1083
|
+
callId: "call_1",
|
|
1084
|
+
arguments: JSON.stringify({ text: "test" }),
|
|
1085
|
+
},
|
|
1086
|
+
],
|
|
1087
|
+
finishReason: "stop",
|
|
1088
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
1089
|
+
warnings: [],
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
return {
|
|
1094
|
+
content: [
|
|
1095
|
+
{
|
|
1096
|
+
kind: "message" as const,
|
|
1097
|
+
id: "msg_2",
|
|
1098
|
+
role: "assistant" as const,
|
|
1099
|
+
content: [{ kind: "text" as const, text: "Done!" }],
|
|
1100
|
+
},
|
|
1101
|
+
],
|
|
1102
|
+
finishReason: "stop",
|
|
1103
|
+
usage: { inputTokens: 4, outputTokens: 2, totalTokens: 6 },
|
|
1104
|
+
warnings: [],
|
|
1105
|
+
};
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
const echoTool = tool({
|
|
1109
|
+
id: "echo",
|
|
1110
|
+
description: "Echoes input",
|
|
1111
|
+
parameters: z.object({ text: z.string() }),
|
|
1112
|
+
execute: async (ctx, { text }) => `Echo: ${text}`,
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
const agent = new Agent({
|
|
1116
|
+
id: "test",
|
|
1117
|
+
name: "Test",
|
|
1118
|
+
instructions: "Test agent",
|
|
1119
|
+
model,
|
|
1120
|
+
toolkits: [
|
|
1121
|
+
new FunctionToolkit({ id: "test-tools", tools: [echoTool] }),
|
|
1122
|
+
],
|
|
1123
|
+
});
|
|
1124
|
+
|
|
1125
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1126
|
+
await thread.execute();
|
|
1127
|
+
|
|
1128
|
+
const history = (thread as any).history as ThreadEvent[];
|
|
1129
|
+
|
|
1130
|
+
// Verify all events have seq values
|
|
1131
|
+
for (const event of history) {
|
|
1132
|
+
expect(event).toHaveProperty("seq");
|
|
1133
|
+
expect(typeof event.seq).toBe("number");
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// Verify seq values increment: 0, 1, 2, 3, 4
|
|
1137
|
+
const seqValues = history.map((e) => e.seq);
|
|
1138
|
+
expect(seqValues).toEqual([0, 1, 2, 3, 4]);
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1141
|
+
it("should assign consistent tid to all events in a thread", async () => {
|
|
1142
|
+
const model = createMockModel(async (req: LanguageModelRequest) => {
|
|
1143
|
+
return {
|
|
1144
|
+
content: [
|
|
1145
|
+
{
|
|
1146
|
+
kind: "message" as const,
|
|
1147
|
+
id: "msg_1",
|
|
1148
|
+
role: "assistant" as const,
|
|
1149
|
+
content: [{ kind: "text" as const, text: "Hello" }],
|
|
1150
|
+
},
|
|
1151
|
+
],
|
|
1152
|
+
finishReason: "stop",
|
|
1153
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
1154
|
+
warnings: [],
|
|
1155
|
+
};
|
|
1156
|
+
});
|
|
1157
|
+
|
|
1158
|
+
const agent = new Agent({
|
|
1159
|
+
id: "test",
|
|
1160
|
+
name: "Test",
|
|
1161
|
+
instructions: "Test agent",
|
|
1162
|
+
model,
|
|
1163
|
+
});
|
|
1164
|
+
|
|
1165
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1166
|
+
await thread.execute();
|
|
1167
|
+
|
|
1168
|
+
const history = (thread as any).history as ThreadEvent[];
|
|
1169
|
+
const threadId = thread.tid;
|
|
1170
|
+
|
|
1171
|
+
// All events should have the same tid as the thread
|
|
1172
|
+
for (const event of history) {
|
|
1173
|
+
expect(event).toHaveProperty("tid");
|
|
1174
|
+
expect(event.tid).toBe(threadId);
|
|
1175
|
+
}
|
|
1176
|
+
});
|
|
1177
|
+
|
|
1178
|
+
it("should assign timestamps to all events", async () => {
|
|
1179
|
+
const model = createMockModel(async (req: LanguageModelRequest) => {
|
|
1180
|
+
return {
|
|
1181
|
+
content: [
|
|
1182
|
+
{
|
|
1183
|
+
kind: "message" as const,
|
|
1184
|
+
id: "msg_1",
|
|
1185
|
+
role: "assistant" as const,
|
|
1186
|
+
content: [{ kind: "text" as const, text: "Hello" }],
|
|
1187
|
+
},
|
|
1188
|
+
],
|
|
1189
|
+
finishReason: "stop",
|
|
1190
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
1191
|
+
warnings: [],
|
|
1192
|
+
};
|
|
1193
|
+
});
|
|
1194
|
+
|
|
1195
|
+
const agent = new Agent({
|
|
1196
|
+
id: "test",
|
|
1197
|
+
name: "Test",
|
|
1198
|
+
instructions: "Test agent",
|
|
1199
|
+
model,
|
|
1200
|
+
});
|
|
1201
|
+
|
|
1202
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1203
|
+
await thread.execute();
|
|
1204
|
+
|
|
1205
|
+
const history = (thread as any).history as ThreadEvent[];
|
|
1206
|
+
|
|
1207
|
+
for (const event of history) {
|
|
1208
|
+
expect(event).toHaveProperty("timestamp");
|
|
1209
|
+
expect(event.timestamp).toBeInstanceOf(Date);
|
|
1210
|
+
}
|
|
1211
|
+
});
|
|
1212
|
+
|
|
1213
|
+
it("should generate event ids in expected format", async () => {
|
|
1214
|
+
let callCount = 0;
|
|
1215
|
+
|
|
1216
|
+
const model = createMockModel(async (req: LanguageModelRequest) => {
|
|
1217
|
+
callCount++;
|
|
1218
|
+
|
|
1219
|
+
if (callCount === 1) {
|
|
1220
|
+
return {
|
|
1221
|
+
content: [
|
|
1222
|
+
{
|
|
1223
|
+
kind: "message" as const,
|
|
1224
|
+
id: "msg_1",
|
|
1225
|
+
role: "assistant" as const,
|
|
1226
|
+
content: [],
|
|
1227
|
+
},
|
|
1228
|
+
{
|
|
1229
|
+
kind: "tool.call" as const,
|
|
1230
|
+
toolId: "simple",
|
|
1231
|
+
state: IN_PROGRESS,
|
|
1232
|
+
callId: "call_1",
|
|
1233
|
+
arguments: "{}",
|
|
1234
|
+
},
|
|
1235
|
+
],
|
|
1236
|
+
finishReason: "stop",
|
|
1237
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
1238
|
+
warnings: [],
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
return {
|
|
1243
|
+
content: [
|
|
1244
|
+
{
|
|
1245
|
+
kind: "message" as const,
|
|
1246
|
+
id: "msg_2",
|
|
1247
|
+
role: "assistant" as const,
|
|
1248
|
+
content: [{ kind: "text" as const, text: "Done" }],
|
|
1249
|
+
},
|
|
1250
|
+
],
|
|
1251
|
+
finishReason: "stop",
|
|
1252
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
1253
|
+
warnings: [],
|
|
1254
|
+
};
|
|
1255
|
+
});
|
|
1256
|
+
|
|
1257
|
+
const simpleTool = tool({
|
|
1258
|
+
id: "simple",
|
|
1259
|
+
description: "Simple tool",
|
|
1260
|
+
parameters: undefined,
|
|
1261
|
+
execute: async () => "result",
|
|
1262
|
+
});
|
|
1263
|
+
|
|
1264
|
+
const agent = new Agent({
|
|
1265
|
+
id: "test",
|
|
1266
|
+
name: "Test",
|
|
1267
|
+
instructions: "Test agent",
|
|
1268
|
+
model,
|
|
1269
|
+
toolkits: [
|
|
1270
|
+
new FunctionToolkit({ id: "test-tools", tools: [simpleTool] }),
|
|
1271
|
+
],
|
|
1272
|
+
});
|
|
1273
|
+
|
|
1274
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1275
|
+
await thread.execute();
|
|
1276
|
+
|
|
1277
|
+
const history = (thread as any).history as ThreadEvent[];
|
|
1278
|
+
|
|
1279
|
+
// Messages should have id format "message:{original_id}"
|
|
1280
|
+
const messages = history.filter((e) => e.kind === "message");
|
|
1281
|
+
for (const msg of messages) {
|
|
1282
|
+
expect(msg.id).toMatch(/^message:/);
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
// Tool calls use callId (not id), so tevent falls back to randomID()
|
|
1286
|
+
const toolCalls = history.filter((e) => e.kind === "tool.call");
|
|
1287
|
+
for (const tc of toolCalls) {
|
|
1288
|
+
expect(tc.id).toBeDefined();
|
|
1289
|
+
expect(typeof tc.id).toBe("string");
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
// Tool results also use callId, so tevent falls back to randomID()
|
|
1293
|
+
const toolResults = history.filter((e) => e.kind === "tool.result");
|
|
1294
|
+
for (const tr of toolResults) {
|
|
1295
|
+
expect(tr.id).toBeDefined();
|
|
1296
|
+
expect(typeof tr.id).toBe("string");
|
|
1297
|
+
}
|
|
1298
|
+
});
|
|
1299
|
+
|
|
1300
|
+
it("should yield sequenced events during streaming", async () => {
|
|
1301
|
+
const model = createMockModel(async (req: LanguageModelRequest) => {
|
|
1302
|
+
return {
|
|
1303
|
+
content: [
|
|
1304
|
+
{
|
|
1305
|
+
kind: "message" as const,
|
|
1306
|
+
id: "msg_1",
|
|
1307
|
+
role: "assistant" as const,
|
|
1308
|
+
content: [{ kind: "text" as const, text: "Hello" }],
|
|
1309
|
+
},
|
|
1310
|
+
],
|
|
1311
|
+
finishReason: "stop",
|
|
1312
|
+
usage: { inputTokens: 2, outputTokens: 2, totalTokens: 4 },
|
|
1313
|
+
warnings: [],
|
|
1314
|
+
};
|
|
1315
|
+
});
|
|
1316
|
+
|
|
1317
|
+
const agent = new Agent({
|
|
1318
|
+
id: "test",
|
|
1319
|
+
name: "Test",
|
|
1320
|
+
instructions: "Test agent",
|
|
1321
|
+
model,
|
|
1322
|
+
});
|
|
1323
|
+
|
|
1324
|
+
const thread = new Thread({ agent, input: userMessage("test") });
|
|
1325
|
+
|
|
1326
|
+
const events: any[] = [];
|
|
1327
|
+
for await (const event of thread.stream()) {
|
|
1328
|
+
events.push(event);
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
// Find the complete message event (not deltas)
|
|
1332
|
+
const messageEvent = events.find(
|
|
1333
|
+
(e) => e.kind === "message" && e.role === "assistant",
|
|
1334
|
+
);
|
|
1335
|
+
|
|
1336
|
+
expect(messageEvent).toBeDefined();
|
|
1337
|
+
expect(messageEvent).toHaveProperty("seq");
|
|
1338
|
+
expect(messageEvent).toHaveProperty("tid");
|
|
1339
|
+
expect(messageEvent).toHaveProperty("timestamp");
|
|
1340
|
+
});
|
|
1341
|
+
});
|
|
1342
|
+
|
|
1063
1343
|
describe("Final Output Parsing", () => {
|
|
1064
1344
|
it("should return text output when output is 'text'", async () => {
|
|
1065
1345
|
const model = createMockModel(async (req: LanguageModelRequest) => {
|
package/src/tool/tool.ts
CHANGED
|
@@ -84,7 +84,7 @@ export class FunctionTool<
|
|
|
84
84
|
readonly description: string;
|
|
85
85
|
readonly parameters?: TParameters;
|
|
86
86
|
readonly mode: "blocking" | "async";
|
|
87
|
-
|
|
87
|
+
execute: ToolExecuteFunction<TContext, TParameters, TResult>;
|
|
88
88
|
|
|
89
89
|
errorfn: ToolErrorFunction | null;
|
|
90
90
|
requiresApproval: ToolApprovalFunction<TParameters>;
|