feat: Complete zCode CLI X with Telegram bot integration

- Add full Telegram bot functionality with Z.AI API integration
- Implement 4 tools: Bash, FileEdit, WebSearch, Git
- Add 3 agents: Code Reviewer, Architect, DevOps Engineer
- Add 6 skills for common coding tasks
- Add systemd service file for 24/7 operation
- Add nginx configuration for HTTPS webhook
- Add comprehensive documentation
- Implement WebSocket server for real-time updates
- Add logging system with Winston
- Add environment validation

🤖 zCode CLI X - Agentic coder with Z.AI + Telegram integration
This commit is contained in:
admin
2026-05-05 09:01:26 +00:00
Unverified
parent 4a7035dd92
commit 875c7f9b91
24688 changed files with 3224957 additions and 221 deletions

View File

@@ -0,0 +1,12 @@
import { BetaMemoryTool20250818, BetaTool, BetaToolBash20241022, BetaToolBash20250124, BetaToolComputerUse20241022, BetaToolComputerUse20250124, BetaToolComputerUse20251124, BetaToolResultContentBlockParam, BetaToolTextEditor20241022, BetaToolTextEditor20250124, BetaToolTextEditor20250429, BetaToolTextEditor20250728 } from "../../resources/beta.mjs";
export type Promisable<T> = T | Promise<T>;
/**
* Tool types that can be implemented on the client.
* Excludes server-side tools like code execution, web search, and MCP toolsets.
*/
export type BetaClientRunnableToolType = BetaTool | BetaMemoryTool20250818 | BetaToolBash20241022 | BetaToolBash20250124 | BetaToolComputerUse20241022 | BetaToolComputerUse20250124 | BetaToolComputerUse20251124 | BetaToolTextEditor20241022 | BetaToolTextEditor20250124 | BetaToolTextEditor20250429 | BetaToolTextEditor20250728;
export type BetaRunnableTool<Input = any> = BetaClientRunnableToolType & {
run: (args: Input) => Promisable<string | Array<BetaToolResultContentBlockParam>>;
parse: (content: unknown) => Input;
};
//# sourceMappingURL=BetaRunnableTool.d.mts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BetaRunnableTool.d.mts","sourceRoot":"","sources":["../../src/lib/tools/BetaRunnableTool.ts"],"names":[],"mappings":"OAAO,EACL,sBAAsB,EACtB,QAAQ,EACR,oBAAoB,EACpB,oBAAoB,EACpB,2BAA2B,EAC3B,2BAA2B,EAC3B,2BAA2B,EAC3B,+BAA+B,EAC/B,0BAA0B,EAC1B,0BAA0B,EAC1B,0BAA0B,EAC1B,0BAA0B,EAC3B;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAE3C;;;GAGG;AACH,MAAM,MAAM,0BAA0B,GAClC,QAAQ,GACR,sBAAsB,GACtB,oBAAoB,GACpB,oBAAoB,GACpB,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,CAAC;AAI/B,MAAM,MAAM,gBAAgB,CAAC,KAAK,GAAG,GAAG,IAAI,0BAA0B,GAAG;IACvE,GAAG,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,UAAU,CAAC,MAAM,GAAG,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;IAClF,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,KAAK,CAAC;CACpC,CAAC"}

View File

