fix(ai): revert selective pi-ai base entrypoints

This commit is contained in:
Mario Zechner 2026-06-22 12:54:12 +02:00
parent 329dceb5f3
commit 717a8f958a
78 changed files with 492 additions and 668 deletions

View file

@ -31,24 +31,6 @@ agent.subscribe((event) => {
await agent.prompt("Hello!");
```
## Base Entry Point
Use `@earendil-works/pi-agent-core/base` with `@earendil-works/pi-ai/base` when bundling applications that should include only selected provider transports:
```typescript
import { Agent } from "@earendil-works/pi-agent-core/base";
import { getModel } from "@earendil-works/pi-ai/base";
import { register } from "@earendil-works/pi-ai/anthropic";
register();
const agent = new Agent({
initialState: { model: getModel("anthropic", "claude-sonnet-4-6") },
});
```
The default `@earendil-works/pi-agent-core` entry point remains batteries-included and registers pi-ai's lazy built-in transports for backward compatibility.
## Core Concepts
### AgentMessage vs LLM Message

View file

@ -10,10 +10,6 @@
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./base": {
"types": "./dist/base.d.ts",
"import": "./dist/base.js"
},
"./node": {
"types": "./dist/node.d.ts",
"import": "./dist/node.js"

View file

@ -10,7 +10,7 @@ import {
streamSimple,
type ToolResultMessage,
validateToolArguments,
} from "@earendil-works/pi-ai/base";
} from "@earendil-works/pi-ai";
import type {
AgentContext,
AgentEvent,

View file

@ -7,7 +7,7 @@ import {
type TextContent,
type ThinkingBudgets,
type Transport,
} from "@earendil-works/pi-ai/base";
} from "@earendil-works/pi-ai";
import { runAgentLoop, runAgentLoopContinue } from "./agent-loop.ts";
import type {
AfterToolCallContext,

View file

@ -1,39 +0,0 @@
export * from "./agent.ts";
export * from "./agent-loop.ts";
export * from "./harness/agent-harness.ts";
export {
type BranchPreparation,
type BranchSummaryDetails,
type CollectEntriesResult,
collectEntriesForBranchSummary,
generateBranchSummary,
prepareBranchEntries,
} from "./harness/compaction/branch-summarization.ts";
export {
calculateContextTokens,
compact,
DEFAULT_COMPACTION_SETTINGS,
estimateContextTokens,
estimateTokens,
findCutPoint,
findTurnStartIndex,
generateSummary,
getLastAssistantUsage,
prepareCompaction,
serializeConversation,
shouldCompact,
} from "./harness/compaction/compaction.ts";
export * from "./harness/messages.ts";
export * from "./harness/prompt-templates.ts";
export * from "./harness/session/jsonl-repo.ts";
export * from "./harness/session/memory-repo.ts";
export * from "./harness/session/repo-utils.ts";
export * from "./harness/session/session.ts";
export { uuidv7 } from "./harness/session/uuid.ts";
export * from "./harness/skills.ts";
export * from "./harness/system-prompt.ts";
export * from "./harness/types.ts";
export * from "./harness/utils/shell-output.ts";
export * from "./harness/utils/truncate.ts";
export * from "./proxy.ts";
export * from "./types.ts";

View file

@ -4,7 +4,7 @@ import {
type Model,
streamSimple,
type UserMessage,
} from "@earendil-works/pi-ai/base";
} from "@earendil-works/pi-ai";
import { runAgentLoop } from "../agent-loop.ts";
import type {
AgentContext,

View file

@ -1,4 +1,5 @@
import { completeSimple, type Model } from "@earendil-works/pi-ai/base";
import type { Model } from "@earendil-works/pi-ai";
import { completeSimple } from "@earendil-works/pi-ai";
import type { AgentMessage } from "../../types.ts";
import {
convertToLlm,

View file

@ -1,11 +1,5 @@
import {
type AssistantMessage,
completeSimple,
type ImageContent,
type Model,
type TextContent,
type Usage,
} from "@earendil-works/pi-ai/base";
import type { AssistantMessage, ImageContent, Model, TextContent, Usage } from "@earendil-works/pi-ai";
import { completeSimple } from "@earendil-works/pi-ai";
import type { AgentMessage, ThinkingLevel } from "../../types.ts";
import {
convertToLlm,

View file

@ -1,4 +1,4 @@
import type { Message } from "@earendil-works/pi-ai/base";
import type { Message } from "@earendil-works/pi-ai";
import type { AgentMessage } from "../../types.ts";
/** File paths touched by a session branch or compaction range. */

View file

@ -1,4 +1,4 @@
import type { ImageContent, Message, TextContent } from "@earendil-works/pi-ai/base";
import type { ImageContent, Message, TextContent } from "@earendil-works/pi-ai";
import type { AgentMessage } from "../types.ts";
export const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:

View file

@ -1,4 +1,4 @@
import type { ImageContent, TextContent } from "@earendil-works/pi-ai/base";
import type { ImageContent, TextContent } from "@earendil-works/pi-ai";
import type { AgentMessage } from "../../types.ts";
import { createBranchSummaryMessage, createCompactionSummaryMessage, createCustomMessage } from "../messages.ts";
import type {

View file

@ -1,5 +1,5 @@
import type { ImageContent, Model, SimpleStreamOptions, TextContent, Transport } from "@earendil-works/pi-ai/base";
import type { AgentEvent, AgentMessage, AgentTool, QueueMode, ThinkingLevel } from "../types.ts";
import type { ImageContent, Model, SimpleStreamOptions, TextContent, Transport } from "@earendil-works/pi-ai";
import type { AgentEvent, AgentMessage, AgentTool, QueueMode, ThinkingLevel } from "../index.ts";
import type { Session } from "./session/session.ts";
/** Result of a fallible operation. Expected failures are returned as `ok: false` instead of thrown. */

View file

@ -1,5 +1,44 @@
// Import the default pi-ai entrypoint so that all built-in providers register
// automatically. Unlike "@earendil-works/pi-ai/base" which does not.
import "@earendil-works/pi-ai";
export * from "./base.ts";
// Core Agent
export * from "./agent.ts";
// Loop functions
export * from "./agent-loop.ts";
export * from "./harness/agent-harness.ts";
export {
type BranchPreparation,
type BranchSummaryDetails,
type CollectEntriesResult,
collectEntriesForBranchSummary,
generateBranchSummary,
prepareBranchEntries,
} from "./harness/compaction/branch-summarization.ts";
export {
calculateContextTokens,
compact,
DEFAULT_COMPACTION_SETTINGS,
estimateContextTokens,
estimateTokens,
findCutPoint,
findTurnStartIndex,
generateSummary,
getLastAssistantUsage,
prepareCompaction,
serializeConversation,
shouldCompact,
} from "./harness/compaction/compaction.ts";
export * from "./harness/messages.ts";
export * from "./harness/prompt-templates.ts";
export * from "./harness/session/jsonl-repo.ts";
export * from "./harness/session/memory-repo.ts";
export * from "./harness/session/repo-utils.ts";
export * from "./harness/session/session.ts";
export { uuidv7 } from "./harness/session/uuid.ts";
export * from "./harness/skills.ts";
export * from "./harness/system-prompt.ts";
// Harness
export * from "./harness/types.ts";
export * from "./harness/utils/shell-output.ts";
export * from "./harness/utils/truncate.ts";
// Proxy utilities
export * from "./proxy.ts";
// Types
export * from "./types.ts";

View file

@ -14,7 +14,7 @@ import {
type SimpleStreamOptions,
type StopReason,
type ToolCall,
} from "@earendil-works/pi-ai/base";
} from "@earendil-works/pi-ai";
// Create stream class matching ProxyMessageEventStream
class ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {

View file

@ -9,7 +9,7 @@ import type {
TextContent,
Tool,
ToolResultMessage,
} from "@earendil-works/pi-ai/base";
} from "@earendil-works/pi-ai";
import type { Static, TSchema } from "typebox";
/**

View file

@ -1,12 +1,6 @@
import { defineConfig } from "vitest/config";
export default defineConfig({
resolve: {
alias: {
"@earendil-works/pi-ai/base": new URL("../ai/src/base.ts", import.meta.url).pathname,
"@earendil-works/pi-ai": new URL("../ai/src/index.ts", import.meta.url).pathname,
},
},
test: {
globals: true,
environment: "node",

View file

@ -1,12 +1,6 @@
import { defineConfig } from "vitest/config";
export default defineConfig({
resolve: {
alias: {
"@earendil-works/pi-ai/base": new URL("../ai/src/base.ts", import.meta.url).pathname,
"@earendil-works/pi-ai": new URL("../ai/src/index.ts", import.meta.url).pathname,
},
},
test: {
globals: true,
environment: "node",

View file

@ -8,7 +8,6 @@ Unified LLM API with automatic model discovery, provider configuration, token an
- [Supported Providers](#supported-providers)
- [Installation](#installation)
- [Base Entry Point](#base-entry-point)
- [Quick Start](#quick-start)
- [Tools](#tools)
- [Defining Tools](#defining-tools)
@ -89,30 +88,6 @@ npm install @earendil-works/pi-ai
TypeBox exports are re-exported from `@earendil-works/pi-ai`: `Type`, `Static`, and `TSchema`.
## Base Entry Point
Use `@earendil-works/pi-ai/base` when a bundler should include only explicitly selected transport implementations. The base entry point exposes model discovery, registries, generic dispatch, environment-key helpers, and provider-neutral utilities without registering built-in transports during module initialization. Generic dispatch still resolves configured environment keys when called.
Import each selected transport directly and call its `register()` function:
```typescript
import { getModel, streamSimple } from '@earendil-works/pi-ai/base';
import { register as registerAnthropic } from '@earendil-works/pi-ai/anthropic';
registerAnthropic();
const model = getModel('anthropic', 'claude-sonnet-4-6');
const response = await streamSimple(model, {
messages: [{ role: 'user', content: 'Hello!' }]
}, {
apiKey: process.env.ANTHROPIC_API_KEY
}).result();
```
Direct transport imports bundle their implementation and SDK code. Register only the transports used by the application. For example, OpenRouter, Groq, xAI, and DeepSeek chat models share the `@earendil-works/pi-ai/openai-completions` transport.
Use `@earendil-works/pi-ai` for the batteries-included behavior. The root entry point remains backward-compatible: it registers lazy wrappers for all built-in transports and resolves environment API keys automatically during dispatch.
## Quick Start
```typescript
@ -463,7 +438,7 @@ Do not use `stream()` or `complete()` for image generation. Image generation is
### Basic Image Generation
```typescript
import { getImageModel, generateImages } from '@earendil-works/pi-ai';
import { getImageModel, generateImages } from '@mariozechner/pi-ai';
const model = getImageModel('openrouter', 'google/gemini-2.5-flash-image');
@ -1123,7 +1098,6 @@ const response = await complete(model, {
- OAuth login flows are not supported in browser environments. Use the `@earendil-works/pi-ai/oauth` entry point in Node.js.
- In browser builds, Bedrock can still appear in model lists. Calls to Bedrock models fail at runtime.
- Use a server-side proxy or backend service if you need Bedrock or OAuth-based auth from a web app.
- Use `@earendil-works/pi-ai/base` plus explicit direct transport registration when a browser bundle should exclude unused provider SDK implementations.
### Environment Variables (Node.js only)
@ -1360,7 +1334,6 @@ Create a new provider file (for example `amazon-bedrock.ts`) that exports:
- `stream<Provider>()` function returning `AssistantMessageEventStream`
- `streamSimple<Provider>()` for `SimpleStreamOptions` mapping
- `register()` for explicit direct transport registration from `@earendil-works/pi-ai/base`
- Provider-specific options interface
- Message conversion functions to transform `Context` to provider format
- Tool conversion if the provider supports tools
@ -1371,8 +1344,7 @@ Create a new provider file (for example `amazon-bedrock.ts`) that exports:
- Register the API with `registerApiProvider()`
- Add a package subpath export in `package.json` for the provider module (`./dist/providers/<provider>.js`)
- Add lazy loader wrappers in `src/providers/register-builtins.ts`, do not statically import provider implementation modules there
- Add any root-level `export type` re-exports in `src/index.ts` and `src/base.ts` that should remain available from `@earendil-works/pi-ai` and `@earendil-works/pi-ai/base`
- Keep `src/base.ts` free of built-in registration imports
- Add any root-level `export type` re-exports in `src/index.ts` that should remain available from `@earendil-works/pi-ai`
- Add credential detection in `env-api-keys.ts` for the new provider
- Ensure `streamSimple` handles auth lookup via `getEnvApiKey()` or provider-specific auth

View file

@ -10,14 +10,6 @@
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./base": {
"types": "./dist/base.d.ts",
"import": "./dist/base.js"
},
"./amazon-bedrock": {
"types": "./dist/providers/amazon-bedrock.d.ts",
"import": "./dist/providers/amazon-bedrock.js"
},
"./anthropic": {
"types": "./dist/providers/anthropic.d.ts",
"import": "./dist/providers/anthropic.js"
@ -50,10 +42,6 @@
"types": "./dist/providers/openai-responses.d.ts",
"import": "./dist/providers/openai-responses.js"
},
"./openrouter-images": {
"types": "./dist/providers/images/openrouter.d.ts",
"import": "./dist/providers/images/openrouter.js"
},
"./oauth": {
"types": "./dist/oauth.d.ts",
"import": "./dist/oauth.js"

View file

@ -1,45 +0,0 @@
export type { Static, TSchema } from "typebox";
export { Type } from "typebox";
export * from "./api-registry.ts";
export * from "./env-api-keys.ts";
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 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 "./session-resources.ts";
export * from "./stream.ts";
export * from "./types.ts";
export * from "./utils/diagnostics.ts";
export * from "./utils/event-stream.ts";
export * from "./utils/json-parse.ts";
export type {
OAuthAuthInfo,
OAuthCredentials,
OAuthDeviceCodeInfo,
OAuthLoginCallbacks,
OAuthPrompt,
OAuthProvider,
OAuthProviderId,
OAuthProviderInfo,
OAuthProviderInterface,
OAuthSelectOption,
OAuthSelectPrompt,
} from "./utils/oauth/types.ts";
export * from "./utils/overflow.ts";
export * from "./utils/typebox-helpers.ts";
export * from "./utils/validation.ts";

View file

@ -1,6 +1,4 @@
import { register, streamBedrock, streamSimpleBedrock } from "./providers/amazon-bedrock.ts";
export { register };
import { streamBedrock, streamSimpleBedrock } from "./providers/amazon-bedrock.ts";
export const bedrockProviderModule = {
streamBedrock,

View file

@ -51,7 +51,3 @@ export function registerImagesApiProvider<TApi extends ImagesApi, TOptions exten
export function getImagesApiProvider(api: ImagesApi): ImagesApiProviderInternal | undefined {
return imagesApiProviderRegistry.get(api)?.provider;
}
export function clearImagesApiProviders(): void {
imagesApiProviderRegistry.clear();
}

View file

@ -1,3 +1,5 @@
import "./providers/images/register-builtins.ts";
import { getImagesApiProvider } from "./images-api-registry.ts";
import type { AssistantImages, ImagesApi, ImagesContext, ImagesModel, ProviderImagesOptions } from "./types.ts";

View file

@ -1,6 +1,47 @@
import { registerBuiltInImagesApiProviders } from "./providers/register-builtins.ts";
export type { Static, TSchema } from "typebox";
export { Type } from "typebox";
export * from "./base.ts";
export * from "./api-registry.ts";
export * from "./env-api-keys.ts";
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";
registerBuiltInImagesApiProviders();
export * from "./session-resources.ts";
export * from "./stream.ts";
export * from "./types.ts";
export * from "./utils/diagnostics.ts";
export * from "./utils/event-stream.ts";
export * from "./utils/json-parse.ts";
export type {
OAuthAuthInfo,
OAuthCredentials,
OAuthDeviceCodeInfo,
OAuthLoginCallbacks,
OAuthPrompt,
OAuthProvider,
OAuthProviderId,
OAuthProviderInfo,
OAuthProviderInterface,
OAuthSelectOption,
OAuthSelectPrompt,
} from "./utils/oauth/types.ts";
export * from "./utils/overflow.ts";
export * from "./utils/typebox-helpers.ts";
export * from "./utils/validation.ts";

View file

@ -26,7 +26,6 @@ import { NodeHttpHandler } from "@smithy/node-http-handler";
import type { BuildMiddleware, DocumentType, MetadataBearer } from "@smithy/types";
import { HttpProxyAgent } from "http-proxy-agent";
import { HttpsProxyAgent } from "https-proxy-agent";
import { registerApiProvider } from "../api-registry.ts";
import { calculateCost } from "../models.ts";
import type {
Api,
@ -414,14 +413,6 @@ export const streamSimpleBedrock: StreamFunction<"bedrock-converse-stream", Simp
} satisfies BedrockOptions);
};
export function register(): void {
registerApiProvider({
api: "bedrock-converse-stream",
stream: streamBedrock,
streamSimple: streamSimpleBedrock,
});
}
function handleContentBlockStart(
event: ContentBlockStartEvent,
blocks: Block[],

View file

@ -7,7 +7,6 @@ import type {
RawMessageStreamEvent,
RefusalStopDetails,
} from "@anthropic-ai/sdk/resources/messages.js";
import { registerApiProvider } from "../api-registry.ts";
import { calculateCost } from "../models.ts";
import type {
AnthropicMessagesCompat,
@ -787,14 +786,6 @@ export const streamSimpleAnthropic: StreamFunction<"anthropic-messages", SimpleS
} satisfies AnthropicOptions);
};
export function register(): void {
registerApiProvider({
api: "anthropic-messages",
stream: streamAnthropic,
streamSimple: streamSimpleAnthropic,
});
}
function isOAuthToken(apiKey: string): boolean {
return apiKey.includes("sk-ant-oat");
}

View file

@ -1,6 +1,5 @@
import { AzureOpenAI } from "openai";
import type { ResponseCreateParamsStreaming } from "openai/resources/responses/responses.js";
import { registerApiProvider } from "../api-registry.ts";
import { clampThinkingLevel } from "../models.ts";
import type {
Api,
@ -171,14 +170,6 @@ export const streamSimpleAzureOpenAIResponses: StreamFunction<"azure-openai-resp
} satisfies AzureOpenAIResponsesOptions);
};
export function register(): void {
registerApiProvider({
api: "azure-openai-responses",
stream: streamAzureOpenAIResponses,
streamSimple: streamSimpleAzureOpenAIResponses,
});
}
function normalizeAzureBaseUrl(baseUrl: string): string {
const trimmed = baseUrl.trim().replace(/\/+$/, "");
let url: URL;

View file

@ -7,7 +7,6 @@ import {
type ThinkingConfig,
ThinkingLevel,
} from "@google/genai";
import { registerApiProvider } from "../api-registry.ts";
import { calculateCost, clampThinkingLevel } from "../models.ts";
import type {
Api,
@ -331,14 +330,6 @@ export const streamSimpleGoogleVertex: StreamFunction<"google-vertex", SimpleStr
} satisfies GoogleVertexOptions);
};
export function register(): void {
registerApiProvider({
api: "google-vertex",
stream: streamGoogleVertex,
streamSimple: streamSimpleGoogleVertex,
});
}
function createClient(
model: Model<"google-vertex">,
project: string,

View file

@ -4,7 +4,6 @@ import {
GoogleGenAI,
type ThinkingConfig,
} from "@google/genai";
import { registerApiProvider } from "../api-registry.ts";
import { calculateCost, clampThinkingLevel } from "../models.ts";
import type {
Api,
@ -316,14 +315,6 @@ export const streamSimpleGoogle: StreamFunction<"google-generative-ai", SimpleSt
} satisfies GoogleOptions);
};
export function register(): void {
registerApiProvider({
api: "google-generative-ai",
stream: streamGoogle,
streamSimple: streamSimpleGoogle,
});
}
function createClient(
model: Model<"google-generative-ai">,
apiKey?: string,

View file

@ -6,7 +6,6 @@ import type {
ChatCompletionContentPartText,
ChatCompletionCreateParamsNonStreaming,
} from "openai/resources/chat/completions.js";
import { registerImagesApiProvider } from "../../images-api-registry.ts";
import type {
AssistantImages,
ImageContent,
@ -104,13 +103,6 @@ export const generateImagesOpenRouter: ImagesFunction<"openrouter-images", Image
}
};
export function register(): void {
registerImagesApiProvider({
api: "openrouter-images",
generateImages: generateImagesOpenRouter,
});
}
function createClient(
model: ImagesModel<"openrouter-images">,
apiKey: string,

View file

@ -0,0 +1,50 @@
import { registerImagesApiProvider } from "../../images-api-registry.ts";
import type { AssistantImages, ImagesContext, ImagesFunction, ImagesModel, ImagesOptions } from "../../types.ts";
import type { generateImagesOpenRouter as generateImagesOpenRouterFunction } from "./openrouter.ts";
interface OpenRouterImagesProviderModule {
generateImagesOpenRouter: typeof generateImagesOpenRouterFunction;
}
let openRouterImagesProviderModulePromise: Promise<OpenRouterImagesProviderModule> | undefined;
function createLazyLoadErrorImages(model: ImagesModel<"openrouter-images">, error: unknown): AssistantImages {
return {
api: model.api,
provider: model.provider,
model: model.id,
output: [],
stopReason: "error",
errorMessage: error instanceof Error ? error.message : String(error),
timestamp: Date.now(),
};
}
function loadOpenRouterImagesProviderModule(): Promise<OpenRouterImagesProviderModule> {
openRouterImagesProviderModulePromise ||= import("./openrouter.ts").then(
(module) => module as OpenRouterImagesProviderModule,
);
return openRouterImagesProviderModulePromise;
}
export const generateImagesOpenRouter: ImagesFunction<"openrouter-images", ImagesOptions> = async (
model: ImagesModel<"openrouter-images">,
context: ImagesContext,
options?: ImagesOptions,
) => {
try {
const module = await loadOpenRouterImagesProviderModule();
return await module.generateImagesOpenRouter(model, context, options);
} catch (error) {
return createLazyLoadErrorImages(model, error);
}
};
export function registerBuiltInImagesApiProviders(): void {
registerImagesApiProvider({
api: "openrouter-images",
generateImages: generateImagesOpenRouter,
});
}
registerBuiltInImagesApiProviders();

View file

@ -6,7 +6,6 @@ import type {
ContentChunk,
FunctionTool,
} from "@mistralai/mistralai/models/components";
import { registerApiProvider } from "../api-registry.ts";
import { calculateCost, clampThinkingLevel } from "../models.ts";
import type {
AssistantMessage,
@ -131,14 +130,6 @@ export const streamSimpleMistral: StreamFunction<"mistral-conversations", Simple
} satisfies MistralOptions);
};
export function register(): void {
registerApiProvider({
api: "mistral-conversations",
stream: streamMistral,
streamSimple: streamSimpleMistral,
});
}
function createOutput(model: Model<"mistral-conversations">): AssistantMessage {
return {
role: "assistant",

View file

@ -20,7 +20,6 @@ if (typeof process !== "undefined" && (process.versions?.node || process.version
});
}
import { registerApiProvider } from "../api-registry.ts";
import { clampThinkingLevel } from "../models.ts";
import { registerSessionResourceCleanup } from "../session-resources.ts";
import type {
@ -429,14 +428,6 @@ export const streamSimpleOpenAICodexResponses: StreamFunction<"openai-codex-resp
} satisfies OpenAICodexResponsesOptions);
};
export function register(): void {
registerApiProvider({
api: "openai-codex-responses",
stream: streamOpenAICodexResponses,
streamSimple: streamSimpleOpenAICodexResponses,
});
}
// ============================================================================
// Request Building
// ============================================================================

View file

@ -10,7 +10,6 @@ import type {
ChatCompletionSystemMessageParam,
ChatCompletionToolMessageParam,
} from "openai/resources/chat/completions.js";
import { registerApiProvider } from "../api-registry.ts";
import { calculateCost, clampThinkingLevel } from "../models.ts";
import type {
AssistantMessage,
@ -486,14 +485,6 @@ export const streamSimpleOpenAICompletions: StreamFunction<"openai-completions",
} satisfies OpenAICompletionsOptions);
};
export function register(): void {
registerApiProvider({
api: "openai-completions",
stream: streamOpenAICompletions,
streamSimple: streamSimpleOpenAICompletions,
});
}
function createClient(
model: Model<"openai-completions">,
context: Context,

View file

@ -1,6 +1,5 @@
import OpenAI from "openai";
import type { ResponseCreateParamsStreaming } from "openai/resources/responses/responses.js";
import { registerApiProvider } from "../api-registry.ts";
import { clampThinkingLevel } from "../models.ts";
import type {
Api,
@ -182,14 +181,6 @@ export const streamSimpleOpenAIResponses: StreamFunction<"openai-responses", Sim
} satisfies OpenAIResponsesOptions);
};
export function register(): void {
registerApiProvider({
api: "openai-responses",
stream: streamOpenAIResponses,
streamSimple: streamSimpleOpenAIResponses,
});
}
function createClient(
model: Model<"openai-responses">,
context: Context,

View file

@ -1,14 +1,9 @@
import { type ApiProvider, clearApiProviders, getApiProvider, registerApiProvider } from "../api-registry.ts";
import { getImagesApiProvider, type ImagesApiProvider, registerImagesApiProvider } from "../images-api-registry.ts";
import { clearApiProviders, registerApiProvider } from "../api-registry.ts";
import type {
Api,
AssistantImages,
AssistantMessage,
AssistantMessageEvent,
ImagesApi,
ImagesContext,
ImagesModel,
ImagesOptions,
Context,
Model,
SimpleStreamOptions,
StreamFunction,
@ -25,47 +20,70 @@ import type { OpenAICodexResponsesOptions } from "./openai-codex-responses.ts";
import type { OpenAICompletionsOptions } from "./openai-completions.ts";
import type { OpenAIResponsesOptions } from "./openai-responses.ts";
interface RegisteringProviderModule {
register(): void;
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>;
}
function createLazyLoadErrorImages(model: ImagesModel<"openrouter-images">, error: unknown): AssistantImages {
return {
api: model.api,
provider: model.provider,
model: model.id,
output: [],
stopReason: "error",
errorMessage: error instanceof Error ? error.message : String(error),
timestamp: Date.now(),
};
interface AnthropicProviderModule {
streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOptions>;
streamSimpleAnthropic: StreamFunction<"anthropic-messages", SimpleStreamOptions>;
}
function createLazyImagesApiProvider<TApi extends ImagesApi, TOptions extends ImagesOptions>(
api: TApi,
loadModule: () => Promise<RegisteringProviderModule>,
): ImagesApiProvider<TApi, TOptions> {
return {
api,
generateImages: async (model: ImagesModel<TApi>, context: ImagesContext, options?: TOptions) => {
try {
const module = await loadModule();
module.register();
const provider = getImagesApiProvider(api);
if (!provider) {
throw new Error(`No API provider registered for api: ${api}`);
}
return await provider.generateImages(model, context, options);
} catch (error) {
return createLazyLoadErrorImages(model as ImagesModel<"openrouter-images">, error);
}
},
};
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: StreamFunction<"bedrock-converse-stream", BedrockOptions>;
streamSimpleBedrock: StreamFunction<"bedrock-converse-stream", SimpleStreamOptions>;
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> => {
@ -73,10 +91,42 @@ const importNodeOnlyProvider = (specifier: string): Promise<unknown> => {
return import(runtimeSpecifier);
};
let bedrockProviderModuleOverride: BedrockProviderModule | undefined;
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 = module;
bedrockProviderModuleOverride = {
stream: module.streamBedrock,
streamSimple: module.streamSimpleBedrock,
};
}
function forwardStream(target: AssistantMessageEventStream, source: AsyncIterable<AssistantMessageEvent>): void {
@ -109,29 +159,15 @@ function createLazyLoadErrorMessage<TApi extends Api>(model: Model<TApi>, error:
};
}
async function loadAndRegisterProvider<TApi extends Api>(
api: TApi,
loadModule: () => Promise<RegisteringProviderModule>,
) {
const module = await loadModule();
module.register();
const provider = getApiProvider(api);
if (!provider) {
throw new Error(`No API provider registered for api: ${api}`);
}
return provider;
}
function createLazyStream<TApi extends Api, TOptions extends StreamOptions>(
api: TApi,
loadModule: () => Promise<RegisteringProviderModule>,
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();
loadAndRegisterProvider(api, loadModule)
.then((provider) => {
const inner = provider.stream(model, context, options);
loadModule()
.then((module) => {
const inner = module.stream(model, context, options);
forwardStream(outer, inner);
})
.catch((error) => {
@ -144,16 +180,17 @@ function createLazyStream<TApi extends Api, TOptions extends StreamOptions>(
};
}
function createLazySimpleStream<TApi extends Api>(
api: TApi,
loadModule: () => Promise<RegisteringProviderModule>,
): StreamFunction<TApi, SimpleStreamOptions> {
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();
loadAndRegisterProvider(api, loadModule)
.then((provider) => {
const inner = provider.streamSimple(model, context, options);
loadModule()
.then((module) => {
const inner = module.streamSimple(model, context, options);
forwardStream(outer, inner);
})
.catch((error) => {
@ -166,112 +203,199 @@ function createLazySimpleStream<TApi extends Api>(
};
}
function createLazyApiProvider<TApi extends Api, TOptions extends StreamOptions>(
api: TApi,
loadModule: () => Promise<RegisteringProviderModule>,
): ApiProvider<TApi, TOptions> {
return {
api,
stream: createLazyStream<TApi, TOptions>(api, loadModule),
streamSimple: createLazySimpleStream(api, loadModule),
};
}
function registerBedrockProviderModule(module: BedrockProviderModule): void {
registerApiProvider({
api: "bedrock-converse-stream",
stream: module.streamBedrock,
streamSimple: module.streamSimpleBedrock,
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 loadBedrockProviderModule(): Promise<RegisteringProviderModule> {
const module = bedrockProviderModuleOverride;
if (module) {
return Promise.resolve({ register: () => registerBedrockProviderModule(module) });
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);
}
return importNodeOnlyProvider("./amazon-bedrock.ts").then((provider) => provider as RegisteringProviderModule);
bedrockProviderModulePromise ||= importNodeOnlyProvider("./amazon-bedrock.ts").then((module) => {
const provider = module as BedrockProviderModule;
return {
stream: provider.streamBedrock,
streamSimple: provider.streamSimpleBedrock,
};
});
return bedrockProviderModulePromise;
}
const anthropicProvider = createLazyApiProvider<"anthropic-messages", AnthropicOptions>(
"anthropic-messages",
() => import("./anthropic.ts"),
);
const azureOpenAIResponsesProvider = createLazyApiProvider<"azure-openai-responses", AzureOpenAIResponsesOptions>(
"azure-openai-responses",
() => import("./azure-openai-responses.ts"),
);
const googleProvider = createLazyApiProvider<"google-generative-ai", GoogleOptions>(
"google-generative-ai",
() => import("./google.ts"),
);
const googleVertexProvider = createLazyApiProvider<"google-vertex", GoogleVertexOptions>(
"google-vertex",
() => import("./google-vertex.ts"),
);
const mistralProvider = createLazyApiProvider<"mistral-conversations", MistralOptions>(
"mistral-conversations",
() => import("./mistral.ts"),
);
const openAICodexResponsesProvider = createLazyApiProvider<"openai-codex-responses", OpenAICodexResponsesOptions>(
"openai-codex-responses",
() => import("./openai-codex-responses.ts"),
);
const openAICompletionsProvider = createLazyApiProvider<"openai-completions", OpenAICompletionsOptions>(
"openai-completions",
() => import("./openai-completions.ts"),
);
const openAIResponsesProvider = createLazyApiProvider<"openai-responses", OpenAIResponsesOptions>(
"openai-responses",
() => import("./openai-responses.ts"),
);
const bedrockProvider = createLazyApiProvider<"bedrock-converse-stream", BedrockOptions>(
"bedrock-converse-stream",
loadBedrockProviderModule,
);
const openRouterImagesProvider = createLazyImagesApiProvider(
"openrouter-images",
() => import("./images/openrouter.ts"),
);
export const generateImagesOpenRouter = openRouterImagesProvider.generateImages;
export const streamAnthropic = anthropicProvider.stream;
export const streamSimpleAnthropic = anthropicProvider.streamSimple;
export const streamAzureOpenAIResponses = azureOpenAIResponsesProvider.stream;
export const streamSimpleAzureOpenAIResponses = azureOpenAIResponsesProvider.streamSimple;
export const streamGoogle = googleProvider.stream;
export const streamSimpleGoogle = googleProvider.streamSimple;
export const streamGoogleVertex = googleVertexProvider.stream;
export const streamSimpleGoogleVertex = googleVertexProvider.streamSimple;
export const streamMistral = mistralProvider.stream;
export const streamSimpleMistral = mistralProvider.streamSimple;
export const streamOpenAICodexResponses = openAICodexResponsesProvider.stream;
export const streamSimpleOpenAICodexResponses = openAICodexResponsesProvider.streamSimple;
export const streamOpenAICompletions = openAICompletionsProvider.stream;
export const streamSimpleOpenAICompletions = openAICompletionsProvider.streamSimple;
export const streamOpenAIResponses = openAIResponsesProvider.stream;
export const streamSimpleOpenAIResponses = openAIResponsesProvider.streamSimple;
const registerBuiltInApiProviderFunctions = [
() => registerApiProvider(anthropicProvider),
() => registerApiProvider(openAICompletionsProvider),
() => registerApiProvider(mistralProvider),
() => registerApiProvider(openAIResponsesProvider),
() => registerApiProvider(azureOpenAIResponsesProvider),
() => registerApiProvider(openAICodexResponsesProvider),
() => registerApiProvider(googleProvider),
() => registerApiProvider(googleVertexProvider),
() => registerApiProvider(bedrockProvider),
];
export function registerBuiltInImagesApiProviders(): void {
registerImagesApiProvider(openRouterImagesProvider);
}
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 {
for (const register of registerBuiltInApiProviderFunctions) {
register();
}
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 {

View file

@ -1,3 +1,5 @@
import "./providers/register-builtins.ts";
import { getApiProvider } from "./api-registry.ts";
import { getEnvApiKey } from "./env-api-keys.ts";
import type {
@ -11,6 +13,8 @@ import type {
StreamOptions,
} from "./types.ts";
export { getEnvApiKey } from "./env-api-keys.ts";
function hasExplicitApiKey(apiKey: string | undefined): apiKey is string {
return typeof apiKey === "string" && apiKey.trim().length > 0;
}

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { complete, stream } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { complete, stream } from "../src/stream.ts";
import type { Api, Context, Model, StreamOptions } from "../src/types.ts";
type StreamOptionsWithExtras = StreamOptions & Record<string, unknown>;

View file

@ -1,8 +1,8 @@
import { Type } from "typebox";
import { describe, expect, it } from "vitest";
import { getEnvApiKey } from "../src/env-api-keys.ts";
import { complete } from "../src/index.ts";
import { getModels, getProviders } from "../src/models.ts";
import { complete } from "../src/stream.ts";
import type { Api, KnownProvider, Model, ProviderStreamOptions, Tool } from "../src/types.ts";
import { resolveApiKey } from "./oauth.ts";

View file

@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { streamSimple } from "../src/index.ts";
import { streamSimple } from "../src/stream.ts";
import type { AssistantMessage, Context, Model } from "../src/types.ts";
interface AnthropicPayload {

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { streamSimple } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { streamSimple } from "../src/stream.ts";
import type { Context, Model, SimpleStreamOptions } from "../src/types.ts";
interface AnthropicThinkingPayload {

View file

@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest";
import { getEnvApiKey } from "../src/env-api-keys.ts";
import { complete } from "../src/index.ts";
import { getModels, getProviders } from "../src/models.ts";
import { complete } from "../src/stream.ts";
import type { Api, KnownProvider, Model, ProviderStreamOptions } from "../src/types.ts";
import { resolveApiKey } from "./oauth.ts";

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { streamSimple } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { streamSimple } from "../src/stream.ts";
import type { Context } from "../src/types.ts";
interface AnthropicThinkingPayload {

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { streamSimple } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { streamSimple } from "../src/stream.ts";
import type { Context, Model, SimpleStreamOptions } from "../src/types.ts";
interface AnthropicTemperaturePayload {

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { streamSimple } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { streamSimple } from "../src/stream.ts";
import type { Context, Model, SimpleStreamOptions } from "../src/types.ts";
interface AnthropicThinkingPayload {

View file

@ -1,7 +1,7 @@
import { Type } from "typebox";
import { describe, expect, it } from "vitest";
import { stream } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { stream } from "../src/stream.ts";
import type { Context, Tool } from "../src/types.ts";
import { resolveApiKey } from "./oauth.ts";

View file

@ -1,68 +0,0 @@
import { afterEach, describe, expect, it } from "vitest";
import { clearApiProviders, complete, getApiProvider, getApiProviders } from "../src/base.ts";
import { register as registerAmazonBedrock } from "../src/providers/amazon-bedrock.ts";
import { register as registerAnthropic } from "../src/providers/anthropic.ts";
import { register as registerAzureOpenAIResponses } from "../src/providers/azure-openai-responses.ts";
import { fauxAssistantMessage, registerFauxProvider } from "../src/providers/faux.ts";
import { register as registerGoogle } from "../src/providers/google.ts";
import { register as registerGoogleVertex } from "../src/providers/google-vertex.ts";
import { register as registerMistral } from "../src/providers/mistral.ts";
import { register as registerOpenAICodexResponses } from "../src/providers/openai-codex-responses.ts";
import { register as registerOpenAICompletions } from "../src/providers/openai-completions.ts";
import { register as registerOpenAIResponses } from "../src/providers/openai-responses.ts";
const registrations = [
["bedrock-converse-stream", registerAmazonBedrock],
["anthropic-messages", registerAnthropic],
["azure-openai-responses", registerAzureOpenAIResponses],
["google-generative-ai", registerGoogle],
["google-vertex", registerGoogleVertex],
["mistral-conversations", registerMistral],
["openai-codex-responses", registerOpenAICodexResponses],
["openai-completions", registerOpenAICompletions],
["openai-responses", registerOpenAIResponses],
] as const;
afterEach(() => {
clearApiProviders();
});
describe("base entrypoint", () => {
it("starts without built-in provider registrations", () => {
expect(getApiProviders()).toEqual([]);
});
it.each(registrations)("registers the %s transport explicitly", (api, register) => {
register();
expect(getApiProvider(api)?.api).toBe(api);
});
it("dispatches custom providers", async () => {
const registration = registerFauxProvider();
registration.setResponses([fauxAssistantMessage("hello")]);
const response = await complete(registration.getModel(), {
messages: [{ role: "user", content: "hi", timestamp: Date.now() }],
});
expect(response.content).toEqual([{ type: "text", text: "hello" }]);
});
it("fails clearly when no transport is registered", async () => {
await expect(
complete(
{
id: "missing-model",
name: "Missing Model",
api: "missing-api",
provider: "missing-provider",
baseUrl: "https://example.com",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 1,
maxTokens: 1,
},
{ messages: [] },
),
).rejects.toThrow("No API provider registered for api: missing-api");
});
});

View file

@ -17,8 +17,8 @@
*/
import { describe, expect, it } from "vitest";
import { complete } from "../src/index.ts";
import { getModels } from "../src/models.ts";
import { complete } from "../src/stream.ts";
import type { Context } from "../src/types.ts";
import { hasBedrockCredentials } from "./bedrock-utils.ts";

View file

@ -1,10 +1,10 @@
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { stream } from "../src/index.ts";
import { MODELS } from "../src/models.generated.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";
class PayloadCaptured extends Error {

View file

@ -14,8 +14,8 @@
import type { ChildProcess } from "child_process";
import { execSync, spawn } from "child_process";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { complete } from "../src/index.ts";
import { getModel, getModels } from "../src/models.ts";
import { complete } from "../src/stream.ts";
import type { AssistantMessage, Context, Model, Usage } from "../src/types.ts";
import { isContextOverflow } from "../src/utils/overflow.ts";
import { hasAzureOpenAICredentials } from "./azure-utils.ts";

View file

@ -25,8 +25,8 @@
import { writeFileSync } from "fs";
import { Type } from "typebox";
import { beforeAll, describe, expect, it } from "vitest";
import { completeSimple, getEnvApiKey } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { completeSimple, getEnvApiKey } from "../src/stream.ts";
import type { Api, AssistantMessage, Message, Model, Tool, ToolResultMessage } from "../src/types.ts";
import { hasAzureOpenAICredentials } from "./azure-utils.ts";
import { hasCloudflareAiGatewayCredentials, hasCloudflareWorkersAICredentials } from "./cloudflare-utils.ts";

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { complete } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { complete } from "../src/stream.ts";
import type { Api, AssistantMessage, Context, Model, StreamOptions, UserMessage } from "../src/types.ts";
type StreamOptionsWithExtras = StreamOptions & Record<string, unknown>;

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { streamSimple } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { streamSimple } from "../src/stream.ts";
import type { Api, Context, Model, SimpleStreamOptions } from "../src/types.ts";
type SimpleOptionsWithExtras = SimpleStreamOptions & Record<string, unknown>;

View file

@ -1,8 +1,8 @@
import { Type } from "typebox";
import { describe, expect, it } from "vitest";
import { getEnvApiKey } from "../src/env-api-keys.ts";
import { completeSimple } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { completeSimple } from "../src/stream.ts";
import type { Api, Context, Model, StopReason, Tool, ToolCall, ToolResultMessage } from "../src/types.ts";
import { StringEnum } from "../src/utils/typebox-helpers.ts";
import { hasBedrockCredentials } from "./bedrock-utils.ts";

View file

@ -5,7 +5,6 @@ import { describe, expect, it } from "vitest";
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const aiEntryUrl = new URL("../src/index.ts", import.meta.url).href;
const baseEntryUrl = new URL("../src/base.ts", import.meta.url).href;
const SDK_SPECIFIERS = [
"@anthropic-ai/sdk",
@ -17,10 +16,9 @@ const SDK_SPECIFIERS = [
type ProbeResult = {
loadedSpecifiers: string[];
value?: unknown;
};
function runProbe(action: string, entryUrl = aiEntryUrl): ProbeResult {
function runProbe(action: string): ProbeResult {
const script = `
import { registerHooks } from "node:module";
@ -36,11 +34,9 @@ function runProbe(action: string, entryUrl = aiEntryUrl): ProbeResult {
},
});
const mod = await import(${JSON.stringify(entryUrl)});
const value = await (async () => {
${action}
})();
console.log(JSON.stringify({ loadedSpecifiers: [...new Set(loaded)], value }));
const mod = await import(${JSON.stringify(aiEntryUrl)});
${action}
console.log(JSON.stringify({ loadedSpecifiers: [...new Set(loaded)] }));
`;
const result = spawnSync(process.execPath, ["--input-type=module", "--eval", script], {
@ -70,33 +66,6 @@ describe("lazy provider module loading", () => {
expect(result.loadedSpecifiers).toEqual([]);
});
it("registers built-in transports when importing the root barrel", () => {
const result = runProbe(`return mod.getApiProviders().map((provider) => provider.api).sort();`);
expect(result.value).toEqual([
"anthropic-messages",
"azure-openai-responses",
"bedrock-converse-stream",
"google-generative-ai",
"google-vertex",
"mistral-conversations",
"openai-codex-responses",
"openai-completions",
"openai-responses",
]);
});
it("registers built-in image transports when importing the root barrel", () => {
const result = runProbe(`return mod.getImagesApiProvider("openrouter-images")?.api;`);
expect(result.loadedSpecifiers).toEqual([]);
expect(result.value).toBe("openrouter-images");
});
it("does not load provider SDKs or register transports when importing the base barrel", () => {
const result = runProbe(`return mod.getApiProviders().map((provider) => provider.api);`, baseEntryUrl);
expect(result.loadedSpecifiers).toEqual([]);
expect(result.value).toEqual([]);
});
it("loads only the Anthropic SDK when calling the root lazy wrapper", () => {
const result = runProbe(`
const model = {
@ -127,17 +96,4 @@ describe("lazy provider module loading", () => {
expect(result.loadedSpecifiers).toEqual(["@anthropic-ai/sdk"]);
});
it("dispatches through a lazy wrapper again after resetting providers", () => {
const result = runProbe(`
const model = mod.getModel("anthropic", "claude-sonnet-4-6");
const context = { messages: [{ role: "user", content: "hi" }] };
await mod.streamSimple(model, context).result();
mod.resetApiProviders();
return (await mod.streamSimple(model, context).result()).stopReason;
`);
expect(result.loadedSpecifiers).toEqual(["@anthropic-ai/sdk"]);
expect(result.value).toBe("error");
});
});

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { streamSimple } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { streamSimple } from "../src/stream.ts";
import type { Context, Model, SimpleStreamOptions } from "../src/types.ts";
interface MistralPayload {

View file

@ -1,7 +1,7 @@
import { Type } from "typebox";
import { describe, expect, it } from "vitest";
import { complete } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { complete } from "../src/stream.ts";
import type { Context, Model } from "../src/types.ts";
interface MistralToolPayload {

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { complete } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { complete } from "../src/stream.ts";
import type { Context } from "../src/types.ts";
import { resolveApiKey } from "./oauth.ts";

View file

@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { streamSimple } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { streamSimple } from "../src/stream.ts";
// Empty tools arrays must NOT be serialized as `tools: []` — some OpenAI-compatible
// backends (e.g. DashScope / Aliyun Qwen via compatible-mode) reject the request with

View file

@ -1,5 +1,5 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { complete } from "../src/index.ts";
import { complete } from "../src/stream.ts";
import type { Model } from "../src/types.ts";
// Router/virtual ids (e.g. OpenRouter `auto`) keep `model` pinned to the

View file

@ -1,8 +1,8 @@
import { Type } from "typebox";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { stream, streamSimple } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { convertMessages } from "../src/providers/openai-completions.ts";
import { stream, streamSimple } from "../src/stream.ts";
import type { AssistantMessage, Model, SimpleStreamOptions, Tool, ToolResultMessage } from "../src/types.ts";
const mockState = vi.hoisted(() => ({

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { complete } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { complete } from "../src/stream.ts";
import type { Context } from "../src/types.ts";
describe.skipIf(!process.env.OPENAI_API_KEY)("openai responses cache affinity e2e", () => {

View file

@ -1,7 +1,7 @@
import { Type } from "typebox";
import { describe, expect, it } from "vitest";
import { complete, getEnvApiKey } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { complete, getEnvApiKey } from "../src/stream.ts";
import type { AssistantMessage, Context, Message, Tool, ToolCall } from "../src/types.ts";
const testToolSchema = Type.Object({

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { completeSimple } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { completeSimple } from "../src/stream.ts";
function createLongSystemPrompt(): string {
const nonce = `${Date.now()}-${Math.random()}`;

View file

@ -1,8 +1,5 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { generateImages } from "../src/images.ts";
import { clearImagesApiProviders, getImagesApiProvider } from "../src/images-api-registry.ts";
import { register as registerOpenRouterImages } from "../src/providers/images/openrouter.ts";
import { registerBuiltInImagesApiProviders } from "../src/providers/register-builtins.ts";
import type { ImagesContext, ImagesModel } from "../src/types.ts";
const mockState = vi.hoisted(() => ({
@ -65,15 +62,6 @@ describe("openrouter images", () => {
beforeEach(() => {
mockState.lastParams = undefined;
mockState.lastRequestOptions = undefined;
clearImagesApiProviders();
registerBuiltInImagesApiProviders();
});
it("registers the direct OpenRouter images transport explicitly", () => {
clearImagesApiProviders();
expect(getImagesApiProvider("openrouter-images")).toBeUndefined();
registerOpenRouterImages();
expect(getImagesApiProvider("openrouter-images")?.api).toBe("openrouter-images");
});
it("returns text plus images in final output", async () => {

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { complete } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { complete } from "../src/stream.ts";
import type { Api, Context, Model, StreamOptions } from "../src/types.ts";
import { hasAzureOpenAICredentials, resolveAzureDeploymentName } from "./azure-utils.ts";
import { resolveApiKey } from "./oauth.ts";

View file

@ -4,8 +4,8 @@ import { dirname, join } from "path";
import { Type } from "typebox";
import { fileURLToPath } from "url";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { complete, stream } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { complete, stream } from "../src/stream.ts";
import type { Api, Context, ImageContent, Model, StreamOptions, Tool, ToolResultMessage } from "../src/types.ts";
type StreamOptionsWithExtras = StreamOptions & Record<string, unknown>;

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { stream } from "../src/index.ts";
import { getModel, getModels } from "../src/models.ts";
import { stream } from "../src/stream.ts";
import type { Api, Context, Model, StreamOptions } from "../src/types.ts";
type StreamOptionsWithExtras = StreamOptions & Record<string, unknown>;

View file

@ -12,8 +12,8 @@
import { Type } from "typebox";
import { describe, expect, it } from "vitest";
import { completeSimple, getEnvApiKey } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { completeSimple, getEnvApiKey } from "../src/stream.ts";
import type { AssistantMessage, Message, Tool, ToolResultMessage } from "../src/types.ts";
import { resolveApiKey } from "./oauth.ts";

View file

@ -1,7 +1,7 @@
import { Type } from "typebox";
import { describe, expect, it } from "vitest";
import { complete } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { complete } from "../src/stream.ts";
import type { Api, Context, Model, StreamOptions, Tool } from "../src/types.ts";
type StreamOptionsWithExtras = StreamOptions & Record<string, unknown>;

View file

@ -13,8 +13,8 @@
*/
import { describe, expect, it } from "vitest";
import { complete } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { complete } from "../src/stream.ts";
import type { Api, Context, Model, StreamOptions, Usage } from "../src/types.ts";
type StreamOptionsWithExtras = StreamOptions & Record<string, unknown>;

View file

@ -1,7 +1,7 @@
import { Type } from "typebox";
import { describe, expect, it } from "vitest";
import { complete } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { complete } from "../src/stream.ts";
import type { Api, Context, Model, StreamOptions, ToolResultMessage } from "../src/types.ts";
type StreamOptionsWithExtras = StreamOptions & Record<string, unknown>;

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { stream } from "../src/index.ts";
import { getModel } from "../src/models.ts";
import { stream } from "../src/stream.ts";
import type { Context, Model } from "../src/types.ts";
function makeContext(): Context {

View file

@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { completeSimple, getEnvApiKey, streamSimple } from "../src/index.ts";
import { completeSimple, getEnvApiKey, streamSimple } from "../src/stream.ts";
import type { AssistantMessage, Context, Model } from "../src/types.ts";
const provider = "xiaomi-token-plan-ams";

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { complete } from "../src/index.ts";
import { MODELS } from "../src/models.generated.ts";
import { complete } from "../src/stream.ts";
import type { Model } from "../src/types.ts";
describe.skipIf(!process.env.OPENCODE_API_KEY)("OpenCode Models Smoke Test", () => {

View file

@ -2,11 +2,8 @@ import { fileURLToPath } from "node:url";
import { defineConfig } from "vitest/config";
const aiSrcIndex = fileURLToPath(new URL("../ai/src/index.ts", import.meta.url));
const aiSrcBase = fileURLToPath(new URL("../ai/src/base.ts", import.meta.url));
const aiSrcOAuth = fileURLToPath(new URL("../ai/src/oauth.ts", import.meta.url));
const aiOpenRouterImages = fileURLToPath(new URL("../ai/src/providers/images/openrouter.ts", import.meta.url));
const agentSrcIndex = fileURLToPath(new URL("../agent/src/index.ts", import.meta.url));
const agentSrcBase = fileURLToPath(new URL("../agent/src/base.ts", import.meta.url));
const tuiSrcIndex = fileURLToPath(new URL("../tui/src/index.ts", import.meta.url));
export default defineConfig({
@ -23,18 +20,12 @@ export default defineConfig({
resolve: {
alias: [
{ find: /^@earendil-works\/pi-ai$/, replacement: aiSrcIndex },
{ find: /^@earendil-works\/pi-ai\/base$/, replacement: aiSrcBase },
{ find: /^@earendil-works\/pi-ai\/oauth$/, replacement: aiSrcOAuth },
{ find: /^@earendil-works\/pi-ai\/openrouter-images$/, replacement: aiOpenRouterImages },
{ find: /^@earendil-works\/pi-agent-core$/, replacement: agentSrcIndex },
{ find: /^@earendil-works\/pi-agent-core\/base$/, replacement: agentSrcBase },
{ find: /^@earendil-works\/pi-tui$/, replacement: tuiSrcIndex },
{ find: /^@mariozechner\/pi-ai$/, replacement: aiSrcIndex },
{ find: /^@mariozechner\/pi-ai\/base$/, replacement: aiSrcBase },
{ find: /^@mariozechner\/pi-ai\/oauth$/, replacement: aiSrcOAuth },
{ find: /^@mariozechner\/pi-ai\/openrouter-images$/, replacement: aiOpenRouterImages },
{ find: /^@mariozechner\/pi-agent-core$/, replacement: agentSrcIndex },
{ find: /^@mariozechner\/pi-agent-core\/base$/, replacement: agentSrcBase },
{ find: /^@mariozechner\/pi-tui$/, replacement: tuiSrcIndex },
],
},

View file

@ -4,21 +4,7 @@ import { join } from "node:path";
import { build } from "esbuild";
const outputPath = join(tmpdir(), "pi-browser-smoke.js");
const baseOutputPath = join(tmpdir(), "pi-browser-base-smoke.js");
const selectiveOutputPath = join(tmpdir(), "pi-browser-selective-smoke.js");
const errorLogPath = join(tmpdir(), "pi-browser-smoke-errors.log");
const providerImplementationInputs = [
"packages/ai/src/providers/amazon-bedrock.ts",
"packages/ai/src/providers/anthropic.ts",
"packages/ai/src/providers/azure-openai-responses.ts",
"packages/ai/src/providers/google.ts",
"packages/ai/src/providers/google-vertex.ts",
"packages/ai/src/providers/images/openrouter.ts",
"packages/ai/src/providers/mistral.ts",
"packages/ai/src/providers/openai-codex-responses.ts",
"packages/ai/src/providers/openai-completions.ts",
"packages/ai/src/providers/openai-responses.ts",
];
try {
await build({
@ -29,36 +15,6 @@ try {
logLevel: "silent",
outfile: outputPath,
});
const baseBuild = await build({
stdin: {
contents: `import { complete } from "@earendil-works/pi-ai/base";\nimport { Agent } from "@earendil-works/pi-agent-core/base";\nconsole.log(typeof complete, typeof Agent);\n`,
resolveDir: process.cwd(),
sourcefile: "pi-browser-base-smoke-entry.ts",
},
bundle: true,
platform: "browser",
format: "esm",
logLevel: "silent",
metafile: true,
outfile: baseOutputPath,
});
const bundledInputs = new Set(Object.keys(baseBuild.metafile.inputs));
const reachableProviderImplementations = providerImplementationInputs.filter((input) => bundledInputs.has(input));
if (reachableProviderImplementations.length > 0) {
throw new Error(`Base browser bundle reached provider implementations:\n${reachableProviderImplementations.join("\n")}`);
}
await build({
stdin: {
contents: `import { register as registerAnthropic } from "@earendil-works/pi-ai/anthropic";\nimport { register as registerOpenAICompletions } from "@earendil-works/pi-ai/openai-completions";\nimport { register as registerOpenRouterImages } from "@earendil-works/pi-ai/openrouter-images";\nconsole.log(typeof registerAnthropic, typeof registerOpenAICompletions, typeof registerOpenRouterImages);\n`,
resolveDir: process.cwd(),
sourcefile: "pi-browser-selective-smoke-entry.ts",
},
bundle: true,
platform: "browser",
format: "esm",
logLevel: "silent",
outfile: selectiveOutputPath,
});
process.exit(0);
} catch (error) {
let detailedErrors = "";

View file

@ -6,7 +6,6 @@
"*": ["./*"],
"@earendil-works/pi-ai": ["./packages/ai/src/index.ts"],
"@earendil-works/pi-ai/oauth": ["./packages/ai/src/oauth.ts"],
"@earendil-works/pi-ai/openrouter-images": ["./packages/ai/src/providers/images/openrouter.ts"],
"@earendil-works/pi-ai/*": ["./packages/ai/src/*.ts", "./packages/ai/src/providers/*.ts"],
"@earendil-works/pi-ai/dist/*": ["./packages/ai/src/*"],
"@earendil-works/pi-agent-core": ["./packages/agent/src/index.ts"],