mirror of
https://github.com/open-gitagent/langship.sh.git
synced 2026-08-03 07:21:04 +02:00
112 lines
3.4 KiB
Go
112 lines
3.4 KiB
Go
package engine
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"github.com/lyzrai/flow/pkg/models"
|
||
|
|
)
|
||
|
|
|
||
|
|
// ExecutionContext is the data bus that carries items between nodes during execution.
|
||
|
|
type ExecutionContext struct {
|
||
|
|
nodeOutputs map[string]map[int][]models.Item
|
||
|
|
|
||
|
|
Workflow *models.WorkflowDefinition
|
||
|
|
DAG *DAG
|
||
|
|
Lookup ExecutorLookup
|
||
|
|
|
||
|
|
// Events is an optional channel for streaming execution events (SSE).
|
||
|
|
// When non-nil, the runner and executors emit events as execution progresses.
|
||
|
|
Events chan<- ExecutionEvent
|
||
|
|
|
||
|
|
// delegatedNodes tracks nodes claimed as delegate tools by an upstream node.
|
||
|
|
// Reserved for governance/sub-agent extensions; unused in the base engine.
|
||
|
|
delegatedNodes map[string]bool
|
||
|
|
}
|
||
|
|
|
||
|
|
// MarkDelegated marks a node as claimed by an upstream node.
|
||
|
|
func (c *ExecutionContext) MarkDelegated(nodeName string) {
|
||
|
|
if c.delegatedNodes == nil {
|
||
|
|
c.delegatedNodes = make(map[string]bool)
|
||
|
|
}
|
||
|
|
c.delegatedNodes[nodeName] = true
|
||
|
|
}
|
||
|
|
|
||
|
|
// IsDelegated returns true if the node has been claimed.
|
||
|
|
func (c *ExecutionContext) IsDelegated(nodeName string) bool {
|
||
|
|
return c.delegatedNodes[nodeName]
|
||
|
|
}
|
||
|
|
|
||
|
|
// NewExecutionContext creates a new execution context for a workflow run.
|
||
|
|
func NewExecutionContext(wf *models.WorkflowDefinition, dag *DAG) *ExecutionContext {
|
||
|
|
return &ExecutionContext{
|
||
|
|
nodeOutputs: make(map[string]map[int][]models.Item),
|
||
|
|
Workflow: wf,
|
||
|
|
DAG: dag,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// NewStreamingExecutionContext creates a context with an event channel for SSE streaming.
|
||
|
|
func NewStreamingExecutionContext(wf *models.WorkflowDefinition, dag *DAG, events chan<- ExecutionEvent) *ExecutionContext {
|
||
|
|
return &ExecutionContext{
|
||
|
|
nodeOutputs: make(map[string]map[int][]models.Item),
|
||
|
|
Workflow: wf,
|
||
|
|
DAG: dag,
|
||
|
|
Events: events,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Emit sends an event if streaming is enabled.
|
||
|
|
func (c *ExecutionContext) Emit(event ExecutionEvent) {
|
||
|
|
if c.Events != nil {
|
||
|
|
c.Events <- event
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// IsStreaming returns true if this context has a streaming event channel.
|
||
|
|
func (c *ExecutionContext) IsStreaming() bool {
|
||
|
|
return c.Events != nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// SetOutput stores the output items of a node at a specific output index.
|
||
|
|
func (c *ExecutionContext) SetOutput(nodeName string, outputIndex int, items []models.Item) {
|
||
|
|
if c.nodeOutputs[nodeName] == nil {
|
||
|
|
c.nodeOutputs[nodeName] = make(map[int][]models.Item)
|
||
|
|
}
|
||
|
|
c.nodeOutputs[nodeName][outputIndex] = items
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetNodeOutput retrieves the output items of a specific node and output index.
|
||
|
|
func (c *ExecutionContext) GetNodeOutput(nodeName string, outputIndex int) []models.Item {
|
||
|
|
if outputs, ok := c.nodeOutputs[nodeName]; ok {
|
||
|
|
return outputs[outputIndex]
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// GatherInputs collects all inputs for a given node by looking at incoming edges.
|
||
|
|
// Returns a slice where each element corresponds to an input index.
|
||
|
|
func (c *ExecutionContext) GatherInputs(nodeName string) [][]models.Item {
|
||
|
|
inEdges := c.DAG.InEdges[nodeName]
|
||
|
|
if len(inEdges) == 0 {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
maxIdx := 0
|
||
|
|
for _, edge := range inEdges {
|
||
|
|
if edge.TargetInputIndex > maxIdx {
|
||
|
|
maxIdx = edge.TargetInputIndex
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
inputs := make([][]models.Item, maxIdx+1)
|
||
|
|
for _, edge := range inEdges {
|
||
|
|
sourceItems := c.GetNodeOutput(edge.Target, edge.SourceOutputIndex)
|
||
|
|
inputs[edge.TargetInputIndex] = append(inputs[edge.TargetInputIndex], sourceItems...)
|
||
|
|
}
|
||
|
|
|
||
|
|
return inputs
|
||
|
|
}
|
||
|
|
|
||
|
|
// AllOutputs returns all node outputs for building the execution result.
|
||
|
|
func (c *ExecutionContext) AllOutputs() map[string]map[int][]models.Item {
|
||
|
|
return c.nodeOutputs
|
||
|
|
}
|