v0.33.0 653c635

resident_handoff.go RawHistoryFolder

1package subagents
2
3import (
4	"encoding/json"
5	"fmt"
6	"strings"
7	"unicode/utf8"
8
9	"github.com/bnema/zut/packages/core"
10)
11
12const residentHandoffBytes = 16 << 10
13
14// residentBudgetHandoff is an evidence-only fallback, not a model-generated
15// claim of completion. The durable transcript retains full tool arguments and
16// results, including side effects that cannot be inferred from a patch.
17func residentBudgetHandoff(dir string, spec ResidentChildSpec) string {
18	var b strings.Builder
19	fmt.Fprintf(&b, "Partial result: budget exhausted; work is NOT complete.\nHistory: %s\nResult: %s\nWorkspace: %s\n", HistoryRef(spec.ID), ResultRef(spec.ID), spec.Workspace)
20	b.WriteString("Recovery: inspect the saved history and artifacts before repeating side effects, then use subagent_resume with the remaining task. Explicit resume grants a fresh allowance of the same size; required work remains unmet until success.\n")
21	b.WriteString("The following are bounded recent observations, not verified findings or an exhaustive list of side effects. Unfinished steps must be reconciled against the accepted task. Raw tool arguments and output are omitted because they may contain secrets; inspect them in the child history.\n")
22	items, err := ReadResidentHistory(dir, 16)
23	if err != nil {
24		b.WriteString("Recent history unavailable; inspect the durable child session before retrying.\n")
25		return b.String()
26	}
27	// Do not mix in earlier turns when the latest prompt is in this page.
28	for i := len(items) - 1; i >= 0; i-- {
29		if items[i].Type == residentRecordUser {
30			items = items[i:]
31			break
32		}
33	}
34	for _, item := range items {
35		switch item.Type {
36		case residentRecordUser, residentRecordAssistant:
37			message, err := core.DecodeMessageJSON(item.Message)
38			if err == nil {
39				fmt.Fprintf(&b, "%s: %s\n", item.Type, handoffExcerpt(residentAssistantSummary(message), 1024))
40			}
41		case residentRecordToolCall:
42			fmt.Fprintf(&b, "tool %s (%s): called; arguments retained in history\n", item.ToolName, item.ToolID)
43		case residentRecordToolResult:
44			var result struct {
45				IsError bool
46			}
47			if err := json.Unmarshal(item.ToolResult, &result); err == nil {
48				fmt.Fprintf(&b, "tool result (%s): is_error=%t; output retained in history\n", item.ToolID, result.IsError)
49			}
50		}
51		if b.Len() >= residentHandoffBytes {
52			break
53		}
54	}
55	return handoffExcerpt(b.String(), residentHandoffBytes)
56}
57
58func handoffExcerpt(text string, limit int) string {
59	if len(text) <= limit {
60		return text
61	}
62	end := limit - len("…")
63	for end > 0 && !utf8.RuneStart(text[end]) {
64		end--
65	}
66	return text[:end] + "…"
67}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 477

↑↓ moveenter openesc close