mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-08-04 14:50:30 +08:00
Port agent PRs to GO - 2 (#16565)
### Summary Port the following PRs to GO in this PR https://github.com/infiniflow/ragflow/pull/16420 https://github.com/infiniflow/ragflow/pull/13295
This commit is contained in:
@@ -9,6 +9,9 @@ package canvas
|
||||
|
||||
import (
|
||||
"ragflow/internal/agent/runtime"
|
||||
"ragflow/internal/common"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// legacyNoOpNames is the set of component names that the Go port
|
||||
@@ -69,6 +72,64 @@ type CanvasComponentObj struct {
|
||||
Params map[string]any `json:"params"`
|
||||
}
|
||||
|
||||
// Close releases resources held by components referenced in the canvas
|
||||
// DSL. It walks every component's params map and calls Close() on any
|
||||
// value that implements a Close() method (MCPToolAdapters, HTTP
|
||||
// clients, etc.). Mirrors Python's Graph.close() in agent/canvas.py.
|
||||
//
|
||||
// In Go's architecture MCP sessions are per-invocation and auto-torn
|
||||
// down; Close() is a best-effort hook that ensures idle HTTP
|
||||
// connections are released even when adapters outlive a single call.
|
||||
func (c *Canvas) Close() {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
seen := make(map[any]bool)
|
||||
for _, comp := range c.Components {
|
||||
for _, v := range comp.Obj.Params {
|
||||
walkAndClose(v, seen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// walkAndClose recursively walks a value and calls Close() on any
|
||||
// objects that implement a Close() method. Maps, slices, and pointers
|
||||
// are recursed into; other types are skipped. Already-seen objects
|
||||
// (by interface identity) are skipped to avoid double-close.
|
||||
func walkAndClose(v any, seen map[any]bool) {
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
if closer, ok := v.(interface{ Close() }); ok {
|
||||
if !seen[closer] {
|
||||
seen[closer] = true
|
||||
safeClose(closer)
|
||||
}
|
||||
return
|
||||
}
|
||||
switch val := v.(type) {
|
||||
case map[string]any:
|
||||
for _, child := range val {
|
||||
walkAndClose(child, seen)
|
||||
}
|
||||
case []any:
|
||||
for _, child := range val {
|
||||
walkAndClose(child, seen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// safeClose calls Close() on a closer value, swallowing panics so a
|
||||
// misbehaving resource doesn't crash the canvas tear-down path.
|
||||
func safeClose(closer interface{ Close() }) {
|
||||
defer func() {
|
||||
if rec := recover(); rec != nil {
|
||||
common.Warn("canvas: Close() panicked", zap.Any("recover", rec))
|
||||
}
|
||||
}()
|
||||
closer.Close()
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
@@ -152,6 +152,19 @@ func (m *MCPToolAdapter) InvokableRun(ctx context.Context, argumentsInJSON strin
|
||||
return res.Text, nil
|
||||
}
|
||||
|
||||
// Close releases resources held by the adapter. In Go's architecture
|
||||
// MCP sessions are per-invocation (created and torn down within each
|
||||
// InvokableRun call), so there are no persistent connections to drain.
|
||||
// The primary resource is the http.Client's idle-connection pool;
|
||||
// calling Close explicitly drops those idle connections so they don't
|
||||
// accumulate across many adapter instances over long-running processes.
|
||||
// Mirrors Python's close_sync() in common/mcp_tool_call_conn.py.
|
||||
func (m *MCPToolAdapter) Close() {
|
||||
if m.httpClient != nil {
|
||||
m.httpClient.CloseIdleConnections()
|
||||
}
|
||||
}
|
||||
|
||||
// BuildMCPToolAdapters wraps a slice of mcpclient.Tool descriptors as
|
||||
// eino InvokableTool. Returned slice is suitable for handing to
|
||||
// agenttool.NewRetrieverTool / NewMCPToolAdapter paths or directly to
|
||||
|
||||
Reference in New Issue
Block a user