adk-llm-bridge 0.5.0 → 0.5.1

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.
Files changed (62) hide show
  1. package/dist/config.d.ts +1 -1
  2. package/dist/converters/index.d.ts +2 -2
  3. package/dist/converters/response.d.ts +1 -1
  4. package/dist/core/base-provider-llm.d.ts +1 -1
  5. package/dist/core/config-resolver.d.ts +2 -2
  6. package/dist/core/create-provider.d.ts +3 -3
  7. package/dist/core/create-register.d.ts +1 -1
  8. package/dist/core/index.d.ts +8 -8
  9. package/dist/core/openai-compatible-llm.d.ts +3 -3
  10. package/dist/index.d.ts +14 -14
  11. package/dist/index.js +2 -6
  12. package/dist/index.js.map +3 -29
  13. package/dist/providers/ai-gateway/definition.d.ts +1 -1
  14. package/dist/providers/ai-gateway/index.d.ts +2 -2
  15. package/dist/providers/anthropic/anthropic-llm.d.ts +2 -2
  16. package/dist/providers/anthropic/index.d.ts +7 -7
  17. package/dist/providers/custom/custom-llm.d.ts +2 -2
  18. package/dist/providers/custom/factory.d.ts +2 -2
  19. package/dist/providers/custom/index.d.ts +2 -2
  20. package/dist/providers/index.d.ts +6 -6
  21. package/dist/providers/openai/definition.d.ts +1 -1
  22. package/dist/providers/openai/index.d.ts +2 -2
  23. package/dist/providers/openrouter/definition.d.ts +1 -1
  24. package/dist/providers/openrouter/index.d.ts +2 -2
  25. package/dist/providers/xai/definition.d.ts +1 -1
  26. package/dist/providers/xai/index.d.ts +2 -2
  27. package/dist/utils/index.d.ts +2 -2
  28. package/package.json +2 -2
  29. package/dist/providers/ai-gateway/ai-gateway-llm.d.ts +0 -71
  30. package/dist/providers/ai-gateway/ai-gateway-llm.d.ts.map +0 -1
  31. package/dist/providers/ai-gateway/factory.d.ts +0 -56
  32. package/dist/providers/ai-gateway/factory.d.ts.map +0 -1
  33. package/dist/providers/ai-gateway/register.d.ts +0 -63
  34. package/dist/providers/ai-gateway/register.d.ts.map +0 -1
  35. package/dist/providers/anthropic/constants.d.ts +0 -36
  36. package/dist/providers/anthropic/constants.d.ts.map +0 -1
  37. package/dist/providers/anthropic/factory.d.ts +0 -60
  38. package/dist/providers/anthropic/factory.d.ts.map +0 -1
  39. package/dist/providers/anthropic/register.d.ts +0 -65
  40. package/dist/providers/anthropic/register.d.ts.map +0 -1
  41. package/dist/providers/openai/constants.d.ts +0 -34
  42. package/dist/providers/openai/constants.d.ts.map +0 -1
  43. package/dist/providers/openai/factory.d.ts +0 -61
  44. package/dist/providers/openai/factory.d.ts.map +0 -1
  45. package/dist/providers/openai/openai-llm.d.ts +0 -69
  46. package/dist/providers/openai/openai-llm.d.ts.map +0 -1
  47. package/dist/providers/openai/register.d.ts +0 -65
  48. package/dist/providers/openai/register.d.ts.map +0 -1
  49. package/dist/providers/openrouter/factory.d.ts +0 -61
  50. package/dist/providers/openrouter/factory.d.ts.map +0 -1
  51. package/dist/providers/openrouter/openrouter-llm.d.ts +0 -97
  52. package/dist/providers/openrouter/openrouter-llm.d.ts.map +0 -1
  53. package/dist/providers/openrouter/register.d.ts +0 -62
  54. package/dist/providers/openrouter/register.d.ts.map +0 -1
  55. package/dist/providers/xai/constants.d.ts +0 -30
  56. package/dist/providers/xai/constants.d.ts.map +0 -1
  57. package/dist/providers/xai/factory.d.ts +0 -54
  58. package/dist/providers/xai/factory.d.ts.map +0 -1
  59. package/dist/providers/xai/register.d.ts +0 -64
  60. package/dist/providers/xai/register.d.ts.map +0 -1
  61. package/dist/providers/xai/xai-llm.d.ts +0 -66
  62. package/dist/providers/xai/xai-llm.d.ts.map +0 -1
package/dist/config.d.ts CHANGED
@@ -34,7 +34,7 @@
34
34
  * });
35
35
  * ```
36
36
  */
37
- import type { AnthropicRegisterOptions, OpenAIRegisterOptions, OpenRouterRegisterOptions, RegisterOptions, XAIRegisterOptions } from "./types";
37
+ import type { AnthropicRegisterOptions, OpenAIRegisterOptions, OpenRouterRegisterOptions, RegisterOptions, XAIRegisterOptions } from "./types.js";
38
38
  /**
39
39
  * Mapping of provider identifiers to their configuration types.
40
40
  *
@@ -27,6 +27,6 @@
27
27
  * const adkResponse = convertResponse(openaiResponse);
28
28
  * ```
29
29
  */
30
- export { convertRequest } from "./request";
31
- export { convertResponse, convertStreamChunk, createStreamAccumulator, } from "./response";
30
+ export { convertRequest } from "./request.js";
31
+ export { convertResponse, convertStreamChunk, createStreamAccumulator, } from "./response.js";
32
32
  //# sourceMappingURL=index.d.ts.map
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import type { LlmResponse } from "@google/adk";
15
15
  import type OpenAI from "openai";
16
- import type { StreamAccumulator, StreamChunkResult } from "../types";
16
+ import type { StreamAccumulator, StreamChunkResult } from "../types.js";
17
17
  /**
18
18
  * Converts an OpenAI chat completion response to ADK LlmResponse format.
19
19
  *
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import type { BaseLlmConnection, LlmRequest, LlmResponse } from "@google/adk";
15
15
  import { BaseLlm } from "@google/adk";
16
- import type { BaseProviderConfig } from "../types";
16
+ import type { BaseProviderConfig } from "../types.js";
17
17
  /**
18
18
  * Abstract base class for all LLM providers in adk-llm-bridge.
19
19
  *
@@ -3,8 +3,8 @@
3
3
  * Copyright 2025 PAI
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
- import type { BaseProviderConfig } from "../types";
7
- import type { ProviderDefinition } from "./provider-definition";
6
+ import type { BaseProviderConfig } from "../types.js";
7
+ import type { ProviderDefinition } from "./provider-definition.js";
8
8
  /**
9
9
  * Fully resolved configuration ready to create an OpenAI client.
10
10
  */
@@ -10,9 +10,9 @@
10
10
  * @module core/create-provider
11
11
  */
12
12
  import type { BaseLlm } from "@google/adk";
13
- import type { BaseProviderConfig } from "../types";
14
- import { OpenAICompatibleLlm } from "./openai-compatible-llm";
15
- import type { ProviderDefinition } from "./provider-definition";
13
+ import type { BaseProviderConfig } from "../types.js";
14
+ import { OpenAICompatibleLlm } from "./openai-compatible-llm.js";
15
+ import type { ProviderDefinition } from "./provider-definition.js";
16
16
  /** Type compatible with LLMRegistry.register(). */
