@averyyy/pi-coding-agent 0.80.10-piclient.2 → 0.82.0-piclient.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +101 -0
- package/README.md +19 -3
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +2 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +1 -1
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +13 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +33 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +91 -59
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +7 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +6 -2
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +23 -4
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +83 -29
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/utils.d.ts +1 -1
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +6 -17
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +13 -2
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +2 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +35 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +20 -2
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-config.d.ts +30 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +6 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts +5 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +19 -4
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +9 -0
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +7 -3
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +42 -21
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +1 -0
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +4 -4
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +21 -7
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +1 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +6 -2
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +9 -4
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +99 -23
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +34 -5
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +1 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +3 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/usage-totals.d.ts +19 -0
- package/dist/core/usage-totals.d.ts.map +1 -0
- package/dist/core/usage-totals.js +52 -0
- package/dist/core/usage-totals.js.map +1 -0
- package/dist/extensions/index.d.ts +3 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/index.js +3 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/extensions/llama/client.d.ts +61 -0
- package/dist/extensions/llama/client.d.ts.map +1 -0
- package/dist/extensions/llama/client.js +302 -0
- package/dist/extensions/llama/client.js.map +1 -0
- package/dist/extensions/llama/huggingface.d.ts +23 -0
- package/dist/extensions/llama/huggingface.d.ts.map +1 -0
- package/dist/extensions/llama/huggingface.js +141 -0
- package/dist/extensions/llama/huggingface.js.map +1 -0
- package/dist/extensions/llama/index.d.ts +3 -0
- package/dist/extensions/llama/index.d.ts.map +1 -0
- package/dist/extensions/llama/index.js +208 -0
- package/dist/extensions/llama/index.js.map +1 -0
- package/dist/extensions/llama/provider.d.ts +10 -0
- package/dist/extensions/llama/provider.d.ts.map +1 -0
- package/dist/extensions/llama/provider.js +101 -0
- package/dist/extensions/llama/provider.js.map +1 -0
- package/dist/extensions/llama/ui.d.ts +42 -0
- package/dist/extensions/llama/ui.d.ts.map +1 -0
- package/dist/extensions/llama/ui.js +416 -0
- package/dist/extensions/llama/ui.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +10 -4
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +16 -46
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +24 -23
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts +12 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -0
- package/dist/modes/interactive/external-editor.js +37 -0
- package/dist/modes/interactive/external-editor.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +2 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +72 -68
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +4 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +7 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +5 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +11 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +19 -8
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +3 -1
- package/dist/utils/version-check.js.map +1 -1
- package/docs/compaction.md +9 -4
- package/docs/custom-provider.md +33 -2
- package/docs/environment-variables.md +88 -0
- package/docs/extensions.md +61 -11
- package/docs/index.md +2 -0
- package/docs/json.md +5 -1
- package/docs/llama-cpp.md +99 -0
- package/docs/models.md +6 -2
- package/docs/prompt-templates.md +1 -0
- package/docs/providers.md +19 -1
- package/docs/rpc.md +104 -8
- package/docs/sdk.md +3 -0
- package/docs/session-format.md +17 -3
- package/docs/settings.md +1 -1
- package/docs/tui.md +41 -26
- package/docs/usage.md +2 -14
- package/examples/extensions/README.md +1 -1
- package/examples/extensions/custom-compaction.ts +4 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/handoff.ts +9 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/summarize.ts +3 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +5 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,kBAAkB,GAAG,mCAAmC,CAAC;AAC/D,MAAM,gCAAgC,GAAG,KAAK,CAAC;AAQ/C,MAAM,UAAU,sBAAsB,CAAC,WAAmB,EAAE,YAAoB,EAAsB;IACrG,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;IACzC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAAA,CAC5B;AAED,MAAM,UAAU,qBAAqB,CAAC,gBAAwB,EAAE,cAAsB,EAAW;IAChG,MAAM,UAAU,GAAG,sBAAsB,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;IAC5E,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,UAAU,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,gBAAgB,CAAC,IAAI,EAAE,KAAK,cAAc,CAAC,IAAI,EAAE,CAAC;AAAA,CACzD;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACvC,cAAsB,EACtB,OAAO,GAA2B,EAAE,EACG;IACvC,IAAI,OAAO,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"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","sourcesContent":["import { compare, valid } from \"semver\";\nimport { getPiUserAgent } from \"./pi-user-agent.ts\";\n\nconst LATEST_VERSION_URL = \"https://pi.dev/api/latest-version\";\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestPiRelease {\n\tversion: string;\n\tpackageName?: string;\n\tnote?: string;\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = valid(leftVersion.trim());\n\tconst right = valid(rightVersion.trim());\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\treturn compare(left, right);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst comparison = comparePackageVersions(candidateVersion, currentVersion);\n\tif (comparison !== undefined) {\n\t\treturn comparison > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nexport async function getLatestPiRelease(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number } = {},\n): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_OFFLINE) return undefined;\n\n\tconst response = await fetch(LATEST_VERSION_URL, {\n\t\theaders: {\n\t\t\t\"User-Agent\": getPiUserAgent(currentVersion),\n\t\t\taccept: \"application/json\",\n\t\t},\n\t\tsignal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS),\n\t});\n\tif (!response.ok) return undefined;\n\n\tconst data = (await response.json()) as {\n\t\tpackageName?: unknown;\n\t\tversion?: unknown;\n\t\tnote?: unknown;\n\t};\n\tif (typeof data.version !== \"string\" || !data.version.trim()) {\n\t\treturn undefined;\n\t}\n\tconst packageName =\n\t\ttypeof data.packageName === \"string\" && data.packageName.trim() ? data.packageName.trim() : undefined;\n\tconst note = typeof data.note === \"string\" && data.note.trim() ? data.note.trim() : undefined;\n\treturn {\n\t\tversion: data.version.trim(),\n\t\tpackageName,\n\t\t...(note ? { note } : {}),\n\t};\n}\n\nexport async function getLatestPiVersion(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number } = {},\n): Promise<string | undefined> {\n\treturn (await getLatestPiRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewPiVersion(currentVersion: string): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_SKIP_VERSION_CHECK) return undefined;\n\n\ttry {\n\t\tconst latestRelease = await getLatestPiRelease(currentVersion);\n\t\tif (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {\n\t\t\treturn latestRelease;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
|
package/docs/compaction.md
CHANGED
|
@@ -20,7 +20,7 @@ Pi has two summarization mechanisms:
|
|
|
20
20
|
| Compaction | Context exceeds threshold, or `/compact` | Summarize old messages to free up context |
|
|
21
21
|
| Branch summarization | `/tree` navigation | Preserve context when switching branches |
|
|
22
22
|
|
|
23
|
-
Both use the same structured summary format and track file operations cumulatively.
|
|
23
|
+
Both use the same structured summary format and track file operations cumulatively. Compaction and branch-summary requests use fresh routing session IDs and, where supported by the provider, disable prompt-cache writes because these one-off prompts are unlikely to be reused.
|
|
24
24
|
|
|
25
25
|
## Compaction
|
|
26
26
|
|
|
@@ -129,6 +129,7 @@ interface CompactionEntry<T = unknown> {
|
|
|
129
129
|
summary: string;
|
|
130
130
|
firstKeptEntryId: string;
|
|
131
131
|
tokensBefore: number;
|
|
132
|
+
usage?: Usage; // LLM usage that generated the summary
|
|
132
133
|
fromHook?: boolean; // true if provided by extension (legacy field name)
|
|
133
134
|
details?: T; // implementation-specific data
|
|
134
135
|
}
|
|
@@ -140,9 +141,9 @@ interface CompactionDetails {
|
|
|
140
141
|
}
|
|
141
142
|
```
|
|
142
143
|
|
|
143
|
-
Extensions can store any JSON-serializable data in `details`. The default compaction tracks file operations, but custom extension implementations can use their own structure.
|
|
144
|
+
Extensions can store any JSON-serializable data in `details`. The default compaction tracks file operations, but custom extension implementations can use their own structure. Generated and extension-provided summaries store their LLM `usage` when available so session totals include summarization work.
|
|
144
145
|
|
|
145
|
-
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.
|
|
146
|
+
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. For direct programmatic summarization, `generateSummary()` returns the summary text and `generateSummaryWithUsage()` returns `{ text, usage }`.
|
|
146
147
|
|
|
147
148
|
## Branch Summarization
|
|
148
149
|
|
|
@@ -195,6 +196,7 @@ interface BranchSummaryEntry<T = unknown> {
|
|
|
195
196
|
timestamp: number;
|
|
196
197
|
summary: string;
|
|
197
198
|
fromId: string; // Entry we navigated from
|
|
199
|
+
usage?: Usage; // LLM usage that generated the summary
|
|
198
200
|
fromHook?: boolean; // true if provided by extension (legacy field name)
|
|
199
201
|
details?: T; // implementation-specific data
|
|
200
202
|
}
|
|
@@ -300,6 +302,7 @@ pi.on("session_before_compact", async (event, ctx) => {
|
|
|
300
302
|
summary: "Your summary...",
|
|
301
303
|
firstKeptEntryId: preparation.firstKeptEntryId,
|
|
302
304
|
tokensBefore: preparation.tokensBefore,
|
|
305
|
+
// usage: summaryResponse.usage, // Optional; included in session totals
|
|
303
306
|
details: { /* custom data */ },
|
|
304
307
|
}
|
|
305
308
|
};
|
|
@@ -328,13 +331,14 @@ pi.on("session_before_compact", async (event, ctx) => {
|
|
|
328
331
|
// [Tool result]: output text
|
|
329
332
|
|
|
330
333
|
// Now send to your model for summarization
|
|
331
|
-
const summary = await myModel.summarize(conversationText);
|
|
334
|
+
const { summary, usage } = await myModel.summarize(conversationText);
|
|
332
335
|
|
|
333
336
|
return {
|
|
334
337
|
compaction: {
|
|
335
338
|
summary,
|
|
336
339
|
firstKeptEntryId: preparation.firstKeptEntryId,
|
|
337
340
|
tokensBefore: preparation.tokensBefore,
|
|
341
|
+
usage,
|
|
338
342
|
}
|
|
339
343
|
};
|
|
340
344
|
});
|
|
@@ -364,6 +368,7 @@ pi.on("session_before_tree", async (event, ctx) => {
|
|
|
364
368
|
return {
|
|
365
369
|
summary: {
|
|
366
370
|
summary: "Your summary...",
|
|
371
|
+
// usage: summaryResponse.usage, // Optional; included in session totals
|
|
367
372
|
details: { /* custom data */ },
|
|
368
373
|
}
|
|
369
374
|
};
|
package/docs/custom-provider.md
CHANGED
|
@@ -30,10 +30,38 @@ See these complete provider examples:
|
|
|
30
30
|
|
|
31
31
|
## Quick Reference
|
|
32
32
|
|
|
33
|
+
Extensions can register either a complete pi-ai `Provider` or use the legacy provider-config form. Prefer a complete provider when custom authentication, filtering, refresh, or streaming behavior is required. Pi composes `models.json` overrides above registered native providers.
|
|
34
|
+
|
|
33
35
|
```typescript
|
|
36
|
+
import { createProvider, openAICompletionsApi } from "@earendil-works/pi-ai";
|
|
34
37
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
35
38
|
|
|
36
39
|
export default function (pi: ExtensionAPI) {
|
|
40
|
+
pi.registerProvider(createProvider({
|
|
41
|
+
id: "native-local",
|
|
42
|
+
name: "Native Local",
|
|
43
|
+
baseUrl: "http://localhost:8080/v1",
|
|
44
|
+
auth: {
|
|
45
|
+
apiKey: {
|
|
46
|
+
name: "Local server API key",
|
|
47
|
+
async login(interaction) {
|
|
48
|
+
return {
|
|
49
|
+
type: "api_key",
|
|
50
|
+
key: await interaction.prompt({ type: "secret", message: "API key" })
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
async resolve({ credential }) {
|
|
54
|
+
return credential?.key
|
|
55
|
+
? { auth: { apiKey: credential.key }, source: "stored API key" }
|
|
56
|
+
: undefined;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
models: [],
|
|
61
|
+
api: openAICompletionsApi()
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
// Legacy provider-config form:
|
|
37
65
|
// Override baseUrl for existing provider
|
|
38
66
|
pi.registerProvider("anthropic", {
|
|
39
67
|
baseUrl: "https://proxy.example.com"
|
|
@@ -231,7 +259,7 @@ models: [{
|
|
|
231
259
|
```
|
|
232
260
|
|
|
233
261
|
Use `openrouter` for OpenRouter-style `reasoning: { effort }` controls. Use `together` for Together-style `reasoning: { enabled }` controls; with `supportsReasoningEffort`, it also sends `reasoning_effort`. Use `qwen-chat-template` for local Qwen-compatible servers that read `chat_template_kwargs.enable_thinking` and need `preserve_thinking`.
|
|
234
|
-
Use `cacheControlFormat: "anthropic"` for OpenAI-compatible providers that expose Anthropic-style prompt caching via `cache_control` on the system prompt, last tool definition, and last user
|
|
262
|
+
Use `cacheControlFormat: "anthropic"` for OpenAI-compatible providers that expose Anthropic-style prompt caching via `cache_control` on the system prompt, last tool definition, and last user, assistant, or tool-result text content.
|
|
235
263
|
|
|
236
264
|
For Anthropic-compatible providers using `api: "anthropic-messages"`, set `compat.forceAdaptiveThinking: true` on models or providers whose upstream model requires adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`). Built-in adaptive Claude models set this automatically. Set `compat.allowEmptySignature: true` only for providers that emit empty thinking signatures and expect `signature: ""` on replay.
|
|
237
265
|
|
|
@@ -709,6 +737,8 @@ interface ProviderModelConfig {
|
|
|
709
737
|
supportsDeveloperRole?: boolean;
|
|
710
738
|
supportsReasoningEffort?: boolean;
|
|
711
739
|
supportsUsageInStreaming?: boolean;
|
|
740
|
+
supportsStrictMode?: boolean;
|
|
741
|
+
supportsOpenAIGrammarTools?: boolean; // openai-completions/openai-responses; false falls back to normal function tools
|
|
712
742
|
maxTokensField?: "max_completion_tokens" | "max_tokens";
|
|
713
743
|
requiresToolResultName?: boolean;
|
|
714
744
|
requiresAssistantAfterToolResult?: boolean;
|
|
@@ -727,9 +757,10 @@ interface ProviderModelConfig {
|
|
|
727
757
|
supportsCacheControlOnTools?: boolean;
|
|
728
758
|
forceAdaptiveThinking?: boolean;
|
|
729
759
|
allowEmptySignature?: boolean;
|
|
760
|
+
supportsStrictTools?: boolean;
|
|
730
761
|
};
|
|
731
762
|
}
|
|
732
763
|
```
|
|
733
764
|
|
|
734
765
|
`openrouter` sends `reasoning: { effort }`. `deepseek` sends `thinking: { type: "enabled" | "disabled" }` and `reasoning_effort` when enabled. `together` sends `reasoning: { enabled }` and also `reasoning_effort` when `supportsReasoningEffort` is enabled. `qwen` is for DashScope-style top-level `enable_thinking`. Use `qwen-chat-template` for local Qwen-compatible servers that read `chat_template_kwargs.enable_thinking` and need `preserve_thinking`. Use `chat-template` for configurable `chat_template_kwargs`, for example DeepSeek V3.x behind vLLM with `chatTemplateKwargs: { "thinking": { "$var": "thinking.enabled" } }`.
|
|
735
|
-
`cacheControlFormat: "anthropic"` applies Anthropic-style `cache_control` markers to the system prompt, last tool definition, and last user
|
|
766
|
+
`cacheControlFormat: "anthropic"` applies Anthropic-style `cache_control` markers to the system prompt, last tool definition, and last user, assistant, or tool-result text content.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Environment Variables
|
|
2
|
+
|
|
3
|
+
Pi uses environment variables in three ways:
|
|
4
|
+
|
|
5
|
+
- Variables such as `PI_OFFLINE` configure the Pi process.
|
|
6
|
+
- Pi sets `PI_CODING_AGENT` so child processes can detect that they run inside Pi.
|
|
7
|
+
- Commands run by the LLM-callable bash tool receive `PI_*` variables describing the current session.
|
|
8
|
+
|
|
9
|
+
Provider API-key variables are documented separately in [Providers](providers.md#environment-variables-or-auth-file).
|
|
10
|
+
|
|
11
|
+
## Process Marker
|
|
12
|
+
|
|
13
|
+
The CLI and RPC entry points set `PI_CODING_AGENT=true`. Child processes inherit it and can use it to detect that they run inside Pi. It is not session-specific and is not set automatically when Pi is embedded through the SDK.
|
|
14
|
+
|
|
15
|
+
## Bash Tool Session Environment
|
|
16
|
+
|
|
17
|
+
Commands run by the bash tool receive the current Pi session state:
|
|
18
|
+
|
|
19
|
+
| Variable | Description |
|
|
20
|
+
|----------|-------------|
|
|
21
|
+
| `PI_SESSION_ID` | Current session ID |
|
|
22
|
+
| `PI_SESSION_FILE` | Absolute path to the current session JSONL file; unset for ephemeral sessions |
|
|
23
|
+
| `PI_PROVIDER` | Currently selected model provider |
|
|
24
|
+
| `PI_MODEL` | Currently selected model ID |
|
|
25
|
+
| `PI_REASONING_LEVEL` | Current effective reasoning level: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, or `max` |
|
|
26
|
+
|
|
27
|
+
The values are resolved when each command starts. Switching models or changing the reasoning level therefore affects the next bash command without restarting Pi. `PI_PROVIDER` and `PI_MODEL` identify the selected Pi model, not a different upstream model that a router may choose internally.
|
|
28
|
+
|
|
29
|
+
When asked which model or provider is running, inspect these variables instead of inferring the answer from the system prompt:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
printf '%s/%s\n' "$PI_PROVIDER" "$PI_MODEL"
|
|
33
|
+
printf 'reasoning=%s session=%s\n' "$PI_REASONING_LEVEL" "$PI_SESSION_ID"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The session file can be inspected directly when the session is persistent:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
if [ -n "$PI_SESSION_FILE" ]; then
|
|
40
|
+
tail -n 1 "$PI_SESSION_FILE"
|
|
41
|
+
fi
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
These variables are injected into the LLM-callable bash tool. They are not injected into user-entered `!` or `!!` commands.
|
|
45
|
+
|
|
46
|
+
### Custom Bash Tools
|
|
47
|
+
|
|
48
|
+
Bash tools created with `createBashTool()` expose the session environment by default when registered with Pi. Injection happens before `spawnHook`, so a hook receives the variables in `ctx.env`:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
const bashTool = createBashTool(cwd, {
|
|
52
|
+
spawnHook: (ctx) => ({
|
|
53
|
+
...ctx,
|
|
54
|
+
env: { ...ctx.env, CI: "1" },
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Disable session metadata independently of the spawn hook:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
const bashTool = createBashTool(cwd, {
|
|
63
|
+
exposeSessionEnvironment: false,
|
|
64
|
+
spawnHook: (ctx) => ctx,
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
When disabled, Pi removes inherited values for these variables so nested Pi processes do not expose stale parent-session metadata.
|
|
69
|
+
|
|
70
|
+
## Pi Process Configuration
|
|
71
|
+
|
|
72
|
+
These variables are read by Pi itself:
|
|
73
|
+
|
|
74
|
+
| Variable | Description |
|
|
75
|
+
|----------|-------------|
|
|
76
|
+
| `PI_CODING_AGENT_DIR` | Override the config directory; default is `~/.pi/agent` |
|
|
77
|
+
| `PI_CODING_AGENT_SESSION_DIR` | Override session storage; overridden by `--session-dir` |
|
|
78
|
+
| `PI_PACKAGE_DIR` | Override the package directory, useful for Nix/Guix store paths |
|
|
79
|
+
| `PI_OFFLINE` | Disable startup network operations, including update checks, package updates, and install/update telemetry |
|
|
80
|
+
| `PI_SKIP_VERSION_CHECK` | Disable the `pi.dev` latest-version request |
|
|
81
|
+
| `PI_TELEMETRY` | Override install/update telemetry and provider attribution headers: `1`/`true`/`yes` or `0`/`false`/`no` |
|
|
82
|
+
| `PI_CACHE_RETENTION` | Set to `long` for extended provider prompt caching where supported |
|
|
83
|
+
| `PI_SHARE_VIEWER_URL` | Override the base URL used by `/share` |
|
|
84
|
+
| `PI_HARDWARE_CURSOR` | Set to `1` to show the hardware cursor; see [Terminal setup](terminal-setup.md) |
|
|
85
|
+
| `VISUAL`, `EDITOR` | External editor fallback when `externalEditor` is unset |
|
|
86
|
+
| `HTTP_PROXY`, `HTTPS_PROXY` | Proxy outbound HTTP requests |
|
|
87
|
+
|
|
88
|
+
Provider credentials such as `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, and cloud-provider configuration are listed in [Providers](providers.md#environment-variables-or-auth-file).
|
package/docs/extensions.md
CHANGED
|
@@ -468,6 +468,7 @@ pi.on("session_before_compact", async (event, ctx) => {
|
|
|
468
468
|
summary: "...",
|
|
469
469
|
firstKeptEntryId: preparation.firstKeptEntryId,
|
|
470
470
|
tokensBefore: preparation.tokensBefore,
|
|
471
|
+
// usage: summaryResponse.usage, // Optional; included in session totals
|
|
471
472
|
}
|
|
472
473
|
};
|
|
473
474
|
});
|
|
@@ -489,7 +490,13 @@ pi.on("session_before_tree", async (event, ctx) => {
|
|
|
489
490
|
const { preparation, signal } = event;
|
|
490
491
|
return { cancel: true };
|
|
491
492
|
// OR provide custom summary:
|
|
492
|
-
return {
|
|
493
|
+
return {
|
|
494
|
+
summary: {
|
|
495
|
+
summary: "...",
|
|
496
|
+
// usage: summaryResponse.usage, // Optional; included in session totals
|
|
497
|
+
details: {},
|
|
498
|
+
},
|
|
499
|
+
};
|
|
493
500
|
});
|
|
494
501
|
|
|
495
502
|
pi.on("session_tree", async (event, ctx) => {
|
|
@@ -813,7 +820,7 @@ In parallel tool mode, `tool_result` and `tool_execution_end` may interleave in
|
|
|
813
820
|
`tool_result` handlers chain like middleware:
|
|
814
821
|
- Handlers run in extension load order
|
|
815
822
|
- Each handler sees the latest result after previous handler changes
|
|
816
|
-
- Handlers can return partial patches (`content`, `details`, or `
|
|
823
|
+
- Handlers can return partial patches (`content`, `details`, `isError`, or `usage`); omitted fields keep their current values
|
|
817
824
|
|
|
818
825
|
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.
|
|
819
826
|
|
|
@@ -822,7 +829,7 @@ import { isBashToolResult } from "@earendil-works/pi-coding-agent";
|
|
|
822
829
|
|
|
823
830
|
pi.on("tool_result", async (event, ctx) => {
|
|
824
831
|
// event.toolName, event.toolCallId, event.input
|
|
825
|
-
// event.content, event.details, event.isError
|
|
832
|
+
// event.content, event.details, event.isError, event.usage
|
|
826
833
|
|
|
827
834
|
if (isBashToolResult(event)) {
|
|
828
835
|
// event.details is typed as BashToolDetails
|
|
@@ -835,7 +842,7 @@ pi.on("tool_result", async (event, ctx) => {
|
|
|
835
842
|
});
|
|
836
843
|
|
|
837
844
|
// Modify result:
|
|
838
|
-
return { content: [...], details: {...}, isError: false };
|
|
845
|
+
return { content: [...], details: {...}, isError: false, usage: nestedModelUsage };
|
|
839
846
|
});
|
|
840
847
|
```
|
|
841
848
|
|
|
@@ -975,9 +982,9 @@ ctx.sessionManager.buildContextEntries() // Active branch entries with compac
|
|
|
975
982
|
ctx.sessionManager.getLeafId() // Current leaf entry ID
|
|
976
983
|
```
|
|
977
984
|
|
|
978
|
-
### ctx.modelRegistry / ctx.model
|
|
985
|
+
### ctx.modelRegistry / ctx.model / ctx.thinkingLevel
|
|
979
986
|
|
|
980
|
-
Access to models and API
|
|
987
|
+
Access to models, providers, and resolved authentication. `ctx.modelRegistry.getProvider(id)` returns the effective pi-ai provider, while `getProviderAuth(id)` resolves its current API key, headers, base URL, and provider-scoped environment without requiring a loaded model. `ctx.model` is the active model, and `ctx.thinkingLevel` is its current effective thinking level.
|
|
981
988
|
|
|
982
989
|
### ctx.signal
|
|
983
990
|
|
|
@@ -1679,7 +1686,37 @@ Calls made during the extension factory function are queued and applied once the
|
|
|
1679
1686
|
|
|
1680
1687
|
Dynamic providers can implement `refreshModels`. Pi calls it during model refresh, publishes the returned list synchronously through the provider, and passes the canonical credential/store/network/signal context. The extension decides whether to persist the catalog through `context.store`; live servers such as llama.cpp can ignore it.
|
|
1681
1688
|
|
|
1689
|
+
Extensions that need native provider auth, filtering, refresh, or stream behavior can register a complete `Provider` from `@earendil-works/pi-ai`. The provider becomes the composition base and `models.json` overrides still apply above it.
|
|
1690
|
+
|
|
1682
1691
|
```typescript
|
|
1692
|
+
import { createProvider, openAICompletionsApi } from "@earendil-works/pi-ai";
|
|
1693
|
+
|
|
1694
|
+
const provider = createProvider({
|
|
1695
|
+
id: "local-server",
|
|
1696
|
+
name: "Local Server",
|
|
1697
|
+
baseUrl: "http://localhost:8080/v1",
|
|
1698
|
+
auth: {
|
|
1699
|
+
apiKey: {
|
|
1700
|
+
name: "Local server setup",
|
|
1701
|
+
async login(interaction) {
|
|
1702
|
+
return {
|
|
1703
|
+
type: "api_key",
|
|
1704
|
+
key: await interaction.prompt({ type: "secret", message: "API key" }),
|
|
1705
|
+
};
|
|
1706
|
+
},
|
|
1707
|
+
async resolve({ credential }) {
|
|
1708
|
+
return credential?.key
|
|
1709
|
+
? { auth: { apiKey: credential.key }, source: "stored API key" }
|
|
1710
|
+
: undefined;
|
|
1711
|
+
},
|
|
1712
|
+
},
|
|
1713
|
+
},
|
|
1714
|
+
models: [],
|
|
1715
|
+
api: openAICompletionsApi(),
|
|
1716
|
+
});
|
|
1717
|
+
|
|
1718
|
+
pi.registerProvider(provider);
|
|
1719
|
+
|
|
1683
1720
|
// Register a new provider with custom models
|
|
1684
1721
|
pi.registerProvider("my-proxy", {
|
|
1685
1722
|
name: "My Proxy",
|
|
@@ -1748,7 +1785,9 @@ pi.registerProvider("corporate-ai", {
|
|
|
1748
1785
|
});
|
|
1749
1786
|
```
|
|
1750
1787
|
|
|
1751
|
-
|
|
1788
|
+
The object form accepts a complete pi-ai `Provider`, including native `auth`, `getModels`, `refreshModels`, `filterModels`, `stream`, and `streamSimple` behavior.
|
|
1789
|
+
|
|
1790
|
+
**Legacy config options:**
|
|
1752
1791
|
- `name` - Display name for the provider in UI such as `/login`.
|
|
1753
1792
|
- `baseUrl` - API endpoint URL. Required when defining models.
|
|
1754
1793
|
- `apiKey` - API key literal, environment interpolation (`$ENV_VAR` or `${ENV_VAR}`), or leading `!command`. Required when defining models (unless `oauth` provided). `$$` escapes `$`, and `$!` escapes a literal `!` without triggering command execution.
|
|
@@ -1900,6 +1939,7 @@ pi.registerTool({
|
|
|
1900
1939
|
return {
|
|
1901
1940
|
content: [{ type: "text", text: "Done" }], // Sent to LLM
|
|
1902
1941
|
details: { data: result }, // For rendering & state
|
|
1942
|
+
// usage: nestedModelResponse.usage, // Optional nested LLM usage
|
|
1903
1943
|
// Optional: stop after this tool batch when every finalized tool result
|
|
1904
1944
|
// in the batch also returns terminate: true.
|
|
1905
1945
|
terminate: true,
|
|
@@ -1912,6 +1952,8 @@ pi.registerTool({
|
|
|
1912
1952
|
});
|
|
1913
1953
|
```
|
|
1914
1954
|
|
|
1955
|
+
**Usage accounting:** If a tool makes nested LLM calls, return their combined `Usage` as `usage`. Pi persists it on the tool result and includes it in footer, `/session`, and RPC session totals. `tool_result` handlers can inspect or replace this value.
|
|
1956
|
+
|
|
1915
1957
|
**Signaling errors:** To mark a tool execution as failed (sets `isError: true` on the result and reports it to the LLM), throw an error from `execute`. Returning a value never sets the error flag regardless of what properties you include in the return object.
|
|
1916
1958
|
|
|
1917
1959
|
**Early termination:** Return `terminate: true` from `execute()` to hint that the automatic follow-up LLM call should be skipped after the current tool batch. This only takes effect when every finalized tool result in that batch is terminating. See [examples/extensions/structured-output.ts](../examples/extensions/structured-output.ts) for a minimal example where the agent ends on a final structured-output tool call.
|
|
@@ -2054,7 +2096,15 @@ const bashTool = createBashTool(cwd, {
|
|
|
2054
2096
|
});
|
|
2055
2097
|
```
|
|
2056
2098
|
|
|
2057
|
-
|
|
2099
|
+
`createBashTool()` exposes the current session to commands through `PI_SESSION_ID`, `PI_SESSION_FILE`, `PI_PROVIDER`, `PI_MODEL`, and `PI_REASONING_LEVEL`. Injection happens before `spawnHook`, so hooks receive these values in `env` and preserve them when they spread the existing environment as above. Set `exposeSessionEnvironment: false` to disable them:
|
|
2100
|
+
|
|
2101
|
+
```typescript
|
|
2102
|
+
const bashTool = createBashTool(cwd, {
|
|
2103
|
+
exposeSessionEnvironment: false,
|
|
2104
|
+
});
|
|
2105
|
+
```
|
|
2106
|
+
|
|
2107
|
+
See [Bash tool session environment](environment-variables.md#bash-tool-session-environment) for variable semantics. See [examples/extensions/ssh.ts](../examples/extensions/ssh.ts) for a complete SSH example with `--ssh` flag.
|
|
2058
2108
|
|
|
2059
2109
|
### Output Truncation
|
|
2060
2110
|
|
|
@@ -2708,8 +2758,8 @@ class VimEditor extends CustomEditor {
|
|
|
2708
2758
|
|
|
2709
2759
|
export default function (pi: ExtensionAPI) {
|
|
2710
2760
|
pi.on("session_start", (_event, ctx) => {
|
|
2711
|
-
ctx.ui.setEditorComponent((
|
|
2712
|
-
new VimEditor(theme, keybindings)
|
|
2761
|
+
ctx.ui.setEditorComponent((tui, theme, keybindings) =>
|
|
2762
|
+
new VimEditor(tui, theme, keybindings)
|
|
2713
2763
|
);
|
|
2714
2764
|
});
|
|
2715
2765
|
}
|
|
@@ -2718,7 +2768,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
2718
2768
|
**Key points:**
|
|
2719
2769
|
- Extend `CustomEditor` (not base `Editor`) to get app keybindings (escape to abort, ctrl+d, model switching)
|
|
2720
2770
|
- Call `super.handleInput(data)` for keys you don't handle
|
|
2721
|
-
- Factory receives `theme
|
|
2771
|
+
- Factory receives `tui`, `theme`, and `keybindings` from the app
|
|
2722
2772
|
- Use `ctx.ui.getEditorComponent()` before `setEditorComponent()` to wrap the previously configured custom editor
|
|
2723
2773
|
- Pass `undefined` to restore default: `ctx.ui.setEditorComponent(undefined)`
|
|
2724
2774
|
|
package/docs/index.md
CHANGED
|
@@ -41,6 +41,7 @@ For the full first-run flow, see [Quickstart](quickstart.md).
|
|
|
41
41
|
- [Quickstart](quickstart.md) - install, authenticate, and run a first session.
|
|
42
42
|
- [Using Pi](usage.md) - interactive mode, slash commands, context files, and CLI reference.
|
|
43
43
|
- [Providers](providers.md) - subscription and API-key setup for built-in providers.
|
|
44
|
+
- [llama.cpp](llama-cpp.md) - run a local router and manage models with `/llama`.
|
|
44
45
|
- [Security](security.md) - project trust, sandbox boundaries, and vulnerability reporting.
|
|
45
46
|
- [Containerization](containerization.md) - sandbox pi with Gondolin, Docker, or OpenShell.
|
|
46
47
|
- [Settings](settings.md) - global and project settings.
|
|
@@ -67,6 +68,7 @@ For the full first-run flow, see [Quickstart](quickstart.md).
|
|
|
67
68
|
|
|
68
69
|
## Reference
|
|
69
70
|
|
|
71
|
+
- [Environment variables](environment-variables.md) - Pi process configuration and session metadata available to bash tools.
|
|
70
72
|
- [Session format](session-format.md) - JSONL session file format, entry types, and SessionManager API.
|
|
71
73
|
|
|
72
74
|
## Platform setup
|
package/docs/json.md
CHANGED
|
@@ -17,7 +17,11 @@ type AgentSessionEvent =
|
|
|
17
17
|
| { type: "compaction_start"; reason: "manual" | "threshold" | "overflow" }
|
|
18
18
|
| { type: "compaction_end"; reason: "manual" | "threshold" | "overflow"; result: CompactionResult | undefined; aborted: boolean; willRetry: boolean; errorMessage?: string }
|
|
19
19
|
| { type: "auto_retry_start"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }
|
|
20
|
-
| { type: "auto_retry_end"; success: boolean; attempt: number; finalError?: string }
|
|
20
|
+
| { type: "auto_retry_end"; success: boolean; attempt: number; finalError?: string }
|
|
21
|
+
| { type: "summarization_retry_scheduled"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }
|
|
22
|
+
| { type: "summarization_retry_attempt_start"; source: "branchSummary" }
|
|
23
|
+
| { type: "summarization_retry_attempt_start"; source: "compaction"; reason: "manual" | "threshold" | "overflow" }
|
|
24
|
+
| { type: "summarization_retry_finished" };
|
|
21
25
|
```
|
|
22
26
|
|
|
23
27
|
`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.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# llama.cpp
|
|
2
|
+
|
|
3
|
+
Pi supports the [llama.cpp](https://github.com/ggml-org/llama.cpp) router server. The router discovers multiple GGUF models and loads or unloads them on demand.
|
|
4
|
+
|
|
5
|
+
Use a current llama.cpp build with router support. Follow the [build instructions](https://github.com/ggml-org/llama.cpp/blob/master/docs/build.md) or install a [prebuilt release](https://github.com/ggml-org/llama.cpp/releases) for your platform.
|
|
6
|
+
|
|
7
|
+
## Start the router
|
|
8
|
+
|
|
9
|
+
Start `llama-server` without `--model` or `-m`. Passing a model starts single-model mode instead of router mode.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
llama-server \
|
|
13
|
+
--models-dir ~/models \
|
|
14
|
+
--no-models-autoload \
|
|
15
|
+
--jinja \
|
|
16
|
+
--host 127.0.0.1 \
|
|
17
|
+
--port 8080 \
|
|
18
|
+
-ngl 999 \
|
|
19
|
+
-c 32768
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Important options:
|
|
23
|
+
|
|
24
|
+
- `--models-dir ~/models` discovers local GGUF files.
|
|
25
|
+
- `--no-models-autoload` keeps loading explicit through `/llama`.
|
|
26
|
+
- `--jinja` enables compatible chat templates and tool calling.
|
|
27
|
+
- `-ngl 999` offloads as many layers as possible to the GPU.
|
|
28
|
+
- `-c 32768` sets the context window for each loaded model. Omit it to use the model's native context, which may require substantially more memory.
|
|
29
|
+
|
|
30
|
+
A single-file model can sit directly in the model directory. Put multimodal and multi-shard models in separate subdirectories:
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
~/models/
|
|
34
|
+
├── llama-3.2-1b-Q4_K_M.gguf
|
|
35
|
+
├── gemma-3-4b-it-Q4_K_M/
|
|
36
|
+
│ ├── gemma-3-4b-it-Q4_K_M.gguf
|
|
37
|
+
│ └── mmproj-F16.gguf
|
|
38
|
+
└── large-model-Q4_K_M/
|
|
39
|
+
├── large-model-Q4_K_M-00001-of-00003.gguf
|
|
40
|
+
├── large-model-Q4_K_M-00002-of-00003.gguf
|
|
41
|
+
└── large-model-Q4_K_M-00003-of-00003.gguf
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Restart the router after manually adding files. For per-model context sizes and other options, use [llama.cpp model presets](https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md#model-presets).
|
|
45
|
+
|
|
46
|
+
## Configure Pi
|
|
47
|
+
|
|
48
|
+
Start Pi and configure the provider:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
/login llama.cpp
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Enter the router URL and optional API key. The default URL is `http://127.0.0.1:8080`.
|
|
55
|
+
|
|
56
|
+
Environment variables can configure the same values without `/login`:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
export LLAMA_BASE_URL=http://127.0.0.1:8080
|
|
60
|
+
export LLAMA_API_KEY=optional-secret
|
|
61
|
+
pi
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
If the server uses an API key, start `llama-server` with the matching `--api-key` value. Keep `--host 127.0.0.1` for local-only access.
|
|
65
|
+
|
|
66
|
+
## Manage models
|
|
67
|
+
|
|
68
|
+
Run:
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
/llama
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- Select an unloaded model to load it.
|
|
75
|
+
- Select a loaded model to unload it.
|
|
76
|
+
- Select **Download model…**, search Hugging Face, then choose a repository and quantization. Exact `owner/repository[:quant]` values also work.
|
|
77
|
+
- Press Escape during a load or download to confirm cancellation.
|
|
78
|
+
|
|
79
|
+
Hugging Face search uses `HF_TOKEN` when set, then checks `$HF_TOKEN_PATH`, `$HF_HOME/token`, `$XDG_CACHE_HOME/huggingface/token`, and `~/.cache/huggingface/token`. Search also works without authentication, subject to lower rate limits. Pi warns before downloading gated repositories and links to their access page. The llama.cpp server performs the download, so its process must also have `HF_TOKEN` when the selected repository requires access.
|
|
80
|
+
|
|
81
|
+
If other models are loaded, Pi asks whether to unload them first or keep them loaded. Pi does not silently unload models and never deletes model files. The router may be shared with other clients, so `/llama` always displays the router's current state.
|
|
82
|
+
|
|
83
|
+
Only loaded models appear in `/model`. After loading a model, run `/model` to select it for the current Pi session.
|
|
84
|
+
|
|
85
|
+
If the router disconnects, `/llama` shows **Retry** and **Close**. Retry reconnects and refreshes model state without replaying the interrupted operation.
|
|
86
|
+
|
|
87
|
+
## Troubleshooting
|
|
88
|
+
|
|
89
|
+
Check that the router is reachable:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
curl http://127.0.0.1:8080/health
|
|
93
|
+
curl http://127.0.0.1:8080/models
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
- **No models in `/llama`:** Check `--models-dir`, the directory layout, and restart the router.
|
|
97
|
+
- **Model missing from `/model`:** Load it with `/llama` first.
|
|
98
|
+
- **Load fails or uses too much memory:** Lower `-c` or unload another model.
|
|
99
|
+
- **Server is not in router mode:** Start it without `--model`, `-m`, or `-hf`.
|
package/docs/models.md
CHANGED
|
@@ -375,6 +375,8 @@ Some Anthropic models require adaptive thinking (`thinking.type: "adaptive"` plu
|
|
|
375
375
|
|
|
376
376
|
Some Anthropic-compatible providers emit thinking blocks with empty signatures and still expect them on replay. Set `allowEmptySignature` to `true` only for those providers; real Anthropic rejects empty thinking signatures.
|
|
377
377
|
|
|
378
|
+
Built-in Anthropic models enable `supportsStrictTools` in their model metadata. Custom Anthropic-compatible models must set it to `true` when their endpoint accepts strict JSON-schema tool definitions.
|
|
379
|
+
|
|
378
380
|
```json
|
|
379
381
|
{
|
|
380
382
|
"providers": {
|
|
@@ -408,6 +410,7 @@ Some Anthropic-compatible providers emit thinking blocks with empty signatures a
|
|
|
408
410
|
| `supportsCacheControlOnTools` | Whether the provider accepts Anthropic-style `cache_control` markers on tool definitions. Default: `true`. |
|
|
409
411
|
| `forceAdaptiveThinking` | Whether to send adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`) for this model. Built-in adaptive models set this automatically. Default: `false`. |
|
|
410
412
|
| `allowEmptySignature` | Whether to replay empty thinking signatures as `signature: ""` instead of converting thinking to text. Default: `false`. |
|
|
413
|
+
| `supportsStrictTools` | Whether the provider accepts strict JSON-schema tool definitions. Default: `false`; built-in Anthropic models enable it in generated metadata. |
|
|
411
414
|
|
|
412
415
|
## OpenAI Compatibility
|
|
413
416
|
|
|
@@ -445,10 +448,11 @@ For providers with partial OpenAI compatibility, use the `compat` field.
|
|
|
445
448
|
| `requiresReasoningContentOnAssistantMessages` | Include empty `reasoning_content` on all replayed assistant messages when reasoning is enabled |
|
|
446
449
|
| `thinkingFormat` | Use `reasoning_effort`, `openrouter`, `deepseek`, `together`, `zai`, `qwen`, `chat-template`, or `qwen-chat-template` thinking parameters |
|
|
447
450
|
| `chatTemplateKwargs` | `chat_template_kwargs` values for `thinkingFormat: "chat-template"`; use `{ "$var": "thinking.enabled" }` or `{ "$var": "thinking.effort" }` for pi-controlled thinking values |
|
|
448
|
-
| `cacheControlFormat` | Use Anthropic-style `cache_control` markers on the system prompt, last tool definition, and last user
|
|
451
|
+
| `cacheControlFormat` | Use Anthropic-style `cache_control` markers on the system prompt, last tool definition, and last user, assistant, or tool-result text content. Currently only `anthropic` is supported. |
|
|
449
452
|
| `sendSessionAffinityHeaders` | For `openai-completions`, send session-affinity headers from the session id when caching is enabled. Default: `false`. |
|
|
450
453
|
| `sessionAffinityFormat` | For `openai-completions` and `openai-responses`, the session-affinity header format: `openai` sends `session_id`/`x-client-request-id` (completions also `x-session-affinity`), `openai-nosession` omits the underscore-containing `session_id` header, `openrouter` sends `x-session-id`. Does not affect the `prompt_cache_key` body param. Default: auto-detected. |
|
|
451
|
-
| `supportsStrictMode` |
|
|
454
|
+
| `supportsStrictMode` | Whether the provider accepts strict JSON-schema function tool definitions. Defaults depend on the API; built-in OpenAI models carry explicit capability metadata. |
|
|
455
|
+
| `supportsOpenAIGrammarTools` | Whether OpenAI-compatible APIs emit custom Lark/regex grammar tools. When `false`, grammar-constrained tools fall back to normal function tools. Default: `false`; the built-in model catalog enables it for GPT-5+ models on OpenAI, OpenAI Codex, Azure OpenAI, GitHub Copilot, opencode, and Cloudflare AI Gateway. |
|
|
452
456
|
| `deferredToolsMode` | Use provider-specific deferred tool serialization. Currently only `"kimi"` is supported for Kimi's OpenAI-compatible Chat Completions format. |
|
|
453
457
|
| `supportsLongCacheRetention` | Whether the provider accepts long cache retention when cache retention is `long`: `prompt_cache_retention: "24h"` for OpenAI prompt caching, or `cache_control.ttl: "1h"` when `cacheControlFormat` is `anthropic`. Default: `true`. |
|
|
454
458
|
| `openRouterRouting` | OpenRouter provider routing preferences. This object is sent as-is in the `provider` field of the [OpenRouter API request](https://openrouter.ai/docs/guides/routing/provider-selection). |
|
package/docs/prompt-templates.md
CHANGED
|
@@ -69,6 +69,7 @@ Templates support positional arguments, defaults, and simple slicing:
|
|
|
69
69
|
- `$1`, `$2`, ... positional args
|
|
70
70
|
- `$@` or `$ARGUMENTS` for all args joined
|
|
71
71
|
- `${1:-default}` uses arg 1 when present/non-empty, otherwise `default`
|
|
72
|
+
- `${@:-default}` or `${ARGUMENTS:-default}` uses all arguments when present/non-empty, otherwise `default`
|
|
72
73
|
- `${@:N}` for args from the Nth position (1-indexed)
|
|
73
74
|
- `${@:N:L}` for `L` args starting at N
|
|
74
75
|
|
package/docs/providers.md
CHANGED
|
@@ -8,6 +8,7 @@ Pi supports subscription-based providers via OAuth and API key providers via env
|
|
|
8
8
|
- [API Keys](#api-keys)
|
|
9
9
|
- [Auth File](#auth-file)
|
|
10
10
|
- [Cloud Providers](#cloud-providers)
|
|
11
|
+
- [llama.cpp](#llamacpp)
|
|
11
12
|
- [Custom Providers](#custom-providers)
|
|
12
13
|
- [Resolution Order](#resolution-order)
|
|
13
14
|
|
|
@@ -19,9 +20,10 @@ Use `/login` in interactive mode, then select a provider:
|
|
|
19
20
|
- Claude Pro/Max
|
|
20
21
|
- GitHub Copilot
|
|
21
22
|
- xAI (Grok/X subscription)
|
|
23
|
+
- OpenRouter (OAuth-minted API key billed from OpenRouter credits)
|
|
22
24
|
- Radius
|
|
23
25
|
|
|
24
|
-
Use `/logout` to clear credentials. Tokens are stored in `~/.pi/agent/auth.json` and auto-refresh when expired.
|
|
26
|
+
Use `/logout` to clear credentials. Tokens are stored in `~/.pi/agent/auth.json` and auto-refresh when expired. OpenRouter instead mints a user-controlled API key that does not expire automatically.
|
|
25
27
|
|
|
26
28
|
### OpenAI Codex
|
|
27
29
|
|
|
@@ -42,6 +44,12 @@ Anthropic subscription auth is active for Claude Pro/Max accounts. Third-party h
|
|
|
42
44
|
- Run `/login xai`, then select **Use a subscription**
|
|
43
45
|
- `XAI_API_KEY` remains available through **Use an API key**
|
|
44
46
|
|
|
47
|
+
### OpenRouter
|
|
48
|
+
|
|
49
|
+
- Run `/login openrouter`, then select **Sign in with OpenRouter** to open the OpenRouter PKCE authorization flow
|
|
50
|
+
- The authorization creates a user-controlled OpenRouter API key billed from your OpenRouter credits
|
|
51
|
+
- `OPENROUTER_API_KEY` remains available through **Use an API key**
|
|
52
|
+
|
|
45
53
|
### Radius
|
|
46
54
|
|
|
47
55
|
Radius is a dynamic `pi-messages` gateway. `/login radius` stores OAuth tokens in `auth.json`; the gateway catalog is refreshed independently and cached in `models-store.json`. Custom Radius gateways can be declared in `models.json` with `"oauth": "radius"` and a gateway `baseUrl`.
|
|
@@ -86,6 +94,8 @@ pi
|
|
|
86
94
|
| Kimi For Coding | `KIMI_API_KEY` | `kimi-coding` |
|
|
87
95
|
| MiniMax | `MINIMAX_API_KEY` | `minimax` |
|
|
88
96
|
| MiniMax (China) | `MINIMAX_CN_API_KEY` | `minimax-cn` |
|
|
97
|
+
| Qwen Token Plan | `QWEN_TOKEN_PLAN_API_KEY` | `qwen-token-plan` |
|
|
98
|
+
| Qwen Token Plan (China) | `QWEN_TOKEN_PLAN_CN_API_KEY` | `qwen-token-plan-cn` |
|
|
89
99
|
| Xiaomi MiMo | `XIAOMI_API_KEY` | `xiaomi` |
|
|
90
100
|
| Xiaomi MiMo Token Plan (China) | `XIAOMI_TOKEN_PLAN_CN_API_KEY` | `xiaomi-token-plan-cn` |
|
|
91
101
|
| Xiaomi MiMo Token Plan (Amsterdam) | `XIAOMI_TOKEN_PLAN_AMS_API_KEY` | `xiaomi-token-plan-ams` |
|
|
@@ -108,6 +118,8 @@ Store credentials in `~/.pi/agent/auth.json`:
|
|
|
108
118
|
"opencode": { "type": "api_key", "key": "..." },
|
|
109
119
|
"opencode-go": { "type": "api_key", "key": "..." },
|
|
110
120
|
"together": { "type": "api_key", "key": "..." },
|
|
121
|
+
"qwen-token-plan": { "type": "api_key", "key": "sk-sp-..." },
|
|
122
|
+
"qwen-token-plan-cn": { "type": "api_key", "key": "sk-sp-..." },
|
|
111
123
|
"xiaomi": { "type": "api_key", "key": "..." },
|
|
112
124
|
"xiaomi-token-plan-cn": { "type": "api_key", "key": "..." },
|
|
113
125
|
"xiaomi-token-plan-ams": { "type": "api_key", "key": "..." },
|
|
@@ -274,6 +286,12 @@ export GOOGLE_CLOUD_LOCATION=us-central1
|
|
|
274
286
|
|
|
275
287
|
Or set `GOOGLE_APPLICATION_CREDENTIALS` to a service account key file.
|
|
276
288
|
|
|
289
|
+
## llama.cpp
|
|
290
|
+
|
|
291
|
+
Pi supports the llama.cpp router server. Configure it with `/login llama.cpp`, manage loaded models with `/llama`, and select a loaded model with `/model`.
|
|
292
|
+
|
|
293
|
+
See [llama.cpp](llama-cpp.md) for server setup, model directory layout, environment variables, and command usage.
|
|
294
|
+
|
|
277
295
|
## Custom Providers
|
|
278
296
|
|
|
279
297
|
**Via models.json:** Add Ollama, LM Studio, vLLM, or any provider that speaks a supported API (OpenAI Completions, OpenAI Responses, Anthropic Messages, Google Generative AI). See [models.md](models.md).
|