mirror of
https://github.com/earendil-works/pi.git
synced 2026-06-18 15:54:04 +08:00
Merge remote-tracking branch 'origin/main' into bigrefactor
# Conflicts: # package-lock.json # packages/agent/package.json
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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", {
|
||||
|
||||
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Generated
+205
-1138
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -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": {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
streamSimple,
|
||||
type ToolResultMessage,
|
||||
validateToolArguments,
|
||||
} from "@mariozechner/pi-ai";
|
||||
} from "@earendil-works/pi-ai";
|
||||
import type {
|
||||
AgentContext,
|
||||
AgentEvent,
|
||||
|
||||
@@ -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,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,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,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";
|
||||
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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,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";
|
||||
|
||||
|
||||
@@ -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,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,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,
|
||||
|
||||
@@ -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
@@ -1,4 +1,4 @@
|
||||
# @mariozechner/pi-ai
|
||||
# @earendil-works/pi-ai
|
||||
|
||||
Unified LLM API with automatic model discovery, provider configuration, token and cost tracking, and simple context persistence and hand-off to other models mid-session.
|
||||
|
||||
@@ -75,15 +75,15 @@ Unified LLM API with automatic model discovery, provider configuration, token an
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @mariozechner/pi-ai
|
||||
npm install @earendil-works/pi-ai
|
||||
```
|
||||
|
||||
TypeBox exports are re-exported from `@mariozechner/pi-ai`: `Type`, `Static`, and `TSchema`.
|
||||
TypeBox exports are re-exported from `@earendil-works/pi-ai`: `Type`, `Static`, and `TSchema`.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```typescript
|
||||
import { Type, getModel, stream, complete, Context, Tool, StringEnum } from '@mariozechner/pi-ai';
|
||||
import { Type, getModel, stream, complete, Context, Tool, StringEnum } from '@earendil-works/pi-ai';
|
||||
|
||||
// Fully typed with auto-complete support for both providers and models
|
||||
const model = getModel('openai', 'gpt-4o-mini');
|
||||
@@ -209,7 +209,7 @@ Tools enable LLMs to interact with external systems. This library uses TypeBox s
|
||||
### Defining Tools
|
||||
|
||||
```typescript
|
||||
import { Type, Tool, StringEnum } from '@mariozechner/pi-ai';
|
||||
import { Type, Tool, StringEnum } from '@earendil-works/pi-ai';
|
||||
|
||||
// Define tool parameters with TypeBox
|
||||
const weatherTool: Tool = {
|
||||
@@ -335,7 +335,7 @@ When using `agentLoop`, tool arguments are automatically validated against your
|
||||
When implementing your own tool execution loop with `stream()` or `complete()`, use `validateToolCall` to validate arguments before passing them to your tools:
|
||||
|
||||
```typescript
|
||||
import { stream, validateToolCall, Tool } from '@mariozechner/pi-ai';
|
||||
import { stream, validateToolCall, Tool } from '@earendil-works/pi-ai';
|
||||
|
||||
const tools: Tool[] = [weatherTool, calculatorTool];
|
||||
const s = stream(model, { messages, tools });
|
||||
@@ -391,7 +391,7 @@ Models with vision capabilities can process images. You can check if a model sup
|
||||
|
||||
```typescript
|
||||
import { readFileSync } from 'fs';
|
||||
import { getModel, complete } from '@mariozechner/pi-ai';
|
||||
import { getModel, complete } from '@earendil-works/pi-ai';
|
||||
|
||||
const model = getModel('openai', 'gpt-4o-mini');
|
||||
|
||||
@@ -428,7 +428,7 @@ Many models support thinking/reasoning capabilities where they can show their in
|
||||
### Unified Interface (streamSimple/completeSimple)
|
||||
|
||||
```typescript
|
||||
import { getModel, streamSimple, completeSimple } from '@mariozechner/pi-ai';
|
||||
import { getModel, streamSimple, completeSimple } from '@earendil-works/pi-ai';
|
||||
|
||||
// Many models across providers support thinking/reasoning
|
||||
const model = getModel('anthropic', 'claude-sonnet-4-20250514');
|
||||
@@ -466,7 +466,7 @@ for (const block of response.content) {
|
||||
For fine-grained control, use the provider-specific options:
|
||||
|
||||
```typescript
|
||||
import { getModel, complete } from '@mariozechner/pi-ai';
|
||||
import { getModel, complete } from '@earendil-works/pi-ai';
|
||||
|
||||
// OpenAI Reasoning (o1, o3, gpt-5)
|
||||
const openaiModel = getModel('openai', 'gpt-5-mini');
|
||||
@@ -555,7 +555,7 @@ if (message.stopReason === 'error' || message.stopReason === 'aborted') {
|
||||
The abort signal allows you to cancel in-progress requests. Aborted requests have `stopReason === 'aborted'`:
|
||||
|
||||
```typescript
|
||||
import { getModel, stream } from '@mariozechner/pi-ai';
|
||||
import { getModel, stream } from '@earendil-works/pi-ai';
|
||||
|
||||
const model = getModel('openai', 'gpt-4o-mini');
|
||||
const controller = new AbortController();
|
||||
@@ -653,7 +653,7 @@ import {
|
||||
fauxToolCall,
|
||||
registerFauxProvider,
|
||||
stream,
|
||||
} from '@mariozechner/pi-ai';
|
||||
} from '@earendil-works/pi-ai';
|
||||
|
||||
const registration = registerFauxProvider({
|
||||
tokensPerSecond: 50 // optional
|
||||
@@ -738,7 +738,7 @@ A **provider** offers models through a specific API. For example:
|
||||
### Querying Providers and Models
|
||||
|
||||
```typescript
|
||||
import { getProviders, getModels, getModel } from '@mariozechner/pi-ai';
|
||||
import { getProviders, getModels, getModel } from '@earendil-works/pi-ai';
|
||||
|
||||
// Get all available providers
|
||||
const providers = getProviders();
|
||||
@@ -764,7 +764,7 @@ console.log(`Using ${model.name} via ${model.api} API`);
|
||||
You can create custom models for local inference servers or custom endpoints:
|
||||
|
||||
```typescript
|
||||
import { Model, stream } from '@mariozechner/pi-ai';
|
||||
import { Model, stream } from '@earendil-works/pi-ai';
|
||||
|
||||
// Example: Ollama using OpenAI-compatible API
|
||||
const ollamaModel: Model<'openai-completions'> = {
|
||||
@@ -892,7 +892,7 @@ If `compat` is not set, the library falls back to URL-based detection. If `compa
|
||||
Models are typed by their API, which keeps the model metadata accurate. Provider-specific option types are enforced when you call the provider functions directly. The generic `stream` and `complete` functions accept `StreamOptions` with additional provider fields.
|
||||
|
||||
```typescript
|
||||
import { streamAnthropic, type AnthropicOptions } from '@mariozechner/pi-ai';
|
||||
import { streamAnthropic, type AnthropicOptions } from '@earendil-works/pi-ai';
|
||||
|
||||
// TypeScript knows this is an Anthropic model
|
||||
const claude = getModel('anthropic', 'claude-sonnet-4-20250514');
|
||||
@@ -921,7 +921,7 @@ When messages from one provider are sent to a different provider, the library au
|
||||
### Example: Multi-Provider Conversation
|
||||
|
||||
```typescript
|
||||
import { getModel, complete, Context } from '@mariozechner/pi-ai';
|
||||
import { getModel, complete, Context } from '@earendil-works/pi-ai';
|
||||
|
||||
// Start with Claude
|
||||
const claude = getModel('anthropic', 'claude-sonnet-4-20250514');
|
||||
@@ -966,7 +966,7 @@ This enables flexible workflows where you can:
|
||||
The `Context` object can be easily serialized and deserialized using standard JSON methods, making it simple to persist conversations, implement chat history, or transfer contexts between services:
|
||||
|
||||
```typescript
|
||||
import { Context, getModel, complete } from '@mariozechner/pi-ai';
|
||||
import { Context, getModel, complete } from '@earendil-works/pi-ai';
|
||||
|
||||
// Create and use a context
|
||||
const context: Context = {
|
||||
@@ -1003,7 +1003,7 @@ const continuation = await complete(newModel, restored);
|
||||
The library supports browser environments. You must pass the API key explicitly since environment variables are not available in browsers:
|
||||
|
||||
```typescript
|
||||
import { getModel, complete } from '@mariozechner/pi-ai';
|
||||
import { getModel, complete } from '@earendil-works/pi-ai';
|
||||
|
||||
// API key must be passed explicitly in browser
|
||||
const model = getModel('anthropic', 'claude-3-5-haiku-20241022');
|
||||
@@ -1020,7 +1020,7 @@ const response = await complete(model, {
|
||||
### Browser Compatibility Notes
|
||||
|
||||
- Amazon Bedrock (`bedrock-converse-stream`) is not supported in browser environments.
|
||||
- OAuth login flows are not supported in browser environments. Use the `@mariozechner/pi-ai/oauth` entry point in Node.js.
|
||||
- OAuth login flows are not supported in browser environments. Use the `@earendil-works/pi-ai/oauth` entry point in Node.js.
|
||||
- In browser builds, Bedrock can still appear in model lists. Calls to Bedrock models fail at runtime.
|
||||
- Use a server-side proxy or backend service if you need Bedrock or OAuth-based auth from a web app.
|
||||
|
||||
@@ -1071,7 +1071,7 @@ const response = await complete(model, context, {
|
||||
### Checking Environment Variables
|
||||
|
||||
```typescript
|
||||
import { getEnvApiKey } from '@mariozechner/pi-ai';
|
||||
import { getEnvApiKey } from '@earendil-works/pi-ai';
|
||||
|
||||
// Check if an API key is set in environment variables
|
||||
const key = getEnvApiKey('openai'); // checks OPENAI_API_KEY
|
||||
@@ -1110,7 +1110,7 @@ export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { getModel, complete } from '@mariozechner/pi-ai';
|
||||
import { getModel, complete } from '@earendil-works/pi-ai';
|
||||
|
||||
(async () => {
|
||||
const model = getModel('google-vertex', 'gemini-2.5-flash');
|
||||
@@ -1133,16 +1133,16 @@ Official docs: [Application Default Credentials](https://cloud.google.com/docs/a
|
||||
The quickest way to authenticate:
|
||||
|
||||
```bash
|
||||
npx @mariozechner/pi-ai login # interactive provider selection
|
||||
npx @mariozechner/pi-ai login anthropic # login to specific provider
|
||||
npx @mariozechner/pi-ai list # list available providers
|
||||
npx @earendil-works/pi-ai login # interactive provider selection
|
||||
npx @earendil-works/pi-ai login anthropic # login to specific provider
|
||||
npx @earendil-works/pi-ai list # list available providers
|
||||
```
|
||||
|
||||
Credentials are saved to `auth.json` in the current directory.
|
||||
|
||||
### Programmatic OAuth
|
||||
|
||||
The library provides login and token refresh functions via the `@mariozechner/pi-ai/oauth` entry point. Credential storage is the caller's responsibility.
|
||||
The library provides login and token refresh functions via the `@earendil-works/pi-ai/oauth` entry point. Credential storage is the caller's responsibility.
|
||||
|
||||
```typescript
|
||||
import {
|
||||
@@ -1159,13 +1159,13 @@ import {
|
||||
// Types
|
||||
type OAuthProvider,
|
||||
type OAuthCredentials,
|
||||
} from '@mariozechner/pi-ai/oauth';
|
||||
} from '@earendil-works/pi-ai/oauth';
|
||||
```
|
||||
|
||||
### Login Flow Example
|
||||
|
||||
```typescript
|
||||
import { loginGitHubCopilot } from '@mariozechner/pi-ai/oauth';
|
||||
import { loginGitHubCopilot } from '@earendil-works/pi-ai/oauth';
|
||||
import { writeFileSync } from 'fs';
|
||||
|
||||
const credentials = await loginGitHubCopilot({
|
||||
@@ -1189,8 +1189,8 @@ writeFileSync('auth.json', JSON.stringify(auth, null, 2));
|
||||
Use `getOAuthApiKey()` to get an API key, automatically refreshing if expired:
|
||||
|
||||
```typescript
|
||||
import { getModel, complete } from '@mariozechner/pi-ai';
|
||||
import { getOAuthApiKey } from '@mariozechner/pi-ai/oauth';
|
||||
import { getModel, complete } from '@earendil-works/pi-ai';
|
||||
import { getOAuthApiKey } from '@earendil-works/pi-ai/oauth';
|
||||
import { readFileSync, writeFileSync } from 'fs';
|
||||
|
||||
// Load your stored credentials
|
||||
@@ -1247,7 +1247,7 @@ Create a new provider file (for example `amazon-bedrock.ts`) that exports:
|
||||
- Register the API with `registerApiProvider()`
|
||||
- Add a package subpath export in `package.json` for the provider module (`./dist/providers/<provider>.js`)
|
||||
- Add lazy loader wrappers in `src/providers/register-builtins.ts`, do not statically import provider implementation modules there
|
||||
- Add any root-level `export type` re-exports in `src/index.ts` that should remain available from `@mariozechner/pi-ai`
|
||||
- Add any root-level `export type` re-exports in `src/index.ts` that should remain available from `@earendil-works/pi-ai`
|
||||
- Add credential detection in `env-api-keys.ts` for the new provider
|
||||
- Ensure `streamSimple` handles auth lookup via `getEnvApiKey()` or provider-specific auth
|
||||
|
||||
|
||||
@@ -1,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": {
|
||||
|
||||
@@ -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" });
|
||||
}
|
||||
|
||||
@@ -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
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 |
|
||||
|------|---------|
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
+2
-2
@@ -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
Reference in New Issue
Block a user