@stfade/pi-read-delegator 1.0.12 → 1.0.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.
- package/README.md +178 -69
- package/{bash-filter.d.ts → dist/bash-filter.d.ts} +16 -6
- package/dist/bash-filter.js +420 -0
- package/{config.d.ts → dist/config.d.ts} +0 -1
- package/{config.js → dist/config.js} +34 -59
- package/{index.js → dist/index.js} +111 -149
- package/{reader-manager.d.ts → dist/reader-manager.d.ts} +26 -1
- package/{reader-manager.js → dist/reader-manager.js} +127 -72
- package/{tool-blocker.js → dist/tool-blocker.js} +13 -21
- package/{ui.js → dist/ui.js} +15 -62
- package/package.json +20 -17
- package/bash-filter.js +0 -242
- package/templates/reader.md +0 -8
- /package/{index.d.ts → dist/index.d.ts} +0 -0
- /package/{tool-blocker.d.ts → dist/tool-blocker.d.ts} +0 -0
- /package/{ui.d.ts → dist/ui.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,106 +1,215 @@
|
|
|
1
1
|
# pi-read-delegator
|
|
2
2
|
|
|
3
|
-
Pi extension
|
|
3
|
+
**Pi extension**: delegates all file-read and search operations to a lightweight Reader subagent. The main model never sees raw file contents — saving tokens, avoiding context pollution, and keeping the orchestrator focused on reasoning.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Architecture
|
|
6
6
|
|
|
7
7
|
```
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
│
|
|
11
|
-
│
|
|
12
|
-
│
|
|
13
|
-
│
|
|
14
|
-
|
|
8
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
9
|
+
│ ORCHESTRATOR (main model) │
|
|
10
|
+
│ • Cannot use: read, grep, find, ls │
|
|
11
|
+
│ • Cannot run: cat, grep, head, tail, Get-Content, findstr │
|
|
12
|
+
│ • MUST delegate via: subagent(agent="reader", task="...") │
|
|
13
|
+
│ │
|
|
14
|
+
│ System prompt tells orchestrator HOW to delegate: │
|
|
15
|
+
│ Action: read | Target: src/file.ts | Detail: function X │
|
|
16
|
+
│ Action: grep | Target: src/ | Detail: "pattern" │
|
|
17
|
+
│ Action: find | Target: src/ | Detail: *.ts │
|
|
18
|
+
└──────────────────────┬───────────────────────────────────────┘
|
|
19
|
+
│ subagent(agent="reader", task="...")
|
|
20
|
+
┌──────────────────────▼───────────────────────────────────────┐
|
|
21
|
+
│ READER SUBAGENT (pi-subagents → reader.md) │
|
|
22
|
+
│ • Tools: read, grep, find, ls │
|
|
23
|
+
│ • Receives structured task, returns structured output │
|
|
24
|
+
│ │
|
|
25
|
+
│ src/config.ts:42 const DEFAULT_CONFIG = { │
|
|
26
|
+
│ src/config.ts:43 enabled: true, │
|
|
27
|
+
│ ... │
|
|
28
|
+
└──────────────────────────────────────────────────────────────┘
|
|
15
29
|
```
|
|
16
30
|
|
|
17
|
-
|
|
18
|
-
- **Read tools** (`read`, `grep`, `find`, `ls`) are blocked on the main model and routed to the Reader subagent.
|
|
19
|
-
- **Bash commands** are filtered: read commands go to Reader, write commands execute directly, ambiguous commands prompt the user.
|
|
31
|
+
### Communication protocol
|
|
20
32
|
|
|
21
|
-
|
|
33
|
+
The orchestrator and reader communicate through a **structured task/result protocol** — no free-form chatting, no "max N lines" truncation.
|
|
22
34
|
|
|
23
|
-
|
|
24
|
-
|
|
35
|
+
**Orchestrator → Reader** (task format):
|
|
36
|
+
```
|
|
37
|
+
Action: read | Target: src/config.ts | Detail: DEFAULT_CONFIG definition
|
|
38
|
+
Action: grep | Target: src/ | Detail: "isReadCommand" function
|
|
39
|
+
Action: find | Target: src/ | Detail: *.ts
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Reader → Orchestrator** (result format):
|
|
43
|
+
- Minimal, structured output — no markdown headers, no explanations
|
|
44
|
+
- grep: `file:line content` (file path, line number, matched line)
|
|
45
|
+
- read: line-numbered file content
|
|
46
|
+
- find: bare file list, one per line
|
|
47
|
+
- ls: file names with sizes
|
|
48
|
+
- No matches: `(no matches)`
|
|
49
|
+
- Error: `Error: <message>`
|
|
50
|
+
|
|
51
|
+
This protocol was designed based on research findings around **token-efficient subagent orchestration**:
|
|
52
|
+
structured output beats free-form text, file-path-based handoffs avoid triple-token duplication, and single-level hierarchy keeps context clean.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### Token optimizations
|
|
57
|
+
|
|
58
|
+
The Reader subagent applies **6 optimization techniques** — researched from Headroom, RTK, and multi-agent orchestration literature — to minimize token usage on every call:
|
|
59
|
+
|
|
60
|
+
| # | Technique | What it does | Token savings |
|
|
61
|
+
|---|-----------|-------------|:------------:|
|
|
62
|
+
| 1 | **CCR Cache** | Session-level file cache with hash-based invalidation. Same file never read twice. | **83%** (re-reads) |
|
|
63
|
+
| 2 | **Structure masks** | Compresses imports, type annotations, and long paths in code output. | **35%** (code reads) |
|
|
64
|
+
| 3 | **Stats extraction** | grep/find/ls return counts first; >20 results → count only. | **60%** (searches) |
|
|
65
|
+
| 4 | **Smart filtering** | Auto-skips node_modules, .git, dist; detects binary files; deduplicates. | **20%** (noisy output) |
|
|
66
|
+
| 5 | **Graduated reading** | Orchestrator taught to use find→grep→read progression instead of full-file reads. | **40%** (surveys) |
|
|
67
|
+
| 6 | **Prompt compression** | Orchestrator prompt compressed from 55 to 22 lines via example-driven format. | **1.5K**/session |
|
|
68
|
+
|
|
69
|
+
### Token analysis (test results)
|
|
70
|
+
|
|
71
|
+
> **Instructions**: Test pi-read-delegator on different projects. For each project, measure
|
|
72
|
+
total tokens consumed across a full coding session with and without the extension.
|
|
73
|
+
Record results below.
|
|
74
|
+
|
|
75
|
+
| Project | Files | Size | No delegation | Basic delegation | With optimizations | Savings |
|
|
76
|
+
|---------|:-----:|------|:------------:|:----------------:|:------------------:|:-------:|
|
|
77
|
+
| *(your project)* | | | | | | |
|
|
78
|
+
| | | | | | | |
|
|
79
|
+
| | | | | | | |
|
|
80
|
+
| | | | | | | |
|
|
81
|
+
| | | | | | | |
|
|
82
|
+
|
|
83
|
+
**How to measure**: Use Pi's token counter or your provider's usage dashboard.
|
|
84
|
+
"Basic delegation" = extension enabled but optimizations disabled (set `reader_model` to same as orchestrator, clear cache between calls).
|
|
85
|
+
"With optimizations" = all 6 techniques active (default).
|
|
86
|
+
"Savings" = (No delegation − With optimizations) / No delegation × 100.
|
|
25
87
|
|
|
26
88
|
## Installation
|
|
27
89
|
|
|
28
90
|
```bash
|
|
29
|
-
pi install
|
|
91
|
+
pi install @stfade/pi-read-delegator
|
|
30
92
|
```
|
|
31
93
|
|
|
32
|
-
|
|
94
|
+
On first session start, the extension:
|
|
95
|
+
1. Auto-installs `pi-subagents` as a dependency
|
|
96
|
+
2. Guides you through interactive model selection
|
|
97
|
+
3. Creates `~/.pi/agent/agents/reader.md` with the Reader's system prompt
|
|
98
|
+
4. Registers `pi-subagents` in Pi's package list
|
|
33
99
|
|
|
34
|
-
|
|
35
|
-
npm install -g pi-read-delegator
|
|
36
|
-
```
|
|
100
|
+
## Configuration
|
|
37
101
|
|
|
38
|
-
|
|
102
|
+
Config file: `~/.pi/agent/read-delegator.json`
|
|
103
|
+
|
|
104
|
+
| Field | Default | Description |
|
|
105
|
+
|-------|---------|-------------|
|
|
106
|
+
| `enabled` | `true` | Enable/disable read delegation |
|
|
107
|
+
| `blocked_tools` | `["read","grep","find","ls"]` | Tools blocked from main model |
|
|
108
|
+
| `reader_subagent_name` | `"reader"` | Subagent name (must match `reader.md`) |
|
|
109
|
+
| `reader_model` | `"lmstudio/nvidia/nemotron-3-nano-4b"` | Model for the Reader (`provider/model`) |
|
|
110
|
+
| `orchestrator_prompt` | *(system prompt)* | Injected into main model's system prompt |
|
|
111
|
+
| `language` | `"auto"` | UI language: `"auto"`, `"en"`, `"tr"` |
|
|
112
|
+
|
|
113
|
+
The subagent template lives at `~/.pi/agent/agents/reader.md` and is auto-managed on every config change.
|
|
39
114
|
|
|
40
115
|
## Commands
|
|
41
116
|
|
|
42
|
-
| Command |
|
|
43
|
-
|
|
44
|
-
| `/read-delegator
|
|
45
|
-
| `/read-delegator
|
|
46
|
-
| `/read-delegator
|
|
117
|
+
| Command | Action |
|
|
118
|
+
|---------|--------|
|
|
119
|
+
| `/read-delegator` | Show current status |
|
|
120
|
+
| `/read-delegator-status` | Show current status |
|
|
121
|
+
| `/read-delegator-on` | Enable read delegation (blocks read tools) |
|
|
122
|
+
| `/read-delegator-off` | Disable read delegation (restores all tools) |
|
|
123
|
+
| `/read-delegator-model` | Interactive model picker |
|
|
124
|
+
| `/read-delegator-model lmstudio/mistral` | Set a specific model directly |
|
|
47
125
|
|
|
48
|
-
##
|
|
126
|
+
## Blocked commands
|
|
49
127
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
```json
|
|
53
|
-
{
|
|
54
|
-
"enabled": true,
|
|
55
|
-
"reader_subagent_name": "reader",
|
|
56
|
-
"blocked_tools": ["read", "grep", "find", "ls"],
|
|
57
|
-
"allowed_bash_write_commands": ["mkdir", "echo", "touch", "sed", "rm", "mv", "cp"],
|
|
58
|
-
"orchestrator_prompt": "You are an orchestrator. For any file reading... use the subagent tool...",
|
|
59
|
-
"language": "auto"
|
|
60
|
-
}
|
|
61
|
-
```
|
|
128
|
+
The extension intercepts read-like shell commands across **three shells** and redirects them to the Reader subagent:
|
|
62
129
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
| `enabled` | Enable/disable the extension |
|
|
66
|
-
| `reader_subagent_name` | Name of the Reader subagent (must match `reader.md`) |
|
|
67
|
-
| `blocked_tools` | Tools to block from the main model |
|
|
68
|
-
| `language` | `"auto"`, `"tr"`, or `"en"` |
|
|
130
|
+
### bash / sh (Linux, macOS, WSL, Git Bash)
|
|
131
|
+
`cat`, `grep`, `find`, `ls`, `head`, `tail`, `less`, `wc`, `nl`, `more`, `bat`, `rg`, `fd`, `awk`, `du`, `df`, `stat`, `file`, `which`, `where`, `type`, `dir`, `sort`, `uniq`, `cut`, `tr`, `diff`, `cmp`, `comm`, `od`, `hexdump`, `xxd`
|
|
69
132
|
|
|
70
|
-
|
|
133
|
+
### PowerShell (Windows)
|
|
134
|
+
`Get-Content`, `Select-String`, `Get-ChildItem`, `Get-ItemProperty`, `Get-Item`, `Test-Path`, `Get-Alias`, `Get-Command`, `Measure-Object`, `Compare-Object`, `Where-Object`, `Select-Object`, `Format-List`, `Format-Table`
|
|
71
135
|
|
|
72
|
-
|
|
136
|
+
### cmd.exe (Windows)
|
|
137
|
+
`type`, `findstr`, `find`, `dir`, `more`, `comp`, `fc`, `tree`
|
|
73
138
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
139
|
+
> **Pipe and chain detection**: `echo hello && cat file | grep x` — each segment is inspected independently. A single read command in any segment blocks the entire chain.
|
|
140
|
+
|
|
141
|
+
## Picking a Reader model
|
|
142
|
+
|
|
143
|
+
> **Critical requirement:** The Reader model **MUST support tool usage** (function calling).
|
|
144
|
+
> It uses `read`, `grep`, `find`, and `ls` via Pi's tool system to fulfill tasks.
|
|
145
|
+
> Models without tool-use capability **will not work** as a Reader.
|
|
146
|
+
|
|
147
|
+
A small, local model is ideal — the Reader executes precise file operations and returns structured results:
|
|
80
148
|
|
|
81
|
-
|
|
149
|
+
| Provider | Recommended models |
|
|
150
|
+
|----------|-------------------|
|
|
151
|
+
| **LM Studio** | `lmstudio/nemotron-mini`, `lmstudio/qwen2.5-7b-instruct` |
|
|
152
|
+
| **Ollama** | `ollama/qwen2.5:7b`, `ollama/llama3.2:3b` |
|
|
153
|
+
| **llama.cpp** | Any model with tool-use support |
|
|
154
|
+
| **OpenAI** | `openai/gpt-4o-mini` |
|
|
155
|
+
| **Anthropic** | `anthropic/claude-3.5-haiku` |
|
|
156
|
+
| **Gemini** | `gemini/gemini-2.0-flash` |
|
|
82
157
|
|
|
83
|
-
|
|
158
|
+
## Troubleshooting
|
|
84
159
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
-
|
|
160
|
+
| Problem | Fix |
|
|
161
|
+
|---------|-----|
|
|
162
|
+
| "pi-subagents not installed" | Restart Pi; the extension auto-installs it on session start |
|
|
163
|
+
| Reader doesn't respond | Check `reader_model` in config; ensure the model supports tool usage |
|
|
164
|
+
| Reader returns incomplete data | The Reader returns minimal, structured output; check reader.md template |
|
|
165
|
+
| Tools not blocked | Run `/read-delegator on` |
|
|
166
|
+
| PowerShell commands bypass filter | Update to latest version; all three shells are covered |
|
|
167
|
+
| Model picker doesn't appear | Check `ctx.modelRegistry` is available in your Pi version |
|
|
88
168
|
|
|
89
|
-
##
|
|
169
|
+
## Project token breakdown
|
|
90
170
|
|
|
91
|
-
|
|
92
|
-
|---|---|
|
|
93
|
-
| `cat`, `grep`, `find`, `ls` | `mkdir`, `touch`, `rm`, `mv` |
|
|
94
|
-
| `head`, `tail`, `less`, `wc` | `cp`, `chmod`, `chown` |
|
|
95
|
-
| `bat`, `rg`, `fd`, `awk` | `npm`, `git`, `docker` |
|
|
96
|
-
| `sed` (without `-i`) | `sed -i` (in-place edit) |
|
|
171
|
+
> Measured 2026-06-14. Token estimates use ~3.5 chars/token (code-heavy ratio).
|
|
97
172
|
|
|
98
|
-
|
|
173
|
+
| File type | Count | Size | Est. tokens |
|
|
174
|
+
|-----------|:-----:|------|:-----------:|
|
|
175
|
+
| TypeScript (`.ts`) | 6 | 66 KB | ~19,300 |
|
|
176
|
+
| JavaScript (`.js`) | 6 | 55 KB | ~16,100 |
|
|
177
|
+
| JSON (`.json`) | 3 | 81 KB | ~23,600 |
|
|
178
|
+
| Source maps (`.map`) | 12 | 42 KB | ~12,200 |
|
|
179
|
+
| Markdown (`.md`) | 3 | 12 KB | ~3,400 |
|
|
180
|
+
| **Total** | **36** | **255 KB** | **~74,700** |
|
|
181
|
+
| **Source only** (`.ts` + `.md`) | **9** | **78 KB** | **~22,700** |
|
|
99
182
|
|
|
100
|
-
|
|
101
|
-
-
|
|
183
|
+
> Source maps and compiled `.js`/`.d.ts` in `dist/` are build artifacts.
|
|
184
|
+
`package-lock.json` accounts for ~78 KB of the JSON total.
|
|
102
185
|
|
|
103
|
-
|
|
186
|
+
## Development
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
git clone <repo>
|
|
190
|
+
cd pi-read-delegator
|
|
191
|
+
npm install
|
|
192
|
+
npm run build # compiles TypeScript to dist/
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Project structure
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
pi-read-delegator/
|
|
199
|
+
├── src/
|
|
200
|
+
│ ├── index.ts # Entry point — events, commands, tool blocking
|
|
201
|
+
│ ├── config.ts # Config load/save with defaults
|
|
202
|
+
│ ├── tool-blocker.ts # Tool removal/restoration
|
|
203
|
+
│ ├── bash-filter.ts # Cross-platform command classification
|
|
204
|
+
│ ├── reader-manager.ts # Subagent health, dependency install, async exec
|
|
205
|
+
│ ├── ui.ts # Localization (tr/en), status bar, log wrappers
|
|
206
|
+
│ └── templates/
|
|
207
|
+
│ └── reader.md # Default Reader subagent template
|
|
208
|
+
├── dist/ # Compiled output (gitignored)
|
|
209
|
+
├── package.json
|
|
210
|
+
├── tsconfig.json
|
|
211
|
+
└── README.md
|
|
212
|
+
```
|
|
104
213
|
|
|
105
214
|
## License
|
|
106
215
|
|
|
@@ -4,23 +4,33 @@
|
|
|
4
4
|
* Classifies shell commands as read-only (delegate to Reader subagent),
|
|
5
5
|
* write (execute directly), or ambiguous (prompt user).
|
|
6
6
|
*/
|
|
7
|
+
/**
|
|
8
|
+
* Split a command string by shell separators (&&, ||, ;, |, &) and return
|
|
9
|
+
* the list of segment strings. Respects quoting so separators inside quotes
|
|
10
|
+
* are not treated as actual shell separators.
|
|
11
|
+
*/
|
|
12
|
+
export declare function splitShellSegments(command: string): string[];
|
|
7
13
|
/**
|
|
8
14
|
* Determine if a bash command is read-only and should be forwarded to Reader.
|
|
9
15
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
16
|
+
* Splits on shell separators (&&, ||, ;, |, &) and checks EACH segment.
|
|
17
|
+
* If ANY segment starts with a read command, the full command is blocked.
|
|
18
|
+
*
|
|
19
|
+
* Examples:
|
|
20
|
+
* isReadCommand("cat file") → true
|
|
21
|
+
* isReadCommand("echo hello && cat file") → true (cat in chain)
|
|
22
|
+
* isReadCommand("npm test") → false
|
|
23
|
+
* isReadCommand("grep x | head -5") → true (pipeline)
|
|
14
24
|
*/
|
|
15
25
|
export declare function isReadCommand(command: string): boolean;
|
|
16
26
|
/**
|
|
17
27
|
* Determine if a bash command modifies the filesystem and should run directly.
|
|
18
28
|
*
|
|
19
29
|
* Rules:
|
|
20
|
-
* - If
|
|
30
|
+
* - If any segment's first word is in WRITE_COMMANDS → true
|
|
21
31
|
* - sed with -i flag → true (in-place edit)
|
|
22
32
|
* - Command contains > or >> redirect → true (writes to file)
|
|
23
|
-
* - Command contains tee
|
|
33
|
+
* - Command contains tee → true (writes to file)
|
|
24
34
|
*/
|
|
25
35
|
export declare function isWriteCommand(command: string): boolean;
|
|
26
36
|
/**
|