@mariozechner/pi-ai 0.16.0 → 0.18.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/README.md +28 -0
- package/dist/agent/agent-loop.d.ts +10 -0
- package/dist/agent/agent-loop.d.ts.map +1 -1
- package/dist/agent/agent-loop.js +91 -62
- package/dist/agent/agent-loop.js.map +1 -1
- package/dist/agent/index.d.ts +2 -2
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/models.generated.d.ts +26 -9
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.generated.js +73 -56
- package/dist/models.generated.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -898,6 +898,34 @@ const messages = await stream.result();
|
|
|
898
898
|
context.messages.push(...messages);
|
|
899
899
|
```
|
|
900
900
|
|
|
901
|
+
### Continuing from Existing Context
|
|
902
|
+
|
|
903
|
+
Use `agentLoopContinue` to resume an agent loop without adding a new user message. This is useful for:
|
|
904
|
+
- Retrying after context overflow (after compaction reduces context size)
|
|
905
|
+
- Resuming from tool results that were added manually to the context
|
|
906
|
+
|
|
907
|
+
```typescript
|
|
908
|
+
import { agentLoopContinue, AgentContext } from '@mariozechner/pi-ai';
|
|
909
|
+
|
|
910
|
+
// Context already has messages - last must be 'user' or 'toolResult'
|
|
911
|
+
const context: AgentContext = {
|
|
912
|
+
systemPrompt: 'You are helpful.',
|
|
913
|
+
messages: [userMessage, assistantMessage, toolResult],
|
|
914
|
+
tools: [myTool]
|
|
915
|
+
};
|
|
916
|
+
|
|
917
|
+
// Continue processing from the tool result
|
|
918
|
+
const stream = agentLoopContinue(context, { model });
|
|
919
|
+
|
|
920
|
+
for await (const event of stream) {
|
|
921
|
+
// Same events as agentLoop, but no user message events emitted
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
const newMessages = await stream.result();
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
**Validation**: Throws if context has no messages or if the last message is an assistant message.
|
|
928
|
+
|
|
901
929
|
### Defining Tools with TypeBox
|
|
902
930
|
|
|
903
931
|
Tools use TypeBox schemas for runtime validation and type inference:
|
|
@@ -2,5 +2,15 @@ import { streamSimple } from "../stream.js";
|
|
|
2
2
|
import type { UserMessage } from "../types.js";
|
|
3
3
|
import { EventStream } from "../utils/event-stream.js";
|
|
4
4
|
import type { AgentContext, AgentEvent, AgentLoopConfig } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Start an agent loop with a new user message.
|
|
7
|
+
* The prompt is added to the context and events are emitted for it.
|
|
8
|
+
*/
|
|
5
9
|
export declare function agentLoop(prompt: UserMessage, context: AgentContext, config: AgentLoopConfig, signal?: AbortSignal, streamFn?: typeof streamSimple): EventStream<AgentEvent, AgentContext["messages"]>;
|
|
10
|
+
/**
|
|
11
|
+
* Continue an agent loop from the current context without adding a new message.
|
|
12
|
+
* Used for retry after overflow - context already has user message or tool results.
|
|
13
|
+
* Throws if the last message is not a user message or tool result.
|
|
14
|
+
*/
|
|
15
|
+
export declare function agentLoopContinue(context: AgentContext, config: AgentLoopConfig, signal?: AbortSignal, streamFn?: typeof streamSimple): EventStream<AgentEvent, AgentContext["messages"]>;
|
|
6
16
|
//# sourceMappingURL=agent-loop.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../../src/agent/agent-loop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAyD,WAAW,EAAE,MAAM,aAAa,CAAC;AACtG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAA6C,MAAM,YAAY,CAAC;AAGvH,wBAAgB,SAAS,CACxB,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,OAAO,YAAY,GAC5B,WAAW,CAAC,UAAU,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC,CAqFnD","sourcesContent":["import { streamSimple } from \"../stream.js\";\nimport type { AssistantMessage, Context, Message, ToolResultMessage, UserMessage } from \"../types.js\";\nimport { EventStream } from \"../utils/event-stream.js\";\nimport { validateToolArguments } from \"../utils/validation.js\";\nimport type { AgentContext, AgentEvent, AgentLoopConfig, AgentTool, AgentToolResult, QueuedMessage } from \"./types.js\";\n\n// Main prompt function - returns a stream of events\nexport function agentLoop(\n\tprompt: UserMessage,\n\tcontext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal?: AbortSignal,\n\tstreamFn?: typeof streamSimple,\n): EventStream<AgentEvent, AgentContext[\"messages\"]> {\n\tconst stream = new EventStream<AgentEvent, AgentContext[\"messages\"]>(\n\t\t(event: AgentEvent) => event.type === \"agent_end\",\n\t\t(event: AgentEvent) => (event.type === \"agent_end\" ? event.messages : []),\n\t);\n\n\t// Run the prompt async\n\t(async () => {\n\t\t// Track new messages generated during this prompt\n\t\tconst newMessages: AgentContext[\"messages\"] = [];\n\t\t// Create user message for the prompt\n\t\tconst messages = [...context.messages, prompt];\n\t\tnewMessages.push(prompt);\n\n\t\tstream.push({ type: \"agent_start\" });\n\t\tstream.push({ type: \"turn_start\" });\n\t\tstream.push({ type: \"message_start\", message: prompt });\n\t\tstream.push({ type: \"message_end\", message: prompt });\n\n\t\t// Update context with new messages\n\t\tconst currentContext: AgentContext = {\n\t\t\t...context,\n\t\t\tmessages,\n\t\t};\n\n\t\t// Keep looping while we have tool calls or queued messages\n\t\tlet hasMoreToolCalls = true;\n\t\tlet firstTurn = true;\n\t\tlet queuedMessages: QueuedMessage<any>[] = (await config.getQueuedMessages?.()) || [];\n\n\t\twhile (hasMoreToolCalls || queuedMessages.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\n\t\t\t// Process queued messages first (inject before next assistant response)\n\t\t\tif (queuedMessages.length > 0) {\n\t\t\t\tfor (const { original, llm } of queuedMessages) {\n\t\t\t\t\tstream.push({ type: \"message_start\", message: original });\n\t\t\t\t\tstream.push({ type: \"message_end\", message: original });\n\t\t\t\t\tif (llm) {\n\t\t\t\t\t\tcurrentContext.messages.push(llm);\n\t\t\t\t\t\tnewMessages.push(llm);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tqueuedMessages = [];\n\t\t\t}\n\n\t\t\t// console.log(\"agent-loop: \", [...currentContext.messages]);\n\n\t\t\t// Stream assistant response\n\t\t\tconst message = await streamAssistantResponse(currentContext, config, signal, stream, streamFn);\n\t\t\tnewMessages.push(message);\n\n\t\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\t\t// Stop the loop on error or abort\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\n\t\t\t// Check for tool calls\n\t\t\tconst toolCalls = message.content.filter((c) => c.type === \"toolCall\");\n\t\t\thasMoreToolCalls = toolCalls.length > 0;\n\n\t\t\tconst toolResults: ToolResultMessage[] = [];\n\t\t\tif (hasMoreToolCalls) {\n\t\t\t\t// Execute tool calls\n\t\t\t\ttoolResults.push(...(await executeToolCalls(currentContext.tools, message, signal, stream)));\n\t\t\t\tcurrentContext.messages.push(...toolResults);\n\t\t\t\tnewMessages.push(...toolResults);\n\t\t\t}\n\t\t\tstream.push({ type: \"turn_end\", message, toolResults: toolResults });\n\n\t\t\t// Get queued messages after turn completes\n\t\t\tqueuedMessages = (await config.getQueuedMessages?.()) || [];\n\t\t}\n\t\tstream.push({ type: \"agent_end\", messages: newMessages });\n\t\tstream.end(newMessages);\n\t})();\n\n\treturn stream;\n}\n\n// Helper functions\nasync function streamAssistantResponse(\n\tcontext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, AgentContext[\"messages\"]>,\n\tstreamFn?: typeof streamSimple,\n): Promise<AssistantMessage> {\n\t// Convert AgentContext to Context for streamSimple\n\t// Use a copy of messages to avoid mutating the original context\n\tconst processedMessages = config.preprocessor\n\t\t? await config.preprocessor(context.messages, signal)\n\t\t: [...context.messages];\n\tconst processedContext: Context = {\n\t\tsystemPrompt: context.systemPrompt,\n\t\tmessages: [...processedMessages].map((m) => {\n\t\t\tif (m.role === \"toolResult\") {\n\t\t\t\tconst { details, ...rest } = m;\n\t\t\t\treturn rest;\n\t\t\t} else {\n\t\t\t\treturn m;\n\t\t\t}\n\t\t}),\n\t\ttools: context.tools, // AgentTool extends Tool, so this works\n\t};\n\n\t// Use custom stream function if provided, otherwise use default streamSimple\n\tconst streamFunction = streamFn || streamSimple;\n\tconst response = await streamFunction(config.model, processedContext, { ...config, signal });\n\n\tlet partialMessage: AssistantMessage | null = null;\n\tlet addedPartial = false;\n\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\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({ type: \"message_update\", assistantMessageEvent: event, message: { ...partialMessage } });\n\t\t\t\t}\n\t\t\t\tbreak;\n\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\n\treturn await response.result();\n}\n\nasync function executeToolCalls<T>(\n\ttools: AgentTool<any, T>[] | undefined,\n\tassistantMessage: AssistantMessage,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, Message[]>,\n): Promise<ToolResultMessage<T>[]> {\n\tconst toolCalls = assistantMessage.content.filter((c) => c.type === \"toolCall\");\n\tconst results: ToolResultMessage<any>[] = [];\n\n\tfor (const toolCall of toolCalls) {\n\t\tconst tool = tools?.find((t) => t.name === toolCall.name);\n\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\n\t\tlet resultOrError: AgentToolResult<T> | string;\n\t\tlet isError = false;\n\n\t\ttry {\n\t\t\tif (!tool) throw new Error(`Tool ${toolCall.name} not found`);\n\n\t\t\t// Validate arguments using shared validation function\n\t\t\tconst validatedArgs = validateToolArguments(tool, toolCall);\n\n\t\t\t// Execute with validated, typed arguments\n\t\t\tresultOrError = await tool.execute(toolCall.id, validatedArgs, signal);\n\t\t} catch (e) {\n\t\t\tresultOrError = e instanceof Error ? e.message : String(e);\n\t\t\tisError = true;\n\t\t}\n\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: resultOrError,\n\t\t\tisError,\n\t\t});\n\n\t\t// Convert result to content blocks\n\t\tconst content: ToolResultMessage<T>[\"content\"] =\n\t\t\ttypeof resultOrError === \"string\" ? [{ type: \"text\", text: resultOrError }] : resultOrError.content;\n\n\t\tconst toolResultMessage: ToolResultMessage<T> = {\n\t\t\trole: \"toolResult\",\n\t\t\ttoolCallId: toolCall.id,\n\t\t\ttoolName: toolCall.name,\n\t\t\tcontent,\n\t\t\tdetails: typeof resultOrError === \"string\" ? ({} as T) : resultOrError.details,\n\t\t\tisError,\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tresults.push(toolResultMessage);\n\t\tstream.push({ type: \"message_start\", message: toolResultMessage });\n\t\tstream.push({ type: \"message_end\", message: toolResultMessage });\n\t}\n\n\treturn results;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../../src/agent/agent-loop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAyD,WAAW,EAAE,MAAM,aAAa,CAAC;AACtG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAA6C,MAAM,YAAY,CAAC;AAEvH;;;GAGG;AACH,wBAAgB,SAAS,CACxB,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,OAAO,YAAY,GAC5B,WAAW,CAAC,UAAU,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC,CAmBnD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,OAAO,YAAY,GAC5B,WAAW,CAAC,UAAU,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC,CAwBnD","sourcesContent":["import { streamSimple } from \"../stream.js\";\nimport type { AssistantMessage, Context, Message, ToolResultMessage, UserMessage } from \"../types.js\";\nimport { EventStream } from \"../utils/event-stream.js\";\nimport { validateToolArguments } from \"../utils/validation.js\";\nimport type { AgentContext, AgentEvent, AgentLoopConfig, AgentTool, AgentToolResult, QueuedMessage } from \"./types.js\";\n\n/**\n * Start an agent loop with a new user message.\n * The prompt is added to the context and events are emitted for it.\n */\nexport function agentLoop(\n\tprompt: UserMessage,\n\tcontext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal?: AbortSignal,\n\tstreamFn?: typeof streamSimple,\n): EventStream<AgentEvent, AgentContext[\"messages\"]> {\n\tconst stream = createAgentStream();\n\n\t(async () => {\n\t\tconst newMessages: AgentContext[\"messages\"] = [prompt];\n\t\tconst currentContext: AgentContext = {\n\t\t\t...context,\n\t\t\tmessages: [...context.messages, prompt],\n\t\t};\n\n\t\tstream.push({ type: \"agent_start\" });\n\t\tstream.push({ type: \"turn_start\" });\n\t\tstream.push({ type: \"message_start\", message: prompt });\n\t\tstream.push({ type: \"message_end\", message: prompt });\n\n\t\tawait runLoop(currentContext, newMessages, config, signal, stream, streamFn);\n\t})();\n\n\treturn stream;\n}\n\n/**\n * Continue an agent loop from the current context without adding a new message.\n * Used for retry after overflow - context already has user message or tool results.\n * Throws if the last message is not a user message or tool result.\n */\nexport function agentLoopContinue(\n\tcontext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal?: AbortSignal,\n\tstreamFn?: typeof streamSimple,\n): EventStream<AgentEvent, AgentContext[\"messages\"]> {\n\t// Validate that we can continue from this context\n\tconst lastMessage = context.messages[context.messages.length - 1];\n\tif (!lastMessage) {\n\t\tthrow new Error(\"Cannot continue: no messages in context\");\n\t}\n\tif (lastMessage.role !== \"user\" && lastMessage.role !== \"toolResult\") {\n\t\tthrow new Error(`Cannot continue from message role: ${lastMessage.role}. Expected 'user' or 'toolResult'.`);\n\t}\n\n\tconst stream = createAgentStream();\n\n\t(async () => {\n\t\tconst newMessages: AgentContext[\"messages\"] = [];\n\t\tconst currentContext: AgentContext = { ...context };\n\n\t\tstream.push({ type: \"agent_start\" });\n\t\tstream.push({ type: \"turn_start\" });\n\t\t// No user message events - we're continuing from existing context\n\n\t\tawait runLoop(currentContext, newMessages, config, signal, stream, streamFn);\n\t})();\n\n\treturn stream;\n}\n\nfunction createAgentStream(): EventStream<AgentEvent, AgentContext[\"messages\"]> {\n\treturn new EventStream<AgentEvent, AgentContext[\"messages\"]>(\n\t\t(event: AgentEvent) => event.type === \"agent_end\",\n\t\t(event: AgentEvent) => (event.type === \"agent_end\" ? event.messages : []),\n\t);\n}\n\n/**\n * Shared loop logic for both agentLoop and agentLoopContinue.\n */\nasync function runLoop(\n\tcurrentContext: AgentContext,\n\tnewMessages: AgentContext[\"messages\"],\n\tconfig: AgentLoopConfig,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, AgentContext[\"messages\"]>,\n\tstreamFn?: typeof streamSimple,\n): Promise<void> {\n\tlet hasMoreToolCalls = true;\n\tlet firstTurn = true;\n\tlet queuedMessages: QueuedMessage<any>[] = (await config.getQueuedMessages?.()) || [];\n\n\twhile (hasMoreToolCalls || queuedMessages.length > 0) {\n\t\tif (!firstTurn) {\n\t\t\tstream.push({ type: \"turn_start\" });\n\t\t} else {\n\t\t\tfirstTurn = false;\n\t\t}\n\n\t\t// Process queued messages first (inject before next assistant response)\n\t\tif (queuedMessages.length > 0) {\n\t\t\tfor (const { original, llm } of queuedMessages) {\n\t\t\t\tstream.push({ type: \"message_start\", message: original });\n\t\t\t\tstream.push({ type: \"message_end\", message: original });\n\t\t\t\tif (llm) {\n\t\t\t\t\tcurrentContext.messages.push(llm);\n\t\t\t\t\tnewMessages.push(llm);\n\t\t\t\t}\n\t\t\t}\n\t\t\tqueuedMessages = [];\n\t\t}\n\n\t\t// Stream assistant response\n\t\tconst message = await streamAssistantResponse(currentContext, config, signal, stream, streamFn);\n\t\tnewMessages.push(message);\n\n\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\t// Stop the loop on error or abort\n\t\t\tstream.push({ type: \"turn_end\", message, toolResults: [] });\n\t\t\tstream.push({ type: \"agent_end\", messages: newMessages });\n\t\t\tstream.end(newMessages);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for tool calls\n\t\tconst toolCalls = message.content.filter((c) => c.type === \"toolCall\");\n\t\thasMoreToolCalls = toolCalls.length > 0;\n\n\t\tconst toolResults: ToolResultMessage[] = [];\n\t\tif (hasMoreToolCalls) {\n\t\t\t// Execute tool calls\n\t\t\ttoolResults.push(...(await executeToolCalls(currentContext.tools, message, signal, stream)));\n\t\t\tcurrentContext.messages.push(...toolResults);\n\t\t\tnewMessages.push(...toolResults);\n\t\t}\n\t\tstream.push({ type: \"turn_end\", message, toolResults: toolResults });\n\n\t\t// Get queued messages after turn completes\n\t\tqueuedMessages = (await config.getQueuedMessages?.()) || [];\n\t}\n\n\tstream.push({ type: \"agent_end\", messages: newMessages });\n\tstream.end(newMessages);\n}\n\n// Helper functions\nasync function streamAssistantResponse(\n\tcontext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, AgentContext[\"messages\"]>,\n\tstreamFn?: typeof streamSimple,\n): Promise<AssistantMessage> {\n\t// Convert AgentContext to Context for streamSimple\n\t// Use a copy of messages to avoid mutating the original context\n\tconst processedMessages = config.preprocessor\n\t\t? await config.preprocessor(context.messages, signal)\n\t\t: [...context.messages];\n\tconst processedContext: Context = {\n\t\tsystemPrompt: context.systemPrompt,\n\t\tmessages: [...processedMessages].map((m) => {\n\t\t\tif (m.role === \"toolResult\") {\n\t\t\t\tconst { details, ...rest } = m;\n\t\t\t\treturn rest;\n\t\t\t} else {\n\t\t\t\treturn m;\n\t\t\t}\n\t\t}),\n\t\ttools: context.tools, // AgentTool extends Tool, so this works\n\t};\n\n\t// Use custom stream function if provided, otherwise use default streamSimple\n\tconst streamFunction = streamFn || streamSimple;\n\tconst response = await streamFunction(config.model, processedContext, { ...config, signal });\n\n\tlet partialMessage: AssistantMessage | null = null;\n\tlet addedPartial = false;\n\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\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({ type: \"message_update\", assistantMessageEvent: event, message: { ...partialMessage } });\n\t\t\t\t}\n\t\t\t\tbreak;\n\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\n\treturn await response.result();\n}\n\nasync function executeToolCalls<T>(\n\ttools: AgentTool<any, T>[] | undefined,\n\tassistantMessage: AssistantMessage,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, Message[]>,\n): Promise<ToolResultMessage<T>[]> {\n\tconst toolCalls = assistantMessage.content.filter((c) => c.type === \"toolCall\");\n\tconst results: ToolResultMessage<any>[] = [];\n\n\tfor (const toolCall of toolCalls) {\n\t\tconst tool = tools?.find((t) => t.name === toolCall.name);\n\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\n\t\tlet resultOrError: AgentToolResult<T> | string;\n\t\tlet isError = false;\n\n\t\ttry {\n\t\t\tif (!tool) throw new Error(`Tool ${toolCall.name} not found`);\n\n\t\t\t// Validate arguments using shared validation function\n\t\t\tconst validatedArgs = validateToolArguments(tool, toolCall);\n\n\t\t\t// Execute with validated, typed arguments\n\t\t\tresultOrError = await tool.execute(toolCall.id, validatedArgs, signal);\n\t\t} catch (e) {\n\t\t\tresultOrError = e instanceof Error ? e.message : String(e);\n\t\t\tisError = true;\n\t\t}\n\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: resultOrError,\n\t\t\tisError,\n\t\t});\n\n\t\t// Convert result to content blocks\n\t\tconst content: ToolResultMessage<T>[\"content\"] =\n\t\t\ttypeof resultOrError === \"string\" ? [{ type: \"text\", text: resultOrError }] : resultOrError.content;\n\n\t\tconst toolResultMessage: ToolResultMessage<T> = {\n\t\t\trole: \"toolResult\",\n\t\t\ttoolCallId: toolCall.id,\n\t\t\ttoolName: toolCall.name,\n\t\t\tcontent,\n\t\t\tdetails: typeof resultOrError === \"string\" ? ({} as T) : resultOrError.details,\n\t\t\tisError,\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tresults.push(toolResultMessage);\n\t\tstream.push({ type: \"message_start\", message: toolResultMessage });\n\t\tstream.push({ type: \"message_end\", message: toolResultMessage });\n\t}\n\n\treturn results;\n}\n"]}
|
package/dist/agent/agent-loop.js
CHANGED
|
@@ -1,77 +1,106 @@
|
|
|
1
1
|
import { streamSimple } from "../stream.js";
|
|
2
2
|
import { EventStream } from "../utils/event-stream.js";
|
|
3
3
|
import { validateToolArguments } from "../utils/validation.js";
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Start an agent loop with a new user message.
|
|
6
|
+
* The prompt is added to the context and events are emitted for it.
|
|
7
|
+
*/
|
|
5
8
|
export function agentLoop(prompt, context, config, signal, streamFn) {
|
|
6
|
-
const stream =
|
|
7
|
-
// Run the prompt async
|
|
9
|
+
const stream = createAgentStream();
|
|
8
10
|
(async () => {
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const newMessages = [prompt];
|
|
12
|
+
const currentContext = {
|
|
13
|
+
...context,
|
|
14
|
+
messages: [...context.messages, prompt],
|
|
15
|
+
};
|
|
14
16
|
stream.push({ type: "agent_start" });
|
|
15
17
|
stream.push({ type: "turn_start" });
|
|
16
18
|
stream.push({ type: "message_start", message: prompt });
|
|
17
19
|
stream.push({ type: "message_end", message: prompt });
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
20
|
+
await runLoop(currentContext, newMessages, config, signal, stream, streamFn);
|
|
21
|
+
})();
|
|
22
|
+
return stream;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Continue an agent loop from the current context without adding a new message.
|
|
26
|
+
* Used for retry after overflow - context already has user message or tool results.
|
|
27
|
+
* Throws if the last message is not a user message or tool result.
|
|
28
|
+
*/
|
|
29
|
+
export function agentLoopContinue(context, config, signal, streamFn) {
|
|
30
|
+
// Validate that we can continue from this context
|
|
31
|
+
const lastMessage = context.messages[context.messages.length - 1];
|
|
32
|
+
if (!lastMessage) {
|
|
33
|
+
throw new Error("Cannot continue: no messages in context");
|
|
34
|
+
}
|
|
35
|
+
if (lastMessage.role !== "user" && lastMessage.role !== "toolResult") {
|
|
36
|
+
throw new Error(`Cannot continue from message role: ${lastMessage.role}. Expected 'user' or 'toolResult'.`);
|
|
37
|
+
}
|
|
38
|
+
const stream = createAgentStream();
|
|
39
|
+
(async () => {
|
|
40
|
+
const newMessages = [];
|
|
41
|
+
const currentContext = { ...context };
|
|
42
|
+
stream.push({ type: "agent_start" });
|
|
43
|
+
stream.push({ type: "turn_start" });
|
|
44
|
+
// No user message events - we're continuing from existing context
|
|
45
|
+
await runLoop(currentContext, newMessages, config, signal, stream, streamFn);
|
|
46
|
+
})();
|
|
47
|
+
return stream;
|
|
48
|
+
}
|
|
49
|
+
function createAgentStream() {
|
|
50
|
+
return new EventStream((event) => event.type === "agent_end", (event) => (event.type === "agent_end" ? event.messages : []));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Shared loop logic for both agentLoop and agentLoopContinue.
|
|
54
|
+
*/
|
|
55
|
+
async function runLoop(currentContext, newMessages, config, signal, stream, streamFn) {
|
|
56
|
+
let hasMoreToolCalls = true;
|
|
57
|
+
let firstTurn = true;
|
|
58
|
+
let queuedMessages = (await config.getQueuedMessages?.()) || [];
|
|
59
|
+
while (hasMoreToolCalls || queuedMessages.length > 0) {
|
|
60
|
+
if (!firstTurn) {
|
|
61
|
+
stream.push({ type: "turn_start" });
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
firstTurn = false;
|
|
65
|
+
}
|
|
66
|
+
// Process queued messages first (inject before next assistant response)
|
|
67
|
+
if (queuedMessages.length > 0) {
|
|
68
|
+
for (const { original, llm } of queuedMessages) {
|
|
69
|
+
stream.push({ type: "message_start", message: original });
|
|
70
|
+
stream.push({ type: "message_end", message: original });
|
|
71
|
+
if (llm) {
|
|
72
|
+
currentContext.messages.push(llm);
|
|
73
|
+
newMessages.push(llm);
|
|
43
74
|
}
|
|
44
|
-
queuedMessages = [];
|
|
45
|
-
}
|
|
46
|
-
// console.log("agent-loop: ", [...currentContext.messages]);
|
|
47
|
-
// Stream assistant response
|
|
48
|
-
const message = await streamAssistantResponse(currentContext, config, signal, stream, streamFn);
|
|
49
|
-
newMessages.push(message);
|
|
50
|
-
if (message.stopReason === "error" || message.stopReason === "aborted") {
|
|
51
|
-
// Stop the loop on error or abort
|
|
52
|
-
stream.push({ type: "turn_end", message, toolResults: [] });
|
|
53
|
-
stream.push({ type: "agent_end", messages: newMessages });
|
|
54
|
-
stream.end(newMessages);
|
|
55
|
-
return;
|
|
56
75
|
}
|
|
57
|
-
|
|
58
|
-
const toolCalls = message.content.filter((c) => c.type === "toolCall");
|
|
59
|
-
hasMoreToolCalls = toolCalls.length > 0;
|
|
60
|
-
const toolResults = [];
|
|
61
|
-
if (hasMoreToolCalls) {
|
|
62
|
-
// Execute tool calls
|
|
63
|
-
toolResults.push(...(await executeToolCalls(currentContext.tools, message, signal, stream)));
|
|
64
|
-
currentContext.messages.push(...toolResults);
|
|
65
|
-
newMessages.push(...toolResults);
|
|
66
|
-
}
|
|
67
|
-
stream.push({ type: "turn_end", message, toolResults: toolResults });
|
|
68
|
-
// Get queued messages after turn completes
|
|
69
|
-
queuedMessages = (await config.getQueuedMessages?.()) || [];
|
|
76
|
+
queuedMessages = [];
|
|
70
77
|
}
|
|
71
|
-
|
|
72
|
-
stream
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
// Stream assistant response
|
|
79
|
+
const message = await streamAssistantResponse(currentContext, config, signal, stream, streamFn);
|
|
80
|
+
newMessages.push(message);
|
|
81
|
+
if (message.stopReason === "error" || message.stopReason === "aborted") {
|
|
82
|
+
// Stop the loop on error or abort
|
|
83
|
+
stream.push({ type: "turn_end", message, toolResults: [] });
|
|
84
|
+
stream.push({ type: "agent_end", messages: newMessages });
|
|
85
|
+
stream.end(newMessages);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
// Check for tool calls
|
|
89
|
+
const toolCalls = message.content.filter((c) => c.type === "toolCall");
|
|
90
|
+
hasMoreToolCalls = toolCalls.length > 0;
|
|
91
|
+
const toolResults = [];
|
|
92
|
+
if (hasMoreToolCalls) {
|
|
93
|
+
// Execute tool calls
|
|
94
|
+
toolResults.push(...(await executeToolCalls(currentContext.tools, message, signal, stream)));
|
|
95
|
+
currentContext.messages.push(...toolResults);
|
|
96
|
+
newMessages.push(...toolResults);
|
|
97
|
+
}
|
|
98
|
+
stream.push({ type: "turn_end", message, toolResults: toolResults });
|
|
99
|
+
// Get queued messages after turn completes
|
|
100
|
+
queuedMessages = (await config.getQueuedMessages?.()) || [];
|
|
101
|
+
}
|
|
102
|
+
stream.push({ type: "agent_end", messages: newMessages });
|
|
103
|
+
stream.end(newMessages);
|
|
75
104
|
}
|
|
76
105
|
// Helper functions
|
|
77
106
|
async function streamAssistantResponse(context, config, signal, stream, streamFn) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-loop.js","sourceRoot":"","sources":["../../src/agent/agent-loop.ts"],"names":[],"mappings":"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","sourcesContent":["import { streamSimple } from \"../stream.js\";\nimport type { AssistantMessage, Context, Message, ToolResultMessage, UserMessage } from \"../types.js\";\nimport { EventStream } from \"../utils/event-stream.js\";\nimport { validateToolArguments } from \"../utils/validation.js\";\nimport type { AgentContext, AgentEvent, AgentLoopConfig, AgentTool, AgentToolResult, QueuedMessage } from \"./types.js\";\n\n// Main prompt function - returns a stream of events\nexport function agentLoop(\n\tprompt: UserMessage,\n\tcontext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal?: AbortSignal,\n\tstreamFn?: typeof streamSimple,\n): EventStream<AgentEvent, AgentContext[\"messages\"]> {\n\tconst stream = new EventStream<AgentEvent, AgentContext[\"messages\"]>(\n\t\t(event: AgentEvent) => event.type === \"agent_end\",\n\t\t(event: AgentEvent) => (event.type === \"agent_end\" ? event.messages : []),\n\t);\n\n\t// Run the prompt async\n\t(async () => {\n\t\t// Track new messages generated during this prompt\n\t\tconst newMessages: AgentContext[\"messages\"] = [];\n\t\t// Create user message for the prompt\n\t\tconst messages = [...context.messages, prompt];\n\t\tnewMessages.push(prompt);\n\n\t\tstream.push({ type: \"agent_start\" });\n\t\tstream.push({ type: \"turn_start\" });\n\t\tstream.push({ type: \"message_start\", message: prompt });\n\t\tstream.push({ type: \"message_end\", message: prompt });\n\n\t\t// Update context with new messages\n\t\tconst currentContext: AgentContext = {\n\t\t\t...context,\n\t\t\tmessages,\n\t\t};\n\n\t\t// Keep looping while we have tool calls or queued messages\n\t\tlet hasMoreToolCalls = true;\n\t\tlet firstTurn = true;\n\t\tlet queuedMessages: QueuedMessage<any>[] = (await config.getQueuedMessages?.()) || [];\n\n\t\twhile (hasMoreToolCalls || queuedMessages.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\n\t\t\t// Process queued messages first (inject before next assistant response)\n\t\t\tif (queuedMessages.length > 0) {\n\t\t\t\tfor (const { original, llm } of queuedMessages) {\n\t\t\t\t\tstream.push({ type: \"message_start\", message: original });\n\t\t\t\t\tstream.push({ type: \"message_end\", message: original });\n\t\t\t\t\tif (llm) {\n\t\t\t\t\t\tcurrentContext.messages.push(llm);\n\t\t\t\t\t\tnewMessages.push(llm);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tqueuedMessages = [];\n\t\t\t}\n\n\t\t\t// console.log(\"agent-loop: \", [...currentContext.messages]);\n\n\t\t\t// Stream assistant response\n\t\t\tconst message = await streamAssistantResponse(currentContext, config, signal, stream, streamFn);\n\t\t\tnewMessages.push(message);\n\n\t\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\t\t// Stop the loop on error or abort\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\n\t\t\t// Check for tool calls\n\t\t\tconst toolCalls = message.content.filter((c) => c.type === \"toolCall\");\n\t\t\thasMoreToolCalls = toolCalls.length > 0;\n\n\t\t\tconst toolResults: ToolResultMessage[] = [];\n\t\t\tif (hasMoreToolCalls) {\n\t\t\t\t// Execute tool calls\n\t\t\t\ttoolResults.push(...(await executeToolCalls(currentContext.tools, message, signal, stream)));\n\t\t\t\tcurrentContext.messages.push(...toolResults);\n\t\t\t\tnewMessages.push(...toolResults);\n\t\t\t}\n\t\t\tstream.push({ type: \"turn_end\", message, toolResults: toolResults });\n\n\t\t\t// Get queued messages after turn completes\n\t\t\tqueuedMessages = (await config.getQueuedMessages?.()) || [];\n\t\t}\n\t\tstream.push({ type: \"agent_end\", messages: newMessages });\n\t\tstream.end(newMessages);\n\t})();\n\n\treturn stream;\n}\n\n// Helper functions\nasync function streamAssistantResponse(\n\tcontext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, AgentContext[\"messages\"]>,\n\tstreamFn?: typeof streamSimple,\n): Promise<AssistantMessage> {\n\t// Convert AgentContext to Context for streamSimple\n\t// Use a copy of messages to avoid mutating the original context\n\tconst processedMessages = config.preprocessor\n\t\t? await config.preprocessor(context.messages, signal)\n\t\t: [...context.messages];\n\tconst processedContext: Context = {\n\t\tsystemPrompt: context.systemPrompt,\n\t\tmessages: [...processedMessages].map((m) => {\n\t\t\tif (m.role === \"toolResult\") {\n\t\t\t\tconst { details, ...rest } = m;\n\t\t\t\treturn rest;\n\t\t\t} else {\n\t\t\t\treturn m;\n\t\t\t}\n\t\t}),\n\t\ttools: context.tools, // AgentTool extends Tool, so this works\n\t};\n\n\t// Use custom stream function if provided, otherwise use default streamSimple\n\tconst streamFunction = streamFn || streamSimple;\n\tconst response = await streamFunction(config.model, processedContext, { ...config, signal });\n\n\tlet partialMessage: AssistantMessage | null = null;\n\tlet addedPartial = false;\n\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\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({ type: \"message_update\", assistantMessageEvent: event, message: { ...partialMessage } });\n\t\t\t\t}\n\t\t\t\tbreak;\n\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\n\treturn await response.result();\n}\n\nasync function executeToolCalls<T>(\n\ttools: AgentTool<any, T>[] | undefined,\n\tassistantMessage: AssistantMessage,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, Message[]>,\n): Promise<ToolResultMessage<T>[]> {\n\tconst toolCalls = assistantMessage.content.filter((c) => c.type === \"toolCall\");\n\tconst results: ToolResultMessage<any>[] = [];\n\n\tfor (const toolCall of toolCalls) {\n\t\tconst tool = tools?.find((t) => t.name === toolCall.name);\n\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\n\t\tlet resultOrError: AgentToolResult<T> | string;\n\t\tlet isError = false;\n\n\t\ttry {\n\t\t\tif (!tool) throw new Error(`Tool ${toolCall.name} not found`);\n\n\t\t\t// Validate arguments using shared validation function\n\t\t\tconst validatedArgs = validateToolArguments(tool, toolCall);\n\n\t\t\t// Execute with validated, typed arguments\n\t\t\tresultOrError = await tool.execute(toolCall.id, validatedArgs, signal);\n\t\t} catch (e) {\n\t\t\tresultOrError = e instanceof Error ? e.message : String(e);\n\t\t\tisError = true;\n\t\t}\n\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: resultOrError,\n\t\t\tisError,\n\t\t});\n\n\t\t// Convert result to content blocks\n\t\tconst content: ToolResultMessage<T>[\"content\"] =\n\t\t\ttypeof resultOrError === \"string\" ? [{ type: \"text\", text: resultOrError }] : resultOrError.content;\n\n\t\tconst toolResultMessage: ToolResultMessage<T> = {\n\t\t\trole: \"toolResult\",\n\t\t\ttoolCallId: toolCall.id,\n\t\t\ttoolName: toolCall.name,\n\t\t\tcontent,\n\t\t\tdetails: typeof resultOrError === \"string\" ? ({} as T) : resultOrError.details,\n\t\t\tisError,\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tresults.push(toolResultMessage);\n\t\tstream.push({ type: \"message_start\", message: toolResultMessage });\n\t\tstream.push({ type: \"message_end\", message: toolResultMessage });\n\t}\n\n\treturn results;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agent-loop.js","sourceRoot":"","sources":["../../src/agent/agent-loop.ts"],"names":[],"mappings":"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","sourcesContent":["import { streamSimple } from \"../stream.js\";\nimport type { AssistantMessage, Context, Message, ToolResultMessage, UserMessage } from \"../types.js\";\nimport { EventStream } from \"../utils/event-stream.js\";\nimport { validateToolArguments } from \"../utils/validation.js\";\nimport type { AgentContext, AgentEvent, AgentLoopConfig, AgentTool, AgentToolResult, QueuedMessage } from \"./types.js\";\n\n/**\n * Start an agent loop with a new user message.\n * The prompt is added to the context and events are emitted for it.\n */\nexport function agentLoop(\n\tprompt: UserMessage,\n\tcontext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal?: AbortSignal,\n\tstreamFn?: typeof streamSimple,\n): EventStream<AgentEvent, AgentContext[\"messages\"]> {\n\tconst stream = createAgentStream();\n\n\t(async () => {\n\t\tconst newMessages: AgentContext[\"messages\"] = [prompt];\n\t\tconst currentContext: AgentContext = {\n\t\t\t...context,\n\t\t\tmessages: [...context.messages, prompt],\n\t\t};\n\n\t\tstream.push({ type: \"agent_start\" });\n\t\tstream.push({ type: \"turn_start\" });\n\t\tstream.push({ type: \"message_start\", message: prompt });\n\t\tstream.push({ type: \"message_end\", message: prompt });\n\n\t\tawait runLoop(currentContext, newMessages, config, signal, stream, streamFn);\n\t})();\n\n\treturn stream;\n}\n\n/**\n * Continue an agent loop from the current context without adding a new message.\n * Used for retry after overflow - context already has user message or tool results.\n * Throws if the last message is not a user message or tool result.\n */\nexport function agentLoopContinue(\n\tcontext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal?: AbortSignal,\n\tstreamFn?: typeof streamSimple,\n): EventStream<AgentEvent, AgentContext[\"messages\"]> {\n\t// Validate that we can continue from this context\n\tconst lastMessage = context.messages[context.messages.length - 1];\n\tif (!lastMessage) {\n\t\tthrow new Error(\"Cannot continue: no messages in context\");\n\t}\n\tif (lastMessage.role !== \"user\" && lastMessage.role !== \"toolResult\") {\n\t\tthrow new Error(`Cannot continue from message role: ${lastMessage.role}. Expected 'user' or 'toolResult'.`);\n\t}\n\n\tconst stream = createAgentStream();\n\n\t(async () => {\n\t\tconst newMessages: AgentContext[\"messages\"] = [];\n\t\tconst currentContext: AgentContext = { ...context };\n\n\t\tstream.push({ type: \"agent_start\" });\n\t\tstream.push({ type: \"turn_start\" });\n\t\t// No user message events - we're continuing from existing context\n\n\t\tawait runLoop(currentContext, newMessages, config, signal, stream, streamFn);\n\t})();\n\n\treturn stream;\n}\n\nfunction createAgentStream(): EventStream<AgentEvent, AgentContext[\"messages\"]> {\n\treturn new EventStream<AgentEvent, AgentContext[\"messages\"]>(\n\t\t(event: AgentEvent) => event.type === \"agent_end\",\n\t\t(event: AgentEvent) => (event.type === \"agent_end\" ? event.messages : []),\n\t);\n}\n\n/**\n * Shared loop logic for both agentLoop and agentLoopContinue.\n */\nasync function runLoop(\n\tcurrentContext: AgentContext,\n\tnewMessages: AgentContext[\"messages\"],\n\tconfig: AgentLoopConfig,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, AgentContext[\"messages\"]>,\n\tstreamFn?: typeof streamSimple,\n): Promise<void> {\n\tlet hasMoreToolCalls = true;\n\tlet firstTurn = true;\n\tlet queuedMessages: QueuedMessage<any>[] = (await config.getQueuedMessages?.()) || [];\n\n\twhile (hasMoreToolCalls || queuedMessages.length > 0) {\n\t\tif (!firstTurn) {\n\t\t\tstream.push({ type: \"turn_start\" });\n\t\t} else {\n\t\t\tfirstTurn = false;\n\t\t}\n\n\t\t// Process queued messages first (inject before next assistant response)\n\t\tif (queuedMessages.length > 0) {\n\t\t\tfor (const { original, llm } of queuedMessages) {\n\t\t\t\tstream.push({ type: \"message_start\", message: original });\n\t\t\t\tstream.push({ type: \"message_end\", message: original });\n\t\t\t\tif (llm) {\n\t\t\t\t\tcurrentContext.messages.push(llm);\n\t\t\t\t\tnewMessages.push(llm);\n\t\t\t\t}\n\t\t\t}\n\t\t\tqueuedMessages = [];\n\t\t}\n\n\t\t// Stream assistant response\n\t\tconst message = await streamAssistantResponse(currentContext, config, signal, stream, streamFn);\n\t\tnewMessages.push(message);\n\n\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\t// Stop the loop on error or abort\n\t\t\tstream.push({ type: \"turn_end\", message, toolResults: [] });\n\t\t\tstream.push({ type: \"agent_end\", messages: newMessages });\n\t\t\tstream.end(newMessages);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for tool calls\n\t\tconst toolCalls = message.content.filter((c) => c.type === \"toolCall\");\n\t\thasMoreToolCalls = toolCalls.length > 0;\n\n\t\tconst toolResults: ToolResultMessage[] = [];\n\t\tif (hasMoreToolCalls) {\n\t\t\t// Execute tool calls\n\t\t\ttoolResults.push(...(await executeToolCalls(currentContext.tools, message, signal, stream)));\n\t\t\tcurrentContext.messages.push(...toolResults);\n\t\t\tnewMessages.push(...toolResults);\n\t\t}\n\t\tstream.push({ type: \"turn_end\", message, toolResults: toolResults });\n\n\t\t// Get queued messages after turn completes\n\t\tqueuedMessages = (await config.getQueuedMessages?.()) || [];\n\t}\n\n\tstream.push({ type: \"agent_end\", messages: newMessages });\n\tstream.end(newMessages);\n}\n\n// Helper functions\nasync function streamAssistantResponse(\n\tcontext: AgentContext,\n\tconfig: AgentLoopConfig,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, AgentContext[\"messages\"]>,\n\tstreamFn?: typeof streamSimple,\n): Promise<AssistantMessage> {\n\t// Convert AgentContext to Context for streamSimple\n\t// Use a copy of messages to avoid mutating the original context\n\tconst processedMessages = config.preprocessor\n\t\t? await config.preprocessor(context.messages, signal)\n\t\t: [...context.messages];\n\tconst processedContext: Context = {\n\t\tsystemPrompt: context.systemPrompt,\n\t\tmessages: [...processedMessages].map((m) => {\n\t\t\tif (m.role === \"toolResult\") {\n\t\t\t\tconst { details, ...rest } = m;\n\t\t\t\treturn rest;\n\t\t\t} else {\n\t\t\t\treturn m;\n\t\t\t}\n\t\t}),\n\t\ttools: context.tools, // AgentTool extends Tool, so this works\n\t};\n\n\t// Use custom stream function if provided, otherwise use default streamSimple\n\tconst streamFunction = streamFn || streamSimple;\n\tconst response = await streamFunction(config.model, processedContext, { ...config, signal });\n\n\tlet partialMessage: AssistantMessage | null = null;\n\tlet addedPartial = false;\n\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\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({ type: \"message_update\", assistantMessageEvent: event, message: { ...partialMessage } });\n\t\t\t\t}\n\t\t\t\tbreak;\n\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\n\treturn await response.result();\n}\n\nasync function executeToolCalls<T>(\n\ttools: AgentTool<any, T>[] | undefined,\n\tassistantMessage: AssistantMessage,\n\tsignal: AbortSignal | undefined,\n\tstream: EventStream<AgentEvent, Message[]>,\n): Promise<ToolResultMessage<T>[]> {\n\tconst toolCalls = assistantMessage.content.filter((c) => c.type === \"toolCall\");\n\tconst results: ToolResultMessage<any>[] = [];\n\n\tfor (const toolCall of toolCalls) {\n\t\tconst tool = tools?.find((t) => t.name === toolCall.name);\n\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\n\t\tlet resultOrError: AgentToolResult<T> | string;\n\t\tlet isError = false;\n\n\t\ttry {\n\t\t\tif (!tool) throw new Error(`Tool ${toolCall.name} not found`);\n\n\t\t\t// Validate arguments using shared validation function\n\t\t\tconst validatedArgs = validateToolArguments(tool, toolCall);\n\n\t\t\t// Execute with validated, typed arguments\n\t\t\tresultOrError = await tool.execute(toolCall.id, validatedArgs, signal);\n\t\t} catch (e) {\n\t\t\tresultOrError = e instanceof Error ? e.message : String(e);\n\t\t\tisError = true;\n\t\t}\n\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: resultOrError,\n\t\t\tisError,\n\t\t});\n\n\t\t// Convert result to content blocks\n\t\tconst content: ToolResultMessage<T>[\"content\"] =\n\t\t\ttypeof resultOrError === \"string\" ? [{ type: \"text\", text: resultOrError }] : resultOrError.content;\n\n\t\tconst toolResultMessage: ToolResultMessage<T> = {\n\t\t\trole: \"toolResult\",\n\t\t\ttoolCallId: toolCall.id,\n\t\t\ttoolName: toolCall.name,\n\t\t\tcontent,\n\t\t\tdetails: typeof resultOrError === \"string\" ? ({} as T) : resultOrError.details,\n\t\t\tisError,\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tresults.push(toolResultMessage);\n\t\tstream.push({ type: \"message_start\", message: toolResultMessage });\n\t\tstream.push({ type: \"message_end\", message: toolResultMessage });\n\t}\n\n\treturn results;\n}\n"]}
|
package/dist/agent/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { agentLoop } from "./agent-loop.js";
|
|
1
|
+
export { agentLoop, agentLoopContinue } from "./agent-loop.js";
|
|
2
2
|
export * from "./tools/index.js";
|
|
3
|
-
export type { AgentContext, AgentEvent, AgentLoopConfig, AgentTool, QueuedMessage } from "./types.js";
|
|
3
|
+
export type { AgentContext, AgentEvent, AgentLoopConfig, AgentTool, AgentToolResult, QueuedMessage } from "./types.js";
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,cAAc,kBAAkB,CAAC;AACjC,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export { agentLoop, agentLoopContinue } from \"./agent-loop.js\";\nexport * from \"./tools/index.js\";\nexport type { AgentContext, AgentEvent, AgentLoopConfig, AgentTool, AgentToolResult, QueuedMessage } from \"./types.js\";\n"]}
|
package/dist/agent/index.js
CHANGED
package/dist/agent/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,cAAc,kBAAkB,CAAC","sourcesContent":["export { agentLoop, agentLoopContinue } from \"./agent-loop.js\";\nexport * from \"./tools/index.js\";\nexport type { AgentContext, AgentEvent, AgentLoopConfig, AgentTool, AgentToolResult, QueuedMessage } from \"./types.js\";\n"]}
|
|
@@ -1986,6 +1986,23 @@ export declare const MODELS: {
|
|
|
1986
1986
|
};
|
|
1987
1987
|
};
|
|
1988
1988
|
readonly openrouter: {
|
|
1989
|
+
readonly "mistralai/devstral-2512:free": {
|
|
1990
|
+
id: string;
|
|
1991
|
+
name: string;
|
|
1992
|
+
api: "openai-completions";
|
|
1993
|
+
provider: string;
|
|
1994
|
+
baseUrl: string;
|
|
1995
|
+
reasoning: false;
|
|
1996
|
+
input: "text"[];
|
|
1997
|
+
cost: {
|
|
1998
|
+
input: number;
|
|
1999
|
+
output: number;
|
|
2000
|
+
cacheRead: number;
|
|
2001
|
+
cacheWrite: number;
|
|
2002
|
+
};
|
|
2003
|
+
contextWindow: number;
|
|
2004
|
+
maxTokens: number;
|
|
2005
|
+
};
|
|
1989
2006
|
readonly "relace/relace-search": {
|
|
1990
2007
|
id: string;
|
|
1991
2008
|
name: string;
|
|
@@ -5250,7 +5267,7 @@ export declare const MODELS: {
|
|
|
5250
5267
|
contextWindow: number;
|
|
5251
5268
|
maxTokens: number;
|
|
5252
5269
|
};
|
|
5253
|
-
readonly "meta-llama/llama-3.1-
|
|
5270
|
+
readonly "meta-llama/llama-3.1-405b-instruct": {
|
|
5254
5271
|
id: string;
|
|
5255
5272
|
name: string;
|
|
5256
5273
|
api: "openai-completions";
|
|
@@ -5284,7 +5301,7 @@ export declare const MODELS: {
|
|
|
5284
5301
|
contextWindow: number;
|
|
5285
5302
|
maxTokens: number;
|
|
5286
5303
|
};
|
|
5287
|
-
readonly "meta-llama/llama-3.1-
|
|
5304
|
+
readonly "meta-llama/llama-3.1-8b-instruct": {
|
|
5288
5305
|
id: string;
|
|
5289
5306
|
name: string;
|
|
5290
5307
|
api: "openai-completions";
|
|
@@ -5318,7 +5335,7 @@ export declare const MODELS: {
|
|
|
5318
5335
|
contextWindow: number;
|
|
5319
5336
|
maxTokens: number;
|
|
5320
5337
|
};
|
|
5321
|
-
readonly "openai/gpt-4o-mini": {
|
|
5338
|
+
readonly "openai/gpt-4o-mini-2024-07-18": {
|
|
5322
5339
|
id: string;
|
|
5323
5340
|
name: string;
|
|
5324
5341
|
api: "openai-completions";
|
|
@@ -5335,7 +5352,7 @@ export declare const MODELS: {
|
|
|
5335
5352
|
contextWindow: number;
|
|
5336
5353
|
maxTokens: number;
|
|
5337
5354
|
};
|
|
5338
|
-
readonly "openai/gpt-4o-mini
|
|
5355
|
+
readonly "openai/gpt-4o-mini": {
|
|
5339
5356
|
id: string;
|
|
5340
5357
|
name: string;
|
|
5341
5358
|
api: "openai-completions";
|
|
@@ -5488,7 +5505,7 @@ export declare const MODELS: {
|
|
|
5488
5505
|
contextWindow: number;
|
|
5489
5506
|
maxTokens: number;
|
|
5490
5507
|
};
|
|
5491
|
-
readonly "meta-llama/llama-3-
|
|
5508
|
+
readonly "meta-llama/llama-3-8b-instruct": {
|
|
5492
5509
|
id: string;
|
|
5493
5510
|
name: string;
|
|
5494
5511
|
api: "openai-completions";
|
|
@@ -5505,7 +5522,7 @@ export declare const MODELS: {
|
|
|
5505
5522
|
contextWindow: number;
|
|
5506
5523
|
maxTokens: number;
|
|
5507
5524
|
};
|
|
5508
|
-
readonly "meta-llama/llama-3-
|
|
5525
|
+
readonly "meta-llama/llama-3-70b-instruct": {
|
|
5509
5526
|
id: string;
|
|
5510
5527
|
name: string;
|
|
5511
5528
|
api: "openai-completions";
|
|
@@ -5709,7 +5726,7 @@ export declare const MODELS: {
|
|
|
5709
5726
|
contextWindow: number;
|
|
5710
5727
|
maxTokens: number;
|
|
5711
5728
|
};
|
|
5712
|
-
readonly "openai/gpt-4
|
|
5729
|
+
readonly "openai/gpt-4": {
|
|
5713
5730
|
id: string;
|
|
5714
5731
|
name: string;
|
|
5715
5732
|
api: "openai-completions";
|
|
@@ -5726,7 +5743,7 @@ export declare const MODELS: {
|
|
|
5726
5743
|
contextWindow: number;
|
|
5727
5744
|
maxTokens: number;
|
|
5728
5745
|
};
|
|
5729
|
-
readonly "openai/gpt-
|
|
5746
|
+
readonly "openai/gpt-3.5-turbo": {
|
|
5730
5747
|
id: string;
|
|
5731
5748
|
name: string;
|
|
5732
5749
|
api: "openai-completions";
|
|
@@ -5743,7 +5760,7 @@ export declare const MODELS: {
|
|
|
5743
5760
|
contextWindow: number;
|
|
5744
5761
|
maxTokens: number;
|
|
5745
5762
|
};
|
|
5746
|
-
readonly "openai/gpt-
|
|
5763
|
+
readonly "openai/gpt-4-0314": {
|
|
5747
5764
|
id: string;
|
|
5748
5765
|
name: string;
|
|
5749
5766
|
api: "openai-completions";
|