mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-06 11:28:38 +08:00
Ports the agent canvas subsystem from Python to Go.
## What's included
### Canvas Engine (Phase 0/1)
- State engine, scheduler, variable resolver, Redis checkpoint store,
cancel protocol
- **209 tests** across canvas / component / io packages
### 22 Components (P0–P4)
| Tier | Components |
|---|---|
| P0 T1+T2+T3 | LLM, Agent, ExitLoop, Switch, Categorize, Begin,
Message, Invoke |
| P1 T3 | VariableAggregator, VariableAssigner, StringTransform,
ListOperations, DataOperations |
| P2 T3 | Iteration, IterationItem, Loop, LoopItem |
| P3 T3 | UserFillUp, Fillup |
| P4 T5 | Browser, ExcelProcessor, DocsGenerator |
### DSL v2 Schema (Phase 2.5)
- Typed v2 in-memory model with v1-to-v2 auto-detect converter
- v1 legacy field stripping per plan §2.11.7
### HTTP Endpoints & Bug Fixes (Plans PR1–PR3)
- **DELETE SQL bug fix**: gorm v2 `Where("id = ?", id).Delete(...)`
pattern
- **CreateAgent validation**: title/DSL required, duplicate check, 103
envelope
- **13 new endpoints**: templates, prompts, tags, sessions CRUD,
chat/completions (SSE + non-stream stubs), rerun, test_db_connection,
logs, webhook/logs
- **756 Go unit tests** (745 → 756, +18)
- **17 → 0 Python integration test failures** (test_agents.py +
test_session_management/)
### Tools
21 eino tools: HTTPHelper, search tools, financial/data tools, mandatory
stubs
### Infrastructure
OTel observability, NATS message queue, DeepDoc gRPC client, SSRF
guards, IDOR mitigation
86 lines
3.5 KiB
Go
86 lines
3.5 KiB
Go
// Package canvas implements the RAGFlow agent canvas Go port.
|
|
// See plan: .claude/plans/agent-go-port.md §2.5 (State + Workflow hybrid),
|
|
// §2.6 (Redis-backed CheckPointStore + RunTracker), §4.2 (CanvasState shape).
|
|
//
|
|
// Shared runtime contracts (CanvasState, Component, ComponentFactory,
|
|
// state context plumbing, template helpers) live in
|
|
// internal/agent/runtime. Canvas re-exports them through thin aliases
|
|
// so existing call sites keep working while breaking the historic
|
|
// canvas <-> component import cycle.
|
|
package canvas
|
|
|
|
import (
|
|
"ragflow/internal/agent/runtime"
|
|
)
|
|
|
|
// legacyNoOpNames is the set of component names that the Go port
|
|
// recognises for DSL v1 compatibility but does not ship a real
|
|
// implementation for. Encountering one of these in a DSL is mapped to
|
|
// the same no-op echo lambda used for placeholder bodies by the
|
|
// BuildWorkflow in scheduler.go. New DSLs should not use these names —
|
|
// they exist only so v1 DSLs that reference Python-era sentinel
|
|
// components ("ExitLoop") still compile and run in the Go port.
|
|
//
|
|
// Membership semantics inside a Loop's sub-graph: legacy names that
|
|
// appear as descendants of a Loop are absorbed as no-op members of the
|
|
// sub-graph; they do not contribute to loop control. Termination is
|
|
// driven by the Loop's loop_termination_condition predicate, not by
|
|
// reaching an ExitLoop node.
|
|
var legacyNoOpNames = map[string]bool{
|
|
"exitloop": true,
|
|
}
|
|
|
|
// CanvasState aliases runtime.CanvasState so existing canvas callers
|
|
// (and component tests that still import the canvas package) keep
|
|
// compiling without changes. The canonical definition lives in
|
|
// internal/agent/runtime/state.go.
|
|
type CanvasState = runtime.CanvasState
|
|
|
|
// NewCanvasState re-exports runtime.NewCanvasState.
|
|
func NewCanvasState(runID, taskID string) *CanvasState {
|
|
return runtime.NewCanvasState(runID, taskID)
|
|
}
|
|
|
|
// Canvas is the in-memory DSL representation loaded from a user_canvas row.
|
|
// It is the input to compile.go which builds the eino Workflow.
|
|
type Canvas struct {
|
|
Version int `json:"version"`
|
|
Components map[string]CanvasComponent `json:"components"`
|
|
Path []string `json:"path"`
|
|
History []map[string]any `json:"history,omitempty"`
|
|
Retrieval map[string]any `json:"retrieval,omitempty"`
|
|
Globals map[string]any `json:"globals,omitempty"`
|
|
}
|
|
|
|
// CanvasComponent is the v1-shape component node (Phase 1 uses v1; v2 lands
|
|
// in Phase 2.5 per plan §2.5.3 and §5).
|
|
//
|
|
// The Obj.ComponentName matches agent/component/<name>.py's class name
|
|
// (case-insensitive per dsl-v1-corner-cases.md §13).
|
|
type CanvasComponent struct {
|
|
Obj CanvasComponentObj `json:"obj"`
|
|
Downstream []string `json:"downstream"`
|
|
Upstream []string `json:"upstream"`
|
|
}
|
|
|
|
type CanvasComponentObj struct {
|
|
ComponentName string `json:"component_name"`
|
|
Params map[string]any `json:"params"`
|
|
}
|
|
|
|
// Component is an alias for runtime.Component — the minimal runtime
|
|
// surface BuildWorkflow needs at sub-graph build time. The canonical
|
|
// definition (and the SetDefaultFactory / DefaultFactory plumbing)
|
|
// lives in internal/agent/runtime/component.go.
|
|
type Component = runtime.Component
|
|
|
|
// ComponentFactory aliases runtime.ComponentFactory.
|
|
type ComponentFactory = runtime.ComponentFactory
|
|
|
|
// SetDefaultFactory re-exports runtime.SetDefaultFactory. The
|
|
// orchestrator's main.go can call either entry point; new code
|
|
// should prefer the runtime package directly.
|
|
func SetDefaultFactory(f ComponentFactory) {
|
|
runtime.SetDefaultFactory(f)
|
|
}
|