mirror of
https://github.com/earendil-works/pi.git
synced 2026-06-18 15:54:04 +08:00
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
|
||||
api/ # API implementations and lazy wrappers
|
||||
openai-completions.ts # real implementation, imports SDKs, exports stream/streamSimple
|
||||
openai-completions-lazy.ts
|
||||
openai-completions.lazy.ts
|
||||
openai-responses.ts
|
||||
openai-responses-lazy.ts
|
||||
openai-responses.lazy.ts
|
||||
openai-codex-responses.ts
|
||||
openai-codex-responses-lazy.ts
|
||||
openai-codex-responses.lazy.ts
|
||||
azure-openai-responses.ts
|
||||
azure-openai-responses-lazy.ts
|
||||
azure-openai-responses.lazy.ts
|
||||
anthropic-messages.ts
|
||||
anthropic-messages-lazy.ts
|
||||
anthropic-messages.lazy.ts
|
||||
google-generative-ai.ts
|
||||
google-generative-ai-lazy.ts
|
||||
google-generative-ai.lazy.ts
|
||||
google-vertex.ts
|
||||
google-vertex-lazy.ts
|
||||
google-vertex.lazy.ts
|
||||
mistral-conversations.ts
|
||||
mistral-conversations-lazy.ts
|
||||
mistral-conversations.lazy.ts
|
||||
bedrock-converse-stream.ts
|
||||
bedrock-converse-stream-lazy.ts
|
||||
bedrock-converse-stream.lazy.ts
|
||||
lazy.ts # lazyStream()/lazyApi() helpers
|
||||
(shared helpers: openai-responses-shared, google-shared, transform-messages, ...)
|
||||
providers/ # concrete provider factories and per-provider catalogs
|
||||
@@ -315,22 +315,18 @@ export function stream(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
|
||||
export interface ProviderStreams {
|
||||
stream<TApi extends Api>(
|
||||
model: Model<TApi>,
|
||||
context: Context,
|
||||
options?: ApiStreamOptions<TApi>,
|
||||
): AssistantMessageEventStream;
|
||||
stream(model: Model<Api>, context: Context, options?: StreamOptions): AssistantMessageEventStream;
|
||||
streamSimple(model: Model<Api>, context: Context, options?: SimpleStreamOptions): AssistantMessageEventStream;
|
||||
}
|
||||
|
||||
// src/api/lazy.ts
|
||||
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"));
|
||||
```
|
||||
|
||||
@@ -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:
|
||||
|
||||
```ts
|
||||
import { openAICompletionsApi } from "../api/openai-completions-lazy.ts";
|
||||
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||
|
||||
export function openrouterProvider(): Provider {
|
||||
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/`
|
||||
|
||||
- [ ] 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`.
|
||||
- [ ] Move shared helpers (`openai-responses-shared`, `google-shared`, `transform-messages`, `openai-prompt-cache`, `github-copilot-headers`) to `src/api/`.
|
||||
- [ ] Extract `lazyStream()`/`lazyApi()` into `src/api/lazy.ts`.
|
||||
- [ ] Add `*-lazy.ts` wrappers per API; bedrock keeps node-only import trick and `setBedrockProviderModule()`.
|
||||
- [ ] Delete `providers/register-builtins.ts`.
|
||||
- [x] Move stream implementations from `src/providers/` to `src/api/`, renamed by API id (`anthropic.ts` -> `api/anthropic-messages.ts`, etc.).
|
||||
- [x] Normalize each implementation module to export exactly `stream` and `streamSimple`.
|
||||
- [x] Move shared helpers (`openai-responses-shared`, `google-shared`, `transform-messages`, `openai-prompt-cache`, `github-copilot-headers`, `cloudflare`, `simple-options`) to `src/api/`.
|
||||
- [x] Extract `lazyStream()`/`lazyApi()` into `src/api/lazy.ts`.
|
||||
- [x] Add `*.lazy.ts` wrappers per API; bedrock keeps node-only import trick and `setBedrockProviderModule()`.
|
||||
- [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
|
||||
|
||||
|
||||
+16
-16
@@ -11,36 +11,36 @@
|
||||
"import": "./dist/index.js"
|
||||
},
|
||||
"./anthropic": {
|
||||
"types": "./dist/providers/anthropic.d.ts",
|
||||
"import": "./dist/providers/anthropic.js"
|
||||
"types": "./dist/api/anthropic-messages.d.ts",
|
||||
"import": "./dist/api/anthropic-messages.js"
|
||||
},
|
||||
"./azure-openai-responses": {
|
||||
"types": "./dist/providers/azure-openai-responses.d.ts",
|
||||
"import": "./dist/providers/azure-openai-responses.js"
|
||||
"types": "./dist/api/azure-openai-responses.d.ts",
|
||||
"import": "./dist/api/azure-openai-responses.js"
|
||||
},
|
||||
"./google": {
|
||||
"types": "./dist/providers/google.d.ts",
|
||||
"import": "./dist/providers/google.js"
|
||||
"types": "./dist/api/google-generative-ai.d.ts",
|
||||
"import": "./dist/api/google-generative-ai.js"
|
||||
},
|
||||
"./google-vertex": {
|
||||
"types": "./dist/providers/google-vertex.d.ts",
|
||||
"import": "./dist/providers/google-vertex.js"
|
||||
"types": "./dist/api/google-vertex.d.ts",
|
||||
"import": "./dist/api/google-vertex.js"
|
||||
},
|
||||
"./mistral": {
|
||||
"types": "./dist/providers/mistral.d.ts",
|
||||
"import": "./dist/providers/mistral.js"
|
||||
"types": "./dist/api/mistral-conversations.d.ts",
|
||||
"import": "./dist/api/mistral-conversations.js"
|
||||
},
|
||||
"./openai-codex-responses": {
|
||||
"types": "./dist/providers/openai-codex-responses.d.ts",
|
||||
"import": "./dist/providers/openai-codex-responses.js"
|
||||
"types": "./dist/api/openai-codex-responses.d.ts",
|
||||
"import": "./dist/api/openai-codex-responses.js"
|
||||
},
|
||||
"./openai-completions": {
|
||||
"types": "./dist/providers/openai-completions.d.ts",
|
||||
"import": "./dist/providers/openai-completions.js"
|
||||
"types": "./dist/api/openai-completions.d.ts",
|
||||
"import": "./dist/api/openai-completions.js"
|
||||
},
|
||||
"./openai-responses": {
|
||||
"types": "./dist/providers/openai-responses.d.ts",
|
||||
"import": "./dist/providers/openai-responses.js"
|
||||
"types": "./dist/api/openai-responses.d.ts",
|
||||
"import": "./dist/api/openai-responses.js"
|
||||
},
|
||||
"./oauth": {
|
||||
"types": "./dist/oauth.d.ts",
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
CLOUDFLARE_AI_GATEWAY_COMPAT_BASE_URL,
|
||||
CLOUDFLARE_AI_GATEWAY_OPENAI_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";
|
||||
|
||||
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.
|
||||
* For adaptive thinking models: the model decides when/how much to think.
|
||||
* 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).
|
||||
*/
|
||||
thinkingEnabled?: boolean;
|
||||
@@ -205,7 +205,7 @@ export interface AnthropicOptions extends StreamOptions {
|
||||
* - "medium": Moderate thinking, may skip for simple queries
|
||||
* - "low": Minimal thinking, skips for simple tasks
|
||||
* Ignored for older models.
|
||||
* Default: omitted unless `streamSimpleAnthropic()` maps a simple reasoning
|
||||
* Default: omitted unless `streamSimple()` maps a simple reasoning
|
||||
* level to this option.
|
||||
*/
|
||||
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">,
|
||||
context: Context,
|
||||
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">,
|
||||
context: Context,
|
||||
options?: SimpleStreamOptions,
|
||||
@@ -745,14 +745,14 @@ export const streamSimpleAnthropic: StreamFunction<"anthropic-messages", SimpleS
|
||||
|
||||
const base = buildBaseOptions(model, options, apiKey);
|
||||
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 older models: use budget-based thinking.
|
||||
if (model.compat?.forceAdaptiveThinking === true) {
|
||||
const effort = mapThinkingLevelToEffort(model, options.reasoning);
|
||||
return streamAnthropic(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
thinkingEnabled: true,
|
||||
effort,
|
||||
@@ -768,7 +768,7 @@ export const streamSimpleAnthropic: StreamFunction<"anthropic-messages", SimpleS
|
||||
options.thinkingBudgets,
|
||||
);
|
||||
|
||||
return streamAnthropic(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
maxTokens: adjusted.maxTokens,
|
||||
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
|
||||
*/
|
||||
export const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses", AzureOpenAIResponsesOptions> = (
|
||||
export const stream: StreamFunction<"azure-openai-responses", AzureOpenAIResponsesOptions> = (
|
||||
model: Model<"azure-openai-responses">,
|
||||
context: Context,
|
||||
options?: AzureOpenAIResponsesOptions,
|
||||
@@ -147,7 +147,7 @@ export const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses"
|
||||
return stream;
|
||||
};
|
||||
|
||||
export const streamSimpleAzureOpenAIResponses: StreamFunction<"azure-openai-responses", SimpleStreamOptions> = (
|
||||
export const streamSimple: StreamFunction<"azure-openai-responses", SimpleStreamOptions> = (
|
||||
model: Model<"azure-openai-responses">,
|
||||
context: Context,
|
||||
options?: SimpleStreamOptions,
|
||||
@@ -161,7 +161,7 @@ export const streamSimpleAzureOpenAIResponses: StreamFunction<"azure-openai-resp
|
||||
const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
|
||||
const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
|
||||
|
||||
return streamAzureOpenAIResponses(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
reasoningEffort,
|
||||
} 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>";
|
||||
|
||||
export const streamBedrock: StreamFunction<"bedrock-converse-stream", BedrockOptions> = (
|
||||
export const stream: StreamFunction<"bedrock-converse-stream", BedrockOptions> = (
|
||||
model: Model<"bedrock-converse-stream">,
|
||||
context: Context,
|
||||
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" });
|
||||
}
|
||||
|
||||
export const streamSimpleBedrock: StreamFunction<"bedrock-converse-stream", SimpleStreamOptions> = (
|
||||
export const streamSimple: StreamFunction<"bedrock-converse-stream", SimpleStreamOptions> = (
|
||||
model: Model<"bedrock-converse-stream">,
|
||||
context: Context,
|
||||
options?: SimpleStreamOptions,
|
||||
): AssistantMessageEventStream => {
|
||||
const base = buildBaseOptions(model, options, undefined);
|
||||
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 (supportsAdaptiveThinking(model.id, model.name)) {
|
||||
return streamBedrock(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
reasoning: options.reasoning,
|
||||
thinkingBudgets: options.thinkingBudgets,
|
||||
@@ -380,7 +380,7 @@ export const streamSimpleBedrock: StreamFunction<"bedrock-converse-stream", Simp
|
||||
options.thinkingBudgets,
|
||||
);
|
||||
|
||||
return streamBedrock(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
maxTokens: adjusted.maxTokens,
|
||||
reasoning: options.reasoning,
|
||||
@@ -391,7 +391,7 @@ export const streamSimpleBedrock: StreamFunction<"bedrock-converse-stream", Simp
|
||||
} satisfies BedrockOptions);
|
||||
}
|
||||
|
||||
return streamBedrock(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
reasoning: options.reasoning,
|
||||
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
|
||||
let toolCallCounter = 0;
|
||||
|
||||
export const streamGoogle: StreamFunction<"google-generative-ai", GoogleOptions> = (
|
||||
export const stream: StreamFunction<"google-generative-ai", GoogleOptions> = (
|
||||
model: Model<"google-generative-ai">,
|
||||
context: Context,
|
||||
options?: GoogleOptions,
|
||||
@@ -277,7 +277,7 @@ export const streamGoogle: StreamFunction<"google-generative-ai", GoogleOptions>
|
||||
return stream;
|
||||
};
|
||||
|
||||
export const streamSimpleGoogle: StreamFunction<"google-generative-ai", SimpleStreamOptions> = (
|
||||
export const streamSimple: StreamFunction<"google-generative-ai", SimpleStreamOptions> = (
|
||||
model: Model<"google-generative-ai">,
|
||||
context: Context,
|
||||
options?: SimpleStreamOptions,
|
||||
@@ -289,7 +289,7 @@ export const streamSimpleGoogle: StreamFunction<"google-generative-ai", SimpleSt
|
||||
|
||||
const base = buildBaseOptions(model, options, apiKey);
|
||||
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);
|
||||
@@ -297,7 +297,7 @@ export const streamSimpleGoogle: StreamFunction<"google-generative-ai", SimpleSt
|
||||
const googleModel = model as Model<"google-generative-ai">;
|
||||
|
||||
if (isGemini3ProModel(googleModel) || isGemini3FlashModel(googleModel) || isGemma4Model(googleModel)) {
|
||||
return streamGoogle(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
thinking: {
|
||||
enabled: true,
|
||||
@@ -306,7 +306,7 @@ export const streamSimpleGoogle: StreamFunction<"google-generative-ai", SimpleSt
|
||||
} satisfies GoogleOptions);
|
||||
}
|
||||
|
||||
return streamGoogle(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
thinking: {
|
||||
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
|
||||
let toolCallCounter = 0;
|
||||
|
||||
export const streamGoogleVertex: StreamFunction<"google-vertex", GoogleVertexOptions> = (
|
||||
export const stream: StreamFunction<"google-vertex", GoogleVertexOptions> = (
|
||||
model: Model<"google-vertex">,
|
||||
context: Context,
|
||||
options?: GoogleVertexOptions,
|
||||
@@ -292,14 +292,14 @@ export const streamGoogleVertex: StreamFunction<"google-vertex", GoogleVertexOpt
|
||||
return stream;
|
||||
};
|
||||
|
||||
export const streamSimpleGoogleVertex: StreamFunction<"google-vertex", SimpleStreamOptions> = (
|
||||
export const streamSimple: StreamFunction<"google-vertex", SimpleStreamOptions> = (
|
||||
model: Model<"google-vertex">,
|
||||
context: Context,
|
||||
options?: SimpleStreamOptions,
|
||||
): AssistantMessageEventStream => {
|
||||
const base = buildBaseOptions(model, options, undefined);
|
||||
if (!options?.reasoning) {
|
||||
return streamGoogleVertex(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
thinking: { enabled: false },
|
||||
} satisfies GoogleVertexOptions);
|
||||
@@ -310,7 +310,7 @@ export const streamSimpleGoogleVertex: StreamFunction<"google-vertex", SimpleStr
|
||||
const geminiModel = model as unknown as Model<"google-generative-ai">;
|
||||
|
||||
if (isGemini3ProModel(geminiModel) || isGemini3FlashModel(geminiModel)) {
|
||||
return streamGoogleVertex(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
thinking: {
|
||||
enabled: true,
|
||||
@@ -319,7 +319,7 @@ export const streamSimpleGoogleVertex: StreamFunction<"google-vertex", SimpleStr
|
||||
} satisfies GoogleVertexOptions);
|
||||
}
|
||||
|
||||
return streamGoogleVertex(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
thinking: {
|
||||
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";
|
||||
|
||||
function createSetupErrorMessage(model: Model<Api>, error: unknown): AssistantMessage {
|
||||
@@ -54,3 +54,17 @@ export function lazyStream(
|
||||
|
||||
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`.
|
||||
*/
|
||||
export const streamMistral: StreamFunction<"mistral-conversations", MistralOptions> = (
|
||||
export const stream: StreamFunction<"mistral-conversations", MistralOptions> = (
|
||||
model: Model<"mistral-conversations">,
|
||||
context: Context,
|
||||
options?: MistralOptions,
|
||||
@@ -107,7 +107,7 @@ export const streamMistral: StreamFunction<"mistral-conversations", MistralOptio
|
||||
/**
|
||||
* 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">,
|
||||
context: Context,
|
||||
options?: SimpleStreamOptions,
|
||||
@@ -122,7 +122,7 @@ export const streamSimpleMistral: StreamFunction<"mistral-conversations", Simple
|
||||
const reasoning = clampedReasoning === "off" ? undefined : clampedReasoning;
|
||||
const shouldUseReasoning = model.reasoning && reasoning !== undefined;
|
||||
|
||||
return streamMistral(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
promptMode: shouldUseReasoning && usesPromptModeReasoning(model) ? "reasoning" : undefined,
|
||||
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
|
||||
// ============================================================================
|
||||
|
||||
export const streamOpenAICodexResponses: StreamFunction<"openai-codex-responses", OpenAICodexResponsesOptions> = (
|
||||
export const stream: StreamFunction<"openai-codex-responses", OpenAICodexResponsesOptions> = (
|
||||
model: Model<"openai-codex-responses">,
|
||||
context: Context,
|
||||
options?: OpenAICodexResponsesOptions,
|
||||
@@ -404,7 +404,7 @@ export const streamOpenAICodexResponses: StreamFunction<"openai-codex-responses"
|
||||
return stream;
|
||||
};
|
||||
|
||||
export const streamSimpleOpenAICodexResponses: StreamFunction<"openai-codex-responses", SimpleStreamOptions> = (
|
||||
export const streamSimple: StreamFunction<"openai-codex-responses", SimpleStreamOptions> = (
|
||||
model: Model<"openai-codex-responses">,
|
||||
context: Context,
|
||||
options?: SimpleStreamOptions,
|
||||
@@ -418,7 +418,7 @@ export const streamSimpleOpenAICodexResponses: StreamFunction<"openai-codex-resp
|
||||
const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
|
||||
const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
|
||||
|
||||
return streamOpenAICodexResponses(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
reasoningEffort,
|
||||
} 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";
|
||||
}
|
||||
|
||||
export const streamOpenAICompletions: StreamFunction<"openai-completions", OpenAICompletionsOptions> = (
|
||||
export const stream: StreamFunction<"openai-completions", OpenAICompletionsOptions> = (
|
||||
model: Model<"openai-completions">,
|
||||
context: Context,
|
||||
options?: OpenAICompletionsOptions,
|
||||
@@ -425,7 +425,7 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions", OpenA
|
||||
return stream;
|
||||
};
|
||||
|
||||
export const streamSimpleOpenAICompletions: StreamFunction<"openai-completions", SimpleStreamOptions> = (
|
||||
export const streamSimple: StreamFunction<"openai-completions", SimpleStreamOptions> = (
|
||||
model: Model<"openai-completions">,
|
||||
context: Context,
|
||||
options?: SimpleStreamOptions,
|
||||
@@ -440,7 +440,7 @@ export const streamSimpleOpenAICompletions: StreamFunction<"openai-completions",
|
||||
const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
|
||||
const toolChoice = (options as OpenAICompletionsOptions | undefined)?.toolChoice;
|
||||
|
||||
return streamOpenAICompletions(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
reasoningEffort,
|
||||
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
|
||||
*/
|
||||
export const streamOpenAIResponses: StreamFunction<"openai-responses", OpenAIResponsesOptions> = (
|
||||
export const stream: StreamFunction<"openai-responses", OpenAIResponsesOptions> = (
|
||||
model: Model<"openai-responses">,
|
||||
context: Context,
|
||||
options?: OpenAIResponsesOptions,
|
||||
@@ -159,7 +159,7 @@ export const streamOpenAIResponses: StreamFunction<"openai-responses", OpenAIRes
|
||||
return stream;
|
||||
};
|
||||
|
||||
export const streamSimpleOpenAIResponses: StreamFunction<"openai-responses", SimpleStreamOptions> = (
|
||||
export const streamSimple: StreamFunction<"openai-responses", SimpleStreamOptions> = (
|
||||
model: Model<"openai-responses">,
|
||||
context: Context,
|
||||
options?: SimpleStreamOptions,
|
||||
@@ -173,7 +173,7 @@ export const streamSimpleOpenAIResponses: StreamFunction<"openai-responses", Sim
|
||||
const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
|
||||
const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
|
||||
|
||||
return streamOpenAIResponses(model, context, {
|
||||
return stream(model, context, {
|
||||
...base,
|
||||
reasoningEffort,
|
||||
} 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 = {
|
||||
streamBedrock,
|
||||
streamSimpleBedrock,
|
||||
stream,
|
||||
streamSimple,
|
||||
};
|
||||
|
||||
+19
-14
@@ -1,7 +1,26 @@
|
||||
export type { Static, TSchema } 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/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 "./auth/context.ts";
|
||||
export * from "./auth/credential-store.ts";
|
||||
@@ -11,22 +30,8 @@ export * from "./image-models.ts";
|
||||
export * from "./images.ts";
|
||||
export * from "./images-api-registry.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 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 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 "./stream.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 { getApiProvider } from "./api-registry.ts";
|
||||
import { anthropicMessagesApi } from "./api/anthropic-messages.lazy.ts";
|
||||
import { azureOpenAIResponsesApi } from "./api/azure-openai-responses.lazy.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 type {
|
||||
Api,
|
||||
@@ -9,12 +16,38 @@ import type {
|
||||
Context,
|
||||
Model,
|
||||
ProviderStreamOptions,
|
||||
ProviderStreams,
|
||||
SimpleStreamOptions,
|
||||
StreamOptions,
|
||||
} from "./types.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 {
|
||||
return typeof apiKey === "string" && apiKey.trim().length > 0;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { BedrockOptions } from "./providers/amazon-bedrock.ts";
|
||||
import type { AnthropicOptions } from "./providers/anthropic.ts";
|
||||
import type { AzureOpenAIResponsesOptions } from "./providers/azure-openai-responses.ts";
|
||||
import type { GoogleOptions } from "./providers/google.ts";
|
||||
import type { GoogleVertexOptions } from "./providers/google-vertex.ts";
|
||||
import type { MistralOptions } from "./providers/mistral.ts";
|
||||
import type { OpenAICodexResponsesOptions } from "./providers/openai-codex-responses.ts";
|
||||
import type { OpenAICompletionsOptions } from "./providers/openai-completions.ts";
|
||||
import type { OpenAIResponsesOptions } from "./providers/openai-responses.ts";
|
||||
import type { AnthropicOptions } from "./api/anthropic-messages.ts";
|
||||
import type { AzureOpenAIResponsesOptions } from "./api/azure-openai-responses.ts";
|
||||
import type { BedrockOptions } from "./api/bedrock-converse-stream.ts";
|
||||
import type { GoogleOptions } from "./api/google-generative-ai.ts";
|
||||
import type { GoogleVertexOptions } from "./api/google-vertex.ts";
|
||||
import type { MistralOptions } from "./api/mistral-conversations.ts";
|
||||
import type { OpenAICodexResponsesOptions } from "./api/openai-codex-responses.ts";
|
||||
import type { OpenAICompletionsOptions } from "./api/openai-completions.ts";
|
||||
import type { OpenAIResponsesOptions } from "./api/openai-responses.ts";
|
||||
import type { AssistantMessageDiagnostic } from "./utils/diagnostics.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]
|
||||
: 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 {
|
||||
signal?: AbortSignal;
|
||||
apiKey?: string;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { createServer, type IncomingMessage, type ServerResponse } from "node:ht
|
||||
import type { AddressInfo } from "node:net";
|
||||
import { Type } from "typebox";
|
||||
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";
|
||||
|
||||
interface CapturedRequest {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type Anthropic from "@anthropic-ai/sdk";
|
||||
import { Type } from "typebox";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { stream as streamAnthropic } from "../src/api/anthropic-messages.ts";
|
||||
import { getModel } from "../src/models.ts";
|
||||
import { streamAnthropic } from "../src/providers/anthropic.ts";
|
||||
import type { Context, ToolCall } from "../src/types.ts";
|
||||
|
||||
function createSseResponse(events: Array<{ event: string; data: string }>): Response {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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 { streamAzureOpenAIResponses } from "../src/providers/azure-openai-responses.ts";
|
||||
import type { Context } from "../src/types.ts";
|
||||
|
||||
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 { streamBedrock } from "../src/providers/amazon-bedrock.ts";
|
||||
import type { Context, Message } from "../src/types.ts";
|
||||
|
||||
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 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";
|
||||
|
||||
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 { streamBedrock } from "../src/providers/amazon-bedrock.ts";
|
||||
import type { Context, Model } from "../src/types.ts";
|
||||
|
||||
const context: Context = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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 { type BedrockOptions, streamBedrock } from "../src/providers/amazon-bedrock.ts";
|
||||
import type { Context, Model } from "../src/types.ts";
|
||||
import { hasBedrockCredentials } from "./bedrock-utils.ts";
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
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 { 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 type { Context, Model } from "../src/types.ts";
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ import { tmpdir } from "node:os";
|
||||
import { join, resolve } from "node:path";
|
||||
import { Type } from "typebox";
|
||||
import { AuthStorage } from "../../coding-agent/src/core/auth-storage.ts";
|
||||
import { getModel } from "../src/models.ts";
|
||||
import {
|
||||
closeOpenAICodexWebSocketSessions,
|
||||
getOpenAICodexWebSocketDebugStats,
|
||||
resetOpenAICodexWebSocketDebugStats,
|
||||
streamOpenAICodexResponses,
|
||||
} from "../src/providers/openai-codex-responses.ts";
|
||||
stream as streamOpenAICodexResponses,
|
||||
} 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";
|
||||
|
||||
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 } from "typebox";
|
||||
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 { getModel, getModels } from "../src/models.ts";
|
||||
import { streamAnthropic } from "../src/providers/anthropic.ts";
|
||||
import type { Context, Model, Tool } from "../src/types.ts";
|
||||
|
||||
const originalFireworksApiKey = process.env.FIREWORKS_API_KEY;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { stream as streamAnthropic } from "../src/api/anthropic-messages.ts";
|
||||
import { getModel } from "../src/models.ts";
|
||||
import { streamAnthropic } from "../src/providers/anthropic.ts";
|
||||
import type { Context } from "../src/types.ts";
|
||||
|
||||
const mockState = vi.hoisted(() => ({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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";
|
||||
|
||||
function makeTool(parameters: Record<string, unknown>): Tool {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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";
|
||||
|
||||
function makeGemini3Model<TApi extends "google-generative-ai" | "google-vertex">(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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";
|
||||
|
||||
function makeModel<TApi extends "google-generative-ai">(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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)", () => {
|
||||
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 { streamGoogleVertex } from "../src/providers/google-vertex.ts";
|
||||
import type { Context, Model } from "../src/types.ts";
|
||||
|
||||
const model = getModel("google-vertex", "gemini-3-flash-preview");
|
||||
|
||||
@@ -66,7 +66,7 @@ describe("lazy provider module loading", () => {
|
||||
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 model = {
|
||||
id: "claude-sonnet-4-6",
|
||||
@@ -81,7 +81,7 @@ describe("lazy provider module loading", () => {
|
||||
maxTokens: 8192,
|
||||
};
|
||||
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"]);
|
||||
|
||||
@@ -5,9 +5,9 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
getOpenAICodexWebSocketDebugStats,
|
||||
resetOpenAICodexWebSocketDebugStats,
|
||||
streamOpenAICodexResponses,
|
||||
streamSimpleOpenAICodexResponses,
|
||||
} from "../src/providers/openai-codex-responses.ts";
|
||||
stream as streamOpenAICodexResponses,
|
||||
streamSimple as streamSimpleOpenAICodexResponses,
|
||||
} from "../src/api/openai-codex-responses.ts";
|
||||
import type { Context, Model } from "../src/types.ts";
|
||||
|
||||
const originalAgentDir = process.env.PI_CODING_AGENT_DIR;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Type } from "typebox";
|
||||
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 { streamOpenAICompletions } from "../src/providers/openai-completions.ts";
|
||||
import type { Model } from "../src/types.ts";
|
||||
|
||||
interface CacheControl {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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 { streamOpenAICompletions } from "../src/providers/openai-completions.ts";
|
||||
import type { Model } from "../src/types.ts";
|
||||
|
||||
interface FakeOpenAIClientOptions {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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";
|
||||
|
||||
const mockState = vi.hoisted(() => ({
|
||||
|
||||
@@ -2,7 +2,7 @@ import { once } from "node:events";
|
||||
import http from "node:http";
|
||||
import type { AddressInfo } from "node:net";
|
||||
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 {
|
||||
AssistantMessage,
|
||||
AssistantMessageEvent,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { convertMessages } from "../src/api/openai-completions.ts";
|
||||
import { getModel } from "../src/models.ts";
|
||||
import { convertMessages } from "../src/providers/openai-completions.ts";
|
||||
import type {
|
||||
AssistantMessage,
|
||||
Context,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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 { streamOpenAIResponses } from "../src/providers/openai-responses.ts";
|
||||
import type { Model } from "../src/types.ts";
|
||||
|
||||
type CapturedHeaders = Headers | string[][] | Record<string, string | readonly string[]> | undefined;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { convertResponsesMessages } from "../src/api/openai-responses-shared.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 { shortHash } from "../src/utils/hash.ts";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { ResponseOutputMessage } from "openai/resources/responses/responses.js";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { convertResponsesMessages } from "../src/api/openai-responses-shared.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";
|
||||
|
||||
const usage: Usage = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ResponseStreamEvent } from "openai/resources/responses/responses.js";
|
||||
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 { AssistantMessageEventStream } from "../src/utils/event-stream.ts";
|
||||
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
// Run from packages/ai: node test/scratch.ts
|
||||
// Requires ANTHROPIC_API_KEY.
|
||||
|
||||
import { anthropicMessagesApi } from "../src/api/anthropic-messages.lazy.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";
|
||||
|
||||
const anthropicApi = anthropicMessagesApi();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 1. Define a provider. In the final design this comes from
|
||||
// `@earendil-works/pi-ai/providers/anthropic` as `anthropicProvider()`;
|
||||
@@ -33,8 +35,8 @@ const anthropic: Provider<"anthropic-messages"> = {
|
||||
getModels: async () => getModels("anthropic"),
|
||||
|
||||
// shared lazy API implementation (loads the SDK on first request)
|
||||
stream: streamAnthropic,
|
||||
streamSimple: streamSimpleAnthropic,
|
||||
stream: anthropicApi.stream,
|
||||
streamSimple: anthropicApi.streamSimple,
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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";
|
||||
|
||||
// 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
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
import {
|
||||
type Api,
|
||||
type AssistantMessageEventStream,
|
||||
anthropicMessagesApi,
|
||||
type Context,
|
||||
createAssistantMessageEventStream,
|
||||
type Model,
|
||||
type OAuthCredentials,
|
||||
type OAuthLoginCallbacks,
|
||||
openAIResponsesApi,
|
||||
type SimpleStreamOptions,
|
||||
streamSimpleAnthropic,
|
||||
streamSimpleOpenAIResponses,
|
||||
type ThinkingLevelMap,
|
||||
} from "@earendil-works/pi-ai";
|
||||
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||||
@@ -325,7 +325,7 @@ export function streamGitLabDuo(
|
||||
|
||||
const innerStream =
|
||||
cfg.backend === "anthropic"
|
||||
? streamSimpleAnthropic(
|
||||
? anthropicMessagesApi().streamSimple(
|
||||
{
|
||||
...(modelWithBaseUrl as Model<"anthropic-messages">),
|
||||
compat: {
|
||||
@@ -336,7 +336,11 @@ export function streamGitLabDuo(
|
||||
context,
|
||||
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);
|
||||
stream.end();
|
||||
|
||||
@@ -23,8 +23,8 @@ import {
|
||||
} from "@earendil-works/pi-ai";
|
||||
import {
|
||||
getOpenAICodexWebSocketDebugStats,
|
||||
streamSimpleOpenAICodexResponses,
|
||||
} from "../../ai/src/providers/openai-codex-responses.ts";
|
||||
streamSimple as streamSimpleOpenAICodexResponses,
|
||||
} from "../../ai/src/api/openai-codex-responses.ts";
|
||||
import { AuthStorage } from "../src/core/auth-storage.ts";
|
||||
import { createExtensionRuntime } from "../src/core/extensions/loader.ts";
|
||||
import type { ToolDefinition } from "../src/core/extensions/types.ts";
|
||||
|
||||
Reference in New Issue
Block a user