Merge remote-tracking branch 'origin/main' into bigrefactor

# Conflicts:
#	package-lock.json
#	packages/agent/package.json
This commit is contained in:
Mario Zechner
2026-05-08 13:38:20 +02:00
Unverified
357 changed files with 2841 additions and 2195 deletions
+1
View File
@@ -4,6 +4,7 @@
# issue future issues stay open
# pr future issues and PRs stay open
herrnel pr
julien-c pr
barapa pr
alasano pr
+2 -2
View File
@@ -5,9 +5,9 @@ body:
- type: markdown
attributes:
value: |
**Before you start:** Read [CONTRIBUTING.md](https://github.com/badlogic/pi-mono/blob/main/CONTRIBUTING.md).
**Before you start:** Read [CONTRIBUTING.md](https://github.com/earendil-works/pi-mono/blob/main/CONTRIBUTING.md).
New issues from new contributors are auto-closed by default. Maintainers review auto-closed issues daily. Issues that do not meet the quality bar in [CONTRIBUTING.md](https://github.com/badlogic/pi-mono/blob/main/CONTRIBUTING.md) will not be reopened or receive a reply.
New issues from new contributors are auto-closed by default. Maintainers review auto-closed issues daily. Issues that do not meet the quality bar in [CONTRIBUTING.md](https://github.com/earendil-works/pi-mono/blob/main/CONTRIBUTING.md) will not be reopened or receive a reply.
Keep this short. If it doesn't fit on one screen, it's too long. Write in your own voice.
+2 -2
View File
@@ -5,9 +5,9 @@ body:
- type: markdown
attributes:
value: |
**Before you start:** Read [CONTRIBUTING.md](https://github.com/badlogic/pi-mono/blob/main/CONTRIBUTING.md).
**Before you start:** Read [CONTRIBUTING.md](https://github.com/earendil-works/pi-mono/blob/main/CONTRIBUTING.md).
New issues from new contributors are auto-closed by default. Maintainers review auto-closed issues daily. Issues that do not meet the quality bar in [CONTRIBUTING.md](https://github.com/badlogic/pi-mono/blob/main/CONTRIBUTING.md) will not be reopened or receive a reply.
New issues from new contributors are auto-closed by default. Maintainers review auto-closed issues daily. Issues that do not meet the quality bar in [CONTRIBUTING.md](https://github.com/earendil-works/pi-mono/blob/main/CONTRIBUTING.md) will not be reopened or receive a reply.
Keep this short. If it doesn't fit on one screen, it's too long. Write in your own voice.
+2 -2
View File
@@ -1,5 +1,5 @@
import { DynamicBorder, type ExtensionAPI, type ExtensionContext } from "@mariozechner/pi-coding-agent";
import { Container, Text } from "@mariozechner/pi-tui";
import { DynamicBorder, type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
import { Container, Text } from "@earendil-works/pi-tui";
const PR_PROMPT_PATTERN = /^\s*You are given one or more GitHub PR URLs:\s*(\S+)/im;
const ISSUE_PROMPT_PATTERN = /^\s*Analyze GitHub issue\(s\):\s*(\S+)/im;
+2 -2
View File
@@ -4,8 +4,8 @@
* Exposes /tui to show TUI redraw stats.
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { Text } from "@mariozechner/pi-tui";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Text } from "@earendil-works/pi-tui";
export default function (pi: ExtensionAPI) {
pi.registerCommand("tui", {
+2 -2
View File
@@ -1,5 +1,5 @@
import type { AssistantMessage } from "@mariozechner/pi-ai";
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { AssistantMessage } from "@earendil-works/pi-ai";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
function isAssistantMessage(message: unknown): message is AssistantMessage {
if (!message || typeof message !== "object") return false;
+2 -2
View File
@@ -50,5 +50,5 @@ Sections (in order):
- `### Removed` - Removed features
Attribution:
- Internal: `Fixed foo ([#123](https://github.com/badlogic/pi-mono/issues/123))`
- External: `Added bar ([#456](https://github.com/badlogic/pi-mono/pull/456) by [@user](https://github.com/user))`
- Internal: `Fixed foo ([#123](https://github.com/earendil-works/pi-mono/issues/123))`
- External: `Added bar ([#456](https://github.com/earendil-works/pi-mono/pull/456) by [@user](https://github.com/user))`
+1 -1
View File
@@ -11,7 +11,7 @@ For each PR URL, do the following in order:
4. Analyze the PR diff. Read all relevant code files in full with no truncation from the current main branch and compare against the diff. Do not fetch PR file blobs unless a file is missing on main or the diff context is insufficient. Include related code paths that are not in the diff but are required to validate behavior.
5. Check for a changelog entry in the relevant `packages/*/CHANGELOG.md` files. Report whether an entry exists. If missing, state that a changelog entry is required before merge and that you will add it if the user decides to merge. Follow the changelog format rules in AGENTS.md. Verify:
- Entry uses correct section (`### Breaking Changes`, `### Added`, `### Fixed`, etc.)
- External contributions include PR link and author: `Fixed foo ([#123](https://github.com/badlogic/pi-mono/pull/123) by [@user](https://github.com/user))`
- External contributions include PR link and author: `Fixed foo ([#123](https://github.com/earendil-works/pi-mono/pull/123) by [@user](https://github.com/user))`
- Breaking changes are in `### Breaking Changes`, not just `### Fixed`
6. Check if packages/coding-agent/README.md, packages/coding-agent/docs/*.md, packages/coding-agent/examples/**/*.md require modification. This is usually the case when existing features have been changed, or new features have been added.
7. Provide a structured review with these sections:
+3 -2
View File
@@ -9,6 +9,7 @@
## Code Quality
- Read files in full before making wide-ranging changes, before editing files you have not already fully inspected, and when the user asks you to investigate or audit something. Do not rely only on search snippets for broad changes.
- No `any` types unless absolutely necessary
- Check node_modules for external API type definitions instead of guessing
- **NEVER use inline imports** - no `await import("./foo.js")`, no `import("pkg").Type` in type positions, no dynamic imports for types. Always use standard top-level imports.
@@ -116,8 +117,8 @@ Use these sections under `## [Unreleased]`:
### Attribution
- **Internal changes (from issues)**: `Fixed foo bar ([#123](https://github.com/badlogic/pi-mono/issues/123))`
- **External contributions**: `Added feature X ([#456](https://github.com/badlogic/pi-mono/pull/456) by [@username](https://github.com/username))`
- **Internal changes (from issues)**: `Fixed foo bar ([#123](https://github.com/earendil-works/pi-mono/issues/123))`
- **External contributions**: `Added feature X ([#456](https://github.com/earendil-works/pi-mono/pull/456) by [@username](https://github.com/username))`
## Adding a New LLM Provider (packages/ai)
+18 -18
View File
@@ -1,15 +1,10 @@
<p align="center">
<a href="https://pi.dev">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://pi.dev/logo.svg">
<source media="(prefers-color-scheme: light)" srcset="https://huggingface.co/buckets/julien-c/my-training-bucket/resolve/pi-logo-dark.svg">
<img alt="pi logo" src="https://pi.dev/logo.svg" width="128">
</picture>
<img alt="pi logo" src="https://pi.dev/logo-auto.svg" width="128">
</a>
</p>
<p align="center">
<a href="https://discord.com/invite/3cU7Bz4UPx"><img alt="Discord" src="https://img.shields.io/badge/discord-community-5865F2?style=flat-square&logo=discord&logoColor=white" /></a>
<a href="https://github.com/badlogic/pi-mono/actions/workflows/ci.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/badlogic/pi-mono/ci.yml?style=flat-square&branch=main" /></a>
</p>
<p align="center">
<a href="https://pi.dev">pi.dev</a> domain graciously donated by
@@ -21,11 +16,18 @@
---
# Pi Monorepo
# Pi Agent Harness Mono Repo
> **Looking for the pi coding agent?** See **[packages/coding-agent](packages/coding-agent)** for installation and usage.
This is the home of the pi agent harness project including our self extensible coding agent.
Tools for building AI agents.
* **[@earendil-works/pi-coding-agent](packages/coding-agent)**: Interactive coding agent CLI
* **[@earendil-works/pi-agent-core](packages/agent)**: Agent runtime with tool calling and state management
* **[@earendil-works/pi-ai](packages/ai)**: Unified multi-provider LLM API (OpenAI, Anthropic, Google, …)
To learn more about pi:
* [Visit pi.dev](https://pi.dev), the project website with demos
* [Read the documentation](https://pi.dev/docs/latest), but you can also ask the agent to explain itself
## Share your OSS coding agent sessions
@@ -43,19 +45,17 @@ I regularly publish my own `pi-mono` work sessions here:
- [badlogicgames/pi-mono on Hugging Face](https://huggingface.co/datasets/badlogicgames/pi-mono)
## Packages
## All Packages
| Package | Description |
|---------|-------------|
| **[@mariozechner/pi-ai](packages/ai)** | Unified multi-provider LLM API (OpenAI, Anthropic, Google, etc.) |
| **[@mariozechner/pi-agent-core](packages/agent)** | Agent runtime with tool calling and state management |
| **[@mariozechner/pi-coding-agent](packages/coding-agent)** | Interactive coding agent CLI |
| **[@mariozechner/pi-tui](packages/tui)** | Terminal UI library with differential rendering |
| **[@mariozechner/pi-web-ui](packages/web-ui)** | Web components for AI chat interfaces |
| **[@earendil-works/pi-ai](packages/ai)** | Unified multi-provider LLM API (OpenAI, Anthropic, Google, etc.) |
| **[@earendil-works/pi-agent-core](packages/agent)** | Agent runtime with tool calling and state management |
| **[@earendil-works/pi-coding-agent](packages/coding-agent)** | Interactive coding agent CLI |
| **[@earendil-works/pi-tui](packages/tui)** | Terminal UI library with differential rendering |
| **[@earendil-works/pi-web-ui](packages/web-ui)** | Web components for AI chat interfaces |
## Chat bot workflows
For Slack/chat automation, see [earendil-works/pi-chat](https://github.com/earendil-works/pi-chat).
For Slack/chat automation and workflows see [earendil-works/pi-chat](https://github.com/earendil-works/pi-chat).
## Contributing
+205 -1138
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -49,7 +49,7 @@
},
"version": "0.0.3",
"dependencies": {
"@mariozechner/pi-coding-agent": "^0.30.2",
"@earendil-works/pi-coding-agent": "^0.30.2",
"get-east-asian-width": "^1.4.0"
},
"overrides": {
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased]
## [0.74.0] - 2026-05-07
## [0.73.1] - 2026-05-07
## [0.73.0] - 2026-05-04
## [0.72.1] - 2026-05-02
+8 -8
View File
@@ -1,18 +1,18 @@
# @mariozechner/pi-agent-core
# @earendil-works/pi-agent-core
Stateful agent with tool execution and event streaming. Built on `@mariozechner/pi-ai`.
Stateful agent with tool execution and event streaming. Built on `@earendil-works/pi-ai`.
## Installation
```bash
npm install @mariozechner/pi-agent-core
npm install @earendil-works/pi-agent-core
```
## Quick Start
```typescript
import { Agent } from "@mariozechner/pi-agent-core";
import { getModel } from "@mariozechner/pi-ai";
import { Agent } from "@earendil-works/pi-agent-core";
import { getModel } from "@earendil-works/pi-ai";
const agent = new Agent({
initialState: {
@@ -355,7 +355,7 @@ Follow-up messages are checked only when there are no more tool calls and no ste
Extend `AgentMessage` via declaration merging:
```typescript
declare module "@mariozechner/pi-agent-core" {
declare module "@earendil-works/pi-agent-core" {
interface CustomAgentMessages {
notification: { role: "notification"; text: string; timestamp: number };
}
@@ -436,7 +436,7 @@ Return `terminate: true` from `execute()` or `afterToolCall` to hint that the ag
For browser apps that proxy through a backend:
```typescript
import { Agent, streamProxy } from "@mariozechner/pi-agent-core";
import { Agent, streamProxy } from "@earendil-works/pi-agent-core";
const agent = new Agent({
streamFn: (model, context, options) =>
@@ -453,7 +453,7 @@ const agent = new Agent({
For direct control without the Agent class:
```typescript
import { agentLoop, agentLoopContinue } from "@mariozechner/pi-agent-core";
import { agentLoop, agentLoopContinue } from "@earendil-works/pi-agent-core";
const context: AgentContext = {
systemPrompt: "You are helpful.",
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@mariozechner/pi-agent-core",
"version": "0.73.0",
"name": "@earendil-works/pi-agent-core",
"version": "0.74.0",
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
"type": "module",
"main": "./dist/index.js",
@@ -17,7 +17,7 @@
"prepublishOnly": "npm run clean && npm run build"
},
"dependencies": {
"@mariozechner/pi-ai": "^0.73.0",
"@earendil-works/pi-ai": "^0.74.0",
"ignore": "^7.0.5",
"typebox": "^1.1.24",
"yaml": "^2.8.2"
@@ -33,7 +33,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/agent"
},
"engines": {
+1 -1
View File
@@ -10,7 +10,7 @@ import {
streamSimple,
type ToolResultMessage,
validateToolArguments,
} from "@mariozechner/pi-ai";
} from "@earendil-works/pi-ai";
import type {
AgentContext,
AgentEvent,
+1 -1
View File
@@ -7,7 +7,7 @@ import {
type TextContent,
type ThinkingBudgets,
type Transport,
} from "@mariozechner/pi-ai";
} from "@earendil-works/pi-ai";
import { runAgentLoop, runAgentLoopContinue } from "./agent-loop.js";
import type {
AfterToolCallContext,
+1 -1
View File
@@ -1,5 +1,5 @@
import { randomUUID } from "node:crypto";
import type { AssistantMessage, ImageContent, Model } from "@mariozechner/pi-ai";
import type { AssistantMessage, ImageContent, Model } from "@earendil-works/pi-ai";
import { Agent } from "../agent.js";
import type { AgentEvent, AgentMessage, AgentTool, ThinkingLevel } from "../types.js";
import { collectEntriesForBranchSummary, generateBranchSummary } from "./compaction/branch-summarization.js";
@@ -5,8 +5,8 @@
* a summary of the branch being left so context isn't lost.
*/
import type { ImageContent, Model, TextContent } from "@mariozechner/pi-ai";
import { completeSimple } from "@mariozechner/pi-ai";
import type { ImageContent, Model, TextContent } from "@earendil-works/pi-ai";
import { completeSimple } from "@earendil-works/pi-ai";
import type { AgentMessage } from "../../types.js";
import {
convertToLlm,
@@ -5,8 +5,8 @@
* and after compaction the session is reloaded.
*/
import type { AssistantMessage, ImageContent, Model, TextContent, Usage } from "@mariozechner/pi-ai";
import { completeSimple } from "@mariozechner/pi-ai";
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.js";
import {
convertToLlm,
@@ -2,7 +2,7 @@
* Shared utilities for compaction and branch summarization.
*/
import type { Message } from "@mariozechner/pi-ai";
import type { Message } from "@earendil-works/pi-ai";
import type { AgentMessage } from "../../types.js";
// ============================================================================
+1 -1
View File
@@ -1,4 +1,4 @@
import type { ImageContent, Message, TextContent } from "@mariozechner/pi-ai";
import type { ImageContent, Message, TextContent } from "@earendil-works/pi-ai";
import type { AgentMessage } from "../types.js";
export const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:
@@ -1,4 +1,4 @@
import type { ImageContent, TextContent } from "@mariozechner/pi-ai";
import type { ImageContent, TextContent } from "@earendil-works/pi-ai";
import type { AgentMessage } from "../../types.js";
import { createBranchSummaryMessage, createCompactionSummaryMessage, createCustomMessage } from "../messages.js";
import type {
+1 -1
View File
@@ -1,4 +1,4 @@
import type { ImageContent, Model, TextContent } from "@mariozechner/pi-ai";
import type { ImageContent, Model, TextContent } from "@earendil-works/pi-ai";
import type { AgentEvent, AgentMessage, AgentTool, ThinkingLevel } from "../index.js";
import type { Session } from "./session/session.js";
+1 -1
View File
@@ -14,7 +14,7 @@ import {
type SimpleStreamOptions,
type StopReason,
type ToolCall,
} from "@mariozechner/pi-ai";
} from "@earendil-works/pi-ai";
// Create stream class matching ProxyMessageEventStream
class ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {
+2 -2
View File
@@ -9,7 +9,7 @@ import type {
TextContent,
Tool,
ToolResultMessage,
} from "@mariozechner/pi-ai";
} from "@earendil-works/pi-ai";
import type { Static, TSchema } from "typebox";
/**
@@ -250,7 +250,7 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
/**
* Thinking/reasoning level for models that support it.
* Note: "xhigh" is only supported by selected model families. Use model thinking-level metadata
* from @mariozechner/pi-ai to detect support for a concrete model.
* from @earendil-works/pi-ai to detect support for a concrete model.
*/
export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
+1 -1
View File
@@ -5,7 +5,7 @@ import {
type Message,
type Model,
type UserMessage,
} from "@mariozechner/pi-ai";
} from "@earendil-works/pi-ai";
import { Type } from "typebox";
import { describe, expect, it } from "vitest";
import { agentLoop, agentLoopContinue } from "../src/agent-loop.js";
+1 -1
View File
@@ -1,4 +1,4 @@
import { type AssistantMessage, type AssistantMessageEvent, EventStream, getModel } from "@mariozechner/pi-ai";
import { type AssistantMessage, type AssistantMessageEvent, EventStream, getModel } from "@earendil-works/pi-ai";
import { describe, expect, it } from "vitest";
import { Agent } from "../src/index.js";
+1 -1
View File
@@ -9,7 +9,7 @@ import {
registerFauxProvider,
type ToolResultMessage,
type UserMessage,
} from "@mariozechner/pi-ai";
} from "@earendil-works/pi-ai";
import { afterEach, describe, expect, it } from "vitest";
import { Agent, type AgentEvent } from "../src/index.js";
import { calculateTool } from "./utils/calculate.js";
@@ -5,7 +5,7 @@ import {
type Model,
registerFauxProvider,
type Usage,
} from "@mariozechner/pi-ai";
} from "@earendil-works/pi-ai";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import {
calculateContextTokens,
+1 -1
View File
@@ -1,4 +1,4 @@
import { getModel } from "@mariozechner/pi-ai";
import { getModel } from "@earendil-works/pi-ai";
import { describe, expect, it } from "vitest";
import { NodeExecutionEnv } from "../../src/harness/execution-env.js";
import { createAgentHarness, createSession } from "../../src/harness/factory.js";
@@ -1,7 +1,7 @@
import { existsSync, mkdirSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { AgentMessage } from "@earendil-works/pi-agent-core";
import { afterEach } from "vitest";
export function createUserMessage(text: string): AgentMessage {
+1 -1
View File
@@ -1,6 +1,6 @@
import { homedir } from "node:os";
import { join } from "node:path";
import { getModel } from "@mariozechner/pi-ai";
import { getModel } from "@earendil-works/pi-ai";
import { InMemorySessionStorage } from "../../src/harness/session/storage/memory.js";
import {
createAgentHarness,
+15
View File
@@ -4,8 +4,23 @@
### Fixed
- Fixed OpenAI Responses requests for models that support disabling reasoning to send `reasoning.effort: "none"` when thinking is off.
## [0.74.0] - 2026-05-07
## [0.73.1] - 2026-05-07
### Added
- Added OAuth login flow metadata so clients can present interactive provider choices during login ([#4190](https://github.com/earendil-works/pi-mono/pull/4190) by [@mitsuhiko](https://github.com/mitsuhiko)).
### Fixed
- Fixed OpenAI Responses reasoning text streaming for LM Studio and other compatible providers that emit `response.reasoning_text.delta` events ([#4191](https://github.com/badlogic/pi-mono/pull/4191) by [@yaanfpv](https://github.com/yaanfpv)).
- Fixed OpenAI Codex OAuth refresh failures writing directly to stderr while the TUI is active ([#4141](https://github.com/badlogic/pi-mono/issues/4141)).
- Fixed OpenAI-compatible chat completion streams that interleave content and tool-call deltas in the same choice.
- Fixed the Kimi K2 P6 model alias to normalize to `kimi-for-coding` ([#4218](https://github.com/earendil-works/pi-mono/issues/4218)).
- Fixed OpenAI Codex Responses requests to send a non-empty system prompt ([#4184](https://github.com/earendil-works/pi-mono/issues/4184)).
## [0.73.0] - 2026-05-04
+29 -29
View File
@@ -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
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@mariozechner/pi-ai",
"version": "0.73.0",
"name": "@earendil-works/pi-ai",
"version": "0.74.0",
"description": "Unified LLM API with automatic model discovery and provider configuration",
"type": "module",
"main": "./dist/index.js",
@@ -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": {
+17
View File
@@ -86,6 +86,16 @@ const DEEPSEEK_V4_THINKING_LEVEL_MAP = {
xhigh: "max",
} as const;
const OPENAI_RESPONSES_NONE_REASONING_MODELS = new Set([
"gpt-5.1",
"gpt-5.2",
"gpt-5.3-codex",
"gpt-5.4",
"gpt-5.4-mini",
"gpt-5.4-nano",
"gpt-5.5",
]);
function mergeThinkingLevelMap(model: Model<any>, map: NonNullable<Model<any>["thinkingLevelMap"]>): void {
model.thinkingLevelMap = { ...model.thinkingLevelMap, ...map };
}
@@ -122,6 +132,13 @@ function applyThinkingLevelMetadata(model: Model<any>): void {
) {
mergeThinkingLevelMap(model, { off: null });
}
if (
model.api === "openai-responses" &&
model.provider === "openai" &&
OPENAI_RESPONSES_NONE_REASONING_MODELS.has(model.id)
) {
mergeThinkingLevelMap(model, { off: "none" });
}
if (supportsOpenAiXhigh(model.id)) {
mergeThinkingLevelMap(model, { xhigh: "xhigh" });
}
+6 -6
View File
@@ -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);
}
+192 -157
View File
@@ -4708,6 +4708,24 @@ export const MODELS = {
contextWindow: 1000000,
maxTokens: 64000,
} satisfies Model<"google-generative-ai">,
"gemini-3.1-flash-lite": {
id: "gemini-3.1-flash-lite",
name: "Gemini 3.1 Flash Lite",
api: "google-generative-ai",
provider: "google",
baseUrl: "https://generativelanguage.googleapis.com/v1beta",
reasoning: true,
thinkingLevelMap: {"off":null},
input: ["text", "image"],
cost: {
input: 0.25,
output: 1.5,
cacheRead: 0.025,
cacheWrite: 1,
},
contextWindow: 1048576,
maxTokens: 65536,
} satisfies Model<"google-generative-ai">,
"gemini-3.1-flash-lite-preview": {
id: "gemini-3.1-flash-lite-preview",
name: "Gemini 3.1 Flash Lite Preview",
@@ -6948,7 +6966,7 @@ export const MODELS = {
provider: "openai",
baseUrl: "https://api.openai.com/v1",
reasoning: true,
thinkingLevelMap: {"off":null},
thinkingLevelMap: {"off":"none"},
input: ["text", "image"],
cost: {
input: 1.25,
@@ -7038,7 +7056,7 @@ export const MODELS = {
provider: "openai",
baseUrl: "https://api.openai.com/v1",
reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"},
thinkingLevelMap: {"off":"none","xhigh":"xhigh"},
input: ["text", "image"],
cost: {
input: 1.75,
@@ -7128,7 +7146,7 @@ export const MODELS = {
provider: "openai",
baseUrl: "https://api.openai.com/v1",
reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"},
thinkingLevelMap: {"off":"none","xhigh":"xhigh"},
input: ["text", "image"],
cost: {
input: 1.75,
@@ -7164,7 +7182,7 @@ export const MODELS = {
provider: "openai",
baseUrl: "https://api.openai.com/v1",
reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"},
thinkingLevelMap: {"off":"none","xhigh":"xhigh"},
input: ["text", "image"],
cost: {
input: 2.5,
@@ -7182,7 +7200,7 @@ export const MODELS = {
provider: "openai",
baseUrl: "https://api.openai.com/v1",
reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"},
thinkingLevelMap: {"off":"none","xhigh":"xhigh"},
input: ["text", "image"],
cost: {
input: 0.75,
@@ -7200,7 +7218,7 @@ export const MODELS = {
provider: "openai",
baseUrl: "https://api.openai.com/v1",
reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"},
thinkingLevelMap: {"off":"none","xhigh":"xhigh"},
input: ["text", "image"],
cost: {
input: 0.2,
@@ -7236,7 +7254,7 @@ export const MODELS = {
provider: "openai",
baseUrl: "https://api.openai.com/v1",
reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"},
thinkingLevelMap: {"off":"none","xhigh":"xhigh"},
input: ["text", "image"],
cost: {
input: 5,
@@ -7586,9 +7604,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 +7617,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 +7872,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 +8360,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 +8515,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 +8649,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 +8926,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 +9245,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",
@@ -9439,6 +9423,23 @@ export const MODELS = {
contextWindow: 1048576,
maxTokens: 65536,
} satisfies Model<"openai-completions">,
"google/gemini-3.1-flash-lite": {
id: "google/gemini-3.1-flash-lite",
name: "Google: Gemini 3.1 Flash Lite",
api: "openai-completions",
provider: "openrouter",
baseUrl: "https://openrouter.ai/api/v1",
reasoning: true,
input: ["text", "image"],
cost: {
input: 0.25,
output: 1.5,
cacheRead: 0.024999999999999998,
cacheWrite: 0.08333333333333334,
},
contextWindow: 1048576,
maxTokens: 65536,
} satisfies Model<"openai-completions">,
"google/gemini-3.1-flash-lite-preview": {
id: "google/gemini-3.1-flash-lite-preview",
name: "Google: Gemini 3.1 Flash Lite Preview",
@@ -9626,18 +9627,18 @@ export const MODELS = {
contextWindow: 128000,
maxTokens: 50000,
} satisfies Model<"openai-completions">,
"inclusionai/ling-2.6-1t:free": {
id: "inclusionai/ling-2.6-1t:free",
name: "inclusionAI: Ling-2.6-1T (free)",
"inclusionai/ling-2.6-1t": {
id: "inclusionai/ling-2.6-1t",
name: "inclusionAI: Ling-2.6-1T",
api: "openai-completions",
provider: "openrouter",
baseUrl: "https://openrouter.ai/api/v1",
reasoning: false,
input: ["text"],
cost: {
input: 0,
output: 0,
cacheRead: 0,
input: 0.3,
output: 2.5,
cacheRead: 0.06,
cacheWrite: 0,
},
contextWindow: 262144,
@@ -9677,23 +9678,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 +10069,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 +10316,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 +11237,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 +11943,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 +12232,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 +12266,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 +13003,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 +13150,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",
@@ -14011,6 +14029,23 @@ export const MODELS = {
contextWindow: 1000000,
maxTokens: 64000,
} satisfies Model<"anthropic-messages">,
"google/gemini-3.1-flash-lite": {
id: "google/gemini-3.1-flash-lite",
name: "Gemini 3.1 Flash Lite",
api: "anthropic-messages",
provider: "vercel-ai-gateway",
baseUrl: "https://ai-gateway.vercel.sh",
reasoning: true,
input: ["text", "image"],
cost: {
input: 0.25,
output: 1.5,
cacheRead: 0.03,
cacheWrite: 0,
},
contextWindow: 1000000,
maxTokens: 65000,
} satisfies Model<"anthropic-messages">,
"google/gemini-3.1-flash-lite-preview": {
id: "google/gemini-3.1-flash-lite-preview",
name: "Gemini 3.1 Flash Lite Preview",
@@ -15528,8 +15563,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 +15580,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 +15597,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 +15614,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 +15631,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 +15648,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 +16422,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 +16439,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 +16456,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 +16466,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 +16483,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 +16509,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 +16526,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 +16543,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 +16553,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 +16570,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 +16596,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 +16613,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 +16630,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 +16640,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 +16657,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 +16683,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 +16700,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 +16717,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 +16727,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 +16744,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,
@@ -91,6 +91,80 @@ describe("openai-responses provider defaults", () => {
});
});
it.each(["gpt-5.1", "gpt-5.2", "gpt-5.3-codex", "gpt-5.4", "gpt-5.4-mini", "gpt-5.4-nano", "gpt-5.5"] as const)(
"sends none reasoning effort for OpenAI %s when no reasoning is requested",
async (modelId) => {
const model = getModel("openai", modelId);
let capturedPayload: unknown;
vi.spyOn(globalThis, "fetch").mockResolvedValue(
new Response("data: [DONE]\n\n", {
status: 200,
headers: { "content-type": "text/event-stream" },
}),
);
const stream = streamOpenAIResponses(
model,
{
systemPrompt: "sys",
messages: [{ role: "user", content: "hi", timestamp: Date.now() }],
},
{
apiKey: "test-key",
onPayload: (payload) => {
capturedPayload = payload;
},
},
);
for await (const event of stream) {
if (event.type === "done" || event.type === "error") break;
}
expect(capturedPayload).toMatchObject({
reasoning: { effort: "none" },
});
},
);
it.each(["gpt-5", "gpt-5-mini", "gpt-5-nano", "gpt-5-pro", "gpt-5.2-pro", "gpt-5.4-pro", "gpt-5.5-pro"] as const)(
"omits reasoning effort for OpenAI %s when off is unsupported",
async (modelId) => {
const model = getModel("openai", modelId);
let capturedPayload: unknown;
vi.spyOn(globalThis, "fetch").mockResolvedValue(
new Response("data: [DONE]\n\n", {
status: 200,
headers: { "content-type": "text/event-stream" },
}),
);
const stream = streamOpenAIResponses(
model,
{
systemPrompt: "sys",
messages: [{ role: "user", content: "hi", timestamp: Date.now() }],
},
{
apiKey: "test-key",
onPayload: (payload) => {
capturedPayload = payload;
},
},
);
for await (const event of stream) {
if (event.type === "done" || event.type === "error") break;
}
expect(capturedPayload).not.toMatchObject({
reasoning: expect.anything(),
});
},
);
it("sets cache-affinity headers for official OpenAI Responses requests with a sessionId", async () => {
const captured = await captureOpenAIResponseHeaders({ sessionId: "session-123" });
@@ -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";
+32
View File
@@ -2,11 +2,43 @@
## [Unreleased]
## [0.74.0] - 2026-05-07
### Changed
- Updated repository links and package references for the move to `earendil-works/pi-mono` and `@earendil-works/*` package scopes.
## [0.73.1] - 2026-05-07
### New Features
- **Self-update support for the npm scope migration**: `pi update --self` now supports the upcoming package rename from `@mariozechner/pi-coding-agent` to `@earendil-works/pi-coding-agent`. After the new package is published, existing global installs can update through the normal self-update flow; pi will uninstall the old global package and install the package name returned by the version check endpoint.
- **Interactive OAuth login selection**: OAuth providers can now present multiple login choices in `/login`, enabling provider-specific interactive authentication flows. See [Providers](docs/providers.md).
- **JSONC-style `models.json` parsing**: `models.json` now allows comments and trailing commas, making custom provider and model configuration easier to maintain. See [Providers](docs/providers.md) and [Custom Providers](docs/custom-provider.md).
### Added
- Added interactive login selection support so OAuth providers can present multiple login choices ([#4190](https://github.com/earendil-works/pi-mono/pull/4190) by [@mitsuhiko](https://github.com/mitsuhiko)).
### Changed
- Changed `pi update --self` to honor the active package name returned by the Pi version check endpoint, defaulting to the current package when omitted and uninstalling the old global package before installing a renamed package.
- Changed extension loading to use upstream `jiti` 2.7 instead of the `@mariozechner/jiti` fork ([#4244](https://github.com/earendil-works/pi-mono/pull/4244) by [@pi0](https://github.com/pi0)).
- Changed `models.json` parsing to allow comments and trailing commas ([#4162](https://github.com/earendil-works/pi-mono/pull/4162) by [@julien-c](https://github.com/julien-c)).
### Fixed
- Fixed `pi -p` treating prompts that start with YAML frontmatter as extension flags instead of user messages ([#4163](https://github.com/badlogic/pi-mono/issues/4163)).
- Fixed pending tool results not updating in the live TUI after toggling thinking block visibility while the tool is running ([#4167](https://github.com/badlogic/pi-mono/issues/4167)).
- Fixed `/copy` reporting success on Linux without writing the clipboard on Wayland-only compositors (Hyprland, Niri, ...) by skipping the X11-only native addon on Linux and routing through `wl-copy`/`xclip`/`xsel` instead ([#4177](https://github.com/badlogic/pi-mono/issues/4177)).
- Fixed HTML session exports to strip skill wrapper XML from rendered user messages ([#4234](https://github.com/earendil-works/pi-mono/pull/4234) by [@aliou](https://github.com/aliou)).
- Fixed OpenAI-compatible chat completion streams that interleave content and tool-call deltas in the same choice.
- Fixed OpenAI Codex OAuth refresh failures writing directly to stderr while the TUI is active ([#4141](https://github.com/badlogic/pi-mono/issues/4141)).
- Fixed OpenAI Codex Responses requests to send a non-empty system prompt ([#4184](https://github.com/earendil-works/pi-mono/issues/4184)).
- Fixed Kimi For Coding model resolution for the Kimi K2 P6 alias ([#4218](https://github.com/earendil-works/pi-mono/issues/4218)).
- Fixed Kitty inline image redraws to stay within TUI-owned terminal regions and avoid writing below the active viewport.
- Fixed Kitty inline image rendering by letting the terminal allocate image ids and bounding parsed image ids to valid values.
- Fixed inline image capability detection to disable inline images in cmux terminals.
## [0.73.0] - 2026-05-04
+13 -12
View File
@@ -1,16 +1,11 @@
<p align="center">
<a href="https://pi.dev">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://pi.dev/logo.svg">
<source media="(prefers-color-scheme: light)" srcset="https://huggingface.co/buckets/julien-c/my-training-bucket/resolve/pi-logo-dark.svg">
<img alt="pi logo" src="https://pi.dev/logo.svg" width="128">
</picture>
<img alt="pi logo" src="https://pi.dev/logo-auto.svg" width="128">
</a>
</p>
<p align="center">
<a href="https://discord.com/invite/3cU7Bz4UPx"><img alt="Discord" src="https://img.shields.io/badge/discord-community-5865F2?style=flat-square&logo=discord&logoColor=white" /></a>
<a href="https://www.npmjs.com/package/@mariozechner/pi-coding-agent"><img alt="npm" src="https://img.shields.io/npm/v/@mariozechner/pi-coding-agent?style=flat-square" /></a>
<a href="https://github.com/badlogic/pi-mono/actions/workflows/ci.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/badlogic/pi-mono/ci.yml?style=flat-square&branch=main" /></a>
<a href="https://www.npmjs.com/package/@earendil-works/pi-coding-agent"><img alt="npm" src="https://img.shields.io/npm/v/@earendil-works/pi-coding-agent?style=flat-square" /></a>
</p>
<p align="center">
<a href="https://pi.dev">pi.dev</a> domain graciously donated by
@@ -73,7 +68,13 @@ I regularly publish my own `pi-mono` work sessions here:
## Quick Start
```bash
npm install -g @mariozechner/pi-coding-agent
curl -fsSL https://pi.dev/install.sh | sh
```
Or with npm:
```bash
npm install -g @earendil-works/pi-coding-agent
```
Authenticate with an API key:
@@ -432,7 +433,7 @@ See [docs/packages.md](docs/packages.md).
### SDK
```typescript
import { AuthStorage, createAgentSession, ModelRegistry, SessionManager } from "@mariozechner/pi-coding-agent";
import { AuthStorage, createAgentSession, ModelRegistry, SessionManager } from "@earendil-works/pi-coding-agent";
const authStorage = AuthStorage.create();
const modelRegistry = ModelRegistry.create(authStorage);
@@ -646,6 +647,6 @@ MIT
## See Also
- [@mariozechner/pi-ai](https://www.npmjs.com/package/@mariozechner/pi-ai): Core LLM toolkit
- [@mariozechner/pi-agent-core](https://www.npmjs.com/package/@mariozechner/pi-agent-core): Agent framework
- [@mariozechner/pi-tui](https://www.npmjs.com/package/@mariozechner/pi-tui): Terminal UI components
- [@earendil-works/pi-ai](https://www.npmjs.com/package/@earendil-works/pi-ai): Core LLM toolkit
- [@earendil-works/pi-agent-core](https://www.npmjs.com/package/@earendil-works/pi-agent-core): Agent framework
- [@earendil-works/pi-tui](https://www.npmjs.com/package/@earendil-works/pi-tui): Terminal UI components
+14 -14
View File
@@ -2,14 +2,14 @@
LLMs have limited context windows. When conversations grow too long, pi uses compaction to summarize older content while preserving recent work. This page covers both auto-compaction and branch summarization.
**Source files** ([pi-mono](https://github.com/badlogic/pi-mono)):
- [`packages/coding-agent/src/core/compaction/compaction.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) - Auto-compaction logic
- [`packages/coding-agent/src/core/compaction/branch-summarization.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts) - Branch summarization
- [`packages/coding-agent/src/core/compaction/utils.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/utils.ts) - Shared utilities (file tracking, serialization)
- [`packages/coding-agent/src/core/session-manager.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/session-manager.ts) - Entry types (`CompactionEntry`, `BranchSummaryEntry`)
- [`packages/coding-agent/src/core/extensions/types.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/extensions/types.ts) - Extension event types
**Source files** ([pi-mono](https://github.com/earendil-works/pi-mono)):
- [`packages/coding-agent/src/core/compaction/compaction.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) - Auto-compaction logic
- [`packages/coding-agent/src/core/compaction/branch-summarization.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts) - Branch summarization
- [`packages/coding-agent/src/core/compaction/utils.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/compaction/utils.ts) - Shared utilities (file tracking, serialization)
- [`packages/coding-agent/src/core/session-manager.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/session-manager.ts) - Entry types (`CompactionEntry`, `BranchSummaryEntry`)
- [`packages/coding-agent/src/core/extensions/types.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/extensions/types.ts) - Extension event types
For TypeScript definitions in your project, inspect `node_modules/@mariozechner/pi-coding-agent/dist/`.
For TypeScript definitions in your project, inspect `node_modules/@earendil-works/pi-coding-agent/dist/`.
## Overview
@@ -118,7 +118,7 @@ Never cut at tool results (they must stay with their tool call).
### CompactionEntry Structure
Defined in [`session-manager.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/session-manager.ts):
Defined in [`session-manager.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/session-manager.ts):
```typescript
interface CompactionEntry<T = unknown> {
@@ -142,7 +142,7 @@ interface CompactionDetails {
Extensions can store any JSON-serializable data in `details`. The default compaction tracks file operations, but custom extension implementations can use their own structure.
See [`prepareCompaction()`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) and [`compact()`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) for the implementation.
See [`prepareCompaction()`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) and [`compact()`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) for the implementation.
## Branch Summarization
@@ -185,7 +185,7 @@ This means file tracking accumulates across multiple compactions or nested branc
### BranchSummaryEntry Structure
Defined in [`session-manager.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/session-manager.ts):
Defined in [`session-manager.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/session-manager.ts):
```typescript
interface BranchSummaryEntry<T = unknown> {
@@ -208,7 +208,7 @@ interface BranchSummaryDetails {
Same as compaction, extensions can store custom data in `details`.
See [`collectEntriesForBranchSummary()`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts), [`prepareBranchEntries()`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts), and [`generateBranchSummary()`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts) for the implementation.
See [`collectEntriesForBranchSummary()`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts), [`prepareBranchEntries()`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts), and [`generateBranchSummary()`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts) for the implementation.
## Summary Format
@@ -252,7 +252,7 @@ path/to/changed.ts
### Message Serialization
Before summarization, messages are serialized to text via [`serializeConversation()`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/compaction/utils.ts):
Before summarization, messages are serialized to text via [`serializeConversation()`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/compaction/utils.ts):
```
[User]: What they said
@@ -268,7 +268,7 @@ Tool results are truncated to 2000 characters during serialization. Content beyo
## Custom Summarization via Extensions
Extensions can intercept and customize both compaction and branch summarization. See [`extensions/types.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/extensions/types.ts) for event type definitions.
Extensions can intercept and customize both compaction and branch summarization. See [`extensions/types.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/extensions/types.ts) for event type definitions.
### session_before_compact
@@ -309,7 +309,7 @@ pi.on("session_before_compact", async (event, ctx) => {
To generate a summary with your own model, convert messages to text using `serializeConversation`:
```typescript
import { convertToLlm, serializeConversation } from "@mariozechner/pi-coding-agent";
import { convertToLlm, serializeConversation } from "@earendil-works/pi-coding-agent";
pi.on("session_before_compact", async (event, ctx) => {
const { preparation } = event;
+11 -11
View File
@@ -30,7 +30,7 @@ See these complete provider examples:
## Quick Reference
```typescript
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
// Override baseUrl for existing provider
@@ -96,7 +96,7 @@ To add a completely new provider, specify `models` along with the required confi
If the model list comes from a remote endpoint, use an async extension factory:
```typescript
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default async function (pi: ExtensionAPI) {
const response = await fetch("http://localhost:1234/v1/models");
@@ -252,7 +252,7 @@ pi.registerProvider("custom-api", {
Add OAuth/SSO authentication that integrates with `/login`:
```typescript
import type { OAuthCredentials, OAuthLoginCallbacks } from "@mariozechner/pi-ai";
import type { OAuthCredentials, OAuthLoginCallbacks } from "@earendil-works/pi-ai";
pi.registerProvider("corporate-ai", {
baseUrl: "https://ai.corp.com/v1",
@@ -345,12 +345,12 @@ interface OAuthCredentials {
For providers with non-standard APIs, implement `streamSimple`. Study the existing provider implementations before writing your own:
**Reference implementations:**
- [anthropic.ts](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/providers/anthropic.ts) - Anthropic Messages API
- [mistral.ts](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/providers/mistral.ts) - Mistral Conversations API
- [openai-completions.ts](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/providers/openai-completions.ts) - OpenAI Chat Completions
- [openai-responses.ts](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/providers/openai-responses.ts) - OpenAI Responses API
- [google.ts](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/providers/google.ts) - Google Generative AI
- [amazon-bedrock.ts](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/providers/amazon-bedrock.ts) - AWS Bedrock
- [anthropic.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/providers/anthropic.ts) - Anthropic Messages API
- [mistral.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/providers/mistral.ts) - Mistral Conversations API
- [openai-completions.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/providers/openai-completions.ts) - OpenAI Chat Completions
- [openai-responses.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/providers/openai-responses.ts) - OpenAI Responses API
- [google.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/providers/google.ts) - Google Generative AI
- [amazon-bedrock.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/providers/amazon-bedrock.ts) - AWS Bedrock
### Stream Pattern
@@ -365,7 +365,7 @@ import {
type SimpleStreamOptions,
calculateCost,
createAssistantMessageEventStream,
} from "@mariozechner/pi-ai";
} from "@earendil-works/pi-ai";
function streamMyProvider(
model: Model<any>,
@@ -522,7 +522,7 @@ pi.registerProvider("my-provider", {
## Testing Your Implementation
Test your provider against the same test suites used by built-in providers. Copy and adapt these test files from [packages/ai/test/](https://github.com/badlogic/pi-mono/tree/main/packages/ai/test):
Test your provider against the same test suites used by built-in providers. Copy and adapt these test files from [packages/ai/test/](https://github.com/earendil-works/pi-mono/tree/main/packages/ai/test):
| Test | Purpose |
|------|---------|
+1 -1
View File
@@ -5,7 +5,7 @@ See [AGENTS.md](../../../AGENTS.md) for additional guidelines.
## Setup
```bash
git clone https://github.com/badlogic/pi-mono
git clone https://github.com/earendil-works/pi-mono
cd pi-mono
npm install
npm run build
+36 -36
View File
@@ -57,7 +57,7 @@ See [examples/extensions/](../examples/extensions/) for working implementations.
Create `~/.pi/agent/extensions/my-extension.ts`:
```typescript
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";
export default function (pi: ExtensionAPI) {
@@ -139,10 +139,10 @@ To share extensions via npm or git as pi packages, see [packages.md](packages.md
| Package | Purpose |
|---------|---------|
| `@mariozechner/pi-coding-agent` | Extension types (`ExtensionAPI`, `ExtensionContext`, events) |
| `@earendil-works/pi-coding-agent` | Extension types (`ExtensionAPI`, `ExtensionContext`, events) |
| `typebox` | Schema definitions for tool parameters |
| `@mariozechner/pi-ai` | AI utilities (`StringEnum` for Google-compatible enums) |
| `@mariozechner/pi-tui` | TUI components for custom rendering |
| `@earendil-works/pi-ai` | AI utilities (`StringEnum` for Google-compatible enums) |
| `@earendil-works/pi-tui` | TUI components for custom rendering |
npm dependencies work too. Add a `package.json` next to your extension (or in a parent directory), run `npm install`, and imports from `node_modules/` are resolved automatically.
@@ -155,7 +155,7 @@ Node.js built-ins (`node:fs`, `node:path`, etc.) are also available.
An extension exports a default factory function that receives `ExtensionAPI`. The factory can be synchronous or asynchronous:
```typescript
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
// Subscribe to events
@@ -184,7 +184,7 @@ If the factory returns a `Promise`, pi awaits it before continuing startup. That
Use an async factory for one-time startup work such as fetching remote configuration or dynamically discovering available models.
```typescript
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default async function (pi: ExtensionAPI) {
const response = await fetch("http://localhost:1234/v1/models");
@@ -688,7 +688,7 @@ Behavior guarantees:
- Return values from `tool_call` only control blocking via `{ block: true, reason?: string }`
```typescript
import { isToolCallEventType } from "@mariozechner/pi-coding-agent";
import { isToolCallEventType } from "@earendil-works/pi-coding-agent";
pi.on("tool_call", async (event, ctx) => {
// event.toolName - "bash", "read", "write", "edit", etc.
@@ -724,7 +724,7 @@ export type MyToolInput = Static<typeof myToolSchema>;
Use `isToolCallEventType` with explicit type parameters:
```typescript
import { isToolCallEventType } from "@mariozechner/pi-coding-agent";
import { isToolCallEventType } from "@earendil-works/pi-coding-agent";
import type { MyToolInput } from "my-extension";
pi.on("tool_call", (event) => {
@@ -748,7 +748,7 @@ In parallel tool mode, `tool_result` and `tool_execution_end` may interleave in
Use `ctx.signal` for nested async work inside the handler. This lets Esc cancel model calls, `fetch()`, and other abort-aware operations started by the extension.
```typescript
import { isBashToolResult } from "@mariozechner/pi-coding-agent";
import { isBashToolResult } from "@earendil-works/pi-coding-agent";
pi.on("tool_result", async (event, ctx) => {
// event.toolName, event.toolCallId, event.input
@@ -776,7 +776,7 @@ pi.on("tool_result", async (event, ctx) => {
Fired when user executes `!` or `!!` commands. **Can intercept.**
```typescript
import { createLocalBashOperations } from "@mariozechner/pi-coding-agent";
import { createLocalBashOperations } from "@earendil-works/pi-coding-agent";
pi.on("user_bash", (event, ctx) => {
// event.command - the bash command
@@ -1087,7 +1087,7 @@ Options:
To discover available sessions, use the static `SessionManager.list()` or `SessionManager.listAll()` methods:
```typescript
import { SessionManager } from "@mariozechner/pi-coding-agent";
import { SessionManager } from "@earendil-works/pi-coding-agent";
pi.registerCommand("switch", {
description: "Switch to another session",
@@ -1181,7 +1181,7 @@ Tools run with `ExtensionContext`, so they cannot call `ctx.reload()` directly.
Example tool the LLM can call to trigger reload:
```typescript
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";
export default function (pi: ExtensionAPI) {
@@ -1230,7 +1230,7 @@ See [dynamic-tools.ts](../examples/extensions/dynamic-tools.ts) for a full examp
```typescript
import { Type } from "typebox";
import { StringEnum } from "@mariozechner/pi-ai";
import { StringEnum } from "@earendil-works/pi-ai";
pi.registerTool({
name: "my_tool",
@@ -1388,7 +1388,7 @@ pi.registerCommand("stats", {
Optional: add argument auto-completion for `/command ...`:
```typescript
import type { AutocompleteItem } from "@mariozechner/pi-tui";
import type { AutocompleteItem } from "@earendil-works/pi-tui";
pi.registerCommand("deploy", {
description: "Deploy to an environment",
@@ -1678,7 +1678,7 @@ Pass the real target file path to `withFileMutationQueue()`, not the raw user ar
Queue the entire mutation window on that target path. That includes read-modify-write logic, not just the final write.
```typescript
import { withFileMutationQueue } from "@mariozechner/pi-coding-agent";
import { withFileMutationQueue } from "@earendil-works/pi-coding-agent";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { dirname, resolve } from "node:path";
@@ -1703,8 +1703,8 @@ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
```typescript
import { Type } from "typebox";
import { StringEnum } from "@mariozechner/pi-ai";
import { Text } from "@mariozechner/pi-tui";
import { StringEnum } from "@earendil-works/pi-ai";
import { Text } from "@earendil-works/pi-tui";
pi.registerTool({
name: "my_tool",
@@ -1772,7 +1772,7 @@ async execute(toolCallId, params) {
}
```
**Important:** Use `StringEnum` from `@mariozechner/pi-ai` for string enums. `Type.Union`/`Type.Literal` doesn't work with Google's API.
**Important:** Use `StringEnum` from `@earendil-works/pi-ai` for string enums. `Type.Union`/`Type.Literal` doesn't work with Google's API.
**Argument preparation:** `prepareArguments(args)` is optional. If defined, it runs before schema validation and before `execute()`. Use it to mimic an older accepted input shape when pi resumes an older session whose stored tool call arguments no longer match the current schema. Return the object you want validated against `parameters`. Keep the public schema strict. Do not add deprecated compatibility fields to `parameters` just to keep old resumed sessions working.
@@ -1845,20 +1845,20 @@ See [examples/extensions/tool-override.ts](../examples/extensions/tool-override.
**Your implementation must match the exact result shape**, including the `details` type. The UI and session logic depend on these shapes for rendering and state tracking.
Built-in tool implementations:
- [read.ts](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/tools/read.ts) - `ReadToolDetails`
- [bash.ts](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/tools/bash.ts) - `BashToolDetails`
- [edit.ts](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/tools/edit.ts)
- [write.ts](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/tools/write.ts)
- [grep.ts](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/tools/grep.ts) - `GrepToolDetails`
- [find.ts](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/tools/find.ts) - `FindToolDetails`
- [ls.ts](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/tools/ls.ts) - `LsToolDetails`
- [read.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/read.ts) - `ReadToolDetails`
- [bash.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/bash.ts) - `BashToolDetails`
- [edit.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/edit.ts)
- [write.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/write.ts)
- [grep.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/grep.ts) - `GrepToolDetails`
- [find.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/find.ts) - `FindToolDetails`
- [ls.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/ls.ts) - `LsToolDetails`
### Remote Execution
Built-in tools support pluggable operations for delegating to remote systems (SSH, containers, etc.):
```typescript
import { createReadTool, createBashTool, type ReadOperations } from "@mariozechner/pi-coding-agent";
import { createReadTool, createBashTool, type ReadOperations } from "@earendil-works/pi-coding-agent";
// Create tool with custom operations
const remoteRead = createReadTool(cwd, {
@@ -1889,7 +1889,7 @@ For `user_bash`, extensions can reuse pi's local shell backend via `createLocalB
The bash tool also supports a spawn hook to adjust the command, cwd, or env before execution:
```typescript
import { createBashTool } from "@mariozechner/pi-coding-agent";
import { createBashTool } from "@earendil-works/pi-coding-agent";
const bashTool = createBashTool(cwd, {
spawnHook: ({ command, cwd, env }) => ({
@@ -1919,7 +1919,7 @@ import {
formatSize, // Human-readable size (e.g., "50KB", "1.5MB")
DEFAULT_MAX_BYTES, // 50KB
DEFAULT_MAX_LINES, // 2000
} from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-coding-agent";
async execute(toolCallId, params, signal, onUpdate, ctx) {
const output = await runCommand();
@@ -1974,7 +1974,7 @@ export default function (pi: ExtensionAPI) {
### Custom Rendering
Tools can provide `renderCall` and `renderResult` for custom TUI display. See [tui.md](tui.md) for the full component API and [tool-execution.ts](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/modes/interactive/components/tool-execution.ts) for how tool rows are composed.
Tools can provide `renderCall` and `renderResult` for custom TUI display. See [tui.md](tui.md) for the full component API and [tool-execution.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/modes/interactive/components/tool-execution.ts) for how tool rows are composed.
By default, tool output is wrapped in a `Box` that handles padding and background. A defined `renderCall` or `renderResult` must return a `Component`. If a slot renderer is not defined, `tool-execution.ts` uses fallback rendering for that slot.
@@ -2010,7 +2010,7 @@ Use `context.state` for cross-slot shared state. Keep slot-local caches on the r
Renders the tool call or header:
```typescript
import { Text } from "@mariozechner/pi-tui";
import { Text } from "@earendil-works/pi-tui";
renderCall(args, theme, context) {
const text = (context.lastComponent as Text | undefined) ?? new Text("", 0, 0);
@@ -2055,7 +2055,7 @@ If a slot intentionally has no visible content, return an empty `Component` such
Use `keyHint()` to display keybinding hints that respect the active keybinding configuration:
```typescript
import { keyHint } from "@mariozechner/pi-coding-agent";
import { keyHint } from "@earendil-works/pi-coding-agent";
renderResult(result, { expanded }, theme, context) {
let text = theme.fg("success", "✓ Done");
@@ -2329,7 +2329,7 @@ See [github-issue-autocomplete.ts](../examples/extensions/github-issue-autocompl
For complex UI, use `ctx.ui.custom()`. This temporarily replaces the editor with your component until `done()` is called:
```typescript
import { Text, Component } from "@mariozechner/pi-tui";
import { Text, Component } from "@earendil-works/pi-tui";
const result = await ctx.ui.custom<boolean>((tui, theme, keybindings, done) => {
const text = new Text("Press Enter to confirm, Escape to cancel", 1, 1);
@@ -2387,8 +2387,8 @@ See [tui.md](tui.md) for the full `OverlayOptions` API and [overlay-qa-tests.ts]
Replace the main input editor with a custom implementation (vim mode, emacs mode, etc.):
```typescript
import { CustomEditor, type ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { matchesKey } from "@mariozechner/pi-tui";
import { CustomEditor, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { matchesKey } from "@earendil-works/pi-tui";
class VimEditor extends CustomEditor {
private mode: "normal" | "insert" = "insert";
@@ -2438,7 +2438,7 @@ See [tui.md](tui.md) Pattern 7 for a complete example with mode indicator.
Register a custom renderer for messages with your `customType`:
```typescript
import { Text } from "@mariozechner/pi-tui";
import { Text } from "@earendil-works/pi-tui";
pi.registerMessageRenderer("my-extension", (message, options, theme) => {
const { expanded } = options;
@@ -2487,7 +2487,7 @@ theme.strikethrough(text)
For syntax highlighting in custom tool renderers:
```typescript
import { highlightCode, getLanguageFromPath } from "@mariozechner/pi-coding-agent";
import { highlightCode, getLanguageFromPath } from "@earendil-works/pi-coding-agent";
// Highlight code with explicit language
const highlighted = highlightCode("const x = 1;", "typescript", theme);
+8 -2
View File
@@ -4,10 +4,16 @@ Pi is a minimal terminal coding harness. It is designed to stay small at the cor
## Quick start
Install pi with npm:
On linux or mac you can install Pi with curl:
```bash
npm install -g @mariozechner/pi-coding-agent
curl -fsSL https://pi.dev/install.sh | sh
```
Or alternatively with npm:
```bash
npm install -g @earendil-works/pi-coding-agent
```
Then run it in a project directory:
+4 -4
View File
@@ -8,7 +8,7 @@ Outputs all session events as JSON lines to stdout. Useful for integrating pi in
## Event Types
Events are defined in [`AgentSessionEvent`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/agent-session.ts#L102):
Events are defined in [`AgentSessionEvent`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/agent-session.ts#L102):
```typescript
type AgentSessionEvent =
@@ -22,7 +22,7 @@ type AgentSessionEvent =
`queue_update` emits the full pending steering and follow-up queues whenever they change. `compaction_start` and `compaction_end` cover both manual and automatic compaction.
Base events from [`AgentEvent`](https://github.com/badlogic/pi-mono/blob/main/packages/agent/src/types.ts#L179):
Base events from [`AgentEvent`](https://github.com/earendil-works/pi-mono/blob/main/packages/agent/src/types.ts#L179):
```typescript
type AgentEvent =
@@ -44,12 +44,12 @@ type AgentEvent =
## Message Types
Base messages from [`packages/ai/src/types.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/types.ts#L134):
Base messages from [`packages/ai/src/types.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/types.ts#L134):
- `UserMessage` (line 134)
- `AssistantMessage` (line 140)
- `ToolResultMessage` (line 152)
Extended messages from [`packages/coding-agent/src/core/messages.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/messages.ts#L29):
Extended messages from [`packages/coding-agent/src/core/messages.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/messages.ts#L29):
- `BashExecutionMessage` (line 29)
- `CustomMessage` (line 46)
- `BranchSummaryMessage` (line 55)
+1 -1
View File
@@ -163,7 +163,7 @@ If no `pi` manifest is present, pi auto-discovers resources from these directori
Third party runtime dependencies belong in `dependencies` in `package.json`. Dependencies that do not register extensions, skills, prompt templates, or themes also belong in `dependencies`. When pi installs a package from npm or git, it runs `npm install`, so those dependencies are installed automatically.
Pi bundles core packages for extensions and skills. If you import any of these, list them in `peerDependencies` with a `"*"` range and do not bundle them: `@mariozechner/pi-ai`, `@mariozechner/pi-agent-core`, `@mariozechner/pi-coding-agent`, `@mariozechner/pi-tui`, `typebox`.
Pi bundles core packages for extensions and skills. If you import any of these, list them in `peerDependencies` with a `"*"` range and do not bundle them: `@earendil-works/pi-ai`, `@earendil-works/pi-agent-core`, `@earendil-works/pi-coding-agent`, `@earendil-works/pi-tui`, `typebox`.
Other pi packages must be bundled in your tarball. Add them to `dependencies` and `bundledDependencies`, then reference their resources through `node_modules/` paths. Pi loads packages with separate module roots, so separate installs do not collide or share modules.
+1 -1
View File
@@ -74,7 +74,7 @@ pi
| Xiaomi MiMo Token Plan (Amsterdam) | `XIAOMI_TOKEN_PLAN_AMS_API_KEY` | `xiaomi-token-plan-ams` |
| Xiaomi MiMo Token Plan (Singapore) | `XIAOMI_TOKEN_PLAN_SGP_API_KEY` | `xiaomi-token-plan-sgp` |
Reference for environment variables and `auth.json` keys: [`const envMap`](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/env-api-keys.ts) in [`packages/ai/src/env-api-keys.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/env-api-keys.ts).
Reference for environment variables and `auth.json` keys: [`const envMap`](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/env-api-keys.ts) in [`packages/ai/src/env-api-keys.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/env-api-keys.ts).
#### Auth File
+1 -1
View File
@@ -7,7 +7,7 @@ This page gets you from install to a useful first pi session.
Pi is distributed as an npm package:
```bash
npm install -g @mariozechner/pi-coding-agent
npm install -g @earendil-works/pi-coding-agent
```
Then start pi in the project directory you want it to work on:
+1 -1
View File
@@ -2,7 +2,7 @@
RPC mode enables headless operation of the coding agent via a JSON protocol over stdin/stdout. This is useful for embedding the agent in other applications, IDEs, or custom UIs.
**Note for Node.js/TypeScript users**: If you're building a Node.js application, consider using `AgentSession` directly from `@mariozechner/pi-coding-agent` instead of spawning a subprocess. See [`src/core/agent-session.ts`](../src/core/agent-session.ts) for the API. For a subprocess-based TypeScript client, see [`src/modes/rpc/rpc-client.ts`](../src/modes/rpc/rpc-client.ts).
**Note for Node.js/TypeScript users**: If you're building a Node.js application, consider using `AgentSession` directly from `@earendil-works/pi-coding-agent` instead of spawning a subprocess. See [`src/core/agent-session.ts`](../src/core/agent-session.ts) for the API. For a subprocess-based TypeScript client, see [`src/modes/rpc/rpc-client.ts`](../src/modes/rpc/rpc-client.ts).
## Starting RPC Mode
+25 -25
View File
@@ -16,7 +16,7 @@ See [examples/sdk/](../examples/sdk/) for working examples from minimal to full
## Quick Start
```typescript
import { AuthStorage, createAgentSession, ModelRegistry, SessionManager } from "@mariozechner/pi-coding-agent";
import { AuthStorage, createAgentSession, ModelRegistry, SessionManager } from "@earendil-works/pi-coding-agent";
// Set up credential storage and model registry
const authStorage = AuthStorage.create();
@@ -40,7 +40,7 @@ await session.prompt("What files are in the current directory?");
## Installation
```bash
npm install @mariozechner/pi-coding-agent
npm install @earendil-works/pi-coding-agent
```
The SDK is included in the main package. No separate installation needed.
@@ -54,7 +54,7 @@ The main factory function for a single `AgentSession`.
`createAgentSession()` uses a `ResourceLoader` to supply extensions, skills, prompt templates, themes, and context files. If you do not provide one, it uses `DefaultResourceLoader` with standard discovery.
```typescript
import { createAgentSession } from "@mariozechner/pi-coding-agent";
import { createAgentSession } from "@earendil-works/pi-coding-agent";
// Minimal: defaults with DefaultResourceLoader
const { session } = await createAgentSession();
@@ -132,7 +132,7 @@ import {
createAgentSessionServices,
getAgentDir,
SessionManager,
} from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-coding-agent";
const createRuntime: CreateAgentSessionRuntimeFactory = async ({ cwd, sessionManager, sessionStartEvent }) => {
const services = await createAgentSessionServices({ cwd });
@@ -239,7 +239,7 @@ Both `steer()` and `followUp()` expand file-based prompt templates but error on
### Agent and AgentState
The `Agent` class (from `@mariozechner/pi-agent-core`) handles the core LLM interaction. Access it via `session.agent`.
The `Agent` class (from `@earendil-works/pi-agent-core`) handles the core LLM interaction. Access it via `session.agent`.
```typescript
// Access current state
@@ -368,8 +368,8 @@ When you pass a custom `ResourceLoader`, `cwd` and `agentDir` no longer control
### Model
```typescript
import { getModel } from "@mariozechner/pi-ai";
import { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
import { getModel } from "@earendil-works/pi-ai";
import { AuthStorage, ModelRegistry } from "@earendil-works/pi-coding-agent";
const authStorage = AuthStorage.create();
const modelRegistry = ModelRegistry.create(authStorage);
@@ -416,7 +416,7 @@ API key resolution priority (handled by AuthStorage):
4. Fallback resolver (for custom provider keys from `models.json`)
```typescript
import { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
import { AuthStorage, ModelRegistry } from "@earendil-works/pi-coding-agent";
// Default: uses ~/.pi/agent/auth.json and ~/.pi/agent/models.json
const authStorage = AuthStorage.create();
@@ -452,7 +452,7 @@ const simpleRegistry = ModelRegistry.inMemory(authStorage);
Use a `ResourceLoader` to override the system prompt:
```typescript
import { createAgentSession, DefaultResourceLoader } from "@mariozechner/pi-coding-agent";
import { createAgentSession, DefaultResourceLoader } from "@earendil-works/pi-coding-agent";
const loader = new DefaultResourceLoader({
systemPromptOverride: () => "You are a helpful assistant.",
@@ -472,7 +472,7 @@ import {
readOnlyTools, // read, grep, find, ls
readTool, bashTool, editTool, writeTool,
grepTool, findTool, lsTool,
} from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-coding-agent";
// Use built-in tool set
const { session } = await createAgentSession({
@@ -500,7 +500,7 @@ import {
createGrepTool,
createFindTool,
createLsTool,
} from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-coding-agent";
const cwd = "/path/to/project";
@@ -530,7 +530,7 @@ const { session } = await createAgentSession({
```typescript
import { Type } from "typebox";
import { createAgentSession, defineTool } from "@mariozechner/pi-coding-agent";
import { createAgentSession, defineTool } from "@earendil-works/pi-coding-agent";
// Inline custom tool
const myTool = defineTool({
@@ -563,7 +563,7 @@ Custom tools passed via `customTools` are combined with extension-registered too
Extensions are loaded by the `ResourceLoader`. `DefaultResourceLoader` discovers extensions from `~/.pi/agent/extensions/`, `.pi/extensions/`, and settings.json extension sources.
```typescript
import { createAgentSession, DefaultResourceLoader } from "@mariozechner/pi-coding-agent";
import { createAgentSession, DefaultResourceLoader } from "@earendil-works/pi-coding-agent";
const loader = new DefaultResourceLoader({
additionalExtensionPaths: ["/path/to/my-extension.ts"],
@@ -585,7 +585,7 @@ Extensions can register tools, subscribe to events, add commands, and more. See
**Event Bus:** Extensions can communicate via `pi.events`. Pass a shared `eventBus` to `DefaultResourceLoader` if you need to emit or listen from outside:
```typescript
import { createEventBus, DefaultResourceLoader } from "@mariozechner/pi-coding-agent";
import { createEventBus, DefaultResourceLoader } from "@earendil-works/pi-coding-agent";
const eventBus = createEventBus();
const loader = new DefaultResourceLoader({
@@ -605,7 +605,7 @@ import {
createAgentSession,
DefaultResourceLoader,
type Skill,
} from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-coding-agent";
const customSkill: Skill = {
name: "my-skill",
@@ -631,7 +631,7 @@ const { session } = await createAgentSession({ resourceLoader: loader });
### Context Files
```typescript
import { createAgentSession, DefaultResourceLoader } from "@mariozechner/pi-coding-agent";
import { createAgentSession, DefaultResourceLoader } from "@earendil-works/pi-coding-agent";
const loader = new DefaultResourceLoader({
agentsFilesOverride: (current) => ({
@@ -655,7 +655,7 @@ import {
createAgentSession,
DefaultResourceLoader,
type PromptTemplate,
} from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-coding-agent";
const customCommand: PromptTemplate = {
name: "deploy",
@@ -690,7 +690,7 @@ import {
createAgentSessionServices,
getAgentDir,
SessionManager,
} from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-coding-agent";
// In-memory (no persistence)
const { session } = await createAgentSession({
@@ -784,7 +784,7 @@ sm.createBranchedSession(leafId); // Extract path to new file
### Settings Management
```typescript
import { createAgentSession, SettingsManager, SessionManager } from "@mariozechner/pi-coding-agent";
import { createAgentSession, SettingsManager, SessionManager } from "@earendil-works/pi-coding-agent";
// Default: loads from files (global + project merged)
const { session } = await createAgentSession({
@@ -840,7 +840,7 @@ Use `DefaultResourceLoader` to discover extensions, skills, prompts, themes, and
import {
DefaultResourceLoader,
getAgentDir,
} from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-coding-agent";
const loader = new DefaultResourceLoader({
cwd,
@@ -881,7 +881,7 @@ interface LoadExtensionsResult {
## Complete Example
```typescript
import { getModel } from "@mariozechner/pi-ai";
import { getModel } from "@earendil-works/pi-ai";
import { Type } from "typebox";
import {
AuthStorage,
@@ -893,7 +893,7 @@ import {
readTool,
SessionManager,
SettingsManager,
} from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-coding-agent";
// Set up auth storage (custom location)
const authStorage = AuthStorage.create("/custom/agent/auth.json");
@@ -978,7 +978,7 @@ import {
getAgentDir,
InteractiveMode,
SessionManager,
} from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-coding-agent";
const createRuntime: CreateAgentSessionRuntimeFactory = async ({ cwd, sessionManager, sessionStartEvent }) => {
const services = await createAgentSessionServices({ cwd });
@@ -1018,7 +1018,7 @@ import {
getAgentDir,
runPrintMode,
SessionManager,
} from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-coding-agent";
const createRuntime: CreateAgentSessionRuntimeFactory = async ({ cwd, sessionManager, sessionStartEvent }) => {
const services = await createAgentSessionServices({ cwd });
@@ -1055,7 +1055,7 @@ import {
getAgentDir,
runRpcMode,
SessionManager,
} from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-coding-agent";
const createRuntime: CreateAgentSessionRuntimeFactory = async ({ cwd, sessionManager, sessionStartEvent }) => {
const services = await createAgentSessionServices({ cwd });
+6 -6
View File
@@ -28,13 +28,13 @@ Existing sessions are automatically migrated to the current version (v3) when lo
## Source Files
Source on GitHub ([pi-mono](https://github.com/badlogic/pi-mono)):
- [`packages/coding-agent/src/core/session-manager.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/session-manager.ts) - Session entry types and SessionManager
- [`packages/coding-agent/src/core/messages.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/core/messages.ts) - Extended message types (BashExecutionMessage, CustomMessage, etc.)
- [`packages/ai/src/types.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/ai/src/types.ts) - Base message types (UserMessage, AssistantMessage, ToolResultMessage)
- [`packages/agent/src/types.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/agent/src/types.ts) - AgentMessage union type
Source on GitHub ([pi-mono](https://github.com/earendil-works/pi-mono)):
- [`packages/coding-agent/src/core/session-manager.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/session-manager.ts) - Session entry types and SessionManager
- [`packages/coding-agent/src/core/messages.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/messages.ts) - Extended message types (BashExecutionMessage, CustomMessage, etc.)
- [`packages/ai/src/types.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/types.ts) - Base message types (UserMessage, AssistantMessage, ToolResultMessage)
- [`packages/agent/src/types.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/agent/src/types.ts) - AgentMessage union type
For TypeScript definitions in your project, inspect `node_modules/@mariozechner/pi-coding-agent/dist/` and `node_modules/@mariozechner/pi-ai/dist/`.
For TypeScript definitions in your project, inspect `node_modules/@earendil-works/pi-coding-agent/dist/` and `node_modules/@earendil-works/pi-ai/dist/`.
## Message Types
+1 -1
View File
@@ -17,7 +17,7 @@ pkg update && pkg upgrade
pkg install nodejs termux-api git
# Install pi
npm install -g @mariozechner/pi-coding-agent
npm install -g @earendil-works/pi-coding-agent
# Create config directory
mkdir -p ~/.pi/agent
+2 -2
View File
@@ -52,7 +52,7 @@ vim ~/.pi/agent/themes/my-theme.json
```json
{
"$schema": "https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
"$schema": "https://raw.githubusercontent.com/earendil-works/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
"name": "my-theme",
"vars": {
"primary": "#00aaff",
@@ -122,7 +122,7 @@ vim ~/.pi/agent/themes/my-theme.json
```json
{
"$schema": "https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
"$schema": "https://raw.githubusercontent.com/earendil-works/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
"name": "my-theme",
"vars": {
"blue": "#0066cc",
+20 -20
View File
@@ -4,7 +4,7 @@
Extensions and custom tools can render custom TUI components for interactive user interfaces. This page covers the component system and available building blocks.
**Source:** [`@mariozechner/pi-tui`](https://github.com/badlogic/pi-mono/tree/main/packages/tui)
**Source:** [`@earendil-works/pi-tui`](https://github.com/earendil-works/pi-mono/tree/main/packages/tui)
## Component Interface
@@ -33,7 +33,7 @@ The TUI appends a full SGR reset and OSC 8 reset at the end of each rendered lin
Components that display a text cursor and need IME (Input Method Editor) support should implement the `Focusable` interface:
```typescript
import { CURSOR_MARKER, type Component, type Focusable } from "@mariozechner/pi-tui";
import { CURSOR_MARKER, type Component, type Focusable } from "@earendil-works/pi-tui";
class MyInput implements Component, Focusable {
focused: boolean = false; // Set by TUI when focus changes
@@ -59,7 +59,7 @@ This enables IME candidate windows to appear at the correct position for CJK inp
When a container component (dialog, selector, etc.) contains an `Input` or `Editor` child, the container must implement `Focusable` and propagate the focus state to the child. Otherwise, the hardware cursor won't be positioned correctly for IME input.
```typescript
import { Container, type Focusable, Input } from "@mariozechner/pi-tui";
import { Container, type Focusable, Input } from "@earendil-works/pi-tui";
class SearchDialog extends Container implements Focusable {
private searchInput: Input;
@@ -179,10 +179,10 @@ See [overlay-qa-tests.ts](../examples/extensions/overlay-qa-tests.ts) for compre
## Built-in Components
Import from `@mariozechner/pi-tui`:
Import from `@earendil-works/pi-tui`:
```typescript
import { Text, Box, Container, Spacer, Markdown } from "@mariozechner/pi-tui";
import { Text, Box, Container, Spacer, Markdown } from "@earendil-works/pi-tui";
```
### Text
@@ -264,7 +264,7 @@ const image = new Image(
Use `matchesKey()` for key detection:
```typescript
import { matchesKey, Key } from "@mariozechner/pi-tui";
import { matchesKey, Key } from "@earendil-works/pi-tui";
handleInput(data: string) {
if (matchesKey(data, Key.up)) {
@@ -290,7 +290,7 @@ handleInput(data: string) {
**Critical:** Each line from `render()` must not exceed the `width` parameter.
```typescript
import { visibleWidth, truncateToWidth } from "@mariozechner/pi-tui";
import { visibleWidth, truncateToWidth } from "@earendil-works/pi-tui";
render(width: number): string[] {
// Truncate long lines
@@ -311,7 +311,7 @@ Example: Interactive selector
import {
matchesKey, Key,
truncateToWidth, visibleWidth
} from "@mariozechner/pi-tui";
} from "@earendil-works/pi-tui";
class MySelector {
private items: string[];
@@ -425,8 +425,8 @@ renderResult(result, options, theme, context) {
**For Markdown**, use `getMarkdownTheme()`:
```typescript
import { getMarkdownTheme } from "@mariozechner/pi-coding-agent";
import { Markdown } from "@mariozechner/pi-tui";
import { getMarkdownTheme } from "@earendil-works/pi-coding-agent";
import { Markdown } from "@earendil-works/pi-tui";
renderResult(result, options, theme, context) {
const mdTheme = getMarkdownTheme();
@@ -587,12 +587,12 @@ These patterns cover the most common UI needs in extensions. **Copy these patter
### Pattern 1: Selection Dialog (SelectList)
For letting users pick from a list of options. Use `SelectList` from `@mariozechner/pi-tui` with `DynamicBorder` for framing.
For letting users pick from a list of options. Use `SelectList` from `@earendil-works/pi-tui` with `DynamicBorder` for framing.
```typescript
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { DynamicBorder } from "@mariozechner/pi-coding-agent";
import { Container, type SelectItem, SelectList, Text } from "@mariozechner/pi-tui";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { DynamicBorder } from "@earendil-works/pi-coding-agent";
import { Container, type SelectItem, SelectList, Text } from "@earendil-works/pi-tui";
pi.registerCommand("pick", {
handler: async (_args, ctx) => {
@@ -650,7 +650,7 @@ pi.registerCommand("pick", {
For operations that take time and should be cancellable. `BorderedLoader` shows a spinner and handles escape to cancel.
```typescript
import { BorderedLoader } from "@mariozechner/pi-coding-agent";
import { BorderedLoader } from "@earendil-works/pi-coding-agent";
pi.registerCommand("fetch", {
handler: async (_args, ctx) => {
@@ -679,11 +679,11 @@ pi.registerCommand("fetch", {
### Pattern 3: Settings/Toggles (SettingsList)
For toggling multiple settings. Use `SettingsList` from `@mariozechner/pi-tui` with `getSettingsListTheme()`.
For toggling multiple settings. Use `SettingsList` from `@earendil-works/pi-tui` with `getSettingsListTheme()`.
```typescript
import { getSettingsListTheme } from "@mariozechner/pi-coding-agent";
import { Container, type SettingItem, SettingsList, Text } from "@mariozechner/pi-tui";
import { getSettingsListTheme } from "@earendil-works/pi-coding-agent";
import { Container, type SettingItem, SettingsList, Text } from "@earendil-works/pi-tui";
pi.registerCommand("settings", {
handler: async (_args, ctx) => {
@@ -822,8 +822,8 @@ Token stats available via `ctx.sessionManager.getBranch()` and `ctx.model`.
Replace the main input editor with a custom implementation. Useful for modal editing (vim), different keybindings (emacs), or specialized input handling.
```typescript
import { CustomEditor, type ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { matchesKey, truncateToWidth } from "@mariozechner/pi-tui";
import { CustomEditor, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { matchesKey, truncateToWidth } from "@earendil-works/pi-tui";
type Mode = "normal" | "insert";
@@ -137,7 +137,7 @@ cp permission-gate.ts ~/.pi/agent/extensions/
See [docs/extensions.md](../../docs/extensions.md) for full documentation.
```typescript
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";
export default function (pi: ExtensionAPI) {
@@ -179,7 +179,7 @@ export default function (pi: ExtensionAPI) {
**Use StringEnum for string parameters** (required for Google API compatibility):
```typescript
import { StringEnum } from "@mariozechner/pi-ai";
import { StringEnum } from "@earendil-works/pi-ai";
// Good
action: StringEnum(["list", "add"] as const)
@@ -5,7 +5,7 @@
* Uses the last assistant message to generate a commit message.
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
pi.on("session_shutdown", async (_event, ctx) => {
@@ -7,8 +7,8 @@
* pi -e ./bash-spawn-hook.ts
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { createBashTool } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { createBashTool } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
const cwd = process.cwd();
@@ -7,7 +7,7 @@
* Usage: /bookmark [label] - bookmark the last assistant message
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
pi.registerCommand("bookmark", {
@@ -3,9 +3,9 @@ import {
type ExtensionAPI,
type ExtensionContext,
type KeybindingsManager,
} from "@mariozechner/pi-coding-agent";
import type { Component, EditorTheme, TUI } from "@mariozechner/pi-tui";
import { truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
} from "@earendil-works/pi-coding-agent";
import type { Component, EditorTheme, TUI } from "@earendil-works/pi-tui";
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
function fitBorder(
left: string,
@@ -25,9 +25,9 @@
* pi -e ./built-in-tool-renderer.ts
*/
import type { BashToolDetails, EditToolDetails, ExtensionAPI, ReadToolDetails } from "@mariozechner/pi-coding-agent";
import { createBashTool, createEditTool, createReadTool, createWriteTool } from "@mariozechner/pi-coding-agent";
import { Text } from "@mariozechner/pi-tui";
import type { BashToolDetails, EditToolDetails, ExtensionAPI, ReadToolDetails } from "@earendil-works/pi-coding-agent";
import { createBashTool, createEditTool, createReadTool, createWriteTool } from "@earendil-works/pi-coding-agent";
import { Text } from "@earendil-works/pi-tui";
export default function (pi: ExtensionAPI) {
const cwd = process.cwd();
@@ -19,7 +19,7 @@
import * as fs from "node:fs";
import * as path from "node:path";
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
/**
* Recursively find all .md files in a directory
@@ -10,7 +10,7 @@
* 3. Use /commands extensions to filter by source
*/
import type { ExtensionAPI, SlashCommandInfo } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI, SlashCommandInfo } from "@earendil-works/pi-coding-agent";
export default function commandsExtension(pi: ExtensionAPI) {
pi.registerCommand("commands", {
@@ -5,7 +5,7 @@
* Demonstrates how to cancel session events using the before_* events.
*/
import type { ExtensionAPI, SessionBeforeSwitchEvent, SessionMessageEntry } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI, SessionBeforeSwitchEvent, SessionMessageEntry } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
pi.on("session_before_switch", async (event: SessionBeforeSwitchEvent, ctx) => {
@@ -13,9 +13,9 @@
* pi --extension examples/extensions/custom-compaction.ts
*/
import { complete } from "@mariozechner/pi-ai";
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { convertToLlm, serializeConversation } from "@mariozechner/pi-coding-agent";
import { complete } from "@earendil-works/pi-ai";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { convertToLlm, serializeConversation } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
pi.on("session_before_compact", async (event, ctx) => {
@@ -8,9 +8,9 @@
* Token stats come from ctx.sessionManager/ctx.model (already accessible).
*/
import type { AssistantMessage } from "@mariozechner/pi-ai";
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
import type { AssistantMessage } from "@earendil-works/pi-ai";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
export default function (pi: ExtensionAPI) {
let enabled = false;
@@ -5,8 +5,8 @@
* (logo + keybinding hints) with a custom component showing the pi mascot.
*/
import type { ExtensionAPI, Theme } from "@mariozechner/pi-coding-agent";
import { VERSION } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI, Theme } from "@earendil-works/pi-coding-agent";
import { VERSION } from "@earendil-works/pi-coding-agent";
// --- PI MASCOT ---
// Based on pi_mascot.ts - the pi agent character
@@ -42,8 +42,8 @@ import {
type Tool,
type ToolCall,
type ToolResultMessage,
} from "@mariozechner/pi-ai";
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-ai";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
// =============================================================================
// OAuth Implementation (copied from packages/ai/src/utils/oauth/anthropic.ts)
@@ -1,12 +1,12 @@
{
"name": "pi-extension-custom-provider",
"version": "0.73.0",
"version": "0.74.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "pi-extension-custom-provider",
"version": "0.73.0",
"version": "0.74.0",
"dependencies": {
"@anthropic-ai/sdk": "^0.52.0"
}
@@ -1,7 +1,7 @@
{
"name": "pi-extension-custom-provider-anthropic",
"private": true,
"version": "0.73.0",
"version": "0.74.0",
"type": "module",
"scripts": {
"clean": "echo 'nothing to clean'",
@@ -20,8 +20,8 @@ import {
type SimpleStreamOptions,
streamSimpleAnthropic,
streamSimpleOpenAIResponses,
} from "@mariozechner/pi-ai";
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-ai";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
// =============================================================================
// Constants
@@ -1,7 +1,7 @@
{
"name": "pi-extension-custom-provider-gitlab-duo",
"private": true,
"version": "0.73.0",
"version": "0.74.0",
"type": "module",
"scripts": {
"clean": "echo 'nothing to clean'",
@@ -8,7 +8,7 @@
* npx tsx test.ts claude-sonnet-4-5-20250929 --thinking
*/
import { type Api, type Context, type Model, registerApiProvider, streamSimple } from "@mariozechner/pi-ai";
import { type Api, type Context, type Model, registerApiProvider, streamSimple } from "@earendil-works/pi-ai";
import { readFileSync } from "fs";
import { getAgentDir } from "packages/coding-agent/src/config.js";
import { join } from "path";
@@ -5,7 +5,7 @@
* Useful to ensure work is committed before switching context.
*/
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
async function checkDirtyRepo(
pi: ExtensionAPI,
@@ -5,8 +5,8 @@
* Height is calculated from width to maintain DOOM's aspect ratio.
*/
import type { Component } from "@mariozechner/pi-tui";
import { isKeyRelease, type TUI } from "@mariozechner/pi-tui";
import type { Component } from "@earendil-works/pi-tui";
import { isKeyRelease, type TUI } from "@earendil-works/pi-tui";
import type { DoomEngine } from "./doom-engine.js";
import { DoomKeys, mapKeyToDoom } from "./doom-keys.js";
@@ -34,7 +34,7 @@ export const DoomKeys = {
KEY_RALT: 0x80 + 0x38,
} as const;
import { Key, matchesKey, parseKey } from "@mariozechner/pi-tui";
import { Key, matchesKey, parseKey } from "@earendil-works/pi-tui";
/**
* Map terminal key input to DOOM key codes
@@ -9,7 +9,7 @@
* This demonstrates that overlays can handle real-time game rendering at 35 FPS.
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { DoomOverlayComponent } from "./doom-component.js";
import { DoomEngine } from "./doom-engine.js";
import { ensureWadFile } from "./wad-finder.js";
@@ -1,5 +1,5 @@
{
"$schema": "https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
"$schema": "https://raw.githubusercontent.com/earendil-works/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
"name": "dynamic-resources",
"vars": {
"cyan": "#00d7ff",
@@ -1,6 +1,6 @@
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
const baseDir = dirname(fileURLToPath(import.meta.url));
@@ -7,7 +7,7 @@
* - Registers additional tools at runtime via /add-echo-tool <name>
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";
const ECHO_PARAMS = Type.Object({
@@ -7,7 +7,7 @@
* Usage: /emit [event-name] [data] - emit an event on the bus
*/
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
// Store ctx for use in event handler
@@ -9,7 +9,7 @@
*/
import * as fs from "node:fs";
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
pi.on("session_start", async (_event, ctx) => {
@@ -5,7 +5,7 @@
* When forking, offers to restore code to that point in history.
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
const checkpoints = new Map<string, string>();
@@ -1,13 +1,13 @@
// Requires GitHub CLI (`gh`) and a GitHub repository checkout.
// Preloads the latest open issues once per session, then filters them locally for fast `#...` completion.
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import {
type AutocompleteItem,
type AutocompleteProvider,
type AutocompleteSuggestions,
fuzzyFilter,
} from "@mariozechner/pi-tui";
} from "@earendil-works/pi-tui";
type GitHubIssue = {
number: number;
@@ -12,10 +12,10 @@
* The generated prompt appears as a draft in the editor for review/editing.
*/
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import { complete, type Message } from "@mariozechner/pi-ai";
import type { ExtensionAPI, SessionEntry } from "@mariozechner/pi-coding-agent";
import { BorderedLoader, convertToLlm, serializeConversation } from "@mariozechner/pi-coding-agent";
import type { AgentMessage } from "@earendil-works/pi-agent-core";
import { complete, type Message } from "@earendil-works/pi-ai";
import type { ExtensionAPI, SessionEntry } from "@earendil-works/pi-coding-agent";
import { BorderedLoader, convertToLlm, serializeConversation } from "@earendil-works/pi-coding-agent";
const SYSTEM_PROMPT = `You are a context transfer assistant. Given a conversation history and the user's goal for a new thread, generate a focused prompt that:
@@ -2,8 +2,8 @@
* Hello Tool - Minimal custom tool example
*/
import { Type } from "@mariozechner/pi-ai";
import { defineTool, type ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { Type } from "@earendil-works/pi-ai";
import { defineTool, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
const helloTool = defineTool({
name: "hello",
@@ -18,7 +18,7 @@
* /thinking-label Reset to the default label
*/
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
const DEFAULT_LABEL = "Pondering...";
@@ -14,7 +14,7 @@
*
* Note: Regular !command syntax (whole-line bash) is preserved and works as before.
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
const PATTERN = /!\{([^}]+)\}/g;
@@ -9,7 +9,7 @@
* ping "pong" (instant, no LLM)
* time current time (instant, no LLM)
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
pi.on("input", async (event, ctx) => {
@@ -21,7 +21,7 @@
*/
import { spawnSync } from "node:child_process";
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
// Default interactive commands - editors, pagers, git ops, TUIs
const DEFAULT_INTERACTIVE_COMMANDS = [
@@ -7,7 +7,7 @@
import { exec } from "node:child_process";
import { promisify } from "node:util";
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
const execAsync = promisify(exec);
@@ -7,8 +7,8 @@
* Usage: /status [message] - sends a status message with custom rendering
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { Box, Text } from "@mariozechner/pi-tui";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Box, Text } from "@earendil-works/pi-tui";
export default function (pi: ExtensionAPI) {
// Register custom renderer for "status-update" messages
@@ -16,7 +16,7 @@
* Then use ctrl+o to toggle between minimal (collapsed) and full (expanded) views.
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import {
createBashTool,
createEditTool,
@@ -25,8 +25,8 @@ import {
createLsTool,
createReadTool,
createWriteTool,
} from "@mariozechner/pi-coding-agent";
import { Text } from "@mariozechner/pi-tui";
} from "@earendil-works/pi-coding-agent";
import { Text } from "@earendil-works/pi-tui";
import { homedir } from "os";
/**
@@ -9,8 +9,8 @@
* - ctrl+c, ctrl+d, etc. work in both modes
*/
import { CustomEditor, type ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { matchesKey, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
import { CustomEditor, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
// Normal mode key mappings: key -> escape sequence (or null for mode switch)
const NORMAL_KEYS: Record<string, string | null> = {
@@ -7,7 +7,7 @@
* Usage: pi -e ./model-status.ts
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
pi.on("model_select", async (event, ctx) => {
@@ -8,7 +8,7 @@
* - Windows toast: Windows Terminal (WSL)
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
function windowsToastScript(title: string, body: string): string {
const type = "Windows.UI.Notifications";

Some files were not shown because too many files have changed in this diff Show More