mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-07 12:00:44 +08:00
fix(go-agent): missing input form for ExeSQL and Browser agent nodes (#16675)
## Summary - Add Go dynamic input form support for ExeSQL and Browser components. - Align their input form metadata with the Python implementation. - Add regression tests for `/components/:component_id/input-form`.
This commit is contained in:
@@ -334,6 +334,19 @@ func (b *BrowserComponent) Inputs() map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BrowserComponent) GetInputForm() map[string]any {
|
||||
return map[string]any{
|
||||
"prompts": map[string]any{
|
||||
"type": "text",
|
||||
"name": "Prompts",
|
||||
},
|
||||
"upload_sources": map[string]any{
|
||||
"type": "line",
|
||||
"name": "Upload sources",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Outputs returns the response surface.
|
||||
func (b *BrowserComponent) Outputs() map[string]string {
|
||||
return map[string]string{
|
||||
|
||||
@@ -517,6 +517,15 @@ func (c *exesqlComponent) Inputs() map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *exesqlComponent) GetInputForm() map[string]any {
|
||||
return map[string]any{
|
||||
"sql": map[string]any{
|
||||
"name": "SQL",
|
||||
"type": "line",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *exesqlComponent) Outputs() map[string]string {
|
||||
return map[string]string{
|
||||
"columns": "Result-set column names.",
|
||||
|
||||
@@ -26,8 +26,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
agentruntime "ragflow/internal/agent/runtime"
|
||||
_ "ragflow/internal/agent/component" // registers the production factory
|
||||
agentruntime "ragflow/internal/agent/runtime"
|
||||
"ragflow/internal/dao"
|
||||
"ragflow/internal/entity"
|
||||
)
|
||||
@@ -104,6 +104,122 @@ func TestGetComponentInputForm_HappyPath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetComponentInputForm_ExeSQLDynamicInputForm(t *testing.T) {
|
||||
cv := &entity.UserCanvas{
|
||||
ID: "c1",
|
||||
DSL: map[string]any{
|
||||
"components": map[string]any{
|
||||
"exesql:0": map[string]any{
|
||||
"obj": map[string]any{
|
||||
"component_name": "ExeSQL",
|
||||
"params": map[string]any{
|
||||
"database": "demo",
|
||||
"username": "root",
|
||||
"host": "127.0.0.1",
|
||||
"port": float64(3306),
|
||||
"password": "secret",
|
||||
"top_n": float64(50),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h := &AgentHandler{loader: &fakeCanvasLoader{canvas: cv}}
|
||||
|
||||
c, w := componentCtx(t, "GET", "/api/v1/agents/c1/components/exesql:0/input-form", "")
|
||||
c.Params = gin.Params{
|
||||
{Key: "canvas_id", Value: "c1"},
|
||||
{Key: "component_id", Value: "exesql:0"},
|
||||
}
|
||||
h.GetComponentInputForm(c)
|
||||
|
||||
if w.Code != 200 {
|
||||
t.Fatalf("status = %d, want 200; body=%s", w.Code, w.Body.String())
|
||||
}
|
||||
var env struct {
|
||||
Code int `json:"code"`
|
||||
Data map[string]interface{} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &env); err != nil {
|
||||
t.Fatalf("decode: %v (body=%s)", err, w.Body.String())
|
||||
}
|
||||
if env.Code != 0 {
|
||||
t.Fatalf("code = %d, want 0; body=%s", env.Code, w.Body.String())
|
||||
}
|
||||
sql, ok := env.Data["sql"].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("data.sql = %v, want a map", env.Data["sql"])
|
||||
}
|
||||
if sql["name"] != "SQL" {
|
||||
t.Errorf("data.sql.name = %v, want SQL", sql["name"])
|
||||
}
|
||||
if sql["type"] != "line" {
|
||||
t.Errorf("data.sql.type = %v, want line", sql["type"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetComponentInputForm_BrowserDynamicInputForm(t *testing.T) {
|
||||
cv := &entity.UserCanvas{
|
||||
ID: "c1",
|
||||
DSL: map[string]any{
|
||||
"components": map[string]any{
|
||||
"Browser:FlatWolvesTry": map[string]any{
|
||||
"obj": map[string]any{
|
||||
"component_name": "Browser",
|
||||
"params": map[string]any{
|
||||
"llm_id": "gpt-4o@OpenAI",
|
||||
"prompts": "{sys.query}",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h := &AgentHandler{loader: &fakeCanvasLoader{canvas: cv}}
|
||||
|
||||
c, w := componentCtx(t, "GET", "/api/v1/agents/c1/components/Browser:FlatWolvesTry/input-form", "")
|
||||
c.Params = gin.Params{
|
||||
{Key: "canvas_id", Value: "c1"},
|
||||
{Key: "component_id", Value: "Browser:FlatWolvesTry"},
|
||||
}
|
||||
h.GetComponentInputForm(c)
|
||||
|
||||
if w.Code != 200 {
|
||||
t.Fatalf("status = %d, want 200; body=%s", w.Code, w.Body.String())
|
||||
}
|
||||
var env struct {
|
||||
Code int `json:"code"`
|
||||
Data map[string]interface{} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &env); err != nil {
|
||||
t.Fatalf("decode: %v (body=%s)", err, w.Body.String())
|
||||
}
|
||||
if env.Code != 0 {
|
||||
t.Fatalf("code = %d, want 0; body=%s", env.Code, w.Body.String())
|
||||
}
|
||||
prompts, ok := env.Data["prompts"].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("data.prompts = %v, want a map", env.Data["prompts"])
|
||||
}
|
||||
if prompts["name"] != "Prompts" {
|
||||
t.Errorf("data.prompts.name = %v, want Prompts", prompts["name"])
|
||||
}
|
||||
if prompts["type"] != "text" {
|
||||
t.Errorf("data.prompts.type = %v, want text", prompts["type"])
|
||||
}
|
||||
uploadSources, ok := env.Data["upload_sources"].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("data.upload_sources = %v, want a map", env.Data["upload_sources"])
|
||||
}
|
||||
if uploadSources["name"] != "Upload sources" {
|
||||
t.Errorf("data.upload_sources.name = %v, want Upload sources", uploadSources["name"])
|
||||
}
|
||||
if uploadSources["type"] != "line" {
|
||||
t.Errorf("data.upload_sources.type = %v, want line", uploadSources["type"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetComponentInputForm_CanvasNotFound(t *testing.T) {
|
||||
h := &AgentHandler{loader: &fakeCanvasLoader{err: dao.ErrUserCanvasNotFound}}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user