mu-agent 0.1.8 → 0.1.13

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 (176) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/README.md +34 -30
  3. package/dist/bundle/chunks/anthropic-messages-4PAJY4R6.js +6 -0
  4. package/dist/bundle/chunks/anthropic.js +1 -1
  5. package/dist/bundle/chunks/azure-openai-responses-Y4BBWQ3N.js +2 -0
  6. package/dist/bundle/chunks/bedrock-converse-stream.js +12 -9
  7. package/dist/bundle/chunks/{chunk-NG4PO5FP.js → chunk-3J3HSHLX.js} +128 -110
  8. package/dist/bundle/chunks/{chunk-TRDNDS6A.js → chunk-3V45WARH.js} +6 -3
  9. package/dist/bundle/chunks/{chunk-S3GGRYIO.js → chunk-5AGIVGSV.js} +1 -1
  10. package/dist/bundle/chunks/chunk-6QGV3IWD.js +6 -0
  11. package/dist/bundle/chunks/{chunk-4OBXYPH4.js → chunk-6Z2347ML.js} +1 -1
  12. package/dist/bundle/chunks/{chunk-F5ZABL6Z.js → chunk-7CBJINYJ.js} +2 -2
  13. package/dist/bundle/chunks/{chunk-DRQDKNXA.js → chunk-7DDKXS2Q.js} +1 -1
  14. package/dist/bundle/chunks/{chunk-H3QXYIF7.js → chunk-CF5GWZHW.js} +1 -1
  15. package/dist/bundle/chunks/{chunk-RLZVFGW4.js → chunk-DYTENXHX.js} +29 -92
  16. package/dist/bundle/chunks/{chunk-NTSWBG4X.js → chunk-FLHKNMLQ.js} +1 -1
  17. package/dist/bundle/chunks/chunk-FTJT2X6E.js +2 -0
  18. package/dist/bundle/chunks/{chunk-4L3WN2XY.js → chunk-JXWJOIH4.js} +1 -1
  19. package/dist/bundle/chunks/{chunk-TAOL3JFA.js → chunk-KIDDRTZP.js} +4 -4
  20. package/dist/bundle/chunks/chunk-LHRPMXVI.js +2 -0
  21. package/dist/bundle/chunks/chunk-LMNWTX2L.js +11 -0
  22. package/dist/bundle/chunks/chunk-LPXNMA2W.js +2 -0
  23. package/dist/bundle/chunks/chunk-LT2C56HV.js +130 -0
  24. package/dist/bundle/chunks/{chunk-6CYCI3EJ.js → chunk-LVVZS2NO.js} +1 -1
  25. package/dist/bundle/chunks/chunk-MF3VB62R.js +91 -0
  26. package/dist/bundle/chunks/chunk-NN4BEPYX.js +2 -0
  27. package/dist/bundle/chunks/{chunk-LD2P6SFZ.js → chunk-PMRZO46Y.js} +1 -1
  28. package/dist/bundle/chunks/chunk-R4VPBBDS.js +2 -0
  29. package/dist/bundle/chunks/chunk-RDZVAGPR.js +2 -0
  30. package/dist/bundle/chunks/chunk-TMTOQ7H7.js +2 -0
  31. package/dist/bundle/chunks/chunk-UKVNB6C4.js +2 -0
  32. package/dist/bundle/chunks/chunk-URBBMV3M.js +9 -0
  33. package/dist/bundle/chunks/chunk-WCGU75WO.js +11 -0
  34. package/dist/bundle/chunks/chunk-WCJNJQO5.js +9 -0
  35. package/dist/bundle/chunks/chunk-WDURT4ZM.js +2 -0
  36. package/dist/bundle/chunks/{cli-AOVD3SSZ.js → cli-M4YBZZ6Q.js} +4 -4
  37. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-MEZHQVNP.js +2 -0
  38. package/dist/bundle/chunks/codemode-worker.js +117 -13
  39. package/dist/bundle/chunks/easter-egg-3d-VFY3YRQR.js +2 -0
  40. package/dist/bundle/chunks/execute-FKI7Y4XR.js +499 -0
  41. package/dist/bundle/chunks/github-copilot.js +1 -1
  42. package/dist/bundle/chunks/{google-generative-ai-XMFHGQC5.js → google-generative-ai-D2VJQBTK.js} +1 -1
  43. package/dist/bundle/chunks/{google-vertex-4XRRNP74.js → google-vertex-SQG2BO6C.js} +1 -1
  44. package/dist/bundle/chunks/https-proxy-agent-LVOO5TPL.js +13 -0
  45. package/dist/bundle/chunks/image-resize-worker.js +1 -1
  46. package/dist/bundle/chunks/{jiti-loader-C3NU2SDH.js → jiti-loader-GL4HJFAD.js} +1 -1
  47. package/dist/bundle/chunks/{jiti-static-loader-E6ANQD5T.js → jiti-static-loader-2RCDI6B4.js} +1 -1
  48. package/dist/bundle/chunks/{lib-TEDK3E5I.js → lib-4AVRLBHM.js} +1 -1
  49. package/dist/bundle/chunks/{llama-cpp-classify-XT44PI3C.js → llama-cpp-classify-5YHLY3RC.js} +2 -2
  50. package/dist/bundle/chunks/mistral-conversations-BDARVJTT.js +5 -0
  51. package/dist/bundle/chunks/{multipart-parser-SQ6GDJL7.js → multipart-parser-FMGQ7342.js} +1 -1
  52. package/dist/bundle/chunks/{node-TWVVAGPO.js → node-AUOGOBCN.js} +1 -1
  53. package/dist/bundle/chunks/{node-N5BSDOA5.js → node-KCMANYC2.js} +1 -1
  54. package/dist/bundle/chunks/openai-chatgpt.js +1 -1
  55. package/dist/bundle/chunks/openai-codex-responses-CECGTDYD.js +10 -0
  56. package/dist/bundle/chunks/openai-codex.js +1 -1
  57. package/dist/bundle/chunks/openai-completions-UOA7MELD.js +7 -0
  58. package/dist/bundle/chunks/openai-decisions-HLM372N6.js +5 -0
  59. package/dist/bundle/chunks/openai-responses-TII7ZY5X.js +3 -0
  60. package/dist/bundle/chunks/{openrouter-images-ZVXWCSIM.js → openrouter-images-7T452AS5.js} +1 -1
  61. package/dist/bundle/chunks/{pi-messages-TM5SOOIW.js → pi-messages-2UDKLKOO.js} +1 -1
  62. package/dist/bundle/chunks/runtime-IKE5OQIW.js +2 -0
  63. package/dist/bundle/chunks/{src-UK77SYZE.js → src-QKGKDFSU.js} +1 -1
  64. package/dist/bundle/chunks/typesafe-system-one-KNCICMO5.js +2 -0
  65. package/dist/bundle/chunks/virtual-modules-TJPHLTRT.js +2 -0
  66. package/dist/bundle/cli-runtime.js +1 -1
  67. package/dist/bundle/index.js +1 -1
  68. package/dist/bundle/rpc-entry.js +1 -1
  69. package/dist/core/export-html/template.js +21 -16
  70. package/dist/modes/interactive/theme/dark.json +1 -1
  71. package/dist/modes/interactive/theme/light.json +1 -1
  72. package/dist/modes/interactive/theme/theme-schema.d.ts +28 -0
  73. package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -0
  74. package/dist/modes/interactive/theme/theme-schema.js +105 -0
  75. package/dist/modes/interactive/theme/theme-schema.js.map +1 -0
  76. package/dist/modes/interactive/theme/theme-tokens.d.ts +257 -0
  77. package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -0
  78. package/dist/modes/interactive/theme/theme-tokens.js +94 -0
  79. package/dist/modes/interactive/theme/theme-tokens.js.map +1 -0
  80. package/dist/modes/interactive/theme/theme.d.ts +13 -16
  81. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  82. package/dist/modes/interactive/theme/theme.js +22 -29
  83. package/dist/modes/interactive/theme/theme.js.map +1 -1
  84. package/docs/cli-integration.md +1 -1
  85. package/docs/cli.md +22 -10
  86. package/docs/codemode.md +29 -6
  87. package/docs/compaction.md +5 -5
  88. package/docs/custom-provider.md +53 -1
  89. package/docs/docs.json +8 -0
  90. package/docs/environment-variables.md +3 -1
  91. package/docs/extensions.md +122 -13
  92. package/docs/json.md +3 -3
  93. package/docs/keybindings.md +5 -4
  94. package/docs/llama-cpp.md +9 -2
  95. package/docs/mcp.md +4 -2
  96. package/docs/message-types.md +22 -4
  97. package/docs/models-configuration.md +187 -0
  98. package/docs/models.md +18 -2
  99. package/docs/nvidia-rtx-llama-cpp.md +96 -0
  100. package/docs/providers.md +47 -0
  101. package/docs/sessions.md +1 -1
  102. package/docs/settings.md +9 -6
  103. package/docs/terminal-setup.md +14 -0
  104. package/docs/themes.md +4 -2
  105. package/docs/tui.md +71 -1
  106. package/docs/usage.md +1 -1
  107. package/examples/README.md +0 -3
  108. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  109. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  110. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  111. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  112. package/examples/extensions/gondolin/package-lock.json +2 -2
  113. package/examples/extensions/gondolin/package.json +1 -1
  114. package/examples/extensions/minimal-mode.ts +4 -5
  115. package/examples/extensions/overlay-test.ts +2 -2
  116. package/examples/extensions/plan-mode/index.ts +6 -2
  117. package/examples/extensions/sandbox/package-lock.json +2 -2
  118. package/examples/extensions/sandbox/package.json +1 -1
  119. package/examples/extensions/subagent/index.ts +4 -6
  120. package/examples/extensions/with-deps/package-lock.json +2 -2
  121. package/examples/extensions/with-deps/package.json +1 -1
  122. package/judge/dist/auth.js +91 -35
  123. package/judge/dist/chrome.js +2 -2
  124. package/judge/dist/import.js +852 -175
  125. package/judge/dist/setup.js +240 -153
  126. package/judge/manifest.json +2512 -546
  127. package/judge/mu/chunk-3NQ5BIBI.js +4773 -0
  128. package/judge/mu/chunk-SKGYWHW6.js +51 -0
  129. package/judge/mu/chunk-WQM4MV6L.js +58 -0
  130. package/judge/mu/cloud-code-V7FOGB4J.js +22802 -0
  131. package/judge/mu/dist-75PS4OC4.js +1283 -0
  132. package/judge/{dist/kyrn-judge.js → mu/index.js} +5365 -32809
  133. package/judge/mu/multipart-parser-ZDXVIOOP.js +372 -0
  134. package/judge/mu/src-TVVA5ZK2.js +1409 -0
  135. package/judge/themes/mu-dark.json +80 -0
  136. package/judge/themes/mu-light.json +80 -0
  137. package/kyrn/bin/kyrn-doctor +44 -19
  138. package/kyrn/bin/kyrn-judge-local +43 -14
  139. package/kyrn/bin/kyrn-ledger +16 -1
  140. package/kyrn/bin/mu.mjs +142 -61
  141. package/kyrn/local-judge/server.py +26 -14
  142. package/package.json +8 -6
  143. package/dist/bundle/chunks/anthropic-messages-MI4QHRXW.js +0 -6
  144. package/dist/bundle/chunks/azure-openai-responses-E3QGN4VN.js +0 -2
  145. package/dist/bundle/chunks/chunk-33KL6IIQ.js +0 -20
  146. package/dist/bundle/chunks/chunk-A3JYRWB6.js +0 -2
  147. package/dist/bundle/chunks/chunk-C47CLQZK.js +0 -2
  148. package/dist/bundle/chunks/chunk-HQHD6PZI.js +0 -2
  149. package/dist/bundle/chunks/chunk-KJUDFE6Y.js +0 -11
  150. package/dist/bundle/chunks/chunk-TE3GUV6H.js +0 -9
  151. package/dist/bundle/chunks/chunk-VIV3CWXG.js +0 -2
  152. package/dist/bundle/chunks/chunk-WE4MXUQS.js +0 -11
  153. package/dist/bundle/chunks/chunk-Y2PP32XV.js +0 -2
  154. package/dist/bundle/chunks/chunk-YLY6CKPK.js +0 -132
  155. package/dist/bundle/chunks/chunk-ZE5FMF3V.js +0 -99
  156. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-NM3JRRWQ.js +0 -2
  157. package/dist/bundle/chunks/easter-egg-3d-G2LUBEMZ.js +0 -2
  158. package/dist/bundle/chunks/execute-MZVUC6BB.js +0 -388
  159. package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +0 -13
  160. package/dist/bundle/chunks/mistral-conversations-Q22M3IBG.js +0 -5
  161. package/dist/bundle/chunks/openai-codex-responses-4MYQSO5E.js +0 -10
  162. package/dist/bundle/chunks/openai-completions-OSRCWAAA.js +0 -7
  163. package/dist/bundle/chunks/openai-responses-UHF3DHNG.js +0 -3
  164. package/dist/bundle/chunks/runtime-VJMMDLVH.js +0 -2
  165. package/dist/bundle/chunks/typesafe-system-one-PRR5K6CI.js +0 -2
  166. package/dist/bundle/chunks/virtual-modules-RJXJGCPI.js +0 -2
  167. package/dist/modes/interactive/theme/theme-json.d.ts +0 -85
  168. package/dist/modes/interactive/theme/theme-json.d.ts.map +0 -1
  169. package/dist/modes/interactive/theme/theme-json.js +0 -132
  170. package/dist/modes/interactive/theme/theme-json.js.map +0 -1
  171. package/dist/modes/interactive/theme/theme-schema.json +0 -361
  172. package/examples/plugins/pi-example-plugin/README.md +0 -38
  173. package/examples/plugins/pi-example-plugin/package.json +0 -10
  174. package/examples/plugins/pi-example-plugin/src/contract.ts +0 -13
  175. package/examples/plugins/pi-example-plugin/src/session.ts +0 -24
  176. package/examples/plugins/pi-example-plugin/src/tui.ts +0 -31
