mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-01 00:05:43 +08:00
Replaces the Python agent canvas runtime with a Go implementation that runs inside `cmd/server_main`. The canvas compiles into an eino Workflow that pauses on wait-for-user via native Interrupt/Resume (no sentinel flag) and resumes from a Redis-backed CheckPointStore. All 21 Python agent components and ~35 tools are ported with functional parity. Sandbox providers now read their JSON config from the admin-panel system_settings table with env fallback. 234 files / +35,413 / -6,111. All Go files are gofmt-clean (CI gate added); drops the v2 DSL E2E step and the gap-analysis plan (both redundant after the port ships). ## Type of change - [x] Refactoring - [x] New feature - [x] Bug fix 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude <noreply@anthropic.com>
114 lines
4.1 KiB
Go
114 lines
4.1 KiB
Go
//
|
|
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
// CodeExec sandbox client. The Python sandbox service is kept
|
|
// as-is (we do NOT rewrite the sandbox). The Go side has a
|
|
// client that talks to the Python sandbox subsystem via the
|
|
// internal/agent/sandbox providers.
|
|
//
|
|
// The Python agent's code_exec delegates to a
|
|
// `SandboxProvider` subsystem (agent/sandbox/providers/) with
|
|
// three backends: self-managed (Docker + gVisor via local
|
|
// executor_manager HTTP), Aliyun Code Interpreter (cloud), and
|
|
// e2b (cloud SaaS). A `ProviderManager` selects one at
|
|
// startup. The Go side's decision is recorded in
|
|
// code_exec_sandbox_design.md:
|
|
//
|
|
// 1. shell out = spawn a Python subprocess that uses
|
|
// ProviderManager to dispatch to whichever provider the
|
|
// operator has configured. Reuses all three providers.
|
|
// 2. in-process = reimplement all three provider clients in
|
|
// Go. No Python dep, but three SDK surfaces to maintain.
|
|
//
|
|
// Decision: shell out (option A). The interface here is stable —
|
|
// when the implementation lands, callers see no change.
|
|
//
|
|
// Until the proto lands, CodeExecTool.InvokableRun surfaces
|
|
// ErrCodeExecSandboxMissing (defined in code_exec.go) so callers
|
|
// can detect the no-sandbox state.
|
|
package tool
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
)
|
|
|
|
// SandboxClient is the abstract interface for the CodeExec gRPC
|
|
// client. Production code calls SetSandboxClient at boot to install
|
|
// a real client; the default is a stub returning
|
|
// ErrSandboxNotWired.
|
|
type SandboxClient interface {
|
|
ExecuteCode(ctx context.Context, req SandboxRequest) (*SandboxResponse, error)
|
|
}
|
|
|
|
// SandboxRequest is the wire shape between the CodeExec tool and
|
|
// the sandbox subsystem. Mirrors `agent.sandbox.client.execute_code`'s
|
|
// input surface. Arguments and Timeout are optional — the bridge
|
|
// applies defaults (no args, 30s timeout) when zero-valued.
|
|
type SandboxRequest struct {
|
|
Lang string // "python" | "javascript"
|
|
Script string // the user's code
|
|
Arguments map[string]any // optional, passed to main(**args)
|
|
Timeout int // seconds, 0 = use provider default (30s)
|
|
}
|
|
|
|
// SandboxResponse is what the sandbox returns. Stdout / Stderr are
|
|
// captured streams; Returned is the legacy alias for the
|
|
// structured main() return value; StructuredResult carries the
|
|
// full extracted payload; Metadata holds provider-specific extras.
|
|
type SandboxResponse struct {
|
|
Stdout string
|
|
Stderr string
|
|
Returned string
|
|
ExitCode int
|
|
StructuredResult map[string]any
|
|
Metadata map[string]any
|
|
}
|
|
|
|
// ErrSandboxNotWired is the sentinel returned by the default stub
|
|
// client. Kept as an alias of ErrCodeExecSandboxMissing for backward
|
|
// compatibility with existing code_exec_test.go callers — the tool's
|
|
// public error surface is ErrCodeExecSandboxMissing; the client
|
|
// surface here is the same condition, named for code-path clarity.
|
|
var ErrSandboxNotWired = ErrCodeExecSandboxMissing
|
|
|
|
var (
|
|
sandboxClientMu sync.RWMutex
|
|
sandboxClientImpl SandboxClient = stubSandboxClient{}
|
|
)
|
|
|
|
func SetSandboxClient(c SandboxClient) {
|
|
sandboxClientMu.Lock()
|
|
defer sandboxClientMu.Unlock()
|
|
if c == nil {
|
|
sandboxClientImpl = stubSandboxClient{}
|
|
return
|
|
}
|
|
sandboxClientImpl = c
|
|
}
|
|
|
|
func GetSandboxClient() SandboxClient {
|
|
sandboxClientMu.RLock()
|
|
defer sandboxClientMu.RUnlock()
|
|
return sandboxClientImpl
|
|
}
|
|
|
|
type stubSandboxClient struct{}
|
|
|
|
func (stubSandboxClient) ExecuteCode(_ context.Context, _ SandboxRequest) (*SandboxResponse, error) {
|
|
return nil, ErrSandboxNotWired
|
|
}
|