{"version":3,"sources":["../../src/providers/anthropic.ts","../../src/providers/utils.ts"],"sourcesContent":["import type { ReforgeProvider, Message, ProviderCallOptions } from \"./types.js\";\r\nimport { filterReforgeKeys, getMessageText } from \"./utils.js\";\r\n\r\nexport interface AnthropicCallOptions extends ProviderCallOptions {\r\n  max_tokens?: number;\r\n  temperature?: number;\r\n  top_p?: number;\r\n  top_k?: number;\r\n  thinking?: unknown;\r\n  tool_choice?: unknown;\r\n  tools?: unknown;\r\n}\r\n\r\n/**\r\n * Minimal subset of the Anthropic client used by the adapter.\r\n */\r\ninterface AnthropicClient {\r\n  messages: {\r\n    create(params: Record<string, unknown>): Promise<{\r\n      content: Array<{ type: string; text?: string }>;\r\n    }>;\r\n  };\r\n}\r\n\r\ntype AnthropicContentBlock =\r\n  | { type: \"text\"; text: string; cache_control?: unknown }\r\n  | { type: \"tool_use\"; id: string; name: string; input: unknown }\r\n  | { type: \"tool_result\"; tool_use_id: string; content: string; is_error?: boolean };\r\n\r\nfunction toAnthropicContentBlocks(message: Message): AnthropicContentBlock[] {\r\n  const blocks: AnthropicContentBlock[] = [];\r\n\r\n  if (typeof message.content === \"string\") {\r\n    blocks.push({ type: \"text\", text: message.content });\r\n  } else {\r\n    for (const block of message.content) {\r\n      if (block.type === \"text\") {\r\n        blocks.push({\r\n          type: \"text\",\r\n          text: block.text,\r\n          ...(Object.prototype.hasOwnProperty.call(block, \"cache_control\")\r\n            ? { cache_control: (block as unknown as { cache_control?: unknown }).cache_control }\r\n            : {}),\r\n        });\r\n      } else {\r\n        blocks.push({\r\n          type: \"text\",\r\n          text: `[image_url:${block.image_url.url}]`,\r\n        });\r\n      }\r\n    }\r\n  }\r\n\r\n  if (message.toolCalls && message.toolCalls.length > 0) {\r\n    for (const toolCall of message.toolCalls) {\r\n      let parsedInput: unknown = toolCall.arguments;\r\n      try {\r\n        parsedInput = JSON.parse(toolCall.arguments);\r\n      } catch {\r\n        // Keep raw string when parsing fails.\r\n      }\r\n\r\n      blocks.push({\r\n        type: \"tool_use\",\r\n        id: toolCall.id,\r\n        name: toolCall.name,\r\n        input: parsedInput,\r\n      });\r\n    }\r\n  }\r\n\r\n  if (message.toolResponse) {\r\n    blocks.push({\r\n      type: \"tool_result\",\r\n      tool_use_id: message.toolResponse.toolCallId,\r\n      content: getMessageText({\r\n        role: \"tool\",\r\n        content: message.toolResponse.content,\r\n      }),\r\n      ...(message.toolResponse.isError ? { is_error: true } : {}),\r\n    });\r\n  }\r\n\r\n  return blocks;\r\n}\r\n\r\n/**\r\n * Create a `ReforgeProvider` for the Anthropic Messages API.\r\n *\r\n * Only needed for **direct** Anthropic API access. If you're using\r\n * Claude through OpenRouter or another proxy, use `openaiCompatible()` instead.\r\n *\r\n * @param client - An `Anthropic` client instance (from `@anthropic-ai/sdk`).\r\n * @param model  - The model identifier (e.g. `\"claude-sonnet-4-20250514\"`).\r\n * @returns A `ReforgeProvider` ready to use with `forge()`.\r\n *\r\n * @example\r\n * ```ts\r\n * import Anthropic from '@anthropic-ai/sdk';\r\n * import { anthropic } from 'reforge-ai/anthropic';\r\n *\r\n * const provider = anthropic(new Anthropic(), 'claude-sonnet-4-20250514');\r\n * ```\r\n */\r\nexport function anthropic(\r\n  client: AnthropicClient,\r\n  model: string,\r\n): ReforgeProvider<AnthropicCallOptions> {\r\n  return {\r\n    id: `anthropic:${model}`,\r\n    async call(\r\n      messages: Message[],\r\n      options?: AnthropicCallOptions,\r\n    ): Promise<string> {\r\n      const extra = filterReforgeKeys(options);\r\n\r\n      // Anthropic requires system messages to be passed separately\r\n      const systemMessages = messages\r\n        .filter((m) => m.role === \"system\")\r\n        .map((m) => toAnthropicContentBlocks(m))\r\n        .flat();\r\n      const nonSystemMsgs = messages.filter((m) => m.role !== \"system\");\r\n\r\n      const maxTokensOption = options?.max_tokens;\r\n      const maxTokens = typeof maxTokensOption === \"number\" ? maxTokensOption : 4096;\r\n\r\n      const params: Record<string, unknown> = {\r\n        model,\r\n        max_tokens: maxTokens,\r\n        messages: nonSystemMsgs.map((m) => ({\r\n          role: m.role === \"assistant\" ? \"assistant\" : \"user\",\r\n          content: toAnthropicContentBlocks(m),\r\n        })),\r\n        ...extra,\r\n      };\r\n\r\n      if (systemMessages.length > 0) {\r\n        params.system = systemMessages;\r\n      }\r\n\r\n      const response = await client.messages.create(params);\r\n\r\n      const textBlock = response.content.find((b) => b.type === \"text\");\r\n      if (!textBlock || textBlock.type !== \"text\" || !textBlock.text) {\r\n        throw new Error(\"Anthropic returned no text content\");\r\n      }\r\n      return textBlock.text;\r\n    },\r\n  };\r\n}\r\n","import type {\r\n  ProviderCallOptions,\r\n  Message,\r\n  MessageContent,\r\n  MessageContentBlock,\r\n  MessageImageUrlBlock,\r\n} from \"./types.js\";\r\n\r\n/**\r\n * Keys managed by Reforge that should not be spread into the\r\n * provider-specific options object (they are mapped explicitly).\r\n */\r\nconst REFORGE_KEYS = new Set<string>([]);\r\n\r\n/**\r\n * Strip Reforge-managed keys from a `ProviderCallOptions` object so\r\n * they aren't double-sent when spreading into provider SDK calls.\r\n *\r\n * Returns a plain object with only the pass-through keys, or\r\n * `undefined` if there's nothing left.\r\n */\r\nexport function filterReforgeKeys(\r\n  options?: ProviderCallOptions,\r\n): Record<string, unknown> | undefined {\r\n  if (!options) return undefined;\r\n\r\n  const filtered: Record<string, unknown> = {};\r\n  let hasKeys = false;\r\n\r\n  for (const key of Object.keys(options)) {\r\n    if (!REFORGE_KEYS.has(key)) {\r\n      filtered[key] = options[key];\r\n      hasKeys = true;\r\n    }\r\n  }\r\n\r\n  return hasKeys ? filtered : undefined;\r\n}\r\n\r\nfunction isImageBlock(block: MessageContentBlock): block is MessageImageUrlBlock {\r\n  return block.type === \"image_url\";\r\n}\r\n\r\n/**\r\n * Convert message content into plain text for providers that do not support\r\n * image/message blocks in their input shape.\r\n */\r\nexport function messageContentToText(content: MessageContent): string {\r\n  if (typeof content === \"string\") {\r\n    return content;\r\n  }\r\n\r\n  const parts: string[] = [];\r\n  for (const block of content) {\r\n    if (block.type === \"text\") {\r\n      parts.push(block.text);\r\n      continue;\r\n    }\r\n\r\n    if (isImageBlock(block)) {\r\n      parts.push(`[image_url:${block.image_url.url}]`);\r\n    }\r\n  }\r\n\r\n  return parts.join(\"\\n\");\r\n}\r\n\r\n/**\r\n * Extract only text blocks from a message for providers with text-only system\r\n * channels.\r\n */\r\nexport function getMessageText(message: Message): string {\r\n  return messageContentToText(message.content);\r\n}\r\n"],"mappings":"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","names":[]}