chore: migrate pi packages to earendil works scope
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# @mariozechner/pi-ai
|
||||
# @earendil-works/pi-ai
|
||||
|
||||
Unified LLM API with automatic model discovery, provider configuration, token and cost tracking, and simple context persistence and hand-off to other models mid-session.
|
||||
|
||||
@@ -75,15 +75,15 @@ Unified LLM API with automatic model discovery, provider configuration, token an
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @mariozechner/pi-ai
|
||||
npm install @earendil-works/pi-ai
|
||||
```
|
||||
|
||||
TypeBox exports are re-exported from `@mariozechner/pi-ai`: `Type`, `Static`, and `TSchema`.
|
||||
TypeBox exports are re-exported from `@earendil-works/pi-ai`: `Type`, `Static`, and `TSchema`.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```typescript
|
||||
import { Type, getModel, stream, complete, Context, Tool, StringEnum } from '@mariozechner/pi-ai';
|
||||
import { Type, getModel, stream, complete, Context, Tool, StringEnum } from '@earendil-works/pi-ai';
|
||||
|
||||
// Fully typed with auto-complete support for both providers and models
|
||||
const model = getModel('openai', 'gpt-4o-mini');
|
||||
@@ -209,7 +209,7 @@ Tools enable LLMs to interact with external systems. This library uses TypeBox s
|
||||
### Defining Tools
|
||||
|
||||
```typescript
|
||||
import { Type, Tool, StringEnum } from '@mariozechner/pi-ai';
|
||||
import { Type, Tool, StringEnum } from '@earendil-works/pi-ai';
|
||||
|
||||
// Define tool parameters with TypeBox
|
||||
const weatherTool: Tool = {
|
||||
@@ -335,7 +335,7 @@ When using `agentLoop`, tool arguments are automatically validated against your
|
||||
When implementing your own tool execution loop with `stream()` or `complete()`, use `validateToolCall` to validate arguments before passing them to your tools:
|
||||
|
||||
```typescript
|
||||
import { stream, validateToolCall, Tool } from '@mariozechner/pi-ai';
|
||||
import { stream, validateToolCall, Tool } from '@earendil-works/pi-ai';
|
||||
|
||||
const tools: Tool[] = [weatherTool, calculatorTool];
|
||||
const s = stream(model, { messages, tools });
|
||||
@@ -391,7 +391,7 @@ Models with vision capabilities can process images. You can check if a model sup
|
||||
|
||||
```typescript
|
||||
import { readFileSync } from 'fs';
|
||||
import { getModel, complete } from '@mariozechner/pi-ai';
|
||||
import { getModel, complete } from '@earendil-works/pi-ai';
|
||||
|
||||
const model = getModel('openai', 'gpt-4o-mini');
|
||||
|
||||
@@ -428,7 +428,7 @@ Many models support thinking/reasoning capabilities where they can show their in
|
||||
### Unified Interface (streamSimple/completeSimple)
|
||||
|
||||
```typescript
|
||||
import { getModel, streamSimple, completeSimple } from '@mariozechner/pi-ai';
|
||||
import { getModel, streamSimple, completeSimple } from '@earendil-works/pi-ai';
|
||||
|
||||
// Many models across providers support thinking/reasoning
|
||||
const model = getModel('anthropic', 'claude-sonnet-4-20250514');
|
||||
@@ -466,7 +466,7 @@ for (const block of response.content) {
|
||||
For fine-grained control, use the provider-specific options:
|
||||
|
||||
```typescript
|
||||
import { getModel, complete } from '@mariozechner/pi-ai';
|
||||
import { getModel, complete } from '@earendil-works/pi-ai';
|
||||
|
||||
// OpenAI Reasoning (o1, o3, gpt-5)
|
||||
const openaiModel = getModel('openai', 'gpt-5-mini');
|
||||
@@ -555,7 +555,7 @@ if (message.stopReason === 'error' || message.stopReason === 'aborted') {
|
||||
The abort signal allows you to cancel in-progress requests. Aborted requests have `stopReason === 'aborted'`:
|
||||
|
||||
```typescript
|
||||
import { getModel, stream } from '@mariozechner/pi-ai';
|
||||
import { getModel, stream } from '@earendil-works/pi-ai';
|
||||
|
||||
const model = getModel('openai', 'gpt-4o-mini');
|
||||
const controller = new AbortController();
|
||||
@@ -653,7 +653,7 @@ import {
|
||||
fauxToolCall,
|
||||
registerFauxProvider,
|
||||
stream,
|
||||
} from '@mariozechner/pi-ai';
|
||||
} from '@earendil-works/pi-ai';
|
||||
|
||||
const registration = registerFauxProvider({
|
||||
tokensPerSecond: 50 // optional
|
||||
@@ -738,7 +738,7 @@ A **provider** offers models through a specific API. For example:
|
||||
### Querying Providers and Models
|
||||
|
||||
```typescript
|
||||
import { getProviders, getModels, getModel } from '@mariozechner/pi-ai';
|
||||
import { getProviders, getModels, getModel } from '@earendil-works/pi-ai';
|
||||
|
||||
// Get all available providers
|
||||
const providers = getProviders();
|
||||
@@ -764,7 +764,7 @@ console.log(`Using ${model.name} via ${model.api} API`);
|
||||
You can create custom models for local inference servers or custom endpoints:
|
||||
|
||||
```typescript
|
||||
import { Model, stream } from '@mariozechner/pi-ai';
|
||||
import { Model, stream } from '@earendil-works/pi-ai';
|
||||
|
||||
// Example: Ollama using OpenAI-compatible API
|
||||
const ollamaModel: Model<'openai-completions'> = {
|
||||
@@ -892,7 +892,7 @@ If `compat` is not set, the library falls back to URL-based detection. If `compa
|
||||
Models are typed by their API, which keeps the model metadata accurate. Provider-specific option types are enforced when you call the provider functions directly. The generic `stream` and `complete` functions accept `StreamOptions` with additional provider fields.
|
||||
|
||||
```typescript
|
||||
import { streamAnthropic, type AnthropicOptions } from '@mariozechner/pi-ai';
|
||||
import { streamAnthropic, type AnthropicOptions } from '@earendil-works/pi-ai';
|
||||
|
||||
// TypeScript knows this is an Anthropic model
|
||||
const claude = getModel('anthropic', 'claude-sonnet-4-20250514');
|
||||
@@ -921,7 +921,7 @@ When messages from one provider are sent to a different provider, the library au
|
||||
### Example: Multi-Provider Conversation
|
||||
|
||||
```typescript
|
||||
import { getModel, complete, Context } from '@mariozechner/pi-ai';
|
||||
import { getModel, complete, Context } from '@earendil-works/pi-ai';
|
||||
|
||||
// Start with Claude
|
||||
const claude = getModel('anthropic', 'claude-sonnet-4-20250514');
|
||||
@@ -966,7 +966,7 @@ This enables flexible workflows where you can:
|
||||
The `Context` object can be easily serialized and deserialized using standard JSON methods, making it simple to persist conversations, implement chat history, or transfer contexts between services:
|
||||
|
||||
```typescript
|
||||
import { Context, getModel, complete } from '@mariozechner/pi-ai';
|
||||
import { Context, getModel, complete } from '@earendil-works/pi-ai';
|
||||
|
||||
// Create and use a context
|
||||
const context: Context = {
|
||||
@@ -1003,7 +1003,7 @@ const continuation = await complete(newModel, restored);
|
||||
The library supports browser environments. You must pass the API key explicitly since environment variables are not available in browsers:
|
||||
|
||||
```typescript
|
||||
import { getModel, complete } from '@mariozechner/pi-ai';
|
||||
import { getModel, complete } from '@earendil-works/pi-ai';
|
||||
|
||||
// API key must be passed explicitly in browser
|
||||
const model = getModel('anthropic', 'claude-3-5-haiku-20241022');
|
||||
@@ -1020,7 +1020,7 @@ const response = await complete(model, {
|
||||
### Browser Compatibility Notes
|
||||
|
||||
- Amazon Bedrock (`bedrock-converse-stream`) is not supported in browser environments.
|
||||
- OAuth login flows are not supported in browser environments. Use the `@mariozechner/pi-ai/oauth` entry point in Node.js.
|
||||
- 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.
|
||||
|
||||
@@ -1071,7 +1071,7 @@ const response = await complete(model, context, {
|
||||
### Checking Environment Variables
|
||||
|
||||
```typescript
|
||||
import { getEnvApiKey } from '@mariozechner/pi-ai';
|
||||
import { getEnvApiKey } from '@earendil-works/pi-ai';
|
||||
|
||||
// Check if an API key is set in environment variables
|
||||
const key = getEnvApiKey('openai'); // checks OPENAI_API_KEY
|
||||
@@ -1110,7 +1110,7 @@ export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { getModel, complete } from '@mariozechner/pi-ai';
|
||||
import { getModel, complete } from '@earendil-works/pi-ai';
|
||||
|
||||
(async () => {
|
||||
const model = getModel('google-vertex', 'gemini-2.5-flash');
|
||||
@@ -1133,16 +1133,16 @@ Official docs: [Application Default Credentials](https://cloud.google.com/docs/a
|
||||
The quickest way to authenticate:
|
||||
|
||||
```bash
|
||||
npx @mariozechner/pi-ai login # interactive provider selection
|
||||
npx @mariozechner/pi-ai login anthropic # login to specific provider
|
||||
npx @mariozechner/pi-ai list # list available providers
|
||||
npx @earendil-works/pi-ai login # interactive provider selection
|
||||
npx @earendil-works/pi-ai login anthropic # login to specific provider
|
||||
npx @earendil-works/pi-ai list # list available providers
|
||||
```
|
||||
|
||||
Credentials are saved to `auth.json` in the current directory.
|
||||
|
||||
### Programmatic OAuth
|
||||
|
||||
The library provides login and token refresh functions via the `@mariozechner/pi-ai/oauth` entry point. Credential storage is the caller's responsibility.
|
||||
The library provides login and token refresh functions via the `@earendil-works/pi-ai/oauth` entry point. Credential storage is the caller's responsibility.
|
||||
|
||||
```typescript
|
||||
import {
|
||||
@@ -1159,13 +1159,13 @@ import {
|
||||
// Types
|
||||
type OAuthProvider,
|
||||
type OAuthCredentials,
|
||||
} from '@mariozechner/pi-ai/oauth';
|
||||
} from '@earendil-works/pi-ai/oauth';
|
||||
```
|
||||
|
||||
### Login Flow Example
|
||||
|
||||
```typescript
|
||||
import { loginGitHubCopilot } from '@mariozechner/pi-ai/oauth';
|
||||
import { loginGitHubCopilot } from '@earendil-works/pi-ai/oauth';
|
||||
import { writeFileSync } from 'fs';
|
||||
|
||||
const credentials = await loginGitHubCopilot({
|
||||
@@ -1189,8 +1189,8 @@ writeFileSync('auth.json', JSON.stringify(auth, null, 2));
|
||||
Use `getOAuthApiKey()` to get an API key, automatically refreshing if expired:
|
||||
|
||||
```typescript
|
||||
import { getModel, complete } from '@mariozechner/pi-ai';
|
||||
import { getOAuthApiKey } from '@mariozechner/pi-ai/oauth';
|
||||
import { getModel, complete } from '@earendil-works/pi-ai';
|
||||
import { getOAuthApiKey } from '@earendil-works/pi-ai/oauth';
|
||||
import { readFileSync, writeFileSync } from 'fs';
|
||||
|
||||
// Load your stored credentials
|
||||
@@ -1247,7 +1247,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` that should remain available from `@mariozechner/pi-ai`
|
||||
- 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
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@mariozechner/pi-ai",
|
||||
"name": "@earendil-works/pi-ai",
|
||||
"version": "0.73.0",
|
||||
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
||||
"type": "module",
|
||||
@@ -94,7 +94,7 @@
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/badlogic/pi-mono.git",
|
||||
"url": "git+https://github.com/earendil-works/pi-mono.git",
|
||||
"directory": "packages/ai"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -64,7 +64,7 @@ async function main(): Promise<void> {
|
||||
|
||||
if (!command || command === "help" || command === "--help" || command === "-h") {
|
||||
const providerList = PROVIDERS.map((p) => ` ${p.id.padEnd(20)} ${p.name}`).join("\n");
|
||||
console.log(`Usage: npx @mariozechner/pi-ai <command> [provider]
|
||||
console.log(`Usage: npx @earendil-works/pi-ai <command> [provider]
|
||||
|
||||
Commands:
|
||||
login [provider] Login to an OAuth provider
|
||||
@@ -74,9 +74,9 @@ Providers:
|
||||
${providerList}
|
||||
|
||||
Examples:
|
||||
npx @mariozechner/pi-ai login # interactive provider selection
|
||||
npx @mariozechner/pi-ai login anthropic # login to specific provider
|
||||
npx @mariozechner/pi-ai list # list providers
|
||||
npx @earendil-works/pi-ai login # interactive provider selection
|
||||
npx @earendil-works/pi-ai login anthropic # login to specific provider
|
||||
npx @earendil-works/pi-ai list # list providers
|
||||
`);
|
||||
return;
|
||||
}
|
||||
@@ -113,7 +113,7 @@ Examples:
|
||||
|
||||
if (!PROVIDERS.some((p) => p.id === provider)) {
|
||||
console.error(`Unknown provider: ${provider}`);
|
||||
console.error(`Use 'npx @mariozechner/pi-ai list' to see available providers`);
|
||||
console.error(`Use 'npx @earendil-works/pi-ai list' to see available providers`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ Examples:
|
||||
}
|
||||
|
||||
console.error(`Unknown command: ${command}`);
|
||||
console.error(`Use 'npx @mariozechner/pi-ai --help' for usage`);
|
||||
console.error(`Use 'npx @earendil-works/pi-ai --help' for usage`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -7586,9 +7586,9 @@ export const MODELS = {
|
||||
"big-pickle": {
|
||||
id: "big-pickle",
|
||||
name: "Big Pickle",
|
||||
api: "anthropic-messages",
|
||||
api: "openai-completions",
|
||||
provider: "opencode",
|
||||
baseUrl: "https://opencode.ai/zen",
|
||||
baseUrl: "https://opencode.ai/zen/v1",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
@@ -7599,7 +7599,7 @@ export const MODELS = {
|
||||
},
|
||||
contextWindow: 200000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"claude-haiku-4-5": {
|
||||
id: "claude-haiku-4-5",
|
||||
name: "Claude Haiku 4.5",
|
||||
@@ -7854,9 +7854,9 @@ export const MODELS = {
|
||||
thinkingLevelMap: {"off":null},
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
input: 0.05,
|
||||
output: 0.4,
|
||||
cacheRead: 0.005,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 400000,
|
||||
@@ -8342,55 +8342,21 @@ export const MODELS = {
|
||||
} satisfies Model<"openai-completions">,
|
||||
"kimi-k2.6": {
|
||||
id: "kimi-k2.6",
|
||||
name: "Kimi K2.6 (3x limits)",
|
||||
name: "Kimi K2.6",
|
||||
api: "openai-completions",
|
||||
provider: "opencode-go",
|
||||
baseUrl: "https://opencode.ai/zen/go/v1",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.32,
|
||||
output: 1.34,
|
||||
cacheRead: 0.054,
|
||||
input: 0.95,
|
||||
output: 4,
|
||||
cacheRead: 0.16,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"mimo-v2-omni": {
|
||||
id: "mimo-v2-omni",
|
||||
name: "MiMo V2 Omni",
|
||||
api: "openai-completions",
|
||||
provider: "opencode-go",
|
||||
baseUrl: "https://opencode.ai/zen/go/v1",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.4,
|
||||
output: 2,
|
||||
cacheRead: 0.08,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"mimo-v2-pro": {
|
||||
id: "mimo-v2-pro",
|
||||
name: "MiMo V2 Pro",
|
||||
api: "openai-completions",
|
||||
provider: "opencode-go",
|
||||
baseUrl: "https://opencode.ai/zen/go/v1",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 1,
|
||||
output: 3,
|
||||
cacheRead: 0.2,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"mimo-v2.5": {
|
||||
id: "mimo-v2.5",
|
||||
name: "MiMo V2.5",
|
||||
@@ -8531,23 +8497,6 @@ export const MODELS = {
|
||||
contextWindow: 131072,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"allenai/olmo-3.1-32b-instruct": {
|
||||
id: "allenai/olmo-3.1-32b-instruct",
|
||||
name: "AllenAI: Olmo 3.1 32B Instruct",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.19999999999999998,
|
||||
output: 0.6,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 65536,
|
||||
maxTokens: 16384,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"amazon/nova-2-lite-v1": {
|
||||
id: "amazon/nova-2-lite-v1",
|
||||
name: "Amazon: Nova 2 Lite",
|
||||
@@ -8682,7 +8631,7 @@ export const MODELS = {
|
||||
cacheWrite: 3.75,
|
||||
},
|
||||
contextWindow: 200000,
|
||||
maxTokens: 128000,
|
||||
maxTokens: 64000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"anthropic/claude-3.7-sonnet:thinking": {
|
||||
id: "anthropic/claude-3.7-sonnet:thinking",
|
||||
@@ -8959,6 +8908,23 @@ export const MODELS = {
|
||||
contextWindow: 2000000,
|
||||
maxTokens: 30000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"baidu/cobuddy:free": {
|
||||
id: "baidu/cobuddy:free",
|
||||
name: "Baidu Qianfan: CoBuddy (free)",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131072,
|
||||
maxTokens: 65536,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"baidu/ernie-4.5-21b-a3b": {
|
||||
id: "baidu/ernie-4.5-21b-a3b",
|
||||
name: "Baidu: ERNIE 4.5 21B A3B",
|
||||
@@ -9261,13 +9227,13 @@ export const MODELS = {
|
||||
thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max"},
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
input: 0.435,
|
||||
output: 0.87,
|
||||
cacheRead: 0.003625,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 131000,
|
||||
maxTokens: 131000,
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 384000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"essentialai/rnj-1-instruct": {
|
||||
id: "essentialai/rnj-1-instruct",
|
||||
@@ -9677,23 +9643,6 @@ export const MODELS = {
|
||||
contextWindow: 256000,
|
||||
maxTokens: 80000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"meta-llama/llama-3-8b-instruct": {
|
||||
id: "meta-llama/llama-3-8b-instruct",
|
||||
name: "Meta: Llama 3 8B Instruct",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.03,
|
||||
output: 0.04,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 8192,
|
||||
maxTokens: 16384,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"meta-llama/llama-3.1-70b-instruct": {
|
||||
id: "meta-llama/llama-3.1-70b-instruct",
|
||||
name: "Meta: Llama 3.1 70B Instruct",
|
||||
@@ -10085,6 +10034,23 @@ export const MODELS = {
|
||||
contextWindow: 131072,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"mistralai/mistral-medium-3-5": {
|
||||
id: "mistralai/mistral-medium-3-5",
|
||||
name: "Mistral: Mistral Medium 3.5",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 1.5,
|
||||
output: 7.5,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"mistralai/mistral-medium-3.1": {
|
||||
id: "mistralai/mistral-medium-3.1",
|
||||
name: "Mistral: Mistral Medium 3.1",
|
||||
@@ -10315,13 +10281,13 @@ export const MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.74,
|
||||
output: 3.49,
|
||||
cacheRead: 0.14,
|
||||
input: 0.75,
|
||||
output: 3.5,
|
||||
cacheRead: 0.15,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262142,
|
||||
maxTokens: 262142,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 16384,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"nex-agi/deepseek-v3.1-nex-n1": {
|
||||
id: "nex-agi/deepseek-v3.1-nex-n1",
|
||||
@@ -11236,6 +11202,23 @@ export const MODELS = {
|
||||
contextWindow: 128000,
|
||||
maxTokens: 16384,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"openai/gpt-chat-latest": {
|
||||
id: "openai/gpt-chat-latest",
|
||||
name: "OpenAI: GPT Chat Latest",
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 5,
|
||||
output: 30,
|
||||
cacheRead: 0.5,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 400000,
|
||||
maxTokens: 128000,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"openai/gpt-oss-120b": {
|
||||
id: "openai/gpt-oss-120b",
|
||||
name: "OpenAI: gpt-oss-120b",
|
||||
@@ -11925,7 +11908,7 @@ export const MODELS = {
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 0.12,
|
||||
input: 0.11,
|
||||
output: 0.7999999999999999,
|
||||
cacheRead: 0.07,
|
||||
cacheWrite: 0,
|
||||
@@ -12214,13 +12197,13 @@ export const MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.15,
|
||||
input: 0.14,
|
||||
output: 1,
|
||||
cacheRead: 0.049999999999999996,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
maxTokens: 81920,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"qwen/qwen3.5-397b-a17b": {
|
||||
id: "qwen/qwen3.5-397b-a17b",
|
||||
@@ -12248,13 +12231,13 @@ export const MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.09999999999999999,
|
||||
input: 0.04,
|
||||
output: 0.15,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 4096,
|
||||
maxTokens: 81920,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"qwen/qwen3.5-flash-02-23": {
|
||||
id: "qwen/qwen3.5-flash-02-23",
|
||||
@@ -12985,7 +12968,7 @@ export const MODELS = {
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 202752,
|
||||
maxTokens: 16384,
|
||||
maxTokens: 4096,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"z-ai/glm-5-turbo": {
|
||||
id: "z-ai/glm-5-turbo",
|
||||
@@ -13132,13 +13115,13 @@ export const MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.74,
|
||||
output: 3.49,
|
||||
cacheRead: 0.14,
|
||||
input: 0.75,
|
||||
output: 3.5,
|
||||
cacheRead: 0.15,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 262142,
|
||||
maxTokens: 262142,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 16384,
|
||||
} satisfies Model<"openai-completions">,
|
||||
"~openai/gpt-latest": {
|
||||
id: "~openai/gpt-latest",
|
||||
@@ -15528,8 +15511,8 @@ export const MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 2,
|
||||
output: 6,
|
||||
input: 1.25,
|
||||
output: 2.5,
|
||||
cacheRead: 0.19999999999999998,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
@@ -15545,8 +15528,8 @@ export const MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 2,
|
||||
output: 6,
|
||||
input: 1.25,
|
||||
output: 2.5,
|
||||
cacheRead: 0.19999999999999998,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
@@ -15562,8 +15545,8 @@ export const MODELS = {
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 2,
|
||||
output: 6,
|
||||
input: 1.25,
|
||||
output: 2.5,
|
||||
cacheRead: 0.19999999999999998,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
@@ -15579,8 +15562,8 @@ export const MODELS = {
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 2,
|
||||
output: 6,
|
||||
input: 1.25,
|
||||
output: 2.5,
|
||||
cacheRead: 0.19999999999999998,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
@@ -15596,8 +15579,8 @@ export const MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 2,
|
||||
output: 6,
|
||||
input: 1.25,
|
||||
output: 2.5,
|
||||
cacheRead: 0.19999999999999998,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
@@ -15613,8 +15596,8 @@ export const MODELS = {
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 2,
|
||||
output: 6,
|
||||
input: 1.25,
|
||||
output: 2.5,
|
||||
cacheRead: 0.19999999999999998,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
@@ -16387,8 +16370,8 @@ export const MODELS = {
|
||||
cacheRead: 0.01,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 256000,
|
||||
maxTokens: 64000,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mimo-v2-omni": {
|
||||
id: "mimo-v2-omni",
|
||||
@@ -16404,8 +16387,8 @@ export const MODELS = {
|
||||
cacheRead: 0.08,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 256000,
|
||||
maxTokens: 128000,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mimo-v2-pro": {
|
||||
id: "mimo-v2-pro",
|
||||
@@ -16421,8 +16404,8 @@ export const MODELS = {
|
||||
cacheRead: 0.2,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mimo-v2.5": {
|
||||
id: "mimo-v2.5",
|
||||
@@ -16431,7 +16414,7 @@ export const MODELS = {
|
||||
provider: "xiaomi",
|
||||
baseUrl: "https://api.xiaomimimo.com/anthropic",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.4,
|
||||
output: 2,
|
||||
@@ -16448,7 +16431,7 @@ export const MODELS = {
|
||||
provider: "xiaomi",
|
||||
baseUrl: "https://api.xiaomimimo.com/anthropic",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 1,
|
||||
output: 3,
|
||||
@@ -16474,8 +16457,8 @@ export const MODELS = {
|
||||
cacheRead: 0.01,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 256000,
|
||||
maxTokens: 64000,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mimo-v2-omni": {
|
||||
id: "mimo-v2-omni",
|
||||
@@ -16491,8 +16474,8 @@ export const MODELS = {
|
||||
cacheRead: 0.08,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 256000,
|
||||
maxTokens: 128000,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mimo-v2-pro": {
|
||||
id: "mimo-v2-pro",
|
||||
@@ -16508,8 +16491,8 @@ export const MODELS = {
|
||||
cacheRead: 0.2,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mimo-v2.5": {
|
||||
id: "mimo-v2.5",
|
||||
@@ -16518,7 +16501,7 @@ export const MODELS = {
|
||||
provider: "xiaomi-token-plan-ams",
|
||||
baseUrl: "https://token-plan-ams.xiaomimimo.com/anthropic",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.4,
|
||||
output: 2,
|
||||
@@ -16535,7 +16518,7 @@ export const MODELS = {
|
||||
provider: "xiaomi-token-plan-ams",
|
||||
baseUrl: "https://token-plan-ams.xiaomimimo.com/anthropic",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 1,
|
||||
output: 3,
|
||||
@@ -16561,8 +16544,8 @@ export const MODELS = {
|
||||
cacheRead: 0.01,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 256000,
|
||||
maxTokens: 64000,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mimo-v2-omni": {
|
||||
id: "mimo-v2-omni",
|
||||
@@ -16578,8 +16561,8 @@ export const MODELS = {
|
||||
cacheRead: 0.08,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 256000,
|
||||
maxTokens: 128000,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mimo-v2-pro": {
|
||||
id: "mimo-v2-pro",
|
||||
@@ -16595,8 +16578,8 @@ export const MODELS = {
|
||||
cacheRead: 0.2,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mimo-v2.5": {
|
||||
id: "mimo-v2.5",
|
||||
@@ -16605,7 +16588,7 @@ export const MODELS = {
|
||||
provider: "xiaomi-token-plan-cn",
|
||||
baseUrl: "https://token-plan-cn.xiaomimimo.com/anthropic",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.4,
|
||||
output: 2,
|
||||
@@ -16622,7 +16605,7 @@ export const MODELS = {
|
||||
provider: "xiaomi-token-plan-cn",
|
||||
baseUrl: "https://token-plan-cn.xiaomimimo.com/anthropic",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 1,
|
||||
output: 3,
|
||||
@@ -16648,8 +16631,8 @@ export const MODELS = {
|
||||
cacheRead: 0.01,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 256000,
|
||||
maxTokens: 64000,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mimo-v2-omni": {
|
||||
id: "mimo-v2-omni",
|
||||
@@ -16665,8 +16648,8 @@ export const MODELS = {
|
||||
cacheRead: 0.08,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 256000,
|
||||
maxTokens: 128000,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mimo-v2-pro": {
|
||||
id: "mimo-v2-pro",
|
||||
@@ -16682,8 +16665,8 @@ export const MODELS = {
|
||||
cacheRead: 0.2,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 131072,
|
||||
} satisfies Model<"anthropic-messages">,
|
||||
"mimo-v2.5": {
|
||||
id: "mimo-v2.5",
|
||||
@@ -16692,7 +16675,7 @@ export const MODELS = {
|
||||
provider: "xiaomi-token-plan-sgp",
|
||||
baseUrl: "https://token-plan-sgp.xiaomimimo.com/anthropic",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
input: 0.4,
|
||||
output: 2,
|
||||
@@ -16709,7 +16692,7 @@ export const MODELS = {
|
||||
provider: "xiaomi-token-plan-sgp",
|
||||
baseUrl: "https://token-plan-sgp.xiaomimimo.com/anthropic",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: 1,
|
||||
output: 3,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { streamSimple } from "../src/stream.js";
|
||||
// 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
|
||||
// `"[] is too short - 'tools'"` (HTTP 400) when `--no-tools` produces an empty array.
|
||||
// Regression for https://github.com/badlogic/pi-mono/issues/<issue-number>
|
||||
// Regression for https://github.com/earendil-works/pi-mono/issues/<issue-number>
|
||||
|
||||
const mockState = vi.hoisted(() => ({
|
||||
lastParams: undefined as unknown,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* OpenAI Responses API generates IDs in format: {call_id}|{id}
|
||||
* where {id} can be 400+ chars with special characters (+, /, =).
|
||||
*
|
||||
* Regression test for: https://github.com/badlogic/pi-mono/issues/1022
|
||||
* Regression test for: https://github.com/earendil-works/pi-mono/issues/1022
|
||||
*/
|
||||
|
||||
import { Type } from "typebox";
|
||||
|
||||
Reference in New Issue
Block a user