@doclo/providers-llm 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +5 -4
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/package.json +10 -6
package/dist/index.d.ts
CHANGED
|
@@ -4,8 +4,8 @@ import { LLMJsonProvider, VLMProvider } from '@doclo/core';
|
|
|
4
4
|
|
|
5
5
|
/** Unified internal schema (standard JSON Schema) */
|
|
6
6
|
type UnifiedSchema<T = any> = JSONSchemaType<T>;
|
|
7
|
-
/** Provider types - 'x-ai' is an alias for 'xai' */
|
|
8
|
-
type ProviderType = 'openai' | 'anthropic' | 'google' | 'xai' | 'x-ai';
|
|
7
|
+
/** Provider types - 'x-ai' is an alias for 'xai', 'generic-or' for generic OpenRouter models */
|
|
8
|
+
type ProviderType = 'openai' | 'anthropic' | 'google' | 'xai' | 'x-ai' | 'generic-or';
|
|
9
9
|
/** Access method */
|
|
10
10
|
type AccessMethod = 'openrouter' | 'native';
|
|
11
11
|
/** Resource limit configuration (optional overrides for defaults) */
|
|
@@ -387,7 +387,8 @@ declare class GoogleProvider implements LLMProvider {
|
|
|
387
387
|
private limits;
|
|
388
388
|
constructor(config: ProviderConfig);
|
|
389
389
|
completeJson<T>(params: {
|
|
390
|
-
input
|
|
390
|
+
input?: MultimodalInput;
|
|
391
|
+
prompt?: MultimodalInput | string;
|
|
391
392
|
schema?: UnifiedSchema<T>;
|
|
392
393
|
mode?: JsonMode;
|
|
393
394
|
max_tokens?: number;
|
|
@@ -1357,7 +1358,7 @@ type NodeType = 'parse' | 'extract' | 'categorize' | 'qualify' | 'split';
|
|
|
1357
1358
|
* @returns CoreVLMProvider instance (no retry/fallback wrapper)
|
|
1358
1359
|
*/
|
|
1359
1360
|
declare function createVLMProvider(config: {
|
|
1360
|
-
provider: 'openai' | 'anthropic' | 'google' | 'xai' | 'x-ai';
|
|
1361
|
+
provider: 'openai' | 'anthropic' | 'google' | 'xai' | 'x-ai' | 'generic-or';
|
|
1361
1362
|
model: string;
|
|
1362
1363
|
apiKey: string;
|
|
1363
1364
|
via?: 'openrouter';
|
package/dist/index.js
CHANGED
|
@@ -1239,20 +1239,25 @@ var GoogleProvider = class {
|
|
|
1239
1239
|
}
|
|
1240
1240
|
async completeJson(params) {
|
|
1241
1241
|
const startTime = Date.now();
|
|
1242
|
+
const rawInput = params.input ?? params.prompt;
|
|
1243
|
+
if (!rawInput) {
|
|
1244
|
+
throw new Error("Either input or prompt must be provided");
|
|
1245
|
+
}
|
|
1246
|
+
const normalizedInput = typeof rawInput === "string" ? { text: rawInput } : rawInput;
|
|
1242
1247
|
const mode = params.mode || (params.schema ? "strict" : "relaxed");
|
|
1243
1248
|
if (mode === "strict" && !params.schema) {
|
|
1244
1249
|
throw new Error('schema is required when mode is "strict"');
|
|
1245
1250
|
}
|
|
1246
1251
|
const shouldEmbedSchema = params.embedSchemaInPrompt !== false && params.schema;
|
|
1247
|
-
let enhancedInput =
|
|
1252
|
+
let enhancedInput = normalizedInput;
|
|
1248
1253
|
if (shouldEmbedSchema) {
|
|
1249
1254
|
const jsonSchema = this.translator.convertZodIfNeeded(params.schema);
|
|
1250
1255
|
const enhancedText = combineSchemaAndUserPrompt(
|
|
1251
1256
|
jsonSchema,
|
|
1252
|
-
|
|
1257
|
+
normalizedInput.text || ""
|
|
1253
1258
|
);
|
|
1254
1259
|
enhancedInput = {
|
|
1255
|
-
...
|
|
1260
|
+
...normalizedInput,
|
|
1256
1261
|
text: enhancedText
|
|
1257
1262
|
};
|
|
1258
1263
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schema-translator.ts","../src/schema-prompt-formatter.ts","../src/provider-registry.ts","../src/providers/openai.ts","../src/providers/anthropic.ts","../src/providers/google.ts","../src/providers/xai.ts","../src/fallback-manager.ts","../src/adapter.ts","../src/metadata.ts","../src/index.ts"],"sourcesContent":["import type { UnifiedSchema } from \"./types\";\nimport { zodToJsonSchema } from \"@alcyone-labs/zod-to-json-schema\";\n\n/**\n * Internal JSON Schema representation for schema translation.\n * This is more flexible than JSONSchemaNode to accommodate:\n * - Zod schema markers (~standard, _def)\n * - Provider-specific extensions (propertyOrdering)\n * - Intermediate conversion states\n */\ninterface FlexibleSchemaNode {\n type?: string | string[];\n properties?: Record<string, FlexibleSchemaNode>;\n items?: FlexibleSchemaNode | FlexibleSchemaNode[];\n required?: string[];\n enum?: (string | number | boolean | null)[];\n nullable?: boolean;\n anyOf?: FlexibleSchemaNode[];\n oneOf?: FlexibleSchemaNode[];\n allOf?: FlexibleSchemaNode[];\n additionalProperties?: boolean | FlexibleSchemaNode;\n description?: string;\n format?: string;\n default?: unknown;\n $schema?: string;\n $defs?: Record<string, FlexibleSchemaNode>;\n definitions?: Record<string, FlexibleSchemaNode>;\n // Zod schema markers\n '~standard'?: { vendor: string; [key: string]: unknown };\n _def?: unknown;\n // Gemini-specific\n propertyOrdering?: string[];\n [key: string]: unknown; // Allow additional properties for extensibility\n}\n\n/**\n * Translates unified JSON Schema to provider-specific formats\n */\nexport class SchemaTranslator {\n /**\n * Unified → OpenAI/Grok (standard JSON Schema)\n * OpenAI strict mode doesn't support nullable: true\n * Must convert to anyOf: [{ type: \"string\" }, { type: \"null\" }]\n */\n toOpenAISchema<T>(schema: UnifiedSchema<T>): object {\n // Detect and convert Zod schemas\n const jsonSchema = this.convertZodIfNeeded(schema);\n return this.convertNullableToAnyOf(jsonSchema);\n }\n\n /**\n * Detect if schema is a Zod schema and convert to JSON Schema\n * Public method to allow embedding schemas in prompts\n */\n convertZodIfNeeded(schema: FlexibleSchemaNode | unknown): FlexibleSchemaNode {\n // Check for Zod schema markers\n if (schema && typeof schema === 'object') {\n const flexibleSchema = schema as FlexibleSchemaNode;\n // Zod v4 uses ~standard marker\n if (flexibleSchema['~standard']?.vendor === 'zod') {\n // Schema has Zod marker, safe to pass to zodToJsonSchema\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const jsonSchema = zodToJsonSchema(schema as any) as FlexibleSchemaNode;\n // Remove properties not allowed in OpenAI strict mode or Gemini responseSchema\n delete jsonSchema.$schema;\n delete jsonSchema.$defs;\n delete jsonSchema.definitions;\n return jsonSchema;\n }\n // Zod v3 uses _def property\n if (flexibleSchema._def) {\n // Schema has Zod _def, safe to pass to zodToJsonSchema\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const jsonSchema = zodToJsonSchema(schema as any) as FlexibleSchemaNode;\n // Remove properties not allowed in OpenAI strict mode or Gemini responseSchema\n delete jsonSchema.$schema;\n delete jsonSchema.$defs;\n delete jsonSchema.definitions;\n return jsonSchema;\n }\n }\n // Already JSON Schema, return as-is\n return schema as FlexibleSchemaNode;\n }\n\n /**\n * Convert nullable fields to anyOf format for OpenAI strict mode\n * nullable: true is not supported, must use anyOf with null type\n */\n private convertNullableToAnyOf(schema: FlexibleSchemaNode): FlexibleSchemaNode {\n if (typeof schema !== 'object' || schema === null) {\n return schema;\n }\n\n const result: FlexibleSchemaNode = { ...schema };\n\n // Handle nullable property at current level\n if (result.nullable === true) {\n delete result.nullable;\n\n // Get the base type\n const baseType = result.type;\n\n if (baseType) {\n // Create anyOf with base type and null\n return {\n anyOf: [\n { type: baseType as string },\n { type: 'null' }\n ]\n };\n }\n }\n\n // Recursively handle properties\n if (result.properties) {\n result.properties = Object.fromEntries(\n Object.entries(result.properties).map(([key, value]) => {\n if (value && typeof value === 'object' && value.nullable === true) {\n const { nullable, type, ...rest } = value;\n return [key, {\n anyOf: [\n { type, ...rest },\n { type: 'null' }\n ]\n }];\n }\n return [key, this.convertNullableToAnyOf(value)];\n })\n );\n }\n\n // Handle items (for arrays)\n if (result.items && !Array.isArray(result.items)) {\n result.items = this.convertNullableToAnyOf(result.items);\n }\n\n // Handle anyOf, oneOf, allOf\n const keywords = ['anyOf', 'oneOf', 'allOf'] as const;\n keywords.forEach(keyword => {\n const schemaArray = result[keyword];\n if (schemaArray && Array.isArray(schemaArray)) {\n result[keyword] = schemaArray.map((s) => this.convertNullableToAnyOf(s));\n }\n });\n\n return result;\n }\n\n /**\n * Unified → Claude (Tool Input Schema format)\n * Claude requires tool calling with input_schema\n * Claude supports nullable: true directly\n */\n toClaudeToolSchema<T>(schema: UnifiedSchema<T>): object {\n // Detect and convert Zod schemas first\n const jsonSchema = this.convertZodIfNeeded(schema);\n\n // Claude uses JSON Schema but needs it wrapped in a tool definition\n // Claude DOES support nullable: true, so we keep it as-is\n return {\n name: \"extract_data\",\n description: \"Extract structured data according to the schema\",\n input_schema: jsonSchema as object\n };\n }\n\n /**\n * Unified → Claude for OpenRouter\n * When using Claude via OpenRouter, use anyOf format like OpenAI\n */\n toClaudeOpenRouterSchema<T>(schema: UnifiedSchema<T>): object {\n // Detect and convert Zod schemas first\n const jsonSchema = this.convertZodIfNeeded(schema);\n return this.convertNullableToAnyOf(jsonSchema);\n }\n\n /**\n * Unified → Gemini (OpenAPI 3.0 subset with propertyOrdering)\n * Gemini uses a subset of OpenAPI 3.0 schema\n */\n toGeminiSchema<T>(schema: UnifiedSchema<T>): object {\n // Detect and convert Zod schemas first\n const jsonSchema = this.convertZodIfNeeded(schema);\n\n // Convert JSON Schema to Gemini's format\n const geminiSchema: FlexibleSchemaNode = {\n type: jsonSchema.type\n };\n\n if (jsonSchema.properties) {\n geminiSchema.properties = {};\n // Add propertyOrdering for consistent output order\n const propertyNames = Object.keys(jsonSchema.properties);\n geminiSchema.propertyOrdering = propertyNames;\n\n for (const [key, value] of Object.entries(jsonSchema.properties)) {\n geminiSchema.properties[key] = this.convertPropertyToGemini(value);\n }\n }\n\n if (jsonSchema.required && Array.isArray(jsonSchema.required)) {\n geminiSchema.required = jsonSchema.required;\n }\n\n if (jsonSchema.additionalProperties !== undefined) {\n geminiSchema.additionalProperties = jsonSchema.additionalProperties;\n }\n\n return geminiSchema;\n }\n\n /**\n * Convert individual property to Gemini format\n */\n private convertPropertyToGemini(property: FlexibleSchemaNode): FlexibleSchemaNode {\n const geminiProp: FlexibleSchemaNode = {\n type: property.type\n };\n\n if (property.description) {\n geminiProp.description = property.description;\n }\n\n if (property.nullable !== undefined) {\n geminiProp.nullable = property.nullable;\n }\n\n if (property.enum) {\n geminiProp.enum = property.enum;\n }\n\n if (property.items) {\n // Items can be a single schema or array of schemas (tuple validation)\n if (Array.isArray(property.items)) {\n // For tuple validation, just convert the first schema\n geminiProp.items = property.items.length > 0\n ? this.convertPropertyToGemini(property.items[0])\n : undefined;\n } else {\n geminiProp.items = this.convertPropertyToGemini(property.items);\n }\n }\n\n if (property.properties) {\n geminiProp.properties = {};\n for (const [key, value] of Object.entries(property.properties)) {\n geminiProp.properties[key] = this.convertPropertyToGemini(value);\n }\n }\n\n if (property.required) {\n geminiProp.required = property.required;\n }\n\n return geminiProp;\n }\n}\n","/**\n * Utility for converting JSON Schema to human-readable prompt text\n * that emphasizes exact field name requirements for structured extraction.\n */\n\n/**\n * JSON Schema type used for prompt formatting.\n * Uses a recursive structure to support nested schemas.\n */\nexport interface JSONSchema {\n type?: string | string[]; // Can be array for union types (e.g., [\"string\", \"null\"])\n properties?: Record<string, JSONSchema>;\n items?: JSONSchema | JSONSchema[]; // Can be array for tuple validation\n description?: string;\n required?: string[];\n enum?: (string | number | boolean | null)[];\n anyOf?: JSONSchema[];\n oneOf?: JSONSchema[];\n allOf?: JSONSchema[];\n format?: string;\n [key: string]: unknown; // Allow additional properties\n}\n\n/**\n * Formats a JSON Schema into prompt text that emphasizes exact field names.\n * This helps LLMs understand they must use the exact field names specified\n * in the schema, not invent their own based on document content.\n */\nexport function formatSchemaForPrompt(schema: JSONSchema, indent: number = 0): string {\n if (!schema || typeof schema !== 'object') {\n return '';\n }\n\n const indentStr = ' '.repeat(indent);\n let result = '';\n\n // Handle object type with properties\n if (schema.type === 'object' && schema.properties) {\n const properties = schema.properties;\n const required = schema.required || [];\n\n for (const [fieldName, fieldSchema] of Object.entries(properties)) {\n const isRequired = required.includes(fieldName);\n const requiredMarker = isRequired ? ' (REQUIRED)' : ' (optional)';\n\n // Field name in backticks to emphasize exactness\n result += `${indentStr}- \\`${fieldName}\\`${requiredMarker}`;\n\n // Type information\n const type = getTypeDescription(fieldSchema);\n if (type) {\n result += `: ${type}`;\n }\n\n // Description if available\n if (fieldSchema.description) {\n result += `\\n${indentStr} ${fieldSchema.description}`;\n }\n\n // Enum values if specified\n if (fieldSchema.enum) {\n result += `\\n${indentStr} Allowed values: ${fieldSchema.enum.map((v) => JSON.stringify(v)).join(', ')}`;\n }\n\n result += '\\n';\n\n // Nested object properties\n if (fieldSchema.type === 'object' && fieldSchema.properties) {\n result += formatSchemaForPrompt(fieldSchema, indent + 1);\n }\n\n // Array item schema\n if (fieldSchema.type === 'array' && fieldSchema.items) {\n result += `${indentStr} Array items:\\n`;\n // Handle both single schema and tuple schemas (array of schemas)\n const itemSchema = Array.isArray(fieldSchema.items)\n ? fieldSchema.items[0] // For tuple validation, describe first item type\n : fieldSchema.items;\n if (itemSchema && itemSchema.type === 'object' && itemSchema.properties) {\n result += formatSchemaForPrompt(itemSchema, indent + 2);\n } else if (itemSchema) {\n const itemType = getTypeDescription(itemSchema);\n result += `${indentStr} ${itemType}\\n`;\n }\n }\n }\n }\n\n return result;\n}\n\n/**\n * Gets a human-readable type description from a schema property\n */\nfunction getTypeDescription(schema: JSONSchema): string {\n if (!schema) return 'any';\n\n if (schema.type) {\n // Handle array of types (e.g., [\"string\", \"null\"])\n const typeStr = Array.isArray(schema.type) ? schema.type.join(' | ') : schema.type;\n\n if (typeStr === 'array' || (Array.isArray(schema.type) && schema.type.includes('array'))) {\n if (schema.items && !Array.isArray(schema.items) && schema.items.type) {\n const itemType = Array.isArray(schema.items.type)\n ? schema.items.type.join(' | ')\n : schema.items.type;\n return `array of ${itemType}`;\n }\n return 'array';\n }\n // Include format information for strings (e.g., date, time, date-time, email, uri)\n if ((typeStr === 'string' || (Array.isArray(schema.type) && schema.type.includes('string'))) && schema.format) {\n const formatHints: Record<string, string> = {\n 'date': 'YYYY-MM-DD',\n 'time': 'HH:MM or HH:MM:SS',\n 'date-time': 'YYYY-MM-DDTHH:MM:SS (ISO 8601)',\n };\n const hint = formatHints[schema.format];\n if (hint) {\n return `string (format: ${schema.format}, use ${hint})`;\n }\n return `string (format: ${schema.format})`;\n }\n return typeStr;\n }\n\n // Handle anyOf, oneOf, allOf\n if (schema.anyOf) {\n return schema.anyOf.map((s) => getTypeDescription(s)).join(' OR ');\n }\n if (schema.oneOf) {\n return schema.oneOf.map((s) => getTypeDescription(s)).join(' OR ');\n }\n\n return 'any';\n}\n\n/**\n * Generates a complete prompt section with schema information and\n * strict field name instructions.\n */\nexport function buildSchemaPromptSection(schema: JSONSchema): string {\n const schemaFields = formatSchemaForPrompt(schema);\n\n return `\n==================================================\nCRITICAL: OUTPUT STRUCTURE REQUIREMENTS\n==================================================\n\nYOU MUST RETURN JSON MATCHING THIS EXACT STRUCTURE:\n\n${schemaFields}\n\nCRITICAL FIELD NAME REQUIREMENTS:\n✓ Use EXACTLY the field names shown above (character-for-character match)\n✓ Preserve the exact casing (e.g., \"fullName\", not \"full_name\" or \"FullName\")\n✓ Do NOT abbreviate field names (e.g., \"dob\" instead of \"dateOfBirth\")\n✓ Do NOT invent alternative names (e.g., \"directorName\" instead of \"fullName\")\n✓ Do NOT use snake_case if the schema uses camelCase\n✓ Do NOT flatten nested structures or rename nested fields\n✓ The schema above is the SINGLE SOURCE OF TRUTH for field naming\n\nMISSING DATA:\n- If a required field has no data in the document, use null\n- If an optional field has no data, you may omit it or use null\n- Do NOT invent data that isn't in the document\n\n==================================================\n`.trim();\n}\n\n/**\n * Combines schema prompt section with user's custom prompt\n */\nexport function combineSchemaAndUserPrompt(\n schema: JSONSchema,\n userPrompt: string\n): string {\n const schemaSection = buildSchemaPromptSection(schema);\n\n if (!userPrompt || userPrompt.trim() === '') {\n return schemaSection + '\\n\\nTASK: Extract structured data from the provided document.';\n }\n\n return schemaSection + '\\n\\n' + userPrompt;\n}\n","import type { LLMProvider, ProviderConfig, ProviderType } from './types';\n\n/**\n * Factory function type for creating provider instances\n */\nexport type ProviderFactory = (config: ProviderConfig) => LLMProvider;\n\n/**\n * Normalize provider type aliases (e.g., 'x-ai' -> 'xai')\n */\nfunction normalizeProviderType(type: ProviderType): ProviderType {\n if (type === 'x-ai') return 'xai';\n return type;\n}\n\n/**\n * Provider registry for dynamic provider loading\n *\n * This allows provider packages to register themselves when imported,\n * avoiding hardcoded imports in the core package.\n */\nclass ProviderRegistry {\n private factories: Map<ProviderType, ProviderFactory> = new Map();\n\n /**\n * Register a provider factory\n * Called by each provider package when it's imported\n */\n register(type: ProviderType, factory: ProviderFactory): void {\n const normalizedType = normalizeProviderType(type);\n this.factories.set(normalizedType, factory);\n }\n\n /**\n * Check if a provider is registered\n */\n has(type: ProviderType): boolean {\n const normalizedType = normalizeProviderType(type);\n return this.factories.has(normalizedType);\n }\n\n /**\n * Get a provider factory\n */\n get(type: ProviderType): ProviderFactory | undefined {\n const normalizedType = normalizeProviderType(type);\n return this.factories.get(normalizedType);\n }\n\n /**\n * Create a provider instance\n * @throws Error if provider is not registered\n */\n create(config: ProviderConfig): LLMProvider {\n const normalizedType = normalizeProviderType(config.provider);\n const factory = this.factories.get(normalizedType);\n if (!factory) {\n const registered = Array.from(this.factories.keys()).join(', ') || 'none';\n throw new Error(\n `Provider '${config.provider}' is not registered. ` +\n `Registered providers: ${registered}. ` +\n `Make sure to import the provider package (e.g., import '@doclo/providers-${normalizedType}').`\n );\n }\n // Pass config with normalized provider type\n return factory({ ...config, provider: normalizedType });\n }\n\n /**\n * Get all registered provider types\n */\n getRegisteredTypes(): ProviderType[] {\n return Array.from(this.factories.keys());\n }\n\n /**\n * Clear all registrations (for testing)\n */\n clear(): void {\n this.factories.clear();\n }\n}\n\n/**\n * Global provider registry instance\n */\nexport const providerRegistry = new ProviderRegistry();\n\n/**\n * Register a provider factory\n * Convenience function for provider packages\n */\nexport function registerProvider(type: ProviderType, factory: ProviderFactory): void {\n providerRegistry.register(type, factory);\n}\n\n/**\n * Create a provider instance from the registry\n */\nexport function createProviderFromRegistry(config: ProviderConfig): LLMProvider {\n return providerRegistry.create(config);\n}\n","import type {\n LLMProvider,\n ProviderConfig,\n MultimodalInput,\n UnifiedSchema,\n LLMResponse,\n ProviderCapabilities,\n ResourceLimits\n} from \"../types\";\nimport { SchemaTranslator } from \"../schema-translator\";\nimport { combineSchemaAndUserPrompt } from \"../schema-prompt-formatter\";\nimport { fetchWithTimeout, DEFAULT_LIMITS, safeJsonParse } from \"@doclo/core/security\";\n\n/**\n * Extract base provider name from model identifier.\n * For OpenRouter models like \"openai/gpt-4...\", extracts \"openai\".\n * For direct models like \"gpt-4...\", returns the default provider.\n */\nfunction extractProviderFromModel(model: string, defaultProvider: string): string {\n const slashIndex = model.indexOf('/');\n return slashIndex > 0 ? model.substring(0, slashIndex) : defaultProvider;\n}\n\nexport class OpenAIProvider implements LLMProvider {\n readonly name: string;\n readonly capabilities: ProviderCapabilities = {\n supportsStructuredOutput: true,\n supportsStreaming: true,\n supportsImages: true,\n supportsPDFs: true,\n maxPDFPages: 100,\n maxPDFSize: 32,\n maxContextTokens: 128000\n };\n\n private config: ProviderConfig;\n private translator: SchemaTranslator;\n private limits: typeof DEFAULT_LIMITS;\n\n constructor(config: ProviderConfig) {\n this.config = config;\n // Extract base provider from model if it's an OpenRouter model (e.g., \"openai/gpt-4...\")\n const baseProvider = extractProviderFromModel(config.model, 'openai');\n this.name = `${baseProvider}:${config.model}`;\n this.translator = new SchemaTranslator();\n\n // Merge custom limits with defaults\n this.limits = {\n ...DEFAULT_LIMITS,\n ...(config.limits || {})\n };\n }\n\n async completeJson<T>(params: {\n input: MultimodalInput;\n schema?: UnifiedSchema<T>;\n mode?: import(\"../types\").JsonMode;\n max_tokens?: number;\n reasoning?: import(\"../types\").ReasoningConfig;\n embedSchemaInPrompt?: boolean;\n }): Promise<LLMResponse<T>> {\n const startTime = Date.now();\n\n // Determine mode: default to 'strict', auto-relaxed if schema omitted\n const mode = params.mode || (params.schema ? 'strict' : 'relaxed');\n\n // Validate: strict mode requires schema\n if (mode === 'strict' && !params.schema) {\n throw new Error('schema is required when mode is \"strict\"');\n }\n\n // Embed schema in prompt if enabled (default: true) and schema exists\n const shouldEmbedSchema = params.embedSchemaInPrompt !== false && params.schema;\n let enhancedInput = params.input;\n\n if (shouldEmbedSchema) {\n // Convert schema to JSON Schema format\n const jsonSchema = this.translator.convertZodIfNeeded(params.schema!);\n\n // Combine schema prompt with user's text\n const enhancedText = combineSchemaAndUserPrompt(\n jsonSchema,\n params.input.text || ''\n );\n\n enhancedInput = {\n ...params.input,\n text: enhancedText\n };\n }\n\n // Build messages with multimodal content (using enhanced input)\n const messages = this.buildMessages(enhancedInput);\n\n // Build request body\n const requestBody: any = {\n model: this.config.model,\n messages,\n max_tokens: params.max_tokens || 4096, // Set reasonable default to avoid massive token requests\n // Enable usage tracking for OpenRouter cost info\n usage: {\n include: true\n }\n };\n\n // Set response_format based on mode\n if (mode === 'relaxed') {\n // Relaxed mode: just request valid JSON without strict schema validation\n requestBody.response_format = {\n type: \"json_object\"\n };\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[OpenAIProvider] Using relaxed JSON mode (json_object)');\n }\n } else {\n // Strict mode: use json_schema with strict validation\n const schema: any = this.translator.toOpenAISchema(params.schema!);\n\n // Recursively fix schema for Azure strict mode requirements\n // Azure requires additionalProperties: false on ALL nested objects\n const fixSchemaForAzure = (obj: any): any => {\n if (obj && typeof obj === 'object') {\n if (obj.type === 'object' && obj.properties) {\n const allProps = Object.keys(obj.properties);\n obj.required = allProps;\n obj.additionalProperties = false;\n\n // Recursively fix nested properties\n for (const key in obj.properties) {\n obj.properties[key] = fixSchemaForAzure(obj.properties[key]);\n }\n } else if (obj.type === 'array' && obj.items) {\n // Recursively fix array items schema\n obj.items = fixSchemaForAzure(obj.items);\n }\n }\n return obj;\n };\n\n fixSchemaForAzure(schema);\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[OpenAIProvider] Using strict JSON mode (json_schema)');\n console.log('[OpenAIProvider] Fixed schema:', JSON.stringify(schema, null, 2));\n }\n\n requestBody.response_format = {\n type: \"json_schema\",\n json_schema: {\n name: \"extraction\",\n strict: true,\n schema\n }\n };\n }\n\n // Add reasoning configuration if provided (OpenAI uses effort directly)\n if (params.reasoning) {\n requestBody.reasoning = this.buildReasoningConfig(params.reasoning);\n }\n\n // Add OpenRouter model filtering for strict mode\n if (this.config.via === 'openrouter' && mode === 'strict') {\n requestBody.provider = {\n require_parameters: true // Only route to models supporting json_schema\n };\n }\n\n // Make API call - check if using OpenRouter\n const endpoint = this.config.via === 'openrouter'\n ? \"https://openrouter.ai/api/v1\"\n : (this.config.baseUrl || \"https://api.openai.com/v1\");\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.config.apiKey}`\n };\n\n // Add OpenRouter-specific headers\n if (this.config.via === 'openrouter') {\n headers[\"HTTP-Referer\"] = \"https://github.com/docloai/sdk\";\n headers[\"X-Title\"] = \"Doclo SDK\";\n }\n\n const response = await fetchWithTimeout(`${endpoint}/chat/completions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(requestBody)\n }, this.limits.REQUEST_TIMEOUT);\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`OpenAI API error (${response.status}): ${error}`);\n }\n\n const data = await response.json();\n const latencyMs = Date.now() - startTime;\n\n // Parse response\n const content = data.choices?.[0]?.message?.content ?? \"{}\";\n const parsed = safeJsonParse(content) as T;\n\n // Extract reasoning fields if present\n const message = data.choices?.[0]?.message;\n const reasoning = message?.reasoning;\n const reasoning_details = message?.reasoning_details;\n\n // Extract cost from OpenRouter or calculate locally\n let costUSD: number | undefined;\n if (this.config.via === 'openrouter') {\n // Read cost from OpenRouter response (more accurate than local calculation)\n costUSD = data.usage?.total_cost ?? data.usage?.cost;\n } else {\n // Calculate cost locally for native OpenAI API\n costUSD = this.calculateCost(data.usage);\n }\n\n // Extract base provider from model for metrics\n const baseProvider = extractProviderFromModel(this.config.model, 'openai');\n\n return {\n json: parsed as T,\n rawText: content,\n metrics: {\n costUSD,\n inputTokens: data.usage?.prompt_tokens,\n outputTokens: data.usage?.completion_tokens,\n latencyMs,\n attemptNumber: 1,\n provider: baseProvider, // Base provider (e.g., \"openai\" from \"openai/gpt-4...\")\n model: this.config.model\n },\n reasoning,\n reasoning_details\n };\n }\n\n private buildReasoningConfig(reasoning: import(\"../types\").ReasoningConfig): any {\n const config: any = {};\n\n // OpenAI uses effort directly\n if (reasoning.effort) {\n config.effort = reasoning.effort;\n } else if (reasoning.enabled) {\n config.effort = 'medium'; // Default to medium\n }\n\n // Add exclude flag if specified\n if (reasoning.exclude !== undefined) {\n config.exclude = reasoning.exclude;\n }\n\n return Object.keys(config).length > 0 ? config : undefined;\n }\n\n private buildMessages(input: MultimodalInput): any[] {\n const content: any[] = [];\n\n // Add text\n if (input.text) {\n content.push({ type: \"text\", text: input.text });\n }\n\n // Add images\n if (input.images && input.images.length > 0) {\n for (const image of input.images) {\n if (image.url) {\n content.push({\n type: \"image_url\",\n image_url: { url: image.url }\n });\n } else if (image.base64) {\n content.push({\n type: \"image_url\",\n image_url: {\n url: `data:${image.mimeType};base64,${this.extractBase64(image.base64)}`\n }\n });\n }\n }\n }\n\n // Add PDFs - OpenRouter requires type: \"file\" format\n if (input.pdfs && input.pdfs.length > 0) {\n for (const pdf of input.pdfs) {\n let fileData: string;\n if (pdf.url) {\n fileData = pdf.url;\n } else if (pdf.base64) {\n fileData = `data:application/pdf;base64,${this.extractBase64(pdf.base64)}`;\n } else {\n continue;\n }\n\n content.push({\n type: \"file\",\n file: {\n filename: \"document.pdf\",\n file_data: fileData\n }\n });\n }\n }\n\n return [{ role: \"user\", content }];\n }\n\n /**\n * Extract base64 data from a data URL or return as-is if already raw base64\n */\n private extractBase64(input: string): string {\n if (input.startsWith('data:')) {\n // Extract base64 part from data URL: data:image/jpeg;base64,XXXXX -> XXXXX\n const base64Part = input.split(',')[1];\n if (!base64Part) {\n throw new Error(`Invalid data URL format: ${input.substring(0, 50)}`);\n }\n return base64Part;\n }\n return input;\n }\n\n private calculateCost(usage: any): number | undefined {\n if (!usage) return undefined;\n\n // Approximate costs for GPT-4o (as of 2025)\n // These should be updated based on current pricing\n const inputCostPer1k = 0.005; // $0.005 per 1K input tokens\n const outputCostPer1k = 0.015; // $0.015 per 1K output tokens\n\n const inputCost = (usage.prompt_tokens / 1000) * inputCostPer1k;\n const outputCost = (usage.completion_tokens / 1000) * outputCostPer1k;\n\n return inputCost + outputCost;\n }\n}\n","import type {\n LLMProvider,\n ProviderConfig,\n MultimodalInput,\n UnifiedSchema,\n LLMResponse,\n ProviderCapabilities,\n ResourceLimits\n} from \"../types\";\nimport { SchemaTranslator } from \"../schema-translator\";\nimport { combineSchemaAndUserPrompt } from \"../schema-prompt-formatter\";\nimport { fetchWithTimeout, DEFAULT_LIMITS, validateUrl, safeJsonParse } from \"@doclo/core/security\";\nimport { detectMimeTypeFromBase64, validateMimeType } from \"@doclo/core\";\n\n/**\n * Extract base provider name from model identifier.\n * For OpenRouter models like \"anthropic/claude-...\", extracts \"anthropic\".\n * For direct models like \"claude-...\", returns the default provider.\n */\nfunction extractProviderFromModel(model: string, defaultProvider: string): string {\n const slashIndex = model.indexOf('/');\n return slashIndex > 0 ? model.substring(0, slashIndex) : defaultProvider;\n}\n\nexport class AnthropicProvider implements LLMProvider {\n readonly name: string;\n readonly capabilities: ProviderCapabilities = {\n supportsStructuredOutput: true, // via tool calling\n supportsStreaming: true,\n supportsImages: true,\n supportsPDFs: true,\n maxPDFPages: 100,\n maxPDFSize: undefined, // ~400k tokens with overhead\n maxContextTokens: 200000\n };\n\n private config: ProviderConfig;\n private translator: SchemaTranslator;\n private limits: typeof DEFAULT_LIMITS;\n\n constructor(config: ProviderConfig) {\n this.config = config;\n // Extract base provider from model if it's an OpenRouter model (e.g., \"anthropic/claude-...\")\n const baseProvider = extractProviderFromModel(config.model, 'anthropic');\n this.name = `${baseProvider}:${config.model}`;\n this.translator = new SchemaTranslator();\n\n // Merge custom limits with defaults\n this.limits = {\n ...DEFAULT_LIMITS,\n ...(config.limits || {})\n };\n }\n\n async completeJson<T>(params: {\n input: MultimodalInput;\n schema?: UnifiedSchema<T>;\n mode?: import(\"../types\").JsonMode;\n max_tokens?: number;\n reasoning?: import(\"../types\").ReasoningConfig;\n embedSchemaInPrompt?: boolean;\n }): Promise<LLMResponse<T>> {\n const startTime = Date.now();\n\n // Determine mode: default to 'strict', auto-relaxed if schema omitted\n const mode = params.mode || (params.schema ? 'strict' : 'relaxed');\n\n // Validate: strict mode requires schema\n if (mode === 'strict' && !params.schema) {\n throw new Error('schema is required when mode is \"strict\"');\n }\n\n // Embed schema in prompt if enabled (default: true) and schema exists\n const shouldEmbedSchema = params.embedSchemaInPrompt !== false && params.schema;\n let enhancedInput = params.input;\n\n if (shouldEmbedSchema) {\n // Convert schema to JSON Schema format\n const jsonSchema = this.translator.convertZodIfNeeded(params.schema!);\n\n // Combine schema prompt with user's text\n const enhancedText = combineSchemaAndUserPrompt(\n jsonSchema,\n params.input.text || ''\n );\n\n enhancedInput = {\n ...params.input,\n text: enhancedText\n };\n }\n\n // Build messages with multimodal content (using enhanced input)\n const messages = await this.buildMessages(enhancedInput);\n\n // Check if model supports new structured outputs API\n // OpenRouter now supports structured outputs for Sonnet 4.5 and Opus 4.1\n const useNewStructuredOutputs = this.supportsNewStructuredOutputs();\n\n // Build request body\n const requestBody: any = {\n model: this.config.model,\n max_tokens: params.max_tokens || 4096,\n messages\n };\n\n if (mode === 'relaxed') {\n // Relaxed mode: use prompt engineering with response prefilling\n // Anthropic doesn't have native json_object mode, so we rely on prefilling\n // Add prefill message to force JSON output\n requestBody.messages.push({\n role: \"assistant\",\n content: \"{\"\n });\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] Using relaxed JSON mode (prompt + prefilling)');\n }\n } else if (useNewStructuredOutputs) {\n // Strict mode with NEW structured outputs API (output_format)\n const jsonSchema = this.translator.convertZodIfNeeded(params.schema!);\n const fixedSchema = this.fixSchemaForStrictMode(jsonSchema);\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] Original schema:', JSON.stringify(jsonSchema, null, 2));\n console.log('[AnthropicProvider] Fixed schema:', JSON.stringify(fixedSchema, null, 2));\n }\n\n requestBody.output_format = {\n type: \"json_schema\",\n schema: fixedSchema\n };\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] Using NEW structured outputs API (strict mode)');\n }\n } else {\n // Strict mode with legacy tool calling approach\n const tool = this.translator.toClaudeToolSchema(params.schema!);\n requestBody.tools = [tool];\n requestBody.tool_choice = { type: \"tool\", name: \"extract_data\" };\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] Using legacy tool calling approach (strict mode)');\n }\n }\n\n // Add native thinking configuration if using native API and reasoning is enabled\n if (this.config.via !== 'openrouter' && params.reasoning) {\n const thinkingConfig = this.buildNativeThinkingConfig(params.reasoning, params.max_tokens);\n if (thinkingConfig) {\n requestBody.thinking = thinkingConfig;\n }\n }\n\n // Make API call - check if using OpenRouter\n let response: Response;\n let parsed: any;\n let inputTokens: number | undefined;\n let outputTokens: number | undefined;\n let costUSD: number | undefined;\n\n if (this.config.via === 'openrouter') {\n // Check if model supports new structured outputs\n const useNewStructuredOutputs = this.supportsNewStructuredOutputs();\n\n // Use OpenRouter with OpenAI-compatible format\n const openRouterRequest = this.translateToOpenRouterFormat(messages, params.schema, mode, params.max_tokens, params.reasoning);\n\n // Debug: Log request body to verify cache_control is present\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] OpenRouter request body (messages):');\n console.log(JSON.stringify(openRouterRequest.messages, null, 2));\n console.log('[AnthropicProvider] Using new structured outputs:', useNewStructuredOutputs);\n }\n\n response = await fetchWithTimeout(\"https://openrouter.ai/api/v1/chat/completions\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.config.apiKey}`,\n \"HTTP-Referer\": \"https://github.com/docloai/sdk\",\n \"X-Title\": \"Doclo SDK\"\n },\n body: JSON.stringify(openRouterRequest)\n }, this.limits.REQUEST_TIMEOUT);\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Anthropic API error (${response.status}): ${error}`);\n }\n\n const data = await response.json();\n const message = data.choices?.[0]?.message;\n let content = message?.content ?? (useNewStructuredOutputs ? \"{}\" : \"}\");\n\n // For OLDER models: we prefilled with \"{\", so prepend it back\n // For NEW models: content is already complete JSON\n if (!useNewStructuredOutputs) {\n content = \"{\" + content;\n }\n\n // Extract reasoning fields if present\n const reasoning = message?.reasoning;\n const reasoning_details = message?.reasoning_details;\n\n // Claude via OpenRouter with response prefilling should return clean JSON\n // But apply defensive parsing just in case:\n\n // 1. Strip markdown code blocks if present\n content = content.replace(/^```json\\s*\\n?/,'').replace(/\\n?```\\s*$/,'').trim();\n\n // 2. Strip markdown bold/italic formatting\n content = content.replace(/\\*\\*/g, '').replace(/\\*/g, '');\n\n // 3. Extract just the JSON object (handle extra text after closing brace)\n const firstBrace = content.indexOf('{');\n if (firstBrace !== -1) {\n // Find the matching closing brace using brace counting\n let braceCount = 0;\n let jsonEnd = -1;\n for (let i = firstBrace; i < content.length; i++) {\n if (content[i] === '{') braceCount++;\n if (content[i] === '}') braceCount--;\n if (braceCount === 0) {\n jsonEnd = i + 1;\n break;\n }\n }\n if (jsonEnd !== -1) {\n content = content.substring(firstBrace, jsonEnd);\n }\n } else if (!content.startsWith('[')) {\n // No JSON found at all - throw detailed error\n throw new Error(`Claude did not return JSON. Response: ${content.substring(0, 200)}`);\n }\n\n // 4. Remove any leading/trailing whitespace\n content = content.trim();\n\n parsed = safeJsonParse(content) as T;\n\n // Auto-wrap detection: If relaxed mode returns unwrapped properties, wrap them\n // This handles cases where the LLM returns properties directly instead of a full schema\n if (mode === 'relaxed' && this.looksLikeUnwrappedProperties(parsed)) {\n parsed = this.wrapAsSchema(parsed) as T;\n }\n\n inputTokens = data.usage?.prompt_tokens;\n outputTokens = data.usage?.completion_tokens;\n // Try different cost fields that OpenRouter might use\n costUSD = data.usage?.total_cost ?? data.usage?.cost;\n\n // Extract prompt caching metrics (OpenRouter/Anthropic)\n const cacheCreationInputTokens = data.usage?.cache_creation_input_tokens;\n const cacheReadInputTokens = data.usage?.cache_read_input_tokens;\n\n // Debug: Log usage fields if DEBUG_PROVIDERS is set\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] OpenRouter usage response:', JSON.stringify(data.usage, null, 2));\n console.log('[AnthropicProvider] Extracted costUSD:', costUSD);\n console.log('[AnthropicProvider] Cache creation tokens:', cacheCreationInputTokens);\n console.log('[AnthropicProvider] Cache read tokens:', cacheReadInputTokens);\n }\n\n // Return with reasoning fields\n const latencyMs = Date.now() - startTime;\n // Extract base provider from model for metrics\n const baseProvider = extractProviderFromModel(this.config.model, 'anthropic');\n\n return {\n json: parsed as T,\n rawText: JSON.stringify(parsed),\n metrics: {\n costUSD,\n inputTokens,\n outputTokens,\n latencyMs,\n attemptNumber: 1,\n provider: baseProvider, // Base provider (e.g., \"anthropic\" from \"anthropic/claude-...\")\n model: this.config.model,\n cacheCreationInputTokens,\n cacheReadInputTokens\n },\n reasoning,\n reasoning_details\n };\n } else {\n // Use native Anthropic API\n const endpoint = this.config.baseUrl || \"https://api.anthropic.com/v1\";\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.config.apiKey,\n \"anthropic-version\": \"2023-06-01\"\n };\n\n // Add beta header for new structured outputs API\n if (useNewStructuredOutputs) {\n headers[\"anthropic-beta\"] = \"structured-outputs-2025-11-13\";\n }\n\n response = await fetchWithTimeout(`${endpoint}/messages`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(requestBody)\n }, this.limits.REQUEST_TIMEOUT);\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Anthropic API error (${response.status}): ${error}`);\n }\n\n const data = await response.json();\n\n // Extract JSON based on mode and API version\n if (mode === 'relaxed') {\n // Relaxed mode: JSON in text block with prefilling\n const textBlock = data.content?.find((block: any) => block.type === \"text\");\n if (!textBlock || !textBlock.text) {\n throw new Error(\"Claude did not return structured output (relaxed mode)\");\n }\n\n // Prepend \"{\" since we used prefilling\n let content = \"{\" + textBlock.text;\n\n // Clean up: extract just the JSON object\n // Sometimes there's extra text after the closing brace\n const firstBrace = content.indexOf('{');\n if (firstBrace !== -1) {\n // Find the matching closing brace\n let braceCount = 0;\n let jsonEnd = -1;\n for (let i = firstBrace; i < content.length; i++) {\n if (content[i] === '{') braceCount++;\n if (content[i] === '}') braceCount--;\n if (braceCount === 0) {\n jsonEnd = i + 1;\n break;\n }\n }\n if (jsonEnd !== -1) {\n content = content.substring(firstBrace, jsonEnd);\n }\n }\n\n parsed = safeJsonParse(content) as T;\n } else if (useNewStructuredOutputs) {\n // NEW API (strict mode): JSON in content text block\n const textBlock = data.content?.find((block: any) => block.type === \"text\");\n if (!textBlock || !textBlock.text) {\n throw new Error(\"Claude did not return structured output via new API\");\n }\n\n parsed = safeJsonParse(textBlock.text) as T;\n } else {\n // OLD API (strict mode): JSON in tool_use block\n const toolUseBlock = data.content?.find((block: any) => block.type === \"tool_use\");\n if (!toolUseBlock || !toolUseBlock.input) {\n throw new Error(\"Claude did not return structured output via tool calling\");\n }\n\n parsed = toolUseBlock.input;\n }\n\n inputTokens = data.usage?.input_tokens;\n outputTokens = data.usage?.output_tokens;\n costUSD = this.calculateCost(data.usage);\n\n // Extract thinking content if present (native API)\n const thinkingBlock = data.content?.find((block: any) => block.type === \"thinking\");\n const reasoning = thinkingBlock?.thinking;\n\n const latencyMs = Date.now() - startTime;\n\n // Extract base provider from model for metrics\n const baseProvider = extractProviderFromModel(this.config.model, 'anthropic');\n\n return {\n json: parsed as T,\n rawText: JSON.stringify(parsed),\n metrics: {\n costUSD,\n inputTokens,\n outputTokens,\n latencyMs,\n attemptNumber: 1,\n provider: baseProvider, // Base provider (e.g., \"anthropic\" from \"anthropic/claude-...\")\n model: this.config.model\n },\n reasoning,\n reasoning_details: reasoning ? [{\n type: 'reasoning.text' as const,\n text: reasoning,\n signature: null,\n id: 'thinking-1',\n format: 'anthropic-claude-v1'\n }] : undefined\n };\n }\n }\n\n private buildNativeThinkingConfig(reasoning: import(\"../types\").ReasoningConfig, max_tokens?: number): any {\n // Native Anthropic uses \"thinking\" object with \"type\" and \"budget_tokens\"\n if (!reasoning.effort && !reasoning.enabled) {\n return undefined;\n }\n\n const effort = reasoning.effort || 'medium';\n const requestMaxTokens = max_tokens || 4096;\n\n // Convert effort to budget_tokens (minimum 1024 for Anthropic)\n const effortRatios = { low: 0.2, medium: 0.5, high: 0.8 };\n const ratio = effortRatios[effort];\n const budget_tokens = Math.max(1024, Math.min(32000, Math.floor(requestMaxTokens * ratio)));\n\n return {\n type: \"enabled\",\n budget_tokens\n };\n }\n\n private translateToOpenRouterFormat(\n messages: any[],\n schema: any | undefined,\n mode: import(\"../types\").JsonMode,\n max_tokens?: number,\n reasoning?: import(\"../types\").ReasoningConfig\n ): any {\n // Check if model supports new structured outputs\n const useNewStructuredOutputs = this.supportsNewStructuredOutputs();\n\n // Add system message for JSON enforcement\n const systemMessage = {\n role: \"system\",\n content: mode === 'strict'\n ? \"You are a data extraction assistant. You must respond ONLY with valid JSON that matches the provided schema. Do not include any markdown formatting, explanations, or additional text.\"\n : \"You are a data extraction assistant. You must respond ONLY with valid JSON. Do not include any markdown formatting, explanations, or additional text.\"\n };\n\n // Prepare messages array\n const messageArray = [systemMessage, ...messages];\n\n const requestBody: any = {\n model: this.config.model,\n messages: messageArray,\n // Enable usage tracking for OpenRouter cost info\n usage: {\n include: true\n }\n };\n\n if (mode === 'relaxed') {\n // Relaxed mode: use json_object without strict schema\n // Note: We don't use response prefilling here to allow more flexible JSON generation\n // (e.g., generating JSON Schemas which need the root type/properties wrapper)\n requestBody.response_format = {\n type: 'json_object'\n };\n } else {\n // Strict mode: use json_schema with strict validation\n const openRouterSchema = this.translator.toClaudeOpenRouterSchema(schema!);\n const fixedSchema = this.fixSchemaForStrictMode(openRouterSchema);\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] Original schema:', JSON.stringify(openRouterSchema, null, 2));\n console.log('[AnthropicProvider] Fixed schema:', JSON.stringify(fixedSchema, null, 2));\n }\n\n // Add response prefill for OLDER models (legacy workaround)\n // NEW models don't need prefilling with json_schema response_format\n if (!useNewStructuredOutputs) {\n messageArray.push({\n role: \"assistant\",\n content: \"{\"\n });\n }\n\n requestBody.response_format = {\n type: 'json_schema',\n json_schema: {\n name: 'extraction',\n strict: true,\n schema: fixedSchema\n }\n };\n }\n\n // Add reasoning configuration if provided (Anthropic uses max_tokens)\n if (reasoning) {\n requestBody.reasoning = this.buildReasoningConfig(reasoning, max_tokens);\n }\n\n // Note: We don't add require_parameters: true here because:\n // - Models like Haiku that don't support json_schema natively\n // will still work using the prefill workaround\n // - The supportsNewStructuredOutputs() check handles routing internally\n\n return requestBody;\n }\n\n private buildReasoningConfig(reasoning: import(\"../types\").ReasoningConfig, max_tokens?: number): any {\n const config: any = {};\n\n // Anthropic uses max_tokens - convert effort to max_tokens\n if (reasoning.effort || reasoning.enabled) {\n const effort = reasoning.effort || 'medium';\n const requestMaxTokens = max_tokens || 4096; // Default if not specified\n\n // Convert effort to percentage of max_tokens\n const effortRatios = { low: 0.2, medium: 0.5, high: 0.8 };\n const ratio = effortRatios[effort];\n\n // Calculate reasoning budget with Anthropic limits (1024 min, 32000 max)\n const reasoningBudget = Math.max(1024, Math.min(32000, Math.floor(requestMaxTokens * ratio)));\n config.max_tokens = reasoningBudget;\n }\n\n // Add exclude flag if specified\n if (reasoning.exclude !== undefined) {\n config.exclude = reasoning.exclude;\n }\n\n return Object.keys(config).length > 0 ? config : undefined;\n }\n\n private supportsNewStructuredOutputs(): boolean {\n // Check if model supports the new structured outputs API (Nov 2025)\n // Supported models: Sonnet >= 4.5, Opus >= 4.1\n // Note: Haiku does NOT support native structured outputs yet - uses tool workaround\n const model = this.config.model.toLowerCase();\n\n // Extract model family and version\n // Supports formats like: \"claude-sonnet-4-5\", \"anthropic/claude-opus-4.1\", \"claude-opus-4-5-20251124\"\n const sonnetMatch = model.match(/sonnet[_-](\\d+)[._-](\\d+)/);\n const opusMatch = model.match(/opus[_-](\\d+)[._-](\\d+)/);\n\n if (sonnetMatch) {\n const major = parseInt(sonnetMatch[1], 10);\n const minor = parseInt(sonnetMatch[2], 10);\n const version = major + minor / 10; // 4.5 = 4.5, 4.10 = 5.0\n return version >= 4.5;\n }\n\n if (opusMatch) {\n const major = parseInt(opusMatch[1], 10);\n const minor = parseInt(opusMatch[2], 10);\n const version = major + minor / 10;\n return version >= 4.1;\n }\n\n return false;\n }\n\n private fixSchemaForStrictMode(schema: any): any {\n // Recursively fix schema for strict mode requirements\n // Strict mode requires additionalProperties: false on ALL nested objects\n // STEP 1: Deep clone to prevent mutation (critical for consensus)\n const clonedSchema = JSON.parse(JSON.stringify(schema));\n\n // STEP 2: Ensure root has type: \"object\" (Anthropic requirement)\n if (!clonedSchema.type) {\n clonedSchema.type = 'object';\n }\n\n // STEP 3: Recursively fix all nested structures\n const fixRecursive = (obj: any): any => {\n if (!obj || typeof obj !== 'object') {\n return obj;\n }\n\n // Handle objects (both with and without properties)\n if (obj.type === 'object') {\n // Always add additionalProperties: false\n obj.additionalProperties = false;\n\n // If has properties, make all required and recurse\n if (obj.properties) {\n const allProps = Object.keys(obj.properties);\n obj.required = allProps;\n\n // Recursively fix nested properties\n for (const key in obj.properties) {\n obj.properties[key] = fixRecursive(obj.properties[key]);\n }\n }\n }\n\n // Handle arrays\n if (obj.type === 'array' && obj.items) {\n obj.items = fixRecursive(obj.items);\n }\n\n // Handle anyOf/oneOf/allOf (NEW - critical for nullable fields)\n ['anyOf', 'oneOf', 'allOf'].forEach(keyword => {\n if (obj[keyword] && Array.isArray(obj[keyword])) {\n obj[keyword] = obj[keyword].map((s: any) => fixRecursive(s));\n }\n });\n\n return obj;\n };\n\n return fixRecursive(clonedSchema);\n }\n\n private async buildMessages(input: MultimodalInput): Promise<any[]> {\n const content: any[] = [];\n const hasMedia = (input.images && input.images.length > 0) || (input.pdfs && input.pdfs.length > 0);\n\n // Debug: Log input state\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider.buildMessages] Input state:');\n console.log(' hasMedia:', hasMedia);\n console.log(' input.images:', input.images?.length || 0);\n console.log(' input.pdfs:', input.pdfs?.length || 0);\n console.log(' input.text:', input.text ? `\"${input.text.substring(0, 50)}...\"` : 'undefined');\n console.log(' via:', this.config.via);\n }\n\n // When using OpenRouter, use OpenAI-compatible format\n if (this.config.via === 'openrouter') {\n // Add images first (before text, so they get cached)\n if (input.images && input.images.length > 0) {\n for (const image of input.images) {\n if (image.url) {\n // If it's a data URL, use directly; otherwise it's a regular URL\n content.push({\n type: \"image_url\",\n image_url: { url: image.url }\n });\n } else if (image.base64) {\n // Automatically detect MIME type from actual file data to prevent mismatches\n const actualMimeType = detectMimeTypeFromBase64(image.base64);\n\n // Warn if declared MIME type doesn't match actual data\n if (image.mimeType && image.mimeType !== actualMimeType) {\n console.warn(\n `[AnthropicProvider] MIME type mismatch detected: ` +\n `declared \"${image.mimeType}\", actual \"${actualMimeType}\". ` +\n `Using detected type \"${actualMimeType}\" to prevent API errors.`\n );\n }\n\n content.push({\n type: \"image_url\",\n image_url: {\n url: `data:${actualMimeType};base64,${this.extractBase64(image.base64)}`\n }\n });\n }\n }\n }\n\n // Add PDFs second (before text, so they get cached)\n if (input.pdfs && input.pdfs.length > 0) {\n for (const pdf of input.pdfs) {\n let fileData: string;\n if (pdf.url) {\n fileData = pdf.url;\n } else if (pdf.base64) {\n // Automatically detect MIME type for PDFs too\n const actualMimeType = detectMimeTypeFromBase64(pdf.base64);\n\n if (actualMimeType !== 'application/pdf') {\n console.warn(\n `[AnthropicProvider] PDF MIME type mismatch: ` +\n `expected \"application/pdf\", detected \"${actualMimeType}\". ` +\n `Using detected type.`\n );\n }\n\n fileData = `data:${actualMimeType};base64,${this.extractBase64(pdf.base64)}`;\n } else {\n continue;\n }\n\n content.push({\n type: \"file\",\n file: {\n filename: \"document.pdf\",\n file_data: fileData\n }\n });\n }\n }\n\n // Add text last with cache_control if there's media\n // According to OpenRouter docs, cache_control can only be on text blocks\n // This caches all the images/PDFs that came before it\n if (hasMedia) {\n // Always add a text block with cache_control when we have media\n // Use provided text or a default instruction\n const textContent = input.text || \"Extract the requested information from the document.\";\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider.buildMessages] Adding text block with cache_control');\n console.log(' textContent:', textContent);\n }\n\n content.push({\n type: \"text\",\n text: textContent,\n cache_control: { type: \"ephemeral\" }\n });\n } else if (input.text) {\n // No media, just add text without caching\n content.push({\n type: \"text\",\n text: input.text\n });\n }\n } else {\n // Native Anthropic API format\n // Add text first\n if (input.text) {\n content.push({ type: \"text\", text: input.text });\n }\n // Native Anthropic API format\n // Add images\n if (input.images && input.images.length > 0) {\n for (const image of input.images) {\n if (image.url) {\n // Download and convert to base64 for Claude\n const base64 = await this.urlToBase64(image.url);\n content.push({\n type: \"image\",\n source: {\n type: \"base64\",\n media_type: image.mimeType,\n data: base64\n }\n });\n } else if (image.base64) {\n content.push({\n type: \"image\",\n source: {\n type: \"base64\",\n media_type: image.mimeType,\n data: this.extractBase64(image.base64)\n }\n });\n }\n }\n }\n\n // Add PDFs (convert to base64 or use Files API if fileId provided)\n if (input.pdfs && input.pdfs.length > 0) {\n for (const pdf of input.pdfs) {\n if (pdf.fileId) {\n // Use Files API reference\n content.push({\n type: \"document\",\n source: {\n type: \"file\",\n file_id: pdf.fileId\n }\n });\n } else if (pdf.base64) {\n content.push({\n type: \"document\",\n source: {\n type: \"base64\",\n media_type: \"application/pdf\",\n data: this.extractBase64(pdf.base64)\n }\n });\n } else if (pdf.url) {\n const base64 = await this.urlToBase64(pdf.url);\n content.push({\n type: \"document\",\n source: {\n type: \"base64\",\n media_type: \"application/pdf\",\n data: base64\n }\n });\n }\n }\n }\n }\n\n // Debug: Log final content array\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider.buildMessages] Final content array length:', content.length);\n console.log('[AnthropicProvider.buildMessages] Final content array:', JSON.stringify(content, null, 2));\n }\n\n return [{ role: \"user\", content }];\n }\n\n private async urlToBase64(url: string): Promise<string> {\n validateUrl(url); // SSRF protection\n const response = await fetchWithTimeout(url, {}, this.limits.REQUEST_TIMEOUT);\n if (!response.ok) {\n throw new Error(`Failed to fetch URL: ${url}`);\n }\n const buffer = await response.arrayBuffer();\n return Buffer.from(buffer).toString('base64');\n }\n\n /**\n * Extract base64 data from a data URL or return as-is if already raw base64\n */\n private extractBase64(input: string): string {\n if (input.startsWith('data:')) {\n // Extract base64 part from data URL: data:image/jpeg;base64,XXXXX -> XXXXX\n const base64Part = input.split(',')[1];\n if (!base64Part) {\n throw new Error(`Invalid data URL format: ${input.substring(0, 50)}`);\n }\n return base64Part;\n }\n return input;\n }\n\n private calculateCost(usage: any): number | undefined {\n if (!usage) return undefined;\n\n // Approximate costs for Claude 3.5 Sonnet (as of 2025)\n const inputCostPer1k = 0.003; // $0.003 per 1K input tokens\n const outputCostPer1k = 0.015; // $0.015 per 1K output tokens\n\n const inputCost = (usage.input_tokens / 1000) * inputCostPer1k;\n const outputCost = (usage.output_tokens / 1000) * outputCostPer1k;\n\n return inputCost + outputCost;\n }\n\n /**\n * Detect if a parsed JSON object looks like unwrapped JSON Schema properties\n * (e.g., missing the root \"type\": \"object\" and \"properties\": {...} wrapper)\n */\n private looksLikeUnwrappedProperties(obj: any): boolean {\n if (!obj || typeof obj !== 'object' || Array.isArray(obj)) {\n return false;\n }\n\n // If it already has \"type\" and \"properties\" at root, it's properly wrapped\n if (obj.type === 'object' && obj.properties) {\n return false;\n }\n\n // Check if it looks like a properties object:\n // - Has multiple keys\n // - Most/all values are objects with \"type\" property\n const keys = Object.keys(obj);\n if (keys.length === 0) {\n return false;\n }\n\n // Count how many top-level values look like schema property definitions\n let schemaPropertyCount = 0;\n for (const key of keys) {\n const value = obj[key];\n if (value && typeof value === 'object' && 'type' in value) {\n schemaPropertyCount++;\n }\n }\n\n // If most values look like schema properties, it's likely unwrapped\n return schemaPropertyCount / keys.length > 0.5;\n }\n\n /**\n * Wrap unwrapped properties into a proper JSON Schema structure\n */\n private wrapAsSchema(unwrapped: any): any {\n // Extract required fields (those that don't have optional markers)\n const required: string[] = [];\n for (const [key, value] of Object.entries(unwrapped)) {\n if (value && typeof value === 'object') {\n const propDef = value as any;\n // If the property definition has \"required\" array, it's a nested object\n // Otherwise, assume top-level properties are required\n if (!propDef.type || (propDef.type === 'string' || propDef.type === 'number' || propDef.type === 'boolean' || propDef.type === 'integer')) {\n required.push(key);\n } else if (propDef.type === 'object' || propDef.type === 'array') {\n required.push(key);\n }\n }\n }\n\n return {\n type: 'object',\n properties: unwrapped,\n required\n };\n }\n}\n","import type {\n LLMProvider,\n ProviderConfig,\n MultimodalInput,\n UnifiedSchema,\n LLMResponse,\n ProviderCapabilities,\n ResourceLimits,\n JsonMode,\n ReasoningConfig\n} from \"../types\";\nimport { SchemaTranslator } from \"../schema-translator\";\nimport { combineSchemaAndUserPrompt } from \"../schema-prompt-formatter\";\nimport { fetchWithTimeout, validateUrl, DEFAULT_LIMITS, safeJsonParse } from \"@doclo/core/security\";\n\n/** Internal types for Google API structures */\n\n/** Inline data for multimodal content (images/PDFs) */\ninterface GeminiInlineData {\n mimeType: string;\n data: string;\n}\n\n/** File data for Gemini Files API */\ninterface GeminiFileData {\n fileUri: string;\n mimeType: string;\n}\n\n/** A part of Gemini content */\ninterface GeminiPart {\n text?: string;\n inlineData?: GeminiInlineData;\n fileData?: GeminiFileData;\n thought?: boolean;\n}\n\n/** Gemini content structure */\ninterface GeminiContent {\n role: 'user' | 'model';\n parts: GeminiPart[];\n}\n\n/** Gemini generation config */\ninterface GeminiGenerationConfig {\n responseMimeType?: string;\n responseSchema?: object;\n thinking_config?: {\n thinking_budget: number;\n };\n}\n\n/** Gemini request body */\ninterface GeminiRequestBody {\n contents: GeminiContent[];\n generationConfig: GeminiGenerationConfig;\n}\n\n/** OpenRouter message content */\ntype OpenRouterContentPart =\n | { type: 'text'; text: string }\n | { type: 'image_url'; image_url: { url: string } }\n | { type: 'file'; file: { filename: string; file_data: string } };\n\n/** OpenRouter message */\ninterface OpenRouterMessage {\n role: 'user' | 'assistant' | 'system';\n content: string | OpenRouterContentPart[];\n}\n\n/** OpenRouter request format */\ninterface OpenRouterRequest {\n model: string;\n messages: OpenRouterMessage[];\n response_format?: { type: string };\n max_tokens?: number;\n reasoning?: { effort?: string; max_tokens?: number; exclude?: boolean };\n usage?: { include: boolean };\n}\n\n/** Reasoning config for OpenRouter */\ninterface OpenRouterReasoningConfig {\n effort?: string;\n max_tokens?: number;\n exclude?: boolean;\n}\n\n/**\n * Extract base provider name from model identifier.\n * For OpenRouter models like \"google/gemini-...\", extracts \"google\".\n * For direct models like \"gemini-...\", returns the default provider.\n */\nfunction extractProviderFromModel(model: string, defaultProvider: string): string {\n const slashIndex = model.indexOf('/');\n return slashIndex > 0 ? model.substring(0, slashIndex) : defaultProvider;\n}\n\nexport class GoogleProvider implements LLMProvider {\n readonly name: string;\n readonly capabilities: ProviderCapabilities = {\n supportsStructuredOutput: true,\n supportsStreaming: true,\n supportsImages: true,\n supportsPDFs: true,\n maxPDFPages: 1000, // 1 page = 1 image\n maxPDFSize: 50,\n maxContextTokens: 1000000 // 1M tokens\n };\n\n private config: ProviderConfig;\n private translator: SchemaTranslator;\n private limits: typeof DEFAULT_LIMITS;\n\n constructor(config: ProviderConfig) {\n this.config = config;\n // Extract base provider from model if it's an OpenRouter model (e.g., \"google/gemini-...\")\n const baseProvider = extractProviderFromModel(config.model, 'google');\n this.name = `${baseProvider}:${config.model}`;\n this.translator = new SchemaTranslator();\n\n // Merge custom limits with defaults (custom limits override defaults)\n this.limits = {\n ...DEFAULT_LIMITS,\n ...(config.limits || {})\n };\n\n // Debug logging\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[GoogleProvider] Config:', JSON.stringify({\n provider: config.provider,\n model: config.model,\n via: config.via,\n hasApiKey: !!config.apiKey\n }));\n }\n }\n\n async completeJson<T>(params: {\n input: MultimodalInput;\n schema?: UnifiedSchema<T>;\n mode?: import(\"../types\").JsonMode;\n max_tokens?: number;\n reasoning?: import(\"../types\").ReasoningConfig;\n embedSchemaInPrompt?: boolean;\n }): Promise<LLMResponse<T>> {\n const startTime = Date.now();\n\n // Determine mode: default to 'strict', auto-relaxed if schema omitted\n const mode = params.mode || (params.schema ? 'strict' : 'relaxed');\n\n // Validate: strict mode requires schema\n if (mode === 'strict' && !params.schema) {\n throw new Error('schema is required when mode is \"strict\"');\n }\n\n // Embed schema in prompt if enabled (default: true) and schema exists\n const shouldEmbedSchema = params.embedSchemaInPrompt !== false && params.schema;\n let enhancedInput = params.input;\n\n if (shouldEmbedSchema) {\n // Convert schema to JSON Schema format\n const jsonSchema = this.translator.convertZodIfNeeded(params.schema!);\n\n // Combine schema prompt with user's text\n const enhancedText = combineSchemaAndUserPrompt(\n jsonSchema,\n params.input.text || ''\n );\n\n enhancedInput = {\n ...params.input,\n text: enhancedText\n };\n }\n\n // Build contents with multimodal parts (using enhanced input)\n const contents = await this.buildContents(enhancedInput);\n\n // Build request\n const requestBody: GeminiRequestBody = {\n contents,\n generationConfig: {\n // Google's native responseSchema has strict validation issues with complex schemas.\n // Use JSON mode without responseSchema - schema is already in the prompt via combineSchemaAndUserPrompt.\n // See: https://ubaidullahmomer.medium.com/why-google-geminis-response-schema-isn-t-ready-for-complex-json-46f35c3aaaea\n responseMimeType: \"application/json\"\n }\n };\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log(`[GoogleProvider] Using ${mode} JSON mode (schema in prompt, no responseSchema)`);\n }\n\n // Add native thinking configuration if using native API and reasoning is enabled\n if (this.config.via !== 'openrouter' && params.reasoning) {\n const thinkingConfig = this.buildNativeThinkingConfig(params.reasoning, params.max_tokens);\n if (thinkingConfig) {\n requestBody.generationConfig.thinking_config = thinkingConfig;\n }\n }\n\n // Make API call - check if using OpenRouter\n let response: Response;\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[GoogleProvider] Using via:', this.config.via, 'Checking:', this.config.via === 'openrouter');\n }\n\n if (this.config.via === 'openrouter') {\n // Use OpenRouter endpoint with OpenAI-compatible format\n const openRouterRequest = this.translateToOpenRouterFormat(contents, mode, params.max_tokens, params.reasoning);\n response = await fetchWithTimeout(\"https://openrouter.ai/api/v1/chat/completions\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.config.apiKey}`,\n \"HTTP-Referer\": \"https://github.com/docloai/sdk\",\n \"X-Title\": \"Doclo SDK\"\n },\n body: JSON.stringify(openRouterRequest)\n }, this.limits.REQUEST_TIMEOUT);\n } else {\n // Use native Google API\n // Note: Google's native API doesn't support Authorization headers,\n // so we must use the API key in the query parameter for authentication.\n // This is a documented limitation of Google's REST API.\n const endpoint = this.config.baseUrl ||\n `https://generativelanguage.googleapis.com/v1beta/models/${this.config.model}:generateContent`;\n\n // Validate the endpoint URL for SSRF attacks\n validateUrl(endpoint);\n\n response = await fetchWithTimeout(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-goog-api-key\": this.config.apiKey // Use header instead of query param\n },\n body: JSON.stringify(requestBody)\n }, this.limits.REQUEST_TIMEOUT);\n }\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Google API error (${response.status}): ${error}`);\n }\n\n const data = await response.json();\n const latencyMs = Date.now() - startTime;\n\n // Parse response based on via parameter\n let content: string;\n let inputTokens: number | undefined;\n let outputTokens: number | undefined;\n let costUSD: number | undefined;\n\n if (this.config.via === 'openrouter') {\n // OpenRouter format (OpenAI-compatible)\n const message = data.choices?.[0]?.message;\n content = message?.content?.trim() || \"{}\";\n inputTokens = data.usage?.prompt_tokens;\n outputTokens = data.usage?.completion_tokens;\n\n // Try different cost fields that OpenRouter might use\n costUSD = data.usage?.total_cost ?? data.usage?.cost;\n\n // Extract reasoning fields if present\n const reasoning = message?.reasoning;\n const reasoning_details = message?.reasoning_details;\n\n // Clean up markdown code blocks if present\n content = content.replace(/^```json\\s*\\n?/,'').replace(/\\n?```\\s*$/,'').trim();\n\n const parsed = safeJsonParse(content) as T;\n\n // Extract base provider from model for metrics\n const baseProvider = extractProviderFromModel(this.config.model, 'google');\n\n return {\n json: parsed as T,\n rawText: content,\n metrics: {\n costUSD,\n inputTokens,\n outputTokens,\n latencyMs,\n attemptNumber: 1,\n provider: baseProvider, // Base provider (e.g., \"google\" from \"google/gemini-...\")\n model: this.config.model\n },\n reasoning,\n reasoning_details\n };\n } else {\n // Native Google format\n const candidate = data.candidates?.[0];\n content = candidate?.content?.parts?.[0]?.text?.trim() || \"{}\";\n inputTokens = data.usageMetadata?.promptTokenCount;\n outputTokens = data.usageMetadata?.candidatesTokenCount;\n costUSD = this.calculateCost(data.usageMetadata);\n\n // Extract thinking content if present (native API)\n const thinkingPart = candidate?.content?.parts?.find((part: GeminiPart) => part.thought === true);\n const reasoning = thinkingPart?.text;\n\n const parsed = safeJsonParse(content) as T;\n\n // Extract base provider from model for metrics\n const baseProvider = extractProviderFromModel(this.config.model, 'google');\n\n return {\n json: parsed as T,\n rawText: content,\n metrics: {\n costUSD,\n inputTokens,\n outputTokens,\n latencyMs,\n attemptNumber: 1,\n provider: baseProvider, // Base provider (e.g., \"google\" from \"google/gemini-...\")\n model: this.config.model\n },\n reasoning,\n reasoning_details: reasoning ? [{\n type: 'reasoning.text' as const,\n text: reasoning,\n signature: null,\n id: 'thinking-1',\n format: 'google-gemini-v1'\n }] : undefined\n };\n }\n }\n\n private buildNativeThinkingConfig(reasoning: ReasoningConfig, max_tokens?: number): GeminiGenerationConfig['thinking_config'] | undefined {\n // Native Google uses \"thinking_budget\" parameter\n if (!reasoning.effort && !reasoning.enabled) {\n return undefined;\n }\n\n const effort = reasoning.effort || 'medium';\n const requestMaxTokens = max_tokens || 8192;\n\n // Convert effort to thinking_budget\n // Gemini 2.5 Flash supports 0-24576 tokens, default auto max is 8192\n const effortRatios = { low: 0.2, medium: 0.5, high: 0.8 };\n const ratio = effortRatios[effort];\n const thinking_budget = Math.min(24576, Math.floor(requestMaxTokens * ratio));\n\n return {\n thinking_budget\n };\n }\n\n private translateToOpenRouterFormat(\n contents: GeminiContent[],\n mode: JsonMode,\n max_tokens?: number,\n reasoning?: ReasoningConfig\n ): OpenRouterRequest {\n // Convert Gemini contents format to OpenAI messages format\n const messages: OpenRouterMessage[] = [];\n\n for (const content of contents) {\n if (content.role === 'user') {\n const messageContent: OpenRouterContentPart[] = [];\n\n for (const part of content.parts) {\n if (!part) continue; // Skip undefined/null parts\n if (part.text) {\n messageContent.push({ type: 'text', text: part.text });\n } else if (part.inlineData) {\n // Check if it's a PDF or image based on MIME type\n if (part.inlineData.mimeType === 'application/pdf') {\n // PDF - use file format\n messageContent.push({\n type: 'file',\n file: {\n filename: 'document.pdf',\n file_data: `data:${part.inlineData.mimeType};base64,${part.inlineData.data}`\n }\n });\n } else {\n // Image - use image_url format\n messageContent.push({\n type: 'image_url',\n image_url: {\n url: `data:${part.inlineData.mimeType};base64,${part.inlineData.data}`\n }\n });\n }\n }\n }\n\n messages.push({\n role: 'user',\n content: messageContent.length === 1 && messageContent[0].type === 'text'\n ? messageContent[0].text\n : messageContent\n });\n }\n }\n\n const requestBody: OpenRouterRequest = {\n model: this.config.model,\n messages,\n // Enable usage tracking for OpenRouter cost info\n usage: {\n include: true\n },\n // Both relaxed and strict modes use json_object for Google via OpenRouter\n // Schema is already in the prompt via combineSchemaAndUserPrompt\n response_format: {\n type: 'json_object'\n }\n };\n\n // Add reasoning configuration if provided (Google uses max_tokens like Anthropic)\n if (reasoning) {\n requestBody.reasoning = this.buildReasoningConfig(reasoning, max_tokens);\n }\n\n return requestBody;\n }\n\n private buildReasoningConfig(reasoning: ReasoningConfig, max_tokens?: number): OpenRouterReasoningConfig | undefined {\n const config: OpenRouterReasoningConfig = {};\n\n // Google uses max_tokens - convert effort to max_tokens\n if (reasoning.effort || reasoning.enabled) {\n const effort = reasoning.effort || 'medium';\n const requestMaxTokens = max_tokens || 8192; // Default for Gemini\n\n // Convert effort to percentage of max_tokens\n const effortRatios = { low: 0.2, medium: 0.5, high: 0.8 };\n const ratio = effortRatios[effort];\n\n // Calculate reasoning budget\n const reasoningBudget = Math.floor(requestMaxTokens * ratio);\n config.max_tokens = reasoningBudget;\n }\n\n // Add exclude flag if specified\n if (reasoning.exclude !== undefined) {\n config.exclude = reasoning.exclude;\n }\n\n return Object.keys(config).length > 0 ? config : undefined;\n }\n\n private async buildContents(input: MultimodalInput): Promise<GeminiContent[]> {\n const parts: GeminiPart[] = [];\n\n // Add text\n if (input.text) {\n parts.push({ text: input.text });\n }\n\n // Add images\n if (input.images && input.images.length > 0) {\n for (const image of input.images) {\n if (image.url) {\n const base64 = await this.urlToBase64(image.url);\n parts.push({\n inlineData: {\n mimeType: image.mimeType,\n data: base64\n }\n });\n } else if (image.base64) {\n parts.push({\n inlineData: {\n mimeType: image.mimeType,\n data: this.extractBase64(image.base64)\n }\n });\n }\n }\n }\n\n // Add PDFs (treated as images, 1 page = 1 image)\n if (input.pdfs && input.pdfs.length > 0) {\n for (const pdf of input.pdfs) {\n if (pdf.fileId) {\n // Use File API reference\n parts.push({\n fileData: {\n fileUri: `https://generativelanguage.googleapis.com/v1beta/files/${pdf.fileId}`,\n mimeType: \"application/pdf\"\n }\n });\n } else if (pdf.base64) {\n parts.push({\n inlineData: {\n mimeType: \"application/pdf\",\n data: this.extractBase64(pdf.base64)\n }\n });\n } else if (pdf.url) {\n const base64 = await this.urlToBase64(pdf.url);\n parts.push({\n inlineData: {\n mimeType: \"application/pdf\",\n data: base64\n }\n });\n }\n }\n }\n\n return [{ role: \"user\", parts }];\n }\n\n private async urlToBase64(url: string): Promise<string> {\n // Validate URL for SSRF attacks\n validateUrl(url);\n\n // Fetch with timeout protection (using instance-configured timeout)\n const response = await fetchWithTimeout(url, {}, this.limits.REQUEST_TIMEOUT);\n if (!response.ok) {\n throw new Error(`Failed to fetch URL: ${url}`);\n }\n const buffer = await response.arrayBuffer();\n return Buffer.from(buffer).toString('base64');\n }\n\n /**\n * Extract base64 data from a data URL or return as-is if already raw base64\n */\n private extractBase64(input: string): string {\n if (input.startsWith('data:')) {\n // Extract base64 part from data URL: data:image/jpeg;base64,XXXXX -> XXXXX\n const base64Part = input.split(',')[1];\n if (!base64Part) {\n throw new Error(`Invalid data URL format: ${input.substring(0, 50)}`);\n }\n return base64Part;\n }\n return input;\n }\n\n private calculateCost(usage: any): number | undefined {\n if (!usage) return undefined;\n\n // Approximate costs for Gemini 2.5 Flash (as of 2025)\n const inputCostPer1k = 0.00025; // $0.00025 per 1K input tokens\n const outputCostPer1k = 0.001; // $0.001 per 1K output tokens\n\n const inputCost = (usage.promptTokenCount / 1000) * inputCostPer1k;\n const outputCost = (usage.candidatesTokenCount / 1000) * outputCostPer1k;\n\n return inputCost + outputCost;\n }\n}\n","import type {\n LLMProvider,\n ProviderConfig,\n MultimodalInput,\n UnifiedSchema,\n LLMResponse,\n ProviderCapabilities,\n ResourceLimits\n} from \"../types\";\nimport { SchemaTranslator } from \"../schema-translator\";\nimport { combineSchemaAndUserPrompt } from \"../schema-prompt-formatter\";\nimport { fetchWithTimeout, DEFAULT_LIMITS, safeJsonParse } from \"@doclo/core/security\";\n\n/**\n * Extract base provider name from model identifier.\n * For OpenRouter models like \"x-ai/grok-...\", extracts \"x-ai\".\n * For direct models like \"grok-...\", returns the default provider.\n */\nfunction extractProviderFromModel(model: string, defaultProvider: string): string {\n const slashIndex = model.indexOf('/');\n return slashIndex > 0 ? model.substring(0, slashIndex) : defaultProvider;\n}\n\nexport class XAIProvider implements LLMProvider {\n readonly name: string;\n readonly capabilities: ProviderCapabilities = {\n supportsStructuredOutput: true,\n supportsStreaming: false, // Not with structured outputs\n supportsImages: true,\n supportsPDFs: true, // via page-by-page images\n maxPDFPages: undefined,\n maxPDFSize: undefined,\n maxContextTokens: 131072\n };\n\n private config: ProviderConfig;\n private translator: SchemaTranslator;\n private limits: typeof DEFAULT_LIMITS;\n\n constructor(config: ProviderConfig) {\n this.config = config;\n // Extract base provider from model if it's an OpenRouter model (e.g., \"x-ai/grok-...\")\n const baseProvider = extractProviderFromModel(config.model, 'xai');\n this.name = `${baseProvider}:${config.model}`;\n this.translator = new SchemaTranslator();\n\n // Merge custom limits with defaults\n this.limits = {\n ...DEFAULT_LIMITS,\n ...(config.limits || {})\n };\n }\n\n async completeJson<T>(params: {\n input: MultimodalInput;\n schema?: UnifiedSchema<T>;\n mode?: import(\"../types\").JsonMode;\n max_tokens?: number;\n reasoning?: import(\"../types\").ReasoningConfig;\n embedSchemaInPrompt?: boolean;\n }): Promise<LLMResponse<T>> {\n const startTime = Date.now();\n\n // Determine mode: default to 'strict', auto-relaxed if schema omitted\n const mode = params.mode || (params.schema ? 'strict' : 'relaxed');\n\n // Validate: strict mode requires schema\n if (mode === 'strict' && !params.schema) {\n throw new Error('schema is required when mode is \"strict\"');\n }\n\n // Embed schema in prompt if enabled (default: true) and schema exists\n const shouldEmbedSchema = params.embedSchemaInPrompt !== false && params.schema;\n let enhancedInput = params.input;\n\n if (shouldEmbedSchema) {\n // Convert schema to JSON Schema format\n const jsonSchema = this.translator.convertZodIfNeeded(params.schema!);\n\n // Combine schema prompt with user's text\n const enhancedText = combineSchemaAndUserPrompt(\n jsonSchema,\n params.input.text || ''\n );\n\n enhancedInput = {\n ...params.input,\n text: enhancedText\n };\n }\n\n // Build messages with multimodal content (using enhanced input)\n const messages = await this.buildMessages(enhancedInput);\n\n // Build request body\n const requestBody: any = {\n model: this.config.model,\n messages,\n max_tokens: params.max_tokens || 4096,\n stream: false, // Structured output doesn't support streaming\n // Enable usage tracking for OpenRouter cost info\n usage: {\n include: true\n }\n };\n\n if (mode === 'relaxed') {\n // Relaxed mode: just request valid JSON without strict schema\n requestBody.response_format = {\n type: \"json_object\"\n };\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[XAIProvider] Using relaxed JSON mode (json_object)');\n }\n } else {\n // Strict mode: use json_schema with strict validation\n const schema = this.translator.toOpenAISchema(params.schema!);\n\n // Recursively fix schema for strict mode requirements\n const fixSchemaRecursive = (obj: any): any => {\n if (obj && typeof obj === 'object') {\n if (obj.type === 'object' && obj.properties) {\n const allProps = Object.keys(obj.properties);\n obj.required = allProps;\n obj.additionalProperties = false;\n\n // Recursively fix nested properties\n for (const key in obj.properties) {\n obj.properties[key] = fixSchemaRecursive(obj.properties[key]);\n }\n } else if (obj.type === 'array' && obj.items) {\n // Recursively fix array items schema\n obj.items = fixSchemaRecursive(obj.items);\n }\n }\n return obj;\n };\n fixSchemaRecursive(schema);\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[XAIProvider] Using strict JSON mode (json_schema)');\n }\n\n requestBody.response_format = {\n type: \"json_schema\",\n json_schema: {\n name: \"extraction\",\n schema\n }\n };\n }\n\n // Add reasoning configuration if provided (xAI uses effort like OpenAI)\n if (params.reasoning) {\n requestBody.reasoning = this.buildReasoningConfig(params.reasoning);\n }\n\n // Add OpenRouter model filtering for strict mode\n if (this.config.via === 'openrouter' && mode === 'strict') {\n requestBody.provider = {\n require_parameters: true // Only route to models supporting json_schema\n };\n }\n\n // Make API call - check if using OpenRouter\n const endpoint = this.config.via === 'openrouter'\n ? \"https://openrouter.ai/api/v1\"\n : (this.config.baseUrl || \"https://api.x.ai/v1\");\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.config.apiKey}`\n };\n\n // Add OpenRouter-specific headers\n if (this.config.via === 'openrouter') {\n headers[\"HTTP-Referer\"] = \"https://github.com/docloai/sdk\";\n headers[\"X-Title\"] = \"Doclo SDK\";\n }\n\n const response = await fetchWithTimeout(`${endpoint}/chat/completions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(requestBody)\n }, this.limits.REQUEST_TIMEOUT);\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`xAI API error (${response.status}): ${error}`);\n }\n\n const data = await response.json();\n const latencyMs = Date.now() - startTime;\n\n // Parse response\n const message = data.choices?.[0]?.message;\n const content = message?.content ?? \"{}\";\n const parsed = safeJsonParse(content) as T;\n\n // Extract reasoning fields if present\n const reasoning = message?.reasoning;\n const reasoning_details = message?.reasoning_details;\n\n // Extract cost from OpenRouter or calculate locally\n let costUSD: number | undefined;\n if (this.config.via === 'openrouter') {\n // Read cost from OpenRouter response (more accurate than local calculation)\n costUSD = data.usage?.total_cost ?? data.usage?.cost;\n } else {\n // Calculate cost locally for native xAI API\n costUSD = this.calculateCost(data.usage);\n }\n\n // Extract base provider from model for metrics\n const baseProvider = extractProviderFromModel(this.config.model, 'xai');\n\n return {\n json: parsed as T,\n rawText: content,\n metrics: {\n costUSD,\n inputTokens: data.usage?.prompt_tokens,\n outputTokens: data.usage?.completion_tokens,\n latencyMs,\n attemptNumber: 1,\n provider: baseProvider, // Base provider (e.g., \"x-ai\" from \"x-ai/grok-...\")\n model: this.config.model\n },\n reasoning,\n reasoning_details\n };\n }\n\n private buildReasoningConfig(reasoning: import(\"../types\").ReasoningConfig): any {\n const config: any = {};\n\n // xAI uses effort directly (like OpenAI)\n if (reasoning.effort) {\n config.effort = reasoning.effort;\n } else if (reasoning.enabled) {\n config.effort = 'medium'; // Default to medium\n }\n\n // Add exclude flag if specified\n if (reasoning.exclude !== undefined) {\n config.exclude = reasoning.exclude;\n }\n\n return Object.keys(config).length > 0 ? config : undefined;\n }\n\n private async buildMessages(input: MultimodalInput): Promise<any[]> {\n const content: any[] = [];\n\n // Add text\n if (input.text) {\n content.push({ type: \"text\", text: input.text });\n }\n\n // Add images\n if (input.images && input.images.length > 0) {\n for (const image of input.images) {\n if (image.url) {\n content.push({\n type: \"image_url\",\n image_url: { url: image.url }\n });\n } else if (image.base64) {\n content.push({\n type: \"image_url\",\n image_url: {\n url: `data:${image.mimeType};base64,${this.extractBase64(image.base64)}`\n }\n });\n }\n }\n }\n\n // Add PDFs - OpenRouter requires type: \"file\" format\n if (input.pdfs && input.pdfs.length > 0) {\n for (const pdf of input.pdfs) {\n let fileData: string;\n if (pdf.url) {\n fileData = pdf.url;\n } else if (pdf.base64) {\n fileData = `data:application/pdf;base64,${this.extractBase64(pdf.base64)}`;\n } else {\n continue;\n }\n\n content.push({\n type: \"file\",\n file: {\n filename: \"document.pdf\",\n file_data: fileData\n }\n });\n }\n }\n\n return [{ role: \"user\", content }];\n }\n\n /**\n * Extract base64 data from a data URL or return as-is if already raw base64\n */\n private extractBase64(input: string): string {\n if (input.startsWith('data:')) {\n // Extract base64 part from data URL: data:image/jpeg;base64,XXXXX -> XXXXX\n const base64Part = input.split(',')[1];\n if (!base64Part) {\n throw new Error(`Invalid data URL format: ${input.substring(0, 50)}`);\n }\n return base64Part;\n }\n return input;\n }\n\n private calculateCost(usage: any): number | undefined {\n if (!usage) return undefined;\n\n // Approximate costs for Grok (as of 2025)\n const inputCostPer1k = 0.005; // $0.005 per 1K input tokens\n const outputCostPer1k = 0.015; // $0.015 per 1K output tokens\n\n const inputCost = (usage.prompt_tokens / 1000) * inputCostPer1k;\n const outputCost = (usage.completion_tokens / 1000) * outputCostPer1k;\n\n return inputCost + outputCost;\n }\n}\n","import type {\n FallbackConfig,\n LLMProvider,\n MultimodalInput,\n UnifiedSchema,\n LLMResponse,\n CircuitBreakerState,\n JsonMode,\n ProviderConfig,\n ReasoningConfig\n} from \"./types\";\nimport { createProviderFromRegistry } from \"./provider-registry\";\nimport type {\n ObservabilityConfig,\n ProviderRequestContext,\n ProviderResponseContext,\n ProviderRetryContext,\n CircuitBreakerContext,\n TraceContext,\n} from \"@doclo/core/observability\";\nimport {\n executeHook,\n generateSpanId,\n createLogger,\n} from \"@doclo/core/observability\";\n\nexport class FallbackManager {\n private config: FallbackConfig;\n private circuitBreakers: Map<string, CircuitBreakerState>;\n\n constructor(config: FallbackConfig) {\n this.config = config;\n this.circuitBreakers = new Map();\n }\n\n async executeWithFallback<T>(\n input: MultimodalInput,\n schema: UnifiedSchema<T>,\n max_tokens?: number,\n reasoning?: ReasoningConfig,\n mode?: JsonMode,\n observability?: {\n config?: ObservabilityConfig;\n flowId?: string;\n executionId?: string;\n stepId?: string;\n traceContext?: TraceContext;\n metadata?: Record<string, unknown>;\n }\n ): Promise<LLMResponse<T>> {\n const errors: Array<{ provider: string; error: Error }> = [];\n\n // Create logger for this execution\n const logger = createLogger({\n observability: observability?.config,\n flowId: observability?.flowId,\n executionId: observability?.executionId,\n stepId: observability?.stepId,\n traceContext: observability?.traceContext,\n metadata: observability?.metadata,\n });\n\n for (const [providerIndex, providerConfig] of this.config.providers.entries()) {\n const providerKey = `${providerConfig.provider}:${providerConfig.model}`;\n\n // Check circuit breaker\n if (this.isCircuitOpen(providerKey)) {\n logger.warn(`Circuit breaker open for ${providerKey}, skipping`);\n\n // onCircuitBreakerTriggered hook\n if (observability?.config && observability.traceContext && observability.executionId) {\n const cbState = this.circuitBreakers.get(providerKey);\n const circuitBreakerContext: CircuitBreakerContext = {\n flowId: observability.flowId ?? 'flow',\n executionId: observability.executionId,\n timestamp: Date.now(),\n provider: providerConfig.provider,\n model: providerConfig.model,\n failureCount: cbState?.consecutiveFailures ?? 0,\n threshold: this.config.circuitBreakerThreshold ?? 5,\n cooldownMs: 60000, // Default cooldown\n metadata: observability.metadata,\n traceContext: observability.traceContext,\n };\n await executeHook(observability.config.onCircuitBreakerTriggered, {\n hookName: 'onCircuitBreakerTriggered',\n config: observability.config,\n context: circuitBreakerContext,\n });\n }\n\n continue;\n }\n\n // Create provider instance\n const provider = this.createProvider(providerConfig);\n\n // Primary (index 0) uses primaryMaxRetries, fallbacks use maxRetries\n const maxRetriesForProvider = providerIndex === 0\n ? (this.config.primaryMaxRetries ?? this.config.maxRetries)\n : this.config.maxRetries;\n\n // Try with retries\n let lastError: Error | null = null;\n for (let attempt = 1; attempt <= maxRetriesForProvider; attempt++) {\n try {\n logger.info(`Attempting ${providerKey} (attempt ${attempt}/${maxRetriesForProvider})`);\n\n const requestStartTime = Date.now();\n\n // onProviderRequest hook\n if (observability?.config && observability.traceContext && observability.executionId) {\n const providerRequestContext: ProviderRequestContext = {\n flowId: observability.flowId ?? 'flow',\n executionId: observability.executionId,\n stepId: observability.stepId,\n timestamp: requestStartTime,\n provider: providerConfig.provider,\n model: providerConfig.model,\n input: input,\n schema: schema,\n attemptNumber: attempt,\n maxAttempts: maxRetriesForProvider,\n metadata: observability.metadata,\n traceContext: observability.traceContext,\n };\n await executeHook(observability.config.onProviderRequest, {\n hookName: 'onProviderRequest',\n config: observability.config,\n context: providerRequestContext,\n });\n }\n\n const response = await provider.completeJson({ input, schema, max_tokens, reasoning, mode });\n\n // Success! Validate and return\n if (this.validateResponse(response)) {\n this.recordSuccess(providerKey);\n\n // onProviderResponse hook\n if (observability?.config && observability.traceContext && observability.executionId) {\n const providerResponseContext: ProviderResponseContext = {\n flowId: observability.flowId ?? 'flow',\n executionId: observability.executionId,\n stepId: observability.stepId,\n timestamp: Date.now(),\n startTime: requestStartTime,\n duration: Date.now() - requestStartTime,\n provider: providerConfig.provider,\n model: providerConfig.model,\n modelUsed: response.metrics.model,\n output: response.json,\n usage: {\n inputTokens: response.metrics.inputTokens ?? 0,\n outputTokens: response.metrics.outputTokens ?? 0,\n totalTokens: (response.metrics.inputTokens ?? 0) + (response.metrics.outputTokens ?? 0),\n cacheCreationInputTokens: response.metrics.cacheCreationInputTokens,\n cacheReadInputTokens: response.metrics.cacheReadInputTokens,\n },\n cost: response.metrics.costUSD ?? 0,\n finishReason: response.metrics.finishReason,\n attemptNumber: attempt,\n metadata: observability.metadata,\n traceContext: observability.traceContext,\n };\n await executeHook(observability.config.onProviderResponse, {\n hookName: 'onProviderResponse',\n config: observability.config,\n context: providerResponseContext,\n });\n }\n\n return {\n ...response,\n metrics: {\n ...response.metrics,\n attemptNumber: attempt\n }\n };\n } else {\n throw new Error(\"Response validation failed: incomplete or invalid data\");\n }\n } catch (error) {\n lastError = error as Error;\n logger.error(`${providerKey} attempt ${attempt} failed`, lastError, { providerKey, attempt });\n\n // Check if retryable\n if (!this.isRetryable(lastError) || attempt === maxRetriesForProvider) {\n break;\n }\n\n const retryDelay = this.calculateDelay(attempt);\n\n // onProviderRetry hook\n if (observability?.config && observability.traceContext && observability.executionId) {\n const providerRetryContext: ProviderRetryContext = {\n flowId: observability.flowId ?? 'flow',\n executionId: observability.executionId,\n stepId: observability.stepId,\n timestamp: Date.now(),\n provider: providerConfig.provider,\n model: providerConfig.model,\n attemptNumber: attempt,\n maxAttempts: maxRetriesForProvider,\n error: lastError,\n nextRetryDelay: retryDelay,\n metadata: observability.metadata,\n traceContext: observability.traceContext,\n };\n await executeHook(observability.config.onProviderRetry, {\n hookName: 'onProviderRetry',\n config: observability.config,\n context: providerRetryContext,\n });\n }\n\n // Wait before retry with exponential backoff + jitter\n await this.sleep(retryDelay);\n }\n }\n\n // All retries failed for this provider\n if (lastError) {\n errors.push({ provider: providerKey, error: lastError });\n this.recordFailure(providerKey);\n }\n }\n\n // All providers exhausted\n throw new Error(\n `All providers failed:\\n${errors.map(e => ` ${e.provider}: ${e.error.message}`).join('\\n')}`\n );\n }\n\n private createProvider(config: ProviderConfig): LLMProvider {\n return createProviderFromRegistry(config);\n }\n\n private validateResponse(response: LLMResponse): boolean {\n // Check if response has valid JSON\n if (!response.json || typeof response.json !== 'object') {\n return false;\n }\n\n // Empty objects are valid - the schema determines if they're acceptable\n // Models may return {} when no data matches the extraction criteria\n return true;\n }\n\n private isRetryable(error: Error): boolean {\n const message = error.message.toLowerCase();\n\n // Retryable status codes\n const retryablePatterns = [\n '408', '429', '500', '502', '503', '504',\n 'timeout', 'rate limit', 'overloaded'\n ];\n\n return retryablePatterns.some(pattern =>\n message.includes(pattern)\n );\n }\n\n private calculateDelay(attempt: number): number {\n if (!this.config.useExponentialBackoff) {\n return this.config.retryDelay;\n }\n\n // Exponential backoff: baseDelay * (2 ^ attempt) + jitter\n const exponentialDelay = this.config.retryDelay * Math.pow(2, attempt - 1);\n const jitter = Math.random() * 1000; // 0-1000ms jitter\n return Math.min(exponentialDelay + jitter, 30000); // Max 30s\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n // Circuit breaker logic\n private isCircuitOpen(providerKey: string): boolean {\n const state = this.circuitBreakers.get(providerKey);\n if (!state || !state.isOpen) return false;\n\n // Check if enough time has passed to try again (30 seconds)\n if (state.lastFailureTime && Date.now() - state.lastFailureTime > 30000) {\n this.circuitBreakers.set(providerKey, {\n consecutiveFailures: 0,\n isOpen: false\n });\n return false;\n }\n\n return true;\n }\n\n private recordSuccess(providerKey: string): void {\n this.circuitBreakers.set(providerKey, {\n consecutiveFailures: 0,\n isOpen: false\n });\n }\n\n private recordFailure(providerKey: string): void {\n const state = this.circuitBreakers.get(providerKey) || {\n consecutiveFailures: 0,\n isOpen: false\n };\n\n state.consecutiveFailures++;\n state.lastFailureTime = Date.now();\n\n // Open circuit if threshold reached\n const threshold = this.config.circuitBreakerThreshold || 3;\n if (state.consecutiveFailures >= threshold) {\n state.isOpen = true;\n // Use console.warn here as we don't have observability context in this method\n console.warn(`Circuit breaker opened for ${providerKey} after ${state.consecutiveFailures} failures`);\n }\n\n this.circuitBreakers.set(providerKey, state);\n }\n}\n","import type { LLMJsonProvider as CoreLLMProvider, MultimodalInput as CoreMultimodalInput } from \"@doclo/core\";\nimport type { LLMProvider, MultimodalInput } from \"./types\";\n\n/**\n * Adapter to make new LLMProvider compatible with core LLMJsonProvider interface\n */\nexport function adaptToCoreLLMProvider(provider: LLMProvider): CoreLLMProvider {\n return {\n name: provider.name,\n capabilities: {\n supportsImages: true,\n supportsPDFs: provider.capabilities.supportsPDFs,\n maxPDFPages: provider.capabilities.maxPDFPages\n },\n async completeJson(input: {\n prompt: string | CoreMultimodalInput;\n schema: object;\n max_tokens?: number;\n reasoning?: import(\"./types\").ReasoningConfig;\n }) {\n // Convert input to MultimodalInput format\n let multimodalInput: MultimodalInput;\n\n if (typeof input.prompt === 'string') {\n // Simple string prompt\n multimodalInput = { text: input.prompt };\n } else {\n // Already multimodal\n multimodalInput = input.prompt as MultimodalInput;\n }\n\n // Call the new provider with reasoning parameters\n const response = await provider.completeJson({\n input: multimodalInput,\n schema: input.schema as any,\n max_tokens: input.max_tokens,\n reasoning: input.reasoning\n });\n\n // Convert response to core format (including reasoning fields and cache metrics)\n return {\n json: response.json,\n rawText: response.rawText,\n costUSD: response.metrics.costUSD,\n inputTokens: response.metrics.inputTokens,\n outputTokens: response.metrics.outputTokens,\n cacheCreationInputTokens: response.metrics.cacheCreationInputTokens,\n cacheReadInputTokens: response.metrics.cacheReadInputTokens\n };\n }\n };\n}\n","/**\n * LLM Provider Metadata\n *\n * Comprehensive metadata for all LLM/VLM providers including:\n * - Supported file types (inline/base64 encoded)\n * - Input/output formats\n * - Pricing\n * - Capabilities\n * - Native API vs OpenRouter differences\n */\n\n// Supported image MIME types (common across providers)\nexport const SUPPORTED_IMAGE_TYPES = {\n COMMON: ['image/png', 'image/jpeg', 'image/webp', 'image/gif'] as const,\n EXTENDED: ['image/png', 'image/jpeg', 'image/webp', 'image/gif', 'image/bmp', 'image/tiff', 'image/heif'] as const\n} as const;\n\n/**\n * Input type requirements for providers.\n * - 'raw-document': Needs FlowInput with base64/url\n * - 'parsed-text': Needs DocumentIR text output\n * - 'any': Can work with either (LLM providers with vision)\n */\nexport type ProviderInputType = 'raw-document' | 'parsed-text' | 'any';\n\n/**\n * Model-level metadata for per-model capability overrides\n */\nexport type LLMModelMetadata = {\n /** Model ID as used in API calls */\n id: string;\n\n /** Human-readable name */\n name?: string;\n\n /** OpenRouter model ID (e.g., 'openai/gpt-4.1') */\n openRouterId: string;\n\n /** Capability overrides (inherit from provider if unset) */\n capabilities?: {\n supportsReasoning?: boolean;\n supportsImages?: boolean;\n supportsPDFs?: boolean;\n supportsStructuredOutput?: boolean;\n };\n\n /** Model-specific limits */\n limits?: {\n maxContextTokens?: number;\n maxOutputTokens?: number;\n };\n\n /** Model-specific pricing (USD per 1k tokens) */\n pricing?: {\n inputPer1k?: number;\n outputPer1k?: number;\n };\n};\n\n// Provider metadata type\nexport type LLMProviderMetadata = {\n id: string;\n name: string;\n vendor: 'openai' | 'anthropic' | 'google' | 'xai';\n models: string[]; // Legacy: list of model IDs\n /**\n * Detailed per-model metadata with capability overrides.\n * Use this for model-specific reasoning, pricing, and limits.\n */\n detailedModels?: LLMModelMetadata[];\n accessMethods: {\n native: {\n available: boolean;\n endpoint: string;\n requiresApiKey: boolean;\n };\n openrouter: {\n available: boolean;\n modelPrefix: string; // e.g., 'openai/', 'anthropic/'\n };\n };\n capabilities: {\n supportsImages: boolean;\n supportsPDFs: boolean;\n supportsReasoning: boolean;\n supportsStreaming: boolean;\n supportsStructuredOutput: boolean;\n };\n /**\n * Input requirements for this provider.\n * LLM providers with vision can accept either raw documents OR parsed text.\n */\n inputRequirements?: {\n inputType: ProviderInputType;\n acceptedMethods?: readonly ('url' | 'base64')[];\n };\n compatibleNodes: {\n parse: boolean; // Can be used in parse() node\n extract: boolean; // Can be used in extract() node\n categorize: boolean; // Can be used in categorize() node\n qualify: boolean; // Can be used in qualify() node\n split: boolean; // Can be used in split() node\n };\n inputFormats: {\n images: {\n mimeTypes: readonly string[];\n methods: ('url' | 'base64')[];\n maxSize?: number; // MB\n maxDimensions?: { width: number; height: number };\n notes?: string;\n };\n pdfs: {\n supported: boolean;\n methods: ('url' | 'base64' | 'fileId')[];\n maxSize?: number; // MB\n maxPages?: number;\n notes?: string;\n };\n };\n outputFormat: {\n supportsJSON: boolean;\n supportsReasoning: boolean;\n tokenTracking: boolean;\n costTracking: boolean;\n };\n pricing: {\n model: 'per-token';\n inputPer1k: number; // USD - used for native API cost calculation\n outputPer1k: number; // USD - used for native API cost calculation\n currency: 'USD';\n notes?: string; // OpenRouter returns cost; native APIs require calculation\n };\n limits: {\n maxContextTokens: number;\n maxOutputTokens?: number;\n requestsPerMinute?: number;\n };\n nativeAPI: {\n imageFormat: string; // e.g., 'type: image, source: base64'\n pdfFormat: string; // e.g., 'type: document, source: base64'\n reasoningConfig: string; // e.g., 'thinking: { type: enabled }'\n };\n openRouterAPI: {\n imageFormat: string; // e.g., 'type: image_url'\n pdfFormat: string; // e.g., 'type: file'\n reasoningConfig: string; // e.g., 'reasoning: { max_tokens }'\n differences: string[]; // Key differences from native\n };\n};\n\n// Provider metadata\nexport const PROVIDER_METADATA = {\n openai: {\n id: 'openai',\n name: 'OpenAI',\n vendor: 'openai',\n models: ['gpt-5.1', 'gpt-4.1', 'gpt-4.1-mini', 'o3', 'o3-mini', 'o4-mini'],\n detailedModels: [\n {\n id: 'gpt-4.1',\n name: 'GPT-4.1',\n openRouterId: 'openai/gpt-4.1',\n capabilities: { supportsReasoning: false },\n limits: { maxContextTokens: 128000, maxOutputTokens: 16384 },\n pricing: { inputPer1k: 0.002, outputPer1k: 0.008 },\n },\n {\n id: 'gpt-4.1-mini',\n name: 'GPT-4.1 Mini',\n openRouterId: 'openai/gpt-4.1-mini',\n capabilities: { supportsReasoning: false },\n limits: { maxContextTokens: 128000, maxOutputTokens: 16384 },\n pricing: { inputPer1k: 0.0004, outputPer1k: 0.0016 },\n },\n {\n id: 'o3',\n name: 'o3',\n openRouterId: 'openai/o3',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 100000 },\n pricing: { inputPer1k: 0.010, outputPer1k: 0.040 },\n },\n {\n id: 'o3-mini',\n name: 'o3-mini',\n openRouterId: 'openai/o3-mini',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 100000 },\n pricing: { inputPer1k: 0.0011, outputPer1k: 0.0044 },\n },\n {\n id: 'o4-mini',\n name: 'o4-mini',\n openRouterId: 'openai/o4-mini',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 100000 },\n pricing: { inputPer1k: 0.0011, outputPer1k: 0.0044 },\n },\n {\n id: 'gpt-5.1',\n name: 'GPT-5.1',\n openRouterId: 'openai/gpt-5.1',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 256000, maxOutputTokens: 32768 },\n pricing: { inputPer1k: 0.005, outputPer1k: 0.015 },\n },\n ],\n accessMethods: {\n native: {\n available: true,\n endpoint: 'https://api.openai.com/v1',\n requiresApiKey: true\n },\n openrouter: {\n available: true,\n modelPrefix: 'openai/'\n }\n },\n capabilities: {\n supportsImages: true,\n supportsPDFs: true,\n supportsReasoning: true,\n supportsStreaming: true,\n supportsStructuredOutput: true\n },\n // LLM with vision - can work with raw documents OR parsed text\n inputRequirements: {\n inputType: 'any',\n acceptedMethods: ['url', 'base64']\n },\n compatibleNodes: {\n parse: true, // ✅ VLMProvider - can convert images/PDFs to text\n extract: true, // ✅ VLMProvider - can extract structured data\n categorize: true, // ✅ VLMProvider - can classify documents\n qualify: true, // ✅ VLMProvider - can assess quality\n split: true // ✅ VLMProvider - can detect document boundaries\n },\n inputFormats: {\n images: {\n mimeTypes: SUPPORTED_IMAGE_TYPES.COMMON,\n methods: ['url', 'base64'],\n maxSize: 20, // 20 MB per image\n maxDimensions: undefined, // Images resized server-side\n notes: 'Inline via image_url with data URL or HTTP URL. Large images auto-resized.'\n },\n pdfs: {\n supported: true,\n methods: ['base64', 'fileId'],\n maxSize: 50, // 50 MB per file, 50 MB total per request\n maxPages: 100,\n notes: 'Inline via type: file with base64, or via Files API. Extracts text + images of each page. File URLs NOT supported for chat completions.'\n }\n },\n outputFormat: {\n supportsJSON: true,\n supportsReasoning: true,\n tokenTracking: true,\n costTracking: true\n },\n pricing: {\n model: 'per-token',\n inputPer1k: 0.005,\n outputPer1k: 0.015,\n currency: 'USD',\n notes: 'Cost calculated from tokens. OpenRouter may include cost in response. GPT-4.1 baseline.'\n },\n limits: {\n maxContextTokens: 128000,\n maxOutputTokens: 16384,\n requestsPerMinute: undefined\n },\n nativeAPI: {\n imageFormat: 'type: \"image_url\", image_url: { url: \"data:image/jpeg;base64,...\" }',\n pdfFormat: 'type: \"file\", file: { file_id: \"...\" } OR file: { filename: \"...\", file_data: \"data:application/pdf;base64,...\" }',\n reasoningConfig: 'reasoning: { effort: \"low\"|\"medium\"|\"high\", exclude?: boolean }'\n },\n openRouterAPI: {\n imageFormat: 'Same as native (OpenAI-compatible)',\n pdfFormat: 'Same as native (OpenAI-compatible)',\n reasoningConfig: 'Same as native (OpenAI-compatible)',\n differences: [\n 'File URLs not supported (base64 only)',\n 'Cost may be available via usage.total_cost or generation endpoint'\n ]\n }\n },\n\n anthropic: {\n id: 'anthropic',\n name: 'Anthropic (Claude)',\n vendor: 'anthropic',\n models: ['claude-opus-4.5', 'claude-sonnet-4.5', 'claude-haiku-4.5', 'claude-opus-4', 'claude-sonnet-4'],\n detailedModels: [\n {\n id: 'claude-opus-4.5',\n name: 'Claude Opus 4.5',\n openRouterId: 'anthropic/claude-opus-4.5',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 32000 },\n pricing: { inputPer1k: 0.015, outputPer1k: 0.075 },\n },\n {\n id: 'claude-sonnet-4.5',\n name: 'Claude Sonnet 4.5',\n openRouterId: 'anthropic/claude-sonnet-4.5',\n // Reasoning available via toggle (extended thinking)\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 16000 },\n pricing: { inputPer1k: 0.003, outputPer1k: 0.015 },\n },\n {\n id: 'claude-haiku-4.5',\n name: 'Claude Haiku 4.5',\n openRouterId: 'anthropic/claude-haiku-4.5',\n // Reasoning available via toggle (extended thinking)\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 8192 },\n pricing: { inputPer1k: 0.0008, outputPer1k: 0.004 },\n },\n {\n id: 'claude-opus-4',\n name: 'Claude Opus 4',\n openRouterId: 'anthropic/claude-opus-4',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 32000 },\n pricing: { inputPer1k: 0.015, outputPer1k: 0.075 },\n },\n {\n id: 'claude-sonnet-4',\n name: 'Claude Sonnet 4',\n openRouterId: 'anthropic/claude-sonnet-4',\n // Reasoning available via toggle (extended thinking)\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 16000 },\n pricing: { inputPer1k: 0.003, outputPer1k: 0.015 },\n },\n ],\n accessMethods: {\n native: {\n available: true,\n endpoint: 'https://api.anthropic.com/v1',\n requiresApiKey: true\n },\n openrouter: {\n available: true,\n modelPrefix: 'anthropic/'\n }\n },\n capabilities: {\n supportsImages: true,\n supportsPDFs: true,\n supportsReasoning: true,\n supportsStreaming: true,\n supportsStructuredOutput: true\n },\n // LLM with vision - can work with raw documents OR parsed text\n inputRequirements: {\n inputType: 'any',\n acceptedMethods: ['base64'] // URLs must be downloaded and converted\n },\n compatibleNodes: {\n parse: true,\n extract: true,\n categorize: true,\n qualify: true,\n split: true\n },\n inputFormats: {\n images: {\n mimeTypes: SUPPORTED_IMAGE_TYPES.COMMON,\n methods: ['base64'], // URLs must be downloaded and converted\n maxSize: 5, // 5 MB per image (API), 10 MB (claude.ai)\n maxDimensions: { width: 8000, height: 8000 }, // Standard limit, 2000x2000 for 20+ images\n notes: 'Native API requires base64. Max 100 images/request. Optimal at 1568px max dimension.'\n },\n pdfs: {\n supported: true,\n methods: ['base64', 'fileId'],\n maxSize: 32, // 32 MB per file\n maxPages: 100, // 100 pages for full visual analysis\n notes: 'Inline via type: document with base64, or via Files API (beta). PDFs over 100 pages: text-only processing.'\n }\n },\n outputFormat: {\n supportsJSON: true,\n supportsReasoning: true,\n tokenTracking: true,\n costTracking: true\n },\n pricing: {\n model: 'per-token',\n inputPer1k: 0.003,\n outputPer1k: 0.015,\n currency: 'USD',\n notes: 'Cost calculated from tokens. OpenRouter may include cost in response. Claude 3.5 Sonnet baseline.'\n },\n limits: {\n maxContextTokens: 200000,\n maxOutputTokens: 8192,\n requestsPerMinute: undefined\n },\n nativeAPI: {\n imageFormat: 'type: \"image\", source: { type: \"base64\", media_type: \"image/jpeg\", data: \"...\" }',\n pdfFormat: 'type: \"document\", source: { type: \"base64\"|\"file\", media_type: \"application/pdf\", data: \"...\" | file_id: \"...\" }',\n reasoningConfig: 'thinking: { type: \"enabled\", budget_tokens: 1024-32000 }'\n },\n openRouterAPI: {\n imageFormat: 'type: \"image_url\", image_url: { url: \"data:image/jpeg;base64,...\" }',\n pdfFormat: 'type: \"file\", file: { filename: \"...\", file_data: \"data:application/pdf;base64,...\" }',\n reasoningConfig: 'reasoning: { max_tokens: number, exclude?: boolean }',\n differences: [\n 'Uses OpenAI-compatible format (image_url, file types)',\n 'Reasoning uses max_tokens instead of budget_tokens',\n 'Response prefill trick ({ role: \"assistant\", content: \"{\" }) for strict JSON',\n 'Tool calling instead of native structured output'\n ]\n }\n },\n\n google: {\n id: 'google',\n name: 'Google (Gemini)',\n vendor: 'google',\n models: ['gemini-3-pro', 'gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-2.5-flash-lite'],\n detailedModels: [\n {\n id: 'gemini-3-pro',\n name: 'Gemini 3 Pro',\n openRouterId: 'google/gemini-3-pro',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 1000000, maxOutputTokens: 65536 },\n pricing: { inputPer1k: 0.00125, outputPer1k: 0.005 },\n },\n {\n id: 'gemini-2.5-pro',\n name: 'Gemini 2.5 Pro',\n openRouterId: 'google/gemini-2.5-pro-preview-06-05',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 1000000, maxOutputTokens: 65536 },\n pricing: { inputPer1k: 0.00125, outputPer1k: 0.005 },\n },\n {\n id: 'gemini-2.5-flash',\n name: 'Gemini 2.5 Flash',\n openRouterId: 'google/gemini-2.5-flash-preview-09-2025',\n capabilities: { supportsReasoning: false },\n limits: { maxContextTokens: 1000000, maxOutputTokens: 8192 },\n pricing: { inputPer1k: 0.00015, outputPer1k: 0.0006 },\n },\n {\n id: 'gemini-2.5-flash-lite',\n name: 'Gemini 2.5 Flash Lite',\n openRouterId: 'google/gemini-2.5-flash-lite',\n capabilities: { supportsReasoning: false },\n limits: { maxContextTokens: 1000000, maxOutputTokens: 8192 },\n pricing: { inputPer1k: 0.000075, outputPer1k: 0.0003 },\n },\n ],\n accessMethods: {\n native: {\n available: true,\n endpoint: 'https://generativelanguage.googleapis.com/v1beta',\n requiresApiKey: true\n },\n openrouter: {\n available: true,\n modelPrefix: 'google/'\n }\n },\n capabilities: {\n supportsImages: true,\n supportsPDFs: true,\n supportsReasoning: true,\n supportsStreaming: true,\n supportsStructuredOutput: true\n },\n // LLM with vision - can work with raw documents OR parsed text\n inputRequirements: {\n inputType: 'any',\n acceptedMethods: ['base64'] // URLs are downloaded and converted\n },\n compatibleNodes: {\n parse: true,\n extract: true,\n categorize: true,\n qualify: true,\n split: true\n },\n inputFormats: {\n images: {\n mimeTypes: [...SUPPORTED_IMAGE_TYPES.COMMON, 'image/bmp', 'image/tiff', 'image/heif'],\n methods: ['base64'], // URLs are downloaded and converted\n maxSize: 20, // 20 MB inline data limit (File API: 2GB for Gemini 2.0)\n maxDimensions: { width: 3072, height: 3072 }, // Images scaled to fit, padded to preserve ratio\n notes: 'Inline via inlineData. Max 3000 images/request. File API supports larger files (stored 48 hours).'\n },\n pdfs: {\n supported: true,\n methods: ['base64', 'fileId'],\n maxSize: 50, // 50 MB limit (inline & File API)\n maxPages: 1000, // 1000 pages max, each page = 258 tokens\n notes: 'Inline via inlineData OR File API. Pages scaled to 3072x3072 max. Native text not charged.'\n }\n },\n outputFormat: {\n supportsJSON: true,\n supportsReasoning: true,\n tokenTracking: true,\n costTracking: true\n },\n pricing: {\n model: 'per-token',\n inputPer1k: 0.00025,\n outputPer1k: 0.001,\n currency: 'USD',\n notes: 'Cost calculated from tokens. OpenRouter may include cost in response. Gemini 2.5 Flash baseline.'\n },\n limits: {\n maxContextTokens: 1000000, // 1M tokens\n maxOutputTokens: 8192,\n requestsPerMinute: undefined\n },\n nativeAPI: {\n imageFormat: 'inlineData: { mimeType: \"image/jpeg\", data: \"...\" }',\n pdfFormat: 'inlineData: { mimeType: \"application/pdf\", data: \"...\" } OR fileData: { fileUri: \"...\", mimeType: \"application/pdf\" }',\n reasoningConfig: 'generationConfig.thinking_config: { thinking_budget: number } (max 24576)'\n },\n openRouterAPI: {\n imageFormat: 'type: \"image_url\", image_url: { url: \"data:image/jpeg;base64,...\" }',\n pdfFormat: 'type: \"file\", file: { filename: \"...\", file_data: \"data:application/pdf;base64,...\" }',\n reasoningConfig: 'reasoning: { max_tokens: number, exclude?: boolean }',\n differences: [\n 'Uses OpenAI-compatible format instead of parts/inlineData',\n 'Reasoning uses max_tokens instead of thinking_budget',\n 'Different content structure (messages vs contents.parts)'\n ]\n }\n },\n\n xai: {\n id: 'xai',\n name: 'xAI (Grok)',\n vendor: 'xai',\n models: ['grok-4.1', 'grok-4.1-fast', 'grok-4', 'grok-4-fast'],\n detailedModels: [\n {\n id: 'grok-4.1',\n name: 'Grok 4.1',\n openRouterId: 'x-ai/grok-4.1',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 256000, maxOutputTokens: 32768 },\n pricing: { inputPer1k: 0.003, outputPer1k: 0.015 },\n },\n {\n id: 'grok-4.1-fast',\n name: 'Grok 4.1 Fast',\n openRouterId: 'x-ai/grok-4.1-fast',\n capabilities: { supportsReasoning: false },\n limits: { maxContextTokens: 2000000, maxOutputTokens: 32768 },\n pricing: { inputPer1k: 0.005, outputPer1k: 0.025 },\n },\n {\n id: 'grok-4',\n name: 'Grok 4',\n openRouterId: 'x-ai/grok-4',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 256000, maxOutputTokens: 32768 },\n pricing: { inputPer1k: 0.003, outputPer1k: 0.015 },\n },\n {\n id: 'grok-4-fast',\n name: 'Grok 4 Fast',\n openRouterId: 'x-ai/grok-4-fast',\n capabilities: { supportsReasoning: false },\n limits: { maxContextTokens: 2000000, maxOutputTokens: 32768 },\n pricing: { inputPer1k: 0.005, outputPer1k: 0.025 },\n },\n ],\n accessMethods: {\n native: {\n available: true,\n endpoint: 'https://api.x.ai/v1',\n requiresApiKey: true\n },\n openrouter: {\n available: true,\n modelPrefix: 'xai/'\n }\n },\n capabilities: {\n supportsImages: true,\n supportsPDFs: true,\n supportsReasoning: true,\n supportsStreaming: false, // Not with structured outputs\n supportsStructuredOutput: true\n },\n // LLM with vision - can work with raw documents OR parsed text\n inputRequirements: {\n inputType: 'any',\n acceptedMethods: ['url', 'base64']\n },\n compatibleNodes: {\n parse: true,\n extract: true,\n categorize: true,\n qualify: true,\n split: true\n },\n inputFormats: {\n images: {\n mimeTypes: ['image/jpeg', 'image/png'], // Only jpg/jpeg and png supported\n methods: ['url', 'base64'],\n maxSize: 30, // 30 MB per file (API), 25 MB (chat)\n maxDimensions: undefined,\n notes: 'OpenAI-compatible format. Max 10 images via API. Only JPEG/PNG supported.'\n },\n pdfs: {\n supported: true,\n methods: ['url', 'base64'],\n maxSize: 30, // 30 MB per file\n maxPages: undefined,\n notes: 'OpenAI-compatible format. Inline via type: file. Also supports DOCX, TXT, MD, CSV.'\n }\n },\n outputFormat: {\n supportsJSON: true,\n supportsReasoning: true,\n tokenTracking: true,\n costTracking: true\n },\n pricing: {\n model: 'per-token',\n inputPer1k: 0.005,\n outputPer1k: 0.015,\n currency: 'USD',\n notes: 'Cost calculated from tokens. OpenRouter may include cost in response. Grok-4 baseline.'\n },\n limits: {\n maxContextTokens: 131072,\n maxOutputTokens: undefined,\n requestsPerMinute: undefined\n },\n nativeAPI: {\n imageFormat: 'type: \"image_url\", image_url: { url: \"data:image/jpeg;base64,...\" }',\n pdfFormat: 'type: \"file\", file: { filename: \"...\", file_data: \"data:application/pdf;base64,...\" }',\n reasoningConfig: 'reasoning: { effort: \"low\"|\"medium\"|\"high\", exclude?: boolean }'\n },\n openRouterAPI: {\n imageFormat: 'Same as native (OpenAI-compatible)',\n pdfFormat: 'Same as native (OpenAI-compatible)',\n reasoningConfig: 'Same as native (OpenAI-compatible)',\n differences: [\n 'Minimal differences - xAI uses OpenAI-compatible format',\n 'Cost tracking via usage.total_cost field in OpenRouter'\n ]\n }\n }\n} as const satisfies Record<string, LLMProviderMetadata>;\n\n// Helper functions\n\n/**\n * Check if an image MIME type is supported by a provider\n *\n * @param providerId - Provider ID\n * @param mimeType - MIME type to check\n * @returns True if supported\n *\n * @example\n * ```typescript\n * isImageTypeSupported('openai', 'image/png') // true\n * isImageTypeSupported('openai', 'image/bmp') // false\n * isImageTypeSupported('google', 'image/bmp') // true\n * ```\n */\nexport function isImageTypeSupported(\n providerId: keyof typeof PROVIDER_METADATA,\n mimeType: string\n): boolean {\n const provider = PROVIDER_METADATA[providerId];\n return provider.inputFormats.images.mimeTypes.includes(mimeType as any);\n}\n\n/**\n * Check if a provider supports PDFs inline (base64)\n *\n * @param providerId - Provider ID\n * @returns True if inline PDFs are supported\n *\n * @example\n * ```typescript\n * supportsPDFsInline('openai') // true\n * supportsPDFsInline('anthropic') // true\n * supportsPDFsInline('google') // true\n * ```\n */\nexport function supportsPDFsInline(\n providerId: keyof typeof PROVIDER_METADATA\n): boolean {\n const provider = PROVIDER_METADATA[providerId];\n return provider.inputFormats.pdfs.supported &&\n provider.inputFormats.pdfs.methods.includes('base64');\n}\n\n/**\n * Get providers compatible with a specific node type\n *\n * @param nodeType - Node type to check\n * @returns Array of compatible provider metadata\n *\n * @example\n * ```typescript\n * // Get providers that work with parse()\n * const parseProviders = getProvidersForNode('parse');\n * // Returns: [openai, anthropic, google, xai] (all VLM providers)\n *\n * // Get providers that work with extract()\n * const extractProviders = getProvidersForNode('extract');\n * // Returns: [openai, anthropic, google, xai] (all VLM providers)\n * ```\n */\nexport function getProvidersForNode(\n nodeType: 'parse' | 'extract' | 'categorize' | 'qualify' | 'split'\n): LLMProviderMetadata[] {\n return Object.values(PROVIDER_METADATA).filter(\n provider => provider.compatibleNodes[nodeType]\n );\n}\n\n/**\n * Check if a provider is compatible with a node type\n *\n * @param providerId - Provider ID\n * @param nodeType - Node type to check\n * @returns True if compatible\n *\n * @example\n * ```typescript\n * isProviderCompatibleWithNode('openai', 'parse'); // true\n * isProviderCompatibleWithNode('openai', 'extract'); // true\n * isProviderCompatibleWithNode('anthropic', 'qualify'); // true\n * ```\n */\nexport function isProviderCompatibleWithNode(\n providerId: keyof typeof PROVIDER_METADATA,\n nodeType: 'parse' | 'extract' | 'categorize' | 'qualify' | 'split'\n): boolean {\n return PROVIDER_METADATA[providerId].compatibleNodes[nodeType];\n}\n\n/**\n * Estimate cost for a request\n *\n * @param providerId - Provider ID\n * @param inputTokens - Number of input tokens\n * @param outputTokens - Number of output tokens\n * @returns Estimated cost in USD\n *\n * @example\n * ```typescript\n * const cost = estimateCost('openai', 1000, 500);\n * console.log(`$${cost.toFixed(4)}`); // \"$0.0125\"\n *\n * const cost = estimateCost('google', 10000, 1000);\n * console.log(`$${cost.toFixed(4)}`); // \"$0.0035\"\n * ```\n */\nexport function estimateCost(\n providerId: keyof typeof PROVIDER_METADATA,\n inputTokens: number,\n outputTokens: number\n): number {\n const provider = PROVIDER_METADATA[providerId];\n const inputCost = (inputTokens / 1000) * provider.pricing.inputPer1k;\n const outputCost = (outputTokens / 1000) * provider.pricing.outputPer1k;\n return inputCost + outputCost;\n}\n\n/**\n * Get the cheapest provider for a given workload\n *\n * @param inputTokens - Number of input tokens\n * @param outputTokens - Number of output tokens\n * @returns Cheapest provider metadata\n *\n * @example\n * ```typescript\n * const cheapest = getCheapestProvider(10000, 1000);\n * console.log(cheapest.name); // \"Google (Gemini)\"\n * ```\n */\nexport function getCheapestProvider(\n inputTokens: number,\n outputTokens: number\n): LLMProviderMetadata {\n const providers = Object.values(PROVIDER_METADATA);\n return providers.reduce((cheapest, current) => {\n const cheapestCost = estimateCost(cheapest.id as LLMProviderType, inputTokens, outputTokens);\n const currentCost = estimateCost(current.id as LLMProviderType, inputTokens, outputTokens);\n return currentCost < cheapestCost ? current : cheapest;\n });\n}\n\n/**\n * Compare native vs OpenRouter for a provider\n *\n * @param providerId - Provider ID\n * @returns Comparison object with key differences\n *\n * @example\n * ```typescript\n * const comparison = compareNativeVsOpenRouter('anthropic');\n * console.log(comparison.differences);\n * // ['Uses OpenAI-compatible format...', 'Response prefill trick...']\n * ```\n */\nexport function compareNativeVsOpenRouter(\n providerId: keyof typeof PROVIDER_METADATA\n): {\n provider: string;\n nativeAvailable: boolean;\n openRouterAvailable: boolean;\n differences: string[];\n} {\n const provider = PROVIDER_METADATA[providerId];\n return {\n provider: provider.name,\n nativeAvailable: provider.accessMethods.native.available,\n openRouterAvailable: provider.accessMethods.openrouter.available,\n differences: provider.openRouterAPI.differences\n };\n}\n\n// Type exports\nexport type LLMProviderType = keyof typeof PROVIDER_METADATA;\nexport type SupportedImageMimeType = typeof SUPPORTED_IMAGE_TYPES.COMMON[number];\nexport type NodeType = 'parse' | 'extract' | 'categorize' | 'qualify' | 'split';\n","// Export types\nexport * from \"./types\";\n\n// Export schema translator\nexport { SchemaTranslator } from \"./schema-translator\";\n\n// Export schema prompt formatter\nexport { buildSchemaPromptSection, formatSchemaForPrompt, combineSchemaAndUserPrompt } from \"./schema-prompt-formatter\";\n\n// Export provider registry\nexport { providerRegistry, registerProvider, createProviderFromRegistry } from \"./provider-registry\";\nexport type { ProviderFactory } from \"./provider-registry\";\n\n// Export providers (backward compatibility - still export from local files)\n// These will be deprecated in favor of importing from individual provider packages\nexport { OpenAIProvider } from \"./providers/openai\";\nexport { AnthropicProvider } from \"./providers/anthropic\";\nexport { GoogleProvider } from \"./providers/google\";\nexport { XAIProvider } from \"./providers/xai\";\n\n// Export fallback manager\nexport { FallbackManager } from \"./fallback-manager\";\n\n// Export adapter\nexport { adaptToCoreLLMProvider } from \"./adapter\";\n\n// Factory functions\nimport type { VLMProvider as CoreVLMProvider } from \"@doclo/core\";\nimport type { ObservabilityConfig, TraceContext } from \"@doclo/core/observability\";\nimport type { FallbackConfig, LLMProvider, MultimodalInput, ProviderConfig, AccessMethod, ReasoningConfig } from \"./types\";\nimport { FallbackManager } from \"./fallback-manager\";\nimport { createProviderFromRegistry, providerRegistry } from \"./provider-registry\";\nimport { adaptToCoreLLMProvider } from \"./adapter\";\n\n// Register built-in providers for backward compatibility\n// Users can also import individual provider packages to register them\nimport { OpenAIProvider } from \"./providers/openai\";\nimport { AnthropicProvider } from \"./providers/anthropic\";\nimport { GoogleProvider } from \"./providers/google\";\nimport { XAIProvider } from \"./providers/xai\";\n\n// Auto-register providers if not already registered\nif (!providerRegistry.has('openai')) {\n providerRegistry.register('openai', (config) => new OpenAIProvider(config));\n}\nif (!providerRegistry.has('anthropic')) {\n providerRegistry.register('anthropic', (config) => new AnthropicProvider(config));\n}\nif (!providerRegistry.has('google')) {\n providerRegistry.register('google', (config) => new GoogleProvider(config));\n}\nif (!providerRegistry.has('xai')) {\n providerRegistry.register('xai', (config) => new XAIProvider(config));\n}\n\n/**\n * Create a single VLM provider with direct instantiation (no retry/fallback logic).\n *\n * Use this for:\n * - Simple scripts and quick prototypes\n * - Testing individual provider behavior\n * - Benchmarking (no retry overhead)\n * - Cases where you want immediate failures without retry logic\n *\n * For production applications requiring resilience, use `buildLLMProvider()` instead.\n *\n * @example\n * ```typescript\n * const provider = createVLMProvider({\n * provider: 'google',\n * model: 'gemini-2.5-flash-preview-09-2025',\n * apiKey: process.env.OPENROUTER_API_KEY,\n * via: 'openrouter'\n * });\n * ```\n *\n * @param config - Provider configuration\n * @returns CoreVLMProvider instance (no retry/fallback wrapper)\n */\nexport function createVLMProvider(config: {\n provider: 'openai' | 'anthropic' | 'google' | 'xai' | 'x-ai';\n model: string;\n apiKey: string;\n via?: 'openrouter';\n baseUrl?: string;\n}): CoreVLMProvider {\n let internalProvider: LLMProvider;\n\n // Build proper ProviderConfig with explicit typing\n const providerConfig: ProviderConfig = {\n provider: config.provider,\n model: config.model,\n apiKey: config.apiKey,\n via: config.via as AccessMethod | undefined,\n baseUrl: config.baseUrl\n };\n\n // Use registry to create provider (allows external provider packages to register)\n internalProvider = createProviderFromRegistry(providerConfig);\n\n // Adapt to core VLMProvider interface\n return {\n name: internalProvider.name,\n capabilities: {\n supportsImages: true,\n supportsPDFs: internalProvider.capabilities.supportsPDFs,\n maxPDFPages: internalProvider.capabilities.maxPDFPages\n },\n async completeJson(input: {\n prompt: string | import(\"@doclo/core\").MultimodalInput;\n schema: object;\n max_tokens?: number;\n reasoning?: import(\"./types\").ReasoningConfig;\n }) {\n // Convert input to internal MultimodalInput format\n let multimodalInput: MultimodalInput;\n\n if (typeof input.prompt === 'string') {\n multimodalInput = { text: input.prompt };\n } else {\n multimodalInput = input.prompt as any;\n }\n\n // Call internal provider with reasoning parameters\n const response = await internalProvider.completeJson({\n input: multimodalInput,\n schema: input.schema as any,\n max_tokens: input.max_tokens,\n reasoning: input.reasoning\n });\n\n // Return in core format\n return {\n json: response.json,\n rawText: response.rawText,\n costUSD: response.metrics.costUSD,\n inputTokens: response.metrics.inputTokens,\n outputTokens: response.metrics.outputTokens\n };\n }\n };\n}\n\n/**\n * Build a production-ready LLM provider with retry logic, fallback support, and circuit breakers.\n *\n * Features:\n * - **Retry Logic**: Configurable retries with exponential backoff for transient failures\n * - **Fallback Chain**: Automatically tries next provider if current one fails\n * - **Circuit Breaker**: Temporarily skips providers with repeated failures\n * - **Observability**: Full integration with observability hooks for monitoring\n * - **Mode Support**: Supports both strict and relaxed JSON modes\n *\n * Works with single OR multiple providers:\n * - Single provider: Gets retry logic and circuit breaker protection\n * - Multiple providers: Adds fallback to alternative providers\n *\n * Use this for:\n * - Production applications requiring high availability\n * - Cases where you need retry logic even with a single provider\n * - Multi-provider fallback chains\n * - Advanced error handling and monitoring\n *\n * @example Single provider with retry\n * ```typescript\n * const provider = buildLLMProvider({\n * providers: [{\n * provider: 'google',\n * model: 'gemini-2.5-flash-preview-09-2025',\n * apiKey: process.env.OPENROUTER_API_KEY,\n * via: 'openrouter'\n * }],\n * maxRetries: 2,\n * retryDelay: 1000,\n * useExponentialBackoff: true,\n * circuitBreakerThreshold: 3\n * });\n * ```\n *\n * @example Multi-provider fallback\n * ```typescript\n * const provider = buildLLMProvider({\n * providers: [\n * { provider: 'google', model: 'gemini-2.5-flash', apiKey: key1 },\n * { provider: 'openai', model: 'gpt-4.1', apiKey: key2 },\n * { provider: 'anthropic', model: 'claude-haiku-4.5', apiKey: key3 }\n * ],\n * maxRetries: 2,\n * retryDelay: 1000,\n * useExponentialBackoff: true\n * });\n * ```\n *\n * @param config - Fallback configuration with providers array and retry settings\n * @returns CoreVLMProvider with retry/fallback capabilities (compatible with flow interface)\n */\nexport function buildLLMProvider(config: FallbackConfig): CoreVLMProvider {\n const manager = new FallbackManager(config);\n\n // Observability context storage\n let observabilityContext: {\n config?: ObservabilityConfig;\n flowId?: string;\n executionId?: string;\n stepId?: string;\n traceContext?: TraceContext;\n metadata?: Record<string, unknown>;\n } | undefined;\n\n // Return CoreVLMProvider interface (compatible with createVLMProvider)\n const coreProvider: CoreVLMProvider = {\n name: config.providers.map(p => `${p.provider}:${p.model}`).join(\" -> \"),\n capabilities: {\n supportsImages: true,\n supportsPDFs: true,\n maxPDFPages: Math.min(...config.providers.map(_ => 100))\n },\n async completeJson(input: {\n prompt: string | import(\"@doclo/core\").MultimodalInput;\n schema: object;\n max_tokens?: number;\n reasoning?: import(\"./types\").ReasoningConfig;\n }) {\n // Convert input to internal MultimodalInput format (same as createVLMProvider)\n let multimodalInput: MultimodalInput;\n\n if (typeof input.prompt === 'string') {\n multimodalInput = { text: input.prompt };\n } else {\n multimodalInput = input.prompt as any;\n }\n\n // Call fallback manager with converted input\n const response = await manager.executeWithFallback(\n multimodalInput,\n input.schema as any,\n input.max_tokens,\n input.reasoning,\n undefined, // mode - defaults to strict when schema provided\n observabilityContext\n );\n\n // Return in core format\n return {\n json: response.json,\n rawText: response.rawText,\n costUSD: response.metrics.costUSD,\n inputTokens: response.metrics.inputTokens,\n outputTokens: response.metrics.outputTokens,\n cacheCreationInputTokens: response.metrics.cacheCreationInputTokens,\n cacheReadInputTokens: response.metrics.cacheReadInputTokens\n };\n }\n };\n\n // Attach observability context setter\n (coreProvider as any).__setObservabilityContext = (ctx: typeof observabilityContext) => {\n observabilityContext = ctx;\n };\n\n return coreProvider;\n}\n\n// Export comprehensive metadata (MIME types, capabilities, helpers)\nexport * from './metadata.js';\n"],"mappings":"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","names":["fetchWithTimeout","DEFAULT_LIMITS","safeJsonParse","extractProviderFromModel","useNewStructuredOutputs","fetchWithTimeout","validateUrl","DEFAULT_LIMITS","safeJsonParse","extractProviderFromModel","fetchWithTimeout","DEFAULT_LIMITS","safeJsonParse","extractProviderFromModel"]}
|
|
1
|
+
{"version":3,"sources":["../src/schema-translator.ts","../src/schema-prompt-formatter.ts","../src/provider-registry.ts","../src/providers/openai.ts","../src/providers/anthropic.ts","../src/providers/google.ts","../src/providers/xai.ts","../src/fallback-manager.ts","../src/adapter.ts","../src/metadata.ts","../src/index.ts"],"sourcesContent":["import type { UnifiedSchema } from \"./types\";\nimport { zodToJsonSchema } from \"@alcyone-labs/zod-to-json-schema\";\n\n/**\n * Internal JSON Schema representation for schema translation.\n * This is more flexible than JSONSchemaNode to accommodate:\n * - Zod schema markers (~standard, _def)\n * - Provider-specific extensions (propertyOrdering)\n * - Intermediate conversion states\n */\ninterface FlexibleSchemaNode {\n type?: string | string[];\n properties?: Record<string, FlexibleSchemaNode>;\n items?: FlexibleSchemaNode | FlexibleSchemaNode[];\n required?: string[];\n enum?: (string | number | boolean | null)[];\n nullable?: boolean;\n anyOf?: FlexibleSchemaNode[];\n oneOf?: FlexibleSchemaNode[];\n allOf?: FlexibleSchemaNode[];\n additionalProperties?: boolean | FlexibleSchemaNode;\n description?: string;\n format?: string;\n default?: unknown;\n $schema?: string;\n $defs?: Record<string, FlexibleSchemaNode>;\n definitions?: Record<string, FlexibleSchemaNode>;\n // Zod schema markers\n '~standard'?: { vendor: string; [key: string]: unknown };\n _def?: unknown;\n // Gemini-specific\n propertyOrdering?: string[];\n [key: string]: unknown; // Allow additional properties for extensibility\n}\n\n/**\n * Translates unified JSON Schema to provider-specific formats\n */\nexport class SchemaTranslator {\n /**\n * Unified → OpenAI/Grok (standard JSON Schema)\n * OpenAI strict mode doesn't support nullable: true\n * Must convert to anyOf: [{ type: \"string\" }, { type: \"null\" }]\n */\n toOpenAISchema<T>(schema: UnifiedSchema<T>): object {\n // Detect and convert Zod schemas\n const jsonSchema = this.convertZodIfNeeded(schema);\n return this.convertNullableToAnyOf(jsonSchema);\n }\n\n /**\n * Detect if schema is a Zod schema and convert to JSON Schema\n * Public method to allow embedding schemas in prompts\n */\n convertZodIfNeeded(schema: FlexibleSchemaNode | unknown): FlexibleSchemaNode {\n // Check for Zod schema markers\n if (schema && typeof schema === 'object') {\n const flexibleSchema = schema as FlexibleSchemaNode;\n // Zod v4 uses ~standard marker\n if (flexibleSchema['~standard']?.vendor === 'zod') {\n // Schema has Zod marker, safe to pass to zodToJsonSchema\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const jsonSchema = zodToJsonSchema(schema as any) as FlexibleSchemaNode;\n // Remove properties not allowed in OpenAI strict mode or Gemini responseSchema\n delete jsonSchema.$schema;\n delete jsonSchema.$defs;\n delete jsonSchema.definitions;\n return jsonSchema;\n }\n // Zod v3 uses _def property\n if (flexibleSchema._def) {\n // Schema has Zod _def, safe to pass to zodToJsonSchema\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const jsonSchema = zodToJsonSchema(schema as any) as FlexibleSchemaNode;\n // Remove properties not allowed in OpenAI strict mode or Gemini responseSchema\n delete jsonSchema.$schema;\n delete jsonSchema.$defs;\n delete jsonSchema.definitions;\n return jsonSchema;\n }\n }\n // Already JSON Schema, return as-is\n return schema as FlexibleSchemaNode;\n }\n\n /**\n * Convert nullable fields to anyOf format for OpenAI strict mode\n * nullable: true is not supported, must use anyOf with null type\n */\n private convertNullableToAnyOf(schema: FlexibleSchemaNode): FlexibleSchemaNode {\n if (typeof schema !== 'object' || schema === null) {\n return schema;\n }\n\n const result: FlexibleSchemaNode = { ...schema };\n\n // Handle nullable property at current level\n if (result.nullable === true) {\n delete result.nullable;\n\n // Get the base type\n const baseType = result.type;\n\n if (baseType) {\n // Create anyOf with base type and null\n return {\n anyOf: [\n { type: baseType as string },\n { type: 'null' }\n ]\n };\n }\n }\n\n // Recursively handle properties\n if (result.properties) {\n result.properties = Object.fromEntries(\n Object.entries(result.properties).map(([key, value]) => {\n if (value && typeof value === 'object' && value.nullable === true) {\n const { nullable, type, ...rest } = value;\n return [key, {\n anyOf: [\n { type, ...rest },\n { type: 'null' }\n ]\n }];\n }\n return [key, this.convertNullableToAnyOf(value)];\n })\n );\n }\n\n // Handle items (for arrays)\n if (result.items && !Array.isArray(result.items)) {\n result.items = this.convertNullableToAnyOf(result.items);\n }\n\n // Handle anyOf, oneOf, allOf\n const keywords = ['anyOf', 'oneOf', 'allOf'] as const;\n keywords.forEach(keyword => {\n const schemaArray = result[keyword];\n if (schemaArray && Array.isArray(schemaArray)) {\n result[keyword] = schemaArray.map((s) => this.convertNullableToAnyOf(s));\n }\n });\n\n return result;\n }\n\n /**\n * Unified → Claude (Tool Input Schema format)\n * Claude requires tool calling with input_schema\n * Claude supports nullable: true directly\n */\n toClaudeToolSchema<T>(schema: UnifiedSchema<T>): object {\n // Detect and convert Zod schemas first\n const jsonSchema = this.convertZodIfNeeded(schema);\n\n // Claude uses JSON Schema but needs it wrapped in a tool definition\n // Claude DOES support nullable: true, so we keep it as-is\n return {\n name: \"extract_data\",\n description: \"Extract structured data according to the schema\",\n input_schema: jsonSchema as object\n };\n }\n\n /**\n * Unified → Claude for OpenRouter\n * When using Claude via OpenRouter, use anyOf format like OpenAI\n */\n toClaudeOpenRouterSchema<T>(schema: UnifiedSchema<T>): object {\n // Detect and convert Zod schemas first\n const jsonSchema = this.convertZodIfNeeded(schema);\n return this.convertNullableToAnyOf(jsonSchema);\n }\n\n /**\n * Unified → Gemini (OpenAPI 3.0 subset with propertyOrdering)\n * Gemini uses a subset of OpenAPI 3.0 schema\n */\n toGeminiSchema<T>(schema: UnifiedSchema<T>): object {\n // Detect and convert Zod schemas first\n const jsonSchema = this.convertZodIfNeeded(schema);\n\n // Convert JSON Schema to Gemini's format\n const geminiSchema: FlexibleSchemaNode = {\n type: jsonSchema.type\n };\n\n if (jsonSchema.properties) {\n geminiSchema.properties = {};\n // Add propertyOrdering for consistent output order\n const propertyNames = Object.keys(jsonSchema.properties);\n geminiSchema.propertyOrdering = propertyNames;\n\n for (const [key, value] of Object.entries(jsonSchema.properties)) {\n geminiSchema.properties[key] = this.convertPropertyToGemini(value);\n }\n }\n\n if (jsonSchema.required && Array.isArray(jsonSchema.required)) {\n geminiSchema.required = jsonSchema.required;\n }\n\n if (jsonSchema.additionalProperties !== undefined) {\n geminiSchema.additionalProperties = jsonSchema.additionalProperties;\n }\n\n return geminiSchema;\n }\n\n /**\n * Convert individual property to Gemini format\n */\n private convertPropertyToGemini(property: FlexibleSchemaNode): FlexibleSchemaNode {\n const geminiProp: FlexibleSchemaNode = {\n type: property.type\n };\n\n if (property.description) {\n geminiProp.description = property.description;\n }\n\n if (property.nullable !== undefined) {\n geminiProp.nullable = property.nullable;\n }\n\n if (property.enum) {\n geminiProp.enum = property.enum;\n }\n\n if (property.items) {\n // Items can be a single schema or array of schemas (tuple validation)\n if (Array.isArray(property.items)) {\n // For tuple validation, just convert the first schema\n geminiProp.items = property.items.length > 0\n ? this.convertPropertyToGemini(property.items[0])\n : undefined;\n } else {\n geminiProp.items = this.convertPropertyToGemini(property.items);\n }\n }\n\n if (property.properties) {\n geminiProp.properties = {};\n for (const [key, value] of Object.entries(property.properties)) {\n geminiProp.properties[key] = this.convertPropertyToGemini(value);\n }\n }\n\n if (property.required) {\n geminiProp.required = property.required;\n }\n\n return geminiProp;\n }\n}\n","/**\n * Utility for converting JSON Schema to human-readable prompt text\n * that emphasizes exact field name requirements for structured extraction.\n */\n\n/**\n * JSON Schema type used for prompt formatting.\n * Uses a recursive structure to support nested schemas.\n */\nexport interface JSONSchema {\n type?: string | string[]; // Can be array for union types (e.g., [\"string\", \"null\"])\n properties?: Record<string, JSONSchema>;\n items?: JSONSchema | JSONSchema[]; // Can be array for tuple validation\n description?: string;\n required?: string[];\n enum?: (string | number | boolean | null)[];\n anyOf?: JSONSchema[];\n oneOf?: JSONSchema[];\n allOf?: JSONSchema[];\n format?: string;\n [key: string]: unknown; // Allow additional properties\n}\n\n/**\n * Formats a JSON Schema into prompt text that emphasizes exact field names.\n * This helps LLMs understand they must use the exact field names specified\n * in the schema, not invent their own based on document content.\n */\nexport function formatSchemaForPrompt(schema: JSONSchema, indent: number = 0): string {\n if (!schema || typeof schema !== 'object') {\n return '';\n }\n\n const indentStr = ' '.repeat(indent);\n let result = '';\n\n // Handle object type with properties\n if (schema.type === 'object' && schema.properties) {\n const properties = schema.properties;\n const required = schema.required || [];\n\n for (const [fieldName, fieldSchema] of Object.entries(properties)) {\n const isRequired = required.includes(fieldName);\n const requiredMarker = isRequired ? ' (REQUIRED)' : ' (optional)';\n\n // Field name in backticks to emphasize exactness\n result += `${indentStr}- \\`${fieldName}\\`${requiredMarker}`;\n\n // Type information\n const type = getTypeDescription(fieldSchema);\n if (type) {\n result += `: ${type}`;\n }\n\n // Description if available\n if (fieldSchema.description) {\n result += `\\n${indentStr} ${fieldSchema.description}`;\n }\n\n // Enum values if specified\n if (fieldSchema.enum) {\n result += `\\n${indentStr} Allowed values: ${fieldSchema.enum.map((v) => JSON.stringify(v)).join(', ')}`;\n }\n\n result += '\\n';\n\n // Nested object properties\n if (fieldSchema.type === 'object' && fieldSchema.properties) {\n result += formatSchemaForPrompt(fieldSchema, indent + 1);\n }\n\n // Array item schema\n if (fieldSchema.type === 'array' && fieldSchema.items) {\n result += `${indentStr} Array items:\\n`;\n // Handle both single schema and tuple schemas (array of schemas)\n const itemSchema = Array.isArray(fieldSchema.items)\n ? fieldSchema.items[0] // For tuple validation, describe first item type\n : fieldSchema.items;\n if (itemSchema && itemSchema.type === 'object' && itemSchema.properties) {\n result += formatSchemaForPrompt(itemSchema, indent + 2);\n } else if (itemSchema) {\n const itemType = getTypeDescription(itemSchema);\n result += `${indentStr} ${itemType}\\n`;\n }\n }\n }\n }\n\n return result;\n}\n\n/**\n * Gets a human-readable type description from a schema property\n */\nfunction getTypeDescription(schema: JSONSchema): string {\n if (!schema) return 'any';\n\n if (schema.type) {\n // Handle array of types (e.g., [\"string\", \"null\"])\n const typeStr = Array.isArray(schema.type) ? schema.type.join(' | ') : schema.type;\n\n if (typeStr === 'array' || (Array.isArray(schema.type) && schema.type.includes('array'))) {\n if (schema.items && !Array.isArray(schema.items) && schema.items.type) {\n const itemType = Array.isArray(schema.items.type)\n ? schema.items.type.join(' | ')\n : schema.items.type;\n return `array of ${itemType}`;\n }\n return 'array';\n }\n // Include format information for strings (e.g., date, time, date-time, email, uri)\n if ((typeStr === 'string' || (Array.isArray(schema.type) && schema.type.includes('string'))) && schema.format) {\n const formatHints: Record<string, string> = {\n 'date': 'YYYY-MM-DD',\n 'time': 'HH:MM or HH:MM:SS',\n 'date-time': 'YYYY-MM-DDTHH:MM:SS (ISO 8601)',\n };\n const hint = formatHints[schema.format];\n if (hint) {\n return `string (format: ${schema.format}, use ${hint})`;\n }\n return `string (format: ${schema.format})`;\n }\n return typeStr;\n }\n\n // Handle anyOf, oneOf, allOf\n if (schema.anyOf) {\n return schema.anyOf.map((s) => getTypeDescription(s)).join(' OR ');\n }\n if (schema.oneOf) {\n return schema.oneOf.map((s) => getTypeDescription(s)).join(' OR ');\n }\n\n return 'any';\n}\n\n/**\n * Generates a complete prompt section with schema information and\n * strict field name instructions.\n */\nexport function buildSchemaPromptSection(schema: JSONSchema): string {\n const schemaFields = formatSchemaForPrompt(schema);\n\n return `\n==================================================\nCRITICAL: OUTPUT STRUCTURE REQUIREMENTS\n==================================================\n\nYOU MUST RETURN JSON MATCHING THIS EXACT STRUCTURE:\n\n${schemaFields}\n\nCRITICAL FIELD NAME REQUIREMENTS:\n✓ Use EXACTLY the field names shown above (character-for-character match)\n✓ Preserve the exact casing (e.g., \"fullName\", not \"full_name\" or \"FullName\")\n✓ Do NOT abbreviate field names (e.g., \"dob\" instead of \"dateOfBirth\")\n✓ Do NOT invent alternative names (e.g., \"directorName\" instead of \"fullName\")\n✓ Do NOT use snake_case if the schema uses camelCase\n✓ Do NOT flatten nested structures or rename nested fields\n✓ The schema above is the SINGLE SOURCE OF TRUTH for field naming\n\nMISSING DATA:\n- If a required field has no data in the document, use null\n- If an optional field has no data, you may omit it or use null\n- Do NOT invent data that isn't in the document\n\n==================================================\n`.trim();\n}\n\n/**\n * Combines schema prompt section with user's custom prompt\n */\nexport function combineSchemaAndUserPrompt(\n schema: JSONSchema,\n userPrompt: string\n): string {\n const schemaSection = buildSchemaPromptSection(schema);\n\n if (!userPrompt || userPrompt.trim() === '') {\n return schemaSection + '\\n\\nTASK: Extract structured data from the provided document.';\n }\n\n return schemaSection + '\\n\\n' + userPrompt;\n}\n","import type { LLMProvider, ProviderConfig, ProviderType } from './types';\n\n/**\n * Factory function type for creating provider instances\n */\nexport type ProviderFactory = (config: ProviderConfig) => LLMProvider;\n\n/**\n * Normalize provider type aliases (e.g., 'x-ai' -> 'xai')\n */\nfunction normalizeProviderType(type: ProviderType): ProviderType {\n if (type === 'x-ai') return 'xai';\n return type;\n}\n\n/**\n * Provider registry for dynamic provider loading\n *\n * This allows provider packages to register themselves when imported,\n * avoiding hardcoded imports in the core package.\n */\nclass ProviderRegistry {\n private factories: Map<ProviderType, ProviderFactory> = new Map();\n\n /**\n * Register a provider factory\n * Called by each provider package when it's imported\n */\n register(type: ProviderType, factory: ProviderFactory): void {\n const normalizedType = normalizeProviderType(type);\n this.factories.set(normalizedType, factory);\n }\n\n /**\n * Check if a provider is registered\n */\n has(type: ProviderType): boolean {\n const normalizedType = normalizeProviderType(type);\n return this.factories.has(normalizedType);\n }\n\n /**\n * Get a provider factory\n */\n get(type: ProviderType): ProviderFactory | undefined {\n const normalizedType = normalizeProviderType(type);\n return this.factories.get(normalizedType);\n }\n\n /**\n * Create a provider instance\n * @throws Error if provider is not registered\n */\n create(config: ProviderConfig): LLMProvider {\n const normalizedType = normalizeProviderType(config.provider);\n const factory = this.factories.get(normalizedType);\n if (!factory) {\n const registered = Array.from(this.factories.keys()).join(', ') || 'none';\n throw new Error(\n `Provider '${config.provider}' is not registered. ` +\n `Registered providers: ${registered}. ` +\n `Make sure to import the provider package (e.g., import '@doclo/providers-${normalizedType}').`\n );\n }\n // Pass config with normalized provider type\n return factory({ ...config, provider: normalizedType });\n }\n\n /**\n * Get all registered provider types\n */\n getRegisteredTypes(): ProviderType[] {\n return Array.from(this.factories.keys());\n }\n\n /**\n * Clear all registrations (for testing)\n */\n clear(): void {\n this.factories.clear();\n }\n}\n\n/**\n * Global provider registry instance\n */\nexport const providerRegistry = new ProviderRegistry();\n\n/**\n * Register a provider factory\n * Convenience function for provider packages\n */\nexport function registerProvider(type: ProviderType, factory: ProviderFactory): void {\n providerRegistry.register(type, factory);\n}\n\n/**\n * Create a provider instance from the registry\n */\nexport function createProviderFromRegistry(config: ProviderConfig): LLMProvider {\n return providerRegistry.create(config);\n}\n","import type {\n LLMProvider,\n ProviderConfig,\n MultimodalInput,\n UnifiedSchema,\n LLMResponse,\n ProviderCapabilities,\n ResourceLimits\n} from \"../types\";\nimport { SchemaTranslator } from \"../schema-translator\";\nimport { combineSchemaAndUserPrompt } from \"../schema-prompt-formatter\";\nimport { fetchWithTimeout, DEFAULT_LIMITS, safeJsonParse } from \"@doclo/core/security\";\n\n/**\n * Extract base provider name from model identifier.\n * For OpenRouter models like \"openai/gpt-4...\", extracts \"openai\".\n * For direct models like \"gpt-4...\", returns the default provider.\n */\nfunction extractProviderFromModel(model: string, defaultProvider: string): string {\n const slashIndex = model.indexOf('/');\n return slashIndex > 0 ? model.substring(0, slashIndex) : defaultProvider;\n}\n\nexport class OpenAIProvider implements LLMProvider {\n readonly name: string;\n readonly capabilities: ProviderCapabilities = {\n supportsStructuredOutput: true,\n supportsStreaming: true,\n supportsImages: true,\n supportsPDFs: true,\n maxPDFPages: 100,\n maxPDFSize: 32,\n maxContextTokens: 128000\n };\n\n private config: ProviderConfig;\n private translator: SchemaTranslator;\n private limits: typeof DEFAULT_LIMITS;\n\n constructor(config: ProviderConfig) {\n this.config = config;\n // Extract base provider from model if it's an OpenRouter model (e.g., \"openai/gpt-4...\")\n const baseProvider = extractProviderFromModel(config.model, 'openai');\n this.name = `${baseProvider}:${config.model}`;\n this.translator = new SchemaTranslator();\n\n // Merge custom limits with defaults\n this.limits = {\n ...DEFAULT_LIMITS,\n ...(config.limits || {})\n };\n }\n\n async completeJson<T>(params: {\n input: MultimodalInput;\n schema?: UnifiedSchema<T>;\n mode?: import(\"../types\").JsonMode;\n max_tokens?: number;\n reasoning?: import(\"../types\").ReasoningConfig;\n embedSchemaInPrompt?: boolean;\n }): Promise<LLMResponse<T>> {\n const startTime = Date.now();\n\n // Determine mode: default to 'strict', auto-relaxed if schema omitted\n const mode = params.mode || (params.schema ? 'strict' : 'relaxed');\n\n // Validate: strict mode requires schema\n if (mode === 'strict' && !params.schema) {\n throw new Error('schema is required when mode is \"strict\"');\n }\n\n // Embed schema in prompt if enabled (default: true) and schema exists\n const shouldEmbedSchema = params.embedSchemaInPrompt !== false && params.schema;\n let enhancedInput = params.input;\n\n if (shouldEmbedSchema) {\n // Convert schema to JSON Schema format\n const jsonSchema = this.translator.convertZodIfNeeded(params.schema!);\n\n // Combine schema prompt with user's text\n const enhancedText = combineSchemaAndUserPrompt(\n jsonSchema,\n params.input.text || ''\n );\n\n enhancedInput = {\n ...params.input,\n text: enhancedText\n };\n }\n\n // Build messages with multimodal content (using enhanced input)\n const messages = this.buildMessages(enhancedInput);\n\n // Build request body\n const requestBody: any = {\n model: this.config.model,\n messages,\n max_tokens: params.max_tokens || 4096, // Set reasonable default to avoid massive token requests\n // Enable usage tracking for OpenRouter cost info\n usage: {\n include: true\n }\n };\n\n // Set response_format based on mode\n if (mode === 'relaxed') {\n // Relaxed mode: just request valid JSON without strict schema validation\n requestBody.response_format = {\n type: \"json_object\"\n };\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[OpenAIProvider] Using relaxed JSON mode (json_object)');\n }\n } else {\n // Strict mode: use json_schema with strict validation\n const schema: any = this.translator.toOpenAISchema(params.schema!);\n\n // Recursively fix schema for Azure strict mode requirements\n // Azure requires additionalProperties: false on ALL nested objects\n const fixSchemaForAzure = (obj: any): any => {\n if (obj && typeof obj === 'object') {\n if (obj.type === 'object' && obj.properties) {\n const allProps = Object.keys(obj.properties);\n obj.required = allProps;\n obj.additionalProperties = false;\n\n // Recursively fix nested properties\n for (const key in obj.properties) {\n obj.properties[key] = fixSchemaForAzure(obj.properties[key]);\n }\n } else if (obj.type === 'array' && obj.items) {\n // Recursively fix array items schema\n obj.items = fixSchemaForAzure(obj.items);\n }\n }\n return obj;\n };\n\n fixSchemaForAzure(schema);\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[OpenAIProvider] Using strict JSON mode (json_schema)');\n console.log('[OpenAIProvider] Fixed schema:', JSON.stringify(schema, null, 2));\n }\n\n requestBody.response_format = {\n type: \"json_schema\",\n json_schema: {\n name: \"extraction\",\n strict: true,\n schema\n }\n };\n }\n\n // Add reasoning configuration if provided (OpenAI uses effort directly)\n if (params.reasoning) {\n requestBody.reasoning = this.buildReasoningConfig(params.reasoning);\n }\n\n // Add OpenRouter model filtering for strict mode\n if (this.config.via === 'openrouter' && mode === 'strict') {\n requestBody.provider = {\n require_parameters: true // Only route to models supporting json_schema\n };\n }\n\n // Make API call - check if using OpenRouter\n const endpoint = this.config.via === 'openrouter'\n ? \"https://openrouter.ai/api/v1\"\n : (this.config.baseUrl || \"https://api.openai.com/v1\");\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.config.apiKey}`\n };\n\n // Add OpenRouter-specific headers\n if (this.config.via === 'openrouter') {\n headers[\"HTTP-Referer\"] = \"https://github.com/docloai/sdk\";\n headers[\"X-Title\"] = \"Doclo SDK\";\n }\n\n const response = await fetchWithTimeout(`${endpoint}/chat/completions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(requestBody)\n }, this.limits.REQUEST_TIMEOUT);\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`OpenAI API error (${response.status}): ${error}`);\n }\n\n const data = await response.json();\n const latencyMs = Date.now() - startTime;\n\n // Parse response\n const content = data.choices?.[0]?.message?.content ?? \"{}\";\n const parsed = safeJsonParse(content) as T;\n\n // Extract reasoning fields if present\n const message = data.choices?.[0]?.message;\n const reasoning = message?.reasoning;\n const reasoning_details = message?.reasoning_details;\n\n // Extract cost from OpenRouter or calculate locally\n let costUSD: number | undefined;\n if (this.config.via === 'openrouter') {\n // Read cost from OpenRouter response (more accurate than local calculation)\n costUSD = data.usage?.total_cost ?? data.usage?.cost;\n } else {\n // Calculate cost locally for native OpenAI API\n costUSD = this.calculateCost(data.usage);\n }\n\n // Extract base provider from model for metrics\n const baseProvider = extractProviderFromModel(this.config.model, 'openai');\n\n return {\n json: parsed as T,\n rawText: content,\n metrics: {\n costUSD,\n inputTokens: data.usage?.prompt_tokens,\n outputTokens: data.usage?.completion_tokens,\n latencyMs,\n attemptNumber: 1,\n provider: baseProvider, // Base provider (e.g., \"openai\" from \"openai/gpt-4...\")\n model: this.config.model\n },\n reasoning,\n reasoning_details\n };\n }\n\n private buildReasoningConfig(reasoning: import(\"../types\").ReasoningConfig): any {\n const config: any = {};\n\n // OpenAI uses effort directly\n if (reasoning.effort) {\n config.effort = reasoning.effort;\n } else if (reasoning.enabled) {\n config.effort = 'medium'; // Default to medium\n }\n\n // Add exclude flag if specified\n if (reasoning.exclude !== undefined) {\n config.exclude = reasoning.exclude;\n }\n\n return Object.keys(config).length > 0 ? config : undefined;\n }\n\n private buildMessages(input: MultimodalInput): any[] {\n const content: any[] = [];\n\n // Add text\n if (input.text) {\n content.push({ type: \"text\", text: input.text });\n }\n\n // Add images\n if (input.images && input.images.length > 0) {\n for (const image of input.images) {\n if (image.url) {\n content.push({\n type: \"image_url\",\n image_url: { url: image.url }\n });\n } else if (image.base64) {\n content.push({\n type: \"image_url\",\n image_url: {\n url: `data:${image.mimeType};base64,${this.extractBase64(image.base64)}`\n }\n });\n }\n }\n }\n\n // Add PDFs - OpenRouter requires type: \"file\" format\n if (input.pdfs && input.pdfs.length > 0) {\n for (const pdf of input.pdfs) {\n let fileData: string;\n if (pdf.url) {\n fileData = pdf.url;\n } else if (pdf.base64) {\n fileData = `data:application/pdf;base64,${this.extractBase64(pdf.base64)}`;\n } else {\n continue;\n }\n\n content.push({\n type: \"file\",\n file: {\n filename: \"document.pdf\",\n file_data: fileData\n }\n });\n }\n }\n\n return [{ role: \"user\", content }];\n }\n\n /**\n * Extract base64 data from a data URL or return as-is if already raw base64\n */\n private extractBase64(input: string): string {\n if (input.startsWith('data:')) {\n // Extract base64 part from data URL: data:image/jpeg;base64,XXXXX -> XXXXX\n const base64Part = input.split(',')[1];\n if (!base64Part) {\n throw new Error(`Invalid data URL format: ${input.substring(0, 50)}`);\n }\n return base64Part;\n }\n return input;\n }\n\n private calculateCost(usage: any): number | undefined {\n if (!usage) return undefined;\n\n // Approximate costs for GPT-4o (as of 2025)\n // These should be updated based on current pricing\n const inputCostPer1k = 0.005; // $0.005 per 1K input tokens\n const outputCostPer1k = 0.015; // $0.015 per 1K output tokens\n\n const inputCost = (usage.prompt_tokens / 1000) * inputCostPer1k;\n const outputCost = (usage.completion_tokens / 1000) * outputCostPer1k;\n\n return inputCost + outputCost;\n }\n}\n","import type {\n LLMProvider,\n ProviderConfig,\n MultimodalInput,\n UnifiedSchema,\n LLMResponse,\n ProviderCapabilities,\n ResourceLimits\n} from \"../types\";\nimport { SchemaTranslator } from \"../schema-translator\";\nimport { combineSchemaAndUserPrompt } from \"../schema-prompt-formatter\";\nimport { fetchWithTimeout, DEFAULT_LIMITS, validateUrl, safeJsonParse } from \"@doclo/core/security\";\nimport { detectMimeTypeFromBase64, validateMimeType } from \"@doclo/core\";\n\n/**\n * Extract base provider name from model identifier.\n * For OpenRouter models like \"anthropic/claude-...\", extracts \"anthropic\".\n * For direct models like \"claude-...\", returns the default provider.\n */\nfunction extractProviderFromModel(model: string, defaultProvider: string): string {\n const slashIndex = model.indexOf('/');\n return slashIndex > 0 ? model.substring(0, slashIndex) : defaultProvider;\n}\n\nexport class AnthropicProvider implements LLMProvider {\n readonly name: string;\n readonly capabilities: ProviderCapabilities = {\n supportsStructuredOutput: true, // via tool calling\n supportsStreaming: true,\n supportsImages: true,\n supportsPDFs: true,\n maxPDFPages: 100,\n maxPDFSize: undefined, // ~400k tokens with overhead\n maxContextTokens: 200000\n };\n\n private config: ProviderConfig;\n private translator: SchemaTranslator;\n private limits: typeof DEFAULT_LIMITS;\n\n constructor(config: ProviderConfig) {\n this.config = config;\n // Extract base provider from model if it's an OpenRouter model (e.g., \"anthropic/claude-...\")\n const baseProvider = extractProviderFromModel(config.model, 'anthropic');\n this.name = `${baseProvider}:${config.model}`;\n this.translator = new SchemaTranslator();\n\n // Merge custom limits with defaults\n this.limits = {\n ...DEFAULT_LIMITS,\n ...(config.limits || {})\n };\n }\n\n async completeJson<T>(params: {\n input: MultimodalInput;\n schema?: UnifiedSchema<T>;\n mode?: import(\"../types\").JsonMode;\n max_tokens?: number;\n reasoning?: import(\"../types\").ReasoningConfig;\n embedSchemaInPrompt?: boolean;\n }): Promise<LLMResponse<T>> {\n const startTime = Date.now();\n\n // Determine mode: default to 'strict', auto-relaxed if schema omitted\n const mode = params.mode || (params.schema ? 'strict' : 'relaxed');\n\n // Validate: strict mode requires schema\n if (mode === 'strict' && !params.schema) {\n throw new Error('schema is required when mode is \"strict\"');\n }\n\n // Embed schema in prompt if enabled (default: true) and schema exists\n const shouldEmbedSchema = params.embedSchemaInPrompt !== false && params.schema;\n let enhancedInput = params.input;\n\n if (shouldEmbedSchema) {\n // Convert schema to JSON Schema format\n const jsonSchema = this.translator.convertZodIfNeeded(params.schema!);\n\n // Combine schema prompt with user's text\n const enhancedText = combineSchemaAndUserPrompt(\n jsonSchema,\n params.input.text || ''\n );\n\n enhancedInput = {\n ...params.input,\n text: enhancedText\n };\n }\n\n // Build messages with multimodal content (using enhanced input)\n const messages = await this.buildMessages(enhancedInput);\n\n // Check if model supports new structured outputs API\n // OpenRouter now supports structured outputs for Sonnet 4.5 and Opus 4.1\n const useNewStructuredOutputs = this.supportsNewStructuredOutputs();\n\n // Build request body\n const requestBody: any = {\n model: this.config.model,\n max_tokens: params.max_tokens || 4096,\n messages\n };\n\n if (mode === 'relaxed') {\n // Relaxed mode: use prompt engineering with response prefilling\n // Anthropic doesn't have native json_object mode, so we rely on prefilling\n // Add prefill message to force JSON output\n requestBody.messages.push({\n role: \"assistant\",\n content: \"{\"\n });\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] Using relaxed JSON mode (prompt + prefilling)');\n }\n } else if (useNewStructuredOutputs) {\n // Strict mode with NEW structured outputs API (output_format)\n const jsonSchema = this.translator.convertZodIfNeeded(params.schema!);\n const fixedSchema = this.fixSchemaForStrictMode(jsonSchema);\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] Original schema:', JSON.stringify(jsonSchema, null, 2));\n console.log('[AnthropicProvider] Fixed schema:', JSON.stringify(fixedSchema, null, 2));\n }\n\n requestBody.output_format = {\n type: \"json_schema\",\n schema: fixedSchema\n };\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] Using NEW structured outputs API (strict mode)');\n }\n } else {\n // Strict mode with legacy tool calling approach\n const tool = this.translator.toClaudeToolSchema(params.schema!);\n requestBody.tools = [tool];\n requestBody.tool_choice = { type: \"tool\", name: \"extract_data\" };\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] Using legacy tool calling approach (strict mode)');\n }\n }\n\n // Add native thinking configuration if using native API and reasoning is enabled\n if (this.config.via !== 'openrouter' && params.reasoning) {\n const thinkingConfig = this.buildNativeThinkingConfig(params.reasoning, params.max_tokens);\n if (thinkingConfig) {\n requestBody.thinking = thinkingConfig;\n }\n }\n\n // Make API call - check if using OpenRouter\n let response: Response;\n let parsed: any;\n let inputTokens: number | undefined;\n let outputTokens: number | undefined;\n let costUSD: number | undefined;\n\n if (this.config.via === 'openrouter') {\n // Check if model supports new structured outputs\n const useNewStructuredOutputs = this.supportsNewStructuredOutputs();\n\n // Use OpenRouter with OpenAI-compatible format\n const openRouterRequest = this.translateToOpenRouterFormat(messages, params.schema, mode, params.max_tokens, params.reasoning);\n\n // Debug: Log request body to verify cache_control is present\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] OpenRouter request body (messages):');\n console.log(JSON.stringify(openRouterRequest.messages, null, 2));\n console.log('[AnthropicProvider] Using new structured outputs:', useNewStructuredOutputs);\n }\n\n response = await fetchWithTimeout(\"https://openrouter.ai/api/v1/chat/completions\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.config.apiKey}`,\n \"HTTP-Referer\": \"https://github.com/docloai/sdk\",\n \"X-Title\": \"Doclo SDK\"\n },\n body: JSON.stringify(openRouterRequest)\n }, this.limits.REQUEST_TIMEOUT);\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Anthropic API error (${response.status}): ${error}`);\n }\n\n const data = await response.json();\n const message = data.choices?.[0]?.message;\n let content = message?.content ?? (useNewStructuredOutputs ? \"{}\" : \"}\");\n\n // For OLDER models: we prefilled with \"{\", so prepend it back\n // For NEW models: content is already complete JSON\n if (!useNewStructuredOutputs) {\n content = \"{\" + content;\n }\n\n // Extract reasoning fields if present\n const reasoning = message?.reasoning;\n const reasoning_details = message?.reasoning_details;\n\n // Claude via OpenRouter with response prefilling should return clean JSON\n // But apply defensive parsing just in case:\n\n // 1. Strip markdown code blocks if present\n content = content.replace(/^```json\\s*\\n?/,'').replace(/\\n?```\\s*$/,'').trim();\n\n // 2. Strip markdown bold/italic formatting\n content = content.replace(/\\*\\*/g, '').replace(/\\*/g, '');\n\n // 3. Extract just the JSON object (handle extra text after closing brace)\n const firstBrace = content.indexOf('{');\n if (firstBrace !== -1) {\n // Find the matching closing brace using brace counting\n let braceCount = 0;\n let jsonEnd = -1;\n for (let i = firstBrace; i < content.length; i++) {\n if (content[i] === '{') braceCount++;\n if (content[i] === '}') braceCount--;\n if (braceCount === 0) {\n jsonEnd = i + 1;\n break;\n }\n }\n if (jsonEnd !== -1) {\n content = content.substring(firstBrace, jsonEnd);\n }\n } else if (!content.startsWith('[')) {\n // No JSON found at all - throw detailed error\n throw new Error(`Claude did not return JSON. Response: ${content.substring(0, 200)}`);\n }\n\n // 4. Remove any leading/trailing whitespace\n content = content.trim();\n\n parsed = safeJsonParse(content) as T;\n\n // Auto-wrap detection: If relaxed mode returns unwrapped properties, wrap them\n // This handles cases where the LLM returns properties directly instead of a full schema\n if (mode === 'relaxed' && this.looksLikeUnwrappedProperties(parsed)) {\n parsed = this.wrapAsSchema(parsed) as T;\n }\n\n inputTokens = data.usage?.prompt_tokens;\n outputTokens = data.usage?.completion_tokens;\n // Try different cost fields that OpenRouter might use\n costUSD = data.usage?.total_cost ?? data.usage?.cost;\n\n // Extract prompt caching metrics (OpenRouter/Anthropic)\n const cacheCreationInputTokens = data.usage?.cache_creation_input_tokens;\n const cacheReadInputTokens = data.usage?.cache_read_input_tokens;\n\n // Debug: Log usage fields if DEBUG_PROVIDERS is set\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] OpenRouter usage response:', JSON.stringify(data.usage, null, 2));\n console.log('[AnthropicProvider] Extracted costUSD:', costUSD);\n console.log('[AnthropicProvider] Cache creation tokens:', cacheCreationInputTokens);\n console.log('[AnthropicProvider] Cache read tokens:', cacheReadInputTokens);\n }\n\n // Return with reasoning fields\n const latencyMs = Date.now() - startTime;\n // Extract base provider from model for metrics\n const baseProvider = extractProviderFromModel(this.config.model, 'anthropic');\n\n return {\n json: parsed as T,\n rawText: JSON.stringify(parsed),\n metrics: {\n costUSD,\n inputTokens,\n outputTokens,\n latencyMs,\n attemptNumber: 1,\n provider: baseProvider, // Base provider (e.g., \"anthropic\" from \"anthropic/claude-...\")\n model: this.config.model,\n cacheCreationInputTokens,\n cacheReadInputTokens\n },\n reasoning,\n reasoning_details\n };\n } else {\n // Use native Anthropic API\n const endpoint = this.config.baseUrl || \"https://api.anthropic.com/v1\";\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.config.apiKey,\n \"anthropic-version\": \"2023-06-01\"\n };\n\n // Add beta header for new structured outputs API\n if (useNewStructuredOutputs) {\n headers[\"anthropic-beta\"] = \"structured-outputs-2025-11-13\";\n }\n\n response = await fetchWithTimeout(`${endpoint}/messages`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(requestBody)\n }, this.limits.REQUEST_TIMEOUT);\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Anthropic API error (${response.status}): ${error}`);\n }\n\n const data = await response.json();\n\n // Extract JSON based on mode and API version\n if (mode === 'relaxed') {\n // Relaxed mode: JSON in text block with prefilling\n const textBlock = data.content?.find((block: any) => block.type === \"text\");\n if (!textBlock || !textBlock.text) {\n throw new Error(\"Claude did not return structured output (relaxed mode)\");\n }\n\n // Prepend \"{\" since we used prefilling\n let content = \"{\" + textBlock.text;\n\n // Clean up: extract just the JSON object\n // Sometimes there's extra text after the closing brace\n const firstBrace = content.indexOf('{');\n if (firstBrace !== -1) {\n // Find the matching closing brace\n let braceCount = 0;\n let jsonEnd = -1;\n for (let i = firstBrace; i < content.length; i++) {\n if (content[i] === '{') braceCount++;\n if (content[i] === '}') braceCount--;\n if (braceCount === 0) {\n jsonEnd = i + 1;\n break;\n }\n }\n if (jsonEnd !== -1) {\n content = content.substring(firstBrace, jsonEnd);\n }\n }\n\n parsed = safeJsonParse(content) as T;\n } else if (useNewStructuredOutputs) {\n // NEW API (strict mode): JSON in content text block\n const textBlock = data.content?.find((block: any) => block.type === \"text\");\n if (!textBlock || !textBlock.text) {\n throw new Error(\"Claude did not return structured output via new API\");\n }\n\n parsed = safeJsonParse(textBlock.text) as T;\n } else {\n // OLD API (strict mode): JSON in tool_use block\n const toolUseBlock = data.content?.find((block: any) => block.type === \"tool_use\");\n if (!toolUseBlock || !toolUseBlock.input) {\n throw new Error(\"Claude did not return structured output via tool calling\");\n }\n\n parsed = toolUseBlock.input;\n }\n\n inputTokens = data.usage?.input_tokens;\n outputTokens = data.usage?.output_tokens;\n costUSD = this.calculateCost(data.usage);\n\n // Extract thinking content if present (native API)\n const thinkingBlock = data.content?.find((block: any) => block.type === \"thinking\");\n const reasoning = thinkingBlock?.thinking;\n\n const latencyMs = Date.now() - startTime;\n\n // Extract base provider from model for metrics\n const baseProvider = extractProviderFromModel(this.config.model, 'anthropic');\n\n return {\n json: parsed as T,\n rawText: JSON.stringify(parsed),\n metrics: {\n costUSD,\n inputTokens,\n outputTokens,\n latencyMs,\n attemptNumber: 1,\n provider: baseProvider, // Base provider (e.g., \"anthropic\" from \"anthropic/claude-...\")\n model: this.config.model\n },\n reasoning,\n reasoning_details: reasoning ? [{\n type: 'reasoning.text' as const,\n text: reasoning,\n signature: null,\n id: 'thinking-1',\n format: 'anthropic-claude-v1'\n }] : undefined\n };\n }\n }\n\n private buildNativeThinkingConfig(reasoning: import(\"../types\").ReasoningConfig, max_tokens?: number): any {\n // Native Anthropic uses \"thinking\" object with \"type\" and \"budget_tokens\"\n if (!reasoning.effort && !reasoning.enabled) {\n return undefined;\n }\n\n const effort = reasoning.effort || 'medium';\n const requestMaxTokens = max_tokens || 4096;\n\n // Convert effort to budget_tokens (minimum 1024 for Anthropic)\n const effortRatios = { low: 0.2, medium: 0.5, high: 0.8 };\n const ratio = effortRatios[effort];\n const budget_tokens = Math.max(1024, Math.min(32000, Math.floor(requestMaxTokens * ratio)));\n\n return {\n type: \"enabled\",\n budget_tokens\n };\n }\n\n private translateToOpenRouterFormat(\n messages: any[],\n schema: any | undefined,\n mode: import(\"../types\").JsonMode,\n max_tokens?: number,\n reasoning?: import(\"../types\").ReasoningConfig\n ): any {\n // Check if model supports new structured outputs\n const useNewStructuredOutputs = this.supportsNewStructuredOutputs();\n\n // Add system message for JSON enforcement\n const systemMessage = {\n role: \"system\",\n content: mode === 'strict'\n ? \"You are a data extraction assistant. You must respond ONLY with valid JSON that matches the provided schema. Do not include any markdown formatting, explanations, or additional text.\"\n : \"You are a data extraction assistant. You must respond ONLY with valid JSON. Do not include any markdown formatting, explanations, or additional text.\"\n };\n\n // Prepare messages array\n const messageArray = [systemMessage, ...messages];\n\n const requestBody: any = {\n model: this.config.model,\n messages: messageArray,\n // Enable usage tracking for OpenRouter cost info\n usage: {\n include: true\n }\n };\n\n if (mode === 'relaxed') {\n // Relaxed mode: use json_object without strict schema\n // Note: We don't use response prefilling here to allow more flexible JSON generation\n // (e.g., generating JSON Schemas which need the root type/properties wrapper)\n requestBody.response_format = {\n type: 'json_object'\n };\n } else {\n // Strict mode: use json_schema with strict validation\n const openRouterSchema = this.translator.toClaudeOpenRouterSchema(schema!);\n const fixedSchema = this.fixSchemaForStrictMode(openRouterSchema);\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider] Original schema:', JSON.stringify(openRouterSchema, null, 2));\n console.log('[AnthropicProvider] Fixed schema:', JSON.stringify(fixedSchema, null, 2));\n }\n\n // Add response prefill for OLDER models (legacy workaround)\n // NEW models don't need prefilling with json_schema response_format\n if (!useNewStructuredOutputs) {\n messageArray.push({\n role: \"assistant\",\n content: \"{\"\n });\n }\n\n requestBody.response_format = {\n type: 'json_schema',\n json_schema: {\n name: 'extraction',\n strict: true,\n schema: fixedSchema\n }\n };\n }\n\n // Add reasoning configuration if provided (Anthropic uses max_tokens)\n if (reasoning) {\n requestBody.reasoning = this.buildReasoningConfig(reasoning, max_tokens);\n }\n\n // Note: We don't add require_parameters: true here because:\n // - Models like Haiku that don't support json_schema natively\n // will still work using the prefill workaround\n // - The supportsNewStructuredOutputs() check handles routing internally\n\n return requestBody;\n }\n\n private buildReasoningConfig(reasoning: import(\"../types\").ReasoningConfig, max_tokens?: number): any {\n const config: any = {};\n\n // Anthropic uses max_tokens - convert effort to max_tokens\n if (reasoning.effort || reasoning.enabled) {\n const effort = reasoning.effort || 'medium';\n const requestMaxTokens = max_tokens || 4096; // Default if not specified\n\n // Convert effort to percentage of max_tokens\n const effortRatios = { low: 0.2, medium: 0.5, high: 0.8 };\n const ratio = effortRatios[effort];\n\n // Calculate reasoning budget with Anthropic limits (1024 min, 32000 max)\n const reasoningBudget = Math.max(1024, Math.min(32000, Math.floor(requestMaxTokens * ratio)));\n config.max_tokens = reasoningBudget;\n }\n\n // Add exclude flag if specified\n if (reasoning.exclude !== undefined) {\n config.exclude = reasoning.exclude;\n }\n\n return Object.keys(config).length > 0 ? config : undefined;\n }\n\n private supportsNewStructuredOutputs(): boolean {\n // Check if model supports the new structured outputs API (Nov 2025)\n // Supported models: Sonnet >= 4.5, Opus >= 4.1\n // Note: Haiku does NOT support native structured outputs yet - uses tool workaround\n const model = this.config.model.toLowerCase();\n\n // Extract model family and version\n // Supports formats like: \"claude-sonnet-4-5\", \"anthropic/claude-opus-4.1\", \"claude-opus-4-5-20251124\"\n const sonnetMatch = model.match(/sonnet[_-](\\d+)[._-](\\d+)/);\n const opusMatch = model.match(/opus[_-](\\d+)[._-](\\d+)/);\n\n if (sonnetMatch) {\n const major = parseInt(sonnetMatch[1], 10);\n const minor = parseInt(sonnetMatch[2], 10);\n const version = major + minor / 10; // 4.5 = 4.5, 4.10 = 5.0\n return version >= 4.5;\n }\n\n if (opusMatch) {\n const major = parseInt(opusMatch[1], 10);\n const minor = parseInt(opusMatch[2], 10);\n const version = major + minor / 10;\n return version >= 4.1;\n }\n\n return false;\n }\n\n private fixSchemaForStrictMode(schema: any): any {\n // Recursively fix schema for strict mode requirements\n // Strict mode requires additionalProperties: false on ALL nested objects\n // STEP 1: Deep clone to prevent mutation (critical for consensus)\n const clonedSchema = JSON.parse(JSON.stringify(schema));\n\n // STEP 2: Ensure root has type: \"object\" (Anthropic requirement)\n if (!clonedSchema.type) {\n clonedSchema.type = 'object';\n }\n\n // STEP 3: Recursively fix all nested structures\n const fixRecursive = (obj: any): any => {\n if (!obj || typeof obj !== 'object') {\n return obj;\n }\n\n // Handle objects (both with and without properties)\n if (obj.type === 'object') {\n // Always add additionalProperties: false\n obj.additionalProperties = false;\n\n // If has properties, make all required and recurse\n if (obj.properties) {\n const allProps = Object.keys(obj.properties);\n obj.required = allProps;\n\n // Recursively fix nested properties\n for (const key in obj.properties) {\n obj.properties[key] = fixRecursive(obj.properties[key]);\n }\n }\n }\n\n // Handle arrays\n if (obj.type === 'array' && obj.items) {\n obj.items = fixRecursive(obj.items);\n }\n\n // Handle anyOf/oneOf/allOf (NEW - critical for nullable fields)\n ['anyOf', 'oneOf', 'allOf'].forEach(keyword => {\n if (obj[keyword] && Array.isArray(obj[keyword])) {\n obj[keyword] = obj[keyword].map((s: any) => fixRecursive(s));\n }\n });\n\n return obj;\n };\n\n return fixRecursive(clonedSchema);\n }\n\n private async buildMessages(input: MultimodalInput): Promise<any[]> {\n const content: any[] = [];\n const hasMedia = (input.images && input.images.length > 0) || (input.pdfs && input.pdfs.length > 0);\n\n // Debug: Log input state\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider.buildMessages] Input state:');\n console.log(' hasMedia:', hasMedia);\n console.log(' input.images:', input.images?.length || 0);\n console.log(' input.pdfs:', input.pdfs?.length || 0);\n console.log(' input.text:', input.text ? `\"${input.text.substring(0, 50)}...\"` : 'undefined');\n console.log(' via:', this.config.via);\n }\n\n // When using OpenRouter, use OpenAI-compatible format\n if (this.config.via === 'openrouter') {\n // Add images first (before text, so they get cached)\n if (input.images && input.images.length > 0) {\n for (const image of input.images) {\n if (image.url) {\n // If it's a data URL, use directly; otherwise it's a regular URL\n content.push({\n type: \"image_url\",\n image_url: { url: image.url }\n });\n } else if (image.base64) {\n // Automatically detect MIME type from actual file data to prevent mismatches\n const actualMimeType = detectMimeTypeFromBase64(image.base64);\n\n // Warn if declared MIME type doesn't match actual data\n if (image.mimeType && image.mimeType !== actualMimeType) {\n console.warn(\n `[AnthropicProvider] MIME type mismatch detected: ` +\n `declared \"${image.mimeType}\", actual \"${actualMimeType}\". ` +\n `Using detected type \"${actualMimeType}\" to prevent API errors.`\n );\n }\n\n content.push({\n type: \"image_url\",\n image_url: {\n url: `data:${actualMimeType};base64,${this.extractBase64(image.base64)}`\n }\n });\n }\n }\n }\n\n // Add PDFs second (before text, so they get cached)\n if (input.pdfs && input.pdfs.length > 0) {\n for (const pdf of input.pdfs) {\n let fileData: string;\n if (pdf.url) {\n fileData = pdf.url;\n } else if (pdf.base64) {\n // Automatically detect MIME type for PDFs too\n const actualMimeType = detectMimeTypeFromBase64(pdf.base64);\n\n if (actualMimeType !== 'application/pdf') {\n console.warn(\n `[AnthropicProvider] PDF MIME type mismatch: ` +\n `expected \"application/pdf\", detected \"${actualMimeType}\". ` +\n `Using detected type.`\n );\n }\n\n fileData = `data:${actualMimeType};base64,${this.extractBase64(pdf.base64)}`;\n } else {\n continue;\n }\n\n content.push({\n type: \"file\",\n file: {\n filename: \"document.pdf\",\n file_data: fileData\n }\n });\n }\n }\n\n // Add text last with cache_control if there's media\n // According to OpenRouter docs, cache_control can only be on text blocks\n // This caches all the images/PDFs that came before it\n if (hasMedia) {\n // Always add a text block with cache_control when we have media\n // Use provided text or a default instruction\n const textContent = input.text || \"Extract the requested information from the document.\";\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider.buildMessages] Adding text block with cache_control');\n console.log(' textContent:', textContent);\n }\n\n content.push({\n type: \"text\",\n text: textContent,\n cache_control: { type: \"ephemeral\" }\n });\n } else if (input.text) {\n // No media, just add text without caching\n content.push({\n type: \"text\",\n text: input.text\n });\n }\n } else {\n // Native Anthropic API format\n // Add text first\n if (input.text) {\n content.push({ type: \"text\", text: input.text });\n }\n // Native Anthropic API format\n // Add images\n if (input.images && input.images.length > 0) {\n for (const image of input.images) {\n if (image.url) {\n // Download and convert to base64 for Claude\n const base64 = await this.urlToBase64(image.url);\n content.push({\n type: \"image\",\n source: {\n type: \"base64\",\n media_type: image.mimeType,\n data: base64\n }\n });\n } else if (image.base64) {\n content.push({\n type: \"image\",\n source: {\n type: \"base64\",\n media_type: image.mimeType,\n data: this.extractBase64(image.base64)\n }\n });\n }\n }\n }\n\n // Add PDFs (convert to base64 or use Files API if fileId provided)\n if (input.pdfs && input.pdfs.length > 0) {\n for (const pdf of input.pdfs) {\n if (pdf.fileId) {\n // Use Files API reference\n content.push({\n type: \"document\",\n source: {\n type: \"file\",\n file_id: pdf.fileId\n }\n });\n } else if (pdf.base64) {\n content.push({\n type: \"document\",\n source: {\n type: \"base64\",\n media_type: \"application/pdf\",\n data: this.extractBase64(pdf.base64)\n }\n });\n } else if (pdf.url) {\n const base64 = await this.urlToBase64(pdf.url);\n content.push({\n type: \"document\",\n source: {\n type: \"base64\",\n media_type: \"application/pdf\",\n data: base64\n }\n });\n }\n }\n }\n }\n\n // Debug: Log final content array\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[AnthropicProvider.buildMessages] Final content array length:', content.length);\n console.log('[AnthropicProvider.buildMessages] Final content array:', JSON.stringify(content, null, 2));\n }\n\n return [{ role: \"user\", content }];\n }\n\n private async urlToBase64(url: string): Promise<string> {\n validateUrl(url); // SSRF protection\n const response = await fetchWithTimeout(url, {}, this.limits.REQUEST_TIMEOUT);\n if (!response.ok) {\n throw new Error(`Failed to fetch URL: ${url}`);\n }\n const buffer = await response.arrayBuffer();\n return Buffer.from(buffer).toString('base64');\n }\n\n /**\n * Extract base64 data from a data URL or return as-is if already raw base64\n */\n private extractBase64(input: string): string {\n if (input.startsWith('data:')) {\n // Extract base64 part from data URL: data:image/jpeg;base64,XXXXX -> XXXXX\n const base64Part = input.split(',')[1];\n if (!base64Part) {\n throw new Error(`Invalid data URL format: ${input.substring(0, 50)}`);\n }\n return base64Part;\n }\n return input;\n }\n\n private calculateCost(usage: any): number | undefined {\n if (!usage) return undefined;\n\n // Approximate costs for Claude 3.5 Sonnet (as of 2025)\n const inputCostPer1k = 0.003; // $0.003 per 1K input tokens\n const outputCostPer1k = 0.015; // $0.015 per 1K output tokens\n\n const inputCost = (usage.input_tokens / 1000) * inputCostPer1k;\n const outputCost = (usage.output_tokens / 1000) * outputCostPer1k;\n\n return inputCost + outputCost;\n }\n\n /**\n * Detect if a parsed JSON object looks like unwrapped JSON Schema properties\n * (e.g., missing the root \"type\": \"object\" and \"properties\": {...} wrapper)\n */\n private looksLikeUnwrappedProperties(obj: any): boolean {\n if (!obj || typeof obj !== 'object' || Array.isArray(obj)) {\n return false;\n }\n\n // If it already has \"type\" and \"properties\" at root, it's properly wrapped\n if (obj.type === 'object' && obj.properties) {\n return false;\n }\n\n // Check if it looks like a properties object:\n // - Has multiple keys\n // - Most/all values are objects with \"type\" property\n const keys = Object.keys(obj);\n if (keys.length === 0) {\n return false;\n }\n\n // Count how many top-level values look like schema property definitions\n let schemaPropertyCount = 0;\n for (const key of keys) {\n const value = obj[key];\n if (value && typeof value === 'object' && 'type' in value) {\n schemaPropertyCount++;\n }\n }\n\n // If most values look like schema properties, it's likely unwrapped\n return schemaPropertyCount / keys.length > 0.5;\n }\n\n /**\n * Wrap unwrapped properties into a proper JSON Schema structure\n */\n private wrapAsSchema(unwrapped: any): any {\n // Extract required fields (those that don't have optional markers)\n const required: string[] = [];\n for (const [key, value] of Object.entries(unwrapped)) {\n if (value && typeof value === 'object') {\n const propDef = value as any;\n // If the property definition has \"required\" array, it's a nested object\n // Otherwise, assume top-level properties are required\n if (!propDef.type || (propDef.type === 'string' || propDef.type === 'number' || propDef.type === 'boolean' || propDef.type === 'integer')) {\n required.push(key);\n } else if (propDef.type === 'object' || propDef.type === 'array') {\n required.push(key);\n }\n }\n }\n\n return {\n type: 'object',\n properties: unwrapped,\n required\n };\n }\n}\n","import type {\n LLMProvider,\n ProviderConfig,\n MultimodalInput,\n UnifiedSchema,\n LLMResponse,\n ProviderCapabilities,\n ResourceLimits,\n JsonMode,\n ReasoningConfig\n} from \"../types\";\nimport { SchemaTranslator } from \"../schema-translator\";\nimport { combineSchemaAndUserPrompt } from \"../schema-prompt-formatter\";\nimport { fetchWithTimeout, validateUrl, DEFAULT_LIMITS, safeJsonParse } from \"@doclo/core/security\";\n\n/** Internal types for Google API structures */\n\n/** Inline data for multimodal content (images/PDFs) */\ninterface GeminiInlineData {\n mimeType: string;\n data: string;\n}\n\n/** File data for Gemini Files API */\ninterface GeminiFileData {\n fileUri: string;\n mimeType: string;\n}\n\n/** A part of Gemini content */\ninterface GeminiPart {\n text?: string;\n inlineData?: GeminiInlineData;\n fileData?: GeminiFileData;\n thought?: boolean;\n}\n\n/** Gemini content structure */\ninterface GeminiContent {\n role: 'user' | 'model';\n parts: GeminiPart[];\n}\n\n/** Gemini generation config */\ninterface GeminiGenerationConfig {\n responseMimeType?: string;\n responseSchema?: object;\n thinking_config?: {\n thinking_budget: number;\n };\n}\n\n/** Gemini request body */\ninterface GeminiRequestBody {\n contents: GeminiContent[];\n generationConfig: GeminiGenerationConfig;\n}\n\n/** OpenRouter message content */\ntype OpenRouterContentPart =\n | { type: 'text'; text: string }\n | { type: 'image_url'; image_url: { url: string } }\n | { type: 'file'; file: { filename: string; file_data: string } };\n\n/** OpenRouter message */\ninterface OpenRouterMessage {\n role: 'user' | 'assistant' | 'system';\n content: string | OpenRouterContentPart[];\n}\n\n/** OpenRouter request format */\ninterface OpenRouterRequest {\n model: string;\n messages: OpenRouterMessage[];\n response_format?: { type: string };\n max_tokens?: number;\n reasoning?: { effort?: string; max_tokens?: number; exclude?: boolean };\n usage?: { include: boolean };\n}\n\n/** Reasoning config for OpenRouter */\ninterface OpenRouterReasoningConfig {\n effort?: string;\n max_tokens?: number;\n exclude?: boolean;\n}\n\n/**\n * Extract base provider name from model identifier.\n * For OpenRouter models like \"google/gemini-...\", extracts \"google\".\n * For direct models like \"gemini-...\", returns the default provider.\n */\nfunction extractProviderFromModel(model: string, defaultProvider: string): string {\n const slashIndex = model.indexOf('/');\n return slashIndex > 0 ? model.substring(0, slashIndex) : defaultProvider;\n}\n\nexport class GoogleProvider implements LLMProvider {\n readonly name: string;\n readonly capabilities: ProviderCapabilities = {\n supportsStructuredOutput: true,\n supportsStreaming: true,\n supportsImages: true,\n supportsPDFs: true,\n maxPDFPages: 1000, // 1 page = 1 image\n maxPDFSize: 50,\n maxContextTokens: 1000000 // 1M tokens\n };\n\n private config: ProviderConfig;\n private translator: SchemaTranslator;\n private limits: typeof DEFAULT_LIMITS;\n\n constructor(config: ProviderConfig) {\n this.config = config;\n // Extract base provider from model if it's an OpenRouter model (e.g., \"google/gemini-...\")\n const baseProvider = extractProviderFromModel(config.model, 'google');\n this.name = `${baseProvider}:${config.model}`;\n this.translator = new SchemaTranslator();\n\n // Merge custom limits with defaults (custom limits override defaults)\n this.limits = {\n ...DEFAULT_LIMITS,\n ...(config.limits || {})\n };\n\n // Debug logging\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[GoogleProvider] Config:', JSON.stringify({\n provider: config.provider,\n model: config.model,\n via: config.via,\n hasApiKey: !!config.apiKey\n }));\n }\n }\n\n async completeJson<T>(params: {\n input?: MultimodalInput;\n prompt?: MultimodalInput | string; // Alias for input (backwards compatibility with nodes)\n schema?: UnifiedSchema<T>;\n mode?: import(\"../types\").JsonMode;\n max_tokens?: number;\n reasoning?: import(\"../types\").ReasoningConfig;\n embedSchemaInPrompt?: boolean;\n }): Promise<LLMResponse<T>> {\n const startTime = Date.now();\n\n // Support both 'input' and 'prompt' parameter names (nodes use 'prompt')\n const rawInput = params.input ?? params.prompt;\n if (!rawInput) {\n throw new Error('Either input or prompt must be provided');\n }\n // Normalize string prompt to MultimodalInput\n const normalizedInput: MultimodalInput = typeof rawInput === 'string'\n ? { text: rawInput }\n : rawInput;\n\n // Determine mode: default to 'strict', auto-relaxed if schema omitted\n const mode = params.mode || (params.schema ? 'strict' : 'relaxed');\n\n // Validate: strict mode requires schema\n if (mode === 'strict' && !params.schema) {\n throw new Error('schema is required when mode is \"strict\"');\n }\n\n // Embed schema in prompt if enabled (default: true) and schema exists\n const shouldEmbedSchema = params.embedSchemaInPrompt !== false && params.schema;\n let enhancedInput = normalizedInput;\n\n if (shouldEmbedSchema) {\n // Convert schema to JSON Schema format\n const jsonSchema = this.translator.convertZodIfNeeded(params.schema!);\n\n // Combine schema prompt with user's text\n const enhancedText = combineSchemaAndUserPrompt(\n jsonSchema,\n normalizedInput.text || ''\n );\n\n enhancedInput = {\n ...normalizedInput,\n text: enhancedText\n };\n }\n\n // Build contents with multimodal parts (using enhanced input)\n const contents = await this.buildContents(enhancedInput);\n\n // Build request\n const requestBody: GeminiRequestBody = {\n contents,\n generationConfig: {\n // Google's native responseSchema has strict validation issues with complex schemas.\n // Use JSON mode without responseSchema - schema is already in the prompt via combineSchemaAndUserPrompt.\n // See: https://ubaidullahmomer.medium.com/why-google-geminis-response-schema-isn-t-ready-for-complex-json-46f35c3aaaea\n responseMimeType: \"application/json\"\n }\n };\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log(`[GoogleProvider] Using ${mode} JSON mode (schema in prompt, no responseSchema)`);\n }\n\n // Add native thinking configuration if using native API and reasoning is enabled\n if (this.config.via !== 'openrouter' && params.reasoning) {\n const thinkingConfig = this.buildNativeThinkingConfig(params.reasoning, params.max_tokens);\n if (thinkingConfig) {\n requestBody.generationConfig.thinking_config = thinkingConfig;\n }\n }\n\n // Make API call - check if using OpenRouter\n let response: Response;\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[GoogleProvider] Using via:', this.config.via, 'Checking:', this.config.via === 'openrouter');\n }\n\n if (this.config.via === 'openrouter') {\n // Use OpenRouter endpoint with OpenAI-compatible format\n const openRouterRequest = this.translateToOpenRouterFormat(contents, mode, params.max_tokens, params.reasoning);\n response = await fetchWithTimeout(\"https://openrouter.ai/api/v1/chat/completions\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.config.apiKey}`,\n \"HTTP-Referer\": \"https://github.com/docloai/sdk\",\n \"X-Title\": \"Doclo SDK\"\n },\n body: JSON.stringify(openRouterRequest)\n }, this.limits.REQUEST_TIMEOUT);\n } else {\n // Use native Google API\n // Note: Google's native API doesn't support Authorization headers,\n // so we must use the API key in the query parameter for authentication.\n // This is a documented limitation of Google's REST API.\n const endpoint = this.config.baseUrl ||\n `https://generativelanguage.googleapis.com/v1beta/models/${this.config.model}:generateContent`;\n\n // Validate the endpoint URL for SSRF attacks\n validateUrl(endpoint);\n\n response = await fetchWithTimeout(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-goog-api-key\": this.config.apiKey // Use header instead of query param\n },\n body: JSON.stringify(requestBody)\n }, this.limits.REQUEST_TIMEOUT);\n }\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Google API error (${response.status}): ${error}`);\n }\n\n const data = await response.json();\n const latencyMs = Date.now() - startTime;\n\n // Parse response based on via parameter\n let content: string;\n let inputTokens: number | undefined;\n let outputTokens: number | undefined;\n let costUSD: number | undefined;\n\n if (this.config.via === 'openrouter') {\n // OpenRouter format (OpenAI-compatible)\n const message = data.choices?.[0]?.message;\n content = message?.content?.trim() || \"{}\";\n inputTokens = data.usage?.prompt_tokens;\n outputTokens = data.usage?.completion_tokens;\n\n // Try different cost fields that OpenRouter might use\n costUSD = data.usage?.total_cost ?? data.usage?.cost;\n\n // Extract reasoning fields if present\n const reasoning = message?.reasoning;\n const reasoning_details = message?.reasoning_details;\n\n // Clean up markdown code blocks if present\n content = content.replace(/^```json\\s*\\n?/,'').replace(/\\n?```\\s*$/,'').trim();\n\n const parsed = safeJsonParse(content) as T;\n\n // Extract base provider from model for metrics\n const baseProvider = extractProviderFromModel(this.config.model, 'google');\n\n return {\n json: parsed as T,\n rawText: content,\n metrics: {\n costUSD,\n inputTokens,\n outputTokens,\n latencyMs,\n attemptNumber: 1,\n provider: baseProvider, // Base provider (e.g., \"google\" from \"google/gemini-...\")\n model: this.config.model\n },\n reasoning,\n reasoning_details\n };\n } else {\n // Native Google format\n const candidate = data.candidates?.[0];\n content = candidate?.content?.parts?.[0]?.text?.trim() || \"{}\";\n inputTokens = data.usageMetadata?.promptTokenCount;\n outputTokens = data.usageMetadata?.candidatesTokenCount;\n costUSD = this.calculateCost(data.usageMetadata);\n\n // Extract thinking content if present (native API)\n const thinkingPart = candidate?.content?.parts?.find((part: GeminiPart) => part.thought === true);\n const reasoning = thinkingPart?.text;\n\n const parsed = safeJsonParse(content) as T;\n\n // Extract base provider from model for metrics\n const baseProvider = extractProviderFromModel(this.config.model, 'google');\n\n return {\n json: parsed as T,\n rawText: content,\n metrics: {\n costUSD,\n inputTokens,\n outputTokens,\n latencyMs,\n attemptNumber: 1,\n provider: baseProvider, // Base provider (e.g., \"google\" from \"google/gemini-...\")\n model: this.config.model\n },\n reasoning,\n reasoning_details: reasoning ? [{\n type: 'reasoning.text' as const,\n text: reasoning,\n signature: null,\n id: 'thinking-1',\n format: 'google-gemini-v1'\n }] : undefined\n };\n }\n }\n\n private buildNativeThinkingConfig(reasoning: ReasoningConfig, max_tokens?: number): GeminiGenerationConfig['thinking_config'] | undefined {\n // Native Google uses \"thinking_budget\" parameter\n if (!reasoning.effort && !reasoning.enabled) {\n return undefined;\n }\n\n const effort = reasoning.effort || 'medium';\n const requestMaxTokens = max_tokens || 8192;\n\n // Convert effort to thinking_budget\n // Gemini 2.5 Flash supports 0-24576 tokens, default auto max is 8192\n const effortRatios = { low: 0.2, medium: 0.5, high: 0.8 };\n const ratio = effortRatios[effort];\n const thinking_budget = Math.min(24576, Math.floor(requestMaxTokens * ratio));\n\n return {\n thinking_budget\n };\n }\n\n private translateToOpenRouterFormat(\n contents: GeminiContent[],\n mode: JsonMode,\n max_tokens?: number,\n reasoning?: ReasoningConfig\n ): OpenRouterRequest {\n // Convert Gemini contents format to OpenAI messages format\n const messages: OpenRouterMessage[] = [];\n\n for (const content of contents) {\n if (content.role === 'user') {\n const messageContent: OpenRouterContentPart[] = [];\n\n for (const part of content.parts) {\n if (!part) continue; // Skip undefined/null parts\n if (part.text) {\n messageContent.push({ type: 'text', text: part.text });\n } else if (part.inlineData) {\n // Check if it's a PDF or image based on MIME type\n if (part.inlineData.mimeType === 'application/pdf') {\n // PDF - use file format\n messageContent.push({\n type: 'file',\n file: {\n filename: 'document.pdf',\n file_data: `data:${part.inlineData.mimeType};base64,${part.inlineData.data}`\n }\n });\n } else {\n // Image - use image_url format\n messageContent.push({\n type: 'image_url',\n image_url: {\n url: `data:${part.inlineData.mimeType};base64,${part.inlineData.data}`\n }\n });\n }\n }\n }\n\n messages.push({\n role: 'user',\n content: messageContent.length === 1 && messageContent[0].type === 'text'\n ? messageContent[0].text\n : messageContent\n });\n }\n }\n\n const requestBody: OpenRouterRequest = {\n model: this.config.model,\n messages,\n // Enable usage tracking for OpenRouter cost info\n usage: {\n include: true\n },\n // Both relaxed and strict modes use json_object for Google via OpenRouter\n // Schema is already in the prompt via combineSchemaAndUserPrompt\n response_format: {\n type: 'json_object'\n }\n };\n\n // Add reasoning configuration if provided (Google uses max_tokens like Anthropic)\n if (reasoning) {\n requestBody.reasoning = this.buildReasoningConfig(reasoning, max_tokens);\n }\n\n return requestBody;\n }\n\n private buildReasoningConfig(reasoning: ReasoningConfig, max_tokens?: number): OpenRouterReasoningConfig | undefined {\n const config: OpenRouterReasoningConfig = {};\n\n // Google uses max_tokens - convert effort to max_tokens\n if (reasoning.effort || reasoning.enabled) {\n const effort = reasoning.effort || 'medium';\n const requestMaxTokens = max_tokens || 8192; // Default for Gemini\n\n // Convert effort to percentage of max_tokens\n const effortRatios = { low: 0.2, medium: 0.5, high: 0.8 };\n const ratio = effortRatios[effort];\n\n // Calculate reasoning budget\n const reasoningBudget = Math.floor(requestMaxTokens * ratio);\n config.max_tokens = reasoningBudget;\n }\n\n // Add exclude flag if specified\n if (reasoning.exclude !== undefined) {\n config.exclude = reasoning.exclude;\n }\n\n return Object.keys(config).length > 0 ? config : undefined;\n }\n\n private async buildContents(input: MultimodalInput): Promise<GeminiContent[]> {\n const parts: GeminiPart[] = [];\n\n // Add text\n if (input.text) {\n parts.push({ text: input.text });\n }\n\n // Add images\n if (input.images && input.images.length > 0) {\n for (const image of input.images) {\n if (image.url) {\n const base64 = await this.urlToBase64(image.url);\n parts.push({\n inlineData: {\n mimeType: image.mimeType,\n data: base64\n }\n });\n } else if (image.base64) {\n parts.push({\n inlineData: {\n mimeType: image.mimeType,\n data: this.extractBase64(image.base64)\n }\n });\n }\n }\n }\n\n // Add PDFs (treated as images, 1 page = 1 image)\n if (input.pdfs && input.pdfs.length > 0) {\n for (const pdf of input.pdfs) {\n if (pdf.fileId) {\n // Use File API reference\n parts.push({\n fileData: {\n fileUri: `https://generativelanguage.googleapis.com/v1beta/files/${pdf.fileId}`,\n mimeType: \"application/pdf\"\n }\n });\n } else if (pdf.base64) {\n parts.push({\n inlineData: {\n mimeType: \"application/pdf\",\n data: this.extractBase64(pdf.base64)\n }\n });\n } else if (pdf.url) {\n const base64 = await this.urlToBase64(pdf.url);\n parts.push({\n inlineData: {\n mimeType: \"application/pdf\",\n data: base64\n }\n });\n }\n }\n }\n\n return [{ role: \"user\", parts }];\n }\n\n private async urlToBase64(url: string): Promise<string> {\n // Validate URL for SSRF attacks\n validateUrl(url);\n\n // Fetch with timeout protection (using instance-configured timeout)\n const response = await fetchWithTimeout(url, {}, this.limits.REQUEST_TIMEOUT);\n if (!response.ok) {\n throw new Error(`Failed to fetch URL: ${url}`);\n }\n const buffer = await response.arrayBuffer();\n return Buffer.from(buffer).toString('base64');\n }\n\n /**\n * Extract base64 data from a data URL or return as-is if already raw base64\n */\n private extractBase64(input: string): string {\n if (input.startsWith('data:')) {\n // Extract base64 part from data URL: data:image/jpeg;base64,XXXXX -> XXXXX\n const base64Part = input.split(',')[1];\n if (!base64Part) {\n throw new Error(`Invalid data URL format: ${input.substring(0, 50)}`);\n }\n return base64Part;\n }\n return input;\n }\n\n private calculateCost(usage: any): number | undefined {\n if (!usage) return undefined;\n\n // Approximate costs for Gemini 2.5 Flash (as of 2025)\n const inputCostPer1k = 0.00025; // $0.00025 per 1K input tokens\n const outputCostPer1k = 0.001; // $0.001 per 1K output tokens\n\n const inputCost = (usage.promptTokenCount / 1000) * inputCostPer1k;\n const outputCost = (usage.candidatesTokenCount / 1000) * outputCostPer1k;\n\n return inputCost + outputCost;\n }\n}\n","import type {\n LLMProvider,\n ProviderConfig,\n MultimodalInput,\n UnifiedSchema,\n LLMResponse,\n ProviderCapabilities,\n ResourceLimits\n} from \"../types\";\nimport { SchemaTranslator } from \"../schema-translator\";\nimport { combineSchemaAndUserPrompt } from \"../schema-prompt-formatter\";\nimport { fetchWithTimeout, DEFAULT_LIMITS, safeJsonParse } from \"@doclo/core/security\";\n\n/**\n * Extract base provider name from model identifier.\n * For OpenRouter models like \"x-ai/grok-...\", extracts \"x-ai\".\n * For direct models like \"grok-...\", returns the default provider.\n */\nfunction extractProviderFromModel(model: string, defaultProvider: string): string {\n const slashIndex = model.indexOf('/');\n return slashIndex > 0 ? model.substring(0, slashIndex) : defaultProvider;\n}\n\nexport class XAIProvider implements LLMProvider {\n readonly name: string;\n readonly capabilities: ProviderCapabilities = {\n supportsStructuredOutput: true,\n supportsStreaming: false, // Not with structured outputs\n supportsImages: true,\n supportsPDFs: true, // via page-by-page images\n maxPDFPages: undefined,\n maxPDFSize: undefined,\n maxContextTokens: 131072\n };\n\n private config: ProviderConfig;\n private translator: SchemaTranslator;\n private limits: typeof DEFAULT_LIMITS;\n\n constructor(config: ProviderConfig) {\n this.config = config;\n // Extract base provider from model if it's an OpenRouter model (e.g., \"x-ai/grok-...\")\n const baseProvider = extractProviderFromModel(config.model, 'xai');\n this.name = `${baseProvider}:${config.model}`;\n this.translator = new SchemaTranslator();\n\n // Merge custom limits with defaults\n this.limits = {\n ...DEFAULT_LIMITS,\n ...(config.limits || {})\n };\n }\n\n async completeJson<T>(params: {\n input: MultimodalInput;\n schema?: UnifiedSchema<T>;\n mode?: import(\"../types\").JsonMode;\n max_tokens?: number;\n reasoning?: import(\"../types\").ReasoningConfig;\n embedSchemaInPrompt?: boolean;\n }): Promise<LLMResponse<T>> {\n const startTime = Date.now();\n\n // Determine mode: default to 'strict', auto-relaxed if schema omitted\n const mode = params.mode || (params.schema ? 'strict' : 'relaxed');\n\n // Validate: strict mode requires schema\n if (mode === 'strict' && !params.schema) {\n throw new Error('schema is required when mode is \"strict\"');\n }\n\n // Embed schema in prompt if enabled (default: true) and schema exists\n const shouldEmbedSchema = params.embedSchemaInPrompt !== false && params.schema;\n let enhancedInput = params.input;\n\n if (shouldEmbedSchema) {\n // Convert schema to JSON Schema format\n const jsonSchema = this.translator.convertZodIfNeeded(params.schema!);\n\n // Combine schema prompt with user's text\n const enhancedText = combineSchemaAndUserPrompt(\n jsonSchema,\n params.input.text || ''\n );\n\n enhancedInput = {\n ...params.input,\n text: enhancedText\n };\n }\n\n // Build messages with multimodal content (using enhanced input)\n const messages = await this.buildMessages(enhancedInput);\n\n // Build request body\n const requestBody: any = {\n model: this.config.model,\n messages,\n max_tokens: params.max_tokens || 4096,\n stream: false, // Structured output doesn't support streaming\n // Enable usage tracking for OpenRouter cost info\n usage: {\n include: true\n }\n };\n\n if (mode === 'relaxed') {\n // Relaxed mode: just request valid JSON without strict schema\n requestBody.response_format = {\n type: \"json_object\"\n };\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[XAIProvider] Using relaxed JSON mode (json_object)');\n }\n } else {\n // Strict mode: use json_schema with strict validation\n const schema = this.translator.toOpenAISchema(params.schema!);\n\n // Recursively fix schema for strict mode requirements\n const fixSchemaRecursive = (obj: any): any => {\n if (obj && typeof obj === 'object') {\n if (obj.type === 'object' && obj.properties) {\n const allProps = Object.keys(obj.properties);\n obj.required = allProps;\n obj.additionalProperties = false;\n\n // Recursively fix nested properties\n for (const key in obj.properties) {\n obj.properties[key] = fixSchemaRecursive(obj.properties[key]);\n }\n } else if (obj.type === 'array' && obj.items) {\n // Recursively fix array items schema\n obj.items = fixSchemaRecursive(obj.items);\n }\n }\n return obj;\n };\n fixSchemaRecursive(schema);\n\n if (process.env.DEBUG_PROVIDERS) {\n console.log('[XAIProvider] Using strict JSON mode (json_schema)');\n }\n\n requestBody.response_format = {\n type: \"json_schema\",\n json_schema: {\n name: \"extraction\",\n schema\n }\n };\n }\n\n // Add reasoning configuration if provided (xAI uses effort like OpenAI)\n if (params.reasoning) {\n requestBody.reasoning = this.buildReasoningConfig(params.reasoning);\n }\n\n // Add OpenRouter model filtering for strict mode\n if (this.config.via === 'openrouter' && mode === 'strict') {\n requestBody.provider = {\n require_parameters: true // Only route to models supporting json_schema\n };\n }\n\n // Make API call - check if using OpenRouter\n const endpoint = this.config.via === 'openrouter'\n ? \"https://openrouter.ai/api/v1\"\n : (this.config.baseUrl || \"https://api.x.ai/v1\");\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.config.apiKey}`\n };\n\n // Add OpenRouter-specific headers\n if (this.config.via === 'openrouter') {\n headers[\"HTTP-Referer\"] = \"https://github.com/docloai/sdk\";\n headers[\"X-Title\"] = \"Doclo SDK\";\n }\n\n const response = await fetchWithTimeout(`${endpoint}/chat/completions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(requestBody)\n }, this.limits.REQUEST_TIMEOUT);\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`xAI API error (${response.status}): ${error}`);\n }\n\n const data = await response.json();\n const latencyMs = Date.now() - startTime;\n\n // Parse response\n const message = data.choices?.[0]?.message;\n const content = message?.content ?? \"{}\";\n const parsed = safeJsonParse(content) as T;\n\n // Extract reasoning fields if present\n const reasoning = message?.reasoning;\n const reasoning_details = message?.reasoning_details;\n\n // Extract cost from OpenRouter or calculate locally\n let costUSD: number | undefined;\n if (this.config.via === 'openrouter') {\n // Read cost from OpenRouter response (more accurate than local calculation)\n costUSD = data.usage?.total_cost ?? data.usage?.cost;\n } else {\n // Calculate cost locally for native xAI API\n costUSD = this.calculateCost(data.usage);\n }\n\n // Extract base provider from model for metrics\n const baseProvider = extractProviderFromModel(this.config.model, 'xai');\n\n return {\n json: parsed as T,\n rawText: content,\n metrics: {\n costUSD,\n inputTokens: data.usage?.prompt_tokens,\n outputTokens: data.usage?.completion_tokens,\n latencyMs,\n attemptNumber: 1,\n provider: baseProvider, // Base provider (e.g., \"x-ai\" from \"x-ai/grok-...\")\n model: this.config.model\n },\n reasoning,\n reasoning_details\n };\n }\n\n private buildReasoningConfig(reasoning: import(\"../types\").ReasoningConfig): any {\n const config: any = {};\n\n // xAI uses effort directly (like OpenAI)\n if (reasoning.effort) {\n config.effort = reasoning.effort;\n } else if (reasoning.enabled) {\n config.effort = 'medium'; // Default to medium\n }\n\n // Add exclude flag if specified\n if (reasoning.exclude !== undefined) {\n config.exclude = reasoning.exclude;\n }\n\n return Object.keys(config).length > 0 ? config : undefined;\n }\n\n private async buildMessages(input: MultimodalInput): Promise<any[]> {\n const content: any[] = [];\n\n // Add text\n if (input.text) {\n content.push({ type: \"text\", text: input.text });\n }\n\n // Add images\n if (input.images && input.images.length > 0) {\n for (const image of input.images) {\n if (image.url) {\n content.push({\n type: \"image_url\",\n image_url: { url: image.url }\n });\n } else if (image.base64) {\n content.push({\n type: \"image_url\",\n image_url: {\n url: `data:${image.mimeType};base64,${this.extractBase64(image.base64)}`\n }\n });\n }\n }\n }\n\n // Add PDFs - OpenRouter requires type: \"file\" format\n if (input.pdfs && input.pdfs.length > 0) {\n for (const pdf of input.pdfs) {\n let fileData: string;\n if (pdf.url) {\n fileData = pdf.url;\n } else if (pdf.base64) {\n fileData = `data:application/pdf;base64,${this.extractBase64(pdf.base64)}`;\n } else {\n continue;\n }\n\n content.push({\n type: \"file\",\n file: {\n filename: \"document.pdf\",\n file_data: fileData\n }\n });\n }\n }\n\n return [{ role: \"user\", content }];\n }\n\n /**\n * Extract base64 data from a data URL or return as-is if already raw base64\n */\n private extractBase64(input: string): string {\n if (input.startsWith('data:')) {\n // Extract base64 part from data URL: data:image/jpeg;base64,XXXXX -> XXXXX\n const base64Part = input.split(',')[1];\n if (!base64Part) {\n throw new Error(`Invalid data URL format: ${input.substring(0, 50)}`);\n }\n return base64Part;\n }\n return input;\n }\n\n private calculateCost(usage: any): number | undefined {\n if (!usage) return undefined;\n\n // Approximate costs for Grok (as of 2025)\n const inputCostPer1k = 0.005; // $0.005 per 1K input tokens\n const outputCostPer1k = 0.015; // $0.015 per 1K output tokens\n\n const inputCost = (usage.prompt_tokens / 1000) * inputCostPer1k;\n const outputCost = (usage.completion_tokens / 1000) * outputCostPer1k;\n\n return inputCost + outputCost;\n }\n}\n","import type {\n FallbackConfig,\n LLMProvider,\n MultimodalInput,\n UnifiedSchema,\n LLMResponse,\n CircuitBreakerState,\n JsonMode,\n ProviderConfig,\n ReasoningConfig\n} from \"./types\";\nimport { createProviderFromRegistry } from \"./provider-registry\";\nimport type {\n ObservabilityConfig,\n ProviderRequestContext,\n ProviderResponseContext,\n ProviderRetryContext,\n CircuitBreakerContext,\n TraceContext,\n} from \"@doclo/core/observability\";\nimport {\n executeHook,\n generateSpanId,\n createLogger,\n} from \"@doclo/core/observability\";\n\nexport class FallbackManager {\n private config: FallbackConfig;\n private circuitBreakers: Map<string, CircuitBreakerState>;\n\n constructor(config: FallbackConfig) {\n this.config = config;\n this.circuitBreakers = new Map();\n }\n\n async executeWithFallback<T>(\n input: MultimodalInput,\n schema: UnifiedSchema<T>,\n max_tokens?: number,\n reasoning?: ReasoningConfig,\n mode?: JsonMode,\n observability?: {\n config?: ObservabilityConfig;\n flowId?: string;\n executionId?: string;\n stepId?: string;\n traceContext?: TraceContext;\n metadata?: Record<string, unknown>;\n }\n ): Promise<LLMResponse<T>> {\n const errors: Array<{ provider: string; error: Error }> = [];\n\n // Create logger for this execution\n const logger = createLogger({\n observability: observability?.config,\n flowId: observability?.flowId,\n executionId: observability?.executionId,\n stepId: observability?.stepId,\n traceContext: observability?.traceContext,\n metadata: observability?.metadata,\n });\n\n for (const [providerIndex, providerConfig] of this.config.providers.entries()) {\n const providerKey = `${providerConfig.provider}:${providerConfig.model}`;\n\n // Check circuit breaker\n if (this.isCircuitOpen(providerKey)) {\n logger.warn(`Circuit breaker open for ${providerKey}, skipping`);\n\n // onCircuitBreakerTriggered hook\n if (observability?.config && observability.traceContext && observability.executionId) {\n const cbState = this.circuitBreakers.get(providerKey);\n const circuitBreakerContext: CircuitBreakerContext = {\n flowId: observability.flowId ?? 'flow',\n executionId: observability.executionId,\n timestamp: Date.now(),\n provider: providerConfig.provider,\n model: providerConfig.model,\n failureCount: cbState?.consecutiveFailures ?? 0,\n threshold: this.config.circuitBreakerThreshold ?? 5,\n cooldownMs: 60000, // Default cooldown\n metadata: observability.metadata,\n traceContext: observability.traceContext,\n };\n await executeHook(observability.config.onCircuitBreakerTriggered, {\n hookName: 'onCircuitBreakerTriggered',\n config: observability.config,\n context: circuitBreakerContext,\n });\n }\n\n continue;\n }\n\n // Create provider instance\n const provider = this.createProvider(providerConfig);\n\n // Primary (index 0) uses primaryMaxRetries, fallbacks use maxRetries\n const maxRetriesForProvider = providerIndex === 0\n ? (this.config.primaryMaxRetries ?? this.config.maxRetries)\n : this.config.maxRetries;\n\n // Try with retries\n let lastError: Error | null = null;\n for (let attempt = 1; attempt <= maxRetriesForProvider; attempt++) {\n try {\n logger.info(`Attempting ${providerKey} (attempt ${attempt}/${maxRetriesForProvider})`);\n\n const requestStartTime = Date.now();\n\n // onProviderRequest hook\n if (observability?.config && observability.traceContext && observability.executionId) {\n const providerRequestContext: ProviderRequestContext = {\n flowId: observability.flowId ?? 'flow',\n executionId: observability.executionId,\n stepId: observability.stepId,\n timestamp: requestStartTime,\n provider: providerConfig.provider,\n model: providerConfig.model,\n input: input,\n schema: schema,\n attemptNumber: attempt,\n maxAttempts: maxRetriesForProvider,\n metadata: observability.metadata,\n traceContext: observability.traceContext,\n };\n await executeHook(observability.config.onProviderRequest, {\n hookName: 'onProviderRequest',\n config: observability.config,\n context: providerRequestContext,\n });\n }\n\n const response = await provider.completeJson({ input, schema, max_tokens, reasoning, mode });\n\n // Success! Validate and return\n if (this.validateResponse(response)) {\n this.recordSuccess(providerKey);\n\n // onProviderResponse hook\n if (observability?.config && observability.traceContext && observability.executionId) {\n const providerResponseContext: ProviderResponseContext = {\n flowId: observability.flowId ?? 'flow',\n executionId: observability.executionId,\n stepId: observability.stepId,\n timestamp: Date.now(),\n startTime: requestStartTime,\n duration: Date.now() - requestStartTime,\n provider: providerConfig.provider,\n model: providerConfig.model,\n modelUsed: response.metrics.model,\n output: response.json,\n usage: {\n inputTokens: response.metrics.inputTokens ?? 0,\n outputTokens: response.metrics.outputTokens ?? 0,\n totalTokens: (response.metrics.inputTokens ?? 0) + (response.metrics.outputTokens ?? 0),\n cacheCreationInputTokens: response.metrics.cacheCreationInputTokens,\n cacheReadInputTokens: response.metrics.cacheReadInputTokens,\n },\n cost: response.metrics.costUSD ?? 0,\n finishReason: response.metrics.finishReason,\n attemptNumber: attempt,\n metadata: observability.metadata,\n traceContext: observability.traceContext,\n };\n await executeHook(observability.config.onProviderResponse, {\n hookName: 'onProviderResponse',\n config: observability.config,\n context: providerResponseContext,\n });\n }\n\n return {\n ...response,\n metrics: {\n ...response.metrics,\n attemptNumber: attempt\n }\n };\n } else {\n throw new Error(\"Response validation failed: incomplete or invalid data\");\n }\n } catch (error) {\n lastError = error as Error;\n logger.error(`${providerKey} attempt ${attempt} failed`, lastError, { providerKey, attempt });\n\n // Check if retryable\n if (!this.isRetryable(lastError) || attempt === maxRetriesForProvider) {\n break;\n }\n\n const retryDelay = this.calculateDelay(attempt);\n\n // onProviderRetry hook\n if (observability?.config && observability.traceContext && observability.executionId) {\n const providerRetryContext: ProviderRetryContext = {\n flowId: observability.flowId ?? 'flow',\n executionId: observability.executionId,\n stepId: observability.stepId,\n timestamp: Date.now(),\n provider: providerConfig.provider,\n model: providerConfig.model,\n attemptNumber: attempt,\n maxAttempts: maxRetriesForProvider,\n error: lastError,\n nextRetryDelay: retryDelay,\n metadata: observability.metadata,\n traceContext: observability.traceContext,\n };\n await executeHook(observability.config.onProviderRetry, {\n hookName: 'onProviderRetry',\n config: observability.config,\n context: providerRetryContext,\n });\n }\n\n // Wait before retry with exponential backoff + jitter\n await this.sleep(retryDelay);\n }\n }\n\n // All retries failed for this provider\n if (lastError) {\n errors.push({ provider: providerKey, error: lastError });\n this.recordFailure(providerKey);\n }\n }\n\n // All providers exhausted\n throw new Error(\n `All providers failed:\\n${errors.map(e => ` ${e.provider}: ${e.error.message}`).join('\\n')}`\n );\n }\n\n private createProvider(config: ProviderConfig): LLMProvider {\n return createProviderFromRegistry(config);\n }\n\n private validateResponse(response: LLMResponse): boolean {\n // Check if response has valid JSON\n if (!response.json || typeof response.json !== 'object') {\n return false;\n }\n\n // Empty objects are valid - the schema determines if they're acceptable\n // Models may return {} when no data matches the extraction criteria\n return true;\n }\n\n private isRetryable(error: Error): boolean {\n const message = error.message.toLowerCase();\n\n // Retryable status codes\n const retryablePatterns = [\n '408', '429', '500', '502', '503', '504',\n 'timeout', 'rate limit', 'overloaded'\n ];\n\n return retryablePatterns.some(pattern =>\n message.includes(pattern)\n );\n }\n\n private calculateDelay(attempt: number): number {\n if (!this.config.useExponentialBackoff) {\n return this.config.retryDelay;\n }\n\n // Exponential backoff: baseDelay * (2 ^ attempt) + jitter\n const exponentialDelay = this.config.retryDelay * Math.pow(2, attempt - 1);\n const jitter = Math.random() * 1000; // 0-1000ms jitter\n return Math.min(exponentialDelay + jitter, 30000); // Max 30s\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n\n // Circuit breaker logic\n private isCircuitOpen(providerKey: string): boolean {\n const state = this.circuitBreakers.get(providerKey);\n if (!state || !state.isOpen) return false;\n\n // Check if enough time has passed to try again (30 seconds)\n if (state.lastFailureTime && Date.now() - state.lastFailureTime > 30000) {\n this.circuitBreakers.set(providerKey, {\n consecutiveFailures: 0,\n isOpen: false\n });\n return false;\n }\n\n return true;\n }\n\n private recordSuccess(providerKey: string): void {\n this.circuitBreakers.set(providerKey, {\n consecutiveFailures: 0,\n isOpen: false\n });\n }\n\n private recordFailure(providerKey: string): void {\n const state = this.circuitBreakers.get(providerKey) || {\n consecutiveFailures: 0,\n isOpen: false\n };\n\n state.consecutiveFailures++;\n state.lastFailureTime = Date.now();\n\n // Open circuit if threshold reached\n const threshold = this.config.circuitBreakerThreshold || 3;\n if (state.consecutiveFailures >= threshold) {\n state.isOpen = true;\n // Use console.warn here as we don't have observability context in this method\n console.warn(`Circuit breaker opened for ${providerKey} after ${state.consecutiveFailures} failures`);\n }\n\n this.circuitBreakers.set(providerKey, state);\n }\n}\n","import type { LLMJsonProvider as CoreLLMProvider, MultimodalInput as CoreMultimodalInput } from \"@doclo/core\";\nimport type { LLMProvider, MultimodalInput } from \"./types\";\n\n/**\n * Adapter to make new LLMProvider compatible with core LLMJsonProvider interface\n */\nexport function adaptToCoreLLMProvider(provider: LLMProvider): CoreLLMProvider {\n return {\n name: provider.name,\n capabilities: {\n supportsImages: true,\n supportsPDFs: provider.capabilities.supportsPDFs,\n maxPDFPages: provider.capabilities.maxPDFPages\n },\n async completeJson(input: {\n prompt: string | CoreMultimodalInput;\n schema: object;\n max_tokens?: number;\n reasoning?: import(\"./types\").ReasoningConfig;\n }) {\n // Convert input to MultimodalInput format\n let multimodalInput: MultimodalInput;\n\n if (typeof input.prompt === 'string') {\n // Simple string prompt\n multimodalInput = { text: input.prompt };\n } else {\n // Already multimodal\n multimodalInput = input.prompt as MultimodalInput;\n }\n\n // Call the new provider with reasoning parameters\n const response = await provider.completeJson({\n input: multimodalInput,\n schema: input.schema as any,\n max_tokens: input.max_tokens,\n reasoning: input.reasoning\n });\n\n // Convert response to core format (including reasoning fields and cache metrics)\n return {\n json: response.json,\n rawText: response.rawText,\n costUSD: response.metrics.costUSD,\n inputTokens: response.metrics.inputTokens,\n outputTokens: response.metrics.outputTokens,\n cacheCreationInputTokens: response.metrics.cacheCreationInputTokens,\n cacheReadInputTokens: response.metrics.cacheReadInputTokens\n };\n }\n };\n}\n","/**\n * LLM Provider Metadata\n *\n * Comprehensive metadata for all LLM/VLM providers including:\n * - Supported file types (inline/base64 encoded)\n * - Input/output formats\n * - Pricing\n * - Capabilities\n * - Native API vs OpenRouter differences\n */\n\n// Supported image MIME types (common across providers)\nexport const SUPPORTED_IMAGE_TYPES = {\n COMMON: ['image/png', 'image/jpeg', 'image/webp', 'image/gif'] as const,\n EXTENDED: ['image/png', 'image/jpeg', 'image/webp', 'image/gif', 'image/bmp', 'image/tiff', 'image/heif'] as const\n} as const;\n\n/**\n * Input type requirements for providers.\n * - 'raw-document': Needs FlowInput with base64/url\n * - 'parsed-text': Needs DocumentIR text output\n * - 'any': Can work with either (LLM providers with vision)\n */\nexport type ProviderInputType = 'raw-document' | 'parsed-text' | 'any';\n\n/**\n * Model-level metadata for per-model capability overrides\n */\nexport type LLMModelMetadata = {\n /** Model ID as used in API calls */\n id: string;\n\n /** Human-readable name */\n name?: string;\n\n /** OpenRouter model ID (e.g., 'openai/gpt-4.1') */\n openRouterId: string;\n\n /** Capability overrides (inherit from provider if unset) */\n capabilities?: {\n supportsReasoning?: boolean;\n supportsImages?: boolean;\n supportsPDFs?: boolean;\n supportsStructuredOutput?: boolean;\n };\n\n /** Model-specific limits */\n limits?: {\n maxContextTokens?: number;\n maxOutputTokens?: number;\n };\n\n /** Model-specific pricing (USD per 1k tokens) */\n pricing?: {\n inputPer1k?: number;\n outputPer1k?: number;\n };\n};\n\n// Provider metadata type\nexport type LLMProviderMetadata = {\n id: string;\n name: string;\n vendor: 'openai' | 'anthropic' | 'google' | 'xai';\n models: string[]; // Legacy: list of model IDs\n /**\n * Detailed per-model metadata with capability overrides.\n * Use this for model-specific reasoning, pricing, and limits.\n */\n detailedModels?: LLMModelMetadata[];\n accessMethods: {\n native: {\n available: boolean;\n endpoint: string;\n requiresApiKey: boolean;\n };\n openrouter: {\n available: boolean;\n modelPrefix: string; // e.g., 'openai/', 'anthropic/'\n };\n };\n capabilities: {\n supportsImages: boolean;\n supportsPDFs: boolean;\n supportsReasoning: boolean;\n supportsStreaming: boolean;\n supportsStructuredOutput: boolean;\n };\n /**\n * Input requirements for this provider.\n * LLM providers with vision can accept either raw documents OR parsed text.\n */\n inputRequirements?: {\n inputType: ProviderInputType;\n acceptedMethods?: readonly ('url' | 'base64')[];\n };\n compatibleNodes: {\n parse: boolean; // Can be used in parse() node\n extract: boolean; // Can be used in extract() node\n categorize: boolean; // Can be used in categorize() node\n qualify: boolean; // Can be used in qualify() node\n split: boolean; // Can be used in split() node\n };\n inputFormats: {\n images: {\n mimeTypes: readonly string[];\n methods: ('url' | 'base64')[];\n maxSize?: number; // MB\n maxDimensions?: { width: number; height: number };\n notes?: string;\n };\n pdfs: {\n supported: boolean;\n methods: ('url' | 'base64' | 'fileId')[];\n maxSize?: number; // MB\n maxPages?: number;\n notes?: string;\n };\n };\n outputFormat: {\n supportsJSON: boolean;\n supportsReasoning: boolean;\n tokenTracking: boolean;\n costTracking: boolean;\n };\n pricing: {\n model: 'per-token';\n inputPer1k: number; // USD - used for native API cost calculation\n outputPer1k: number; // USD - used for native API cost calculation\n currency: 'USD';\n notes?: string; // OpenRouter returns cost; native APIs require calculation\n };\n limits: {\n maxContextTokens: number;\n maxOutputTokens?: number;\n requestsPerMinute?: number;\n };\n nativeAPI: {\n imageFormat: string; // e.g., 'type: image, source: base64'\n pdfFormat: string; // e.g., 'type: document, source: base64'\n reasoningConfig: string; // e.g., 'thinking: { type: enabled }'\n };\n openRouterAPI: {\n imageFormat: string; // e.g., 'type: image_url'\n pdfFormat: string; // e.g., 'type: file'\n reasoningConfig: string; // e.g., 'reasoning: { max_tokens }'\n differences: string[]; // Key differences from native\n };\n};\n\n// Provider metadata\nexport const PROVIDER_METADATA = {\n openai: {\n id: 'openai',\n name: 'OpenAI',\n vendor: 'openai',\n models: ['gpt-5.1', 'gpt-4.1', 'gpt-4.1-mini', 'o3', 'o3-mini', 'o4-mini'],\n detailedModels: [\n {\n id: 'gpt-4.1',\n name: 'GPT-4.1',\n openRouterId: 'openai/gpt-4.1',\n capabilities: { supportsReasoning: false },\n limits: { maxContextTokens: 128000, maxOutputTokens: 16384 },\n pricing: { inputPer1k: 0.002, outputPer1k: 0.008 },\n },\n {\n id: 'gpt-4.1-mini',\n name: 'GPT-4.1 Mini',\n openRouterId: 'openai/gpt-4.1-mini',\n capabilities: { supportsReasoning: false },\n limits: { maxContextTokens: 128000, maxOutputTokens: 16384 },\n pricing: { inputPer1k: 0.0004, outputPer1k: 0.0016 },\n },\n {\n id: 'o3',\n name: 'o3',\n openRouterId: 'openai/o3',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 100000 },\n pricing: { inputPer1k: 0.010, outputPer1k: 0.040 },\n },\n {\n id: 'o3-mini',\n name: 'o3-mini',\n openRouterId: 'openai/o3-mini',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 100000 },\n pricing: { inputPer1k: 0.0011, outputPer1k: 0.0044 },\n },\n {\n id: 'o4-mini',\n name: 'o4-mini',\n openRouterId: 'openai/o4-mini',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 100000 },\n pricing: { inputPer1k: 0.0011, outputPer1k: 0.0044 },\n },\n {\n id: 'gpt-5.1',\n name: 'GPT-5.1',\n openRouterId: 'openai/gpt-5.1',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 256000, maxOutputTokens: 32768 },\n pricing: { inputPer1k: 0.005, outputPer1k: 0.015 },\n },\n ],\n accessMethods: {\n native: {\n available: true,\n endpoint: 'https://api.openai.com/v1',\n requiresApiKey: true\n },\n openrouter: {\n available: true,\n modelPrefix: 'openai/'\n }\n },\n capabilities: {\n supportsImages: true,\n supportsPDFs: true,\n supportsReasoning: true,\n supportsStreaming: true,\n supportsStructuredOutput: true\n },\n // LLM with vision - can work with raw documents OR parsed text\n inputRequirements: {\n inputType: 'any',\n acceptedMethods: ['url', 'base64']\n },\n compatibleNodes: {\n parse: true, // ✅ VLMProvider - can convert images/PDFs to text\n extract: true, // ✅ VLMProvider - can extract structured data\n categorize: true, // ✅ VLMProvider - can classify documents\n qualify: true, // ✅ VLMProvider - can assess quality\n split: true // ✅ VLMProvider - can detect document boundaries\n },\n inputFormats: {\n images: {\n mimeTypes: SUPPORTED_IMAGE_TYPES.COMMON,\n methods: ['url', 'base64'],\n maxSize: 20, // 20 MB per image\n maxDimensions: undefined, // Images resized server-side\n notes: 'Inline via image_url with data URL or HTTP URL. Large images auto-resized.'\n },\n pdfs: {\n supported: true,\n methods: ['base64', 'fileId'],\n maxSize: 50, // 50 MB per file, 50 MB total per request\n maxPages: 100,\n notes: 'Inline via type: file with base64, or via Files API. Extracts text + images of each page. File URLs NOT supported for chat completions.'\n }\n },\n outputFormat: {\n supportsJSON: true,\n supportsReasoning: true,\n tokenTracking: true,\n costTracking: true\n },\n pricing: {\n model: 'per-token',\n inputPer1k: 0.005,\n outputPer1k: 0.015,\n currency: 'USD',\n notes: 'Cost calculated from tokens. OpenRouter may include cost in response. GPT-4.1 baseline.'\n },\n limits: {\n maxContextTokens: 128000,\n maxOutputTokens: 16384,\n requestsPerMinute: undefined\n },\n nativeAPI: {\n imageFormat: 'type: \"image_url\", image_url: { url: \"data:image/jpeg;base64,...\" }',\n pdfFormat: 'type: \"file\", file: { file_id: \"...\" } OR file: { filename: \"...\", file_data: \"data:application/pdf;base64,...\" }',\n reasoningConfig: 'reasoning: { effort: \"low\"|\"medium\"|\"high\", exclude?: boolean }'\n },\n openRouterAPI: {\n imageFormat: 'Same as native (OpenAI-compatible)',\n pdfFormat: 'Same as native (OpenAI-compatible)',\n reasoningConfig: 'Same as native (OpenAI-compatible)',\n differences: [\n 'File URLs not supported (base64 only)',\n 'Cost may be available via usage.total_cost or generation endpoint'\n ]\n }\n },\n\n anthropic: {\n id: 'anthropic',\n name: 'Anthropic (Claude)',\n vendor: 'anthropic',\n models: ['claude-opus-4.5', 'claude-sonnet-4.5', 'claude-haiku-4.5', 'claude-opus-4', 'claude-sonnet-4'],\n detailedModels: [\n {\n id: 'claude-opus-4.5',\n name: 'Claude Opus 4.5',\n openRouterId: 'anthropic/claude-opus-4.5',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 32000 },\n pricing: { inputPer1k: 0.015, outputPer1k: 0.075 },\n },\n {\n id: 'claude-sonnet-4.5',\n name: 'Claude Sonnet 4.5',\n openRouterId: 'anthropic/claude-sonnet-4.5',\n // Reasoning available via toggle (extended thinking)\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 16000 },\n pricing: { inputPer1k: 0.003, outputPer1k: 0.015 },\n },\n {\n id: 'claude-haiku-4.5',\n name: 'Claude Haiku 4.5',\n openRouterId: 'anthropic/claude-haiku-4.5',\n // Reasoning available via toggle (extended thinking)\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 8192 },\n pricing: { inputPer1k: 0.0008, outputPer1k: 0.004 },\n },\n {\n id: 'claude-opus-4',\n name: 'Claude Opus 4',\n openRouterId: 'anthropic/claude-opus-4',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 32000 },\n pricing: { inputPer1k: 0.015, outputPer1k: 0.075 },\n },\n {\n id: 'claude-sonnet-4',\n name: 'Claude Sonnet 4',\n openRouterId: 'anthropic/claude-sonnet-4',\n // Reasoning available via toggle (extended thinking)\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 200000, maxOutputTokens: 16000 },\n pricing: { inputPer1k: 0.003, outputPer1k: 0.015 },\n },\n ],\n accessMethods: {\n native: {\n available: true,\n endpoint: 'https://api.anthropic.com/v1',\n requiresApiKey: true\n },\n openrouter: {\n available: true,\n modelPrefix: 'anthropic/'\n }\n },\n capabilities: {\n supportsImages: true,\n supportsPDFs: true,\n supportsReasoning: true,\n supportsStreaming: true,\n supportsStructuredOutput: true\n },\n // LLM with vision - can work with raw documents OR parsed text\n inputRequirements: {\n inputType: 'any',\n acceptedMethods: ['base64'] // URLs must be downloaded and converted\n },\n compatibleNodes: {\n parse: true,\n extract: true,\n categorize: true,\n qualify: true,\n split: true\n },\n inputFormats: {\n images: {\n mimeTypes: SUPPORTED_IMAGE_TYPES.COMMON,\n methods: ['base64'], // URLs must be downloaded and converted\n maxSize: 5, // 5 MB per image (API), 10 MB (claude.ai)\n maxDimensions: { width: 8000, height: 8000 }, // Standard limit, 2000x2000 for 20+ images\n notes: 'Native API requires base64. Max 100 images/request. Optimal at 1568px max dimension.'\n },\n pdfs: {\n supported: true,\n methods: ['base64', 'fileId'],\n maxSize: 32, // 32 MB per file\n maxPages: 100, // 100 pages for full visual analysis\n notes: 'Inline via type: document with base64, or via Files API (beta). PDFs over 100 pages: text-only processing.'\n }\n },\n outputFormat: {\n supportsJSON: true,\n supportsReasoning: true,\n tokenTracking: true,\n costTracking: true\n },\n pricing: {\n model: 'per-token',\n inputPer1k: 0.003,\n outputPer1k: 0.015,\n currency: 'USD',\n notes: 'Cost calculated from tokens. OpenRouter may include cost in response. Claude 3.5 Sonnet baseline.'\n },\n limits: {\n maxContextTokens: 200000,\n maxOutputTokens: 8192,\n requestsPerMinute: undefined\n },\n nativeAPI: {\n imageFormat: 'type: \"image\", source: { type: \"base64\", media_type: \"image/jpeg\", data: \"...\" }',\n pdfFormat: 'type: \"document\", source: { type: \"base64\"|\"file\", media_type: \"application/pdf\", data: \"...\" | file_id: \"...\" }',\n reasoningConfig: 'thinking: { type: \"enabled\", budget_tokens: 1024-32000 }'\n },\n openRouterAPI: {\n imageFormat: 'type: \"image_url\", image_url: { url: \"data:image/jpeg;base64,...\" }',\n pdfFormat: 'type: \"file\", file: { filename: \"...\", file_data: \"data:application/pdf;base64,...\" }',\n reasoningConfig: 'reasoning: { max_tokens: number, exclude?: boolean }',\n differences: [\n 'Uses OpenAI-compatible format (image_url, file types)',\n 'Reasoning uses max_tokens instead of budget_tokens',\n 'Response prefill trick ({ role: \"assistant\", content: \"{\" }) for strict JSON',\n 'Tool calling instead of native structured output'\n ]\n }\n },\n\n google: {\n id: 'google',\n name: 'Google (Gemini)',\n vendor: 'google',\n models: ['gemini-3-pro', 'gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-2.5-flash-lite'],\n detailedModels: [\n {\n id: 'gemini-3-pro',\n name: 'Gemini 3 Pro',\n openRouterId: 'google/gemini-3-pro',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 1000000, maxOutputTokens: 65536 },\n pricing: { inputPer1k: 0.00125, outputPer1k: 0.005 },\n },\n {\n id: 'gemini-2.5-pro',\n name: 'Gemini 2.5 Pro',\n openRouterId: 'google/gemini-2.5-pro-preview-06-05',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 1000000, maxOutputTokens: 65536 },\n pricing: { inputPer1k: 0.00125, outputPer1k: 0.005 },\n },\n {\n id: 'gemini-2.5-flash',\n name: 'Gemini 2.5 Flash',\n openRouterId: 'google/gemini-2.5-flash-preview-09-2025',\n capabilities: { supportsReasoning: false },\n limits: { maxContextTokens: 1000000, maxOutputTokens: 8192 },\n pricing: { inputPer1k: 0.00015, outputPer1k: 0.0006 },\n },\n {\n id: 'gemini-2.5-flash-lite',\n name: 'Gemini 2.5 Flash Lite',\n openRouterId: 'google/gemini-2.5-flash-lite',\n capabilities: { supportsReasoning: false },\n limits: { maxContextTokens: 1000000, maxOutputTokens: 8192 },\n pricing: { inputPer1k: 0.000075, outputPer1k: 0.0003 },\n },\n ],\n accessMethods: {\n native: {\n available: true,\n endpoint: 'https://generativelanguage.googleapis.com/v1beta',\n requiresApiKey: true\n },\n openrouter: {\n available: true,\n modelPrefix: 'google/'\n }\n },\n capabilities: {\n supportsImages: true,\n supportsPDFs: true,\n supportsReasoning: true,\n supportsStreaming: true,\n supportsStructuredOutput: true\n },\n // LLM with vision - can work with raw documents OR parsed text\n inputRequirements: {\n inputType: 'any',\n acceptedMethods: ['base64'] // URLs are downloaded and converted\n },\n compatibleNodes: {\n parse: true,\n extract: true,\n categorize: true,\n qualify: true,\n split: true\n },\n inputFormats: {\n images: {\n mimeTypes: [...SUPPORTED_IMAGE_TYPES.COMMON, 'image/bmp', 'image/tiff', 'image/heif'],\n methods: ['base64'], // URLs are downloaded and converted\n maxSize: 20, // 20 MB inline data limit (File API: 2GB for Gemini 2.0)\n maxDimensions: { width: 3072, height: 3072 }, // Images scaled to fit, padded to preserve ratio\n notes: 'Inline via inlineData. Max 3000 images/request. File API supports larger files (stored 48 hours).'\n },\n pdfs: {\n supported: true,\n methods: ['base64', 'fileId'],\n maxSize: 50, // 50 MB limit (inline & File API)\n maxPages: 1000, // 1000 pages max, each page = 258 tokens\n notes: 'Inline via inlineData OR File API. Pages scaled to 3072x3072 max. Native text not charged.'\n }\n },\n outputFormat: {\n supportsJSON: true,\n supportsReasoning: true,\n tokenTracking: true,\n costTracking: true\n },\n pricing: {\n model: 'per-token',\n inputPer1k: 0.00025,\n outputPer1k: 0.001,\n currency: 'USD',\n notes: 'Cost calculated from tokens. OpenRouter may include cost in response. Gemini 2.5 Flash baseline.'\n },\n limits: {\n maxContextTokens: 1000000, // 1M tokens\n maxOutputTokens: 8192,\n requestsPerMinute: undefined\n },\n nativeAPI: {\n imageFormat: 'inlineData: { mimeType: \"image/jpeg\", data: \"...\" }',\n pdfFormat: 'inlineData: { mimeType: \"application/pdf\", data: \"...\" } OR fileData: { fileUri: \"...\", mimeType: \"application/pdf\" }',\n reasoningConfig: 'generationConfig.thinking_config: { thinking_budget: number } (max 24576)'\n },\n openRouterAPI: {\n imageFormat: 'type: \"image_url\", image_url: { url: \"data:image/jpeg;base64,...\" }',\n pdfFormat: 'type: \"file\", file: { filename: \"...\", file_data: \"data:application/pdf;base64,...\" }',\n reasoningConfig: 'reasoning: { max_tokens: number, exclude?: boolean }',\n differences: [\n 'Uses OpenAI-compatible format instead of parts/inlineData',\n 'Reasoning uses max_tokens instead of thinking_budget',\n 'Different content structure (messages vs contents.parts)'\n ]\n }\n },\n\n xai: {\n id: 'xai',\n name: 'xAI (Grok)',\n vendor: 'xai',\n models: ['grok-4.1', 'grok-4.1-fast', 'grok-4', 'grok-4-fast'],\n detailedModels: [\n {\n id: 'grok-4.1',\n name: 'Grok 4.1',\n openRouterId: 'x-ai/grok-4.1',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 256000, maxOutputTokens: 32768 },\n pricing: { inputPer1k: 0.003, outputPer1k: 0.015 },\n },\n {\n id: 'grok-4.1-fast',\n name: 'Grok 4.1 Fast',\n openRouterId: 'x-ai/grok-4.1-fast',\n capabilities: { supportsReasoning: false },\n limits: { maxContextTokens: 2000000, maxOutputTokens: 32768 },\n pricing: { inputPer1k: 0.005, outputPer1k: 0.025 },\n },\n {\n id: 'grok-4',\n name: 'Grok 4',\n openRouterId: 'x-ai/grok-4',\n capabilities: { supportsReasoning: true },\n limits: { maxContextTokens: 256000, maxOutputTokens: 32768 },\n pricing: { inputPer1k: 0.003, outputPer1k: 0.015 },\n },\n {\n id: 'grok-4-fast',\n name: 'Grok 4 Fast',\n openRouterId: 'x-ai/grok-4-fast',\n capabilities: { supportsReasoning: false },\n limits: { maxContextTokens: 2000000, maxOutputTokens: 32768 },\n pricing: { inputPer1k: 0.005, outputPer1k: 0.025 },\n },\n ],\n accessMethods: {\n native: {\n available: true,\n endpoint: 'https://api.x.ai/v1',\n requiresApiKey: true\n },\n openrouter: {\n available: true,\n modelPrefix: 'xai/'\n }\n },\n capabilities: {\n supportsImages: true,\n supportsPDFs: true,\n supportsReasoning: true,\n supportsStreaming: false, // Not with structured outputs\n supportsStructuredOutput: true\n },\n // LLM with vision - can work with raw documents OR parsed text\n inputRequirements: {\n inputType: 'any',\n acceptedMethods: ['url', 'base64']\n },\n compatibleNodes: {\n parse: true,\n extract: true,\n categorize: true,\n qualify: true,\n split: true\n },\n inputFormats: {\n images: {\n mimeTypes: ['image/jpeg', 'image/png'], // Only jpg/jpeg and png supported\n methods: ['url', 'base64'],\n maxSize: 30, // 30 MB per file (API), 25 MB (chat)\n maxDimensions: undefined,\n notes: 'OpenAI-compatible format. Max 10 images via API. Only JPEG/PNG supported.'\n },\n pdfs: {\n supported: true,\n methods: ['url', 'base64'],\n maxSize: 30, // 30 MB per file\n maxPages: undefined,\n notes: 'OpenAI-compatible format. Inline via type: file. Also supports DOCX, TXT, MD, CSV.'\n }\n },\n outputFormat: {\n supportsJSON: true,\n supportsReasoning: true,\n tokenTracking: true,\n costTracking: true\n },\n pricing: {\n model: 'per-token',\n inputPer1k: 0.005,\n outputPer1k: 0.015,\n currency: 'USD',\n notes: 'Cost calculated from tokens. OpenRouter may include cost in response. Grok-4 baseline.'\n },\n limits: {\n maxContextTokens: 131072,\n maxOutputTokens: undefined,\n requestsPerMinute: undefined\n },\n nativeAPI: {\n imageFormat: 'type: \"image_url\", image_url: { url: \"data:image/jpeg;base64,...\" }',\n pdfFormat: 'type: \"file\", file: { filename: \"...\", file_data: \"data:application/pdf;base64,...\" }',\n reasoningConfig: 'reasoning: { effort: \"low\"|\"medium\"|\"high\", exclude?: boolean }'\n },\n openRouterAPI: {\n imageFormat: 'Same as native (OpenAI-compatible)',\n pdfFormat: 'Same as native (OpenAI-compatible)',\n reasoningConfig: 'Same as native (OpenAI-compatible)',\n differences: [\n 'Minimal differences - xAI uses OpenAI-compatible format',\n 'Cost tracking via usage.total_cost field in OpenRouter'\n ]\n }\n }\n} as const satisfies Record<string, LLMProviderMetadata>;\n\n// Helper functions\n\n/**\n * Check if an image MIME type is supported by a provider\n *\n * @param providerId - Provider ID\n * @param mimeType - MIME type to check\n * @returns True if supported\n *\n * @example\n * ```typescript\n * isImageTypeSupported('openai', 'image/png') // true\n * isImageTypeSupported('openai', 'image/bmp') // false\n * isImageTypeSupported('google', 'image/bmp') // true\n * ```\n */\nexport function isImageTypeSupported(\n providerId: keyof typeof PROVIDER_METADATA,\n mimeType: string\n): boolean {\n const provider = PROVIDER_METADATA[providerId];\n return provider.inputFormats.images.mimeTypes.includes(mimeType as any);\n}\n\n/**\n * Check if a provider supports PDFs inline (base64)\n *\n * @param providerId - Provider ID\n * @returns True if inline PDFs are supported\n *\n * @example\n * ```typescript\n * supportsPDFsInline('openai') // true\n * supportsPDFsInline('anthropic') // true\n * supportsPDFsInline('google') // true\n * ```\n */\nexport function supportsPDFsInline(\n providerId: keyof typeof PROVIDER_METADATA\n): boolean {\n const provider = PROVIDER_METADATA[providerId];\n return provider.inputFormats.pdfs.supported &&\n provider.inputFormats.pdfs.methods.includes('base64');\n}\n\n/**\n * Get providers compatible with a specific node type\n *\n * @param nodeType - Node type to check\n * @returns Array of compatible provider metadata\n *\n * @example\n * ```typescript\n * // Get providers that work with parse()\n * const parseProviders = getProvidersForNode('parse');\n * // Returns: [openai, anthropic, google, xai] (all VLM providers)\n *\n * // Get providers that work with extract()\n * const extractProviders = getProvidersForNode('extract');\n * // Returns: [openai, anthropic, google, xai] (all VLM providers)\n * ```\n */\nexport function getProvidersForNode(\n nodeType: 'parse' | 'extract' | 'categorize' | 'qualify' | 'split'\n): LLMProviderMetadata[] {\n return Object.values(PROVIDER_METADATA).filter(\n provider => provider.compatibleNodes[nodeType]\n );\n}\n\n/**\n * Check if a provider is compatible with a node type\n *\n * @param providerId - Provider ID\n * @param nodeType - Node type to check\n * @returns True if compatible\n *\n * @example\n * ```typescript\n * isProviderCompatibleWithNode('openai', 'parse'); // true\n * isProviderCompatibleWithNode('openai', 'extract'); // true\n * isProviderCompatibleWithNode('anthropic', 'qualify'); // true\n * ```\n */\nexport function isProviderCompatibleWithNode(\n providerId: keyof typeof PROVIDER_METADATA,\n nodeType: 'parse' | 'extract' | 'categorize' | 'qualify' | 'split'\n): boolean {\n return PROVIDER_METADATA[providerId].compatibleNodes[nodeType];\n}\n\n/**\n * Estimate cost for a request\n *\n * @param providerId - Provider ID\n * @param inputTokens - Number of input tokens\n * @param outputTokens - Number of output tokens\n * @returns Estimated cost in USD\n *\n * @example\n * ```typescript\n * const cost = estimateCost('openai', 1000, 500);\n * console.log(`$${cost.toFixed(4)}`); // \"$0.0125\"\n *\n * const cost = estimateCost('google', 10000, 1000);\n * console.log(`$${cost.toFixed(4)}`); // \"$0.0035\"\n * ```\n */\nexport function estimateCost(\n providerId: keyof typeof PROVIDER_METADATA,\n inputTokens: number,\n outputTokens: number\n): number {\n const provider = PROVIDER_METADATA[providerId];\n const inputCost = (inputTokens / 1000) * provider.pricing.inputPer1k;\n const outputCost = (outputTokens / 1000) * provider.pricing.outputPer1k;\n return inputCost + outputCost;\n}\n\n/**\n * Get the cheapest provider for a given workload\n *\n * @param inputTokens - Number of input tokens\n * @param outputTokens - Number of output tokens\n * @returns Cheapest provider metadata\n *\n * @example\n * ```typescript\n * const cheapest = getCheapestProvider(10000, 1000);\n * console.log(cheapest.name); // \"Google (Gemini)\"\n * ```\n */\nexport function getCheapestProvider(\n inputTokens: number,\n outputTokens: number\n): LLMProviderMetadata {\n const providers = Object.values(PROVIDER_METADATA);\n return providers.reduce((cheapest, current) => {\n const cheapestCost = estimateCost(cheapest.id as LLMProviderType, inputTokens, outputTokens);\n const currentCost = estimateCost(current.id as LLMProviderType, inputTokens, outputTokens);\n return currentCost < cheapestCost ? current : cheapest;\n });\n}\n\n/**\n * Compare native vs OpenRouter for a provider\n *\n * @param providerId - Provider ID\n * @returns Comparison object with key differences\n *\n * @example\n * ```typescript\n * const comparison = compareNativeVsOpenRouter('anthropic');\n * console.log(comparison.differences);\n * // ['Uses OpenAI-compatible format...', 'Response prefill trick...']\n * ```\n */\nexport function compareNativeVsOpenRouter(\n providerId: keyof typeof PROVIDER_METADATA\n): {\n provider: string;\n nativeAvailable: boolean;\n openRouterAvailable: boolean;\n differences: string[];\n} {\n const provider = PROVIDER_METADATA[providerId];\n return {\n provider: provider.name,\n nativeAvailable: provider.accessMethods.native.available,\n openRouterAvailable: provider.accessMethods.openrouter.available,\n differences: provider.openRouterAPI.differences\n };\n}\n\n// Type exports\nexport type LLMProviderType = keyof typeof PROVIDER_METADATA;\nexport type SupportedImageMimeType = typeof SUPPORTED_IMAGE_TYPES.COMMON[number];\nexport type NodeType = 'parse' | 'extract' | 'categorize' | 'qualify' | 'split';\n","// Export types\nexport * from \"./types\";\n\n// Export schema translator\nexport { SchemaTranslator } from \"./schema-translator\";\n\n// Export schema prompt formatter\nexport { buildSchemaPromptSection, formatSchemaForPrompt, combineSchemaAndUserPrompt } from \"./schema-prompt-formatter\";\n\n// Export provider registry\nexport { providerRegistry, registerProvider, createProviderFromRegistry } from \"./provider-registry\";\nexport type { ProviderFactory } from \"./provider-registry\";\n\n// Export providers (backward compatibility - still export from local files)\n// These will be deprecated in favor of importing from individual provider packages\nexport { OpenAIProvider } from \"./providers/openai\";\nexport { AnthropicProvider } from \"./providers/anthropic\";\nexport { GoogleProvider } from \"./providers/google\";\nexport { XAIProvider } from \"./providers/xai\";\n\n// Export fallback manager\nexport { FallbackManager } from \"./fallback-manager\";\n\n// Export adapter\nexport { adaptToCoreLLMProvider } from \"./adapter\";\n\n// Factory functions\nimport type { VLMProvider as CoreVLMProvider } from \"@doclo/core\";\nimport type { ObservabilityConfig, TraceContext } from \"@doclo/core/observability\";\nimport type { FallbackConfig, LLMProvider, MultimodalInput, ProviderConfig, AccessMethod, ReasoningConfig } from \"./types\";\nimport { FallbackManager } from \"./fallback-manager\";\nimport { createProviderFromRegistry, providerRegistry } from \"./provider-registry\";\nimport { adaptToCoreLLMProvider } from \"./adapter\";\n\n// Register built-in providers for backward compatibility\n// Users can also import individual provider packages to register them\nimport { OpenAIProvider } from \"./providers/openai\";\nimport { AnthropicProvider } from \"./providers/anthropic\";\nimport { GoogleProvider } from \"./providers/google\";\nimport { XAIProvider } from \"./providers/xai\";\n\n// Auto-register providers if not already registered\nif (!providerRegistry.has('openai')) {\n providerRegistry.register('openai', (config) => new OpenAIProvider(config));\n}\nif (!providerRegistry.has('anthropic')) {\n providerRegistry.register('anthropic', (config) => new AnthropicProvider(config));\n}\nif (!providerRegistry.has('google')) {\n providerRegistry.register('google', (config) => new GoogleProvider(config));\n}\nif (!providerRegistry.has('xai')) {\n providerRegistry.register('xai', (config) => new XAIProvider(config));\n}\n\n/**\n * Create a single VLM provider with direct instantiation (no retry/fallback logic).\n *\n * Use this for:\n * - Simple scripts and quick prototypes\n * - Testing individual provider behavior\n * - Benchmarking (no retry overhead)\n * - Cases where you want immediate failures without retry logic\n *\n * For production applications requiring resilience, use `buildLLMProvider()` instead.\n *\n * @example\n * ```typescript\n * const provider = createVLMProvider({\n * provider: 'google',\n * model: 'gemini-2.5-flash-preview-09-2025',\n * apiKey: process.env.OPENROUTER_API_KEY,\n * via: 'openrouter'\n * });\n * ```\n *\n * @param config - Provider configuration\n * @returns CoreVLMProvider instance (no retry/fallback wrapper)\n */\nexport function createVLMProvider(config: {\n provider: 'openai' | 'anthropic' | 'google' | 'xai' | 'x-ai' | 'generic-or';\n model: string;\n apiKey: string;\n via?: 'openrouter';\n baseUrl?: string;\n}): CoreVLMProvider {\n let internalProvider: LLMProvider;\n\n // Build proper ProviderConfig with explicit typing\n const providerConfig: ProviderConfig = {\n provider: config.provider,\n model: config.model,\n apiKey: config.apiKey,\n via: config.via as AccessMethod | undefined,\n baseUrl: config.baseUrl\n };\n\n // Use registry to create provider (allows external provider packages to register)\n internalProvider = createProviderFromRegistry(providerConfig);\n\n // Adapt to core VLMProvider interface\n return {\n name: internalProvider.name,\n capabilities: {\n supportsImages: true,\n supportsPDFs: internalProvider.capabilities.supportsPDFs,\n maxPDFPages: internalProvider.capabilities.maxPDFPages\n },\n async completeJson(input: {\n prompt: string | import(\"@doclo/core\").MultimodalInput;\n schema: object;\n max_tokens?: number;\n reasoning?: import(\"./types\").ReasoningConfig;\n }) {\n // Convert input to internal MultimodalInput format\n let multimodalInput: MultimodalInput;\n\n if (typeof input.prompt === 'string') {\n multimodalInput = { text: input.prompt };\n } else {\n multimodalInput = input.prompt as any;\n }\n\n // Call internal provider with reasoning parameters\n const response = await internalProvider.completeJson({\n input: multimodalInput,\n schema: input.schema as any,\n max_tokens: input.max_tokens,\n reasoning: input.reasoning\n });\n\n // Return in core format\n return {\n json: response.json,\n rawText: response.rawText,\n costUSD: response.metrics.costUSD,\n inputTokens: response.metrics.inputTokens,\n outputTokens: response.metrics.outputTokens\n };\n }\n };\n}\n\n/**\n * Build a production-ready LLM provider with retry logic, fallback support, and circuit breakers.\n *\n * Features:\n * - **Retry Logic**: Configurable retries with exponential backoff for transient failures\n * - **Fallback Chain**: Automatically tries next provider if current one fails\n * - **Circuit Breaker**: Temporarily skips providers with repeated failures\n * - **Observability**: Full integration with observability hooks for monitoring\n * - **Mode Support**: Supports both strict and relaxed JSON modes\n *\n * Works with single OR multiple providers:\n * - Single provider: Gets retry logic and circuit breaker protection\n * - Multiple providers: Adds fallback to alternative providers\n *\n * Use this for:\n * - Production applications requiring high availability\n * - Cases where you need retry logic even with a single provider\n * - Multi-provider fallback chains\n * - Advanced error handling and monitoring\n *\n * @example Single provider with retry\n * ```typescript\n * const provider = buildLLMProvider({\n * providers: [{\n * provider: 'google',\n * model: 'gemini-2.5-flash-preview-09-2025',\n * apiKey: process.env.OPENROUTER_API_KEY,\n * via: 'openrouter'\n * }],\n * maxRetries: 2,\n * retryDelay: 1000,\n * useExponentialBackoff: true,\n * circuitBreakerThreshold: 3\n * });\n * ```\n *\n * @example Multi-provider fallback\n * ```typescript\n * const provider = buildLLMProvider({\n * providers: [\n * { provider: 'google', model: 'gemini-2.5-flash', apiKey: key1 },\n * { provider: 'openai', model: 'gpt-4.1', apiKey: key2 },\n * { provider: 'anthropic', model: 'claude-haiku-4.5', apiKey: key3 }\n * ],\n * maxRetries: 2,\n * retryDelay: 1000,\n * useExponentialBackoff: true\n * });\n * ```\n *\n * @param config - Fallback configuration with providers array and retry settings\n * @returns CoreVLMProvider with retry/fallback capabilities (compatible with flow interface)\n */\nexport function buildLLMProvider(config: FallbackConfig): CoreVLMProvider {\n const manager = new FallbackManager(config);\n\n // Observability context storage\n let observabilityContext: {\n config?: ObservabilityConfig;\n flowId?: string;\n executionId?: string;\n stepId?: string;\n traceContext?: TraceContext;\n metadata?: Record<string, unknown>;\n } | undefined;\n\n // Return CoreVLMProvider interface (compatible with createVLMProvider)\n const coreProvider: CoreVLMProvider = {\n name: config.providers.map(p => `${p.provider}:${p.model}`).join(\" -> \"),\n capabilities: {\n supportsImages: true,\n supportsPDFs: true,\n maxPDFPages: Math.min(...config.providers.map(_ => 100))\n },\n async completeJson(input: {\n prompt: string | import(\"@doclo/core\").MultimodalInput;\n schema: object;\n max_tokens?: number;\n reasoning?: import(\"./types\").ReasoningConfig;\n }) {\n // Convert input to internal MultimodalInput format (same as createVLMProvider)\n let multimodalInput: MultimodalInput;\n\n if (typeof input.prompt === 'string') {\n multimodalInput = { text: input.prompt };\n } else {\n multimodalInput = input.prompt as any;\n }\n\n // Call fallback manager with converted input\n const response = await manager.executeWithFallback(\n multimodalInput,\n input.schema as any,\n input.max_tokens,\n input.reasoning,\n undefined, // mode - defaults to strict when schema provided\n observabilityContext\n );\n\n // Return in core format\n return {\n json: response.json,\n rawText: response.rawText,\n costUSD: response.metrics.costUSD,\n inputTokens: response.metrics.inputTokens,\n outputTokens: response.metrics.outputTokens,\n cacheCreationInputTokens: response.metrics.cacheCreationInputTokens,\n cacheReadInputTokens: response.metrics.cacheReadInputTokens\n };\n }\n };\n\n // Attach observability context setter\n (coreProvider as any).__setObservabilityContext = (ctx: typeof observabilityContext) => {\n observabilityContext = ctx;\n };\n\n return coreProvider;\n}\n\n// Export comprehensive metadata (MIME types, capabilities, helpers)\nexport * from './metadata.js';\n"],"mappings":"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","names":["fetchWithTimeout","DEFAULT_LIMITS","safeJsonParse","extractProviderFromModel","useNewStructuredOutputs","fetchWithTimeout","validateUrl","DEFAULT_LIMITS","safeJsonParse","extractProviderFromModel","fetchWithTimeout","DEFAULT_LIMITS","safeJsonParse","extractProviderFromModel"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doclo/providers-llm",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Core LLM provider utilities, types, and schema translation for Doclo SDK",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -25,13 +25,14 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@alcyone-labs/zod-to-json-schema": "^4.0.10",
|
|
27
27
|
"ajv": "^8.17.1",
|
|
28
|
-
"@doclo/core": "0.1.
|
|
28
|
+
"@doclo/core": "^0.1.9"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@doclo/providers-openai": "^0.1.
|
|
32
|
-
"@doclo/providers-anthropic": "^0.1.
|
|
33
|
-
"@doclo/providers-google": "^0.1.
|
|
34
|
-
"@doclo/providers-xai": "^0.1.
|
|
31
|
+
"@doclo/providers-openai": "^0.1.1",
|
|
32
|
+
"@doclo/providers-anthropic": "^0.1.1",
|
|
33
|
+
"@doclo/providers-google": "^0.1.1",
|
|
34
|
+
"@doclo/providers-xai": "^0.1.1",
|
|
35
|
+
"@doclo/providers-generic-or": "^0.1.0"
|
|
35
36
|
},
|
|
36
37
|
"peerDependenciesMeta": {
|
|
37
38
|
"@doclo/providers-openai": {
|
|
@@ -45,6 +46,9 @@
|
|
|
45
46
|
},
|
|
46
47
|
"@doclo/providers-xai": {
|
|
47
48
|
"optional": true
|
|
49
|
+
},
|
|
50
|
+
"@doclo/providers-generic-or": {
|
|
51
|
+
"optional": true
|
|
48
52
|
}
|
|
49
53
|
},
|
|
50
54
|
"devDependencies": {
|