@pi-kaush/pi-tool-call-markers 0.2.4 → 0.2.6
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 +21 -14
- package/README.md +58 -31
- package/package.json +1 -1
- package/src/container-hooks.ts +57 -0
- package/src/index.ts +475 -422
- package/src/thinking-block-merger.ts +113 -8
package/CHANGELOG.md
CHANGED
|
@@ -2,20 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
5
|
+
- Group consecutive tool blocks under one `%` marker with per-tool sub-headings and nested sub-bullets, dropping the blank lines between tool sections (F25's compact goal, with the hierarchy that makes it readable).
|
|
6
|
+
- Render subagent calls as an unboxed plan — `% subagent` heading with chain/parallel counts and numbered steps as they execute, agent names in accent with emojis scraped from the native plan component (args fallback) — replacing the accent-rail card; failed subagents follow the full-red failure tone.
|
|
7
|
+
- Strip display sequences and control bytes (notably `\r` from progress writers like git) from collapsed-row text so command output cannot return the cursor to column 0 and overwrite the row.
|
|
8
|
+
- Color the truncation ellipsis to match its row tone (`muted` settled, `error` failed) instead of the terminal default foreground left by pi-tui's truncation reset.
|
|
9
|
+
- Render failed tool rows entirely in `error` — marker, call label, and outcome tail including the arrow and truncation ellipsis — so errored calls stand out as full red lines.
|
|
10
|
+
- Render settled tool rows in one uniform `muted` tone — group headings, bullets, summaries, and outcomes — while keeping `warning` pending and `error` failure states semantic.
|
|
11
|
+
- Compose container-level rendering through the shared
|
|
12
|
+
`kg.pi.chatContainerHooks.v1` registry so grouping no longer shadows (or is
|
|
13
|
+
shadowed by) `pi-content-layout`'s system-message inset in either load order.
|
|
14
|
+
- Label self-rendered `edit` rows by path (`edit <path>`), matching Pi's native
|
|
15
|
+
call line instead of dumping the raw `{ path, edits }` JSON payload.
|
|
16
|
+
- Redesign collapsed tools as unboxed, background-free transcript lines with a two-column outer inset, `%` tool/group headings, `•` grouped children, and semantic low-contrast foregrounds with clear warning/error states.
|
|
17
|
+
- Preserve compact outcomes, right-hand tail reservation, `bash` duration, errors, image output, quiet-turn grouping, grouped-render caching, and MCP/self-rendered tool labels in the new shell.
|
|
18
|
+
- Keep expanded rows fully native so `Ctrl+O` restores complete results, custom renderers, and errors without collapsed decoration.
|
|
19
|
+
- Label hidden local reasoning with Pi's native braille spinner sequence (`⠋ Thinking…`, `⠙ Thinking…`, …) while streaming and `+ Thought · X.Xs` when finalized; use `+ Thought` for restored messages and older runtimes without streaming metadata.
|
|
20
|
+
- Track thinking duration per assistant row in a `WeakMap`, forward optional/future `updateContent` arguments, retain display-only adjacent thinking merging, and add no timer or render loop.
|
|
21
|
+
- Feature-detect private tool and thinking component shapes and fail open to Pi's native rendering while retaining Pi `>=0.80.6` support.
|
|
22
|
+
- Compact multiline singleton calls into one width-safe summary after settlement, including timeout metadata, while preserving the full native call under `Ctrl+O`.
|
|
23
|
+
- Group adjacent calls while they are still running, update pending outcomes in place, and merge sequential calls across quiet assistant turns.
|
|
24
|
+
- Add `PI_TOOL_CALL_MARKERS_COLLAPSE_PARALLEL`, enabled by default, to optionally keep same-assistant-message calls individual.
|
|
25
|
+
- Only invalidate grouped-render caches on meaningful state transitions.
|
|
19
26
|
|
|
20
27
|
## 0.1.2
|
|
21
28
|
|
package/README.md
CHANGED
|
@@ -1,34 +1,59 @@
|
|
|
1
1
|
# @pi-kaush/pi-tool-call-markers
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Give Pi's collapsed tool calls a quiet, width-safe transcript shell while preserving native details under `Ctrl+O`. The package also includes a display-only thinking-block adapter.
|
|
4
4
|
|
|
5
5
|
## What it changes
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Collapsed tool rows use semantic theme colors with no gear, background fill, box padding, or filled blank rows:
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- **
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- **
|
|
9
|
+
```text
|
|
10
|
+
% Read
|
|
11
|
+
• src/a.ts 42 lines
|
|
12
|
+
• src/b.ts 18 lines
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- **Two-column outer inset.** Tool markers and image output align with an inset conversation surface. Very narrow terminals reduce the decoration before useful content.
|
|
16
|
+
- **`%` tool headings.** A singleton stays on one line when its summary and outcome fit. A multi-call group has one `%` heading per contiguous tool type.
|
|
17
|
+
- **`•` grouped children.** Bullets appear only for members of a multi-call group.
|
|
18
|
+
- **Semantic, low-contrast status.** Tool names are emphasized, summaries and settled metadata are muted, pending state is warning-colored, and failures remain error-colored. Ordinary tool states have no background.
|
|
19
|
+
- **Width-safe outcome tails.** Long summaries truncate before useful tails such as `→ done`, `→ 42 lines`, `→ +2/-1`, or a `bash` duration.
|
|
20
|
+
- **Stable running groups.** Adjacent calls group as they appear. Pending state and elapsed `bash` time settle into the final outcome without changing the row count.
|
|
21
|
+
- **Quiet-turn grouping.** Sequential calls can join across an assistant row with no visible prose or thinking. Visible assistant content remains a boundary.
|
|
22
|
+
- **MCP and self-rendered tools.** Their stable call labels, compact arguments, pending state, success, and first error line use the same collapsed shell. Native self-rendered details return when expanded.
|
|
23
|
+
- **Images remain visible.** Image fallback text and terminal image components render below the corresponding marker with the same inset.
|
|
24
|
+
- **Native expansion remains authoritative.** `Ctrl+O` restores Pi's full individual tool rendering, including complete results, custom renderers, and error details.
|
|
25
|
+
|
|
26
|
+
## Subagent plans
|
|
27
|
+
|
|
28
|
+
A recognized `subagent` call renders as an unboxed plan in the shared tool aesthetic:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
% subagent chain (3 steps) [repo-review]
|
|
32
|
+
1. 🐝 bee [workhorse] Challenge the compatibility conclusion…
|
|
33
|
+
2. 🐝 bee …
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Single calls stay on one `% subagent <agent> [profile] <task preview>` row; chain calls get a heading with the kind, count, and scope followed by numbered steps (parallel tasks list without numbers). Agent display names (emoji + name) are scraped from the native plan component with an args fallback, and render in `accent`; everything else stays muted, and failed subagents go full red. Subagents never join ordinary tool groups.
|
|
37
|
+
|
|
38
|
+
Malformed, ambiguous, future, or too-narrow shapes fall back to the generic `% subagent …` collapsed row rather than dropping information, and `Ctrl+O` still exposes the native subagent renderer.
|
|
19
39
|
|
|
20
40
|
## Bundled thinking-block extension
|
|
21
41
|
|
|
22
|
-
The
|
|
42
|
+
The second package entrypoint, `src/thinking-block-merger.ts`, combines only directly adjacent `thinking` blocks in a display copy. Tool calls, text, provider blocks, signatures, and stored session messages are unchanged.
|
|
23
43
|
|
|
24
|
-
|
|
44
|
+
When Pi exposes its per-row hidden-thinking and streaming fields, hidden reasoning uses these native-themed labels:
|
|
25
45
|
|
|
26
|
-
|
|
46
|
+
```text
|
|
47
|
+
⠋ Thinking… → ⠙ Thinking… → …
|
|
48
|
+
+ Thought · 2.5s
|
|
49
|
+
```
|
|
27
50
|
|
|
28
|
-
|
|
51
|
+
The live label samples Pi's native braille spinner sequence from the content updates Pi already renders; it does not add a timer. The adapter stores the first local streaming timestamp per assistant row in a `WeakMap`. A restored message or an older runtime with no streaming argument uses `+ Thought`. Visible-thinking mode remains native. There is no interval, timeout, render request, model call, or network work.
|
|
52
|
+
|
|
53
|
+
## Install
|
|
29
54
|
|
|
30
55
|
```bash
|
|
31
|
-
pi install npm:@pi-kaush/pi-tool-call-markers
|
|
56
|
+
pi install npm:@pi-kaush/pi-tool-call-markers
|
|
32
57
|
```
|
|
33
58
|
|
|
34
59
|
For local development:
|
|
@@ -41,7 +66,7 @@ pi \
|
|
|
41
66
|
|
|
42
67
|
## Configuration
|
|
43
68
|
|
|
44
|
-
Grouping calls from the same assistant message is enabled by default. Pi normally executes those calls in parallel. To keep
|
|
69
|
+
Grouping calls from the same assistant message is enabled by default. Pi normally executes those calls in parallel. To keep same-message calls as individual compact rows while continuing to group sequential calls across quiet turns:
|
|
45
70
|
|
|
46
71
|
```fish
|
|
47
72
|
set -lx PI_TOOL_CALL_MARKERS_COLLAPSE_PARALLEL 0
|
|
@@ -50,35 +75,37 @@ pi
|
|
|
50
75
|
|
|
51
76
|
`0`, `false`, `no`, and `off` disable parallel grouping. `1`, `true`, `yes`, and `on` enable it. The value is read when the extension loads.
|
|
52
77
|
|
|
53
|
-
## Compatibility and
|
|
78
|
+
## Compatibility and fallback policy
|
|
54
79
|
|
|
55
|
-
|
|
80
|
+
**Compatible Pi version:** `@earendil-works/pi-coding-agent` and `@earendil-works/pi-tui` `>=0.80.6`.
|
|
56
81
|
|
|
57
|
-
-
|
|
58
|
-
- `Container` (transcript grouping).
|
|
82
|
+
Pi has no public hook for native tool rows, transcript grouping, or per-message hidden-thinking labels. The package therefore uses three small guarded prototype adapters:
|
|
59
83
|
|
|
60
|
-
|
|
84
|
+
- `ToolExecutionComponent` for collapsed presentation;
|
|
85
|
+
- `Container` for adjacent grouping; and
|
|
86
|
+
- `AssistantMessageComponent.updateContent` for display-only thinking merging and lifecycle labels.
|
|
61
87
|
|
|
62
|
-
|
|
88
|
+
Each adapter feature-detects the fields and methods it needs, keeps the original method, uses an idempotency symbol, catches cosmetic failures, and restores the original on `session_shutdown` when it still owns the patch. Unsupported shapes fail open to Pi's native rendering. The thinking adapter continues adjacent merging even when the private label shape is unavailable.
|
|
63
89
|
|
|
64
|
-
|
|
90
|
+
Expanded tools always use Pi's native renderer. The collapsed tool shell owns its two-column inset directly; transcript layout extensions should leave tool rows unchanged, preventing load-order-dependent double padding.
|
|
65
91
|
|
|
66
|
-
> TODO: migrate to
|
|
92
|
+
> TODO: migrate these adapters to public Pi transcript and tool-rendering APIs when available.
|
|
67
93
|
|
|
68
94
|
## Design
|
|
69
95
|
|
|
70
96
|
- No runtime dependencies.
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
97
|
+
- No mutation of tool arguments, tool results, provider content, or session messages.
|
|
98
|
+
- Group output is cached per row and invalidated on meaningful display transitions.
|
|
99
|
+
- No timers or independent render loops.
|
|
74
100
|
|
|
75
101
|
## Development
|
|
76
102
|
|
|
77
103
|
From the repository root:
|
|
78
104
|
|
|
79
105
|
```bash
|
|
80
|
-
|
|
81
|
-
npm run
|
|
106
|
+
npx vitest run extensions/pi-tool-call-markers/test
|
|
107
|
+
npm run typecheck
|
|
108
|
+
npm run package:check --workspace @pi-kaush/pi-tool-call-markers
|
|
82
109
|
```
|
|
83
110
|
|
|
84
111
|
Inspect the publish payload:
|
package/package.json
CHANGED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Shared chat-container composition contract. pi-content-layout and
|
|
2
|
+
// pi-tool-call-markers each replace Container.prototype.render for different
|
|
3
|
+
// concerns (system-text inset vs tool grouping), and a whole-container
|
|
4
|
+
// wrapper always shadows whatever wrapped the prototype before it. Both
|
|
5
|
+
// packages instead run every registered hook before rendering and restore
|
|
6
|
+
// after, so child-level decoration composes in either load order. The
|
|
7
|
+
// registry is a globalThis set keyed by a well-known symbol: no module
|
|
8
|
+
// coupling, and an empty registry is a no-op when the other package is
|
|
9
|
+
// absent. This file is a deliberate copy of pi-content-layout's contract
|
|
10
|
+
// module: the Symbol key is the shared contract, duplicated to keep both
|
|
11
|
+
// packages free of runtime dependencies on each other.
|
|
12
|
+
|
|
13
|
+
export type ChatContainerHook = (
|
|
14
|
+
container: object,
|
|
15
|
+
children: unknown[],
|
|
16
|
+
width: number,
|
|
17
|
+
) => (() => void) | undefined;
|
|
18
|
+
|
|
19
|
+
export const CHAT_CONTAINER_HOOKS = Symbol.for("kg.pi.chatContainerHooks.v1");
|
|
20
|
+
|
|
21
|
+
type HookRegistry = Set<ChatContainerHook>;
|
|
22
|
+
|
|
23
|
+
export function chatContainerHooks(): HookRegistry {
|
|
24
|
+
const root = globalThis as Record<symbol, HookRegistry | undefined>;
|
|
25
|
+
const existing = root[CHAT_CONTAINER_HOOKS];
|
|
26
|
+
if (existing) return existing;
|
|
27
|
+
const created: HookRegistry = new Set();
|
|
28
|
+
root[CHAT_CONTAINER_HOOKS] = created;
|
|
29
|
+
return created;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function runChatContainerHooks(
|
|
33
|
+
container: object,
|
|
34
|
+
children: unknown,
|
|
35
|
+
width: number,
|
|
36
|
+
): () => void {
|
|
37
|
+
const restores: Array<() => void> = [];
|
|
38
|
+
if (Array.isArray(children)) {
|
|
39
|
+
for (const hook of chatContainerHooks()) {
|
|
40
|
+
try {
|
|
41
|
+
const restore = hook(container, children, width);
|
|
42
|
+
if (typeof restore === "function") restores.push(restore);
|
|
43
|
+
} catch {
|
|
44
|
+
// Hooks are cosmetic; one failing hook must not break rendering.
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return () => {
|
|
49
|
+
for (const restore of restores.reverse()) {
|
|
50
|
+
try {
|
|
51
|
+
restore();
|
|
52
|
+
} catch {
|
|
53
|
+
// Best-effort restore; rendering already completed.
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|