@psnext/slingcli 3.0.20260810-3 → 3.0.20260811-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.
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl/codec.js +4 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/testing/conformance.js +19 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js +12 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +2 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-workers-ai.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/deepseek.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/google.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/project-trust.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -3
- package/node_modules/@earendil-works/pi-coding-agent/docs/compaction.md +9 -9
- package/node_modules/@earendil-works/pi-coding-agent/docs/containerization.md +8 -8
- package/node_modules/@earendil-works/pi-coding-agent/docs/custom-provider.md +20 -12
- package/node_modules/@earendil-works/pi-coding-agent/docs/development.md +71 -0
- package/node_modules/@earendil-works/pi-coding-agent/docs/docs.json +14 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/environment-variables.md +9 -9
- package/node_modules/@earendil-works/pi-coding-agent/docs/extensions.md +53 -26
- package/node_modules/@earendil-works/pi-coding-agent/docs/index.md +10 -9
- package/node_modules/@earendil-works/pi-coding-agent/docs/json.md +21 -16
- package/node_modules/@earendil-works/pi-coding-agent/docs/keybindings.md +46 -14
- package/node_modules/@earendil-works/pi-coding-agent/docs/llama-cpp.md +3 -3
- package/node_modules/@earendil-works/pi-coding-agent/docs/mcp.md +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/docs/models.md +25 -4
- package/node_modules/@earendil-works/pi-coding-agent/docs/packages.md +13 -13
- package/node_modules/@earendil-works/pi-coding-agent/docs/prompt-templates.md +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/providers.md +317 -0
- package/node_modules/@earendil-works/pi-coding-agent/docs/quickstart.md +11 -9
- package/node_modules/@earendil-works/pi-coding-agent/docs/rpc.md +15 -13
- package/node_modules/@earendil-works/pi-coding-agent/docs/sdk.md +33 -14
- package/node_modules/@earendil-works/pi-coding-agent/docs/security.md +5 -5
- package/node_modules/@earendil-works/pi-coding-agent/docs/session-format.md +3 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/sessions.md +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/settings.md +6 -2
- package/node_modules/@earendil-works/pi-coding-agent/docs/shell-aliases.md +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/skills.md +5 -5
- package/node_modules/@earendil-works/pi-coding-agent/docs/terminal-setup.md +3 -3
- package/node_modules/@earendil-works/pi-coding-agent/docs/termux.md +5 -5
- package/node_modules/@earendil-works/pi-coding-agent/docs/themes.md +7 -5
- package/node_modules/@earendil-works/pi-coding-agent/docs/tmux.md +3 -3
- package/node_modules/@earendil-works/pi-coding-agent/docs/usage.md +17 -10
- package/node_modules/@earendil-works/pi-coding-agent/docs/windows.md +1 -1
- package/package.json +2 -2
- package/slingshot/index.js +9 -7
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
>
|
|
1
|
+
> sling can create extensions. Ask it to build one for your use case.
|
|
2
2
|
|
|
3
3
|
# Extensions
|
|
4
4
|
|
|
@@ -103,7 +103,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
103
103
|
Test with `--extension` (or `-e`) flag:
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
|
-
|
|
106
|
+
pi -e ./my-extension.ts
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
## Extension Locations
|
|
@@ -134,7 +134,7 @@ Additional paths via `settings.json`:
|
|
|
134
134
|
}
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
-
To share extensions via npm or git as sling packages, see [packages.md](packages.md).
|
|
137
|
+
To share extensions via npm or git as sling/pi packages, see [packages.md](packages.md).
|
|
138
138
|
|
|
139
139
|
## Available Imports
|
|
140
140
|
|
|
@@ -178,7 +178,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
178
178
|
|
|
179
179
|
Extensions are loaded via [jiti](https://github.com/unjs/jiti), so TypeScript works without compilation.
|
|
180
180
|
|
|
181
|
-
If the factory returns a `Promise`, sling awaits it before continuing startup. That means async initialization completes before `session_start`, before `resources_discover`, and before provider registrations queued via `
|
|
181
|
+
If the factory returns a `Promise`, sling awaits it before continuing startup. That means async initialization completes before `session_start`, before `resources_discover`, and before provider registrations queued via `pi.registerProvider()` are flushed.
|
|
182
182
|
|
|
183
183
|
### Async factory functions
|
|
184
184
|
|
|
@@ -275,7 +275,7 @@ Run `npm install` in the extension directory, then imports from `node_modules/`
|
|
|
275
275
|
### Lifecycle Overview
|
|
276
276
|
|
|
277
277
|
```
|
|
278
|
-
|
|
278
|
+
pi starts
|
|
279
279
|
│
|
|
280
280
|
├─► project_trust (user/global and CLI extensions only, before project resources load)
|
|
281
281
|
├─► session_start { reason: "startup" }
|
|
@@ -551,13 +551,13 @@ pi.on("before_agent_start", async (event, ctx) => {
|
|
|
551
551
|
});
|
|
552
552
|
```
|
|
553
553
|
|
|
554
|
-
The `systemPromptOptions` field gives extensions access to the same structured data
|
|
554
|
+
The `systemPromptOptions` field gives extensions access to the same structured data Sling uses to build the system prompt. This lets you inspect what Sling has loaded — custom prompts, guidelines, tool snippets, context files, skills — without re-discovering resources or re-parsing flags. Use it when your extension needs to make deep, informed changes to the system prompt while respecting user-provided configuration.
|
|
555
555
|
|
|
556
556
|
Inside `before_agent_start`, `event.systemPrompt` and `ctx.getSystemPrompt()` both reflect the chained system prompt as of the current handler. Later `before_agent_start` handlers can still modify it again.
|
|
557
557
|
|
|
558
558
|
#### agent_start / agent_end / agent_settled
|
|
559
559
|
|
|
560
|
-
`agent_start` fires when a low-level agent run begins. `agent_end` fires when that run ends, but
|
|
560
|
+
`agent_start` fires when a low-level agent run begins. `agent_end` fires when that run ends, but Sling may still auto-retry, auto-compact and retry, or continue with queued follow-up messages. Use `agent_settled` for status integrations that need to know Sling will not continue running automatically.
|
|
561
561
|
|
|
562
562
|
```typescript
|
|
563
563
|
pi.on("agent_start", async (_event, ctx) => {});
|
|
@@ -668,7 +668,7 @@ pi.on("before_provider_headers", (event, ctx) => {
|
|
|
668
668
|
// Add or override — e.g. a session id for gateway tracing/attribution
|
|
669
669
|
event.headers["x-session-id"] = ctx.sessionManager.getSessionId();
|
|
670
670
|
|
|
671
|
-
// Drop a tracking header
|
|
671
|
+
// Drop a tracking header pi adds for this call
|
|
672
672
|
event.headers["X-OpenRouter-Title"] = null;
|
|
673
673
|
});
|
|
674
674
|
```
|
|
@@ -679,7 +679,7 @@ Runs once per provider request; retries reuse the same headers rather than re-fi
|
|
|
679
679
|
|
|
680
680
|
Fired after the provider-specific payload is built, right before the request is sent. Handlers run in extension load order. Returning `undefined` keeps the payload unchanged. Returning any other value replaces the payload for later handlers and for the actual request.
|
|
681
681
|
|
|
682
|
-
This hook can rewrite provider-level system instructions or remove them entirely. Those payload-level changes are not reflected by `ctx.getSystemPrompt()`, which reports
|
|
682
|
+
This hook can rewrite provider-level system instructions or remove them entirely. Those payload-level changes are not reflected by `ctx.getSystemPrompt()`, which reports Sling's system prompt string rather than the final serialized provider payload.
|
|
683
683
|
|
|
684
684
|
```typescript
|
|
685
685
|
pi.on("before_provider_request", (event, ctx) => {
|
|
@@ -762,7 +762,8 @@ Behavior guarantees:
|
|
|
762
762
|
- Mutations to `event.input` affect the actual tool execution
|
|
763
763
|
- Later `tool_call` handlers see mutations made by earlier handlers
|
|
764
764
|
- No re-validation is performed after your mutation
|
|
765
|
-
- Return values from `tool_call`
|
|
765
|
+
- Return values from `tool_call` control blocking via `{ block: true, reason?: string, terminate?: boolean }`
|
|
766
|
+
- `terminate` only applies to a blocked call; the agent stops early only when every finalized result in the batch is terminating
|
|
766
767
|
|
|
767
768
|
```typescript
|
|
768
769
|
import { isToolCallEventType } from "@earendil-works/pi-coding-agent";
|
|
@@ -778,7 +779,7 @@ pi.on("tool_call", async (event, ctx) => {
|
|
|
778
779
|
event.input.command = `source ~/.profile\n${event.input.command}`;
|
|
779
780
|
|
|
780
781
|
if (event.input.command.includes("rm -rf")) {
|
|
781
|
-
return { block: true, reason: "Dangerous command" };
|
|
782
|
+
return { block: true, reason: "Dangerous command", terminate: true };
|
|
782
783
|
}
|
|
783
784
|
}
|
|
784
785
|
|
|
@@ -982,10 +983,12 @@ ctx.sessionManager.buildContextEntries() // Active branch entries with compac
|
|
|
982
983
|
ctx.sessionManager.getLeafId() // Current leaf entry ID
|
|
983
984
|
```
|
|
984
985
|
|
|
985
|
-
### ctx.modelRegistry / ctx.model / ctx.thinkingLevel
|
|
986
|
+
### ctx.modelRegistry / ctx.model / ctx.thinkingLevel / ctx.scopedModels
|
|
986
987
|
|
|
987
988
|
Access to models, providers, and resolved authentication. `ctx.modelRegistry.getProvider(id)` returns the effective pi-ai provider, while `getProviderAuth(id)` resolves its current API key, headers, base URL, and provider-scoped environment without requiring a loaded model. `ctx.model` is the active model, and `ctx.thinkingLevel` is its current effective thinking level.
|
|
988
989
|
|
|
990
|
+
`ctx.scopedModels` is the read-only list of models scoped to the current session — the same set the `/scoped-models` command shows. It is resolved at session start from the `--models` CLI flag and the `enabledModels` setting (matched against the available catalogue with minimatch on `provider/modelId` or a bare `modelId`). It is empty when no scoping is configured, meaning every available model is usable. Each entry is `{ model, thinkingLevel? }`, where `thinkingLevel` is set only when a pattern pinned it (e.g. `anthropic/*:high`). Use it to populate a model picker that mirrors the built-in one instead of enumerating the whole catalogue via `ctx.modelRegistry.getAvailable()`.
|
|
991
|
+
|
|
989
992
|
### ctx.signal
|
|
990
993
|
|
|
991
994
|
The current agent abort signal, or `undefined` when no agent turn is active.
|
|
@@ -1013,7 +1016,7 @@ pi.on("tool_result", async (event, ctx) => {
|
|
|
1013
1016
|
|
|
1014
1017
|
### ctx.isIdle() / ctx.abort() / ctx.hasPendingMessages()
|
|
1015
1018
|
|
|
1016
|
-
Control flow helpers. `ctx.isIdle()` is false while
|
|
1019
|
+
Control flow helpers. `ctx.isIdle()` is false while Sling is processing an agent run, automatic retry, auto-compaction retry, or queued continuation.
|
|
1017
1020
|
|
|
1018
1021
|
### ctx.shutdown()
|
|
1019
1022
|
|
|
@@ -1062,7 +1065,7 @@ ctx.compact({
|
|
|
1062
1065
|
|
|
1063
1066
|
### ctx.getSystemPrompt()
|
|
1064
1067
|
|
|
1065
|
-
Returns
|
|
1068
|
+
Returns Sling's current system prompt string.
|
|
1066
1069
|
|
|
1067
1070
|
- During `before_agent_start`, this reflects chained system-prompt changes made so far for the current turn.
|
|
1068
1071
|
- It does not include later `context` message mutations.
|
|
@@ -1082,7 +1085,7 @@ Command handlers receive `ExtensionCommandContext`, which extends `ExtensionCont
|
|
|
1082
1085
|
|
|
1083
1086
|
### ctx.getSystemPromptOptions()
|
|
1084
1087
|
|
|
1085
|
-
Returns the base inputs
|
|
1088
|
+
Returns the base inputs Sling currently uses to build the system prompt.
|
|
1086
1089
|
|
|
1087
1090
|
```typescript
|
|
1088
1091
|
const options = ctx.getSystemPromptOptions();
|
|
@@ -1560,6 +1563,27 @@ mode and would not execute if sent via `prompt`.
|
|
|
1560
1563
|
|
|
1561
1564
|
Register a custom TUI renderer for custom messages with your `customType`. Custom messages are created with `pi.sendMessage()` and participate in LLM context. See [Custom UI](#custom-ui).
|
|
1562
1565
|
|
|
1566
|
+
### pi.registerMarkdownTransformer(transformer)
|
|
1567
|
+
|
|
1568
|
+
Register a transformer for the Markdown in normal user text, assistant text, and thinking blocks. Transformers run in extension load order, and each transformer receives the Markdown returned by the previous transformer. After the chain finishes, Sling renders the transformed content with its built-in renderer.
|
|
1569
|
+
|
|
1570
|
+
The transformer receives the Markdown string and a context with:
|
|
1571
|
+
|
|
1572
|
+
- `messageType` — `"user"`, `"assistant"`, or `"assistant-thinking"`
|
|
1573
|
+
- `isStreaming` — `true` for partial assistant updates; `false` for user, finalized assistant, and restored messages
|
|
1574
|
+
- `availableWidth` — exact terminal columns available for the transformed Markdown content
|
|
1575
|
+
|
|
1576
|
+
Return the transformed Markdown:
|
|
1577
|
+
|
|
1578
|
+
```typescript
|
|
1579
|
+
pi.registerMarkdownTransformer((markdown, { messageType, isStreaming }) => {
|
|
1580
|
+
if (isStreaming || messageType === "assistant-thinking") return markdown;
|
|
1581
|
+
return markdown.replaceAll("-->", "→");
|
|
1582
|
+
});
|
|
1583
|
+
```
|
|
1584
|
+
|
|
1585
|
+
If a transformer throws, Sling keeps the Markdown produced so far and continues with the next transformer. The hook is display-only: the original message remains unchanged in the session and model context. It runs for new user messages, assistant streaming updates, restored session messages, and terminal width changes, so transformers should remain synchronous and inexpensive.
|
|
1586
|
+
|
|
1563
1587
|
### pi.registerEntryRenderer(customType, renderer)
|
|
1564
1588
|
|
|
1565
1589
|
Register a custom TUI renderer for custom entries with your `customType`. Custom entries are created with `pi.appendEntry()` and do not participate in LLM context.
|
|
@@ -1684,7 +1708,9 @@ Register or override a model provider dynamically. Useful for proxies, custom en
|
|
|
1684
1708
|
|
|
1685
1709
|
Calls made during the extension factory function are queued and applied once the runner initialises. Calls made after that — for example from a command handler following a user setup flow — take effect immediately without requiring a `/reload`.
|
|
1686
1710
|
|
|
1687
|
-
Dynamic providers can implement `refreshModels`.
|
|
1711
|
+
Dynamic providers can implement `refreshModels`. Sling calls it during model refresh, publishes the returned list synchronously through the provider, and passes the canonical credential/stored-catalog/network/signal context. The extension decides whether to persist catalog metadata through generation-checked `context.publish({ persist: entry })`; live servers such as llama.cpp can return models without persisting them.
|
|
1712
|
+
|
|
1713
|
+
`context.signal` is always a concrete signal and provider callbacks must pass it to blocking I/O. Public `ModelRuntime.refresh()` and `ModelRegistry.refresh()` calls accept an optional signal and are unbounded when it is omitted; extensions and applications choose their own deadlines. Cancellation stops the caller waiting even if a provider ignores the signal, but cooperation is still required to stop the underlying work.
|
|
1688
1714
|
|
|
1689
1715
|
Extensions that need native provider auth, filtering, refresh, or stream behavior can register a complete `Provider` from `@earendil-works/pi-ai`. The provider becomes the composition base and `models.json` overrides still apply above it.
|
|
1690
1716
|
|
|
@@ -1774,7 +1800,8 @@ pi.registerProvider("corporate-ai", {
|
|
|
1774
1800
|
const code = await callbacks.onPrompt({ message: "Enter code:" });
|
|
1775
1801
|
return { refresh: code, access: code, expires: Date.now() + 3600000 };
|
|
1776
1802
|
},
|
|
1777
|
-
async refreshToken(credentials) {
|
|
1803
|
+
async refreshToken(credentials, signal) {
|
|
1804
|
+
signal.throwIfAborted();
|
|
1778
1805
|
// Refresh logic
|
|
1779
1806
|
return credentials;
|
|
1780
1807
|
},
|
|
@@ -1795,7 +1822,7 @@ The object form accepts a complete pi-ai `Provider`, including native `auth`, `g
|
|
|
1795
1822
|
- `headers` - Custom headers to include in requests.
|
|
1796
1823
|
- `authHeader` - If true, adds `Authorization: Bearer` header automatically.
|
|
1797
1824
|
- `models` - Array of model definitions. If provided, replaces all existing models for this provider. Model definitions can set `baseUrl` to override the provider endpoint for that model.
|
|
1798
|
-
- `refreshModels` - Async dynamic discovery callback. Its returned models replace extension-provided models.
|
|
1825
|
+
- `refreshModels` - Async dynamic discovery callback. Its returned models replace extension-provided models. `context.stored` contains the persisted provider snapshot; use generation-checked `context.publish({ persist: entry })` only when updated catalog data should persist. Use `persist: null` to delete that snapshot.
|
|
1799
1826
|
- `oauth` - OAuth provider config for `/login` support. When provided, the provider appears in the login menu.
|
|
1800
1827
|
- `streamSimple` - Custom streaming implementation for non-standard APIs.
|
|
1801
1828
|
|
|
@@ -1952,7 +1979,7 @@ pi.registerTool({
|
|
|
1952
1979
|
});
|
|
1953
1980
|
```
|
|
1954
1981
|
|
|
1955
|
-
**Usage accounting:** If a tool makes nested LLM calls, return their combined `Usage` as `usage`.
|
|
1982
|
+
**Usage accounting:** If a tool makes nested LLM calls, return their combined `Usage` as `usage`. Sling persists it on the tool result and includes it in footer, `/session`, and RPC session totals. `tool_result` handlers can inspect or replace this value.
|
|
1956
1983
|
|
|
1957
1984
|
**Signaling errors:** To mark a tool execution as failed (sets `isError: true` on the result and reports it to the LLM), throw an error from `execute`. Returning a value never sets the error flag regardless of what properties you include in the return object.
|
|
1958
1985
|
|
|
@@ -2023,13 +2050,13 @@ Extensions can override built-in tools (`read`, `bash`, `edit`, `write`, `grep`,
|
|
|
2023
2050
|
|
|
2024
2051
|
```bash
|
|
2025
2052
|
# Extension's read tool replaces built-in read
|
|
2026
|
-
|
|
2053
|
+
pi -e ./tool-override.ts
|
|
2027
2054
|
```
|
|
2028
2055
|
|
|
2029
2056
|
Alternatively, use `--no-builtin-tools` to start without any built-in tools while keeping extension tools enabled:
|
|
2030
2057
|
```bash
|
|
2031
2058
|
# No built-in tools, only extension tools
|
|
2032
|
-
|
|
2059
|
+
pi --no-builtin-tools -e ./my-extension.ts
|
|
2033
2060
|
```
|
|
2034
2061
|
|
|
2035
2062
|
See [examples/extensions/tool-override.ts](../examples/extensions/tool-override.ts) for a complete example that overrides `read` with logging and access control.
|
|
@@ -2303,7 +2330,7 @@ If a slot renderer is not defined or throws:
|
|
|
2303
2330
|
|
|
2304
2331
|
### Dynamic Tool Loading
|
|
2305
2332
|
|
|
2306
|
-
Extensions can register many tools while keeping only a small initial set active. A tool can then add more tools with `pi.setActiveTools()` during execution.
|
|
2333
|
+
Extensions can register many tools while keeping only a small initial set active. A tool can then add more tools with `pi.setActiveTools()` during execution. sling detects purely additive changes, records the newly available tool names on that tool result, and applies the updated active set before the next model request.
|
|
2307
2334
|
|
|
2308
2335
|
This works with every model. Models with native deferred-loading support preserve the stable prompt prefix and load the new definitions at the tool-result position. Other models use the fallback described below.
|
|
2309
2336
|
|
|
@@ -2312,8 +2339,8 @@ The lifecycle is:
|
|
|
2312
2339
|
1. Register every tool with `pi.registerTool()` so it appears in `pi.getAllTools()`.
|
|
2313
2340
|
2. Keep loader tools, such as `search_tools`, active and leave searchable tools inactive.
|
|
2314
2341
|
3. During loader execution, call `pi.setActiveTools([...currentTools, ...matchingTools])`. The change must be additive: do not remove currently active tools in the same call.
|
|
2315
|
-
4.
|
|
2316
|
-
5. Before the next model response,
|
|
2342
|
+
4. sling records which tools were added on the loader's tool result.
|
|
2343
|
+
5. Before the next model response, sling exposes the added definitions using native deferred loading when supported, or the normal active tool list otherwise.
|
|
2317
2344
|
|
|
2318
2345
|
You do not need to return provider-specific tool references or mark the loader as a special search tool. The active-tool change is the signal. Names passed to `pi.setActiveTools()` must already be registered; unknown names are ignored.
|
|
2319
2346
|
|
|
@@ -2324,13 +2351,13 @@ You do not need to return provider-specific tool references or mark the loader a
|
|
|
2324
2351
|
- **Native representation:** Deferred definitions use `defer_loading`; the load point uses `tool_reference` content.
|
|
2325
2352
|
- **OpenAI**
|
|
2326
2353
|
- **Models:** `gpt-5.4` and newer family
|
|
2327
|
-
- **Native representation:**
|
|
2354
|
+
- **Native representation:** sling adds completed client `tool_search_call` and `tool_search_output` items at the load point.
|
|
2328
2355
|
|
|
2329
2356
|
For a verified custom model or proxy, native handling can be enabled with `compat.supportsToolReferences: true` for `anthropic-messages`, or `compat.supportsToolSearch: true` for `openai-responses` and `openai-codex-responses`. Leave these disabled unless the endpoint and model accept the corresponding native protocol.
|
|
2330
2357
|
|
|
2331
2358
|
#### Fallback behavior
|
|
2332
2359
|
|
|
2333
|
-
For all other models and providers, dynamic activation still works:
|
|
2360
|
+
For all other models and providers, dynamic activation still works: sling sends the complete current active tool list normally on the next request. The model can call the newly activated tools, but adding their definitions may invalidate the provider's cached prompt prefix.
|
|
2334
2361
|
|
|
2335
2362
|
Pi also uses this safe fallback when the active set is not purely additive, such as replacing one group of tools with another. Tool removals therefore work, but they do not use deferred loading.
|
|
2336
2363
|
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
#
|
|
1
|
+
# sling Documentation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
sling is a minimal terminal coding harness. It is designed to stay small at the core while being extended through TypeScript extensions, skills, prompt templates, themes, and sling packages.
|
|
4
4
|
|
|
5
5
|
## Quick start
|
|
6
6
|
|
|
7
|
-
Install
|
|
7
|
+
Install sling with npm:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
npm install -g --ignore-scripts @psnext/slingcli
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
`--ignore-scripts` disables dependency lifecycle scripts during install.
|
|
13
|
+
`--ignore-scripts` disables dependency lifecycle scripts during install. sling does not require install scripts for normal npm installs.
|
|
14
14
|
|
|
15
15
|
On Linux or macOS, you can also use the installer:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
curl -fsSL https://
|
|
18
|
+
curl -fsSL https://sapientaiproducts.com/slingshot/slingcli/install.sh | sh
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
To uninstall sling itself, use npm for curl and npm installs:
|
|
@@ -32,14 +32,14 @@ Then run it in a project directory:
|
|
|
32
32
|
sling
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
Authenticate with `/login` for subscription providers, or set an API key such as `
|
|
35
|
+
Authenticate with `/login` for subscription providers, or set an API key such as `SLINGSHOT_API_KEY` before starting sling.
|
|
36
36
|
|
|
37
37
|
For the full first-run flow, see [Quickstart](quickstart.md).
|
|
38
38
|
|
|
39
39
|
## Start here
|
|
40
40
|
|
|
41
41
|
- [Quickstart](quickstart.md) - install, authenticate, and run a first session.
|
|
42
|
-
- [Using
|
|
42
|
+
- [Using sling](usage.md) - interactive mode, slash commands, context files, and CLI reference.
|
|
43
43
|
- [Providers](providers.md) - subscription and API-key setup for built-in providers.
|
|
44
44
|
- [llama.cpp](llama-cpp.md) - run a local router and manage models with `/llama`.
|
|
45
45
|
- [Security](security.md) - project trust, sandbox boundaries, and vulnerability reporting.
|
|
@@ -55,19 +55,20 @@ For the full first-run flow, see [Quickstart](quickstart.md).
|
|
|
55
55
|
- [Skills](skills.md) - Agent Skills for reusable on-demand capabilities.
|
|
56
56
|
- [Prompt templates](prompt-templates.md) - reusable prompts that expand from slash commands.
|
|
57
57
|
- [Themes](themes.md) - built-in and custom terminal themes.
|
|
58
|
-
- [
|
|
58
|
+
- [sling packages](packages.md) - bundle and share extensions, skills, prompts, and themes.
|
|
59
59
|
- [Custom models](models.md) - add model entries for supported provider APIs.
|
|
60
60
|
- [Custom providers](custom-provider.md) - implement custom APIs and OAuth flows.
|
|
61
61
|
|
|
62
62
|
## Programmatic usage
|
|
63
63
|
|
|
64
|
+
- [SDK](sdk.md) - embed sling in Node.js applications.
|
|
64
65
|
- [RPC mode](rpc.md) - integrate over stdin/stdout JSONL.
|
|
65
66
|
- [JSON event stream mode](json.md) - print mode with structured events.
|
|
66
67
|
- [TUI components](tui.md) - build custom terminal UI for extensions.
|
|
67
68
|
|
|
68
69
|
## Reference
|
|
69
70
|
|
|
70
|
-
- [Environment variables](environment-variables.md) -
|
|
71
|
+
- [Environment variables](environment-variables.md) - sling process configuration and session metadata available to bash tools.
|
|
71
72
|
- [Session format](session-format.md) - JSONL session file format, entry types, and SessionManager API.
|
|
72
73
|
|
|
73
74
|
## Platform setup
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
# JSON Event Stream Mode
|
|
2
2
|
|
|
3
3
|
```bash
|
|
4
|
-
|
|
4
|
+
pi --mode json "Your prompt"
|
|
5
5
|
```
|
|
6
6
|
|
|
7
7
|
Outputs all session events as JSON lines to stdout. Useful for integrating sling into other tools or custom UIs.
|
|
8
8
|
|
|
9
9
|
## Event Types
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Wire events use `JsonAgentSessionEvent`. It matches
|
|
12
|
+
[`AgentSessionEvent`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/agent-session.ts)
|
|
13
|
+
except that streaming message updates omit cumulative snapshots:
|
|
12
14
|
|
|
13
15
|
```typescript
|
|
14
|
-
type
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
| { type: "
|
|
18
|
-
| {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
| { type: "summarization_retry_attempt_start"; source: "branchSummary" }
|
|
23
|
-
| { type: "summarization_retry_attempt_start"; source: "compaction"; reason: "manual" | "threshold" | "overflow" }
|
|
24
|
-
| { type: "summarization_retry_finished" };
|
|
16
|
+
type WithoutPartial<T> = T extends { partial: unknown } ? Omit<T, "partial"> : T;
|
|
17
|
+
|
|
18
|
+
type JsonAgentSessionEvent =
|
|
19
|
+
| Exclude<AgentSessionEvent, { type: "message_update" }>
|
|
20
|
+
| {
|
|
21
|
+
type: "message_update";
|
|
22
|
+
assistantMessageEvent: WithoutPartial<AssistantMessageEvent>;
|
|
23
|
+
};
|
|
25
24
|
```
|
|
26
25
|
|
|
27
26
|
`queue_update` emits the full pending steering and follow-up queues whenever they change. `compaction_start` and `compaction_end` cover both manual and automatic compaction.
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
Other base events come from
|
|
29
|
+
[`AgentEvent`](https://github.com/earendil-works/pi-mono/blob/main/packages/agent/src/types.ts):
|
|
30
30
|
|
|
31
31
|
```typescript
|
|
32
32
|
type AgentEvent =
|
|
@@ -73,14 +73,19 @@ Followed by events as they occur:
|
|
|
73
73
|
{"type":"agent_start"}
|
|
74
74
|
{"type":"turn_start"}
|
|
75
75
|
{"type":"message_start","message":{"role":"assistant","content":[],...}}
|
|
76
|
-
{"type":"message_update","
|
|
76
|
+
{"type":"message_update","assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
|
|
77
77
|
{"type":"message_end","message":{...}}
|
|
78
78
|
{"type":"turn_end","message":{...},"toolResults":[]}
|
|
79
79
|
{"type":"agent_end","messages":[...]}
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
+
`message_update` records are delta-only. They omit both the cumulative `message` field and
|
|
83
|
+
`assistantMessageEvent.partial` to keep stream size linear. Use `contentIndex` and `delta`
|
|
84
|
+
to assemble live text, thinking, or tool-call arguments if needed. `message_end` contains
|
|
85
|
+
the final authoritative message.
|
|
86
|
+
|
|
82
87
|
## Example
|
|
83
88
|
|
|
84
89
|
```bash
|
|
85
|
-
|
|
90
|
+
pi --mode json "List files" 2>/dev/null | jq -c 'select(.type == "message_end")'
|
|
86
91
|
```
|
|
@@ -10,7 +10,7 @@ After editing `keybindings.json`, run `/reload` in sling to apply the changes wi
|
|
|
10
10
|
|
|
11
11
|
## Key Format
|
|
12
12
|
|
|
13
|
-
`modifier+key` where modifiers are `ctrl`, `shift`, `alt` (combinable) and keys are:
|
|
13
|
+
`modifier+key` where modifiers are `ctrl`, `shift`, `alt`, `super` (combinable) and keys are:
|
|
14
14
|
|
|
15
15
|
- **Letters:** `a-z`
|
|
16
16
|
- **Digits:** `0-9`
|
|
@@ -18,7 +18,9 @@ After editing `keybindings.json`, run `/reload` in sling to apply the changes wi
|
|
|
18
18
|
- **Function:** `f1`-`f12`
|
|
19
19
|
- **Symbols:** `` ` ``, `-`, `=`, `[`, `]`, `\`, `;`, `'`, `,`, `.`, `/`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `)`, `_`, `+`, `|`, `~`, `{`, `}`, `:`, `<`, `>`, `?`
|
|
20
20
|
|
|
21
|
-
Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1`, etc.
|
|
21
|
+
Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `super+k`, `ctrl+super+k`, `ctrl+1`, etc.
|
|
22
|
+
|
|
23
|
+
`super` bindings require a terminal that reports the modifier separately, typically through the Kitty keyboard protocol. They may not work in terminals without that support.
|
|
22
24
|
|
|
23
25
|
## All Actions
|
|
24
26
|
|
|
@@ -26,18 +28,22 @@ Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1
|
|
|
26
28
|
|
|
27
29
|
| Keybinding id | Default | Description |
|
|
28
30
|
|--------|---------|-------------|
|
|
29
|
-
| `tui.editor.cursorUp` | `up` | Move cursor up |
|
|
30
|
-
| `tui.editor.cursorDown` | `down` | Move cursor down |
|
|
31
|
+
| `tui.editor.cursorUp` | `up` | Move cursor up, browsing older history at the top |
|
|
32
|
+
| `tui.editor.cursorDown` | `down` | Move cursor down, browsing newer history at the bottom |
|
|
33
|
+
| `tui.editor.historyPrevious` | *(none)* | Select the previous prompt history entry |
|
|
34
|
+
| `tui.editor.historyNext` | *(none)* | Select the next prompt history entry |
|
|
31
35
|
| `tui.editor.cursorLeft` | `left`, `ctrl+b` | Move cursor left |
|
|
32
36
|
| `tui.editor.cursorRight` | `right`, `ctrl+f` | Move cursor right |
|
|
33
37
|
| `tui.editor.cursorWordLeft` | `alt+left`, `ctrl+left`, `alt+b` | Move cursor word left |
|
|
34
38
|
| `tui.editor.cursorWordRight` | `alt+right`, `ctrl+right`, `alt+f` | Move cursor word right |
|
|
35
|
-
| `tui.editor.cursorLineStart` | `home`, `ctrl+a` | Move to line start |
|
|
36
|
-
| `tui.editor.cursorLineEnd` | `end`, `ctrl+e` | Move to line end |
|
|
39
|
+
| `tui.editor.cursorLineStart` | `home`, `ctrl+home`, `ctrl+a` | Move to line start |
|
|
40
|
+
| `tui.editor.cursorLineEnd` | `end`, `ctrl+end`, `ctrl+e` | Move to line end |
|
|
37
41
|
| `tui.editor.jumpForward` | `ctrl+]` | Jump forward to character |
|
|
38
42
|
| `tui.editor.jumpBackward` | `ctrl+alt+]` | Jump backward to character |
|
|
39
|
-
| `tui.editor.pageUp` | `pageUp` | Scroll up by page |
|
|
40
|
-
| `tui.editor.pageDown` | `pageDown` | Scroll down by page |
|
|
43
|
+
| `tui.editor.pageUp` | `pageUp`, `ctrl+pageUp` | Scroll up by page |
|
|
44
|
+
| `tui.editor.pageDown` | `pageDown`, `ctrl+pageDown` | Scroll down by page |
|
|
45
|
+
|
|
46
|
+
The dedicated history actions always change history entries, regardless of the cursor position in a multiline prompt. Explicit history bindings take precedence over application actions while the main editor is focused, so binding `tui.editor.historyPrevious` to `ctrl+p` overrides model cycling in that context without changing `Ctrl+P` in selectors.
|
|
41
47
|
|
|
42
48
|
### TUI Editor Deletion
|
|
43
49
|
|
|
@@ -78,16 +84,42 @@ Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1
|
|
|
78
84
|
| `tui.select.confirm` | `enter` | Confirm selection |
|
|
79
85
|
| `tui.select.cancel` | `escape`, `ctrl+c` | Cancel selection |
|
|
80
86
|
|
|
87
|
+
### TUI Fullscreen Viewport
|
|
88
|
+
|
|
89
|
+
These actions apply when interactive mode uses `--tui-mode fullscreen` and target the primary transcript scroll region. Two-finger trackpad and mouse-wheel input scroll the region under the pointer, falling back to the transcript over the fixed editor/status/footer dock. Clicking an OSC 8 hyperlink opens it in the default handler. Dragging with the primary mouse button selects text and copies it to the clipboard; holding at the transcript's top or bottom edge auto-scrolls into off-screen content.
|
|
90
|
+
|
|
91
|
+
Fullscreen transcript bindings take precedence over editor bindings. The default unmodified navigation keys therefore control the transcript in fullscreen mode, while their `ctrl` variants continue to control the editor. Outside fullscreen mode, both variants control the editor.
|
|
92
|
+
|
|
93
|
+
| Key | Default mode | Fullscreen mode |
|
|
94
|
+
|-----|--------------|-----------------|
|
|
95
|
+
| `home`, `end` | Editor | Transcript |
|
|
96
|
+
| `ctrl+home`, `ctrl+end` | Editor | Editor |
|
|
97
|
+
| `pageUp`, `pageDown` | Editor | Transcript |
|
|
98
|
+
| `ctrl+pageUp`, `ctrl+pageDown` | Editor | Editor |
|
|
99
|
+
|
|
100
|
+
This routing remains configurable through the ordinary action bindings. For example, `"tui.altScreen.pageUp": "ctrl+pageUp"` makes `pageUp` control the editor and `ctrl+pageUp` control the transcript in fullscreen mode. Bind `tui.altScreen.halfPageUp` and `tui.altScreen.halfPageDown` for smaller transcript steps while keeping the full-page bindings. Setting `"tui.altScreen.pageUp": []` disables that transcript shortcut entirely. User bindings replace the defaults for that action.
|
|
101
|
+
|
|
102
|
+
| Keybinding id | Default | Description |
|
|
103
|
+
|--------|---------|-------------|
|
|
104
|
+
| `tui.altScreen.pageUp` | `pageUp` | Scroll the transcript up by one page |
|
|
105
|
+
| `tui.altScreen.pageDown` | `pageDown` | Scroll the transcript down by one page |
|
|
106
|
+
| `tui.altScreen.halfPageUp` | *(none)* | Scroll the transcript up by half a page |
|
|
107
|
+
| `tui.altScreen.halfPageDown` | *(none)* | Scroll the transcript down by half a page |
|
|
108
|
+
| `tui.altScreen.previousPrompt` | `ctrl+shift+up` | Jump to the previous marked message |
|
|
109
|
+
| `tui.altScreen.nextPrompt` | `ctrl+shift+down` | Jump to the next marked message |
|
|
110
|
+
| `tui.altScreen.top` | `home` | Scroll to the beginning of the transcript |
|
|
111
|
+
| `tui.altScreen.bottom` | `end` | Scroll to the transcript end and follow new output |
|
|
112
|
+
|
|
81
113
|
### Application
|
|
82
114
|
|
|
83
115
|
| Keybinding id | Default | Description |
|
|
84
116
|
|--------|---------|-------------|
|
|
85
117
|
| `app.interrupt` | `escape` | Cancel / abort |
|
|
86
|
-
| `app.clear` | `ctrl+c` | Clear editor |
|
|
118
|
+
| `app.clear` | `ctrl+c` | Clear editor (first) / exit (second) |
|
|
87
119
|
| `app.exit` | `ctrl+d` | Exit (when editor empty) |
|
|
88
120
|
| `app.suspend` | `ctrl+z` (none on Windows) | Suspend to background |
|
|
89
121
|
| `app.editor.external` | `ctrl+g` | Open in external editor (`externalEditor`, `$VISUAL`, `$EDITOR`, Notepad on Windows, or `nano` elsewhere) |
|
|
90
|
-
| `app.clipboard.pasteImage` | `ctrl+v` (`alt+v` on Windows) | Paste image from clipboard |
|
|
122
|
+
| `app.clipboard.pasteImage` | `ctrl+v` (`alt+v` on Windows) | Paste image or text from clipboard |
|
|
91
123
|
|
|
92
124
|
### Sessions
|
|
93
125
|
|
|
@@ -158,8 +190,8 @@ Create `~/.sling/agent/keybindings.json`:
|
|
|
158
190
|
|
|
159
191
|
```json
|
|
160
192
|
{
|
|
161
|
-
"tui.editor.
|
|
162
|
-
"tui.editor.
|
|
193
|
+
"tui.editor.historyPrevious": "ctrl+p",
|
|
194
|
+
"tui.editor.historyNext": "ctrl+n",
|
|
163
195
|
"tui.editor.deleteWordBackward": ["ctrl+w", "alt+backspace"]
|
|
164
196
|
}
|
|
165
197
|
```
|
|
@@ -172,8 +204,8 @@ On native Windows, `app.suspend` has no default binding because Windows terminal
|
|
|
172
204
|
|
|
173
205
|
```json
|
|
174
206
|
{
|
|
175
|
-
"tui.editor.
|
|
176
|
-
"tui.editor.
|
|
207
|
+
"tui.editor.historyPrevious": "ctrl+p",
|
|
208
|
+
"tui.editor.historyNext": "ctrl+n",
|
|
177
209
|
"tui.editor.cursorLeft": ["left", "ctrl+b"],
|
|
178
210
|
"tui.editor.cursorRight": ["right", "ctrl+f"],
|
|
179
211
|
"tui.editor.cursorWordLeft": ["alt+left", "alt+b"],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# llama.cpp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Pi supports the [llama.cpp](https://github.com/ggml-org/llama.cpp) router server. The router discovers multiple GGUF models and loads or unloads them on demand.
|
|
4
4
|
|
|
5
5
|
Use a current llama.cpp build with router support. Follow the [build instructions](https://github.com/ggml-org/llama.cpp/blob/master/docs/build.md) or install a [prebuilt release](https://github.com/ggml-org/llama.cpp/releases) for your platform.
|
|
6
6
|
|
|
@@ -43,7 +43,7 @@ A single-file model can sit directly in the model directory. Put multimodal and
|
|
|
43
43
|
|
|
44
44
|
Restart the router after manually adding files. For per-model context sizes and other options, use [llama.cpp model presets](https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md#model-presets).
|
|
45
45
|
|
|
46
|
-
## Configure
|
|
46
|
+
## Configure Pi
|
|
47
47
|
|
|
48
48
|
Start sling and configure the provider:
|
|
49
49
|
|
|
@@ -58,7 +58,7 @@ Environment variables can configure the same values without `/login`:
|
|
|
58
58
|
```bash
|
|
59
59
|
export LLAMA_BASE_URL=http://127.0.0.1:8080
|
|
60
60
|
export LLAMA_API_KEY=optional-secret
|
|
61
|
-
|
|
61
|
+
pi
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
If the server uses an API key, start `llama-server` with the matching `--api-key` value. Keep `--host 127.0.0.1` for local-only access.
|
|
@@ -40,7 +40,7 @@ If you prefer the terminal, you can also run:
|
|
|
40
40
|
pi-mcp-adapter init
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
That scans for compatible configs and writes the missing
|
|
43
|
+
That scans for compatible configs and writes the missing sling adapter files.
|
|
44
44
|
|
|
45
45
|
## Using MCP Servers
|
|
46
46
|
|
|
@@ -134,7 +134,7 @@ Create or edit `~/.config/mcp/mcp.json` for servers you want available everywher
|
|
|
134
134
|
Use Sling-owned files when you need Sling-specific overrides:
|
|
135
135
|
|
|
136
136
|
- `<Sling agent dir>/mcp.json` — global override, usually `~/.sling/agent/mcp.json`
|
|
137
|
-
- `.
|
|
137
|
+
- `.sling/mcp.json` — project override
|
|
138
138
|
|
|
139
139
|
These files let Sling store adapter-specific settings without modifying shared MCP configs.
|
|
140
140
|
|
|
@@ -206,6 +206,7 @@ If your command is slow, expensive, rate-limited, or should keep using a previou
|
|
|
206
206
|
| `input` | No | `["text"]` | Input types: `["text"]` or `["text", "image"]` |
|
|
207
207
|
| `contextWindow` | No | `128000` | Context window size in tokens |
|
|
208
208
|
| `maxTokens` | No | `16384` | Maximum output tokens |
|
|
209
|
+
| `samplingParams` | No | omitted | Sampling parameters merged verbatim into every request body (see below) |
|
|
209
210
|
| `cost` | No | all zeros | Per-million-token rates with optional request-wide input pricing tiers |
|
|
210
211
|
| `compat` | No | provider `compat` | Provider compatibility overrides. Merged with provider-level `compat` when both are set. |
|
|
211
212
|
|
|
@@ -235,6 +236,24 @@ Current behavior:
|
|
|
235
236
|
- `/model`, `--list-models`, and the interactive footer display entries by model `id`.
|
|
236
237
|
- The configured `name` is used for model matching and secondary model detail text. It does not replace the footer/status-bar model id.
|
|
237
238
|
|
|
239
|
+
### Sampling Parameters
|
|
240
|
+
|
|
241
|
+
`samplingParams` is a free-form object merged verbatim into every request body for the model, after the fields sling sets itself, so its keys win. Use it to send sampling parameters sling does not model — including server-specific ones like llama.cpp's `min_p` or vLLM's `top_k`:
|
|
242
|
+
|
|
243
|
+
```json
|
|
244
|
+
{
|
|
245
|
+
"id": "deepseek-v4-flash",
|
|
246
|
+
"samplingParams": {
|
|
247
|
+
"temperature": 1.0,
|
|
248
|
+
"top_p": 0.95,
|
|
249
|
+
"top_k": 0,
|
|
250
|
+
"min_p": 0.0
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Only OpenAI-compatible APIs apply it (`openai-completions`, `openai-responses`, `azure-openai-responses`); other APIs ignore it. Keys override sling's named request fields (for example a `temperature` key here beats the request-level temperature), so prefer it as the single source of sampling truth for a model. In `modelOverrides`, `samplingParams` merges per key with the base model's value.
|
|
256
|
+
|
|
238
257
|
### Thinking Level Map
|
|
239
258
|
|
|
240
259
|
Use `thinkingLevelMap` on a model to describe model-specific thinking controls. Keys are sling thinking levels: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`. Maps may contain holes; for example, a model can expose `high` and `max` without exposing `xhigh`.
|
|
@@ -338,7 +357,7 @@ Use `modelOverrides` to customize built-in models and matching extension-registe
|
|
|
338
357
|
}
|
|
339
358
|
```
|
|
340
359
|
|
|
341
|
-
`modelOverrides` supports these fields per model: `name`, `reasoning`, `thinkingLevelMap`, `input`, `cost` (partial), `contextWindow`, `maxTokens`, `headers`, `compat`.
|
|
360
|
+
`modelOverrides` supports these fields per model: `name`, `reasoning`, `thinkingLevelMap`, `input`, `cost` (partial), `contextWindow`, `maxTokens`, `samplingParams` (merged per key), `headers`, `compat`.
|
|
342
361
|
|
|
343
362
|
Direct OpenAI GPT-5.6 Sol, Terra, and Luna default to a `272000` context window so requests remain within OpenAI's short-context pricing tier. To opt into OpenAI's 1.05M context window, increase it for each model you use:
|
|
344
363
|
|
|
@@ -441,13 +460,15 @@ For providers with partial OpenAI compatibility, use the `compat` field.
|
|
|
441
460
|
| `supportsDeveloperRole` | Use `developer` vs `system` role |
|
|
442
461
|
| `supportsReasoningEffort` | Support for `reasoning_effort` parameter |
|
|
443
462
|
| `supportsUsageInStreaming` | Supports `stream_options: { include_usage: true }` (default: `true`) |
|
|
463
|
+
| `supportsFinishReason` | Whether streamed responses include `finish_reason`. When `false`, sling infers `stop` or `toolUse` when the stream ends. Default: `true`. |
|
|
444
464
|
| `maxTokensField` | Use `max_completion_tokens` or `max_tokens` |
|
|
445
465
|
| `requiresToolResultName` | Include `name` on tool result messages |
|
|
446
466
|
| `requiresAssistantAfterToolResult` | Insert an assistant message before a user message after tool results |
|
|
447
467
|
| `requiresThinkingAsText` | Convert thinking blocks to plain text |
|
|
448
468
|
| `requiresReasoningContentOnAssistantMessages` | Include empty `reasoning_content` on all replayed assistant messages when reasoning is enabled |
|
|
449
|
-
| `thinkingFormat` | Use `reasoning_effort`, `openrouter`, `deepseek`, `together`, `zai`, `qwen`, `chat-template`, or `qwen-chat-template` thinking parameters |
|
|
450
|
-
| `chatTemplateKwargs` | `chat_template_kwargs` values for `thinkingFormat: "chat-template"`; use `{ "$var": "thinking.enabled" }` or `{ "$var": "thinking.effort" }` for
|
|
469
|
+
| `thinkingFormat` | Use `reasoning_effort`, `openrouter`, `deepseek`, `together`, `baseten`, `zai`, `qwen`, `chat-template`, or `qwen-chat-template` thinking parameters |
|
|
470
|
+
| `chatTemplateKwargs` | `chat_template_kwargs` values for `thinkingFormat: "chat-template"`; use `{ "$var": "thinking.enabled" }` or `{ "$var": "thinking.effort" }` for pi-controlled thinking values |
|
|
471
|
+
| `chatTemplateArgs` | `chat_template_args` values for `thinkingFormat: "baseten"`; use `{ "$var": "thinking.enabled" }` or `{ "$var": "thinking.effort" }` for pi-controlled thinking values |
|
|
451
472
|
| `cacheControlFormat` | Use Anthropic-style `cache_control` markers on the system prompt, last tool definition, and last user, assistant, or tool-result text content. Currently only `anthropic` is supported. |
|
|
452
473
|
| `sendSessionAffinityHeaders` | For `openai-completions`, send session-affinity headers from the session id when caching is enabled. Default: `false`. |
|
|
453
474
|
| `sessionAffinityFormat` | For `openai-completions` and `openai-responses`, the session-affinity header format: `openai` sends `session_id`/`x-client-request-id` (completions also `x-session-affinity`), `openai-nosession` omits the underscore-containing `session_id` header, `openrouter` sends `x-session-id`. Does not affect the `prompt_cache_key` body param. Default: auto-detected. |
|
|
@@ -458,7 +479,7 @@ For providers with partial OpenAI compatibility, use the `compat` field.
|
|
|
458
479
|
| `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). |
|
|
459
480
|
| `vercelGatewayRouting` | Vercel AI Gateway routing config for provider selection (`only`, `order`) |
|
|
460
481
|
|
|
461
|
-
`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` and `preserve_thinking`. Use `chat-template` for vLLM/Hugging Face chat templates that need configurable `chat_template_kwargs`, such as `chatTemplateKwargs: { "thinking": { "$var": "thinking.enabled" } }` for DeepSeek V3.x templates.
|
|
482
|
+
`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` and `preserve_thinking`. Use `chat-template` for vLLM/Hugging Face chat templates that need configurable `chat_template_kwargs`, such as `chatTemplateKwargs: { "thinking": { "$var": "thinking.enabled" } }` for DeepSeek V3.x templates. Use `thinkingFormat: "baseten"` with `chatTemplateArgs` for providers that expose toggle controls through `chat_template_args` and optionally support top-level `reasoning_effort`.
|
|
462
483
|
|
|
463
484
|
`cacheControlFormat: "anthropic"` is for OpenAI-compatible providers that expose Anthropic-style prompt caching through `cache_control` markers on text content and tool definitions.
|
|
464
485
|
|