@@ -0,0 +1,187 @@
1
+ # Models Configuration
2
+
3
+ <!-- This file is generated from TypeScript source. Do not edit it manually; run npm run generate:references. -->
4
+
5
+ This reference lists the fields of `models.json`. See [Configure a compatible endpoint](models.md#configure-a-compatible-endpoint) for examples and [Configuration](configuration.md#agent-directory) for the file location.
6
+
7
+ Add `"$schema": "https://pi.dev/schemas/models.schema.json"` to `models.json` for editor validation and completion.
8
+
9
+ ## Providers
10
+
11
+ Each key under `providers` is a provider ID. A built-in provider ID changes that provider. Any other ID adds a provider, which needs `baseUrl` and an `api` at provider or model level.
12
+
13
+ | Field | Type | Default | Description |
14
+ |---|---|---|---|
15
+ | `name` | string | | Display name. |
16
+ | `baseUrl` | string | | API base URL. Also applies to the provider's built-in models. |
17
+ | `apiKey` | string | | Literal key, "$NAME" environment interpolation, or "!command" output. |
18
+ | `api` | string | | API for the provider's models, such as "openai-completions", "openai-responses", "anthropic-messages", or "google-generative-ai". |
19
+ | `oauth` | `"radius"` | | OAuth login flow. Requires baseUrl. |
20
+ | `headers` | object | | Request headers. Values resolve like apiKey. |
21
+ | `compat` | [object](#compatibility) | | Provider and model compatibility overrides. |
22
+ | `authHeader` | boolean | `false` | Whether to send the resolved API key as Authorization: Bearer. |
23
+ | `models` | [`object[]`](#models) | | |
24
+ | `modelOverrides` | [object](#model-overrides) | | |
25
+
26
+ ## Models
27
+
28
+ Each `models` entry adds a model to the provider. An entry whose `id` matches an existing model replaces it.
29
+
30
+ | Field | Type | Default | Description |
31
+ |---|---|---|---|
32
+ | `id` | string | | Required. Model ID sent to the API. |
33
+ | `name` | string | | Display name, also matched by --model patterns. |
34
+ | `api` | string | | Overrides the provider api. |
35
+ | `baseUrl` | string | | Overrides the provider baseUrl. |
36
+ | `reasoning` | boolean | `false` | Whether the model supports thinking. |
37
+ | `thinkingLevelMap` | object | | Provider value sent for each thinking level. null marks a level unsupported. Levels the model does not map use the provider's default value through high; xhigh and max are unsupported. |
38
+ | `input` | `("text" \| "image")[]` | `["text"]` | |
39
+ | `inputLimits` | [object](#input-limits) | | |
40
+ | `cost` | object | | |
41
+ | `cost.input` | number | | Required. Input cost in USD per million tokens. |
42
+ | `cost.output` | number | | Required. Output cost in USD per million tokens. |
43
+ | `cost.cacheRead` | number | | Required. Cache-read cost in USD per million tokens. |
44
+ | `cost.cacheWrite` | number | | Required. Cache-write cost in USD per million tokens. |
45
+ | `cost.tiers` | `object[]` | | Request-wide pricing tiers. The highest matching input threshold applies to the full request. |
46
+ | `cost.tiers[].inputTokensAbove` | number | | Required. Use this tier when total request input exceeds this token count. |
47
+ | `cost.tiers[].input` | number | | Required. Input cost in USD per million tokens. |
48
+ | `cost.tiers[].output` | number | | Required. Output cost in USD per million tokens. |
49
+ | `cost.tiers[].cacheRead` | number | | Required. Cache-read cost in USD per million tokens. |
50
+ | `cost.tiers[].cacheWrite` | number | | Required. Cache-write cost in USD per million tokens. |
51
+ | `promptCache` | object | | Best-effort prompt cache lifetime in seconds for the short and long retention tiers. Pi warms only tiers with a known lifetime. |
52
+ | `contextWindow` | number | `128000` | Context window in tokens. |
53
+ | `maxTokens` | number | `16384` | Maximum output tokens. |
54
+ | `samplingParams` | object | | Fields merged into every request body. Applies only to OpenAI-compatible APIs. |
55
+ | `samplingParamsByThinkingLevel` | object | | samplingParams per thinking level, merged over samplingParams. |
56
+ | `headers` | object | | Request headers. Values resolve like apiKey. |
57
+ | `compat` | [object](#compatibility) | | Provider and model compatibility overrides. |
58
+
59
+ ## Model overrides
60
+
61
+ Each `modelOverrides` key is the ID of a built-in or extension model. Unknown IDs are ignored. Object fields, such as `cost`, merge with the model's value field by field; other fields replace it.
62
+
63
+ | Field | Type | Default | Description |
64
+ |---|---|---|---|
65
+ | `name` | string | | Display name, also matched by --model patterns. |
66
+ | `reasoning` | boolean | | Whether the model supports thinking. |
67
+ | `thinkingLevelMap` | object | | Provider value sent for each thinking level. null marks a level unsupported. Levels the model does not map use the provider's default value through high; xhigh and max are unsupported. |
68
+ | `input` | `("text" \| "image")[]` | | |
69
+ | `inputLimits` | [object](#input-limits) | | |
70
+ | `cost` | object | | |
71
+ | `cost.input` | number | | Input cost in USD per million tokens. |
72
+ | `cost.output` | number | | Output cost in USD per million tokens. |
73
+ | `cost.cacheRead` | number | | Cache-read cost in USD per million tokens. |
74
+ | `cost.cacheWrite` | number | | Cache-write cost in USD per million tokens. |
75
+ | `cost.tiers` | `object[]` | | Request-wide pricing tiers. The highest matching input threshold applies to the full request. |
76
+ | `cost.tiers[].inputTokensAbove` | number | | Required. Use this tier when total request input exceeds this token count. |
77
+ | `cost.tiers[].input` | number | | Required. Input cost in USD per million tokens. |
78
+ | `cost.tiers[].output` | number | | Required. Output cost in USD per million tokens. |
79
+ | `cost.tiers[].cacheRead` | number | | Required. Cache-read cost in USD per million tokens. |
80
+ | `cost.tiers[].cacheWrite` | number | | Required. Cache-write cost in USD per million tokens. |
81
+ | `promptCache` | object | | Best-effort prompt cache lifetime in seconds for the short and long retention tiers. Pi warms only tiers with a known lifetime. |
82
+ | `contextWindow` | number | | Context window in tokens. |
83
+ | `maxTokens` | number | | Maximum output tokens. |
84
+ | `samplingParams` | object | | Fields merged into every request body. Applies only to OpenAI-compatible APIs. |
85
+ | `samplingParamsByThinkingLevel` | object | | samplingParams per thinking level, merged over samplingParams. |
86
+ | `headers` | object | | Request headers. Values resolve like apiKey. |
87
+ | `compat` | [object](#compatibility) | | Provider and model compatibility overrides. |
88
+
89
+ ## Input limits
90
+
91
+ See [Describe model input and caching](models.md#describe-model-input-and-caching).
92
+
93
+ | Field | Type | Default | Description |
94
+ |---|---|---|---|
95
+ | `maxRequestBytes` | integer | | Maximum serialized provider request size in bytes. |
96
+ | `images` | object | | |
97
+ | `images.resize` | object | | Cache-safe resize profile applied before a new image enters conversation history. |
98
+ | `images.resize.maxWidth` | integer | | |
99
+ | `images.resize.maxHeight` | integer | | |
100
+ | `images.resize.maxBytes` | integer | | Maximum base64-encoded payload size in bytes. |
101
+ | `images.resize.jpegQuality` | integer | | |
102
+ | `images.maxPerMessage` | integer | | Maximum images accepted in one provider message. |
103
+ | `images.maxPerRequest` | integer | | Maximum images accepted across one provider request. |
104
+
105
+ ## Compatibility
106
+
107
+ `compat` describes verified differences from an API's standard request and response behavior. Model values override provider values per field. The fields that apply depend on the model's `api`.
108
+
109
+ ### `openai-completions`
110
+
111
+ | Field | Type | Default | Description |
112
+ |---|---|---|---|
113
+ | `supportsStore` | boolean | | Whether the provider supports the store field. Default: auto-detected from URL. |
114
+ | `supportsDeveloperRole` | boolean | | Whether the provider supports the developer role instead of system. Default: auto-detected from URL. |
115
+ | `supportsReasoningEffort` | boolean | | Whether the provider supports reasoning_effort. Default: auto-detected from URL. |
116
+ | `supportsUsageInStreaming` | boolean | `true` | Whether the provider supports stream_options.include_usage for token usage in streaming responses. |
117
+ | `supportsFinishReason` | boolean | `true` | Whether streamed responses include finish_reason. When false, pi infers stop or toolUse when the stream ends. |
118
+ | `maxTokensField` | `"max_completion_tokens" \| "max_tokens"` | | Which field to use for max tokens. Default: auto-detected from URL. |
119
+ | `requiresToolResultName` | boolean | | Whether tool results require the name field. Default: auto-detected from URL. |
120
+ | `requiresAssistantAfterToolResult` | boolean | | Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL. |
121
+ | `requiresThinkingAsText` | boolean | | Whether thinking blocks must be converted to text blocks with &lt;thinking> delimiters. Default: auto-detected from URL. |
122
+ | `requiresReasoningContentOnAssistantMessages` | boolean | | Whether all replayed assistant messages must include an empty reasoning_content field when reasoning is enabled. Default: auto-detected from URL. |
123
+ | `thinkingFormat` | `"openai" \| "openrouter" \| "deepseek" \| "together" \| "baseten" \| "zai" \| "qwen" \| "chat-template" \| "qwen-chat-template" \| "string-thinking" \| "ant-ling"` | | Format for reasoning or thinking parameters. When omitted, Pi auto-detects the format from the provider URL. "openai" uses reasoning_effort, "openrouter" uses reasoning.effort, "deepseek" uses thinking.type plus reasoning_effort when supported, "together" uses reasoning.enabled plus reasoning_effort when supported, "baseten" uses configurable chat_template_args plus reasoning_effort when supported, "zai" uses thinking.type, "qwen" uses top-level enable_thinking, "qwen-chat-template" uses chat_template_kwargs.enable_thinking and preserve_thinking, "chat-template" uses configurable chat_template_kwargs, "string-thinking" uses top-level thinking, and "ant-ling" uses reasoning.effort only when the mapped effort is non-null. |
124
+ | `chatTemplateKwargs` | object | | Kwargs sent as chat_template_kwargs when thinkingFormat is "chat-template". Use $var with "thinking.enabled", "thinking.effort", or "thinking.budget" for pi-controlled values. |
125
+ | `chatTemplateArgs` | object | | Arguments sent as chat_template_args when thinkingFormat is "baseten". Use $var with "thinking.enabled", "thinking.effort", or "thinking.budget" for pi-controlled values. |
126
+ | `openRouterRouting` | object | | OpenRouter provider routing preferences. Controls which upstream providers OpenRouter routes requests to. Sent as the provider field in the OpenRouter API request body. See https://openrouter.ai/docs/guides/routing/provider-selection. |
127
+ | `vercelGatewayRouting` | object | | Vercel AI Gateway routing preferences. Controls which upstream providers the gateway routes requests to. See https://vercel.com/docs/ai-gateway/models-and-providers/provider-options. |
128
+ | `zaiToolStream` | boolean | `false` | Whether z.ai supports top-level tool_stream for streaming tool call deltas. |
129
+ | `thinkingTokenBudgetField` | `"thinking_token_budget" \| "thinking_budget" \| "thinking_budget_tokens"` | | Top-level request field used to cap reasoning tokens from thinkingBudgets. Reasoning and the answer share max_tokens on these endpoints. "thinking_token_budget" is vLLM, "thinking_budget" is Qwen, DashScope, or SGLang, and "thinking_budget_tokens" is llama.cpp. Off by default and not set on the generated catalog. |
130
+ | `supportsThinkingTokenBudget` | boolean | `false` | Alias for thinkingTokenBudgetField: "thinking_token_budget" (vLLM). Prefer thinkingTokenBudgetField. |
131
+ | `supportsOpenAIGrammarTools` | boolean | `false` | Whether the provider supports OpenAI custom tools with Lark or regex grammar formats. When false, grammar-constrained tools fall back to normal function tools. The generated catalog enables this for capable models. |
132
+ | `supportsMidConvoSystemMessages` | boolean | `false` | Whether the exact model accepts system or developer messages after the conversation has started. When false, later system messages are folded into the leading system message. The generated catalog enables this for verified models. |
133
+ | `supportsMidConvoToolAdditions` | boolean | `false` | Whether system messages can introduce additional tools mid-conversation. Requires supportsMidConvoSystemMessages. The generated catalog enables this for capable models. |
134
+ | `supportsStrictMode` | boolean | `false` | Whether the provider supports the strict field in tool definitions. Generated capable models enable it explicitly. |
135
+ | `cacheControlFormat` | `"anthropic"` | | Cache control convention for prompt caching. Anthropic applies cache_control markers to the system prompt, last tool definition, and last user, assistant, or tool-result text content. |
136
+ | `sendSessionAffinityHeaders` | boolean | | Whether to send session-affinity data from options.sessionId. Default: true for OpenRouter endpoints, false otherwise. |
137
+ | `sessionAffinityFormat` | `"openai" \| "openai-nosession" \| "openrouter"` | | Session-affinity header format. openai sends session_id, x-client-request-id, and x-session-affinity; openai-nosession sends x-client-request-id and x-session-affinity; openrouter sends x-session-id. Does not affect prompt_cache_key. Default: auto-detected. |
138
+ | `supportsLongCacheRetention` | boolean | | Whether the provider supports long prompt cache retention (prompt_cache_retention: "24h" or Anthropic-style cache_control.ttl: "1h", depending on format). Default: auto-detected from provider and URL. |
139
+ | `vllmPriority` | number | | vLLM scheduler priority sent as the top-level priority request field. Lower values are handled earlier and the server default is 0. Only meaningful with --scheduling-policy priority. Off by default and not set on the generated catalog. |
140
+
141
+ ### `openai-responses`
142
+
143
+ Also applies to `azure-openai-responses` and `openai-codex-responses`.
144
+
145
+ | Field | Type | Default | Description |
146
+ |---|---|---|---|
147
+ | `supportsDeveloperRole` | boolean | `true` | Whether the provider supports the developer role instead of system. |
148
+ | `supportsMidConvoSystemMessages` | boolean | `false` | Whether the exact model accepts developer or system messages after the conversation has started. When false, later system messages are folded into the leading system message. The generated catalog enables this for verified models. |
149
+ | `sessionAffinityFormat` | `"openai" \| "openai-nosession" \| "openrouter"` | | Session-affinity header format. openai sends session_id and x-client-request-id; openai-nosession sends x-client-request-id; openrouter sends x-session-id. Does not affect prompt_cache_key. Default: auto-detected. |
150
+ | `supportsLongCacheRetention` | boolean | `true` | Whether the provider supports long prompt cache retention. This uses prompt_cache_options.ttl: "30m" on GPT-5.6+ and prompt_cache_retention: "24h" on earlier models. |
151
+ | `supportsStrictMode` | boolean | | Whether the provider supports strict JSON-schema function tools. Defaults are API-specific; generated OpenAI models enable it explicitly. |
152
+ | `supportsOpenAIGrammarTools` | boolean | `false` | Whether to emit OpenAI custom tools with Lark or regex grammar formats. When false, grammar-constrained tools fall back to normal function tools. The generated catalog enables this for capable models. |
153
+ | `supportsAdditionalTools` | boolean | `false` | Whether the model supports message-anchored additional_tools input items. |
154
+ | `supportsToolSearch` | boolean | `false` | Whether the model supports client-executed tool search for transcript-anchored additions. |
155
+ | `supportsExplicitPromptCacheMode` | boolean | `false` | Whether the model accepts prompt_cache_options. Older OpenAI models reject the parameter. |
156
+ | `supportsMidConvoEffort` | boolean | `false` | Whether thinking level changes are sent as configuration_update input items instead of changing reasoning.effort, so a change keeps the prompt cache. Only used by the openai-responses API, and ignored with Sign in with ChatGPT on the openai provider. |
157
+ | `supportsMaxOutputTokens` | boolean | `true` | Whether the provider accepts max_output_tokens. Some Codex-protocol gateways reject it. |
158
+
159
+ ### `anthropic-messages`
160
+
161
+ | Field | Type | Default | Description |
162
+ |---|---|---|---|
163
+ | `supportsEagerToolInputStreaming` | boolean | `true` | Whether the provider accepts per-tool eager_input_streaming. When false, the Anthropic provider omits tools[].eager_input_streaming and sends the legacy fine-grained-tool-streaming-2025-05-14 beta header for tool-enabled requests. |
164
+ | `supportsLongCacheRetention` | boolean | `true` | Whether the provider supports Anthropic long cache retention through cache_control.ttl. |
165
+ | `sendSessionAffinityHeaders` | boolean | | Whether to send x-session-affinity from options.sessionId when caching is enabled. Required for providers like Fireworks that use session affinity for prompt cache routing; requests to the same replica maximize cache hits. Default: true for OpenRouter endpoints, false otherwise. |
166
+ | `sessionAffinityFormat` | `"openrouter"` | | Session-affinity format. openrouter sends x-session-id; when unset, sends x-session-affinity. |
167
+ | `supportsCacheControlOnTools` | boolean | `true` | Whether the provider supports Anthropic-style cache_control markers on tool definitions. When false, cache_control is omitted from tool parameters. Some Anthropic-compatible providers, such as Fireworks, do not support this field on tools and may reject or ignore it. |
168
+ | `supportsTemperature` | boolean | `true` | Whether the model accepts the Anthropic temperature request field. Claude Opus 4.7+ rejects non-default values. |
169
+ | `forceAdaptiveThinking` | boolean | `false` | Whether to force adaptive thinking (thinking.type: adaptive plus output_config.effort) regardless of model ID. Built-in models that require adaptive thinking set this in generated metadata. Custom Anthropic-compatible providers can set this to true for any model whose upstream requires the adaptive format. Set false to opt out on overridden built-in models. |
170
+ | `allowEmptySignature` | boolean | `false` | Whether to replay empty thinking signatures instead of converting thinking to text. |
171
+ | `supportsStrictTools` | boolean | `false` | Whether the provider supports Anthropic strict tool schemas. Generated Anthropic models enable it explicitly. |
172
+ | `supportsMidConvoEffort` | boolean | `false` | Whether the exact model transport supports effort-only system messages and thinking binding controls. |
173
+ | `supportsMidConvoSystemMessages` | boolean | `false` | Whether the exact model accepts system-role messages inside the conversation. When false, later system messages are folded into the top-level system prompt. |
174
+ | `supportsMidConvoToolChanges` | boolean | `false` | Whether the exact model accepts mid-conversation tool_addition and tool_removal blocks. Requires supportsMidConvoSystemMessages. |
175
+ | `allowedFallbackModels` | `object[]` | | Models Anthropic accepts for server-side refusal fallback, with local pricing metadata for returned fallback responses. When absent or empty, callers must omit fallbacks; Anthropic rejects the field for models with no permitted fallback targets. |
176
+
177
+ ### `bedrock-converse-stream`
178
+
179
+ | Field | Type | Default | Description |
180
+ |---|---|---|---|
181
+ | `supportsStrictMode` | boolean | `false` | Whether the model supports Bedrock strict tool schemas. |
182
+
183
+ ### `mistral-conversations`
184
+
185
+ | Field | Type | Default | Description |
186
+ |---|---|---|---|
187
+ | `supportsMidConvoSystemMessages` | boolean | `false` | Whether the exact model accepts system messages after the conversation has started. When false, later system messages are folded into the leading system message. |
package/docs/models.md CHANGED
@@ -48,6 +48,7 @@ Use [`models.json`](configuration.md#agent-directory) when an endpoint speaks an
48
48
 
49
49
  ```json
50
50
  {
51
+ "$schema": "https://pi.dev/schemas/models.schema.json",
51
52
  "providers": {
52
53
  "ollama": {
53
54
  "baseUrl": "http://localhost:11434/v1",
@@ -61,10 +62,22 @@ Use [`models.json`](configuration.md#agent-directory) when an endpoint speaks an
61
62
  }
62
63
  ```
63
64
 
64
- The dummy key makes the model available to Pi; Ollama ignores it. For an authenticated endpoint, `apiKey` and header values can use `$NAME` or `${NAME}` environment interpolation, a literal value, or a leading `!command`. Commands in `models.json` run at request time and are not cached by Pi.
65
+ The dummy key makes the model available to Pi; Ollama ignores it. For an authenticated endpoint, `apiKey` and header values can use `$NAME` or `${NAME}` environment interpolation, a literal value, or a leading `!command`. `$$` and `$!` produce a literal `$` and `!`. Commands in `models.json` run at request time and are not cached by Pi.
65
66
 
66
67
  Opening `/model` reloads the file. A `models` entry adds or replaces a model with the same ID on that provider. Use `modelOverrides` to change metadata for an existing built-in or extension-provided model without replacing the provider's model list. Unknown override IDs are ignored.
67
68
 
69
+ To route a built-in provider through a proxy, set only its `baseUrl`. Its models and authentication stay unchanged:
70
+
71
+ ```json
72
+ {
73
+ "providers": {
74
+ "anthropic": { "baseUrl": "https://proxy.example.com/v1" }
75
+ }
76
+ }
77
+ ```
78
+
79
+ [Models Configuration](models-configuration.md) lists every field.
80
+
68
81
  ### Describe model input and caching
69
82
 
70
83
  Use `inputLimits.images.resize` to control how Pi encodes new image attachments, `read` results, and tool-result images before storing them in conversation history:
@@ -128,7 +141,7 @@ Compatibility settings should describe verified differences in the endpoint's re
128
141
 
129
142
  ## Use classifier models
130
143
 
131
- Classifier models do not chat. They answer typed questions about JSON state: pick one of several choices, answer yes or no, or give a score, each with probabilities. Pi includes TypeSafe's Jev model from these providers, and Cloudflare's Clef and Clef Flash models from Workers AI:
144
+ Classifier models do not chat. They answer typed questions about JSON state: pick one of several choices, answer yes or no, or give a score, each with probabilities. Pi includes TypeSafe's Jev model from these providers, Cloudflare's Clef and Clef Flash models from Workers AI, and OpenAI's GPT-6 Luna through the [Decisions API](https://developers.openai.com/api/docs/guides/decisions):
132
145
 
133
146
  | Provider | Model IDs | Authentication |
134
147
  |---|---|---|
@@ -137,9 +150,12 @@ Classifier models do not chat. They answer typed questions about JSON state: pic
137
150
  | `cloudflare-workers-ai` | `typesafe/jev`, `@cf/cloudflare/clef`, `@cf/cloudflare/clef-flash` | `CLOUDFLARE_API_KEY` and `CLOUDFLARE_ACCOUNT_ID` |
138
151
  | `vercel-ai-gateway` | `typesafe-ai/jev` | `AI_GATEWAY_API_KEY` |
139
152
  | `opencode` | `jev-1.13`, `jev-1.13-free` | `OPENCODE_API_KEY` |
153
+ | `openai` | `gpt-6-luna` | `OPENAI_API_KEY` |
140
154
 
141
155
  Chat models on a [llama.cpp router](llama-cpp.md#classification) are also listed as classifier models.
142
156
 
157
+ OpenAI's Decisions API needs an API key. Sign in with ChatGPT credentials do not work with it, so `gpt-6-luna` is not listed as available while `openai` is logged in through `/login`, even when `OPENAI_API_KEY` is set; log out of `openai` to use the key. GPT-6 Luna also judges images passed in `images` (see [Codemode](codemode.md#classify)); other classifier models return an error for them. The API rejects inputs above 922K tokens, but requests that run longer than about five seconds, currently above roughly 600K input tokens, fail with a gateway timeout.
158
+
143
159
  Classifier models do not appear in `/model`. The model reaches them through the [`codemode`](cli.md#enable-codemode) tool, which is off unless an MCP server turned it on. Enable it with `"defaultTools": ["+codemode"]` in [settings](settings.md#tools). Scripts then list classifier models with `models.getAvailableOfType("classifier")` and call `models.classify(model, { state, questions })`:
144
160
 
145
161
  ```js
@@ -0,0 +1,96 @@
1
+ # Run Pi with NVIDIA RTX and llama.cpp
2
+
3
+ [NVIDIA Local AI Inference Recipes](https://nvidia.github.io/local-ai-inference-recipes/index.html) provides llama.cpp settings tuned for specific NVIDIA hardware and models. Each recipe gives a single-model `llama-server` command. Pi works with the llama.cpp router, which can serve and manage several models, so this guide converts the recipe command into a router preset.
4
+
5
+ The examples below use Windows PowerShell. See [Local Models with llama.cpp](llama-cpp.md) for Pi's complete router and model-management reference.
6
+
7
+ ## Before you begin
8
+
9
+ 1. Open the [recipe catalog](https://nvidia.github.io/local-ai-inference-recipes/index.html), select your hardware, operating system, and model, then choose **llama.cpp**. Check the prerequisites and memory requirements. Keep the recipe's launch command for the conversion below.
10
+ 2. Install llama.cpp with the recipe's setup instructions. The recipe's settings depend on its build, for example CUDA support or speculative decoding options.
11
+ 3. Run `llama-server --help` and check that it lists `--models-preset`. Without it, the build cannot load the recipe as a router preset. Use a newer build that still meets the recipe's requirements.
12
+ 4. Install Pi with the [Quickstart](quickstart.md). On native Windows, also see [Run Pi on Windows](windows.md).
13
+
14
+ ## Convert the recipe to a preset
15
+
16
+ A preset lists the settings for one or more models. Each section name becomes the model ID shown in Pi. Save the preset next to `llama-server`, or pass its full path when starting the router.
17
+
18
+ Convert each option from the recipe command into one preset line:
19
+
20
+ - Remove the leading dashes: `--ctx-size 65536` becomes `ctx-size = 65536`.
21
+ - Write options without a value as `true`: `--jinja` becomes `jinja = true`.
22
+ - Remove quotes and PowerShell line-continuation backticks around values.
23
+ - Leave out `--host` and `--port`. They belong on the router command line.
24
+ - Add `load-on-startup = true` so the router loads the model when it starts.
25
+ - Replace short model-file options with their long preset keys:
26
+
27
+ | Recipe option | Preset key |
28
+ |---|---|
29
+ | `-hf` | `hf-repo` |
30
+ | `-hff` | `hf-file` |
31
+ | `-hfrd` | `hf-repo-draft` |
32
+ | `--spec-draft-model` | `spec-draft-model` |
33
+
34
+ For example, this recipe command:
35
+
36
+ ```powershell
37
+ llama-server.exe -hf "unsloth/Qwen3.8-27B-GGUF" `
38
+ -hff "Qwen3.8-27B-UD-Q4_K_M.gguf" `
39
+ -hfrd "z-lab/Qwen3.8-27B-DFlash2-GGUF" `
40
+ --spec-draft-model "Qwen3.8-27B-DFlash2-Q4_K_M.gguf" `
41
+ --no-mmproj `
42
+ --host 127.0.0.1 `
43
+ --port 9931 `
44
+ --batch-size 4096 `
45
+ --ubatch-size 1024 `
46
+ --ctx-size 65536 `
47
+ --parallel 1 `
48
+ -ngl 999 `
49
+ --jinja `
50
+ --chat-template-kwargs '{"preserve_thinking":true}' `
51
+ --spec-type draft-dflash `
52
+ --spec-draft-n-max 7 `
53
+ --spec-draft-backend-sampling
54
+ ```
55
+
56
+ becomes `qwen3.8-27b.ini`:
57
+
58
+ ```ini
59
+ version = 1
60
+
61
+ [qwen3.8-27b]
62
+ load-on-startup = true
63
+ hf-repo = unsloth/Qwen3.8-27B-GGUF
64
+ hf-file = Qwen3.8-27B-UD-Q4_K_M.gguf
65
+ hf-repo-draft = z-lab/Qwen3.8-27B-DFlash2-GGUF
66
+ spec-draft-model = Qwen3.8-27B-DFlash2-Q4_K_M.gguf
67
+ no-mmproj = true
68
+ batch-size = 4096
69
+ ubatch-size = 1024
70
+ ctx-size = 65536
71
+ parallel = 1
72
+ ngl = 999
73
+ jinja = true
74
+ chat-template-kwargs = {"preserve_thinking":true}
75
+ spec-type = draft-dflash
76
+ spec-draft-n-max = 7
77
+ spec-draft-backend-sampling = true
78
+ ```
79
+
80
+ ## Start the router
81
+
82
+ Open PowerShell in the llama.cpp folder and run:
83
+
84
+ ```powershell
85
+ .\llama-server.exe --models-preset qwen3.8-27b.ini --host 127.0.0.1 --port 8080
86
+ ```
87
+
88
+ If the recipe requires a Hugging Face token, set `$env:HF_TOKEN` in the same PowerShell window before starting the router. On its first start, the router downloads the model files.
89
+
90
+ Use the [router health checks](llama-cpp.md#troubleshooting) to confirm that the server is ready. In Windows PowerShell, use `curl.exe` rather than `curl`, which PowerShell maps to a different command. The model is ready when `/models` lists `qwen3.8-27b` with the status `loaded`.
91
+
92
+ ## Use the model in Pi
93
+
94
+ Follow [Configure Pi](llama-cpp.md#configure-pi) and connect to `http://127.0.0.1:8080`. The preset section name is the model ID, so select `qwen3.8-27b` in `/model` for this example.
95
+
96
+ NVIDIA recipe memory settings assume that only the selected model uses the GPU. If `/llama` shows other loaded models, unload them before using the recipe model.
package/docs/providers.md CHANGED
@@ -113,8 +113,32 @@ Radius is currently in early alpha and evolving quickly. See [radius.earendil.co
113
113
 
114
114
  Radius authentication uses its gateway catalog and caches refreshed model metadata for later offline startup. A custom Radius gateway configured in `models.json` uses its own catalog rather than inheriting the public `radius.pi.dev` catalog.
115
115
 
116
+ ### OpenRouter
117
+
118
+ Authenticate with `/login openrouter` or `OPENROUTER_API_KEY`.
119
+
120
+ With a key, Pi lists only the OpenRouter chat models that key may use, with the key's context size, max output, and prices. These come from OpenRouter's `/models/user` endpoint and reflect guardrails and provider restrictions set in OpenRouter. Image and classifier models are not filtered.
121
+
122
+ Pi refreshes the list in the background at startup in interactive mode, when `/model` opens, after `/login`, and on `pi update --models`. The last list is saved and used offline and in `pi -p` and RPC mode. After switching keys outside `/login`, the previous key's list stays until the next refresh.
123
+
124
+ Regional endpoints filter models to their region. To use one, set the base URL in [`models.json`](models.md#configure-a-compatible-endpoint):
125
+
126
+ ```json
127
+ {
128
+ "providers": {
129
+ "openrouter": { "baseUrl": "https://us.openrouter.ai/api/v1" }
130
+ }
131
+ }
132
+ ```
133
+
134
+ If the base URL rejects the key at `/models/user` or does not have that endpoint, for example a proxy configured as the OpenRouter base URL, Pi lists every OpenRouter model.
135
+
116
136
  ### Azure OpenAI
117
137
 
138
+ The provider ID is `azure` (formerly `azure-openai-responses`). Use it as the key in `auth.json`, `models.json`, and `settings.json`, and in model references such as `--model azure/gpt-5.4`.
139
+
140
+ The `azure` provider serves OpenAI models through the Responses API and Microsoft Foundry models through Chat Completions, such as `azure/deepseek-v4-pro`.
141
+
118
142
  Set an API key plus either a base URL or resource name:
119
143
 
120
144
  ```bash
@@ -126,6 +150,29 @@ export AZURE_OPENAI_RESOURCE_NAME=your-resource
126
150
 
127
151
  Resource root URLs under `ai.azure.com`, `cognitiveservices.azure.com`, and `openai.azure.com` are normalized to the OpenAI API path.
128
152
 
153
+ Pi sends the model ID as the deployment name. If a deployment has a different name, map it with `AZURE_OPENAI_DEPLOYMENT_NAME_MAP`:
154
+
155
+ ```bash
156
+ export AZURE_OPENAI_DEPLOYMENT_NAME_MAP=gpt-5.4=my-gpt-deployment,deepseek-v4-pro=my-deepseek
157
+ ```
158
+
159
+ `AZURE_OPENAI_API_VERSION` overrides the API version for OpenAI models (default `v1`).
160
+
161
+ To use a Foundry model that Pi does not include, add it under `azure` in [`models.json`](models.md#configure-a-compatible-endpoint) with `api: "openai-completions"`. Custom models require a `baseUrl`; `AZURE_OPENAI_BASE_URL` and `AZURE_OPENAI_RESOURCE_NAME` take priority over it when set:
162
+
163
+ ```json
164
+ {
165
+ "providers": {
166
+ "azure": {
167
+ "baseUrl": "https://your-resource.services.ai.azure.com",
168
+ "models": [
169
+ { "id": "your-deployment", "api": "openai-completions" }
170
+ ]
171
+ }
172
+ }
173
+ }
174
+ ```
175
+
129
176
  ### Amazon Bedrock
130
177
 
131
178
  Bedrock can use a bearer token or an ambient AWS credential source:
package/docs/sessions.md CHANGED
@@ -55,7 +55,7 @@ Use `--session` when you already know the session path or ID. Use `--fork` to cr
55
55
 
56
56
  ## Export or share a session
57
57
 
58
- Use `/export` to write the current session as HTML or JSONL. Use `/share` to upload it and get a viewer link. Pi uses a Radius artifact when Radius authentication is configured; otherwise, it uses a private GitHub gist.
58
+ Use `/export` to write the current session as HTML or JSONL. Use `/share` to upload it and get a viewer link. By default, Pi uses a Radius artifact when Radius authentication is configured; otherwise, it uses a private GitHub gist. Set [`sessionShareDestination`](settings.md#sessions-and-context) to `gist` or `radius` to force one destination.
59
59
 
60
60
  Review exported or shared sessions first. They can contain prompts, model responses, tool arguments, command output, file contents, and extension messages.
61
61
 
package/docs/settings.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  This reference lists user-configurable settings, their types, defaults, and purposes. Project settings override agent-directory settings. Resource lists are combined. See [Configuration](configuration.md) for file locations and trust behavior.
4
4
 
5
+ Add `"$schema": "https://pi.dev/schemas/settings.schema.json"` to `settings.json` for editor validation and completion.
6
+
5
7
  ## Model and thinking
6
8
 
7
9
  <a id="model-cycling"></a>
@@ -53,22 +55,23 @@ A list of only `+name` and `-name` entries changes the inherited selection inste
53
55
 
54
56
  This replaces `bash` with `powershell` and enables `grep`: `["-bash", "+powershell", "+grep"]`. Project settings apply on top of user settings: a project list with only `+name` and `-name` entries changes the user's selection, and a project list with a plain name replaces it. In one list, plain names form the selection, and `+name` and `-name` then apply in order.
55
57
 
56
- `/reload` enables tools newly added to `defaultTools`. It does not disable tools removed from it or re-enable unchanged tools you turned off. `--tools`, `--no-tools`, and `--no-builtin-tools` override `defaultTools`, also on reload.
58
+ `/reload` enables tools newly added to `defaultTools`. It does not disable tools removed from it or re-enable unchanged tools you turned off. `--tools` with plain names, `--no-tools`, and `--no-builtin-tools` override `defaultTools`, also on reload.
57
59
 
58
- CLI tool options override this setting for one invocation; `--tools` does not accept `+name` or `-name`. See [Command Line](cli.md#tools).
60
+ CLI tool options override this setting for one invocation. `--tools` with only `+name` and `-name` entries changes the resolved `defaultTools` selection instead, for example `pi --tools +codemode`. On `/reload`, these entries apply to the reloaded setting too, so a tool removed with `-name` stays removed. See [Command Line](cli.md#tools).
59
61
 
60
62
  ## Sessions and context
61
63
 
62
64
  | Setting | Type | Default | Description |
63
65
  |---|---|---|---|
64
66
  | `sessionDir` | string | Agent session directory | Session storage directory. Relative paths resolve from the working directory. `PI_CODING_AGENT_SESSION_DIR` and `--session-dir` override this setting. |
67
+ | `sessionShareDestination` | `"auto" \| "gist" \| "radius"` | `"auto"` | Destination used by `/share`. `auto` uses Radius when authenticated and otherwise creates a GitHub gist. `gist` always uses a gist. `radius` requires Radius authentication and never falls back to a gist. |
65
68
 
66
69
  ### Compaction
67
70
 
68
71
  | Setting | Type | Default | Description |
69
72
  |---|---|---|---|
70
73
  | `compaction.enabled` | boolean | `true` | Enable automatic compaction. |
71
- | `compaction.reserveTokens` | number | `16384` | Tokens reserved for the model response. |
74
+ | `compaction.reserveTokens` | number | `16384` | Free context tokens below which automatic compaction starts. |
72
75
  | `compaction.keepRecentTokens` | number | `20000` | Recent tokens retained without summarization. |
73
76
  | `compaction.modelOverrides` | object | None | Per-model token settings keyed by exact `provider/modelId`. |
74
77
 
@@ -97,9 +100,9 @@ See [Compaction Reference](compaction.md) for trigger, summarization, and valida
97
100
  | `fullscreenCopyOnSelect` | boolean | `true` | Copy selected text automatically in fullscreen mode. |
98
101
  | `fullscreenWheelScrollLines` | `"auto"` \| number | `"auto"` | Lines per mouse-wheel event in fullscreen mode, from 1 to 100. `"auto"` moves one line per event in local macOS terminals, which already accelerate wheel and trackpad input; elsewhere, and over SSH, it speeds up fast wheel spins to at most 6 lines per event. Alt+wheel moves five times as far. |
99
102
  | `editorPaddingX` | number | `0` | Horizontal editor padding from 0 to 3 cells. |
100
- | `outputPad` | `0 \| 1` | `1` | Horizontal transcript padding. |
103
+ | `outputPad` | `0 \| 1` | `1` | Horizontal transcript padding for messages, tool output, `!` command output, and summary blocks. |
101
104
  | `autocompleteMaxVisible` | number | `5` | Visible autocomplete entries, from 3 to 20. |
102
- | `showHardwareCursor` | boolean | `false` | Show the terminal cursor while Pi positions it for input methods. |
105
+ | `showHardwareCursor` | boolean | `false` | Use the terminal cursor instead of Pi's drawn cursor. Pi still positions it for input methods. |
103
106
  | `terminal.showImages` | boolean | `true` | Display inline images when supported. |
104
107
  | `terminal.imageWidthCells` | number | `60` | Preferred inline image width in terminal cells. |
105
108
  | `terminal.clearOnShrink` | boolean | `false` | Clear empty rows when rendered content shrinks. |
@@ -123,7 +126,7 @@ See [Themes](themes.md) and [Terminal Setup](terminal-setup.md) for format and p
123
126
  | `httpIdleTimeoutMs` | number | `300000` | HTTP header and body idle timeout in milliseconds. Set to `0` to disable. |
124
127
  | `websocketConnectTimeoutMs` | number | `15000` | WebSocket connection timeout in milliseconds. Set to `0` to disable. |
125
128
  | `retry.enabled` | boolean | `true` | Enable automatic agent-level retry for transient failures. |
126
- | `retry.maxRetries` | number | `3` | Maximum agent-level retry attempts. |
129
+ | `retry.maxRetries` | number | `8` | Maximum agent-level retry attempts. With the default delays, about four minutes of backoff in all. |
127
130
  | `retry.baseDelayMs` | number | `2000` | Initial exponential-backoff delay in milliseconds. |
128
131
  | `retry.maxAgentDelayMs` | number | `60000` | Maximum agent-level retry delay in milliseconds. |
129
132
  | `retry.provider.timeoutMs` | number | `httpIdleTimeoutMs` | Provider request timeout in milliseconds. |
@@ -217,3 +217,17 @@ Pi automatically detects OSC 8 hyperlinks, inline image protocols, and truecolor
217
217
  Settings take precedence over environment variables. An unset value or `auto` preserves automatic detection.
218
218
 
219
219
  Only force a capability supported by the complete terminal path. Unsupported escape sequences can corrupt rendering. See [Environment Variables](environment-variables.md#pi-process-configuration) and [Settings](settings.md) for the canonical value definitions.
220
+
221
+ ## Program status
222
+
223
+ Pi reports its state with the [Program Status Protocol (OSC 7501)](https://www.superlogical.com/rex/docs/build/program-status), so terminals and agent dashboards can show whether it is working, waiting for you, done, or failed:
224
+
225
+ | State | When |
226
+ |---|---|
227
+ | `working` | An agent run or compaction is in progress. The message is the session name. |
228
+ | `blocked` | An extension dialog or login waits for you. The message is the dialog title. |
229
+ | `done` | A run finished. The message is the session name. |
230
+ | `error` | A run ended with an error that is not retried. The message is the first line of the error. |
231
+ | `idle` | Pi started, or you cancelled the run. |
232
+
233
+ Reports never contain prompts or model output. Pi sends them only after the terminal answers the protocol's support query; tmux and screen do not forward them. Set `PI_PROGRAM_STATUS=1` to send reports without asking, or `PI_PROGRAM_STATUS=0` to turn them off.
package/docs/themes.md CHANGED
@@ -58,7 +58,7 @@ See [CLI resources](cli.md#resources) for the command-line option.
58
58
 
59
59
  ## Create a custom theme
60
60
 
61
- Copy one of the [built-in themes](https://github.com/earendil-works/pi/tree/main/packages/coding-agent/src/modes/interactive/theme) or create a new JSON file conforming to the [schema](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json). The built-in themes use OKHSL colors, with variables for colors that several roles share, so you can adjust a hue, saturation, or lightness directly.
61
+ Copy one of the [built-in themes](https://github.com/earendil-works/pi/tree/main/packages/coding-agent/src/modes/interactive/theme) or create a new JSON file conforming to the [schema](https://pi.dev/schemas/theme.schema.json). The built-in themes use OKHSL colors, with variables for colors that several roles share, so you can adjust a hue, saturation, or lightness directly.
62
62
 
63
63
  1. Save the file as `<agent-dir>/themes/my-theme.json`. The agent directory defaults to `~/.pi/agent`.
64
64
  2. Set its `name` to `my-theme`.
@@ -78,6 +78,8 @@ Use the theme name as the filename. Pi hot-reloads the active user theme only fr
78
78
  | `colors` | Yes | Assigns colors to terminal UI roles. The schema identifies required and optional roles. |
79
79
  | `export` | No | Overrides page and panel backgrounds in HTML exports. |
80
80
 
81
+ Theme objects are strict: only documented top-level fields and color tokens are accepted. Define reusable custom colors under `vars`; custom keys under `colors` or `export` and additional top-level metadata are rejected.
82
+
81
83
  A color can be written in six forms:
82
84
 
83
85
  | Form | Example | Meaning |
@@ -93,7 +95,7 @@ Terminal default colors render as the terminal's own colors. Where Pi needs a co
93
95
 
94
96
  Pi resolves chained variable references. A missing variable or circular reference makes the theme invalid. Pi uses truecolor when available, gamut-maps OKLCH to sRGB, and approximates colors for 256-color terminals. HTML exports convert OKHSL values to hexadecimal because CSS does not support them. If colors differ from their source values, check your terminal's truecolor detection and contrast settings. See [Configure Your Terminal](terminal-setup.md#override-detected-capabilities).
95
97
 
96
- Use the [theme JSON schema](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json) for the exact properties, required colors, and accepted value types.
98
+ Use the [theme JSON schema](https://pi.dev/schemas/theme.schema.json) for the exact properties, required colors, and accepted value types.
97
99
 
98
100
  Pi reports invalid theme files during startup and `/reload`.
99
101
 
package/docs/tui.md CHANGED
@@ -45,7 +45,7 @@ Prefer these components over rebuilding selection, scrolling, text editing, or w
45
45
 
46
46
  Use `matchesKey()` and `Key` for terminal keyboard input. The parser accounts for supported terminal protocols and key modifiers. Extension components should use the injected `KeybindingsManager` for configurable application actions.
47
47
 
48
- A component that displays a text cursor should implement `Focusable` and place `CURSOR_MARKER` immediately before its visual cursor. The TUI uses that marker to position the hardware cursor for input method editors.
48
+ A component that displays a text cursor should implement `Focusable` and place `CURSOR_MARKER` immediately before its visual cursor. Wrap the cursor cell in `renderFakeCursor()` so the TUI draws it in reverse video, or hides it after `CURSOR_MARKER` when the hardware cursor is shown. The TUI uses the marker to position the hardware cursor for input method editors.
49
49
 
50
50
  Containers that wrap an `Input` or `Editor` must propagate their `focused` state to that child. Without propagation, Chinese, Japanese, Korean, and other IME candidate windows can appear at the wrong screen position.
51
51
 
@@ -65,6 +65,76 @@ Regular mode leaves mouse input to the terminal because the terminal owns scroll
65
65
 
66
66
  `ctx.ui.custom()` temporarily gives one component control of the interactive area and resolves when that component calls the supplied completion callback.
67
67
 
68
+ ### Build a minimal custom screen
69
+
70
+ This complete extension shows the custom-component lifecycle: render within the supplied width, use injected keybindings, invalidate cached output after state changes, request a render, and finish through `done()`.
71
+
72
+ ```typescript
73
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
74
+ import { truncateToWidth } from "@earendil-works/pi-tui";
75
+
76
+ export default function (pi: ExtensionAPI) {
77
+ pi.registerCommand("pick-target", {
78
+ description: "Pick a deployment target",
79
+ handler: async (_args, ctx) => {
80
+ if (ctx.mode !== "tui") {
81
+ ctx.ui.notify("pick-target requires interactive mode", "error");
82
+ return;
83
+ }
84
+
85
+ const choices = ["development", "staging", "production"];
86
+ const selected = await ctx.ui.custom<string | undefined>((tui, theme, keybindings, done) => {
87
+ let selectedIndex = 0;
88
+ let cachedWidth: number | undefined;
89
+ let cachedLines: string[] | undefined;
90
+
91
+ const invalidate = () => {
92
+ cachedWidth = undefined;
93
+ cachedLines = undefined;
94
+ };
95
+
96
+ return {
97
+ render(width: number): string[] {
98
+ if (cachedLines && cachedWidth === width) return cachedLines;
99
+
100
+ cachedWidth = width;
101
+ cachedLines = [
102
+ theme.fg("accent", "Choose a deployment target"),
103
+ ...choices.map((choice, index) => `${index === selectedIndex ? "> " : " "}${choice}`),
104
+ theme.fg("dim", "up/down move, enter selects, escape cancels"),
105
+ ].map((line) => truncateToWidth(line, width));
106
+ return cachedLines;
107
+ },
108
+ handleInput(data: string): void {
109
+ if (keybindings.matches(data, "tui.select.up")) {
110
+ selectedIndex = (selectedIndex - 1 + choices.length) % choices.length;
111
+ } else if (keybindings.matches(data, "tui.select.down")) {
112
+ selectedIndex = (selectedIndex + 1) % choices.length;
113
+ } else if (keybindings.matches(data, "tui.select.confirm")) {
114
+ done(choices[selectedIndex]);
115
+ return;
116
+ } else if (keybindings.matches(data, "tui.select.cancel")) {
117
+ done(undefined);
118
+ return;
119
+ } else {
120
+ return;
121
+ }
122
+
123
+ invalidate();
124
+ tui.requestRender();
125
+ },
126
+ invalidate,
127
+ };
128
+ });
129
+
130
+ if (selected) ctx.ui.notify(`Selected ${selected}`, "info");
131
+ },
132
+ });
133
+ }
134
+ ```
135
+
136
+ This component does not display a text cursor, so it does not need `Focusable`. A component containing `Input` or `Editor` must implement `Focusable` and propagate its `focused` value to that child.
137
+
68
138
  Pass `overlay: true` to draw above existing content. Overlay options control size, anchors, offsets, margins, and responsive visibility. An overlay handle can change focus or temporarily hide and show the overlay with `setHidden()` while the interaction remains active.
69
139
 
70
140
  Focused overlays retain input ownership across ordinary renders. If another component should receive input while an overlay remains visible, explicitly release or redirect focus through the handle.
package/docs/usage.md CHANGED
@@ -79,7 +79,7 @@ Use `!!` when you want to run a command without sending its output to the model.
79
79
 
80
80
  Press `Ctrl+X` or run `/copy` to copy the last assistant response. Use `/export` to save the session as HTML or JSONL.
81
81
 
82
- Use `/share` to upload the session and get a viewer link. With Radius authentication, the artifact is visible to your Radius organization. Otherwise, Pi creates a private GitHub gist through the GitHub CLI. Review the session first because it can contain prompts, tool output, file contents, and credentials exposed during the conversation.
82
+ Use `/share` to upload the session and get a viewer link. By default, Radius authentication makes the artifact visible to your Radius organization; otherwise, Pi creates a private GitHub gist through the GitHub CLI. The [`sessionShareDestination`](settings.md#sessions-and-context) setting can force either destination. Review the session first because it can contain prompts, tool output, file contents, and credentials exposed during the conversation.
83
83
 
84
84
  ## Adjust the terminal
85
85
 
@@ -28,9 +28,6 @@ Example extensions demonstrating:
28
28
  - External integrations (SSH, file watchers, system theme sync)
29
29
  - Custom providers (Anthropic with custom streaming, GitLab Duo)
30
30
 
31
- ### [plugins/pi-example-plugin/](plugins/pi-example-plugin/)
32
- An experimental plugin package that Pi automatically builds into separate Session-worker and TUI Chord facets.
33
-
34
31
  ## Documentation
35
32
 
36
33
  - [SDK Examples](sdk/README.md)