@oh-my-pi/pi-coding-agent 5.3.1 → 5.4.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/CHANGELOG.md +9 -0
- package/package.json +5 -5
- package/src/core/tools/lsp/utils.ts +20 -1
- package/src/core/tools/task/executor.ts +5 -2
- package/src/core/tools/task/model-resolver.ts +12 -5
- package/src/core/tools/web-fetch.ts +14 -0
- package/src/prompts/system/system-prompt.md +10 -2
- package/src/prompts/tools/edit.md +21 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.4.2] - 2026-01-16
|
|
6
|
+
### Changed
|
|
7
|
+
|
|
8
|
+
- Updated model resolution to accept pre-serialized settings for better performance
|
|
9
|
+
- Improved system prompt guidance for position-addressed vs content-addressed file edits
|
|
10
|
+
- Enhanced edit tool documentation with clear use cases for bash alternatives
|
|
11
|
+
|
|
12
|
+
## [5.4.0] - 2026-01-15
|
|
13
|
+
|
|
5
14
|
## [5.3.1] - 2026-01-15
|
|
6
15
|
|
|
7
16
|
## [5.3.0] - 2026-01-15
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.2",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"ompConfig": {
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"prepublishOnly": "bun run generate-template && bun run clean && bun run build"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@oh-my-pi/pi-agent-core": "5.
|
|
43
|
-
"@oh-my-pi/pi-ai": "5.
|
|
44
|
-
"@oh-my-pi/pi-git-tool": "5.
|
|
45
|
-
"@oh-my-pi/pi-tui": "5.
|
|
42
|
+
"@oh-my-pi/pi-agent-core": "5.4.2",
|
|
43
|
+
"@oh-my-pi/pi-ai": "5.4.2",
|
|
44
|
+
"@oh-my-pi/pi-git-tool": "5.4.2",
|
|
45
|
+
"@oh-my-pi/pi-tui": "5.4.2",
|
|
46
46
|
"@openai/agents": "^0.3.7",
|
|
47
47
|
"@silvia-odwyer/photon-node": "^0.3.4",
|
|
48
48
|
"@sinclair/typebox": "^0.34.46",
|
|
@@ -226,6 +226,24 @@ export function severityToIcon(severity?: DiagnosticSeverity): string {
|
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
/**
|
|
230
|
+
* Strip noise from diagnostic messages (clippy URLs, override hints).
|
|
231
|
+
*/
|
|
232
|
+
function stripDiagnosticNoise(message: string): string {
|
|
233
|
+
return message
|
|
234
|
+
.split("\n")
|
|
235
|
+
.filter((line) => {
|
|
236
|
+
const trimmed = line.trim();
|
|
237
|
+
// Skip "for further information visit <url>" lines
|
|
238
|
+
if (trimmed.startsWith("for further information visit")) return false;
|
|
239
|
+
// Skip bare URLs
|
|
240
|
+
if (/^https?:\/\//.test(trimmed)) return false;
|
|
241
|
+
return true;
|
|
242
|
+
})
|
|
243
|
+
.join("\n")
|
|
244
|
+
.trim();
|
|
245
|
+
}
|
|
246
|
+
|
|
229
247
|
/**
|
|
230
248
|
* Format a diagnostic as a human-readable string.
|
|
231
249
|
*/
|
|
@@ -235,8 +253,9 @@ export function formatDiagnostic(diagnostic: Diagnostic, filePath: string): stri
|
|
|
235
253
|
const col = diagnostic.range.start.character + 1;
|
|
236
254
|
const source = diagnostic.source ? `[${diagnostic.source}] ` : "";
|
|
237
255
|
const code = diagnostic.code ? ` (${diagnostic.code})` : "";
|
|
256
|
+
const message = stripDiagnosticNoise(diagnostic.message);
|
|
238
257
|
|
|
239
|
-
return `${filePath}:${line}:${col} [${severity}] ${source}${
|
|
258
|
+
return `${filePath}:${line}:${col} [${severity}] ${source}${message}${code}`;
|
|
240
259
|
}
|
|
241
260
|
|
|
242
261
|
/**
|
|
@@ -269,8 +269,11 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
const serializedSettings = options.settingsManager?.serialize();
|
|
273
|
+
const availableModels = options.modelRegistry?.getAvailable().map((model) => `${model.provider}/${model.id}`);
|
|
274
|
+
|
|
272
275
|
// Resolve and add model
|
|
273
|
-
const resolvedModel = await resolveModelPattern(modelOverride || agent.model);
|
|
276
|
+
const resolvedModel = await resolveModelPattern(modelOverride || agent.model, availableModels, serializedSettings);
|
|
274
277
|
const sessionFile = subtaskSessionFile ?? options.sessionFile ?? null;
|
|
275
278
|
const spawnsEnv = agent.spawns === undefined ? "" : agent.spawns === "*" ? "*" : agent.spawns.join(",");
|
|
276
279
|
|
|
@@ -601,7 +604,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
601
604
|
enableLsp,
|
|
602
605
|
serializedAuth: options.authStorage?.serialize(),
|
|
603
606
|
serializedModels: options.modelRegistry?.serialize(),
|
|
604
|
-
serializedSettings
|
|
607
|
+
serializedSettings,
|
|
605
608
|
mcpTools: options.mcpManager ? extractMCPToolMetadata(options.mcpManager) : undefined,
|
|
606
609
|
},
|
|
607
610
|
};
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
* - "omp/slow" or "pi/slow" → configured slow model from settings
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import { type Settings, settingsCapability } from "../../../capability/settings";
|
|
14
|
+
import { type Settings as SettingsFile, settingsCapability } from "../../../capability/settings";
|
|
15
15
|
import { loadCapability } from "../../../discovery";
|
|
16
|
+
import type { Settings as SettingsData } from "../../settings-manager";
|
|
16
17
|
import { resolveOmpCommand } from "./omp-command";
|
|
17
18
|
|
|
18
19
|
/** Cache for available models (provider/modelId format) */
|
|
@@ -80,7 +81,7 @@ export function clearModelCache(): void {
|
|
|
80
81
|
* Load model roles from settings files using capability API.
|
|
81
82
|
*/
|
|
82
83
|
async function loadModelRoles(): Promise<Record<string, string>> {
|
|
83
|
-
const result = await loadCapability<
|
|
84
|
+
const result = await loadCapability<SettingsFile>(settingsCapability.id, { cwd: process.cwd() });
|
|
84
85
|
|
|
85
86
|
// Merge all settings, prioritizing first (highest priority)
|
|
86
87
|
let modelRoles: Record<string, string> = {};
|
|
@@ -99,8 +100,12 @@ async function loadModelRoles(): Promise<Record<string, string>> {
|
|
|
99
100
|
* Looks up the role in settings.modelRoles and returns the configured model.
|
|
100
101
|
* Returns undefined if the role isn't configured.
|
|
101
102
|
*/
|
|
102
|
-
async function resolveOmpAlias(
|
|
103
|
-
|
|
103
|
+
async function resolveOmpAlias(
|
|
104
|
+
role: string,
|
|
105
|
+
availableModels: string[],
|
|
106
|
+
settings?: SettingsData,
|
|
107
|
+
): Promise<string | undefined> {
|
|
108
|
+
const roles = settings?.modelRoles ?? (await loadModelRoles());
|
|
104
109
|
|
|
105
110
|
// Look up role in settings (case-insensitive)
|
|
106
111
|
const configured = roles[role] || roles[role.toLowerCase()];
|
|
@@ -135,10 +140,12 @@ function getProvider(fullModel: string): string | undefined {
|
|
|
135
140
|
*
|
|
136
141
|
* @param pattern - Model pattern to resolve
|
|
137
142
|
* @param availableModels - Optional pre-fetched list of available models (in provider/modelId format)
|
|
143
|
+
* @param settings - Optional settings for role alias resolution (pi/..., omp/...)
|
|
138
144
|
*/
|
|
139
145
|
export async function resolveModelPattern(
|
|
140
146
|
pattern: string | undefined,
|
|
141
147
|
availableModels?: string[],
|
|
148
|
+
settings?: SettingsData,
|
|
142
149
|
): Promise<string | undefined> {
|
|
143
150
|
if (!pattern || pattern === "default") {
|
|
144
151
|
return undefined;
|
|
@@ -161,7 +168,7 @@ export async function resolveModelPattern(
|
|
|
161
168
|
const lower = p.toLowerCase();
|
|
162
169
|
if (lower.startsWith("omp/") || lower.startsWith("pi/")) {
|
|
163
170
|
const role = lower.startsWith("omp/") ? p.slice(4) : p.slice(3);
|
|
164
|
-
const resolved = await resolveOmpAlias(role, models);
|
|
171
|
+
const resolved = await resolveOmpAlias(role, models, settings);
|
|
165
172
|
if (resolved) return resolved;
|
|
166
173
|
continue; // Role not configured, try next pattern
|
|
167
174
|
}
|
|
@@ -519,6 +519,20 @@ async function renderUrl(
|
|
|
519
519
|
throw new Error("Operation aborted");
|
|
520
520
|
}
|
|
521
521
|
|
|
522
|
+
// Handle internal protocol URLs (e.g., pi-internal://) - return empty
|
|
523
|
+
if (url.startsWith("pi-internal://")) {
|
|
524
|
+
return {
|
|
525
|
+
url,
|
|
526
|
+
finalUrl: url,
|
|
527
|
+
contentType: "text/plain",
|
|
528
|
+
method: "internal",
|
|
529
|
+
content: "",
|
|
530
|
+
fetchedAt,
|
|
531
|
+
truncated: false,
|
|
532
|
+
notes: ["Internal protocol URL - no external content"],
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
|
|
522
536
|
// Step 0: Normalize URL (ensure scheme for special handlers)
|
|
523
537
|
url = normalizeUrl(url);
|
|
524
538
|
const origin = getOrigin(url);
|
|
@@ -71,12 +71,20 @@ Every tool is a choice. The wrong choice is friction. The right choice is invisi
|
|
|
71
71
|
File and system operations:
|
|
72
72
|
- `mv`, `cp`, `rm`, `ln -s` — moving, copying, deleting, symlinking
|
|
73
73
|
- `mkdir -p`, `chmod` — directory creation, permissions
|
|
74
|
-
- `sd` — bulk find/replace across multiple files (faster than repeated edits)
|
|
75
74
|
- `tar`, `zip`, `unzip` — archives
|
|
76
75
|
- `curl` — downloading files
|
|
77
76
|
- Build commands: `cargo`, `npm`, `make`, `docker`
|
|
78
77
|
- Process management: running servers, background tasks
|
|
79
78
|
|
|
79
|
+
Position-addressed and pattern-addressed edits:
|
|
80
|
+
- `cat >> file <<'EOF'` — append to file
|
|
81
|
+
- `sed -i 'N,Md' file` — delete lines N-M
|
|
82
|
+
- `sed -i 'Na\text' file` — insert after line N
|
|
83
|
+
- `sd 'pattern' 'replacement' file` — regex replace
|
|
84
|
+
- `sd 'pattern' 'replacement' **/*.ts` — bulk regex across files
|
|
85
|
+
- `sed -n 'N,Mp' src >> dest` — copy lines N-M to another file
|
|
86
|
+
- `sed -n 'N,Mp' src >> dest && sed -i 'N,Md' src` — move lines N-M to another file
|
|
87
|
+
|
|
80
88
|
### What bash is NOT for
|
|
81
89
|
Specialized tools exist. Use them.
|
|
82
90
|
|
|
@@ -84,7 +92,7 @@ Specialized tools exist. Use them.
|
|
|
84
92
|
{{#has tools "grep"}}- Searching content: `grep` finds. Shell pipelines guess.{{/has}}
|
|
85
93
|
{{#has tools "find"}}- Finding files: `find` knows structure. `ls | grep` hopes.{{/has}}
|
|
86
94
|
{{#has tools "ls"}}- Listing directories: `ls` tool, not bash ls.{{/has}}
|
|
87
|
-
{{#has tools "edit"}}-
|
|
95
|
+
{{#has tools "edit"}}- Content-addressed edits: `edit` finds text. Use bash for position/pattern (append, line N, regex).{{/has}}
|
|
88
96
|
{{#has tools "git"}}- Git operations: `git` tool has guards. Bash git has none.{{/has}}
|
|
89
97
|
|
|
90
98
|
### Hierarchy of trust
|
|
@@ -1,9 +1,30 @@
|
|
|
1
1
|
Performs string replacements in files with fuzzy whitespace matching.
|
|
2
2
|
|
|
3
3
|
Usage:
|
|
4
|
+
- Use the smallest edit that uniquely identifies the change. To toggle a checkbox: `- [ ] Task` → `- [x] Task`, not the entire line.
|
|
4
5
|
- You must use your read tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file.
|
|
5
6
|
- Fuzzy matching handles minor whitespace/indentation differences automatically - you don't need to match indentation exactly.
|
|
6
7
|
- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.
|
|
7
8
|
- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.
|
|
8
9
|
- The edit will FAIL if old_string is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use replace_all to change every instance of old_string.
|
|
9
10
|
- Use replace_all for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.
|
|
11
|
+
|
|
12
|
+
## When to use bash instead
|
|
13
|
+
|
|
14
|
+
Edit is for content-addressed changes—you identify *what* to change by its text.
|
|
15
|
+
|
|
16
|
+
For position-addressed or pattern-addressed changes, bash is more efficient:
|
|
17
|
+
|
|
18
|
+
| Operation | Command |
|
|
19
|
+
|-----------|---------|
|
|
20
|
+
| Append to file | `cat >> file <<'EOF'`...`EOF` |
|
|
21
|
+
| Prepend to file | `{ cat - file; } <<'EOF' > tmp && mv tmp file` |
|
|
22
|
+
| Delete lines N-M | `sed -i 'N,Md' file` |
|
|
23
|
+
| Insert after line N | `sed -i 'Na\text' file` |
|
|
24
|
+
| Regex replace | `sd 'pattern' 'replacement' file` |
|
|
25
|
+
| Bulk replace across files | `sd 'pattern' 'replacement' **/*.ts` |
|
|
26
|
+
| Copy lines N-M to another file | `sed -n 'N,Mp' src >> dest` |
|
|
27
|
+
| Move lines N-M to another file | `sed -n 'N,Mp' src >> dest && sed -i 'N,Md' src` |
|
|
28
|
+
|
|
29
|
+
Use Edit when the *content itself* identifies the location.
|
|
30
|
+
Use bash when *position* or *pattern* identifies what to change.
|