@genui-a3/providers 0.0.5 → 0.0.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../anthropic/streamProcessor.ts","../../utils/backoff.ts","../../utils/executeWithFallback.ts","../../anthropic/index.ts"],"names":["EventType","A3TimeoutError","DEFAULT_RESILIENCE_CONFIG","A3ResilienceError","generateText","Output","streamText","createAnthropic","resolveResilienceConfig"],"mappings":"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","file":"index.cjs","sourcesContent":["import { EventType } from '@ag-ui/client'\nimport { ZodType } from 'zod'\nimport type { AgentId, StreamEvent, BaseState } from '@genui-a3/core'\nimport type { StreamTextResult, ToolSet } from 'ai'\n\n/**\n * Processes an Anthropic streaming response (via Vercel AI SDK) into AG-UI events.\n *\n * Uses `partialOutputStream` from `streamText` + `Output.object()` to receive\n * progressively-built partial objects. Tracks `chatbotMessage` growth to yield\n * TEXT_MESSAGE_CONTENT deltas. After the stream completes, validates the final\n * object and yields TOOL_CALL_RESULT.\n *\n * @param streamResult - The streamText result containing partialOutputStream and output promise\n * @param reader - Pre-started async iterator for the partial object stream\n * @param first - The first iteration result (already consumed to trigger the API call)\n * @param agentId - Agent identifier for event tagging\n * @param schema - Zod schema for final response validation\n * @returns Async generator of AG-UI stream events\n */\nexport async function* processAnthropicStream<TState extends BaseState = BaseState>(\n streamResult: StreamTextResult<ToolSet, never>,\n reader: AsyncIterator<unknown>,\n first: IteratorResult<unknown>,\n agentId: AgentId,\n schema: ZodType,\n): AsyncGenerator<StreamEvent<TState>> {\n let prevMessageLength = 0\n\n try {\n // Process the first partial (already consumed to trigger the API call)\n if (!first.done) {\n const partial = first.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n }\n\n // Process remaining partials\n let next = await reader.next()\n while (!next.done) {\n const partial = next.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n // eslint-disable-next-line no-await-in-loop\n next = await reader.next()\n }\n\n // Stream complete — await and validate the final object\n const finalObject = await streamResult.output\n\n if (finalObject === null) {\n yield {\n type: EventType.RUN_ERROR,\n message: 'Anthropic stream completed with null output',\n agentId,\n } as StreamEvent<TState>\n return\n }\n\n const validated = schema.parse(finalObject)\n yield {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: '',\n messageId: '',\n content: JSON.stringify(validated),\n agentId,\n } as StreamEvent<TState>\n } catch (err) {\n yield {\n type: EventType.RUN_ERROR,\n message: `Anthropic stream error: ${(err as Error).message}`,\n agentId,\n } as StreamEvent<TState>\n }\n}\n\n/**\n * Extracts the new portion of chatbotMessage from a partial object.\n */\nfunction extractDelta(partial: Record<string, unknown>, prevLength: number): string | null {\n const chatbotMessage = partial.chatbotMessage\n if (typeof chatbotMessage !== 'string' || chatbotMessage.length <= prevLength) {\n return null\n }\n return chatbotMessage.slice(prevLength)\n}\n","import type { BackoffConfig } from '@genui-a3/core'\n\n/**\n * Calculates the backoff delay for a given retry attempt.\n *\n * @param attempt - Zero-based attempt index (0 = first retry)\n * @param config - Backoff configuration with all fields required\n * @returns Delay in milliseconds\n */\nexport function calculateBackoff(attempt: number, config: Required<BackoffConfig>): number {\n let delay: number\n\n switch (config.strategy) {\n case 'exponential':\n delay = config.baseDelayMs * Math.pow(2, attempt)\n break\n case 'linear':\n delay = config.baseDelayMs * (attempt + 1)\n break\n case 'fixed':\n delay = config.baseDelayMs\n break\n }\n\n delay = Math.min(delay, config.maxDelayMs)\n\n if (config.jitter) {\n delay = Math.random() * delay\n }\n\n return delay\n}\n\n/**\n * Sleeps for the specified duration. Can be aborted via an AbortSignal.\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal to cancel the sleep early\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason as Error)\n return\n }\n\n const timer = setTimeout(resolve, ms)\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason as Error)\n },\n { once: true },\n )\n })\n}\n","import {\n A3ResilienceError,\n A3TimeoutError,\n DEFAULT_RESILIENCE_CONFIG,\n type ResilienceErrorEntry,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { calculateBackoff, sleep } from './backoff'\n\n/**\n * Builds an AbortSignal that fires when either the per-request timeout or total timeout expires.\n */\nfunction buildSignal(requestTimeoutMs?: number, totalAbort?: AbortSignal): AbortSignal | undefined {\n const signals: AbortSignal[] = []\n\n if (requestTimeoutMs !== undefined) {\n signals.push(AbortSignal.timeout(requestTimeoutMs))\n }\n\n if (totalAbort) {\n signals.push(totalAbort)\n }\n\n if (signals.length === 0) return undefined\n if (signals.length === 1) return signals[0]\n return AbortSignal.any(signals)\n}\n\ntype AttemptResult<T> = { ok: true; value: T } | { ok: false; error: Error }\n\nasync function attemptAction<T>(\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n model: string,\n signal: AbortSignal | undefined,\n attempt: number,\n errors: ResilienceErrorEntry[],\n): Promise<AttemptResult<T>> {\n try {\n const value = await action(model, signal)\n return { ok: true, value }\n } catch (error) {\n const errorObj = error as Error\n errors.push({ model, attempt, error: errorObj })\n return { ok: false, error: errorObj }\n }\n}\n\nfunction checkTotalTimeout(totalAbort: AbortController | undefined, timeoutMs: number | undefined, errors: ResilienceErrorEntry[]): void {\n if (totalAbort?.signal.aborted) {\n throw new A3TimeoutError(`Total timeout of ${timeoutMs}ms exceeded`, errors)\n }\n}\n\nasync function handleAttemptError(\n errorObj: Error,\n attempt: number,\n maxRetries: number,\n retryAll: boolean,\n resolved: ResolvedResilienceConfig,\n totalAbort: AbortController | undefined,\n): Promise<'retry' | 'next-model'> {\n const isLastAttempt = attempt === 1 + maxRetries\n const isRetryable = retryAll || resolved.isRetryableError(errorObj)\n\n if (isRetryable && !isLastAttempt) {\n const delay = calculateBackoff(attempt - 1, resolved.backoff)\n await sleep(delay, totalAbort?.signal).catch(() => {\n // Sleep was aborted by total timeout — will be caught at top of loop\n })\n return 'retry'\n }\n\n return 'next-model'\n}\n\n/**\n * Executes an action with model fallback, retry, backoff, and timeout support.\n *\n * For each model (in priority order):\n * 1. Attempts the action up to `1 + maxAttempts` times\n * 2. On transient errors, waits with backoff before retrying\n * 3. On non-retryable errors (or after exhausting retries), falls back to the next model\n *\n * Throws `A3ResilienceError` with full error history when all models are exhausted.\n * Throws `A3TimeoutError` when the total timeout is exceeded.\n *\n * @param models - Model identifiers in priority order\n * @param action - Async action to attempt with each model. Receives an optional AbortSignal.\n * @param config - Resolved resilience configuration (defaults applied if omitted)\n * @returns The result from the first successful attempt\n * @throws {A3ResilienceError} When all models and retries are exhausted\n * @throws {A3TimeoutError} When the total timeout is exceeded\n *\n * @example\n * ```typescript\n * const result = await executeWithFallback(\n * ['model-primary', 'model-fallback'],\n * (model, signal) => provider.call(model, params, { abortSignal: signal }),\n * resolvedConfig,\n * )\n * ```\n */\nexport async function executeWithFallback<T>(\n models: string[],\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n config?: ResolvedResilienceConfig,\n): Promise<T> {\n const resolved = config ?? DEFAULT_RESILIENCE_CONFIG\n const errors: ResilienceErrorEntry[] = []\n const maxRetries = resolved.retry === false ? 0 : resolved.retry.maxAttempts\n const retryAll = resolved.retry !== false && resolved.retry.retryOn === 'all'\n\n // Total timeout controller\n let totalAbort: AbortController | undefined\n let totalTimer: ReturnType<typeof setTimeout> | undefined\n\n if (resolved.timeout.totalTimeoutMs !== undefined) {\n totalAbort = new AbortController()\n totalTimer = setTimeout(\n () => totalAbort!.abort(new Error('Total timeout exceeded')),\n resolved.timeout.totalTimeoutMs,\n )\n }\n\n try {\n for (let modelIndex = 0; modelIndex < models.length; modelIndex++) {\n const model = models[modelIndex]\n\n for (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n const signal = buildSignal(resolved.timeout.requestTimeoutMs, totalAbort?.signal)\n // eslint-disable-next-line no-await-in-loop\n const result = await attemptAction(action, model, signal, attempt, errors)\n if (result.ok) return result.value\n\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n // eslint-disable-next-line no-await-in-loop\n const decision = await handleAttemptError(result.error, attempt, maxRetries, retryAll, resolved, totalAbort)\n if (decision === 'next-model') break\n }\n }\n\n // All models exhausted\n throw new A3ResilienceError(\n `All models failed after ${errors.length} total attempt(s): ${models.join(', ')}`,\n errors,\n )\n } finally {\n if (totalTimer !== undefined) {\n clearTimeout(totalTimer)\n }\n }\n}\n","import { createAnthropic } from '@ai-sdk/anthropic'\nimport { generateText, streamText, Output, ModelMessage } from 'ai'\nimport {\n resolveResilienceConfig,\n type Provider,\n type ProviderRequest,\n type ProviderResponse,\n type ProviderMessage,\n type BaseState,\n type StreamEvent,\n type ResilienceConfig,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { processAnthropicStream } from './streamProcessor'\nimport { executeWithFallback } from '../utils/executeWithFallback'\n\n/**\n * Configuration for creating an Anthropic provider.\n */\nexport interface AnthropicProviderConfig {\n /** Anthropic API key. Defaults to ANTHROPIC_API_KEY env var. */\n apiKey?: string\n /**\n * Model identifiers in order of preference (first = primary, rest = fallbacks).\n * e.g. ['claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001']\n */\n models: string[]\n /** Optional custom base URL for the Anthropic API */\n baseURL?: string\n /** Resilience configuration (retry, backoff, timeout). Uses industry-standard defaults if omitted. */\n resilience?: ResilienceConfig\n}\n\nfunction toAIMessages(messages: ProviderMessage[]): ModelMessage[] {\n return messages.map((msg) => ({\n role: msg.role,\n content: msg.content,\n }))\n}\n\nexport function prepareMessages(messages: ModelMessage[]): ModelMessage[] {\n if (messages.length === 0) return messages\n const lastMessage = messages[messages.length - 1]\n if (lastMessage.role === 'assistant') {\n return [...messages, { role: 'user', content: 'Continue' }]\n }\n return messages\n}\n\nasync function sendWithModel(\n anthropicProvider: ReturnType<typeof createAnthropic>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n): Promise<ProviderResponse> {\n const preparedMessages = prepareMessages(messages)\n const result = await generateText({\n model: anthropicProvider(model),\n system,\n messages: preparedMessages,\n output: Output.object({ schema }),\n })\n\n return {\n content: JSON.stringify(result.output),\n usage: {\n inputTokens: result.usage.inputTokens ?? 0,\n outputTokens: result.usage.outputTokens ?? 0,\n totalTokens: (result.usage.inputTokens ?? 0) + (result.usage.outputTokens ?? 0),\n },\n }\n}\n\nasync function sendStreamWithModel(\n anthropicProvider: ReturnType<typeof createAnthropic>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n) {\n const preparedMessages = prepareMessages(messages)\n const result = streamText({\n model: anthropicProvider(model),\n system,\n messages: preparedMessages,\n output: Output.object({ schema }),\n })\n\n // Force the API call to start so executeWithFallback can catch connection errors\n const partialStream = result.partialOutputStream\n const reader = partialStream[Symbol.asyncIterator]()\n const first = await reader.next()\n\n return { result, reader, first }\n}\n\n/**\n * Creates an Anthropic provider instance.\n *\n * Uses the Vercel AI SDK (`ai` + `@ai-sdk/anthropic`) for structured output via\n * `generateText` + `Output.object()` (blocking) and `streamText` + `Output.object()`\n * (streaming). The AI SDK handles Zod-to-JSON-schema conversion, partial JSON\n * parsing, and validation internally.\n *\n * @param config - Anthropic provider configuration\n * @returns A Provider implementation using Anthropic\n *\n * @example\n * ```typescript\n * const provider = createAnthropicProvider({\n * models: ['claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001'],\n * })\n * ```\n */\nexport function createAnthropicProvider(config: AnthropicProviderConfig): Provider {\n const anthropicProvider = createAnthropic({\n apiKey: config.apiKey,\n baseURL: config.baseURL,\n })\n const models = config.models\n const resilience: ResolvedResilienceConfig = resolveResilienceConfig(config.resilience)\n\n return {\n name: 'anthropic',\n\n async sendRequest(request: ProviderRequest): Promise<ProviderResponse> {\n const messages = toAIMessages(request.messages)\n\n return executeWithFallback(\n models,\n (model) => sendWithModel(anthropicProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n },\n\n async *sendRequestStream<TState extends BaseState = BaseState>(\n request: ProviderRequest,\n ): AsyncGenerator<StreamEvent<TState>> {\n const messages = toAIMessages(request.messages)\n\n const { result, reader, first } = await executeWithFallback(\n models,\n (model) => sendStreamWithModel(anthropicProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n\n yield* processAnthropicStream<TState>(result, reader, first, 'anthropic', request.responseSchema)\n },\n }\n}\n"]}
1
+ {"version":3,"sources":["../../anthropic/streamProcessor.ts","../../utils/backoff.ts","../../utils/executeWithFallback.ts","../../anthropic/index.ts"],"names":["EventType","A3TimeoutError","DEFAULT_RESILIENCE_CONFIG","A3ResilienceError","generateText","Output","streamText","createAnthropic","resolveResilienceConfig"],"mappings":"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","file":"index.cjs","sourcesContent":["import { EventType } from '@ag-ui/client'\nimport { ZodType } from 'zod'\nimport type { AgentId, StreamEvent, BaseState } from '@genui-a3/core'\nimport type { StreamTextResult, ToolSet } from 'ai'\n\n/**\n * Processes an Anthropic streaming response (via Vercel AI SDK) into AG-UI events.\n *\n * Uses `partialOutputStream` from `streamText` + `Output.object()` to receive\n * progressively-built partial objects. Tracks `chatbotMessage` growth to yield\n * TEXT_MESSAGE_CONTENT deltas. After the stream completes, validates the final\n * object and yields TOOL_CALL_RESULT.\n *\n * @param streamResult - The streamText result containing partialOutputStream and output promise\n * @param reader - Pre-started async iterator for the partial object stream\n * @param first - The first iteration result (already consumed to trigger the API call)\n * @param agentId - Agent identifier for event tagging\n * @param schema - Zod schema for final response validation\n * @returns Async generator of AG-UI stream events\n */\nexport async function* processAnthropicStream<TState extends BaseState = BaseState>(\n streamResult: StreamTextResult<ToolSet, never>,\n reader: AsyncIterator<unknown>,\n first: IteratorResult<unknown>,\n agentId: AgentId,\n schema: ZodType,\n): AsyncGenerator<StreamEvent<TState>> {\n let prevMessageLength = 0\n\n try {\n // Process the first partial (already consumed to trigger the API call)\n if (!first.done) {\n const partial = first.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n }\n\n // Process remaining partials\n let next = await reader.next()\n while (!next.done) {\n const partial = next.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n // eslint-disable-next-line no-await-in-loop\n next = await reader.next()\n }\n\n // Stream complete — await and validate the final object\n const finalObject = await streamResult.output\n\n if (finalObject === null) {\n yield {\n type: EventType.RUN_ERROR,\n message: 'Anthropic stream completed with null output',\n agentId,\n } as StreamEvent<TState>\n return\n }\n\n const validated = schema.parse(finalObject)\n yield {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: '',\n messageId: '',\n content: JSON.stringify(validated),\n agentId,\n } as StreamEvent<TState>\n } catch (err) {\n yield {\n type: EventType.RUN_ERROR,\n message: `Anthropic stream error: ${(err as Error).message}`,\n agentId,\n } as StreamEvent<TState>\n }\n}\n\n/**\n * Extracts the new portion of chatbotMessage from a partial object.\n */\nfunction extractDelta(partial: Record<string, unknown>, prevLength: number): string | null {\n const chatbotMessage = partial.chatbotMessage\n if (typeof chatbotMessage !== 'string' || chatbotMessage.length <= prevLength) {\n return null\n }\n return chatbotMessage.slice(prevLength)\n}\n","import type { BackoffConfig } from '@genui-a3/core'\n\n/**\n * Calculates the backoff delay for a given retry attempt.\n *\n * @param attempt - Zero-based attempt index (0 = first retry)\n * @param config - Backoff configuration with all fields required\n * @returns Delay in milliseconds\n */\nexport function calculateBackoff(attempt: number, config: Required<BackoffConfig>): number {\n let delay: number\n\n switch (config.strategy) {\n case 'exponential':\n delay = config.baseDelayMs * Math.pow(2, attempt)\n break\n case 'linear':\n delay = config.baseDelayMs * (attempt + 1)\n break\n case 'fixed':\n delay = config.baseDelayMs\n break\n }\n\n delay = Math.min(delay, config.maxDelayMs)\n\n if (config.jitter) {\n delay = Math.random() * delay\n }\n\n return delay\n}\n\n/**\n * Sleeps for the specified duration. Can be aborted via an AbortSignal.\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal to cancel the sleep early\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason as Error)\n return\n }\n\n const timer = setTimeout(resolve, ms)\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason as Error)\n },\n { once: true },\n )\n })\n}\n","import {\n A3ResilienceError,\n A3TimeoutError,\n DEFAULT_RESILIENCE_CONFIG,\n type ResilienceErrorEntry,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { calculateBackoff, sleep } from './backoff'\n\n/**\n * Builds an AbortSignal that fires when either the per-request timeout or total timeout expires.\n */\nfunction buildSignal(requestTimeoutMs?: number, totalAbort?: AbortSignal): AbortSignal | undefined {\n const signals: AbortSignal[] = []\n\n if (requestTimeoutMs !== undefined) {\n signals.push(AbortSignal.timeout(requestTimeoutMs))\n }\n\n if (totalAbort) {\n signals.push(totalAbort)\n }\n\n if (signals.length === 0) return undefined\n if (signals.length === 1) return signals[0]\n return AbortSignal.any(signals)\n}\n\ntype AttemptResult<T> = { ok: true; value: T } | { ok: false; error: Error }\n\nasync function attemptAction<T>(\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n model: string,\n signal: AbortSignal | undefined,\n attempt: number,\n errors: ResilienceErrorEntry[],\n): Promise<AttemptResult<T>> {\n try {\n const value = await action(model, signal)\n return { ok: true, value }\n } catch (error) {\n const errorObj = error as Error\n errors.push({ model, attempt, error: errorObj })\n return { ok: false, error: errorObj }\n }\n}\n\nfunction checkTotalTimeout(totalAbort: AbortController | undefined, timeoutMs: number | undefined, errors: ResilienceErrorEntry[]): void {\n if (totalAbort?.signal.aborted) {\n throw new A3TimeoutError(`Total timeout of ${timeoutMs}ms exceeded`, errors)\n }\n}\n\nasync function handleAttemptError(\n errorObj: Error,\n attempt: number,\n maxRetries: number,\n retryAll: boolean,\n resolved: ResolvedResilienceConfig,\n totalAbort: AbortController | undefined,\n): Promise<'retry' | 'next-model'> {\n const isLastAttempt = attempt === 1 + maxRetries\n const isRetryable = retryAll || resolved.isRetryableError(errorObj)\n\n if (isRetryable && !isLastAttempt) {\n const delay = calculateBackoff(attempt - 1, resolved.backoff)\n await sleep(delay, totalAbort?.signal).catch(() => {\n // Sleep was aborted by total timeout — will be caught at top of loop\n })\n return 'retry'\n }\n\n return 'next-model'\n}\n\n/**\n * Executes an action with model fallback, retry, backoff, and timeout support.\n *\n * For each model (in priority order):\n * 1. Attempts the action up to `1 + maxAttempts` times\n * 2. On transient errors, waits with backoff before retrying\n * 3. On non-retryable errors (or after exhausting retries), falls back to the next model\n *\n * Throws `A3ResilienceError` with full error history when all models are exhausted.\n * Throws `A3TimeoutError` when the total timeout is exceeded.\n *\n * @param models - Model identifiers in priority order\n * @param action - Async action to attempt with each model. Receives an optional AbortSignal.\n * @param config - Resolved resilience configuration (defaults applied if omitted)\n * @returns The result from the first successful attempt\n * @throws {A3ResilienceError} When all models and retries are exhausted\n * @throws {A3TimeoutError} When the total timeout is exceeded\n *\n * @example\n * ```typescript\n * const result = await executeWithFallback(\n * ['model-primary', 'model-fallback'],\n * (model, signal) => provider.call(model, params, { abortSignal: signal }),\n * resolvedConfig,\n * )\n * ```\n */\nexport async function executeWithFallback<T>(\n models: string[],\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n config?: ResolvedResilienceConfig,\n): Promise<T> {\n const resolved = config ?? DEFAULT_RESILIENCE_CONFIG\n const errors: ResilienceErrorEntry[] = []\n const maxRetries = resolved.retry === false ? 0 : resolved.retry.maxAttempts\n const retryAll = resolved.retry !== false && resolved.retry.retryOn === 'all'\n\n // Total timeout controller\n let totalAbort: AbortController | undefined\n let totalTimer: ReturnType<typeof setTimeout> | undefined\n\n if (resolved.timeout.totalTimeoutMs !== undefined) {\n totalAbort = new AbortController()\n totalTimer = setTimeout(\n () => totalAbort!.abort(new Error('Total timeout exceeded')),\n resolved.timeout.totalTimeoutMs,\n )\n }\n\n try {\n for (let modelIndex = 0; modelIndex < models.length; modelIndex++) {\n const model = models[modelIndex]\n\n for (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n const signal = buildSignal(resolved.timeout.requestTimeoutMs, totalAbort?.signal)\n // eslint-disable-next-line no-await-in-loop\n const result = await attemptAction(action, model, signal, attempt, errors)\n if (result.ok) return result.value\n\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n // eslint-disable-next-line no-await-in-loop\n const decision = await handleAttemptError(result.error, attempt, maxRetries, retryAll, resolved, totalAbort)\n if (decision === 'next-model') break\n }\n }\n\n // All models exhausted\n throw new A3ResilienceError(\n `All models failed after ${errors.length} total attempt(s): ${models.join(', ')}`,\n errors,\n )\n } finally {\n if (totalTimer !== undefined) {\n clearTimeout(totalTimer)\n }\n }\n}\n","import { createAnthropic } from '@ai-sdk/anthropic'\nimport { generateText, streamText, Output, ModelMessage } from 'ai'\nimport {\n resolveResilienceConfig,\n type Provider,\n type ProviderRequest,\n type ProviderResponse,\n type ProviderMessage,\n type BaseState,\n type StreamEvent,\n type ResilienceConfig,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { processAnthropicStream } from './streamProcessor'\nimport { executeWithFallback } from '@providers/utils/executeWithFallback'\n\n/**\n * Configuration for creating an Anthropic provider.\n */\nexport interface AnthropicProviderConfig {\n /** Anthropic API key. Defaults to ANTHROPIC_API_KEY env var. */\n apiKey?: string\n /**\n * Model identifiers in order of preference (first = primary, rest = fallbacks).\n * e.g. ['claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001']\n */\n models: string[]\n /** Optional custom base URL for the Anthropic API */\n baseURL?: string\n /** Resilience configuration (retry, backoff, timeout). Uses industry-standard defaults if omitted. */\n resilience?: ResilienceConfig\n}\n\nfunction toAIMessages(messages: ProviderMessage[]): ModelMessage[] {\n return messages.map((msg) => ({\n role: msg.role,\n content: msg.content,\n }))\n}\n\nexport function prepareMessages(messages: ModelMessage[]): ModelMessage[] {\n if (messages.length === 0) return messages\n const lastMessage = messages[messages.length - 1]\n if (lastMessage.role === 'assistant') {\n return [...messages, { role: 'user', content: 'Continue' }]\n }\n return messages\n}\n\nasync function sendWithModel(\n anthropicProvider: ReturnType<typeof createAnthropic>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n): Promise<ProviderResponse> {\n const preparedMessages = prepareMessages(messages)\n const result = await generateText({\n model: anthropicProvider(model),\n system,\n messages: preparedMessages,\n output: Output.object({ schema }),\n })\n\n return {\n content: JSON.stringify(result.output),\n usage: {\n inputTokens: result.usage.inputTokens ?? 0,\n outputTokens: result.usage.outputTokens ?? 0,\n totalTokens: (result.usage.inputTokens ?? 0) + (result.usage.outputTokens ?? 0),\n },\n }\n}\n\nasync function sendStreamWithModel(\n anthropicProvider: ReturnType<typeof createAnthropic>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n) {\n const preparedMessages = prepareMessages(messages)\n const result = streamText({\n model: anthropicProvider(model),\n system,\n messages: preparedMessages,\n output: Output.object({ schema }),\n })\n\n // Force the API call to start so executeWithFallback can catch connection errors\n const partialStream = result.partialOutputStream\n const reader = partialStream[Symbol.asyncIterator]()\n const first = await reader.next()\n\n return { result, reader, first }\n}\n\n/**\n * Creates an Anthropic provider instance.\n *\n * Uses the Vercel AI SDK (`ai` + `@ai-sdk/anthropic`) for structured output via\n * `generateText` + `Output.object()` (blocking) and `streamText` + `Output.object()`\n * (streaming). The AI SDK handles Zod-to-JSON-schema conversion, partial JSON\n * parsing, and validation internally.\n *\n * @param config - Anthropic provider configuration\n * @returns A Provider implementation using Anthropic\n *\n * @example\n * ```typescript\n * const provider = createAnthropicProvider({\n * models: ['claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001'],\n * })\n * ```\n */\nexport function createAnthropicProvider(config: AnthropicProviderConfig): Provider {\n const anthropicProvider = createAnthropic({\n apiKey: config.apiKey,\n baseURL: config.baseURL,\n })\n const models = config.models\n const resilience: ResolvedResilienceConfig = resolveResilienceConfig(config.resilience)\n\n return {\n name: 'anthropic',\n\n async sendRequest(request: ProviderRequest): Promise<ProviderResponse> {\n const messages = toAIMessages(request.messages)\n\n return executeWithFallback(\n models,\n (model) => sendWithModel(anthropicProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n },\n\n async *sendRequestStream<TState extends BaseState = BaseState>(\n request: ProviderRequest,\n ): AsyncGenerator<StreamEvent<TState>> {\n const messages = toAIMessages(request.messages)\n\n const { result, reader, first } = await executeWithFallback(\n models,\n (model) =>\n sendStreamWithModel(anthropicProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n\n yield* processAnthropicStream<TState>(result, reader, first, 'anthropic', request.responseSchema)\n },\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../anthropic/streamProcessor.ts","../../utils/backoff.ts","../../utils/executeWithFallback.ts","../../anthropic/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { EventType } from '@ag-ui/client'\nimport { ZodType } from 'zod'\nimport type { AgentId, StreamEvent, BaseState } from '@genui-a3/core'\nimport type { StreamTextResult, ToolSet } from 'ai'\n\n/**\n * Processes an Anthropic streaming response (via Vercel AI SDK) into AG-UI events.\n *\n * Uses `partialOutputStream` from `streamText` + `Output.object()` to receive\n * progressively-built partial objects. Tracks `chatbotMessage` growth to yield\n * TEXT_MESSAGE_CONTENT deltas. After the stream completes, validates the final\n * object and yields TOOL_CALL_RESULT.\n *\n * @param streamResult - The streamText result containing partialOutputStream and output promise\n * @param reader - Pre-started async iterator for the partial object stream\n * @param first - The first iteration result (already consumed to trigger the API call)\n * @param agentId - Agent identifier for event tagging\n * @param schema - Zod schema for final response validation\n * @returns Async generator of AG-UI stream events\n */\nexport async function* processAnthropicStream<TState extends BaseState = BaseState>(\n streamResult: StreamTextResult<ToolSet, never>,\n reader: AsyncIterator<unknown>,\n first: IteratorResult<unknown>,\n agentId: AgentId,\n schema: ZodType,\n): AsyncGenerator<StreamEvent<TState>> {\n let prevMessageLength = 0\n\n try {\n // Process the first partial (already consumed to trigger the API call)\n if (!first.done) {\n const partial = first.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n }\n\n // Process remaining partials\n let next = await reader.next()\n while (!next.done) {\n const partial = next.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n // eslint-disable-next-line no-await-in-loop\n next = await reader.next()\n }\n\n // Stream complete — await and validate the final object\n const finalObject = await streamResult.output\n\n if (finalObject === null) {\n yield {\n type: EventType.RUN_ERROR,\n message: 'Anthropic stream completed with null output',\n agentId,\n } as StreamEvent<TState>\n return\n }\n\n const validated = schema.parse(finalObject)\n yield {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: '',\n messageId: '',\n content: JSON.stringify(validated),\n agentId,\n } as StreamEvent<TState>\n } catch (err) {\n yield {\n type: EventType.RUN_ERROR,\n message: `Anthropic stream error: ${(err as Error).message}`,\n agentId,\n } as StreamEvent<TState>\n }\n}\n\n/**\n * Extracts the new portion of chatbotMessage from a partial object.\n */\nfunction extractDelta(partial: Record<string, unknown>, prevLength: number): string | null {\n const chatbotMessage = partial.chatbotMessage\n if (typeof chatbotMessage !== 'string' || chatbotMessage.length <= prevLength) {\n return null\n }\n return chatbotMessage.slice(prevLength)\n}\n","import type { BackoffConfig } from '@genui-a3/core'\n\n/**\n * Calculates the backoff delay for a given retry attempt.\n *\n * @param attempt - Zero-based attempt index (0 = first retry)\n * @param config - Backoff configuration with all fields required\n * @returns Delay in milliseconds\n */\nexport function calculateBackoff(attempt: number, config: Required<BackoffConfig>): number {\n let delay: number\n\n switch (config.strategy) {\n case 'exponential':\n delay = config.baseDelayMs * Math.pow(2, attempt)\n break\n case 'linear':\n delay = config.baseDelayMs * (attempt + 1)\n break\n case 'fixed':\n delay = config.baseDelayMs\n break\n }\n\n delay = Math.min(delay, config.maxDelayMs)\n\n if (config.jitter) {\n delay = Math.random() * delay\n }\n\n return delay\n}\n\n/**\n * Sleeps for the specified duration. Can be aborted via an AbortSignal.\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal to cancel the sleep early\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason as Error)\n return\n }\n\n const timer = setTimeout(resolve, ms)\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason as Error)\n },\n { once: true },\n )\n })\n}\n","import {\n A3ResilienceError,\n A3TimeoutError,\n DEFAULT_RESILIENCE_CONFIG,\n type ResilienceErrorEntry,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { calculateBackoff, sleep } from './backoff'\n\n/**\n * Builds an AbortSignal that fires when either the per-request timeout or total timeout expires.\n */\nfunction buildSignal(requestTimeoutMs?: number, totalAbort?: AbortSignal): AbortSignal | undefined {\n const signals: AbortSignal[] = []\n\n if (requestTimeoutMs !== undefined) {\n signals.push(AbortSignal.timeout(requestTimeoutMs))\n }\n\n if (totalAbort) {\n signals.push(totalAbort)\n }\n\n if (signals.length === 0) return undefined\n if (signals.length === 1) return signals[0]\n return AbortSignal.any(signals)\n}\n\ntype AttemptResult<T> = { ok: true; value: T } | { ok: false; error: Error }\n\nasync function attemptAction<T>(\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n model: string,\n signal: AbortSignal | undefined,\n attempt: number,\n errors: ResilienceErrorEntry[],\n): Promise<AttemptResult<T>> {\n try {\n const value = await action(model, signal)\n return { ok: true, value }\n } catch (error) {\n const errorObj = error as Error\n errors.push({ model, attempt, error: errorObj })\n return { ok: false, error: errorObj }\n }\n}\n\nfunction checkTotalTimeout(totalAbort: AbortController | undefined, timeoutMs: number | undefined, errors: ResilienceErrorEntry[]): void {\n if (totalAbort?.signal.aborted) {\n throw new A3TimeoutError(`Total timeout of ${timeoutMs}ms exceeded`, errors)\n }\n}\n\nasync function handleAttemptError(\n errorObj: Error,\n attempt: number,\n maxRetries: number,\n retryAll: boolean,\n resolved: ResolvedResilienceConfig,\n totalAbort: AbortController | undefined,\n): Promise<'retry' | 'next-model'> {\n const isLastAttempt = attempt === 1 + maxRetries\n const isRetryable = retryAll || resolved.isRetryableError(errorObj)\n\n if (isRetryable && !isLastAttempt) {\n const delay = calculateBackoff(attempt - 1, resolved.backoff)\n await sleep(delay, totalAbort?.signal).catch(() => {\n // Sleep was aborted by total timeout — will be caught at top of loop\n })\n return 'retry'\n }\n\n return 'next-model'\n}\n\n/**\n * Executes an action with model fallback, retry, backoff, and timeout support.\n *\n * For each model (in priority order):\n * 1. Attempts the action up to `1 + maxAttempts` times\n * 2. On transient errors, waits with backoff before retrying\n * 3. On non-retryable errors (or after exhausting retries), falls back to the next model\n *\n * Throws `A3ResilienceError` with full error history when all models are exhausted.\n * Throws `A3TimeoutError` when the total timeout is exceeded.\n *\n * @param models - Model identifiers in priority order\n * @param action - Async action to attempt with each model. Receives an optional AbortSignal.\n * @param config - Resolved resilience configuration (defaults applied if omitted)\n * @returns The result from the first successful attempt\n * @throws {A3ResilienceError} When all models and retries are exhausted\n * @throws {A3TimeoutError} When the total timeout is exceeded\n *\n * @example\n * ```typescript\n * const result = await executeWithFallback(\n * ['model-primary', 'model-fallback'],\n * (model, signal) => provider.call(model, params, { abortSignal: signal }),\n * resolvedConfig,\n * )\n * ```\n */\nexport async function executeWithFallback<T>(\n models: string[],\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n config?: ResolvedResilienceConfig,\n): Promise<T> {\n const resolved = config ?? DEFAULT_RESILIENCE_CONFIG\n const errors: ResilienceErrorEntry[] = []\n const maxRetries = resolved.retry === false ? 0 : resolved.retry.maxAttempts\n const retryAll = resolved.retry !== false && resolved.retry.retryOn === 'all'\n\n // Total timeout controller\n let totalAbort: AbortController | undefined\n let totalTimer: ReturnType<typeof setTimeout> | undefined\n\n if (resolved.timeout.totalTimeoutMs !== undefined) {\n totalAbort = new AbortController()\n totalTimer = setTimeout(\n () => totalAbort!.abort(new Error('Total timeout exceeded')),\n resolved.timeout.totalTimeoutMs,\n )\n }\n\n try {\n for (let modelIndex = 0; modelIndex < models.length; modelIndex++) {\n const model = models[modelIndex]\n\n for (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n const signal = buildSignal(resolved.timeout.requestTimeoutMs, totalAbort?.signal)\n // eslint-disable-next-line no-await-in-loop\n const result = await attemptAction(action, model, signal, attempt, errors)\n if (result.ok) return result.value\n\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n // eslint-disable-next-line no-await-in-loop\n const decision = await handleAttemptError(result.error, attempt, maxRetries, retryAll, resolved, totalAbort)\n if (decision === 'next-model') break\n }\n }\n\n // All models exhausted\n throw new A3ResilienceError(\n `All models failed after ${errors.length} total attempt(s): ${models.join(', ')}`,\n errors,\n )\n } finally {\n if (totalTimer !== undefined) {\n clearTimeout(totalTimer)\n }\n }\n}\n","import { createAnthropic } from '@ai-sdk/anthropic'\nimport { generateText, streamText, Output, ModelMessage } from 'ai'\nimport {\n resolveResilienceConfig,\n type Provider,\n type ProviderRequest,\n type ProviderResponse,\n type ProviderMessage,\n type BaseState,\n type StreamEvent,\n type ResilienceConfig,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { processAnthropicStream } from './streamProcessor'\nimport { executeWithFallback } from '../utils/executeWithFallback'\n\n/**\n * Configuration for creating an Anthropic provider.\n */\nexport interface AnthropicProviderConfig {\n /** Anthropic API key. Defaults to ANTHROPIC_API_KEY env var. */\n apiKey?: string\n /**\n * Model identifiers in order of preference (first = primary, rest = fallbacks).\n * e.g. ['claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001']\n */\n models: string[]\n /** Optional custom base URL for the Anthropic API */\n baseURL?: string\n /** Resilience configuration (retry, backoff, timeout). Uses industry-standard defaults if omitted. */\n resilience?: ResilienceConfig\n}\n\nfunction toAIMessages(messages: ProviderMessage[]): ModelMessage[] {\n return messages.map((msg) => ({\n role: msg.role,\n content: msg.content,\n }))\n}\n\nexport function prepareMessages(messages: ModelMessage[]): ModelMessage[] {\n if (messages.length === 0) return messages\n const lastMessage = messages[messages.length - 1]\n if (lastMessage.role === 'assistant') {\n return [...messages, { role: 'user', content: 'Continue' }]\n }\n return messages\n}\n\nasync function sendWithModel(\n anthropicProvider: ReturnType<typeof createAnthropic>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n): Promise<ProviderResponse> {\n const preparedMessages = prepareMessages(messages)\n const result = await generateText({\n model: anthropicProvider(model),\n system,\n messages: preparedMessages,\n output: Output.object({ schema }),\n })\n\n return {\n content: JSON.stringify(result.output),\n usage: {\n inputTokens: result.usage.inputTokens ?? 0,\n outputTokens: result.usage.outputTokens ?? 0,\n totalTokens: (result.usage.inputTokens ?? 0) + (result.usage.outputTokens ?? 0),\n },\n }\n}\n\nasync function sendStreamWithModel(\n anthropicProvider: ReturnType<typeof createAnthropic>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n) {\n const preparedMessages = prepareMessages(messages)\n const result = streamText({\n model: anthropicProvider(model),\n system,\n messages: preparedMessages,\n output: Output.object({ schema }),\n })\n\n // Force the API call to start so executeWithFallback can catch connection errors\n const partialStream = result.partialOutputStream\n const reader = partialStream[Symbol.asyncIterator]()\n const first = await reader.next()\n\n return { result, reader, first }\n}\n\n/**\n * Creates an Anthropic provider instance.\n *\n * Uses the Vercel AI SDK (`ai` + `@ai-sdk/anthropic`) for structured output via\n * `generateText` + `Output.object()` (blocking) and `streamText` + `Output.object()`\n * (streaming). The AI SDK handles Zod-to-JSON-schema conversion, partial JSON\n * parsing, and validation internally.\n *\n * @param config - Anthropic provider configuration\n * @returns A Provider implementation using Anthropic\n *\n * @example\n * ```typescript\n * const provider = createAnthropicProvider({\n * models: ['claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001'],\n * })\n * ```\n */\nexport function createAnthropicProvider(config: AnthropicProviderConfig): Provider {\n const anthropicProvider = createAnthropic({\n apiKey: config.apiKey,\n baseURL: config.baseURL,\n })\n const models = config.models\n const resilience: ResolvedResilienceConfig = resolveResilienceConfig(config.resilience)\n\n return {\n name: 'anthropic',\n\n async sendRequest(request: ProviderRequest): Promise<ProviderResponse> {\n const messages = toAIMessages(request.messages)\n\n return executeWithFallback(\n models,\n (model) => sendWithModel(anthropicProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n },\n\n async *sendRequestStream<TState extends BaseState = BaseState>(\n request: ProviderRequest,\n ): AsyncGenerator<StreamEvent<TState>> {\n const messages = toAIMessages(request.messages)\n\n const { result, reader, first } = await executeWithFallback(\n models,\n (model) => sendStreamWithModel(anthropicProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n\n yield* processAnthropicStream<TState>(result, reader, first, 'anthropic', request.responseSchema)\n },\n }\n}\n"]}
1
+ {"version":3,"sources":["../../anthropic/streamProcessor.ts","../../utils/backoff.ts","../../utils/executeWithFallback.ts","../../anthropic/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { EventType } from '@ag-ui/client'\nimport { ZodType } from 'zod'\nimport type { AgentId, StreamEvent, BaseState } from '@genui-a3/core'\nimport type { StreamTextResult, ToolSet } from 'ai'\n\n/**\n * Processes an Anthropic streaming response (via Vercel AI SDK) into AG-UI events.\n *\n * Uses `partialOutputStream` from `streamText` + `Output.object()` to receive\n * progressively-built partial objects. Tracks `chatbotMessage` growth to yield\n * TEXT_MESSAGE_CONTENT deltas. After the stream completes, validates the final\n * object and yields TOOL_CALL_RESULT.\n *\n * @param streamResult - The streamText result containing partialOutputStream and output promise\n * @param reader - Pre-started async iterator for the partial object stream\n * @param first - The first iteration result (already consumed to trigger the API call)\n * @param agentId - Agent identifier for event tagging\n * @param schema - Zod schema for final response validation\n * @returns Async generator of AG-UI stream events\n */\nexport async function* processAnthropicStream<TState extends BaseState = BaseState>(\n streamResult: StreamTextResult<ToolSet, never>,\n reader: AsyncIterator<unknown>,\n first: IteratorResult<unknown>,\n agentId: AgentId,\n schema: ZodType,\n): AsyncGenerator<StreamEvent<TState>> {\n let prevMessageLength = 0\n\n try {\n // Process the first partial (already consumed to trigger the API call)\n if (!first.done) {\n const partial = first.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n }\n\n // Process remaining partials\n let next = await reader.next()\n while (!next.done) {\n const partial = next.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n // eslint-disable-next-line no-await-in-loop\n next = await reader.next()\n }\n\n // Stream complete — await and validate the final object\n const finalObject = await streamResult.output\n\n if (finalObject === null) {\n yield {\n type: EventType.RUN_ERROR,\n message: 'Anthropic stream completed with null output',\n agentId,\n } as StreamEvent<TState>\n return\n }\n\n const validated = schema.parse(finalObject)\n yield {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: '',\n messageId: '',\n content: JSON.stringify(validated),\n agentId,\n } as StreamEvent<TState>\n } catch (err) {\n yield {\n type: EventType.RUN_ERROR,\n message: `Anthropic stream error: ${(err as Error).message}`,\n agentId,\n } as StreamEvent<TState>\n }\n}\n\n/**\n * Extracts the new portion of chatbotMessage from a partial object.\n */\nfunction extractDelta(partial: Record<string, unknown>, prevLength: number): string | null {\n const chatbotMessage = partial.chatbotMessage\n if (typeof chatbotMessage !== 'string' || chatbotMessage.length <= prevLength) {\n return null\n }\n return chatbotMessage.slice(prevLength)\n}\n","import type { BackoffConfig } from '@genui-a3/core'\n\n/**\n * Calculates the backoff delay for a given retry attempt.\n *\n * @param attempt - Zero-based attempt index (0 = first retry)\n * @param config - Backoff configuration with all fields required\n * @returns Delay in milliseconds\n */\nexport function calculateBackoff(attempt: number, config: Required<BackoffConfig>): number {\n let delay: number\n\n switch (config.strategy) {\n case 'exponential':\n delay = config.baseDelayMs * Math.pow(2, attempt)\n break\n case 'linear':\n delay = config.baseDelayMs * (attempt + 1)\n break\n case 'fixed':\n delay = config.baseDelayMs\n break\n }\n\n delay = Math.min(delay, config.maxDelayMs)\n\n if (config.jitter) {\n delay = Math.random() * delay\n }\n\n return delay\n}\n\n/**\n * Sleeps for the specified duration. Can be aborted via an AbortSignal.\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal to cancel the sleep early\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason as Error)\n return\n }\n\n const timer = setTimeout(resolve, ms)\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason as Error)\n },\n { once: true },\n )\n })\n}\n","import {\n A3ResilienceError,\n A3TimeoutError,\n DEFAULT_RESILIENCE_CONFIG,\n type ResilienceErrorEntry,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { calculateBackoff, sleep } from './backoff'\n\n/**\n * Builds an AbortSignal that fires when either the per-request timeout or total timeout expires.\n */\nfunction buildSignal(requestTimeoutMs?: number, totalAbort?: AbortSignal): AbortSignal | undefined {\n const signals: AbortSignal[] = []\n\n if (requestTimeoutMs !== undefined) {\n signals.push(AbortSignal.timeout(requestTimeoutMs))\n }\n\n if (totalAbort) {\n signals.push(totalAbort)\n }\n\n if (signals.length === 0) return undefined\n if (signals.length === 1) return signals[0]\n return AbortSignal.any(signals)\n}\n\ntype AttemptResult<T> = { ok: true; value: T } | { ok: false; error: Error }\n\nasync function attemptAction<T>(\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n model: string,\n signal: AbortSignal | undefined,\n attempt: number,\n errors: ResilienceErrorEntry[],\n): Promise<AttemptResult<T>> {\n try {\n const value = await action(model, signal)\n return { ok: true, value }\n } catch (error) {\n const errorObj = error as Error\n errors.push({ model, attempt, error: errorObj })\n return { ok: false, error: errorObj }\n }\n}\n\nfunction checkTotalTimeout(totalAbort: AbortController | undefined, timeoutMs: number | undefined, errors: ResilienceErrorEntry[]): void {\n if (totalAbort?.signal.aborted) {\n throw new A3TimeoutError(`Total timeout of ${timeoutMs}ms exceeded`, errors)\n }\n}\n\nasync function handleAttemptError(\n errorObj: Error,\n attempt: number,\n maxRetries: number,\n retryAll: boolean,\n resolved: ResolvedResilienceConfig,\n totalAbort: AbortController | undefined,\n): Promise<'retry' | 'next-model'> {\n const isLastAttempt = attempt === 1 + maxRetries\n const isRetryable = retryAll || resolved.isRetryableError(errorObj)\n\n if (isRetryable && !isLastAttempt) {\n const delay = calculateBackoff(attempt - 1, resolved.backoff)\n await sleep(delay, totalAbort?.signal).catch(() => {\n // Sleep was aborted by total timeout — will be caught at top of loop\n })\n return 'retry'\n }\n\n return 'next-model'\n}\n\n/**\n * Executes an action with model fallback, retry, backoff, and timeout support.\n *\n * For each model (in priority order):\n * 1. Attempts the action up to `1 + maxAttempts` times\n * 2. On transient errors, waits with backoff before retrying\n * 3. On non-retryable errors (or after exhausting retries), falls back to the next model\n *\n * Throws `A3ResilienceError` with full error history when all models are exhausted.\n * Throws `A3TimeoutError` when the total timeout is exceeded.\n *\n * @param models - Model identifiers in priority order\n * @param action - Async action to attempt with each model. Receives an optional AbortSignal.\n * @param config - Resolved resilience configuration (defaults applied if omitted)\n * @returns The result from the first successful attempt\n * @throws {A3ResilienceError} When all models and retries are exhausted\n * @throws {A3TimeoutError} When the total timeout is exceeded\n *\n * @example\n * ```typescript\n * const result = await executeWithFallback(\n * ['model-primary', 'model-fallback'],\n * (model, signal) => provider.call(model, params, { abortSignal: signal }),\n * resolvedConfig,\n * )\n * ```\n */\nexport async function executeWithFallback<T>(\n models: string[],\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n config?: ResolvedResilienceConfig,\n): Promise<T> {\n const resolved = config ?? DEFAULT_RESILIENCE_CONFIG\n const errors: ResilienceErrorEntry[] = []\n const maxRetries = resolved.retry === false ? 0 : resolved.retry.maxAttempts\n const retryAll = resolved.retry !== false && resolved.retry.retryOn === 'all'\n\n // Total timeout controller\n let totalAbort: AbortController | undefined\n let totalTimer: ReturnType<typeof setTimeout> | undefined\n\n if (resolved.timeout.totalTimeoutMs !== undefined) {\n totalAbort = new AbortController()\n totalTimer = setTimeout(\n () => totalAbort!.abort(new Error('Total timeout exceeded')),\n resolved.timeout.totalTimeoutMs,\n )\n }\n\n try {\n for (let modelIndex = 0; modelIndex < models.length; modelIndex++) {\n const model = models[modelIndex]\n\n for (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n const signal = buildSignal(resolved.timeout.requestTimeoutMs, totalAbort?.signal)\n // eslint-disable-next-line no-await-in-loop\n const result = await attemptAction(action, model, signal, attempt, errors)\n if (result.ok) return result.value\n\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n // eslint-disable-next-line no-await-in-loop\n const decision = await handleAttemptError(result.error, attempt, maxRetries, retryAll, resolved, totalAbort)\n if (decision === 'next-model') break\n }\n }\n\n // All models exhausted\n throw new A3ResilienceError(\n `All models failed after ${errors.length} total attempt(s): ${models.join(', ')}`,\n errors,\n )\n } finally {\n if (totalTimer !== undefined) {\n clearTimeout(totalTimer)\n }\n }\n}\n","import { createAnthropic } from '@ai-sdk/anthropic'\nimport { generateText, streamText, Output, ModelMessage } from 'ai'\nimport {\n resolveResilienceConfig,\n type Provider,\n type ProviderRequest,\n type ProviderResponse,\n type ProviderMessage,\n type BaseState,\n type StreamEvent,\n type ResilienceConfig,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { processAnthropicStream } from './streamProcessor'\nimport { executeWithFallback } from '@providers/utils/executeWithFallback'\n\n/**\n * Configuration for creating an Anthropic provider.\n */\nexport interface AnthropicProviderConfig {\n /** Anthropic API key. Defaults to ANTHROPIC_API_KEY env var. */\n apiKey?: string\n /**\n * Model identifiers in order of preference (first = primary, rest = fallbacks).\n * e.g. ['claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001']\n */\n models: string[]\n /** Optional custom base URL for the Anthropic API */\n baseURL?: string\n /** Resilience configuration (retry, backoff, timeout). Uses industry-standard defaults if omitted. */\n resilience?: ResilienceConfig\n}\n\nfunction toAIMessages(messages: ProviderMessage[]): ModelMessage[] {\n return messages.map((msg) => ({\n role: msg.role,\n content: msg.content,\n }))\n}\n\nexport function prepareMessages(messages: ModelMessage[]): ModelMessage[] {\n if (messages.length === 0) return messages\n const lastMessage = messages[messages.length - 1]\n if (lastMessage.role === 'assistant') {\n return [...messages, { role: 'user', content: 'Continue' }]\n }\n return messages\n}\n\nasync function sendWithModel(\n anthropicProvider: ReturnType<typeof createAnthropic>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n): Promise<ProviderResponse> {\n const preparedMessages = prepareMessages(messages)\n const result = await generateText({\n model: anthropicProvider(model),\n system,\n messages: preparedMessages,\n output: Output.object({ schema }),\n })\n\n return {\n content: JSON.stringify(result.output),\n usage: {\n inputTokens: result.usage.inputTokens ?? 0,\n outputTokens: result.usage.outputTokens ?? 0,\n totalTokens: (result.usage.inputTokens ?? 0) + (result.usage.outputTokens ?? 0),\n },\n }\n}\n\nasync function sendStreamWithModel(\n anthropicProvider: ReturnType<typeof createAnthropic>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n) {\n const preparedMessages = prepareMessages(messages)\n const result = streamText({\n model: anthropicProvider(model),\n system,\n messages: preparedMessages,\n output: Output.object({ schema }),\n })\n\n // Force the API call to start so executeWithFallback can catch connection errors\n const partialStream = result.partialOutputStream\n const reader = partialStream[Symbol.asyncIterator]()\n const first = await reader.next()\n\n return { result, reader, first }\n}\n\n/**\n * Creates an Anthropic provider instance.\n *\n * Uses the Vercel AI SDK (`ai` + `@ai-sdk/anthropic`) for structured output via\n * `generateText` + `Output.object()` (blocking) and `streamText` + `Output.object()`\n * (streaming). The AI SDK handles Zod-to-JSON-schema conversion, partial JSON\n * parsing, and validation internally.\n *\n * @param config - Anthropic provider configuration\n * @returns A Provider implementation using Anthropic\n *\n * @example\n * ```typescript\n * const provider = createAnthropicProvider({\n * models: ['claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001'],\n * })\n * ```\n */\nexport function createAnthropicProvider(config: AnthropicProviderConfig): Provider {\n const anthropicProvider = createAnthropic({\n apiKey: config.apiKey,\n baseURL: config.baseURL,\n })\n const models = config.models\n const resilience: ResolvedResilienceConfig = resolveResilienceConfig(config.resilience)\n\n return {\n name: 'anthropic',\n\n async sendRequest(request: ProviderRequest): Promise<ProviderResponse> {\n const messages = toAIMessages(request.messages)\n\n return executeWithFallback(\n models,\n (model) => sendWithModel(anthropicProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n },\n\n async *sendRequestStream<TState extends BaseState = BaseState>(\n request: ProviderRequest,\n ): AsyncGenerator<StreamEvent<TState>> {\n const messages = toAIMessages(request.messages)\n\n const { result, reader, first } = await executeWithFallback(\n models,\n (model) =>\n sendStreamWithModel(anthropicProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n\n yield* processAnthropicStream<TState>(result, reader, first, 'anthropic', request.responseSchema)\n },\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../bedrock/messageMerger.ts","../../bedrock/streamProcessor.ts","../../utils/backoff.ts","../../utils/executeWithFallback.ts","../../bedrock/index.ts"],"names":["EventType","A3TimeoutError","DEFAULT_RESILIENCE_CONFIG","A3ResilienceError","ConverseCommand","ConverseStreamCommand","BedrockRuntimeClient","resolveResilienceConfig"],"mappings":"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","file":"index.cjs","sourcesContent":["import { Message as BedrockMessage } from '@aws-sdk/client-bedrock-runtime'\nimport type { ProviderMessage } from '@genui-a3/core'\n\n/**\n * Converts provider-agnostic messages to Bedrock format, merging sequential same-role messages.\n * Bedrock requires alternating user/assistant roles — this merges consecutive same-role messages\n * into a single message with multiple content blocks.\n */\nexport function mergeSequentialMessages(messages: ProviderMessage[]): BedrockMessage[] {\n if (messages.length === 0) return []\n\n const result: BedrockMessage[] = []\n let currentMessage: BedrockMessage | null = null\n\n for (const message of messages) {\n if (!message.content) continue\n\n if (!currentMessage) {\n currentMessage = {\n role: message.role,\n content: [{ text: message.content }],\n }\n } else if (currentMessage.role === message.role && currentMessage.content) {\n currentMessage.content.push({ text: message.content })\n } else {\n result.push(currentMessage)\n currentMessage = {\n role: message.role,\n content: [{ text: message.content }],\n }\n }\n }\n\n if (currentMessage) {\n result.push(currentMessage)\n }\n\n return result\n}\n","import { ConverseStreamOutput } from '@aws-sdk/client-bedrock-runtime'\nimport { EventType } from '@ag-ui/client'\nimport { ZodType } from 'zod'\nimport type { AgentId, StreamEvent, BaseState } from '@genui-a3/core'\n\nexport async function* processBedrockStream<TState extends BaseState = BaseState>(\n rawStream: AsyncIterable<ConverseStreamOutput>,\n agentId: AgentId,\n schema: ZodType,\n): AsyncGenerator<StreamEvent<TState>> {\n let currentBlockType: 'text' | 'toolUse' | null = null\n let toolInputBuffer = ''\n\n for await (const event of rawStream) {\n // --- Content block start: determine block type ---\n if (event.contentBlockStart) {\n if (event.contentBlockStart.start?.toolUse) {\n currentBlockType = 'toolUse'\n toolInputBuffer = ''\n } else {\n currentBlockType = 'text'\n }\n continue\n }\n\n // --- Content block delta: text or tool input ---\n if (event.contentBlockDelta) {\n const delta = event.contentBlockDelta.delta\n if (!delta) continue\n\n // Infer block type from delta content if no contentBlockStart was received\n // (Bedrock may omit contentBlockStart for the first text block)\n if (delta.text && (currentBlockType === 'text' || currentBlockType === null)) {\n currentBlockType = 'text'\n yield { type: EventType.TEXT_MESSAGE_CONTENT, messageId: '', delta: delta.text, agentId } as StreamEvent<TState>\n } else if (delta.toolUse && (currentBlockType === 'toolUse' || currentBlockType === null)) {\n currentBlockType = 'toolUse'\n toolInputBuffer += delta.toolUse.input ?? ''\n }\n continue\n }\n\n // --- Content block stop: parse and validate tool call ---\n if (event.contentBlockStop) {\n if (currentBlockType === 'toolUse' && toolInputBuffer) {\n yield parseToolCall<TState>(toolInputBuffer, schema, agentId)\n toolInputBuffer = ''\n }\n currentBlockType = null\n continue\n }\n\n // --- Metadata: log usage ---\n if (event.metadata) {\n continue\n }\n\n // --- Error events: throw to surface to caller ---\n throwIfStreamError(event)\n }\n}\n\nfunction parseToolCall<TState extends BaseState>(\n toolInputBuffer: string,\n schema: ZodType,\n agentId: AgentId,\n): StreamEvent<TState> {\n try {\n const parsed = JSON.parse(toolInputBuffer) as Record<string, unknown>\n const validated = schema.parse(parsed)\n return {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: '',\n messageId: '',\n content: JSON.stringify(validated),\n agentId,\n } as StreamEvent<TState>\n } catch (err) {\n return {\n type: EventType.RUN_ERROR,\n message: `Tool call parse/validation failed: ${(err as Error).message}`,\n agentId,\n } as StreamEvent<TState>\n }\n}\n\nfunction throwIfStreamError(event: ConverseStreamOutput): void {\n if (event.internalServerException) {\n throw new Error(`Bedrock internal error: ${event.internalServerException.message}`)\n }\n if (event.modelStreamErrorException) {\n throw new Error(`Bedrock model stream error: ${event.modelStreamErrorException.message}`)\n }\n if (event.throttlingException) {\n throw new Error(`Bedrock throttling: ${event.throttlingException.message}`)\n }\n if (event.validationException) {\n throw new Error(`Bedrock validation error: ${event.validationException.message}`)\n }\n if (event.serviceUnavailableException) {\n throw new Error(`Bedrock service unavailable: ${event.serviceUnavailableException.message}`)\n }\n}\n","import type { BackoffConfig } from '@genui-a3/core'\n\n/**\n * Calculates the backoff delay for a given retry attempt.\n *\n * @param attempt - Zero-based attempt index (0 = first retry)\n * @param config - Backoff configuration with all fields required\n * @returns Delay in milliseconds\n */\nexport function calculateBackoff(attempt: number, config: Required<BackoffConfig>): number {\n let delay: number\n\n switch (config.strategy) {\n case 'exponential':\n delay = config.baseDelayMs * Math.pow(2, attempt)\n break\n case 'linear':\n delay = config.baseDelayMs * (attempt + 1)\n break\n case 'fixed':\n delay = config.baseDelayMs\n break\n }\n\n delay = Math.min(delay, config.maxDelayMs)\n\n if (config.jitter) {\n delay = Math.random() * delay\n }\n\n return delay\n}\n\n/**\n * Sleeps for the specified duration. Can be aborted via an AbortSignal.\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal to cancel the sleep early\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason as Error)\n return\n }\n\n const timer = setTimeout(resolve, ms)\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason as Error)\n },\n { once: true },\n )\n })\n}\n","import {\n A3ResilienceError,\n A3TimeoutError,\n DEFAULT_RESILIENCE_CONFIG,\n type ResilienceErrorEntry,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { calculateBackoff, sleep } from './backoff'\n\n/**\n * Builds an AbortSignal that fires when either the per-request timeout or total timeout expires.\n */\nfunction buildSignal(requestTimeoutMs?: number, totalAbort?: AbortSignal): AbortSignal | undefined {\n const signals: AbortSignal[] = []\n\n if (requestTimeoutMs !== undefined) {\n signals.push(AbortSignal.timeout(requestTimeoutMs))\n }\n\n if (totalAbort) {\n signals.push(totalAbort)\n }\n\n if (signals.length === 0) return undefined\n if (signals.length === 1) return signals[0]\n return AbortSignal.any(signals)\n}\n\ntype AttemptResult<T> = { ok: true; value: T } | { ok: false; error: Error }\n\nasync function attemptAction<T>(\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n model: string,\n signal: AbortSignal | undefined,\n attempt: number,\n errors: ResilienceErrorEntry[],\n): Promise<AttemptResult<T>> {\n try {\n const value = await action(model, signal)\n return { ok: true, value }\n } catch (error) {\n const errorObj = error as Error\n errors.push({ model, attempt, error: errorObj })\n return { ok: false, error: errorObj }\n }\n}\n\nfunction checkTotalTimeout(totalAbort: AbortController | undefined, timeoutMs: number | undefined, errors: ResilienceErrorEntry[]): void {\n if (totalAbort?.signal.aborted) {\n throw new A3TimeoutError(`Total timeout of ${timeoutMs}ms exceeded`, errors)\n }\n}\n\nasync function handleAttemptError(\n errorObj: Error,\n attempt: number,\n maxRetries: number,\n retryAll: boolean,\n resolved: ResolvedResilienceConfig,\n totalAbort: AbortController | undefined,\n): Promise<'retry' | 'next-model'> {\n const isLastAttempt = attempt === 1 + maxRetries\n const isRetryable = retryAll || resolved.isRetryableError(errorObj)\n\n if (isRetryable && !isLastAttempt) {\n const delay = calculateBackoff(attempt - 1, resolved.backoff)\n await sleep(delay, totalAbort?.signal).catch(() => {\n // Sleep was aborted by total timeout — will be caught at top of loop\n })\n return 'retry'\n }\n\n return 'next-model'\n}\n\n/**\n * Executes an action with model fallback, retry, backoff, and timeout support.\n *\n * For each model (in priority order):\n * 1. Attempts the action up to `1 + maxAttempts` times\n * 2. On transient errors, waits with backoff before retrying\n * 3. On non-retryable errors (or after exhausting retries), falls back to the next model\n *\n * Throws `A3ResilienceError` with full error history when all models are exhausted.\n * Throws `A3TimeoutError` when the total timeout is exceeded.\n *\n * @param models - Model identifiers in priority order\n * @param action - Async action to attempt with each model. Receives an optional AbortSignal.\n * @param config - Resolved resilience configuration (defaults applied if omitted)\n * @returns The result from the first successful attempt\n * @throws {A3ResilienceError} When all models and retries are exhausted\n * @throws {A3TimeoutError} When the total timeout is exceeded\n *\n * @example\n * ```typescript\n * const result = await executeWithFallback(\n * ['model-primary', 'model-fallback'],\n * (model, signal) => provider.call(model, params, { abortSignal: signal }),\n * resolvedConfig,\n * )\n * ```\n */\nexport async function executeWithFallback<T>(\n models: string[],\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n config?: ResolvedResilienceConfig,\n): Promise<T> {\n const resolved = config ?? DEFAULT_RESILIENCE_CONFIG\n const errors: ResilienceErrorEntry[] = []\n const maxRetries = resolved.retry === false ? 0 : resolved.retry.maxAttempts\n const retryAll = resolved.retry !== false && resolved.retry.retryOn === 'all'\n\n // Total timeout controller\n let totalAbort: AbortController | undefined\n let totalTimer: ReturnType<typeof setTimeout> | undefined\n\n if (resolved.timeout.totalTimeoutMs !== undefined) {\n totalAbort = new AbortController()\n totalTimer = setTimeout(\n () => totalAbort!.abort(new Error('Total timeout exceeded')),\n resolved.timeout.totalTimeoutMs,\n )\n }\n\n try {\n for (let modelIndex = 0; modelIndex < models.length; modelIndex++) {\n const model = models[modelIndex]\n\n for (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n const signal = buildSignal(resolved.timeout.requestTimeoutMs, totalAbort?.signal)\n // eslint-disable-next-line no-await-in-loop\n const result = await attemptAction(action, model, signal, attempt, errors)\n if (result.ok) return result.value\n\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n // eslint-disable-next-line no-await-in-loop\n const decision = await handleAttemptError(result.error, attempt, maxRetries, retryAll, resolved, totalAbort)\n if (decision === 'next-model') break\n }\n }\n\n // All models exhausted\n throw new A3ResilienceError(\n `All models failed after ${errors.length} total attempt(s): ${models.join(', ')}`,\n errors,\n )\n } finally {\n if (totalTimer !== undefined) {\n clearTimeout(totalTimer)\n }\n }\n}\n","import {\n BedrockRuntimeClient,\n ConverseCommand,\n ConverseStreamCommand,\n ConverseStreamOutput,\n ToolInputSchema,\n} from '@aws-sdk/client-bedrock-runtime'\nimport {\n resolveResilienceConfig,\n type Provider,\n type ProviderRequest,\n type ProviderResponse,\n type ProviderMessage,\n type BaseState,\n type StreamEvent,\n type ResilienceConfig,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { mergeSequentialMessages } from './messageMerger'\nimport { processBedrockStream } from './streamProcessor'\nimport { executeWithFallback } from '../utils/executeWithFallback'\n\nconst RESPONSE_FORMAT_INSTRUCTIONS = `\n\n# RESPONSE FORMAT — MANDATORY\n\n<<CRITICAL INSTRUCTION>>\nYou MUST ALWAYS output plain text FIRST, then call the structuredResponse tool SECOND. NEVER call the tool without writing text first. This is non-negotiable.\n<</CRITICAL INSTRUCTION>>\n\nYour response MUST have exactly two parts in this order:\n\nPART 1 — TEXT: Write your full conversational reply as plain text. This text is streamed to the user in real-time. Do not skip this.\n\nPART 2 — TOOL CALL: After the text, call the \\`structuredResponse\\` tool with the JSON payload. The \\`chatbotMessage\\` field MUST contain the same text you wrote in Part 1.\n\nIf you call the tool without writing text first, the response will be broken.`\n\n/**\n * Configuration for creating a Bedrock provider.\n */\nexport interface BedrockProviderConfig {\n /** AWS region for the Bedrock client */\n region?: string\n /**\n * Model identifiers in order of preference (first = primary, rest = fallbacks).\n * Uses Bedrock model ARNs, e.g. 'us.anthropic.claude-sonnet-4-5-20250929-v1:0'\n */\n models: string[]\n /** Resilience configuration (retry, backoff, timeout). Uses industry-standard defaults if omitted. */\n resilience?: ResilienceConfig\n}\n\ntype SendWithModelParams = {\n modelId: string\n systemPrompt: string\n mergedMessages: ReturnType<typeof mergeSequentialMessages>\n inputSchema: ToolInputSchema | undefined\n}\n\nfunction getCommandInput(params: SendWithModelParams, isStream: boolean) {\n return {\n modelId: params.modelId,\n system: [{ text: params.systemPrompt }],\n messages: params.mergedMessages,\n toolConfig: {\n tools: [\n {\n toolSpec: {\n name: 'structuredResponse',\n description: isStream\n ? 'Submit your structured response data. IMPORTANT: You MUST write your full text reply BEFORE calling this tool. Never call this tool as your first action.'\n : 'A tool to generate a structured response',\n inputSchema: params.inputSchema,\n },\n },\n ],\n toolChoice: isStream ? { auto: {} } : { any: {} },\n },\n }\n}\n\nasync function sendWithModel(client: BedrockRuntimeClient, params: SendWithModelParams): Promise<ProviderResponse> {\n const command = new ConverseCommand(getCommandInput(params, false))\n const response = await client.send(command)\n\n const contentBlocks = response.output?.message?.content ?? []\n const toolUseBlock = contentBlocks.find((block) => block.toolUse)\n const result = toolUseBlock?.toolUse?.input\n\n const isValidResponse =\n result &&\n typeof result === 'object' &&\n 'conversationPayload' in result &&\n 'chatbotMessage' in result &&\n typeof result.conversationPayload === 'object' &&\n typeof result.chatbotMessage === 'string'\n\n if (!isValidResponse) {\n throw new Error('Bedrock returned invalid tool response')\n }\n\n return {\n content: JSON.stringify(result),\n usage: response.usage\n ? {\n inputTokens: response.usage.inputTokens,\n outputTokens: response.usage.outputTokens,\n totalTokens: (response.usage.inputTokens ?? 0) + (response.usage.outputTokens ?? 0),\n }\n : undefined,\n }\n}\n\nasync function sendStreamWithModel(\n client: BedrockRuntimeClient,\n params: SendWithModelParams,\n): Promise<AsyncIterable<ConverseStreamOutput>> {\n const command = new ConverseStreamCommand(getCommandInput(params, true))\n const response = await client.send(command)\n\n if (!response.stream) {\n throw new Error('No stream returned from Bedrock')\n }\n\n return response.stream\n}\n\nfunction prepareRequest(request: ProviderRequest) {\n const systemPrompt = RESPONSE_FORMAT_INSTRUCTIONS + '\\n\\n' + request.systemPrompt\n const jsonSchema = request.responseSchema.toJSONSchema()\n const inputSchema = { json: jsonSchema } as ToolInputSchema\n\n // Bedrock requires messages to start with a user message — prepend \"Hi\" if needed\n const prependedMessages: ProviderMessage[] = [{ role: 'user', content: 'Hi\\n' }, ...request.messages]\n const mergedMessages = mergeSequentialMessages(prependedMessages)\n\n return { systemPrompt, inputSchema, mergedMessages }\n}\n\n/**\n * Creates an AWS Bedrock provider instance.\n *\n * @param config - Bedrock provider configuration\n * @returns A Provider implementation using AWS Bedrock\n *\n * @example\n * ```typescript\n * const provider = createBedrockProvider({\n * models: ['us.anthropic.claude-sonnet-4-5-20250929-v1:0'],\n * region: 'us-east-1',\n * })\n * ```\n */\nexport function createBedrockProvider(config: BedrockProviderConfig): Provider {\n const client = new BedrockRuntimeClient(config.region ? { region: config.region } : {})\n const models = config.models\n const resilience: ResolvedResilienceConfig = resolveResilienceConfig(config.resilience)\n\n return {\n name: 'bedrock',\n\n async sendRequest(request: ProviderRequest): Promise<ProviderResponse> {\n const { systemPrompt, inputSchema, mergedMessages } = prepareRequest(request)\n\n return executeWithFallback(\n models,\n (modelId) =>\n sendWithModel(client, {\n modelId,\n systemPrompt,\n mergedMessages,\n inputSchema,\n }),\n resilience,\n )\n },\n\n async *sendRequestStream<TState extends BaseState = BaseState>(\n request: ProviderRequest,\n ): AsyncGenerator<StreamEvent<TState>> {\n const { systemPrompt, inputSchema, mergedMessages } = prepareRequest(request)\n\n const rawStream = await executeWithFallback(\n models,\n (modelId) =>\n sendStreamWithModel(client, {\n modelId,\n systemPrompt,\n mergedMessages,\n inputSchema,\n }),\n resilience,\n )\n\n yield* processBedrockStream<TState>(rawStream, 'bedrock', request.responseSchema)\n },\n }\n}\n"]}
1
+ {"version":3,"sources":["../../bedrock/messageMerger.ts","../../bedrock/streamProcessor.ts","../../utils/backoff.ts","../../utils/executeWithFallback.ts","../../bedrock/index.ts"],"names":["EventType","A3TimeoutError","DEFAULT_RESILIENCE_CONFIG","A3ResilienceError","ConverseCommand","ConverseStreamCommand","BedrockRuntimeClient","resolveResilienceConfig"],"mappings":"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","file":"index.cjs","sourcesContent":["import { Message as BedrockMessage } from '@aws-sdk/client-bedrock-runtime'\nimport type { ProviderMessage } from '@genui-a3/core'\n\n/**\n * Converts provider-agnostic messages to Bedrock format, merging sequential same-role messages.\n * Bedrock requires alternating user/assistant roles — this merges consecutive same-role messages\n * into a single message with multiple content blocks.\n */\nexport function mergeSequentialMessages(messages: ProviderMessage[]): BedrockMessage[] {\n if (messages.length === 0) return []\n\n const result: BedrockMessage[] = []\n let currentMessage: BedrockMessage | null = null\n\n for (const message of messages) {\n if (!message.content) continue\n\n if (!currentMessage) {\n currentMessage = {\n role: message.role,\n content: [{ text: message.content }],\n }\n } else if (currentMessage.role === message.role && currentMessage.content) {\n currentMessage.content.push({ text: message.content })\n } else {\n result.push(currentMessage)\n currentMessage = {\n role: message.role,\n content: [{ text: message.content }],\n }\n }\n }\n\n if (currentMessage) {\n result.push(currentMessage)\n }\n\n return result\n}\n","import { ConverseStreamOutput } from '@aws-sdk/client-bedrock-runtime'\nimport { EventType } from '@ag-ui/client'\nimport { ZodType } from 'zod'\nimport type { AgentId, StreamEvent, BaseState } from '@genui-a3/core'\n\nexport async function* processBedrockStream<TState extends BaseState = BaseState>(\n rawStream: AsyncIterable<ConverseStreamOutput>,\n agentId: AgentId,\n schema: ZodType,\n): AsyncGenerator<StreamEvent<TState>> {\n let currentBlockType: 'text' | 'toolUse' | null = null\n let toolInputBuffer = ''\n\n for await (const event of rawStream) {\n // --- Content block start: determine block type ---\n if (event.contentBlockStart) {\n if (event.contentBlockStart.start?.toolUse) {\n currentBlockType = 'toolUse'\n toolInputBuffer = ''\n } else {\n currentBlockType = 'text'\n }\n continue\n }\n\n // --- Content block delta: text or tool input ---\n if (event.contentBlockDelta) {\n const delta = event.contentBlockDelta.delta\n if (!delta) continue\n\n // Infer block type from delta content if no contentBlockStart was received\n // (Bedrock may omit contentBlockStart for the first text block)\n if (delta.text && (currentBlockType === 'text' || currentBlockType === null)) {\n currentBlockType = 'text'\n yield { type: EventType.TEXT_MESSAGE_CONTENT, messageId: '', delta: delta.text, agentId } as StreamEvent<TState>\n } else if (delta.toolUse && (currentBlockType === 'toolUse' || currentBlockType === null)) {\n currentBlockType = 'toolUse'\n toolInputBuffer += delta.toolUse.input ?? ''\n }\n continue\n }\n\n // --- Content block stop: parse and validate tool call ---\n if (event.contentBlockStop) {\n if (currentBlockType === 'toolUse' && toolInputBuffer) {\n yield parseToolCall<TState>(toolInputBuffer, schema, agentId)\n toolInputBuffer = ''\n }\n currentBlockType = null\n continue\n }\n\n // --- Metadata: log usage ---\n if (event.metadata) {\n continue\n }\n\n // --- Error events: throw to surface to caller ---\n throwIfStreamError(event)\n }\n}\n\nfunction parseToolCall<TState extends BaseState>(\n toolInputBuffer: string,\n schema: ZodType,\n agentId: AgentId,\n): StreamEvent<TState> {\n try {\n const parsed = JSON.parse(toolInputBuffer) as Record<string, unknown>\n const validated = schema.parse(parsed)\n return {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: '',\n messageId: '',\n content: JSON.stringify(validated),\n agentId,\n } as StreamEvent<TState>\n } catch (err) {\n return {\n type: EventType.RUN_ERROR,\n message: `Tool call parse/validation failed: ${(err as Error).message}`,\n agentId,\n } as StreamEvent<TState>\n }\n}\n\nfunction throwIfStreamError(event: ConverseStreamOutput): void {\n if (event.internalServerException) {\n throw new Error(`Bedrock internal error: ${event.internalServerException.message}`)\n }\n if (event.modelStreamErrorException) {\n throw new Error(`Bedrock model stream error: ${event.modelStreamErrorException.message}`)\n }\n if (event.throttlingException) {\n throw new Error(`Bedrock throttling: ${event.throttlingException.message}`)\n }\n if (event.validationException) {\n throw new Error(`Bedrock validation error: ${event.validationException.message}`)\n }\n if (event.serviceUnavailableException) {\n throw new Error(`Bedrock service unavailable: ${event.serviceUnavailableException.message}`)\n }\n}\n","import type { BackoffConfig } from '@genui-a3/core'\n\n/**\n * Calculates the backoff delay for a given retry attempt.\n *\n * @param attempt - Zero-based attempt index (0 = first retry)\n * @param config - Backoff configuration with all fields required\n * @returns Delay in milliseconds\n */\nexport function calculateBackoff(attempt: number, config: Required<BackoffConfig>): number {\n let delay: number\n\n switch (config.strategy) {\n case 'exponential':\n delay = config.baseDelayMs * Math.pow(2, attempt)\n break\n case 'linear':\n delay = config.baseDelayMs * (attempt + 1)\n break\n case 'fixed':\n delay = config.baseDelayMs\n break\n }\n\n delay = Math.min(delay, config.maxDelayMs)\n\n if (config.jitter) {\n delay = Math.random() * delay\n }\n\n return delay\n}\n\n/**\n * Sleeps for the specified duration. Can be aborted via an AbortSignal.\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal to cancel the sleep early\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason as Error)\n return\n }\n\n const timer = setTimeout(resolve, ms)\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason as Error)\n },\n { once: true },\n )\n })\n}\n","import {\n A3ResilienceError,\n A3TimeoutError,\n DEFAULT_RESILIENCE_CONFIG,\n type ResilienceErrorEntry,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { calculateBackoff, sleep } from './backoff'\n\n/**\n * Builds an AbortSignal that fires when either the per-request timeout or total timeout expires.\n */\nfunction buildSignal(requestTimeoutMs?: number, totalAbort?: AbortSignal): AbortSignal | undefined {\n const signals: AbortSignal[] = []\n\n if (requestTimeoutMs !== undefined) {\n signals.push(AbortSignal.timeout(requestTimeoutMs))\n }\n\n if (totalAbort) {\n signals.push(totalAbort)\n }\n\n if (signals.length === 0) return undefined\n if (signals.length === 1) return signals[0]\n return AbortSignal.any(signals)\n}\n\ntype AttemptResult<T> = { ok: true; value: T } | { ok: false; error: Error }\n\nasync function attemptAction<T>(\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n model: string,\n signal: AbortSignal | undefined,\n attempt: number,\n errors: ResilienceErrorEntry[],\n): Promise<AttemptResult<T>> {\n try {\n const value = await action(model, signal)\n return { ok: true, value }\n } catch (error) {\n const errorObj = error as Error\n errors.push({ model, attempt, error: errorObj })\n return { ok: false, error: errorObj }\n }\n}\n\nfunction checkTotalTimeout(totalAbort: AbortController | undefined, timeoutMs: number | undefined, errors: ResilienceErrorEntry[]): void {\n if (totalAbort?.signal.aborted) {\n throw new A3TimeoutError(`Total timeout of ${timeoutMs}ms exceeded`, errors)\n }\n}\n\nasync function handleAttemptError(\n errorObj: Error,\n attempt: number,\n maxRetries: number,\n retryAll: boolean,\n resolved: ResolvedResilienceConfig,\n totalAbort: AbortController | undefined,\n): Promise<'retry' | 'next-model'> {\n const isLastAttempt = attempt === 1 + maxRetries\n const isRetryable = retryAll || resolved.isRetryableError(errorObj)\n\n if (isRetryable && !isLastAttempt) {\n const delay = calculateBackoff(attempt - 1, resolved.backoff)\n await sleep(delay, totalAbort?.signal).catch(() => {\n // Sleep was aborted by total timeout — will be caught at top of loop\n })\n return 'retry'\n }\n\n return 'next-model'\n}\n\n/**\n * Executes an action with model fallback, retry, backoff, and timeout support.\n *\n * For each model (in priority order):\n * 1. Attempts the action up to `1 + maxAttempts` times\n * 2. On transient errors, waits with backoff before retrying\n * 3. On non-retryable errors (or after exhausting retries), falls back to the next model\n *\n * Throws `A3ResilienceError` with full error history when all models are exhausted.\n * Throws `A3TimeoutError` when the total timeout is exceeded.\n *\n * @param models - Model identifiers in priority order\n * @param action - Async action to attempt with each model. Receives an optional AbortSignal.\n * @param config - Resolved resilience configuration (defaults applied if omitted)\n * @returns The result from the first successful attempt\n * @throws {A3ResilienceError} When all models and retries are exhausted\n * @throws {A3TimeoutError} When the total timeout is exceeded\n *\n * @example\n * ```typescript\n * const result = await executeWithFallback(\n * ['model-primary', 'model-fallback'],\n * (model, signal) => provider.call(model, params, { abortSignal: signal }),\n * resolvedConfig,\n * )\n * ```\n */\nexport async function executeWithFallback<T>(\n models: string[],\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n config?: ResolvedResilienceConfig,\n): Promise<T> {\n const resolved = config ?? DEFAULT_RESILIENCE_CONFIG\n const errors: ResilienceErrorEntry[] = []\n const maxRetries = resolved.retry === false ? 0 : resolved.retry.maxAttempts\n const retryAll = resolved.retry !== false && resolved.retry.retryOn === 'all'\n\n // Total timeout controller\n let totalAbort: AbortController | undefined\n let totalTimer: ReturnType<typeof setTimeout> | undefined\n\n if (resolved.timeout.totalTimeoutMs !== undefined) {\n totalAbort = new AbortController()\n totalTimer = setTimeout(\n () => totalAbort!.abort(new Error('Total timeout exceeded')),\n resolved.timeout.totalTimeoutMs,\n )\n }\n\n try {\n for (let modelIndex = 0; modelIndex < models.length; modelIndex++) {\n const model = models[modelIndex]\n\n for (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n const signal = buildSignal(resolved.timeout.requestTimeoutMs, totalAbort?.signal)\n // eslint-disable-next-line no-await-in-loop\n const result = await attemptAction(action, model, signal, attempt, errors)\n if (result.ok) return result.value\n\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n // eslint-disable-next-line no-await-in-loop\n const decision = await handleAttemptError(result.error, attempt, maxRetries, retryAll, resolved, totalAbort)\n if (decision === 'next-model') break\n }\n }\n\n // All models exhausted\n throw new A3ResilienceError(\n `All models failed after ${errors.length} total attempt(s): ${models.join(', ')}`,\n errors,\n )\n } finally {\n if (totalTimer !== undefined) {\n clearTimeout(totalTimer)\n }\n }\n}\n","import {\n BedrockRuntimeClient,\n ConverseCommand,\n ConverseStreamCommand,\n ConverseStreamOutput,\n ToolInputSchema,\n} from '@aws-sdk/client-bedrock-runtime'\nimport {\n resolveResilienceConfig,\n type Provider,\n type ProviderRequest,\n type ProviderResponse,\n type ProviderMessage,\n type BaseState,\n type StreamEvent,\n type ResilienceConfig,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { mergeSequentialMessages } from './messageMerger'\nimport { processBedrockStream } from './streamProcessor'\nimport { executeWithFallback } from '@providers/utils/executeWithFallback'\n\nconst RESPONSE_FORMAT_INSTRUCTIONS = `\n\n# RESPONSE FORMAT — MANDATORY\n\n<<CRITICAL INSTRUCTION>>\nYou MUST ALWAYS output plain text FIRST, then call the structuredResponse tool SECOND. NEVER call the tool without writing text first. This is non-negotiable.\n<</CRITICAL INSTRUCTION>>\n\nYour response MUST have exactly two parts in this order:\n\nPART 1 — TEXT: Write your full conversational reply as plain text. This text is streamed to the user in real-time. Do not skip this.\n\nPART 2 — TOOL CALL: After the text, call the \\`structuredResponse\\` tool with the JSON payload. The \\`chatbotMessage\\` field MUST contain the same text you wrote in Part 1.\n\nIf you call the tool without writing text first, the response will be broken.`\n\n/**\n * Configuration for creating a Bedrock provider.\n */\nexport interface BedrockProviderConfig {\n /** AWS region for the Bedrock client */\n region?: string\n /**\n * Model identifiers in order of preference (first = primary, rest = fallbacks).\n * Uses Bedrock model ARNs, e.g. 'us.anthropic.claude-sonnet-4-5-20250929-v1:0'\n */\n models: string[]\n /** Resilience configuration (retry, backoff, timeout). Uses industry-standard defaults if omitted. */\n resilience?: ResilienceConfig\n}\n\ntype SendWithModelParams = {\n modelId: string\n systemPrompt: string\n mergedMessages: ReturnType<typeof mergeSequentialMessages>\n inputSchema: ToolInputSchema | undefined\n}\n\nfunction getCommandInput(params: SendWithModelParams, isStream: boolean) {\n return {\n modelId: params.modelId,\n system: [{ text: params.systemPrompt }],\n messages: params.mergedMessages,\n toolConfig: {\n tools: [\n {\n toolSpec: {\n name: 'structuredResponse',\n description: isStream\n ? 'Submit your structured response data. IMPORTANT: You MUST write your full text reply BEFORE calling this tool. Never call this tool as your first action.'\n : 'A tool to generate a structured response',\n inputSchema: params.inputSchema,\n },\n },\n ],\n toolChoice: isStream ? { auto: {} } : { any: {} },\n },\n }\n}\n\nasync function sendWithModel(client: BedrockRuntimeClient, params: SendWithModelParams): Promise<ProviderResponse> {\n const command = new ConverseCommand(getCommandInput(params, false))\n const response = await client.send(command)\n\n const contentBlocks = response.output?.message?.content ?? []\n const toolUseBlock = contentBlocks.find((block) => block.toolUse)\n const result = toolUseBlock?.toolUse?.input\n\n const isValidResponse =\n result &&\n typeof result === 'object' &&\n 'conversationPayload' in result &&\n 'chatbotMessage' in result &&\n typeof result.conversationPayload === 'object' &&\n typeof result.chatbotMessage === 'string'\n\n if (!isValidResponse) {\n throw new Error('Bedrock returned invalid tool response')\n }\n\n return {\n content: JSON.stringify(result),\n usage: response.usage\n ? {\n inputTokens: response.usage.inputTokens,\n outputTokens: response.usage.outputTokens,\n totalTokens: (response.usage.inputTokens ?? 0) + (response.usage.outputTokens ?? 0),\n }\n : undefined,\n }\n}\n\nasync function sendStreamWithModel(\n client: BedrockRuntimeClient,\n params: SendWithModelParams,\n): Promise<AsyncIterable<ConverseStreamOutput>> {\n const command = new ConverseStreamCommand(getCommandInput(params, true))\n const response = await client.send(command)\n\n if (!response.stream) {\n throw new Error('No stream returned from Bedrock')\n }\n\n return response.stream\n}\n\nfunction prepareRequest(request: ProviderRequest) {\n const systemPrompt = RESPONSE_FORMAT_INSTRUCTIONS + '\\n\\n' + request.systemPrompt\n const jsonSchema = request.responseSchema.toJSONSchema()\n const inputSchema = { json: jsonSchema } as ToolInputSchema\n\n // Bedrock requires messages to start with a user message — prepend \"Hi\" if needed\n const prependedMessages: ProviderMessage[] = [{ role: 'user', content: 'Hi\\n' }, ...request.messages]\n const mergedMessages = mergeSequentialMessages(prependedMessages)\n\n return { systemPrompt, inputSchema, mergedMessages }\n}\n\n/**\n * Creates an AWS Bedrock provider instance.\n *\n * @param config - Bedrock provider configuration\n * @returns A Provider implementation using AWS Bedrock\n *\n * @example\n * ```typescript\n * const provider = createBedrockProvider({\n * models: ['us.anthropic.claude-sonnet-4-5-20250929-v1:0'],\n * region: 'us-east-1',\n * })\n * ```\n */\nexport function createBedrockProvider(config: BedrockProviderConfig): Provider {\n const client = new BedrockRuntimeClient(config.region ? { region: config.region } : {})\n const models = config.models\n const resilience: ResolvedResilienceConfig = resolveResilienceConfig(config.resilience)\n\n return {\n name: 'bedrock',\n\n async sendRequest(request: ProviderRequest): Promise<ProviderResponse> {\n const { systemPrompt, inputSchema, mergedMessages } = prepareRequest(request)\n\n return executeWithFallback(\n models,\n (modelId) =>\n sendWithModel(client, {\n modelId,\n systemPrompt,\n mergedMessages,\n inputSchema,\n }),\n resilience,\n )\n },\n\n async *sendRequestStream<TState extends BaseState = BaseState>(\n request: ProviderRequest,\n ): AsyncGenerator<StreamEvent<TState>> {\n const { systemPrompt, inputSchema, mergedMessages } = prepareRequest(request)\n\n const rawStream = await executeWithFallback(\n models,\n (modelId) =>\n sendStreamWithModel(client, {\n modelId,\n systemPrompt,\n mergedMessages,\n inputSchema,\n }),\n resilience,\n )\n\n yield* processBedrockStream<TState>(rawStream, 'bedrock', request.responseSchema)\n },\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../bedrock/messageMerger.ts","../../bedrock/streamProcessor.ts","../../utils/backoff.ts","../../utils/executeWithFallback.ts","../../bedrock/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { Message as BedrockMessage } from '@aws-sdk/client-bedrock-runtime'\nimport type { ProviderMessage } from '@genui-a3/core'\n\n/**\n * Converts provider-agnostic messages to Bedrock format, merging sequential same-role messages.\n * Bedrock requires alternating user/assistant roles — this merges consecutive same-role messages\n * into a single message with multiple content blocks.\n */\nexport function mergeSequentialMessages(messages: ProviderMessage[]): BedrockMessage[] {\n if (messages.length === 0) return []\n\n const result: BedrockMessage[] = []\n let currentMessage: BedrockMessage | null = null\n\n for (const message of messages) {\n if (!message.content) continue\n\n if (!currentMessage) {\n currentMessage = {\n role: message.role,\n content: [{ text: message.content }],\n }\n } else if (currentMessage.role === message.role && currentMessage.content) {\n currentMessage.content.push({ text: message.content })\n } else {\n result.push(currentMessage)\n currentMessage = {\n role: message.role,\n content: [{ text: message.content }],\n }\n }\n }\n\n if (currentMessage) {\n result.push(currentMessage)\n }\n\n return result\n}\n","import { ConverseStreamOutput } from '@aws-sdk/client-bedrock-runtime'\nimport { EventType } from '@ag-ui/client'\nimport { ZodType } from 'zod'\nimport type { AgentId, StreamEvent, BaseState } from '@genui-a3/core'\n\nexport async function* processBedrockStream<TState extends BaseState = BaseState>(\n rawStream: AsyncIterable<ConverseStreamOutput>,\n agentId: AgentId,\n schema: ZodType,\n): AsyncGenerator<StreamEvent<TState>> {\n let currentBlockType: 'text' | 'toolUse' | null = null\n let toolInputBuffer = ''\n\n for await (const event of rawStream) {\n // --- Content block start: determine block type ---\n if (event.contentBlockStart) {\n if (event.contentBlockStart.start?.toolUse) {\n currentBlockType = 'toolUse'\n toolInputBuffer = ''\n } else {\n currentBlockType = 'text'\n }\n continue\n }\n\n // --- Content block delta: text or tool input ---\n if (event.contentBlockDelta) {\n const delta = event.contentBlockDelta.delta\n if (!delta) continue\n\n // Infer block type from delta content if no contentBlockStart was received\n // (Bedrock may omit contentBlockStart for the first text block)\n if (delta.text && (currentBlockType === 'text' || currentBlockType === null)) {\n currentBlockType = 'text'\n yield { type: EventType.TEXT_MESSAGE_CONTENT, messageId: '', delta: delta.text, agentId } as StreamEvent<TState>\n } else if (delta.toolUse && (currentBlockType === 'toolUse' || currentBlockType === null)) {\n currentBlockType = 'toolUse'\n toolInputBuffer += delta.toolUse.input ?? ''\n }\n continue\n }\n\n // --- Content block stop: parse and validate tool call ---\n if (event.contentBlockStop) {\n if (currentBlockType === 'toolUse' && toolInputBuffer) {\n yield parseToolCall<TState>(toolInputBuffer, schema, agentId)\n toolInputBuffer = ''\n }\n currentBlockType = null\n continue\n }\n\n // --- Metadata: log usage ---\n if (event.metadata) {\n continue\n }\n\n // --- Error events: throw to surface to caller ---\n throwIfStreamError(event)\n }\n}\n\nfunction parseToolCall<TState extends BaseState>(\n toolInputBuffer: string,\n schema: ZodType,\n agentId: AgentId,\n): StreamEvent<TState> {\n try {\n const parsed = JSON.parse(toolInputBuffer) as Record<string, unknown>\n const validated = schema.parse(parsed)\n return {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: '',\n messageId: '',\n content: JSON.stringify(validated),\n agentId,\n } as StreamEvent<TState>\n } catch (err) {\n return {\n type: EventType.RUN_ERROR,\n message: `Tool call parse/validation failed: ${(err as Error).message}`,\n agentId,\n } as StreamEvent<TState>\n }\n}\n\nfunction throwIfStreamError(event: ConverseStreamOutput): void {\n if (event.internalServerException) {\n throw new Error(`Bedrock internal error: ${event.internalServerException.message}`)\n }\n if (event.modelStreamErrorException) {\n throw new Error(`Bedrock model stream error: ${event.modelStreamErrorException.message}`)\n }\n if (event.throttlingException) {\n throw new Error(`Bedrock throttling: ${event.throttlingException.message}`)\n }\n if (event.validationException) {\n throw new Error(`Bedrock validation error: ${event.validationException.message}`)\n }\n if (event.serviceUnavailableException) {\n throw new Error(`Bedrock service unavailable: ${event.serviceUnavailableException.message}`)\n }\n}\n","import type { BackoffConfig } from '@genui-a3/core'\n\n/**\n * Calculates the backoff delay for a given retry attempt.\n *\n * @param attempt - Zero-based attempt index (0 = first retry)\n * @param config - Backoff configuration with all fields required\n * @returns Delay in milliseconds\n */\nexport function calculateBackoff(attempt: number, config: Required<BackoffConfig>): number {\n let delay: number\n\n switch (config.strategy) {\n case 'exponential':\n delay = config.baseDelayMs * Math.pow(2, attempt)\n break\n case 'linear':\n delay = config.baseDelayMs * (attempt + 1)\n break\n case 'fixed':\n delay = config.baseDelayMs\n break\n }\n\n delay = Math.min(delay, config.maxDelayMs)\n\n if (config.jitter) {\n delay = Math.random() * delay\n }\n\n return delay\n}\n\n/**\n * Sleeps for the specified duration. Can be aborted via an AbortSignal.\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal to cancel the sleep early\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason as Error)\n return\n }\n\n const timer = setTimeout(resolve, ms)\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason as Error)\n },\n { once: true },\n )\n })\n}\n","import {\n A3ResilienceError,\n A3TimeoutError,\n DEFAULT_RESILIENCE_CONFIG,\n type ResilienceErrorEntry,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { calculateBackoff, sleep } from './backoff'\n\n/**\n * Builds an AbortSignal that fires when either the per-request timeout or total timeout expires.\n */\nfunction buildSignal(requestTimeoutMs?: number, totalAbort?: AbortSignal): AbortSignal | undefined {\n const signals: AbortSignal[] = []\n\n if (requestTimeoutMs !== undefined) {\n signals.push(AbortSignal.timeout(requestTimeoutMs))\n }\n\n if (totalAbort) {\n signals.push(totalAbort)\n }\n\n if (signals.length === 0) return undefined\n if (signals.length === 1) return signals[0]\n return AbortSignal.any(signals)\n}\n\ntype AttemptResult<T> = { ok: true; value: T } | { ok: false; error: Error }\n\nasync function attemptAction<T>(\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n model: string,\n signal: AbortSignal | undefined,\n attempt: number,\n errors: ResilienceErrorEntry[],\n): Promise<AttemptResult<T>> {\n try {\n const value = await action(model, signal)\n return { ok: true, value }\n } catch (error) {\n const errorObj = error as Error\n errors.push({ model, attempt, error: errorObj })\n return { ok: false, error: errorObj }\n }\n}\n\nfunction checkTotalTimeout(totalAbort: AbortController | undefined, timeoutMs: number | undefined, errors: ResilienceErrorEntry[]): void {\n if (totalAbort?.signal.aborted) {\n throw new A3TimeoutError(`Total timeout of ${timeoutMs}ms exceeded`, errors)\n }\n}\n\nasync function handleAttemptError(\n errorObj: Error,\n attempt: number,\n maxRetries: number,\n retryAll: boolean,\n resolved: ResolvedResilienceConfig,\n totalAbort: AbortController | undefined,\n): Promise<'retry' | 'next-model'> {\n const isLastAttempt = attempt === 1 + maxRetries\n const isRetryable = retryAll || resolved.isRetryableError(errorObj)\n\n if (isRetryable && !isLastAttempt) {\n const delay = calculateBackoff(attempt - 1, resolved.backoff)\n await sleep(delay, totalAbort?.signal).catch(() => {\n // Sleep was aborted by total timeout — will be caught at top of loop\n })\n return 'retry'\n }\n\n return 'next-model'\n}\n\n/**\n * Executes an action with model fallback, retry, backoff, and timeout support.\n *\n * For each model (in priority order):\n * 1. Attempts the action up to `1 + maxAttempts` times\n * 2. On transient errors, waits with backoff before retrying\n * 3. On non-retryable errors (or after exhausting retries), falls back to the next model\n *\n * Throws `A3ResilienceError` with full error history when all models are exhausted.\n * Throws `A3TimeoutError` when the total timeout is exceeded.\n *\n * @param models - Model identifiers in priority order\n * @param action - Async action to attempt with each model. Receives an optional AbortSignal.\n * @param config - Resolved resilience configuration (defaults applied if omitted)\n * @returns The result from the first successful attempt\n * @throws {A3ResilienceError} When all models and retries are exhausted\n * @throws {A3TimeoutError} When the total timeout is exceeded\n *\n * @example\n * ```typescript\n * const result = await executeWithFallback(\n * ['model-primary', 'model-fallback'],\n * (model, signal) => provider.call(model, params, { abortSignal: signal }),\n * resolvedConfig,\n * )\n * ```\n */\nexport async function executeWithFallback<T>(\n models: string[],\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n config?: ResolvedResilienceConfig,\n): Promise<T> {\n const resolved = config ?? DEFAULT_RESILIENCE_CONFIG\n const errors: ResilienceErrorEntry[] = []\n const maxRetries = resolved.retry === false ? 0 : resolved.retry.maxAttempts\n const retryAll = resolved.retry !== false && resolved.retry.retryOn === 'all'\n\n // Total timeout controller\n let totalAbort: AbortController | undefined\n let totalTimer: ReturnType<typeof setTimeout> | undefined\n\n if (resolved.timeout.totalTimeoutMs !== undefined) {\n totalAbort = new AbortController()\n totalTimer = setTimeout(\n () => totalAbort!.abort(new Error('Total timeout exceeded')),\n resolved.timeout.totalTimeoutMs,\n )\n }\n\n try {\n for (let modelIndex = 0; modelIndex < models.length; modelIndex++) {\n const model = models[modelIndex]\n\n for (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n const signal = buildSignal(resolved.timeout.requestTimeoutMs, totalAbort?.signal)\n // eslint-disable-next-line no-await-in-loop\n const result = await attemptAction(action, model, signal, attempt, errors)\n if (result.ok) return result.value\n\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n // eslint-disable-next-line no-await-in-loop\n const decision = await handleAttemptError(result.error, attempt, maxRetries, retryAll, resolved, totalAbort)\n if (decision === 'next-model') break\n }\n }\n\n // All models exhausted\n throw new A3ResilienceError(\n `All models failed after ${errors.length} total attempt(s): ${models.join(', ')}`,\n errors,\n )\n } finally {\n if (totalTimer !== undefined) {\n clearTimeout(totalTimer)\n }\n }\n}\n","import {\n BedrockRuntimeClient,\n ConverseCommand,\n ConverseStreamCommand,\n ConverseStreamOutput,\n ToolInputSchema,\n} from '@aws-sdk/client-bedrock-runtime'\nimport {\n resolveResilienceConfig,\n type Provider,\n type ProviderRequest,\n type ProviderResponse,\n type ProviderMessage,\n type BaseState,\n type StreamEvent,\n type ResilienceConfig,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { mergeSequentialMessages } from './messageMerger'\nimport { processBedrockStream } from './streamProcessor'\nimport { executeWithFallback } from '../utils/executeWithFallback'\n\nconst RESPONSE_FORMAT_INSTRUCTIONS = `\n\n# RESPONSE FORMAT — MANDATORY\n\n<<CRITICAL INSTRUCTION>>\nYou MUST ALWAYS output plain text FIRST, then call the structuredResponse tool SECOND. NEVER call the tool without writing text first. This is non-negotiable.\n<</CRITICAL INSTRUCTION>>\n\nYour response MUST have exactly two parts in this order:\n\nPART 1 — TEXT: Write your full conversational reply as plain text. This text is streamed to the user in real-time. Do not skip this.\n\nPART 2 — TOOL CALL: After the text, call the \\`structuredResponse\\` tool with the JSON payload. The \\`chatbotMessage\\` field MUST contain the same text you wrote in Part 1.\n\nIf you call the tool without writing text first, the response will be broken.`\n\n/**\n * Configuration for creating a Bedrock provider.\n */\nexport interface BedrockProviderConfig {\n /** AWS region for the Bedrock client */\n region?: string\n /**\n * Model identifiers in order of preference (first = primary, rest = fallbacks).\n * Uses Bedrock model ARNs, e.g. 'us.anthropic.claude-sonnet-4-5-20250929-v1:0'\n */\n models: string[]\n /** Resilience configuration (retry, backoff, timeout). Uses industry-standard defaults if omitted. */\n resilience?: ResilienceConfig\n}\n\ntype SendWithModelParams = {\n modelId: string\n systemPrompt: string\n mergedMessages: ReturnType<typeof mergeSequentialMessages>\n inputSchema: ToolInputSchema | undefined\n}\n\nfunction getCommandInput(params: SendWithModelParams, isStream: boolean) {\n return {\n modelId: params.modelId,\n system: [{ text: params.systemPrompt }],\n messages: params.mergedMessages,\n toolConfig: {\n tools: [\n {\n toolSpec: {\n name: 'structuredResponse',\n description: isStream\n ? 'Submit your structured response data. IMPORTANT: You MUST write your full text reply BEFORE calling this tool. Never call this tool as your first action.'\n : 'A tool to generate a structured response',\n inputSchema: params.inputSchema,\n },\n },\n ],\n toolChoice: isStream ? { auto: {} } : { any: {} },\n },\n }\n}\n\nasync function sendWithModel(client: BedrockRuntimeClient, params: SendWithModelParams): Promise<ProviderResponse> {\n const command = new ConverseCommand(getCommandInput(params, false))\n const response = await client.send(command)\n\n const contentBlocks = response.output?.message?.content ?? []\n const toolUseBlock = contentBlocks.find((block) => block.toolUse)\n const result = toolUseBlock?.toolUse?.input\n\n const isValidResponse =\n result &&\n typeof result === 'object' &&\n 'conversationPayload' in result &&\n 'chatbotMessage' in result &&\n typeof result.conversationPayload === 'object' &&\n typeof result.chatbotMessage === 'string'\n\n if (!isValidResponse) {\n throw new Error('Bedrock returned invalid tool response')\n }\n\n return {\n content: JSON.stringify(result),\n usage: response.usage\n ? {\n inputTokens: response.usage.inputTokens,\n outputTokens: response.usage.outputTokens,\n totalTokens: (response.usage.inputTokens ?? 0) + (response.usage.outputTokens ?? 0),\n }\n : undefined,\n }\n}\n\nasync function sendStreamWithModel(\n client: BedrockRuntimeClient,\n params: SendWithModelParams,\n): Promise<AsyncIterable<ConverseStreamOutput>> {\n const command = new ConverseStreamCommand(getCommandInput(params, true))\n const response = await client.send(command)\n\n if (!response.stream) {\n throw new Error('No stream returned from Bedrock')\n }\n\n return response.stream\n}\n\nfunction prepareRequest(request: ProviderRequest) {\n const systemPrompt = RESPONSE_FORMAT_INSTRUCTIONS + '\\n\\n' + request.systemPrompt\n const jsonSchema = request.responseSchema.toJSONSchema()\n const inputSchema = { json: jsonSchema } as ToolInputSchema\n\n // Bedrock requires messages to start with a user message — prepend \"Hi\" if needed\n const prependedMessages: ProviderMessage[] = [{ role: 'user', content: 'Hi\\n' }, ...request.messages]\n const mergedMessages = mergeSequentialMessages(prependedMessages)\n\n return { systemPrompt, inputSchema, mergedMessages }\n}\n\n/**\n * Creates an AWS Bedrock provider instance.\n *\n * @param config - Bedrock provider configuration\n * @returns A Provider implementation using AWS Bedrock\n *\n * @example\n * ```typescript\n * const provider = createBedrockProvider({\n * models: ['us.anthropic.claude-sonnet-4-5-20250929-v1:0'],\n * region: 'us-east-1',\n * })\n * ```\n */\nexport function createBedrockProvider(config: BedrockProviderConfig): Provider {\n const client = new BedrockRuntimeClient(config.region ? { region: config.region } : {})\n const models = config.models\n const resilience: ResolvedResilienceConfig = resolveResilienceConfig(config.resilience)\n\n return {\n name: 'bedrock',\n\n async sendRequest(request: ProviderRequest): Promise<ProviderResponse> {\n const { systemPrompt, inputSchema, mergedMessages } = prepareRequest(request)\n\n return executeWithFallback(\n models,\n (modelId) =>\n sendWithModel(client, {\n modelId,\n systemPrompt,\n mergedMessages,\n inputSchema,\n }),\n resilience,\n )\n },\n\n async *sendRequestStream<TState extends BaseState = BaseState>(\n request: ProviderRequest,\n ): AsyncGenerator<StreamEvent<TState>> {\n const { systemPrompt, inputSchema, mergedMessages } = prepareRequest(request)\n\n const rawStream = await executeWithFallback(\n models,\n (modelId) =>\n sendStreamWithModel(client, {\n modelId,\n systemPrompt,\n mergedMessages,\n inputSchema,\n }),\n resilience,\n )\n\n yield* processBedrockStream<TState>(rawStream, 'bedrock', request.responseSchema)\n },\n }\n}\n"]}
1
+ {"version":3,"sources":["../../bedrock/messageMerger.ts","../../bedrock/streamProcessor.ts","../../utils/backoff.ts","../../utils/executeWithFallback.ts","../../bedrock/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { Message as BedrockMessage } from '@aws-sdk/client-bedrock-runtime'\nimport type { ProviderMessage } from '@genui-a3/core'\n\n/**\n * Converts provider-agnostic messages to Bedrock format, merging sequential same-role messages.\n * Bedrock requires alternating user/assistant roles — this merges consecutive same-role messages\n * into a single message with multiple content blocks.\n */\nexport function mergeSequentialMessages(messages: ProviderMessage[]): BedrockMessage[] {\n if (messages.length === 0) return []\n\n const result: BedrockMessage[] = []\n let currentMessage: BedrockMessage | null = null\n\n for (const message of messages) {\n if (!message.content) continue\n\n if (!currentMessage) {\n currentMessage = {\n role: message.role,\n content: [{ text: message.content }],\n }\n } else if (currentMessage.role === message.role && currentMessage.content) {\n currentMessage.content.push({ text: message.content })\n } else {\n result.push(currentMessage)\n currentMessage = {\n role: message.role,\n content: [{ text: message.content }],\n }\n }\n }\n\n if (currentMessage) {\n result.push(currentMessage)\n }\n\n return result\n}\n","import { ConverseStreamOutput } from '@aws-sdk/client-bedrock-runtime'\nimport { EventType } from '@ag-ui/client'\nimport { ZodType } from 'zod'\nimport type { AgentId, StreamEvent, BaseState } from '@genui-a3/core'\n\nexport async function* processBedrockStream<TState extends BaseState = BaseState>(\n rawStream: AsyncIterable<ConverseStreamOutput>,\n agentId: AgentId,\n schema: ZodType,\n): AsyncGenerator<StreamEvent<TState>> {\n let currentBlockType: 'text' | 'toolUse' | null = null\n let toolInputBuffer = ''\n\n for await (const event of rawStream) {\n // --- Content block start: determine block type ---\n if (event.contentBlockStart) {\n if (event.contentBlockStart.start?.toolUse) {\n currentBlockType = 'toolUse'\n toolInputBuffer = ''\n } else {\n currentBlockType = 'text'\n }\n continue\n }\n\n // --- Content block delta: text or tool input ---\n if (event.contentBlockDelta) {\n const delta = event.contentBlockDelta.delta\n if (!delta) continue\n\n // Infer block type from delta content if no contentBlockStart was received\n // (Bedrock may omit contentBlockStart for the first text block)\n if (delta.text && (currentBlockType === 'text' || currentBlockType === null)) {\n currentBlockType = 'text'\n yield { type: EventType.TEXT_MESSAGE_CONTENT, messageId: '', delta: delta.text, agentId } as StreamEvent<TState>\n } else if (delta.toolUse && (currentBlockType === 'toolUse' || currentBlockType === null)) {\n currentBlockType = 'toolUse'\n toolInputBuffer += delta.toolUse.input ?? ''\n }\n continue\n }\n\n // --- Content block stop: parse and validate tool call ---\n if (event.contentBlockStop) {\n if (currentBlockType === 'toolUse' && toolInputBuffer) {\n yield parseToolCall<TState>(toolInputBuffer, schema, agentId)\n toolInputBuffer = ''\n }\n currentBlockType = null\n continue\n }\n\n // --- Metadata: log usage ---\n if (event.metadata) {\n continue\n }\n\n // --- Error events: throw to surface to caller ---\n throwIfStreamError(event)\n }\n}\n\nfunction parseToolCall<TState extends BaseState>(\n toolInputBuffer: string,\n schema: ZodType,\n agentId: AgentId,\n): StreamEvent<TState> {\n try {\n const parsed = JSON.parse(toolInputBuffer) as Record<string, unknown>\n const validated = schema.parse(parsed)\n return {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: '',\n messageId: '',\n content: JSON.stringify(validated),\n agentId,\n } as StreamEvent<TState>\n } catch (err) {\n return {\n type: EventType.RUN_ERROR,\n message: `Tool call parse/validation failed: ${(err as Error).message}`,\n agentId,\n } as StreamEvent<TState>\n }\n}\n\nfunction throwIfStreamError(event: ConverseStreamOutput): void {\n if (event.internalServerException) {\n throw new Error(`Bedrock internal error: ${event.internalServerException.message}`)\n }\n if (event.modelStreamErrorException) {\n throw new Error(`Bedrock model stream error: ${event.modelStreamErrorException.message}`)\n }\n if (event.throttlingException) {\n throw new Error(`Bedrock throttling: ${event.throttlingException.message}`)\n }\n if (event.validationException) {\n throw new Error(`Bedrock validation error: ${event.validationException.message}`)\n }\n if (event.serviceUnavailableException) {\n throw new Error(`Bedrock service unavailable: ${event.serviceUnavailableException.message}`)\n }\n}\n","import type { BackoffConfig } from '@genui-a3/core'\n\n/**\n * Calculates the backoff delay for a given retry attempt.\n *\n * @param attempt - Zero-based attempt index (0 = first retry)\n * @param config - Backoff configuration with all fields required\n * @returns Delay in milliseconds\n */\nexport function calculateBackoff(attempt: number, config: Required<BackoffConfig>): number {\n let delay: number\n\n switch (config.strategy) {\n case 'exponential':\n delay = config.baseDelayMs * Math.pow(2, attempt)\n break\n case 'linear':\n delay = config.baseDelayMs * (attempt + 1)\n break\n case 'fixed':\n delay = config.baseDelayMs\n break\n }\n\n delay = Math.min(delay, config.maxDelayMs)\n\n if (config.jitter) {\n delay = Math.random() * delay\n }\n\n return delay\n}\n\n/**\n * Sleeps for the specified duration. Can be aborted via an AbortSignal.\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal to cancel the sleep early\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason as Error)\n return\n }\n\n const timer = setTimeout(resolve, ms)\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason as Error)\n },\n { once: true },\n )\n })\n}\n","import {\n A3ResilienceError,\n A3TimeoutError,\n DEFAULT_RESILIENCE_CONFIG,\n type ResilienceErrorEntry,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { calculateBackoff, sleep } from './backoff'\n\n/**\n * Builds an AbortSignal that fires when either the per-request timeout or total timeout expires.\n */\nfunction buildSignal(requestTimeoutMs?: number, totalAbort?: AbortSignal): AbortSignal | undefined {\n const signals: AbortSignal[] = []\n\n if (requestTimeoutMs !== undefined) {\n signals.push(AbortSignal.timeout(requestTimeoutMs))\n }\n\n if (totalAbort) {\n signals.push(totalAbort)\n }\n\n if (signals.length === 0) return undefined\n if (signals.length === 1) return signals[0]\n return AbortSignal.any(signals)\n}\n\ntype AttemptResult<T> = { ok: true; value: T } | { ok: false; error: Error }\n\nasync function attemptAction<T>(\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n model: string,\n signal: AbortSignal | undefined,\n attempt: number,\n errors: ResilienceErrorEntry[],\n): Promise<AttemptResult<T>> {\n try {\n const value = await action(model, signal)\n return { ok: true, value }\n } catch (error) {\n const errorObj = error as Error\n errors.push({ model, attempt, error: errorObj })\n return { ok: false, error: errorObj }\n }\n}\n\nfunction checkTotalTimeout(totalAbort: AbortController | undefined, timeoutMs: number | undefined, errors: ResilienceErrorEntry[]): void {\n if (totalAbort?.signal.aborted) {\n throw new A3TimeoutError(`Total timeout of ${timeoutMs}ms exceeded`, errors)\n }\n}\n\nasync function handleAttemptError(\n errorObj: Error,\n attempt: number,\n maxRetries: number,\n retryAll: boolean,\n resolved: ResolvedResilienceConfig,\n totalAbort: AbortController | undefined,\n): Promise<'retry' | 'next-model'> {\n const isLastAttempt = attempt === 1 + maxRetries\n const isRetryable = retryAll || resolved.isRetryableError(errorObj)\n\n if (isRetryable && !isLastAttempt) {\n const delay = calculateBackoff(attempt - 1, resolved.backoff)\n await sleep(delay, totalAbort?.signal).catch(() => {\n // Sleep was aborted by total timeout — will be caught at top of loop\n })\n return 'retry'\n }\n\n return 'next-model'\n}\n\n/**\n * Executes an action with model fallback, retry, backoff, and timeout support.\n *\n * For each model (in priority order):\n * 1. Attempts the action up to `1 + maxAttempts` times\n * 2. On transient errors, waits with backoff before retrying\n * 3. On non-retryable errors (or after exhausting retries), falls back to the next model\n *\n * Throws `A3ResilienceError` with full error history when all models are exhausted.\n * Throws `A3TimeoutError` when the total timeout is exceeded.\n *\n * @param models - Model identifiers in priority order\n * @param action - Async action to attempt with each model. Receives an optional AbortSignal.\n * @param config - Resolved resilience configuration (defaults applied if omitted)\n * @returns The result from the first successful attempt\n * @throws {A3ResilienceError} When all models and retries are exhausted\n * @throws {A3TimeoutError} When the total timeout is exceeded\n *\n * @example\n * ```typescript\n * const result = await executeWithFallback(\n * ['model-primary', 'model-fallback'],\n * (model, signal) => provider.call(model, params, { abortSignal: signal }),\n * resolvedConfig,\n * )\n * ```\n */\nexport async function executeWithFallback<T>(\n models: string[],\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n config?: ResolvedResilienceConfig,\n): Promise<T> {\n const resolved = config ?? DEFAULT_RESILIENCE_CONFIG\n const errors: ResilienceErrorEntry[] = []\n const maxRetries = resolved.retry === false ? 0 : resolved.retry.maxAttempts\n const retryAll = resolved.retry !== false && resolved.retry.retryOn === 'all'\n\n // Total timeout controller\n let totalAbort: AbortController | undefined\n let totalTimer: ReturnType<typeof setTimeout> | undefined\n\n if (resolved.timeout.totalTimeoutMs !== undefined) {\n totalAbort = new AbortController()\n totalTimer = setTimeout(\n () => totalAbort!.abort(new Error('Total timeout exceeded')),\n resolved.timeout.totalTimeoutMs,\n )\n }\n\n try {\n for (let modelIndex = 0; modelIndex < models.length; modelIndex++) {\n const model = models[modelIndex]\n\n for (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n const signal = buildSignal(resolved.timeout.requestTimeoutMs, totalAbort?.signal)\n // eslint-disable-next-line no-await-in-loop\n const result = await attemptAction(action, model, signal, attempt, errors)\n if (result.ok) return result.value\n\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n // eslint-disable-next-line no-await-in-loop\n const decision = await handleAttemptError(result.error, attempt, maxRetries, retryAll, resolved, totalAbort)\n if (decision === 'next-model') break\n }\n }\n\n // All models exhausted\n throw new A3ResilienceError(\n `All models failed after ${errors.length} total attempt(s): ${models.join(', ')}`,\n errors,\n )\n } finally {\n if (totalTimer !== undefined) {\n clearTimeout(totalTimer)\n }\n }\n}\n","import {\n BedrockRuntimeClient,\n ConverseCommand,\n ConverseStreamCommand,\n ConverseStreamOutput,\n ToolInputSchema,\n} from '@aws-sdk/client-bedrock-runtime'\nimport {\n resolveResilienceConfig,\n type Provider,\n type ProviderRequest,\n type ProviderResponse,\n type ProviderMessage,\n type BaseState,\n type StreamEvent,\n type ResilienceConfig,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { mergeSequentialMessages } from './messageMerger'\nimport { processBedrockStream } from './streamProcessor'\nimport { executeWithFallback } from '@providers/utils/executeWithFallback'\n\nconst RESPONSE_FORMAT_INSTRUCTIONS = `\n\n# RESPONSE FORMAT — MANDATORY\n\n<<CRITICAL INSTRUCTION>>\nYou MUST ALWAYS output plain text FIRST, then call the structuredResponse tool SECOND. NEVER call the tool without writing text first. This is non-negotiable.\n<</CRITICAL INSTRUCTION>>\n\nYour response MUST have exactly two parts in this order:\n\nPART 1 — TEXT: Write your full conversational reply as plain text. This text is streamed to the user in real-time. Do not skip this.\n\nPART 2 — TOOL CALL: After the text, call the \\`structuredResponse\\` tool with the JSON payload. The \\`chatbotMessage\\` field MUST contain the same text you wrote in Part 1.\n\nIf you call the tool without writing text first, the response will be broken.`\n\n/**\n * Configuration for creating a Bedrock provider.\n */\nexport interface BedrockProviderConfig {\n /** AWS region for the Bedrock client */\n region?: string\n /**\n * Model identifiers in order of preference (first = primary, rest = fallbacks).\n * Uses Bedrock model ARNs, e.g. 'us.anthropic.claude-sonnet-4-5-20250929-v1:0'\n */\n models: string[]\n /** Resilience configuration (retry, backoff, timeout). Uses industry-standard defaults if omitted. */\n resilience?: ResilienceConfig\n}\n\ntype SendWithModelParams = {\n modelId: string\n systemPrompt: string\n mergedMessages: ReturnType<typeof mergeSequentialMessages>\n inputSchema: ToolInputSchema | undefined\n}\n\nfunction getCommandInput(params: SendWithModelParams, isStream: boolean) {\n return {\n modelId: params.modelId,\n system: [{ text: params.systemPrompt }],\n messages: params.mergedMessages,\n toolConfig: {\n tools: [\n {\n toolSpec: {\n name: 'structuredResponse',\n description: isStream\n ? 'Submit your structured response data. IMPORTANT: You MUST write your full text reply BEFORE calling this tool. Never call this tool as your first action.'\n : 'A tool to generate a structured response',\n inputSchema: params.inputSchema,\n },\n },\n ],\n toolChoice: isStream ? { auto: {} } : { any: {} },\n },\n }\n}\n\nasync function sendWithModel(client: BedrockRuntimeClient, params: SendWithModelParams): Promise<ProviderResponse> {\n const command = new ConverseCommand(getCommandInput(params, false))\n const response = await client.send(command)\n\n const contentBlocks = response.output?.message?.content ?? []\n const toolUseBlock = contentBlocks.find((block) => block.toolUse)\n const result = toolUseBlock?.toolUse?.input\n\n const isValidResponse =\n result &&\n typeof result === 'object' &&\n 'conversationPayload' in result &&\n 'chatbotMessage' in result &&\n typeof result.conversationPayload === 'object' &&\n typeof result.chatbotMessage === 'string'\n\n if (!isValidResponse) {\n throw new Error('Bedrock returned invalid tool response')\n }\n\n return {\n content: JSON.stringify(result),\n usage: response.usage\n ? {\n inputTokens: response.usage.inputTokens,\n outputTokens: response.usage.outputTokens,\n totalTokens: (response.usage.inputTokens ?? 0) + (response.usage.outputTokens ?? 0),\n }\n : undefined,\n }\n}\n\nasync function sendStreamWithModel(\n client: BedrockRuntimeClient,\n params: SendWithModelParams,\n): Promise<AsyncIterable<ConverseStreamOutput>> {\n const command = new ConverseStreamCommand(getCommandInput(params, true))\n const response = await client.send(command)\n\n if (!response.stream) {\n throw new Error('No stream returned from Bedrock')\n }\n\n return response.stream\n}\n\nfunction prepareRequest(request: ProviderRequest) {\n const systemPrompt = RESPONSE_FORMAT_INSTRUCTIONS + '\\n\\n' + request.systemPrompt\n const jsonSchema = request.responseSchema.toJSONSchema()\n const inputSchema = { json: jsonSchema } as ToolInputSchema\n\n // Bedrock requires messages to start with a user message — prepend \"Hi\" if needed\n const prependedMessages: ProviderMessage[] = [{ role: 'user', content: 'Hi\\n' }, ...request.messages]\n const mergedMessages = mergeSequentialMessages(prependedMessages)\n\n return { systemPrompt, inputSchema, mergedMessages }\n}\n\n/**\n * Creates an AWS Bedrock provider instance.\n *\n * @param config - Bedrock provider configuration\n * @returns A Provider implementation using AWS Bedrock\n *\n * @example\n * ```typescript\n * const provider = createBedrockProvider({\n * models: ['us.anthropic.claude-sonnet-4-5-20250929-v1:0'],\n * region: 'us-east-1',\n * })\n * ```\n */\nexport function createBedrockProvider(config: BedrockProviderConfig): Provider {\n const client = new BedrockRuntimeClient(config.region ? { region: config.region } : {})\n const models = config.models\n const resilience: ResolvedResilienceConfig = resolveResilienceConfig(config.resilience)\n\n return {\n name: 'bedrock',\n\n async sendRequest(request: ProviderRequest): Promise<ProviderResponse> {\n const { systemPrompt, inputSchema, mergedMessages } = prepareRequest(request)\n\n return executeWithFallback(\n models,\n (modelId) =>\n sendWithModel(client, {\n modelId,\n systemPrompt,\n mergedMessages,\n inputSchema,\n }),\n resilience,\n )\n },\n\n async *sendRequestStream<TState extends BaseState = BaseState>(\n request: ProviderRequest,\n ): AsyncGenerator<StreamEvent<TState>> {\n const { systemPrompt, inputSchema, mergedMessages } = prepareRequest(request)\n\n const rawStream = await executeWithFallback(\n models,\n (modelId) =>\n sendStreamWithModel(client, {\n modelId,\n systemPrompt,\n mergedMessages,\n inputSchema,\n }),\n resilience,\n )\n\n yield* processBedrockStream<TState>(rawStream, 'bedrock', request.responseSchema)\n },\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../openai/streamProcessor.ts","../../utils/backoff.ts","../../utils/executeWithFallback.ts","../../openai/index.ts"],"names":["EventType","A3TimeoutError","DEFAULT_RESILIENCE_CONFIG","A3ResilienceError","jsonSchema","generateText","Output","streamText","createOpenAI","resolveResilienceConfig"],"mappings":"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","file":"index.cjs","sourcesContent":["import { EventType } from '@ag-ui/client'\nimport { ZodType } from 'zod'\nimport type { AgentId, StreamEvent, BaseState } from '@genui-a3/core'\nimport type { StreamTextResult, ToolSet } from 'ai'\n\n/**\n * Processes an OpenAI streaming response (via Vercel AI SDK) into AG-UI events.\n *\n * Uses `partialOutputStream` from `streamText` + `Output.object()` to receive\n * progressively-built partial objects. Tracks `chatbotMessage` growth to yield\n * TEXT_MESSAGE_CONTENT deltas. After the stream completes, validates the final\n * object and yields TOOL_CALL_RESULT.\n *\n * @param streamResult - The streamText result containing partialOutputStream and output promise\n * @param reader - Pre-started async iterator for the partial object stream\n * @param first - The first iteration result (already consumed to trigger the API call)\n * @param agentId - Agent identifier for event tagging\n * @param schema - Zod schema for final response validation\n * @returns Async generator of AG-UI stream events\n */\nexport async function* processOpenAIStream<TState extends BaseState = BaseState>(\n streamResult: StreamTextResult<ToolSet, never>,\n reader: AsyncIterator<unknown>,\n first: IteratorResult<unknown>,\n agentId: AgentId,\n schema: ZodType,\n): AsyncGenerator<StreamEvent<TState>> {\n let prevMessageLength = 0\n\n try {\n // Process the first partial (already consumed to trigger the API call)\n if (!first.done) {\n const partial = first.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n }\n\n // Process remaining partials\n let next = await reader.next()\n while (!next.done) {\n const partial = next.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n // eslint-disable-next-line no-await-in-loop\n next = await reader.next()\n }\n\n // Stream complete — await and validate the final object\n const finalObject = await streamResult.output\n\n if (finalObject === null) {\n yield {\n type: EventType.RUN_ERROR,\n message: 'OpenAI stream completed with null output',\n agentId,\n } as StreamEvent<TState>\n return\n }\n\n const validated = schema.parse(finalObject)\n yield {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: '',\n messageId: '',\n content: JSON.stringify(validated),\n agentId,\n } as StreamEvent<TState>\n } catch (err) {\n yield {\n type: EventType.RUN_ERROR,\n message: `OpenAI stream error: ${(err as Error).message}`,\n agentId,\n } as StreamEvent<TState>\n }\n}\n\n/**\n * Extracts the new portion of chatbotMessage from a partial object.\n */\nfunction extractDelta(partial: Record<string, unknown>, prevLength: number): string | null {\n const chatbotMessage = partial.chatbotMessage\n if (typeof chatbotMessage !== 'string' || chatbotMessage.length <= prevLength) {\n return null\n }\n return chatbotMessage.slice(prevLength)\n}\n","import type { BackoffConfig } from '@genui-a3/core'\n\n/**\n * Calculates the backoff delay for a given retry attempt.\n *\n * @param attempt - Zero-based attempt index (0 = first retry)\n * @param config - Backoff configuration with all fields required\n * @returns Delay in milliseconds\n */\nexport function calculateBackoff(attempt: number, config: Required<BackoffConfig>): number {\n let delay: number\n\n switch (config.strategy) {\n case 'exponential':\n delay = config.baseDelayMs * Math.pow(2, attempt)\n break\n case 'linear':\n delay = config.baseDelayMs * (attempt + 1)\n break\n case 'fixed':\n delay = config.baseDelayMs\n break\n }\n\n delay = Math.min(delay, config.maxDelayMs)\n\n if (config.jitter) {\n delay = Math.random() * delay\n }\n\n return delay\n}\n\n/**\n * Sleeps for the specified duration. Can be aborted via an AbortSignal.\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal to cancel the sleep early\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason as Error)\n return\n }\n\n const timer = setTimeout(resolve, ms)\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason as Error)\n },\n { once: true },\n )\n })\n}\n","import {\n A3ResilienceError,\n A3TimeoutError,\n DEFAULT_RESILIENCE_CONFIG,\n type ResilienceErrorEntry,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { calculateBackoff, sleep } from './backoff'\n\n/**\n * Builds an AbortSignal that fires when either the per-request timeout or total timeout expires.\n */\nfunction buildSignal(requestTimeoutMs?: number, totalAbort?: AbortSignal): AbortSignal | undefined {\n const signals: AbortSignal[] = []\n\n if (requestTimeoutMs !== undefined) {\n signals.push(AbortSignal.timeout(requestTimeoutMs))\n }\n\n if (totalAbort) {\n signals.push(totalAbort)\n }\n\n if (signals.length === 0) return undefined\n if (signals.length === 1) return signals[0]\n return AbortSignal.any(signals)\n}\n\ntype AttemptResult<T> = { ok: true; value: T } | { ok: false; error: Error }\n\nasync function attemptAction<T>(\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n model: string,\n signal: AbortSignal | undefined,\n attempt: number,\n errors: ResilienceErrorEntry[],\n): Promise<AttemptResult<T>> {\n try {\n const value = await action(model, signal)\n return { ok: true, value }\n } catch (error) {\n const errorObj = error as Error\n errors.push({ model, attempt, error: errorObj })\n return { ok: false, error: errorObj }\n }\n}\n\nfunction checkTotalTimeout(totalAbort: AbortController | undefined, timeoutMs: number | undefined, errors: ResilienceErrorEntry[]): void {\n if (totalAbort?.signal.aborted) {\n throw new A3TimeoutError(`Total timeout of ${timeoutMs}ms exceeded`, errors)\n }\n}\n\nasync function handleAttemptError(\n errorObj: Error,\n attempt: number,\n maxRetries: number,\n retryAll: boolean,\n resolved: ResolvedResilienceConfig,\n totalAbort: AbortController | undefined,\n): Promise<'retry' | 'next-model'> {\n const isLastAttempt = attempt === 1 + maxRetries\n const isRetryable = retryAll || resolved.isRetryableError(errorObj)\n\n if (isRetryable && !isLastAttempt) {\n const delay = calculateBackoff(attempt - 1, resolved.backoff)\n await sleep(delay, totalAbort?.signal).catch(() => {\n // Sleep was aborted by total timeout — will be caught at top of loop\n })\n return 'retry'\n }\n\n return 'next-model'\n}\n\n/**\n * Executes an action with model fallback, retry, backoff, and timeout support.\n *\n * For each model (in priority order):\n * 1. Attempts the action up to `1 + maxAttempts` times\n * 2. On transient errors, waits with backoff before retrying\n * 3. On non-retryable errors (or after exhausting retries), falls back to the next model\n *\n * Throws `A3ResilienceError` with full error history when all models are exhausted.\n * Throws `A3TimeoutError` when the total timeout is exceeded.\n *\n * @param models - Model identifiers in priority order\n * @param action - Async action to attempt with each model. Receives an optional AbortSignal.\n * @param config - Resolved resilience configuration (defaults applied if omitted)\n * @returns The result from the first successful attempt\n * @throws {A3ResilienceError} When all models and retries are exhausted\n * @throws {A3TimeoutError} When the total timeout is exceeded\n *\n * @example\n * ```typescript\n * const result = await executeWithFallback(\n * ['model-primary', 'model-fallback'],\n * (model, signal) => provider.call(model, params, { abortSignal: signal }),\n * resolvedConfig,\n * )\n * ```\n */\nexport async function executeWithFallback<T>(\n models: string[],\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n config?: ResolvedResilienceConfig,\n): Promise<T> {\n const resolved = config ?? DEFAULT_RESILIENCE_CONFIG\n const errors: ResilienceErrorEntry[] = []\n const maxRetries = resolved.retry === false ? 0 : resolved.retry.maxAttempts\n const retryAll = resolved.retry !== false && resolved.retry.retryOn === 'all'\n\n // Total timeout controller\n let totalAbort: AbortController | undefined\n let totalTimer: ReturnType<typeof setTimeout> | undefined\n\n if (resolved.timeout.totalTimeoutMs !== undefined) {\n totalAbort = new AbortController()\n totalTimer = setTimeout(\n () => totalAbort!.abort(new Error('Total timeout exceeded')),\n resolved.timeout.totalTimeoutMs,\n )\n }\n\n try {\n for (let modelIndex = 0; modelIndex < models.length; modelIndex++) {\n const model = models[modelIndex]\n\n for (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n const signal = buildSignal(resolved.timeout.requestTimeoutMs, totalAbort?.signal)\n // eslint-disable-next-line no-await-in-loop\n const result = await attemptAction(action, model, signal, attempt, errors)\n if (result.ok) return result.value\n\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n // eslint-disable-next-line no-await-in-loop\n const decision = await handleAttemptError(result.error, attempt, maxRetries, retryAll, resolved, totalAbort)\n if (decision === 'next-model') break\n }\n }\n\n // All models exhausted\n throw new A3ResilienceError(\n `All models failed after ${errors.length} total attempt(s): ${models.join(', ')}`,\n errors,\n )\n } finally {\n if (totalTimer !== undefined) {\n clearTimeout(totalTimer)\n }\n }\n}\n","import { createOpenAI } from '@ai-sdk/openai'\nimport { generateText, streamText, Output, ModelMessage, jsonSchema } from 'ai'\nimport {\n resolveResilienceConfig,\n type Provider,\n type ProviderRequest,\n type ProviderResponse,\n type ProviderMessage,\n type BaseState,\n type StreamEvent,\n type ResilienceConfig,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { processOpenAIStream } from './streamProcessor'\nimport { executeWithFallback } from '../utils/executeWithFallback'\n\n/**\n * Configuration for creating an OpenAI provider.\n */\nexport interface OpenAIProviderConfig {\n /** OpenAI API key. Defaults to OPENAI_API_KEY env var (OpenAI SDK default). */\n apiKey?: string\n /**\n * Model identifiers in order of preference (first = primary, rest = fallbacks).\n * e.g. ['gpt-4o', 'gpt-4o-mini']\n */\n models: string[]\n /** Optional base URL for Azure OpenAI or compatible endpoints */\n baseURL?: string\n /** Optional OpenAI organization ID */\n organization?: string\n /** Resilience configuration (retry, backoff, timeout). Uses industry-standard defaults if omitted. */\n resilience?: ResilienceConfig\n}\n\ntype JsonSchema = Record<string, unknown>\n\n/**\n * Enforces strict JSON schema constraints required by OpenAI's structured output API.\n * OpenAI requires all object properties — including optional ones — to be in the `required` array.\n * This function recursively adds `required` and `additionalProperties: false` to all objects.\n *\n * @param schema - JSON schema to enforce\n * @returns Enforced JSON schema\n */\nfunction enforceStrictSchema(schema: JsonSchema): JsonSchema {\n const result = { ...schema }\n if (result.type === 'object' && result.properties) {\n result.additionalProperties = false\n result.required = Object.keys(result.properties as Record<string, unknown>)\n const props = result.properties as Record<string, JsonSchema>\n const strictProps: Record<string, JsonSchema> = {}\n for (const [key, value] of Object.entries(props)) {\n strictProps[key] = enforceStrictSchema(value)\n }\n result.properties = strictProps\n }\n if (result.items && typeof result.items === 'object') {\n result.items = enforceStrictSchema(result.items as JsonSchema)\n }\n for (const keyword of ['anyOf', 'oneOf', 'allOf'] as const) {\n if (Array.isArray(result[keyword])) {\n result[keyword] = (result[keyword] as JsonSchema[]).map((s) => enforceStrictSchema(s))\n }\n }\n return result\n}\n\n/**\n * Converts a Zod schema to an OpenAI-compatible strict JSON schema wrapped for the Vercel AI SDK.\n *\n * @param zodSchema - Zod schema to convert\n * @returns JSON schema wrapped for Vercel AI SDK\n */\nfunction toOpenAISchema(zodSchema: ProviderRequest['responseSchema']) {\n const strict = enforceStrictSchema(zodSchema.toJSONSchema() as JsonSchema)\n return jsonSchema(strict as never, {\n validate: (value: unknown) => {\n const result = zodSchema.safeParse(value)\n return result.success\n ? { success: true as const, value: result.data }\n : { success: false as const, error: result.error }\n },\n })\n}\n\nfunction toAIMessages(messages: ProviderMessage[]): ModelMessage[] {\n return messages.map((msg) => ({\n role: msg.role,\n content: msg.content,\n }))\n}\n\nasync function sendWithModel(\n openaiProvider: ReturnType<typeof createOpenAI>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n): Promise<ProviderResponse> {\n const result = await generateText({\n model: openaiProvider(model),\n system,\n messages,\n output: Output.object({ schema: toOpenAISchema(schema) }),\n })\n\n return {\n content: JSON.stringify(result.output),\n usage: {\n inputTokens: result.usage.inputTokens ?? 0,\n outputTokens: result.usage.outputTokens ?? 0,\n totalTokens: (result.usage.inputTokens ?? 0) + (result.usage.outputTokens ?? 0),\n },\n }\n}\n\nasync function sendStreamWithModel(\n openaiProvider: ReturnType<typeof createOpenAI>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n) {\n const result = streamText({\n model: openaiProvider(model),\n system,\n messages,\n output: Output.object({ schema: toOpenAISchema(schema) }),\n })\n\n // Force the API call to start so executeWithFallback can catch connection errors\n const partialStream = result.partialOutputStream\n const reader = partialStream[Symbol.asyncIterator]()\n const first = await reader.next()\n\n return { result, reader, first }\n}\n\n/**\n * Creates an OpenAI provider instance.\n *\n * Uses the Vercel AI SDK (`ai` + `@ai-sdk/openai`) for structured output via\n * `generateText` + `Output.object()` (blocking) and `streamText` + `Output.object()`\n * (streaming). The AI SDK handles Zod-to-JSON-schema conversion, partial JSON\n * parsing, and validation internally.\n *\n * @param config - OpenAI provider configuration\n * @returns A Provider implementation using OpenAI\n *\n * @example\n * ```typescript\n * const provider = createOpenAIProvider({\n * models: ['gpt-4o', 'gpt-4o-mini'],\n * })\n * ```\n */\nexport function createOpenAIProvider(config: OpenAIProviderConfig): Provider {\n const openaiProvider = createOpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseURL,\n organization: config.organization,\n })\n const models = config.models\n const resilience: ResolvedResilienceConfig = resolveResilienceConfig(config.resilience)\n\n return {\n name: 'openai',\n\n async sendRequest(request: ProviderRequest): Promise<ProviderResponse> {\n const messages = toAIMessages(request.messages)\n\n return executeWithFallback(\n models,\n (model) => sendWithModel(openaiProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n },\n\n async *sendRequestStream<TState extends BaseState = BaseState>(\n request: ProviderRequest,\n ): AsyncGenerator<StreamEvent<TState>> {\n const messages = toAIMessages(request.messages)\n\n const { result, reader, first } = await executeWithFallback(\n models,\n (model) => sendStreamWithModel(openaiProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n\n yield* processOpenAIStream<TState>(result, reader, first, 'openai', request.responseSchema)\n },\n }\n}\n"]}
1
+ {"version":3,"sources":["../../openai/streamProcessor.ts","../../utils/backoff.ts","../../utils/executeWithFallback.ts","../../openai/index.ts"],"names":["EventType","A3TimeoutError","DEFAULT_RESILIENCE_CONFIG","A3ResilienceError","jsonSchema","generateText","Output","streamText","createOpenAI","resolveResilienceConfig"],"mappings":"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","file":"index.cjs","sourcesContent":["import { EventType } from '@ag-ui/client'\nimport { ZodType } from 'zod'\nimport type { AgentId, StreamEvent, BaseState } from '@genui-a3/core'\nimport type { StreamTextResult, ToolSet } from 'ai'\n\n/**\n * Processes an OpenAI streaming response (via Vercel AI SDK) into AG-UI events.\n *\n * Uses `partialOutputStream` from `streamText` + `Output.object()` to receive\n * progressively-built partial objects. Tracks `chatbotMessage` growth to yield\n * TEXT_MESSAGE_CONTENT deltas. After the stream completes, validates the final\n * object and yields TOOL_CALL_RESULT.\n *\n * @param streamResult - The streamText result containing partialOutputStream and output promise\n * @param reader - Pre-started async iterator for the partial object stream\n * @param first - The first iteration result (already consumed to trigger the API call)\n * @param agentId - Agent identifier for event tagging\n * @param schema - Zod schema for final response validation\n * @returns Async generator of AG-UI stream events\n */\nexport async function* processOpenAIStream<TState extends BaseState = BaseState>(\n streamResult: StreamTextResult<ToolSet, never>,\n reader: AsyncIterator<unknown>,\n first: IteratorResult<unknown>,\n agentId: AgentId,\n schema: ZodType,\n): AsyncGenerator<StreamEvent<TState>> {\n let prevMessageLength = 0\n\n try {\n // Process the first partial (already consumed to trigger the API call)\n if (!first.done) {\n const partial = first.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n }\n\n // Process remaining partials\n let next = await reader.next()\n while (!next.done) {\n const partial = next.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n // eslint-disable-next-line no-await-in-loop\n next = await reader.next()\n }\n\n // Stream complete — await and validate the final object\n const finalObject = await streamResult.output\n\n if (finalObject === null) {\n yield {\n type: EventType.RUN_ERROR,\n message: 'OpenAI stream completed with null output',\n agentId,\n } as StreamEvent<TState>\n return\n }\n\n const validated = schema.parse(finalObject)\n yield {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: '',\n messageId: '',\n content: JSON.stringify(validated),\n agentId,\n } as StreamEvent<TState>\n } catch (err) {\n yield {\n type: EventType.RUN_ERROR,\n message: `OpenAI stream error: ${(err as Error).message}`,\n agentId,\n } as StreamEvent<TState>\n }\n}\n\n/**\n * Extracts the new portion of chatbotMessage from a partial object.\n */\nfunction extractDelta(partial: Record<string, unknown>, prevLength: number): string | null {\n const chatbotMessage = partial.chatbotMessage\n if (typeof chatbotMessage !== 'string' || chatbotMessage.length <= prevLength) {\n return null\n }\n return chatbotMessage.slice(prevLength)\n}\n","import type { BackoffConfig } from '@genui-a3/core'\n\n/**\n * Calculates the backoff delay for a given retry attempt.\n *\n * @param attempt - Zero-based attempt index (0 = first retry)\n * @param config - Backoff configuration with all fields required\n * @returns Delay in milliseconds\n */\nexport function calculateBackoff(attempt: number, config: Required<BackoffConfig>): number {\n let delay: number\n\n switch (config.strategy) {\n case 'exponential':\n delay = config.baseDelayMs * Math.pow(2, attempt)\n break\n case 'linear':\n delay = config.baseDelayMs * (attempt + 1)\n break\n case 'fixed':\n delay = config.baseDelayMs\n break\n }\n\n delay = Math.min(delay, config.maxDelayMs)\n\n if (config.jitter) {\n delay = Math.random() * delay\n }\n\n return delay\n}\n\n/**\n * Sleeps for the specified duration. Can be aborted via an AbortSignal.\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal to cancel the sleep early\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason as Error)\n return\n }\n\n const timer = setTimeout(resolve, ms)\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason as Error)\n },\n { once: true },\n )\n })\n}\n","import {\n A3ResilienceError,\n A3TimeoutError,\n DEFAULT_RESILIENCE_CONFIG,\n type ResilienceErrorEntry,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { calculateBackoff, sleep } from './backoff'\n\n/**\n * Builds an AbortSignal that fires when either the per-request timeout or total timeout expires.\n */\nfunction buildSignal(requestTimeoutMs?: number, totalAbort?: AbortSignal): AbortSignal | undefined {\n const signals: AbortSignal[] = []\n\n if (requestTimeoutMs !== undefined) {\n signals.push(AbortSignal.timeout(requestTimeoutMs))\n }\n\n if (totalAbort) {\n signals.push(totalAbort)\n }\n\n if (signals.length === 0) return undefined\n if (signals.length === 1) return signals[0]\n return AbortSignal.any(signals)\n}\n\ntype AttemptResult<T> = { ok: true; value: T } | { ok: false; error: Error }\n\nasync function attemptAction<T>(\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n model: string,\n signal: AbortSignal | undefined,\n attempt: number,\n errors: ResilienceErrorEntry[],\n): Promise<AttemptResult<T>> {\n try {\n const value = await action(model, signal)\n return { ok: true, value }\n } catch (error) {\n const errorObj = error as Error\n errors.push({ model, attempt, error: errorObj })\n return { ok: false, error: errorObj }\n }\n}\n\nfunction checkTotalTimeout(totalAbort: AbortController | undefined, timeoutMs: number | undefined, errors: ResilienceErrorEntry[]): void {\n if (totalAbort?.signal.aborted) {\n throw new A3TimeoutError(`Total timeout of ${timeoutMs}ms exceeded`, errors)\n }\n}\n\nasync function handleAttemptError(\n errorObj: Error,\n attempt: number,\n maxRetries: number,\n retryAll: boolean,\n resolved: ResolvedResilienceConfig,\n totalAbort: AbortController | undefined,\n): Promise<'retry' | 'next-model'> {\n const isLastAttempt = attempt === 1 + maxRetries\n const isRetryable = retryAll || resolved.isRetryableError(errorObj)\n\n if (isRetryable && !isLastAttempt) {\n const delay = calculateBackoff(attempt - 1, resolved.backoff)\n await sleep(delay, totalAbort?.signal).catch(() => {\n // Sleep was aborted by total timeout — will be caught at top of loop\n })\n return 'retry'\n }\n\n return 'next-model'\n}\n\n/**\n * Executes an action with model fallback, retry, backoff, and timeout support.\n *\n * For each model (in priority order):\n * 1. Attempts the action up to `1 + maxAttempts` times\n * 2. On transient errors, waits with backoff before retrying\n * 3. On non-retryable errors (or after exhausting retries), falls back to the next model\n *\n * Throws `A3ResilienceError` with full error history when all models are exhausted.\n * Throws `A3TimeoutError` when the total timeout is exceeded.\n *\n * @param models - Model identifiers in priority order\n * @param action - Async action to attempt with each model. Receives an optional AbortSignal.\n * @param config - Resolved resilience configuration (defaults applied if omitted)\n * @returns The result from the first successful attempt\n * @throws {A3ResilienceError} When all models and retries are exhausted\n * @throws {A3TimeoutError} When the total timeout is exceeded\n *\n * @example\n * ```typescript\n * const result = await executeWithFallback(\n * ['model-primary', 'model-fallback'],\n * (model, signal) => provider.call(model, params, { abortSignal: signal }),\n * resolvedConfig,\n * )\n * ```\n */\nexport async function executeWithFallback<T>(\n models: string[],\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n config?: ResolvedResilienceConfig,\n): Promise<T> {\n const resolved = config ?? DEFAULT_RESILIENCE_CONFIG\n const errors: ResilienceErrorEntry[] = []\n const maxRetries = resolved.retry === false ? 0 : resolved.retry.maxAttempts\n const retryAll = resolved.retry !== false && resolved.retry.retryOn === 'all'\n\n // Total timeout controller\n let totalAbort: AbortController | undefined\n let totalTimer: ReturnType<typeof setTimeout> | undefined\n\n if (resolved.timeout.totalTimeoutMs !== undefined) {\n totalAbort = new AbortController()\n totalTimer = setTimeout(\n () => totalAbort!.abort(new Error('Total timeout exceeded')),\n resolved.timeout.totalTimeoutMs,\n )\n }\n\n try {\n for (let modelIndex = 0; modelIndex < models.length; modelIndex++) {\n const model = models[modelIndex]\n\n for (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n const signal = buildSignal(resolved.timeout.requestTimeoutMs, totalAbort?.signal)\n // eslint-disable-next-line no-await-in-loop\n const result = await attemptAction(action, model, signal, attempt, errors)\n if (result.ok) return result.value\n\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n // eslint-disable-next-line no-await-in-loop\n const decision = await handleAttemptError(result.error, attempt, maxRetries, retryAll, resolved, totalAbort)\n if (decision === 'next-model') break\n }\n }\n\n // All models exhausted\n throw new A3ResilienceError(\n `All models failed after ${errors.length} total attempt(s): ${models.join(', ')}`,\n errors,\n )\n } finally {\n if (totalTimer !== undefined) {\n clearTimeout(totalTimer)\n }\n }\n}\n","import { createOpenAI } from '@ai-sdk/openai'\nimport { generateText, streamText, Output, ModelMessage, jsonSchema } from 'ai'\nimport {\n resolveResilienceConfig,\n type Provider,\n type ProviderRequest,\n type ProviderResponse,\n type ProviderMessage,\n type BaseState,\n type StreamEvent,\n type ResilienceConfig,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { processOpenAIStream } from './streamProcessor'\nimport { executeWithFallback } from '@providers/utils/executeWithFallback'\n\n/**\n * Configuration for creating an OpenAI provider.\n */\nexport interface OpenAIProviderConfig {\n /** OpenAI API key. Defaults to OPENAI_API_KEY env var (OpenAI SDK default). */\n apiKey?: string\n /**\n * Model identifiers in order of preference (first = primary, rest = fallbacks).\n * e.g. ['gpt-4o', 'gpt-4o-mini']\n */\n models: string[]\n /** Optional base URL for Azure OpenAI or compatible endpoints */\n baseURL?: string\n /** Optional OpenAI organization ID */\n organization?: string\n /** Resilience configuration (retry, backoff, timeout). Uses industry-standard defaults if omitted. */\n resilience?: ResilienceConfig\n}\n\ntype JsonSchema = Record<string, unknown>\n\n/**\n * Enforces strict JSON schema constraints required by OpenAI's structured output API.\n * OpenAI requires all object properties — including optional ones — to be in the `required` array.\n * This function recursively adds `required` and `additionalProperties: false` to all objects.\n *\n * @param schema - JSON schema to enforce\n * @returns Enforced JSON schema\n */\nfunction enforceStrictSchema(schema: JsonSchema): JsonSchema {\n const result = { ...schema }\n if (result.type === 'object' && result.properties) {\n result.additionalProperties = false\n result.required = Object.keys(result.properties as Record<string, unknown>)\n const props = result.properties as Record<string, JsonSchema>\n const strictProps: Record<string, JsonSchema> = {}\n for (const [key, value] of Object.entries(props)) {\n strictProps[key] = enforceStrictSchema(value)\n }\n result.properties = strictProps\n }\n if (result.items && typeof result.items === 'object') {\n result.items = enforceStrictSchema(result.items as JsonSchema)\n }\n for (const keyword of ['anyOf', 'oneOf', 'allOf'] as const) {\n if (Array.isArray(result[keyword])) {\n result[keyword] = (result[keyword] as JsonSchema[]).map((s) => enforceStrictSchema(s))\n }\n }\n return result\n}\n\n/**\n * Converts a Zod schema to an OpenAI-compatible strict JSON schema wrapped for the Vercel AI SDK.\n *\n * @param zodSchema - Zod schema to convert\n * @returns JSON schema wrapped for Vercel AI SDK\n */\nfunction toOpenAISchema(zodSchema: ProviderRequest['responseSchema']) {\n const strict = enforceStrictSchema(zodSchema.toJSONSchema() as JsonSchema)\n return jsonSchema(strict as never, {\n validate: (value: unknown) => {\n const result = zodSchema.safeParse(value)\n return result.success\n ? { success: true as const, value: result.data }\n : { success: false as const, error: result.error }\n },\n })\n}\n\nfunction toAIMessages(messages: ProviderMessage[]): ModelMessage[] {\n return messages.map((msg) => ({\n role: msg.role,\n content: msg.content,\n }))\n}\n\nasync function sendWithModel(\n openaiProvider: ReturnType<typeof createOpenAI>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n): Promise<ProviderResponse> {\n const result = await generateText({\n model: openaiProvider(model),\n system,\n messages,\n output: Output.object({ schema: toOpenAISchema(schema) }),\n })\n\n return {\n content: JSON.stringify(result.output),\n usage: {\n inputTokens: result.usage.inputTokens ?? 0,\n outputTokens: result.usage.outputTokens ?? 0,\n totalTokens: (result.usage.inputTokens ?? 0) + (result.usage.outputTokens ?? 0),\n },\n }\n}\n\nasync function sendStreamWithModel(\n openaiProvider: ReturnType<typeof createOpenAI>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n) {\n const result = streamText({\n model: openaiProvider(model),\n system,\n messages,\n output: Output.object({ schema: toOpenAISchema(schema) }),\n })\n\n // Force the API call to start so executeWithFallback can catch connection errors\n const partialStream = result.partialOutputStream\n const reader = partialStream[Symbol.asyncIterator]()\n const first = await reader.next()\n\n return { result, reader, first }\n}\n\n/**\n * Creates an OpenAI provider instance.\n *\n * Uses the Vercel AI SDK (`ai` + `@ai-sdk/openai`) for structured output via\n * `generateText` + `Output.object()` (blocking) and `streamText` + `Output.object()`\n * (streaming). The AI SDK handles Zod-to-JSON-schema conversion, partial JSON\n * parsing, and validation internally.\n *\n * @param config - OpenAI provider configuration\n * @returns A Provider implementation using OpenAI\n *\n * @example\n * ```typescript\n * const provider = createOpenAIProvider({\n * models: ['gpt-4o', 'gpt-4o-mini'],\n * })\n * ```\n */\nexport function createOpenAIProvider(config: OpenAIProviderConfig): Provider {\n const openaiProvider = createOpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseURL,\n organization: config.organization,\n })\n const models = config.models\n const resilience: ResolvedResilienceConfig = resolveResilienceConfig(config.resilience)\n\n return {\n name: 'openai',\n\n async sendRequest(request: ProviderRequest): Promise<ProviderResponse> {\n const messages = toAIMessages(request.messages)\n\n return executeWithFallback(\n models,\n (model) => sendWithModel(openaiProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n },\n\n async *sendRequestStream<TState extends BaseState = BaseState>(\n request: ProviderRequest,\n ): AsyncGenerator<StreamEvent<TState>> {\n const messages = toAIMessages(request.messages)\n\n const { result, reader, first } = await executeWithFallback(\n models,\n (model) => sendStreamWithModel(openaiProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n\n yield* processOpenAIStream<TState>(result, reader, first, 'openai', request.responseSchema)\n },\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../openai/streamProcessor.ts","../../utils/backoff.ts","../../utils/executeWithFallback.ts","../../openai/index.ts"],"names":[],"mappings":";;;;;;AAoBA,gBAAuB,mBAAA,CACrB,YAAA,EACA,MAAA,EACA,KAAA,EACA,SACA,MAAA,EACqC;AACrC,EAAA,IAAI,iBAAA,GAAoB,CAAA;AAExB,EAAA,IAAI;AAEF,IAAA,IAAI,CAAC,MAAM,IAAA,EAAM;AACf,MAAA,MAAM,UAAU,KAAA,CAAM,KAAA;AACtB,MAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,OAAA,EAAS,iBAAiB,CAAA;AACrD,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,iBAAA,IAAqB,KAAA,CAAM,MAAA;AAC3B,QAAA,MAAM;AAAA,UACJ,MAAM,SAAA,CAAU,oBAAA;AAAA,UAChB,SAAA,EAAW,EAAA;AAAA,UACX,KAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAAA,IACF;AAGA,IAAA,IAAI,IAAA,GAAO,MAAM,MAAA,CAAO,IAAA,EAAK;AAC7B,IAAA,OAAO,CAAC,KAAK,IAAA,EAAM;AACjB,MAAA,MAAM,UAAU,IAAA,CAAK,KAAA;AACrB,MAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,OAAA,EAAS,iBAAiB,CAAA;AACrD,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,iBAAA,IAAqB,KAAA,CAAM,MAAA;AAC3B,QAAA,MAAM;AAAA,UACJ,MAAM,SAAA,CAAU,oBAAA;AAAA,UAChB,SAAA,EAAW,EAAA;AAAA,UACX,KAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAEA,MAAA,IAAA,GAAO,MAAM,OAAO,IAAA,EAAK;AAAA,IAC3B;AAGA,IAAA,MAAM,WAAA,GAAc,MAAM,YAAA,CAAa,MAAA;AAEvC,IAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,MAAA,MAAM;AAAA,QACJ,MAAM,SAAA,CAAU,SAAA;AAAA,QAChB,OAAA,EAAS,0CAAA;AAAA,QACT;AAAA,OACF;AACA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,KAAA,CAAM,WAAW,CAAA;AAC1C,IAAA,MAAM;AAAA,MACJ,MAAM,SAAA,CAAU,gBAAA;AAAA,MAChB,UAAA,EAAY,EAAA;AAAA,MACZ,SAAA,EAAW,EAAA;AAAA,MACX,OAAA,EAAS,IAAA,CAAK,SAAA,CAAU,SAAS,CAAA;AAAA,MACjC;AAAA,KACF;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM;AAAA,MACJ,MAAM,SAAA,CAAU,SAAA;AAAA,MAChB,OAAA,EAAS,CAAA,qBAAA,EAAyB,GAAA,CAAc,OAAO,CAAA,CAAA;AAAA,MACvD;AAAA,KACF;AAAA,EACF;AACF;AAKA,SAAS,YAAA,CAAa,SAAkC,UAAA,EAAmC;AACzF,EAAA,MAAM,iBAAiB,OAAA,CAAQ,cAAA;AAC/B,EAAA,IAAI,OAAO,cAAA,KAAmB,QAAA,IAAY,cAAA,CAAe,UAAU,UAAA,EAAY;AAC7E,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,cAAA,CAAe,MAAM,UAAU,CAAA;AACxC;;;AC5FO,SAAS,gBAAA,CAAiB,SAAiB,MAAA,EAAyC;AACzF,EAAA,IAAI,KAAA;AAEJ,EAAA,QAAQ,OAAO,QAAA;AAAU,IACvB,KAAK,aAAA;AACH,MAAA,KAAA,GAAQ,MAAA,CAAO,WAAA,GAAc,IAAA,CAAK,GAAA,CAAI,GAAG,OAAO,CAAA;AAChD,MAAA;AAAA,IACF,KAAK,QAAA;AACH,MAAA,KAAA,GAAQ,MAAA,CAAO,eAAe,OAAA,GAAU,CAAA,CAAA;AACxC,MAAA;AAAA,IACF,KAAK,OAAA;AACH,MAAA,KAAA,GAAQ,MAAA,CAAO,WAAA;AACf,MAAA;AAAA;AAGJ,EAAA,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,MAAA,CAAO,UAAU,CAAA;AAEzC,EAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,IAAA,KAAA,GAAQ,IAAA,CAAK,QAAO,GAAI,KAAA;AAAA,EAC1B;AAEA,EAAA,OAAO,KAAA;AACT;AAQO,SAAS,KAAA,CAAM,IAAY,MAAA,EAAqC;AACrE,EAAA,OAAO,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAA,KAAW;AAC5C,IAAA,IAAI,QAAQ,OAAA,EAAS;AACnB,MAAA,MAAA,CAAO,OAAO,MAAe,CAAA;AAC7B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,OAAA,EAAS,EAAE,CAAA;AAEpC,IAAA,MAAA,EAAQ,gBAAA;AAAA,MACN,OAAA;AAAA,MACA,MAAM;AACJ,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,MAAA,CAAO,OAAO,MAAe,CAAA;AAAA,MAC/B,CAAA;AAAA,MACA,EAAE,MAAM,IAAA;AAAK,KACf;AAAA,EACF,CAAC,CAAA;AACH;;;AC7CA,SAAS,WAAA,CAAY,kBAA2B,UAAA,EAAmD;AACjG,EAAA,MAAM,UAAyB,EAAC;AAEhC,EAAA,IAAI,qBAAqB,MAAA,EAAW;AAClC,IAAA,OAAA,CAAQ,IAAA,CAAK,WAAA,CAAY,OAAA,CAAQ,gBAAgB,CAAC,CAAA;AAAA,EACpD;AAEA,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,OAAA,CAAQ,KAAK,UAAU,CAAA;AAAA,EACzB;AAEA,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AACjC,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,QAAQ,CAAC,CAAA;AAC1C,EAAA,OAAO,WAAA,CAAY,IAAI,OAAO,CAAA;AAChC;AAIA,eAAe,aAAA,CACb,MAAA,EACA,KAAA,EACA,MAAA,EACA,SACA,MAAA,EAC2B;AAC3B,EAAA,IAAI;AACF,IAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,KAAA,EAAO,MAAM,CAAA;AACxC,IAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,KAAA,EAAM;AAAA,EAC3B,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,QAAA,GAAW,KAAA;AACjB,IAAA,MAAA,CAAO,KAAK,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,UAAU,CAAA;AAC/C,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,QAAA,EAAS;AAAA,EACtC;AACF;AAEA,SAAS,iBAAA,CAAkB,UAAA,EAAyC,SAAA,EAA+B,MAAA,EAAsC;AACvI,EAAA,IAAI,UAAA,EAAY,OAAO,OAAA,EAAS;AAC9B,IAAA,MAAM,IAAI,cAAA,CAAe,CAAA,iBAAA,EAAoB,SAAS,eAAe,MAAM,CAAA;AAAA,EAC7E;AACF;AAEA,eAAe,mBACb,QAAA,EACA,OAAA,EACA,UAAA,EACA,QAAA,EACA,UACA,UAAA,EACiC;AACjC,EAAA,MAAM,aAAA,GAAgB,YAAY,CAAA,GAAI,UAAA;AACtC,EAAA,MAAM,WAAA,GAAc,QAAA,IAAY,QAAA,CAAS,gBAAA,CAAiB,QAAQ,CAAA;AAElE,EAAA,IAAI,WAAA,IAAe,CAAC,aAAA,EAAe;AACjC,IAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,OAAA,GAAU,CAAA,EAAG,SAAS,OAAO,CAAA;AAC5D,IAAA,MAAM,MAAM,KAAA,EAAO,UAAA,EAAY,MAAM,CAAA,CAAE,MAAM,MAAM;AAAA,IAEnD,CAAC,CAAA;AACD,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,OAAO,YAAA;AACT;AA6BA,eAAsB,mBAAA,CACpB,MAAA,EACA,MAAA,EACA,MAAA,EACY;AACZ,EAAA,MAAM,WAAW,MAAA,IAAU,yBAAA;AAC3B,EAAA,MAAM,SAAiC,EAAC;AACxC,EAAA,MAAM,aAAa,QAAA,CAAS,KAAA,KAAU,KAAA,GAAQ,CAAA,GAAI,SAAS,KAAA,CAAM,WAAA;AACjE,EAAA,MAAM,WAAW,QAAA,CAAS,KAAA,KAAU,KAAA,IAAS,QAAA,CAAS,MAAM,OAAA,KAAY,KAAA;AAGxE,EAAA,IAAI,UAAA;AACJ,EAAA,IAAI,UAAA;AAEJ,EAAA,IAAI,QAAA,CAAS,OAAA,CAAQ,cAAA,KAAmB,MAAA,EAAW;AACjD,IAAA,UAAA,GAAa,IAAI,eAAA,EAAgB;AACjC,IAAA,UAAA,GAAa,UAAA;AAAA,MACX,MAAM,UAAA,CAAY,KAAA,CAAM,IAAI,KAAA,CAAM,wBAAwB,CAAC,CAAA;AAAA,MAC3D,SAAS,OAAA,CAAQ;AAAA,KACnB;AAAA,EACF;AAEA,EAAA,IAAI;AACF,IAAA,KAAA,IAAS,UAAA,GAAa,CAAA,EAAG,UAAA,GAAa,MAAA,CAAO,QAAQ,UAAA,EAAA,EAAc;AACjE,MAAA,MAAM,KAAA,GAAQ,OAAO,UAAU,CAAA;AAE/B,MAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,CAAA,GAAI,YAAY,OAAA,EAAA,EAAW;AAC1D,QAAA,iBAAA,CAAkB,UAAA,EAAY,QAAA,CAAS,OAAA,CAAQ,cAAA,EAAgB,MAAM,CAAA;AAErE,QAAA,MAAM,SAAS,WAAA,CAAY,QAAA,CAAS,OAAA,CAAQ,gBAAA,EAAkB,YAAY,MAAM,CAAA;AAEhF,QAAA,MAAM,SAAS,MAAM,aAAA,CAAc,QAAQ,KAAA,EAAO,MAAA,EAAQ,SAAS,MAAM,CAAA;AACzE,QAAA,IAAI,MAAA,CAAO,EAAA,EAAI,OAAO,MAAA,CAAO,KAAA;AAE7B,QAAA,iBAAA,CAAkB,UAAA,EAAY,QAAA,CAAS,OAAA,CAAQ,cAAA,EAAgB,MAAM,CAAA;AAGrE,QAAA,MAAM,QAAA,GAAW,MAAM,kBAAA,CAAmB,MAAA,CAAO,OAAO,OAAA,EAAS,UAAA,EAAY,QAAA,EAAU,QAAA,EAAU,UAAU,CAAA;AAC3G,QAAA,IAAI,aAAa,YAAA,EAAc;AAAA,MACjC;AAAA,IACF;AAGA,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,2BAA2B,MAAA,CAAO,MAAM,sBAAsB,MAAA,CAAO,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAA,MAC/E;AAAA,KACF;AAAA,EACF,CAAA,SAAE;AACA,IAAA,IAAI,eAAe,MAAA,EAAW;AAC5B,MAAA,YAAA,CAAa,UAAU,CAAA;AAAA,IACzB;AAAA,EACF;AACF;;;AC7GA,SAAS,oBAAoB,MAAA,EAAgC;AAC3D,EAAA,MAAM,MAAA,GAAS,EAAE,GAAG,MAAA,EAAO;AAC3B,EAAA,IAAI,MAAA,CAAO,IAAA,KAAS,QAAA,IAAY,MAAA,CAAO,UAAA,EAAY;AACjD,IAAA,MAAA,CAAO,oBAAA,GAAuB,KAAA;AAC9B,IAAA,MAAA,CAAO,QAAA,GAAW,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,UAAqC,CAAA;AAC1E,IAAA,MAAM,QAAQ,MAAA,CAAO,UAAA;AACrB,IAAA,MAAM,cAA0C,EAAC;AACjD,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAChD,MAAA,WAAA,CAAY,GAAG,CAAA,GAAI,mBAAA,CAAoB,KAAK,CAAA;AAAA,IAC9C;AACA,IAAA,MAAA,CAAO,UAAA,GAAa,WAAA;AAAA,EACtB;AACA,EAAA,IAAI,MAAA,CAAO,KAAA,IAAS,OAAO,MAAA,CAAO,UAAU,QAAA,EAAU;AACpD,IAAA,MAAA,CAAO,KAAA,GAAQ,mBAAA,CAAoB,MAAA,CAAO,KAAmB,CAAA;AAAA,EAC/D;AACA,EAAA,KAAA,MAAW,OAAA,IAAW,CAAC,OAAA,EAAS,OAAA,EAAS,OAAO,CAAA,EAAY;AAC1D,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,MAAA,CAAO,OAAO,CAAC,CAAA,EAAG;AAClC,MAAA,MAAA,CAAO,OAAO,CAAA,GAAK,MAAA,CAAO,OAAO,CAAA,CAAmB,IAAI,CAAC,CAAA,KAAM,mBAAA,CAAoB,CAAC,CAAC,CAAA;AAAA,IACvF;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAQA,SAAS,eAAe,SAAA,EAA8C;AACpE,EAAA,MAAM,MAAA,GAAS,mBAAA,CAAoB,SAAA,CAAU,YAAA,EAA4B,CAAA;AACzE,EAAA,OAAO,WAAW,MAAA,EAAiB;AAAA,IACjC,QAAA,EAAU,CAAC,KAAA,KAAmB;AAC5B,MAAA,MAAM,MAAA,GAAS,SAAA,CAAU,SAAA,CAAU,KAAK,CAAA;AACxC,MAAA,OAAO,MAAA,CAAO,OAAA,GACV,EAAE,OAAA,EAAS,MAAe,KAAA,EAAO,MAAA,CAAO,IAAA,EAAK,GAC7C,EAAE,OAAA,EAAS,KAAA,EAAgB,KAAA,EAAO,OAAO,KAAA,EAAM;AAAA,IACrD;AAAA,GACD,CAAA;AACH;AAEA,SAAS,aAAa,QAAA,EAA6C;AACjE,EAAA,OAAO,QAAA,CAAS,GAAA,CAAI,CAAC,GAAA,MAAS;AAAA,IAC5B,MAAM,GAAA,CAAI,IAAA;AAAA,IACV,SAAS,GAAA,CAAI;AAAA,GACf,CAAE,CAAA;AACJ;AAEA,eAAe,aAAA,CACb,cAAA,EACA,KAAA,EACA,MAAA,EACA,UACA,MAAA,EAC2B;AAC3B,EAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa;AAAA,IAChC,KAAA,EAAO,eAAe,KAAK,CAAA;AAAA,IAC3B,MAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA,EAAQ,OAAO,MAAA,CAAO,EAAE,QAAQ,cAAA,CAAe,MAAM,GAAG;AAAA,GACzD,CAAA;AAED,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,MAAM,CAAA;AAAA,IACrC,KAAA,EAAO;AAAA,MACL,WAAA,EAAa,MAAA,CAAO,KAAA,CAAM,WAAA,IAAe,CAAA;AAAA,MACzC,YAAA,EAAc,MAAA,CAAO,KAAA,CAAM,YAAA,IAAgB,CAAA;AAAA,MAC3C,cAAc,MAAA,CAAO,KAAA,CAAM,eAAe,CAAA,KAAM,MAAA,CAAO,MAAM,YAAA,IAAgB,CAAA;AAAA;AAC/E,GACF;AACF;AAEA,eAAe,mBAAA,CACb,cAAA,EACA,KAAA,EACA,MAAA,EACA,UACA,MAAA,EACA;AACA,EAAA,MAAM,SAAS,UAAA,CAAW;AAAA,IACxB,KAAA,EAAO,eAAe,KAAK,CAAA;AAAA,IAC3B,MAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA,EAAQ,OAAO,MAAA,CAAO,EAAE,QAAQ,cAAA,CAAe,MAAM,GAAG;AAAA,GACzD,CAAA;AAGD,EAAA,MAAM,gBAAgB,MAAA,CAAO,mBAAA;AAC7B,EAAA,MAAM,MAAA,GAAS,aAAA,CAAc,MAAA,CAAO,aAAa,CAAA,EAAE;AACnD,EAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,IAAA,EAAK;AAEhC,EAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAM;AACjC;AAoBO,SAAS,qBAAqB,MAAA,EAAwC;AAC3E,EAAA,MAAM,iBAAiB,YAAA,CAAa;AAAA,IAClC,QAAQ,MAAA,CAAO,MAAA;AAAA,IACf,SAAS,MAAA,CAAO,OAAA;AAAA,IAChB,cAAc,MAAA,CAAO;AAAA,GACtB,CAAA;AACD,EAAA,MAAM,SAAS,MAAA,CAAO,MAAA;AACtB,EAAA,MAAM,UAAA,GAAuC,uBAAA,CAAwB,MAAA,CAAO,UAAU,CAAA;AAEtF,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAA;AAAA,IAEN,MAAM,YAAY,OAAA,EAAqD;AACrE,MAAA,MAAM,QAAA,GAAW,YAAA,CAAa,OAAA,CAAQ,QAAQ,CAAA;AAE9C,MAAA,OAAO,mBAAA;AAAA,QACL,MAAA;AAAA,QACA,CAAC,UAAU,aAAA,CAAc,cAAA,EAAgB,OAAO,OAAA,CAAQ,YAAA,EAAc,QAAA,EAAU,OAAA,CAAQ,cAAc,CAAA;AAAA,QACtG;AAAA,OACF;AAAA,IACF,CAAA;AAAA,IAEA,OAAO,kBACL,OAAA,EACqC;AACrC,MAAA,MAAM,QAAA,GAAW,YAAA,CAAa,OAAA,CAAQ,QAAQ,CAAA;AAE9C,MAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,KAAU,MAAM,mBAAA;AAAA,QACtC,MAAA;AAAA,QACA,CAAC,UAAU,mBAAA,CAAoB,cAAA,EAAgB,OAAO,OAAA,CAAQ,YAAA,EAAc,QAAA,EAAU,OAAA,CAAQ,cAAc,CAAA;AAAA,QAC5G;AAAA,OACF;AAEA,MAAA,OAAO,oBAA4B,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,QAAA,EAAU,QAAQ,cAAc,CAAA;AAAA,IAC5F;AAAA,GACF;AACF","file":"index.js","sourcesContent":["import { EventType } from '@ag-ui/client'\nimport { ZodType } from 'zod'\nimport type { AgentId, StreamEvent, BaseState } from '@genui-a3/core'\nimport type { StreamTextResult, ToolSet } from 'ai'\n\n/**\n * Processes an OpenAI streaming response (via Vercel AI SDK) into AG-UI events.\n *\n * Uses `partialOutputStream` from `streamText` + `Output.object()` to receive\n * progressively-built partial objects. Tracks `chatbotMessage` growth to yield\n * TEXT_MESSAGE_CONTENT deltas. After the stream completes, validates the final\n * object and yields TOOL_CALL_RESULT.\n *\n * @param streamResult - The streamText result containing partialOutputStream and output promise\n * @param reader - Pre-started async iterator for the partial object stream\n * @param first - The first iteration result (already consumed to trigger the API call)\n * @param agentId - Agent identifier for event tagging\n * @param schema - Zod schema for final response validation\n * @returns Async generator of AG-UI stream events\n */\nexport async function* processOpenAIStream<TState extends BaseState = BaseState>(\n streamResult: StreamTextResult<ToolSet, never>,\n reader: AsyncIterator<unknown>,\n first: IteratorResult<unknown>,\n agentId: AgentId,\n schema: ZodType,\n): AsyncGenerator<StreamEvent<TState>> {\n let prevMessageLength = 0\n\n try {\n // Process the first partial (already consumed to trigger the API call)\n if (!first.done) {\n const partial = first.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n }\n\n // Process remaining partials\n let next = await reader.next()\n while (!next.done) {\n const partial = next.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n // eslint-disable-next-line no-await-in-loop\n next = await reader.next()\n }\n\n // Stream complete — await and validate the final object\n const finalObject = await streamResult.output\n\n if (finalObject === null) {\n yield {\n type: EventType.RUN_ERROR,\n message: 'OpenAI stream completed with null output',\n agentId,\n } as StreamEvent<TState>\n return\n }\n\n const validated = schema.parse(finalObject)\n yield {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: '',\n messageId: '',\n content: JSON.stringify(validated),\n agentId,\n } as StreamEvent<TState>\n } catch (err) {\n yield {\n type: EventType.RUN_ERROR,\n message: `OpenAI stream error: ${(err as Error).message}`,\n agentId,\n } as StreamEvent<TState>\n }\n}\n\n/**\n * Extracts the new portion of chatbotMessage from a partial object.\n */\nfunction extractDelta(partial: Record<string, unknown>, prevLength: number): string | null {\n const chatbotMessage = partial.chatbotMessage\n if (typeof chatbotMessage !== 'string' || chatbotMessage.length <= prevLength) {\n return null\n }\n return chatbotMessage.slice(prevLength)\n}\n","import type { BackoffConfig } from '@genui-a3/core'\n\n/**\n * Calculates the backoff delay for a given retry attempt.\n *\n * @param attempt - Zero-based attempt index (0 = first retry)\n * @param config - Backoff configuration with all fields required\n * @returns Delay in milliseconds\n */\nexport function calculateBackoff(attempt: number, config: Required<BackoffConfig>): number {\n let delay: number\n\n switch (config.strategy) {\n case 'exponential':\n delay = config.baseDelayMs * Math.pow(2, attempt)\n break\n case 'linear':\n delay = config.baseDelayMs * (attempt + 1)\n break\n case 'fixed':\n delay = config.baseDelayMs\n break\n }\n\n delay = Math.min(delay, config.maxDelayMs)\n\n if (config.jitter) {\n delay = Math.random() * delay\n }\n\n return delay\n}\n\n/**\n * Sleeps for the specified duration. Can be aborted via an AbortSignal.\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal to cancel the sleep early\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason as Error)\n return\n }\n\n const timer = setTimeout(resolve, ms)\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason as Error)\n },\n { once: true },\n )\n })\n}\n","import {\n A3ResilienceError,\n A3TimeoutError,\n DEFAULT_RESILIENCE_CONFIG,\n type ResilienceErrorEntry,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { calculateBackoff, sleep } from './backoff'\n\n/**\n * Builds an AbortSignal that fires when either the per-request timeout or total timeout expires.\n */\nfunction buildSignal(requestTimeoutMs?: number, totalAbort?: AbortSignal): AbortSignal | undefined {\n const signals: AbortSignal[] = []\n\n if (requestTimeoutMs !== undefined) {\n signals.push(AbortSignal.timeout(requestTimeoutMs))\n }\n\n if (totalAbort) {\n signals.push(totalAbort)\n }\n\n if (signals.length === 0) return undefined\n if (signals.length === 1) return signals[0]\n return AbortSignal.any(signals)\n}\n\ntype AttemptResult<T> = { ok: true; value: T } | { ok: false; error: Error }\n\nasync function attemptAction<T>(\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n model: string,\n signal: AbortSignal | undefined,\n attempt: number,\n errors: ResilienceErrorEntry[],\n): Promise<AttemptResult<T>> {\n try {\n const value = await action(model, signal)\n return { ok: true, value }\n } catch (error) {\n const errorObj = error as Error\n errors.push({ model, attempt, error: errorObj })\n return { ok: false, error: errorObj }\n }\n}\n\nfunction checkTotalTimeout(totalAbort: AbortController | undefined, timeoutMs: number | undefined, errors: ResilienceErrorEntry[]): void {\n if (totalAbort?.signal.aborted) {\n throw new A3TimeoutError(`Total timeout of ${timeoutMs}ms exceeded`, errors)\n }\n}\n\nasync function handleAttemptError(\n errorObj: Error,\n attempt: number,\n maxRetries: number,\n retryAll: boolean,\n resolved: ResolvedResilienceConfig,\n totalAbort: AbortController | undefined,\n): Promise<'retry' | 'next-model'> {\n const isLastAttempt = attempt === 1 + maxRetries\n const isRetryable = retryAll || resolved.isRetryableError(errorObj)\n\n if (isRetryable && !isLastAttempt) {\n const delay = calculateBackoff(attempt - 1, resolved.backoff)\n await sleep(delay, totalAbort?.signal).catch(() => {\n // Sleep was aborted by total timeout — will be caught at top of loop\n })\n return 'retry'\n }\n\n return 'next-model'\n}\n\n/**\n * Executes an action with model fallback, retry, backoff, and timeout support.\n *\n * For each model (in priority order):\n * 1. Attempts the action up to `1 + maxAttempts` times\n * 2. On transient errors, waits with backoff before retrying\n * 3. On non-retryable errors (or after exhausting retries), falls back to the next model\n *\n * Throws `A3ResilienceError` with full error history when all models are exhausted.\n * Throws `A3TimeoutError` when the total timeout is exceeded.\n *\n * @param models - Model identifiers in priority order\n * @param action - Async action to attempt with each model. Receives an optional AbortSignal.\n * @param config - Resolved resilience configuration (defaults applied if omitted)\n * @returns The result from the first successful attempt\n * @throws {A3ResilienceError} When all models and retries are exhausted\n * @throws {A3TimeoutError} When the total timeout is exceeded\n *\n * @example\n * ```typescript\n * const result = await executeWithFallback(\n * ['model-primary', 'model-fallback'],\n * (model, signal) => provider.call(model, params, { abortSignal: signal }),\n * resolvedConfig,\n * )\n * ```\n */\nexport async function executeWithFallback<T>(\n models: string[],\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n config?: ResolvedResilienceConfig,\n): Promise<T> {\n const resolved = config ?? DEFAULT_RESILIENCE_CONFIG\n const errors: ResilienceErrorEntry[] = []\n const maxRetries = resolved.retry === false ? 0 : resolved.retry.maxAttempts\n const retryAll = resolved.retry !== false && resolved.retry.retryOn === 'all'\n\n // Total timeout controller\n let totalAbort: AbortController | undefined\n let totalTimer: ReturnType<typeof setTimeout> | undefined\n\n if (resolved.timeout.totalTimeoutMs !== undefined) {\n totalAbort = new AbortController()\n totalTimer = setTimeout(\n () => totalAbort!.abort(new Error('Total timeout exceeded')),\n resolved.timeout.totalTimeoutMs,\n )\n }\n\n try {\n for (let modelIndex = 0; modelIndex < models.length; modelIndex++) {\n const model = models[modelIndex]\n\n for (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n const signal = buildSignal(resolved.timeout.requestTimeoutMs, totalAbort?.signal)\n // eslint-disable-next-line no-await-in-loop\n const result = await attemptAction(action, model, signal, attempt, errors)\n if (result.ok) return result.value\n\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n // eslint-disable-next-line no-await-in-loop\n const decision = await handleAttemptError(result.error, attempt, maxRetries, retryAll, resolved, totalAbort)\n if (decision === 'next-model') break\n }\n }\n\n // All models exhausted\n throw new A3ResilienceError(\n `All models failed after ${errors.length} total attempt(s): ${models.join(', ')}`,\n errors,\n )\n } finally {\n if (totalTimer !== undefined) {\n clearTimeout(totalTimer)\n }\n }\n}\n","import { createOpenAI } from '@ai-sdk/openai'\nimport { generateText, streamText, Output, ModelMessage, jsonSchema } from 'ai'\nimport {\n resolveResilienceConfig,\n type Provider,\n type ProviderRequest,\n type ProviderResponse,\n type ProviderMessage,\n type BaseState,\n type StreamEvent,\n type ResilienceConfig,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { processOpenAIStream } from './streamProcessor'\nimport { executeWithFallback } from '../utils/executeWithFallback'\n\n/**\n * Configuration for creating an OpenAI provider.\n */\nexport interface OpenAIProviderConfig {\n /** OpenAI API key. Defaults to OPENAI_API_KEY env var (OpenAI SDK default). */\n apiKey?: string\n /**\n * Model identifiers in order of preference (first = primary, rest = fallbacks).\n * e.g. ['gpt-4o', 'gpt-4o-mini']\n */\n models: string[]\n /** Optional base URL for Azure OpenAI or compatible endpoints */\n baseURL?: string\n /** Optional OpenAI organization ID */\n organization?: string\n /** Resilience configuration (retry, backoff, timeout). Uses industry-standard defaults if omitted. */\n resilience?: ResilienceConfig\n}\n\ntype JsonSchema = Record<string, unknown>\n\n/**\n * Enforces strict JSON schema constraints required by OpenAI's structured output API.\n * OpenAI requires all object properties — including optional ones — to be in the `required` array.\n * This function recursively adds `required` and `additionalProperties: false` to all objects.\n *\n * @param schema - JSON schema to enforce\n * @returns Enforced JSON schema\n */\nfunction enforceStrictSchema(schema: JsonSchema): JsonSchema {\n const result = { ...schema }\n if (result.type === 'object' && result.properties) {\n result.additionalProperties = false\n result.required = Object.keys(result.properties as Record<string, unknown>)\n const props = result.properties as Record<string, JsonSchema>\n const strictProps: Record<string, JsonSchema> = {}\n for (const [key, value] of Object.entries(props)) {\n strictProps[key] = enforceStrictSchema(value)\n }\n result.properties = strictProps\n }\n if (result.items && typeof result.items === 'object') {\n result.items = enforceStrictSchema(result.items as JsonSchema)\n }\n for (const keyword of ['anyOf', 'oneOf', 'allOf'] as const) {\n if (Array.isArray(result[keyword])) {\n result[keyword] = (result[keyword] as JsonSchema[]).map((s) => enforceStrictSchema(s))\n }\n }\n return result\n}\n\n/**\n * Converts a Zod schema to an OpenAI-compatible strict JSON schema wrapped for the Vercel AI SDK.\n *\n * @param zodSchema - Zod schema to convert\n * @returns JSON schema wrapped for Vercel AI SDK\n */\nfunction toOpenAISchema(zodSchema: ProviderRequest['responseSchema']) {\n const strict = enforceStrictSchema(zodSchema.toJSONSchema() as JsonSchema)\n return jsonSchema(strict as never, {\n validate: (value: unknown) => {\n const result = zodSchema.safeParse(value)\n return result.success\n ? { success: true as const, value: result.data }\n : { success: false as const, error: result.error }\n },\n })\n}\n\nfunction toAIMessages(messages: ProviderMessage[]): ModelMessage[] {\n return messages.map((msg) => ({\n role: msg.role,\n content: msg.content,\n }))\n}\n\nasync function sendWithModel(\n openaiProvider: ReturnType<typeof createOpenAI>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n): Promise<ProviderResponse> {\n const result = await generateText({\n model: openaiProvider(model),\n system,\n messages,\n output: Output.object({ schema: toOpenAISchema(schema) }),\n })\n\n return {\n content: JSON.stringify(result.output),\n usage: {\n inputTokens: result.usage.inputTokens ?? 0,\n outputTokens: result.usage.outputTokens ?? 0,\n totalTokens: (result.usage.inputTokens ?? 0) + (result.usage.outputTokens ?? 0),\n },\n }\n}\n\nasync function sendStreamWithModel(\n openaiProvider: ReturnType<typeof createOpenAI>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n) {\n const result = streamText({\n model: openaiProvider(model),\n system,\n messages,\n output: Output.object({ schema: toOpenAISchema(schema) }),\n })\n\n // Force the API call to start so executeWithFallback can catch connection errors\n const partialStream = result.partialOutputStream\n const reader = partialStream[Symbol.asyncIterator]()\n const first = await reader.next()\n\n return { result, reader, first }\n}\n\n/**\n * Creates an OpenAI provider instance.\n *\n * Uses the Vercel AI SDK (`ai` + `@ai-sdk/openai`) for structured output via\n * `generateText` + `Output.object()` (blocking) and `streamText` + `Output.object()`\n * (streaming). The AI SDK handles Zod-to-JSON-schema conversion, partial JSON\n * parsing, and validation internally.\n *\n * @param config - OpenAI provider configuration\n * @returns A Provider implementation using OpenAI\n *\n * @example\n * ```typescript\n * const provider = createOpenAIProvider({\n * models: ['gpt-4o', 'gpt-4o-mini'],\n * })\n * ```\n */\nexport function createOpenAIProvider(config: OpenAIProviderConfig): Provider {\n const openaiProvider = createOpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseURL,\n organization: config.organization,\n })\n const models = config.models\n const resilience: ResolvedResilienceConfig = resolveResilienceConfig(config.resilience)\n\n return {\n name: 'openai',\n\n async sendRequest(request: ProviderRequest): Promise<ProviderResponse> {\n const messages = toAIMessages(request.messages)\n\n return executeWithFallback(\n models,\n (model) => sendWithModel(openaiProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n },\n\n async *sendRequestStream<TState extends BaseState = BaseState>(\n request: ProviderRequest,\n ): AsyncGenerator<StreamEvent<TState>> {\n const messages = toAIMessages(request.messages)\n\n const { result, reader, first } = await executeWithFallback(\n models,\n (model) => sendStreamWithModel(openaiProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n\n yield* processOpenAIStream<TState>(result, reader, first, 'openai', request.responseSchema)\n },\n }\n}\n"]}
1
+ {"version":3,"sources":["../../openai/streamProcessor.ts","../../utils/backoff.ts","../../utils/executeWithFallback.ts","../../openai/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { EventType } from '@ag-ui/client'\nimport { ZodType } from 'zod'\nimport type { AgentId, StreamEvent, BaseState } from '@genui-a3/core'\nimport type { StreamTextResult, ToolSet } from 'ai'\n\n/**\n * Processes an OpenAI streaming response (via Vercel AI SDK) into AG-UI events.\n *\n * Uses `partialOutputStream` from `streamText` + `Output.object()` to receive\n * progressively-built partial objects. Tracks `chatbotMessage` growth to yield\n * TEXT_MESSAGE_CONTENT deltas. After the stream completes, validates the final\n * object and yields TOOL_CALL_RESULT.\n *\n * @param streamResult - The streamText result containing partialOutputStream and output promise\n * @param reader - Pre-started async iterator for the partial object stream\n * @param first - The first iteration result (already consumed to trigger the API call)\n * @param agentId - Agent identifier for event tagging\n * @param schema - Zod schema for final response validation\n * @returns Async generator of AG-UI stream events\n */\nexport async function* processOpenAIStream<TState extends BaseState = BaseState>(\n streamResult: StreamTextResult<ToolSet, never>,\n reader: AsyncIterator<unknown>,\n first: IteratorResult<unknown>,\n agentId: AgentId,\n schema: ZodType,\n): AsyncGenerator<StreamEvent<TState>> {\n let prevMessageLength = 0\n\n try {\n // Process the first partial (already consumed to trigger the API call)\n if (!first.done) {\n const partial = first.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n }\n\n // Process remaining partials\n let next = await reader.next()\n while (!next.done) {\n const partial = next.value as Record<string, unknown>\n const delta = extractDelta(partial, prevMessageLength)\n if (delta) {\n prevMessageLength += delta.length\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: '',\n delta,\n agentId,\n } as StreamEvent<TState>\n }\n // eslint-disable-next-line no-await-in-loop\n next = await reader.next()\n }\n\n // Stream complete — await and validate the final object\n const finalObject = await streamResult.output\n\n if (finalObject === null) {\n yield {\n type: EventType.RUN_ERROR,\n message: 'OpenAI stream completed with null output',\n agentId,\n } as StreamEvent<TState>\n return\n }\n\n const validated = schema.parse(finalObject)\n yield {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: '',\n messageId: '',\n content: JSON.stringify(validated),\n agentId,\n } as StreamEvent<TState>\n } catch (err) {\n yield {\n type: EventType.RUN_ERROR,\n message: `OpenAI stream error: ${(err as Error).message}`,\n agentId,\n } as StreamEvent<TState>\n }\n}\n\n/**\n * Extracts the new portion of chatbotMessage from a partial object.\n */\nfunction extractDelta(partial: Record<string, unknown>, prevLength: number): string | null {\n const chatbotMessage = partial.chatbotMessage\n if (typeof chatbotMessage !== 'string' || chatbotMessage.length <= prevLength) {\n return null\n }\n return chatbotMessage.slice(prevLength)\n}\n","import type { BackoffConfig } from '@genui-a3/core'\n\n/**\n * Calculates the backoff delay for a given retry attempt.\n *\n * @param attempt - Zero-based attempt index (0 = first retry)\n * @param config - Backoff configuration with all fields required\n * @returns Delay in milliseconds\n */\nexport function calculateBackoff(attempt: number, config: Required<BackoffConfig>): number {\n let delay: number\n\n switch (config.strategy) {\n case 'exponential':\n delay = config.baseDelayMs * Math.pow(2, attempt)\n break\n case 'linear':\n delay = config.baseDelayMs * (attempt + 1)\n break\n case 'fixed':\n delay = config.baseDelayMs\n break\n }\n\n delay = Math.min(delay, config.maxDelayMs)\n\n if (config.jitter) {\n delay = Math.random() * delay\n }\n\n return delay\n}\n\n/**\n * Sleeps for the specified duration. Can be aborted via an AbortSignal.\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal to cancel the sleep early\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason as Error)\n return\n }\n\n const timer = setTimeout(resolve, ms)\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(signal.reason as Error)\n },\n { once: true },\n )\n })\n}\n","import {\n A3ResilienceError,\n A3TimeoutError,\n DEFAULT_RESILIENCE_CONFIG,\n type ResilienceErrorEntry,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { calculateBackoff, sleep } from './backoff'\n\n/**\n * Builds an AbortSignal that fires when either the per-request timeout or total timeout expires.\n */\nfunction buildSignal(requestTimeoutMs?: number, totalAbort?: AbortSignal): AbortSignal | undefined {\n const signals: AbortSignal[] = []\n\n if (requestTimeoutMs !== undefined) {\n signals.push(AbortSignal.timeout(requestTimeoutMs))\n }\n\n if (totalAbort) {\n signals.push(totalAbort)\n }\n\n if (signals.length === 0) return undefined\n if (signals.length === 1) return signals[0]\n return AbortSignal.any(signals)\n}\n\ntype AttemptResult<T> = { ok: true; value: T } | { ok: false; error: Error }\n\nasync function attemptAction<T>(\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n model: string,\n signal: AbortSignal | undefined,\n attempt: number,\n errors: ResilienceErrorEntry[],\n): Promise<AttemptResult<T>> {\n try {\n const value = await action(model, signal)\n return { ok: true, value }\n } catch (error) {\n const errorObj = error as Error\n errors.push({ model, attempt, error: errorObj })\n return { ok: false, error: errorObj }\n }\n}\n\nfunction checkTotalTimeout(totalAbort: AbortController | undefined, timeoutMs: number | undefined, errors: ResilienceErrorEntry[]): void {\n if (totalAbort?.signal.aborted) {\n throw new A3TimeoutError(`Total timeout of ${timeoutMs}ms exceeded`, errors)\n }\n}\n\nasync function handleAttemptError(\n errorObj: Error,\n attempt: number,\n maxRetries: number,\n retryAll: boolean,\n resolved: ResolvedResilienceConfig,\n totalAbort: AbortController | undefined,\n): Promise<'retry' | 'next-model'> {\n const isLastAttempt = attempt === 1 + maxRetries\n const isRetryable = retryAll || resolved.isRetryableError(errorObj)\n\n if (isRetryable && !isLastAttempt) {\n const delay = calculateBackoff(attempt - 1, resolved.backoff)\n await sleep(delay, totalAbort?.signal).catch(() => {\n // Sleep was aborted by total timeout — will be caught at top of loop\n })\n return 'retry'\n }\n\n return 'next-model'\n}\n\n/**\n * Executes an action with model fallback, retry, backoff, and timeout support.\n *\n * For each model (in priority order):\n * 1. Attempts the action up to `1 + maxAttempts` times\n * 2. On transient errors, waits with backoff before retrying\n * 3. On non-retryable errors (or after exhausting retries), falls back to the next model\n *\n * Throws `A3ResilienceError` with full error history when all models are exhausted.\n * Throws `A3TimeoutError` when the total timeout is exceeded.\n *\n * @param models - Model identifiers in priority order\n * @param action - Async action to attempt with each model. Receives an optional AbortSignal.\n * @param config - Resolved resilience configuration (defaults applied if omitted)\n * @returns The result from the first successful attempt\n * @throws {A3ResilienceError} When all models and retries are exhausted\n * @throws {A3TimeoutError} When the total timeout is exceeded\n *\n * @example\n * ```typescript\n * const result = await executeWithFallback(\n * ['model-primary', 'model-fallback'],\n * (model, signal) => provider.call(model, params, { abortSignal: signal }),\n * resolvedConfig,\n * )\n * ```\n */\nexport async function executeWithFallback<T>(\n models: string[],\n action: (model: string, signal?: AbortSignal) => Promise<T>,\n config?: ResolvedResilienceConfig,\n): Promise<T> {\n const resolved = config ?? DEFAULT_RESILIENCE_CONFIG\n const errors: ResilienceErrorEntry[] = []\n const maxRetries = resolved.retry === false ? 0 : resolved.retry.maxAttempts\n const retryAll = resolved.retry !== false && resolved.retry.retryOn === 'all'\n\n // Total timeout controller\n let totalAbort: AbortController | undefined\n let totalTimer: ReturnType<typeof setTimeout> | undefined\n\n if (resolved.timeout.totalTimeoutMs !== undefined) {\n totalAbort = new AbortController()\n totalTimer = setTimeout(\n () => totalAbort!.abort(new Error('Total timeout exceeded')),\n resolved.timeout.totalTimeoutMs,\n )\n }\n\n try {\n for (let modelIndex = 0; modelIndex < models.length; modelIndex++) {\n const model = models[modelIndex]\n\n for (let attempt = 1; attempt <= 1 + maxRetries; attempt++) {\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n const signal = buildSignal(resolved.timeout.requestTimeoutMs, totalAbort?.signal)\n // eslint-disable-next-line no-await-in-loop\n const result = await attemptAction(action, model, signal, attempt, errors)\n if (result.ok) return result.value\n\n checkTotalTimeout(totalAbort, resolved.timeout.totalTimeoutMs, errors)\n\n // eslint-disable-next-line no-await-in-loop\n const decision = await handleAttemptError(result.error, attempt, maxRetries, retryAll, resolved, totalAbort)\n if (decision === 'next-model') break\n }\n }\n\n // All models exhausted\n throw new A3ResilienceError(\n `All models failed after ${errors.length} total attempt(s): ${models.join(', ')}`,\n errors,\n )\n } finally {\n if (totalTimer !== undefined) {\n clearTimeout(totalTimer)\n }\n }\n}\n","import { createOpenAI } from '@ai-sdk/openai'\nimport { generateText, streamText, Output, ModelMessage, jsonSchema } from 'ai'\nimport {\n resolveResilienceConfig,\n type Provider,\n type ProviderRequest,\n type ProviderResponse,\n type ProviderMessage,\n type BaseState,\n type StreamEvent,\n type ResilienceConfig,\n type ResolvedResilienceConfig,\n} from '@genui-a3/core'\nimport { processOpenAIStream } from './streamProcessor'\nimport { executeWithFallback } from '@providers/utils/executeWithFallback'\n\n/**\n * Configuration for creating an OpenAI provider.\n */\nexport interface OpenAIProviderConfig {\n /** OpenAI API key. Defaults to OPENAI_API_KEY env var (OpenAI SDK default). */\n apiKey?: string\n /**\n * Model identifiers in order of preference (first = primary, rest = fallbacks).\n * e.g. ['gpt-4o', 'gpt-4o-mini']\n */\n models: string[]\n /** Optional base URL for Azure OpenAI or compatible endpoints */\n baseURL?: string\n /** Optional OpenAI organization ID */\n organization?: string\n /** Resilience configuration (retry, backoff, timeout). Uses industry-standard defaults if omitted. */\n resilience?: ResilienceConfig\n}\n\ntype JsonSchema = Record<string, unknown>\n\n/**\n * Enforces strict JSON schema constraints required by OpenAI's structured output API.\n * OpenAI requires all object properties — including optional ones — to be in the `required` array.\n * This function recursively adds `required` and `additionalProperties: false` to all objects.\n *\n * @param schema - JSON schema to enforce\n * @returns Enforced JSON schema\n */\nfunction enforceStrictSchema(schema: JsonSchema): JsonSchema {\n const result = { ...schema }\n if (result.type === 'object' && result.properties) {\n result.additionalProperties = false\n result.required = Object.keys(result.properties as Record<string, unknown>)\n const props = result.properties as Record<string, JsonSchema>\n const strictProps: Record<string, JsonSchema> = {}\n for (const [key, value] of Object.entries(props)) {\n strictProps[key] = enforceStrictSchema(value)\n }\n result.properties = strictProps\n }\n if (result.items && typeof result.items === 'object') {\n result.items = enforceStrictSchema(result.items as JsonSchema)\n }\n for (const keyword of ['anyOf', 'oneOf', 'allOf'] as const) {\n if (Array.isArray(result[keyword])) {\n result[keyword] = (result[keyword] as JsonSchema[]).map((s) => enforceStrictSchema(s))\n }\n }\n return result\n}\n\n/**\n * Converts a Zod schema to an OpenAI-compatible strict JSON schema wrapped for the Vercel AI SDK.\n *\n * @param zodSchema - Zod schema to convert\n * @returns JSON schema wrapped for Vercel AI SDK\n */\nfunction toOpenAISchema(zodSchema: ProviderRequest['responseSchema']) {\n const strict = enforceStrictSchema(zodSchema.toJSONSchema() as JsonSchema)\n return jsonSchema(strict as never, {\n validate: (value: unknown) => {\n const result = zodSchema.safeParse(value)\n return result.success\n ? { success: true as const, value: result.data }\n : { success: false as const, error: result.error }\n },\n })\n}\n\nfunction toAIMessages(messages: ProviderMessage[]): ModelMessage[] {\n return messages.map((msg) => ({\n role: msg.role,\n content: msg.content,\n }))\n}\n\nasync function sendWithModel(\n openaiProvider: ReturnType<typeof createOpenAI>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n): Promise<ProviderResponse> {\n const result = await generateText({\n model: openaiProvider(model),\n system,\n messages,\n output: Output.object({ schema: toOpenAISchema(schema) }),\n })\n\n return {\n content: JSON.stringify(result.output),\n usage: {\n inputTokens: result.usage.inputTokens ?? 0,\n outputTokens: result.usage.outputTokens ?? 0,\n totalTokens: (result.usage.inputTokens ?? 0) + (result.usage.outputTokens ?? 0),\n },\n }\n}\n\nasync function sendStreamWithModel(\n openaiProvider: ReturnType<typeof createOpenAI>,\n model: string,\n system: string,\n messages: ModelMessage[],\n schema: ProviderRequest['responseSchema'],\n) {\n const result = streamText({\n model: openaiProvider(model),\n system,\n messages,\n output: Output.object({ schema: toOpenAISchema(schema) }),\n })\n\n // Force the API call to start so executeWithFallback can catch connection errors\n const partialStream = result.partialOutputStream\n const reader = partialStream[Symbol.asyncIterator]()\n const first = await reader.next()\n\n return { result, reader, first }\n}\n\n/**\n * Creates an OpenAI provider instance.\n *\n * Uses the Vercel AI SDK (`ai` + `@ai-sdk/openai`) for structured output via\n * `generateText` + `Output.object()` (blocking) and `streamText` + `Output.object()`\n * (streaming). The AI SDK handles Zod-to-JSON-schema conversion, partial JSON\n * parsing, and validation internally.\n *\n * @param config - OpenAI provider configuration\n * @returns A Provider implementation using OpenAI\n *\n * @example\n * ```typescript\n * const provider = createOpenAIProvider({\n * models: ['gpt-4o', 'gpt-4o-mini'],\n * })\n * ```\n */\nexport function createOpenAIProvider(config: OpenAIProviderConfig): Provider {\n const openaiProvider = createOpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseURL,\n organization: config.organization,\n })\n const models = config.models\n const resilience: ResolvedResilienceConfig = resolveResilienceConfig(config.resilience)\n\n return {\n name: 'openai',\n\n async sendRequest(request: ProviderRequest): Promise<ProviderResponse> {\n const messages = toAIMessages(request.messages)\n\n return executeWithFallback(\n models,\n (model) => sendWithModel(openaiProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n },\n\n async *sendRequestStream<TState extends BaseState = BaseState>(\n request: ProviderRequest,\n ): AsyncGenerator<StreamEvent<TState>> {\n const messages = toAIMessages(request.messages)\n\n const { result, reader, first } = await executeWithFallback(\n models,\n (model) => sendStreamWithModel(openaiProvider, model, request.systemPrompt, messages, request.responseSchema),\n resilience,\n )\n\n yield* processOpenAIStream<TState>(result, reader, first, 'openai', request.responseSchema)\n },\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genui-a3/providers",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Provider implementations for the A3 agentic framework",
5
5
  "type": "module",
6
6
  "exports": {