Documentation
¶
Index ¶
- Constants
- Variables
- func BuildStepInstruction(step Step, source Source, pc *StepPromptCtx) string
- func ChatTurnCountLabel(n int) string
- func DefToConfigDef(d Def) config.WorkflowDef
- func EndTurnInstructionBlock(loop *LoopPromptCtx) string
- func ExportBytes(d Def) ([]byte, error)
- func ExportFile(d Def) (string, error)
- func FileName(name string) string
- func GlobalDir() string
- func LoopNoteLine(loopName, action, detail string) string
- func MutateWorkflows(cwd string, fn func(items []Def) ([]Def, error)) error
- func ProviderMeta(provider, model string) string
- func RepoDir(cwd string) string
- func SaveAll(cwd string, items []Def) error
- func StepSummaryLine(name, provider, model, summary string) string
- func WorkflowNoteLine(msg, detail string) string
- type ChatTurn
- type Compiled
- type Def
- type FinishData
- type LoopPromptCtx
- type NoopRunnerListener
- func (NoopRunnerListener) OnNote(int, string)
- func (NoopRunnerListener) OnWorkflowDone(int, string, []string)
- func (NoopRunnerListener) OnWorkflowFailed(int, string)
- func (NoopRunnerListener) OnWorkflowStarted(int, Def, Source)
- func (NoopRunnerListener) OnWorkflowStepDone(int, int, string)
- func (NoopRunnerListener) OnWorkflowStepStarted(int, int, string, string, string)
- type Progress
- type RunState
- type RunnerListener
- type Scope
- type Source
- type SourceKind
- type StatusListener
- type Step
- type StepAgentInfo
- type StepPromptCtx
- type StepRole
- type Tracker
- func (t *Tracker) ActiveTabFor(key string) (int, bool)
- func (t *Tracker) ActiveWorkflowNames() map[string]struct{}
- func (t *Tracker) Clear(key string)
- func (t *Tracker) Lookup(cwd, key string) (TrackerEntry, bool)
- func (t *Tracker) MarkFinal(cwd, key, workflow, status string, stepIdx int)
- func (t *Tracker) MarkStep(key string, stepIdx int)
- func (t *Tracker) MarkWorking(cwd, key, workflow string, tabID int)
- func (t *Tracker) ResetForTest()
- func (t *Tracker) SetListener(l StatusListener)
- type TrackerEntry
- type WorkflowAgentConfig
Constants ¶
const ( StatusWorking = "working" StatusDone = "done" StatusFailed = "failed" )
Workflow status constants.
const WorkflowsGlobalDirName = "workflows"
const WorkflowsRepoDirName = ".ask/workflows"
Variables ¶
var DefaultTracker = NewTracker()
DefaultTracker is the package-wide tracker instance.
var ErrWorkflowAmbiguous = errors.New("workflow exists in multiple scopes; pass scope to pick one")
Functions ¶
func BuildStepInstruction ¶
func BuildStepInstruction(step Step, source Source, pc *StepPromptCtx) string
BuildStepInstruction assembles the system instruction for one workflow step: the author's prompt, the run's reference block, and the end_turn contract (plus loop framing when the step sits inside a loop).
It does NOT thread previous step output. The graph does that: a node's output arrives as the next node's input, and every step agent runs with IncludeContentsNone so it sees that input and its own work rather than the full transcript of everything before it.
func ChatTurnCountLabel ¶
func DefToConfigDef ¶
func DefToConfigDef(d Def) config.WorkflowDef
DefToConfigDef converts a workflow.Def to a config.WorkflowDef.
func EndTurnInstructionBlock ¶
func EndTurnInstructionBlock(loop *LoopPromptCtx) string
EndTurnInstructionBlock renders the end_turn contract for a step, and inside a loop the iteration framing plus how to break out.
Breaking a loop is ADK's exit_loop tool, not an end_turn argument: the tool sets Actions.Escalate, which is what a loopagent watches for.
func ExportBytes ¶
ExportBytes renders d as the standalone JSON a plugin's workflows/ directory holds (scope-free).
func ExportFile ¶
ExportFile writes ExportBytes(d) as FileName(d.Name).json in a fresh temporary directory and returns its path.
func GlobalDir ¶
func GlobalDir() string
GlobalDir returns the absolute global workflows directory (~/.config/ask/workflows/).
func LoopNoteLine ¶
LoopNoteLine formats a loop transition note.
func MutateWorkflows ¶
MutateWorkflows runs a read-modify-write cycle on the merged workflows.
func ProviderMeta ¶
ProviderMeta formats provider and model strings into a metadata label.
func StepSummaryLine ¶
StepSummaryLine formats a step completion summary.
func WorkflowNoteLine ¶
WorkflowNoteLine formats a single-line status note.
Types ¶
type Compiled ¶
type Compiled struct {
Workflow *adkworkflow.Workflow
// AgentInfo maps an emitted event's Author (an ADK agent
// name) to its metadata. Inner loop agents map to their
// containing loop step index.
AgentInfo map[string]StepAgentInfo
// Models are the per-step models built at compile time. Close releases
// them after the run — a subprocess-backed provider (Claude Code) forks
// a child per step that must be terminated.
Models []model.LLM
}
Compiled is a Def rendered as an executable ADK graph, plus the lookup the event adapter needs to attribute events back to steps.
func CompileWorkflow ¶
func CompileWorkflow(ctx context.Context, cfg WorkflowAgentConfig) (*Compiled, error)
CompileWorkflow compiles a Def into an ADK workflow graph.
Every top-level step becomes one node, chained Start -> n0 -> n1 -> …:
- An agent step becomes an AgentNode wrapping an llmagent.
- A loop step becomes an AgentNode wrapping a loopagent whose sub-agents are the inner steps, each carrying ADK's exit_loop tool. Any inner step calling exit_loop escalates and ends the loop; otherwise it runs to MaxIterations.
Two llmagent settings carry the workflow semantics and must not be dropped:
- IncludeContentsNone gives each step its own context. Without it a step inherits every prior step's events, and ADK renders those foreign events as prose — every tool call and every full tool result — so step 3 would carry steps 1 and 2 in full.
- InstructionProvider, never Config.Instruction. Step prompts are user-authored and routinely contain braces; a static Instruction is run through ADK's state interpolator and hard-fails the invocation on the first `{...}`.
type Def ¶
type Def struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Steps []Step `json:"steps"`
Scope Scope `json:"-"`
// Plugin is the "name@marketplace" that ships this workflow when
// Scope == ScopePlugin.
Plugin string `json:"-"`
}
Def defines a named sequence of workflow steps.
func ConfigDefToDef ¶
func ConfigDefToDef(d config.WorkflowDef) Def
ConfigDefToDef converts a config.WorkflowDef to a workflow.Def.
func ListAll ¶
ListAll returns all workflows visible to cwd in order: global, repo, user, then the read-only plugin workflows.
func LoadFileWorkflows ¶
LoadFileWorkflows reads every *.json under dir and tags them with scope.
func LoadPluginWorkflows ¶
LoadPluginWorkflows reads the workflows shipped by every enabled plugin.
func LoadUserWorkflows ¶
LoadUserWorkflows reads the user-scope workflow list from ask.json for cwd.
func ResolveByName ¶
ResolveByName resolves a workflow by name and optional scope. With no scope specified, the first matching workflow in global -> repo -> user order is returned (personal-wins).
func (Def) EffectiveMaxIterations ¶
type FinishData ¶
type FinishData struct {
Description string `json:"description"`
Artifacts []string `json:"artifacts"`
}
FinishData captures completion metadata reported at workflow termination.
type LoopPromptCtx ¶
LoopPromptCtx carries loop metadata for instruction assembly.
type NoopRunnerListener ¶
type NoopRunnerListener struct{}
NoopRunnerListener provides a default empty implementation of RunnerListener.
func (NoopRunnerListener) OnNote ¶
func (NoopRunnerListener) OnNote(int, string)
func (NoopRunnerListener) OnWorkflowDone ¶
func (NoopRunnerListener) OnWorkflowDone(int, string, []string)
func (NoopRunnerListener) OnWorkflowFailed ¶
func (NoopRunnerListener) OnWorkflowFailed(int, string)
func (NoopRunnerListener) OnWorkflowStarted ¶
func (NoopRunnerListener) OnWorkflowStarted(int, Def, Source)
func (NoopRunnerListener) OnWorkflowStepDone ¶
func (NoopRunnerListener) OnWorkflowStepDone(int, int, string)
func (NoopRunnerListener) OnWorkflowStepStarted ¶
type Progress ¶
type Progress struct {
// contains filtered or unexported fields
}
Progress turns the ADK event stream of a running workflow graph into RunnerListener callbacks.
Every callback is driven by something that actually happened in the stream: a step is "started" when an event authored by its agent arrives, and "done" when that step's successor starts or the run ends cleanly. Steps that never ran are never reported, and a run that fails partway reports only the steps that got that far — the previous implementation closed out every remaining step as completed and hardcoded a successful FinishData, so a chain that died at step 1 of 5 showed 5/5 green.
func NewProgress ¶
func NewProgress(compiled *Compiled, def Def, src Source, cwd string, tabID int, listener RunnerListener, tracker *Tracker) *Progress
NewProgress builds a Progress for one run and emits OnWorkflowStarted.
func (*Progress) Finish ¶
Finish closes the run. A nil err completes the in-flight step and reports success; a non-nil err leaves every unfinished step unfinished and reports the failure.
func (*Progress) SetFinishData ¶
func (p *Progress) SetFinishData(fd *FinishData)
SetFinishData records the run's completion report when it is read directly off the tool environment rather than seen in the event stream — the finish_workflow tool parks it there as it runs.
type RunState ¶
type RunState struct {
Workflow Def
Source Source
StartedAt time.Time
StepIdx int
Done bool
Failed bool
FailedReason string
FinishData *FinishData
}
RunState represents the state of a workflow run.
type RunnerListener ¶
type RunnerListener interface {
OnWorkflowStarted(tabID int, def Def, src Source)
OnWorkflowStepStarted(tabID int, stepIdx int, stepName, provider, model string)
OnWorkflowStepDone(tabID int, stepIdx int, summary string)
OnWorkflowDone(tabID int, description string, artifacts []string)
OnWorkflowFailed(tabID int, reason string)
OnNote(tabID int, text string)
}
RunnerListener receives progress notifications during workflow execution.
type Scope ¶
type Scope string
func NormalizeScope ¶
NormalizeScope maps empty string to ScopeUser and validates Scope.
type Source ¶
type Source struct {
Kind SourceKind `json:"kind"`
IssueDisplay string `json:"issue_display,omitempty"`
IssueKey string `json:"issue_key,omitempty"`
ChatLabel string `json:"chat_label,omitempty"`
ChatKey string `json:"chat_key,omitempty"`
ChatTranscript []ChatTurn `json:"chat_transcript,omitempty"`
TextLabel string `json:"text_label,omitempty"`
TextKey string `json:"text_key,omitempty"`
TextAppend string `json:"text_append,omitempty"`
}
func NewChatSource ¶
func NewTextSource ¶
type SourceKind ¶
type SourceKind int
const ( SourceKindIssue SourceKind = iota SourceKindChat SourceKindText )
type StatusListener ¶
StatusListener receives notifications whenever a workflow status changes.
type Step ¶
type Step struct {
Name string `json:"name"`
Kind string `json:"kind,omitempty"` // "loop" or empty/omitted for standard step
Provider string `json:"provider,omitempty"`
Model string `json:"model,omitempty"`
Prompt string `json:"prompt,omitempty"`
Steps []Step `json:"steps,omitempty"`
MaxIterations int `json:"maxIterations,omitempty"`
ExitCondition string `json:"exitCondition,omitempty"`
}
Step represents a single agent step or a loop of inner steps.
type StepAgentInfo ¶
type StepAgentInfo struct {
StepIndex int
StepName string
Provider string
Model string
InLoop bool
LoopName string
InnerIdx int
}
StepAgentInfo tracks metadata for one step agent in the compiled graph.
type StepPromptCtx ¶
type StepPromptCtx struct {
Loop *LoopPromptCtx
IsStartStep bool
IsWorkflowFinalStep bool
}
StepPromptCtx carries contextual details injected into a step's instruction.
type StepRole ¶
type StepRole struct {
// InLoop is true when the step runs inside a loop container.
InLoop bool
// IsTail is true when the step is the last inner step of its loop —
// the only step allowed to break the loop early via exit_loop.
IsTail bool
// IsFinal is true when the step is the last thing the whole workflow
// runs (the last top-level step, or the tail of a final loop). Only
// this step gets finish_workflow.
IsFinal bool
}
StepRole tells a ToolsBuilder where a step sits in the workflow, so it can decide which position-dependent tools to attach.
type Tracker ¶
type Tracker struct {
// contains filtered or unexported fields
}
Tracker manages workflow runtime statuses across tabs and projects.
func GlobalTracker ¶
func GlobalTracker() *Tracker
GlobalTracker returns the package-wide default tracker singleton.
func NewTracker ¶
func NewTracker() *Tracker
NewTracker instantiates a new thread-safe workflow tracker.
func (*Tracker) ActiveTabFor ¶
ActiveTabFor returns (tabID, true) if key currently has an active in-memory working entry.
func (*Tracker) ActiveWorkflowNames ¶
ActiveWorkflowNames returns the set of workflow names that currently have running sessions.
func (*Tracker) Lookup ¶
func (t *Tracker) Lookup(cwd, key string) (TrackerEntry, bool)
Lookup returns the runtime entry for key, hydrating from disk if missing in memory.
func (*Tracker) MarkFinal ¶
MarkFinal records and persists a terminal status (StatusDone or StatusFailed).
func (*Tracker) MarkWorking ¶
MarkWorking marks a workflow run as actively running in tab tabID.
func (*Tracker) ResetForTest ¶
func (t *Tracker) ResetForTest()
ResetForTest clears the in-memory tracker entries for test isolation.
func (*Tracker) SetListener ¶
func (t *Tracker) SetListener(l StatusListener)
SetListener attaches a listener function called on every status change.
type TrackerEntry ¶
type TrackerEntry struct {
Status string `json:"status"`
TabID int `json:"tab_id,omitempty"`
Workflow string `json:"workflow"`
StepIndex int `json:"step_index"`
StartedAt time.Time `json:"started_at"`
UpdatedAt time.Time `json:"updated_at"`
}
TrackerEntry is one in-memory or persisted runtime status entry for an issue or target.
type WorkflowAgentConfig ¶
type WorkflowAgentConfig struct {
Def Def
Source Source
Cwd string
TabID int
// ModelBuilder resolves the LLM for one step. Required.
ModelBuilder func(ctx context.Context, step Step) (model.LLM, error)
// ToolsBuilder and ToolsetsBuilder supply the step's tool surface.
// StepRole tells them where the step sits, so the builder can attach
// finish_workflow to the final step only, and so on.
ToolsBuilder func(ctx context.Context, step Step, role StepRole) ([]tool.Tool, error)
ToolsetsBuilder func(ctx context.Context, step Step, role StepRole) ([]tool.Toolset, error)
// InstructionBuilder renders the step's system instruction. Defaults
// to BuildStepInstruction.
InstructionBuilder func(step Step, src Source, pc *StepPromptCtx) string
// MaxRetries bounds per-node retries on failure. Zero means
// workflowDefaultMaxRetries; negative disables retries.
MaxRetries int
// BeforeModelCallbacks run before every LLM invocation.
BeforeModelCallbacks []llmagent.BeforeModelCallback
}
WorkflowAgentConfig carries everything the compiler needs to turn a Def into a runnable ADK graph. The builder callbacks are the seam the engine and the TUI fill in with their own model/tool wiring, and the seam tests swap for fakes.