// Package eino 封装基于 CloudWeGo Eino 的 Agent 图编排引擎。 package eino import ( "context" "log" "github.com/sundynix/sundynix-dispatcher/internal/harness" "github.com/sundynix/sundynix-dispatcher/internal/llm" "github.com/sundynix/sundynix-shared/contract" ) // TokenSink 是 Token 流回流出口(由 NATS bus 实现)。 type TokenSink interface { PublishToken(taskID string, token []byte) error CompleteStream(taskID string) error } // Orchestrator 将 DSL 图编译为 Eino Graph 并驱动执行。 type Orchestrator struct { pool *llm.Pool breaker *harness.CircuitBreaker sink TokenSink } func NewOrchestrator(pool *llm.Pool, breaker *harness.CircuitBreaker, sink TokenSink) *Orchestrator { return &Orchestrator{pool: pool, breaker: breaker, sink: sink} } // Handle 消费一个任务:编译图 → 流式推理 → 经 sink 把 Token 回流到 sundynix.streams.。 func (o *Orchestrator) Handle(ctx context.Context, t *contract.Task) error { if !o.breaker.Allow() { log.Printf("[eino] circuit open, drop task %s", t.ID) return nil } log.Printf("[eino] task %s received (graph=%d bytes), streaming tokens...", t.ID, len(t.Graph)) // TODO: compose.NewGraph(...) 编译 DSL;此处 prompt 占位为图原文。 // 工具节点经 NATS 调用第 5 层 MCP(sundynix.tools.go.* / sundynix.tools.py.*)。 prompt := string(t.Graph) n := 0 err := o.pool.Stream(ctx, prompt, func(tok []byte) { if perr := o.sink.PublishToken(t.ID, tok); perr != nil { log.Printf("[eino] publish token failed: %v", perr) return } n++ }) if err != nil { log.Printf("[eino] task %s stream error: %v", t.ID, err) } if cerr := o.sink.CompleteStream(t.ID); cerr != nil { log.Printf("[eino] complete stream failed: %v", cerr) } log.Printf("[eino] task %s done, %d tokens streamed", t.ID, n) o.breaker.Report(err == nil) return err }