17
17
  type RegisterableLlm = (new (params: {
18
18
  model: string;
@@ -12,7 +12,7 @@
12
12
  * @module core/create-register
13
13
  */
14
14
  import type { BaseLlm } from "@google/adk";
15
- import type { ProviderDefinition } from "./provider-definition";
15
+ import type { ProviderDefinition } from "./provider-definition.js";
16
16
  /** Type that LLMRegistry.register() expects. */
17
17
  type RegisterableLlm = (new (params: {
18
18
  model: string;
@@ -35,12 +35,12 @@
35
35
  * }
36
36
  * ```
37
37
  */
38
- export { BaseProviderLlm } from "./base-provider-llm";
39
- export { resolveConfig, resolveEnvVar } from "./config-resolver";
40
- export type { ResolvedConfig } from "./config-resolver";
41
- export { createProviderClass, createProviderFactory } from "./create-provider";
42
- export { createRegisterFunction } from "./create-register";
43
- export type { OpenAIClientConfig } from "./openai-compatible-llm";
44
- export { OpenAICompatibleLlm } from "./openai-compatible-llm";
45
- export type { ProviderDefinition, ProviderEnvKeys, } from "./provider-definition";
38
+ export { BaseProviderLlm } from "./base-provider-llm.js";
39
+ export { resolveConfig, resolveEnvVar } from "./config-resolver.js";
40
+ export type { ResolvedConfig } from "./config-resolver.js";
41
+ export { createProviderClass, createProviderFactory } from "./create-provider.js";
42
+ export { createRegisterFunction } from "./create-register.js";
43
+ export type { OpenAIClientConfig } from "./openai-compatible-llm.js";
44
+ export { OpenAICompatibleLlm } from "./openai-compatible-llm.js";
45
+ export type { ProviderDefinition, ProviderEnvKeys, } from "./provider-definition.js";
46
46
  //# sourceMappingURL=index.d.ts.map
@@ -15,9 +15,9 @@
15
15
  */
16
16
  import type { LlmRequest, LlmResponse } from "@google/adk";
17
17
  import OpenAI from "openai";
18
- import type { BaseProviderConfig } from "../types";
19
- import { BaseProviderLlm } from "./base-provider-llm";
20
- import type { ProviderDefinition } from "./provider-definition";
18
+ import type { BaseProviderConfig } from "../types.js";
19
+ import { BaseProviderLlm } from "./base-provider-llm.js";
20
+ import type { ProviderDefinition } from "./provider-definition.js";
21
21
  /**
22
22
  * Configuration for the underlying OpenAI client.
23
23
  *
package/dist/index.d.ts CHANGED
@@ -58,18 +58,18 @@
58
58
  * @see {@link https://google.github.io/adk-docs/|Google ADK Documentation}
59
59
  */
60
60
  export { BaseLlm } from "@google/adk";
61
- export { BaseProviderLlm } from "./core/base-provider-llm";
62
- export type { OpenAIClientConfig } from "./core/openai-compatible-llm";
63
- export { OpenAICompatibleLlm } from "./core/openai-compatible-llm";
64
- export { AIGateway, AIGatewayLlm, isAIGatewayRegistered, registerAIGateway, } from "./providers/ai-gateway";
65
- export { isOpenRouterRegistered, OpenRouter, OpenRouterLlm, registerOpenRouter, } from "./providers/openrouter";
66
- export { isOpenAIRegistered, OpenAI, OpenAILlm, registerOpenAI, } from "./providers/openai";
67
- export { isXAIRegistered, registerXAI, XAI, XAILlm } from "./providers/xai";
68
- export { Anthropic, AnthropicLlm, isAnthropicRegistered, registerAnthropic, } from "./providers/anthropic";
69
- export { Custom, CustomLlm, type CustomLlmProviderConfig, createCustomLlm, } from "./providers/custom";
70
- export type { AIGatewayConfig, AnthropicProviderConfig, AnthropicRegisterOptions, BaseProviderConfig, CustomLlmConfig, OpenAIProviderConfig, OpenAIRegisterOptions, OpenRouterConfig, OpenRouterProviderPreferences, OpenRouterRegisterOptions, RegisterOptions, StreamAccumulator, StreamChunkResult, ToolCallAccumulator, XAIProviderConfig, XAIRegisterOptions, } from "./types";
71
- export { DEFAULT_BASE_URL, MODEL_PATTERNS, OPENROUTER_BASE_URL, OPENROUTER_MODEL_PATTERNS, PROVIDER_IDS, } from "./constants";
72
- export { getConfig, getProviderConfig, resetAllConfigs, resetConfig, resetProviderConfig, setConfig, setProviderConfig, } from "./config";
73
- export { convertRequest } from "./converters/request";
74
- export { convertResponse, convertStreamChunk, createStreamAccumulator, } from "./converters/response";
61
+ export { BaseProviderLlm } from "./core/base-provider-llm.js";
62
+ export type { OpenAIClientConfig } from "./core/openai-compatible-llm.js";
63
+ export { OpenAICompatibleLlm } from "./core/openai-compatible-llm.js";
64
+ export { AIGateway, AIGatewayLlm, isAIGatewayRegistered, registerAIGateway, } from "./providers/ai-gateway/index.js";
65
+ export { isOpenRouterRegistered, OpenRouter, OpenRouterLlm, registerOpenRouter, } from "./providers/openrouter/index.js";
66
+ export { isOpenAIRegistered, OpenAI, OpenAILlm, registerOpenAI, } from "./providers/openai/index.js";
67
+ export { isXAIRegistered, registerXAI, XAI, XAILlm } from "./providers/xai/index.js";
68
+ export { Anthropic, AnthropicLlm, isAnthropicRegistered, registerAnthropic, } from "./providers/anthropic/index.js";
69
+ export { Custom, CustomLlm, type CustomLlmProviderConfig, createCustomLlm, } from "./providers/custom/index.js";
70
+ export type { AIGatewayConfig, AnthropicProviderConfig, AnthropicRegisterOptions, BaseProviderConfig, CustomLlmConfig, OpenAIProviderConfig, OpenAIRegisterOptions, OpenRouterConfig, OpenRouterProviderPreferences, OpenRouterRegisterOptions, RegisterOptions, StreamAccumulator, StreamChunkResult, ToolCallAccumulator, XAIProviderConfig, XAIRegisterOptions, } from "./types.js";
71
+ export { DEFAULT_BASE_URL, MODEL_PATTERNS, OPENROUTER_BASE_URL, OPENROUTER_MODEL_PATTERNS, PROVIDER_IDS, } from "./constants.js";
72
+ export { getConfig, getProviderConfig, resetAllConfigs, resetConfig, resetProviderConfig, setConfig, setProviderConfig, } from "./config.js";
73
+ export { convertRequest } from "./converters/request.js";
74
+ export { convertResponse, convertStreamChunk, createStreamAccumulator, } from "./converters/response.js";
75
75
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,8 +1,4 @@
1
- import{BaseLlm as BaseLlm2}from"@google/adk";import{BaseLlm}from"@google/adk";class BaseProviderLlm extends BaseLlm{config;constructor(config){if(!config.model?.trim())throw Error("[adk-llm-bridge] model is required and cannot be empty.");super({model:config.model});this.config=config}async connect(_){throw Error(`${this.constructor.name} does not support bidirectional streaming`)}createErrorResponse(error,prefix){return{errorCode:error!==null&&typeof error==="object"&&"status"in error&&typeof error.status==="number"?`API_ERROR_${error.status}`:`${prefix}_ERROR`,errorMessage:error instanceof Error?error.message:String(error),turnComplete:!0}}}import OpenAI from"openai";function convertRequest(llmRequest){let messages=[],systemContent=extractSystemInstruction(llmRequest);if(systemContent)messages.push({role:"system",content:systemContent});for(let content of llmRequest.contents??[])processContent(content,messages);return{messages,tools:convertTools(llmRequest)}}function extractSystemInstruction(req){let sys=req.config?.systemInstruction;if(!sys)return null;if(typeof sys==="string")return sys;if("parts"in sys)return extractText(sys.parts??[]);return null}function extractText(parts){return parts.map((p)=>p.text).filter(Boolean).join(`
2
- `)}function processContent(content,messages){if(!content.parts?.length)return;let texts=[],calls=[],responses=[];for(let part of content.parts){if(part.text)texts.push(part.text);if(part.functionCall){if(!part.functionCall.id)console.warn("[adk-llm-bridge] functionCall missing id, using generated ID");if(!part.functionCall.name)console.warn("[adk-llm-bridge] functionCall missing name");calls.push({id:part.functionCall.id??`call_${Date.now()}`,name:part.functionCall.name??"",arguments:JSON.stringify(part.functionCall.args??{})})}if(part.functionResponse){if(!part.functionResponse.id)console.warn("[adk-llm-bridge] functionResponse missing id");responses.push({id:part.functionResponse.id??"",content:JSON.stringify(part.functionResponse.response??{})})}}if(content.role==="user"){if(texts.length)messages.push({role:"user",content:texts.join(`
3
- `)});for(let r of responses)messages.push({role:"tool",tool_call_id:r.id,content:r.content})}else if(content.role==="model"){if(texts.length||calls.length){let msg={role:"assistant",content:texts.length?texts.join(`
4
- `):null};if(calls.length)msg.tool_calls=calls.map((c)=>({id:c.id,type:"function",function:{name:c.name,arguments:c.arguments}}));messages.push(msg)}}}function convertTools(req){let adkTools=req.config?.tools;if(!adkTools?.length)return;let tools=[];for(let group of adkTools)if("functionDeclarations"in group&&Array.isArray(group.functionDeclarations))for(let fn of group.functionDeclarations){if(!fn.name){console.warn("[adk-llm-bridge] Tool function missing name, skipping");continue}tools.push({type:"function",function:{name:fn.name,description:fn.description??"",parameters:normalizeSchema(fn.parameters)??{type:"object",properties:{}}}})}return tools.length?tools:void 0}function normalizeSchema(schema){if(!schema||typeof schema!=="object")return;let result={},input=schema;for(let[key,value]of Object.entries(input))if(key==="type"&&typeof value==="string")result[key]=value.toLowerCase();else if(typeof value==="object"&&value!==null&&!Array.isArray(value))result[key]=normalizeSchema(value);else if(Array.isArray(value))result[key]=value;else result[key]=value;return result}function safeJsonParse(str){if(!str||typeof str!=="string")return{};try{let safe=str.replace(/([:[,])\s*(-?\d{17,})(?!\.\d)(?=\s*[,\]}])/g,(_,delimiter,num)=>`${delimiter} "${num}"`);return JSON.parse(safe)}catch{return{}}}function requireValidURL(value,field,context){try{return new URL(value),value}catch{throw Error(`[${context}] Invalid ${field}: "${value}". Must be a valid URL (e.g., http://localhost:11434/v1).`)}}function clampPositive(value,fallback,min=0){return Math.max(Number.isFinite(value)?value:fallback,min)}function convertResponse(response){let choice=response.choices[0];if(!choice)return{errorCode:"NO_CHOICE",errorMessage:"No response choice",turnComplete:!0};let parts=[];if(choice.message.content)parts.push({text:choice.message.content});for(let tc of choice.message.tool_calls??[]){if(tc.type!=="function")continue;parts.push({functionCall:{id:tc.id,name:tc.function.name,args:safeJsonParse(tc.function.arguments)}})}return{content:parts.length?{role:"model",parts}:void 0,turnComplete:!0,usageMetadata:response.usage?{promptTokenCount:response.usage.prompt_tokens,candidatesTokenCount:response.usage.completion_tokens,totalTokenCount:response.usage.total_tokens}:void 0}}function convertStreamChunk(chunk,acc){let choice=chunk.choices[0];if(!choice)return{isComplete:!1};let delta=choice.delta;if(delta?.content)return acc.text+=delta.content,{response:{content:{role:"model",parts:[{text:delta.content}]},partial:!0},isComplete:!1};if(delta?.tool_calls)for(let tc of delta.tool_calls){let idx=tc.index??acc.toolCalls.size,a=acc.toolCalls.get(idx);if(!a)a={id:"",name:"",arguments:""},acc.toolCalls.set(idx,a);if(tc.id)a.id=tc.id;if(tc.function?.name)a.name+=tc.function.name;if(tc.function?.arguments)a.arguments+=tc.function.arguments}if(choice.finish_reason){let parts=[];if(acc.text)parts.push({text:acc.text});for(let tc of Array.from(acc.toolCalls.values()))if(tc.name)parts.push({functionCall:{id:tc.id,name:tc.name,args:safeJsonParse(tc.arguments)}});return acc.text="",acc.toolCalls.clear(),{response:{content:parts.length?{role:"model",parts}:void 0,turnComplete:!0},isComplete:!0}}return{isComplete:!1}}function createStreamAccumulator(){return{text:"",toolCalls:new Map}}var configs={};function setProviderConfig(provider,options){configs[provider]={...options}}function getProviderConfig(provider){return configs[provider]}function resetProviderConfig(provider){delete configs[provider]}function resetAllConfigs(){for(let key of Object.keys(configs))delete configs[key]}function setConfig(options){setProviderConfig("ai-gateway",options)}function getConfig(){return getProviderConfig("ai-gateway")??{}}function resetConfig(){resetProviderConfig("ai-gateway")}var DEFAULT_BASE_URL="https://ai-gateway.vercel.sh/v1",DEFAULT_TIMEOUT=60000,DEFAULT_MAX_RETRIES=2,MODEL_PATTERNS=[/.+\/.+/];var OPENROUTER_BASE_URL="https://openrouter.ai/api/v1",OPENROUTER_MODEL_PATTERNS=[/.+\/.+/];var PROVIDER_IDS={AI_GATEWAY:"ai-gateway",OPENROUTER:"openrouter"};function resolveEnvVar(keys){for(let key of keys){let value=process.env[key];if(value)return value}return}function resolveConfig(definition,instanceConfig){let globalConfig=getProviderConfig(definition.id)??{},apiKey=instanceConfig.apiKey??globalConfig.apiKey??resolveEnvVar(definition.envKeys.apiKey)??"";if(definition.requireApiKey&&!apiKey){let envHint=definition.envKeys.apiKey.join(" or ");throw Error(`[${definition.id}] API key is required. Provide it via config, setProviderConfig("${definition.id}", { apiKey }), or set the ${envHint} env var.`)}let baseURL=instanceConfig.baseURL??globalConfig.baseURL??resolveEnvVar(definition.envKeys.baseURL??[])??definition.defaultBaseURL;requireValidURL(baseURL,"baseURL",definition.id);let headers=definition.buildHeaders?.({...globalConfig,...instanceConfig})??{};return{apiKey,baseURL,timeout:clampPositive(instanceConfig.timeout??DEFAULT_TIMEOUT,DEFAULT_TIMEOUT,1000),maxRetries:clampPositive(instanceConfig.maxRetries??DEFAULT_MAX_RETRIES,DEFAULT_MAX_RETRIES,0),headers}}class OpenAICompatibleLlm extends BaseProviderLlm{static supportedModels=[];client;_errorPrefix;_getRequestOptions;constructor(first,second){if("id"in first&&"model"in second){let definition=first,config=second;super(config);this._errorPrefix=definition.errorPrefix;let resolved=resolveConfig(definition,config);if(this.client=new OpenAI({baseURL:resolved.baseURL,apiKey:resolved.apiKey,timeout:resolved.timeout,maxRetries:resolved.maxRetries,defaultHeaders:Object.keys(resolved.headers).length?resolved.headers:void 0}),definition.buildRequestOptions){let buildFn=definition.buildRequestOptions,configRef=config;this._getRequestOptions=()=>buildFn(configRef)}}else{let config=first,clientConfig=second;super(config);this._errorPrefix="CUSTOM",this.client=new OpenAI({baseURL:clientConfig.baseURL,apiKey:clientConfig.apiKey,timeout:clientConfig.timeout,maxRetries:clientConfig.maxRetries,defaultHeaders:clientConfig.defaultHeaders})}}getErrorPrefix(){return this._errorPrefix}getProviderRequestOptions(){return this._getRequestOptions?.()??{}}async*generateContentAsync(llmRequest,stream=!1){try{let{messages,tools}=convertRequest(llmRequest);if(stream)yield*this.streamResponse(messages,tools);else yield await this.singleResponse(messages,tools)}catch(error){yield this.createErrorResponse(error,this.getErrorPrefix())}}async singleResponse(messages,tools){let response=await this.client.chat.completions.create({model:this.model,messages,...tools?.length?{tools}:{},...this.getProviderRequestOptions()});return convertResponse(response)}async*streamResponse(messages,tools){let stream=await this.client.chat.completions.create({model:this.model,messages,stream:!0,...tools?.length?{tools}:{},...this.getProviderRequestOptions()}),acc=createStreamAccumulator();for await(let chunk of stream){let{response,isComplete}=convertStreamChunk(chunk,acc);if(response)yield response;if(isComplete)break}}}function createProviderClass(definition){return class extends OpenAICompatibleLlm{static supportedModels=definition.modelPatterns;constructor(config){super(definition,config)}}}function createProviderFactory(definition){return(model,options)=>new OpenAICompatibleLlm(definition,{model,...options})}import{LLMRegistry}from"@google/adk";function createRegisterFunction(definition,ProviderClass){let registered=!1;return{register(options){if(registered){console.warn(`[adk-llm-bridge] ${definition.id} already registered, skipping`);return}if(options)setProviderConfig(definition.id,options);LLMRegistry.register(ProviderClass),registered=!0},isRegistered(){return registered},_reset(){registered=!1,resetProviderConfig(definition.id)}}}var AI_GATEWAY_DEFINITION={id:"ai-gateway",errorPrefix:"AI_GATEWAY",defaultBaseURL:"https://ai-gateway.vercel.sh/v1",envKeys:{apiKey:["AI_GATEWAY_API_KEY","OPENAI_API_KEY"],baseURL:["AI_GATEWAY_URL","OPENAI_BASE_URL"]},modelPatterns:[/.+\/.+/],requireApiKey:!0};var AIGatewayLlm=createProviderClass(AI_GATEWAY_DEFINITION),AIGateway=createProviderFactory(AI_GATEWAY_DEFINITION),reg=createRegisterFunction(AI_GATEWAY_DEFINITION,AIGatewayLlm),registerAIGateway=reg.register,isAIGatewayRegistered=reg.isRegistered,_resetAIGatewayRegistration=reg._reset;var OPENROUTER_DEFINITION={id:"openrouter",errorPrefix:"OPENROUTER",defaultBaseURL:"https://openrouter.ai/api/v1",envKeys:{apiKey:["OPENROUTER_API_KEY"]},modelPatterns:[/.+\/.+/],requireApiKey:!0,buildHeaders:(config)=>{let headers={},siteUrl=config.siteUrl??process.env.OPENROUTER_SITE_URL,appName=config.appName??process.env.OPENROUTER_APP_NAME;if(siteUrl)headers["HTTP-Referer"]=siteUrl;if(appName)headers["X-Title"]=appName;return headers},buildRequestOptions:(config)=>{let provider=config.provider;return provider?{provider}:{}}};var OpenRouterLlm=createProviderClass(OPENROUTER_DEFINITION),OpenRouter=createProviderFactory(OPENROUTER_DEFINITION),reg2=createRegisterFunction(OPENROUTER_DEFINITION,OpenRouterLlm),registerOpenRouter=reg2.register,isOpenRouterRegistered=reg2.isRegistered,_resetOpenRouterRegistration=reg2._reset;var OPENAI_DEFINITION={id:"openai",errorPrefix:"OPENAI",defaultBaseURL:"https://api.openai.com/v1",envKeys:{apiKey:["OPENAI_API_KEY"]},modelPatterns:[/gpt-.+/,/o\d+.*/,/chatgpt-.+/],requireApiKey:!0,buildHeaders:(config)=>{let headers={},org=config.organization??process.env.OPENAI_ORGANIZATION,proj=config.project??process.env.OPENAI_PROJECT;if(org)headers["OpenAI-Organization"]=org;if(proj)headers["OpenAI-Project"]=proj;return headers}};var OpenAILlm=createProviderClass(OPENAI_DEFINITION),OpenAI2=createProviderFactory(OPENAI_DEFINITION),reg3=createRegisterFunction(OPENAI_DEFINITION,OpenAILlm),registerOpenAI=reg3.register,isOpenAIRegistered=reg3.isRegistered,_resetOpenAIRegistration=reg3._reset;var XAI_DEFINITION={id:"xai",errorPrefix:"XAI",defaultBaseURL:"https://api.x.ai/v1",envKeys:{apiKey:["XAI_API_KEY"]},modelPatterns:[/grok-.+/],requireApiKey:!0};var XAILlm=createProviderClass(XAI_DEFINITION),XAI=createProviderFactory(XAI_DEFINITION),reg4=createRegisterFunction(XAI_DEFINITION,XAILlm),registerXAI=reg4.register,isXAIRegistered=reg4.isRegistered,_resetXAIRegistration=reg4._reset;import{LLMRegistry as LLMRegistry2}from"@google/adk";import AnthropicSDK from"@anthropic-ai/sdk";function convertAnthropicRequest(llmRequest){let messages=[],system=extractSystemInstruction2(llmRequest);for(let content of llmRequest.contents??[]){let msg=processContent2(content);if(msg)messages.push(msg)}if(messages.length>0&&messages[0].role!=="user")messages.unshift({role:"user",content:"[System: Continue conversation]"});return{messages,system:system||void 0,tools:convertTools2(llmRequest)}}function extractSystemInstruction2(req){let sys=req.config?.systemInstruction;if(!sys)return null;if(typeof sys==="string")return sys;if("parts"in sys)return extractText2(sys.parts??[]);return null}function extractText2(parts){return parts.map((p)=>p.text).filter(Boolean).join(`
5
- `)}function processContent2(content){if(!content.parts?.length)return null;let contentBlocks=[];for(let part of content.parts){if(part.text)contentBlocks.push({type:"text",text:part.text});if(part.functionCall){if(!part.functionCall.id)console.warn("[adk-llm-bridge] functionCall missing id, using generated ID");if(!part.functionCall.name)console.warn("[adk-llm-bridge] functionCall missing name");contentBlocks.push({type:"tool_use",id:part.functionCall.id??crypto.randomUUID(),name:part.functionCall.name??"",input:part.functionCall.args??{}})}if(part.functionResponse){if(!part.functionResponse.id)console.warn("[adk-llm-bridge] functionResponse missing id, using generated ID");contentBlocks.push({type:"tool_result",tool_use_id:part.functionResponse.id??crypto.randomUUID(),content:JSON.stringify(part.functionResponse.response??{})})}}if(contentBlocks.length===0)return null;return{role:content.role==="model"?"assistant":"user",content:contentBlocks}}function convertTools2(req){let adkTools=req.config?.tools;if(!adkTools?.length)return;let tools=[];for(let group of adkTools)if("functionDeclarations"in group&&Array.isArray(group.functionDeclarations))for(let fn of group.functionDeclarations){if(!fn.name){console.warn("[adk-llm-bridge] Tool function missing name, skipping");continue}tools.push({name:fn.name,description:fn.description??"",input_schema:normalizeSchema2(fn.parameters)??{type:"object",properties:{}}})}return tools.length?tools:void 0}function normalizeSchema2(schema){if(!schema||typeof schema!=="object")return;let result={},input=schema;for(let[key,value]of Object.entries(input))if(key==="type"&&typeof value==="string")result[key]=value.toLowerCase();else if(typeof value==="object"&&value!==null&&!Array.isArray(value))result[key]=normalizeSchema2(value);else if(Array.isArray(value))result[key]=value;else result[key]=value;return result}function convertAnthropicResponse(message){let parts=[];for(let block of message.content){if(block.type==="text")parts.push({text:block.text});if(block.type==="tool_use"){let input=typeof block.input==="object"&&block.input!==null?block.input:{};parts.push({functionCall:{id:block.id,name:block.name,args:input}})}}return{content:parts.length?{role:"model",parts}:void 0,turnComplete:!0,usageMetadata:message.usage?{promptTokenCount:message.usage.input_tokens,candidatesTokenCount:message.usage.output_tokens,totalTokenCount:message.usage.input_tokens+message.usage.output_tokens}:void 0}}function createAnthropicStreamAccumulator(){return{text:"",toolUses:new Map,currentBlockIndex:-1,inputTokens:void 0,outputTokens:void 0}}function convertAnthropicStreamEvent(event,acc){switch(event.type){case"message_start":{if(event.message?.usage?.input_tokens)acc.inputTokens=event.message.usage.input_tokens;return{isComplete:!1}}case"message_delta":{if(event.usage?.output_tokens)acc.outputTokens=event.usage.output_tokens;return{isComplete:!1}}case"content_block_start":{if(acc.currentBlockIndex=event.index,event.content_block.type==="tool_use")acc.toolUses.set(event.index,{id:event.content_block.id,name:event.content_block.name,input:""});return{isComplete:!1}}case"content_block_delta":{let delta=event.delta;if(delta.type==="text_delta")return acc.text+=delta.text,{response:{content:{role:"model",parts:[{text:delta.text}]},partial:!0},isComplete:!1};if(delta.type==="input_json_delta"){let toolUse=acc.toolUses.get(event.index);if(toolUse)toolUse.input+=delta.partial_json}return{isComplete:!1}}case"message_stop":{let parts=[];if(acc.text)parts.push({text:acc.text});for(let toolUse of acc.toolUses.values())if(toolUse.name)parts.push({functionCall:{id:toolUse.id,name:toolUse.name,args:safeJsonParse(toolUse.input)}});let usageMetadata=acc.inputTokens!==void 0||acc.outputTokens!==void 0?{promptTokenCount:acc.inputTokens??0,candidatesTokenCount:acc.outputTokens??0,totalTokenCount:(acc.inputTokens??0)+(acc.outputTokens??0)}:void 0;return acc.text="",acc.toolUses.clear(),acc.currentBlockIndex=-1,acc.inputTokens=void 0,acc.outputTokens=void 0,{response:{content:parts.length?{role:"model",parts}:void 0,turnComplete:!0,usageMetadata},isComplete:!0}}default:return{isComplete:!1}}}var ANTHROPIC_ENV={API_KEY:"ANTHROPIC_API_KEY"},DEFAULT_ANTHROPIC_MAX_TOKENS=4096,ANTHROPIC_MODEL_PATTERNS=[/claude-.*/];class AnthropicLlm extends BaseProviderLlm{static supportedModels=ANTHROPIC_MODEL_PATTERNS;client;maxTokens;constructor(config){super(config);let globalConfig=getProviderConfig("anthropic")??{},apiKey=config.apiKey??globalConfig.apiKey??process.env[ANTHROPIC_ENV.API_KEY]??"";if(!apiKey)throw Error('[anthropic] API key is required. Provide it via config, setProviderConfig("anthropic", { apiKey }), or set the ANTHROPIC_API_KEY env var.');this.maxTokens=clampPositive(config.maxTokens??globalConfig.maxTokens??DEFAULT_ANTHROPIC_MAX_TOKENS,DEFAULT_ANTHROPIC_MAX_TOKENS,1),this.client=new AnthropicSDK({apiKey,timeout:clampPositive(config.timeout??DEFAULT_TIMEOUT,DEFAULT_TIMEOUT,1000),maxRetries:clampPositive(config.maxRetries??DEFAULT_MAX_RETRIES,DEFAULT_MAX_RETRIES,0)})}async*generateContentAsync(llmRequest,stream=!1){try{let{messages,system,tools}=convertAnthropicRequest(llmRequest);if(stream)yield*this.streamResponse(messages,system,tools);else yield await this.singleResponse(messages,system,tools)}catch(error){yield this.createErrorResponse(error,"ANTHROPIC")}}buildRequestParams(messages,system,tools){return{model:this.model,max_tokens:this.maxTokens,messages,...system?{system}:{},...tools?.length?{tools}:{}}}async singleResponse(messages,system,tools){let response=await this.client.messages.create(this.buildRequestParams(messages,system,tools));return convertAnthropicResponse(response)}async*streamResponse(messages,system,tools){let stream=this.client.messages.stream(this.buildRequestParams(messages,system,tools)),acc=createAnthropicStreamAccumulator();for await(let event of stream){let{response,isComplete}=convertAnthropicStreamEvent(event,acc);if(response)yield response;if(isComplete)break}}}function Anthropic(model,options){return new AnthropicLlm({model,...options})}var registered=!1;function registerAnthropic(options){if(registered){console.warn("[adk-llm-bridge] anthropic already registered, skipping");return}if(options)setProviderConfig("anthropic",options);LLMRegistry2.register(AnthropicLlm),registered=!0}function isAnthropicRegistered(){return registered}class CustomLlm extends OpenAICompatibleLlm{static supportedModels=[/.*/];providerName;providerOptionsConfig;constructor(config){let providerName=config.name??"custom";requireValidURL(config.baseURL,"baseURL",providerName);let finalBaseURL=config.baseURL;if(config.queryParams&&Object.keys(config.queryParams).length>0){let url=new URL(config.baseURL);for(let[key,value]of Object.entries(config.queryParams))url.searchParams.append(key,value);finalBaseURL=url.toString()}super(config,{baseURL:finalBaseURL,apiKey:config.apiKey??"",timeout:clampPositive(config.timeout??DEFAULT_TIMEOUT,DEFAULT_TIMEOUT,1000),maxRetries:clampPositive(config.maxRetries??DEFAULT_MAX_RETRIES,DEFAULT_MAX_RETRIES,0),defaultHeaders:config.headers});this.providerName=config.name??"CUSTOM",this.providerOptionsConfig=config.providerOptions}getErrorPrefix(){return this.providerName.toUpperCase().replace(/[^A-Z0-9]/g,"_")||"CUSTOM"}getProviderRequestOptions(){return this.providerOptionsConfig??{}}}function createCustomLlm(config){return new CustomLlm(config)}function Custom(model,options){return createCustomLlm({model,...options})}export{setProviderConfig,setConfig,resetProviderConfig,resetConfig,resetAllConfigs,registerXAI,registerOpenRouter,registerOpenAI,registerAnthropic,registerAIGateway,isXAIRegistered,isOpenRouterRegistered,isOpenAIRegistered,isAnthropicRegistered,isAIGatewayRegistered,getProviderConfig,getConfig,createStreamAccumulator,createCustomLlm,convertStreamChunk,convertResponse,convertRequest,XAILlm,XAI,PROVIDER_IDS,OpenRouterLlm,OpenRouter,OpenAILlm,OpenAICompatibleLlm,OpenAI2 as OpenAI,OPENROUTER_MODEL_PATTERNS,OPENROUTER_BASE_URL,MODEL_PATTERNS,DEFAULT_BASE_URL,CustomLlm,Custom,BaseProviderLlm,BaseLlm2 as BaseLlm,AnthropicLlm,Anthropic,AIGatewayLlm,AIGateway};
1
+ export{setProviderConfig,setConfig,resetProviderConfig,resetConfig,resetAllConfigs,registerXAI,registerOpenRouter,registerOpenAI,registerAnthropic,registerAIGateway,isXAIRegistered,isOpenRouterRegistered,isOpenAIRegistered,isAnthropicRegistered,isAIGatewayRegistered,getProviderConfig,getConfig,createStreamAccumulator,createCustomLlm,convertStreamChunk,convertResponse,convertRequest,XAILlm,XAI,PROVIDER_IDS,OpenRouterLlm,OpenRouter,OpenAILlm,OpenAICompatibleLlm,OpenAI,OPENROUTER_MODEL_PATTERNS,OPENROUTER_BASE_URL,MODEL_PATTERNS,DEFAULT_BASE_URL,CustomLlm,Custom,BaseProviderLlm,BaseLlm,AnthropicLlm,Anthropic,AIGatewayLlm,AIGateway};
6
2
 
7
- //# debugId=50BA85D913D4D1B664756E2164756E21
3
+ //# debugId=5830DDF6248C5A4D64756E2164756E21
8
4
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,35 +1,9 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/index.ts", "../src/core/base-provider-llm.ts", "../src/core/openai-compatible-llm.ts", "../src/converters/request.ts", "../src/utils/json.ts", "../src/utils/validate.ts", "../src/converters/response.ts", "../src/config.ts", "../src/constants.ts", "../src/core/config-resolver.ts", "../src/core/create-provider.ts", "../src/core/create-register.ts", "../src/providers/ai-gateway/definition.ts", "../src/providers/ai-gateway/index.ts", "../src/providers/openrouter/definition.ts", "../src/providers/openrouter/index.ts", "../src/providers/openai/definition.ts", "../src/providers/openai/index.ts", "../src/providers/xai/definition.ts", "../src/providers/xai/index.ts", "../src/providers/anthropic/index.ts", "../src/providers/anthropic/anthropic-llm.ts", "../src/providers/anthropic/converters/request.ts", "../src/providers/anthropic/converters/response.ts", "../src/providers/custom/custom-llm.ts", "../src/providers/custom/factory.ts"],
3
+ "sources": [],
4
4
  "sourcesContent": [
5
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * adk-llm-bridge - Connect Google ADK to 100+ LLM models.\n *\n * This library bridges Google ADK (Agent Development Kit) to multiple LLM providers\n * through OpenAI-compatible APIs, enabling access to models from Anthropic, OpenAI,\n * Google, Meta, and more while preserving ADK features like multi-agent orchestration,\n * tool calling, and streaming.\n *\n * ## Supported Providers\n *\n * - **AI Gateway** (Vercel): Unified gateway for 100+ models\n * - **OpenRouter**: Multi-provider routing with fallbacks and price optimization\n *\n * ## Quick Start\n *\n * ### Option 1: Factory Functions (Recommended)\n *\n * ```typescript\n * import { AIGateway, OpenRouter } from \"adk-llm-bridge\";\n * import { LlmAgent } from \"@google/adk\";\n *\n * const agent = new LlmAgent({\n * name: \"assistant\",\n * llm: AIGateway(\"anthropic/claude-sonnet-4\")\n * });\n * ```\n *\n * ### Option 2: Registry (for adk-devtools)\n *\n * ```typescript\n * import { registerAIGateway } from \"adk-llm-bridge\";\n * import { LlmAgent } from \"@google/adk\";\n *\n * registerAIGateway({ apiKey: process.env.AI_GATEWAY_API_KEY });\n *\n * const agent = new LlmAgent({\n * name: \"assistant\",\n * model: \"anthropic/claude-sonnet-4\"\n * });\n * ```\n *\n * ## Configuration\n *\n * Configuration is resolved in priority order:\n * 1. Instance configuration (passed to constructor/factory)\n * 2. Global configuration (via `setProviderConfig`)\n * 3. Environment variables\n * 4. Default values\n *\n * @module adk-llm-bridge\n *\n * @see {@link https://github.com/pailat/adk-llm-bridge|GitHub Repository}\n * @see {@link https://google.github.io/adk-docs/|Google ADK Documentation}\n */\n\n// =============================================================================\n// Re-exports from @google/adk (for type consistency)\n// =============================================================================\n\n// Re-export BaseLlm to ensure consumers use the same instance\n// This prevents TypeScript errors from duplicate @google/adk installations\nexport { BaseLlm } from \"@google/adk\";\n\n// =============================================================================\n// Core (for building custom providers)\n// =============================================================================\n\nexport { BaseProviderLlm } from \"./core/base-provider-llm\";\nexport type { OpenAIClientConfig } from \"./core/openai-compatible-llm\";\nexport { OpenAICompatibleLlm } from \"./core/openai-compatible-llm\";\n\n// =============================================================================\n// AI Gateway Provider\n// =============================================================================\n\nexport {\n AIGateway,\n AIGatewayLlm,\n isAIGatewayRegistered,\n registerAIGateway,\n} from \"./providers/ai-gateway\";\n\n// =============================================================================\n// OpenRouter Provider\n// =============================================================================\n\nexport {\n isOpenRouterRegistered,\n OpenRouter,\n OpenRouterLlm,\n registerOpenRouter,\n} from \"./providers/openrouter\";\n\n// =============================================================================\n// OpenAI Provider\n// =============================================================================\n\nexport {\n isOpenAIRegistered,\n OpenAI,\n OpenAILlm,\n registerOpenAI,\n} from \"./providers/openai\";\n\n// =============================================================================\n// xAI Provider\n// =============================================================================\n\nexport { isXAIRegistered, registerXAI, XAI, XAILlm } from \"./providers/xai\";\n\n// =============================================================================\n// Anthropic Provider\n// =============================================================================\n\nexport {\n Anthropic,\n AnthropicLlm,\n isAnthropicRegistered,\n registerAnthropic,\n} from \"./providers/anthropic\";\n\n// =============================================================================\n// Custom LLM Provider (Any Compatible API)\n// =============================================================================\n\nexport {\n Custom,\n CustomLlm,\n type CustomLlmProviderConfig,\n createCustomLlm,\n} from \"./providers/custom\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type {\n // AI Gateway types\n AIGatewayConfig,\n // Anthropic types\n AnthropicProviderConfig,\n AnthropicRegisterOptions,\n // Base types\n BaseProviderConfig,\n // Custom LLM types\n CustomLlmConfig,\n // OpenAI types\n OpenAIProviderConfig,\n OpenAIRegisterOptions,\n // OpenRouter types\n OpenRouterConfig,\n OpenRouterProviderPreferences,\n OpenRouterRegisterOptions,\n RegisterOptions,\n StreamAccumulator,\n StreamChunkResult,\n // Streaming types\n ToolCallAccumulator,\n // xAI types\n XAIProviderConfig,\n XAIRegisterOptions,\n} from \"./types\";\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nexport {\n DEFAULT_BASE_URL,\n MODEL_PATTERNS,\n OPENROUTER_BASE_URL,\n OPENROUTER_MODEL_PATTERNS,\n PROVIDER_IDS,\n} from \"./constants\";\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport {\n getConfig,\n getProviderConfig,\n resetAllConfigs,\n resetConfig,\n resetProviderConfig,\n // Legacy API (deprecated but still exported for backward compatibility)\n setConfig,\n // Multi-provider API\n setProviderConfig,\n} from \"./config\";\n\n// =============================================================================\n// Converters (for building custom providers)\n// =============================================================================\n\nexport { convertRequest } from \"./converters/request\";\nexport {\n convertResponse,\n convertStreamChunk,\n createStreamAccumulator,\n} from \"./converters/response\";\n",
6
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Base LLM provider class for adk-llm-bridge.\n *\n * This module provides the abstract base class that all LLM providers extend.\n * It handles common functionality like error response creation and ADK integration.\n *\n * @module core/base-provider-llm\n */\n\nimport type { BaseLlmConnection, LlmRequest, LlmResponse } from \"@google/adk\";\nimport { BaseLlm } from \"@google/adk\";\nimport type { BaseProviderConfig } from \"../types\";\n\n/**\n * Abstract base class for all LLM providers in adk-llm-bridge.\n *\n * Extends ADK's `BaseLlm` and provides common infrastructure for error handling\n * and configuration management. All provider implementations (AI Gateway,\n * OpenRouter, custom providers) should extend this class.\n *\n * @abstract\n *\n * @example\n * ```typescript\n * class CustomLlm extends BaseProviderLlm {\n * static supportedModels = [/^custom\\/.+$/];\n *\n * async *generateContentAsync(\n * llmRequest: LlmRequest,\n * stream?: boolean\n * ): AsyncGenerator<LlmResponse, void> {\n * try {\n * // Implementation here\n * yield response;\n * } catch (error) {\n * yield this.createErrorResponse(error, \"CUSTOM\");\n * }\n * }\n * }\n * ```\n *\n * @see {@link OpenAICompatibleLlm} for OpenAI-compatible API implementations\n */\nexport abstract class BaseProviderLlm extends BaseLlm {\n /**\n * Provider configuration.\n *\n * Contains the resolved configuration including model, API key, base URL, etc.\n *\n * @protected\n */\n protected readonly config: BaseProviderConfig;\n\n /**\n * Creates a new BaseProviderLlm instance.\n *\n * @param config - Provider configuration options\n */\n constructor(config: BaseProviderConfig) {\n if (!config.model?.trim()) {\n throw new Error(\n \"[adk-llm-bridge] model is required and cannot be empty.\",\n );\n }\n super({ model: config.model });\n this.config = config;\n }\n\n /**\n * Generates content from the LLM.\n *\n * This is the main method that must be implemented by all providers.\n * It should handle both streaming and non-streaming responses.\n *\n * @param llmRequest - The ADK LLM request containing messages and tools\n * @param stream - Whether to stream the response (default: false)\n * @returns An async generator yielding LLM responses\n *\n * @abstract\n */\n abstract generateContentAsync(\n llmRequest: LlmRequest,\n stream?: boolean,\n ): AsyncGenerator<LlmResponse, void>;\n\n /**\n * Establishes a bidirectional streaming connection.\n *\n * This method is required by ADK's BaseLlm interface but is not supported\n * by OpenAI-compatible APIs. It always throws an error.\n *\n * @param _ - The LLM request (unused)\n * @returns Never - always throws\n * @throws Error indicating bidirectional streaming is not supported\n */\n async connect(_: LlmRequest): Promise<BaseLlmConnection> {\n throw new Error(\n `${this.constructor.name} does not support bidirectional streaming`,\n );\n }\n\n /**\n * Creates a standardized error response for ADK.\n *\n * Converts JavaScript errors into ADK-compatible LlmResponse objects\n * with appropriate error codes and messages.\n *\n * @param error - The error that occurred (Error instance or any value)\n * @param prefix - Provider-specific error prefix (e.g., \"AI_GATEWAY\", \"OPENROUTER\")\n * @returns An LlmResponse with error information and turnComplete: true\n *\n * @protected\n *\n * @example\n * ```typescript\n * try {\n * // API call\n * } catch (error) {\n * yield this.createErrorResponse(error, \"MY_PROVIDER\");\n * // Returns: { errorCode: \"MY_PROVIDER_ERROR\", errorMessage: \"...\", turnComplete: true }\n * }\n * ```\n */\n protected createErrorResponse(error: unknown, prefix: string): LlmResponse {\n const isApiError =\n error !== null &&\n typeof error === \"object\" &&\n \"status\" in error &&\n typeof (error as { status: unknown }).status === \"number\";\n\n return {\n errorCode: isApiError\n ? `API_ERROR_${(error as { status: number }).status}`\n : `${prefix}_ERROR`,\n errorMessage: error instanceof Error ? error.message : String(error),\n turnComplete: true,\n };\n }\n}\n",
7
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * OpenAI-compatible LLM base class.\n *\n * This module provides the base class for LLM providers that use\n * OpenAI-compatible APIs (chat completions endpoint). Providers can\n * be created either by extending this class or by using a declarative\n * {@link ProviderDefinition}.\n *\n * @module core/openai-compatible-llm\n */\n\nimport type { LlmRequest, LlmResponse } from \"@google/adk\";\nimport OpenAI from \"openai\";\nimport { convertRequest } from \"../converters/request\";\nimport {\n convertResponse,\n convertStreamChunk,\n createStreamAccumulator,\n} from \"../converters/response\";\nimport type { BaseProviderConfig } from \"../types\";\nimport { BaseProviderLlm } from \"./base-provider-llm\";\nimport { resolveConfig } from \"./config-resolver\";\nimport type { ProviderDefinition } from \"./provider-definition\";\n\n/**\n * Configuration for the underlying OpenAI client.\n *\n * These options are passed directly to the OpenAI SDK constructor.\n */\nexport interface OpenAIClientConfig {\n /** Base URL for the API endpoint. */\n baseURL: string;\n /** API key for authentication. */\n apiKey: string;\n /** Request timeout in milliseconds. */\n timeout: number;\n /** Maximum number of retry attempts. */\n maxRetries: number;\n /** Additional HTTP headers to include in all requests. */\n defaultHeaders?: Record<string, string>;\n}\n\n/**\n * Base class for LLM providers that use OpenAI-compatible APIs.\n *\n * Supports two construction modes:\n *\n * 1. **Declarative** (recommended): Pass a {@link ProviderDefinition} that\n * describes the provider's configuration. Config resolution is automatic.\n *\n * 2. **Manual**: Pass a {@link BaseProviderConfig} + {@link OpenAIClientConfig}\n * with pre-resolved values. Used by CustomLlm which has unique URL logic.\n *\n * @example\n * ```typescript\n * // Declarative (most providers)\n * const llm = new OpenAICompatibleLlm(MY_DEFINITION, { model: \"gpt-4o\" });\n *\n * // Manual (Custom provider)\n * class CustomLlm extends OpenAICompatibleLlm {\n * constructor(config) {\n * super(config, { baseURL, apiKey, timeout, maxRetries });\n * }\n * }\n * ```\n */\nexport class OpenAICompatibleLlm extends BaseProviderLlm {\n /** Model patterns for LLMRegistry — set by createProviderClass(). */\n static supportedModels: (string | RegExp)[] = [];\n\n /** @protected */\n protected readonly client: OpenAI;\n\n private readonly _errorPrefix: string;\n private readonly _getRequestOptions?: () => Record<string, unknown>;\n\n /** Declarative constructor: definition + config */\n constructor(definition: ProviderDefinition, config: BaseProviderConfig);\n /** Manual constructor: config + clientConfig (for CustomLlm) */\n constructor(config: BaseProviderConfig, clientConfig: OpenAIClientConfig);\n constructor(\n first: ProviderDefinition | BaseProviderConfig,\n second: BaseProviderConfig | OpenAIClientConfig,\n ) {\n // Detect which overload: ProviderDefinition has 'id', BaseProviderConfig has 'model'\n if (\"id\" in first && \"model\" in second) {\n // Declarative mode\n const definition = first as ProviderDefinition;\n const config = second as BaseProviderConfig;\n\n super(config);\n this._errorPrefix = definition.errorPrefix;\n\n const resolved = resolveConfig(definition, config);\n this.client = new OpenAI({\n baseURL: resolved.baseURL,\n apiKey: resolved.apiKey,\n timeout: resolved.timeout,\n maxRetries: resolved.maxRetries,\n defaultHeaders: Object.keys(resolved.headers).length\n ? resolved.headers\n : undefined,\n });\n\n if (definition.buildRequestOptions) {\n const buildFn = definition.buildRequestOptions;\n const configRef = config as unknown as Record<string, unknown>;\n this._getRequestOptions = () => buildFn(configRef);\n }\n } else {\n // Manual mode (CustomLlm)\n const config = first as BaseProviderConfig;\n const clientConfig = second as OpenAIClientConfig;\n\n super(config);\n this._errorPrefix = \"CUSTOM\";\n this.client = new OpenAI({\n baseURL: clientConfig.baseURL,\n apiKey: clientConfig.apiKey,\n timeout: clientConfig.timeout,\n maxRetries: clientConfig.maxRetries,\n defaultHeaders: clientConfig.defaultHeaders,\n });\n }\n }\n\n /** Returns the provider error prefix. */\n protected getErrorPrefix(): string {\n return this._errorPrefix;\n }\n\n /** Returns provider-specific request options. */\n protected getProviderRequestOptions(): Record<string, unknown> {\n return this._getRequestOptions?.() ?? {};\n }\n\n async *generateContentAsync(\n llmRequest: LlmRequest,\n stream = false,\n ): AsyncGenerator<LlmResponse, void> {\n try {\n const { messages, tools } = convertRequest(llmRequest);\n\n if (stream) {\n yield* this.streamResponse(messages, tools);\n } else {\n yield await this.singleResponse(messages, tools);\n }\n } catch (error) {\n yield this.createErrorResponse(error, this.getErrorPrefix());\n }\n }\n\n private async singleResponse(\n messages: OpenAI.ChatCompletionMessageParam[],\n tools?: OpenAI.ChatCompletionTool[],\n ): Promise<LlmResponse> {\n const response = await this.client.chat.completions.create({\n model: this.model,\n messages,\n ...(tools?.length ? { tools } : {}),\n ...this.getProviderRequestOptions(),\n });\n return convertResponse(response);\n }\n\n private async *streamResponse(\n messages: OpenAI.ChatCompletionMessageParam[],\n tools?: OpenAI.ChatCompletionTool[],\n ): AsyncGenerator<LlmResponse, void> {\n const stream = await this.client.chat.completions.create({\n model: this.model,\n messages,\n stream: true,\n ...(tools?.length ? { tools } : {}),\n ...this.getProviderRequestOptions(),\n });\n\n const acc = createStreamAccumulator();\n\n for await (const chunk of stream) {\n const { response, isComplete } = convertStreamChunk(chunk, acc);\n if (response) yield response;\n if (isComplete) break;\n }\n }\n}\n",
8
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Request converter for ADK to OpenAI format.\n *\n * This module handles the conversion of ADK LlmRequest objects to\n * OpenAI-compatible chat completion request format.\n *\n * @module converters/request\n */\n\nimport type { LlmRequest } from \"@google/adk\";\nimport type { Content, Part } from \"@google/genai\";\nimport type OpenAI from \"openai\";\n\n/**\n * Result of converting an ADK LlmRequest to OpenAI format.\n *\n * Contains the converted messages array and optional tools array\n * ready for use with the OpenAI chat completions API.\n */\nexport interface ConvertedRequest {\n /**\n * Array of OpenAI-format chat messages.\n *\n * Includes system, user, assistant, and tool messages\n * converted from ADK Content objects.\n */\n messages: OpenAI.ChatCompletionMessageParam[];\n\n /**\n * Array of OpenAI-format tool definitions.\n *\n * Converted from ADK function declarations with schema normalization.\n */\n tools?: OpenAI.ChatCompletionTool[];\n}\n\n/**\n * Converts an ADK LlmRequest to OpenAI chat completion format.\n *\n * This function handles:\n * - System instruction extraction\n * - User and model message conversion\n * - Function call and response handling\n * - Tool/function declaration conversion\n * - Schema normalization (Gemini UPPERCASE to OpenAI lowercase types)\n *\n * @param llmRequest - The ADK LlmRequest to convert\n * @returns The converted request with messages and optional tools\n *\n * @example\n * ```typescript\n * import { convertRequest } from \"adk-llm-bridge\";\n *\n * const adkRequest: LlmRequest = {\n * contents: [{ role: \"user\", parts: [{ text: \"Hello!\" }] }],\n * config: { systemInstruction: \"You are a helpful assistant.\" }\n * };\n *\n * const { messages, tools } = convertRequest(adkRequest);\n * // messages = [\n * // { role: \"system\", content: \"You are a helpful assistant.\" },\n * // { role: \"user\", content: \"Hello!\" }\n * // ]\n * ```\n *\n * @example\n * ```typescript\n * // With tools/functions\n * const adkRequest: LlmRequest = {\n * contents: [...],\n * config: {\n * tools: [{\n * functionDeclarations: [{\n * name: \"get_weather\",\n * description: \"Get current weather\",\n * parameters: { type: \"OBJECT\", properties: { city: { type: \"STRING\" } } }\n * }]\n * }]\n * }\n * };\n *\n * const { messages, tools } = convertRequest(adkRequest);\n * // tools[0].function.parameters.type = \"object\" (normalized from \"OBJECT\")\n * ```\n */\nexport function convertRequest(llmRequest: LlmRequest): ConvertedRequest {\n const messages: OpenAI.ChatCompletionMessageParam[] = [];\n\n const systemContent = extractSystemInstruction(llmRequest);\n if (systemContent) {\n messages.push({ role: \"system\", content: systemContent });\n }\n\n for (const content of llmRequest.contents ?? []) {\n processContent(content, messages);\n }\n\n return { messages, tools: convertTools(llmRequest) };\n}\n\n/**\n * Extracts the system instruction from an LlmRequest.\n *\n * Handles both string and Content object formats.\n *\n * @param req - The LLM request\n * @returns The system instruction text, or null if not present\n *\n * @internal\n */\nfunction extractSystemInstruction(req: LlmRequest): string | null {\n const sys = req.config?.systemInstruction;\n if (!sys) return null;\n if (typeof sys === \"string\") return sys;\n if (\"parts\" in sys) return extractText(sys.parts ?? []);\n return null;\n}\n\n/**\n * Extracts text from an array of Parts.\n *\n * @param parts - Array of Part objects\n * @returns Concatenated text from all text parts\n *\n * @internal\n */\nfunction extractText(parts: Part[]): string {\n return parts\n .map((p) => p.text)\n .filter(Boolean)\n .join(\"\\n\");\n}\n\n/**\n * Processes a Content object and adds appropriate messages.\n *\n * Handles user messages, model responses, function calls, and function responses.\n *\n * @param content - The ADK Content object\n * @param messages - The messages array to append to\n *\n * @internal\n */\nfunction processContent(\n content: Content,\n messages: OpenAI.ChatCompletionMessageParam[],\n): void {\n if (!content.parts?.length) return;\n\n const texts: string[] = [];\n const calls: { id: string; name: string; arguments: string }[] = [];\n const responses: { id: string; content: string }[] = [];\n\n for (const part of content.parts) {\n if (part.text) texts.push(part.text);\n if (part.functionCall) {\n if (!part.functionCall.id) {\n console.warn(\n \"[adk-llm-bridge] functionCall missing id, using generated ID\",\n );\n }\n if (!part.functionCall.name) {\n console.warn(\"[adk-llm-bridge] functionCall missing name\");\n }\n calls.push({\n id: part.functionCall.id ?? `call_${Date.now()}`,\n name: part.functionCall.name ?? \"\",\n arguments: JSON.stringify(part.functionCall.args ?? {}),\n });\n }\n if (part.functionResponse) {\n if (!part.functionResponse.id) {\n console.warn(\n \"[adk-llm-bridge] functionResponse missing id\",\n );\n }\n responses.push({\n id: part.functionResponse.id ?? \"\",\n content: JSON.stringify(part.functionResponse.response ?? {}),\n });\n }\n }\n\n if (content.role === \"user\") {\n if (texts.length)\n messages.push({ role: \"user\", content: texts.join(\"\\n\") });\n for (const r of responses) {\n messages.push({ role: \"tool\", tool_call_id: r.id, content: r.content });\n }\n } else if (content.role === \"model\") {\n if (texts.length || calls.length) {\n const msg: OpenAI.ChatCompletionAssistantMessageParam = {\n role: \"assistant\",\n content: texts.length ? texts.join(\"\\n\") : null,\n };\n if (calls.length) {\n msg.tool_calls = calls.map((c) => ({\n id: c.id,\n type: \"function\" as const,\n function: { name: c.name, arguments: c.arguments },\n }));\n }\n messages.push(msg);\n }\n }\n}\n\n/**\n * Converts ADK tool declarations to OpenAI format.\n *\n * @param req - The LLM request containing tool definitions\n * @returns Array of OpenAI tool objects, or undefined if no tools\n *\n * @internal\n */\nfunction convertTools(\n req: LlmRequest,\n): OpenAI.ChatCompletionTool[] | undefined {\n const adkTools = req.config?.tools;\n if (!adkTools?.length) return undefined;\n\n const tools: OpenAI.ChatCompletionTool[] = [];\n\n for (const group of adkTools) {\n if (\n \"functionDeclarations\" in group &&\n Array.isArray(group.functionDeclarations)\n ) {\n for (const fn of group.functionDeclarations) {\n if (!fn.name) {\n console.warn(\"[adk-llm-bridge] Tool function missing name, skipping\");\n continue;\n }\n tools.push({\n type: \"function\",\n function: {\n name: fn.name,\n description: fn.description ?? \"\",\n parameters: normalizeSchema(fn.parameters) ?? {\n type: \"object\",\n properties: {},\n },\n },\n });\n }\n }\n }\n\n return tools.length ? tools : undefined;\n}\n\n/**\n * Normalizes Gemini-style schema to OpenAI-style schema.\n *\n * Converts UPPERCASE type names (Gemini format) to lowercase (OpenAI format).\n * For example: \"OBJECT\" → \"object\", \"STRING\" → \"string\".\n *\n * @param schema - The schema object to normalize\n * @returns The normalized schema, or undefined if input is invalid\n *\n * @internal\n *\n * @example\n * ```typescript\n * normalizeSchema({ type: \"OBJECT\", properties: { name: { type: \"STRING\" } } });\n * // Returns: { type: \"object\", properties: { name: { type: \"string\" } } }\n * ```\n */\nfunction normalizeSchema(schema: unknown): Record<string, unknown> | undefined {\n if (!schema || typeof schema !== \"object\") return undefined;\n\n const result: Record<string, unknown> = {};\n const input = schema as Record<string, unknown>;\n\n for (const [key, value] of Object.entries(input)) {\n if (key === \"type\" && typeof value === \"string\") {\n // Convert UPPERCASE type to lowercase (OBJECT -> object, STRING -> string, etc.)\n result[key] = value.toLowerCase();\n } else if (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value)\n ) {\n // Recursively normalize nested objects (like properties)\n result[key] = normalizeSchema(value);\n } else if (Array.isArray(value)) {\n // Handle arrays (like required)\n result[key] = value;\n } else {\n result[key] = value;\n }\n }\n\n return result;\n}\n",
9
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * JSON utilities for safe parsing with large integer handling.\n *\n * @module utils/json\n */\n\n/**\n * Safely parses a JSON string, returning an empty object on failure.\n *\n * Pre-processes the JSON string to convert large integers (17+ digits) to\n * strings before parsing, preventing IEEE 754 double precision loss.\n * Numbers with 17+ digits exceed Number.MAX_SAFE_INTEGER (16 digits), so\n * they are silently rounded by JSON.parse — this is especially problematic\n * for IDs like Zoho Desk ticket IDs (19 digits).\n *\n * @param str - The JSON string to parse\n * @returns The parsed object, or empty object if parsing fails\n *\n * @internal\n */\nexport function safeJsonParse(str: string): Record<string, unknown> {\n if (!str || typeof str !== \"string\") return {};\n\n try {\n // Pre-process: wrap large integers (17+ digits) in quotes to prevent\n // IEEE 754 precision loss. The pattern matches integers that appear as\n // JSON values (preceded by :, [, or , and followed by ,, ], or }).\n // Negative lookahead (?!\\.\\d) prevents matching large decimals.\n const safe = str.replace(\n /([:[,])\\s*(-?\\d{17,})(?!\\.\\d)(?=\\s*[,\\]}])/g,\n (_, delimiter, num) => `${delimiter} \"${num}\"`,\n );\n return JSON.parse(safe);\n } catch {\n return {};\n }\n}\n",
10
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Runtime validation helpers for configuration boundaries.\n *\n * These are lightweight, zero-dependency checks applied at system boundaries\n * (config resolution, constructor initialization) to fail fast with clear\n * error messages instead of propagating invalid state.\n *\n * @module utils/validate\n */\n\n/**\n * Asserts that a string value is non-empty.\n *\n * @param value - The string to check\n * @param field - The field name (for error messages)\n * @param context - The provider/module context (for error messages)\n * @returns The validated non-empty string\n * @throws {Error} If the value is empty or only whitespace\n *\n * @internal\n */\nexport function requireNonEmpty(\n value: string,\n field: string,\n context: string,\n): string {\n if (!value?.trim()) {\n throw new Error(`[${context}] ${field} is required but was empty.`);\n }\n return value;\n}\n\n/**\n * Asserts that a string is a valid URL.\n *\n * @param value - The URL string to validate\n * @param field - The field name (for error messages)\n * @param context - The provider/module context (for error messages)\n * @returns The validated URL string\n * @throws {Error} If the value is not a valid URL\n *\n * @internal\n */\nexport function requireValidURL(\n value: string,\n field: string,\n context: string,\n): string {\n try {\n new URL(value);\n return value;\n } catch {\n throw new Error(\n `[${context}] Invalid ${field}: \"${value}\". Must be a valid URL (e.g., http://localhost:11434/v1).`,\n );\n }\n}\n\n/**\n * Clamps a numeric value to be at least `min`, falling back to `fallback`\n * if the value is not a finite number.\n *\n * @param value - The number to clamp\n * @param fallback - The fallback value if input is not finite\n * @param min - The minimum allowed value (default: 0)\n * @returns A finite number >= min\n *\n * @internal\n */\nexport function clampPositive(\n value: number,\n fallback: number,\n min = 0,\n): number {\n return Math.max(Number.isFinite(value) ? value : fallback, min);\n}\n",
11
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Response converter for OpenAI to ADK format.\n *\n * This module handles the conversion of OpenAI API responses to\n * ADK LlmResponse format, supporting both single responses and streaming.\n *\n * @module converters/response\n */\n\nimport type { LlmResponse } from \"@google/adk\";\nimport type { Part } from \"@google/genai\";\nimport type OpenAI from \"openai\";\nimport type { StreamAccumulator, StreamChunkResult } from \"../types\";\nimport { safeJsonParse } from \"../utils\";\n\n/**\n * Converts an OpenAI chat completion response to ADK LlmResponse format.\n *\n * Handles:\n * - Text content extraction\n * - Tool/function call conversion\n * - Usage metadata mapping\n *\n * @param response - The OpenAI ChatCompletion response\n * @returns The converted ADK LlmResponse\n *\n * @example\n * ```typescript\n * import { convertResponse } from \"adk-llm-bridge\";\n *\n * const openaiResponse = await client.chat.completions.create({...});\n * const adkResponse = convertResponse(openaiResponse);\n *\n * if (adkResponse.content?.parts) {\n * for (const part of adkResponse.content.parts) {\n * if (part.text) console.log(part.text);\n * if (part.functionCall) console.log(\"Tool call:\", part.functionCall.name);\n * }\n * }\n * ```\n */\nexport function convertResponse(response: OpenAI.ChatCompletion): LlmResponse {\n const choice = response.choices[0];\n if (!choice) {\n return {\n errorCode: \"NO_CHOICE\",\n errorMessage: \"No response choice\",\n turnComplete: true,\n };\n }\n\n const parts: Part[] = [];\n\n if (choice.message.content) {\n parts.push({ text: choice.message.content });\n }\n\n for (const tc of choice.message.tool_calls ?? []) {\n if (tc.type !== \"function\") continue;\n parts.push({\n functionCall: {\n id: tc.id,\n name: tc.function.name,\n args: safeJsonParse(tc.function.arguments),\n },\n });\n }\n\n return {\n content: parts.length ? { role: \"model\", parts } : undefined,\n turnComplete: true,\n usageMetadata: response.usage\n ? {\n promptTokenCount: response.usage.prompt_tokens,\n candidatesTokenCount: response.usage.completion_tokens,\n totalTokenCount: response.usage.total_tokens,\n }\n : undefined,\n };\n}\n\n/**\n * Processes a streaming chunk and returns the appropriate response.\n *\n * This function accumulates partial data (text and tool calls) across\n * multiple chunks and returns:\n * - Partial responses for text content (streamed immediately)\n * - Complete responses when finish_reason is received\n *\n * Tool calls are accumulated and only returned in the final response\n * because their arguments arrive in fragments across multiple chunks.\n *\n * @param chunk - The OpenAI streaming chunk\n * @param acc - The stream accumulator for tracking partial data\n * @returns Object containing optional response and completion status\n *\n * @example\n * ```typescript\n * import { createStreamAccumulator, convertStreamChunk } from \"adk-llm-bridge\";\n *\n * const accumulator = createStreamAccumulator();\n *\n * for await (const chunk of stream) {\n * const { response, isComplete } = convertStreamChunk(chunk, accumulator);\n *\n * if (response?.content?.parts?.[0]?.text) {\n * // Stream text to user immediately\n * process.stdout.write(response.content.parts[0].text);\n * }\n *\n * if (isComplete) {\n * // Final response with complete tool calls\n * return response;\n * }\n * }\n * ```\n */\nexport function convertStreamChunk(\n chunk: OpenAI.ChatCompletionChunk,\n acc: StreamAccumulator,\n): StreamChunkResult {\n const choice = chunk.choices[0];\n if (!choice) return { isComplete: false };\n\n const delta = choice.delta;\n\n if (delta?.content) {\n acc.text += delta.content;\n return {\n response: {\n content: { role: \"model\", parts: [{ text: delta.content }] },\n partial: true,\n },\n isComplete: false,\n };\n }\n\n if (delta?.tool_calls) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index ?? acc.toolCalls.size;\n let a = acc.toolCalls.get(idx);\n if (!a) {\n a = { id: \"\", name: \"\", arguments: \"\" };\n acc.toolCalls.set(idx, a);\n }\n if (tc.id) a.id = tc.id;\n if (tc.function?.name) a.name += tc.function.name;\n if (tc.function?.arguments) a.arguments += tc.function.arguments;\n }\n }\n\n if (choice.finish_reason) {\n const parts: Part[] = [];\n if (acc.text) parts.push({ text: acc.text });\n for (const tc of Array.from(acc.toolCalls.values())) {\n if (tc.name) {\n parts.push({\n functionCall: {\n id: tc.id,\n name: tc.name,\n args: safeJsonParse(tc.arguments),\n },\n });\n }\n }\n\n acc.text = \"\";\n acc.toolCalls.clear();\n\n return {\n response: {\n content: parts.length ? { role: \"model\", parts } : undefined,\n turnComplete: true,\n },\n isComplete: true,\n };\n }\n\n return { isComplete: false };\n}\n\n/**\n * Creates a new stream accumulator for tracking partial responses.\n *\n * The accumulator stores:\n * - Accumulated text content\n * - Partial tool call data (indexed by position)\n *\n * Use with {@link convertStreamChunk} to process streaming responses.\n *\n * @returns A fresh StreamAccumulator instance\n *\n * @example\n * ```typescript\n * const accumulator = createStreamAccumulator();\n *\n * for await (const chunk of stream) {\n * const result = convertStreamChunk(chunk, accumulator);\n * // accumulator state is updated automatically\n * }\n * ```\n */\nexport function createStreamAccumulator(): StreamAccumulator {\n return { text: \"\", toolCalls: new Map() };\n}",
12
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Global configuration management for LLM providers.\n *\n * This module provides functions to set, get, and reset global configuration\n * that applies to all instances of a provider. Configuration set here acts\n * as a fallback when instance-specific configuration is not provided.\n *\n * Configuration priority (highest to lowest):\n * 1. Instance configuration (passed to constructor or factory)\n * 2. Global configuration (set via this module)\n * 3. Environment variables\n * 4. Default values\n *\n * @module config\n *\n * @example\n * ```typescript\n * import { setProviderConfig } from \"adk-llm-bridge\";\n *\n * // Set global config for AI Gateway\n * setProviderConfig(\"ai-gateway\", {\n * apiKey: process.env.AI_GATEWAY_API_KEY\n * });\n *\n * // Set global config for OpenRouter\n * setProviderConfig(\"openrouter\", {\n * apiKey: process.env.OPENROUTER_API_KEY,\n * siteUrl: \"https://myapp.com\"\n * });\n * ```\n */\n\nimport type {\n AnthropicRegisterOptions,\n OpenAIRegisterOptions,\n OpenRouterRegisterOptions,\n RegisterOptions,\n XAIRegisterOptions,\n} from \"./types\";\n\n/**\n * Mapping of provider identifiers to their configuration types.\n *\n * @internal\n */\ntype ProviderConfigMap = {\n \"ai-gateway\": RegisterOptions;\n openrouter: OpenRouterRegisterOptions;\n openai: OpenAIRegisterOptions;\n xai: XAIRegisterOptions;\n anthropic: AnthropicRegisterOptions;\n};\n\n/**\n * Valid provider type identifiers.\n *\n * @internal\n */\ntype ProviderType = keyof ProviderConfigMap;\n\n/** Internal storage for provider configurations */\nconst configs: Partial<Record<ProviderType, ProviderConfigMap[ProviderType]>> =\n {};\n\n// =============================================================================\n// Multi-provider Configuration API\n// =============================================================================\n\n/**\n * Sets global configuration for a specific provider.\n *\n * This configuration is used as a fallback when creating LLM instances\n * without explicit configuration. Instance configuration always takes\n * precedence over global configuration.\n *\n * @param provider - The provider identifier (\"ai-gateway\" or \"openrouter\")\n * @param options - Configuration options for the provider\n *\n * @example\n * ```typescript\n * // Configure AI Gateway globally\n * setProviderConfig(\"ai-gateway\", {\n * apiKey: \"your-api-key\",\n * baseURL: \"https://custom-gateway.example.com/v1\"\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Configure OpenRouter with site attribution\n * setProviderConfig(\"openrouter\", {\n * apiKey: \"your-api-key\",\n * siteUrl: \"https://myapp.com\",\n * appName: \"My Application\"\n * });\n * ```\n */\nexport function setProviderConfig<T extends ProviderType>(\n provider: T,\n options: ProviderConfigMap[T],\n): void {\n configs[provider] = { ...options };\n}\n\n/**\n * Gets the current global configuration for a specific provider.\n *\n * @param provider - The provider identifier (\"ai-gateway\" or \"openrouter\")\n * @returns The current configuration, or `undefined` if not set\n *\n * @example\n * ```typescript\n * const config = getProviderConfig(\"ai-gateway\");\n * if (config?.apiKey) {\n * console.log(\"AI Gateway is configured\");\n * }\n * ```\n */\nexport function getProviderConfig<T extends ProviderType>(\n provider: T,\n): Readonly<ProviderConfigMap[T]> | undefined {\n return configs[provider] as ProviderConfigMap[T] | undefined;\n}\n\n/**\n * Resets the global configuration for a specific provider.\n *\n * After calling this, the provider will fall back to environment variables\n * or default values.\n *\n * @param provider - The provider identifier (\"ai-gateway\" or \"openrouter\")\n *\n * @example\n * ```typescript\n * resetProviderConfig(\"ai-gateway\");\n * ```\n */\nexport function resetProviderConfig(provider: ProviderType): void {\n delete configs[provider];\n}\n\n/**\n * Resets all provider configurations.\n *\n * Useful for testing or when you need to clear all global state.\n *\n * @example\n * ```typescript\n * // In test teardown\n * afterEach(() => {\n * resetAllConfigs();\n * });\n * ```\n */\nexport function resetAllConfigs(): void {\n for (const key of Object.keys(configs) as ProviderType[]) {\n delete configs[key];\n }\n}\n\n// =============================================================================\n// Legacy API (backward compatible)\n// =============================================================================\n\n/**\n * Sets global configuration for AI Gateway.\n *\n * @param options - Configuration options\n *\n * @deprecated Use {@link setProviderConfig | setProviderConfig(\"ai-gateway\", options)} instead.\n * This function will be removed in a future major version.\n *\n * @example\n * ```typescript\n * // Old way (deprecated)\n * setConfig({ apiKey: \"...\" });\n *\n * // New way\n * setProviderConfig(\"ai-gateway\", { apiKey: \"...\" });\n * ```\n */\nexport function setConfig(options: RegisterOptions): void {\n setProviderConfig(\"ai-gateway\", options);\n}\n\n/**\n * Gets global configuration for AI Gateway.\n *\n * @returns The current AI Gateway configuration\n *\n * @deprecated Use {@link getProviderConfig | getProviderConfig(\"ai-gateway\")} instead.\n * This function will be removed in a future major version.\n */\nexport function getConfig(): Readonly<RegisterOptions> {\n return getProviderConfig(\"ai-gateway\") ?? {};\n}\n\n/**\n * Resets global configuration for AI Gateway.\n *\n * @deprecated Use {@link resetProviderConfig | resetProviderConfig(\"ai-gateway\")} instead.\n * This function will be removed in a future major version.\n */\nexport function resetConfig(): void {\n resetProviderConfig(\"ai-gateway\");\n}\n",
13
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Constants and default values for adk-llm-bridge.\n *\n * This module contains all constant values including default URLs,\n * timeouts, environment variable names, and model patterns.\n *\n * @module constants\n */\n\n// =============================================================================\n// AI Gateway Constants\n// =============================================================================\n\n/**\n * Default base URL for the Vercel AI Gateway API.\n *\n * @constant\n * @see {@link https://vercel.com/ai-gateway|Vercel AI Gateway}\n */\nexport const DEFAULT_BASE_URL = \"https://ai-gateway.vercel.sh/v1\";\n\n/**\n * Default request timeout in milliseconds.\n *\n * @constant\n * @defaultValue 60000 (60 seconds)\n */\nexport const DEFAULT_TIMEOUT = 60_000;\n\n/**\n * Default maximum number of retry attempts for failed requests.\n *\n * @constant\n * @defaultValue 2\n */\nexport const DEFAULT_MAX_RETRIES = 2;\n\n/**\n * Model patterns for AI Gateway model validation.\n *\n * Matches any model identifier with the format \"provider/model\".\n * AI Gateway validates actual model availability at runtime.\n *\n * Note: Do not include ^ or $ anchors - ADK's LLMRegistry adds them automatically.\n *\n * @constant\n * @example\n * ```typescript\n * MODEL_PATTERNS[0].test(\"anthropic/claude-sonnet-4\"); // true\n * MODEL_PATTERNS[0].test(\"invalid\"); // false\n * ```\n */\nexport const MODEL_PATTERNS: (string | RegExp)[] = [/.+\\/.+/];\n\n/**\n * Environment variable names for AI Gateway configuration.\n *\n * These environment variables are checked in order when resolving configuration.\n *\n * @constant\n *\n * @example\n * ```bash\n * # Set in your environment or .env file\n * export AI_GATEWAY_API_KEY=\"your-api-key\"\n * export AI_GATEWAY_URL=\"https://custom-gateway.example.com/v1\"\n * ```\n */\nexport const ENV = {\n /** Environment variable for AI Gateway URL override */\n AI_GATEWAY_URL: \"AI_GATEWAY_URL\",\n\n /** Environment variable for AI Gateway API key */\n AI_GATEWAY_API_KEY: \"AI_GATEWAY_API_KEY\",\n\n /** Fallback environment variable for base URL (OpenAI compatibility) */\n OPENAI_BASE_URL: \"OPENAI_BASE_URL\",\n\n /** Fallback environment variable for API key (OpenAI compatibility) */\n OPENAI_API_KEY: \"OPENAI_API_KEY\",\n} as const;\n\n// =============================================================================\n// OpenRouter Constants\n// =============================================================================\n\n/**\n * Default base URL for the OpenRouter API.\n *\n * @constant\n * @see {@link https://openrouter.ai/docs|OpenRouter Documentation}\n */\nexport const OPENROUTER_BASE_URL = \"https://openrouter.ai/api/v1\";\n\n/**\n * Model patterns for OpenRouter model validation.\n *\n * Uses the same \"provider/model\" format as AI Gateway.\n *\n * Note: Do not include ^ or $ anchors - ADK's LLMRegistry adds them automatically.\n *\n * @constant\n * @example\n * ```typescript\n * OPENROUTER_MODEL_PATTERNS[0].test(\"anthropic/claude-sonnet-4\"); // true\n * ```\n */\nexport const OPENROUTER_MODEL_PATTERNS: (string | RegExp)[] = [/.+\\/.+/];\n\n/**\n * Environment variable names for OpenRouter configuration.\n *\n * @constant\n *\n * @example\n * ```bash\n * # Set in your environment or .env file\n * export OPENROUTER_API_KEY=\"your-api-key\"\n * export OPENROUTER_SITE_URL=\"https://myapp.com\"\n * export OPENROUTER_APP_NAME=\"My Application\"\n * ```\n */\nexport const OPENROUTER_ENV = {\n /** Environment variable for OpenRouter API key */\n API_KEY: \"OPENROUTER_API_KEY\",\n\n /** Environment variable for site URL (used for rankings) */\n SITE_URL: \"OPENROUTER_SITE_URL\",\n\n /** Environment variable for app name (used for rankings) */\n APP_NAME: \"OPENROUTER_APP_NAME\",\n} as const;\n\n// =============================================================================\n// Provider Identifiers\n// =============================================================================\n\n/**\n * Unique identifiers for each provider.\n *\n * Used internally for configuration management and registry operations.\n *\n * @constant\n */\nexport const PROVIDER_IDS = {\n /** Identifier for the AI Gateway provider */\n AI_GATEWAY: \"ai-gateway\",\n\n /** Identifier for the OpenRouter provider */\n OPENROUTER: \"openrouter\",\n} as const;\n",
14
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Centralized configuration resolution for OpenAI-compatible providers.\n *\n * Eliminates the duplicated config resolution logic that was previously\n * copy-pasted in every provider constructor.\n *\n * @module core/config-resolver\n */\n\nimport { getProviderConfig } from \"../config\";\nimport { DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT } from \"../constants\";\nimport type { BaseProviderConfig } from \"../types\";\nimport { clampPositive, requireValidURL } from \"../utils/validate\";\nimport type { ProviderDefinition } from \"./provider-definition\";\n\n/**\n * Fully resolved configuration ready to create an OpenAI client.\n */\nexport interface ResolvedConfig {\n baseURL: string;\n apiKey: string;\n timeout: number;\n maxRetries: number;\n headers: Record<string, string>;\n}\n\n/**\n * Resolves the first defined environment variable from a list of keys.\n *\n * @param keys - Environment variable names to check, in priority order\n * @returns The first found value, or undefined\n */\nexport function resolveEnvVar(keys: string[]): string | undefined {\n for (const key of keys) {\n const value = process.env[key];\n if (value) return value;\n }\n return undefined;\n}\n\n/**\n * Resolves provider configuration from multiple sources.\n *\n * Priority order (highest to lowest):\n * 1. Instance config (passed to constructor)\n * 2. Global config (via setProviderConfig)\n * 3. Environment variables\n * 4. Default values from the provider definition\n *\n * @param definition - The provider definition with defaults and env var names\n * @param instanceConfig - Instance-level configuration\n * @returns Fully resolved configuration\n */\nexport function resolveConfig(\n definition: ProviderDefinition,\n instanceConfig: BaseProviderConfig,\n): ResolvedConfig {\n const globalConfig =\n (getProviderConfig(definition.id as \"ai-gateway\") as\n | Record<string, unknown>\n | undefined) ?? {};\n\n const apiKey =\n instanceConfig.apiKey ??\n (globalConfig.apiKey as string | undefined) ??\n resolveEnvVar(definition.envKeys.apiKey) ??\n \"\";\n\n if (definition.requireApiKey && !apiKey) {\n const envHint = definition.envKeys.apiKey.join(\" or \");\n throw new Error(\n `[${definition.id}] API key is required. Provide it via config, ` +\n `setProviderConfig(\"${definition.id}\", { apiKey }), or set the ${envHint} env var.`,\n );\n }\n\n const baseURL =\n instanceConfig.baseURL ??\n (globalConfig.baseURL as string | undefined) ??\n resolveEnvVar(definition.envKeys.baseURL ?? []) ??\n definition.defaultBaseURL;\n\n requireValidURL(baseURL, \"baseURL\", definition.id);\n\n const headers =\n definition.buildHeaders?.({\n ...globalConfig,\n ...instanceConfig,\n }) ?? {};\n\n return {\n apiKey,\n baseURL,\n timeout: clampPositive(\n instanceConfig.timeout ?? DEFAULT_TIMEOUT,\n DEFAULT_TIMEOUT,\n 1000,\n ),\n maxRetries: clampPositive(\n instanceConfig.maxRetries ?? DEFAULT_MAX_RETRIES,\n DEFAULT_MAX_RETRIES,\n 0,\n ),\n headers,\n };\n}\n",
15
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Factory utilities for creating provider classes and functions\n * from declarative provider definitions.\n *\n * @module core/create-provider\n */\n\nimport type { BaseLlm } from \"@google/adk\";\nimport type { BaseProviderConfig } from \"../types\";\nimport { OpenAICompatibleLlm } from \"./openai-compatible-llm\";\nimport type { ProviderDefinition } from \"./provider-definition\";\n\n/** Type compatible with LLMRegistry.register(). */\ntype RegisterableLlm = (new (params: { model: string }) => BaseLlm) & {\n readonly supportedModels: (string | RegExp)[];\n};\n\n/**\n * Creates a typed LLM class with static `supportedModels` for LLMRegistry.\n *\n * The returned class can be registered with ADK's LLMRegistry and\n * instantiated by model name matching.\n *\n * @param definition - The provider definition\n * @returns A concrete class extending OpenAICompatibleLlm\n */\nexport function createProviderClass(\n definition: ProviderDefinition,\n): RegisterableLlm {\n return class extends OpenAICompatibleLlm {\n static readonly supportedModels = definition.modelPatterns;\n\n constructor(config: BaseProviderConfig) {\n super(definition, config);\n }\n };\n}\n\n/**\n * Creates a factory function for convenient provider instantiation.\n *\n * @param definition - The provider definition\n * @returns A factory function: `(model, options?) => OpenAICompatibleLlm`\n */\nexport function createProviderFactory(definition: ProviderDefinition) {\n return (\n model: string,\n options?: Partial<Omit<BaseProviderConfig, \"model\">>,\n ): OpenAICompatibleLlm =>\n new OpenAICompatibleLlm(definition, { model, ...options });\n}\n",
16
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Factory for creating provider registration functions.\n *\n * Eliminates the duplicated singleton registration pattern that was\n * previously copy-pasted in every provider's register.ts file.\n *\n * @module core/create-register\n */\n\nimport type { BaseLlm } from \"@google/adk\";\nimport { LLMRegistry } from \"@google/adk\";\nimport { resetProviderConfig, setProviderConfig } from \"../config\";\nimport type { ProviderDefinition } from \"./provider-definition\";\n\n/** Type that LLMRegistry.register() expects. */\ntype RegisterableLlm = (new (params: { model: string }) => BaseLlm) & {\n readonly supportedModels: (string | RegExp)[];\n};\n\n/**\n * Creates registration functions for a provider.\n *\n * Returns an object with `register`, `isRegistered`, and `_reset` functions\n * that implement the idempotent singleton registration pattern.\n *\n * @param definition - The provider definition\n * @param ProviderClass - The LLM class to register (must have static supportedModels)\n * @returns Registration function set\n */\nexport function createRegisterFunction(\n definition: ProviderDefinition,\n ProviderClass: RegisterableLlm,\n) {\n let registered = false;\n\n return {\n register(options?: Record<string, unknown>): void {\n if (registered) {\n console.warn(\n `[adk-llm-bridge] ${definition.id} already registered, skipping`,\n );\n return;\n }\n if (options) {\n setProviderConfig(\n definition.id as \"ai-gateway\",\n options as Parameters<typeof setProviderConfig>[1],\n );\n }\n LLMRegistry.register(ProviderClass);\n registered = true;\n },\n\n isRegistered(): boolean {\n return registered;\n },\n\n _reset(): void {\n registered = false;\n resetProviderConfig(definition.id as \"ai-gateway\");\n },\n };\n}\n",
17
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\nimport type { ProviderDefinition } from \"../../core/provider-definition\";\n\nexport const AI_GATEWAY_DEFINITION: ProviderDefinition = {\n id: \"ai-gateway\",\n errorPrefix: \"AI_GATEWAY\",\n defaultBaseURL: \"https://ai-gateway.vercel.sh/v1\",\n envKeys: {\n apiKey: [\"AI_GATEWAY_API_KEY\", \"OPENAI_API_KEY\"],\n baseURL: [\"AI_GATEWAY_URL\", \"OPENAI_BASE_URL\"],\n },\n modelPatterns: [/.+\\/.+/],\n requireApiKey: true,\n};\n",
18
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\nimport { createProviderClass, createProviderFactory } from \"../../core/create-provider\";\nimport { createRegisterFunction } from \"../../core/create-register\";\nimport { AI_GATEWAY_DEFINITION } from \"./definition\";\n\nexport { AI_GATEWAY_DEFINITION } from \"./definition\";\n\nexport const AIGatewayLlm = createProviderClass(AI_GATEWAY_DEFINITION);\nexport const AIGateway = createProviderFactory(AI_GATEWAY_DEFINITION);\n\nconst reg = createRegisterFunction(AI_GATEWAY_DEFINITION, AIGatewayLlm);\nexport const registerAIGateway = reg.register;\nexport const isAIGatewayRegistered = reg.isRegistered;\nexport const _resetAIGatewayRegistration = reg._reset;\n",
19
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\nimport type { ProviderDefinition } from \"../../core/provider-definition\";\n\nexport const OPENROUTER_DEFINITION: ProviderDefinition = {\n id: \"openrouter\",\n errorPrefix: \"OPENROUTER\",\n defaultBaseURL: \"https://openrouter.ai/api/v1\",\n envKeys: { apiKey: [\"OPENROUTER_API_KEY\"] },\n modelPatterns: [/.+\\/.+/],\n requireApiKey: true,\n buildHeaders: (config) => {\n const headers: Record<string, string> = {};\n const siteUrl =\n (config as Record<string, unknown>).siteUrl as string | undefined ??\n process.env.OPENROUTER_SITE_URL;\n const appName =\n (config as Record<string, unknown>).appName as string | undefined ??\n process.env.OPENROUTER_APP_NAME;\n if (siteUrl) headers[\"HTTP-Referer\"] = siteUrl;\n if (appName) headers[\"X-Title\"] = appName;\n return headers;\n },\n buildRequestOptions: (config) => {\n const provider = (config as Record<string, unknown>).provider;\n return provider ? { provider } : {};\n },\n};\n",
20
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\nimport { createProviderClass, createProviderFactory } from \"../../core/create-provider\";\nimport { createRegisterFunction } from \"../../core/create-register\";\nimport { OPENROUTER_DEFINITION } from \"./definition\";\n\nexport { OPENROUTER_DEFINITION } from \"./definition\";\n\nexport const OpenRouterLlm = createProviderClass(OPENROUTER_DEFINITION);\nexport const OpenRouter = createProviderFactory(OPENROUTER_DEFINITION);\n\nconst reg = createRegisterFunction(OPENROUTER_DEFINITION, OpenRouterLlm);\nexport const registerOpenRouter = reg.register;\nexport const isOpenRouterRegistered = reg.isRegistered;\nexport const _resetOpenRouterRegistration = reg._reset;\n",
21
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\nimport type { ProviderDefinition } from \"../../core/provider-definition\";\n\nexport const OPENAI_DEFINITION: ProviderDefinition = {\n id: \"openai\",\n errorPrefix: \"OPENAI\",\n defaultBaseURL: \"https://api.openai.com/v1\",\n envKeys: { apiKey: [\"OPENAI_API_KEY\"] },\n modelPatterns: [/gpt-.+/, /o\\d+.*/, /chatgpt-.+/],\n requireApiKey: true,\n buildHeaders: (config) => {\n const headers: Record<string, string> = {};\n const org =\n (config as Record<string, unknown>).organization as string | undefined ??\n process.env.OPENAI_ORGANIZATION;\n const proj =\n (config as Record<string, unknown>).project as string | undefined ??\n process.env.OPENAI_PROJECT;\n if (org) headers[\"OpenAI-Organization\"] = org;\n if (proj) headers[\"OpenAI-Project\"] = proj;\n return headers;\n },\n};\n",
22
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\nimport { createProviderClass, createProviderFactory } from \"../../core/create-provider\";\nimport { createRegisterFunction } from \"../../core/create-register\";\nimport { OPENAI_DEFINITION } from \"./definition\";\n\nexport { OPENAI_DEFINITION } from \"./definition\";\n\nexport const OpenAILlm = createProviderClass(OPENAI_DEFINITION);\nexport const OpenAI = createProviderFactory(OPENAI_DEFINITION);\n\nconst reg = createRegisterFunction(OPENAI_DEFINITION, OpenAILlm);\nexport const registerOpenAI = reg.register;\nexport const isOpenAIRegistered = reg.isRegistered;\nexport const _resetOpenAIRegistration = reg._reset;\n",
23
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\nimport type { ProviderDefinition } from \"../../core/provider-definition\";\n\nexport const XAI_DEFINITION: ProviderDefinition = {\n id: \"xai\",\n errorPrefix: \"XAI\",\n defaultBaseURL: \"https://api.x.ai/v1\",\n envKeys: { apiKey: [\"XAI_API_KEY\"] },\n modelPatterns: [/grok-.+/],\n requireApiKey: true,\n};\n",
24
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\nimport { createProviderClass, createProviderFactory } from \"../../core/create-provider\";\nimport { createRegisterFunction } from \"../../core/create-register\";\nimport { XAI_DEFINITION } from \"./definition\";\n\nexport { XAI_DEFINITION } from \"./definition\";\n\nexport const XAILlm = createProviderClass(XAI_DEFINITION);\nexport const XAI = createProviderFactory(XAI_DEFINITION);\n\nconst reg = createRegisterFunction(XAI_DEFINITION, XAILlm);\nexport const registerXAI = reg.register;\nexport const isXAIRegistered = reg.isRegistered;\nexport const _resetXAIRegistration = reg._reset;\n",
25
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Anthropic (Claude) provider module.\n *\n * @module providers/anthropic\n */\n\nimport { LLMRegistry } from \"@google/adk\";\nimport { resetProviderConfig, setProviderConfig } from \"../../config\";\nimport type { AnthropicProviderConfig, AnthropicRegisterOptions } from \"../../types\";\nimport { AnthropicLlm } from \"./anthropic-llm\";\n\n// Re-exports\nexport { AnthropicLlm, ANTHROPIC_MODEL_PATTERNS } from \"./anthropic-llm\";\nexport type { ConvertedAnthropicRequest } from \"./converters/request\";\nexport { convertAnthropicRequest } from \"./converters/request\";\nexport type {\n AnthropicStreamAccumulator,\n AnthropicStreamResult,\n} from \"./converters/response\";\nexport {\n convertAnthropicResponse,\n convertAnthropicStreamEvent,\n createAnthropicStreamAccumulator,\n} from \"./converters/response\";\n\n/**\n * Creates an Anthropic (Claude) LLM instance.\n *\n * @param model - The Claude model to use\n * @param options - Optional configuration options\n * @returns A configured Anthropic LLM instance\n */\nexport function Anthropic(\n model: string,\n options?: Omit<AnthropicProviderConfig, \"model\">,\n): AnthropicLlm {\n return new AnthropicLlm({ model, ...options });\n}\n\n// --- Registration (singleton pattern) ---\n\nlet registered = false;\n\nexport function registerAnthropic(options?: AnthropicRegisterOptions): void {\n if (registered) {\n console.warn(\"[adk-llm-bridge] anthropic already registered, skipping\");\n return;\n }\n if (options) {\n setProviderConfig(\"anthropic\", options);\n }\n LLMRegistry.register(AnthropicLlm);\n registered = true;\n}\n\nexport function isAnthropicRegistered(): boolean {\n return registered;\n}\n\nexport function _resetAnthropicRegistration(): void {\n registered = false;\n resetProviderConfig(\"anthropic\");\n}\n",
26
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Anthropic (Claude) LLM provider implementation.\n *\n * This module provides the Anthropic-specific LLM class that connects\n * directly to Anthropic's Messages API.\n *\n * @module providers/anthropic/anthropic-llm\n */\n\nimport AnthropicSDK from \"@anthropic-ai/sdk\";\nimport type { LlmRequest, LlmResponse } from \"@google/adk\";\nimport { getProviderConfig } from \"../../config\";\nimport { DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT } from \"../../constants\";\nimport { BaseProviderLlm } from \"../../core/base-provider-llm\";\nimport type { AnthropicProviderConfig } from \"../../types\";\nimport { clampPositive } from \"../../utils/validate\";\n/** Environment variable names for Anthropic configuration. */\nconst ANTHROPIC_ENV = { API_KEY: \"ANTHROPIC_API_KEY\" } as const;\n\n/** Default max tokens for Anthropic requests. */\nconst DEFAULT_ANTHROPIC_MAX_TOKENS = 4096;\n\n/** Model patterns for Anthropic models. Matches claude-* */\nexport const ANTHROPIC_MODEL_PATTERNS = [/claude-.*/];\nimport { convertAnthropicRequest } from \"./converters/request\";\nimport {\n convertAnthropicResponse,\n convertAnthropicStreamEvent,\n createAnthropicStreamAccumulator,\n} from \"./converters/response\";\n\n/**\n * Anthropic (Claude) LLM provider.\n *\n * Provides direct access to Anthropic's Messages API for Claude models.\n * Unlike OpenAI-compatible providers, this uses the native Anthropic SDK\n * with custom request/response converters.\n *\n * Configuration priority (highest to lowest):\n * 1. Instance configuration (passed to constructor)\n * 2. Global configuration (via `setProviderConfig(\"anthropic\", {...})`)\n * 3. Environment variables (`ANTHROPIC_API_KEY`)\n *\n * @example\n * ```typescript\n * // Basic usage\n * const llm = new AnthropicLlm({ model: \"claude-sonnet-4-5-20250929\" });\n *\n * // With max tokens\n * const llm = new AnthropicLlm({\n * model: \"claude-sonnet-4-5-20250929\",\n * apiKey: \"...\",\n * maxTokens: 8192\n * });\n * ```\n *\n * @see {@link Anthropic} for the recommended factory function\n * @see {@link registerAnthropic} for LLMRegistry integration\n */\nexport class AnthropicLlm extends BaseProviderLlm {\n /**\n * Model patterns supported by this provider.\n *\n * Used by ADK's LLMRegistry to match model strings to this provider.\n * Matches: claude-*\n *\n * @static\n */\n static readonly supportedModels = ANTHROPIC_MODEL_PATTERNS;\n\n /**\n * The Anthropic SDK client instance.\n *\n * @private\n */\n private readonly client: AnthropicSDK;\n\n /**\n * Maximum tokens to generate in responses.\n *\n * @private\n */\n private readonly maxTokens: number;\n\n /**\n * Creates a new Anthropic LLM instance.\n *\n * @param config - Configuration options for the Anthropic provider\n *\n * @example\n * ```typescript\n * const llm = new AnthropicLlm({\n * model: \"claude-sonnet-4-5-20250929\",\n * apiKey: process.env.ANTHROPIC_API_KEY,\n * maxTokens: 4096\n * });\n * ```\n */\n constructor(config: AnthropicProviderConfig) {\n super(config);\n\n const globalConfig = getProviderConfig(\"anthropic\") ?? {};\n\n const apiKey =\n config.apiKey ??\n globalConfig.apiKey ??\n process.env[ANTHROPIC_ENV.API_KEY] ??\n \"\";\n\n if (!apiKey) {\n throw new Error(\n `[anthropic] API key is required. Provide it via config, ` +\n `setProviderConfig(\"anthropic\", { apiKey }), or set the ANTHROPIC_API_KEY env var.`,\n );\n }\n\n this.maxTokens = clampPositive(\n config.maxTokens ?? globalConfig.maxTokens ?? DEFAULT_ANTHROPIC_MAX_TOKENS,\n DEFAULT_ANTHROPIC_MAX_TOKENS,\n 1,\n );\n\n this.client = new AnthropicSDK({\n apiKey,\n timeout: clampPositive(\n config.timeout ?? DEFAULT_TIMEOUT,\n DEFAULT_TIMEOUT,\n 1000,\n ),\n maxRetries: clampPositive(\n config.maxRetries ?? DEFAULT_MAX_RETRIES,\n DEFAULT_MAX_RETRIES,\n 0,\n ),\n });\n }\n\n /**\n * Generates content from the Anthropic API.\n *\n * Converts the ADK request to Anthropic format, makes the API call,\n * and converts the response back to ADK format.\n *\n * @param llmRequest - The ADK LLM request\n * @param stream - Whether to stream the response (default: false)\n * @returns An async generator yielding LLM responses\n */\n async *generateContentAsync(\n llmRequest: LlmRequest,\n stream = false,\n ): AsyncGenerator<LlmResponse, void> {\n try {\n const { messages, system, tools } = convertAnthropicRequest(llmRequest);\n\n if (stream) {\n yield* this.streamResponse(messages, system, tools);\n } else {\n yield await this.singleResponse(messages, system, tools);\n }\n } catch (error) {\n yield this.createErrorResponse(error, \"ANTHROPIC\");\n }\n }\n\n /**\n * Builds the shared request parameters for the Anthropic API.\n *\n * @private\n */\n private buildRequestParams(\n messages: AnthropicSDK.MessageParam[],\n system: string | undefined,\n tools: AnthropicSDK.Tool[] | undefined,\n ) {\n return {\n model: this.model,\n max_tokens: this.maxTokens,\n messages,\n ...(system ? { system } : {}),\n ...(tools?.length ? { tools } : {}),\n };\n }\n\n /**\n * Makes a single (non-streaming) API request.\n *\n * @private\n */\n private async singleResponse(\n messages: AnthropicSDK.MessageParam[],\n system: string | undefined,\n tools: AnthropicSDK.Tool[] | undefined,\n ): Promise<LlmResponse> {\n const response = await this.client.messages.create(\n this.buildRequestParams(messages, system, tools),\n );\n return convertAnthropicResponse(response);\n }\n\n /**\n * Makes a streaming API request and yields responses as they arrive.\n *\n * @private\n */\n private async *streamResponse(\n messages: AnthropicSDK.MessageParam[],\n system: string | undefined,\n tools: AnthropicSDK.Tool[] | undefined,\n ): AsyncGenerator<LlmResponse, void> {\n const stream = this.client.messages.stream(\n this.buildRequestParams(messages, system, tools),\n );\n\n const acc = createAnthropicStreamAccumulator();\n\n for await (const event of stream) {\n const { response, isComplete } = convertAnthropicStreamEvent(event, acc);\n if (response) yield response;\n if (isComplete) break;\n }\n }\n}\n",
27
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Request converter for ADK to Anthropic Messages API format.\n *\n * This module handles the conversion of ADK LlmRequest objects to\n * Anthropic's Messages API format.\n *\n * Key differences from OpenAI format:\n * - System instruction is a separate field, not a message\n * - Tools have a different schema format\n * - Content can be an array of content blocks\n *\n * @module providers/anthropic/converters/request\n */\n\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport type { LlmRequest } from \"@google/adk\";\nimport type { Content, Part } from \"@google/genai\";\n\n/**\n * Result of converting an ADK LlmRequest to Anthropic format.\n */\nexport interface ConvertedAnthropicRequest {\n /**\n * Array of Anthropic-format messages.\n */\n messages: Anthropic.MessageParam[];\n\n /**\n * System instruction as a string (Anthropic uses separate field).\n */\n system?: string;\n\n /**\n * Array of Anthropic-format tool definitions.\n */\n tools?: Anthropic.Tool[];\n}\n\n/**\n * Converts an ADK LlmRequest to Anthropic Messages API format.\n *\n * Handles:\n * - System instruction extraction (as separate field)\n * - User and assistant message conversion\n * - Function call and response handling\n * - Tool/function declaration conversion\n *\n * @param llmRequest - The ADK LlmRequest to convert\n * @returns The converted request with messages, system, and optional tools\n */\nexport function convertAnthropicRequest(\n llmRequest: LlmRequest,\n): ConvertedAnthropicRequest {\n const messages: Anthropic.MessageParam[] = [];\n\n // Extract system instruction as separate field\n const system = extractSystemInstruction(llmRequest);\n\n // Process contents into messages\n for (const content of llmRequest.contents ?? []) {\n const msg = processContent(content);\n if (msg) {\n messages.push(msg);\n }\n }\n\n // Ensure first message is from user (Anthropic requirement)\n if (messages.length > 0 && messages[0].role !== \"user\") {\n messages.unshift({\n role: \"user\",\n content: \"[System: Continue conversation]\",\n });\n }\n\n return {\n messages,\n system: system || undefined,\n tools: convertTools(llmRequest),\n };\n}\n\n/**\n * Extracts the system instruction from an LlmRequest.\n */\nfunction extractSystemInstruction(req: LlmRequest): string | null {\n const sys = req.config?.systemInstruction;\n if (!sys) return null;\n if (typeof sys === \"string\") return sys;\n if (\"parts\" in sys) return extractText(sys.parts ?? []);\n return null;\n}\n\n/**\n * Extracts text from an array of Parts.\n */\nfunction extractText(parts: Part[]): string {\n return parts\n .map((p) => p.text)\n .filter(Boolean)\n .join(\"\\n\");\n}\n\n/**\n * Processes a Content object and returns an Anthropic message.\n */\nfunction processContent(content: Content): Anthropic.MessageParam | null {\n if (!content.parts?.length) return null;\n\n const contentBlocks: Anthropic.ContentBlockParam[] = [];\n\n for (const part of content.parts) {\n if (part.text) {\n contentBlocks.push({ type: \"text\", text: part.text });\n }\n\n if (part.functionCall) {\n if (!part.functionCall.id) {\n console.warn(\n \"[adk-llm-bridge] functionCall missing id, using generated ID\",\n );\n }\n if (!part.functionCall.name) {\n console.warn(\"[adk-llm-bridge] functionCall missing name\");\n }\n contentBlocks.push({\n type: \"tool_use\",\n id: part.functionCall.id ?? crypto.randomUUID(),\n name: part.functionCall.name ?? \"\",\n input: part.functionCall.args ?? {},\n });\n }\n\n if (part.functionResponse) {\n if (!part.functionResponse.id) {\n console.warn(\n \"[adk-llm-bridge] functionResponse missing id, using generated ID\",\n );\n }\n contentBlocks.push({\n type: \"tool_result\",\n tool_use_id: part.functionResponse.id ?? crypto.randomUUID(),\n content: JSON.stringify(part.functionResponse.response ?? {}),\n });\n }\n }\n\n if (contentBlocks.length === 0) return null;\n\n // Map ADK role to Anthropic role\n const role = content.role === \"model\" ? \"assistant\" : \"user\";\n\n return {\n role,\n content: contentBlocks,\n };\n}\n\n/**\n * Converts ADK tool declarations to Anthropic format.\n */\nfunction convertTools(req: LlmRequest): Anthropic.Tool[] | undefined {\n const adkTools = req.config?.tools;\n if (!adkTools?.length) return undefined;\n\n const tools: Anthropic.Tool[] = [];\n\n for (const group of adkTools) {\n if (\n \"functionDeclarations\" in group &&\n Array.isArray(group.functionDeclarations)\n ) {\n for (const fn of group.functionDeclarations) {\n if (!fn.name) {\n console.warn(\"[adk-llm-bridge] Tool function missing name, skipping\");\n continue;\n }\n tools.push({\n name: fn.name,\n description: fn.description ?? \"\",\n input_schema: normalizeSchema(fn.parameters) ?? {\n type: \"object\",\n properties: {},\n },\n });\n }\n }\n }\n\n return tools.length ? tools : undefined;\n}\n\n/**\n * Normalizes Gemini-style schema to Anthropic-style schema.\n *\n * Converts UPPERCASE type names to lowercase.\n */\nfunction normalizeSchema(\n schema: unknown,\n): Anthropic.Tool.InputSchema | undefined {\n if (!schema || typeof schema !== \"object\") return undefined;\n\n const result: Record<string, unknown> = {};\n const input = schema as Record<string, unknown>;\n\n for (const [key, value] of Object.entries(input)) {\n if (key === \"type\" && typeof value === \"string\") {\n result[key] = value.toLowerCase();\n } else if (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value)\n ) {\n result[key] = normalizeSchema(value);\n } else if (Array.isArray(value)) {\n result[key] = value;\n } else {\n result[key] = value;\n }\n }\n\n return result as Anthropic.Tool.InputSchema;\n}\n",
28
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Response converter for Anthropic Messages API to ADK format.\n *\n * This module handles the conversion of Anthropic API responses to\n * ADK LlmResponse format, supporting both single responses and streaming.\n *\n * @module providers/anthropic/converters/response\n */\n\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport type { LlmResponse } from \"@google/adk\";\nimport type { Part } from \"@google/genai\";\nimport { safeJsonParse } from \"../../../utils\";\n\n/**\n * Accumulator for Anthropic streaming responses.\n */\nexport interface AnthropicStreamAccumulator {\n /** Accumulated text content */\n text: string;\n\n /** Accumulated tool uses */\n toolUses: Map<\n number,\n {\n id: string;\n name: string;\n input: string;\n }\n >;\n\n /** Current content block index being processed */\n currentBlockIndex: number;\n\n /** Input tokens from message_start event */\n inputTokens?: number;\n\n /** Output tokens accumulated during streaming */\n outputTokens?: number;\n}\n\n/**\n * Result from processing an Anthropic stream event.\n */\nexport interface AnthropicStreamResult {\n /** The LLM response, if any */\n response?: LlmResponse;\n\n /** Whether the stream is complete */\n isComplete: boolean;\n}\n\n/**\n * Converts an Anthropic Message response to ADK LlmResponse format.\n *\n * @param message - The Anthropic Message response\n * @returns The converted ADK LlmResponse\n */\nexport function convertAnthropicResponse(\n message: Anthropic.Message,\n): LlmResponse {\n const parts: Part[] = [];\n\n for (const block of message.content) {\n if (block.type === \"text\") {\n parts.push({ text: block.text });\n }\n\n if (block.type === \"tool_use\") {\n const input =\n typeof block.input === \"object\" && block.input !== null\n ? (block.input as Record<string, unknown>)\n : {};\n parts.push({\n functionCall: {\n id: block.id,\n name: block.name,\n args: input,\n },\n });\n }\n }\n\n return {\n content: parts.length ? { role: \"model\", parts } : undefined,\n turnComplete: true,\n usageMetadata: message.usage\n ? {\n promptTokenCount: message.usage.input_tokens,\n candidatesTokenCount: message.usage.output_tokens,\n totalTokenCount:\n message.usage.input_tokens + message.usage.output_tokens,\n }\n : undefined,\n };\n}\n\n/**\n * Creates a new stream accumulator for Anthropic responses.\n */\nexport function createAnthropicStreamAccumulator(): AnthropicStreamAccumulator {\n return {\n text: \"\",\n toolUses: new Map(),\n currentBlockIndex: -1,\n inputTokens: undefined,\n outputTokens: undefined,\n };\n}\n\n/**\n * Processes an Anthropic streaming event and returns the appropriate response.\n *\n * @param event - The Anthropic stream event\n * @param acc - The stream accumulator\n * @returns Object containing optional response and completion status\n */\nexport function convertAnthropicStreamEvent(\n event: Anthropic.MessageStreamEvent,\n acc: AnthropicStreamAccumulator,\n): AnthropicStreamResult {\n switch (event.type) {\n case \"message_start\": {\n // Capture input tokens from message_start event\n if (event.message?.usage?.input_tokens) {\n acc.inputTokens = event.message.usage.input_tokens;\n }\n return { isComplete: false };\n }\n\n case \"message_delta\": {\n // Capture output tokens from message_delta event\n if (event.usage?.output_tokens) {\n acc.outputTokens = event.usage.output_tokens;\n }\n return { isComplete: false };\n }\n\n case \"content_block_start\": {\n acc.currentBlockIndex = event.index;\n\n if (event.content_block.type === \"tool_use\") {\n acc.toolUses.set(event.index, {\n id: event.content_block.id,\n name: event.content_block.name,\n input: \"\",\n });\n }\n\n return { isComplete: false };\n }\n\n case \"content_block_delta\": {\n const delta = event.delta;\n\n if (delta.type === \"text_delta\") {\n acc.text += delta.text;\n return {\n response: {\n content: { role: \"model\", parts: [{ text: delta.text }] },\n partial: true,\n },\n isComplete: false,\n };\n }\n\n if (delta.type === \"input_json_delta\") {\n const toolUse = acc.toolUses.get(event.index);\n if (toolUse) {\n toolUse.input += delta.partial_json;\n }\n }\n\n return { isComplete: false };\n }\n\n case \"message_stop\": {\n // Build final response with accumulated content\n const parts: Part[] = [];\n\n if (acc.text) {\n parts.push({ text: acc.text });\n }\n\n for (const toolUse of acc.toolUses.values()) {\n if (toolUse.name) {\n parts.push({\n functionCall: {\n id: toolUse.id,\n name: toolUse.name,\n args: safeJsonParse(toolUse.input),\n },\n });\n }\n }\n\n // Build usage metadata if available\n const hasUsage =\n acc.inputTokens !== undefined || acc.outputTokens !== undefined;\n const usageMetadata = hasUsage\n ? {\n promptTokenCount: acc.inputTokens ?? 0,\n candidatesTokenCount: acc.outputTokens ?? 0,\n totalTokenCount: (acc.inputTokens ?? 0) + (acc.outputTokens ?? 0),\n }\n : undefined;\n\n // Reset accumulator\n acc.text = \"\";\n acc.toolUses.clear();\n acc.currentBlockIndex = -1;\n acc.inputTokens = undefined;\n acc.outputTokens = undefined;\n\n return {\n response: {\n content: parts.length ? { role: \"model\", parts } : undefined,\n turnComplete: true,\n usageMetadata,\n },\n isComplete: true,\n };\n }\n\n default:\n return { isComplete: false };\n }\n}",
29
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Custom LLM provider implementation.\n *\n * This module provides an LLM class for connecting to any API that implements\n * the OpenAI chat completions interface, such as Ollama, LM Studio, vLLM,\n * Azure OpenAI, or self-hosted models.\n *\n * @module providers/custom/custom-llm\n */\n\nimport { DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT } from \"../../constants\";\nimport { OpenAICompatibleLlm } from \"../../core/openai-compatible-llm\";\nimport type { CustomLlmConfig } from \"../../types\";\nimport { clampPositive, requireValidURL } from \"../../utils/validate\";\n\n/**\n * Configuration type with required baseURL for custom providers.\n *\n * Unlike built-in providers (AI Gateway, OpenRouter) which have default URLs,\n * custom providers require an explicit baseURL.\n */\nexport type CustomLlmProviderConfig = CustomLlmConfig & {\n /**\n * Base URL for the API endpoint (required).\n *\n * @example \"http://localhost:11434/v1\" // Ollama\n * @example \"http://localhost:8000/v1\" // vLLM\n * @example \"https://my-resource.openai.azure.com/openai/deployments/gpt-4\" // Azure\n */\n baseURL: string;\n};\n\n/**\n * LLM implementation for any API that supports the chat completions interface.\n *\n * This provider allows connecting to any API that implements the OpenAI\n * chat completions interface. Use this for:\n *\n * - **Local models**: Ollama, LM Studio, vLLM, llama.cpp\n * - **Cloud providers**: Azure OpenAI, Together AI, Anyscale\n * - **Self-hosted**: Any compatible server\n *\n * Unlike AI Gateway and OpenRouter, this provider:\n * - Requires explicit `baseURL` configuration\n * - Does not use environment variables for defaults\n * - Supports custom headers and query parameters\n *\n * @example\n * ```typescript\n * // Ollama\n * const llm = new CustomLlm({\n * name: \"ollama\",\n * model: \"llama3\",\n * baseURL: \"http://localhost:11434/v1\"\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Azure OpenAI\n * const llm = new CustomLlm({\n * name: \"azure\",\n * model: \"gpt-4\",\n * baseURL: \"https://my-resource.openai.azure.com/openai/deployments/gpt-4\",\n * headers: { \"api-key\": process.env.AZURE_API_KEY },\n * queryParams: { \"api-version\": \"2024-02-01\" }\n * });\n * ```\n *\n * @see {@link createCustomLlm} for the factory function\n * @see {@link Custom} for the shorthand alias\n */\nexport class CustomLlm extends OpenAICompatibleLlm {\n /**\n * Model patterns supported by this provider.\n *\n * Accepts any model identifier since different APIs use different naming conventions.\n *\n * @static\n */\n static readonly supportedModels = [/.*/];\n\n /**\n * Provider name used for error prefixes.\n *\n * @private\n */\n private readonly providerName: string;\n\n /**\n * Provider-specific options to include in requests.\n *\n * @private\n */\n private readonly providerOptionsConfig?: Record<string, unknown>;\n\n /**\n * Creates a new custom LLM provider instance.\n *\n * @param config - Configuration options including model, baseURL, and optional settings\n *\n * @example\n * ```typescript\n * const llm = new CustomLlm({\n * name: \"vllm\",\n * model: \"meta-llama/Llama-3-8b\",\n * baseURL: \"http://localhost:8000/v1\"\n * });\n * ```\n */\n constructor(config: CustomLlmProviderConfig) {\n const providerName = config.name ?? \"custom\";\n\n requireValidURL(config.baseURL, \"baseURL\", providerName);\n\n // Build final URL with query params if provided\n let finalBaseURL = config.baseURL;\n if (config.queryParams && Object.keys(config.queryParams).length > 0) {\n const url = new URL(config.baseURL);\n for (const [key, value] of Object.entries(config.queryParams)) {\n url.searchParams.append(key, value);\n }\n finalBaseURL = url.toString();\n }\n\n super(config, {\n baseURL: finalBaseURL,\n apiKey: config.apiKey ?? \"\",\n timeout: clampPositive(config.timeout ?? DEFAULT_TIMEOUT, DEFAULT_TIMEOUT, 1000),\n maxRetries: clampPositive(config.maxRetries ?? DEFAULT_MAX_RETRIES, DEFAULT_MAX_RETRIES, 0),\n defaultHeaders: config.headers,\n });\n\n this.providerName = config.name ?? \"CUSTOM\";\n this.providerOptionsConfig = config.providerOptions;\n }\n\n /**\n * Returns the error prefix for this provider.\n *\n * Sanitizes the provider name to create a valid error code prefix.\n * For example, \"my-provider\" becomes \"MY_PROVIDER\".\n *\n * @returns The sanitized provider name in uppercase\n * @protected\n */\n protected getErrorPrefix(): string {\n const sanitized = this.providerName\n .toUpperCase()\n .replace(/[^A-Z0-9]/g, \"_\");\n return sanitized || \"CUSTOM\";\n }\n\n /**\n * Returns provider-specific options to include in requests.\n *\n * These options are spread into the chat completion request body,\n * allowing custom parameters beyond the standard OpenAI API.\n *\n * @returns The configured provider options or an empty object\n * @protected\n */\n protected getProviderRequestOptions(): Record<string, unknown> {\n return this.providerOptionsConfig ?? {};\n }\n}\n",
30
- "/**\n * @license\n * Copyright 2025 PAI\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * Factory functions for custom LLM providers.\n *\n * @module providers/custom/factory\n */\n\nimport type { CustomLlmConfig } from \"../../types\";\nimport { CustomLlm, type CustomLlmProviderConfig } from \"./custom-llm\";\n\n/**\n * Creates a custom LLM instance.\n *\n * This is the recommended way to connect to any API that implements\n * the chat completions interface. It provides a clean, functional API.\n *\n * @param config - Configuration options including model, baseURL, and optional settings\n * @returns A configured CustomLlm instance\n *\n * @example\n * ```typescript\n * // Ollama\n * const llm = createCustomLlm({\n * name: \"ollama\",\n * model: \"llama3\",\n * baseURL: \"http://localhost:11434/v1\"\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Azure OpenAI\n * const llm = createCustomLlm({\n * name: \"azure\",\n * model: \"gpt-4\",\n * baseURL: \"https://my-resource.openai.azure.com/openai/deployments/gpt-4\",\n * apiKey: process.env.AZURE_API_KEY,\n * headers: { \"api-key\": process.env.AZURE_API_KEY },\n * queryParams: { \"api-version\": \"2024-02-01\" }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // vLLM / LM Studio\n * const llm = createCustomLlm({\n * baseURL: \"http://localhost:8000/v1\",\n * model: \"meta-llama/Llama-3-8b\"\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With provider-specific options\n * const llm = createCustomLlm({\n * name: \"custom\",\n * model: \"my-model\",\n * baseURL: \"https://api.example.com/v1\",\n * apiKey: \"sk-...\",\n * providerOptions: {\n * temperature: 0.7,\n * custom_param: \"value\"\n * }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Use with ADK agent\n * import { LlmAgent } from \"@google/adk\";\n *\n * const agent = new LlmAgent({\n * name: \"assistant\",\n * model: createCustomLlm({\n * name: \"ollama\",\n * model: \"llama3\",\n * baseURL: \"http://localhost:11434/v1\"\n * }),\n * instruction: \"You are a helpful assistant.\"\n * });\n * ```\n *\n * @see {@link CustomLlm} for direct class usage\n * @see {@link Custom} for a shorthand alias\n */\nexport function createCustomLlm(config: CustomLlmProviderConfig): CustomLlm {\n return new CustomLlm(config);\n}\n\n/**\n * Configuration options for the Custom factory (model is specified separately).\n */\ntype CustomOptions = Omit<CustomLlmConfig, \"model\"> & {\n /**\n * Base URL for the API endpoint (required).\n */\n baseURL: string;\n};\n\n/**\n * Creates a custom LLM instance with a shorthand syntax.\n *\n * This is an alias for `createCustomLlm` that takes the model\n * as the first argument, similar to the `AIGateway` and `OpenRouter`\n * factory functions.\n *\n * @param model - The model identifier\n * @param options - Configuration options including baseURL and optional settings\n * @returns A configured CustomLlm instance\n *\n * @example\n * ```typescript\n * // Simple usage\n * const llm = Custom(\"llama3\", {\n * baseURL: \"http://localhost:11434/v1\"\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With full options\n * const llm = Custom(\"gpt-4\", {\n * name: \"azure\",\n * baseURL: \"https://my-resource.openai.azure.com/openai/deployments/gpt-4\",\n * apiKey: process.env.AZURE_API_KEY,\n * headers: { \"api-key\": process.env.AZURE_API_KEY },\n * queryParams: { \"api-version\": \"2024-02-01\" }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Use with ADK agent\n * import { LlmAgent } from \"@google/adk\";\n *\n * const agent = new LlmAgent({\n * name: \"assistant\",\n * model: Custom(\"llama3\", { baseURL: \"http://localhost:11434/v1\" }),\n * instruction: \"You are a helpful assistant.\"\n * });\n * ```\n *\n * @see {@link createCustomLlm} for the full configuration syntax\n */\nexport function Custom(model: string, options: CustomOptions): CustomLlm {\n return createCustomLlm({ model, ...options });\n}\n"
31
5
  ],
32
- "mappings": "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",
33
- "debugId": "50BA85D913D4D1B664756E2164756E21",
6
+ "mappings": "",
7
+ "debugId": "5830DDF6248C5A4D64756E2164756E21",
34
8
  "names": []
35
9
  }
@@ -3,6 +3,6 @@
3
3
  * Copyright 2025 PAI
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
- import type { ProviderDefinition } from "../../core/provider-definition";
6
+ import type { ProviderDefinition } from "../../core/provider-definition.js";
7
7
  export declare const AI_GATEWAY_DEFINITION: ProviderDefinition;
8
8
  //# sourceMappingURL=definition.d.ts.map
@@ -1,10 +1,10 @@
1
- export { AI_GATEWAY_DEFINITION } from "./definition";
1
+ export { AI_GATEWAY_DEFINITION } from "./definition.js";
2
2
  export declare const AIGatewayLlm: (new (params: {
3
3
  model: string;
4
4
  }) => import("@google/adk").BaseLlm) & {
5
5
  readonly supportedModels: (string | RegExp)[];
6
6
  };
7
- export declare const AIGateway: (model: string, options?: Partial<Omit<import("../..").BaseProviderConfig, "model">>) => import("../..").OpenAICompatibleLlm;
7
+ export declare const AIGateway: (model: string, options?: Partial<Omit<import("../../index.js").BaseProviderConfig, "model">>) => import("../../index.js").OpenAICompatibleLlm;
8
8
  export declare const registerAIGateway: (options?: Record<string, unknown>) => void;
9
9
  export declare const isAIGatewayRegistered: () => boolean;
10
10
  export declare const _resetAIGatewayRegistration: () => void;
@@ -4,8 +4,8 @@
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
6
  import type { LlmRequest, LlmResponse } from "@google/adk";
7
- import { BaseProviderLlm } from "../../core/base-provider-llm";
8
- import type { AnthropicProviderConfig } from "../../types";
7
+ import { BaseProviderLlm } from "../../core/base-provider-llm.js";
8
+ import type { AnthropicProviderConfig } from "../../types.js";
9
9
  /** Model patterns for Anthropic models. Matches claude-* */
10
10
  export declare const ANTHROPIC_MODEL_PATTERNS: RegExp[];
11
11
  /**
@@ -3,13 +3,13 @@
3
3
  * Copyright 2025 PAI
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
- import type { AnthropicProviderConfig, AnthropicRegisterOptions } from "../../types";
7
- import { AnthropicLlm } from "./anthropic-llm";
8
- export { AnthropicLlm, ANTHROPIC_MODEL_PATTERNS } from "./anthropic-llm";
9
- export type { ConvertedAnthropicRequest } from "./converters/request";
10
- export { convertAnthropicRequest } from "./converters/request";
11
- export type { AnthropicStreamAccumulator, AnthropicStreamResult, } from "./converters/response";
12
- export { convertAnthropicResponse, convertAnthropicStreamEvent, createAnthropicStreamAccumulator, } from "./converters/response";
6
+ import type { AnthropicProviderConfig, AnthropicRegisterOptions } from "../../types.js";
7
+ import { AnthropicLlm } from "./anthropic-llm.js";
8
+ export { AnthropicLlm, ANTHROPIC_MODEL_PATTERNS } from "./anthropic-llm.js";
9
+ export type { ConvertedAnthropicRequest } from "./converters/request.js";
10
+ export { convertAnthropicRequest } from "./converters/request.js";
11
+ export type { AnthropicStreamAccumulator, AnthropicStreamResult, } from "./converters/response.js";
12
+ export { convertAnthropicResponse, convertAnthropicStreamEvent, createAnthropicStreamAccumulator, } from "./converters/response.js";
13
13
  /**
14
14
  * Creates an Anthropic (Claude) LLM instance.
15
15
  *
@@ -3,8 +3,8 @@
3
3
  * Copyright 2025 PAI
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
- import { OpenAICompatibleLlm } from "../../core/openai-compatible-llm";
7
- import type { CustomLlmConfig } from "../../types";
6
+ import { OpenAICompatibleLlm } from "../../core/openai-compatible-llm.js";
7
+ import type { CustomLlmConfig } from "../../types.js";
8
8
  /**
9
9
  * Configuration type with required baseURL for custom providers.
10
10
  *
@@ -8,8 +8,8 @@
8
8
  *
9
9
  * @module providers/custom/factory
10
10
  */
11
- import type { CustomLlmConfig } from "../../types";
12
- import { CustomLlm, type CustomLlmProviderConfig } from "./custom-llm";
11
+ import type { CustomLlmConfig } from "../../types.js";
12
+ import { CustomLlm, type CustomLlmProviderConfig } from "./custom-llm.js";
13
13
  /**
14
14
  * Creates a custom LLM instance.
15
15
  *
@@ -30,6 +30,6 @@
30
30
  *
31
31
  * @module providers/custom
32
32
  */
33
- export { CustomLlm, type CustomLlmProviderConfig } from "./custom-llm";
34
- export { Custom, createCustomLlm } from "./factory";
33
+ export { CustomLlm, type CustomLlmProviderConfig } from "./custom-llm.js";
34
+ export { Custom, createCustomLlm } from "./factory.js";
35
35
  //# sourceMappingURL=index.d.ts.map