Documentation
¶
Index ¶
- Variables
- func EffectiveConfig(run *model.GraphRun) model.GraphConfig
- func MergeVisibleSnapshotsWithWriters(upstreams []UpstreamSnapshot) (map[string]string, map[string]string)
- func ParseQuartetOutput(rawOutput string, declared []string) (*OutputParseResult, *OutputProtocolError)
- func ParseShellControl(controlBody string, declared []string) (*ShellControlResult, *ShellControlError)
- type AgentBindingLeaseResolver
- type AgentSessionLeaseResolver
- type AgentSnapshotLeaseResolver
- type AgentSnapshotResolver
- type CondBinary
- type CondCompare
- type CondEvalError
- type CondEvalInput
- type CondNot
- type CondOperand
- type ConditionExpr
- type GraphBufferStats
- type GraphEventReader
- type GraphReadEntry
- type GraphReadStatus
- type JobStateSink
- type LegacyAgentBindingResolver
- type OutputParseResult
- type OutputProtocolError
- type PromptUserMessageRecorder
- type Runner
- type Service
- type SessionLastAssistantReader
- type ShellControlError
- type ShellControlResult
- type ShellSessionRecorder
- type TitleInput
- type UpstreamSnapshot
- type ValidationError
Constants ¶
This section is empty.
Variables ¶
var ( ErrGraphRunNotFound = errors.New("graph run not found") // ErrGraphRunUnsupported is returned when a graph uses features the current // scheduler does not yet drive (loop containers / subgraph child nodes). ErrGraphRunUnsupported = errors.New("graph run uses features not yet supported by the scheduler") ErrGraphRunnerMissing = errors.New("graph runner is required") // ErrGraphRunNotRunning is returned when a control action (stop/step-stop) // targets a run with no live scheduler. ErrGraphRunNotRunning = errors.New("graph run is not currently running") // ErrGraphRunControlBusy is returned when a live scheduler's control queue // is full and the requested control signal was not accepted. ErrGraphRunControlBusy = errors.New("graph run control queue is busy") // ErrGraphRunNotResumable is returned when ResumeRun targets a run that is // not in a resumable terminal state. ErrGraphRunNotResumable = errors.New("graph run is not resumable") // ErrGraphRunInFlight is returned when DeleteRun targets a run that is still // in flight. ErrGraphRunInFlight = errors.New("graph run is in flight and cannot be deleted") // ErrGraphRunNotEditable is returned when UpdateRunVersion cannot reach the // live scheduler for an in-flight run, or the run state otherwise cannot // accept a version edit. ErrGraphRunNotEditable = errors.New("graph run cannot be edited") )
var ( // ErrWorkflowNotFound is returned when a workflow ID does not resolve to a // live (non-soft-deleted) GraphWorkflow. ErrWorkflowNotFound = errors.New("graph workflow not found") // ErrInvalidGraphConfig wraps graph config validation failures so the HTTP // layer can return them with the full GraphValidationError list. The // per-error detail is carried separately via ValidationErrors. ErrInvalidGraphConfig = errors.New("invalid graph workflow config") // ErrWorkflowConflict is returned when an update is based on a stale // workflow snapshot, usually from another open tab. ErrWorkflowConflict = errors.New("graph workflow has been modified") // ErrWorkflowBadRequest is returned when request parameters are invalid. ErrWorkflowBadRequest = errors.New("invalid graph workflow request") )
var ErrSeqGone = errors.New("graph event buffer: requested sequence has been garbage-collected")
ErrSeqGone is returned by Subscribe when the requested resume sequence has already been GC'd from the buffer. The SSE handler maps this to HTTP 410 so the client falls back to its reconcile (re-fetch run status) path.
Functions ¶
func EffectiveConfig ¶
func EffectiveConfig(run *model.GraphRun) model.GraphConfig
EffectiveConfig exposes effectiveConfig to callers outside this package (the HTTP handler reads the run's resolved config for Job-title generation). It is a pure function of the run object — no service state — so it lives here rather than on the Service interface. The fallback to BaseSnapshot keeps it correct for legacy runs whose config was only ever stored on the base snapshot.
func MergeVisibleSnapshotsWithWriters ¶
func MergeVisibleSnapshotsWithWriters(upstreams []UpstreamSnapshot) (map[string]string, map[string]string)
func ParseQuartetOutput ¶
func ParseQuartetOutput(rawOutput string, declared []string) (*OutputParseResult, *OutputProtocolError)
ParseQuartetOutput extracts named output blocks and legacy single-line markers from a model's raw output, then validates them against the declared set.
Rules (§1):
- primary multiline form: QUARTET_OUTPUT_BEGIN:<name> may be preceded by accumulated assistant text on its line; the value is every subsequent line verbatim until a dedicated QUARTET_OUTPUT_END:<name> line. It may be empty and may contain newlines, equals signs, quotes, and JSON-like text;
- a same-name begin marker before the closing marker restarts that block (models may abandon an overlong draft and rewrite it); a different-name nested begin marker, mismatched closing name, unexpected closing marker, or missing closing marker fails the node with the complete protocol error;
- legacy single-line form remains accepted: QUARTET_OUTPUT:<name>=<value> is matched as a substring anywhere within a line, may occur multiple times on that line, splits on the first '=', and preserves the value verbatim;
- variable name must match [A-Za-z_][A-Za-z0-9_]* and must not be reserved (leading '_' or 'QUARTET_');
- same name produced multiple times → last value wins;
- declaration is OPTIONAL and does NOT gate output (relaxed §1, mirroring ParseShellControl): EVERY named output flows downstream whether or not it was declared. The declared set drives only the completeness check — every DECLARED variable must still be produced (a missing output fails the node).
On any violation it returns the first located error (callers attach the raw output); a single error is enough because the whole node fails. Declared names are assumed already validated at save time, but reserved/invalid names produced by the model are still rejected here.
Trade-off (same as Shell): because undeclared outputs are no longer dropped, the save-time parallel-writer conflict check (validateOutputConflicts) — which only looks at DECLARED names — cannot catch two parallel Prompt nodes that emit the same undeclared variable. That collision is the author's responsibility, mirroring the intentionally permissive "set whatever you want" model.
func ParseShellControl ¶
func ParseShellControl(controlBody string, declared []string) (*ShellControlResult, *ShellControlError)
ParseShellControl parses a Graph Shell control file body and validates the produced output variables against the declared set.
Each non-empty line (after TrimSpace) is one of:
- "STOP_LOOP" → StopLoop = true
- "STOP_WORKFLOW" → StopWorkflow = true
- "B64:key=base64val" → base64-decoded value (written by quartet_set)
- "key=value" → plain text value (legacy compatibility)
Validation (§1, relaxed): produced variable names must still be valid and non-reserved, and a base64 decode failure still fails the node. For a Shell node, declaration is OPTIONAL and does NOT gate output: EVERY quartet_set variable flows downstream whether or not it was declared, so a script can publish variables ad hoc and have them visible to later nodes without pre-declaring them on the node. The declared set is used only for the completeness check below — every DECLARED variable must still be produced (a missing declared output fails the node). STOP_LOOP / STOP_WORKFLOW are control signals, not subject to either check.
Trade-off: because undeclared outputs are no longer dropped, the save-time parallel-writer conflict check (validateOutputConflicts) — which only looks at DECLARED names — cannot catch two parallel Shell nodes that quartet_set the same undeclared variable. That collision is the author's responsibility; it mirrors the intentionally permissive "set whatever you want" Shell model.
Note: STOP_LOOP is a scope-dependent signal; the scheduler applies it inside a loop container and drops it (no-op) outside one. That contextual rule needs scheduler/scope context not available to this pure parser.
Types ¶
type AgentBindingLeaseResolver ¶
type AgentBindingLeaseResolver interface {
ValidateAgentBindingWithLease(ctx context.Context, binding model.AgentRuntimeBinding) (func(), error)
}
type AgentSnapshotLeaseResolver ¶
type AgentSnapshotLeaseResolver interface {
ResolveAgentSnapshotWithLease(ctx context.Context, identifier string) (model.GraphAgentSnapshot, func(), error)
}
AgentSnapshotLeaseResolver extends AgentSnapshotResolver for runtimes that must hold an execution admission lease from snapshot resolution until the GraphRun has been durably bound to its Job. The release callback must be called on every success and failure path.
type AgentSnapshotResolver ¶
type CondBinary ¶
type CondBinary struct {
Op string // "且" or "或"
Left ConditionExpr
Right ConditionExpr
}
CondBinary is a 且/或 node.
type CondCompare ¶
type CondCompare struct {
Left CondOperand
Op string
Right CondOperand
IgnoreCase bool
IgnoreSpace bool
}
CondCompare is a leaf comparison.
type CondEvalError ¶
CondEvalError is a runtime condition failure carrying the full context the error-display spec (§4) requires: the expression text and the comparison operator/options in play.
func EvaluateCondition ¶
func EvaluateCondition(exprText string, in CondEvalInput) (bool, *CondEvalError)
EvaluateCondition parses exprText and evaluates it in one call. A parse error (which should not happen for save-validated configs) is surfaced as a CondEvalError so callers have a single error type to handle.
func EvaluateConditionExpr ¶
func EvaluateConditionExpr(exprText string, root ConditionExpr, in CondEvalInput) (bool, *CondEvalError)
EvaluateConditionExpr evaluates a pre-parsed AST. exprText is only used to annotate errors.
func (*CondEvalError) Error ¶
func (e *CondEvalError) Error() string
type CondEvalInput ¶
type CondEvalInput struct {
// Variables is the instance's visible variable snapshot (named outputs,
// _last_assistant_msg, aliases and initial variables already merged).
Variables map[string]string
// Disabled holds variable names toggled off. A disabled variable
// participates in comparisons as the empty string (§3), regardless of any
// value it might still carry in Variables.
Disabled map[string]struct{}
}
CondEvalInput carries everything an expression needs to resolve its operands at run time.
type CondOperand ¶
type CondOperand struct {
IsVar bool
Var string // variable name when IsVar
Lit string // literal value (already unescaped) otherwise
}
CondOperand is a variable reference or a string literal.
type ConditionExpr ¶
type ConditionExpr interface {
// contains filtered or unexported methods
}
ConditionExpr is the parsed AST root. Exported so the future execution engine can evaluate it; this module only constructs and syntactically validates it.
func ParseCondition ¶
func ParseCondition(expr string) (ConditionExpr, error)
ParseCondition parses and statically validates a condition expression. Returns a descriptive error (with position) on any unknown token, illegal escape, unterminated string, unmatched parenthesis, missing operator, or bare-variable truth test.
type GraphBufferStats ¶
type GraphBufferStats struct {
Events int
Readers int
HeadSeq uint64
NextSeq uint64
MaxLagSeq uint64
GCRunCount uint64
GCReleasedEvents uint64
Terminal bool
Closed bool
}
GraphBufferStats is a read-only snapshot of a buffer's runtime state for observability. Mirrors job.BufferStats.
type GraphEventReader ¶
type GraphEventReader interface {
// ReadWithTimeout returns up to maxN buffered events after the cursor, or a
// timeout/closed status. See graphReader.ReadWithTimeout.
ReadWithTimeout(ctx context.Context, timeout time.Duration, maxN int) ([]GraphReadEntry, GraphReadStatus)
// Ack advances the cursor past seq (forward only) and triggers GC.
Ack(seq uint64)
// Close detaches the reader from its buffer.
Close()
}
GraphEventReader is the SSE handler's view of a buffer subscription. It is satisfied by *graphReader and lets the handler stream events without importing buffer internals.
type GraphReadEntry ¶
type GraphReadEntry struct {
Seq uint64
Event *model.GraphEvent
}
GraphReadEntry is one delivered event with its sequence. Exported for the SSE handler.
type GraphReadStatus ¶
type GraphReadStatus int
GraphReadStatus communicates how a ReadWithTimeout call ended.
const ( // GraphReadOK means the call returned at least one entry. GraphReadOK GraphReadStatus = iota // GraphReadTimeout means the per-call deadline elapsed before any event // arrived. The reader is still alive — the caller may loop and read again // (e.g. to write an SSE keep-alive from the single writer goroutine). GraphReadTimeout // GraphReadClosed means the parent ctx was cancelled or the buffer/reader // was closed. The caller should release the reader and exit. GraphReadClosed )
type JobStateSink ¶
type JobStateSink interface {
SetGraphRunState(ctx context.Context, jobID, graphRunID string, status model.JobStatus, graphStatus model.GraphRunStatus, startedAt, finishedAt int64, graphSessionID string) error
// ClearGraphRunLinkage detaches a Job from a deleted GraphRun, but only if
// the Job is still bound to that exact run (it may have been re-bound to a
// newer run since).
ClearGraphRunLinkage(ctx context.Context, jobID, graphRunID string) error
// AttachGraphSession records an Agent node's session on the job's
// GraphSessionIDs whitelist (de-duplicated) so an interactive message may
// later target it — letting a user keep chatting in a finished node's
// session after the run stops. Best-effort and idempotent; kept off
// SessionIDs to preserve that field's linear-iteration semantics.
AttachGraphSession(ctx context.Context, jobID, sessionID string) error
// JobTitle returns the bound Job's display title for hook env injection
// ($QUARTET_JOB_TITLE). Best-effort: an unknown job (or any lookup miss)
// returns "" rather than an error, since hooks only log-and-continue.
JobTitle(ctx context.Context, jobID string) string
}
type OutputParseResult ¶
OutputParseResult carries the parsed named outputs and any failure detail.
type OutputProtocolError ¶
OutputProtocolError describes a model-output protocol violation with enough detail for full error display (§4): which variable, what went wrong, plus the caller attaches the raw model output.
func (*OutputProtocolError) Error ¶
func (e *OutputProtocolError) Error() string
type PromptUserMessageRecorder ¶
type PromptUserMessageRecorder interface {
RecordPromptUserMessage(ctx context.Context, jobID, sessionID, content string, startedAt int64) error
}
PromptUserMessageRecorder is an optional capability a Runner may implement so an Agent-class node (Prompt/Clarify) can persist its rendered prompt as the session's user message at enqueue time — before the agent subprocess spawns and starts replying. Without it, the user message is only written inside the agent's Run (ctxManager.BeginRun), which for a freshly-minted ACP session sits behind subprocess warmup, so the Chat sidebar lists the session but shows nothing for the whole startup. Recording it up front makes the auto-sent prompt visible the instant the node starts (the Chat reconcile path reloads history on "session opened").
The recorded message is tagged in-memory with msgextra.KeyPrePersisted when handed to RunIteration so BeginRun knows it is already on disk and must not append it again (see chatctx.BeginRun). Only used for `new`/unset session strategy — never `inherit`, whose continuation session would otherwise drift the ACP fingerprint and force a needless subprocess reset every turn. Like ShellSessionRecorder this is best-effort: a missing implementation or a record failure leaves the node to persist normally inside its Run.
type Runner ¶
type Runner interface {
InitSession(ctx context.Context, jobID string, overrides *model.SessionOverrides) (sessionID string, err error)
RunIteration(ctx context.Context, sessionID string, messages []*schema.Message, handler agui.EventHandler) error
SessionModelID(sessionID string) string
// ResolveModelSnapshot returns the display form of the model bound to
// modelID, so a GraphRun can freeze it into its snapshot. The numeric eino
// model-config store is gone; a graph node's ModelID is now the ACP model
// identifier, which is already display-ready and snapshotted as-is.
// ok=false when modelID is empty — the caller treats this as a degraded
// (best-effort) snapshot rather than a start failure.
ResolveModelSnapshot(ctx context.Context, modelID string) (string, bool)
}
type Service ¶
type Service interface {
CreateWorkflow(ctx context.Context, req *model.CreateGraphWorkflowRequest) (*model.GraphWorkflow, error)
GetWorkflow(ctx context.Context, id string) (*model.GraphWorkflow, error)
ListWorkflows(ctx context.Context) ([]*model.GraphWorkflow, []model.GraphWorkflowWarning, error)
UpdateWorkflow(ctx context.Context, id string, req *model.UpdateGraphWorkflowRequest) (*model.GraphWorkflow, error)
DeleteWorkflow(ctx context.Context, id string, expectedUpdatedAt *time.Time) error
CreateRunJob(ctx context.Context, req *model.StartGraphRunRequest, jobs jobsvc.Service, workspaces workspacesvc.Service) (*model.Job, error)
CreateScheduledRunJob(ctx context.Context, task *model.ScheduledTask, jobs jobsvc.Service, workspaces workspacesvc.Service) (*model.Job, error)
// ValidateConfig runs the full static legality check without persisting.
ValidateConfig(ctx context.Context, cfg *model.GraphConfig) []model.GraphValidationError
StartRun(ctx context.Context, req *model.StartGraphRunRequest, runner Runner, jobs JobStateSink) (*model.GraphRun, error)
RegisterRunLocation(ctx context.Context, runID, workspaceID, jobID string) error
GetRunStatus(ctx context.Context, runID string) (*model.GraphRunStatusResponse, error)
ListRunEvents(ctx context.Context, runID string, startLine int, count *int) (*model.GraphRunEventsResponse, error)
// ListReplayEvents reads at most limit persistable structural events from
// startLine for SSE disk-replay (a run with no live buffer in this process).
// It bounds the read so a pathologically large event log can't be streamed in
// full, and filters out any agent streaming deltas that may linger in legacy
// logs. The canvas is rebuilt from the run snapshot, so this stream is only a
// best-effort structural backfill.
ListReplayEvents(ctx context.Context, runID string, startLine, limit int) (*model.GraphRunEventsResponse, error)
// ListHookResults projects a run's persisted hook (completed/failed) events
// into per-node results for the run-view node-detail panel, keeping the latest
// result per node.
ListHookResults(ctx context.Context, runID string) (*model.GraphHookResultsResponse, error)
// SubscribeRunEvents attaches an SSE reader to a live run's in-memory event
// buffer, resuming after startSeq. live=false means no buffer exists in this
// process (run not active here, e.g. after a restart) — the caller degrades
// to replaying persisted structural events from disk. A non-nil error means
// the resume point has been GC'd (caller maps to HTTP 410). The returned
// reader must be Closed by the caller.
SubscribeRunEvents(runID string, startSeq uint64) (reader GraphEventReader, live bool, err error)
// RunEventSnapshotSeq returns the seq a fresh subscriber should resume from
// for a live run, and ok=false when no live buffer exists.
RunEventSnapshotSeq(runID string) (seq uint64, ok bool)
// StopRun hard-stops a running GraphRun: in-flight instances are cancelled
// and marked interrupted, the run becomes "stopped" and stays resumable.
StopRun(ctx context.Context, runID, reason string) (*model.GraphRun, error)
// StopRunAndWait is the lifecycle-safe hard-stop used before destructive
// follow-up work. It is idempotent for settled runs, repairs schedulerless
// in-flight runs, and for a live scheduler waits until all run persistence,
// Job sink updates, and asynchronous hooks have completed.
StopRunAndWait(ctx context.Context, runID, reason string) (*model.GraphRun, error)
// StepStopRun freezes the current ready batch and stops after its members
// reach a terminal state; the run becomes "stepStopped" and stays resumable.
StepStopRun(ctx context.Context, runID, reason string) (*model.GraphRun, error)
// SessionStopRun continues inherited Agent turns and stops before dispatching
// an Agent node that needs a new session. The run stays resumable.
SessionStopRun(ctx context.Context, runID, reason string) (*model.GraphRun, error)
// CancelStopRun cancels a pending step/session stop, releases the held
// dispatch frontier, and returns the run to "running".
CancelStopRun(ctx context.Context, runID, reason string) (*model.GraphRun, error)
// ResumeRun re-launches a resumable GraphRun (failed/stepStopped/sessionStopped/stopped/
// timedOut/recovering): succeeded/skipped instances are kept,
// failed/interrupted ones are reset and rescheduled.
ResumeRun(ctx context.Context, runID string, runner Runner, jobs JobStateSink) (*model.GraphRun, error)
// ContinueRun continues a GraphRun parked at awaitingInput (§ 交互澄清结点): it
// finalizes the clarify instances (capturing each session's discussion 结论
// into their output variables), resolves their held out-edges, and resumes the
// DAG. Rejected unless the run is in awaitingInput.
ContinueRun(ctx context.Context, runID string, runner Runner, jobs JobStateSink) (*model.GraphRun, error)
// DeleteRun deletes a non-in-flight GraphRun, cascading all of its run
// artifacts and clearing the bound Job's GraphRunID linkage.
DeleteRun(ctx context.Context, runID string, jobs JobStateSink) error
// UpdateRunVersion appends a new graph version to a GraphRun after validating
// the edit against the persisted run state (already-running/succeeded/skipped
// instances and their config are immutable; paths/edges depended on by
// completed instances may not be removed). The new version's referenced
// Agent/model config content is frozen into the run. On a live run the
// scheduler refreshes its effective topology, so not-yet-started instances
// use the new version while in-flight and completed instances keep their
// execution-time version.
UpdateRunVersion(ctx context.Context, runID string, req *model.UpdateGraphRunVersionRequest, src Runner) (*model.GraphRun, error)
// SetUsageRecorder wires the optional usage-stats sink for Agent-class graph
// nodes. Passing nil disables recording (used by tests).
SetUsageRecorder(r usagestats.Recorder)
// SetEndHookScriptProvider wires the getter for the global default End-node
// hook script (settings.EndHookScript). Read at hook time so a mid-run
// edit takes effect; nil (or returning "") disables the "default" End hook.
SetEndHookScriptProvider(fn func() string)
// SetJobStateSink wires the persistent Job state sink used by the
// orphan-reconcile paths (StopRun's no-scheduler fallback and
// ReconcileInterruptedRun) that run without a live scheduler. Set once at
// startup, before serving.
SetJobStateSink(jobs JobStateSink)
// ReconcileInterruptedRun repairs a run left in an in-flight status by a
// crash/restart: no live scheduler can exist for it after boot, so its
// still-running instances are marked interrupted and the run is moved to
// `recovering` (a static, resumable state) with the bound Job set to a
// non-running status. No-op for runs already in a settled status. Called
// once per graph job at startup.
ReconcileInterruptedRun(ctx context.Context, runID string) error
}
Service exposes Graph workflow config management. Runtime concerns (GraphRun execution, scheduling, sessions) live in other modules.
func NewService ¶
type SessionLastAssistantReader ¶
type SessionLastAssistantReader interface {
SessionLastAssistantMessage(ctx context.Context, jobID, sessionID string) (content string, ok bool, err error)
}
SessionLastAssistantReader is an optional capability a Runner may implement so the graph engine can read the latest assistant reply of a session — used by the Clarify node (§ 交互澄清结点) to capture the「讨论结论」at continue time: the authoritative result of an open-ended discussion is the session's last assistant message, written into _last_assistant_msg / the optional alias / declared output variables when the user clicks「讨论完成」. Returns the trimmed content of the last non-empty assistant message, or "" (ok=false) when the session has no assistant turn yet (e.g. a clarify node opened with no initial prompt that the user continued without ever getting a reply). Best-effort: a missing implementation or a read error degrades to an empty 结论, not a failure.
type ShellControlError ¶
ShellControlError describes a Shell output protocol violation. Callers attach stdout/stderr/exit code; this carries the variable and reason.
func (*ShellControlError) Error ¶
func (e *ShellControlError) Error() string
type ShellControlResult ¶
ShellControlResult is the parsed outcome of a Graph Shell node's control file.
type ShellSessionRecorder ¶
type ShellSessionRecorder interface {
BeginShellSession(ctx context.Context, jobID, script string, startedAt int64) (sessionID string, err error)
FinishShellSession(ctx context.Context, jobID, sessionID, output string, startedAt, finishedAt int64) error
}
ShellSessionRecorder is an optional capability a Runner may implement to give Shell nodes their own session (Graph Shell 默认新开 session). Recording is split in two so the session — and the script as its user message — surfaces the instant the node starts rather than only after the shell exits:
- BeginShellSession is called by the scheduler when a Shell node is enqueued (before the shell runs). It mints a fresh session for the job, appends the script as the user message, and returns the new session id for GraphInstanceState.DisplaySessionID so the Chat sidebar lists it immediately (a slow shell no longer hides the session for its whole run).
- FinishShellSession is called when the node completes (success or failure) to append the combined stdout/stderr as the assistant message.
This session is purely for display — it never participates in §3 会话血缘 lineage. A runner that does not implement it, or a Begin failure, leaves the Shell node without a display session and is treated as best-effort, not a node failure.
type TitleInput ¶
type TitleInput struct {
// Summary 是按执行顺序整理出的提示词列表(含少量结构信息),作为标题模型的
// 用户消息。
Summary string
// FallbackSeed 是第一个提示词节点的开头内容,模型失败时用它派生标题。
FallbackSeed string
}
TitleInput 是标题生成所需的两份文本:Summary 交给模型,FallbackSeed 在模型 不可用/连续失败时用于派生一个"够用"的标题。二者都可能为空(例如工作流里只有 start/end 节点),调用方需要自行判空。
func BuildTitleInput ¶
func BuildTitleInput(cfg model.GraphConfig) TitleInput
BuildTitleInput 从 workflow 配置中提炼标题生成输入:
- 只保留承载业务语义的内容:Prompt / Clarify 节点的提示词是主体,Shell、 条件、循环节点只留一行摘要(标题或脚本/条件的首行),start/end 忽略;
- 节点按执行顺序(拓扑序,循环体紧随其循环节点)排列,让模型能分辨"取数据 → 处理 → 通知"这样的流程走向;
- 工作流级变量会代入提示词,未定义的(运行时才产生的节点输出)保持 {{name}} 字面量;
- 单条提示词和整体输入都有字符预算,超出部分截断并显式标注,模型据此知道 自己看到的是片段。
type UpstreamSnapshot ¶
type UpstreamSnapshot struct {
// NodeID is the upstream node's stable ID. Used to break ties for
// _last_assistant_msg deterministically (ascending node ID, last wins).
NodeID string
// Variables is the upstream instance's visible variable snapshot, including
// any named outputs and aliases it wrote.
Variables map[string]string
// Writers identifies variables written by a concrete node ID. Variables not
// present here are still inherited from the run's initial variable table.
Writers map[string]string
// LastAssistantMsg is the upstream instance's raw final output
// (_last_assistant_msg). Empty string is a valid value.
LastAssistantMsg string
// SessionID is the upstream instance's outflow session (§3 会话血缘): the
// session an inheriting downstream Agent forks from. Empty when the upstream
// chain has not yet created any session (e.g. before the first Agent node).
SessionID string
}
UpstreamSnapshot is one activated upstream's contribution to a join.
type ValidationError ¶
type ValidationError struct {
Errors []model.GraphValidationError
}
ValidationError wraps the full list of GraphValidationError so the handler can surface every located error at once while still using errors.Is against ErrInvalidGraphConfig.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
func (*ValidationError) Is ¶
func (e *ValidationError) Is(target error) bool