@earendil-works/pi-coding-agent 0.74.0 → 0.74.2

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.
Files changed (146) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +8 -6
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +1 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +10 -2
  8. package/dist/cli.js.map +1 -1
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/config.js +23 -20
  11. package/dist/config.js.map +1 -1
  12. package/dist/core/agent-session.d.ts.map +1 -1
  13. package/dist/core/agent-session.js +2 -2
  14. package/dist/core/agent-session.js.map +1 -1
  15. package/dist/core/bash-executor.d.ts.map +1 -1
  16. package/dist/core/bash-executor.js +1 -1
  17. package/dist/core/bash-executor.js.map +1 -1
  18. package/dist/core/compaction/compaction.d.ts.map +1 -1
  19. package/dist/core/compaction/compaction.js +2 -2
  20. package/dist/core/compaction/compaction.js.map +1 -1
  21. package/dist/core/model-registry.d.ts.map +1 -1
  22. package/dist/core/model-registry.js +1 -0
  23. package/dist/core/model-registry.js.map +1 -1
  24. package/dist/core/model-resolver.d.ts.map +1 -1
  25. package/dist/core/model-resolver.js +1 -0
  26. package/dist/core/model-resolver.js.map +1 -1
  27. package/dist/core/package-manager.d.ts +1 -0
  28. package/dist/core/package-manager.d.ts.map +1 -1
  29. package/dist/core/package-manager.js +45 -7
  30. package/dist/core/package-manager.js.map +1 -1
  31. package/dist/core/prompt-templates.d.ts.map +1 -1
  32. package/dist/core/prompt-templates.js +6 -4
  33. package/dist/core/prompt-templates.js.map +1 -1
  34. package/dist/core/provider-display-names.d.ts.map +1 -1
  35. package/dist/core/provider-display-names.js +1 -0
  36. package/dist/core/provider-display-names.js.map +1 -1
  37. package/dist/core/sdk.d.ts +1 -1
  38. package/dist/core/sdk.d.ts.map +1 -1
  39. package/dist/core/sdk.js +1 -1
  40. package/dist/core/sdk.js.map +1 -1
  41. package/dist/core/session-manager.d.ts +1 -1
  42. package/dist/core/session-manager.d.ts.map +1 -1
  43. package/dist/core/session-manager.js +39 -9
  44. package/dist/core/session-manager.js.map +1 -1
  45. package/dist/core/skills.d.ts.map +1 -1
  46. package/dist/core/skills.js +2 -5
  47. package/dist/core/skills.js.map +1 -1
  48. package/dist/core/tools/read.d.ts.map +1 -1
  49. package/dist/core/tools/read.js +2 -1
  50. package/dist/core/tools/read.js.map +1 -1
  51. package/dist/core/tools/render-utils.d.ts.map +1 -1
  52. package/dist/core/tools/render-utils.js +1 -1
  53. package/dist/core/tools/render-utils.js.map +1 -1
  54. package/dist/main.d.ts.map +1 -1
  55. package/dist/main.js +0 -10
  56. package/dist/main.js.map +1 -1
  57. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  58. package/dist/modes/interactive/components/bash-execution.js +1 -1
  59. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  60. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  61. package/dist/modes/interactive/components/config-selector.js +23 -1
  62. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  63. package/dist/modes/interactive/components/extension-selector.d.ts +2 -0
  64. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  65. package/dist/modes/interactive/components/extension-selector.js +6 -1
  66. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  67. package/dist/modes/interactive/components/keybinding-hints.d.ts +5 -0
  68. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  69. package/dist/modes/interactive/components/keybinding-hints.js +19 -5
  70. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  71. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  72. package/dist/modes/interactive/components/settings-selector.js +3 -1
  73. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  74. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  75. package/dist/modes/interactive/components/tree-selector.js +2 -1
  76. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  77. package/dist/modes/interactive/interactive-mode.d.ts +12 -4
  78. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  79. package/dist/modes/interactive/interactive-mode.js +74 -30
  80. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  81. package/dist/modes/interactive/theme/dark.json +1 -1
  82. package/dist/modes/interactive/theme/light.json +1 -1
  83. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  84. package/dist/modes/interactive/theme/theme.js +3 -1
  85. package/dist/modes/interactive/theme/theme.js.map +1 -1
  86. package/dist/package-manager-cli.d.ts.map +1 -1
  87. package/dist/package-manager-cli.js +6 -1
  88. package/dist/package-manager-cli.js.map +1 -1
  89. package/dist/utils/ansi.d.ts +2 -0
  90. package/dist/utils/ansi.d.ts.map +1 -0
  91. package/dist/utils/ansi.js +52 -0
  92. package/dist/utils/ansi.js.map +1 -0
  93. package/dist/utils/html.d.ts +7 -0
  94. package/dist/utils/html.d.ts.map +1 -0
  95. package/dist/utils/html.js +40 -0
  96. package/dist/utils/html.js.map +1 -0
  97. package/dist/utils/mime.d.ts +1 -0
  98. package/dist/utils/mime.d.ts.map +1 -1
  99. package/dist/utils/mime.js +59 -16
  100. package/dist/utils/mime.js.map +1 -1
  101. package/dist/utils/paths.d.ts +2 -0
  102. package/dist/utils/paths.d.ts.map +1 -1
  103. package/dist/utils/paths.js +16 -0
  104. package/dist/utils/paths.js.map +1 -1
  105. package/dist/utils/syntax-highlight.d.ts +12 -0
  106. package/dist/utils/syntax-highlight.d.ts.map +1 -0
  107. package/dist/utils/syntax-highlight.js +118 -0
  108. package/dist/utils/syntax-highlight.js.map +1 -0
  109. package/dist/utils/tools-manager.d.ts.map +1 -1
  110. package/dist/utils/tools-manager.js +80 -8
  111. package/dist/utils/tools-manager.js.map +1 -1
  112. package/dist/utils/version-check.d.ts +4 -0
  113. package/dist/utils/version-check.d.ts.map +1 -1
  114. package/dist/utils/version-check.js +14 -0
  115. package/dist/utils/version-check.js.map +1 -1
  116. package/docs/custom-provider.md +58 -3
  117. package/docs/extensions.md +1 -1
  118. package/docs/index.md +7 -1
  119. package/docs/models.md +2 -2
  120. package/docs/providers.md +2 -0
  121. package/docs/sdk.md +24 -44
  122. package/docs/skills.md +3 -4
  123. package/docs/termux.md +3 -3
  124. package/docs/themes.md +2 -2
  125. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  126. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  127. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  128. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  129. package/examples/extensions/sandbox/package-lock.json +2 -2
  130. package/examples/extensions/sandbox/package.json +1 -1
  131. package/examples/extensions/with-deps/package-lock.json +2 -2
  132. package/examples/extensions/with-deps/package.json +1 -1
  133. package/examples/sdk/01-minimal.ts +14 -10
  134. package/examples/sdk/02-custom-model.ts +12 -8
  135. package/examples/sdk/03-custom-prompt.ts +24 -16
  136. package/examples/sdk/04-skills.ts +2 -2
  137. package/examples/sdk/05-tools.ts +8 -4
  138. package/examples/sdk/06-extensions.ts +11 -7
  139. package/examples/sdk/07-context-files.ts +2 -2
  140. package/examples/sdk/08-prompt-templates.ts +2 -2
  141. package/examples/sdk/09-api-keys-and-oauth.ts +8 -4
  142. package/examples/sdk/10-settings.ts +4 -4
  143. package/examples/sdk/11-sessions.ts +4 -0
  144. package/examples/sdk/12-full-control.ts +11 -7
  145. package/examples/sdk/README.md +5 -8
  146. package/package.json +6 -11
