@psnext/slingcli 3.0.20260810-3 → 3.0.20260811-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/project-trust.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 +7 -5
|
@@ -2,7 +2,7 @@ import { CONFIG_DIR_NAME } from "../config.js";
|
|
|
2
2
|
import { emitProjectTrustEvent } from "./extensions/runner.js";
|
|
3
3
|
import { getProjectTrustOptions, hasTrustRequiringProjectResources, } from "./trust-manager.js";
|
|
4
4
|
function formatProjectTrustPrompt(cwd) {
|
|
5
|
-
return `Trust project folder?\n${cwd}\n\nThis allows
|
|
5
|
+
return `Trust project folder?\n${cwd}\n\nThis allows sling to load ${CONFIG_DIR_NAME} settings and resources, install missing project packages, and execute project extensions.`;
|
|
6
6
|
}
|
|
7
7
|
async function selectProjectTrustOption(cwd, ctx) {
|
|
8
8
|
const options = getProjectTrustOptions(cwd, { includeSessionOnly: true });
|
package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js
CHANGED
|
@@ -874,7 +874,7 @@ export class InteractiveMode {
|
|
|
874
874
|
return "tmux extended-keys is off. Modified Enter keys may not work. Add `set -g extended-keys on` to ~/.tmux.conf and restart tmux.";
|
|
875
875
|
}
|
|
876
876
|
if (extendedKeysFormat === "xterm") {
|
|
877
|
-
return "tmux extended-keys-format is xterm.
|
|
877
|
+
return "tmux extended-keys-format is xterm. sling works best with csi-u. Add `set -g extended-keys-format csi-u` to ~/.tmux.conf and restart tmux.";
|
|
878
878
|
}
|
|
879
879
|
return undefined;
|
|
880
880
|
}
|
|
@@ -3137,7 +3137,7 @@ export class InteractiveMode {
|
|
|
3137
3137
|
this.ui.stop();
|
|
3138
3138
|
}
|
|
3139
3139
|
catch { }
|
|
3140
|
-
console.error("
|
|
3140
|
+
console.error("sling exiting due to uncaughtException:");
|
|
3141
3141
|
console.error(error);
|
|
3142
3142
|
process.exit(1);
|
|
3143
3143
|
}
|
|
@@ -3939,7 +3939,7 @@ export class InteractiveMode {
|
|
|
3939
3939
|
onSelect: (selection) => {
|
|
3940
3940
|
trustStore.setMany(selection.updates);
|
|
3941
3941
|
done();
|
|
3942
|
-
this.showStatus(`Saved trust decision: ${selection.trusted ? "trusted" : "untrusted"}. Restart
|
|
3942
|
+
this.showStatus(`Saved trust decision: ${selection.trusted ? "trusted" : "untrusted"}. Restart sling for this to take effect.`);
|
|
3943
3943
|
},
|
|
3944
3944
|
onCancel: () => {
|
|
3945
3945
|
done();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Compaction & Branch Summarization
|
|
2
2
|
|
|
3
|
-
LLMs have limited context windows. When conversations grow too long,
|
|
3
|
+
LLMs have limited context windows. When conversations grow too long, Sling uses compaction to summarize older content while preserving recent work. This page covers both auto-compaction and branch summarization.
|
|
4
4
|
|
|
5
5
|
**Source files** ([pi-mono](https://github.com/earendil-works/pi-mono)):
|
|
6
6
|
- [`packages/coding-agent/src/core/compaction/compaction.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) - Auto-compaction logic
|
|
@@ -13,7 +13,7 @@ For TypeScript definitions in your project, inspect `node_modules/@earendil-work
|
|
|
13
13
|
|
|
14
14
|
## Overview
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Pi has two summarization mechanisms:
|
|
17
17
|
|
|
18
18
|
| Mechanism | Trigger | Purpose |
|
|
19
19
|
|-----------|---------|---------|
|
|
@@ -48,7 +48,7 @@ You can also trigger manually with `/compact [instructions]`, where optional ins
|
|
|
48
48
|
Before compaction:
|
|
49
49
|
|
|
50
50
|
entry: 0 1 2 3 4 5 6 7 8 9
|
|
51
|
-
|
|
51
|
+
┌─────┬─────┬─────┬─────┬──────┬─────┬──── ─┬──────┬─────┬─────┐
|
|
52
52
|
│ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│
|
|
53
53
|
└─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┘
|
|
54
54
|
└────────┬───────┘ └──────────────┬──────────────┘
|
|
@@ -59,7 +59,7 @@ Before compaction:
|
|
|
59
59
|
After compaction (new entry appended):
|
|
60
60
|
|
|
61
61
|
entry: 0 1 2 3 4 5 6 7 8 9 10
|
|
62
|
-
|
|
62
|
+
┌─────┬─────┬─────┬─────┬──────┬─────┬──── ─┬──────┬─────┬─────┬─────┐
|
|
63
63
|
│ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│ cmp │
|
|
64
64
|
└─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┴─────┘
|
|
65
65
|
└──────────┬──────┘ └──────────────────────┬───────────────────┘
|
|
@@ -102,7 +102,7 @@ Split turn (one huge turn exceeds budget):
|
|
|
102
102
|
turnPrefixMessages = [usr, ass, tool, ass, tool, tool]
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
For split turns,
|
|
105
|
+
For split turns, Sling generates two summaries and merges them:
|
|
106
106
|
1. **History summary**: Previous context (if any)
|
|
107
107
|
2. **Turn prefix summary**: The early part of the split turn
|
|
108
108
|
|
|
@@ -149,7 +149,7 @@ See [`prepareCompaction()`](https://github.com/earendil-works/pi-mono/blob/main/
|
|
|
149
149
|
|
|
150
150
|
### When It Triggers
|
|
151
151
|
|
|
152
|
-
When you use `/tree` to navigate to a different branch,
|
|
152
|
+
When you use `/tree` to navigate to a different branch, Sling offers to summarize the work you're leaving. This injects context from the left branch into the new branch.
|
|
153
153
|
|
|
154
154
|
### How It Works
|
|
155
155
|
|
|
@@ -171,14 +171,14 @@ Entries to summarize: B, C, D
|
|
|
171
171
|
|
|
172
172
|
After navigation with summary:
|
|
173
173
|
|
|
174
|
-
┌─ B ─ C ─ D
|
|
174
|
+
┌─ B ─ C ─ D
|
|
175
175
|
A ───┤
|
|
176
|
-
└─ E ─ F (new leaf)
|
|
176
|
+
└─ E ─ F ─ [summary of B,C,D] (new leaf)
|
|
177
177
|
```
|
|
178
178
|
|
|
179
179
|
### Cumulative File Tracking
|
|
180
180
|
|
|
181
|
-
Both compaction and branch summarization track files cumulatively. When generating a summary,
|
|
181
|
+
Both compaction and branch summarization track files cumulatively. When generating a summary, Sling extracts file operations from:
|
|
182
182
|
- Tool calls in the messages being summarized
|
|
183
183
|
- Previous compaction or branch summary `details` (if any)
|
|
184
184
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Containerization
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Sling runs with all permissions by default, but in some cases, you will want to have more control over what directories Sling can write to and which accesses it has.
|
|
4
4
|
|
|
5
5
|
There are two general options. You can either
|
|
6
6
|
1. run the whole `sling` process inside an isolated environment, or
|
|
@@ -54,22 +54,22 @@ FROM node:24-bookworm-slim
|
|
|
54
54
|
RUN apt-get update \
|
|
55
55
|
&& apt-get install -y --no-install-recommends bash ca-certificates git ripgrep \
|
|
56
56
|
&& rm -rf /var/lib/apt/lists/*
|
|
57
|
-
RUN npm install -g --ignore-scripts @
|
|
57
|
+
RUN npm install -g --ignore-scripts @earendil-works/pi-coding-agent
|
|
58
58
|
|
|
59
59
|
WORKDIR /workspace
|
|
60
|
-
ENTRYPOINT ["
|
|
60
|
+
ENTRYPOINT ["pi"]
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
Build and run:
|
|
64
64
|
|
|
65
65
|
```bash
|
|
66
|
-
docker build -t
|
|
66
|
+
docker build -t pi-sandbox -f Dockerfile.sling .
|
|
67
67
|
|
|
68
68
|
docker run --rm -it \
|
|
69
69
|
-e ANTHROPIC_API_KEY \
|
|
70
70
|
-v "$PWD:/workspace" \
|
|
71
71
|
-v sling-agent-home:/root/.sling/agent \
|
|
72
|
-
|
|
72
|
+
pi-sandbox
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
The `-v "$PWD:/workspace"` mounts your current directory into the container at /workspace such that reads and writes in `/workspace` inside Docker directly affect your host files, like in the Gondolin example.
|
|
@@ -102,10 +102,10 @@ If the gateway is remote, project files are not bind-mounted from the host, mean
|
|
|
102
102
|
Clone the repository inside the sandbox or use OpenShell file transfer commands:
|
|
103
103
|
|
|
104
104
|
```bash
|
|
105
|
-
openshell sandbox upload
|
|
106
|
-
openshell sandbox download
|
|
105
|
+
openshell sandbox upload pi-sandbox ./repo /workspace
|
|
106
|
+
openshell sandbox download pi-sandbox /workspace/repo ./repo-out
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
OpenShell providers can keep raw model API keys outside the sandbox.
|
|
110
110
|
When inference routing is configured, code inside the sandbox can call `https://inference.local`, and the gateway injects the configured provider credentials upstream.
|
|
111
|
-
Configure
|
|
111
|
+
Configure Sling to use the corresponding OpenAI-compatible or Anthropic-compatible endpoint if you want model traffic to use this route.
|
|
@@ -30,7 +30,7 @@ See these complete provider examples:
|
|
|
30
30
|
|
|
31
31
|
## Quick Reference
|
|
32
32
|
|
|
33
|
-
Extensions can register either a complete pi-ai `Provider` or use the legacy provider-config form. Prefer a complete provider when custom authentication, filtering, refresh, or streaming behavior is required.
|
|
33
|
+
Extensions can register either a complete pi-ai `Provider` or use the legacy provider-config form. Prefer a complete provider when custom authentication, filtering, refresh, or streaming behavior is required. Sling composes `models.json` overrides above registered native providers.
|
|
34
34
|
|
|
35
35
|
```typescript
|
|
36
36
|
import { createProvider, openAICompletionsApi } from "@earendil-works/pi-ai";
|
|
@@ -88,7 +88,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
88
88
|
}
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
The extension factory can also be `async`. For dynamic model discovery, fetch and register models in the factory instead of `session_start`.
|
|
91
|
+
The extension factory can also be `async`. For dynamic model discovery, fetch and register models in the factory instead of `session_start`. Sling waits for the factory before startup continues, so the provider is available during interactive startup and to `sling --list-models`.
|
|
92
92
|
|
|
93
93
|
## Override Existing Provider
|
|
94
94
|
|
|
@@ -227,7 +227,7 @@ The `api` field determines which streaming implementation is used:
|
|
|
227
227
|
| `openai-responses` | OpenAI Responses API |
|
|
228
228
|
| `azure-openai-responses` | Azure OpenAI Responses API |
|
|
229
229
|
| `openai-codex-responses` | OpenAI Codex Responses API |
|
|
230
|
-
| `mistral-conversations` | Mistral
|
|
230
|
+
| `mistral-conversations` | Native Mistral Chat Completions streaming |
|
|
231
231
|
| `google-generative-ai` | Google Generative AI API |
|
|
232
232
|
| `google-vertex` | Google Vertex AI API |
|
|
233
233
|
| `bedrock-converse-stream` | Amazon Bedrock Converse API |
|
|
@@ -331,8 +331,8 @@ pi.registerProvider("corporate-ai", {
|
|
|
331
331
|
};
|
|
332
332
|
},
|
|
333
333
|
|
|
334
|
-
async refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {
|
|
335
|
-
const tokens = await refreshAccessToken(credentials.refresh);
|
|
334
|
+
async refreshToken(credentials: OAuthCredentials, signal: AbortSignal): Promise<OAuthCredentials> {
|
|
335
|
+
const tokens = await refreshAccessToken(credentials.refresh, signal);
|
|
336
336
|
return {
|
|
337
337
|
refresh: tokens.refreshToken ?? credentials.refresh,
|
|
338
338
|
access: tokens.accessToken,
|
|
@@ -442,7 +442,7 @@ function streamMyProvider(
|
|
|
442
442
|
totalTokens: 0,
|
|
443
443
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
444
444
|
},
|
|
445
|
-
stopReason: "
|
|
445
|
+
stopReason: "pending",
|
|
446
446
|
timestamp: Date.now(),
|
|
447
447
|
};
|
|
448
448
|
|
|
@@ -451,12 +451,18 @@ function streamMyProvider(
|
|
|
451
451
|
stream.push({ type: "start", partial: output });
|
|
452
452
|
|
|
453
453
|
// Make API request and process response...
|
|
454
|
-
// Push content events as they arrive
|
|
454
|
+
// Push content events as they arrive and set stopReason from the terminal event.
|
|
455
|
+
if (output.stopReason === "pending") {
|
|
456
|
+
throw new Error("Provider stream ended without a stop reason");
|
|
457
|
+
}
|
|
458
|
+
if (output.stopReason === "error" || output.stopReason === "aborted") {
|
|
459
|
+
throw new Error(output.errorMessage || "An unknown error occurred");
|
|
460
|
+
}
|
|
455
461
|
|
|
456
462
|
// Push done event
|
|
457
463
|
stream.push({
|
|
458
464
|
type: "done",
|
|
459
|
-
reason: output.stopReason
|
|
465
|
+
reason: output.stopReason,
|
|
460
466
|
message: output
|
|
461
467
|
});
|
|
462
468
|
stream.end();
|
|
@@ -617,7 +623,7 @@ Guard the rewrite carefully:
|
|
|
617
623
|
Register your stream function:
|
|
618
624
|
|
|
619
625
|
```typescript
|
|
620
|
-
|
|
626
|
+
pi.registerProvider("my-provider", {
|
|
621
627
|
baseUrl: "https://api.example.com",
|
|
622
628
|
apiKey: "$MY_API_KEY",
|
|
623
629
|
api: "my-custom-api",
|
|
@@ -682,7 +688,7 @@ interface ProviderConfig {
|
|
|
682
688
|
oauth?: {
|
|
683
689
|
name: string;
|
|
684
690
|
login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;
|
|
685
|
-
refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials>;
|
|
691
|
+
refreshToken(credentials: OAuthCredentials, signal: AbortSignal): Promise<OAuthCredentials>;
|
|
686
692
|
getApiKey(credentials: OAuthCredentials): string;
|
|
687
693
|
};
|
|
688
694
|
}
|
|
@@ -737,6 +743,7 @@ interface ProviderModelConfig {
|
|
|
737
743
|
supportsDeveloperRole?: boolean;
|
|
738
744
|
supportsReasoningEffort?: boolean;
|
|
739
745
|
supportsUsageInStreaming?: boolean;
|
|
746
|
+
supportsFinishReason?: boolean;
|
|
740
747
|
supportsStrictMode?: boolean;
|
|
741
748
|
supportsOpenAIGrammarTools?: boolean; // openai-completions/openai-responses; false falls back to normal function tools
|
|
742
749
|
maxTokensField?: "max_completion_tokens" | "max_tokens";
|
|
@@ -744,8 +751,9 @@ interface ProviderModelConfig {
|
|
|
744
751
|
requiresAssistantAfterToolResult?: boolean;
|
|
745
752
|
requiresThinkingAsText?: boolean;
|
|
746
753
|
requiresReasoningContentOnAssistantMessages?: boolean;
|
|
747
|
-
thinkingFormat?: "openai" | "openrouter" | "deepseek" | "together" | "zai" | "qwen" | "chat-template" | "qwen-chat-template" | "string-thinking" | "ant-ling";
|
|
754
|
+
thinkingFormat?: "openai" | "openrouter" | "deepseek" | "together" | "baseten" | "zai" | "qwen" | "chat-template" | "qwen-chat-template" | "string-thinking" | "ant-ling";
|
|
748
755
|
chatTemplateKwargs?: Record<string, string | number | boolean | null | { "$var": "thinking.enabled" | "thinking.effort"; omitWhenOff?: boolean }>;
|
|
756
|
+
chatTemplateArgs?: Record<string, string | number | boolean | null | { "$var": "thinking.enabled" | "thinking.effort"; omitWhenOff?: boolean }>;
|
|
749
757
|
cacheControlFormat?: "anthropic";
|
|
750
758
|
sessionAffinityFormat?: "openai" | "openai-nosession" | "openrouter";
|
|
751
759
|
sendSessionAffinityHeaders?: boolean;
|
|
@@ -762,5 +770,5 @@ interface ProviderModelConfig {
|
|
|
762
770
|
}
|
|
763
771
|
```
|
|
764
772
|
|
|
765
|
-
`openrouter` sends `reasoning: { effort }`. `deepseek` sends `thinking: { type: "enabled" | "disabled" }` and `reasoning_effort` when enabled. `together` sends `reasoning: { enabled }` and also `reasoning_effort` when `supportsReasoningEffort` is enabled. `qwen` is for DashScope-style top-level `enable_thinking`. Use `qwen-chat-template` for local Qwen-compatible servers that read `chat_template_kwargs.enable_thinking` and need `preserve_thinking`. Use `chat-template` for configurable `chat_template_kwargs`, for example DeepSeek V3.x behind vLLM with `chatTemplateKwargs: { "thinking": { "$var": "thinking.enabled" } }`.
|
|
773
|
+
`openrouter` sends `reasoning: { effort }`. `deepseek` sends `thinking: { type: "enabled" | "disabled" }` and `reasoning_effort` when enabled. `together` sends `reasoning: { enabled }` and also `reasoning_effort` when `supportsReasoningEffort` is enabled. `qwen` is for DashScope-style top-level `enable_thinking`. Use `qwen-chat-template` for local Qwen-compatible servers that read `chat_template_kwargs.enable_thinking` and need `preserve_thinking`. Use `chat-template` for configurable `chat_template_kwargs`, for example DeepSeek V3.x behind vLLM with `chatTemplateKwargs: { "thinking": { "$var": "thinking.enabled" } }`. Use `thinkingFormat: "baseten"` with `chatTemplateArgs` when the provider expects toggle values under `chat_template_args` and optionally supports top-level `reasoning_effort`.
|
|
766
774
|
`cacheControlFormat: "anthropic"` applies Anthropic-style `cache_control` markers to the system prompt, last tool definition, and last user, assistant, or tool-result text content.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
See [AGENTS.md](https://github.com/earendil-works/pi-mono/blob/main/AGENTS.md) for additional guidelines.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/earendil-works/pi-mono
|
|
9
|
+
cd pi-mono
|
|
10
|
+
npm install
|
|
11
|
+
npm run build
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Run from source:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
/path/to/pi-mono/pi-test.sh
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The script can be run from any directory. Sling keeps the caller's current working directory.
|
|
21
|
+
|
|
22
|
+
## Forking / Rebranding
|
|
23
|
+
|
|
24
|
+
Configure via `package.json`:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"piConfig": {
|
|
29
|
+
"name": "sling",
|
|
30
|
+
"configDir": ".sling"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Change `name`, `configDir`, and `bin` field for your fork. Affects CLI banner, config paths, and environment variable names.
|
|
36
|
+
|
|
37
|
+
## Path Resolution
|
|
38
|
+
|
|
39
|
+
Three execution modes: npm install, standalone binary, tsx from source.
|
|
40
|
+
|
|
41
|
+
**Always use `src/config.ts`** for package assets:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { getPackageDir, getThemeDir } from "./config.js";
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Never use `__dirname` directly for package assets.
|
|
48
|
+
|
|
49
|
+
## Debug Command
|
|
50
|
+
|
|
51
|
+
`/debug` (hidden) writes to `~/.sling/agent/sling-debug.log`:
|
|
52
|
+
- Rendered TUI lines with ANSI codes
|
|
53
|
+
- Last messages sent to the LLM
|
|
54
|
+
|
|
55
|
+
## Testing
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
./test.sh # Run non-LLM tests (no API keys needed)
|
|
59
|
+
npm test # Run all tests
|
|
60
|
+
npm test -- test/specific.test.ts # Run specific test
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Project Structure
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
packages/
|
|
67
|
+
ai/ # LLM provider abstraction
|
|
68
|
+
agent/ # Agent loop and message types
|
|
69
|
+
tui/ # Terminal UI components
|
|
70
|
+
coding-agent/ # CLI and interactive mode
|
|
71
|
+
```
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"path": "themes.md"
|
|
66
66
|
},
|
|
67
67
|
{
|
|
68
|
-
"title": "
|
|
68
|
+
"title": "Sling Packages",
|
|
69
69
|
"path": "packages.md"
|
|
70
70
|
},
|
|
71
71
|
{
|
|
@@ -90,6 +90,10 @@
|
|
|
90
90
|
{
|
|
91
91
|
"title": "Programmatic Usage",
|
|
92
92
|
"items": [
|
|
93
|
+
{
|
|
94
|
+
"title": "SDK",
|
|
95
|
+
"path": "sdk.md"
|
|
96
|
+
},
|
|
93
97
|
{
|
|
94
98
|
"title": "RPC Mode",
|
|
95
99
|
"path": "rpc.md"
|
|
@@ -128,6 +132,15 @@
|
|
|
128
132
|
"path": "shell-aliases.md"
|
|
129
133
|
}
|
|
130
134
|
]
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"title": "Development",
|
|
138
|
+
"items": [
|
|
139
|
+
{
|
|
140
|
+
"title": "Development",
|
|
141
|
+
"path": "development.md"
|
|
142
|
+
}
|
|
143
|
+
]
|
|
131
144
|
}
|
|
132
145
|
],
|
|
133
146
|
"redirects": [
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
Pi uses environment variables in three ways:
|
|
4
4
|
|
|
5
|
-
- Variables such as `PI_OFFLINE` configure the
|
|
6
|
-
-
|
|
5
|
+
- Variables such as `PI_OFFLINE` configure the Sling process.
|
|
6
|
+
- Sling sets `PI_CODING_AGENT` so child processes can detect that they run inside Pi.
|
|
7
7
|
- Commands run by the LLM-callable bash tool receive `PI_*` variables describing the current session.
|
|
8
8
|
|
|
9
9
|
Provider API-key variables are documented separately in [Providers](providers.md#environment-variables-or-auth-file).
|
|
10
10
|
|
|
11
11
|
## Process Marker
|
|
12
12
|
|
|
13
|
-
The CLI and RPC entry points set `PI_CODING_AGENT=true`. Child processes inherit it and can use it to detect that they run inside Pi. It is not session-specific and is not set automatically when
|
|
13
|
+
The CLI and RPC entry points set `PI_CODING_AGENT=true`. Child processes inherit it and can use it to detect that they run inside Pi. It is not session-specific and is not set automatically when Sling is embedded through the SDK.
|
|
14
14
|
|
|
15
15
|
## Bash Tool Session Environment
|
|
16
16
|
|
|
17
|
-
Commands run by the bash tool receive the current
|
|
17
|
+
Commands run by the bash tool receive the current Sling session state:
|
|
18
18
|
|
|
19
19
|
| Variable | Description |
|
|
20
20
|
|----------|-------------|
|
|
@@ -24,7 +24,7 @@ Commands run by the bash tool receive the current Pi session state:
|
|
|
24
24
|
| `PI_MODEL` | Currently selected model ID |
|
|
25
25
|
| `PI_REASONING_LEVEL` | Current effective reasoning level: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, or `max` |
|
|
26
26
|
|
|
27
|
-
The values are resolved when each command starts. Switching models or changing the reasoning level therefore affects the next bash command without restarting Pi. `PI_PROVIDER` and `PI_MODEL` identify the selected
|
|
27
|
+
The values are resolved when each command starts. Switching models or changing the reasoning level therefore affects the next bash command without restarting Pi. `PI_PROVIDER` and `PI_MODEL` identify the selected Sling model, not a different upstream model that a router may choose internally.
|
|
28
28
|
|
|
29
29
|
When asked which model or provider is running, inspect these variables instead of inferring the answer from the system prompt:
|
|
30
30
|
|
|
@@ -65,15 +65,15 @@ const bashTool = createBashTool(cwd, {
|
|
|
65
65
|
});
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
When disabled,
|
|
68
|
+
When disabled, Sling removes inherited values for these variables so nested Sling processes do not expose stale parent-session metadata.
|
|
69
69
|
|
|
70
|
-
##
|
|
70
|
+
## Sling Process Configuration
|
|
71
71
|
|
|
72
|
-
These variables are read by
|
|
72
|
+
These variables are read by Sling itself:
|
|
73
73
|
|
|
74
74
|
| Variable | Description |
|
|
75
75
|
|----------|-------------|
|
|
76
|
-
| `PI_CODING_AGENT_DIR` | Override the config directory; default is `~/.
|
|
76
|
+
| `PI_CODING_AGENT_DIR` | Override the config directory; default is `~/.sling/agent` |
|
|
77
77
|
| `PI_CODING_AGENT_SESSION_DIR` | Override session storage; overridden by `--session-dir` |
|
|
78
78
|
| `PI_PACKAGE_DIR` | Override the package directory, useful for Nix/Guix store paths |
|
|
79
79
|
| `PI_OFFLINE` | Disable startup network operations, including update checks, package updates, and install/update telemetry |
|