@aigne/anthropic 1.74.0-beta.7 → 1.74.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -289,7 +289,7 @@ async function convertContent(content) {
289
289
  type: "text",
290
290
  text: item.text
291
291
  };
292
- const media_type = await _aigne_model_base.ChatModel.getMimeType(item.mimeType || item.filename || "");
292
+ const media_type = item.mimeType || await _aigne_model_base.ChatModel.getMimeType(item.filename || "");
293
293
  switch (item.type) {
294
294
  case "url": return {
295
295
  type: "image",
@@ -287,7 +287,7 @@ async function convertContent(content) {
287
287
  type: "text",
288
288
  text: item.text
289
289
  };
290
- const media_type = await ChatModel.getMimeType(item.mimeType || item.filename || "");
290
+ const media_type = item.mimeType || await ChatModel.getMimeType(item.filename || "");
291
291
  switch (item.type) {
292
292
  case "url": return {
293
293
  type: "image",
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic-chat-model.mjs","names":[],"sources":["../src/anthropic-chat-model.ts"],"sourcesContent":["import {\n ChatModel,\n type ChatModelInput,\n type ChatModelInputMessageContent,\n type ChatModelOptions,\n type ChatModelOutput,\n type ChatModelOutputToolCall,\n type ChatModelOutputUsage,\n type ModelInvokeOptions,\n type ModelProcessAsyncGenerator,\n type ModelProcessResult,\n} from \"@aigne/model-base\";\nimport { parseJSON } from \"@aigne/model-base/utils/json-schema\";\nimport {\n checkArguments,\n isEmpty,\n isNonNullable,\n omit,\n type PromiseOrValue,\n} from \"@aigne/model-base/utils/type-utils\";\nimport Anthropic, { type ClientOptions } from \"@anthropic-ai/sdk\";\nimport type {\n Base64ImageSource,\n ImageBlockParam,\n TextBlockParam,\n} from \"@anthropic-ai/sdk/resources\";\nimport type {\n MessageParam,\n Tool,\n ToolChoice,\n ToolUnion,\n} from \"@anthropic-ai/sdk/resources/index.js\";\nimport { z } from \"zod\";\n\nconst CHAT_MODEL_CLAUDE_DEFAULT_MODEL = \"claude-3-7-sonnet-latest\";\nconst OUTPUT_FUNCTION_NAME = \"generate_json\";\n\n/**\n * Configuration options for Claude Chat Model\n */\nexport interface AnthropicChatModelOptions extends ChatModelOptions {\n /**\n * API key for Anthropic's Claude API\n *\n * If not provided, will look for ANTHROPIC_API_KEY or CLAUDE_API_KEY in environment variables\n */\n apiKey?: string;\n\n /**\n * Optional client options for the Anthropic SDK\n */\n clientOptions?: Partial<ClientOptions>;\n}\n\n/**\n * @hidden\n */\nexport const claudeChatModelOptionsSchema = z.object({\n apiKey: z.string().optional(),\n model: z.string().optional(),\n modelOptions: z\n .object({\n model: z.string().optional(),\n temperature: z.number().optional(),\n topP: z.number().optional(),\n frequencyPenalty: z.number().optional(),\n presencePenalty: z.number().optional(),\n parallelToolCalls: z.boolean().optional().default(true),\n })\n .optional(),\n});\n\n/**\n * Implementation of the ChatModel interface for Anthropic's Claude API\n *\n * This model provides access to Claude's capabilities including:\n * - Text generation\n * - Tool use\n * - JSON structured output\n *\n * Default model: 'claude-3-7-sonnet-latest'\n *\n * @example\n * Here's how to create and use a Claude chat model:\n * {@includeCode ../test/anthropic-chat-model.test.ts#example-anthropic-chat-model}\n *\n * @example\n * Here's an example with streaming response:\n * {@includeCode ../test/anthropic-chat-model.test.ts#example-anthropic-chat-model-streaming-async-generator}\n */\nexport class AnthropicChatModel extends ChatModel {\n constructor(public override options?: AnthropicChatModelOptions) {\n if (options) checkArguments(\"AnthropicChatModel\", claudeChatModelOptionsSchema, options);\n super();\n }\n\n protected apiKeyEnvName = \"ANTHROPIC_API_KEY\";\n\n /**\n * @hidden\n */\n protected _client?: Anthropic;\n\n get client() {\n const { apiKey } = this.credential;\n if (!apiKey)\n throw new Error(\n \"AnthropicChatModel requires an API key. Please provide it via `options.apiKey`, or set the `ANTHROPIC_API_KEY` or `CLAUDE_API_KEY` environment variable\",\n );\n\n this._client ??= new Anthropic({\n apiKey,\n ...this.options?.clientOptions,\n timeout: this.options?.clientOptions?.timeout ?? 600e3,\n });\n return this._client;\n }\n\n get modelOptions() {\n return this.options?.modelOptions;\n }\n\n override get credential() {\n const apiKey =\n this.options?.apiKey || process.env[this.apiKeyEnvName] || process.env.CLAUDE_API_KEY;\n\n return {\n apiKey,\n model: this.options?.model || CHAT_MODEL_CLAUDE_DEFAULT_MODEL,\n };\n }\n\n override async countTokens(input: ChatModelInput): Promise<number> {\n const request = await this.getMessageCreateParams(input);\n return (await this.client.messages.countTokens(omit(request, \"max_tokens\"))).input_tokens;\n }\n\n private async getMessageCreateParams(\n input: ChatModelInput,\n ): Promise<Anthropic.Messages.MessageCreateParams> {\n const { modelOptions = {} } = input;\n const model = modelOptions.model || this.credential.model;\n const disableParallelToolUse = modelOptions.parallelToolCalls === false;\n\n return {\n model,\n temperature: modelOptions.temperature,\n top_p: modelOptions.topP,\n max_tokens: this.getMaxTokens(model),\n ...(await convertMessages(input)),\n ...convertTools({ ...input, disableParallelToolUse }),\n };\n }\n\n private getMaxTokens(model: string): number {\n // Order matters: more specific patterns first.\n // Source: https://platform.claude.com/docs/en/docs/about-claude/models/all-models\n const matchers = [\n [/claude-opus-4-6/, 128000], // Opus 4.6: 128K\n [/claude-opus-4-5/, 64000], // Opus 4.5: 64K\n [/claude-opus-4-/, 32000], // Opus 4.0, 4.1: 32K\n [/claude-sonnet-4-/, 64000], // Sonnet 4.0, 4.5, 4.6: 64K\n [/claude-haiku-4-/, 64000], // Haiku 4.5: 64K\n [/claude-3-7-sonnet-/, 64000], // 3.7 Sonnet: 64K\n [/claude-3-5-sonnet-/, 8192], // 3.5 Sonnet: 8K\n [/claude-3-5-haiku-/, 8192], // 3.5 Haiku: 8K\n ] as const;\n\n for (const [regex, maxTokens] of matchers) {\n if (regex.test(model)) {\n return maxTokens;\n }\n }\n\n return 4096; // Claude 3 Haiku: 4K\n }\n\n /**\n * Process the input using Claude's chat model\n * @param input - The input to process\n * @returns The processed output from the model\n */\n override process(\n input: ChatModelInput,\n _options: ModelInvokeOptions,\n ): PromiseOrValue<ModelProcessResult<ChatModelOutput>> {\n return this.processInput(input);\n }\n\n private async *processInput(input: ChatModelInput): ModelProcessAsyncGenerator<ChatModelOutput> {\n const body = await this.getMessageCreateParams(input);\n const stream = this.client.messages.stream({ ...body, stream: true });\n\n const blocks: ((ChatModelOutputToolCall & { args: string }) | null)[] = [];\n let usage: ChatModelOutputUsage | undefined;\n let json: unknown;\n\n for await (const chunk of stream) {\n if (chunk.type === \"message_start\") {\n yield { delta: { json: { model: chunk.message.model } } };\n\n const {\n input_tokens,\n output_tokens,\n cache_creation_input_tokens,\n cache_read_input_tokens,\n } = chunk.message.usage;\n usage = {\n inputTokens: input_tokens,\n outputTokens: output_tokens,\n cacheCreationInputTokens: cache_creation_input_tokens ?? undefined,\n cacheReadInputTokens: cache_read_input_tokens ?? undefined,\n };\n }\n\n if (chunk.type === \"message_delta\" && usage) {\n usage.outputTokens = chunk.usage.output_tokens;\n }\n\n if (chunk.type === \"content_block_delta\" && chunk.delta.type === \"text_delta\") {\n yield { delta: { text: { text: chunk.delta.text } } };\n }\n\n if (chunk.type === \"content_block_start\" && chunk.content_block.type === \"tool_use\") {\n blocks[chunk.index] = {\n type: \"function\",\n id: chunk.content_block.id,\n function: { name: chunk.content_block.name, arguments: {} },\n args: \"\",\n };\n }\n\n if (chunk.type === \"content_block_delta\" && chunk.delta.type === \"input_json_delta\") {\n const call = blocks[chunk.index];\n if (!call) throw new Error(\"Tool call not found\");\n call.args += chunk.delta.partial_json;\n }\n }\n\n const toolCalls = blocks.filter(isNonNullable);\n\n // Separate output tool from business tool calls\n const outputToolCall = toolCalls.find((c) => c.function.name === OUTPUT_FUNCTION_NAME);\n const businessToolCalls = toolCalls\n .filter((c) => c.function.name !== OUTPUT_FUNCTION_NAME)\n .map(({ args, ...c }) => ({\n ...c,\n function: {\n ...c.function,\n arguments: args.trim() ? parseJSON(args) : {},\n },\n }))\n .filter(isNonNullable);\n\n if (outputToolCall) {\n json = outputToolCall.args.trim() ? parseJSON(outputToolCall.args) : {};\n }\n\n if (businessToolCalls.length) {\n yield { delta: { json: { toolCalls: businessToolCalls } } };\n }\n\n if (json !== undefined) {\n yield { delta: { json: { json: json as object } } };\n }\n\n yield { delta: { json: { usage } } };\n }\n}\n\n/**\n * Parse cache configuration from model options\n */\nfunction parseCacheConfig(modelOptions?: ChatModelInput[\"modelOptions\"]) {\n const cacheConfig = modelOptions?.cacheConfig || {};\n const shouldCache = cacheConfig.enabled !== false; // Default: enabled\n const ttl = cacheConfig.ttl === \"1h\" ? \"1h\" : \"5m\"; // Default: 5m\n const strategy = cacheConfig.strategy || \"auto\"; // Default: auto\n const autoBreakpoints = {\n tools: cacheConfig.autoBreakpoints?.tools !== false, // Default: true\n system: cacheConfig.autoBreakpoints?.system !== false, // Default: true\n lastMessage: cacheConfig.autoBreakpoints?.lastMessage === true, // Default: false\n };\n\n return {\n shouldCache,\n ttl,\n strategy,\n autoBreakpoints,\n };\n}\n\nasync function convertMessages({ messages, modelOptions }: ChatModelInput): Promise<{\n messages: MessageParam[];\n system?: Anthropic.Messages.TextBlockParam[];\n}> {\n const systemBlocks: Anthropic.Messages.TextBlockParam[] = [];\n const msgs: MessageParam[] = [];\n\n // Extract cache configuration with defaults\n const { shouldCache, strategy, autoBreakpoints, ...cacheConfig } = parseCacheConfig(modelOptions);\n const ttl = cacheConfig.ttl === \"1h\" ? \"1h\" : undefined;\n\n for (const msg of messages) {\n if (msg.role === \"system\") {\n if (typeof msg.content === \"string\") {\n const block: Anthropic.Messages.TextBlockParam = {\n type: \"text\",\n text: msg.content,\n };\n\n systemBlocks.push(block);\n } else if (Array.isArray(msg.content)) {\n systemBlocks.push(\n ...msg.content.map((item) => {\n if (item.type !== \"text\")\n throw new Error(\"System message only supports text content blocks\");\n return { type: \"text\" as const, text: item.text };\n }),\n );\n } else {\n throw new Error(\"System message must have string or array content\");\n }\n } else if (msg.role === \"tool\") {\n if (!msg.toolCallId) throw new Error(\"Tool message must have toolCallId\");\n if (!msg.content) throw new Error(\"Tool message must have content\");\n\n msgs.push({\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: msg.toolCallId,\n content: await convertContent(msg.content),\n },\n ],\n });\n } else if (msg.role === \"user\") {\n if (!msg.content) throw new Error(\"User message must have content\");\n\n msgs.push({ role: \"user\", content: await convertContent(msg.content) });\n } else if (msg.role === \"agent\") {\n if (msg.toolCalls?.length) {\n msgs.push({\n role: \"assistant\",\n content: msg.toolCalls.map((i) => ({\n type: \"tool_use\",\n id: i.id,\n name: i.function.name,\n input: i.function.arguments,\n })),\n });\n } else if (msg.content) {\n msgs.push({ role: \"assistant\", content: await convertContent(msg.content) });\n } else {\n throw new Error(\"Agent message must have content or toolCalls\");\n }\n }\n }\n\n // Apply cache_control to the last system block if auto strategy is enabled\n if (shouldCache && strategy === \"auto\") {\n if (autoBreakpoints.system && systemBlocks.length > 0) {\n const lastBlock = systemBlocks[systemBlocks.length - 1];\n if (lastBlock) {\n lastBlock.cache_control = { type: \"ephemeral\", ttl };\n }\n }\n\n if (autoBreakpoints.lastMessage) {\n const lastMsg = msgs[msgs.length - 1];\n if (lastMsg) {\n if (typeof lastMsg.content === \"string\") {\n lastMsg.content = [\n { type: \"text\", text: lastMsg.content, cache_control: { type: \"ephemeral\", ttl } },\n ];\n } else if (Array.isArray(lastMsg.content)) {\n const lastBlock = lastMsg.content[lastMsg.content.length - 1];\n if (\n lastBlock &&\n lastBlock.type !== \"thinking\" &&\n lastBlock.type !== \"redacted_thinking\"\n ) {\n lastBlock.cache_control = { type: \"ephemeral\", ttl };\n }\n }\n }\n }\n }\n\n // Manual cache control: apply user-specified cacheControl from system messages\n if (shouldCache && strategy === \"manual\") {\n for (const [index, msg] of messages.entries()) {\n const msgWithCache = msg;\n if (msg.role === \"system\" && msgWithCache.cacheControl) {\n const block = systemBlocks[index];\n if (block) {\n block.cache_control = {\n type: msgWithCache.cacheControl.type,\n ...(msgWithCache.cacheControl.ttl && { ttl: msgWithCache.cacheControl.ttl }),\n };\n }\n }\n }\n }\n\n // Claude requires at least one message, so we add a system message if there are no messages\n if (msgs.length === 0) {\n if (systemBlocks.length === 0) throw new Error(\"No messages provided\");\n // Convert system blocks to a single user message\n const systemText = systemBlocks.map((b) => b.text).join(\"\\n\");\n return { messages: [{ role: \"user\", content: systemText }] };\n }\n\n return {\n messages: msgs,\n system: systemBlocks.length > 0 ? systemBlocks : undefined,\n };\n}\n\nasync function convertContent(\n content: ChatModelInputMessageContent,\n): Promise<string | (TextBlockParam | ImageBlockParam)[]> {\n if (typeof content === \"string\") return content;\n\n if (Array.isArray(content)) {\n return Promise.all(\n content.map<Promise<TextBlockParam | ImageBlockParam>>(async (item) => {\n if (item.type === \"text\") return { type: \"text\", text: item.text };\n\n const media_type = (await ChatModel.getMimeType(\n item.mimeType || item.filename || \"\",\n )) as Base64ImageSource[\"media_type\"];\n\n switch (item.type) {\n case \"url\":\n return { type: \"image\", source: { type: \"url\", url: item.url } };\n case \"file\":\n return {\n type: \"image\",\n source: { type: \"base64\", data: item.data, media_type },\n };\n case \"local\":\n throw new Error(\n `Unsupported local file: ${item.path}, it should be converted to base64 at ChatModel`,\n );\n }\n }),\n );\n }\n\n throw new Error(\"Invalid chat message content\");\n}\n\nfunction convertTools({\n tools,\n toolChoice,\n disableParallelToolUse,\n modelOptions,\n responseFormat,\n}: ChatModelInput & {\n disableParallelToolUse?: boolean;\n}): { tools?: ToolUnion[]; tool_choice?: ToolChoice } | undefined {\n // Extract cache configuration with defaults\n const { shouldCache, ttl, strategy, autoBreakpoints } = parseCacheConfig(modelOptions);\n const shouldCacheTools = shouldCache && strategy === \"auto\" && autoBreakpoints.tools;\n\n // Convert business tools\n const convertedTools: Tool[] = (tools ?? []).map((i) => {\n const tool: Tool = {\n name: i.function.name,\n description: i.function.description,\n input_schema: isEmpty(i.function.parameters)\n ? { type: \"object\" }\n : (i.function.parameters as Anthropic.Messages.Tool.InputSchema),\n };\n\n // Manual cache mode: apply tool-specific cacheControl\n if (shouldCache && strategy === \"manual\" && i.cacheControl) {\n tool.cache_control = {\n type: i.cacheControl.type,\n ...(i.cacheControl.ttl && { ttl: i.cacheControl.ttl }),\n };\n }\n\n return tool;\n });\n\n // Add output tool for structured output\n if (responseFormat?.type === \"json_schema\") {\n convertedTools.push({\n name: OUTPUT_FUNCTION_NAME,\n description: \"Generate a json result by given context\",\n input_schema: responseFormat.jsonSchema.schema as Anthropic.Messages.Tool.InputSchema,\n });\n }\n\n // Auto cache mode: add cache_control to the last tool\n if (shouldCacheTools && convertedTools.length) {\n const lastTool = convertedTools[convertedTools.length - 1];\n if (lastTool) {\n lastTool.cache_control = { type: \"ephemeral\", ...(ttl === \"1h\" && { ttl: \"1h\" }) };\n }\n }\n\n // Determine tool choice\n const choice: ToolChoice | undefined =\n responseFormat?.type === \"json_schema\"\n ? // For structured output: force output tool if no business tools, otherwise let model choose\n tools?.length\n ? { type: \"any\", disable_parallel_tool_use: disableParallelToolUse }\n : { type: \"tool\", name: OUTPUT_FUNCTION_NAME, disable_parallel_tool_use: true }\n : typeof toolChoice === \"object\" && \"type\" in toolChoice && toolChoice.type === \"function\"\n ? {\n type: \"tool\",\n name: toolChoice.function.name,\n disable_parallel_tool_use: disableParallelToolUse,\n }\n : toolChoice === \"required\"\n ? { type: \"any\", disable_parallel_tool_use: disableParallelToolUse }\n : toolChoice === \"auto\"\n ? { type: \"auto\", disable_parallel_tool_use: disableParallelToolUse }\n : toolChoice === \"none\"\n ? { type: \"none\" }\n : undefined;\n\n return {\n tools: convertedTools.length ? convertedTools : undefined,\n tool_choice: choice,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"anthropic-chat-model.mjs","names":[],"sources":["../src/anthropic-chat-model.ts"],"sourcesContent":["import {\n ChatModel,\n type ChatModelInput,\n type ChatModelInputMessageContent,\n type ChatModelOptions,\n type ChatModelOutput,\n type ChatModelOutputToolCall,\n type ChatModelOutputUsage,\n type ModelInvokeOptions,\n type ModelProcessAsyncGenerator,\n type ModelProcessResult,\n} from \"@aigne/model-base\";\nimport { parseJSON } from \"@aigne/model-base/utils/json-schema\";\nimport {\n checkArguments,\n isEmpty,\n isNonNullable,\n omit,\n type PromiseOrValue,\n} from \"@aigne/model-base/utils/type-utils\";\nimport Anthropic, { type ClientOptions } from \"@anthropic-ai/sdk\";\nimport type {\n Base64ImageSource,\n ImageBlockParam,\n TextBlockParam,\n} from \"@anthropic-ai/sdk/resources\";\nimport type {\n MessageParam,\n Tool,\n ToolChoice,\n ToolUnion,\n} from \"@anthropic-ai/sdk/resources/index.js\";\nimport { z } from \"zod\";\n\nconst CHAT_MODEL_CLAUDE_DEFAULT_MODEL = \"claude-3-7-sonnet-latest\";\nconst OUTPUT_FUNCTION_NAME = \"generate_json\";\n\n/**\n * Configuration options for Claude Chat Model\n */\nexport interface AnthropicChatModelOptions extends ChatModelOptions {\n /**\n * API key for Anthropic's Claude API\n *\n * If not provided, will look for ANTHROPIC_API_KEY or CLAUDE_API_KEY in environment variables\n */\n apiKey?: string;\n\n /**\n * Optional client options for the Anthropic SDK\n */\n clientOptions?: Partial<ClientOptions>;\n}\n\n/**\n * @hidden\n */\nexport const claudeChatModelOptionsSchema = z.object({\n apiKey: z.string().optional(),\n model: z.string().optional(),\n modelOptions: z\n .object({\n model: z.string().optional(),\n temperature: z.number().optional(),\n topP: z.number().optional(),\n frequencyPenalty: z.number().optional(),\n presencePenalty: z.number().optional(),\n parallelToolCalls: z.boolean().optional().default(true),\n })\n .optional(),\n});\n\n/**\n * Implementation of the ChatModel interface for Anthropic's Claude API\n *\n * This model provides access to Claude's capabilities including:\n * - Text generation\n * - Tool use\n * - JSON structured output\n *\n * Default model: 'claude-3-7-sonnet-latest'\n *\n * @example\n * Here's how to create and use a Claude chat model:\n * {@includeCode ../test/anthropic-chat-model.test.ts#example-anthropic-chat-model}\n *\n * @example\n * Here's an example with streaming response:\n * {@includeCode ../test/anthropic-chat-model.test.ts#example-anthropic-chat-model-streaming-async-generator}\n */\nexport class AnthropicChatModel extends ChatModel {\n constructor(public override options?: AnthropicChatModelOptions) {\n if (options) checkArguments(\"AnthropicChatModel\", claudeChatModelOptionsSchema, options);\n super();\n }\n\n protected apiKeyEnvName = \"ANTHROPIC_API_KEY\";\n\n /**\n * @hidden\n */\n protected _client?: Anthropic;\n\n get client() {\n const { apiKey } = this.credential;\n if (!apiKey)\n throw new Error(\n \"AnthropicChatModel requires an API key. Please provide it via `options.apiKey`, or set the `ANTHROPIC_API_KEY` or `CLAUDE_API_KEY` environment variable\",\n );\n\n this._client ??= new Anthropic({\n apiKey,\n ...this.options?.clientOptions,\n timeout: this.options?.clientOptions?.timeout ?? 600e3,\n });\n return this._client;\n }\n\n get modelOptions() {\n return this.options?.modelOptions;\n }\n\n override get credential() {\n const apiKey =\n this.options?.apiKey || process.env[this.apiKeyEnvName] || process.env.CLAUDE_API_KEY;\n\n return {\n apiKey,\n model: this.options?.model || CHAT_MODEL_CLAUDE_DEFAULT_MODEL,\n };\n }\n\n override async countTokens(input: ChatModelInput): Promise<number> {\n const request = await this.getMessageCreateParams(input);\n return (await this.client.messages.countTokens(omit(request, \"max_tokens\"))).input_tokens;\n }\n\n private async getMessageCreateParams(\n input: ChatModelInput,\n ): Promise<Anthropic.Messages.MessageCreateParams> {\n const { modelOptions = {} } = input;\n const model = modelOptions.model || this.credential.model;\n const disableParallelToolUse = modelOptions.parallelToolCalls === false;\n\n return {\n model,\n temperature: modelOptions.temperature,\n top_p: modelOptions.topP,\n max_tokens: this.getMaxTokens(model),\n ...(await convertMessages(input)),\n ...convertTools({ ...input, disableParallelToolUse }),\n };\n }\n\n private getMaxTokens(model: string): number {\n // Order matters: more specific patterns first.\n // Source: https://platform.claude.com/docs/en/docs/about-claude/models/all-models\n const matchers = [\n [/claude-opus-4-6/, 128000], // Opus 4.6: 128K\n [/claude-opus-4-5/, 64000], // Opus 4.5: 64K\n [/claude-opus-4-/, 32000], // Opus 4.0, 4.1: 32K\n [/claude-sonnet-4-/, 64000], // Sonnet 4.0, 4.5, 4.6: 64K\n [/claude-haiku-4-/, 64000], // Haiku 4.5: 64K\n [/claude-3-7-sonnet-/, 64000], // 3.7 Sonnet: 64K\n [/claude-3-5-sonnet-/, 8192], // 3.5 Sonnet: 8K\n [/claude-3-5-haiku-/, 8192], // 3.5 Haiku: 8K\n ] as const;\n\n for (const [regex, maxTokens] of matchers) {\n if (regex.test(model)) {\n return maxTokens;\n }\n }\n\n return 4096; // Claude 3 Haiku: 4K\n }\n\n /**\n * Process the input using Claude's chat model\n * @param input - The input to process\n * @returns The processed output from the model\n */\n override process(\n input: ChatModelInput,\n _options: ModelInvokeOptions,\n ): PromiseOrValue<ModelProcessResult<ChatModelOutput>> {\n return this.processInput(input);\n }\n\n private async *processInput(input: ChatModelInput): ModelProcessAsyncGenerator<ChatModelOutput> {\n const body = await this.getMessageCreateParams(input);\n const stream = this.client.messages.stream({ ...body, stream: true });\n\n const blocks: ((ChatModelOutputToolCall & { args: string }) | null)[] = [];\n let usage: ChatModelOutputUsage | undefined;\n let json: unknown;\n\n for await (const chunk of stream) {\n if (chunk.type === \"message_start\") {\n yield { delta: { json: { model: chunk.message.model } } };\n\n const {\n input_tokens,\n output_tokens,\n cache_creation_input_tokens,\n cache_read_input_tokens,\n } = chunk.message.usage;\n usage = {\n inputTokens: input_tokens,\n outputTokens: output_tokens,\n cacheCreationInputTokens: cache_creation_input_tokens ?? undefined,\n cacheReadInputTokens: cache_read_input_tokens ?? undefined,\n };\n }\n\n if (chunk.type === \"message_delta\" && usage) {\n usage.outputTokens = chunk.usage.output_tokens;\n }\n\n if (chunk.type === \"content_block_delta\" && chunk.delta.type === \"text_delta\") {\n yield { delta: { text: { text: chunk.delta.text } } };\n }\n\n if (chunk.type === \"content_block_start\" && chunk.content_block.type === \"tool_use\") {\n blocks[chunk.index] = {\n type: \"function\",\n id: chunk.content_block.id,\n function: { name: chunk.content_block.name, arguments: {} },\n args: \"\",\n };\n }\n\n if (chunk.type === \"content_block_delta\" && chunk.delta.type === \"input_json_delta\") {\n const call = blocks[chunk.index];\n if (!call) throw new Error(\"Tool call not found\");\n call.args += chunk.delta.partial_json;\n }\n }\n\n const toolCalls = blocks.filter(isNonNullable);\n\n // Separate output tool from business tool calls\n const outputToolCall = toolCalls.find((c) => c.function.name === OUTPUT_FUNCTION_NAME);\n const businessToolCalls = toolCalls\n .filter((c) => c.function.name !== OUTPUT_FUNCTION_NAME)\n .map(({ args, ...c }) => ({\n ...c,\n function: {\n ...c.function,\n arguments: args.trim() ? parseJSON(args) : {},\n },\n }))\n .filter(isNonNullable);\n\n if (outputToolCall) {\n json = outputToolCall.args.trim() ? parseJSON(outputToolCall.args) : {};\n }\n\n if (businessToolCalls.length) {\n yield { delta: { json: { toolCalls: businessToolCalls } } };\n }\n\n if (json !== undefined) {\n yield { delta: { json: { json: json as object } } };\n }\n\n yield { delta: { json: { usage } } };\n }\n}\n\n/**\n * Parse cache configuration from model options\n */\nfunction parseCacheConfig(modelOptions?: ChatModelInput[\"modelOptions\"]) {\n const cacheConfig = modelOptions?.cacheConfig || {};\n const shouldCache = cacheConfig.enabled !== false; // Default: enabled\n const ttl = cacheConfig.ttl === \"1h\" ? \"1h\" : \"5m\"; // Default: 5m\n const strategy = cacheConfig.strategy || \"auto\"; // Default: auto\n const autoBreakpoints = {\n tools: cacheConfig.autoBreakpoints?.tools !== false, // Default: true\n system: cacheConfig.autoBreakpoints?.system !== false, // Default: true\n lastMessage: cacheConfig.autoBreakpoints?.lastMessage === true, // Default: false\n };\n\n return {\n shouldCache,\n ttl,\n strategy,\n autoBreakpoints,\n };\n}\n\nasync function convertMessages({ messages, modelOptions }: ChatModelInput): Promise<{\n messages: MessageParam[];\n system?: Anthropic.Messages.TextBlockParam[];\n}> {\n const systemBlocks: Anthropic.Messages.TextBlockParam[] = [];\n const msgs: MessageParam[] = [];\n\n // Extract cache configuration with defaults\n const { shouldCache, strategy, autoBreakpoints, ...cacheConfig } = parseCacheConfig(modelOptions);\n const ttl = cacheConfig.ttl === \"1h\" ? \"1h\" : undefined;\n\n for (const msg of messages) {\n if (msg.role === \"system\") {\n if (typeof msg.content === \"string\") {\n const block: Anthropic.Messages.TextBlockParam = {\n type: \"text\",\n text: msg.content,\n };\n\n systemBlocks.push(block);\n } else if (Array.isArray(msg.content)) {\n systemBlocks.push(\n ...msg.content.map((item) => {\n if (item.type !== \"text\")\n throw new Error(\"System message only supports text content blocks\");\n return { type: \"text\" as const, text: item.text };\n }),\n );\n } else {\n throw new Error(\"System message must have string or array content\");\n }\n } else if (msg.role === \"tool\") {\n if (!msg.toolCallId) throw new Error(\"Tool message must have toolCallId\");\n if (!msg.content) throw new Error(\"Tool message must have content\");\n\n msgs.push({\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: msg.toolCallId,\n content: await convertContent(msg.content),\n },\n ],\n });\n } else if (msg.role === \"user\") {\n if (!msg.content) throw new Error(\"User message must have content\");\n\n msgs.push({ role: \"user\", content: await convertContent(msg.content) });\n } else if (msg.role === \"agent\") {\n if (msg.toolCalls?.length) {\n msgs.push({\n role: \"assistant\",\n content: msg.toolCalls.map((i) => ({\n type: \"tool_use\",\n id: i.id,\n name: i.function.name,\n input: i.function.arguments,\n })),\n });\n } else if (msg.content) {\n msgs.push({ role: \"assistant\", content: await convertContent(msg.content) });\n } else {\n throw new Error(\"Agent message must have content or toolCalls\");\n }\n }\n }\n\n // Apply cache_control to the last system block if auto strategy is enabled\n if (shouldCache && strategy === \"auto\") {\n if (autoBreakpoints.system && systemBlocks.length > 0) {\n const lastBlock = systemBlocks[systemBlocks.length - 1];\n if (lastBlock) {\n lastBlock.cache_control = { type: \"ephemeral\", ttl };\n }\n }\n\n if (autoBreakpoints.lastMessage) {\n const lastMsg = msgs[msgs.length - 1];\n if (lastMsg) {\n if (typeof lastMsg.content === \"string\") {\n lastMsg.content = [\n { type: \"text\", text: lastMsg.content, cache_control: { type: \"ephemeral\", ttl } },\n ];\n } else if (Array.isArray(lastMsg.content)) {\n const lastBlock = lastMsg.content[lastMsg.content.length - 1];\n if (\n lastBlock &&\n lastBlock.type !== \"thinking\" &&\n lastBlock.type !== \"redacted_thinking\"\n ) {\n lastBlock.cache_control = { type: \"ephemeral\", ttl };\n }\n }\n }\n }\n }\n\n // Manual cache control: apply user-specified cacheControl from system messages\n if (shouldCache && strategy === \"manual\") {\n for (const [index, msg] of messages.entries()) {\n const msgWithCache = msg;\n if (msg.role === \"system\" && msgWithCache.cacheControl) {\n const block = systemBlocks[index];\n if (block) {\n block.cache_control = {\n type: msgWithCache.cacheControl.type,\n ...(msgWithCache.cacheControl.ttl && { ttl: msgWithCache.cacheControl.ttl }),\n };\n }\n }\n }\n }\n\n // Claude requires at least one message, so we add a system message if there are no messages\n if (msgs.length === 0) {\n if (systemBlocks.length === 0) throw new Error(\"No messages provided\");\n // Convert system blocks to a single user message\n const systemText = systemBlocks.map((b) => b.text).join(\"\\n\");\n return { messages: [{ role: \"user\", content: systemText }] };\n }\n\n return {\n messages: msgs,\n system: systemBlocks.length > 0 ? systemBlocks : undefined,\n };\n}\n\nasync function convertContent(\n content: ChatModelInputMessageContent,\n): Promise<string | (TextBlockParam | ImageBlockParam)[]> {\n if (typeof content === \"string\") return content;\n\n if (Array.isArray(content)) {\n return Promise.all(\n content.map<Promise<TextBlockParam | ImageBlockParam>>(async (item) => {\n if (item.type === \"text\") return { type: \"text\", text: item.text };\n\n const media_type = (item.mimeType ||\n (await ChatModel.getMimeType(item.filename || \"\"))) as Base64ImageSource[\"media_type\"];\n\n switch (item.type) {\n case \"url\":\n return { type: \"image\", source: { type: \"url\", url: item.url } };\n case \"file\":\n return {\n type: \"image\",\n source: { type: \"base64\", data: item.data, media_type },\n };\n case \"local\":\n throw new Error(\n `Unsupported local file: ${item.path}, it should be converted to base64 at ChatModel`,\n );\n }\n }),\n );\n }\n\n throw new Error(\"Invalid chat message content\");\n}\n\nfunction convertTools({\n tools,\n toolChoice,\n disableParallelToolUse,\n modelOptions,\n responseFormat,\n}: ChatModelInput & {\n disableParallelToolUse?: boolean;\n}): { tools?: ToolUnion[]; tool_choice?: ToolChoice } | undefined {\n // Extract cache configuration with defaults\n const { shouldCache, ttl, strategy, autoBreakpoints } = parseCacheConfig(modelOptions);\n const shouldCacheTools = shouldCache && strategy === \"auto\" && autoBreakpoints.tools;\n\n // Convert business tools\n const convertedTools: Tool[] = (tools ?? []).map((i) => {\n const tool: Tool = {\n name: i.function.name,\n description: i.function.description,\n input_schema: isEmpty(i.function.parameters)\n ? { type: \"object\" }\n : (i.function.parameters as Anthropic.Messages.Tool.InputSchema),\n };\n\n // Manual cache mode: apply tool-specific cacheControl\n if (shouldCache && strategy === \"manual\" && i.cacheControl) {\n tool.cache_control = {\n type: i.cacheControl.type,\n ...(i.cacheControl.ttl && { ttl: i.cacheControl.ttl }),\n };\n }\n\n return tool;\n });\n\n // Add output tool for structured output\n if (responseFormat?.type === \"json_schema\") {\n convertedTools.push({\n name: OUTPUT_FUNCTION_NAME,\n description: \"Generate a json result by given context\",\n input_schema: responseFormat.jsonSchema.schema as Anthropic.Messages.Tool.InputSchema,\n });\n }\n\n // Auto cache mode: add cache_control to the last tool\n if (shouldCacheTools && convertedTools.length) {\n const lastTool = convertedTools[convertedTools.length - 1];\n if (lastTool) {\n lastTool.cache_control = { type: \"ephemeral\", ...(ttl === \"1h\" && { ttl: \"1h\" }) };\n }\n }\n\n // Determine tool choice\n const choice: ToolChoice | undefined =\n responseFormat?.type === \"json_schema\"\n ? // For structured output: force output tool if no business tools, otherwise let model choose\n tools?.length\n ? { type: \"any\", disable_parallel_tool_use: disableParallelToolUse }\n : { type: \"tool\", name: OUTPUT_FUNCTION_NAME, disable_parallel_tool_use: true }\n : typeof toolChoice === \"object\" && \"type\" in toolChoice && toolChoice.type === \"function\"\n ? {\n type: \"tool\",\n name: toolChoice.function.name,\n disable_parallel_tool_use: disableParallelToolUse,\n }\n : toolChoice === \"required\"\n ? { type: \"any\", disable_parallel_tool_use: disableParallelToolUse }\n : toolChoice === \"auto\"\n ? { type: \"auto\", disable_parallel_tool_use: disableParallelToolUse }\n : toolChoice === \"none\"\n ? { type: \"none\" }\n : undefined;\n\n return {\n tools: convertedTools.length ? convertedTools : undefined,\n tool_choice: choice,\n };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/anthropic",
3
- "version": "1.74.0-beta.7",
3
+ "version": "1.74.0-beta.8",
4
4
  "description": "AIGNE Anthropic SDK for integrating with Claude AI models",
5
5
  "license": "Elastic-2.0",
6
6
  "publishConfig": {
@@ -35,7 +35,7 @@
35
35
  "dependencies": {
36
36
  "@anthropic-ai/sdk": "^0.63.0",
37
37
  "zod": "^3.25.67",
38
- "@aigne/model-base": "^1.74.0-beta.7"
38
+ "@aigne/model-base": "^1.74.0-beta.8"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/bun": "^1.3.6",