mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-07 03:48:44 +08:00
fix(agent): enable single-component debug for Agent in Go backend (#16606)
### Summary This PR fixes two issues that prevented the Agent component's single-component debug/test run from working under the Go backend: 1. **Dynamic input_form generation**: Some components (e.g. `Agent`) do not store a static `input_form` in the DSL. The Go handler now falls back to the runtime component's `GetInputForm()` method, matching Python's `Canvas.get_component_input_form` behavior. This resolves the frontend 102 error: `component has no input_form`. 2. **Tenant ID injection for debug**: Single-component debug runs use a fresh `CanvasState` that previously lacked `tenant_id`. `AgentComponent.Invoke` resolves LLM credentials via the tenant tables, so the debug run failed with `api key is required`. The handler now seeds `state.Sys["tenant_id"]` with the authenticated user's ID, mirroring Python's `@add_tenant_id_to_kwargs` decorator. ### Changes - `internal/handler/agent_component.go`: - Added `componentInputForm` helper that first reads the static `input_form` and, if missing, instantiates the component and calls `GetInputForm()`. - In `DebugComponent`, set `debugState.Sys["tenant_id"] = user.ID` before invoking the component.
This commit is contained in:
@@ -29,7 +29,9 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
@@ -64,7 +66,7 @@ func (h *AgentHandler) GetComponentInputForm(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
form, err := dsl.ExtractComponentInputForm(cv.DSL, componentID)
|
||||
form, err := h.componentInputForm(c.Request.Context(), cv.DSL, componentID, user.ID)
|
||||
if err != nil {
|
||||
mapDSLError(c, componentID, err)
|
||||
return
|
||||
@@ -76,6 +78,41 @@ func (h *AgentHandler) GetComponentInputForm(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// componentInputForm returns the input-form schema for a single component.
|
||||
// It first tries the static input_form stored in the DSL; if the component
|
||||
// does not define one (e.g. Agent components that generate it dynamically),
|
||||
// it instantiates the runtime component and calls its GetInputForm method.
|
||||
// This mirrors Python's Canvas.get_component_input_form which invokes the
|
||||
// component's own get_input_form when the static field is absent.
|
||||
func (h *AgentHandler) componentInputForm(ctx context.Context, dslMap map[string]any, componentID, userID string) (map[string]any, error) {
|
||||
form, err := dsl.ExtractComponentInputForm(dslMap, componentID)
|
||||
if err == nil {
|
||||
return form, nil
|
||||
}
|
||||
if !errors.Is(err, dsl.ErrMissingInputForm) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name, err := dsl.ExtractComponentName(dslMap, componentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params, _ := dsl.ExtractComponentParams(dslMap, componentID)
|
||||
comp, err := runtime.DefaultFactory()(name, params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: component factory: %v", dsl.ErrMalformedDSL, err)
|
||||
}
|
||||
getter, ok := comp.(interface{ GetInputForm() map[string]any })
|
||||
if !ok {
|
||||
return nil, dsl.ErrMissingInputForm
|
||||
}
|
||||
form = getter.GetInputForm()
|
||||
if form == nil {
|
||||
form = map[string]any{}
|
||||
}
|
||||
return form, nil
|
||||
}
|
||||
|
||||
// DebugComponent POST /api/v1/agents/:canvas_id/components/:component_id/debug
|
||||
//
|
||||
// Body shape (python parity): {"params": {"input_name": {"value": ...}, ...}}
|
||||
@@ -166,7 +203,15 @@ func (h *AgentHandler) DebugComponent(c *gin.Context) {
|
||||
// from the request context. We attach a fresh one here so
|
||||
// debug works on a single component without standing up the
|
||||
// full canvas compile.
|
||||
invokeCtx := runtime.WithState(c.Request.Context(), canvas.NewCanvasState("debug-"+componentID, "debug-task"))
|
||||
//
|
||||
// Seed state.Sys["tenant_id"] with the canvas owner so that
|
||||
// components which resolve LLM credentials from the tenant
|
||||
// tables (e.g. AgentComponent) can find the API key in single-
|
||||
// component debug mode. Mirrors Python's @add_tenant_id_to_kwargs
|
||||
// decorator for the debug endpoint.
|
||||
debugState := canvas.NewCanvasState("debug-"+componentID, "debug-task")
|
||||
debugState.Sys["tenant_id"] = user.ID
|
||||
invokeCtx := runtime.WithState(c.Request.Context(), debugState)
|
||||
|
||||
outputs, err := comp.Invoke(invokeCtx, inputs)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user