@@ -0,0 +1,12 @@
import { BetaMemoryTool20250818, BetaTool, BetaToolBash20241022, BetaToolBash20250124, BetaToolComputerUse20241022, BetaToolComputerUse20250124, BetaToolComputerUse20251124, BetaToolResultContentBlockParam, BetaToolTextEditor20241022, BetaToolTextEditor20250124, BetaToolTextEditor20250429, BetaToolTextEditor20250728 } from "../../resources/beta.js";
export type Promisable<T> = T | Promise<T>;
/**
* Tool types that can be implemented on the client.
* Excludes server-side tools like code execution, web search, and MCP toolsets.
*/
export type BetaClientRunnableToolType = BetaTool | BetaMemoryTool20250818 | BetaToolBash20241022 | BetaToolBash20250124 | BetaToolComputerUse20241022 | BetaToolComputerUse20250124 | BetaToolComputerUse20251124 | BetaToolTextEditor20241022 | BetaToolTextEditor20250124 | BetaToolTextEditor20250429 | BetaToolTextEditor20250728;
export type BetaRunnableTool<Input = any> = BetaClientRunnableToolType & {
run: (args: Input) => Promisable<string | Array<BetaToolResultContentBlockParam>>;
parse: (content: unknown) => Input;
};
//# sourceMappingURL=BetaRunnableTool.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BetaRunnableTool.d.ts","sourceRoot":"","sources":["../../src/lib/tools/BetaRunnableTool.ts"],"names":[],"mappings":"OAAO,EACL,sBAAsB,EACtB,QAAQ,EACR,oBAAoB,EACpB,oBAAoB,EACpB,2BAA2B,EAC3B,2BAA2B,EAC3B,2BAA2B,EAC3B,+BAA+B,EAC/B,0BAA0B,EAC1B,0BAA0B,EAC1B,0BAA0B,EAC1B,0BAA0B,EAC3B;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAE3C;;;GAGG;AACH,MAAM,MAAM,0BAA0B,GAClC,QAAQ,GACR,sBAAsB,GACtB,oBAAoB,GACpB,oBAAoB,GACpB,2BAA2B,GAC3B,2BAA2B,GAC3B,2BAA2B,GAC3B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,GAC1B,0BAA0B,CAAC;AAI/B,MAAM,MAAM,gBAAgB,CAAC,KAAK,GAAG,GAAG,IAAI,0BAA0B,GAAG;IACvE,GAAG,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,UAAU,CAAC,MAAM,GAAG,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;IAClF,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,KAAK,CAAC;CACpC,CAAC"}

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=BetaRunnableTool.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BetaRunnableTool.js","sourceRoot":"","sources":["../../src/lib/tools/BetaRunnableTool.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=BetaRunnableTool.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BetaRunnableTool.mjs","sourceRoot":"","sources":["../../src/lib/tools/BetaRunnableTool.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,136 @@
import { BetaRunnableTool } from "./BetaRunnableTool.mjs";
import { Anthropic } from "../../index.mjs";
import { BetaMessage, BetaMessageParam, BetaToolUnion, MessageCreateParams } from "../../resources/beta.mjs";
import { BetaMessageStream } from "../BetaMessageStream.mjs";
import { RequestOptions } from "../../internal/request-options.mjs";
import { CompactionControl } from "./CompactionControl.mjs";
/**
* A ToolRunner handles the automatic conversation loop between the assistant and tools.
*
* A ToolRunner is an async iterable that yields either BetaMessage or BetaMessageStream objects
* depending on the streaming configuration.
*/
export declare class BetaToolRunner<Stream extends boolean> {
#private;
private client;
constructor(client: Anthropic, params: BetaToolRunnerParams, options?: BetaToolRunnerRequestOptions);
[Symbol.asyncIterator](): AsyncIterator<Stream extends true ? BetaMessageStream : Stream extends false ? BetaMessage : BetaMessage | BetaMessageStream>;
/**
* Update the parameters for the next API call. This invalidates any cached tool responses.
*
* @param paramsOrMutator - Either new parameters or a function to mutate existing parameters
*
* @example
* // Direct parameter update
* runner.setMessagesParams({
* model: 'claude-haiku-4-5',
* max_tokens: 500,
* });
*
* @example
* // Using a mutator function
* runner.setMessagesParams((params) => ({
* ...params,
* max_tokens: 100,
* }));
*/
setMessagesParams(params: BetaToolRunnerParams): void;
setMessagesParams(mutator: (prevParams: BetaToolRunnerParams) => BetaToolRunnerParams): void;
/**
* Get the tool response for the last message from the assistant.
* Avoids redundant tool executions by caching results.
*
* @returns A promise that resolves to a BetaMessageParam containing tool results, or null if no tools need to be executed
*
* @example
* const toolResponse = await runner.generateToolResponse();
* if (toolResponse) {
* console.log('Tool results:', toolResponse.content);
* }
*/
generateToolResponse(): Promise<Anthropic.Beta.Messages.BetaMessageParam | null>;
/**
* Wait for the async iterator to complete. This works even if the async iterator hasn't yet started, and
* will wait for an instance to start and go to completion.
*
* @returns A promise that resolves to the final BetaMessage when the iterator completes
*
* @example
* // Start consuming the iterator
* for await (const message of runner) {
* console.log('Message:', message.content);
* }
*
* // Meanwhile, wait for completion from another part of the code
* const finalMessage = await runner.done();
* console.log('Final response:', finalMessage.content);
*/
done(): Promise<BetaMessage>;
/**
* Returns a promise indicating that the stream is done. Unlike .done(), this will eagerly read the stream:
* * If the iterator has not been consumed, consume the entire iterator and return the final message from the
* assistant.
* * If the iterator has been consumed, waits for it to complete and returns the final message.
*
* @returns A promise that resolves to the final BetaMessage from the conversation
* @throws {AnthropicError} If no messages were processed during the conversation
*
* @example
* const finalMessage = await runner.runUntilDone();
* console.log('Final response:', finalMessage.content);
*/
runUntilDone(): Promise<BetaMessage>;
/**
* Get the current parameters being used by the ToolRunner.
*
* @returns A readonly view of the current ToolRunnerParams
*
* @example
* const currentParams = runner.params;
* console.log('Current model:', currentParams.model);
* console.log('Message count:', currentParams.messages.length);
*/
get params(): Readonly<BetaToolRunnerParams>;
/**
* Add one or more messages to the conversation history.
*
* @param messages - One or more BetaMessageParam objects to add to the conversation
*
* @example
* runner.pushMessages(
* { role: 'user', content: 'Also, what about the weather in NYC?' }
* );
*
* @example
* // Adding multiple messages
* runner.pushMessages(
* { role: 'user', content: 'What about NYC?' },
* { role: 'user', content: 'And Boston?' }
* );
*/
pushMessages(...messages: BetaMessageParam[]): void;
/**
* Makes the ToolRunner directly awaitable, equivalent to calling .runUntilDone()
* This allows using `await runner` instead of `await runner.runUntilDone()`
*/
then<TResult1 = BetaMessage, TResult2 = never>(onfulfilled?: ((value: BetaMessage) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
}
type Simplify<T> = {
[KeyType in keyof T]: T[KeyType];
} & {};
/**
* Parameters for creating a ToolRunner, extending MessageCreateParams with runnable tools.
*/
export type BetaToolRunnerParams = Simplify<Omit<MessageCreateParams, 'tools'> & {
tools: (BetaToolUnion | BetaRunnableTool<any>)[];
/**
* Maximum number of iterations (API requests) to make in the tool execution loop.
* Each iteration consists of: assistant response → tool execution → tool results.
* When exceeded, the loop will terminate even if tools are still being requested.
*/
max_iterations?: number;
compactionControl?: CompactionControl;
}>;
export type BetaToolRunnerRequestOptions = Pick<RequestOptions, 'headers'>;
export {};
//# sourceMappingURL=BetaToolRunner.d.mts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BetaToolRunner.d.mts","sourceRoot":"","sources":["../../src/lib/tools/BetaToolRunner.ts"],"names":[],"mappings":"OAAO,EAAE,gBAAgB,EAAE;OAEpB,EAAE,SAAS,EAAE;OAEb,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,mBAAmB,EAAE;OACrE,EAAE,iBAAiB,EAAE;OACrB,EAAE,cAAc,EAAE;OAElB,EAAE,iBAAiB,EAAmD;AAoB7E;;;;;GAKG;AACH,qBAAa,cAAc,CAAC,MAAM,SAAS,OAAO;;IAsB9C,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS,EACzB,MAAM,EAAE,oBAAoB,EAC5B,OAAO,CAAC,EAAE,4BAA4B;IAwGjC,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAC5C,MAAM,SAAS,IAAI,GAAG,iBAAiB,GACrC,MAAM,SAAS,KAAK,GAAG,WAAW,GAClC,WAAW,GAAG,iBAAiB,CAClC;IA2ED;;;;;;;;;;;;;;;;;;OAkBG;IACH,iBAAiB,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IACrD,iBAAiB,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,oBAAoB,KAAK,oBAAoB,GAAG,IAAI;IAc5F;;;;;;;;;;;OAWG;IACG,oBAAoB;IAgB1B;;;;;;;;;;;;;;;OAeG;IACH,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC;IAI5B;;;;;;;;;;;;OAYG;IACG,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC;IAY1C;;;;;;;;;OASG;IACH,IAAI,MAAM,IAAI,QAAQ,CAAC,oBAAoB,CAAC,CAE3C;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,YAAY,CAAC,GAAG,QAAQ,EAAE,gBAAgB,EAAE;IAO5C;;;OAGG;IACH,IAAI,CAAC,QAAQ,GAAG,WAAW,EAAE,QAAQ,GAAG,KAAK,EAC3C,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,EAC3F,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,GAClF,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;CAGhC;AAkED,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;CAAE,GAAG,EAAE,CAAC;AAE7D;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CACzC,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,GAAG;IACnC,KAAK,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;IACjD;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC,CACF,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC"}

View File

@@ -0,0 +1,136 @@
import { BetaRunnableTool } from "./BetaRunnableTool.js";
import { Anthropic } from "../../index.js";
import { BetaMessage, BetaMessageParam, BetaToolUnion, MessageCreateParams } from "../../resources/beta.js";
import { BetaMessageStream } from "../BetaMessageStream.js";
import { RequestOptions } from "../../internal/request-options.js";
import { CompactionControl } from "./CompactionControl.js";
/**
* A ToolRunner handles the automatic conversation loop between the assistant and tools.
*
* A ToolRunner is an async iterable that yields either BetaMessage or BetaMessageStream objects
* depending on the streaming configuration.
*/
export declare class BetaToolRunner<Stream extends boolean> {
#private;
private client;
constructor(client: Anthropic, params: BetaToolRunnerParams, options?: BetaToolRunnerRequestOptions);
[Symbol.asyncIterator](): AsyncIterator<Stream extends true ? BetaMessageStream : Stream extends false ? BetaMessage : BetaMessage | BetaMessageStream>;
/**
* Update the parameters for the next API call. This invalidates any cached tool responses.
*
* @param paramsOrMutator - Either new parameters or a function to mutate existing parameters
*
* @example
* // Direct parameter update
* runner.setMessagesParams({
* model: 'claude-haiku-4-5',
* max_tokens: 500,
* });
*
* @example
* // Using a mutator function
* runner.setMessagesParams((params) => ({
* ...params,
* max_tokens: 100,
* }));
*/
setMessagesParams(params: BetaToolRunnerParams): void;
setMessagesParams(mutator: (prevParams: BetaToolRunnerParams) => BetaToolRunnerParams): void;
/**
* Get the tool response for the last message from the assistant.
* Avoids redundant tool executions by caching results.
*
* @returns A promise that resolves to a BetaMessageParam containing tool results, or null if no tools need to be executed
*
* @example
* const toolResponse = await runner.generateToolResponse();
* if (toolResponse) {
* console.log('Tool results:', toolResponse.content);
* }
*/
generateToolResponse(): Promise<Anthropic.Beta.Messages.BetaMessageParam | null>;
/**
* Wait for the async iterator to complete. This works even if the async iterator hasn't yet started, and
* will wait for an instance to start and go to completion.
*
* @returns A promise that resolves to the final BetaMessage when the iterator completes
*
* @example
* // Start consuming the iterator
* for await (const message of runner) {
* console.log('Message:', message.content);
* }
*
* // Meanwhile, wait for completion from another part of the code
* const finalMessage = await runner.done();
* console.log('Final response:', finalMessage.content);
*/
done(): Promise<BetaMessage>;
/**
* Returns a promise indicating that the stream is done. Unlike .done(), this will eagerly read the stream:
* * If the iterator has not been consumed, consume the entire iterator and return the final message from the
* assistant.
* * If the iterator has been consumed, waits for it to complete and returns the final message.
*
* @returns A promise that resolves to the final BetaMessage from the conversation
* @throws {AnthropicError} If no messages were processed during the conversation
*
* @example
* const finalMessage = await runner.runUntilDone();
* console.log('Final response:', finalMessage.content);
*/
runUntilDone(): Promise<BetaMessage>;
/**
* Get the current parameters being used by the ToolRunner.
*
* @returns A readonly view of the current ToolRunnerParams
*
* @example
* const currentParams = runner.params;
* console.log('Current model:', currentParams.model);
* console.log('Message count:', currentParams.messages.length);
*/
get params(): Readonly<BetaToolRunnerParams>;
/**
* Add one or more messages to the conversation history.
*
* @param messages - One or more BetaMessageParam objects to add to the conversation
*
* @example
* runner.pushMessages(
* { role: 'user', content: 'Also, what about the weather in NYC?' }
* );
*
* @example
* // Adding multiple messages
* runner.pushMessages(
* { role: 'user', content: 'What about NYC?' },
* { role: 'user', content: 'And Boston?' }
* );
*/
pushMessages(...messages: BetaMessageParam[]): void;
/**
* Makes the ToolRunner directly awaitable, equivalent to calling .runUntilDone()
* This allows using `await runner` instead of `await runner.runUntilDone()`
*/
then<TResult1 = BetaMessage, TResult2 = never>(onfulfilled?: ((value: BetaMessage) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
}
type Simplify<T> = {
[KeyType in keyof T]: T[KeyType];
} & {};
/**
* Parameters for creating a ToolRunner, extending MessageCreateParams with runnable tools.
*/
export type BetaToolRunnerParams = Simplify<Omit<MessageCreateParams, 'tools'> & {
tools: (BetaToolUnion | BetaRunnableTool<any>)[];
/**
* Maximum number of iterations (API requests) to make in the tool execution loop.
* Each iteration consists of: assistant response → tool execution → tool results.
* When exceeded, the loop will terminate even if tools are still being requested.
*/
max_iterations?: number;
compactionControl?: CompactionControl;
}>;
export type BetaToolRunnerRequestOptions = Pick<RequestOptions, 'headers'>;
export {};
//# sourceMappingURL=BetaToolRunner.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BetaToolRunner.d.ts","sourceRoot":"","sources":["../../src/lib/tools/BetaToolRunner.ts"],"names":[],"mappings":"OAAO,EAAE,gBAAgB,EAAE;OAEpB,EAAE,SAAS,EAAE;OAEb,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,mBAAmB,EAAE;OACrE,EAAE,iBAAiB,EAAE;OACrB,EAAE,cAAc,EAAE;OAElB,EAAE,iBAAiB,EAAmD;AAoB7E;;;;;GAKG;AACH,qBAAa,cAAc,CAAC,MAAM,SAAS,OAAO;;IAsB9C,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS,EACzB,MAAM,EAAE,oBAAoB,EAC5B,OAAO,CAAC,EAAE,4BAA4B;IAwGjC,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAC5C,MAAM,SAAS,IAAI,GAAG,iBAAiB,GACrC,MAAM,SAAS,KAAK,GAAG,WAAW,GAClC,WAAW,GAAG,iBAAiB,CAClC;IA2ED;;;;;;;;;;;;;;;;;;OAkBG;IACH,iBAAiB,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IACrD,iBAAiB,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,oBAAoB,KAAK,oBAAoB,GAAG,IAAI;IAc5F;;;;;;;;;;;OAWG;IACG,oBAAoB;IAgB1B;;;;;;;;;;;;;;;OAeG;IACH,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC;IAI5B;;;;;;;;;;;;OAYG;IACG,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC;IAY1C;;;;;;;;;OASG;IACH,IAAI,MAAM,IAAI,QAAQ,CAAC,oBAAoB,CAAC,CAE3C;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,YAAY,CAAC,GAAG,QAAQ,EAAE,gBAAgB,EAAE;IAO5C;;;OAGG;IACH,IAAI,CAAC,QAAQ,GAAG,WAAW,EAAE,QAAQ,GAAG,KAAK,EAC3C,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,EAC3F,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,GAClF,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;CAGhC;AAkED,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;CAAE,GAAG,EAAE,CAAC;AAE7D;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CACzC,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,GAAG;IACnC,KAAK,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;IACjD;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC,CACF,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC"}

View File

@@ -0,0 +1,376 @@
"use strict";
var _BetaToolRunner_instances, _BetaToolRunner_consumed, _BetaToolRunner_mutated, _BetaToolRunner_state, _BetaToolRunner_options, _BetaToolRunner_message, _BetaToolRunner_toolResponse, _BetaToolRunner_completion, _BetaToolRunner_iterationCount, _BetaToolRunner_checkAndCompact, _BetaToolRunner_generateToolResponse;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BetaToolRunner = void 0;
const tslib_1 = require("../../internal/tslib.js");
const ToolError_1 = require("./ToolError.js");
const error_1 = require("../../core/error.js");
const headers_1 = require("../../internal/headers.js");
const CompactionControl_1 = require("./CompactionControl.js");
const stainless_helper_header_1 = require("../stainless-helper-header.js");
/**
* Just Promise.withResolvers(), which is not available in all environments.
*/
function promiseWithResolvers() {
let resolve;
let reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve: resolve, reject: reject };
}
/**
* A ToolRunner handles the automatic conversation loop between the assistant and tools.
*
* A ToolRunner is an async iterable that yields either BetaMessage or BetaMessageStream objects
* depending on the streaming configuration.
*/
class BetaToolRunner {
constructor(client, params, options) {
_BetaToolRunner_instances.add(this);
this.client = client;
/** Whether the async iterator has been consumed */
_BetaToolRunner_consumed.set(this, false);
/** Whether parameters have been mutated since the last API call */
_BetaToolRunner_mutated.set(this, false);
/** Current state containing the request parameters */
_BetaToolRunner_state.set(this, void 0);
_BetaToolRunner_options.set(this, void 0);
/** Promise for the last message received from the assistant */
_BetaToolRunner_message.set(this, void 0);
/** Cached tool response to avoid redundant executions */
_BetaToolRunner_toolResponse.set(this, void 0);
/** Promise resolvers for waiting on completion */
_BetaToolRunner_completion.set(this, void 0);
/** Number of iterations (API requests) made so far */
_BetaToolRunner_iterationCount.set(this, 0);
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_state, {
params: {
// You can't clone the entire params since there are functions as handlers.
// You also don't really need to clone params.messages, but it probably will prevent a foot gun
// somewhere.
...params,
messages: structuredClone(params.messages),
},
}, "f");
const helpers = (0, stainless_helper_header_1.collectStainlessHelpers)(params.tools, params.messages);
const helperValue = ['BetaToolRunner', ...helpers].join(', ');
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_options, {
...options,
headers: (0, headers_1.buildHeaders)([{ 'x-stainless-helper': helperValue }, options?.headers]),
}, "f");
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_completion, promiseWithResolvers(), "f");
}
async *[(_BetaToolRunner_consumed = new WeakMap(), _BetaToolRunner_mutated = new WeakMap(), _BetaToolRunner_state = new WeakMap(), _BetaToolRunner_options = new WeakMap(), _BetaToolRunner_message = new WeakMap(), _BetaToolRunner_toolResponse = new WeakMap(), _BetaToolRunner_completion = new WeakMap(), _BetaToolRunner_iterationCount = new WeakMap(), _BetaToolRunner_instances = new WeakSet(), _BetaToolRunner_checkAndCompact = async function _BetaToolRunner_checkAndCompact() {
const compactionControl = tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.compactionControl;
if (!compactionControl || !compactionControl.enabled) {
return false;
}
let tokensUsed = 0;
if (tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f") !== undefined) {
try {
const message = await tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f");
const totalInputTokens = message.usage.input_tokens +
(message.usage.cache_creation_input_tokens ?? 0) +
(message.usage.cache_read_input_tokens ?? 0);
tokensUsed = totalInputTokens + message.usage.output_tokens;
}
catch {
// If we can't get the message, skip compaction
return false;
}
}
const threshold = compactionControl.contextTokenThreshold ?? CompactionControl_1.DEFAULT_TOKEN_THRESHOLD;
if (tokensUsed < threshold) {
return false;
}
const model = compactionControl.model ?? tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.model;
const summaryPrompt = compactionControl.summaryPrompt ?? CompactionControl_1.DEFAULT_SUMMARY_PROMPT;
const messages = tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages;
if (messages[messages.length - 1].role === 'assistant') {
// Remove tool_use blocks from the last message to avoid 400 error
// (tool_use requires tool_result, which we don't have yet)
const lastMessage = messages[messages.length - 1];
if (Array.isArray(lastMessage.content)) {
const nonToolBlocks = lastMessage.content.filter((block) => block.type !== 'tool_use');
if (nonToolBlocks.length === 0) {
// If all blocks were tool_use, just remove the message entirely
messages.pop();
}
else {
lastMessage.content = nonToolBlocks;
}
}
}
const response = await this.client.beta.messages.create({
model,
messages: [
...messages,
{
role: 'user',
content: [
{
type: 'text',
text: summaryPrompt,
},
],
},
],
max_tokens: tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.max_tokens,
}, {
headers: { 'x-stainless-helper': 'compaction' },
});
if (response.content[0]?.type !== 'text') {
throw new error_1.AnthropicError('Expected text response for compaction');
}
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages = [
{
role: 'user',
content: response.content,
},
];
return true;
}, Symbol.asyncIterator)]() {
var _a;
if (tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_consumed, "f")) {
throw new error_1.AnthropicError('Cannot iterate over a consumed stream');
}
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_consumed, true, "f");
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_mutated, true, "f");
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, undefined, "f");
try {
while (true) {
let stream;
try {
if (tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.max_iterations &&
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_iterationCount, "f") >= tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.max_iterations) {
break;
}
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_mutated, false, "f");
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, undefined, "f");
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_iterationCount, (_a = tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_iterationCount, "f"), _a++, _a), "f");
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_message, undefined, "f");
const { max_iterations, compactionControl, ...params } = tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params;
if (params.stream) {
stream = this.client.beta.messages.stream({ ...params }, tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_options, "f"));
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_message, stream.finalMessage(), "f");
// Make sure that this promise doesn't throw before we get the option to do something about it.
// Error will be caught when we call await this.#message ultimately
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f").catch(() => { });
yield stream;
}
else {
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_message, this.client.beta.messages.create({ ...params, stream: false }, tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_options, "f")), "f");
yield tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f");
}
const isCompacted = await tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_instances, "m", _BetaToolRunner_checkAndCompact).call(this);
if (!isCompacted) {
if (!tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_mutated, "f")) {
const { role, content } = await tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f");
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages.push({ role, content });
}
const toolMessage = await tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_instances, "m", _BetaToolRunner_generateToolResponse).call(this, tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages.at(-1));
if (toolMessage) {
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages.push(toolMessage);
}
else if (!tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_mutated, "f")) {
break;
}
}
}
finally {
if (stream) {
stream.abort();
}
}
}
if (!tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f")) {
throw new error_1.AnthropicError('ToolRunner concluded without a message from the server');
}
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").resolve(await tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f"));
}
catch (error) {
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_consumed, false, "f");
// Silence unhandled promise errors
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").promise.catch(() => { });
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").reject(error);
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_completion, promiseWithResolvers(), "f");
throw error;
}
}
setMessagesParams(paramsOrMutator) {
if (typeof paramsOrMutator === 'function') {
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params = paramsOrMutator(tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params);
}
else {
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params = paramsOrMutator;
}
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_mutated, true, "f");
// Invalidate cached tool response since parameters changed
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, undefined, "f");
}
/**
* Get the tool response for the last message from the assistant.
* Avoids redundant tool executions by caching results.
*
* @returns A promise that resolves to a BetaMessageParam containing tool results, or null if no tools need to be executed
*
* @example
* const toolResponse = await runner.generateToolResponse();
* if (toolResponse) {
* console.log('Tool results:', toolResponse.content);
* }
*/
async generateToolResponse() {
const message = (await tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f")) ?? this.params.messages.at(-1);
if (!message) {
return null;
}
return tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_instances, "m", _BetaToolRunner_generateToolResponse).call(this, message);
}
/**
* Wait for the async iterator to complete. This works even if the async iterator hasn't yet started, and
* will wait for an instance to start and go to completion.
*
* @returns A promise that resolves to the final BetaMessage when the iterator completes
*
* @example
* // Start consuming the iterator
* for await (const message of runner) {
* console.log('Message:', message.content);
* }
*
* // Meanwhile, wait for completion from another part of the code
* const finalMessage = await runner.done();
* console.log('Final response:', finalMessage.content);
*/
done() {
return tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").promise;
}
/**
* Returns a promise indicating that the stream is done. Unlike .done(), this will eagerly read the stream:
* * If the iterator has not been consumed, consume the entire iterator and return the final message from the
* assistant.
* * If the iterator has been consumed, waits for it to complete and returns the final message.
*
* @returns A promise that resolves to the final BetaMessage from the conversation
* @throws {AnthropicError} If no messages were processed during the conversation
*
* @example
* const finalMessage = await runner.runUntilDone();
* console.log('Final response:', finalMessage.content);
*/
async runUntilDone() {
// If not yet consumed, start consuming and wait for completion
if (!tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_consumed, "f")) {
for await (const _ of this) {
// Iterator naturally populates this.#message
}
}
// If consumed but not completed, wait for completion
return this.done();
}
/**
* Get the current parameters being used by the ToolRunner.
*
* @returns A readonly view of the current ToolRunnerParams
*
* @example
* const currentParams = runner.params;
* console.log('Current model:', currentParams.model);
* console.log('Message count:', currentParams.messages.length);
*/
get params() {
return tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params;
}
/**
* Add one or more messages to the conversation history.
*
* @param messages - One or more BetaMessageParam objects to add to the conversation
*
* @example
* runner.pushMessages(
* { role: 'user', content: 'Also, what about the weather in NYC?' }
* );
*
* @example
* // Adding multiple messages
* runner.pushMessages(
* { role: 'user', content: 'What about NYC?' },
* { role: 'user', content: 'And Boston?' }
* );
*/
pushMessages(...messages) {
this.setMessagesParams((params) => ({
...params,
messages: [...params.messages, ...messages],
}));
}
/**
* Makes the ToolRunner directly awaitable, equivalent to calling .runUntilDone()
* This allows using `await runner` instead of `await runner.runUntilDone()`
*/
then(onfulfilled, onrejected) {
return this.runUntilDone().then(onfulfilled, onrejected);
}
}
exports.BetaToolRunner = BetaToolRunner;
_BetaToolRunner_generateToolResponse = async function _BetaToolRunner_generateToolResponse(lastMessage) {
if (tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_toolResponse, "f") !== undefined) {
return tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_toolResponse, "f");
}
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, generateToolResponse(tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params, lastMessage), "f");
return tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_toolResponse, "f");
};
async function generateToolResponse(params, lastMessage = params.messages.at(-1)) {
// Only process if the last message is from the assistant and has tool use blocks
if (!lastMessage ||
lastMessage.role !== 'assistant' ||
!lastMessage.content ||
typeof lastMessage.content === 'string') {
return null;
}
const toolUseBlocks = lastMessage.content.filter((content) => content.type === 'tool_use');
if (toolUseBlocks.length === 0) {
return null;
}
const toolResults = await Promise.all(toolUseBlocks.map(async (toolUse) => {
const tool = params.tools.find((t) => ('name' in t ? t.name : t.mcp_server_name) === toolUse.name);
if (!tool || !('run' in tool)) {
return {
type: 'tool_result',
tool_use_id: toolUse.id,
content: `Error: Tool '${toolUse.name}' not found`,
is_error: true,
};
}
try {
let input = toolUse.input;
if ('parse' in tool && tool.parse) {
input = tool.parse(input);
}
const result = await tool.run(input);
return {
type: 'tool_result',
tool_use_id: toolUse.id,
content: result,
};
}
catch (error) {
return {
type: 'tool_result',
tool_use_id: toolUse.id,
content: error instanceof ToolError_1.ToolError ?
error.content
: `Error: ${error instanceof Error ? error.message : String(error)}`,
is_error: true,
};
}
}));
return {
role: 'user',
content: toolResults,
};
}
//# sourceMappingURL=BetaToolRunner.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,372 @@
var _BetaToolRunner_instances, _BetaToolRunner_consumed, _BetaToolRunner_mutated, _BetaToolRunner_state, _BetaToolRunner_options, _BetaToolRunner_message, _BetaToolRunner_toolResponse, _BetaToolRunner_completion, _BetaToolRunner_iterationCount, _BetaToolRunner_checkAndCompact, _BetaToolRunner_generateToolResponse;
import { __classPrivateFieldGet, __classPrivateFieldSet } from "../../internal/tslib.mjs";
import { ToolError } from "./ToolError.mjs";
import { AnthropicError } from "../../core/error.mjs";
import { buildHeaders } from "../../internal/headers.mjs";
import { DEFAULT_SUMMARY_PROMPT, DEFAULT_TOKEN_THRESHOLD } from "./CompactionControl.mjs";
import { collectStainlessHelpers } from "../stainless-helper-header.mjs";
/**
* Just Promise.withResolvers(), which is not available in all environments.
*/
function promiseWithResolvers() {
let resolve;
let reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve: resolve, reject: reject };
}
/**
* A ToolRunner handles the automatic conversation loop between the assistant and tools.
*
* A ToolRunner is an async iterable that yields either BetaMessage or BetaMessageStream objects
* depending on the streaming configuration.
*/
export class BetaToolRunner {
constructor(client, params, options) {
_BetaToolRunner_instances.add(this);
this.client = client;
/** Whether the async iterator has been consumed */
_BetaToolRunner_consumed.set(this, false);
/** Whether parameters have been mutated since the last API call */
_BetaToolRunner_mutated.set(this, false);
/** Current state containing the request parameters */
_BetaToolRunner_state.set(this, void 0);
_BetaToolRunner_options.set(this, void 0);
/** Promise for the last message received from the assistant */
_BetaToolRunner_message.set(this, void 0);
/** Cached tool response to avoid redundant executions */
_BetaToolRunner_toolResponse.set(this, void 0);
/** Promise resolvers for waiting on completion */
_BetaToolRunner_completion.set(this, void 0);
/** Number of iterations (API requests) made so far */
_BetaToolRunner_iterationCount.set(this, 0);
__classPrivateFieldSet(this, _BetaToolRunner_state, {
params: {
// You can't clone the entire params since there are functions as handlers.
// You also don't really need to clone params.messages, but it probably will prevent a foot gun
// somewhere.
...params,
messages: structuredClone(params.messages),
},
}, "f");
const helpers = collectStainlessHelpers(params.tools, params.messages);
const helperValue = ['BetaToolRunner', ...helpers].join(', ');
__classPrivateFieldSet(this, _BetaToolRunner_options, {
...options,
headers: buildHeaders([{ 'x-stainless-helper': helperValue }, options?.headers]),
}, "f");
__classPrivateFieldSet(this, _BetaToolRunner_completion, promiseWithResolvers(), "f");
}
async *[(_BetaToolRunner_consumed = new WeakMap(), _BetaToolRunner_mutated = new WeakMap(), _BetaToolRunner_state = new WeakMap(), _BetaToolRunner_options = new WeakMap(), _BetaToolRunner_message = new WeakMap(), _BetaToolRunner_toolResponse = new WeakMap(), _BetaToolRunner_completion = new WeakMap(), _BetaToolRunner_iterationCount = new WeakMap(), _BetaToolRunner_instances = new WeakSet(), _BetaToolRunner_checkAndCompact = async function _BetaToolRunner_checkAndCompact() {
const compactionControl = __classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.compactionControl;
if (!compactionControl || !compactionControl.enabled) {
return false;
}
let tokensUsed = 0;
if (__classPrivateFieldGet(this, _BetaToolRunner_message, "f") !== undefined) {
try {
const message = await __classPrivateFieldGet(this, _BetaToolRunner_message, "f");
const totalInputTokens = message.usage.input_tokens +
(message.usage.cache_creation_input_tokens ?? 0) +
(message.usage.cache_read_input_tokens ?? 0);
tokensUsed = totalInputTokens + message.usage.output_tokens;
}
catch {
// If we can't get the message, skip compaction
return false;
}
}
const threshold = compactionControl.contextTokenThreshold ?? DEFAULT_TOKEN_THRESHOLD;
if (tokensUsed < threshold) {
return false;
}
const model = compactionControl.model ?? __classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.model;
const summaryPrompt = compactionControl.summaryPrompt ?? DEFAULT_SUMMARY_PROMPT;
const messages = __classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages;
if (messages[messages.length - 1].role === 'assistant') {
// Remove tool_use blocks from the last message to avoid 400 error
// (tool_use requires tool_result, which we don't have yet)
const lastMessage = messages[messages.length - 1];
if (Array.isArray(lastMessage.content)) {
const nonToolBlocks = lastMessage.content.filter((block) => block.type !== 'tool_use');
if (nonToolBlocks.length === 0) {
// If all blocks were tool_use, just remove the message entirely
messages.pop();
}
else {
lastMessage.content = nonToolBlocks;
}
}
}
const response = await this.client.beta.messages.create({
model,
messages: [
...messages,
{
role: 'user',
content: [
{
type: 'text',
text: summaryPrompt,
},
],
},
],
max_tokens: __classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.max_tokens,
}, {
headers: { 'x-stainless-helper': 'compaction' },
});
if (response.content[0]?.type !== 'text') {
throw new AnthropicError('Expected text response for compaction');
}
__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages = [
{
role: 'user',
content: response.content,
},
];
return true;
}, Symbol.asyncIterator)]() {
var _a;
if (__classPrivateFieldGet(this, _BetaToolRunner_consumed, "f")) {
throw new AnthropicError('Cannot iterate over a consumed stream');
}
__classPrivateFieldSet(this, _BetaToolRunner_consumed, true, "f");
__classPrivateFieldSet(this, _BetaToolRunner_mutated, true, "f");
__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, undefined, "f");
try {
while (true) {
let stream;
try {
if (__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.max_iterations &&
__classPrivateFieldGet(this, _BetaToolRunner_iterationCount, "f") >= __classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.max_iterations) {
break;
}
__classPrivateFieldSet(this, _BetaToolRunner_mutated, false, "f");
__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, undefined, "f");
__classPrivateFieldSet(this, _BetaToolRunner_iterationCount, (_a = __classPrivateFieldGet(this, _BetaToolRunner_iterationCount, "f"), _a++, _a), "f");
__classPrivateFieldSet(this, _BetaToolRunner_message, undefined, "f");
const { max_iterations, compactionControl, ...params } = __classPrivateFieldGet(this, _BetaToolRunner_state, "f").params;
if (params.stream) {
stream = this.client.beta.messages.stream({ ...params }, __classPrivateFieldGet(this, _BetaToolRunner_options, "f"));
__classPrivateFieldSet(this, _BetaToolRunner_message, stream.finalMessage(), "f");
// Make sure that this promise doesn't throw before we get the option to do something about it.
// Error will be caught when we call await this.#message ultimately
__classPrivateFieldGet(this, _BetaToolRunner_message, "f").catch(() => { });
yield stream;
}
else {
__classPrivateFieldSet(this, _BetaToolRunner_message, this.client.beta.messages.create({ ...params, stream: false }, __classPrivateFieldGet(this, _BetaToolRunner_options, "f")), "f");
yield __classPrivateFieldGet(this, _BetaToolRunner_message, "f");
}
const isCompacted = await __classPrivateFieldGet(this, _BetaToolRunner_instances, "m", _BetaToolRunner_checkAndCompact).call(this);
if (!isCompacted) {
if (!__classPrivateFieldGet(this, _BetaToolRunner_mutated, "f")) {
const { role, content } = await __classPrivateFieldGet(this, _BetaToolRunner_message, "f");
__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages.push({ role, content });
}
const toolMessage = await __classPrivateFieldGet(this, _BetaToolRunner_instances, "m", _BetaToolRunner_generateToolResponse).call(this, __classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages.at(-1));
if (toolMessage) {
__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages.push(toolMessage);
}
else if (!__classPrivateFieldGet(this, _BetaToolRunner_mutated, "f")) {
break;
}
}
}
finally {
if (stream) {
stream.abort();
}
}
}
if (!__classPrivateFieldGet(this, _BetaToolRunner_message, "f")) {
throw new AnthropicError('ToolRunner concluded without a message from the server');
}
__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").resolve(await __classPrivateFieldGet(this, _BetaToolRunner_message, "f"));
}
catch (error) {
__classPrivateFieldSet(this, _BetaToolRunner_consumed, false, "f");
// Silence unhandled promise errors
__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").promise.catch(() => { });
__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").reject(error);
__classPrivateFieldSet(this, _BetaToolRunner_completion, promiseWithResolvers(), "f");
throw error;
}
}
setMessagesParams(paramsOrMutator) {
if (typeof paramsOrMutator === 'function') {
__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params = paramsOrMutator(__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params);
}
else {
__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params = paramsOrMutator;
}
__classPrivateFieldSet(this, _BetaToolRunner_mutated, true, "f");
// Invalidate cached tool response since parameters changed
__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, undefined, "f");
}
/**
* Get the tool response for the last message from the assistant.
* Avoids redundant tool executions by caching results.
*
* @returns A promise that resolves to a BetaMessageParam containing tool results, or null if no tools need to be executed
*
* @example
* const toolResponse = await runner.generateToolResponse();
* if (toolResponse) {
* console.log('Tool results:', toolResponse.content);
* }
*/
async generateToolResponse() {
const message = (await __classPrivateFieldGet(this, _BetaToolRunner_message, "f")) ?? this.params.messages.at(-1);
if (!message) {
return null;
}
return __classPrivateFieldGet(this, _BetaToolRunner_instances, "m", _BetaToolRunner_generateToolResponse).call(this, message);
}
/**
* Wait for the async iterator to complete. This works even if the async iterator hasn't yet started, and
* will wait for an instance to start and go to completion.
*
* @returns A promise that resolves to the final BetaMessage when the iterator completes
*
* @example
* // Start consuming the iterator
* for await (const message of runner) {
* console.log('Message:', message.content);
* }
*
* // Meanwhile, wait for completion from another part of the code
* const finalMessage = await runner.done();
* console.log('Final response:', finalMessage.content);
*/
done() {
return __classPrivateFieldGet(this, _BetaToolRunner_completion, "f").promise;
}
/**
* Returns a promise indicating that the stream is done. Unlike .done(), this will eagerly read the stream:
* * If the iterator has not been consumed, consume the entire iterator and return the final message from the
* assistant.
* * If the iterator has been consumed, waits for it to complete and returns the final message.
*
* @returns A promise that resolves to the final BetaMessage from the conversation
* @throws {AnthropicError} If no messages were processed during the conversation
*
* @example
* const finalMessage = await runner.runUntilDone();
* console.log('Final response:', finalMessage.content);
*/
async runUntilDone() {
// If not yet consumed, start consuming and wait for completion
if (!__classPrivateFieldGet(this, _BetaToolRunner_consumed, "f")) {
for await (const _ of this) {
// Iterator naturally populates this.#message
}
}
// If consumed but not completed, wait for completion
return this.done();
}
/**
* Get the current parameters being used by the ToolRunner.
*
* @returns A readonly view of the current ToolRunnerParams
*
* @example
* const currentParams = runner.params;
* console.log('Current model:', currentParams.model);
* console.log('Message count:', currentParams.messages.length);
*/
get params() {
return __classPrivateFieldGet(this, _BetaToolRunner_state, "f").params;
}
/**
* Add one or more messages to the conversation history.
*
* @param messages - One or more BetaMessageParam objects to add to the conversation
*
* @example
* runner.pushMessages(
* { role: 'user', content: 'Also, what about the weather in NYC?' }
* );
*
* @example
* // Adding multiple messages
* runner.pushMessages(
* { role: 'user', content: 'What about NYC?' },
* { role: 'user', content: 'And Boston?' }
* );
*/
pushMessages(...messages) {
this.setMessagesParams((params) => ({
...params,
messages: [...params.messages, ...messages],
}));
}
/**
* Makes the ToolRunner directly awaitable, equivalent to calling .runUntilDone()
* This allows using `await runner` instead of `await runner.runUntilDone()`
*/
then(onfulfilled, onrejected) {
return this.runUntilDone().then(onfulfilled, onrejected);
}
}
_BetaToolRunner_generateToolResponse = async function _BetaToolRunner_generateToolResponse(lastMessage) {
if (__classPrivateFieldGet(this, _BetaToolRunner_toolResponse, "f") !== undefined) {
return __classPrivateFieldGet(this, _BetaToolRunner_toolResponse, "f");
}
__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, generateToolResponse(__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params, lastMessage), "f");
return __classPrivateFieldGet(this, _BetaToolRunner_toolResponse, "f");
};
async function generateToolResponse(params, lastMessage = params.messages.at(-1)) {
// Only process if the last message is from the assistant and has tool use blocks
if (!lastMessage ||
lastMessage.role !== 'assistant' ||
!lastMessage.content ||
typeof lastMessage.content === 'string') {
return null;
}
const toolUseBlocks = lastMessage.content.filter((content) => content.type === 'tool_use');
if (toolUseBlocks.length === 0) {
return null;
}
const toolResults = await Promise.all(toolUseBlocks.map(async (toolUse) => {
const tool = params.tools.find((t) => ('name' in t ? t.name : t.mcp_server_name) === toolUse.name);
if (!tool || !('run' in tool)) {
return {
type: 'tool_result',
tool_use_id: toolUse.id,
content: `Error: Tool '${toolUse.name}' not found`,
is_error: true,
};
}
try {
let input = toolUse.input;
if ('parse' in tool && tool.parse) {
input = tool.parse(input);
}
const result = await tool.run(input);
return {
type: 'tool_result',
tool_use_id: toolUse.id,
content: result,
};
}
catch (error) {
return {
type: 'tool_result',
tool_use_id: toolUse.id,
content: error instanceof ToolError ?
error.content
: `Error: ${error instanceof Error ? error.message : String(error)}`,
is_error: true,
};
}
}));
return {
role: 'user',
content: toolResults,
};
}
//# sourceMappingURL=BetaToolRunner.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,25 @@
import { Model } from "../../resources.mjs";
export declare const DEFAULT_TOKEN_THRESHOLD = 100000;
export declare const DEFAULT_SUMMARY_PROMPT = "You have been working on the task described above but have not yet completed it. Write a continuation summary that will allow you (or another instance of yourself) to resume work efficiently in a future context window where the conversation history will be replaced with this summary. Your summary should be structured, concise, and actionable. Include:\n1. Task Overview\nThe user's core request and success criteria\nAny clarifications or constraints they specified\n2. Current State\nWhat has been completed so far\nFiles created, modified, or analyzed (with paths if relevant)\nKey outputs or artifacts produced\n3. Important Discoveries\nTechnical constraints or requirements uncovered\nDecisions made and their rationale\nErrors encountered and how they were resolved\nWhat approaches were tried that didn't work (and why)\n4. Next Steps\nSpecific actions needed to complete the task\nAny blockers or open questions to resolve\nPriority order if multiple steps remain\n5. Context to Preserve\nUser preferences or style requirements\nDomain-specific details that aren't obvious\nAny promises made to the user\nBe concise but complete\u2014err on the side of including information that would prevent duplicate work or repeated mistakes. Write in a way that enables immediate resumption of the task.\nWrap your summary in <summary></summary> tags.";
export interface CompactionControl {
/**
* The context token threshold at which to trigger compaction.
*
* When the cumulative token count (input + output) across all messages exceeds this threshold,
* the message history will be automatically summarized and compressed.
*
* @default 100000
*/
contextTokenThreshold?: number;
/**
* The model to use for generating the compaction summary.
* If not specified, defaults to the same model used for the tool runner.
*/
model?: Model;
/**
* The prompt used to instruct the model on how to generate the summary.
*/
summaryPrompt?: string;
enabled: boolean;
}
//# sourceMappingURL=CompactionControl.d.mts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CompactionControl.d.mts","sourceRoot":"","sources":["../../src/lib/tools/CompactionControl.ts"],"names":[],"mappings":"OAAO,EAAE,KAAK,EAAE;AAEhB,eAAO,MAAM,uBAAuB,SAAU,CAAC;AAE/C,eAAO,MAAM,sBAAsB,20CAsBY,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC;;;;;;;OAOG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;OAGG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IAEd;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,EAAE,OAAO,CAAC;CAClB"}

