Add files via upload

This commit is contained in:
公明
2026-08-15 11:09:28 +08:00
committed by GitHub
parent b935e1f90f
commit 6db0975223
3 changed files with 111 additions and 6 deletions
@@ -64,6 +64,17 @@ func toolCallArgsFromAccumulated(msgs []adk.Message, toolCallID, expectToolName
return map[string]interface{}{} return map[string]interface{}{}
} }
func mustMarshalToolArguments(args map[string]interface{}) string {
if len(args) == 0 {
return "{}"
}
raw, err := json.Marshal(args)
if err != nil {
return "{}"
}
return string(raw)
}
// beginEinoADKFilesystemToolMonitor 在 Eino ADK filesystem 工具开始调用时写入 running 状态。 // beginEinoADKFilesystemToolMonitor 在 Eino ADK filesystem 工具开始调用时写入 running 状态。
func beginEinoADKFilesystemToolMonitor( func beginEinoADKFilesystemToolMonitor(
ctx context.Context, ctx context.Context,
@@ -71,6 +82,7 @@ func beginEinoADKFilesystemToolMonitor(
rec einomcp.ExecutionRecorder, rec einomcp.ExecutionRecorder,
binder *MCPExecutionBinder, binder *MCPExecutionBinder,
toolCallID, toolName string, toolCallID, toolName string,
args map[string]interface{},
) { ) {
if ag == nil || rec == nil { if ag == nil || rec == nil {
return return
@@ -87,7 +99,7 @@ func beginEinoADKFilesystemToolMonitor(
return return
} }
storedName := "eino_fs::" + strings.ToLower(name) storedName := "eino_fs::" + strings.ToLower(name)
id := ag.BeginLocalToolExecution(ctx, storedName, map[string]interface{}{}) id := ag.BeginLocalToolExecution(ctx, storedName, args)
if id == "" { if id == "" {
return return
} }
@@ -108,18 +120,21 @@ func recordEinoADKFilesystemToolMonitor(
msgs []adk.Message, msgs []adk.Message,
resultText string, resultText string,
isErr bool, isErr bool,
) { ) string {
if ag == nil || rec == nil { if ag == nil || rec == nil {
return return ""
} }
name := strings.TrimSpace(toolName) name := strings.TrimSpace(toolName)
if name == "" || strings.EqualFold(name, "execute") { if name == "" || strings.EqualFold(name, "execute") {
return return ""
} }
if !isBuiltinEinoADKFilesystemToolName(name) { if !isBuiltinEinoADKFilesystemToolName(name) {
return return ""
} }
args := toolCallArgsFromAccumulated(msgs, toolCallID, name) args := toolCallArgsFromAccumulated(msgs, toolCallID, name)
if len(args) == 0 && binder != nil {
args = binder.Arguments(toolCallID)
}
storedName := "eino_fs::" + strings.ToLower(name) storedName := "eino_fs::" + strings.ToLower(name)
var invErr error var invErr error
if isErr { if isErr {
@@ -138,4 +153,5 @@ func recordEinoADKFilesystemToolMonitor(
if id != "" && execID == "" { if id != "" && execID == "" {
rec(id, toolCallID) rec(id, toolCallID)
} }
return id
} }
@@ -2,6 +2,7 @@ package multiagent
import ( import (
"context" "context"
"strings"
"testing" "testing"
"cyberstrike-ai/internal/agent" "cyberstrike-ai/internal/agent"
@@ -10,6 +11,7 @@ import (
"cyberstrike-ai/internal/mcp" "cyberstrike-ai/internal/mcp"
"github.com/cloudwego/eino/adk" "github.com/cloudwego/eino/adk"
"github.com/cloudwego/eino/components/tool"
"github.com/cloudwego/eino/schema" "github.com/cloudwego/eino/schema"
"go.uber.org/zap" "go.uber.org/zap"
) )
@@ -26,7 +28,7 @@ func TestEinoADKFilesystemToolMonitorBindsFinishesAndUpdatesDisplayResult(t *tes
recorded = append(recorded, executionID+"|"+toolCallID) recorded = append(recorded, executionID+"|"+toolCallID)
}) })
beginEinoADKFilesystemToolMonitor(ctx, ag, rec, binder, "call-read", "read_file") beginEinoADKFilesystemToolMonitor(ctx, ag, rec, binder, "call-read", "read_file", map[string]interface{}{"path": "/tmp/secret.txt"})
execID := binder.ExecutionID("call-read") execID := binder.ExecutionID("call-read")
if execID == "" { if execID == "" {
t.Fatal("expected begin to bind execution id") t.Fatal("expected begin to bind execution id")
@@ -38,6 +40,9 @@ func TestEinoADKFilesystemToolMonitorBindsFinishesAndUpdatesDisplayResult(t *tes
if len(recorded) != 1 || recorded[0] != execID+"|call-read" { if len(recorded) != 1 || recorded[0] != execID+"|call-read" {
t.Fatalf("recorded begin ids = %#v", recorded) t.Fatalf("recorded begin ids = %#v", recorded)
} }
if got, _ := exec.Arguments["path"].(string); got != "/tmp/secret.txt" {
t.Fatalf("begin execution args = %#v", exec.Arguments)
}
runMessages := newEinoRunMessageAccumulator([]adk.Message{ runMessages := newEinoRunMessageAccumulator([]adk.Message{
&schema.Message{ &schema.Message{
@@ -80,3 +85,86 @@ func TestEinoADKFilesystemToolMonitorBindsFinishesAndUpdatesDisplayResult(t *tes
t.Fatalf("finish should reuse existing execution without recording a second id, got %#v", recorded) t.Fatalf("finish should reuse existing execution without recording a second id, got %#v", recorded)
} }
} }
func TestEinoADKFilesystemToolMonitorSpillsLargeReadFileResultForProgress(t *testing.T) {
t.Parallel()
ctx := context.Background()
logger := zap.NewNop()
server := mcp.NewServer(logger)
server.ConfigureToolResultMaxBytes(400)
server.ConfigureToolResultSpillRoot(t.TempDir())
ag := agent.NewAgent(&config.OpenAIConfig{}, &config.AgentConfig{}, server, nil, logger, 1)
binder := NewMCPExecutionBinder()
rec := einomcp.ExecutionRecorder(func(executionID, toolCallID string) {})
var event map[string]interface{}
runMessages := newEinoRunMessageAccumulator([]adk.Message{
&schema.Message{
Role: schema.Assistant,
ToolCalls: []schema.ToolCall{{
ID: "call-read",
Type: "function",
Function: schema.FunctionCall{
Name: "read_file",
Arguments: `{"path":"/tmp/large.txt"}`,
},
}},
},
})
beginEinoADKFilesystemToolMonitor(ctx, ag, rec, binder, "call-read", "read_file", map[string]interface{}{"path": "/tmp/large.txt"})
emitter := newEinoToolResultProgressEmitter(einoToolResultProgressEmitterConfig{
ConversationID: "conv-1",
RunMessages: runMessages,
FilesystemMonitorAgent: ag,
FilesystemMonitorRecord: rec,
MCPExecutionBinder: binder,
Progress: func(eventType, _ string, data interface{}) {
if eventType == "tool_result" {
event, _ = data.(map[string]interface{})
}
},
})
if !emitter.Emit(ctx, "read_file", strings.Repeat("0123456789", 100), "call-read", false, "lead") {
t.Fatal("expected tool result emit")
}
result, _ := event["result"].(string)
if !strings.Contains(result, "<persisted-output>") || !strings.Contains(result, "Full output saved to:") {
t.Fatalf("large read_file result was not spilled in progress event: %q", result)
}
if len(result) > 400 {
t.Fatalf("progress result exceeded configured max: len=%d text=%q", len(result), result)
}
}
func TestEinoAgenticFilesystemWrapperCapturesArgumentsAndSpillsResult(t *testing.T) {
t.Parallel()
binder := NewMCPExecutionBinder()
mw := &einoAgenticFilesystemToolMiddleware{
TypedChatModelAgentMiddleware: &adk.TypedBaseChatModelAgentMiddleware[*schema.AgenticMessage]{},
conversationID: "conv-1",
toolMaxBytes: 400,
reductionRootDir: t.TempDir(),
binder: binder,
}
endpoint, err := mw.WrapInvokableToolCall(context.Background(), func(ctx context.Context, argumentsInJSON string, opts ...tool.Option) (string, error) {
return strings.Repeat("0123456789", 100), nil
}, &adk.ToolContext{Name: "read_file", CallID: "call-read"})
if err != nil {
t.Fatalf("WrapInvokableToolCall: %v", err)
}
result, err := endpoint(context.Background(), `{"file_path":"/tmp/requirements.txt","limit":2000}`)
if err != nil {
t.Fatalf("endpoint: %v", err)
}
args := binder.Arguments("call-read")
if args["file_path"] != "/tmp/requirements.txt" {
t.Fatalf("captured args = %#v", args)
}
if !strings.Contains(result, "<persisted-output>") || !strings.Contains(result, "Full output saved to:") {
t.Fatalf("expected persisted-output summary, got %q", result)
}
if len(result) > 400 {
t.Fatalf("summary exceeded max bytes: len=%d", len(result))
}
}
@@ -228,6 +228,7 @@ func (d *einoRunEventDrain) markPendingWithMonitor(tc toolCallPendingInfo) {
d.cfg.MCPExecutionBinder, d.cfg.MCPExecutionBinder,
tc.ToolCallID, tc.ToolCallID,
tc.ToolName, tc.ToolName,
tc.Arguments,
) )
} }