@pi-kaush/pi-tool-call-markers 0.1.1 → 0.1.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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2
4
+
5
+ - Keep grouping within one assistant tool batch, so a later pending batch does not reopen completed groups.
6
+ - Wait for every tool in a batch to settle, including tools beyond failed or expanded siblings.
7
+ - Preserve partial and image-bearing results instead of collapsing them.
8
+ - Treat self-rendered tools as owning their full shell and use only their stable header line in grouped summaries.
9
+
3
10
  ## 0.1.1
4
11
 
5
12
  - Wait for every call in a contiguous parallel run to settle before grouping successful calls, which prevents completed prefixes and suffixes from repeatedly collapsing around active calls.
package/README.md CHANGED
@@ -10,7 +10,9 @@ When several tool calls of the same type succeed in a row, Pi normally renders e
10
10
  - **Bulleted call summaries.** Each call in a group becomes one bullet with a short summary (the tool name is stripped from the bullet since the header already names the tool).
11
11
  - **Vertical spacing between tool types.** A blank line separates one tool group from the next.
12
12
  - **Hanging indent for wrapped bullets.** When a summary wraps, continuation lines align under the bullet text rather than under the gear.
13
- - **Parallel runs settle before grouping.** A contiguous run stays ungrouped while any call is active. After every call settles, successful calls group around visible thinking or text and failed-call boundaries.
13
+ - **Tool batches settle before grouping.** A tool batch stays ungrouped while any sibling call is active. Completed batches remain stable when a later assistant turn starts, and successful calls group around failed-call boundaries after the batch settles.
14
+ - **Self-rendered tools keep their shell.** Tools that own their framing keep singleton previews intact. Grouped summaries use only their stable header instead of scraping preview or diff lines.
15
+ - **Partial and image results stay visible.** Streaming progress and image-bearing results are not collapsed into text-only groups.
14
16
  - **Errors expand in place.** A failed call keeps its own block and shows its full detail.
15
17
  - **Ctrl+O restores full blocks.** Expanding tools (`setToolsExpanded(true)`) brings back Pi's individual full blocks, results and all.
16
18
  - **Adjacent thinking blocks combine.** Only directly adjacent `thinking` blocks merge into one; a non-thinking block between them keeps them separate. Malformed thinking content safely falls back to Pi's renderer exactly once, so the display never breaks.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-kaush/pi-tool-call-markers",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Collapse adjacent successful tool calls into one compact, gear-headed block per tool type in Pi's transcript.",
5
5
  "license": "MIT",
6
6
  "author": "Kaushik Gopal",
