feat(ai): move API implementations to src/api with lazy wrappers (phase 2)
Stream implementations move from src/providers/ to src/api/, renamed by API id (anthropic.ts -> anthropic-messages.ts, google.ts -> google-generative-ai.ts, mistral.ts -> mistral-conversations.ts, amazon-bedrock.ts -> bedrock-converse-stream.ts). Every module now exports exactly stream/streamSimple; shared helpers move alongside. New ProviderStreams dispatch contract in types.ts, lazyApi() wrapper in api/lazy.ts, and one .lazy.ts wrapper per API. Bedrock's wrapper keeps the node-only variable-specifier import and setBedrockProviderModule() (now taking ProviderStreams). providers/register-builtins.ts deleted; interim until the compat entrypoint lands, builtin api-registry registration lives in stream.ts and lazy wrappers are exported from the root barrel. Old per-API lazy exports (streamAnthropic, ...) are gone; package.json subpaths retarget to dist/api/.
This commit is contained in:
@@ -33,23 +33,23 @@ packages/ai/src/
|
|||||||
auth/ # auth method types, helpers, login callbacks
|
auth/ # auth method types, helpers, login callbacks
|
||||||
api/ # API implementations and lazy wrappers
|
api/ # API implementations and lazy wrappers
|
||||||
openai-completions.ts # real implementation, imports SDKs, exports stream/streamSimple
|
openai-completions.ts # real implementation, imports SDKs, exports stream/streamSimple
|
||||||
openai-completions-lazy.ts
|
openai-completions.lazy.ts
|
||||||
openai-responses.ts
|
openai-responses.ts
|
||||||
openai-responses-lazy.ts
|
openai-responses.lazy.ts
|
||||||
openai-codex-responses.ts
|
openai-codex-responses.ts
|
||||||
openai-codex-responses-lazy.ts
|
openai-codex-responses.lazy.ts
|
||||||
azure-openai-responses.ts
|
azure-openai-responses.ts
|
||||||
azure-openai-responses-lazy.ts
|
azure-openai-responses.lazy.ts
|
||||||
anthropic-messages.ts
|
anthropic-messages.ts
|
||||||
anthropic-messages-lazy.ts
|
anthropic-messages.lazy.ts
|
||||||
google-generative-ai.ts
|
google-generative-ai.ts
|
||||||
google-generative-ai-lazy.ts
|
google-generative-ai.lazy.ts
|
||||||
google-vertex.ts
|
google-vertex.ts
|
||||||
google-vertex-lazy.ts
|
google-vertex.lazy.ts
|
||||||
mistral-conversations.ts
|
mistral-conversations.ts
|
||||||
mistral-conversations-lazy.ts
|
mistral-conversations.lazy.ts
|
||||||
bedrock-converse-stream.ts
|
bedrock-converse-stream.ts
|
||||||
bedrock-converse-stream-lazy.ts
|
bedrock-converse-stream.lazy.ts
|
||||||
lazy.ts # lazyStream()/lazyApi() helpers
|
lazy.ts # lazyStream()/lazyApi() helpers
|
||||||
(shared helpers: openai-responses-shared, google-shared, transform-messages, ...)
|
(shared helpers: openai-responses-shared, google-shared, transform-messages, ...)
|
||||||
providers/ # concrete provider factories and per-provider catalogs
|
providers/ # concrete provider factories and per-provider catalogs
|
||||||
@@ -315,22 +315,18 @@ export function stream(model, context, options) { ... }
|
|||||||
export function streamSimple(model, context, options) { ... }
|
export function streamSimple(model, context, options) { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
This makes the module itself satisfy `ProviderStreams`, so the lazy wrapper is one generic helper instead of bespoke per-API plumbing:
|
This makes the module itself satisfy `ProviderStreams`, so the lazy wrapper is one generic helper instead of bespoke per-API plumbing. `ProviderStreams` is the untyped dispatch shape (implementation modules export concretely typed functions, which would not be assignable to a generic method); per-API option typing lives on the modules themselves and on `Provider.stream()` via `ApiStreamOptions`:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
export interface ProviderStreams {
|
export interface ProviderStreams {
|
||||||
stream<TApi extends Api>(
|
stream(model: Model<Api>, context: Context, options?: StreamOptions): AssistantMessageEventStream;
|
||||||
model: Model<TApi>,
|
|
||||||
context: Context,
|
|
||||||
options?: ApiStreamOptions<TApi>,
|
|
||||||
): AssistantMessageEventStream;
|
|
||||||
streamSimple(model: Model<Api>, context: Context, options?: SimpleStreamOptions): AssistantMessageEventStream;
|
streamSimple(model: Model<Api>, context: Context, options?: SimpleStreamOptions): AssistantMessageEventStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/api/lazy.ts
|
// src/api/lazy.ts
|
||||||
export function lazyApi(load: () => Promise<ProviderStreams>): ProviderStreams;
|
export function lazyApi(load: () => Promise<ProviderStreams>): ProviderStreams;
|
||||||
|
|
||||||
// src/api/anthropic-messages-lazy.ts
|
// src/api/anthropic-messages.lazy.ts
|
||||||
export const anthropicMessagesApi = (): ProviderStreams => lazyApi(() => import("./anthropic-messages.ts"));
|
export const anthropicMessagesApi = (): ProviderStreams => lazyApi(() => import("./anthropic-messages.ts"));
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -350,7 +346,7 @@ Notes:
|
|||||||
Many concrete providers share an API implementation (OpenAI-completions: OpenRouter, Groq, Cerebras, xAI, ZAI, ...). They share lazy API objects by reference:
|
Many concrete providers share an API implementation (OpenAI-completions: OpenRouter, Groq, Cerebras, xAI, ZAI, ...). They share lazy API objects by reference:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { openAICompletionsApi } from "../api/openai-completions-lazy.ts";
|
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||||
|
|
||||||
export function openrouterProvider(): Provider {
|
export function openrouterProvider(): Provider {
|
||||||
return createProvider({
|
return createProvider({
|
||||||
@@ -804,12 +800,12 @@ Check items off as they land. Keep this list current; it is the working state fo
|
|||||||
|
|
||||||
### Phase 2 — `src/api/`
|
### Phase 2 — `src/api/`
|
||||||
|
|
||||||
- [ ] Move stream implementations from `src/providers/` to `src/api/`, renamed by API id (`anthropic.ts` -> `api/anthropic-messages.ts`, etc.).
|
- [x] Move stream implementations from `src/providers/` to `src/api/`, renamed by API id (`anthropic.ts` -> `api/anthropic-messages.ts`, etc.).
|
||||||
- [ ] Normalize each implementation module to export exactly `stream` and `streamSimple`.
|
- [x] Normalize each implementation module to export exactly `stream` and `streamSimple`.
|
||||||
- [ ] Move shared helpers (`openai-responses-shared`, `google-shared`, `transform-messages`, `openai-prompt-cache`, `github-copilot-headers`) to `src/api/`.
|
- [x] Move shared helpers (`openai-responses-shared`, `google-shared`, `transform-messages`, `openai-prompt-cache`, `github-copilot-headers`, `cloudflare`, `simple-options`) to `src/api/`.
|
||||||
- [ ] Extract `lazyStream()`/`lazyApi()` into `src/api/lazy.ts`.
|
- [x] Extract `lazyStream()`/`lazyApi()` into `src/api/lazy.ts`.
|
||||||
- [ ] Add `*-lazy.ts` wrappers per API; bedrock keeps node-only import trick and `setBedrockProviderModule()`.
|
- [x] Add `*.lazy.ts` wrappers per API; bedrock keeps node-only import trick and `setBedrockProviderModule()`.
|
||||||
- [ ] Delete `providers/register-builtins.ts`.
|
- [x] Delete `providers/register-builtins.ts`. Interim until Phase 5 compat: builtin api-registry registration lives in `stream.ts`; lazy API wrappers are exported from the root barrel.
|
||||||
|
|
||||||
### Phase 3 — provider factories + catalogs
|
### Phase 3 — provider factories + catalogs
|
||||||
|
|
||||||
|
|||||||
+16
-16
@@ -11,36 +11,36 @@
|
|||||||
"import": "./dist/index.js"
|
"import": "./dist/index.js"
|
||||||
},
|
},
|
||||||
"./anthropic": {
|
"./anthropic": {
|
||||||
"types": "./dist/providers/anthropic.d.ts",
|
"types": "./dist/api/anthropic-messages.d.ts",
|
||||||
"import": "./dist/providers/anthropic.js"
|
"import": "./dist/api/anthropic-messages.js"
|
||||||
},
|
},
|
||||||
"./azure-openai-responses": {
|
"./azure-openai-responses": {
|
||||||
"types": "./dist/providers/azure-openai-responses.d.ts",
|
"types": "./dist/api/azure-openai-responses.d.ts",
|
||||||
"import": "./dist/providers/azure-openai-responses.js"
|
"import": "./dist/api/azure-openai-responses.js"
|
||||||
},
|
},
|
||||||
"./google": {
|
"./google": {
|
||||||
"types": "./dist/providers/google.d.ts",
|
"types": "./dist/api/google-generative-ai.d.ts",
|
||||||
"import": "./dist/providers/google.js"
|
"import": "./dist/api/google-generative-ai.js"
|
||||||
},
|
},
|
||||||
"./google-vertex": {
|
"./google-vertex": {
|
||||||
"types": "./dist/providers/google-vertex.d.ts",
|
"types": "./dist/api/google-vertex.d.ts",
|
||||||
"import": "./dist/providers/google-vertex.js"
|
"import": "./dist/api/google-vertex.js"
|
||||||
},
|
},
|
||||||
"./mistral": {
|
"./mistral": {
|
||||||
"types": "./dist/providers/mistral.d.ts",
|
"types": "./dist/api/mistral-conversations.d.ts",
|
||||||
"import": "./dist/providers/mistral.js"
|
"import": "./dist/api/mistral-conversations.js"
|
||||||
},
|
},
|
||||||
"./openai-codex-responses": {
|
"./openai-codex-responses": {
|
||||||
"types": "./dist/providers/openai-codex-responses.d.ts",
|
"types": "./dist/api/openai-codex-responses.d.ts",
|
||||||
"import": "./dist/providers/openai-codex-responses.js"
|
"import": "./dist/api/openai-codex-responses.js"
|
||||||
},
|
},
|
||||||
"./openai-completions": {
|
"./openai-completions": {
|
||||||
"types": "./dist/providers/openai-completions.d.ts",
|
"types": "./dist/api/openai-completions.d.ts",
|
||||||
"import": "./dist/providers/openai-completions.js"
|
"import": "./dist/api/openai-completions.js"
|
||||||
},
|
},
|
||||||
"./openai-responses": {
|
"./openai-responses": {
|
||||||
"types": "./dist/providers/openai-responses.d.ts",
|
"types": "./dist/api/openai-responses.d.ts",
|
||||||
"import": "./dist/providers/openai-responses.js"
|
"import": "./dist/api/openai-responses.js"
|
||||||
},
|
},
|
||||||
"./oauth": {
|
"./oauth": {
|
||||||
"types": "./dist/oauth.d.ts",
|
"types": "./dist/oauth.d.ts",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
CLOUDFLARE_AI_GATEWAY_COMPAT_BASE_URL,
|
CLOUDFLARE_AI_GATEWAY_COMPAT_BASE_URL,
|
||||||
CLOUDFLARE_AI_GATEWAY_OPENAI_BASE_URL,
|
CLOUDFLARE_AI_GATEWAY_OPENAI_BASE_URL,
|
||||||
CLOUDFLARE_WORKERS_AI_BASE_URL,
|
CLOUDFLARE_WORKERS_AI_BASE_URL,
|
||||||
} from "../src/providers/cloudflare.ts";
|
} from "../src/api/cloudflare.ts";
|
||||||
import type { AnthropicMessagesCompat, Api, KnownProvider, Model, OpenAICompletionsCompat } from "../src/types.ts";
|
import type { AnthropicMessagesCompat, Api, KnownProvider, Model, OpenAICompletionsCompat } from "../src/types.ts";
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import type { ProviderStreams } from "../types.ts";
|
||||||
|
import { lazyApi } from "./lazy.ts";
|
||||||
|
|
||||||
|
export const anthropicMessagesApi = (): ProviderStreams => lazyApi(() => import("./anthropic-messages.ts"));
|
||||||
@@ -186,7 +186,7 @@ export interface AnthropicOptions extends StreamOptions {
|
|||||||
* Enable extended thinking.
|
* Enable extended thinking.
|
||||||
* For adaptive thinking models: the model decides when/how much to think.
|
* For adaptive thinking models: the model decides when/how much to think.
|
||||||
* For older models: uses budget-based thinking with thinkingBudgetTokens.
|
* For older models: uses budget-based thinking with thinkingBudgetTokens.
|
||||||
* Default: undefined (thinking is omitted unless `streamSimpleAnthropic()` maps
|
* Default: undefined (thinking is omitted unless `streamSimple()` maps
|
||||||
* a simple reasoning level to this option, or callers set it explicitly).
|
* a simple reasoning level to this option, or callers set it explicitly).
|
||||||
*/
|
*/
|
||||||
thinkingEnabled?: boolean;
|
thinkingEnabled?: boolean;
|
||||||
@@ -205,7 +205,7 @@ export interface AnthropicOptions extends StreamOptions {
|
|||||||
* - "medium": Moderate thinking, may skip for simple queries
|
* - "medium": Moderate thinking, may skip for simple queries
|
||||||
* - "low": Minimal thinking, skips for simple tasks
|
* - "low": Minimal thinking, skips for simple tasks
|
||||||
* Ignored for older models.
|
* Ignored for older models.
|
||||||
* Default: omitted unless `streamSimpleAnthropic()` maps a simple reasoning
|
* Default: omitted unless `streamSimple()` maps a simple reasoning
|
||||||
* level to this option.
|
* level to this option.
|
||||||
*/
|
*/
|
||||||
effort?: AnthropicEffort;
|
effort?: AnthropicEffort;
|
||||||
@@ -445,7 +445,7 @@ async function* iterateAnthropicEvents(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOptions> = (
|
export const stream: StreamFunction<"anthropic-messages", AnthropicOptions> = (
|
||||||
model: Model<"anthropic-messages">,
|
model: Model<"anthropic-messages">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: AnthropicOptions,
|
options?: AnthropicOptions,
|
||||||
@@ -733,7 +733,7 @@ function mapThinkingLevelToEffort(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const streamSimpleAnthropic: StreamFunction<"anthropic-messages", SimpleStreamOptions> = (
|
export const streamSimple: StreamFunction<"anthropic-messages", SimpleStreamOptions> = (
|
||||||
model: Model<"anthropic-messages">,
|
model: Model<"anthropic-messages">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: SimpleStreamOptions,
|
options?: SimpleStreamOptions,
|
||||||
@@ -745,14 +745,14 @@ export const streamSimpleAnthropic: StreamFunction<"anthropic-messages", SimpleS
|
|||||||
|
|
||||||
const base = buildBaseOptions(model, options, apiKey);
|
const base = buildBaseOptions(model, options, apiKey);
|
||||||
if (!options?.reasoning) {
|
if (!options?.reasoning) {
|
||||||
return streamAnthropic(model, context, { ...base, thinkingEnabled: false } satisfies AnthropicOptions);
|
return stream(model, context, { ...base, thinkingEnabled: false } satisfies AnthropicOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For models with adaptive thinking: use an effort level.
|
// For models with adaptive thinking: use an effort level.
|
||||||
// For older models: use budget-based thinking.
|
// For older models: use budget-based thinking.
|
||||||
if (model.compat?.forceAdaptiveThinking === true) {
|
if (model.compat?.forceAdaptiveThinking === true) {
|
||||||
const effort = mapThinkingLevelToEffort(model, options.reasoning);
|
const effort = mapThinkingLevelToEffort(model, options.reasoning);
|
||||||
return streamAnthropic(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
thinkingEnabled: true,
|
thinkingEnabled: true,
|
||||||
effort,
|
effort,
|
||||||
@@ -768,7 +768,7 @@ export const streamSimpleAnthropic: StreamFunction<"anthropic-messages", SimpleS
|
|||||||
options.thinkingBudgets,
|
options.thinkingBudgets,
|
||||||
);
|
);
|
||||||
|
|
||||||
return streamAnthropic(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
maxTokens: adjusted.maxTokens,
|
maxTokens: adjusted.maxTokens,
|
||||||
thinkingEnabled: true,
|
thinkingEnabled: true,
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import type { ProviderStreams } from "../types.ts";
|
||||||
|
import { lazyApi } from "./lazy.ts";
|
||||||
|
|
||||||
|
export const azureOpenAIResponsesApi = (): ProviderStreams => lazyApi(() => import("./azure-openai-responses.ts"));
|
||||||
+3
-3
@@ -69,7 +69,7 @@ export interface AzureOpenAIResponsesOptions extends StreamOptions {
|
|||||||
/**
|
/**
|
||||||
* Generate function for Azure OpenAI Responses API
|
* Generate function for Azure OpenAI Responses API
|
||||||
*/
|
*/
|
||||||
export const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses", AzureOpenAIResponsesOptions> = (
|
export const stream: StreamFunction<"azure-openai-responses", AzureOpenAIResponsesOptions> = (
|
||||||
model: Model<"azure-openai-responses">,
|
model: Model<"azure-openai-responses">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: AzureOpenAIResponsesOptions,
|
options?: AzureOpenAIResponsesOptions,
|
||||||
@@ -147,7 +147,7 @@ export const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses"
|
|||||||
return stream;
|
return stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const streamSimpleAzureOpenAIResponses: StreamFunction<"azure-openai-responses", SimpleStreamOptions> = (
|
export const streamSimple: StreamFunction<"azure-openai-responses", SimpleStreamOptions> = (
|
||||||
model: Model<"azure-openai-responses">,
|
model: Model<"azure-openai-responses">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: SimpleStreamOptions,
|
options?: SimpleStreamOptions,
|
||||||
@@ -161,7 +161,7 @@ export const streamSimpleAzureOpenAIResponses: StreamFunction<"azure-openai-resp
|
|||||||
const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
|
const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
|
||||||
const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
|
const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
|
||||||
|
|
||||||
return streamAzureOpenAIResponses(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
reasoningEffort,
|
reasoningEffort,
|
||||||
} satisfies AzureOpenAIResponsesOptions);
|
} satisfies AzureOpenAIResponsesOptions);
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import type { ProviderStreams } from "../types.ts";
|
||||||
|
import { lazyApi } from "./lazy.ts";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the bedrock implementation through a variable specifier so bundlers
|
||||||
|
* (browser smoke, Bun compile) cannot follow the import into the Node-only
|
||||||
|
* AWS SDK. The `.ts`/`.js` rewrite keeps the trick working from both source
|
||||||
|
* and built output.
|
||||||
|
*/
|
||||||
|
const importNodeOnlyApi = (specifier: string): Promise<unknown> => {
|
||||||
|
const runtimeSpecifier = import.meta.url.endsWith(".js") ? specifier.replace(/\.ts$/, ".js") : specifier;
|
||||||
|
return import(runtimeSpecifier);
|
||||||
|
};
|
||||||
|
|
||||||
|
let bedrockModuleOverride: ProviderStreams | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the dynamically imported bedrock implementation. Used by the Bun
|
||||||
|
* binary build, where the variable-specifier import cannot be bundled; the
|
||||||
|
* build registers a statically imported module instead.
|
||||||
|
*/
|
||||||
|
export function setBedrockProviderModule(module: ProviderStreams): void {
|
||||||
|
bedrockModuleOverride = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const bedrockConverseStreamApi = (): ProviderStreams =>
|
||||||
|
lazyApi(
|
||||||
|
async () =>
|
||||||
|
bedrockModuleOverride ?? ((await importNodeOnlyApi("./bedrock-converse-stream.ts")) as ProviderStreams),
|
||||||
|
);
|
||||||
+6
-6
@@ -90,7 +90,7 @@ type Block = (TextContent | ThinkingContent | ToolCall) & { index?: number; part
|
|||||||
|
|
||||||
const EMPTY_TEXT_PLACEHOLDER = "<empty>";
|
const EMPTY_TEXT_PLACEHOLDER = "<empty>";
|
||||||
|
|
||||||
export const streamBedrock: StreamFunction<"bedrock-converse-stream", BedrockOptions> = (
|
export const stream: StreamFunction<"bedrock-converse-stream", BedrockOptions> = (
|
||||||
model: Model<"bedrock-converse-stream">,
|
model: Model<"bedrock-converse-stream">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options: BedrockOptions = {},
|
options: BedrockOptions = {},
|
||||||
@@ -352,19 +352,19 @@ function addCustomHeadersMiddleware(client: BedrockRuntimeClient, headers: Recor
|
|||||||
client.middlewareStack.add(middleware, { step: "build", name: "pi-ai-custom-headers", priority: "low" });
|
client.middlewareStack.add(middleware, { step: "build", name: "pi-ai-custom-headers", priority: "low" });
|
||||||
}
|
}
|
||||||
|
|
||||||
export const streamSimpleBedrock: StreamFunction<"bedrock-converse-stream", SimpleStreamOptions> = (
|
export const streamSimple: StreamFunction<"bedrock-converse-stream", SimpleStreamOptions> = (
|
||||||
model: Model<"bedrock-converse-stream">,
|
model: Model<"bedrock-converse-stream">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: SimpleStreamOptions,
|
options?: SimpleStreamOptions,
|
||||||
): AssistantMessageEventStream => {
|
): AssistantMessageEventStream => {
|
||||||
const base = buildBaseOptions(model, options, undefined);
|
const base = buildBaseOptions(model, options, undefined);
|
||||||
if (!options?.reasoning) {
|
if (!options?.reasoning) {
|
||||||
return streamBedrock(model, context, { ...base, reasoning: undefined } satisfies BedrockOptions);
|
return stream(model, context, { ...base, reasoning: undefined } satisfies BedrockOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAnthropicClaudeModel(model)) {
|
if (isAnthropicClaudeModel(model)) {
|
||||||
if (supportsAdaptiveThinking(model.id, model.name)) {
|
if (supportsAdaptiveThinking(model.id, model.name)) {
|
||||||
return streamBedrock(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
reasoning: options.reasoning,
|
reasoning: options.reasoning,
|
||||||
thinkingBudgets: options.thinkingBudgets,
|
thinkingBudgets: options.thinkingBudgets,
|
||||||
@@ -380,7 +380,7 @@ export const streamSimpleBedrock: StreamFunction<"bedrock-converse-stream", Simp
|
|||||||
options.thinkingBudgets,
|
options.thinkingBudgets,
|
||||||
);
|
);
|
||||||
|
|
||||||
return streamBedrock(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
maxTokens: adjusted.maxTokens,
|
maxTokens: adjusted.maxTokens,
|
||||||
reasoning: options.reasoning,
|
reasoning: options.reasoning,
|
||||||
@@ -391,7 +391,7 @@ export const streamSimpleBedrock: StreamFunction<"bedrock-converse-stream", Simp
|
|||||||
} satisfies BedrockOptions);
|
} satisfies BedrockOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return streamBedrock(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
reasoning: options.reasoning,
|
reasoning: options.reasoning,
|
||||||
thinkingBudgets: options.thinkingBudgets,
|
thinkingBudgets: options.thinkingBudgets,
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import type { ProviderStreams } from "../types.ts";
|
||||||
|
import { lazyApi } from "./lazy.ts";
|
||||||
|
|
||||||
|
export const googleGenerativeAIApi = (): ProviderStreams => lazyApi(() => import("./google-generative-ai.ts"));
|
||||||
@@ -44,7 +44,7 @@ export interface GoogleOptions extends StreamOptions {
|
|||||||
// Counter for generating unique tool call IDs
|
// Counter for generating unique tool call IDs
|
||||||
let toolCallCounter = 0;
|
let toolCallCounter = 0;
|
||||||
|
|
||||||
export const streamGoogle: StreamFunction<"google-generative-ai", GoogleOptions> = (
|
export const stream: StreamFunction<"google-generative-ai", GoogleOptions> = (
|
||||||
model: Model<"google-generative-ai">,
|
model: Model<"google-generative-ai">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: GoogleOptions,
|
options?: GoogleOptions,
|
||||||
@@ -277,7 +277,7 @@ export const streamGoogle: StreamFunction<"google-generative-ai", GoogleOptions>
|
|||||||
return stream;
|
return stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const streamSimpleGoogle: StreamFunction<"google-generative-ai", SimpleStreamOptions> = (
|
export const streamSimple: StreamFunction<"google-generative-ai", SimpleStreamOptions> = (
|
||||||
model: Model<"google-generative-ai">,
|
model: Model<"google-generative-ai">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: SimpleStreamOptions,
|
options?: SimpleStreamOptions,
|
||||||
@@ -289,7 +289,7 @@ export const streamSimpleGoogle: StreamFunction<"google-generative-ai", SimpleSt
|
|||||||
|
|
||||||
const base = buildBaseOptions(model, options, apiKey);
|
const base = buildBaseOptions(model, options, apiKey);
|
||||||
if (!options?.reasoning) {
|
if (!options?.reasoning) {
|
||||||
return streamGoogle(model, context, { ...base, thinking: { enabled: false } } satisfies GoogleOptions);
|
return stream(model, context, { ...base, thinking: { enabled: false } } satisfies GoogleOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
const clampedReasoning = clampThinkingLevel(model, options.reasoning);
|
const clampedReasoning = clampThinkingLevel(model, options.reasoning);
|
||||||
@@ -297,7 +297,7 @@ export const streamSimpleGoogle: StreamFunction<"google-generative-ai", SimpleSt
|
|||||||
const googleModel = model as Model<"google-generative-ai">;
|
const googleModel = model as Model<"google-generative-ai">;
|
||||||
|
|
||||||
if (isGemini3ProModel(googleModel) || isGemini3FlashModel(googleModel) || isGemma4Model(googleModel)) {
|
if (isGemini3ProModel(googleModel) || isGemini3FlashModel(googleModel) || isGemma4Model(googleModel)) {
|
||||||
return streamGoogle(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
thinking: {
|
thinking: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -306,7 +306,7 @@ export const streamSimpleGoogle: StreamFunction<"google-generative-ai", SimpleSt
|
|||||||
} satisfies GoogleOptions);
|
} satisfies GoogleOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return streamGoogle(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
thinking: {
|
thinking: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import type { ProviderStreams } from "../types.ts";
|
||||||
|
import { lazyApi } from "./lazy.ts";
|
||||||
|
|
||||||
|
export const googleVertexApi = (): ProviderStreams => lazyApi(() => import("./google-vertex.ts"));
|
||||||
@@ -60,7 +60,7 @@ const THINKING_LEVEL_MAP: Record<GoogleThinkingLevel, ThinkingLevel> = {
|
|||||||
// Counter for generating unique tool call IDs
|
// Counter for generating unique tool call IDs
|
||||||
let toolCallCounter = 0;
|
let toolCallCounter = 0;
|
||||||
|
|
||||||
export const streamGoogleVertex: StreamFunction<"google-vertex", GoogleVertexOptions> = (
|
export const stream: StreamFunction<"google-vertex", GoogleVertexOptions> = (
|
||||||
model: Model<"google-vertex">,
|
model: Model<"google-vertex">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: GoogleVertexOptions,
|
options?: GoogleVertexOptions,
|
||||||
@@ -292,14 +292,14 @@ export const streamGoogleVertex: StreamFunction<"google-vertex", GoogleVertexOpt
|
|||||||
return stream;
|
return stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const streamSimpleGoogleVertex: StreamFunction<"google-vertex", SimpleStreamOptions> = (
|
export const streamSimple: StreamFunction<"google-vertex", SimpleStreamOptions> = (
|
||||||
model: Model<"google-vertex">,
|
model: Model<"google-vertex">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: SimpleStreamOptions,
|
options?: SimpleStreamOptions,
|
||||||
): AssistantMessageEventStream => {
|
): AssistantMessageEventStream => {
|
||||||
const base = buildBaseOptions(model, options, undefined);
|
const base = buildBaseOptions(model, options, undefined);
|
||||||
if (!options?.reasoning) {
|
if (!options?.reasoning) {
|
||||||
return streamGoogleVertex(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
thinking: { enabled: false },
|
thinking: { enabled: false },
|
||||||
} satisfies GoogleVertexOptions);
|
} satisfies GoogleVertexOptions);
|
||||||
@@ -310,7 +310,7 @@ export const streamSimpleGoogleVertex: StreamFunction<"google-vertex", SimpleStr
|
|||||||
const geminiModel = model as unknown as Model<"google-generative-ai">;
|
const geminiModel = model as unknown as Model<"google-generative-ai">;
|
||||||
|
|
||||||
if (isGemini3ProModel(geminiModel) || isGemini3FlashModel(geminiModel)) {
|
if (isGemini3ProModel(geminiModel) || isGemini3FlashModel(geminiModel)) {
|
||||||
return streamGoogleVertex(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
thinking: {
|
thinking: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -319,7 +319,7 @@ export const streamSimpleGoogleVertex: StreamFunction<"google-vertex", SimpleStr
|
|||||||
} satisfies GoogleVertexOptions);
|
} satisfies GoogleVertexOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return streamGoogleVertex(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
thinking: {
|
thinking: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { Api, AssistantMessage, AssistantMessageEvent, Model } from "../types.ts";
|
import type { Api, AssistantMessage, AssistantMessageEvent, Model, ProviderStreams } from "../types.ts";
|
||||||
import { AssistantMessageEventStream } from "../utils/event-stream.ts";
|
import { AssistantMessageEventStream } from "../utils/event-stream.ts";
|
||||||
|
|
||||||
function createSetupErrorMessage(model: Model<Api>, error: unknown): AssistantMessage {
|
function createSetupErrorMessage(model: Model<Api>, error: unknown): AssistantMessage {
|
||||||
@@ -54,3 +54,17 @@ export function lazyStream(
|
|||||||
|
|
||||||
return outer;
|
return outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a dynamically imported API implementation module as `ProviderStreams`.
|
||||||
|
* The module loads on first stream call; the host's import cache deduplicates
|
||||||
|
* loads. Load failures terminate the returned stream with an error event.
|
||||||
|
*/
|
||||||
|
export function lazyApi(load: () => Promise<ProviderStreams>): ProviderStreams {
|
||||||
|
return {
|
||||||
|
stream: (model, context, options) =>
|
||||||
|
lazyStream(model, async () => (await load()).stream(model, context, options)),
|
||||||
|
streamSimple: (model, context, options) =>
|
||||||
|
lazyStream(model, async () => (await load()).streamSimple(model, context, options)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import type { ProviderStreams } from "../types.ts";
|
||||||
|
import { lazyApi } from "./lazy.ts";
|
||||||
|
|
||||||
|
export const mistralConversationsApi = (): ProviderStreams => lazyApi(() => import("./mistral-conversations.ts"));
|
||||||
@@ -45,7 +45,7 @@ export interface MistralOptions extends StreamOptions {
|
|||||||
/**
|
/**
|
||||||
* Stream responses from Mistral using `chat.stream`.
|
* Stream responses from Mistral using `chat.stream`.
|
||||||
*/
|
*/
|
||||||
export const streamMistral: StreamFunction<"mistral-conversations", MistralOptions> = (
|
export const stream: StreamFunction<"mistral-conversations", MistralOptions> = (
|
||||||
model: Model<"mistral-conversations">,
|
model: Model<"mistral-conversations">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: MistralOptions,
|
options?: MistralOptions,
|
||||||
@@ -107,7 +107,7 @@ export const streamMistral: StreamFunction<"mistral-conversations", MistralOptio
|
|||||||
/**
|
/**
|
||||||
* Maps provider-agnostic `SimpleStreamOptions` to Mistral options.
|
* Maps provider-agnostic `SimpleStreamOptions` to Mistral options.
|
||||||
*/
|
*/
|
||||||
export const streamSimpleMistral: StreamFunction<"mistral-conversations", SimpleStreamOptions> = (
|
export const streamSimple: StreamFunction<"mistral-conversations", SimpleStreamOptions> = (
|
||||||
model: Model<"mistral-conversations">,
|
model: Model<"mistral-conversations">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: SimpleStreamOptions,
|
options?: SimpleStreamOptions,
|
||||||
@@ -122,7 +122,7 @@ export const streamSimpleMistral: StreamFunction<"mistral-conversations", Simple
|
|||||||
const reasoning = clampedReasoning === "off" ? undefined : clampedReasoning;
|
const reasoning = clampedReasoning === "off" ? undefined : clampedReasoning;
|
||||||
const shouldUseReasoning = model.reasoning && reasoning !== undefined;
|
const shouldUseReasoning = model.reasoning && reasoning !== undefined;
|
||||||
|
|
||||||
return streamMistral(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
promptMode: shouldUseReasoning && usesPromptModeReasoning(model) ? "reasoning" : undefined,
|
promptMode: shouldUseReasoning && usesPromptModeReasoning(model) ? "reasoning" : undefined,
|
||||||
reasoningEffort:
|
reasoningEffort:
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import type { ProviderStreams } from "../types.ts";
|
||||||
|
import { lazyApi } from "./lazy.ts";
|
||||||
|
|
||||||
|
export const openAICodexResponsesApi = (): ProviderStreams => lazyApi(() => import("./openai-codex-responses.ts"));
|
||||||
+3
-3
@@ -191,7 +191,7 @@ function createSSEHeaderTimeout(): { signal: AbortSignal; clear: () => void; err
|
|||||||
// Main Stream Function
|
// Main Stream Function
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
export const streamOpenAICodexResponses: StreamFunction<"openai-codex-responses", OpenAICodexResponsesOptions> = (
|
export const stream: StreamFunction<"openai-codex-responses", OpenAICodexResponsesOptions> = (
|
||||||
model: Model<"openai-codex-responses">,
|
model: Model<"openai-codex-responses">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: OpenAICodexResponsesOptions,
|
options?: OpenAICodexResponsesOptions,
|
||||||
@@ -404,7 +404,7 @@ export const streamOpenAICodexResponses: StreamFunction<"openai-codex-responses"
|
|||||||
return stream;
|
return stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const streamSimpleOpenAICodexResponses: StreamFunction<"openai-codex-responses", SimpleStreamOptions> = (
|
export const streamSimple: StreamFunction<"openai-codex-responses", SimpleStreamOptions> = (
|
||||||
model: Model<"openai-codex-responses">,
|
model: Model<"openai-codex-responses">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: SimpleStreamOptions,
|
options?: SimpleStreamOptions,
|
||||||
@@ -418,7 +418,7 @@ export const streamSimpleOpenAICodexResponses: StreamFunction<"openai-codex-resp
|
|||||||
const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
|
const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
|
||||||
const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
|
const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
|
||||||
|
|
||||||
return streamOpenAICodexResponses(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
reasoningEffort,
|
reasoningEffort,
|
||||||
} satisfies OpenAICodexResponsesOptions);
|
} satisfies OpenAICodexResponsesOptions);
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import type { ProviderStreams } from "../types.ts";
|
||||||
|
import { lazyApi } from "./lazy.ts";
|
||||||
|
|
||||||
|
export const openAICompletionsApi = (): ProviderStreams => lazyApi(() => import("./openai-completions.ts"));
|
||||||
+3
-3
@@ -108,7 +108,7 @@ function resolveCacheRetention(cacheRetention?: CacheRetention): CacheRetention
|
|||||||
return "short";
|
return "short";
|
||||||
}
|
}
|
||||||
|
|
||||||
export const streamOpenAICompletions: StreamFunction<"openai-completions", OpenAICompletionsOptions> = (
|
export const stream: StreamFunction<"openai-completions", OpenAICompletionsOptions> = (
|
||||||
model: Model<"openai-completions">,
|
model: Model<"openai-completions">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: OpenAICompletionsOptions,
|
options?: OpenAICompletionsOptions,
|
||||||
@@ -425,7 +425,7 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions", OpenA
|
|||||||
return stream;
|
return stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const streamSimpleOpenAICompletions: StreamFunction<"openai-completions", SimpleStreamOptions> = (
|
export const streamSimple: StreamFunction<"openai-completions", SimpleStreamOptions> = (
|
||||||
model: Model<"openai-completions">,
|
model: Model<"openai-completions">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: SimpleStreamOptions,
|
options?: SimpleStreamOptions,
|
||||||
@@ -440,7 +440,7 @@ export const streamSimpleOpenAICompletions: StreamFunction<"openai-completions",
|
|||||||
const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
|
const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
|
||||||
const toolChoice = (options as OpenAICompletionsOptions | undefined)?.toolChoice;
|
const toolChoice = (options as OpenAICompletionsOptions | undefined)?.toolChoice;
|
||||||
|
|
||||||
return streamOpenAICompletions(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
reasoningEffort,
|
reasoningEffort,
|
||||||
toolChoice,
|
toolChoice,
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import type { ProviderStreams } from "../types.ts";
|
||||||
|
import { lazyApi } from "./lazy.ts";
|
||||||
|
|
||||||
|
export const openAIResponsesApi = (): ProviderStreams => lazyApi(() => import("./openai-responses.ts"));
|
||||||
+3
-3
@@ -78,7 +78,7 @@ export interface OpenAIResponsesOptions extends StreamOptions {
|
|||||||
/**
|
/**
|
||||||
* Generate function for OpenAI Responses API
|
* Generate function for OpenAI Responses API
|
||||||
*/
|
*/
|
||||||
export const streamOpenAIResponses: StreamFunction<"openai-responses", OpenAIResponsesOptions> = (
|
export const stream: StreamFunction<"openai-responses", OpenAIResponsesOptions> = (
|
||||||
model: Model<"openai-responses">,
|
model: Model<"openai-responses">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: OpenAIResponsesOptions,
|
options?: OpenAIResponsesOptions,
|
||||||
@@ -159,7 +159,7 @@ export const streamOpenAIResponses: StreamFunction<"openai-responses", OpenAIRes
|
|||||||
return stream;
|
return stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const streamSimpleOpenAIResponses: StreamFunction<"openai-responses", SimpleStreamOptions> = (
|
export const streamSimple: StreamFunction<"openai-responses", SimpleStreamOptions> = (
|
||||||
model: Model<"openai-responses">,
|
model: Model<"openai-responses">,
|
||||||
context: Context,
|
context: Context,
|
||||||
options?: SimpleStreamOptions,
|
options?: SimpleStreamOptions,
|
||||||
@@ -173,7 +173,7 @@ export const streamSimpleOpenAIResponses: StreamFunction<"openai-responses", Sim
|
|||||||
const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
|
const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
|
||||||
const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
|
const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
|
||||||
|
|
||||||
return streamOpenAIResponses(model, context, {
|
return stream(model, context, {
|
||||||
...base,
|
...base,
|
||||||
reasoningEffort,
|
reasoningEffort,
|
||||||
} satisfies OpenAIResponsesOptions);
|
} satisfies OpenAIResponsesOptions);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { streamBedrock, streamSimpleBedrock } from "./providers/amazon-bedrock.ts";
|
import { stream, streamSimple } from "./api/bedrock-converse-stream.ts";
|
||||||
|
|
||||||
export const bedrockProviderModule = {
|
export const bedrockProviderModule = {
|
||||||
streamBedrock,
|
stream,
|
||||||
streamSimpleBedrock,
|
streamSimple,
|
||||||
};
|
};
|
||||||
|
|||||||
+19
-14
@@ -1,7 +1,26 @@
|
|||||||
export type { Static, TSchema } from "typebox";
|
export type { Static, TSchema } from "typebox";
|
||||||
export { Type } from "typebox";
|
export { Type } from "typebox";
|
||||||
|
|
||||||
|
export * from "./api/anthropic-messages.lazy.ts";
|
||||||
|
export type { AnthropicEffort, AnthropicOptions, AnthropicThinkingDisplay } from "./api/anthropic-messages.ts";
|
||||||
|
export * from "./api/azure-openai-responses.lazy.ts";
|
||||||
|
export type { AzureOpenAIResponsesOptions } from "./api/azure-openai-responses.ts";
|
||||||
|
export * from "./api/bedrock-converse-stream.lazy.ts";
|
||||||
|
export type { BedrockOptions, BedrockThinkingDisplay } from "./api/bedrock-converse-stream.ts";
|
||||||
|
export * from "./api/google-generative-ai.lazy.ts";
|
||||||
|
export type { GoogleOptions } from "./api/google-generative-ai.ts";
|
||||||
|
export type { GoogleThinkingLevel } from "./api/google-shared.ts";
|
||||||
|
export * from "./api/google-vertex.lazy.ts";
|
||||||
|
export type { GoogleVertexOptions } from "./api/google-vertex.ts";
|
||||||
export * from "./api/lazy.ts";
|
export * from "./api/lazy.ts";
|
||||||
|
export * from "./api/mistral-conversations.lazy.ts";
|
||||||
|
export type { MistralOptions } from "./api/mistral-conversations.ts";
|
||||||
|
export * from "./api/openai-codex-responses.lazy.ts";
|
||||||
|
export type { OpenAICodexResponsesOptions, OpenAICodexWebSocketDebugStats } from "./api/openai-codex-responses.ts";
|
||||||
|
export * from "./api/openai-completions.lazy.ts";
|
||||||
|
export type { OpenAICompletionsOptions } from "./api/openai-completions.ts";
|
||||||
|
export * from "./api/openai-responses.lazy.ts";
|
||||||
|
export type { OpenAIResponsesOptions } from "./api/openai-responses.ts";
|
||||||
export * from "./api-registry.ts";
|
export * from "./api-registry.ts";
|
||||||
export * from "./auth/context.ts";
|
export * from "./auth/context.ts";
|
||||||
export * from "./auth/credential-store.ts";
|
export * from "./auth/credential-store.ts";
|
||||||
@@ -11,22 +30,8 @@ export * from "./image-models.ts";
|
|||||||
export * from "./images.ts";
|
export * from "./images.ts";
|
||||||
export * from "./images-api-registry.ts";
|
export * from "./images-api-registry.ts";
|
||||||
export * from "./models.ts";
|
export * from "./models.ts";
|
||||||
export type { BedrockOptions, BedrockThinkingDisplay } from "./providers/amazon-bedrock.ts";
|
|
||||||
export type { AnthropicEffort, AnthropicOptions, AnthropicThinkingDisplay } from "./providers/anthropic.ts";
|
|
||||||
export type { AzureOpenAIResponsesOptions } from "./providers/azure-openai-responses.ts";
|
|
||||||
export * from "./providers/faux.ts";
|
export * from "./providers/faux.ts";
|
||||||
export type { GoogleOptions } from "./providers/google.ts";
|
|
||||||
export type { GoogleThinkingLevel } from "./providers/google-shared.ts";
|
|
||||||
export type { GoogleVertexOptions } from "./providers/google-vertex.ts";
|
|
||||||
export * from "./providers/images/register-builtins.ts";
|
export * from "./providers/images/register-builtins.ts";
|
||||||
export type { MistralOptions } from "./providers/mistral.ts";
|
|
||||||
export type {
|
|
||||||
OpenAICodexResponsesOptions,
|
|
||||||
OpenAICodexWebSocketDebugStats,
|
|
||||||
} from "./providers/openai-codex-responses.ts";
|
|
||||||
export type { OpenAICompletionsOptions } from "./providers/openai-completions.ts";
|
|
||||||
export type { OpenAIResponsesOptions } from "./providers/openai-responses.ts";
|
|
||||||
export * from "./providers/register-builtins.ts";
|
|
||||||
export * from "./session-resources.ts";
|
export * from "./session-resources.ts";
|
||||||
export * from "./stream.ts";
|
export * from "./stream.ts";
|
||||||
export * from "./types.ts";
|
export * from "./types.ts";
|
||||||
|
|||||||
@@ -1,406 +0,0 @@
|
|||||||
import { clearApiProviders, registerApiProvider } from "../api-registry.ts";
|
|
||||||
import type {
|
|
||||||
Api,
|
|
||||||
AssistantMessage,
|
|
||||||
AssistantMessageEvent,
|
|
||||||
Context,
|
|
||||||
Model,
|
|
||||||
SimpleStreamOptions,
|
|
||||||
StreamFunction,
|
|
||||||
StreamOptions,
|
|
||||||
} from "../types.ts";
|
|
||||||
import { AssistantMessageEventStream } from "../utils/event-stream.ts";
|
|
||||||
import type { BedrockOptions } from "./amazon-bedrock.ts";
|
|
||||||
import type { AnthropicOptions } from "./anthropic.ts";
|
|
||||||
import type { AzureOpenAIResponsesOptions } from "./azure-openai-responses.ts";
|
|
||||||
import type { GoogleOptions } from "./google.ts";
|
|
||||||
import type { GoogleVertexOptions } from "./google-vertex.ts";
|
|
||||||
import type { MistralOptions } from "./mistral.ts";
|
|
||||||
import type { OpenAICodexResponsesOptions } from "./openai-codex-responses.ts";
|
|
||||||
import type { OpenAICompletionsOptions } from "./openai-completions.ts";
|
|
||||||
import type { OpenAIResponsesOptions } from "./openai-responses.ts";
|
|
||||||
|
|
||||||
interface LazyProviderModule<
|
|
||||||
TApi extends Api,
|
|
||||||
TOptions extends StreamOptions,
|
|
||||||
TSimpleOptions extends SimpleStreamOptions,
|
|
||||||
> {
|
|
||||||
stream: (model: Model<TApi>, context: Context, options?: TOptions) => AsyncIterable<AssistantMessageEvent>;
|
|
||||||
streamSimple: (
|
|
||||||
model: Model<TApi>,
|
|
||||||
context: Context,
|
|
||||||
options?: TSimpleOptions,
|
|
||||||
) => AsyncIterable<AssistantMessageEvent>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AnthropicProviderModule {
|
|
||||||
streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOptions>;
|
|
||||||
streamSimpleAnthropic: StreamFunction<"anthropic-messages", SimpleStreamOptions>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AzureOpenAIResponsesProviderModule {
|
|
||||||
streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses", AzureOpenAIResponsesOptions>;
|
|
||||||
streamSimpleAzureOpenAIResponses: StreamFunction<"azure-openai-responses", SimpleStreamOptions>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GoogleProviderModule {
|
|
||||||
streamGoogle: StreamFunction<"google-generative-ai", GoogleOptions>;
|
|
||||||
streamSimpleGoogle: StreamFunction<"google-generative-ai", SimpleStreamOptions>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GoogleVertexProviderModule {
|
|
||||||
streamGoogleVertex: StreamFunction<"google-vertex", GoogleVertexOptions>;
|
|
||||||
streamSimpleGoogleVertex: StreamFunction<"google-vertex", SimpleStreamOptions>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MistralProviderModule {
|
|
||||||
streamMistral: StreamFunction<"mistral-conversations", MistralOptions>;
|
|
||||||
streamSimpleMistral: StreamFunction<"mistral-conversations", SimpleStreamOptions>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface OpenAICodexResponsesProviderModule {
|
|
||||||
streamOpenAICodexResponses: StreamFunction<"openai-codex-responses", OpenAICodexResponsesOptions>;
|
|
||||||
streamSimpleOpenAICodexResponses: StreamFunction<"openai-codex-responses", SimpleStreamOptions>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface OpenAICompletionsProviderModule {
|
|
||||||
streamOpenAICompletions: StreamFunction<"openai-completions", OpenAICompletionsOptions>;
|
|
||||||
streamSimpleOpenAICompletions: StreamFunction<"openai-completions", SimpleStreamOptions>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface OpenAIResponsesProviderModule {
|
|
||||||
streamOpenAIResponses: StreamFunction<"openai-responses", OpenAIResponsesOptions>;
|
|
||||||
streamSimpleOpenAIResponses: StreamFunction<"openai-responses", SimpleStreamOptions>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BedrockProviderModule {
|
|
||||||
streamBedrock: (
|
|
||||||
model: Model<"bedrock-converse-stream">,
|
|
||||||
context: Context,
|
|
||||||
options?: BedrockOptions,
|
|
||||||
) => AsyncIterable<AssistantMessageEvent>;
|
|
||||||
streamSimpleBedrock: (
|
|
||||||
model: Model<"bedrock-converse-stream">,
|
|
||||||
context: Context,
|
|
||||||
options?: SimpleStreamOptions,
|
|
||||||
) => AsyncIterable<AssistantMessageEvent>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const importNodeOnlyProvider = (specifier: string): Promise<unknown> => {
|
|
||||||
const runtimeSpecifier = import.meta.url.endsWith(".js") ? specifier.replace(/\.ts$/, ".js") : specifier;
|
|
||||||
return import(runtimeSpecifier);
|
|
||||||
};
|
|
||||||
|
|
||||||
let anthropicProviderModulePromise:
|
|
||||||
| Promise<LazyProviderModule<"anthropic-messages", AnthropicOptions, SimpleStreamOptions>>
|
|
||||||
| undefined;
|
|
||||||
let azureOpenAIResponsesProviderModulePromise:
|
|
||||||
| Promise<LazyProviderModule<"azure-openai-responses", AzureOpenAIResponsesOptions, SimpleStreamOptions>>
|
|
||||||
| undefined;
|
|
||||||
let googleProviderModulePromise:
|
|
||||||
| Promise<LazyProviderModule<"google-generative-ai", GoogleOptions, SimpleStreamOptions>>
|
|
||||||
| undefined;
|
|
||||||
let googleVertexProviderModulePromise:
|
|
||||||
| Promise<LazyProviderModule<"google-vertex", GoogleVertexOptions, SimpleStreamOptions>>
|
|
||||||
| undefined;
|
|
||||||
let mistralProviderModulePromise:
|
|
||||||
| Promise<LazyProviderModule<"mistral-conversations", MistralOptions, SimpleStreamOptions>>
|
|
||||||
| undefined;
|
|
||||||
let openAICodexResponsesProviderModulePromise:
|
|
||||||
| Promise<LazyProviderModule<"openai-codex-responses", OpenAICodexResponsesOptions, SimpleStreamOptions>>
|
|
||||||
| undefined;
|
|
||||||
let openAICompletionsProviderModulePromise:
|
|
||||||
| Promise<LazyProviderModule<"openai-completions", OpenAICompletionsOptions, SimpleStreamOptions>>
|
|
||||||
| undefined;
|
|
||||||
let openAIResponsesProviderModulePromise:
|
|
||||||
| Promise<LazyProviderModule<"openai-responses", OpenAIResponsesOptions, SimpleStreamOptions>>
|
|
||||||
| undefined;
|
|
||||||
let bedrockProviderModuleOverride:
|
|
||||||
| LazyProviderModule<"bedrock-converse-stream", BedrockOptions, SimpleStreamOptions>
|
|
||||||
| undefined;
|
|
||||||
let bedrockProviderModulePromise:
|
|
||||||
| Promise<LazyProviderModule<"bedrock-converse-stream", BedrockOptions, SimpleStreamOptions>>
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
export function setBedrockProviderModule(module: BedrockProviderModule): void {
|
|
||||||
bedrockProviderModuleOverride = {
|
|
||||||
stream: module.streamBedrock,
|
|
||||||
streamSimple: module.streamSimpleBedrock,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function forwardStream(target: AssistantMessageEventStream, source: AsyncIterable<AssistantMessageEvent>): void {
|
|
||||||
(async () => {
|
|
||||||
for await (const event of source) {
|
|
||||||
target.push(event);
|
|
||||||
}
|
|
||||||
target.end();
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
|
|
||||||
function createLazyLoadErrorMessage<TApi extends Api>(model: Model<TApi>, error: unknown): AssistantMessage {
|
|
||||||
return {
|
|
||||||
role: "assistant",
|
|
||||||
content: [],
|
|
||||||
api: model.api,
|
|
||||||
provider: model.provider,
|
|
||||||
model: model.id,
|
|
||||||
usage: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
totalTokens: 0,
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
||||||
},
|
|
||||||
stopReason: "error",
|
|
||||||
errorMessage: error instanceof Error ? error.message : String(error),
|
|
||||||
timestamp: Date.now(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function createLazyStream<TApi extends Api, TOptions extends StreamOptions, TSimpleOptions extends SimpleStreamOptions>(
|
|
||||||
loadModule: () => Promise<LazyProviderModule<TApi, TOptions, TSimpleOptions>>,
|
|
||||||
): StreamFunction<TApi, TOptions> {
|
|
||||||
return (model, context, options) => {
|
|
||||||
const outer = new AssistantMessageEventStream();
|
|
||||||
|
|
||||||
loadModule()
|
|
||||||
.then((module) => {
|
|
||||||
const inner = module.stream(model, context, options);
|
|
||||||
forwardStream(outer, inner);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
const message = createLazyLoadErrorMessage(model, error);
|
|
||||||
outer.push({ type: "error", reason: "error", error: message });
|
|
||||||
outer.end(message);
|
|
||||||
});
|
|
||||||
|
|
||||||
return outer;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function createLazySimpleStream<
|
|
||||||
TApi extends Api,
|
|
||||||
TOptions extends StreamOptions,
|
|
||||||
TSimpleOptions extends SimpleStreamOptions,
|
|
||||||
>(loadModule: () => Promise<LazyProviderModule<TApi, TOptions, TSimpleOptions>>): StreamFunction<TApi, TSimpleOptions> {
|
|
||||||
return (model, context, options) => {
|
|
||||||
const outer = new AssistantMessageEventStream();
|
|
||||||
|
|
||||||
loadModule()
|
|
||||||
.then((module) => {
|
|
||||||
const inner = module.streamSimple(model, context, options);
|
|
||||||
forwardStream(outer, inner);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
const message = createLazyLoadErrorMessage(model, error);
|
|
||||||
outer.push({ type: "error", reason: "error", error: message });
|
|
||||||
outer.end(message);
|
|
||||||
});
|
|
||||||
|
|
||||||
return outer;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadAnthropicProviderModule(): Promise<
|
|
||||||
LazyProviderModule<"anthropic-messages", AnthropicOptions, SimpleStreamOptions>
|
|
||||||
> {
|
|
||||||
anthropicProviderModulePromise ||= import("./anthropic.ts").then((module) => {
|
|
||||||
const provider = module as AnthropicProviderModule;
|
|
||||||
return {
|
|
||||||
stream: provider.streamAnthropic,
|
|
||||||
streamSimple: provider.streamSimpleAnthropic,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return anthropicProviderModulePromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadAzureOpenAIResponsesProviderModule(): Promise<
|
|
||||||
LazyProviderModule<"azure-openai-responses", AzureOpenAIResponsesOptions, SimpleStreamOptions>
|
|
||||||
> {
|
|
||||||
azureOpenAIResponsesProviderModulePromise ||= import("./azure-openai-responses.ts").then((module) => {
|
|
||||||
const provider = module as AzureOpenAIResponsesProviderModule;
|
|
||||||
return {
|
|
||||||
stream: provider.streamAzureOpenAIResponses,
|
|
||||||
streamSimple: provider.streamSimpleAzureOpenAIResponses,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return azureOpenAIResponsesProviderModulePromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadGoogleProviderModule(): Promise<
|
|
||||||
LazyProviderModule<"google-generative-ai", GoogleOptions, SimpleStreamOptions>
|
|
||||||
> {
|
|
||||||
googleProviderModulePromise ||= import("./google.ts").then((module) => {
|
|
||||||
const provider = module as GoogleProviderModule;
|
|
||||||
return {
|
|
||||||
stream: provider.streamGoogle,
|
|
||||||
streamSimple: provider.streamSimpleGoogle,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return googleProviderModulePromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadGoogleVertexProviderModule(): Promise<
|
|
||||||
LazyProviderModule<"google-vertex", GoogleVertexOptions, SimpleStreamOptions>
|
|
||||||
> {
|
|
||||||
googleVertexProviderModulePromise ||= import("./google-vertex.ts").then((module) => {
|
|
||||||
const provider = module as GoogleVertexProviderModule;
|
|
||||||
return {
|
|
||||||
stream: provider.streamGoogleVertex,
|
|
||||||
streamSimple: provider.streamSimpleGoogleVertex,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return googleVertexProviderModulePromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadMistralProviderModule(): Promise<
|
|
||||||
LazyProviderModule<"mistral-conversations", MistralOptions, SimpleStreamOptions>
|
|
||||||
> {
|
|
||||||
mistralProviderModulePromise ||= import("./mistral.ts").then((module) => {
|
|
||||||
const provider = module as MistralProviderModule;
|
|
||||||
return {
|
|
||||||
stream: provider.streamMistral,
|
|
||||||
streamSimple: provider.streamSimpleMistral,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return mistralProviderModulePromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadOpenAICodexResponsesProviderModule(): Promise<
|
|
||||||
LazyProviderModule<"openai-codex-responses", OpenAICodexResponsesOptions, SimpleStreamOptions>
|
|
||||||
> {
|
|
||||||
openAICodexResponsesProviderModulePromise ||= import("./openai-codex-responses.ts").then((module) => {
|
|
||||||
const provider = module as OpenAICodexResponsesProviderModule;
|
|
||||||
return {
|
|
||||||
stream: provider.streamOpenAICodexResponses,
|
|
||||||
streamSimple: provider.streamSimpleOpenAICodexResponses,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return openAICodexResponsesProviderModulePromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadOpenAICompletionsProviderModule(): Promise<
|
|
||||||
LazyProviderModule<"openai-completions", OpenAICompletionsOptions, SimpleStreamOptions>
|
|
||||||
> {
|
|
||||||
openAICompletionsProviderModulePromise ||= import("./openai-completions.ts").then((module) => {
|
|
||||||
const provider = module as OpenAICompletionsProviderModule;
|
|
||||||
return {
|
|
||||||
stream: provider.streamOpenAICompletions,
|
|
||||||
streamSimple: provider.streamSimpleOpenAICompletions,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return openAICompletionsProviderModulePromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadOpenAIResponsesProviderModule(): Promise<
|
|
||||||
LazyProviderModule<"openai-responses", OpenAIResponsesOptions, SimpleStreamOptions>
|
|
||||||
> {
|
|
||||||
openAIResponsesProviderModulePromise ||= import("./openai-responses.ts").then((module) => {
|
|
||||||
const provider = module as OpenAIResponsesProviderModule;
|
|
||||||
return {
|
|
||||||
stream: provider.streamOpenAIResponses,
|
|
||||||
streamSimple: provider.streamSimpleOpenAIResponses,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return openAIResponsesProviderModulePromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadBedrockProviderModule(): Promise<
|
|
||||||
LazyProviderModule<"bedrock-converse-stream", BedrockOptions, SimpleStreamOptions>
|
|
||||||
> {
|
|
||||||
if (bedrockProviderModuleOverride) {
|
|
||||||
return Promise.resolve(bedrockProviderModuleOverride);
|
|
||||||
}
|
|
||||||
bedrockProviderModulePromise ||= importNodeOnlyProvider("./amazon-bedrock.ts").then((module) => {
|
|
||||||
const provider = module as BedrockProviderModule;
|
|
||||||
return {
|
|
||||||
stream: provider.streamBedrock,
|
|
||||||
streamSimple: provider.streamSimpleBedrock,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return bedrockProviderModulePromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const streamAnthropic = createLazyStream(loadAnthropicProviderModule);
|
|
||||||
export const streamSimpleAnthropic = createLazySimpleStream(loadAnthropicProviderModule);
|
|
||||||
export const streamAzureOpenAIResponses = createLazyStream(loadAzureOpenAIResponsesProviderModule);
|
|
||||||
export const streamSimpleAzureOpenAIResponses = createLazySimpleStream(loadAzureOpenAIResponsesProviderModule);
|
|
||||||
export const streamGoogle = createLazyStream(loadGoogleProviderModule);
|
|
||||||
export const streamSimpleGoogle = createLazySimpleStream(loadGoogleProviderModule);
|
|
||||||
export const streamGoogleVertex = createLazyStream(loadGoogleVertexProviderModule);
|
|
||||||
export const streamSimpleGoogleVertex = createLazySimpleStream(loadGoogleVertexProviderModule);
|
|
||||||
export const streamMistral = createLazyStream(loadMistralProviderModule);
|
|
||||||
export const streamSimpleMistral = createLazySimpleStream(loadMistralProviderModule);
|
|
||||||
export const streamOpenAICodexResponses = createLazyStream(loadOpenAICodexResponsesProviderModule);
|
|
||||||
export const streamSimpleOpenAICodexResponses = createLazySimpleStream(loadOpenAICodexResponsesProviderModule);
|
|
||||||
export const streamOpenAICompletions = createLazyStream(loadOpenAICompletionsProviderModule);
|
|
||||||
export const streamSimpleOpenAICompletions = createLazySimpleStream(loadOpenAICompletionsProviderModule);
|
|
||||||
export const streamOpenAIResponses = createLazyStream(loadOpenAIResponsesProviderModule);
|
|
||||||
export const streamSimpleOpenAIResponses = createLazySimpleStream(loadOpenAIResponsesProviderModule);
|
|
||||||
const streamBedrockLazy = createLazyStream(loadBedrockProviderModule);
|
|
||||||
const streamSimpleBedrockLazy = createLazySimpleStream(loadBedrockProviderModule);
|
|
||||||
|
|
||||||
export function registerBuiltInApiProviders(): void {
|
|
||||||
registerApiProvider({
|
|
||||||
api: "anthropic-messages",
|
|
||||||
stream: streamAnthropic,
|
|
||||||
streamSimple: streamSimpleAnthropic,
|
|
||||||
});
|
|
||||||
|
|
||||||
registerApiProvider({
|
|
||||||
api: "openai-completions",
|
|
||||||
stream: streamOpenAICompletions,
|
|
||||||
streamSimple: streamSimpleOpenAICompletions,
|
|
||||||
});
|
|
||||||
|
|
||||||
registerApiProvider({
|
|
||||||
api: "mistral-conversations",
|
|
||||||
stream: streamMistral,
|
|
||||||
streamSimple: streamSimpleMistral,
|
|
||||||
});
|
|
||||||
|
|
||||||
registerApiProvider({
|
|
||||||
api: "openai-responses",
|
|
||||||
stream: streamOpenAIResponses,
|
|
||||||
streamSimple: streamSimpleOpenAIResponses,
|
|
||||||
});
|
|
||||||
|
|
||||||
registerApiProvider({
|
|
||||||
api: "azure-openai-responses",
|
|
||||||
stream: streamAzureOpenAIResponses,
|
|
||||||
streamSimple: streamSimpleAzureOpenAIResponses,
|
|
||||||
});
|
|
||||||
|
|
||||||
registerApiProvider({
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
stream: streamOpenAICodexResponses,
|
|
||||||
streamSimple: streamSimpleOpenAICodexResponses,
|
|
||||||
});
|
|
||||||
|
|
||||||
registerApiProvider({
|
|
||||||
api: "google-generative-ai",
|
|
||||||
stream: streamGoogle,
|
|
||||||
streamSimple: streamSimpleGoogle,
|
|
||||||
});
|
|
||||||
|
|
||||||
registerApiProvider({
|
|
||||||
api: "google-vertex",
|
|
||||||
stream: streamGoogleVertex,
|
|
||||||
streamSimple: streamSimpleGoogleVertex,
|
|
||||||
});
|
|
||||||
|
|
||||||
registerApiProvider({
|
|
||||||
api: "bedrock-converse-stream",
|
|
||||||
stream: streamBedrockLazy,
|
|
||||||
streamSimple: streamSimpleBedrockLazy,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resetApiProviders(): void {
|
|
||||||
clearApiProviders();
|
|
||||||
registerBuiltInApiProviders();
|
|
||||||
}
|
|
||||||
|
|
||||||
registerBuiltInApiProviders();
|
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
import "./providers/register-builtins.ts";
|
import { anthropicMessagesApi } from "./api/anthropic-messages.lazy.ts";
|
||||||
|
import { azureOpenAIResponsesApi } from "./api/azure-openai-responses.lazy.ts";
|
||||||
import { getApiProvider } from "./api-registry.ts";
|
import { bedrockConverseStreamApi } from "./api/bedrock-converse-stream.lazy.ts";
|
||||||
|
import { googleGenerativeAIApi } from "./api/google-generative-ai.lazy.ts";
|
||||||
|
import { googleVertexApi } from "./api/google-vertex.lazy.ts";
|
||||||
|
import { mistralConversationsApi } from "./api/mistral-conversations.lazy.ts";
|
||||||
|
import { openAICodexResponsesApi } from "./api/openai-codex-responses.lazy.ts";
|
||||||
|
import { openAICompletionsApi } from "./api/openai-completions.lazy.ts";
|
||||||
|
import { openAIResponsesApi } from "./api/openai-responses.lazy.ts";
|
||||||
|
import { clearApiProviders, getApiProvider, registerApiProvider } from "./api-registry.ts";
|
||||||
import { getEnvApiKey } from "./env-api-keys.ts";
|
import { getEnvApiKey } from "./env-api-keys.ts";
|
||||||
import type {
|
import type {
|
||||||
Api,
|
Api,
|
||||||
@@ -9,12 +16,38 @@ import type {
|
|||||||
Context,
|
Context,
|
||||||
Model,
|
Model,
|
||||||
ProviderStreamOptions,
|
ProviderStreamOptions,
|
||||||
|
ProviderStreams,
|
||||||
SimpleStreamOptions,
|
SimpleStreamOptions,
|
||||||
StreamOptions,
|
StreamOptions,
|
||||||
} from "./types.ts";
|
} from "./types.ts";
|
||||||
|
|
||||||
export { getEnvApiKey } from "./env-api-keys.ts";
|
export { getEnvApiKey } from "./env-api-keys.ts";
|
||||||
|
|
||||||
|
const BUILTIN_APIS: [Api, ProviderStreams][] = [
|
||||||
|
["anthropic-messages", anthropicMessagesApi()],
|
||||||
|
["openai-completions", openAICompletionsApi()],
|
||||||
|
["openai-responses", openAIResponsesApi()],
|
||||||
|
["openai-codex-responses", openAICodexResponsesApi()],
|
||||||
|
["azure-openai-responses", azureOpenAIResponsesApi()],
|
||||||
|
["google-generative-ai", googleGenerativeAIApi()],
|
||||||
|
["google-vertex", googleVertexApi()],
|
||||||
|
["mistral-conversations", mistralConversationsApi()],
|
||||||
|
["bedrock-converse-stream", bedrockConverseStreamApi()],
|
||||||
|
];
|
||||||
|
|
||||||
|
export function registerBuiltInApiProviders(): void {
|
||||||
|
for (const [api, streams] of BUILTIN_APIS) {
|
||||||
|
registerApiProvider({ api, stream: streams.stream, streamSimple: streams.streamSimple });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetApiProviders(): void {
|
||||||
|
clearApiProviders();
|
||||||
|
registerBuiltInApiProviders();
|
||||||
|
}
|
||||||
|
|
||||||
|
registerBuiltInApiProviders();
|
||||||
|
|
||||||
function hasExplicitApiKey(apiKey: string | undefined): apiKey is string {
|
function hasExplicitApiKey(apiKey: string | undefined): apiKey is string {
|
||||||
return typeof apiKey === "string" && apiKey.trim().length > 0;
|
return typeof apiKey === "string" && apiKey.trim().length > 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import type { BedrockOptions } from "./providers/amazon-bedrock.ts";
|
import type { AnthropicOptions } from "./api/anthropic-messages.ts";
|
||||||
import type { AnthropicOptions } from "./providers/anthropic.ts";
|
import type { AzureOpenAIResponsesOptions } from "./api/azure-openai-responses.ts";
|
||||||
import type { AzureOpenAIResponsesOptions } from "./providers/azure-openai-responses.ts";
|
import type { BedrockOptions } from "./api/bedrock-converse-stream.ts";
|
||||||
import type { GoogleOptions } from "./providers/google.ts";
|
import type { GoogleOptions } from "./api/google-generative-ai.ts";
|
||||||
import type { GoogleVertexOptions } from "./providers/google-vertex.ts";
|
import type { GoogleVertexOptions } from "./api/google-vertex.ts";
|
||||||
import type { MistralOptions } from "./providers/mistral.ts";
|
import type { MistralOptions } from "./api/mistral-conversations.ts";
|
||||||
import type { OpenAICodexResponsesOptions } from "./providers/openai-codex-responses.ts";
|
import type { OpenAICodexResponsesOptions } from "./api/openai-codex-responses.ts";
|
||||||
import type { OpenAICompletionsOptions } from "./providers/openai-completions.ts";
|
import type { OpenAICompletionsOptions } from "./api/openai-completions.ts";
|
||||||
import type { OpenAIResponsesOptions } from "./providers/openai-responses.ts";
|
import type { OpenAIResponsesOptions } from "./api/openai-responses.ts";
|
||||||
import type { AssistantMessageDiagnostic } from "./utils/diagnostics.ts";
|
import type { AssistantMessageDiagnostic } from "./utils/diagnostics.ts";
|
||||||
import type { AssistantMessageEventStream } from "./utils/event-stream.ts";
|
import type { AssistantMessageEventStream } from "./utils/event-stream.ts";
|
||||||
|
|
||||||
@@ -191,6 +191,19 @@ export type ApiStreamOptions<TApi extends Api> = TApi extends keyof ApiOptionsMa
|
|||||||
? ApiOptionsMap[TApi]
|
? ApiOptionsMap[TApi]
|
||||||
: StreamOptions & Record<string, unknown>;
|
: StreamOptions & Record<string, unknown>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The uniform stream contract of an API implementation module: every module
|
||||||
|
* under `src/api/` exports exactly `stream` and `streamSimple`, so the module
|
||||||
|
* itself satisfies this interface. Lazy wrappers (`lazyApi()`) and provider
|
||||||
|
* factories pass these around as values. This is the untyped dispatch shape;
|
||||||
|
* per-API option typing lives on the implementation modules themselves and on
|
||||||
|
* `Provider.stream()` via `ApiStreamOptions`.
|
||||||
|
*/
|
||||||
|
export interface ProviderStreams {
|
||||||
|
stream(model: Model<Api>, context: Context, options?: StreamOptions): AssistantMessageEventStream;
|
||||||
|
streamSimple(model: Model<Api>, context: Context, options?: SimpleStreamOptions): AssistantMessageEventStream;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ImagesOptions {
|
export interface ImagesOptions {
|
||||||
signal?: AbortSignal;
|
signal?: AbortSignal;
|
||||||
apiKey?: string;
|
apiKey?: string;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { createServer, type IncomingMessage, type ServerResponse } from "node:ht
|
|||||||
import type { AddressInfo } from "node:net";
|
import type { AddressInfo } from "node:net";
|
||||||
import { Type } from "typebox";
|
import { Type } from "typebox";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { streamAnthropic } from "../src/providers/anthropic.ts";
|
import { stream as streamAnthropic } from "../src/api/anthropic-messages.ts";
|
||||||
import type { Context, Model, Tool } from "../src/types.ts";
|
import type { Context, Model, Tool } from "../src/types.ts";
|
||||||
|
|
||||||
interface CapturedRequest {
|
interface CapturedRequest {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type Anthropic from "@anthropic-ai/sdk";
|
import type Anthropic from "@anthropic-ai/sdk";
|
||||||
import { Type } from "typebox";
|
import { Type } from "typebox";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { stream as streamAnthropic } from "../src/api/anthropic-messages.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { streamAnthropic } from "../src/providers/anthropic.ts";
|
|
||||||
import type { Context, ToolCall } from "../src/types.ts";
|
import type { Context, ToolCall } from "../src/types.ts";
|
||||||
|
|
||||||
function createSseResponse(events: Array<{ event: string; data: string }>): Response {
|
function createSseResponse(events: Array<{ event: string; data: string }>): Response {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import { stream as streamAzureOpenAIResponses } from "../src/api/azure-openai-responses.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { streamAzureOpenAIResponses } from "../src/providers/azure-openai-responses.ts";
|
|
||||||
import type { Context } from "../src/types.ts";
|
import type { Context } from "../src/types.ts";
|
||||||
|
|
||||||
interface CapturedAzureClientOptions {
|
interface CapturedAzureClientOptions {
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ vi.mock("@aws-sdk/client-bedrock-runtime", () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
import { stream as streamBedrock } from "../src/api/bedrock-converse-stream.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { streamBedrock } from "../src/providers/amazon-bedrock.ts";
|
|
||||||
import type { Context, Message } from "../src/types.ts";
|
import type { Context, Message } from "../src/types.ts";
|
||||||
|
|
||||||
const baseModel = getModel("amazon-bedrock", "us.anthropic.claude-sonnet-4-5-20250929-v1:0");
|
const baseModel = getModel("amazon-bedrock", "us.anthropic.claude-sonnet-4-5-20250929-v1:0");
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ vi.mock("@aws-sdk/client-bedrock-runtime", () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
import type { BedrockOptions } from "../src/api/bedrock-converse-stream.ts";
|
||||||
|
import { stream as streamBedrock, streamSimple as streamSimpleBedrock } from "../src/api/bedrock-converse-stream.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import type { BedrockOptions } from "../src/providers/amazon-bedrock.ts";
|
|
||||||
import { streamBedrock, streamSimpleBedrock } from "../src/providers/amazon-bedrock.ts";
|
|
||||||
import type { Context, Model } from "../src/types.ts";
|
import type { Context, Model } from "../src/types.ts";
|
||||||
|
|
||||||
const context: Context = {
|
const context: Context = {
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ vi.mock("@aws-sdk/client-bedrock-runtime", () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
import { stream as streamBedrock } from "../src/api/bedrock-converse-stream.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { streamBedrock } from "../src/providers/amazon-bedrock.ts";
|
|
||||||
import type { Context, Model } from "../src/types.ts";
|
import type { Context, Model } from "../src/types.ts";
|
||||||
|
|
||||||
const context: Context = {
|
const context: Context = {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { type BedrockOptions, stream as streamBedrock } from "../src/api/bedrock-converse-stream.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { type BedrockOptions, streamBedrock } from "../src/providers/amazon-bedrock.ts";
|
|
||||||
import type { Context, Model } from "../src/types.ts";
|
import type { Context, Model } from "../src/types.ts";
|
||||||
import { hasBedrockCredentials } from "./bedrock-utils.ts";
|
import { hasBedrockCredentials } from "./bedrock-utils.ts";
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
import { stream as streamAnthropic } from "../src/api/anthropic-messages.ts";
|
||||||
|
import { stream as streamOpenAICompletions } from "../src/api/openai-completions.ts";
|
||||||
|
import { stream as streamOpenAIResponses } from "../src/api/openai-responses.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { streamAnthropic } from "../src/providers/anthropic.ts";
|
|
||||||
import { streamOpenAICompletions } from "../src/providers/openai-completions.ts";
|
|
||||||
import { streamOpenAIResponses } from "../src/providers/openai-responses.ts";
|
|
||||||
import { stream } from "../src/stream.ts";
|
import { stream } from "../src/stream.ts";
|
||||||
import type { Context, Model } from "../src/types.ts";
|
import type { Context, Model } from "../src/types.ts";
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ import { tmpdir } from "node:os";
|
|||||||
import { join, resolve } from "node:path";
|
import { join, resolve } from "node:path";
|
||||||
import { Type } from "typebox";
|
import { Type } from "typebox";
|
||||||
import { AuthStorage } from "../../coding-agent/src/core/auth-storage.ts";
|
import { AuthStorage } from "../../coding-agent/src/core/auth-storage.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
|
||||||
import {
|
import {
|
||||||
closeOpenAICodexWebSocketSessions,
|
closeOpenAICodexWebSocketSessions,
|
||||||
getOpenAICodexWebSocketDebugStats,
|
getOpenAICodexWebSocketDebugStats,
|
||||||
resetOpenAICodexWebSocketDebugStats,
|
resetOpenAICodexWebSocketDebugStats,
|
||||||
streamOpenAICodexResponses,
|
stream as streamOpenAICodexResponses,
|
||||||
} from "../src/providers/openai-codex-responses.ts";
|
} from "../src/api/openai-codex-responses.ts";
|
||||||
|
import { getModel } from "../src/models.ts";
|
||||||
import type { AssistantMessage, Context, Message, Model, Tool, ToolResultMessage, Transport } from "../src/types.ts";
|
import type { AssistantMessage, Context, Message, Model, Tool, ToolResultMessage, Transport } from "../src/types.ts";
|
||||||
|
|
||||||
type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh";
|
type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh";
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { createServer, type IncomingMessage, type ServerResponse } from "node:ht
|
|||||||
import type { AddressInfo } from "node:net";
|
import type { AddressInfo } from "node:net";
|
||||||
import { Type } from "typebox";
|
import { Type } from "typebox";
|
||||||
import { afterEach, describe, expect, it } from "vitest";
|
import { afterEach, describe, expect, it } from "vitest";
|
||||||
|
import { stream as streamAnthropic } from "../src/api/anthropic-messages.ts";
|
||||||
import { findEnvKeys, getEnvApiKey } from "../src/env-api-keys.ts";
|
import { findEnvKeys, getEnvApiKey } from "../src/env-api-keys.ts";
|
||||||
import { getModel, getModels } from "../src/models.ts";
|
import { getModel, getModels } from "../src/models.ts";
|
||||||
import { streamAnthropic } from "../src/providers/anthropic.ts";
|
|
||||||
import type { Context, Model, Tool } from "../src/types.ts";
|
import type { Context, Model, Tool } from "../src/types.ts";
|
||||||
|
|
||||||
const originalFireworksApiKey = process.env.FIREWORKS_API_KEY;
|
const originalFireworksApiKey = process.env.FIREWORKS_API_KEY;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { describe, expect, it, vi } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
import { stream as streamAnthropic } from "../src/api/anthropic-messages.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { streamAnthropic } from "../src/providers/anthropic.ts";
|
|
||||||
import type { Context } from "../src/types.ts";
|
import type { Context } from "../src/types.ts";
|
||||||
|
|
||||||
const mockState = vi.hoisted(() => ({
|
const mockState = vi.hoisted(() => ({
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { convertTools } from "../src/providers/google-shared.ts";
|
import { convertTools } from "../src/api/google-shared.ts";
|
||||||
import type { Tool } from "../src/types.ts";
|
import type { Tool } from "../src/types.ts";
|
||||||
|
|
||||||
function makeTool(parameters: Record<string, unknown>): Tool {
|
function makeTool(parameters: Record<string, unknown>): Tool {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { convertMessages } from "../src/providers/google-shared.ts";
|
import { convertMessages } from "../src/api/google-shared.ts";
|
||||||
import type { Context, Model } from "../src/types.ts";
|
import type { Context, Model } from "../src/types.ts";
|
||||||
|
|
||||||
function makeGemini3Model<TApi extends "google-generative-ai" | "google-vertex">(
|
function makeGemini3Model<TApi extends "google-generative-ai" | "google-vertex">(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { convertMessages } from "../src/providers/google-shared.ts";
|
import { convertMessages } from "../src/api/google-shared.ts";
|
||||||
import type { Context, Model } from "../src/types.ts";
|
import type { Context, Model } from "../src/types.ts";
|
||||||
|
|
||||||
function makeModel<TApi extends "google-generative-ai">(
|
function makeModel<TApi extends "google-generative-ai">(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { isThinkingPart, retainThoughtSignature } from "../src/providers/google-shared.ts";
|
import { isThinkingPart, retainThoughtSignature } from "../src/api/google-shared.ts";
|
||||||
|
|
||||||
describe("Google thinking detection (thoughtSignature)", () => {
|
describe("Google thinking detection (thoughtSignature)", () => {
|
||||||
it("treats part.thought === true as thinking", () => {
|
it("treats part.thought === true as thinking", () => {
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ vi.mock("@google/genai", () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
import { stream as streamGoogleVertex } from "../src/api/google-vertex.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { streamGoogleVertex } from "../src/providers/google-vertex.ts";
|
|
||||||
import type { Context, Model } from "../src/types.ts";
|
import type { Context, Model } from "../src/types.ts";
|
||||||
|
|
||||||
const model = getModel("google-vertex", "gemini-3-flash-preview");
|
const model = getModel("google-vertex", "gemini-3-flash-preview");
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ describe("lazy provider module loading", () => {
|
|||||||
expect(result.loadedSpecifiers).toEqual([]);
|
expect(result.loadedSpecifiers).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("loads only the Anthropic SDK when calling the root lazy wrapper", () => {
|
it("loads only the Anthropic SDK when streaming through the lazy API wrapper", () => {
|
||||||
const result = runProbe(`
|
const result = runProbe(`
|
||||||
const model = {
|
const model = {
|
||||||
id: "claude-sonnet-4-6",
|
id: "claude-sonnet-4-6",
|
||||||
@@ -81,7 +81,7 @@ describe("lazy provider module loading", () => {
|
|||||||
maxTokens: 8192,
|
maxTokens: 8192,
|
||||||
};
|
};
|
||||||
const context = { messages: [{ role: "user", content: "hi" }] };
|
const context = { messages: [{ role: "user", content: "hi" }] };
|
||||||
await mod.streamSimpleAnthropic(model, context).result();
|
await mod.anthropicMessagesApi().streamSimple(model, context).result();
|
||||||
`);
|
`);
|
||||||
|
|
||||||
expect(result.loadedSpecifiers).toEqual(["@anthropic-ai/sdk"]);
|
expect(result.loadedSpecifiers).toEqual(["@anthropic-ai/sdk"]);
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
|||||||
import {
|
import {
|
||||||
getOpenAICodexWebSocketDebugStats,
|
getOpenAICodexWebSocketDebugStats,
|
||||||
resetOpenAICodexWebSocketDebugStats,
|
resetOpenAICodexWebSocketDebugStats,
|
||||||
streamOpenAICodexResponses,
|
stream as streamOpenAICodexResponses,
|
||||||
streamSimpleOpenAICodexResponses,
|
streamSimple as streamSimpleOpenAICodexResponses,
|
||||||
} from "../src/providers/openai-codex-responses.ts";
|
} from "../src/api/openai-codex-responses.ts";
|
||||||
import type { Context, Model } from "../src/types.ts";
|
import type { Context, Model } from "../src/types.ts";
|
||||||
|
|
||||||
const originalAgentDir = process.env.PI_CODING_AGENT_DIR;
|
const originalAgentDir = process.env.PI_CODING_AGENT_DIR;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Type } from "typebox";
|
import { Type } from "typebox";
|
||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import { stream as streamOpenAICompletions } from "../src/api/openai-completions.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { streamOpenAICompletions } from "../src/providers/openai-completions.ts";
|
|
||||||
import type { Model } from "../src/types.ts";
|
import type { Model } from "../src/types.ts";
|
||||||
|
|
||||||
interface CacheControl {
|
interface CacheControl {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import { stream as streamOpenAICompletions } from "../src/api/openai-completions.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { streamOpenAICompletions } from "../src/providers/openai-completions.ts";
|
|
||||||
import type { Model } from "../src/types.ts";
|
import type { Model } from "../src/types.ts";
|
||||||
|
|
||||||
interface FakeOpenAIClientOptions {
|
interface FakeOpenAIClientOptions {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import { streamOpenAICompletions } from "../src/providers/openai-completions.ts";
|
import { stream as streamOpenAICompletions } from "../src/api/openai-completions.ts";
|
||||||
import type { Context, Model } from "../src/types.ts";
|
import type { Context, Model } from "../src/types.ts";
|
||||||
|
|
||||||
const mockState = vi.hoisted(() => ({
|
const mockState = vi.hoisted(() => ({
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { once } from "node:events";
|
|||||||
import http from "node:http";
|
import http from "node:http";
|
||||||
import type { AddressInfo } from "node:net";
|
import type { AddressInfo } from "node:net";
|
||||||
import { afterEach, describe, expect, it } from "vitest";
|
import { afterEach, describe, expect, it } from "vitest";
|
||||||
import { convertMessages, streamOpenAICompletions } from "../src/providers/openai-completions.ts";
|
import { convertMessages, stream as streamOpenAICompletions } from "../src/api/openai-completions.ts";
|
||||||
import type {
|
import type {
|
||||||
AssistantMessage,
|
AssistantMessage,
|
||||||
AssistantMessageEvent,
|
AssistantMessageEvent,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { convertMessages } from "../src/api/openai-completions.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { convertMessages } from "../src/providers/openai-completions.ts";
|
|
||||||
import type {
|
import type {
|
||||||
AssistantMessage,
|
AssistantMessage,
|
||||||
Context,
|
Context,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import { stream as streamOpenAIResponses } from "../src/api/openai-responses.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { streamOpenAIResponses } from "../src/providers/openai-responses.ts";
|
|
||||||
import type { Model } from "../src/types.ts";
|
import type { Model } from "../src/types.ts";
|
||||||
|
|
||||||
type CapturedHeaders = Headers | string[][] | Record<string, string | readonly string[]> | undefined;
|
type CapturedHeaders = Headers | string[][] | Record<string, string | readonly string[]> | undefined;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { convertResponsesMessages } from "../src/api/openai-responses-shared.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { convertResponsesMessages } from "../src/providers/openai-responses-shared.ts";
|
|
||||||
import type { AssistantMessage, Context, ToolResultMessage, Usage } from "../src/types.ts";
|
import type { AssistantMessage, Context, ToolResultMessage, Usage } from "../src/types.ts";
|
||||||
import { shortHash } from "../src/utils/hash.ts";
|
import { shortHash } from "../src/utils/hash.ts";
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { ResponseOutputMessage } from "openai/resources/responses/responses.js";
|
import type { ResponseOutputMessage } from "openai/resources/responses/responses.js";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { convertResponsesMessages } from "../src/api/openai-responses-shared.ts";
|
||||||
import { getModel } from "../src/models.ts";
|
import { getModel } from "../src/models.ts";
|
||||||
import { convertResponsesMessages } from "../src/providers/openai-responses-shared.ts";
|
|
||||||
import type { AssistantMessage, Context, Usage } from "../src/types.ts";
|
import type { AssistantMessage, Context, Usage } from "../src/types.ts";
|
||||||
|
|
||||||
const usage: Usage = {
|
const usage: Usage = {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { ResponseStreamEvent } from "openai/resources/responses/responses.js";
|
import type { ResponseStreamEvent } from "openai/resources/responses/responses.js";
|
||||||
import { describe, expect, it, vi } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
import { processResponsesStream } from "../src/providers/openai-responses-shared.ts";
|
import { processResponsesStream } from "../src/api/openai-responses-shared.ts";
|
||||||
import type { AssistantMessage, AssistantMessageEvent, Model } from "../src/types.ts";
|
import type { AssistantMessage, AssistantMessageEvent, Model } from "../src/types.ts";
|
||||||
import { AssistantMessageEventStream } from "../src/utils/event-stream.ts";
|
import { AssistantMessageEventStream } from "../src/utils/event-stream.ts";
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,12 @@
|
|||||||
// Run from packages/ai: node test/scratch.ts
|
// Run from packages/ai: node test/scratch.ts
|
||||||
// Requires ANTHROPIC_API_KEY.
|
// Requires ANTHROPIC_API_KEY.
|
||||||
|
|
||||||
|
import { anthropicMessagesApi } from "../src/api/anthropic-messages.lazy.ts";
|
||||||
import { createModels, getModels, type Provider } from "../src/models.ts";
|
import { createModels, getModels, type Provider } from "../src/models.ts";
|
||||||
import { streamAnthropic, streamSimpleAnthropic } from "../src/providers/register-builtins.ts";
|
|
||||||
import type { Context } from "../src/types.ts";
|
import type { Context } from "../src/types.ts";
|
||||||
|
|
||||||
|
const anthropicApi = anthropicMessagesApi();
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// 1. Define a provider. In the final design this comes from
|
// 1. Define a provider. In the final design this comes from
|
||||||
// `@earendil-works/pi-ai/providers/anthropic` as `anthropicProvider()`;
|
// `@earendil-works/pi-ai/providers/anthropic` as `anthropicProvider()`;
|
||||||
@@ -33,8 +35,8 @@ const anthropic: Provider<"anthropic-messages"> = {
|
|||||||
getModels: async () => getModels("anthropic"),
|
getModels: async () => getModels("anthropic"),
|
||||||
|
|
||||||
// shared lazy API implementation (loads the SDK on first request)
|
// shared lazy API implementation (loads the SDK on first request)
|
||||||
stream: streamAnthropic,
|
stream: anthropicApi.stream,
|
||||||
streamSimple: streamSimpleAnthropic,
|
streamSimple: anthropicApi.streamSimple,
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { transformMessages } from "../src/providers/transform-messages.ts";
|
import { transformMessages } from "../src/api/transform-messages.ts";
|
||||||
import type { AssistantMessage, Message, Model, ToolCall } from "../src/types.ts";
|
import type { AssistantMessage, Message, Model, ToolCall } from "../src/types.ts";
|
||||||
|
|
||||||
// Normalize function matching what anthropic.ts uses
|
// Normalize function matching what anthropic.ts uses
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ async function refreshAnthropicToken(credentials: OAuthCredentials): Promise<OAu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// Streaming Implementation (simplified from packages/ai/src/providers/anthropic.ts)
|
// Streaming Implementation (simplified from packages/ai/src/api/anthropic-messages.ts)
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
// Claude Code tool names for OAuth stealth mode
|
// Claude Code tool names for OAuth stealth mode
|
||||||
|
|||||||
@@ -12,14 +12,14 @@
|
|||||||
import {
|
import {
|
||||||
type Api,
|
type Api,
|
||||||
type AssistantMessageEventStream,
|
type AssistantMessageEventStream,
|
||||||
|
anthropicMessagesApi,
|
||||||
type Context,
|
type Context,
|
||||||
createAssistantMessageEventStream,
|
createAssistantMessageEventStream,
|
||||||
type Model,
|
type Model,
|
||||||
type OAuthCredentials,
|
type OAuthCredentials,
|
||||||
type OAuthLoginCallbacks,
|
type OAuthLoginCallbacks,
|
||||||
|
openAIResponsesApi,
|
||||||
type SimpleStreamOptions,
|
type SimpleStreamOptions,
|
||||||
streamSimpleAnthropic,
|
|
||||||
streamSimpleOpenAIResponses,
|
|
||||||
type ThinkingLevelMap,
|
type ThinkingLevelMap,
|
||||||
} from "@earendil-works/pi-ai";
|
} from "@earendil-works/pi-ai";
|
||||||
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||||||
@@ -325,7 +325,7 @@ export function streamGitLabDuo(
|
|||||||
|
|
||||||
const innerStream =
|
const innerStream =
|
||||||
cfg.backend === "anthropic"
|
cfg.backend === "anthropic"
|
||||||
? streamSimpleAnthropic(
|
? anthropicMessagesApi().streamSimple(
|
||||||
{
|
{
|
||||||
...(modelWithBaseUrl as Model<"anthropic-messages">),
|
...(modelWithBaseUrl as Model<"anthropic-messages">),
|
||||||
compat: {
|
compat: {
|
||||||
@@ -336,7 +336,11 @@ export function streamGitLabDuo(
|
|||||||
context,
|
context,
|
||||||
streamOptions,
|
streamOptions,
|
||||||
)
|
)
|
||||||
: streamSimpleOpenAIResponses(modelWithBaseUrl as Model<"openai-responses">, context, streamOptions);
|
: openAIResponsesApi().streamSimple(
|
||||||
|
modelWithBaseUrl as Model<"openai-responses">,
|
||||||
|
context,
|
||||||
|
streamOptions,
|
||||||
|
);
|
||||||
|
|
||||||
for await (const event of innerStream) stream.push(event);
|
for await (const event of innerStream) stream.push(event);
|
||||||
stream.end();
|
stream.end();
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ import {
|
|||||||
} from "@earendil-works/pi-ai";
|
} from "@earendil-works/pi-ai";
|
||||||
import {
|
import {
|
||||||
getOpenAICodexWebSocketDebugStats,
|
getOpenAICodexWebSocketDebugStats,
|
||||||
streamSimpleOpenAICodexResponses,
|
streamSimple as streamSimpleOpenAICodexResponses,
|
||||||
} from "../../ai/src/providers/openai-codex-responses.ts";
|
} from "../../ai/src/api/openai-codex-responses.ts";
|
||||||
import { AuthStorage } from "../src/core/auth-storage.ts";
|
import { AuthStorage } from "../src/core/auth-storage.ts";
|
||||||
import { createExtensionRuntime } from "../src/core/extensions/loader.ts";
|
import { createExtensionRuntime } from "../src/core/extensions/loader.ts";
|
||||||
import type { ToolDefinition } from "../src/core/extensions/types.ts";
|
import type { ToolDefinition } from "../src/core/extensions/types.ts";
|
||||||
|
|||||||
Reference in New Issue
Block a user