@mariozechner/pi-ai 0.30.1 → 0.31.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 +0 -270
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/models.generated.d.ts +1084 -1063
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.generated.js +3887 -3880
- package/dist/models.generated.js.map +1 -1
- package/dist/providers/google-gemini-cli.d.ts +6 -2
- package/dist/providers/google-gemini-cli.d.ts.map +1 -1
- package/dist/providers/google-gemini-cli.js +1 -0
- package/dist/providers/google-gemini-cli.js.map +1 -1
- package/dist/providers/google.d.ts +2 -2
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +1 -0
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/openai-completions.d.ts.map +1 -1
- package/dist/providers/openai-completions.js +13 -7
- package/dist/providers/openai-completions.js.map +1 -1
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +17 -15
- package/dist/stream.js.map +1 -1
- package/dist/utils/oauth/anthropic.d.ts.map +1 -1
- package/dist/utils/oauth/anthropic.js +3 -11
- package/dist/utils/oauth/anthropic.js.map +1 -1
- package/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/dist/utils/oauth/github-copilot.js +1 -1
- package/dist/utils/oauth/github-copilot.js.map +1 -1
- package/dist/utils/oauth/google-antigravity.d.ts +3 -0
- package/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
- package/dist/utils/oauth/google-antigravity.js +8 -13
- package/dist/utils/oauth/google-antigravity.js.map +1 -1
- package/dist/utils/oauth/google-gemini-cli.d.ts +3 -0
- package/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
- package/dist/utils/oauth/google-gemini-cli.js +8 -13
- package/dist/utils/oauth/google-gemini-cli.js.map +1 -1
- package/dist/utils/oauth/pkce.d.ts +13 -0
- package/dist/utils/oauth/pkce.d.ts.map +1 -0
- package/dist/utils/oauth/pkce.js +31 -0
- package/dist/utils/oauth/pkce.js.map +1 -0
- package/package.json +1 -1
- package/dist/agent/agent-loop.d.ts +0 -16
- package/dist/agent/agent-loop.d.ts.map +0 -1
- package/dist/agent/agent-loop.js +0 -286
- package/dist/agent/agent-loop.js.map +0 -1
- package/dist/agent/index.d.ts +0 -4
- package/dist/agent/index.d.ts.map +0 -1
- package/dist/agent/index.js +0 -3
- package/dist/agent/index.js.map +0 -1
- package/dist/agent/tools/calculate.d.ts +0 -15
- package/dist/agent/tools/calculate.d.ts.map +0 -1
- package/dist/agent/tools/calculate.js +0 -23
- package/dist/agent/tools/calculate.js.map +0 -1
- package/dist/agent/tools/get-current-time.d.ts +0 -15
- package/dist/agent/tools/get-current-time.d.ts.map +0 -1
- package/dist/agent/tools/get-current-time.js +0 -38
- package/dist/agent/tools/get-current-time.js.map +0 -1
- package/dist/agent/tools/index.d.ts +0 -3
- package/dist/agent/tools/index.d.ts.map +0 -1
- package/dist/agent/tools/index.js +0 -3
- package/dist/agent/tools/index.js.map +0 -1
- package/dist/agent/types.d.ts +0 -78
- package/dist/agent/types.d.ts.map +0 -1
- package/dist/agent/types.js +0 -2
- package/dist/agent/types.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/pkce.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAarF","sourcesContent":["/**\n * PKCE utilities using Web Crypto API.\n * Works in both Node.js 20+ and browsers.\n */\n\n/**\n * Encode bytes as base64url string.\n */\nfunction base64urlEncode(bytes: Uint8Array): string {\n\tlet binary = \"\";\n\tfor (const byte of bytes) {\n\t\tbinary += String.fromCharCode(byte);\n\t}\n\treturn btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=/g, \"\");\n}\n\n/**\n * Generate PKCE code verifier and challenge.\n * Uses Web Crypto API for cross-platform compatibility.\n */\nexport async function generatePKCE(): Promise<{ verifier: string; challenge: string }> {\n\t// Generate random verifier\n\tconst verifierBytes = new Uint8Array(32);\n\tcrypto.getRandomValues(verifierBytes);\n\tconst verifier = base64urlEncode(verifierBytes);\n\n\t// Compute SHA-256 challenge\n\tconst encoder = new TextEncoder();\n\tconst data = encoder.encode(verifier);\n\tconst hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n\tconst challenge = base64urlEncode(new Uint8Array(hashBuffer));\n\n\treturn { verifier, challenge };\n}\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PKCE utilities using Web Crypto API.
|
|
3
|
+
* Works in both Node.js 20+ and browsers.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Encode bytes as base64url string.
|
|
7
|
+
*/
|
|
8
|
+
function base64urlEncode(bytes) {
|
|
9
|
+
let binary = "";
|
|
10
|
+
for (const byte of bytes) {
|
|
11
|
+
binary += String.fromCharCode(byte);
|
|
12
|
+
}
|
|
13
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Generate PKCE code verifier and challenge.
|
|
17
|
+
* Uses Web Crypto API for cross-platform compatibility.
|
|
18
|
+
*/
|
|
19
|
+
export async function generatePKCE() {
|
|
20
|
+
// Generate random verifier
|
|
21
|
+
const verifierBytes = new Uint8Array(32);
|
|
22
|
+
crypto.getRandomValues(verifierBytes);
|
|
23
|
+
const verifier = base64urlEncode(verifierBytes);
|
|
24
|
+
// Compute SHA-256 challenge
|
|
25
|
+
const encoder = new TextEncoder();
|
|
26
|
+
const data = encoder.encode(verifier);
|
|
27
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
28
|
+
const challenge = base64urlEncode(new Uint8Array(hashBuffer));
|
|
29
|
+
return { verifier, challenge };
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=pkce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../../src/utils/oauth/pkce.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,SAAS,eAAe,CAAC,KAAiB,EAAU;IACnD,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAAA,CAC9E;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,GAAqD;IACtF,2BAA2B;IAC3B,MAAM,aAAa,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACzC,MAAM,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;IAEhD,4BAA4B;IAC5B,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;IAE9D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAAA,CAC/B","sourcesContent":["/**\n * PKCE utilities using Web Crypto API.\n * Works in both Node.js 20+ and browsers.\n */\n\n/**\n * Encode bytes as base64url string.\n */\nfunction base64urlEncode(bytes: Uint8Array): string {\n\tlet binary = \"\";\n\tfor (const byte of bytes) {\n\t\tbinary += String.fromCharCode(byte);\n\t}\n\treturn btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=/g, \"\");\n}\n\n/**\n * Generate PKCE code verifier and challenge.\n * Uses Web Crypto API for cross-platform compatibility.\n */\nexport async function generatePKCE(): Promise<{ verifier: string; challenge: string }> {\n\t// Generate random verifier\n\tconst verifierBytes = new Uint8Array(32);\n\tcrypto.getRandomValues(verifierBytes);\n\tconst verifier = base64urlEncode(verifierBytes);\n\n\t// Compute SHA-256 challenge\n\tconst encoder = new TextEncoder();\n\tconst data = encoder.encode(verifier);\n\tconst hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n\tconst challenge = base64urlEncode(new Uint8Array(hashBuffer));\n\n\treturn { verifier, challenge };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { streamSimple } from "../stream.js";
|
|
2
|
-
import type { UserMessage } from "../types.js";
|
|
3
|
-
import { EventStream } from "../utils/event-stream.js";
|
|
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
|
-
*/
|
|
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"]>;
|
|
16
|
-
//# sourceMappingURL=agent-loop.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
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\tlet queuedAfterTools: QueuedMessage<any>[] | null = null;\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\tconst toolExecution = await executeToolCalls(\n\t\t\t\tcurrentContext.tools,\n\t\t\t\tmessage,\n\t\t\t\tsignal,\n\t\t\t\tstream,\n\t\t\t\tconfig.getQueuedMessages,\n\t\t\t);\n\t\t\ttoolResults.push(...toolExecution.toolResults);\n\t\t\tqueuedAfterTools = toolExecution.queuedMessages ?? null;\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\tif (queuedAfterTools && queuedAfterTools.length > 0) {\n\t\t\tqueuedMessages = queuedAfterTools;\n\t\t\tqueuedAfterTools = null;\n\t\t} else {\n\t\t\tqueuedMessages = (await config.getQueuedMessages?.()) || [];\n\t\t}\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\t// biome-ignore lint/correctness/noUnusedVariables: fine here\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\n\t// Resolve API key for every assistant response (important for expiring tokens)\n\tconst resolvedApiKey =\n\t\t(config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;\n\n\tconst response = await streamFunction(config.model, processedContext, { ...config, apiKey: resolvedApiKey, 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\tgetQueuedMessages?: AgentLoopConfig[\"getQueuedMessages\"],\n): Promise<{ toolResults: ToolResultMessage<T>[]; queuedMessages?: QueuedMessage<any>[] }> {\n\tconst toolCalls = assistantMessage.content.filter((c) => c.type === \"toolCall\");\n\tconst results: ToolResultMessage<any>[] = [];\n\tlet queuedMessages: QueuedMessage<any>[] | undefined;\n\n\tfor (let index = 0; index < toolCalls.length; index++) {\n\t\tconst toolCall = toolCalls[index];\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 result: AgentToolResult<T>;\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, passing update callback\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: {} as T,\n\t\t\t};\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,\n\t\t\tisError,\n\t\t});\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: result.content,\n\t\t\tdetails: result.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\n\t\tif (getQueuedMessages) {\n\t\t\tconst queued = await getQueuedMessages();\n\t\t\tif (queued.length > 0) {\n\t\t\t\tqueuedMessages = queued;\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\n\treturn { toolResults: results, queuedMessages };\n}\n\nfunction skipToolCall<T>(\n\ttoolCall: Extract<AssistantMessage[\"content\"][number], { type: \"toolCall\" }>,\n\tstream: EventStream<AgentEvent, Message[]>,\n): ToolResultMessage<T> {\n\tconst result: AgentToolResult<T> = {\n\t\tcontent: [{ type: \"text\", text: \"Skipped due to queued user message.\" }],\n\t\tdetails: {} as T,\n\t};\n\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\n\tconst toolResultMessage: ToolResultMessage<T> = {\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: true,\n\t\ttimestamp: Date.now(),\n\t};\n\n\tstream.push({ type: \"message_start\", message: toolResultMessage });\n\tstream.push({ type: \"message_end\", message: toolResultMessage });\n\n\treturn toolResultMessage;\n}\n"]}
|
package/dist/agent/agent-loop.js
DELETED
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
import { streamSimple } from "../stream.js";
|
|
2
|
-
import { EventStream } from "../utils/event-stream.js";
|
|
3
|
-
import { validateToolArguments } from "../utils/validation.js";
|
|
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
|
-
*/
|
|
8
|
-
export function agentLoop(prompt, context, config, signal, streamFn) {
|
|
9
|
-
const stream = createAgentStream();
|
|
10
|
-
(async () => {
|
|
11
|
-
const newMessages = [prompt];
|
|
12
|
-
const currentContext = {
|
|
13
|
-
...context,
|
|
14
|
-
messages: [...context.messages, prompt],
|
|
15
|
-
};
|
|
16
|
-
stream.push({ type: "agent_start" });
|
|
17
|
-
stream.push({ type: "turn_start" });
|
|
18
|
-
stream.push({ type: "message_start", message: prompt });
|
|
19
|
-
stream.push({ type: "message_end", message: prompt });
|
|
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
|
-
let queuedAfterTools = null;
|
|
60
|
-
while (hasMoreToolCalls || queuedMessages.length > 0) {
|
|
61
|
-
if (!firstTurn) {
|
|
62
|
-
stream.push({ type: "turn_start" });
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
firstTurn = false;
|
|
66
|
-
}
|
|
67
|
-
// Process queued messages first (inject before next assistant response)
|
|
68
|
-
if (queuedMessages.length > 0) {
|
|
69
|
-
for (const { original, llm } of queuedMessages) {
|
|
70
|
-
stream.push({ type: "message_start", message: original });
|
|
71
|
-
stream.push({ type: "message_end", message: original });
|
|
72
|
-
if (llm) {
|
|
73
|
-
currentContext.messages.push(llm);
|
|
74
|
-
newMessages.push(llm);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
queuedMessages = [];
|
|
78
|
-
}
|
|
79
|
-
// Stream assistant response
|
|
80
|
-
const message = await streamAssistantResponse(currentContext, config, signal, stream, streamFn);
|
|
81
|
-
newMessages.push(message);
|
|
82
|
-
if (message.stopReason === "error" || message.stopReason === "aborted") {
|
|
83
|
-
// Stop the loop on error or abort
|
|
84
|
-
stream.push({ type: "turn_end", message, toolResults: [] });
|
|
85
|
-
stream.push({ type: "agent_end", messages: newMessages });
|
|
86
|
-
stream.end(newMessages);
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
// Check for tool calls
|
|
90
|
-
const toolCalls = message.content.filter((c) => c.type === "toolCall");
|
|
91
|
-
hasMoreToolCalls = toolCalls.length > 0;
|
|
92
|
-
const toolResults = [];
|
|
93
|
-
if (hasMoreToolCalls) {
|
|
94
|
-
// Execute tool calls
|
|
95
|
-
const toolExecution = await executeToolCalls(currentContext.tools, message, signal, stream, config.getQueuedMessages);
|
|
96
|
-
toolResults.push(...toolExecution.toolResults);
|
|
97
|
-
queuedAfterTools = toolExecution.queuedMessages ?? null;
|
|
98
|
-
currentContext.messages.push(...toolResults);
|
|
99
|
-
newMessages.push(...toolResults);
|
|
100
|
-
}
|
|
101
|
-
stream.push({ type: "turn_end", message, toolResults: toolResults });
|
|
102
|
-
// Get queued messages after turn completes
|
|
103
|
-
if (queuedAfterTools && queuedAfterTools.length > 0) {
|
|
104
|
-
queuedMessages = queuedAfterTools;
|
|
105
|
-
queuedAfterTools = null;
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
queuedMessages = (await config.getQueuedMessages?.()) || [];
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
stream.push({ type: "agent_end", messages: newMessages });
|
|
112
|
-
stream.end(newMessages);
|
|
113
|
-
}
|
|
114
|
-
// Helper functions
|
|
115
|
-
async function streamAssistantResponse(context, config, signal, stream, streamFn) {
|
|
116
|
-
// Convert AgentContext to Context for streamSimple
|
|
117
|
-
// Use a copy of messages to avoid mutating the original context
|
|
118
|
-
const processedMessages = config.preprocessor
|
|
119
|
-
? await config.preprocessor(context.messages, signal)
|
|
120
|
-
: [...context.messages];
|
|
121
|
-
const processedContext = {
|
|
122
|
-
systemPrompt: context.systemPrompt,
|
|
123
|
-
messages: [...processedMessages].map((m) => {
|
|
124
|
-
if (m.role === "toolResult") {
|
|
125
|
-
// biome-ignore lint/correctness/noUnusedVariables: fine here
|
|
126
|
-
const { details, ...rest } = m;
|
|
127
|
-
return rest;
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
return m;
|
|
131
|
-
}
|
|
132
|
-
}),
|
|
133
|
-
tools: context.tools, // AgentTool extends Tool, so this works
|
|
134
|
-
};
|
|
135
|
-
// Use custom stream function if provided, otherwise use default streamSimple
|
|
136
|
-
const streamFunction = streamFn || streamSimple;
|
|
137
|
-
// Resolve API key for every assistant response (important for expiring tokens)
|
|
138
|
-
const resolvedApiKey = (config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;
|
|
139
|
-
const response = await streamFunction(config.model, processedContext, { ...config, apiKey: resolvedApiKey, signal });
|
|
140
|
-
let partialMessage = null;
|
|
141
|
-
let addedPartial = false;
|
|
142
|
-
for await (const event of response) {
|
|
143
|
-
switch (event.type) {
|
|
144
|
-
case "start":
|
|
145
|
-
partialMessage = event.partial;
|
|
146
|
-
context.messages.push(partialMessage);
|
|
147
|
-
addedPartial = true;
|
|
148
|
-
stream.push({ type: "message_start", message: { ...partialMessage } });
|
|
149
|
-
break;
|
|
150
|
-
case "text_start":
|
|
151
|
-
case "text_delta":
|
|
152
|
-
case "text_end":
|
|
153
|
-
case "thinking_start":
|
|
154
|
-
case "thinking_delta":
|
|
155
|
-
case "thinking_end":
|
|
156
|
-
case "toolcall_start":
|
|
157
|
-
case "toolcall_delta":
|
|
158
|
-
case "toolcall_end":
|
|
159
|
-
if (partialMessage) {
|
|
160
|
-
partialMessage = event.partial;
|
|
161
|
-
context.messages[context.messages.length - 1] = partialMessage;
|
|
162
|
-
stream.push({ type: "message_update", assistantMessageEvent: event, message: { ...partialMessage } });
|
|
163
|
-
}
|
|
164
|
-
break;
|
|
165
|
-
case "done":
|
|
166
|
-
case "error": {
|
|
167
|
-
const finalMessage = await response.result();
|
|
168
|
-
if (addedPartial) {
|
|
169
|
-
context.messages[context.messages.length - 1] = finalMessage;
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
context.messages.push(finalMessage);
|
|
173
|
-
}
|
|
174
|
-
if (!addedPartial) {
|
|
175
|
-
stream.push({ type: "message_start", message: { ...finalMessage } });
|
|
176
|
-
}
|
|
177
|
-
stream.push({ type: "message_end", message: finalMessage });
|
|
178
|
-
return finalMessage;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return await response.result();
|
|
183
|
-
}
|
|
184
|
-
async function executeToolCalls(tools, assistantMessage, signal, stream, getQueuedMessages) {
|
|
185
|
-
const toolCalls = assistantMessage.content.filter((c) => c.type === "toolCall");
|
|
186
|
-
const results = [];
|
|
187
|
-
let queuedMessages;
|
|
188
|
-
for (let index = 0; index < toolCalls.length; index++) {
|
|
189
|
-
const toolCall = toolCalls[index];
|
|
190
|
-
const tool = tools?.find((t) => t.name === toolCall.name);
|
|
191
|
-
stream.push({
|
|
192
|
-
type: "tool_execution_start",
|
|
193
|
-
toolCallId: toolCall.id,
|
|
194
|
-
toolName: toolCall.name,
|
|
195
|
-
args: toolCall.arguments,
|
|
196
|
-
});
|
|
197
|
-
let result;
|
|
198
|
-
let isError = false;
|
|
199
|
-
try {
|
|
200
|
-
if (!tool)
|
|
201
|
-
throw new Error(`Tool ${toolCall.name} not found`);
|
|
202
|
-
// Validate arguments using shared validation function
|
|
203
|
-
const validatedArgs = validateToolArguments(tool, toolCall);
|
|
204
|
-
// Execute with validated, typed arguments, passing update callback
|
|
205
|
-
result = await tool.execute(toolCall.id, validatedArgs, signal, (partialResult) => {
|
|
206
|
-
stream.push({
|
|
207
|
-
type: "tool_execution_update",
|
|
208
|
-
toolCallId: toolCall.id,
|
|
209
|
-
toolName: toolCall.name,
|
|
210
|
-
args: toolCall.arguments,
|
|
211
|
-
partialResult,
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
catch (e) {
|
|
216
|
-
result = {
|
|
217
|
-
content: [{ type: "text", text: e instanceof Error ? e.message : String(e) }],
|
|
218
|
-
details: {},
|
|
219
|
-
};
|
|
220
|
-
isError = true;
|
|
221
|
-
}
|
|
222
|
-
stream.push({
|
|
223
|
-
type: "tool_execution_end",
|
|
224
|
-
toolCallId: toolCall.id,
|
|
225
|
-
toolName: toolCall.name,
|
|
226
|
-
result,
|
|
227
|
-
isError,
|
|
228
|
-
});
|
|
229
|
-
const toolResultMessage = {
|
|
230
|
-
role: "toolResult",
|
|
231
|
-
toolCallId: toolCall.id,
|
|
232
|
-
toolName: toolCall.name,
|
|
233
|
-
content: result.content,
|
|
234
|
-
details: result.details,
|
|
235
|
-
isError,
|
|
236
|
-
timestamp: Date.now(),
|
|
237
|
-
};
|
|
238
|
-
results.push(toolResultMessage);
|
|
239
|
-
stream.push({ type: "message_start", message: toolResultMessage });
|
|
240
|
-
stream.push({ type: "message_end", message: toolResultMessage });
|
|
241
|
-
if (getQueuedMessages) {
|
|
242
|
-
const queued = await getQueuedMessages();
|
|
243
|
-
if (queued.length > 0) {
|
|
244
|
-
queuedMessages = queued;
|
|
245
|
-
const remainingCalls = toolCalls.slice(index + 1);
|
|
246
|
-
for (const skipped of remainingCalls) {
|
|
247
|
-
results.push(skipToolCall(skipped, stream));
|
|
248
|
-
}
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
return { toolResults: results, queuedMessages };
|
|
254
|
-
}
|
|
255
|
-
function skipToolCall(toolCall, stream) {
|
|
256
|
-
const result = {
|
|
257
|
-
content: [{ type: "text", text: "Skipped due to queued user message." }],
|
|
258
|
-
details: {},
|
|
259
|
-
};
|
|
260
|
-
stream.push({
|
|
261
|
-
type: "tool_execution_start",
|
|
262
|
-
toolCallId: toolCall.id,
|
|
263
|
-
toolName: toolCall.name,
|
|
264
|
-
args: toolCall.arguments,
|
|
265
|
-
});
|
|
266
|
-
stream.push({
|
|
267
|
-
type: "tool_execution_end",
|
|
268
|
-
toolCallId: toolCall.id,
|
|
269
|
-
toolName: toolCall.name,
|
|
270
|
-
result,
|
|
271
|
-
isError: true,
|
|
272
|
-
});
|
|
273
|
-
const toolResultMessage = {
|
|
274
|
-
role: "toolResult",
|
|
275
|
-
toolCallId: toolCall.id,
|
|
276
|
-
toolName: toolCall.name,
|
|
277
|
-
content: result.content,
|
|
278
|
-
details: result.details,
|
|
279
|
-
isError: true,
|
|
280
|
-
timestamp: Date.now(),
|
|
281
|
-
};
|
|
282
|
-
stream.push({ type: "message_start", message: toolResultMessage });
|
|
283
|
-
stream.push({ type: "message_end", message: toolResultMessage });
|
|
284
|
-
return toolResultMessage;
|
|
285
|
-
}
|
|
286
|
-
//# sourceMappingURL=agent-loop.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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\tlet queuedAfterTools: QueuedMessage<any>[] | null = null;\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\tconst toolExecution = await executeToolCalls(\n\t\t\t\tcurrentContext.tools,\n\t\t\t\tmessage,\n\t\t\t\tsignal,\n\t\t\t\tstream,\n\t\t\t\tconfig.getQueuedMessages,\n\t\t\t);\n\t\t\ttoolResults.push(...toolExecution.toolResults);\n\t\t\tqueuedAfterTools = toolExecution.queuedMessages ?? null;\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\tif (queuedAfterTools && queuedAfterTools.length > 0) {\n\t\t\tqueuedMessages = queuedAfterTools;\n\t\t\tqueuedAfterTools = null;\n\t\t} else {\n\t\t\tqueuedMessages = (await config.getQueuedMessages?.()) || [];\n\t\t}\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\t// biome-ignore lint/correctness/noUnusedVariables: fine here\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\n\t// Resolve API key for every assistant response (important for expiring tokens)\n\tconst resolvedApiKey =\n\t\t(config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;\n\n\tconst response = await streamFunction(config.model, processedContext, { ...config, apiKey: resolvedApiKey, 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\tgetQueuedMessages?: AgentLoopConfig[\"getQueuedMessages\"],\n): Promise<{ toolResults: ToolResultMessage<T>[]; queuedMessages?: QueuedMessage<any>[] }> {\n\tconst toolCalls = assistantMessage.content.filter((c) => c.type === \"toolCall\");\n\tconst results: ToolResultMessage<any>[] = [];\n\tlet queuedMessages: QueuedMessage<any>[] | undefined;\n\n\tfor (let index = 0; index < toolCalls.length; index++) {\n\t\tconst toolCall = toolCalls[index];\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 result: AgentToolResult<T>;\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, passing update callback\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: {} as T,\n\t\t\t};\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,\n\t\t\tisError,\n\t\t});\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: result.content,\n\t\t\tdetails: result.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\n\t\tif (getQueuedMessages) {\n\t\t\tconst queued = await getQueuedMessages();\n\t\t\tif (queued.length > 0) {\n\t\t\t\tqueuedMessages = queued;\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\n\treturn { toolResults: results, queuedMessages };\n}\n\nfunction skipToolCall<T>(\n\ttoolCall: Extract<AssistantMessage[\"content\"][number], { type: \"toolCall\" }>,\n\tstream: EventStream<AgentEvent, Message[]>,\n): ToolResultMessage<T> {\n\tconst result: AgentToolResult<T> = {\n\t\tcontent: [{ type: \"text\", text: \"Skipped due to queued user message.\" }],\n\t\tdetails: {} as T,\n\t};\n\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\n\tconst toolResultMessage: ToolResultMessage<T> = {\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: true,\n\t\ttimestamp: Date.now(),\n\t};\n\n\tstream.push({ type: \"message_start\", message: toolResultMessage });\n\tstream.push({ type: \"message_end\", message: toolResultMessage });\n\n\treturn toolResultMessage;\n}\n"]}
|
package/dist/agent/index.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export { agentLoop, agentLoopContinue } from "./agent-loop.js";
|
|
2
|
-
export * from "./tools/index.js";
|
|
3
|
-
export type { AgentContext, AgentEvent, AgentLoopConfig, AgentTool, AgentToolResult, AgentToolUpdateCallback, QueuedMessage, } from "./types.js";
|
|
4
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
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,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EACf,SAAS,EACT,eAAe,EACf,uBAAuB,EACvB,aAAa,GACb,MAAM,YAAY,CAAC","sourcesContent":["export { agentLoop, agentLoopContinue } from \"./agent-loop.js\";\nexport * from \"./tools/index.js\";\nexport type {\n\tAgentContext,\n\tAgentEvent,\n\tAgentLoopConfig,\n\tAgentTool,\n\tAgentToolResult,\n\tAgentToolUpdateCallback,\n\tQueuedMessage,\n} from \"./types.js\";\n"]}
|
package/dist/agent/index.js
DELETED
package/dist/agent/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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 {\n\tAgentContext,\n\tAgentEvent,\n\tAgentLoopConfig,\n\tAgentTool,\n\tAgentToolResult,\n\tAgentToolUpdateCallback,\n\tQueuedMessage,\n} from \"./types.js\";\n"]}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { AgentTool, AgentToolResult } from "../../agent/types.js";
|
|
2
|
-
export interface CalculateResult extends AgentToolResult<undefined> {
|
|
3
|
-
content: Array<{
|
|
4
|
-
type: "text";
|
|
5
|
-
text: string;
|
|
6
|
-
}>;
|
|
7
|
-
details: undefined;
|
|
8
|
-
}
|
|
9
|
-
export declare function calculate(expression: string): CalculateResult;
|
|
10
|
-
declare const calculateSchema: import("@sinclair/typebox").TObject<{
|
|
11
|
-
expression: import("@sinclair/typebox").TString;
|
|
12
|
-
}>;
|
|
13
|
-
export declare const calculateTool: AgentTool<typeof calculateSchema, undefined>;
|
|
14
|
-
export {};
|
|
15
|
-
//# sourceMappingURL=calculate.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"calculate.d.ts","sourceRoot":"","sources":["../../../src/agent/tools/calculate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvE,MAAM,WAAW,eAAgB,SAAQ,eAAe,CAAC,SAAS,CAAC;IAClE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,EAAE,SAAS,CAAC;CACnB;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,CAO7D;AAED,QAAA,MAAM,eAAe;;EAEnB,CAAC;AAIH,eAAO,MAAM,aAAa,EAAE,SAAS,CAAC,OAAO,eAAe,EAAE,SAAS,CAQtE,CAAC","sourcesContent":["import { type Static, Type } from \"@sinclair/typebox\";\nimport type { AgentTool, AgentToolResult } from \"../../agent/types.js\";\n\nexport interface CalculateResult extends AgentToolResult<undefined> {\n\tcontent: Array<{ type: \"text\"; text: string }>;\n\tdetails: undefined;\n}\n\nexport function calculate(expression: string): CalculateResult {\n\ttry {\n\t\tconst result = new Function(`return ${expression}`)();\n\t\treturn { content: [{ type: \"text\", text: `${expression} = ${result}` }], details: undefined };\n\t} catch (e: any) {\n\t\tthrow new Error(e.message || String(e));\n\t}\n}\n\nconst calculateSchema = Type.Object({\n\texpression: Type.String({ description: \"The mathematical expression to evaluate\" }),\n});\n\ntype CalculateParams = Static<typeof calculateSchema>;\n\nexport const calculateTool: AgentTool<typeof calculateSchema, undefined> = {\n\tlabel: \"Calculator\",\n\tname: \"calculate\",\n\tdescription: \"Evaluate mathematical expressions\",\n\tparameters: calculateSchema,\n\texecute: async (_toolCallId: string, args: CalculateParams) => {\n\t\treturn calculate(args.expression);\n\t},\n};\n"]}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Type } from "@sinclair/typebox";
|
|
2
|
-
export function calculate(expression) {
|
|
3
|
-
try {
|
|
4
|
-
const result = new Function(`return ${expression}`)();
|
|
5
|
-
return { content: [{ type: "text", text: `${expression} = ${result}` }], details: undefined };
|
|
6
|
-
}
|
|
7
|
-
catch (e) {
|
|
8
|
-
throw new Error(e.message || String(e));
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
const calculateSchema = Type.Object({
|
|
12
|
-
expression: Type.String({ description: "The mathematical expression to evaluate" }),
|
|
13
|
-
});
|
|
14
|
-
export const calculateTool = {
|
|
15
|
-
label: "Calculator",
|
|
16
|
-
name: "calculate",
|
|
17
|
-
description: "Evaluate mathematical expressions",
|
|
18
|
-
parameters: calculateSchema,
|
|
19
|
-
execute: async (_toolCallId, args) => {
|
|
20
|
-
return calculate(args.expression);
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
//# sourceMappingURL=calculate.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"calculate.js","sourceRoot":"","sources":["../../../src/agent/tools/calculate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAQtD,MAAM,UAAU,SAAS,CAAC,UAAkB,EAAmB;IAC9D,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC,UAAU,UAAU,EAAE,CAAC,EAAE,CAAC;QACtD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,UAAU,MAAM,MAAM,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAC/F,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC;AAAA,CACD;AAED,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC;IACnC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,yCAAyC,EAAE,CAAC;CACnF,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,aAAa,GAAiD;IAC1E,KAAK,EAAE,YAAY;IACnB,IAAI,EAAE,WAAW;IACjB,WAAW,EAAE,mCAAmC;IAChD,UAAU,EAAE,eAAe;IAC3B,OAAO,EAAE,KAAK,EAAE,WAAmB,EAAE,IAAqB,EAAE,EAAE,CAAC;QAC9D,OAAO,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAAA,CAClC;CACD,CAAC","sourcesContent":["import { type Static, Type } from \"@sinclair/typebox\";\nimport type { AgentTool, AgentToolResult } from \"../../agent/types.js\";\n\nexport interface CalculateResult extends AgentToolResult<undefined> {\n\tcontent: Array<{ type: \"text\"; text: string }>;\n\tdetails: undefined;\n}\n\nexport function calculate(expression: string): CalculateResult {\n\ttry {\n\t\tconst result = new Function(`return ${expression}`)();\n\t\treturn { content: [{ type: \"text\", text: `${expression} = ${result}` }], details: undefined };\n\t} catch (e: any) {\n\t\tthrow new Error(e.message || String(e));\n\t}\n}\n\nconst calculateSchema = Type.Object({\n\texpression: Type.String({ description: \"The mathematical expression to evaluate\" }),\n});\n\ntype CalculateParams = Static<typeof calculateSchema>;\n\nexport const calculateTool: AgentTool<typeof calculateSchema, undefined> = {\n\tlabel: \"Calculator\",\n\tname: \"calculate\",\n\tdescription: \"Evaluate mathematical expressions\",\n\tparameters: calculateSchema,\n\texecute: async (_toolCallId: string, args: CalculateParams) => {\n\t\treturn calculate(args.expression);\n\t},\n};\n"]}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { AgentTool } from "../../agent/index.js";
|
|
2
|
-
import type { AgentToolResult } from "../types.js";
|
|
3
|
-
export interface GetCurrentTimeResult extends AgentToolResult<{
|
|
4
|
-
utcTimestamp: number;
|
|
5
|
-
}> {
|
|
6
|
-
}
|
|
7
|
-
export declare function getCurrentTime(timezone?: string): Promise<GetCurrentTimeResult>;
|
|
8
|
-
declare const getCurrentTimeSchema: import("@sinclair/typebox").TObject<{
|
|
9
|
-
timezone: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
10
|
-
}>;
|
|
11
|
-
export declare const getCurrentTimeTool: AgentTool<typeof getCurrentTimeSchema, {
|
|
12
|
-
utcTimestamp: number;
|
|
13
|
-
}>;
|
|
14
|
-
export {};
|
|
15
|
-
//# sourceMappingURL=get-current-time.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"get-current-time.d.ts","sourceRoot":"","sources":["../../../src/agent/tools/get-current-time.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,WAAW,oBAAqB,SAAQ,eAAe,CAAC;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC;CAAG;AAE1F,wBAAsB,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAsBrF;AAED,QAAA,MAAM,oBAAoB;;EAIxB,CAAC;AAIH,eAAO,MAAM,kBAAkB,EAAE,SAAS,CAAC,OAAO,oBAAoB,EAAE;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,CAQ/F,CAAC","sourcesContent":["import { type Static, Type } from \"@sinclair/typebox\";\nimport type { AgentTool } from \"../../agent/index.js\";\nimport type { AgentToolResult } from \"../types.js\";\n\nexport interface GetCurrentTimeResult extends AgentToolResult<{ utcTimestamp: number }> {}\n\nexport async function getCurrentTime(timezone?: string): Promise<GetCurrentTimeResult> {\n\tconst date = new Date();\n\tif (timezone) {\n\t\ttry {\n\t\t\tconst timeStr = date.toLocaleString(\"en-US\", {\n\t\t\t\ttimeZone: timezone,\n\t\t\t\tdateStyle: \"full\",\n\t\t\t\ttimeStyle: \"long\",\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: timeStr }],\n\t\t\t\tdetails: { utcTimestamp: date.getTime() },\n\t\t\t};\n\t\t} catch (_e) {\n\t\t\tthrow new Error(`Invalid timezone: ${timezone}. Current UTC time: ${date.toISOString()}`);\n\t\t}\n\t}\n\tconst timeStr = date.toLocaleString(\"en-US\", { dateStyle: \"full\", timeStyle: \"long\" });\n\treturn {\n\t\tcontent: [{ type: \"text\", text: timeStr }],\n\t\tdetails: { utcTimestamp: date.getTime() },\n\t};\n}\n\nconst getCurrentTimeSchema = Type.Object({\n\ttimezone: Type.Optional(\n\t\tType.String({ description: \"Optional timezone (e.g., 'America/New_York', 'Europe/London')\" }),\n\t),\n});\n\ntype GetCurrentTimeParams = Static<typeof getCurrentTimeSchema>;\n\nexport const getCurrentTimeTool: AgentTool<typeof getCurrentTimeSchema, { utcTimestamp: number }> = {\n\tlabel: \"Current Time\",\n\tname: \"get_current_time\",\n\tdescription: \"Get the current date and time\",\n\tparameters: getCurrentTimeSchema,\n\texecute: async (_toolCallId: string, args: GetCurrentTimeParams) => {\n\t\treturn getCurrentTime(args.timezone);\n\t},\n};\n"]}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { Type } from "@sinclair/typebox";
|
|
2
|
-
export async function getCurrentTime(timezone) {
|
|
3
|
-
const date = new Date();
|
|
4
|
-
if (timezone) {
|
|
5
|
-
try {
|
|
6
|
-
const timeStr = date.toLocaleString("en-US", {
|
|
7
|
-
timeZone: timezone,
|
|
8
|
-
dateStyle: "full",
|
|
9
|
-
timeStyle: "long",
|
|
10
|
-
});
|
|
11
|
-
return {
|
|
12
|
-
content: [{ type: "text", text: timeStr }],
|
|
13
|
-
details: { utcTimestamp: date.getTime() },
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
catch (_e) {
|
|
17
|
-
throw new Error(`Invalid timezone: ${timezone}. Current UTC time: ${date.toISOString()}`);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
const timeStr = date.toLocaleString("en-US", { dateStyle: "full", timeStyle: "long" });
|
|
21
|
-
return {
|
|
22
|
-
content: [{ type: "text", text: timeStr }],
|
|
23
|
-
details: { utcTimestamp: date.getTime() },
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
const getCurrentTimeSchema = Type.Object({
|
|
27
|
-
timezone: Type.Optional(Type.String({ description: "Optional timezone (e.g., 'America/New_York', 'Europe/London')" })),
|
|
28
|
-
});
|
|
29
|
-
export const getCurrentTimeTool = {
|
|
30
|
-
label: "Current Time",
|
|
31
|
-
name: "get_current_time",
|
|
32
|
-
description: "Get the current date and time",
|
|
33
|
-
parameters: getCurrentTimeSchema,
|
|
34
|
-
execute: async (_toolCallId, args) => {
|
|
35
|
-
return getCurrentTime(args.timezone);
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
//# sourceMappingURL=get-current-time.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"get-current-time.js","sourceRoot":"","sources":["../../../src/agent/tools/get-current-time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAMtD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAiB,EAAiC;IACtF,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;IACxB,IAAI,QAAQ,EAAE,CAAC;QACd,IAAI,CAAC;YACJ,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;gBAC5C,QAAQ,EAAE,QAAQ;gBAClB,SAAS,EAAE,MAAM;gBACjB,SAAS,EAAE,MAAM;aACjB,CAAC,CAAC;YACH,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;gBAC1C,OAAO,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE;aACzC,CAAC;QACH,CAAC;QAAC,OAAO,EAAE,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,uBAAuB,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC3F,CAAC;IACF,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;IACvF,OAAO;QACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC1C,OAAO,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE;KACzC,CAAC;AAAA,CACF;AAED,MAAM,oBAAoB,GAAG,IAAI,CAAC,MAAM,CAAC;IACxC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CACtB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,+DAA+D,EAAE,CAAC,CAC7F;CACD,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,kBAAkB,GAAqE;IACnG,KAAK,EAAE,cAAc;IACrB,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,+BAA+B;IAC5C,UAAU,EAAE,oBAAoB;IAChC,OAAO,EAAE,KAAK,EAAE,WAAmB,EAAE,IAA0B,EAAE,EAAE,CAAC;QACnE,OAAO,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAAA,CACrC;CACD,CAAC","sourcesContent":["import { type Static, Type } from \"@sinclair/typebox\";\nimport type { AgentTool } from \"../../agent/index.js\";\nimport type { AgentToolResult } from \"../types.js\";\n\nexport interface GetCurrentTimeResult extends AgentToolResult<{ utcTimestamp: number }> {}\n\nexport async function getCurrentTime(timezone?: string): Promise<GetCurrentTimeResult> {\n\tconst date = new Date();\n\tif (timezone) {\n\t\ttry {\n\t\t\tconst timeStr = date.toLocaleString(\"en-US\", {\n\t\t\t\ttimeZone: timezone,\n\t\t\t\tdateStyle: \"full\",\n\t\t\t\ttimeStyle: \"long\",\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: timeStr }],\n\t\t\t\tdetails: { utcTimestamp: date.getTime() },\n\t\t\t};\n\t\t} catch (_e) {\n\t\t\tthrow new Error(`Invalid timezone: ${timezone}. Current UTC time: ${date.toISOString()}`);\n\t\t}\n\t}\n\tconst timeStr = date.toLocaleString(\"en-US\", { dateStyle: \"full\", timeStyle: \"long\" });\n\treturn {\n\t\tcontent: [{ type: \"text\", text: timeStr }],\n\t\tdetails: { utcTimestamp: date.getTime() },\n\t};\n}\n\nconst getCurrentTimeSchema = Type.Object({\n\ttimezone: Type.Optional(\n\t\tType.String({ description: \"Optional timezone (e.g., 'America/New_York', 'Europe/London')\" }),\n\t),\n});\n\ntype GetCurrentTimeParams = Static<typeof getCurrentTimeSchema>;\n\nexport const getCurrentTimeTool: AgentTool<typeof getCurrentTimeSchema, { utcTimestamp: number }> = {\n\tlabel: \"Current Time\",\n\tname: \"get_current_time\",\n\tdescription: \"Get the current date and time\",\n\tparameters: getCurrentTimeSchema,\n\texecute: async (_toolCallId: string, args: GetCurrentTimeParams) => {\n\t\treturn getCurrentTime(args.timezone);\n\t},\n};\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC","sourcesContent":["export { calculate, calculateTool } from \"./calculate.js\";\nexport { getCurrentTime, getCurrentTimeTool } from \"./get-current-time.js\";\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/agent/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC","sourcesContent":["export { calculate, calculateTool } from \"./calculate.js\";\nexport { getCurrentTime, getCurrentTimeTool } from \"./get-current-time.js\";\n"]}
|