docs(cli): regenerate command reference for `session view`
Adds the generated `session view` accordion to the docs snippet and points the session-debugging workflows at it. Trims the docstring to plain prose — the RST double-backticks were rendering literally in `--help`, where every other command uses unmarked flag names — and stops the generator emitting a trailing blank line that tripped end-of-file-fixer on every regeneration. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
0decd2764e
commit
192c3edbff
|
|
@ -305,7 +305,7 @@ honcho peer set-metadata <metadata>
|
|||
|
||||
## honcho session
|
||||
|
||||
List, inspect, create, delete, and manage conversation sessions and their peers.
|
||||
List, inspect, view, create, delete, and manage conversation sessions and their peers.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="add-peers">
|
||||
|
|
@ -461,6 +461,48 @@ honcho session summaries [<session_id>]
|
|||
|
||||
<ParamField path="session_id" type="string" />
|
||||
</Accordion>
|
||||
<Accordion title="view">
|
||||
View a session transcript as a chat log.
|
||||
|
||||
Modes (pick one):
|
||||
|
||||
- default / --last N: tail of the conversation (most recent N)
|
||||
- --page N [--size M]: page through the full transcript
|
||||
- --all: every message
|
||||
|
||||
Paging follows the requested order: --page 1 starts at the oldest message,
|
||||
or the newest with --reverse.
|
||||
|
||||
Human mode prints a row-delimited table. JSON mode emits the message list
|
||||
(same shape as message list).
|
||||
|
||||
```bash
|
||||
honcho session view [<session_id>]
|
||||
```
|
||||
|
||||
<ParamField path="session_id" type="string" />
|
||||
<ParamField path="--last" type="number">
|
||||
Show only the N most recent messages (default when no --page/--all: 50).
|
||||
</ParamField>
|
||||
<ParamField path="--page" type="number">
|
||||
1-indexed page of the full transcript. Use for page 2+.
|
||||
</ParamField>
|
||||
<ParamField path="--size" type="number">
|
||||
Messages per page; requires --page (1-100, default: 50).
|
||||
</ParamField>
|
||||
<ParamField path="--all" type="boolean">
|
||||
Show the full transcript (every page).
|
||||
</ParamField>
|
||||
<ParamField path="--reverse" type="boolean">
|
||||
Newest first (default is chronological: oldest at top).
|
||||
</ParamField>
|
||||
<ParamField path="--ids" type="boolean">
|
||||
Include message IDs in the transcript.
|
||||
</ParamField>
|
||||
<ParamField path="--peer" type="string">
|
||||
Filter by peer ID. Short alias: `-p`.
|
||||
</ParamField>
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## honcho workspace
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ When you pick up a workspace and need to orient — start broad, narrow to the p
|
|||
<Step title="Debug a session">
|
||||
```bash
|
||||
honcho session inspect <session_id> --json
|
||||
honcho message list <session_id> --last 20 --json
|
||||
honcho session view <session_id> --last 20
|
||||
honcho session context <session_id> --json
|
||||
honcho session summaries <session_id> --json
|
||||
```
|
||||
|
|
@ -150,7 +150,7 @@ When you pick up a workspace and need to orient — start broad, narrow to the p
|
|||
</Steps>
|
||||
|
||||
<Tip>
|
||||
`honcho session context` shows exactly what an agent would receive at inference time — check it before `honcho peer chat` if a response surprises you.
|
||||
`honcho session context` shows exactly what an agent would receive at inference time — check it before `honcho peer chat` if a response surprises you. `honcho session view` shows the raw transcript that context was built from; it prints content verbatim, so tag-delimited and multi-line messages appear exactly as stored.
|
||||
</Tip>
|
||||
|
||||
### A peer isn't learning
|
||||
|
|
@ -176,7 +176,7 @@ When an agent's responses don't reflect what you expect it to know.
|
|||
```bash
|
||||
honcho session context <session_id> --json
|
||||
honcho session summaries <session_id> --json
|
||||
honcho message list <session_id> --last 50 --json
|
||||
honcho session view <session_id> --last 50
|
||||
```
|
||||
|
||||
### Dialectic returns bad answers
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ def build() -> str:
|
|||
body: list[str] = []
|
||||
for name in sorted(root.commands):
|
||||
body.extend(_render_top(root.commands[name], ["honcho", name]))
|
||||
return HEADER + "\n".join(body) + "\n"
|
||||
return HEADER + "\n".join(body).rstrip("\n") + "\n"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
|
|
|
|||
|
|
@ -42,9 +42,8 @@ def list_messages(
|
|||
|
||||
try:
|
||||
filters = {"peer_id": config.peer_id} if config.peer_id else None
|
||||
# Fetch newest-first so we always get the most recent N messages — the
|
||||
# shared helper walks pages, so --last above one page isn't truncated —
|
||||
# then flip to oldest-at-top / newest-at-bottom for readable display.
|
||||
# Fetch newest-first so we always get the most recent N messages, then
|
||||
# flip to oldest-at-top / newest-at-bottom for readable display.
|
||||
# --reverse keeps the raw server order (oldest first, descending in table).
|
||||
msgs, _ = _fetch_recent_messages(sess, filters, last)
|
||||
if not reverse:
|
||||
|
|
|
|||
|
|
@ -136,8 +136,7 @@ def inspect(
|
|||
|
||||
|
||||
# Server-side ceiling on page size (fastapi-pagination's default ``Params``
|
||||
# declares ``size`` as ``Query(50, ge=1, le=100)``), enforced locally so an
|
||||
# out-of-range --size is a CLI error rather than an opaque 422.
|
||||
# declares ``size`` as ``Query(50, ge=1, le=100)``).
|
||||
MAX_PAGE_SIZE = 100
|
||||
DEFAULT_PAGE_SIZE = 50
|
||||
|
||||
|
|
@ -145,8 +144,7 @@ DEFAULT_PAGE_SIZE = 50
|
|||
def _fetch_recent_messages(sess, filters: dict | None, last: int) -> tuple[list, int | None]:
|
||||
"""Fetch the ``last`` most recent messages, newest first.
|
||||
|
||||
Walks as many newest-first server pages as it takes to fill the window, so
|
||||
``last`` above the page cap is honored instead of silently truncated.
|
||||
Walks as many newest-first server pages as it takes to fill the window.
|
||||
Returns the messages plus the session's total message count (if reported).
|
||||
"""
|
||||
page = sess.messages(
|
||||
|
|
@ -211,21 +209,20 @@ def view(
|
|||
|
||||
Modes (pick one):
|
||||
|
||||
- default / ``--last N`` — tail of the conversation (most recent N)
|
||||
- ``--page N [--size M]`` — page through the full transcript
|
||||
- ``--all`` — every message
|
||||
- default / --last N: tail of the conversation (most recent N)
|
||||
- --page N [--size M]: page through the full transcript
|
||||
- --all: every message
|
||||
|
||||
Paging follows the requested order: ``--page 1`` starts at the oldest
|
||||
message, or the newest with ``--reverse``.
|
||||
Paging follows the requested order: --page 1 starts at the oldest message,
|
||||
or the newest with --reverse.
|
||||
|
||||
Human mode prints a row-delimited table. JSON mode emits the message list
|
||||
(same shape as ``message list``).
|
||||
(same shape as message list).
|
||||
"""
|
||||
handle_cmd_flags(json_output=json_output, workspace=workspace, peer=peer, session=session)
|
||||
sid = _get_session_id(session_id)
|
||||
|
||||
# Validate every flag before touching the network, so a bad invocation never
|
||||
# reaches the API.
|
||||
# Validate every flag before touching the network.
|
||||
modes = sum([
|
||||
last is not None,
|
||||
page_number is not None,
|
||||
|
|
@ -256,14 +253,13 @@ def view(
|
|||
print_error("INVALID_FLAGS", "--last must be >= 1", {"last": last})
|
||||
raise typer.Exit(1)
|
||||
|
||||
# Default: tail of conversation (most recent 50), matching prior behavior.
|
||||
# Default: tail of conversation (most recent 50).
|
||||
mode = "page" if page_number is not None else ("all" if all_messages else "last")
|
||||
tail = last if last is not None else DEFAULT_PAGE_SIZE
|
||||
page_size = size if size is not None else DEFAULT_PAGE_SIZE
|
||||
|
||||
client, config = get_client()
|
||||
# Read-only: build the Session directly rather than via client.session(),
|
||||
# which is a get-or-create POST and would create a session on a typo.
|
||||
# Read-only: client.session() is a get-or-create POST, so build the Session directly.
|
||||
sess = Session(sid, client)
|
||||
|
||||
try:
|
||||
|
|
@ -272,8 +268,7 @@ def view(
|
|||
pages_meta: int | None = None
|
||||
|
||||
if mode == "page":
|
||||
# Page in the order the caller asked for, so --reverse --page 1 is
|
||||
# the newest page rather than the oldest one displayed backwards.
|
||||
# Page in the order the caller asked for.
|
||||
result_page = sess.messages(
|
||||
filters=filters,
|
||||
page=page_number,
|
||||
|
|
@ -309,8 +304,7 @@ def view(
|
|||
_handle_error(e, "session", sid)
|
||||
raise # unreachable: _handle_error always exits
|
||||
|
||||
# Rendered outside the try so an output-side failure (e.g. a broken pipe
|
||||
# from `| head`) isn't reported as a session API error.
|
||||
# Rendered outside the try: output failures aren't session API errors.
|
||||
print_transcript(
|
||||
items,
|
||||
session_id=sid,
|
||||
|
|
|
|||
|
|
@ -126,11 +126,8 @@ TIMESTAMP_WIDTH = len("2026-01-01T00:00:00.000Z")
|
|||
def _format_timestamp(value: Any) -> str:
|
||||
"""Compact UTC timestamp: ``YYYY-MM-DDTHH:MM:SS.mmmZ``.
|
||||
|
||||
Offsets are *converted* to UTC rather than dropped, so a non-UTC
|
||||
``created_at`` isn't relabelled as UTC. Naive values are assumed UTC, which
|
||||
is what the API returns. Millisecond precision is kept so messages within
|
||||
the same second stay distinguishable. Unparseable values pass through
|
||||
verbatim.
|
||||
Offsets are converted to UTC; naive values are assumed UTC. Unparseable
|
||||
values pass through verbatim.
|
||||
"""
|
||||
if value is None:
|
||||
return ""
|
||||
|
|
@ -161,8 +158,7 @@ def print_transcript(
|
|||
|
||||
Each message dict must have ``peer_id``, ``content``, ``created_at``;
|
||||
``id`` is optional and only shown when ``show_ids`` is set. ``size`` and
|
||||
``reverse`` are echoed back in the next-page hint so following it lands on
|
||||
the adjacent window rather than a differently-sized one.
|
||||
``reverse`` are echoed back in the next-page hint.
|
||||
"""
|
||||
if use_json():
|
||||
print_json(messages)
|
||||
|
|
@ -193,8 +189,8 @@ def print_transcript(
|
|||
expand=True,
|
||||
pad_edge=False,
|
||||
)
|
||||
# time is fixed-width ISO-UTC; ids and peers wrap rather than truncate so a
|
||||
# displayed ID is always a usable one; content takes the rest.
|
||||
# time is fixed-width ISO-UTC; ids and peers wrap rather than truncate;
|
||||
# content takes the rest.
|
||||
table.add_column("time", style="dim", no_wrap=True, width=TIMESTAMP_WIDTH)
|
||||
if show_ids:
|
||||
table.add_column("id", style="dim", no_wrap=True)
|
||||
|
|
@ -207,10 +203,7 @@ def print_transcript(
|
|||
if peer not in peer_color:
|
||||
peer_color[peer] = _PEER_COLORS[len(peer_color) % len(_PEER_COLORS)]
|
||||
|
||||
# Content and IDs go through Text, not Markdown or console markup: this is
|
||||
# a debugging view, so it must show exactly what was stored — Markdown
|
||||
# would reflow newlines and swallow the `<thinking>`-style tags that fill
|
||||
# agent transcripts, and markup would eat bracketed text.
|
||||
# Text, not Markdown or console markup: content renders verbatim.
|
||||
row: list[Any] = [_format_timestamp(msg.get("created_at"))]
|
||||
if show_ids:
|
||||
row.append(Text(str(msg.get("id") or "")))
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ class TestJsonContract:
|
|||
@pytest.mark.parametrize(
|
||||
"args",
|
||||
[
|
||||
["--size", "10"], # --size without --page would be silently ignored
|
||||
["--size", "10"], # --size requires --page
|
||||
["--page", "1", "--size", "500"], # over the server's 100 ceiling
|
||||
["--page", "0"],
|
||||
["--last", "0"],
|
||||
|
|
|
|||
Loading…
Reference in New Issue