pi-open-agents 0.1.31 → 0.1.32

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 CHANGED
@@ -334,9 +334,11 @@ Use `replace-all` for fully isolated agents that should not be influenced by
334
334
  workspace context — e.g., a subagent that must run identically regardless of
335
335
  the project it's invoked from.
336
336
 
337
- For **subagents** (child process), the agent body **is** the system prompt —
338
- pi's default prompt is not included. Skills are injected as an XML block after
339
- the body.
337
+ For **subagents** (child process), the same modes apply: with the default
338
+ `append`, the agent body is appended to pi's default prompt (`--append-system-prompt`);
339
+ `replace`/`replace-all` pass the body as the whole system prompt (`--system-prompt`).
340
+ Skills are injected as an XML block after the body, followed by the result-closing
341
+ contract (`## Outcome` block, file + summary).
340
342
 
341
343
  ---
342
344
 
@@ -415,7 +417,8 @@ six sessions, zero chaos: that's the exact workstation setup documented in
415
417
  - ~~**Per-call model override** in `subagent()`~~ — ✅ shipped in [0.1.19](https://github.com/andrea-tomassi/pi-open-agents/releases/tag/v0.1.19) (#10)
416
418
  - ~~**Primary tool filters incl. extension tools**~~ — ✅ shipped in [0.1.30](https://github.com/andrea-tomassi/pi-open-agents/releases/tag/v0.1.30) (#18)
417
419
  - ~~**Subagent output: file + summary**~~ — ✅ shipped in [0.1.31](https://github.com/andrea-tomassi/pi-open-agents/releases/tag/v0.1.31) (#32)
418
- - **Parallel subagent limit** — #11
420
+ - ~~**Parallel subagent limit**~~ — ✅ closed, see #11 for the outcome
421
+ - **Zero open issues** — the tracker is empty; new work starts from new issues.
419
422
 
420
423
  ---
421
424
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-open-agents",
3
- "version": "0.1.31",
3
+ "version": "0.1.32",
4
4
  "description": "Unified agent and subagent management for pi coding agent, with OpenCode-compatible agent definitions.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -78,8 +78,8 @@ export function buildClosingContract(outputPath?: string): string {
78
78
  "",
79
79
  "If you produced files the caller asked for, list each on its own line as",
80
80
  "`<path>` — <one line describing the content>.",
81
- "Keep the outcome block to 2-3 lines. Never paste the full output after the",
82
- "marker when a file reference suffices; never hide an error behind a file reference.",
81
+ "Keep the outcome block to 2-3 lines. Keep the rest of your answer concise — the",
82
+ "outcome block is what the caller reads first; never hide an error behind brevity.",
83
83
  ];
84
84
  if (outputPath) {
85
85
  lines.push(
@@ -45,7 +45,7 @@ import {
45
45
  parentInheritedRules,
46
46
  type RecursionEnv,
47
47
  } from "./env.ts";
48
- import { preview, shortenPath, stringArg } from "../utils/format.ts";
48
+ import { byteLength, preview, shortenPath, stringArg } from "../utils/format.ts";
49
49
 
50
50
  // ─── Types ───────────────────────────────────────────────────────────────────
51
51
 
@@ -161,11 +161,41 @@ function toToolResult(result: AgentResult) {
161
161
 
162
162
  function toProgressResult(progress: AgentProgress) {
163
163
  return {
164
- content: [{ type: "text" as const, text: progress.output || "(running...)" }],
164
+ content: [{ type: "text" as const, text: liveProgressText(progress.output) }],
165
165
  details: progress,
166
166
  };
167
167
  }
168
168
 
169
+ /**
170
+ * Cap for live progress text (issue #32 follow-up).
171
+ *
172
+ * Every progress emit used to re-send the child's ENTIRE accumulated output:
173
+ * over a long run the same bytes go out N times (once per event, growing).
174
+ * Partial updates are transient (never persisted to the transcript — verified
175
+ * against live session JSONL), so the cap only trims live display/RPC traffic:
176
+ * the tail stays (what the child is doing *now*), the head is already in the
177
+ * temp archive. Final results are untouched (see toToolResult).
178
+ */
179
+ export const LIVE_PROGRESS_MAX_BYTES = 2048;
180
+
181
+ /** Tail a string to a byte budget (halving converge, multibyte-safe). */
182
+ export function tailTextByBytes(text: string, maxBytes: number): string {
183
+ if (byteLength(text) <= maxBytes) return text;
184
+ let take = Math.min(text.length, maxBytes);
185
+ let cut = text.slice(text.length - take);
186
+ while (byteLength(cut) > maxBytes && take > 0) {
187
+ take = Math.floor(take / 2);
188
+ cut = text.slice(text.length - take);
189
+ }
190
+ return cut;
191
+ }
192
+
193
+ function liveProgressText(output: string | undefined): string {
194
+ const text = output || "(running...)";
195
+ const tailed = tailTextByBytes(text, LIVE_PROGRESS_MAX_BYTES);
196
+ return tailed.length < text.length ? `[…earlier live output omitted…]\n${tailed}` : text;
197
+ }
198
+
169
199
  // ─── Styled Rendering ────────────────────────────────────────────────────────
170
200
 
171
201
  function styledPathArg(args: Record<string, unknown>, theme: ThemeLike, fallback?: string): string {