v0.3.96 c5883a4

types.go RawHistoryFolder

1package sdk
2
3import (
4	"encoding/json"
5
6	"github.com/patriceckhart/zot/packages/core"
7	"github.com/patriceckhart/zot/packages/provider"
8)
9
10// Event is the unit emitted by Runtime.Prompt's channel. Type
11// identifies the event kind; remaining fields are populated based on
12// kind. The wire schema is the same as the JSON-RPC stream notifications
13// emitted by `zot rpc`, so consumers can share parsing code.
14type Event struct {
15	Type string `json:"type"`
16
17	// Common fields.
18	Step int    `json:"step,omitempty"`
19	Time string `json:"time,omitempty"`
20
21	// text_delta
22	Delta string `json:"delta,omitempty"`
23
24	// tool_call
25	ID   string          `json:"id,omitempty"`
26	Name string          `json:"name,omitempty"`
27	Args json.RawMessage `json:"args,omitempty"`
28
29	// tool_progress
30	Text string `json:"text,omitempty"`
31
32	// tool_result
33	IsError bool           `json:"is_error,omitempty"`
34	Result  []ContentBlock `json:"content,omitempty"`
35
36	// usage
37	Usage      *Usage `json:"usage,omitempty"`
38	Cumulative *Usage `json:"cumulative,omitempty"`
39
40	// user_message / assistant_message
41	Message *Message `json:"message,omitempty"`
42
43	// turn_end
44	Stop string `json:"stop,omitempty"`
45
46	// error
47	Error string `json:"error,omitempty"`
48}
49
50// Message is one transcript entry — a user prompt, assistant reply,
51// or tool result.
52type Message struct {
53	Role    string         `json:"role"`
54	Content []ContentBlock `json:"content"`
55	Time    string         `json:"time,omitempty"`
56}
57
58// ContentBlock is one piece of message content. Discriminate on Type:
59//   - "text"        → Text
60//   - "image"       → MimeType + Data (or Bytes for size-only)
61//   - "tool_call"   → ID + Name + Args
62//   - "tool_result" → CallID + IsError + Content (recursive)
63type ContentBlock struct {
64	Type string `json:"type"`
65
66	Text     string          `json:"text,omitempty"`
67	MimeType string          `json:"mime_type,omitempty"`
68	Data     []byte          `json:"data,omitempty"`
69	Bytes    int             `json:"bytes,omitempty"`
70	ID       string          `json:"id,omitempty"`
71	Name     string          `json:"name,omitempty"`
72	Args     json.RawMessage `json:"args,omitempty"`
73	CallID   string          `json:"call_id,omitempty"`
74	IsError  bool            `json:"is_error,omitempty"`
75	Content  []ContentBlock  `json:"content,omitempty"`
76}
77
78// Image is a single user-attached image for Prompt.
79type Image struct {
80	MimeType string
81	Data     []byte
82}
83
84// Usage is per-turn or cumulative token / cost counts.
85type Usage struct {
86	Input      int     `json:"input"`
87	Output     int     `json:"output"`
88	Reasoning  *int    `json:"reasoning"`
89	CacheRead  int     `json:"cache_read"`
90	CacheWrite int     `json:"cache_write"`
91	CostUSD    float64 `json:"cost_usd"`
92}
93
94// State is a snapshot of the runtime's current state.
95type State struct {
96	Provider     string `json:"provider"`
97	Model        string `json:"model"`
98	Reasoning    string `json:"reasoning"`
99	CWD          string `json:"cwd"`
100	Busy         bool   `json:"busy"`
101	MessageCount int    `json:"message_count"`
102}
103
104// CompactResult describes the outcome of Compact.
105type CompactResult struct {
106	Summary  string    `json:"summary"`
107	Messages []Message `json:"messages"`
108}
109
110// ModelInfo describes one model known to the runtime.
111type ModelInfo struct {
112	ID            string `json:"id"`
113	Provider      string `json:"provider"`
114	ContextWindow int    `json:"context_window"`
115	MaxOutput     int    `json:"max_output"`
116	Reasoning     bool   `json:"reasoning"`
117}
118
119// ---- internal converters ----
120
121func sdkReasoningTokens(usage provider.Usage) *int {
122	if !usage.ReasoningTokensKnown {
123		return nil
124	}
125	count := usage.ReasoningTokens
126	return &count
127}
128
129func toEvent(ev core.AgentEvent) Event {
130	out := Event{Type: ev.Type()}
131	switch e := ev.(type) {
132	case core.EvTurnStart:
133		out.Step = e.Step
134	case core.EvUserMessage:
135		out.Message = &Message{Role: string(e.Message.Role), Content: convertContent(e.Message.Content)}
136	case core.EvAssistantMessage:
137		out.Message = &Message{Role: string(e.Message.Role), Content: convertContent(e.Message.Content)}
138	case core.EvTextDelta:
139		out.Delta = e.Delta
140	case core.EvToolCall:
141		out.ID = e.ID
142		out.Name = e.Name
143		out.Args = e.Args
144	case core.EvToolProgress:
145		out.ID = e.ID
146		out.Text = e.Text
147	case core.EvToolResult:
148		out.ID = e.ID
149		out.IsError = e.Result.IsError
150		out.Result = convertContent(e.Result.Content)
151	case core.EvUsage:
152		out.Usage = &Usage{
153			Input:      e.Usage.InputTokens,
154			Output:     e.Usage.OutputTokens,
155			Reasoning:  sdkReasoningTokens(e.Usage),
156			CacheRead:  e.Usage.CacheReadTokens,
157			CacheWrite: e.Usage.CacheWriteTokens,
158			CostUSD:    e.Usage.CostUSD,
159		}
160		out.Cumulative = &Usage{
161			Input:      e.Cumulative.InputTokens,
162			Output:     e.Cumulative.OutputTokens,
163			Reasoning:  sdkReasoningTokens(e.Cumulative),
164			CacheRead:  e.Cumulative.CacheReadTokens,
165			CacheWrite: e.Cumulative.CacheWriteTokens,
166			CostUSD:    e.Cumulative.CostUSD,
167		}
168	case core.EvTurnEnd:
169		out.Stop = string(e.Stop)
170		if e.Err != nil {
171			out.Error = e.Err.Error()
172		}
173	case core.EvError:
174		if e.Err != nil {
175			out.Error = e.Err.Error()
176		}
177	}
178	return out
179}
180
181func convertContent(blocks []provider.Content) []ContentBlock {
182	out := make([]ContentBlock, 0, len(blocks))
183	for _, b := range blocks {
184		switch v := b.(type) {
185		case provider.TextBlock:
186			out = append(out, ContentBlock{Type: "text", Text: v.Text})
187		case provider.ImageBlock:
188			out = append(out, ContentBlock{Type: "image", MimeType: v.MimeType, Bytes: len(v.Data)})
189		case provider.ToolCallBlock:
190			out = append(out, ContentBlock{Type: "tool_call", ID: v.ID, Name: v.Name, Args: v.Arguments})
191		case provider.ToolResultBlock:
192			out = append(out, ContentBlock{
193				Type:    "tool_result",
194				CallID:  v.CallID,
195				IsError: v.IsError,
196				Content: convertContent(v.Content),
197			})
198		}
199	}
200	return out
201}
202
203func rebuildContent(blocks []ContentBlock) []provider.Content {
204	out := make([]provider.Content, 0, len(blocks))
205	for _, b := range blocks {
206		switch b.Type {
207		case "text":
208			out = append(out, provider.TextBlock{Text: b.Text})
209		case "image":
210			out = append(out, provider.ImageBlock{MimeType: b.MimeType, Data: b.Data})
211		case "tool_call":
212			args := b.Args
213			if len(args) == 0 {
214				args = json.RawMessage("{}")
215			}
216			out = append(out, provider.ToolCallBlock{ID: b.ID, Name: b.Name, Arguments: args})
217		case "tool_result":
218			out = append(out, provider.ToolResultBlock{
219				CallID:  b.CallID,
220				IsError: b.IsError,
221				Content: rebuildContent(b.Content),
222			})
223		}
224	}
225	return out
226}

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