@oh-my-pi/pi-coding-agent 5.4.0 → 5.5.0

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 CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.5.0] - 2026-01-18
6
+ ### Changed
7
+
8
+ - Updated task execution guidelines to improve prompt framing and parallelization instructions
9
+
10
+ ## [5.4.2] - 2026-01-16
11
+ ### Changed
12
+
13
+ - Updated model resolution to accept pre-serialized settings for better performance
14
+ - Improved system prompt guidance for position-addressed vs content-addressed file edits
15
+ - Enhanced edit tool documentation with clear use cases for bash alternatives
16
+
5
17
  ## [5.4.0] - 2026-01-15
6
18
 
7
19
  ## [5.3.1] - 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.4.0",
3
+ "version": "5.5.0",
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.4.0",
43
- "@oh-my-pi/pi-ai": "5.4.0",
44
- "@oh-my-pi/pi-git-tool": "5.4.0",
45
- "@oh-my-pi/pi-tui": "5.4.0",
42
+ "@oh-my-pi/pi-agent-core": "5.5.0",
43
+ "@oh-my-pi/pi-ai": "5.5.0",
44
+ "@oh-my-pi/pi-git-tool": "5.5.0",
45
+ "@oh-my-pi/pi-tui": "5.5.0",
46
46
  "@openai/agents": "^0.3.7",
47
47
  "@silvia-odwyer/photon-node": "^0.3.4",
48
48
  "@sinclair/typebox": "^0.34.46",
@@ -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: options.settingsManager?.serialize(),
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<Settings>(settingsCapability.id, { cwd: process.cwd() });
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(role: string, availableModels: string[]): Promise<string | undefined> {
103
- const roles = await loadModelRoles();
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
  }
@@ -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"}}- Editing files: `edit` is precise. `sed` is brittle.{{/has}}
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.
@@ -32,9 +32,13 @@ Agents with "Output: structured" have a fixed schema enforced via frontmatter; y
32
32
 
33
33
  - Always include a short description of the task in the task parameter
34
34
  - **Plan-then-execute**: Put shared constraints in `context`, keep each task focused, specify acceptance criteria; use `output` when you need structured output
35
+ - **Ask open-ended questions**: For exploration tasks, frame prompts to elicit factual discovery, not confirmation. Avoid yes/no questions that are easy to hallucinate.
36
+ - Bad: "Is there rate limiting?" or "Does the API validate tokens?" → Binary answers invite hallucination
37
+ - Good: "Find and describe how rate limiting is implemented" or "How does the API handle token validation?" → Forces investigation and factual reporting
38
+ - The subagent should report *what exists*, then YOU verify if it meets requirements
35
39
  - **Minimize tool chatter**: Avoid repeating large context; use Output tool with output ids for full logs
36
40
  - **Structured completion**: If `output` is provided, subagents must call `complete` to finish
37
- - **Parallelize**: Launch multiple agents concurrently whenever possible
41
+ - **Parallelize**: Launch multiple agents whenever possible. You MUST use a single Task call with multiple entries in the `tasks` array to do this.
38
42
  - **Isolate file scopes**: Assign each task distinct files or directories so agents don't conflict
39
43
  - **Results are intermediate data**: Agent findings provide context for YOU to perform actual work. Do not treat agent reports as "task complete" signals.
40
44
  - **Stateless invocations**: Subagents have zero memory of your conversation. Pass ALL relevant context: requirements discussed, decisions made, schemas agreed upon, file paths mentioned. If you reference something from earlier discussion without including it, the subagent will fail.