Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/pi-memory/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
"pack:check": "pnpm pack --pack-destination ../../.pack"
},
"devDependencies": {
"@earendil-works/pi-ai": "^0.80.0",
"@earendil-works/pi-coding-agent": "^0.80.0",
"@earendil-works/pi-ai": "^0.80.9",
"@earendil-works/pi-coding-agent": "^0.80.9",
"@types/node": "^25.5.0",
"markdownlint-cli2": "^0.18.1",
"oxfmt": "^0.42.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/pi-web-search/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
"pack:check": "pnpm pack --pack-destination ../../.pack"
},
"devDependencies": {
"@earendil-works/pi-ai": "^0.80.0",
"@earendil-works/pi-coding-agent": "^0.80.0",
"@earendil-works/pi-ai": "^0.80.9",
"@earendil-works/pi-coding-agent": "^0.80.9",
"@types/node": "^25.5.0",
"oxfmt": "^0.42.0",
"oxlint": "^1.57.0",
Expand Down
33 changes: 33 additions & 0 deletions packages/skill-pi/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
# @counterposition/skill-pi

## 0.80.9

### Minor Changes

- Sync the Pi skill with Pi 0.80.9, covering changes across 0.80.4–0.80.9.
- SDK (breaking in Pi 0.80.8): rewrite `references/sdk.md` around `ModelRuntime`, which
replaces the removed `AuthStorage`/`ModelRegistry` SDK surface and the
`authStorage`/`modelRegistry` options on `createAgentSession()`. Document
`ModelRuntime.create()` (custom paths, injected pi-ai `CredentialStore`),
auth resolution priority, `getAuth()`, `checkAuth()`, `readStoredCredential()`,
the `resolveCliModel`/`resolveModelScopeWithDiagnostics` helpers, named
`InlineExtension` factories, and the `agent_settled` session/RPC event with
`willRetry` on `agent_end`.
- Extensions: document dynamic tool loading (Pi 0.80.7) — additive
`pi.setActiveTools()` during execution, native deferred loading on Anthropic
and OpenAI Responses models, Kimi `deferredToolsMode` (Pi 0.80.9), compat
flags, and cache guidance. Add the `agent_settled` and
`before_provider_headers` hooks, `pi.registerEntryRenderer()` for TUI-only
custom entries, provider `refreshModels(context)` discovery, the async
`ModelRegistry.refresh()`, and `sessionManager.buildContextEntries()`.
- Providers: xAI subscription login and Radius gateway (Pi 0.80.8), Bedrock
`/login` API key (Pi 0.80.7), `/login <provider>` autocomplete, live model
catalog refresh via `/model`, `pi update --models`, and `models-store.json`.
- models.json: replace the removed `compat.sendSessionIdHeader` with
`compat.sessionAffinityFormat` (breaking in Pi 0.80.7), add request-wide
input pricing `cost.tiers` (Pi 0.80.6), `max` in `thinkingLevelMap` with
hole semantics, and expanded `modelOverrides` (extension-registered models,
`thinkingLevelMap`).
- Settings: the `max` thinking level (Pi 0.80.6) across settings and CLI,
`showCacheMissNotices` (Pi 0.80.4), and `~` expansion for `shellPath`.
- Packages: `pi update --models`, `pi config -l` with Tab scope switching
(Pi 0.80.4), and `autoload: false` project-entry delta semantics.

## 0.80.3

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/skill-pi/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@counterposition/skill-pi",
"version": "0.80.3",
"version": "0.80.9",
"description": "Pi coding agent reference skill — extensions, settings, providers, SDK/RPC, packages, and .pi/ config",
"keywords": [
"ai-skill",
Expand Down
34 changes: 31 additions & 3 deletions packages/skill-pi/skills/pi/references/extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,15 @@ Useful agent events:
- `input` — carries `event.streamingBehavior` (`"steer" | "followUp" | undefined`) so handlers can distinguish idle prompts, mid-stream steers, and queued follow-ups; return `{ action: "transform" | "handled" | "continue" }`
- `before_agent_start` — receives `event.systemPromptOptions` (a `BuildSystemPromptOptions`) so handlers can inspect the structured inputs feeding the system prompt
- `agent_start`
- `agent_end`
- `agent_end` — one low-level run; Pi may still auto-retry, auto-compact and retry, or continue with queued follow-ups
- `agent_settled` (Pi 0.80.4) — fired when no retry/compaction/follow-up remains; use for status integrations that need to know Pi will not continue automatically (`ctx.isIdle()` is true here unless another extension started a new run)
- `turn_start`
- `turn_end`
- `message_start`
- `message_update`
- `message_end` — return a replacement message to override usage/cost or rewrite the finalized assistant message
- `context`
- `before_provider_headers` (Pi 0.80.4) — mutate `event.headers` in place after outgoing HTTP headers are assembled: set a key to a string to add/override, `null` to delete. Runs once per provider request; retries reuse the same headers
- `before_provider_request`
- `after_provider_response` — inspect the provider HTTP status and headers before stream consumption
- `model_select`
Expand All @@ -121,8 +123,8 @@ Tool results may include `terminate: true` to end the current tool batch without
- `ctx.ui` for interactive UI hooks
- `ctx.mode` — `"tui" | "rpc" | "json" | "print"`; gate terminal-only features on `ctx.mode === "tui"`
- `ctx.cwd`
- `ctx.sessionManager` (read-only)
- `ctx.modelRegistry` / `ctx.model`
- `ctx.sessionManager` (read-only; `buildContextEntries()` returns active-branch entries with compaction applied, Pi 0.80.4)
- `ctx.modelRegistry` / `ctx.model` — `ctx.modelRegistry` is the synchronous extension-facing facade; its `refresh()` became `Promise<void>` in Pi 0.80.8 (await it before synchronous registry reads)
- `ctx.hasUI` — `true` in TUI and RPC modes
- `ctx.signal` — the active agent abort signal (or `undefined` when idle); pass it to `fetch`/model calls for abort-aware nested work
- `ctx.isIdle()` / `ctx.hasPendingMessages()`
Expand Down Expand Up @@ -171,6 +173,19 @@ Important rules:
4. Use the file-mutation queue for write/edit style tools.
5. Put reconstructable state in `details`; it persists in session history.

## Dynamic Tool Loading

Pi 0.80.7 lets an extension register many tools while keeping only a small initial set active, then add more during execution — cache-friendly on models with native deferred loading. Lifecycle:

1. Register every tool with `pi.registerTool()` (all appear in `pi.getAllTools()`).
2. Keep a loader tool (e.g. `search_tools`) active; leave searchable tools inactive — e.g. on `session_start`, `pi.setActiveTools()` to the filtered set.
3. During loader execution, call `pi.setActiveTools([...pi.getActiveTools(), ...matches])`. The change must be purely additive; unknown names are ignored.
4. Pi records the added tools on that tool result and exposes their definitions before the next model response.

Native deferred loading preserves the cached prompt prefix on Anthropic Sonnet/Opus/Fable ≥ 4.5 (not Haiku) and OpenAI `gpt-5.4`+; Kimi K3 works via `compat.deferredToolsMode: "kimi"` (Pi 0.80.9). For verified custom models/proxies, enable `compat.supportsToolReferences: true` (`anthropic-messages`) or `compat.supportsToolSearch: true` (`openai-responses`/`openai-codex-responses`). All other models fall back to sending the full active tool list on the next request — activation still works, but may invalidate the provider's cached prefix. Non-additive changes (removals/replacements) always use the fallback.

Cache tips: keep the loader active for the whole session; add rather than replace. Activating a tool that has `promptSnippet`/`promptGuidelines` rebuilds the system prompt and can invalidate the prefix even with native support — lazily loaded tools should rely on their `description` alone.

## UI Methods

Check `ctx.hasUI` first. Non-interactive modes may not support UI.
Expand Down Expand Up @@ -240,6 +255,15 @@ Store extension state with custom session entries:
pi.appendEntry("my-extension-state", { key: "value" });
```

Custom entries never participate in LLM context. Since Pi 0.80.4 they can also render in the interactive transcript via `pi.registerEntryRenderer(customType, renderer)` — the TUI-only counterpart to `pi.registerMessageRenderer()` (whose custom messages DO enter LLM context via `pi.sendMessage()`):

```typescript
pi.registerEntryRenderer("status-card", (entry, { expanded }, theme) => {
return new Text(theme.fg("accent", JSON.stringify(entry.data)));
});
pi.appendEntry("status-card", { title: "Indexed files", count: 17 });
```

Use lifecycle hooks to restore it:

```typescript
Expand Down Expand Up @@ -280,12 +304,16 @@ pi.registerProvider("anthropic", { baseUrl: "https://proxy.example.com" });
pi.unregisterProvider("my-provider");
```

Dynamic providers can implement `refreshModels(context)` (Pi 0.80.8) for model discovery: Pi calls it during catalog refresh (`/model`, `pi update --models`) and publishes the returned list; its models replace extension-provided `models`. Persist results through the scoped `context.store` only when they should survive restarts — live servers like llama.cpp can ignore it.

If you need auth for a specific model request, use:

```typescript
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
```

(Still supported for extensions in Pi 0.80.8+; SDK code should use `ModelRuntime.getAuth()` — see `references/sdk.md`.)

Pass `shouldStopAfterTurn` via the SDK to exit the agent loop gracefully after a completed turn. See `references/sdk.md` and `references/providers.md` for the full provider/model schema.

## Handy Patterns
Expand Down
8 changes: 5 additions & 3 deletions packages/skill-pi/skills/pi/references/packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ pi list
pi update # update pi only (changed in Pi 0.79.7)
pi update --all # update pi + packages, reconcile pinned git refs
pi update --extensions # update packages only
pi update --models # refresh model catalogs only (Pi 0.80.8)
pi update --self # update pi only
pi update <source> # update one package
pi config
pi config # starts in global settings; Tab switches scope
pi config -l # start in project overrides (.pi/settings.json)
```

By default, `install` and `remove` write to user settings (`~/.pi/agent/settings.json`). Use `-l` to write to project settings (`.pi/settings.json`) instead. `pi update` installs the exact version returned by the update check.
Expand Down Expand Up @@ -129,6 +131,6 @@ Rules:

## Scope and Deduplication

- Project settings override global settings for the same package identity
- Project settings override global settings for the same package identity — unless the project entry has `autoload: false`, in which case it is applied as a delta over the global entry (Pi 0.80.4)
- Identity is package name for npm, repo URL for git, and resolved absolute path for local sources
- `pi config` can enable or disable package resources after installation
- `pi config` can enable or disable package resources after installation; since Pi 0.80.4 it manages global vs project-local scopes (Tab to switch, `pi config -l` to start in project mode with inherited global resources dimmed)
22 changes: 16 additions & 6 deletions packages/skill-pi/skills/pi/references/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ Use `/login` in interactive mode, then select a provider. The `/login` selector
- Anthropic Claude Pro / Max — third-party usage draws from extra usage and is billed per token (suppress the warning via `warnings.anthropicExtraUsage`)
- OpenAI ChatGPT Plus / Pro (Codex) — `/login` defaults to browser auth but can use a device-code flow for headless environments
- GitHub Copilot
- xAI (Grok/X subscription, Pi 0.80.8) — `/login xai` then **Use a subscription** (device-code OAuth); `XAI_API_KEY` remains available via **Use an API key**
- Radius (Pi 0.80.8) — a dynamic `pi-messages` gateway; `/login radius` stores OAuth tokens, and custom Radius gateways can be declared in `models.json` with `"oauth": "radius"` plus a gateway `baseUrl`

Use `/logout` to clear stored OAuth credentials. Pi 0.71.0 removed built-in Google Gemini CLI and Google Antigravity providers.
`/login <provider>` with autocomplete works since Pi 0.80.4, and login methods are provider-owned since 0.80.8 (registered pi-ai providers expose their own auth options and status in `/login`). Use `/logout` to clear stored OAuth credentials. Pi 0.71.0 removed built-in Google Gemini CLI and Google Antigravity providers.

Since Pi 0.80.8, built-in catalogs are complemented by dynamic ones: `/model` refreshes configured providers in the background, `pi update --models` forces an immediate refresh, and refreshed catalogs are cached in `~/.pi/agent/models-store.json` for offline use.

## API Key Providers

Expand All @@ -35,6 +39,8 @@ Use `/logout` to clear stored OAuth credentials. Pi 0.71.0 removed built-in Goog
| ZAI Coding Plan (China) | `ZAI_CODING_CN_API_KEY` | `zai-coding-cn` |
| OpenCode Zen | `OPENCODE_API_KEY` | `opencode` |
| OpenCode Go | `OPENCODE_API_KEY` | `opencode-go` |
| Amazon Bedrock | `AWS_BEARER_TOKEN_BEDROCK` | `amazon-bedrock` |
| Radius | `RADIUS_API_KEY` | `radius` |
| Hugging Face | `HF_TOKEN` | `huggingface` |
| Fireworks | `FIREWORKS_API_KEY` | `fireworks` |
| Together AI | `TOGETHER_API_KEY` | `together` |
Expand Down Expand Up @@ -99,7 +105,7 @@ export AZURE_OPENAI_DEPLOYMENT_NAME_MAP=gpt-4o=my-gpt4o

### Amazon Bedrock

Pi supports standard AWS auth flows:
`/login amazon-bedrock` stores a Bedrock API key (Pi 0.80.7). Ambient AWS credential flows also work — these keep using SigV4 authentication:

- `AWS_PROFILE`
- `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`
Expand Down Expand Up @@ -182,10 +188,14 @@ Common `api` values:

### Model & Compatibility Knobs

- `thinkingLevelMap` (Pi 0.72) replaces `compat.reasoningEffortMap`. Map pi levels (`off`/`minimal`/`low`/`medium`/`high`/`xhigh`) to provider values; use `null` to hide a level.
- `thinkingLevelMap` (Pi 0.72) replaces `compat.reasoningEffortMap`. Map pi levels (`off`/`minimal`/`low`/`medium`/`high`/`xhigh`/`max`) to provider values; use `null` to hide a level. Maps may contain holes (Pi 0.80.6) — e.g. expose `high` and `max` without `xhigh`. When a key is omitted, standard levels through `high` use the provider default mapping, but the extended `xhigh`/`max` levels are unsupported.
- `cost` supports request-wide input pricing tiers (Pi 0.80.6): a `tiers` array where each tier supplies a complete alternate rate set and applies to the whole request when total input usage (`input + cacheRead + cacheWrite`) exceeds `inputTokensAbove`; the highest matching threshold wins. Also usable in `modelOverrides` and extension-registered providers.
- `modelOverrides` applies to built-in and (since Pi 0.80.4) extension-registered provider models; per-model fields: `name`, `reasoning`, `thinkingLevelMap`, `input`, `cost` (partial), `contextWindow`, `maxTokens`, `headers`, `compat`.
- `openRouterRouting` is forwarded as-is in the OpenRouter `provider` field (fallbacks, ZDR, ignore lists, throughput/latency).
- `compat.thinkingFormat` supports OpenAI-compatible reasoning variants: `openrouter` sends `reasoning: { effort }`, `together` sends `reasoning: { enabled }` plus `reasoning_effort` when supported, `qwen-chat-template` targets local Qwen-compatible servers that read `chat_template_kwargs.enable_thinking`, and `chat-template` (Pi 0.79.9) sends configurable `chat_template_kwargs` via `compat.chatTemplateKwargs` — e.g. `{ "thinking": { "$var": "thinking.enabled" } }` for DeepSeek models behind vLLM/Hugging Face chat templates (`"$var"` accepts `"thinking.enabled"` or `"thinking.effort"`).
- Advanced `compat` flags exist for proxy quirks (`cacheControlFormat`, `supportsReasoningEffort`, `supportsLongCacheRetention`, `supportsEagerToolInputStreaming`, `sendSessionIdHeader`, `sendSessionAffinityHeaders`). See [Pi `docs/models.md`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/models.md) when a proxy rejects pi's defaults.
- **Breaking (Pi 0.80.7):** `compat.sendSessionIdHeader` was removed. Session affinity is now controlled by `compat.sessionAffinityFormat` (`"openai"` sends `session_id`/`x-client-request-id`, `"openai-nosession"` omits the underscore-containing `session_id` header, `"openrouter"` sends `x-session-id`; default auto-detected). Replace `sendSessionIdHeader: false` with `sessionAffinityFormat: "openai-nosession"`. `sendSessionAffinityHeaders` still gates the behavior for `openai-completions`.
- `compat.deferredToolsMode: "kimi"` (Pi 0.80.9) enables Kimi's deferred tool serialization; `compat.supportsToolReferences` / `compat.supportsToolSearch` enable native dynamic tool loading on verified custom endpoints (see `references/extensions.md`).
- Advanced `compat` flags exist for proxy quirks (`cacheControlFormat`, `supportsReasoningEffort`, `supportsLongCacheRetention`, `supportsEagerToolInputStreaming`, `supportsStrictMode`). See [Pi `docs/models.md`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/models.md) when a proxy rejects pi's defaults.

### Context Overflow Recovery

Expand Down Expand Up @@ -219,7 +229,7 @@ pi.registerProvider("anthropic", { baseUrl: "https://proxy.example.com" });

## SDK / Extension Auth Lookup

If extension or SDK code needs auth for a specific model request, use `getApiKeyAndHeaders(model)` rather than the removed `getApiKey(model)`:
If extension code needs auth for a specific model request, use `getApiKeyAndHeaders(model)` rather than the removed `getApiKey(model)`:

```typescript
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
Expand All @@ -228,4 +238,4 @@ if (!auth.ok) throw new Error(auth.error);
const { apiKey, headers } = auth;
```

This matters for providers whose headers or auth values resolve dynamically on every request.
This matters for providers whose headers or auth values resolve dynamically on every request. In SDK code, use `ModelRuntime.getAuth(providerOrModel)` instead (Pi 0.80.8) — passing a model also resolves built-in, `models.json`, and extension model headers; see `references/sdk.md`.
Loading