View File

@@ -0,0 +1,25 @@
import { Model } from "../../resources.js";
export declare const DEFAULT_TOKEN_THRESHOLD = 100000;
export declare const DEFAULT_SUMMARY_PROMPT = "You have been working on the task described above but have not yet completed it. Write a continuation summary that will allow you (or another instance of yourself) to resume work efficiently in a future context window where the conversation history will be replaced with this summary. Your summary should be structured, concise, and actionable. Include:\n1. Task Overview\nThe user's core request and success criteria\nAny clarifications or constraints they specified\n2. Current State\nWhat has been completed so far\nFiles created, modified, or analyzed (with paths if relevant)\nKey outputs or artifacts produced\n3. Important Discoveries\nTechnical constraints or requirements uncovered\nDecisions made and their rationale\nErrors encountered and how they were resolved\nWhat approaches were tried that didn't work (and why)\n4. Next Steps\nSpecific actions needed to complete the task\nAny blockers or open questions to resolve\nPriority order if multiple steps remain\n5. Context to Preserve\nUser preferences or style requirements\nDomain-specific details that aren't obvious\nAny promises made to the user\nBe concise but complete\u2014err on the side of including information that would prevent duplicate work or repeated mistakes. Write in a way that enables immediate resumption of the task.\nWrap your summary in <summary></summary> tags.";
export interface CompactionControl {
/**
* The context token threshold at which to trigger compaction.
*
* When the cumulative token count (input + output) across all messages exceeds this threshold,
* the message history will be automatically summarized and compressed.
*
* @default 100000
*/
contextTokenThreshold?: number;
/**
* The model to use for generating the compaction summary.
* If not specified, defaults to the same model used for the tool runner.
*/
model?: Model;
/**
* The prompt used to instruct the model on how to generate the summary.
*/
summaryPrompt?: string;
enabled: boolean;
}
//# sourceMappingURL=CompactionControl.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CompactionControl.d.ts","sourceRoot":"","sources":["../../src/lib/tools/CompactionControl.ts"],"names":[],"mappings":"OAAO,EAAE,KAAK,EAAE;AAEhB,eAAO,MAAM,uBAAuB,SAAU,CAAC;AAE/C,eAAO,MAAM,sBAAsB,20CAsBY,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC;;;;;;;OAOG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;OAGG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IAEd;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,EAAE,OAAO,CAAC;CAClB"}

