Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

neovim/.system/research/NVIM-RESEARCH-T3BL4TK4-pi-tool-result-formats-for-presentation/index.md

Raw
Rendered preview

id: NVIM-RESEARCH-T3BL4TK4 type: research title: Pi tool result formats for presentation

Pi tool result formats for presentation

Read from real Pi session logs on disk ($PI_CODING_AGENT_SESSION_DIR), not from prose. Each tool result is a toolResult message: { role, toolCallId, toolName, content, isError, timestamp, details? }. content is always a text block list [{ type:"text", text }]; the rich, per-tool structure lives in details.

This closes the evidence gap that blocked grep file-grouping and the bash full-output surface.

Per-tool shapes

Tool details keys content text shape
edit diff, firstChangedLine a short sentence, e.g. Successfully replaced 4 block(s) in <path>.
grep none ripgrep context output, or No matches found
find none newline-separated names, no line numbers
ls none newline-separated entries, directories suffixed /
bash truncation, fullOutputPath the captured output, possibly truncated
read truncation file content
write none a short sentence

edit

details.diff is a display diff with a line-number gutter and change markers, for example:

   9  * ...
+ 11  * The tools use ...
+ 12  * a system prompt section ...

A removed line is marked -, an added line +, and a context line has no marker. details.firstChangedLine is the first changed line number. This matches what pivi already consumes; no change needed for the edit diff.

grep

No details. The match structure is only in content.text, in ripgrep's context format:

  • a match line is PATH:LINE:TEXT
  • a context line is PATH-LINE-TEXT
  • distinct match groups may be separated by a -- line
  • an empty search is exactly No matches found

The path repeats on every line, so grouping by file means reading the PATH prefix and collecting consecutive lines that share it; the match lines are the ones joined by : rather than -. There is no column offset in this format, so an exact in-line match span is not available; only the whole match line can be distinguished without re-searching the text client-side.

find and ls

content.text is a newline-separated list. find returns names or paths with no line numbers, so a find result groups trivially as a flat list. ls suffixes directories with /.

bash

details.truncation carries { truncated: bool, ... }; details.fullOutputPath is a filesystem path to the complete output when the kept result was trimmed. A full-output detail surface opens that path.

read

details.truncation only; the subject path is the file itself, so a preview leads back to the file that was read.

Conclusions

  • grep and find file-grouping is implementable now: parse the ripgrep context format, grouping consecutive lines by their PATH prefix and marking the : match lines; find is a flat list.
  • Exact in-line match highlighting is not supported by the data; distinguish the match line, or re-find the term client-side, rather than relying on an offset.
  • The bash full-output surface opens details.fullOutputPath; truncation is details.truncation.truncated.
  • Edit diff and first-changed-line are already correct against the real shape; no rework there.

Unresolved

  • Whether ripgrep emits -- separators and heading lines under every Pi configuration, or only with certain flags; the parser must tolerate both.
  • Whether a stable match column is ever present in any grep mode; none seen in the sampled logs.
  • Whether details.truncation ever includes a kept/total count useful to show beyond the boolean.
---
id: NVIM-RESEARCH-T3BL4TK4
type: research
title: Pi tool result formats for presentation
---

# Pi tool result formats for presentation

Read from real Pi session logs on disk (`$PI_CODING_AGENT_SESSION_DIR`), not from prose.
Each tool result is a `toolResult` message: `{ role, toolCallId, toolName, content, isError, timestamp, details? }`.
`content` is always a text block list `[{ type:"text", text }]`; the rich, per-tool structure lives in `details`.

This closes the evidence gap that blocked grep file-grouping and the bash full-output surface.

## Per-tool shapes

| Tool | `details` keys | `content` text shape |
| --- | --- | --- |
| edit | `diff`, `firstChangedLine` | a short sentence, e.g. `Successfully replaced 4 block(s) in <path>.` |
| grep | none | ripgrep context output, or `No matches found` |
| find | none | newline-separated names, no line numbers |
| ls | none | newline-separated entries, directories suffixed `/` |
| bash | `truncation`, `fullOutputPath` | the captured output, possibly truncated |
| read | `truncation` | file content |
| write | none | a short sentence |

### edit

`details.diff` is a display diff with a line-number gutter and change markers, for example:

```
   9  * ...
+ 11  * The tools use ...
+ 12  * a system prompt section ...
```

A removed line is marked `-`, an added line `+`, and a context line has no marker.
`details.firstChangedLine` is the first changed line number.
This matches what pivi already consumes; no change needed for the edit diff.

### grep

No `details`. The match structure is only in `content.text`, in ripgrep's context format:

- a match line is `PATH:LINE:TEXT`
- a context line is `PATH-LINE-TEXT`
- distinct match groups may be separated by a `--` line
- an empty search is exactly `No matches found`

The path repeats on every line, so grouping by file means reading the `PATH` prefix and collecting consecutive lines that share it; the match lines are the ones joined by `:` rather than `-`.
There is no column offset in this format, so an exact in-line match span is not available; only the whole match line can be distinguished without re-searching the text client-side.

### find and ls

`content.text` is a newline-separated list.
`find` returns names or paths with no line numbers, so a find result groups trivially as a flat list.
`ls` suffixes directories with `/`.

### bash

`details.truncation` carries `{ truncated: bool, ... }`; `details.fullOutputPath` is a filesystem path to the complete output when the kept result was trimmed.
A full-output detail surface opens that path.

### read

`details.truncation` only; the subject path is the file itself, so a preview leads back to the file that was read.

## Conclusions

- grep and find file-grouping is implementable now: parse the ripgrep context format, grouping consecutive lines by their `PATH` prefix and marking the `:` match lines; `find` is a flat list.
- Exact in-line match highlighting is not supported by the data; distinguish the match line, or re-find the term client-side, rather than relying on an offset.
- The bash full-output surface opens `details.fullOutputPath`; truncation is `details.truncation.truncated`.
- Edit diff and first-changed-line are already correct against the real shape; no rework there.

## Unresolved

- Whether ripgrep emits `--` separators and heading lines under every Pi configuration, or only with certain flags; the parser must tolerate both.
- Whether a stable match column is ever present in any grep mode; none seen in the sampled logs.
- Whether `details.truncation` ever includes a kept/total count useful to show beyond the boolean.