v0.2.83 f2588cf

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	CacheRead  int     `json:"cache_read"`
89	CacheWrite int     `json:"cache_write"`
90	CostUSD    float64 `json:"cost_usd"`
91}
92
93// State is a snapshot of the runtime's current state.
94type State struct {
95	Provider     string `json:"provider"`
96	Model        string `json:"model"`
97	Reasoning    string `json:"reasoning"`
98	CWD          string `json:"cwd"`
99	Busy         bool   `json:"busy"`
100	MessageCount int    `json:"message_count"`
101}
102
103// CompactResult describes the outcome of Compact.
104type CompactResult struct {
105	Summary  string    `json:"summary"`
106	Messages []Message `json:"messages"`
107}
108
109// ModelInfo describes one model known to the runtime.
110type ModelInfo struct {
111	ID            string `json:"id"`
112	Provider      string `json:"provider"`
113	ContextWindow int    `json:"context_window"`
114	MaxOutput     int    `json:"max_output"`
115	Reasoning     bool   `json:"reasoning"`
116}
117
118// ---- internal converters ----
119
120func toEvent(ev core.AgentEvent) Event {
121	out := Event{Type: ev.Type()}
122	switch e := ev.(type) {
123	case core.EvTurnStart:
124		out.Step = e.Step
125	case core.EvUserMessage:
126		out.Message = &Message{Role: string(e.Message.Role), Content: convertContent(e.Message.Content)}
127	case core.EvAssistantMessage:
128		out.Message = &Message{Role: string(e.Message.Role), Content: convertContent(e.Message.Content)}
129	case core.EvTextDelta:
130		out.Delta = e.Delta
131	case core.EvToolCall:
132		out.ID = e.ID
133		out.Name = e.Name
134		out.Args = e.Args
135	case core.EvToolProgress:
136		out.ID = e.ID
137		out.Text = e.Text
138	case core.EvToolResult:
139		out.ID = e.ID
140		out.IsError = e.Result.IsError
141		out.Result = convertContent(e.Result.Content)
142	case core.EvUsage:
143		out.Usage = &Usage{
144			Input:      e.Usage.InputTokens,
145			Output:     e.Usage.OutputTokens,
146			CacheRead:  e.Usage.CacheReadTokens,
147			CacheWrite: e.Usage.CacheWriteTokens,
148			CostUSD:    e.Usage.CostUSD,
149		}
150		out.Cumulative = &Usage{
151			Input:      e.Cumulative.InputTokens,
152			Output:     e.Cumulative.OutputTokens,
153			CacheRead:  e.Cumulative.CacheReadTokens,
154			CacheWrite: e.Cumulative.CacheWriteTokens,
155			CostUSD:    e.Cumulative.CostUSD,
156		}
157	case core.EvTurnEnd:
158		out.Stop = string(e.Stop)
159		if e.Err != nil {
160			out.Error = e.Err.Error()
161		}
162	case core.EvError:
163		if e.Err != nil {
164			out.Error = e.Err.Error()
165		}
166	}
167	return out
168}
169
170func convertContent(blocks []provider.Content) []ContentBlock {
171	out := make([]ContentBlock, 0, len(blocks))
172	for _, b := range blocks {
173		switch v := b.(type) {
174		case provider.TextBlock:
175			out = append(out, ContentBlock{Type: "text", Text: v.Text})
176		case provider.ImageBlock:
177			out = append(out, ContentBlock{Type: "image", MimeType: v.MimeType, Bytes: len(v.Data)})
178		case provider.ToolCallBlock:
179			out = append(out, ContentBlock{Type: "tool_call", ID: v.ID, Name: v.Name, Args: v.Arguments})
180		case provider.ToolResultBlock:
181			out = append(out, ContentBlock{
182				Type:    "tool_result",
183				CallID:  v.CallID,
184				IsError: v.IsError,
185				Content: convertContent(v.Content),
186			})
187		}
188	}
189	return out
190}
191
192func rebuildContent(blocks []ContentBlock) []provider.Content {
193	out := make([]provider.Content, 0, len(blocks))
194	for _, b := range blocks {
195		switch b.Type {
196		case "text":
197			out = append(out, provider.TextBlock{Text: b.Text})
198		case "image":
199			out = append(out, provider.ImageBlock{MimeType: b.MimeType, Data: b.Data})
200		case "tool_call":
201			args := b.Args
202			if len(args) == 0 {
203				args = json.RawMessage("{}")
204			}
205			out = append(out, provider.ToolCallBlock{ID: b.ID, Name: b.Name, Arguments: args})
206		case "tool_result":
207			out = append(out, provider.ToolResultBlock{
208				CallID:  b.CallID,
209				IsError: b.IsError,
210				Content: rebuildContent(b.Content),
211			})
212		}
213	}
214	return out
215}

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 476

↑↓ moveenter openesc close