View File

@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_SUMMARY_PROMPT = exports.DEFAULT_TOKEN_THRESHOLD = void 0;
exports.DEFAULT_TOKEN_THRESHOLD = 100000;
exports.DEFAULT_SUMMARY_PROMPT = `You have been working on the task described above but have not yet completed it. Write a continuation summary that will allow you (or another instance of yourself) to resume work efficiently in a future context window where the conversation history will be replaced with this summary. Your summary should be structured, concise, and actionable. Include:
1. Task Overview
The user's core request and success criteria
Any clarifications or constraints they specified
2. Current State
What has been completed so far
Files created, modified, or analyzed (with paths if relevant)
Key outputs or artifacts produced
3. Important Discoveries
Technical constraints or requirements uncovered
Decisions made and their rationale
Errors encountered and how they were resolved
What approaches were tried that didn't work (and why)
4. Next Steps
Specific actions needed to complete the task
Any blockers or open questions to resolve
Priority order if multiple steps remain
5. Context to Preserve
User preferences or style requirements
Domain-specific details that aren't obvious
Any promises made to the user
Be concise but complete—err on the side of including information that would prevent duplicate work or repeated mistakes. Write in a way that enables immediate resumption of the task.
Wrap your summary in <summary></summary> tags.`;
//# sourceMappingURL=CompactionControl.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CompactionControl.js","sourceRoot":"","sources":["../../src/lib/tools/CompactionControl.ts"],"names":[],"mappings":";;;AAEa,QAAA,uBAAuB,GAAG,MAAO,CAAC;AAElC,QAAA,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;+CAsBS,CAAC"}

