{"version":3,"sources":["../../src/runner/base.ts"],"sourcesContent":["/**\n * Copyright 2025 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Anthropic } from '@anthropic-ai/sdk';\nimport type { DocumentBlockParam } from '@anthropic-ai/sdk/resources/messages';\nimport type {\n  GenerateRequest,\n  GenerateResponseChunkData,\n  GenerateResponseData,\n  MessageData,\n  Part,\n  Role,\n} from 'genkit';\nimport { Message as GenkitMessage } from 'genkit';\nimport type { ToolDefinition } from 'genkit/model';\n\nimport {\n  AnthropicConfigSchema,\n  Media,\n  MediaSchema,\n  MediaType,\n  MediaTypeSchema,\n  type ClaudeRunnerParams,\n  type ThinkingConfig,\n} from '../types.mjs';\n\nimport {\n  RunnerContentBlockParam,\n  RunnerMessage,\n  RunnerMessageParam,\n  RunnerRequestBody,\n  RunnerStream,\n  RunnerStreamEvent,\n  RunnerStreamingRequestBody,\n  RunnerToolResponseContent,\n  RunnerTypes,\n} from './types.mjs';\n\n/**\n * Shared runner logic for Anthropic SDK integrations.\n *\n * Concrete subclasses pass in their SDK-specific type bundle via `RunnerTypes`,\n * letting this base class handle message/tool translation once for both the\n * stable and beta APIs that share the same conceptual surface.\n */\nexport abstract class BaseRunner<ApiTypes extends RunnerTypes> {\n  protected name: string;\n  protected client: Anthropic;\n\n  /**\n   * Default maximum output tokens for Claude models when not specified in the request.\n   */\n  protected readonly DEFAULT_MAX_OUTPUT_TOKENS = 4096;\n\n  constructor(params: ClaudeRunnerParams) {\n    this.name = params.name;\n    this.client = params.client;\n  }\n\n  /**\n   * Converts a Genkit role to the corresponding Anthropic role.\n   */\n  protected toAnthropicRole(\n    role: Role,\n    toolMessageType?: 'tool_use' | 'tool_result'\n  ): 'user' | 'assistant' {\n    if (role === 'user') {\n      return 'user';\n    }\n    if (role === 'model') {\n      return 'assistant';\n    }\n    if (role === 'tool') {\n      return toolMessageType === 'tool_use' ? 'assistant' : 'user';\n    }\n    throw new Error(`Unsupported genkit role: ${role}`);\n  }\n\n  protected isMediaType(value: string): value is MediaType {\n    return MediaTypeSchema.safeParse(value).success;\n  }\n\n  protected isMediaObject(obj: unknown): obj is Media {\n    return MediaSchema.safeParse(obj).success;\n  }\n\n  /**\n   * Checks if a URL is a data URL (starts with 'data:').\n   */\n  protected isDataUrl(url: string): boolean {\n    return url.startsWith('data:');\n  }\n\n  protected extractDataFromBase64Url(\n    url: string\n  ): { data: string; contentType: string } | null {\n    const match = url.match(/^data:([^;]+);base64,(.+)$/);\n    return (\n      match && {\n        contentType: match[1],\n        data: match[2],\n      }\n    );\n  }\n\n  /**\n   * Both the stable and beta Anthropic SDKs accept the same JSON shape for PDF\n   * document sources (either `type: 'base64'` with a base64 payload or `type: 'url'`\n   * with a public URL). Even though the return type references the stable SDK\n   * union, TypeScript’s structural typing lets the beta runner reuse this helper.\n   */\n  protected toPdfDocumentSource(media: Media): DocumentBlockParam['source'] {\n    if (media.contentType !== 'application/pdf') {\n      throw new Error(\n        `PDF contentType mismatch: expected application/pdf, got ${media.contentType}`\n      );\n    }\n    const url = media.url;\n    if (this.isDataUrl(url)) {\n      const extracted = this.extractDataFromBase64Url(url);\n      if (!extracted) {\n        throw new Error(\n          `Invalid PDF data URL format: ${url.substring(0, 50)}...`\n        );\n      }\n      const { data, contentType } = extracted;\n      if (contentType !== 'application/pdf') {\n        throw new Error(\n          `PDF contentType mismatch: expected application/pdf, got ${contentType}`\n        );\n      }\n      return {\n        type: 'base64',\n        media_type: 'application/pdf',\n        data,\n      };\n    }\n    return {\n      type: 'url',\n      url,\n    };\n  }\n\n  /**\n   * Normalizes Genkit `Media` into either a base64 payload or a remote URL\n   * accepted by the Anthropic SDK. Anthropic supports both `data:` URLs (which\n   * we forward as base64) and remote `https` URLs without additional handling.\n   */\n  protected toImageSource(\n    media: Media\n  ):\n    | { kind: 'base64'; data: string; mediaType: MediaType }\n    | { kind: 'url'; url: string } {\n    if (this.isDataUrl(media.url)) {\n      const extracted = this.extractDataFromBase64Url(media.url);\n      const { data, contentType } = extracted ?? {};\n      if (!data || !contentType) {\n        throw new Error(\n          `Invalid genkit part media provided to toAnthropicMessageContent: ${JSON.stringify(\n            media\n          )}.`\n        );\n      }\n\n      const resolvedMediaType = contentType;\n      if (!resolvedMediaType) {\n        throw new Error('Media type is required but was not provided');\n      }\n      if (!this.isMediaType(resolvedMediaType)) {\n        // Provide helpful error message for text files\n        if (resolvedMediaType === 'text/plain') {\n          throw new Error(\n            `Unsupported media type: ${resolvedMediaType}. Text files should be sent as text content in the message, not as media. For example, use { text: '...' } instead of { media: { url: '...', contentType: 'text/plain' } }`\n          );\n        }\n        throw new Error(`Unsupported media type: ${resolvedMediaType}`);\n      }\n      return {\n        kind: 'base64',\n        data,\n        mediaType: resolvedMediaType,\n      };\n    }\n\n    if (!media.url) {\n      throw new Error('Media url is required but was not provided');\n    }\n\n    // For non-data URLs, use the provided contentType or default to a generic type\n    // Note: Anthropic will validate the actual content when fetching from URL\n    if (media.contentType) {\n      if (!this.isMediaType(media.contentType)) {\n        // Provide helpful error message for text files\n        if (media.contentType === 'text/plain') {\n          throw new Error(\n            `Unsupported media type: ${media.contentType}. Text files should be sent as text content in the message, not as media. For example, use { text: '...' } instead of { media: { url: '...', contentType: 'text/plain' } }`\n          );\n        }\n        throw new Error(`Unsupported media type: ${media.contentType}`);\n      }\n    }\n\n    return {\n      kind: 'url',\n      url: media.url,\n    };\n  }\n\n  /**\n   * Converts tool response output to the appropriate Anthropic content format.\n   * Handles Media objects, data URLs, strings, and other outputs.\n   */\n  protected toAnthropicToolResponseContent(\n    part: Part\n  ): RunnerToolResponseContent<ApiTypes> {\n    const output = part.toolResponse?.output ?? {};\n\n    // Handle Media objects (images returned by tools)\n    if (this.isMediaObject(output)) {\n      const { data, contentType } =\n        this.extractDataFromBase64Url(output.url) ?? {};\n      if (data && contentType) {\n        if (!this.isMediaType(contentType)) {\n          // Provide helpful error message for text files\n          if (contentType === 'text/plain') {\n            throw new Error(\n              `Unsupported media type: ${contentType}. Text files should be sent as text content, not as media.`\n            );\n          }\n          throw new Error(`Unsupported media type: ${contentType}`);\n        }\n        return {\n          type: 'image',\n          source: {\n            type: 'base64',\n            data,\n            media_type: contentType,\n          },\n        };\n      }\n    }\n\n    // Handle string outputs - check if it's a data URL\n    if (typeof output === 'string') {\n      // Check if string is a data URL (e.g., \"data:image/gif;base64,...\")\n      if (this.isDataUrl(output)) {\n        const { data, contentType } =\n          this.extractDataFromBase64Url(output) ?? {};\n        if (data && contentType) {\n          if (!this.isMediaType(contentType)) {\n            // Provide helpful error message for text files\n            if (contentType === 'text/plain') {\n              throw new Error(\n                `Unsupported media type: ${contentType}. Text files should be sent as text content, not as media.`\n              );\n            }\n            throw new Error(`Unsupported media type: ${contentType}`);\n          }\n          return {\n            type: 'image',\n            source: {\n              type: 'base64',\n              data,\n              media_type: contentType,\n            },\n          };\n        }\n      }\n      // Regular string output\n      return {\n        type: 'text',\n        text: output,\n      };\n    }\n\n    // Handle other outputs by stringifying\n    return {\n      type: 'text',\n      text: JSON.stringify(output),\n    };\n  }\n\n  protected getThinkingSignature(part: Part): string | undefined {\n    const metadata = part.metadata as Record<string, unknown> | undefined;\n    return typeof metadata?.thoughtSignature === 'string'\n      ? metadata.thoughtSignature\n      : undefined;\n  }\n\n  protected getRedactedThinkingData(part: Part): string | undefined {\n    const custom = part.custom as Record<string, unknown> | undefined;\n    const redacted = custom?.redactedThinking;\n    return typeof redacted === 'string' ? redacted : undefined;\n  }\n\n  protected toAnthropicThinkingConfig(\n    config: ThinkingConfig | undefined\n  ):\n    | { type: 'enabled'; budget_tokens: number }\n    | { type: 'disabled' }\n    | { type: 'adaptive'; display?: 'summarized' | 'omitted' }\n    | undefined {\n    if (!config) return undefined;\n\n    const { enabled, budgetTokens, adaptive, display } = config;\n\n    if (adaptive === true) {\n      return {\n        type: 'adaptive',\n        ...(display !== undefined && { display }),\n      };\n    }\n\n    if (enabled === true) {\n      if (budgetTokens === undefined) {\n        throw new Error('budgetTokens is required when thinking is enabled');\n      }\n      return { type: 'enabled', budget_tokens: budgetTokens };\n    }\n\n    if (enabled === false) {\n      return { type: 'disabled' };\n    }\n\n    if (budgetTokens !== undefined) {\n      return { type: 'enabled', budget_tokens: budgetTokens };\n    }\n\n    return undefined;\n  }\n\n  /**\n   * Converts a Genkit Part to the corresponding Anthropic content block.\n   * Each runner implements this to return its specific API type.\n   */\n  protected abstract toAnthropicMessageContent(\n    part: Part\n  ): RunnerContentBlockParam<ApiTypes>;\n\n  /**\n   * Converts Genkit messages to Anthropic format.\n   * Extracts system message and converts remaining messages using the runner's\n   * toAnthropicMessageContent implementation.\n   */\n  protected toAnthropicMessages(messages: MessageData[]): {\n    system?: RunnerContentBlockParam<ApiTypes>[];\n    messages: RunnerMessageParam<ApiTypes>[];\n  } {\n    let system: RunnerContentBlockParam<ApiTypes>[] | undefined;\n\n    if (messages[0]?.role === 'system') {\n      const systemMessage = messages[0];\n      messages = messages.slice(1);\n\n      for (const part of systemMessage.content ?? []) {\n        if (part.media || part.toolRequest || part.toolResponse) {\n          throw new Error(\n            'System messages can only contain text content. Media, tool requests, and tool responses are not supported in system messages.'\n          );\n        }\n      }\n\n      system = systemMessage.content.map((part) =>\n        this.toAnthropicMessageContent(part)\n      );\n    }\n\n    const anthropicMsgs: RunnerMessageParam<ApiTypes>[] = [];\n\n    for (const message of messages) {\n      const msg = new GenkitMessage(message);\n\n      // Detect tool message kind from Genkit Parts (no SDK typing needed)\n      const hadToolUse = msg.content.some((p) => !!p.toolRequest);\n      const hadToolResult = msg.content.some((p) => !!p.toolResponse);\n\n      const toolMessageType = hadToolUse\n        ? ('tool_use' as const)\n        : hadToolResult\n          ? ('tool_result' as const)\n          : undefined;\n\n      const role = this.toAnthropicRole(message.role, toolMessageType);\n\n      const content = msg.content.map((part) =>\n        this.toAnthropicMessageContent(part)\n      );\n\n      anthropicMsgs.push({ role, content });\n    }\n\n    return { system, messages: anthropicMsgs };\n  }\n\n  /**\n   * Converts a Genkit ToolDefinition to an Anthropic Tool object.\n   *\n   * Anthropic requires `input_schema.type` to be present (usually `\"object\"`).\n   * Genkit's `ToolDefinition` may have an empty schema (e.g. from `z.void()`)\n   * which lacks the `type` field. We default to `{ type: \"object\" }` to\n   * prevent 400 errors from the Anthropic API.\n   */\n  protected toAnthropicTool(tool: ToolDefinition): ApiTypes['Tool'] {\n    const schema = tool.inputSchema || {};\n    const inputSchema =\n      'type' in schema ? schema : { ...schema, type: 'object' as const };\n    return {\n      name: tool.name,\n      description: tool.description,\n      input_schema: inputSchema,\n    } as ApiTypes['Tool'];\n  }\n\n  /**\n   * Converts an Anthropic request to a non-streaming Anthropic API request body.\n   * @param modelName The name of the Anthropic model to use.\n   * @param request The Genkit GenerateRequest to convert.\n   * @returns The converted Anthropic API non-streaming request body.\n   * @throws An error if an unsupported output format is requested.\n   */\n  protected abstract toAnthropicRequestBody(\n    modelName: string,\n    request: GenerateRequest<typeof AnthropicConfigSchema>\n  ): RunnerRequestBody<ApiTypes>;\n\n  /**\n   * Converts an Anthropic request to a streaming Anthropic API request body.\n   * @param modelName The name of the Anthropic model to use.\n   * @param request The Genkit GenerateRequest to convert.\n   * @returns The converted Anthropic API streaming request body.\n   * @throws An error if an unsupported output format is requested.\n   */\n  protected abstract toAnthropicStreamingRequestBody(\n    modelName: string,\n    request: GenerateRequest<typeof AnthropicConfigSchema>\n  ): RunnerStreamingRequestBody<ApiTypes>;\n\n  protected abstract createMessage(\n    body: RunnerRequestBody<ApiTypes>,\n    abortSignal: AbortSignal\n  ): Promise<RunnerMessage<ApiTypes>>;\n\n  protected abstract streamMessages(\n    body: RunnerStreamingRequestBody<ApiTypes>,\n    abortSignal: AbortSignal\n  ): RunnerStream<ApiTypes>;\n\n  protected abstract toGenkitResponse(\n    message: RunnerMessage<ApiTypes>\n  ): GenerateResponseData;\n\n  protected abstract toGenkitPart(\n    event: RunnerStreamEvent<ApiTypes>\n  ): Part | undefined;\n\n  public async run(\n    request: GenerateRequest<typeof AnthropicConfigSchema>,\n    options: {\n      streamingRequested: boolean;\n      sendChunk: (chunk: GenerateResponseChunkData) => void;\n      abortSignal: AbortSignal;\n    }\n  ): Promise<GenerateResponseData> {\n    const { streamingRequested, sendChunk, abortSignal } = options;\n\n    if (streamingRequested) {\n      const body = this.toAnthropicStreamingRequestBody(this.name, request);\n      const stream = this.streamMessages(body, abortSignal);\n      for await (const event of stream) {\n        const part = this.toGenkitPart(event);\n        if (part) {\n          sendChunk({\n            index: 0,\n            content: [part],\n          });\n        }\n      }\n      const finalMessage = await stream.finalMessage();\n      return this.toGenkitResponse(finalMessage);\n    }\n\n    const body = this.toAnthropicRequestBody(this.name, request);\n    const response = await this.createMessage(body, abortSignal);\n    return this.toGenkitResponse(response);\n  }\n}\n"],"mappings":"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","names":["body"]}