package/src/index.ts CHANGED
@@ -47,7 +47,10 @@ type ToolExecutionRow = {
47
47
  args?: unknown;
48
48
  expanded?: boolean;
49
49
  isPartial?: boolean;
50
- result?: { isError?: boolean };
50
+ result?: {
51
+ isError?: boolean;
52
+ content?: Array<{ type?: unknown }>;
53
+ };
51
54
  contentBox?: ComponentContainer;
52
55
  contentText?: TextComponent;
53
56
  selfRenderContainer?: ComponentContainer;
@@ -204,14 +207,18 @@ function hideResultImages(row: ToolExecutionRow): void {
204
207
  }
205
208
 
206
209
  function collapseSuccessfulResult(row: ToolExecutionRow): void {
207
- if (row.expanded !== false || !row.result || row.result.isError) return;
210
+ if (
211
+ row.expanded !== false ||
212
+ row.isPartial !== false ||
213
+ !row.result ||
214
+ row.result.isError ||
215
+ hasImageResult(row) ||
216
+ row.getRenderShell?.() === "self"
217
+ )
218
+ return;
208
219
 
209
220
  const collapsed = row.hasRendererDefinition?.()
210
- ? removeResultComponent(
211
- row.getRenderShell?.() === "self"
212
- ? row.selfRenderContainer
213
- : row.contentBox,
214
- )
221
+ ? removeResultComponent(row.contentBox)
215
222
  : collapseGenericResult(row);
216
223
  if (collapsed) hideResultImages(row);
217
224
  }
@@ -222,12 +229,25 @@ function isToolExecutionRow(
222
229
  return component instanceof ToolExecutionComponent;
223
230
  }
224
231
 
232
+ function isAssistantMessageRow(component: unknown): boolean {
233
+ return component instanceof AssistantMessageComponent;
234
+ }
235
+
236
+ function hasImageResult(row: ToolExecutionRow): boolean {
237
+ return (
238
+ row.result?.content?.some((content) => content.type === "image") === true ||
239
+ (row.imageComponents?.length ?? 0) > 0 ||
240
+ (row.imageSpacers?.length ?? 0) > 0
241
+ );
242
+ }
243
+
225
244
  function isCollapsibleSuccess(row: ToolExecutionRow): boolean {
226
245
  return (
227
246
  row.expanded === false &&
228
247
  row.isPartial === false &&
229
248
  !!row.result &&
230
- !row.result.isError
249
+ !row.result.isError &&
250
+ !hasImageResult(row)
231
251
  );
232
252
  }
233
253
 
@@ -235,7 +255,7 @@ function isSettledToolRow(row: ToolExecutionRow): boolean {
235
255
  return row.isPartial === false && !!row.result;
236
256
  }
237
257
 
238
- function hasUnsettledToolInGroupRun(
258
+ function hasUnsettledToolInBatch(
239
259
  children: unknown[],
240
260
  index: number,
241
261
  renderAt: (index: number) => string[],
@@ -247,9 +267,9 @@ function hasUnsettledToolInGroupRun(
247
267
  candidateIndex += direction
248
268
  ) {
249
269
  const candidate = children[candidateIndex];
270
+ if (isAssistantMessageRow(candidate)) break;
250
271
  if (isToolExecutionRow(candidate)) {
251
272
  if (!isSettledToolRow(candidate)) return true;
252
- if (!isCollapsibleSuccess(candidate)) break;
253
273
  continue;
254
274
  }
255
275
  if (renderAt(candidateIndex).some(hasVisibleContent)) break;
@@ -340,11 +360,12 @@ function renderedCallSummary(
340
360
  component = row.contentBox.children[0] as ComponentLike | undefined;
341
361
  }
342
362
 
363
+ const selfRendered = row.getRenderShell?.() === "self";
343
364
  if (component && typeof component.render === "function") {
344
365
  const visibleLines = component
345
366
  .render(Math.max(1, width))
346
367
  .filter(hasVisibleContent);
347
- const rendered = visibleLines.slice(0, 3);
368
+ const rendered = visibleLines.slice(0, selfRendered ? 1 : 3);
348
369
  const line = rendered[0];
349
370
  if (line) {
350
371
  const first = trimRenderedLine(line);
@@ -380,6 +401,8 @@ function renderedCallSummary(
380
401
  }
381
402
  }
382
403
 
404
+ if (selfRendered) return theme.fg("muted", "(details omitted)");
405
+
383
406
  const fallback = compactArgs(row.args);
384
407
  return fallback
385
408
  ? theme.fg("accent", fallback)
@@ -577,7 +600,7 @@ function renderContainerWithToolGroups(
577
600
  lines.push(...renderAt(index));
578
601
  continue;
579
602
  }
580
- if (hasUnsettledToolInGroupRun(children, index, renderAt)) {
603
+ if (hasUnsettledToolInBatch(children, index, renderAt)) {
581
604
  lines.push(...renderAt(index));
582
605
  continue;
583
606
  }
@@ -590,6 +613,7 @@ function renderContainerWithToolGroups(
590
613
  candidateIndex++
591
614
  ) {
592
615
  const candidate = children[candidateIndex];
616
+ if (isAssistantMessageRow(candidate)) break;
593
617
  if (isToolExecutionRow(candidate)) {
594
618
  if (!isCollapsibleSuccess(candidate)) break;
595
619
  group.push(candidate);