View File

@@ -0,0 +1,25 @@
export const DEFAULT_TOKEN_THRESHOLD = 100000;
export const DEFAULT_SUMMARY_PROMPT = `You have been working on the task described above but have not yet completed it. Write a continuation summary that will allow you (or another instance of yourself) to resume work efficiently in a future context window where the conversation history will be replaced with this summary. Your summary should be structured, concise, and actionable. Include:
1. Task Overview
The user's core request and success criteria
Any clarifications or constraints they specified
2. Current State
What has been completed so far
Files created, modified, or analyzed (with paths if relevant)
Key outputs or artifacts produced
3. Important Discoveries
Technical constraints or requirements uncovered
Decisions made and their rationale
Errors encountered and how they were resolved
What approaches were tried that didn't work (and why)
4. Next Steps
Specific actions needed to complete the task
Any blockers or open questions to resolve
Priority order if multiple steps remain
5. Context to Preserve
User preferences or style requirements
Domain-specific details that aren't obvious
Any promises made to the user
Be concise but complete—err on the side of including information that would prevent duplicate work or repeated mistakes. Write in a way that enables immediate resumption of the task.
Wrap your summary in <summary></summary> tags.`;
//# sourceMappingURL=CompactionControl.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CompactionControl.mjs","sourceRoot":"","sources":["../../src/lib/tools/CompactionControl.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAO,CAAC;AAE/C,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;+CAsBS,CAAC"}

View File

@@ -0,0 +1,33 @@
import { BetaToolResultContentBlockParam } from "../../resources/beta.mjs";
/**
* An error that can be thrown from a tool's `run` method to return structured
* content blocks as the error result, rather than just a string message.
*
* When the ToolRunner catches this error, it will use the `content` property
* as the tool result with `is_error: true`.
*
* @example
* ```ts
* const tool = {
* name: 'my_tool',
* run: async (input) => {
* if (somethingWentWrong) {
* throw new ToolError([
* { type: 'text', text: 'Error details here' },
* { type: 'image', source: { type: 'base64', data: '...', media_type: 'image/png' } },
* ]);
* }
* return 'success';
* },
* };
* ```
*/
export declare class ToolError extends Error {
/**
* The content to return as the tool result. This will be sent back to the model
* with `is_error: true`.
*/
readonly content: string | Array<BetaToolResultContentBlockParam>;
constructor(content: string | Array<BetaToolResultContentBlockParam>);
}
//# sourceMappingURL=ToolError.d.mts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ToolError.d.mts","sourceRoot":"","sources":["../../src/lib/tools/ToolError.ts"],"names":[],"mappings":"OAAO,EAAE,+BAA+B,EAAE;AAE1C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,+BAA+B,CAAC,CAAC;gBAEtD,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,+BAA+B,CAAC;CAcrE"}

View File

@@ -0,0 +1,33 @@
import { BetaToolResultContentBlockParam } from "../../resources/beta.js";
/**
* An error that can be thrown from a tool's `run` method to return structured
* content blocks as the error result, rather than just a string message.
*
* When the ToolRunner catches this error, it will use the `content` property
* as the tool result with `is_error: true`.
*
* @example
* ```ts
* const tool = {
* name: 'my_tool',
* run: async (input) => {
* if (somethingWentWrong) {
* throw new ToolError([
* { type: 'text', text: 'Error details here' },
* { type: 'image', source: { type: 'base64', data: '...', media_type: 'image/png' } },
* ]);
* }
* return 'success';
* },
* };
* ```
*/
export declare class ToolError extends Error {
/**
* The content to return as the tool result. This will be sent back to the model
* with `is_error: true`.
*/
readonly content: string | Array<BetaToolResultContentBlockParam>;
constructor(content: string | Array<BetaToolResultContentBlockParam>);
}
//# sourceMappingURL=ToolError.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ToolError.d.ts","sourceRoot":"","sources":["../../src/lib/tools/ToolError.ts"],"names":[],"mappings":"OAAO,EAAE,+BAA+B,EAAE;AAE1C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,+BAA+B,CAAC,CAAC;gBAEtD,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,+BAA+B,CAAC;CAcrE"}

View File

@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ToolError = void 0;
/**
* An error that can be thrown from a tool's `run` method to return structured
* content blocks as the error result, rather than just a string message.
*
* When the ToolRunner catches this error, it will use the `content` property
* as the tool result with `is_error: true`.
*
* @example
* ```ts
* const tool = {
* name: 'my_tool',
* run: async (input) => {
* if (somethingWentWrong) {
* throw new ToolError([
* { type: 'text', text: 'Error details here' },
* { type: 'image', source: { type: 'base64', data: '...', media_type: 'image/png' } },
* ]);
* }
* return 'success';
* },
* };
* ```
*/
class ToolError extends Error {
constructor(content) {
const message = typeof content === 'string' ? content : (content
.map((block) => {
if (block.type === 'text')
return block.text;
return `[${block.type}]`;
})
.join(' '));
super(message);
this.name = 'ToolError';
this.content = content;
}
}
exports.ToolError = ToolError;
//# sourceMappingURL=ToolError.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ToolError.js","sourceRoot":"","sources":["../../src/lib/tools/ToolError.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAa,SAAU,SAAQ,KAAK;IAOlC,YAAY,OAAwD;QAClE,MAAM,OAAO,GACX,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CACtC,OAAO;aACJ,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACb,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,KAAK,CAAC,IAAI,CAAC;YAC7C,OAAO,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;QAC3B,CAAC,CAAC;aACD,IAAI,CAAC,GAAG,CAAC,CACb,CAAC;QACJ,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;AArBD,8BAqBC"}

View File

