mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-05 19:08:38 +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>
115 lines
2.9 KiB
Go
115 lines
2.9 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
|
|
//
|
|
|
|
package main
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestWriteMarkdown_SpotCheck pins the markdown output contract: it
|
|
// must enumerate both universes and surface at least one entry per
|
|
// universe. The exhaustive list is owned by RegisteredNames() and
|
|
// tool/registry.go — this test just guards against the structural
|
|
// shape regressing (lost header, lost divider, etc.).
|
|
func TestWriteMarkdown_SpotCheck(t *testing.T) {
|
|
// Capture stdout.
|
|
old := os.Stdout
|
|
r, w, err := os.Pipe()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
os.Stdout = w
|
|
defer func() {
|
|
os.Stdout = old
|
|
}()
|
|
|
|
writeMarkdown()
|
|
w.Close()
|
|
out, _ := io.ReadAll(r)
|
|
text := string(out)
|
|
|
|
wants := []string{
|
|
"## Universe A — Canvas DAG components",
|
|
"## Universe B — eino ReAct tools",
|
|
"| llm |",
|
|
"| message |",
|
|
"| agent |",
|
|
"akshare",
|
|
"wikipedia",
|
|
"search_my_dateset",
|
|
}
|
|
for _, want := range wants {
|
|
if !strings.Contains(text, want) {
|
|
t.Errorf("markdown output missing %q", want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestWriteTSV_SpotCheck pins the TSV output contract (used in CI
|
|
// parity checks via the diff toolchain). The format is:
|
|
//
|
|
// universe\tname\tsurface
|
|
//
|
|
// Every line must have exactly two tab separators; the header line
|
|
// and data lines are both checked.
|
|
func TestWriteTSV_SpotCheck(t *testing.T) {
|
|
old := os.Stdout
|
|
r, w, err := os.Pipe()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
os.Stdout = w
|
|
defer func() {
|
|
os.Stdout = old
|
|
}()
|
|
|
|
writeTSV()
|
|
w.Close()
|
|
out, _ := io.ReadAll(r)
|
|
text := string(out)
|
|
|
|
lines := strings.Split(strings.TrimRight(text, "\n"), "\n")
|
|
if len(lines) < 5 {
|
|
t.Fatalf("TSV output too short: %d lines", len(lines))
|
|
}
|
|
if lines[0] != "universe\tname\tsurface" {
|
|
t.Errorf("TSV header wrong: %q", lines[0])
|
|
}
|
|
for i, line := range lines[1:] {
|
|
fields := strings.Split(line, "\t")
|
|
if len(fields) != 3 {
|
|
t.Errorf("TSV line %d has %d fields, want 3: %q", i+1, len(fields), line)
|
|
}
|
|
if fields[0] != "A" && fields[0] != "B" {
|
|
t.Errorf("TSV line %d universe %q not in {A,B}: %q", i+1, fields[0], line)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestSummariseComponent_NotEmpty guards the surface string format.
|
|
func TestSummariseComponent_NotEmpty(t *testing.T) {
|
|
// We can't easily call summariseComponent without a real
|
|
// component instance, so this test simply asserts the
|
|
// formatter helpers are exported and don't panic on
|
|
// empty input. (summariseComponent takes a Component; the
|
|
// type assertion in the formatter would crash on nil, so
|
|
// we only test truncate here.)
|
|
if got := truncate("hello", 10); got != "hello" {
|
|
t.Errorf("truncate short: got %q", got)
|
|
}
|
|
if got := truncate("hello world", 5); got != "he..." {
|
|
t.Errorf("truncate long: got %q want %q", got, "he...")
|
|
}
|
|
}
|