Documentation
¶
Overview ¶
Package eventpipe implements a Reasonix-inspired event-sourcing pipeline: discriminated-union typed events → pure-function reducer projections → composable sink middleware chain → JSONL event log.
It lives alongside the old event.Event struct in internal/event; consumers can migrate event by event.
Index ¶
- func ByType(types ...string) func(Event) bool
- func MarshalEvent(ev Event) ([]byte, error)
- func SkipType(types ...string) func(Event) bool
- type ApprovalRequestEvent
- type AskOption
- type AskQuestion
- type AskRequestEvent
- type BudgetBlockedEvent
- type BudgetView
- type BudgetWarningEvent
- type ChatMsg
- type ConversationView
- type ErrorEvent
- type Event
- type Eventizer
- type EventizerSink
- type FileChange
- type FrontendBridge
- type FuncSink
- type LegacySink
- type LogConfig
- type LogSink
- type Meta
- type ModelDeltaEvent
- type ModelFinalEvent
- type ModelTurnStartedEvent
- type NoticeEvent
- type NoticeLevel
- type PendingTool
- type PhaseEvent
- type PlanStep
- type PlanStepChangedEvent
- type PlanStepView
- type PlanSubmittedEvent
- type PlanView
- type ProjectionSet
- type Reducer
- type SessionCompactedEvent
- type SessionOpenedEvent
- type Sink
- func FanOut(sinks ...Sink) Sink
- func FanOutByType(routes map[string]Sink, fallback Sink) Sink
- func Filter(next Sink, fn func(Event) bool) Sink
- func Map(next Sink, fn func(Event) Event) Sink
- func NewFrontendBridge(old event.Sink) Sink
- func Pipe(sinks ...Sink) Sink
- func Tap(next Sink, fn func(Event)) Sink
- type StatusEvent
- type ToolDeniedEvent
- type ToolIntentEvent
- type ToolPreparingEvent
- type ToolResultEvent
- type TurnAbortedEvent
- type TurnDoneEvent
- type Usage
- type UserMessageEvent
- type WireApproval
- type WireAsk
- type WireEvent
- type WireOption
- type WireQuestion
- type WireTool
- type WireUsage
- type WorkspaceView
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ByType ¶
ByType returns a predicate that matches the given type strings. Usage: Filter(sink, ByType("model.delta", "model.final"))
func MarshalEvent ¶
MarshalEvent serializes any Event to JSON. The top-level {"type","meta","body"} envelope makes it self-describing for log/replay.
Types ¶
type ApprovalRequestEvent ¶
type ApprovalRequestEvent struct {
AskID string `json:"askId"`
Tool string `json:"tool"`
Subject string `json:"subject"`
// contains filtered or unexported fields
}
func NewApprovalRequestEvent ¶
func NewApprovalRequestEvent(turn int, id int, askID, tool, subject string) ApprovalRequestEvent
func (ApprovalRequestEvent) Meta ¶
func (e ApprovalRequestEvent) Meta() Meta
func (ApprovalRequestEvent) Type ¶
func (e ApprovalRequestEvent) Type() string
type AskQuestion ¶
type AskRequestEvent ¶
type AskRequestEvent struct {
AskID string `json:"askId"`
Questions []AskQuestion `json:"questions"`
// contains filtered or unexported fields
}
func NewAskRequestEvent ¶
func NewAskRequestEvent(turn int, id int, askID string, questions []AskQuestion) AskRequestEvent
func (AskRequestEvent) Meta ¶
func (e AskRequestEvent) Meta() Meta
func (AskRequestEvent) Type ¶
func (e AskRequestEvent) Type() string
type BudgetBlockedEvent ¶
type BudgetBlockedEvent struct {
SpentUSD float64 `json:"spentUsd"`
CapUSD float64 `json:"capUsd"`
// contains filtered or unexported fields
}
func NewBudgetBlockedEvent ¶
func NewBudgetBlockedEvent(turn int, id int, spent, cap float64) BudgetBlockedEvent
func (BudgetBlockedEvent) Meta ¶
func (e BudgetBlockedEvent) Meta() Meta
func (BudgetBlockedEvent) Type ¶
func (e BudgetBlockedEvent) Type() string
type BudgetView ¶
type BudgetView struct {
SpentUSD float64 `json:"spentUsd"`
CapUSD float64 `json:"capUsd,omitempty"`
PromptTokens int `json:"promptTokens"`
CompletionTokens int `json:"completionTokens"`
CacheHitTokens int `json:"cacheHitTokens"`
CacheMissTokens int `json:"cacheMissTokens"`
Warned bool `json:"warned"`
Blocked bool `json:"blocked"`
}
func EmptyBudget ¶
func EmptyBudget(capUSD float64) BudgetView
type BudgetWarningEvent ¶
type BudgetWarningEvent struct {
SpentUSD float64 `json:"spentUsd"`
CapUSD float64 `json:"capUsd"`
// contains filtered or unexported fields
}
func NewBudgetWarningEvent ¶
func NewBudgetWarningEvent(turn int, id int, spent, cap float64) BudgetWarningEvent
func (BudgetWarningEvent) Meta ¶
func (e BudgetWarningEvent) Meta() Meta
func (BudgetWarningEvent) Type ¶
func (e BudgetWarningEvent) Type() string
type ChatMsg ¶
type ChatMsg struct {
Role string `json:"role"` // "user" | "assistant" | "tool"
Content string `json:"content"`
}
ChatMsg is a simplified representation for the conversation transcript.
type ConversationView ¶
type ConversationView struct {
Messages []ChatMsg `json:"messages"`
PendingToolCalls []PendingTool `json:"pendingToolCalls"`
}
func EmptyConversation ¶
func EmptyConversation() ConversationView
type ErrorEvent ¶
type ErrorEvent struct {
Message string `json:"message"`
Recoverable bool `json:"recoverable"`
Name string `json:"name,omitempty"`
Code string `json:"code,omitempty"`
Phase string `json:"phase,omitempty"`
// contains filtered or unexported fields
}
func NewErrorEvent ¶
func NewErrorEvent(turn int, id int, msg string, recoverable bool) ErrorEvent
func (ErrorEvent) Meta ¶
func (e ErrorEvent) Meta() Meta
func (ErrorEvent) Type ¶
func (e ErrorEvent) Type() string
type Event ¶
type Event interface {
Meta() Meta
Type() string // machine-readable type tag, e.g. "user.message"
// contains filtered or unexported methods
}
Event is the marker interface. Only implementations in this package satisfy it. Consumers type-switch on the concrete type to access typed fields.
type Eventizer ¶
type Eventizer struct {
// contains filtered or unexported fields
}
Eventizer adapts the old event.Sink contract to the typed eventpipe.Sink. It implements event.Sink, converts each old-style Event to its typed counterpart, and forwards it to the typed pipeline.
Usage:
pipe := FanOut(logSink, uiSink)
ez := eventpipe.NewEventizer(pipe)
ctrl := control.New(control.Options{Sink: ez, ...})
The agent emits old-style events; the Eventizer translates them to typed events and feeds the pipeline. Zero agent code changes.
func NewEventizer ¶
NewEventizer wraps a typed pipeline sink with the old-style adapter.
type EventizerSink ¶
type EventizerSink struct {
*Eventizer
}
EventizerSink is a drop-in event.Sink that translates to typed events.
func NewEventizerSink ¶
func NewEventizerSink(pipeline Sink) *EventizerSink
NewEventizerSink creates a sink that accepts old events and forwards typed events to the pipeline. Useful as a drop-in for control.New().
type FileChange ¶
type FrontendBridge ¶
type FrontendBridge struct {
// contains filtered or unexported fields
}
FrontendBridge implements eventpipe.Sink by converting typed events back to the old event.Event format and forwarding to an old-style event.Sink. This lets frontends consume typed events through the pipeline without changing their existing ingest/emit code.
Session-cumulative cache tokens (SessionHit/SessionMiss) are tracked automatically across ModelFinalEvent emissions so the old-style event carries both per-turn and cumulative values.
func (*FrontendBridge) Emit ¶
func (b *FrontendBridge) Emit(ev Event)
Emit converts a typed event to old format and forwards it.
type LegacySink ¶
type LegacySink struct {
// contains filtered or unexported fields
}
LegacySink adapts an eventpipe.Sink to the old event.Sink interface.
func NewLegacySink ¶
func NewLegacySink(pipeline Sink) *LegacySink
func (*LegacySink) Emit ¶
func (s *LegacySink) Emit(ev *event.Event)
type LogConfig ¶
type LogConfig struct {
Dir string // directory to write event log files
SessionID string // session identifier for the filename
}
LogConfig controls event log behaviour.
type LogSink ¶
type LogSink struct {
// contains filtered or unexported fields
}
LogSink writes every event to a JSONL file for replay and auditing. Each line is a self-describing {"type":"...","meta":{...},"body":{...}} JSON object.
func NewLogSink ¶
NewLogSink opens (or creates) a JSONL event log file at dir/sessionID.events.jsonl.
func (*LogSink) Close ¶
Close flushes and closes the log file. Reports the first prior write error, if any.
func (*LogSink) Emit ¶
Emit appends one event to the log file. After the first write error, subsequent events are silently dropped; the error is surfaced via Flush() and Close().
type ModelDeltaEvent ¶
type ModelDeltaEvent struct {
Channel string `json:"channel"` // "content" | "reasoning" | "tool_args"
Text string `json:"text"`
// contains filtered or unexported fields
}
func NewModelDeltaEvent ¶
func NewModelDeltaEvent(turn int, id int, channel, text string) ModelDeltaEvent
func (ModelDeltaEvent) Meta ¶
func (e ModelDeltaEvent) Meta() Meta
func (ModelDeltaEvent) Type ¶
func (e ModelDeltaEvent) Type() string
type ModelFinalEvent ¶
type ModelFinalEvent struct {
Content string `json:"content"`
ReasoningContent string `json:"reasoningContent,omitempty"`
Usage Usage `json:"usage,omitempty"`
CostUSD float64 `json:"costUsd"`
ForcedSummary bool `json:"forcedSummary,omitempty"`
// contains filtered or unexported fields
}
func NewModelFinalEvent ¶
func (ModelFinalEvent) Meta ¶
func (e ModelFinalEvent) Meta() Meta
func (ModelFinalEvent) Type ¶
func (e ModelFinalEvent) Type() string
type ModelTurnStartedEvent ¶
type ModelTurnStartedEvent struct {
Model string `json:"model"`
ReasoningEffort string `json:"reasoningEffort"`
PrefixHash string `json:"prefixHash"`
// contains filtered or unexported fields
}
func NewModelTurnStartedEvent ¶
func NewModelTurnStartedEvent(turn int, id int, model, effort, prefixHash string) ModelTurnStartedEvent
func (ModelTurnStartedEvent) Meta ¶
func (e ModelTurnStartedEvent) Meta() Meta
func (ModelTurnStartedEvent) Type ¶
func (e ModelTurnStartedEvent) Type() string
type NoticeEvent ¶
type NoticeEvent struct {
Text string `json:"text"`
Level NoticeLevel `json:"level"`
// contains filtered or unexported fields
}
func NewNoticeEvent ¶
func NewNoticeEvent(turn int, id int, text string, level NoticeLevel) NoticeEvent
func (NoticeEvent) Meta ¶
func (e NoticeEvent) Meta() Meta
func (NoticeEvent) Type ¶
func (e NoticeEvent) Type() string
type NoticeLevel ¶
type NoticeLevel int
const ( NoticeLevelInfo NoticeLevel = iota NoticeLevelWarn )
type PendingTool ¶
type PhaseEvent ¶
type PhaseEvent struct {
Text string `json:"text"`
// contains filtered or unexported fields
}
func NewPhaseEvent ¶
func NewPhaseEvent(turn int, id int, text string) PhaseEvent
func (PhaseEvent) Meta ¶
func (e PhaseEvent) Meta() Meta
func (PhaseEvent) Type ¶
func (e PhaseEvent) Type() string
type PlanStepChangedEvent ¶
type PlanStepChangedEvent struct {
StepID string `json:"stepId"`
Title string `json:"title,omitempty"`
Notes string `json:"notes,omitempty"`
Status string `json:"status"`
// contains filtered or unexported fields
}
func NewPlanStepChangedEvent ¶
func NewPlanStepChangedEvent(turn int, id int, stepID, title, notes, status string) PlanStepChangedEvent
func (PlanStepChangedEvent) Meta ¶
func (e PlanStepChangedEvent) Meta() Meta
func (PlanStepChangedEvent) Type ¶
func (e PlanStepChangedEvent) Type() string
type PlanStepView ¶
type PlanSubmittedEvent ¶
type PlanSubmittedEvent struct {
Steps []PlanStep `json:"steps"`
Body string `json:"body"`
// contains filtered or unexported fields
}
func NewPlanSubmittedEvent ¶
func NewPlanSubmittedEvent(turn int, id int, steps []PlanStep, body string) PlanSubmittedEvent
func (PlanSubmittedEvent) Meta ¶
func (e PlanSubmittedEvent) Meta() Meta
func (PlanSubmittedEvent) Type ¶
func (e PlanSubmittedEvent) Type() string
type PlanView ¶
type PlanView struct {
Steps []PlanStepView `json:"steps"`
Body string `json:"body,omitempty"`
SubmittedTurn int `json:"submittedTurn,omitempty"`
}
type ProjectionSet ¶
type ProjectionSet struct {
Conversation ConversationView `json:"conversation"`
Budget BudgetView `json:"budget"`
Plan PlanView `json:"plan"`
Workspace WorkspaceView `json:"workspace"`
}
func Apply ¶
func Apply(state ProjectionSet, ev Event) ProjectionSet
Apply folds one event into all projections.
func EmptyProjections ¶
func EmptyProjections(capUSD float64) ProjectionSet
func Replay ¶
func Replay(events []Event, capUSD float64) ProjectionSet
Replay folds an event sequence into a projection set.
type Reducer ¶
Reducer is a pure function that folds an Event into a view. Deterministic, no I/O, no mutation. Given the same (view, event) pair it always returns the same result.
var BudgetReducer Reducer[BudgetView] = func(v BudgetView, ev Event) BudgetView { switch e := ev.(type) { case ModelFinalEvent: v.SpentUSD += e.CostUSD v.PromptTokens += e.Usage.PromptTokens v.CompletionTokens += e.Usage.CompletionTokens v.CacheHitTokens += e.Usage.CacheHitTokens v.CacheMissTokens += e.Usage.CacheMissTokens return v case BudgetWarningEvent: v.Warned = true v.SpentUSD = e.SpentUSD return v case BudgetBlockedEvent: v.Blocked = true v.SpentUSD = e.SpentUSD return v default: return v } }
var ConversationReducer Reducer[ConversationView] = func(v ConversationView, ev Event) ConversationView { switch e := ev.(type) { case UserMessageEvent: return pushMsg(v, ChatMsg{Role: "user", Content: e.Text}) case ModelFinalEvent: return pushMsg(v, ChatMsg{Role: "assistant", Content: e.Content}) case ToolIntentEvent: return ConversationView{ Messages: v.Messages, PendingToolCalls: append(v.PendingToolCalls, PendingTool{CallID: e.CallID, Name: e.Name}), } case ToolResultEvent: return ConversationView{ Messages: append(v.Messages, ChatMsg{Role: "tool", Content: e.Output}), PendingToolCalls: removePending(v.PendingToolCalls, e.CallID), } case ToolDeniedEvent: return ConversationView{ Messages: append(v.Messages, ChatMsg{Role: "tool", Content: "denied: " + e.Reason}), PendingToolCalls: removePending(v.PendingToolCalls, e.CallID), } default: return v } }
var PlanReducer Reducer[PlanView] = func(v PlanView, ev Event) PlanView { switch e := ev.(type) { case PlanSubmittedEvent: steps := make([]PlanStepView, len(e.Steps)) for i, s := range e.Steps { steps[i] = PlanStepView{ ID: s.ID, Title: s.Title, Action: s.Action, Risk: s.Risk, Completed: false, } } return PlanView{Steps: steps, Body: e.Body, SubmittedTurn: e.meta.Turn} case PlanStepChangedEvent: for i := range v.Steps { if v.Steps[i].ID == e.StepID { v.Steps[i].Completed = e.Status == "completed" v.Steps[i].Notes = e.Notes break } } return v default: return v } }
var WorkspaceReducer Reducer[WorkspaceView] = func(v WorkspaceView, ev Event) WorkspaceView {
_ = ev
return v
}
WorkspaceReducer reduces file-touch and checkpoint events. Currently a placeholder — wire up actual FileTouchedEvent / CheckpointEvent when those typed events are added.
type SessionCompactedEvent ¶
type SessionCompactedEvent struct {
BeforeMessages int `json:"beforeMessages"`
AfterMessages int `json:"afterMessages"`
Reason string `json:"reason"`
// contains filtered or unexported fields
}
func NewSessionCompactedEvent ¶
func NewSessionCompactedEvent(turn int, id int, before, after int, reason string) SessionCompactedEvent
func (SessionCompactedEvent) Meta ¶
func (e SessionCompactedEvent) Meta() Meta
func (SessionCompactedEvent) Type ¶
func (e SessionCompactedEvent) Type() string
type SessionOpenedEvent ¶
type SessionOpenedEvent struct {
Name string `json:"name"`
ResumedFromTurn int `json:"resumedFromTurn"`
// contains filtered or unexported fields
}
func NewSessionOpenedEvent ¶
func NewSessionOpenedEvent(turn int, id int, name string, resumedFromTurn int) SessionOpenedEvent
func (SessionOpenedEvent) Meta ¶
func (e SessionOpenedEvent) Meta() Meta
func (SessionOpenedEvent) Type ¶
func (e SessionOpenedEvent) Type() string
type Sink ¶
type Sink interface {
Emit(Event)
}
Sink consumes a typed event stream. Sinks are composable via wrappers (Filter, Map, FanOut, etc.) forming a middleware chain.
func FanOut ¶
FanOut broadcasts each event to all sinks. If a sink is nil it's skipped. All sinks see the same event; there is no transformation.
func FanOutByType ¶
FanOutByType creates a router that sends each event to the matching sink based on its Type(). Events whose type doesn't match any key go to fallback (which may be nil to drop unmatched).
func Map ¶
Map transforms each event before passing it to the next sink. Returning nil drops the event.
func NewFrontendBridge ¶
NewFrontendBridge wraps an old event.Sink so it can be used in the typed pipeline. The old sink receives converted old-style events.
type StatusEvent ¶
type StatusEvent struct {
Text string `json:"text"`
// contains filtered or unexported fields
}
func NewStatusEvent ¶
func NewStatusEvent(turn int, id int, text string) StatusEvent
func (StatusEvent) Meta ¶
func (e StatusEvent) Meta() Meta
func (StatusEvent) Type ¶
func (e StatusEvent) Type() string
type ToolDeniedEvent ¶
type ToolDeniedEvent struct {
CallID string `json:"callId"`
Name string `json:"name"`
Reason string `json:"reason"`
// contains filtered or unexported fields
}
func NewToolDeniedEvent ¶
func NewToolDeniedEvent(turn int, id int, callID, name, reason string) ToolDeniedEvent
func (ToolDeniedEvent) Meta ¶
func (e ToolDeniedEvent) Meta() Meta
func (ToolDeniedEvent) Type ¶
func (e ToolDeniedEvent) Type() string
type ToolIntentEvent ¶
type ToolIntentEvent struct {
CallID string `json:"callId"`
Name string `json:"name"`
Args string `json:"args"`
ReadOnly bool `json:"readOnly,omitempty"`
ParentID string `json:"parentId,omitempty"`
// contains filtered or unexported fields
}
func NewToolIntentEvent ¶
func (ToolIntentEvent) Meta ¶
func (e ToolIntentEvent) Meta() Meta
func (ToolIntentEvent) Type ¶
func (e ToolIntentEvent) Type() string
type ToolPreparingEvent ¶
type ToolPreparingEvent struct {
CallID string `json:"callId"`
Name string `json:"name"`
// contains filtered or unexported fields
}
func NewToolPreparingEvent ¶
func NewToolPreparingEvent(turn int, id int, callID, name string) ToolPreparingEvent
func (ToolPreparingEvent) Meta ¶
func (e ToolPreparingEvent) Meta() Meta
func (ToolPreparingEvent) Type ¶
func (e ToolPreparingEvent) Type() string
type ToolResultEvent ¶
type ToolResultEvent struct {
CallID string `json:"callId"`
Name string `json:"name"`
OK bool `json:"ok"`
Output string `json:"output,omitempty"`
Err string `json:"err,omitempty"`
Truncated bool `json:"truncated,omitempty"`
DurationMs int64 `json:"durationMs,omitempty"`
// contains filtered or unexported fields
}
func NewToolResultEvent ¶
func (ToolResultEvent) Meta ¶
func (e ToolResultEvent) Meta() Meta
func (ToolResultEvent) Type ¶
func (e ToolResultEvent) Type() string
type TurnAbortedEvent ¶
type TurnAbortedEvent struct {
Err error `json:"-"`
Covenant string `json:"covenant"`
Reason string `json:"reason"`
// contains filtered or unexported fields
}
func NewTurnAbortedEvent ¶
func NewTurnAbortedEvent(turn int, id int, err error, covenantID, reason string) TurnAbortedEvent
func (TurnAbortedEvent) Meta ¶
func (e TurnAbortedEvent) Meta() Meta
func (TurnAbortedEvent) Type ¶
func (e TurnAbortedEvent) Type() string
type TurnDoneEvent ¶
type TurnDoneEvent struct {
Err error `json:"-"`
Text string `json:"text,omitempty"`
// contains filtered or unexported fields
}
func NewTurnDoneEvent ¶
func NewTurnDoneEvent(turn int, id int, err error) TurnDoneEvent
func (TurnDoneEvent) Meta ¶
func (e TurnDoneEvent) Meta() Meta
func (TurnDoneEvent) Type ¶
func (e TurnDoneEvent) Type() string
type Usage ¶
type Usage struct {
PromptTokens int `json:"prompt_tokens,omitempty"`
CompletionTokens int `json:"completion_tokens,omitempty"`
TotalTokens int `json:"total_tokens,omitempty"`
CacheHitTokens int `json:"prompt_cache_hit_tokens,omitempty"`
CacheMissTokens int `json:"prompt_cache_miss_tokens,omitempty"`
}
type UserMessageEvent ¶
type UserMessageEvent struct {
Text string `json:"text"`
// contains filtered or unexported fields
}
func NewUserMessageEvent ¶
func NewUserMessageEvent(turn int, id int, text string) UserMessageEvent
func (UserMessageEvent) Meta ¶
func (e UserMessageEvent) Meta() Meta
func (UserMessageEvent) Type ¶
func (e UserMessageEvent) Type() string
type WireApproval ¶
type WireAsk ¶
type WireAsk struct {
ID string `json:"id"`
Questions []WireQuestion `json:"questions"`
}
type WireEvent ¶
type WireEvent struct {
Kind string `json:"kind"`
Text string `json:"text,omitempty"`
Reasoning string `json:"reasoning,omitempty"`
Level string `json:"level,omitempty"`
Tool *WireTool `json:"tool,omitempty"`
Usage *WireUsage `json:"usage,omitempty"`
Approval *WireApproval `json:"approval,omitempty"`
Ask *WireAsk `json:"ask,omitempty"`
Err string `json:"err,omitempty"`
}
WireEvent is the JSON wire format shared by HTTP/SSE and desktop frontends. It mirrors the old toWire contract field-for-field so both transports emit the identical typed stream and a single JS/TS type definition (wireEvent) serves both.
This replaces the previously duplicated toWire in internal/serve/wire.go and desktop/wire.go.
type WireOption ¶
type WireQuestion ¶
type WireQuestion struct {
ID string `json:"id"`
Header string `json:"header,omitempty"`
Prompt string `json:"prompt"`
Options []WireOption `json:"options"`
Multi bool `json:"multi,omitempty"`
}
type WireTool ¶
type WireTool struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Args string `json:"args,omitempty"`
Output string `json:"output,omitempty"`
Err string `json:"err,omitempty"`
ReadOnly bool `json:"readOnly"`
Truncated bool `json:"truncated,omitempty"`
Partial bool `json:"partial,omitempty"`
ParentID string `json:"parentId,omitempty"`
}
type WireUsage ¶
type WireUsage struct {
PromptTokens int `json:"promptTokens"`
CompletionTokens int `json:"completionTokens"`
TotalTokens int `json:"totalTokens"`
CacheHitTokens int `json:"cacheHitTokens"`
CacheMissTokens int `json:"cacheMissTokens"`
ReasoningTokens int `json:"reasoningTokens,omitempty"`
SessionCacheHitTokens int `json:"sessionCacheHitTokens"`
SessionCacheMissTokens int `json:"sessionCacheMissTokens"`
CostUSD float64 `json:"costUsd,omitempty"`
}
type WorkspaceView ¶
type WorkspaceView struct {
FilesTouched []FileChange `json:"filesTouched"`
LastCheckpoint string `json:"lastCheckpoint,omitempty"`
}
func EmptyWorkspace ¶
func EmptyWorkspace() WorkspaceView