feat(go-agent): Ported retrieval node, added Keenable web search tool (#16396)

Ported retrieval node, added Keenable web search tool
- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
Zhichang Yu
2026-06-26 22:55:49 +08:00
committed by GitHub
parent 9d18f33296
commit 70546ea406
91 changed files with 5920 additions and 3817 deletions

View File

@@ -447,7 +447,7 @@ func (f *fullFakeAgentService) UpdateAgent(context.Context, string, string, enti
func (f *fullFakeAgentService) DeleteAgent(context.Context, string, string) error {
return nil
}
func (f *fullFakeAgentService) RunAgent(context.Context, string, string, string, string, string) (<-chan canvas.RunEvent, error) {
func (f *fullFakeAgentService) RunAgent(context.Context, string, string, string, string, any) (<-chan canvas.RunEvent, error) {
ch := make(chan canvas.RunEvent)
close(ch)
return ch, nil
@@ -715,7 +715,7 @@ type stubChatRunner struct {
err error
}
func (s *stubChatRunner) RunAgent(_ context.Context, _, _, _, _, _ string) (<-chan canvas.RunEvent, error) {
func (s *stubChatRunner) RunAgent(_ context.Context, _, _, _, _ string, _ any) (<-chan canvas.RunEvent, error) {
if s.err != nil {
return nil, s.err
}
@@ -815,13 +815,61 @@ func TestAgentChatCompletions_DerivesUserInputFromMessages(t *testing.T) {
c.Set("user", &entity.User{ID: "u1"})
c.Set("user_id", "u1")
var captured string
var captured any
runner := &captureChatRunner{captured: &captured}
h := &AgentHandler{chatRunner: runner}
h.AgentChatCompletions(c)
if captured != "from-messages" {
t.Errorf("userInput = %q, want %q (last user message content)", captured, "from-messages")
t.Errorf("userInput = %#v, want %q (last user message content)", captured, "from-messages")
}
}
// TestAgentChatCompletions_DerivesUserInputFromInputs covers the wait-for-user
// resume path used by the front-end: the follow-up submit posts `inputs`
// instead of a top-level `query`. The handler must lift the nested field value
// and pass it through as the resumed user input.
func TestAgentChatCompletions_DerivesUserInputFromInputs(t *testing.T) {
gin.SetMode(gin.TestMode)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest("POST", "/api/v1/agents/chat/completions",
strings.NewReader(`{"agent_id":"a1","session_id":"s1","inputs":{"text":{"name":"text","value":"a b c d e","type":"line"}}}`))
c.Request.Header.Set("Content-Type", "application/json")
c.Set("user", &entity.User{ID: "u1"})
c.Set("user_id", "u1")
var captured any
runner := &captureChatRunner{captured: &captured}
h := &AgentHandler{chatRunner: runner}
h.AgentChatCompletions(c)
if captured != "a b c d e" {
t.Errorf("userInput = %#v, want %q (nested inputs.value)", captured, "a b c d e")
}
}
func TestAgentChatCompletions_DerivesStructuredUserInputFromInputs(t *testing.T) {
gin.SetMode(gin.TestMode)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest("POST", "/api/v1/agents/chat/completions",
strings.NewReader(`{"agent_id":"a1","session_id":"s1","inputs":{"kb":{"name":"KB","value":"da1","type":"line"},"query":{"name":"Query","value":"合同","type":"line"}}}`))
c.Request.Header.Set("Content-Type", "application/json")
c.Set("user", &entity.User{ID: "u1"})
c.Set("user_id", "u1")
var captured any
runner := &captureChatRunner{captured: &captured}
h := &AgentHandler{chatRunner: runner}
h.AgentChatCompletions(c)
got, ok := captured.(map[string]any)
if !ok {
t.Fatalf("userInput type = %T, want map[string]any", captured)
}
if got["kb"] != "da1" || got["query"] != "合同" {
t.Fatalf("userInput = %#v, want kb=da1 query=合同", got)
}
}
@@ -829,10 +877,10 @@ func TestAgentChatCompletions_DerivesUserInputFromMessages(t *testing.T) {
// returns an empty (closed) channel. Used to assert on argument
// derivation without exercising the runner.
type captureChatRunner struct {
captured *string
captured *any
}
func (c *captureChatRunner) RunAgent(_ context.Context, _, _, _, _, userInput string) (<-chan canvas.RunEvent, error) {
func (c *captureChatRunner) RunAgent(_ context.Context, _, _, _, _ string, userInput any) (<-chan canvas.RunEvent, error) {
*c.captured = userInput
ch := make(chan canvas.RunEvent)
close(ch)