@@ -0,0 +1,38 @@
/**
* An error that can be thrown from a tool's `run` method to return structured
* content blocks as the error result, rather than just a string message.
*
* When the ToolRunner catches this error, it will use the `content` property
* as the tool result with `is_error: true`.
*
* @example
* ```ts
* const tool = {
* name: 'my_tool',
* run: async (input) => {
* if (somethingWentWrong) {
* throw new ToolError([
* { type: 'text', text: 'Error details here' },
* { type: 'image', source: { type: 'base64', data: '...', media_type: 'image/png' } },
* ]);
* }
* return 'success';
* },
* };
* ```
*/
export class ToolError extends Error {
constructor(content) {
const message = typeof content === 'string' ? content : (content
.map((block) => {
if (block.type === 'text')
return block.text;
return `[${block.type}]`;
})
.join(' '));
super(message);
this.name = 'ToolError';
this.content = content;
}
}
//# sourceMappingURL=ToolError.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ToolError.mjs","sourceRoot":"","sources":["../../src/lib/tools/ToolError.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAOlC,YAAY,OAAwD;QAClE,MAAM,OAAO,GACX,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CACtC,OAAO;aACJ,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACb,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,KAAK,CAAC,IAAI,CAAC;YAC7C,OAAO,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;QAC3B,CAAC,CAAC;aACD,IAAI,CAAC,GAAG,CAAC,CACb,CAAC;QACJ,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF"}

View File

