@boxiaolanya2008/pi-agent-core 0.60.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/README.md +412 -0
- package/dist/agent-loop.d.ts +5 -0
- package/dist/agent-loop.d.ts.map +1 -0
- package/dist/agent-loop.js +350 -0
- package/dist/agent-loop.js.map +1 -0
- package/dist/agent.d.ts +157 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +413 -0
- package/dist/agent.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/proxy.d.ts +57 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +237 -0
- package/dist/proxy.js.map +1 -0
- package/dist/types.d.ts +80 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { EventStream, streamSimple, validateToolArguments, } from "@boxiaolanya2008/pi-ai";
|
|
2
|
+
const PARALLEL_TOOL_EXECUTION = true;
|
|
3
|
+
const MAX_TOOL_CONCURRENCY = 8;
|
|
4
|
+
export function agentLoop(prompts, context, config, signal, streamFn) {
|
|
5
|
+
const stream = createAgentStream();
|
|
6
|
+
(async () => {
|
|
7
|
+
const newMessages = [...prompts];
|
|
8
|
+
const currentContext = {
|
|
9
|
+
...context,
|
|
10
|
+
messages: [...context.messages, ...prompts],
|
|
11
|
+
};
|
|
12
|
+
stream.push({ type: "agent_start" });
|
|
13
|
+
stream.push({ type: "turn_start" });
|
|
14
|
+
for (const prompt of prompts) {
|
|
15
|
+
stream.push({ type: "message_start", message: prompt });
|
|
16
|
+
stream.push({ type: "message_end", message: prompt });
|
|
17
|
+
}
|
|
18
|
+
await runLoop(currentContext, newMessages, config, signal, stream, streamFn);
|
|
19
|
+
})();
|
|
20
|
+
return stream;
|
|
21
|
+
}
|
|
22
|
+
export function agentLoopContinue(context, config, signal, streamFn) {
|
|
23
|
+
if (context.messages.length === 0) {
|
|
24
|
+
throw new Error("Cannot continue: no messages in context");
|
|
25
|
+
}
|
|
26
|
+
if (context.messages[context.messages.length - 1].role === "assistant") {
|
|
27
|
+
throw new Error("Cannot continue from message role: assistant");
|
|
28
|
+
}
|
|
29
|
+
const stream = createAgentStream();
|
|
30
|
+
(async () => {
|
|
31
|
+
const newMessages = [];
|
|
32
|
+
const currentContext = { ...context };
|
|
33
|
+
stream.push({ type: "agent_start" });
|
|
34
|
+
stream.push({ type: "turn_start" });
|
|
35
|
+
await runLoop(currentContext, newMessages, config, signal, stream, streamFn);
|
|
36
|
+
})();
|
|
37
|
+
return stream;
|
|
38
|
+
}
|
|
39
|
+
function createAgentStream() {
|
|
40
|
+
return new EventStream((event) => event.type === "agent_end", (event) => (event.type === "agent_end" ? event.messages : []));
|
|
41
|
+
}
|
|
42
|
+
async function runLoop(currentContext, newMessages, config, signal, stream, streamFn) {
|
|
43
|
+
let firstTurn = true;
|
|
44
|
+
let pendingMessages = (await config.getSteeringMessages?.()) || [];
|
|
45
|
+
while (true) {
|
|
46
|
+
let hasMoreToolCalls = true;
|
|
47
|
+
let steeringAfterTools = null;
|
|
48
|
+
while (hasMoreToolCalls || pendingMessages.length > 0) {
|
|
49
|
+
if (!firstTurn) {
|
|
50
|
+
stream.push({ type: "turn_start" });
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
firstTurn = false;
|
|
54
|
+
}
|
|
55
|
+
if (pendingMessages.length > 0) {
|
|
56
|
+
for (const message of pendingMessages) {
|
|
57
|
+
stream.push({ type: "message_start", message });
|
|
58
|
+
stream.push({ type: "message_end", message });
|
|
59
|
+
currentContext.messages.push(message);
|
|
60
|
+
newMessages.push(message);
|
|
61
|
+
}
|
|
62
|
+
pendingMessages = [];
|
|
63
|
+
}
|
|
64
|
+
const message = await streamAssistantResponse(currentContext, config, signal, stream, streamFn);
|
|
65
|
+
newMessages.push(message);
|
|
66
|
+
if (message.stopReason === "error" || message.stopReason === "aborted") {
|
|
67
|
+
stream.push({ type: "turn_end", message, toolResults: [] });
|
|
68
|
+
stream.push({ type: "agent_end", messages: newMessages });
|
|
69
|
+
stream.end(newMessages);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const toolCalls = message.content.filter((c) => c.type === "toolCall");
|
|
73
|
+
hasMoreToolCalls = toolCalls.length > 0;
|
|
74
|
+
const toolResults = [];
|
|
75
|
+
if (hasMoreToolCalls) {
|
|
76
|
+
const toolExecution = await executeToolCalls(currentContext.tools, message, signal, stream, config.getSteeringMessages);
|
|
77
|
+
toolResults.push(...toolExecution.toolResults);
|
|
78
|
+
steeringAfterTools = toolExecution.steeringMessages ?? null;
|
|
79
|
+
for (const result of toolResults) {
|
|
80
|
+
currentContext.messages.push(result);
|
|
81
|
+
newMessages.push(result);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
stream.push({ type: "turn_end", message, toolResults });
|
|
85
|
+
if (steeringAfterTools && steeringAfterTools.length > 0) {
|
|
86
|
+
pendingMessages = steeringAfterTools;
|
|
87
|
+
steeringAfterTools = null;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
pendingMessages = (await config.getSteeringMessages?.()) || [];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const followUpMessages = (await config.getFollowUpMessages?.()) || [];
|
|
94
|
+
if (followUpMessages.length > 0) {
|
|
95
|
+
pendingMessages = followUpMessages;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
stream.push({ type: "agent_end", messages: newMessages });
|
|
101
|
+
stream.end(newMessages);
|
|
102
|
+
}
|
|
103
|
+
async function streamAssistantResponse(context, config, signal, stream, streamFn) {
|
|
104
|
+
let messages = context.messages;
|
|
105
|
+
if (config.transformContext) {
|
|
106
|
+
messages = await config.transformContext(messages, signal);
|
|
107
|
+
}
|
|
108
|
+
const llmMessages = await config.convertToLlm(messages);
|
|
109
|
+
const llmContext = {
|
|
110
|
+
systemPrompt: context.systemPrompt,
|
|
111
|
+
messages: llmMessages,
|
|
112
|
+
tools: context.tools,
|
|
113
|
+
};
|
|
114
|
+
const streamFunction = streamFn || streamSimple;
|
|
115
|
+
const resolvedApiKey = (config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;
|
|
116
|
+
const response = await streamFunction(config.model, llmContext, {
|
|
117
|
+
...config,
|
|
118
|
+
apiKey: resolvedApiKey,
|
|
119
|
+
signal,
|
|
120
|
+
});
|
|
121
|
+
let partialMessage = null;
|
|
122
|
+
let addedPartial = false;
|
|
123
|
+
for await (const event of response) {
|
|
124
|
+
switch (event.type) {
|
|
125
|
+
case "start":
|
|
126
|
+
partialMessage = event.partial;
|
|
127
|
+
context.messages.push(partialMessage);
|
|
128
|
+
addedPartial = true;
|
|
129
|
+
stream.push({ type: "message_start", message: { ...partialMessage } });
|
|
130
|
+
break;
|
|
131
|
+
case "text_start":
|
|
132
|
+
case "text_delta":
|
|
133
|
+
case "text_end":
|
|
134
|
+
case "thinking_start":
|
|
135
|
+
case "thinking_delta":
|
|
136
|
+
case "thinking_end":
|
|
137
|
+
case "toolcall_start":
|
|
138
|
+
case "toolcall_delta":
|
|
139
|
+
case "toolcall_end":
|
|
140
|
+
if (partialMessage) {
|
|
141
|
+
partialMessage = event.partial;
|
|
142
|
+
context.messages[context.messages.length - 1] = partialMessage;
|
|
143
|
+
stream.push({
|
|
144
|
+
type: "message_update",
|
|
145
|
+
assistantMessageEvent: event,
|
|
146
|
+
message: { ...partialMessage },
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
break;
|
|
150
|
+
case "done":
|
|
151
|
+
case "error": {
|
|
152
|
+
const finalMessage = await response.result();
|
|
153
|
+
if (addedPartial) {
|
|
154
|
+
context.messages[context.messages.length - 1] = finalMessage;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
context.messages.push(finalMessage);
|
|
158
|
+
}
|
|
159
|
+
if (!addedPartial) {
|
|
160
|
+
stream.push({ type: "message_start", message: { ...finalMessage } });
|
|
161
|
+
}
|
|
162
|
+
stream.push({ type: "message_end", message: finalMessage });
|
|
163
|
+
return finalMessage;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return await response.result();
|
|
168
|
+
}
|
|
169
|
+
async function executeToolCalls(tools, assistantMessage, signal, stream, getSteeringMessages) {
|
|
170
|
+
const toolCalls = assistantMessage.content.filter((c) => c.type === "toolCall");
|
|
171
|
+
const results = [];
|
|
172
|
+
let steeringMessages;
|
|
173
|
+
if (PARALLEL_TOOL_EXECUTION && toolCalls.length > 1) {
|
|
174
|
+
return executeToolCallsParallel(tools, toolCalls, signal, stream, getSteeringMessages);
|
|
175
|
+
}
|
|
176
|
+
for (let index = 0; index < toolCalls.length; index++) {
|
|
177
|
+
const toolCall = toolCalls[index];
|
|
178
|
+
const result = await executeSingleToolCall(tools, toolCall, signal, stream);
|
|
179
|
+
results.push(result);
|
|
180
|
+
if (getSteeringMessages) {
|
|
181
|
+
const steering = await getSteeringMessages();
|
|
182
|
+
if (steering.length > 0) {
|
|
183
|
+
steeringMessages = steering;
|
|
184
|
+
const remainingCalls = toolCalls.slice(index + 1);
|
|
185
|
+
for (const skipped of remainingCalls) {
|
|
186
|
+
results.push(skipToolCall(skipped, stream));
|
|
187
|
+
}
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return { toolResults: results, steeringMessages };
|
|
193
|
+
}
|
|
194
|
+
async function executeSingleToolCall(tools, toolCall, signal, stream) {
|
|
195
|
+
const tool = tools?.find((t) => t.name === toolCall.name);
|
|
196
|
+
stream.push({
|
|
197
|
+
type: "tool_execution_start",
|
|
198
|
+
toolCallId: toolCall.id,
|
|
199
|
+
toolName: toolCall.name,
|
|
200
|
+
args: toolCall.arguments,
|
|
201
|
+
});
|
|
202
|
+
let result;
|
|
203
|
+
let isError = false;
|
|
204
|
+
try {
|
|
205
|
+
if (!tool)
|
|
206
|
+
throw new Error(`Tool ${toolCall.name} not found`);
|
|
207
|
+
const validatedArgs = validateToolArguments(tool, toolCall);
|
|
208
|
+
result = await tool.execute(toolCall.id, validatedArgs, signal, (partialResult) => {
|
|
209
|
+
stream.push({
|
|
210
|
+
type: "tool_execution_update",
|
|
211
|
+
toolCallId: toolCall.id,
|
|
212
|
+
toolName: toolCall.name,
|
|
213
|
+
args: toolCall.arguments,
|
|
214
|
+
partialResult,
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
catch (e) {
|
|
219
|
+
result = {
|
|
220
|
+
content: [{ type: "text", text: e instanceof Error ? e.message : String(e) }],
|
|
221
|
+
details: {},
|
|
222
|
+
};
|
|
223
|
+
isError = true;
|
|
224
|
+
}
|
|
225
|
+
stream.push({
|
|
226
|
+
type: "tool_execution_end",
|
|
227
|
+
toolCallId: toolCall.id,
|
|
228
|
+
toolName: toolCall.name,
|
|
229
|
+
result,
|
|
230
|
+
isError,
|
|
231
|
+
});
|
|
232
|
+
const toolResultMessage = {
|
|
233
|
+
role: "toolResult",
|
|
234
|
+
toolCallId: toolCall.id,
|
|
235
|
+
toolName: toolCall.name,
|
|
236
|
+
content: result.content,
|
|
237
|
+
details: result.details,
|
|
238
|
+
isError,
|
|
239
|
+
timestamp: Date.now(),
|
|
240
|
+
};
|
|
241
|
+
stream.push({ type: "message_start", message: toolResultMessage });
|
|
242
|
+
stream.push({ type: "message_end", message: toolResultMessage });
|
|
243
|
+
return toolResultMessage;
|
|
244
|
+
}
|
|
245
|
+
async function executeToolCallsParallel(tools, toolCalls, signal, stream, getSteeringMessages) {
|
|
246
|
+
const results = [];
|
|
247
|
+
let steeringMessages;
|
|
248
|
+
for (const toolCall of toolCalls) {
|
|
249
|
+
stream.push({
|
|
250
|
+
type: "tool_execution_start",
|
|
251
|
+
toolCallId: toolCall.id,
|
|
252
|
+
toolName: toolCall.name,
|
|
253
|
+
args: toolCall.arguments,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
const executing = toolCalls.map(async (toolCall) => {
|
|
257
|
+
const tool = tools?.find((t) => t.name === toolCall.name);
|
|
258
|
+
let result;
|
|
259
|
+
let isError = false;
|
|
260
|
+
try {
|
|
261
|
+
if (!tool)
|
|
262
|
+
throw new Error(`Tool ${toolCall.name} not found`);
|
|
263
|
+
const validatedArgs = validateToolArguments(tool, toolCall);
|
|
264
|
+
result = await tool.execute(toolCall.id, validatedArgs, signal, (partialResult) => {
|
|
265
|
+
stream.push({
|
|
266
|
+
type: "tool_execution_update",
|
|
267
|
+
toolCallId: toolCall.id,
|
|
268
|
+
toolName: toolCall.name,
|
|
269
|
+
args: toolCall.arguments,
|
|
270
|
+
partialResult,
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
catch (e) {
|
|
275
|
+
result = {
|
|
276
|
+
content: [{ type: "text", text: e instanceof Error ? e.message : String(e) }],
|
|
277
|
+
details: {},
|
|
278
|
+
};
|
|
279
|
+
isError = true;
|
|
280
|
+
}
|
|
281
|
+
stream.push({
|
|
282
|
+
type: "tool_execution_end",
|
|
283
|
+
toolCallId: toolCall.id,
|
|
284
|
+
toolName: toolCall.name,
|
|
285
|
+
result,
|
|
286
|
+
isError,
|
|
287
|
+
});
|
|
288
|
+
const toolResultMessage = {
|
|
289
|
+
role: "toolResult",
|
|
290
|
+
toolCallId: toolCall.id,
|
|
291
|
+
toolName: toolCall.name,
|
|
292
|
+
content: result.content,
|
|
293
|
+
details: result.details,
|
|
294
|
+
isError,
|
|
295
|
+
timestamp: Date.now(),
|
|
296
|
+
};
|
|
297
|
+
stream.push({ type: "message_start", message: toolResultMessage });
|
|
298
|
+
stream.push({ type: "message_end", message: toolResultMessage });
|
|
299
|
+
return toolResultMessage;
|
|
300
|
+
});
|
|
301
|
+
const concurrencyLimit = Math.min(MAX_TOOL_CONCURRENCY, toolCalls.length);
|
|
302
|
+
const chunks = [];
|
|
303
|
+
for (let i = 0; i < executing.length; i += concurrencyLimit) {
|
|
304
|
+
chunks.push(executing.slice(i, i + concurrencyLimit));
|
|
305
|
+
}
|
|
306
|
+
for (const chunk of chunks) {
|
|
307
|
+
const chunkResults = await Promise.all(chunk);
|
|
308
|
+
results.push(...chunkResults);
|
|
309
|
+
if (getSteeringMessages) {
|
|
310
|
+
const steering = await getSteeringMessages();
|
|
311
|
+
if (steering.length > 0) {
|
|
312
|
+
steeringMessages = steering;
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return { toolResults: results, steeringMessages };
|
|
318
|
+
}
|
|
319
|
+
function skipToolCall(toolCall, stream) {
|
|
320
|
+
const result = {
|
|
321
|
+
content: [{ type: "text", text: "Skipped due to queued user message." }],
|
|
322
|
+
details: {},
|
|
323
|
+
};
|
|
324
|
+
stream.push({
|
|
325
|
+
type: "tool_execution_start",
|
|
326
|
+
toolCallId: toolCall.id,
|
|
327
|
+
toolName: toolCall.name,
|
|
328
|
+
args: toolCall.arguments,
|
|
329
|
+
});
|
|
330
|
+
stream.push({
|
|
331
|
+
type: "tool_execution_end",
|
|
332
|
+
toolCallId: toolCall.id,
|
|
333
|
+
toolName: toolCall.name,
|
|
334
|
+
result,
|
|
335
|
+
isError: true,
|
|
336
|
+
});
|
|
337
|
+
const toolResultMessage = {
|
|
338
|
+
role: "toolResult",
|
|
339
|
+
toolCallId: toolCall.id,
|
|
340
|
+
toolName: toolCall.name,
|
|
341
|
+
content: result.content,
|
|
342
|
+
details: {},
|
|
343
|
+
isError: true,
|
|
344
|
+
timestamp: Date.now(),
|
|
345
|
+
};
|
|
346
|
+
stream.push({ type: "message_start", message: toolResultMessage });
|
|
347
|
+
stream.push({ type: "message_end", message: toolResultMessage });
|
|
348
|
+
return toolResultMessage;
|
|
349
|
+
}
|
|
350
|
+
//# sourceMappingURL=agent-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-loop.js","sourceRoot":"","sources":["../src/agent-loop.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype AssistantMessage,\n\ttype Context,\n\tEventStream,\n\tstreamSimple,\n\ttype ToolResultMessage,\n\tvalidateToolArguments,\n} from \"@boxiaolanya2008/pi-ai\";\nimport type {\n\tAgentContext,\n\tAgentEvent,\n\tAgentLoopConfig,\n\tAgentMessage,\n\tAgentTool,\n\tAgentToolResult,\n\tStreamFn,\n} from \"./types.js\";\n\nconst PARALLEL_TOOL_EXECUTION = true;\nconst MAX_TOOL_CONCURRENCY = 8;\nexport function agentLoop(\n\tprompts: AgentMessage[],\n\tcontext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal?: AbortSignal,\n\tstreamFn?: StreamFn,\n): EventStream<AgentEvent, AgentMessage[]> {\n\tconst stream = createAgentStream();\n\t(async () => {\n\t\tconst newMessages: AgentMessage[] = [...prompts];\n\t\tconst currentContext: AgentContext = {\n\t\t\t...context,\n\t\t\tmessages: [...context.messages, ...prompts],\n\t\t};\n\t\tstream.push({ type: \"agent_start\" });\n\t\tstream.push({ type: \"turn_start\" });\n\t\tfor (const prompt of prompts) {\n\t\t\tstream.push({ type: \"message_start\", message: prompt });\n\t\t\tstream.push({ type: \"message_end\", message: prompt });\n\t\t}\n\t\tawait runLoop(currentContext, newMessages, config, signal, stream, streamFn);\n\t})();\n\treturn stream;\n}\nexport function agentLoopContinue(\n\tcontext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal?: AbortSignal,\n\tstreamFn?: StreamFn,\n): EventStream<AgentEvent, AgentMessage[]> {\n\tif (context.messages.length === 0) {\n\t\tthrow new Error(\"Cannot continue: no messages in context\");\n\t}\n\tif (context.messages[context.messages.length - 1].role === \"assistant\") {\n\t\tthrow new Error(\"Cannot continue from message role: assistant\");\n\t}\n\tconst stream = createAgentStream();\n\t(async () => {\n\t\tconst newMessages: AgentMessage[] = [];\n\t\tconst currentContext: AgentContext = { ...context };\n\t\tstream.push({ type: \"agent_start\" });\n\t\tstream.push({ type: \"turn_start\" });\n\t\tawait runLoop(currentContext, newMessages, config, signal, stream, streamFn);\n\t})();\n\treturn stream;\n}\nfunction createAgentStream(): EventStream<AgentEvent, AgentMessage[]> {\n\treturn new EventStream<AgentEvent, AgentMessage[]>(\n\t\t(event: AgentEvent) => event.type === \"agent_end\",\n\t\t(event: AgentEvent) => (event.type === \"agent_end\" ? event.messages : []),\n\t);\n}\nasync function runLoop(\n\tcurrentContext: AgentContext,\n\tnewMessages: AgentMessage[],\n\tconfig: AgentLoopConfig,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, AgentMessage[]>,\n\tstreamFn?: StreamFn,\n): Promise<void> {\n\tlet firstTurn = true;\n\tlet pendingMessages: AgentMessage[] = (await config.getSteeringMessages?.()) || [];\n\twhile (true) {\n\t\tlet hasMoreToolCalls = true;\n\t\tlet steeringAfterTools: AgentMessage[] | null = null;\n\t\twhile (hasMoreToolCalls || pendingMessages.length > 0) {\n\t\t\tif (!firstTurn) {\n\t\t\t\tstream.push({ type: \"turn_start\" });\n\t\t\t} else {\n\t\t\t\tfirstTurn = false;\n\t\t\t}\n\t\t\tif (pendingMessages.length > 0) {\n\t\t\t\tfor (const message of pendingMessages) {\n\t\t\t\t\tstream.push({ type: \"message_start\", message });\n\t\t\t\t\tstream.push({ type: \"message_end\", message });\n\t\t\t\t\tcurrentContext.messages.push(message);\n\t\t\t\t\tnewMessages.push(message);\n\t\t\t\t}\n\t\t\t\tpendingMessages = [];\n\t\t\t}\n\t\t\tconst message = await streamAssistantResponse(currentContext, config, signal, stream, streamFn);\n\t\t\tnewMessages.push(message);\n\t\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\t\tstream.push({ type: \"turn_end\", message, toolResults: [] });\n\t\t\t\tstream.push({ type: \"agent_end\", messages: newMessages });\n\t\t\t\tstream.end(newMessages);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst toolCalls = message.content.filter((c) => c.type === \"toolCall\");\n\t\t\thasMoreToolCalls = toolCalls.length > 0;\n\t\t\tconst toolResults: ToolResultMessage[] = [];\n\t\t\tif (hasMoreToolCalls) {\n\t\t\t\tconst toolExecution = await executeToolCalls(\n\t\t\t\t\tcurrentContext.tools,\n\t\t\t\t\tmessage,\n\t\t\t\t\tsignal,\n\t\t\t\t\tstream,\n\t\t\t\t\tconfig.getSteeringMessages,\n\t\t\t\t);\n\t\t\t\ttoolResults.push(...toolExecution.toolResults);\n\t\t\t\tsteeringAfterTools = toolExecution.steeringMessages ?? null;\n\t\t\t\tfor (const result of toolResults) {\n\t\t\t\t\tcurrentContext.messages.push(result);\n\t\t\t\t\tnewMessages.push(result);\n\t\t\t\t}\n\t\t\t}\n\t\t\tstream.push({ type: \"turn_end\", message, toolResults });\n\t\t\tif (steeringAfterTools && steeringAfterTools.length > 0) {\n\t\t\t\tpendingMessages = steeringAfterTools;\n\t\t\t\tsteeringAfterTools = null;\n\t\t\t} else {\n\t\t\t\tpendingMessages = (await config.getSteeringMessages?.()) || [];\n\t\t\t}\n\t\t}\n\t\tconst followUpMessages = (await config.getFollowUpMessages?.()) || [];\n\t\tif (followUpMessages.length > 0) {\n\t\t\tpendingMessages = followUpMessages;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\tstream.push({ type: \"agent_end\", messages: newMessages });\n\tstream.end(newMessages);\n}\nasync function streamAssistantResponse(\n\tcontext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, AgentMessage[]>,\n\tstreamFn?: StreamFn,\n): Promise<AssistantMessage> {\n\tlet messages = context.messages;\n\tif (config.transformContext) {\n\t\tmessages = await config.transformContext(messages, signal);\n\t}\n\tconst llmMessages = await config.convertToLlm(messages);\n\tconst llmContext: Context = {\n\t\tsystemPrompt: context.systemPrompt,\n\t\tmessages: llmMessages,\n\t\ttools: context.tools,\n\t};\n\tconst streamFunction = streamFn || streamSimple;\n\tconst resolvedApiKey =\n\t\t(config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;\n\tconst response = await streamFunction(config.model, llmContext, {\n\t\t...config,\n\t\tapiKey: resolvedApiKey,\n\t\tsignal,\n\t});\n\tlet partialMessage: AssistantMessage | null = null;\n\tlet addedPartial = false;\n\tfor await (const event of response) {\n\t\tswitch (event.type) {\n\t\t\tcase \"start\":\n\t\t\t\tpartialMessage = event.partial;\n\t\t\t\tcontext.messages.push(partialMessage);\n\t\t\t\taddedPartial = true;\n\t\t\t\tstream.push({ type: \"message_start\", message: { ...partialMessage } });\n\t\t\t\tbreak;\n\t\t\tcase \"text_start\":\n\t\t\tcase \"text_delta\":\n\t\t\tcase \"text_end\":\n\t\t\tcase \"thinking_start\":\n\t\t\tcase \"thinking_delta\":\n\t\t\tcase \"thinking_end\":\n\t\t\tcase \"toolcall_start\":\n\t\t\tcase \"toolcall_delta\":\n\t\t\tcase \"toolcall_end\":\n\t\t\t\tif (partialMessage) {\n\t\t\t\t\tpartialMessage = event.partial;\n\t\t\t\t\tcontext.messages[context.messages.length - 1] = partialMessage;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"message_update\",\n\t\t\t\t\t\tassistantMessageEvent: event,\n\t\t\t\t\t\tmessage: { ...partialMessage },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"done\":\n\t\t\tcase \"error\": {\n\t\t\t\tconst finalMessage = await response.result();\n\t\t\t\tif (addedPartial) {\n\t\t\t\t\tcontext.messages[context.messages.length - 1] = finalMessage;\n\t\t\t\t} else {\n\t\t\t\t\tcontext.messages.push(finalMessage);\n\t\t\t\t}\n\t\t\t\tif (!addedPartial) {\n\t\t\t\t\tstream.push({ type: \"message_start\", message: { ...finalMessage } });\n\t\t\t\t}\n\t\t\t\tstream.push({ type: \"message_end\", message: finalMessage });\n\t\t\t\treturn finalMessage;\n\t\t\t}\n\t\t}\n\t}\n\treturn await response.result();\n}\nasync function executeToolCalls(\n\ttools: AgentTool<any>[] | undefined,\n\tassistantMessage: AssistantMessage,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, AgentMessage[]>,\n\tgetSteeringMessages?: AgentLoopConfig[\"getSteeringMessages\"],\n): Promise<{ toolResults: ToolResultMessage[]; steeringMessages?: AgentMessage[] }> {\n\tconst toolCalls = assistantMessage.content.filter((c) => c.type === \"toolCall\");\n\tconst results: ToolResultMessage[] = [];\n\tlet steeringMessages: AgentMessage[] | undefined;\n\tif (PARALLEL_TOOL_EXECUTION && toolCalls.length > 1) {\n\t\treturn executeToolCallsParallel(tools, toolCalls, signal, stream, getSteeringMessages);\n\t}\n\tfor (let index = 0; index < toolCalls.length; index++) {\n\t\tconst toolCall = toolCalls[index];\n\t\tconst result = await executeSingleToolCall(tools, toolCall, signal, stream);\n\t\tresults.push(result);\n\t\tif (getSteeringMessages) {\n\t\t\tconst steering = await getSteeringMessages();\n\t\t\tif (steering.length > 0) {\n\t\t\t\tsteeringMessages = steering;\n\t\t\t\tconst remainingCalls = toolCalls.slice(index + 1);\n\t\t\t\tfor (const skipped of remainingCalls) {\n\t\t\t\t\tresults.push(skipToolCall(skipped, stream));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn { toolResults: results, steeringMessages };\n}\nasync function executeSingleToolCall(\n\ttools: AgentTool<any>[] | undefined,\n\ttoolCall: Extract<AssistantMessage[\"content\"][number], { type: \"toolCall\" }>,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, AgentMessage[]>,\n): Promise<ToolResultMessage> {\n\tconst tool = tools?.find((t) => t.name === toolCall.name);\n\tstream.push({\n\t\ttype: \"tool_execution_start\",\n\t\ttoolCallId: toolCall.id,\n\t\ttoolName: toolCall.name,\n\t\targs: toolCall.arguments,\n\t});\n\tlet result: AgentToolResult<any>;\n\tlet isError = false;\n\ttry {\n\t\tif (!tool) throw new Error(`Tool ${toolCall.name} not found`);\n\t\tconst validatedArgs = validateToolArguments(tool, toolCall);\n\t\tresult = await tool.execute(toolCall.id, validatedArgs, signal, (partialResult) => {\n\t\t\tstream.push({\n\t\t\t\ttype: \"tool_execution_update\",\n\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\ttoolName: toolCall.name,\n\t\t\t\targs: toolCall.arguments,\n\t\t\t\tpartialResult,\n\t\t\t});\n\t\t});\n\t} catch (e) {\n\t\tresult = {\n\t\t\tcontent: [{ type: \"text\", text: e instanceof Error ? e.message : String(e) }],\n\t\t\tdetails: {},\n\t\t};\n\t\tisError = true;\n\t}\n\tstream.push({\n\t\ttype: \"tool_execution_end\",\n\t\ttoolCallId: toolCall.id,\n\t\ttoolName: toolCall.name,\n\t\tresult,\n\t\tisError,\n\t});\n\tconst toolResultMessage: ToolResultMessage = {\n\t\trole: \"toolResult\",\n\t\ttoolCallId: toolCall.id,\n\t\ttoolName: toolCall.name,\n\t\tcontent: result.content,\n\t\tdetails: result.details,\n\t\tisError,\n\t\ttimestamp: Date.now(),\n\t};\n\tstream.push({ type: \"message_start\", message: toolResultMessage });\n\tstream.push({ type: \"message_end\", message: toolResultMessage });\n\treturn toolResultMessage;\n}\nasync function executeToolCallsParallel(\n\ttools: AgentTool<any>[] | undefined,\n\ttoolCalls: Extract<AssistantMessage[\"content\"][number], { type: \"toolCall\" }>[],\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, AgentMessage[]>,\n\tgetSteeringMessages?: AgentLoopConfig[\"getSteeringMessages\"],\n): Promise<{ toolResults: ToolResultMessage[]; steeringMessages?: AgentMessage[] }> {\n\tconst results: ToolResultMessage[] = [];\n\tlet steeringMessages: AgentMessage[] | undefined;\n\tfor (const toolCall of toolCalls) {\n\t\tstream.push({\n\t\t\ttype: \"tool_execution_start\",\n\t\t\ttoolCallId: toolCall.id,\n\t\t\ttoolName: toolCall.name,\n\t\t\targs: toolCall.arguments,\n\t\t});\n\t}\n\tconst executing = toolCalls.map(async (toolCall) => {\n\t\tconst tool = tools?.find((t) => t.name === toolCall.name);\n\t\tlet result: AgentToolResult<any>;\n\t\tlet isError = false;\n\t\ttry {\n\t\t\tif (!tool) throw new Error(`Tool ${toolCall.name} not found`);\n\t\t\tconst validatedArgs = validateToolArguments(tool, toolCall);\n\t\t\tresult = await tool.execute(toolCall.id, validatedArgs, signal, (partialResult) => {\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"tool_execution_update\",\n\t\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\t\ttoolName: toolCall.name,\n\t\t\t\t\targs: toolCall.arguments,\n\t\t\t\t\tpartialResult,\n\t\t\t\t});\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tresult = {\n\t\t\t\tcontent: [{ type: \"text\", text: e instanceof Error ? e.message : String(e) }],\n\t\t\t\tdetails: {},\n\t\t\t};\n\t\t\tisError = true;\n\t\t}\n\t\tstream.push({\n\t\t\ttype: \"tool_execution_end\",\n\t\t\ttoolCallId: toolCall.id,\n\t\t\ttoolName: toolCall.name,\n\t\t\tresult,\n\t\t\tisError,\n\t\t});\n\t\tconst toolResultMessage: ToolResultMessage = {\n\t\t\trole: \"toolResult\",\n\t\t\ttoolCallId: toolCall.id,\n\t\t\ttoolName: toolCall.name,\n\t\t\tcontent: result.content,\n\t\t\tdetails: result.details,\n\t\t\tisError,\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\t\tstream.push({ type: \"message_start\", message: toolResultMessage });\n\t\tstream.push({ type: \"message_end\", message: toolResultMessage });\n\t\treturn toolResultMessage;\n\t});\n\tconst concurrencyLimit = Math.min(MAX_TOOL_CONCURRENCY, toolCalls.length);\n\tconst chunks: Promise<ToolResultMessage>[][] = [];\n\tfor (let i = 0; i < executing.length; i += concurrencyLimit) {\n\t\tchunks.push(executing.slice(i, i + concurrencyLimit));\n\t}\n\tfor (const chunk of chunks) {\n\t\tconst chunkResults = await Promise.all(chunk);\n\t\tresults.push(...chunkResults);\n\t\tif (getSteeringMessages) {\n\t\t\tconst steering = await getSteeringMessages();\n\t\t\tif (steering.length > 0) {\n\t\t\t\tsteeringMessages = steering;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn { toolResults: results, steeringMessages };\n}\nfunction skipToolCall(\n\ttoolCall: Extract<AssistantMessage[\"content\"][number], { type: \"toolCall\" }>,\n\tstream: EventStream<AgentEvent, AgentMessage[]>,\n): ToolResultMessage {\n\tconst result: AgentToolResult<any> = {\n\t\tcontent: [{ type: \"text\", text: \"Skipped due to queued user message.\" }],\n\t\tdetails: {},\n\t};\n\tstream.push({\n\t\ttype: \"tool_execution_start\",\n\t\ttoolCallId: toolCall.id,\n\t\ttoolName: toolCall.name,\n\t\targs: toolCall.arguments,\n\t});\n\tstream.push({\n\t\ttype: \"tool_execution_end\",\n\t\ttoolCallId: toolCall.id,\n\t\ttoolName: toolCall.name,\n\t\tresult,\n\t\tisError: true,\n\t});\n\tconst toolResultMessage: ToolResultMessage = {\n\t\trole: \"toolResult\",\n\t\ttoolCallId: toolCall.id,\n\t\ttoolName: toolCall.name,\n\t\tcontent: result.content,\n\t\tdetails: {},\n\t\tisError: true,\n\t\ttimestamp: Date.now(),\n\t};\n\tstream.push({ type: \"message_start\", message: toolResultMessage });\n\tstream.push({ type: \"message_end\", message: toolResultMessage });\n\treturn toolResultMessage;\n}\n"]}
|
package/dist/agent.d.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent class that uses the agent-loop directly.
|
|
3
|
+
* No transport abstraction - calls streamSimple via the loop.
|
|
4
|
+
*/
|
|
5
|
+
import { type ImageContent, type Message, type Model, type SimpleStreamOptions, type ThinkingBudgets, type Transport } from "@boxiaolanya2008/pi-ai";
|
|
6
|
+
import type { AgentEvent, AgentMessage, AgentState, AgentTool, StreamFn, ThinkingLevel } from "./types.js";
|
|
7
|
+
export interface AgentOptions {
|
|
8
|
+
initialState?: Partial<AgentState>;
|
|
9
|
+
/**
|
|
10
|
+
* Converts AgentMessage[] to LLM-compatible Message[] before each LLM call.
|
|
11
|
+
* Default filters to user/assistant/toolResult and converts attachments.
|
|
12
|
+
*/
|
|
13
|
+
convertToLlm?: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Optional transform applied to context before convertToLlm.
|
|
16
|
+
* Use for context pruning, injecting external context, etc.
|
|
17
|
+
*/
|
|
18
|
+
transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;
|
|
19
|
+
/**
|
|
20
|
+
* Steering mode: "all" = send all steering messages at once, "one-at-a-time" = one per turn
|
|
21
|
+
*/
|
|
22
|
+
steeringMode?: "all" | "one-at-a-time";
|
|
23
|
+
/**
|
|
24
|
+
* Follow-up mode: "all" = send all follow-up messages at once, "one-at-a-time" = one per turn
|
|
25
|
+
*/
|
|
26
|
+
followUpMode?: "all" | "one-at-a-time";
|
|
27
|
+
/**
|
|
28
|
+
* Custom stream function (for proxy backends, etc.). Default uses streamSimple.
|
|
29
|
+
*/
|
|
30
|
+
streamFn?: StreamFn;
|
|
31
|
+
/**
|
|
32
|
+
* Optional session identifier forwarded to LLM providers.
|
|
33
|
+
* Used by providers that support session-based caching (e.g., OpenAI Codex).
|
|
34
|
+
*/
|
|
35
|
+
sessionId?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Resolves an API key dynamically for each LLM call.
|
|
38
|
+
* Useful for expiring tokens (e.g., GitHub Copilot OAuth).
|
|
39
|
+
*/
|
|
40
|
+
getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Inspect or replace provider payloads before they are sent.
|
|
43
|
+
*/
|
|
44
|
+
onPayload?: SimpleStreamOptions["onPayload"];
|
|
45
|
+
/**
|
|
46
|
+
* Custom token budgets for thinking levels (token-based providers only).
|
|
47
|
+
*/
|
|
48
|
+
thinkingBudgets?: ThinkingBudgets;
|
|
49
|
+
/**
|
|
50
|
+
* Preferred transport for providers that support multiple transports.
|
|
51
|
+
*/
|
|
52
|
+
transport?: Transport;
|
|
53
|
+
/**
|
|
54
|
+
* Maximum delay in milliseconds to wait for a retry when the server requests a long wait.
|
|
55
|
+
* If the server's requested delay exceeds this value, the request fails immediately,
|
|
56
|
+
* allowing higher-level retry logic to handle it with user visibility.
|
|
57
|
+
* Default: 60000 (60 seconds). Set to 0 to disable the cap.
|
|
58
|
+
*/
|
|
59
|
+
maxRetryDelayMs?: number;
|
|
60
|
+
}
|
|
61
|
+
export declare class Agent {
|
|
62
|
+
private _state;
|
|
63
|
+
private listeners;
|
|
64
|
+
private abortController?;
|
|
65
|
+
private convertToLlm;
|
|
66
|
+
private transformContext?;
|
|
67
|
+
private steeringQueue;
|
|
68
|
+
private followUpQueue;
|
|
69
|
+
private steeringMode;
|
|
70
|
+
private followUpMode;
|
|
71
|
+
streamFn: StreamFn;
|
|
72
|
+
private _sessionId?;
|
|
73
|
+
getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
|
|
74
|
+
private _onPayload?;
|
|
75
|
+
private runningPrompt?;
|
|
76
|
+
private resolveRunningPrompt?;
|
|
77
|
+
private _thinkingBudgets?;
|
|
78
|
+
private _transport;
|
|
79
|
+
private _maxRetryDelayMs?;
|
|
80
|
+
constructor(opts?: AgentOptions);
|
|
81
|
+
/**
|
|
82
|
+
* Get the current session ID used for provider caching.
|
|
83
|
+
*/
|
|
84
|
+
get sessionId(): string | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* Set the session ID for provider caching.
|
|
87
|
+
* Call this when switching sessions (new session, branch, resume).
|
|
88
|
+
*/
|
|
89
|
+
set sessionId(value: string | undefined);
|
|
90
|
+
/**
|
|
91
|
+
* Get the current thinking budgets.
|
|
92
|
+
*/
|
|
93
|
+
get thinkingBudgets(): ThinkingBudgets | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* Set custom thinking budgets for token-based providers.
|
|
96
|
+
*/
|
|
97
|
+
set thinkingBudgets(value: ThinkingBudgets | undefined);
|
|
98
|
+
/**
|
|
99
|
+
* Get the current preferred transport.
|
|
100
|
+
*/
|
|
101
|
+
get transport(): Transport;
|
|
102
|
+
/**
|
|
103
|
+
* Set the preferred transport.
|
|
104
|
+
*/
|
|
105
|
+
setTransport(value: Transport): void;
|
|
106
|
+
/**
|
|
107
|
+
* Get the current max retry delay in milliseconds.
|
|
108
|
+
*/
|
|
109
|
+
get maxRetryDelayMs(): number | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* Set the maximum delay to wait for server-requested retries.
|
|
112
|
+
* Set to 0 to disable the cap.
|
|
113
|
+
*/
|
|
114
|
+
set maxRetryDelayMs(value: number | undefined);
|
|
115
|
+
get state(): AgentState;
|
|
116
|
+
subscribe(fn: (e: AgentEvent) => void): () => void;
|
|
117
|
+
setSystemPrompt(v: string): void;
|
|
118
|
+
setModel(m: Model<any>): void;
|
|
119
|
+
setThinkingLevel(l: ThinkingLevel): void;
|
|
120
|
+
setSteeringMode(mode: "all" | "one-at-a-time"): void;
|
|
121
|
+
getSteeringMode(): "all" | "one-at-a-time";
|
|
122
|
+
setFollowUpMode(mode: "all" | "one-at-a-time"): void;
|
|
123
|
+
getFollowUpMode(): "all" | "one-at-a-time";
|
|
124
|
+
setTools(t: AgentTool<any>[]): void;
|
|
125
|
+
replaceMessages(ms: AgentMessage[]): void;
|
|
126
|
+
appendMessage(m: AgentMessage): void;
|
|
127
|
+
/**
|
|
128
|
+
* Queue a steering message to interrupt the agent mid-run.
|
|
129
|
+
* Delivered after current tool execution, skips remaining tools.
|
|
130
|
+
*/
|
|
131
|
+
steer(m: AgentMessage): void;
|
|
132
|
+
/**
|
|
133
|
+
* Queue a follow-up message to be processed after the agent finishes.
|
|
134
|
+
* Delivered only when agent has no more tool calls or steering messages.
|
|
135
|
+
*/
|
|
136
|
+
followUp(m: AgentMessage): void;
|
|
137
|
+
clearSteeringQueue(): void;
|
|
138
|
+
clearFollowUpQueue(): void;
|
|
139
|
+
clearAllQueues(): void;
|
|
140
|
+
hasQueuedMessages(): boolean;
|
|
141
|
+
private dequeueSteeringMessages;
|
|
142
|
+
private dequeueFollowUpMessages;
|
|
143
|
+
clearMessages(): void;
|
|
144
|
+
abort(): void;
|
|
145
|
+
waitForIdle(): Promise<void>;
|
|
146
|
+
reset(): void;
|
|
147
|
+
/** Send a prompt with an AgentMessage */
|
|
148
|
+
prompt(message: AgentMessage | AgentMessage[]): Promise<void>;
|
|
149
|
+
prompt(input: string, images?: ImageContent[]): Promise<void>;
|
|
150
|
+
/**
|
|
151
|
+
* Continue from current context (used for retries and resuming queued messages).
|
|
152
|
+
*/
|
|
153
|
+
continue(): Promise<void>;
|
|
154
|
+
private _runLoop;
|
|
155
|
+
private emit;
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Agent class that uses the agent-loop directly.\n * No transport abstraction - calls streamSimple via the loop.\n */\n\nimport {\n\tgetModel,\n\ttype ImageContent,\n\ttype Message,\n\ttype Model,\n\ttype SimpleStreamOptions,\n\tstreamSimple,\n\ttype TextContent,\n\ttype ThinkingBudgets,\n\ttype Transport,\n} from \"@boxiaolanya2008/pi-ai\";\nimport { agentLoop, agentLoopContinue } from \"./agent-loop.js\";\nimport type {\n\tAgentContext,\n\tAgentEvent,\n\tAgentLoopConfig,\n\tAgentMessage,\n\tAgentState,\n\tAgentTool,\n\tStreamFn,\n\tThinkingLevel,\n} from \"./types.js\";\n\n/**\n * Default convertToLlm: Keep only LLM-compatible messages, convert attachments.\n */\nfunction defaultConvertToLlm(messages: AgentMessage[]): Message[] {\n\treturn messages.filter((m) => m.role === \"user\" || m.role === \"assistant\" || m.role === \"toolResult\");\n}\n\nexport interface AgentOptions {\n\tinitialState?: Partial<AgentState>;\n\n\t/**\n\t * Converts AgentMessage[] to LLM-compatible Message[] before each LLM call.\n\t * Default filters to user/assistant/toolResult and converts attachments.\n\t */\n\tconvertToLlm?: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;\n\n\t/**\n\t * Optional transform applied to context before convertToLlm.\n\t * Use for context pruning, injecting external context, etc.\n\t */\n\ttransformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;\n\n\t/**\n\t * Steering mode: \"all\" = send all steering messages at once, \"one-at-a-time\" = one per turn\n\t */\n\tsteeringMode?: \"all\" | \"one-at-a-time\";\n\n\t/**\n\t * Follow-up mode: \"all\" = send all follow-up messages at once, \"one-at-a-time\" = one per turn\n\t */\n\tfollowUpMode?: \"all\" | \"one-at-a-time\";\n\n\t/**\n\t * Custom stream function (for proxy backends, etc.). Default uses streamSimple.\n\t */\n\tstreamFn?: StreamFn;\n\n\t/**\n\t * Optional session identifier forwarded to LLM providers.\n\t * Used by providers that support session-based caching (e.g., OpenAI Codex).\n\t */\n\tsessionId?: string;\n\n\t/**\n\t * Resolves an API key dynamically for each LLM call.\n\t * Useful for expiring tokens (e.g., GitHub Copilot OAuth).\n\t */\n\tgetApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\n\t/**\n\t * Inspect or replace provider payloads before they are sent.\n\t */\n\tonPayload?: SimpleStreamOptions[\"onPayload\"];\n\n\t/**\n\t * Custom token budgets for thinking levels (token-based providers only).\n\t */\n\tthinkingBudgets?: ThinkingBudgets;\n\n\t/**\n\t * Preferred transport for providers that support multiple transports.\n\t */\n\ttransport?: Transport;\n\n\t/**\n\t * Maximum delay in milliseconds to wait for a retry when the server requests a long wait.\n\t * If the server's requested delay exceeds this value, the request fails immediately,\n\t * allowing higher-level retry logic to handle it with user visibility.\n\t * Default: 60000 (60 seconds). Set to 0 to disable the cap.\n\t */\n\tmaxRetryDelayMs?: number;\n}\n\nexport class Agent {\n\tprivate _state: AgentState = {\n\t\tsystemPrompt: \"\",\n\t\tmodel: getModel(\"openai\", \"gpt-4o-mini\")!,\n\t\tthinkingLevel: \"off\",\n\t\ttools: [],\n\t\tmessages: [],\n\t\tisStreaming: false,\n\t\tstreamMessage: null,\n\t\tpendingToolCalls: new Set<string>(),\n\t\terror: undefined,\n\t};\n\n\tprivate listeners = new Set<(e: AgentEvent) => void>();\n\tprivate abortController?: AbortController;\n\tprivate convertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;\n\tprivate transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;\n\tprivate steeringQueue: AgentMessage[] = [];\n\tprivate followUpQueue: AgentMessage[] = [];\n\tprivate steeringMode: \"all\" | \"one-at-a-time\";\n\tprivate followUpMode: \"all\" | \"one-at-a-time\";\n\tpublic streamFn: StreamFn;\n\tprivate _sessionId?: string;\n\tpublic getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\tprivate _onPayload?: SimpleStreamOptions[\"onPayload\"];\n\tprivate runningPrompt?: Promise<void>;\n\tprivate resolveRunningPrompt?: () => void;\n\tprivate _thinkingBudgets?: ThinkingBudgets;\n\tprivate _transport: Transport;\n\tprivate _maxRetryDelayMs?: number;\n\n\tconstructor(opts: AgentOptions = {}) {\n\t\tthis._state = { ...this._state, ...opts.initialState };\n\t\tthis.convertToLlm = opts.convertToLlm || defaultConvertToLlm;\n\t\tthis.transformContext = opts.transformContext;\n\t\tthis.steeringMode = opts.steeringMode || \"one-at-a-time\";\n\t\tthis.followUpMode = opts.followUpMode || \"one-at-a-time\";\n\t\tthis.streamFn = opts.streamFn || streamSimple;\n\t\tthis._sessionId = opts.sessionId;\n\t\tthis.getApiKey = opts.getApiKey;\n\t\tthis._onPayload = opts.onPayload;\n\t\tthis._thinkingBudgets = opts.thinkingBudgets;\n\t\tthis._transport = opts.transport ?? \"sse\";\n\t\tthis._maxRetryDelayMs = opts.maxRetryDelayMs;\n\t}\n\n\t/**\n\t * Get the current session ID used for provider caching.\n\t */\n\tget sessionId(): string | undefined {\n\t\treturn this._sessionId;\n\t}\n\n\t/**\n\t * Set the session ID for provider caching.\n\t * Call this when switching sessions (new session, branch, resume).\n\t */\n\tset sessionId(value: string | undefined) {\n\t\tthis._sessionId = value;\n\t}\n\n\t/**\n\t * Get the current thinking budgets.\n\t */\n\tget thinkingBudgets(): ThinkingBudgets | undefined {\n\t\treturn this._thinkingBudgets;\n\t}\n\n\t/**\n\t * Set custom thinking budgets for token-based providers.\n\t */\n\tset thinkingBudgets(value: ThinkingBudgets | undefined) {\n\t\tthis._thinkingBudgets = value;\n\t}\n\n\t/**\n\t * Get the current preferred transport.\n\t */\n\tget transport(): Transport {\n\t\treturn this._transport;\n\t}\n\n\t/**\n\t * Set the preferred transport.\n\t */\n\tsetTransport(value: Transport) {\n\t\tthis._transport = value;\n\t}\n\n\t/**\n\t * Get the current max retry delay in milliseconds.\n\t */\n\tget maxRetryDelayMs(): number | undefined {\n\t\treturn this._maxRetryDelayMs;\n\t}\n\n\t/**\n\t * Set the maximum delay to wait for server-requested retries.\n\t * Set to 0 to disable the cap.\n\t */\n\tset maxRetryDelayMs(value: number | undefined) {\n\t\tthis._maxRetryDelayMs = value;\n\t}\n\n\tget state(): AgentState {\n\t\treturn this._state;\n\t}\n\n\tsubscribe(fn: (e: AgentEvent) => void): () => void {\n\t\tthis.listeners.add(fn);\n\t\treturn () => this.listeners.delete(fn);\n\t}\n\n\t// State mutators\n\tsetSystemPrompt(v: string) {\n\t\tthis._state.systemPrompt = v;\n\t}\n\n\tsetModel(m: Model<any>) {\n\t\tthis._state.model = m;\n\t}\n\n\tsetThinkingLevel(l: ThinkingLevel) {\n\t\tthis._state.thinkingLevel = l;\n\t}\n\n\tsetSteeringMode(mode: \"all\" | \"one-at-a-time\") {\n\t\tthis.steeringMode = mode;\n\t}\n\n\tgetSteeringMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.steeringMode;\n\t}\n\n\tsetFollowUpMode(mode: \"all\" | \"one-at-a-time\") {\n\t\tthis.followUpMode = mode;\n\t}\n\n\tgetFollowUpMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.followUpMode;\n\t}\n\n\tsetTools(t: AgentTool<any>[]) {\n\t\tthis._state.tools = t;\n\t}\n\n\treplaceMessages(ms: AgentMessage[]) {\n\t\tthis._state.messages = ms.slice();\n\t}\n\n\tappendMessage(m: AgentMessage) {\n\t\tthis._state.messages = [...this._state.messages, m];\n\t}\n\n\t/**\n\t * Queue a steering message to interrupt the agent mid-run.\n\t * Delivered after current tool execution, skips remaining tools.\n\t */\n\tsteer(m: AgentMessage) {\n\t\tthis.steeringQueue.push(m);\n\t}\n\n\t/**\n\t * Queue a follow-up message to be processed after the agent finishes.\n\t * Delivered only when agent has no more tool calls or steering messages.\n\t */\n\tfollowUp(m: AgentMessage) {\n\t\tthis.followUpQueue.push(m);\n\t}\n\n\tclearSteeringQueue() {\n\t\tthis.steeringQueue = [];\n\t}\n\n\tclearFollowUpQueue() {\n\t\tthis.followUpQueue = [];\n\t}\n\n\tclearAllQueues() {\n\t\tthis.steeringQueue = [];\n\t\tthis.followUpQueue = [];\n\t}\n\n\thasQueuedMessages(): boolean {\n\t\treturn this.steeringQueue.length > 0 || this.followUpQueue.length > 0;\n\t}\n\n\tprivate dequeueSteeringMessages(): AgentMessage[] {\n\t\tif (this.steeringMode === \"one-at-a-time\") {\n\t\t\tif (this.steeringQueue.length > 0) {\n\t\t\t\tconst first = this.steeringQueue[0];\n\t\t\t\tthis.steeringQueue = this.steeringQueue.slice(1);\n\t\t\t\treturn [first];\n\t\t\t}\n\t\t\treturn [];\n\t\t}\n\n\t\tconst steering = this.steeringQueue.slice();\n\t\tthis.steeringQueue = [];\n\t\treturn steering;\n\t}\n\n\tprivate dequeueFollowUpMessages(): AgentMessage[] {\n\t\tif (this.followUpMode === \"one-at-a-time\") {\n\t\t\tif (this.followUpQueue.length > 0) {\n\t\t\t\tconst first = this.followUpQueue[0];\n\t\t\t\tthis.followUpQueue = this.followUpQueue.slice(1);\n\t\t\t\treturn [first];\n\t\t\t}\n\t\t\treturn [];\n\t\t}\n\n\t\tconst followUp = this.followUpQueue.slice();\n\t\tthis.followUpQueue = [];\n\t\treturn followUp;\n\t}\n\n\tclearMessages() {\n\t\tthis._state.messages = [];\n\t}\n\n\tabort() {\n\t\tthis.abortController?.abort();\n\t}\n\n\twaitForIdle(): Promise<void> {\n\t\treturn this.runningPrompt ?? Promise.resolve();\n\t}\n\n\treset() {\n\t\tthis._state.messages = [];\n\t\tthis._state.isStreaming = false;\n\t\tthis._state.streamMessage = null;\n\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\tthis._state.error = undefined;\n\t\tthis.steeringQueue = [];\n\t\tthis.followUpQueue = [];\n\t}\n\n\t/** Send a prompt with an AgentMessage */\n\tasync prompt(message: AgentMessage | AgentMessage[]): Promise<void>;\n\tasync prompt(input: string, images?: ImageContent[]): Promise<void>;\n\tasync prompt(input: string | AgentMessage | AgentMessage[], images?: ImageContent[]) {\n\t\tif (this._state.isStreaming) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Agent is already processing a prompt. Use steer() or followUp() to queue messages, or wait for completion.\",\n\t\t\t);\n\t\t}\n\n\t\tconst model = this._state.model;\n\t\tif (!model) throw new Error(\"No model configured\");\n\n\t\tlet msgs: AgentMessage[];\n\n\t\tif (Array.isArray(input)) {\n\t\t\tmsgs = input;\n\t\t} else if (typeof input === \"string\") {\n\t\t\tconst content: Array<TextContent | ImageContent> = [{ type: \"text\", text: input }];\n\t\t\tif (images && images.length > 0) {\n\t\t\t\tcontent.push(...images);\n\t\t\t}\n\t\t\tmsgs = [\n\t\t\t\t{\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t},\n\t\t\t];\n\t\t} else {\n\t\t\tmsgs = [input];\n\t\t}\n\n\t\tawait this._runLoop(msgs);\n\t}\n\n\t/**\n\t * Continue from current context (used for retries and resuming queued messages).\n\t */\n\tasync continue() {\n\t\tif (this._state.isStreaming) {\n\t\t\tthrow new Error(\"Agent is already processing. Wait for completion before continuing.\");\n\t\t}\n\n\t\tconst messages = this._state.messages;\n\t\tif (messages.length === 0) {\n\t\t\tthrow new Error(\"No messages to continue from\");\n\t\t}\n\t\tif (messages[messages.length - 1].role === \"assistant\") {\n\t\t\tconst queuedSteering = this.dequeueSteeringMessages();\n\t\t\tif (queuedSteering.length > 0) {\n\t\t\t\tawait this._runLoop(queuedSteering, { skipInitialSteeringPoll: true });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst queuedFollowUp = this.dequeueFollowUpMessages();\n\t\t\tif (queuedFollowUp.length > 0) {\n\t\t\t\tawait this._runLoop(queuedFollowUp);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthrow new Error(\"Cannot continue from message role: assistant\");\n\t\t}\n\n\t\tawait this._runLoop(undefined);\n\t}\n\n\t/**\n\t * Run the agent loop.\n\t * If messages are provided, starts a new conversation turn with those messages.\n\t * Otherwise, continues from existing context.\n\t */\n\tprivate async _runLoop(messages?: AgentMessage[], options?: { skipInitialSteeringPoll?: boolean }) {\n\t\tconst model = this._state.model;\n\t\tif (!model) throw new Error(\"No model configured\");\n\n\t\tthis.runningPrompt = new Promise<void>((resolve) => {\n\t\t\tthis.resolveRunningPrompt = resolve;\n\t\t});\n\n\t\tthis.abortController = new AbortController();\n\t\tthis._state.isStreaming = true;\n\t\tthis._state.streamMessage = null;\n\t\tthis._state.error = undefined;\n\n\t\tconst reasoning = this._state.thinkingLevel === \"off\" ? undefined : this._state.thinkingLevel;\n\n\t\tconst context: AgentContext = {\n\t\t\tsystemPrompt: this._state.systemPrompt,\n\t\t\tmessages: this._state.messages.slice(),\n\t\t\ttools: this._state.tools,\n\t\t};\n\n\t\tlet skipInitialSteeringPoll = options?.skipInitialSteeringPoll === true;\n\n\t\tconst config: AgentLoopConfig = {\n\t\t\tmodel,\n\t\t\treasoning,\n\t\t\tsessionId: this._sessionId,\n\t\t\tonPayload: this._onPayload,\n\t\t\ttransport: this._transport,\n\t\t\tthinkingBudgets: this._thinkingBudgets,\n\t\t\tmaxRetryDelayMs: this._maxRetryDelayMs,\n\t\t\tconvertToLlm: this.convertToLlm,\n\t\t\ttransformContext: this.transformContext,\n\t\t\tgetApiKey: this.getApiKey,\n\t\t\tgetSteeringMessages: async () => {\n\t\t\t\tif (skipInitialSteeringPoll) {\n\t\t\t\t\tskipInitialSteeringPoll = false;\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t\treturn this.dequeueSteeringMessages();\n\t\t\t},\n\t\t\tgetFollowUpMessages: async () => this.dequeueFollowUpMessages(),\n\t\t};\n\n\t\tlet partial: AgentMessage | null = null;\n\n\t\ttry {\n\t\t\tconst stream = messages\n\t\t\t\t? agentLoop(messages, context, config, this.abortController.signal, this.streamFn)\n\t\t\t\t: agentLoopContinue(context, config, this.abortController.signal, this.streamFn);\n\n\t\t\tfor await (const event of stream) {\n\t\t\t\t// Update internal state based on events\n\t\t\t\tswitch (event.type) {\n\t\t\t\t\tcase \"message_start\":\n\t\t\t\t\t\tpartial = event.message;\n\t\t\t\t\t\tthis._state.streamMessage = event.message;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"message_update\":\n\t\t\t\t\t\tpartial = event.message;\n\t\t\t\t\t\tthis._state.streamMessage = event.message;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"message_end\":\n\t\t\t\t\t\tpartial = null;\n\t\t\t\t\t\tthis._state.streamMessage = null;\n\t\t\t\t\t\tthis.appendMessage(event.message);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"tool_execution_start\": {\n\t\t\t\t\t\tconst s = new Set(this._state.pendingToolCalls);\n\t\t\t\t\t\ts.add(event.toolCallId);\n\t\t\t\t\t\tthis._state.pendingToolCalls = s;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase \"tool_execution_end\": {\n\t\t\t\t\t\tconst s = new Set(this._state.pendingToolCalls);\n\t\t\t\t\t\ts.delete(event.toolCallId);\n\t\t\t\t\t\tthis._state.pendingToolCalls = s;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase \"turn_end\":\n\t\t\t\t\t\tif (event.message.role === \"assistant\" && (event.message as any).errorMessage) {\n\t\t\t\t\t\t\tthis._state.error = (event.message as any).errorMessage;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase \"agent_end\":\n\t\t\t\t\t\tthis._state.isStreaming = false;\n\t\t\t\t\t\tthis._state.streamMessage = null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// Emit to listeners\n\t\t\t\tthis.emit(event);\n\t\t\t}\n\n\t\t\t// Handle any remaining partial message\n\t\t\tif (partial && partial.role === \"assistant\" && partial.content.length > 0) {\n\t\t\t\tconst onlyEmpty = !partial.content.some(\n\t\t\t\t\t(c) =>\n\t\t\t\t\t\t(c.type === \"thinking\" && c.thinking.trim().length > 0) ||\n\t\t\t\t\t\t(c.type === \"text\" && c.text.trim().length > 0) ||\n\t\t\t\t\t\t(c.type === \"toolCall\" && c.name.trim().length > 0),\n\t\t\t\t);\n\t\t\t\tif (!onlyEmpty) {\n\t\t\t\t\tthis.appendMessage(partial);\n\t\t\t\t} else {\n\t\t\t\t\tif (this.abortController?.signal.aborted) {\n\t\t\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err: any) {\n\t\t\tconst errorMsg: AgentMessage = {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: [{ type: \"text\", text: \"\" }],\n\t\t\t\tapi: model.api,\n\t\t\t\tprovider: model.provider,\n\t\t\t\tmodel: model.id,\n\t\t\t\tusage: {\n\t\t\t\t\tinput: 0,\n\t\t\t\t\toutput: 0,\n\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\ttotalTokens: 0,\n\t\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t\t},\n\t\t\t\tstopReason: this.abortController?.signal.aborted ? \"aborted\" : \"error\",\n\t\t\t\terrorMessage: err?.message || String(err),\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t} as AgentMessage;\n\n\t\t\tthis.appendMessage(errorMsg);\n\t\t\tthis._state.error = err?.message || String(err);\n\t\t\tthis.emit({ type: \"agent_end\", messages: [errorMsg] });\n\t\t} finally {\n\t\t\tthis._state.isStreaming = false;\n\t\t\tthis._state.streamMessage = null;\n\t\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\t\tthis.abortController = undefined;\n\t\t\tthis.resolveRunningPrompt?.();\n\t\t\tthis.runningPrompt = undefined;\n\t\t\tthis.resolveRunningPrompt = undefined;\n\t\t}\n\t}\n\n\tprivate emit(e: AgentEvent) {\n\t\tfor (const listener of this.listeners) {\n\t\t\tlistener(e);\n\t\t}\n\t}\n}\n"]}
|