@@ -23,6 +23,7 @@ See these complete provider examples:
23
23
  - [Unregister Provider](#unregister-provider)
24
24
  - [OAuth Support](#oauth-support)
25
25
  - [Custom Streaming API](#custom-streaming-api)
26
+ - [Context Overflow Errors](#context-overflow-errors)
26
27
  - [Testing Your Implementation](#testing-your-implementation)
27
28
  - [Config Reference](#config-reference)
28
29
  - [Model Definition Reference](#model-definition-reference)
@@ -226,7 +227,7 @@ models: [{
226
227
  }]
227
228
  ```
228
229
 
229
- Use `qwen-chat-template` instead for local Qwen-compatible servers that read `chat_template_kwargs.enable_thinking`.
230
+ 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` instead for local Qwen-compatible servers that read `chat_template_kwargs.enable_thinking`.
230
231
  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 text content.
231
232
 
232
233
  > Migration note: Mistral moved from `openai-completions` to `mistral-conversations`.
@@ -506,6 +507,60 @@ output.usage.totalTokens = output.usage.input + output.usage.output +
506
507
  calculateCost(model, output.usage);
507
508
  ```
508
509
 
510
+ ### Context Overflow Errors
511
+
512
+ When a request exceeds the model's context window, pi can recover automatically by compacting the conversation and retrying. This recovery only kicks in if pi recognizes the failure as an overflow.
513
+
514
+ Detection runs on the finalized assistant message:
515
+
516
+ - `stopReason === "error"`
517
+ - `errorMessage` matches one of pi's known overflow patterns (see [`packages/ai/src/utils/overflow.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/utils/overflow.ts))
518
+
519
+ If your provider returns overflow errors with a message pi does not recognize, normalize the error from the same extension that registers the provider. Use a `message_end` handler to rewrite the assistant message so its `errorMessage` starts with a phrase pi recognizes. The generic fallback `context_length_exceeded` is the safest choice.
520
+
521
+ ```typescript
522
+ const MY_PROVIDER_OVERFLOW_PATTERN = /your provider's overflow phrase/i;
523
+
524
+ export default function (pi: ExtensionAPI) {
525
+ pi.registerProvider("my-provider", { /* ... */ });
526
+
527
+ pi.on("message_end", (event, ctx) => {
528
+ const message = event.message;
529
+ if (message.role !== "assistant") return;
530
+ if (message.stopReason !== "error") return;
531
+ if (
532
+ message.provider !== "my-provider" &&
533
+ ctx.model?.provider !== "my-provider"
534
+ )
535
+ return;
536
+
537
+ const errorMessage = message.errorMessage ?? "";
538
+ if (errorMessage.includes("context_length_exceeded")) return;
539
+ if (!MY_PROVIDER_OVERFLOW_PATTERN.test(errorMessage)) return;
540
+
541
+ return {
542
+ message: {
543
+ ...message,
544
+ errorMessage: `context_length_exceeded: ${errorMessage}`,
545
+ },
546
+ };
547
+ });
548
+ }
549
+ ```
550
+
551
+ `message_end` runs before pi tracks the assistant message for auto-compaction, so the rewritten `errorMessage` is what pi checks. With this in place, pi will:
552
+
553
+ 1. Detect the overflow from `errorMessage`.
554
+ 2. Drop the failed assistant message from live context.
555
+ 3. Run compaction.
556
+ 4. Retry the request once.
557
+
558
+ Guard the rewrite carefully:
559
+
560
+ - Scope it to your provider (`message.provider` and `ctx.model?.provider`) so unrelated errors from other providers are untouched.
561
+ - Match a provider-specific pattern, not pi's generic overflow patterns. Rewriting rate-limit or throttling errors (`rate limit`, `too many requests`) would falsely trigger compaction instead of pi's normal retry-with-backoff path.
562
+ - Skip when `errorMessage` already includes `context_length_exceeded` so the handler is idempotent.
563
+
509
564
  ### Registration
510
565
 
511
566
  Register your stream function:
@@ -636,11 +691,11 @@ interface ProviderModelConfig {
636
691
  requiresAssistantAfterToolResult?: boolean;
637
692
  requiresThinkingAsText?: boolean;
638
693
  requiresReasoningContentOnAssistantMessages?: boolean;
639
- thinkingFormat?: "openai" | "deepseek" | "zai" | "qwen" | "qwen-chat-template";
694
+ thinkingFormat?: "openai" | "openrouter" | "deepseek" | "together" | "zai" | "qwen" | "qwen-chat-template";
640
695
  cacheControlFormat?: "anthropic";
641
696
  };
642
697
  }
643
698
  ```
644
699
 
645
- `deepseek` sends `thinking: { type: "enabled" | "disabled" }` and `reasoning_effort` when 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`.
700
+ `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`.
646
701
  `cacheControlFormat: "anthropic"` applies Anthropic-style `cache_control` markers to the system prompt, last tool definition, and last user/assistant text content.
@@ -162,7 +162,7 @@ export default function (pi: ExtensionAPI) {
162
162
  pi.on("event_name", async (event, ctx) => {
163
163
  // ctx.ui for user interaction
164
164
  const ok = await ctx.ui.confirm("Title", "Are you sure?");
165
- ctx.ui.notify("Done!", "success");
165
+ ctx.ui.notify("Done!", "info");
166
166
  ctx.ui.setStatus("my-ext", "Processing..."); // Footer status
167
167
  ctx.ui.setWidget("my-ext", ["Line 1", "Line 2"]); // Widget above editor (default)
168
168
  });
package/docs/index.md CHANGED
@@ -4,7 +4,13 @@ Pi is a minimal terminal coding harness. It is designed to stay small at the cor
4
4
 
5
5
  ## Quick start
6
6
 
7
- Install pi with npm:
7
+ On linux or mac you can install Pi with curl:
8
+
9
+ ```bash
10
+ curl -fsSL https://pi.dev/install.sh | sh
11
+ ```
12
+
13
+ Or alternatively with npm:
8
14
 
9
15
  ```bash
10
16
  npm install -g @earendil-works/pi-coding-agent
package/docs/models.md CHANGED
@@ -381,14 +381,14 @@ For providers with partial OpenAI compatibility, use the `compat` field.
381
381
  | `requiresAssistantAfterToolResult` | Insert an assistant message before a user message after tool results |
382
382
  | `requiresThinkingAsText` | Convert thinking blocks to plain text |
383
383
  | `requiresReasoningContentOnAssistantMessages` | Include empty `reasoning_content` on all replayed assistant messages when reasoning is enabled |
384
- | `thinkingFormat` | Use `reasoning_effort`, `deepseek`, `zai`, `qwen`, or `qwen-chat-template` thinking parameters |
384
+ | `thinkingFormat` | Use `reasoning_effort`, `openrouter`, `deepseek`, `together`, `zai`, `qwen`, or `qwen-chat-template` thinking parameters |
385
385
  | `cacheControlFormat` | Use Anthropic-style `cache_control` markers on the system prompt, last tool definition, and last user/assistant text content. Currently only `anthropic` is supported. |
386
386
  | `supportsStrictMode` | Include the `strict` field in tool definitions |
387
387
  | `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`. |
388
388
  | `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). |
389
389
  | `vercelGatewayRouting` | Vercel AI Gateway routing config for provider selection (`only`, `order`) |
390
390
 
391
- `qwen` uses top-level `enable_thinking`. Use `qwen-chat-template` for local Qwen-compatible servers that require `chat_template_kwargs.enable_thinking`.
391
+ `openrouter` uses `reasoning: { effort }`. `together` uses `reasoning: { enabled }` and also `reasoning_effort` when `supportsReasoningEffort` is enabled. `qwen` uses top-level `enable_thinking`. Use `qwen-chat-template` for local Qwen-compatible servers that require `chat_template_kwargs.enable_thinking`.
392
392
 
393
393
  `cacheControlFormat: "anthropic"` is for OpenAI-compatible providers that expose Anthropic-style prompt caching through `cache_control` markers on text content and tool definitions.
394
394
 
package/docs/providers.md CHANGED
@@ -66,6 +66,7 @@ pi
66
66
  | OpenCode Go | `OPENCODE_API_KEY` | `opencode-go` |
67
67
  | Hugging Face | `HF_TOKEN` | `huggingface` |
68
68
  | Fireworks | `FIREWORKS_API_KEY` | `fireworks` |
69
+ | Together AI | `TOGETHER_API_KEY` | `together` |
69
70
  | Kimi For Coding | `KIMI_API_KEY` | `kimi-coding` |
70
71
  | MiniMax | `MINIMAX_API_KEY` | `minimax` |
71
72
  | MiniMax (China) | `MINIMAX_CN_API_KEY` | `minimax-cn` |
@@ -88,6 +89,7 @@ Store credentials in `~/.pi/agent/auth.json`:
88
89
  "google": { "type": "api_key", "key": "..." },
89
90
  "opencode": { "type": "api_key", "key": "..." },
90
91
  "opencode-go": { "type": "api_key", "key": "..." },
92
+ "together": { "type": "api_key", "key": "..." },
91
93
  "xiaomi": { "type": "api_key", "key": "..." },
92
94
  "xiaomi-token-plan-cn": { "type": "api_key", "key": "..." },
93
95
  "xiaomi-token-plan-ams": { "type": "api_key", "key": "..." },
package/docs/sdk.md CHANGED
@@ -54,7 +54,7 @@ The main factory function for a single `AgentSession`.
54
54
  `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.
55
55
 
56
56
  ```typescript
57
- import { createAgentSession } from "@earendil-works/pi-coding-agent";
57
+ import { createAgentSession, SessionManager } from "@earendil-works/pi-coding-agent";
58
58
 
59
59
  // Minimal: defaults with DefaultResourceLoader
60
60
  const { session } = await createAgentSession();
@@ -62,7 +62,7 @@ const { session } = await createAgentSession();
62
62
  // Custom: override specific options
63
63
  const { session } = await createAgentSession({
64
64
  model: myModel,
65
- tools: [readTool, bashTool],
65
+ tools: ["read", "bash"],
66
66
  sessionManager: SessionManager.inMemory(),
67
67
  });
68
68
  ```
@@ -466,64 +466,50 @@ const { session } = await createAgentSession({ resourceLoader: loader });
466
466
 
467
467
  ### Tools
468
468
 
469
+ Specify which built-in tools to enable:
470
+
471
+ - Built-in tool names: `read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`
472
+ - Default built-ins: `read`, `bash`, `edit`, `write`
473
+ - `noTools: "all"` disables all tools
474
+ - `noTools: "builtin"` disables default built-ins while keeping extension and custom tools enabled
475
+
469
476
  ```typescript
470
- import {
471
- codingTools, // read, bash, edit, write (default)
472
- readOnlyTools, // read, grep, find, ls
473
- readTool, bashTool, editTool, writeTool,
474
- grepTool, findTool, lsTool,
475
- } from "@earendil-works/pi-coding-agent";
477
+ import { createAgentSession } from "@earendil-works/pi-coding-agent";
476
478
 
477
- // Use built-in tool set
479
+ // Read-only mode
478
480
  const { session } = await createAgentSession({
479
- tools: readOnlyTools,
481
+ tools: ["read", "grep", "find", "ls"],
480
482
  });
481
483
 
482
484
  // Pick specific tools
483
485
  const { session } = await createAgentSession({
484
- tools: [readTool, bashTool, grepTool],
486
+ tools: ["read", "bash", "grep"],
485
487
  });
486
488
  ```
487
489
 
488
490
  #### Tools with Custom cwd
489
491
 
490
- **Important:** The pre-built tool instances (`readTool`, `bashTool`, etc.) use `process.cwd()` for path resolution. When you specify a custom `cwd` AND provide explicit `tools`, you must use the tool factory functions to ensure paths resolve correctly:
492
+ When you pass a custom `cwd`, `createAgentSession()` builds selected built-in tools for that cwd.
491
493
 
492
494
  ```typescript
493
- import {
494
- createCodingTools, // Creates [read, bash, edit, write] for specific cwd
495
- createReadOnlyTools, // Creates [read, grep, find, ls] for specific cwd
496
- createReadTool,
497
- createBashTool,
498
- createEditTool,
499
- createWriteTool,
500
- createGrepTool,
501
- createFindTool,
502
- createLsTool,
503
- } from "@earendil-works/pi-coding-agent";
495
+ import { createAgentSession, SessionManager } from "@earendil-works/pi-coding-agent";
504
496
 
505
497
  const cwd = "/path/to/project";
506
498
 
507
- // Use factory for tool sets
499
+ // Use default tools for custom cwd
508
500
  const { session } = await createAgentSession({
509
501
  cwd,
510
- tools: createCodingTools(cwd), // Tools resolve paths relative to cwd
502
+ sessionManager: SessionManager.inMemory(cwd),
511
503
  });
512
504
 
513
- // Or pick specific tools
505
+ // Or pick specific tools for custom cwd
514
506
  const { session } = await createAgentSession({
515
507
  cwd,
516
- tools: [createReadTool(cwd), createBashTool(cwd), createGrepTool(cwd)],
508
+ tools: ["read", "bash", "grep"],
509
+ sessionManager: SessionManager.inMemory(cwd),
517
510
  });
518
511
  ```
519
512
 
520
- **When you don't need factories:**
521
- - If you omit `tools`, pi automatically creates them with the correct `cwd`
522
- - If you use `process.cwd()` as your `cwd`, the pre-built instances work fine
523
-
524
- **When you must use factories:**
525
- - When you specify both `cwd` (different from `process.cwd()`) AND `tools`
526
-
527
513
  > See [examples/sdk/05-tools.ts](../examples/sdk/05-tools.ts)
528
514
 
529
515
  ### Custom Tools
@@ -556,6 +542,8 @@ Use `defineTool()` for standalone definitions and arrays like `customTools: [myT
556
542
 
557
543
  Custom tools passed via `customTools` are combined with extension-registered tools. Extensions loaded by the ResourceLoader can also register tools via `pi.registerTool()`.
558
544
 
545
+ If you pass `tools`, include each custom or extension tool name you want enabled, for example `tools: ["read", "bash", "my_tool"]`.
546
+
559
547
  > See [examples/sdk/05-tools.ts](../examples/sdk/05-tools.ts)
560
548
 
561
549
  ### Extensions
@@ -885,12 +873,10 @@ import { getModel } from "@earendil-works/pi-ai";
885
873
  import { Type } from "typebox";
886
874
  import {
887
875
  AuthStorage,
888
- bashTool,
889
876
  createAgentSession,
890
877
  DefaultResourceLoader,
891
878
  defineTool,
892
879
  ModelRegistry,
893
- readTool,
894
880
  SessionManager,
895
881
  SettingsManager,
896
882
  } from "@earendil-works/pi-coding-agent";
@@ -944,7 +930,7 @@ const { session } = await createAgentSession({
944
930
  authStorage,
945
931
  modelRegistry,
946
932
 
947
- tools: [readTool, bashTool],
933
+ tools: ["read", "bash", "status"],
948
934
  customTools: [statusTool],
949
935
  resourceLoader: loader,
950
936
 
@@ -1123,13 +1109,7 @@ defineTool
1123
1109
  SessionManager
1124
1110
  SettingsManager
1125
1111
 
1126
- // Built-in tools (use process.cwd())
1127
- codingTools
1128
- readOnlyTools
1129
- readTool, bashTool, editTool, writeTool
1130
- grepTool, findTool, lsTool
1131
-
1132
- // Tool factories (for custom cwd)
1112
+ // Tool factories
1133
1113
  createCodingTools
1134
1114
  createReadOnlyTools
1135
1115
  createReadTool, createBashTool, createEditTool, createWriteTool
package/docs/skills.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Skills are self-contained capability packages that the agent loads on-demand. A skill provides specialized workflows, setup instructions, helper scripts, and reference documentation for specific tasks.
6
6
 
7
- Pi implements the [Agent Skills standard](https://agentskills.io/specification), warning about violations but remaining lenient.
7
+ Pi implements the [Agent Skills standard](https://agentskills.io/specification), warning about most violations but remaining lenient. Pi allows skill names to differ from their parent directory even though the standard disallows it; that rule is suboptimal for shared skill directories used across multiple agent harnesses.
8
8
 
9
9
  ## Table of Contents
10
10
 
@@ -140,7 +140,7 @@ Per the [Agent Skills specification](https://agentskills.io/specification#frontm
140
140
 
141
141
  | Field | Required | Description |
142
142
  |-------|----------|-------------|
143
- | `name` | Yes | Max 64 chars. Lowercase a-z, 0-9, hyphens. Must match parent directory. |
143
+ | `name` | Yes | Max 64 chars. Lowercase a-z, 0-9, hyphens. Unlike the standard, Pi does not require this to match the parent directory because that standard requirement is suboptimal for shared skill directories. |
144
144
  | `description` | Yes | Max 1024 chars. What the skill does and when to use it. |
145
145
  | `license` | No | License name or reference to bundled file. |
146
146
  | `compatibility` | No | Max 500 chars. Environment requirements. |
@@ -154,7 +154,7 @@ Per the [Agent Skills specification](https://agentskills.io/specification#frontm
154
154
  - Lowercase letters, numbers, hyphens only
155
155
  - No leading/trailing hyphens
156
156
  - No consecutive hyphens
157
- - Must match parent directory name
157
+ Pi does not require the name to match the parent directory. The Agent Skills standard does, but that requirement is suboptimal for shared skill directories used by multiple tools.
158
158
 
159
159
  Valid: `pdf-processing`, `data-analysis`, `code-review`
160
160
  Invalid: `PDF-Processing`, `-pdf`, `pdf--processing`
@@ -177,7 +177,6 @@ description: Helps with PDFs.
177
177
 
178
178
  Pi validates skills against the Agent Skills standard. Most issues produce warnings but still load the skill:
179
179
 
180
- - Name doesn't match parent directory
181
180
  - Name exceeds 64 characters or contains invalid characters
182
181
  - Name starts/ends with hyphen or has consecutive hyphens
183
182
  - Description exceeds 1024 characters
package/docs/termux.md CHANGED
@@ -36,7 +36,7 @@ Image clipboard is not supported on Termux (the `ctrl+v` image paste feature wil
36
36
 
37
37
  Create `~/.pi/agent/AGENTS.md` to help the agent understand the Termux environment:
38
38
 
39
- ```markdown
39
+ ````markdown
40
40
  # Agent Environment: Termux on Android
41
41
 
42
42
  ## Location
@@ -53,7 +53,7 @@ termux-open-url "https://example.com"
53
53
  ## Opening Files
54
54
  ```bash
55
55
  termux-open file.pdf # Opens with default app
56
- termux-open -c image.jpg # Choose app
56
+ termux-open --chooser image.jpg # Choose app
57
57
  ```
58
58
 
59
59
  ## Clipboard
@@ -91,7 +91,7 @@ termux-camera-photo out.jpg # Take photo
91
91
  - Termux:API app must be installed for `termux-*` commands
92
92
  - Use `pkg install termux-api` for the command-line tools
93
93
  - Storage permission needed for `/storage/emulated/0` access
94
- ```
94
+ ````
95
95
 
96
96
  ## Limitations
97
97
 
package/docs/themes.md CHANGED
@@ -52,7 +52,7 @@ vim ~/.pi/agent/themes/my-theme.json
52
52
 
53
53
  ```json
54
54
  {
55
- "$schema": "https://raw.githubusercontent.com/earendil-works/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
55
+ "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
56
56
  "name": "my-theme",
57
57
  "vars": {
58
58
  "primary": "#00aaff",
@@ -122,7 +122,7 @@ vim ~/.pi/agent/themes/my-theme.json
122
122
 
123
123
  ```json
124
124
  {
125
- "$schema": "https://raw.githubusercontent.com/earendil-works/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
125
+ "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
126
126
  "name": "my-theme",
127
127
  "vars": {
128
128
  "blue": "#0066cc",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider",
3
- "version": "0.74.0",
3
+ "version": "0.74.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-custom-provider",
9
- "version": "0.74.0",
9
+ "version": "0.74.1",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.52.0"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-anthropic",
3
3
  "private": true,
4
- "version": "0.74.0",
4
+ "version": "0.74.1",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-gitlab-duo",
3
3
  "private": true,
4
- "version": "0.74.0",
4
+ "version": "0.74.1",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://raw.githubusercontent.com/earendil-works/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
2
+ "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
3
3
  "name": "dynamic-resources",
4
4
  "vars": {
5
5
  "cyan": "#00d7ff",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-sandbox",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-sandbox",
9
- "version": "1.4.0",
9
+ "version": "1.4.1",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sandbox-runtime": "^0.0.26"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-sandbox",
3
3
  "private": true,
4
- "version": "1.4.0",
4
+ "version": "1.4.1",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
- "version": "0.74.0",
3
+ "version": "0.74.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-with-deps",
9
- "version": "0.74.0",
9
+ "version": "0.74.1",
10
10
  "dependencies": {
11
11
  "ms": "^2.1.3"
12
12
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
3
  "private": true,
4
- "version": "0.74.0",
4
+ "version": "0.74.1",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -9,14 +9,18 @@ import { createAgentSession } from "@earendil-works/pi-coding-agent";
9
9
 
10
10
  const { session } = await createAgentSession();
11
11
 
12
- session.subscribe((event) => {
13
- if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
14
- process.stdout.write(event.assistantMessageEvent.delta);
15
- }
16
- });
12
+ try {
13
+ session.subscribe((event) => {
14
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
15
+ process.stdout.write(event.assistantMessageEvent.delta);
16
+ }
17
+ });
17
18
 
18
- await session.prompt("What files are in the current directory?");
19
- session.state.messages.forEach((msg) => {
20
- console.log(msg);
21
- });
22
- console.log();
19
+ await session.prompt("What files are in the current directory?");
20
+ session.state.messages.forEach((msg) => {
21
+ console.log(msg);
22
+ });
23
+ console.log();
24
+ } finally {
25
+ session.dispose();
26
+ }
@@ -38,12 +38,16 @@ if (available.length > 0) {
38
38
  modelRegistry,
39
39
  });
40
40
 
41
- session.subscribe((event) => {
42
- if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
43
- process.stdout.write(event.assistantMessageEvent.delta);
44
- }
45
- });
46
-
47
- await session.prompt("Say hello in one sentence.");
48
- console.log();
41
+ try {
42
+ session.subscribe((event) => {
43
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
44
+ process.stdout.write(event.assistantMessageEvent.delta);
45
+ }
46
+ });
47
+
48
+ await session.prompt("Say hello in one sentence.");
49
+ console.log();
50
+ } finally {
51
+ session.dispose();
52
+ }
49
53
  }
@@ -30,15 +30,19 @@ const { session: session1 } = await createAgentSession({
30
30
  sessionManager: SessionManager.inMemory(),
31
31
  });
32
32
 
33
- session1.subscribe((event) => {
34
- if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
35
- process.stdout.write(event.assistantMessageEvent.delta);
36
- }
37
- });
33
+ try {
34
+ session1.subscribe((event) => {
35
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
36
+ process.stdout.write(event.assistantMessageEvent.delta);
37
+ }
38
+ });
38
39
 
39
- console.log("=== Replace prompt ===");
40
- await session1.prompt("What is 2 + 2?");
41
- console.log("\n");
40
+ console.log("=== Replace prompt ===");
41
+ await session1.prompt("What is 2 + 2?");
42
+ console.log("\n");
43
+ } finally {
44
+ session1.dispose();
45
+ }
42
46
 
43
47
  // Option 2: Append instructions to the default prompt
44
48
  const loader2 = new DefaultResourceLoader({
@@ -56,12 +60,16 @@ const { session: session2 } = await createAgentSession({
56
60
  sessionManager: SessionManager.inMemory(),
57
61
  });
58
62
 
59
- session2.subscribe((event) => {
60
- if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
61
- process.stdout.write(event.assistantMessageEvent.delta);
62
- }
63
- });
63
+ try {
64
+ session2.subscribe((event) => {
65
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
66
+ process.stdout.write(event.assistantMessageEvent.delta);
67
+ }
68
+ });
64
69
 
65
- console.log("=== Modify prompt ===");
66
- await session2.prompt("List 3 benefits of TypeScript.");
67
- console.log();
70
+ console.log("=== Modify prompt ===");
71
+ await session2.prompt("List 3 benefits of TypeScript.");
72
+ console.log();
73
+ } finally {
74
+ session2.dispose();
75
+ }
@@ -47,9 +47,9 @@ if (diagnostics.length > 0) {
47
47
  console.log("Warnings:", diagnostics);
48
48
  }
49
49
 
50
- await createAgentSession({
50
+ const { session } = await createAgentSession({
51
51
  resourceLoader: loader,
52
52
  sessionManager: SessionManager.inMemory(),
53
53
  });
54
-
55
54
  console.log("Session created with filtered skills");
55
+ session.dispose();
@@ -13,32 +13,36 @@
13
13
  import { createAgentSession, SessionManager } from "@earendil-works/pi-coding-agent";
14
14
 
15
15
  // Read-only mode (no edit/write)
16
- await createAgentSession({
16
+ const { session: readOnlySession } = await createAgentSession({
17
17
  tools: ["read", "grep", "find", "ls"],
18
18
  sessionManager: SessionManager.inMemory(),
19
19
  });
20
20
  console.log("Read-only session created");
21
+ readOnlySession.dispose();
21
22
 
22
23
  // Custom tool selection
23
- await createAgentSession({
24
+ const { session: customToolsSession } = await createAgentSession({
24
25
  tools: ["read", "bash", "grep"],
25
26
  sessionManager: SessionManager.inMemory(),
26
27
  });
27
28
  console.log("Custom tools session created");
29
+ customToolsSession.dispose();
28
30
 
29
31
  // With custom cwd
30
32
  const customCwd = "/path/to/project";
31
- await createAgentSession({
33
+ const { session: customCwdSession } = await createAgentSession({
32
34
  cwd: customCwd,
33
35
  tools: ["read", "bash", "edit", "write"],
34
36
  sessionManager: SessionManager.inMemory(customCwd),
35
37
  });
36
38
  console.log("Custom cwd session created");
39
+ customCwdSession.dispose();
37
40
 
38
41
  // Or pick specific tools for custom cwd
39
- await createAgentSession({
42
+ const { session: specificToolsSession } = await createAgentSession({
40
43
  cwd: customCwd,
41
44
  tools: ["read", "bash", "grep"],
42
45
  sessionManager: SessionManager.inMemory(customCwd),
43
46
  });
44
47
  console.log("Specific tools with custom cwd session created");
48
+ specificToolsSession.dispose();