@@ -0,0 +1,132 @@
import { BetaRunnableTool } from "./BetaRunnableTool.mjs";
import { Anthropic } from "../../index.mjs";
import { BetaMessage, BetaMessageParam, BetaToolUnion, MessageCreateParams } from "../../resources/beta.mjs";
import { BetaMessageStream } from "../BetaMessageStream.mjs";
/**
* A ToolRunner handles the automatic conversation loop between the assistant and tools.
*
* A ToolRunner is an async iterable that yields either BetaMessage or BetaMessageStream objects
* depending on the streaming configuration.
*/
export declare class BetaToolRunner<Stream extends boolean> {
#private;
private client;
constructor(client: Anthropic, params: BetaToolRunnerParams);
[Symbol.asyncIterator](): AsyncIterator<Stream extends true ? BetaMessageStream : Stream extends false ? BetaMessage : BetaMessage | BetaMessageStream>;
/**
* Update the parameters for the next API call. This invalidates any cached tool responses.
*
* @param paramsOrMutator - Either new parameters or a function to mutate existing parameters
*
* @example
* // Direct parameter update
* runner.setMessagesParams({
* model: 'claude-haiku-4-5',
* max_tokens: 500,
* });
*
* @example
* // Using a mutator function
* runner.setMessagesParams((params) => ({
* ...params,
* max_tokens: 100,
* }));
*/
setMessagesParams(params: BetaToolRunnerParams): void;
setMessagesParams(mutator: (prevParams: BetaToolRunnerParams) => BetaToolRunnerParams): void;
/**
* Get the tool response for the last message from the assistant.
* Avoids redundant tool executions by caching results.
*
* @returns A promise that resolves to a BetaMessageParam containing tool results, or null if no tools need to be executed
*
* @example
* const toolResponse = await runner.generateToolResponse();
* if (toolResponse) {
* console.log('Tool results:', toolResponse.content);
* }
*/
generateToolResponse(): Promise<Anthropic.Beta.Messages.BetaMessageParam | null>;
/**
* Wait for the async iterator to complete. This works even if the async iterator hasn't yet started, and
* will wait for an instance to start and go to completion.
*
* @returns A promise that resolves to the final BetaMessage when the iterator completes
*
* @example
* // Start consuming the iterator
* for await (const message of runner) {
* console.log('Message:', message.content);
* }
*
* // Meanwhile, wait for completion from another part of the code
* const finalMessage = await runner.done();
* console.log('Final response:', finalMessage.content);
*/
done(): Promise<BetaMessage>;
/**
* Returns a promise indicating that the stream is done. Unlike .done(), this will eagerly read the stream:
* * If the iterator has not been consumed, consume the entire iterator and return the final message from the
* assistant.
* * If the iterator has been consumed, waits for it to complete and returns the final message.
*
* @returns A promise that resolves to the final BetaMessage from the conversation
* @throws {AnthropicError} If no messages were processed during the conversation
*
* @example
* const finalMessage = await runner.runUntilDone();
* console.log('Final response:', finalMessage.content);
*/
runUntilDone(): Promise<BetaMessage>;
/**
* Get the current parameters being used by the ToolRunner.
*
* @returns A readonly view of the current ToolRunnerParams
*
* @example
* const currentParams = runner.params;
* console.log('Current model:', currentParams.model);
* console.log('Message count:', currentParams.messages.length);
*/
get params(): Readonly<BetaToolRunnerParams>;
/**
* Add one or more messages to the conversation history.
*
* @param messages - One or more BetaMessageParam objects to add to the conversation
*
* @example
* runner.pushMessages(
* { role: 'user', content: 'Also, what about the weather in NYC?' }
* );
*
* @example
* // Adding multiple messages
* runner.pushMessages(
* { role: 'user', content: 'What about NYC?' },
* { role: 'user', content: 'And Boston?' }
* );
*/
pushMessages(...messages: BetaMessageParam[]): void;
/**
* Makes the ToolRunner directly awaitable, equivalent to calling .runUntilDone()
* This allows using `await runner` instead of `await runner.runUntilDone()`
*/
then<TResult1 = BetaMessage, TResult2 = never>(onfulfilled?: ((value: BetaMessage) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
}
type Simplify<T> = {
[KeyType in keyof T]: T[KeyType];
} & {};
/**
* Parameters for creating a ToolRunner, extending MessageCreateParams with runnable tools.
*/
export type BetaToolRunnerParams = Simplify<Omit<MessageCreateParams, 'tools'> & {
tools: (BetaToolUnion | BetaRunnableTool<any>)[];
/**
* Maximum number of iterations (API requests) to make in the tool execution loop.
* Each iteration consists of: assistant response → tool execution → tool results.
* When exceeded, the loop will terminate even if tools are still being requested.
*/
max_iterations?: number;
}>;
export {};
//# sourceMappingURL=ToolRunner.d.mts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ToolRunner.d.mts","sourceRoot":"","sources":["../../src/lib/tools/ToolRunner.ts"],"names":[],"mappings":"OAAO,EAAE,gBAAgB,EAAE;OAEpB,EAAE,SAAS,EAAE;OAEb,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,mBAAmB,EAAE;OACrE,EAAE,iBAAiB,EAAE;AAmB5B;;;;;GAKG;AACH,qBAAa,cAAc,CAAC,MAAM,SAAS,OAAO;;IAqB9C,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS,EACzB,MAAM,EAAE,oBAAoB;IAevB,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAC5C,MAAM,SAAS,IAAI,GAAG,iBAAiB,GACrC,MAAM,SAAS,KAAK,GAAG,WAAW,GAClC,WAAW,GAAG,iBAAiB,CAClC;IAyED;;;;;;;;;;;;;;;;;;OAkBG;IACH,iBAAiB,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IACrD,iBAAiB,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,oBAAoB,KAAK,oBAAoB,GAAG,IAAI;IAc5F;;;;;;;;;;;OAWG;IACG,oBAAoB;IAgB1B;;;;;;;;;;;;;;;OAeG;IACH,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC;IAI5B;;;;;;;;;;;;OAYG;IACG,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC;IAY1C;;;;;;;;;OASG;IACH,IAAI,MAAM,IAAI,QAAQ,CAAC,oBAAoB,CAAC,CAE3C;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,YAAY,CAAC,GAAG,QAAQ,EAAE,gBAAgB,EAAE;IAO5C;;;OAGG;IACH,IAAI,CAAC,QAAQ,GAAG,WAAW,EAAE,QAAQ,GAAG,KAAK,EAC3C,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,EAC3F,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,GAClF,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;CAGhC;AAkED,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;CAAE,GAAG,EAAE,CAAC;AAE7D;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CACzC,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,GAAG;IACnC,KAAK,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;IACjD;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CACF,CAAC"}

View File

@@ -0,0 +1,132 @@
import { BetaRunnableTool } from "./BetaRunnableTool.js";
import { Anthropic } from "../../index.js";
import { BetaMessage, BetaMessageParam, BetaToolUnion, MessageCreateParams } from "../../resources/beta.js";
import { BetaMessageStream } from "../BetaMessageStream.js";
/**
* A ToolRunner handles the automatic conversation loop between the assistant and tools.
*
* A ToolRunner is an async iterable that yields either BetaMessage or BetaMessageStream objects
* depending on the streaming configuration.
*/
export declare class BetaToolRunner<Stream extends boolean> {
#private;
private client;
constructor(client: Anthropic, params: BetaToolRunnerParams);
[Symbol.asyncIterator](): AsyncIterator<Stream extends true ? BetaMessageStream : Stream extends false ? BetaMessage : BetaMessage | BetaMessageStream>;
/**
* Update the parameters for the next API call. This invalidates any cached tool responses.
*
* @param paramsOrMutator - Either new parameters or a function to mutate existing parameters
*
* @example
* // Direct parameter update
* runner.setMessagesParams({
* model: 'claude-haiku-4-5',
* max_tokens: 500,
* });
*
* @example
* // Using a mutator function
* runner.setMessagesParams((params) => ({
* ...params,
* max_tokens: 100,
* }));
*/
setMessagesParams(params: BetaToolRunnerParams): void;
setMessagesParams(mutator: (prevParams: BetaToolRunnerParams) => BetaToolRunnerParams): void;
/**
* Get the tool response for the last message from the assistant.
* Avoids redundant tool executions by caching results.
*
* @returns A promise that resolves to a BetaMessageParam containing tool results, or null if no tools need to be executed
*
* @example
* const toolResponse = await runner.generateToolResponse();
* if (toolResponse) {
* console.log('Tool results:', toolResponse.content);
* }
*/
generateToolResponse(): Promise<Anthropic.Beta.Messages.BetaMessageParam | null>;
/**
* Wait for the async iterator to complete. This works even if the async iterator hasn't yet started, and
* will wait for an instance to start and go to completion.
*
* @returns A promise that resolves to the final BetaMessage when the iterator completes
*
* @example
* // Start consuming the iterator
* for await (const message of runner) {
* console.log('Message:', message.content);
* }
*
* // Meanwhile, wait for completion from another part of the code
* const finalMessage = await runner.done();
* console.log('Final response:', finalMessage.content);
*/
done(): Promise<BetaMessage>;
/**
* Returns a promise indicating that the stream is done. Unlike .done(), this will eagerly read the stream:
* * If the iterator has not been consumed, consume the entire iterator and return the final message from the
* assistant.
* * If the iterator has been consumed, waits for it to complete and returns the final message.
*
* @returns A promise that resolves to the final BetaMessage from the conversation
* @throws {AnthropicError} If no messages were processed during the conversation
*
* @example
* const finalMessage = await runner.runUntilDone();
* console.log('Final response:', finalMessage.content);
*/
runUntilDone(): Promise<BetaMessage>;
/**
* Get the current parameters being used by the ToolRunner.
*
* @returns A readonly view of the current ToolRunnerParams
*
* @example
* const currentParams = runner.params;
* console.log('Current model:', currentParams.model);
* console.log('Message count:', currentParams.messages.length);
*/
get params(): Readonly<BetaToolRunnerParams>;
/**
* Add one or more messages to the conversation history.
*
* @param messages - One or more BetaMessageParam objects to add to the conversation
*
* @example
* runner.pushMessages(
* { role: 'user', content: 'Also, what about the weather in NYC?' }
* );
*
* @example
* // Adding multiple messages
* runner.pushMessages(
* { role: 'user', content: 'What about NYC?' },
* { role: 'user', content: 'And Boston?' }
* );
*/
pushMessages(...messages: BetaMessageParam[]): void;
/**
* Makes the ToolRunner directly awaitable, equivalent to calling .runUntilDone()
* This allows using `await runner` instead of `await runner.runUntilDone()`
*/
then<TResult1 = BetaMessage, TResult2 = never>(onfulfilled?: ((value: BetaMessage) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
}
type Simplify<T> = {
[KeyType in keyof T]: T[KeyType];
} & {};
/**
* Parameters for creating a ToolRunner, extending MessageCreateParams with runnable tools.
*/
export type BetaToolRunnerParams = Simplify<Omit<MessageCreateParams, 'tools'> & {
tools: (BetaToolUnion | BetaRunnableTool<any>)[];
/**
* Maximum number of iterations (API requests) to make in the tool execution loop.
* Each iteration consists of: assistant response → tool execution → tool results.
* When exceeded, the loop will terminate even if tools are still being requested.
*/
max_iterations?: number;
}>;
export {};
//# sourceMappingURL=ToolRunner.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ToolRunner.d.ts","sourceRoot":"","sources":["../../src/lib/tools/ToolRunner.ts"],"names":[],"mappings":"OAAO,EAAE,gBAAgB,EAAE;OAEpB,EAAE,SAAS,EAAE;OAEb,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,mBAAmB,EAAE;OACrE,EAAE,iBAAiB,EAAE;AAmB5B;;;;;GAKG;AACH,qBAAa,cAAc,CAAC,MAAM,SAAS,OAAO;;IAqB9C,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS,EACzB,MAAM,EAAE,oBAAoB;IAevB,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAC5C,MAAM,SAAS,IAAI,GAAG,iBAAiB,GACrC,MAAM,SAAS,KAAK,GAAG,WAAW,GAClC,WAAW,GAAG,iBAAiB,CAClC;IAyED;;;;;;;;;;;;;;;;;;OAkBG;IACH,iBAAiB,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IACrD,iBAAiB,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,oBAAoB,KAAK,oBAAoB,GAAG,IAAI;IAc5F;;;;;;;;;;;OAWG;IACG,oBAAoB;IAgB1B;;;;;;;;;;;;;;;OAeG;IACH,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC;IAI5B;;;;;;;;;;;;OAYG;IACG,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC;IAY1C;;;;;;;;;OASG;IACH,IAAI,MAAM,IAAI,QAAQ,CAAC,oBAAoB,CAAC,CAE3C;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,YAAY,CAAC,GAAG,QAAQ,EAAE,gBAAgB,EAAE;IAO5C;;;OAGG;IACH,IAAI,CAAC,QAAQ,GAAG,WAAW,EAAE,QAAQ,GAAG,KAAK,EAC3C,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,EAC3F,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,GAClF,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;CAGhC;AAkED,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;CAAE,GAAG,EAAE,CAAC;AAE7D;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CACzC,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,GAAG;IACnC,KAAK,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;IACjD;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CACF,CAAC"}

View File

@@ -0,0 +1,294 @@
"use strict";
var _BetaToolRunner_instances, _BetaToolRunner_consumed, _BetaToolRunner_mutated, _BetaToolRunner_state, _BetaToolRunner_message, _BetaToolRunner_toolResponse, _BetaToolRunner_completion, _BetaToolRunner_iterationCount, _BetaToolRunner_generateToolResponse;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BetaToolRunner = void 0;
const tslib_1 = require("../../internal/tslib.js");
const ToolError_1 = require("./ToolError.js");
const error_1 = require("../../core/error.js");
/**
* Just Promise.withResolvers(), which is not available in all environments.
*/
function promiseWithResolvers() {
let resolve;
let reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve: resolve, reject: reject };
}
/**
* A ToolRunner handles the automatic conversation loop between the assistant and tools.
*
* A ToolRunner is an async iterable that yields either BetaMessage or BetaMessageStream objects
* depending on the streaming configuration.
*/
class BetaToolRunner {
constructor(client, params) {
_BetaToolRunner_instances.add(this);
this.client = client;
/** Whether the async iterator has been consumed */
_BetaToolRunner_consumed.set(this, false);
/** Whether parameters have been mutated since the last API call */
_BetaToolRunner_mutated.set(this, false);
/** Current state containing the request parameters */
_BetaToolRunner_state.set(this, void 0);
/** Promise for the last message received from the assistant */
_BetaToolRunner_message.set(this, void 0);
/** Cached tool response to avoid redundant executions */
_BetaToolRunner_toolResponse.set(this, void 0);
/** Promise resolvers for waiting on completion */
_BetaToolRunner_completion.set(this, void 0);
/** Number of iterations (API requests) made so far */
_BetaToolRunner_iterationCount.set(this, 0);
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_state, {
params: {
// You can't clone the entire params since there are functions as handlers.
// You also don't really need to clone params.messages, but it probably will prevent a foot gun
// somewhere.
...params,
messages: structuredClone(params.messages),
},
}, "f");
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_completion, promiseWithResolvers(), "f");
}
async *[(_BetaToolRunner_consumed = new WeakMap(), _BetaToolRunner_mutated = new WeakMap(), _BetaToolRunner_state = new WeakMap(), _BetaToolRunner_message = new WeakMap(), _BetaToolRunner_toolResponse = new WeakMap(), _BetaToolRunner_completion = new WeakMap(), _BetaToolRunner_iterationCount = new WeakMap(), _BetaToolRunner_instances = new WeakSet(), Symbol.asyncIterator)]() {
var _a;
if (tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_consumed, "f")) {
throw new error_1.AnthropicError('Cannot iterate over a consumed stream');
}
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_consumed, true, "f");
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_mutated, true, "f");
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, undefined, "f");
try {
while (true) {
let stream;
try {
if (tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.max_iterations &&
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_iterationCount, "f") >= tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.max_iterations) {
break;
}
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_mutated, false, "f");
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_message, undefined, "f");
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, undefined, "f");
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_iterationCount, (_a = tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_iterationCount, "f"), _a++, _a), "f");
const { max_iterations, ...params } = tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params;
if (params.stream) {
stream = this.client.beta.messages.stream({ ...params });
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_message, stream.finalMessage(), "f");
// Make sure that this promise doesn't throw before we get the option to do something about it.
// Error will be caught when we call await this.#message ultimately
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f").catch(() => { });
yield stream;
}
else {
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_message, this.client.beta.messages.create({ ...params, stream: false }), "f");
yield tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f");
}
if (!tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_mutated, "f")) {
const { role, content } = await tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f");
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages.push({ role, content });
}
const toolMessage = await tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_instances, "m", _BetaToolRunner_generateToolResponse).call(this, tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages.at(-1));
if (toolMessage) {
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages.push(toolMessage);
}
if (!toolMessage && !tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_mutated, "f")) {
break;
}
}
finally {
if (stream) {
stream.abort();
}
}
}
if (!tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f")) {
throw new error_1.AnthropicError('ToolRunner concluded without a message from the server');
}
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").resolve(await tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f"));
}
catch (error) {
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_consumed, false, "f");
// Silence unhandled promise errors
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").promise.catch(() => { });
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").reject(error);
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_completion, promiseWithResolvers(), "f");
throw error;
}
}
setMessagesParams(paramsOrMutator) {
if (typeof paramsOrMutator === 'function') {
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params = paramsOrMutator(tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params);
}
else {
tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params = paramsOrMutator;
}
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_mutated, true, "f");
// Invalidate cached tool response since parameters changed
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, undefined, "f");
}
/**
* Get the tool response for the last message from the assistant.
* Avoids redundant tool executions by caching results.
*
* @returns A promise that resolves to a BetaMessageParam containing tool results, or null if no tools need to be executed
*
* @example
* const toolResponse = await runner.generateToolResponse();
* if (toolResponse) {
* console.log('Tool results:', toolResponse.content);
* }
*/
async generateToolResponse() {
const message = (await tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_message, "f")) ?? this.params.messages.at(-1);
if (!message) {
return null;
}
return tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_instances, "m", _BetaToolRunner_generateToolResponse).call(this, message);
}
/**
* Wait for the async iterator to complete. This works even if the async iterator hasn't yet started, and
* will wait for an instance to start and go to completion.
*
* @returns A promise that resolves to the final BetaMessage when the iterator completes
*
* @example
* // Start consuming the iterator
* for await (const message of runner) {
* console.log('Message:', message.content);
* }
*
* // Meanwhile, wait for completion from another part of the code
* const finalMessage = await runner.done();
* console.log('Final response:', finalMessage.content);
*/
done() {
return tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").promise;
}
/**
* Returns a promise indicating that the stream is done. Unlike .done(), this will eagerly read the stream:
* * If the iterator has not been consumed, consume the entire iterator and return the final message from the
* assistant.
* * If the iterator has been consumed, waits for it to complete and returns the final message.
*
* @returns A promise that resolves to the final BetaMessage from the conversation
* @throws {AnthropicError} If no messages were processed during the conversation
*
* @example
* const finalMessage = await runner.runUntilDone();
* console.log('Final response:', finalMessage.content);
*/
async runUntilDone() {
// If not yet consumed, start consuming and wait for completion
if (!tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_consumed, "f")) {
for await (const _ of this) {
// Iterator naturally populates this.#message
}
}
// If consumed but not completed, wait for completion
return this.done();
}
/**
* Get the current parameters being used by the ToolRunner.
*
* @returns A readonly view of the current ToolRunnerParams
*
* @example
* const currentParams = runner.params;
* console.log('Current model:', currentParams.model);
* console.log('Message count:', currentParams.messages.length);
*/
get params() {
return tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params;
}
/**
* Add one or more messages to the conversation history.
*
* @param messages - One or more BetaMessageParam objects to add to the conversation
*
* @example
* runner.pushMessages(
* { role: 'user', content: 'Also, what about the weather in NYC?' }
* );
*
* @example
* // Adding multiple messages
* runner.pushMessages(
* { role: 'user', content: 'What about NYC?' },
* { role: 'user', content: 'And Boston?' }
* );
*/
pushMessages(...messages) {
this.setMessagesParams((params) => ({
...params,
messages: [...params.messages, ...messages],
}));
}
/**
* Makes the ToolRunner directly awaitable, equivalent to calling .runUntilDone()
* This allows using `await runner` instead of `await runner.runUntilDone()`
*/
then(onfulfilled, onrejected) {
return this.runUntilDone().then(onfulfilled, onrejected);
}
}
exports.BetaToolRunner = BetaToolRunner;
_BetaToolRunner_generateToolResponse = async function _BetaToolRunner_generateToolResponse(lastMessage) {
if (tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_toolResponse, "f") !== undefined) {
return tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_toolResponse, "f");
}
tslib_1.__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, generateToolResponse(tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params, lastMessage), "f");
return tslib_1.__classPrivateFieldGet(this, _BetaToolRunner_toolResponse, "f");
};
async function generateToolResponse(params, lastMessage = params.messages.at(-1)) {
// Only process if the last message is from the assistant and has tool use blocks
if (!lastMessage ||
lastMessage.role !== 'assistant' ||
!lastMessage.content ||
typeof lastMessage.content === 'string') {
return null;
}
const toolUseBlocks = lastMessage.content.filter((content) => content.type === 'tool_use');
if (toolUseBlocks.length === 0) {
return null;
}
const toolResults = await Promise.all(toolUseBlocks.map(async (toolUse) => {
const tool = params.tools.find((t) => ('name' in t ? t.name : t.mcp_server_name) === toolUse.name);
if (!tool || !('run' in tool)) {
return {
type: 'tool_result',
tool_use_id: toolUse.id,
content: `Error: Tool '${toolUse.name}' not found`,
is_error: true,
};
}
try {
let input = toolUse.input;
if ('parse' in tool && tool.parse) {
input = tool.parse(input);
}
const result = await tool.run(input);
return {
type: 'tool_result',
tool_use_id: toolUse.id,
content: result,
};
}
catch (error) {
return {
type: 'tool_result',
tool_use_id: toolUse.id,
content: error instanceof ToolError_1.ToolError ?
error.content
: `Error: ${error instanceof Error ? error.message : String(error)}`,
is_error: true,
};
}
}));
return {
role: 'user',
content: toolResults,
};
}
//# sourceMappingURL=ToolRunner.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,290 @@
var _BetaToolRunner_instances, _BetaToolRunner_consumed, _BetaToolRunner_mutated, _BetaToolRunner_state, _BetaToolRunner_message, _BetaToolRunner_toolResponse, _BetaToolRunner_completion, _BetaToolRunner_iterationCount, _BetaToolRunner_generateToolResponse;
import { __classPrivateFieldGet, __classPrivateFieldSet } from "../../internal/tslib.mjs";
import { ToolError } from "./ToolError.mjs";
import { AnthropicError } from "../../core/error.mjs";
/**
* Just Promise.withResolvers(), which is not available in all environments.
*/
function promiseWithResolvers() {
let resolve;
let reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve: resolve, reject: reject };
}
/**
* A ToolRunner handles the automatic conversation loop between the assistant and tools.
*
* A ToolRunner is an async iterable that yields either BetaMessage or BetaMessageStream objects
* depending on the streaming configuration.
*/
export class BetaToolRunner {
constructor(client, params) {
_BetaToolRunner_instances.add(this);
this.client = client;
/** Whether the async iterator has been consumed */
_BetaToolRunner_consumed.set(this, false);
/** Whether parameters have been mutated since the last API call */
_BetaToolRunner_mutated.set(this, false);
/** Current state containing the request parameters */
_BetaToolRunner_state.set(this, void 0);
/** Promise for the last message received from the assistant */
_BetaToolRunner_message.set(this, void 0);
/** Cached tool response to avoid redundant executions */
_BetaToolRunner_toolResponse.set(this, void 0);
/** Promise resolvers for waiting on completion */
_BetaToolRunner_completion.set(this, void 0);
/** Number of iterations (API requests) made so far */
_BetaToolRunner_iterationCount.set(this, 0);
__classPrivateFieldSet(this, _BetaToolRunner_state, {
params: {
// You can't clone the entire params since there are functions as handlers.
// You also don't really need to clone params.messages, but it probably will prevent a foot gun
// somewhere.
...params,
messages: structuredClone(params.messages),
},
}, "f");
__classPrivateFieldSet(this, _BetaToolRunner_completion, promiseWithResolvers(), "f");
}
async *[(_BetaToolRunner_consumed = new WeakMap(), _BetaToolRunner_mutated = new WeakMap(), _BetaToolRunner_state = new WeakMap(), _BetaToolRunner_message = new WeakMap(), _BetaToolRunner_toolResponse = new WeakMap(), _BetaToolRunner_completion = new WeakMap(), _BetaToolRunner_iterationCount = new WeakMap(), _BetaToolRunner_instances = new WeakSet(), Symbol.asyncIterator)]() {
var _a;
if (__classPrivateFieldGet(this, _BetaToolRunner_consumed, "f")) {
throw new AnthropicError('Cannot iterate over a consumed stream');
}
__classPrivateFieldSet(this, _BetaToolRunner_consumed, true, "f");
__classPrivateFieldSet(this, _BetaToolRunner_mutated, true, "f");
__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, undefined, "f");
try {
while (true) {
let stream;
try {
if (__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.max_iterations &&
__classPrivateFieldGet(this, _BetaToolRunner_iterationCount, "f") >= __classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.max_iterations) {
break;
}
__classPrivateFieldSet(this, _BetaToolRunner_mutated, false, "f");
__classPrivateFieldSet(this, _BetaToolRunner_message, undefined, "f");
__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, undefined, "f");
__classPrivateFieldSet(this, _BetaToolRunner_iterationCount, (_a = __classPrivateFieldGet(this, _BetaToolRunner_iterationCount, "f"), _a++, _a), "f");
const { max_iterations, ...params } = __classPrivateFieldGet(this, _BetaToolRunner_state, "f").params;
if (params.stream) {
stream = this.client.beta.messages.stream({ ...params });
__classPrivateFieldSet(this, _BetaToolRunner_message, stream.finalMessage(), "f");
// Make sure that this promise doesn't throw before we get the option to do something about it.
// Error will be caught when we call await this.#message ultimately
__classPrivateFieldGet(this, _BetaToolRunner_message, "f").catch(() => { });
yield stream;
}
else {
__classPrivateFieldSet(this, _BetaToolRunner_message, this.client.beta.messages.create({ ...params, stream: false }), "f");
yield __classPrivateFieldGet(this, _BetaToolRunner_message, "f");
}
if (!__classPrivateFieldGet(this, _BetaToolRunner_mutated, "f")) {
const { role, content } = await __classPrivateFieldGet(this, _BetaToolRunner_message, "f");
__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages.push({ role, content });
}
const toolMessage = await __classPrivateFieldGet(this, _BetaToolRunner_instances, "m", _BetaToolRunner_generateToolResponse).call(this, __classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages.at(-1));
if (toolMessage) {
__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params.messages.push(toolMessage);
}
if (!toolMessage && !__classPrivateFieldGet(this, _BetaToolRunner_mutated, "f")) {
break;
}
}
finally {
if (stream) {
stream.abort();
}
}
}
if (!__classPrivateFieldGet(this, _BetaToolRunner_message, "f")) {
throw new AnthropicError('ToolRunner concluded without a message from the server');
}
__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").resolve(await __classPrivateFieldGet(this, _BetaToolRunner_message, "f"));
}
catch (error) {
__classPrivateFieldSet(this, _BetaToolRunner_consumed, false, "f");
// Silence unhandled promise errors
__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").promise.catch(() => { });
__classPrivateFieldGet(this, _BetaToolRunner_completion, "f").reject(error);
__classPrivateFieldSet(this, _BetaToolRunner_completion, promiseWithResolvers(), "f");
throw error;
}
}
setMessagesParams(paramsOrMutator) {
if (typeof paramsOrMutator === 'function') {
__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params = paramsOrMutator(__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params);
}
else {
__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params = paramsOrMutator;
}
__classPrivateFieldSet(this, _BetaToolRunner_mutated, true, "f");
// Invalidate cached tool response since parameters changed
__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, undefined, "f");
}
/**
* Get the tool response for the last message from the assistant.
* Avoids redundant tool executions by caching results.
*
* @returns A promise that resolves to a BetaMessageParam containing tool results, or null if no tools need to be executed
*
* @example
* const toolResponse = await runner.generateToolResponse();
* if (toolResponse) {
* console.log('Tool results:', toolResponse.content);
* }
*/
async generateToolResponse() {
const message = (await __classPrivateFieldGet(this, _BetaToolRunner_message, "f")) ?? this.params.messages.at(-1);
if (!message) {
return null;
}
return __classPrivateFieldGet(this, _BetaToolRunner_instances, "m", _BetaToolRunner_generateToolResponse).call(this, message);
}
/**
* Wait for the async iterator to complete. This works even if the async iterator hasn't yet started, and
* will wait for an instance to start and go to completion.
*
* @returns A promise that resolves to the final BetaMessage when the iterator completes
*
* @example
* // Start consuming the iterator
* for await (const message of runner) {
* console.log('Message:', message.content);
* }
*
* // Meanwhile, wait for completion from another part of the code
* const finalMessage = await runner.done();
* console.log('Final response:', finalMessage.content);
*/
done() {
return __classPrivateFieldGet(this, _BetaToolRunner_completion, "f").promise;
}
/**
* Returns a promise indicating that the stream is done. Unlike .done(), this will eagerly read the stream:
* * If the iterator has not been consumed, consume the entire iterator and return the final message from the
* assistant.
* * If the iterator has been consumed, waits for it to complete and returns the final message.
*
* @returns A promise that resolves to the final BetaMessage from the conversation
* @throws {AnthropicError} If no messages were processed during the conversation
*
* @example
* const finalMessage = await runner.runUntilDone();
* console.log('Final response:', finalMessage.content);
*/
async runUntilDone() {
// If not yet consumed, start consuming and wait for completion
if (!__classPrivateFieldGet(this, _BetaToolRunner_consumed, "f")) {
for await (const _ of this) {
// Iterator naturally populates this.#message
}
}
// If consumed but not completed, wait for completion
return this.done();
}
/**
* Get the current parameters being used by the ToolRunner.
*
* @returns A readonly view of the current ToolRunnerParams
*
* @example
* const currentParams = runner.params;
* console.log('Current model:', currentParams.model);
* console.log('Message count:', currentParams.messages.length);
*/
get params() {
return __classPrivateFieldGet(this, _BetaToolRunner_state, "f").params;
}
/**
* Add one or more messages to the conversation history.
*
* @param messages - One or more BetaMessageParam objects to add to the conversation
*
* @example
* runner.pushMessages(
* { role: 'user', content: 'Also, what about the weather in NYC?' }
* );
*
* @example
* // Adding multiple messages
* runner.pushMessages(
* { role: 'user', content: 'What about NYC?' },
* { role: 'user', content: 'And Boston?' }
* );
*/
pushMessages(...messages) {
this.setMessagesParams((params) => ({
...params,
messages: [...params.messages, ...messages],
}));
}
/**
* Makes the ToolRunner directly awaitable, equivalent to calling .runUntilDone()
* This allows using `await runner` instead of `await runner.runUntilDone()`
*/
then(onfulfilled, onrejected) {
return this.runUntilDone().then(onfulfilled, onrejected);
}
}
_BetaToolRunner_generateToolResponse = async function _BetaToolRunner_generateToolResponse(lastMessage) {
if (__classPrivateFieldGet(this, _BetaToolRunner_toolResponse, "f") !== undefined) {
return __classPrivateFieldGet(this, _BetaToolRunner_toolResponse, "f");
}
__classPrivateFieldSet(this, _BetaToolRunner_toolResponse, generateToolResponse(__classPrivateFieldGet(this, _BetaToolRunner_state, "f").params, lastMessage), "f");
return __classPrivateFieldGet(this, _BetaToolRunner_toolResponse, "f");
};
async function generateToolResponse(params, lastMessage = params.messages.at(-1)) {
// Only process if the last message is from the assistant and has tool use blocks
if (!lastMessage ||
lastMessage.role !== 'assistant' ||
!lastMessage.content ||
typeof lastMessage.content === 'string') {
return null;
}
const toolUseBlocks = lastMessage.content.filter((content) => content.type === 'tool_use');
if (toolUseBlocks.length === 0) {
return null;
}
const toolResults = await Promise.all(toolUseBlocks.map(async (toolUse) => {
const tool = params.tools.find((t) => ('name' in t ? t.name : t.mcp_server_name) === toolUse.name);
if (!tool || !('run' in tool)) {
return {
type: 'tool_result',
tool_use_id: toolUse.id,
content: `Error: Tool '${toolUse.name}' not found`,
is_error: true,
};
}
try {
let input = toolUse.input;
if ('parse' in tool && tool.parse) {
input = tool.parse(input);
}
const result = await tool.run(input);
return {
type: 'tool_result',
tool_use_id: toolUse.id,
content: result,
};
}
catch (error) {
return {
type: 'tool_result',
tool_use_id: toolUse.id,
content: error instanceof ToolError ?
error.content
: `Error: ${error instanceof Error ? error.message : String(error)}`,
is_error: true,
};
}
}));
return {
role: 'user',
content: toolResults,
};
}
//# sourceMappingURL=ToolRunner.mjs.map

File diff suppressed because one or more lines are too long