mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-01 16:38:48 +02:00
Add files via upload
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -315,10 +316,12 @@ func runEinoADKAgentLoop(ctx context.Context, args *einoADKRunLoopArgs, baseMsgs
|
||||
if len(preview) > 200 {
|
||||
preview = preview[:200] + "..."
|
||||
}
|
||||
backgroundRunning := isErr && isMCPBackgroundWaitResult(content)
|
||||
displayIsErr := isErr && !backgroundRunning
|
||||
data := map[string]interface{}{
|
||||
"toolName": toolName,
|
||||
"success": !isErr,
|
||||
"isError": isErr,
|
||||
"success": !displayIsErr,
|
||||
"isError": displayIsErr,
|
||||
"result": content,
|
||||
"resultPreview": preview,
|
||||
"agentFacing": true, // 与 reduction 后送入 ChatModel 的正文一致,供前端展示
|
||||
@@ -327,6 +330,13 @@ func runEinoADKAgentLoop(ctx context.Context, args *einoADKRunLoopArgs, baseMsgs
|
||||
"einoRole": einoRoleTag(agentName),
|
||||
"source": "eino",
|
||||
}
|
||||
if backgroundRunning {
|
||||
data["status"] = "background_running"
|
||||
data["modelFacingIsError"] = isErr
|
||||
if execID := mcpExecutionIDFromWaitResult(content); execID != "" {
|
||||
data["executionId"] = execID
|
||||
}
|
||||
}
|
||||
tid := strings.TrimSpace(toolCallID)
|
||||
if tid == "" {
|
||||
if inferred, ok := popNextPendingForAgent(agentName); ok {
|
||||
@@ -347,8 +357,8 @@ func runEinoADKAgentLoop(ctx context.Context, args *einoADKRunLoopArgs, baseMsgs
|
||||
data["toolCallId"] = tid
|
||||
toolCallID = tid
|
||||
}
|
||||
recordPendingExecuteStdoutDup(toolName, content, isErr)
|
||||
recordEinoADKFilesystemToolMonitor(ctx, args.FilesystemMonitorAgent, args.FilesystemMonitorRecord, args.MCPExecutionBinder, toolName, toolCallID, runAccumulatedMsgs, content, isErr)
|
||||
recordPendingExecuteStdoutDup(toolName, content, displayIsErr)
|
||||
recordEinoADKFilesystemToolMonitor(ctx, args.FilesystemMonitorAgent, args.FilesystemMonitorRecord, args.MCPExecutionBinder, toolName, toolCallID, runAccumulatedMsgs, content, displayIsErr)
|
||||
if args.FilesystemMonitorAgent != nil && args.MCPExecutionBinder != nil {
|
||||
if execID := args.MCPExecutionBinder.ExecutionID(toolCallID); execID != "" {
|
||||
args.FilesystemMonitorAgent.UpdateMCPExecutionDisplayResult(execID, content)
|
||||
@@ -1242,6 +1252,40 @@ func einoToolResultIsError(toolName, content string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func isMCPBackgroundWaitResult(content string) bool {
|
||||
text := strings.ToLower(strings.TrimSpace(content))
|
||||
if text == "" {
|
||||
return false
|
||||
}
|
||||
hasExecutionID := strings.Contains(text, "execution_id:") || strings.Contains(text, `"execution_id"`)
|
||||
hasRunningStatus := strings.Contains(text, "status: running") || strings.Contains(text, "status: queued") ||
|
||||
strings.Contains(text, `"status": "running"`) || strings.Contains(text, `"status":"running"`) ||
|
||||
strings.Contains(text, `"status": "queued"`) || strings.Contains(text, `"status":"queued"`)
|
||||
hasSoftWaitSignal := strings.Contains(text, "工具已提交到后台执行") ||
|
||||
strings.Contains(text, "本次等待已到达") ||
|
||||
strings.Contains(text, "wait_timeout:") ||
|
||||
strings.Contains(text, "background execution") ||
|
||||
strings.Contains(text, "still running") ||
|
||||
strings.Contains(text, "仍未完成")
|
||||
return hasExecutionID && hasRunningStatus && hasSoftWaitSignal
|
||||
}
|
||||
|
||||
func mcpExecutionIDFromWaitResult(content string) string {
|
||||
re := regexp.MustCompile(`(?i)"?execution_id"?\s*[:=]\s*"?([0-9a-f]{8}-[0-9a-f-]{12,})"?`)
|
||||
if m := re.FindStringSubmatch(content); len(m) > 1 {
|
||||
return strings.TrimSpace(m[1])
|
||||
}
|
||||
for _, line := range strings.Split(content, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
lower := strings.ToLower(line)
|
||||
if !strings.HasPrefix(lower, "execution_id:") {
|
||||
continue
|
||||
}
|
||||
return strings.Trim(strings.TrimSpace(line[len("execution_id:"):]), `"'`)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// einoToolResultBody 去掉工具错误前缀,返回展示/持久化正文。
|
||||
func einoToolResultBody(content string) string {
|
||||
if strings.HasPrefix(content, einomcp.ToolErrorPrefix) {
|
||||
|
||||
@@ -112,3 +112,41 @@ func TestFriendlyEinoExecuteInvokeTail(t *testing.T) {
|
||||
t.Fatal("unexpected error should get tail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCPBackgroundWaitResultIsDisplayRunning(t *testing.T) {
|
||||
body := `工具已提交到后台执行,但本次等待已到达上限。
|
||||
|
||||
execution_id: 3eaaa391-050b-4be1-a870-48a855923cb7
|
||||
tool: exec
|
||||
status: running
|
||||
wait_timeout: 10s
|
||||
elapsed: 10s
|
||||
|
||||
你可以继续推理、改用其他工具,或调用 wait_tool_execution 继续等待该 execution_id;也可以调用 cancel_tool_execution 取消。`
|
||||
modelFacing := einomcp.ToolErrorPrefix + body
|
||||
if !einoToolResultIsError("exec", modelFacing) {
|
||||
t.Fatal("soft wait timeout must remain model-facing tool error")
|
||||
}
|
||||
if !isMCPBackgroundWaitResult(einoToolResultBody(modelFacing)) {
|
||||
t.Fatal("soft wait timeout should display as background running")
|
||||
}
|
||||
if got := mcpExecutionIDFromWaitResult(einoToolResultBody(modelFacing)); got != "3eaaa391-050b-4be1-a870-48a855923cb7" {
|
||||
t.Fatalf("execution id = %q", got)
|
||||
}
|
||||
if isMCPBackgroundWaitResult("execution_id: abc\nstatus: failed\nerror: boom") {
|
||||
t.Fatal("real failures must not display as background running")
|
||||
}
|
||||
jsonBody := `{
|
||||
"execution_id": "e98baefc-72eb-4a7e-9091-9be179a75d71",
|
||||
"tool": "exec",
|
||||
"status": "running"
|
||||
}
|
||||
|
||||
本次等待已到达 timeout_seconds,上述 execution 仍未完成。可继续等待、取消,或采用其他步骤。`
|
||||
if !isMCPBackgroundWaitResult(jsonBody) {
|
||||
t.Fatal("json wait_tool_execution timeout should display as background running")
|
||||
}
|
||||
if got := mcpExecutionIDFromWaitResult(jsonBody); got != "e98baefc-72eb-4a7e-9091-9be179a75d71" {
|
||||
t.Fatalf("json execution id = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -715,7 +715,7 @@ func historyToMessages(history []agent.ChatMessage, appCfg *config.Config, mwCfg
|
||||
opts = append(opts, schema.WithToolName(tn))
|
||||
}
|
||||
content := h.Content
|
||||
if !h.ModelFacingTrace {
|
||||
if !h.ModelFacingTrace || (toolContentMax > 0 && len(content) > toolContentMax) {
|
||||
content = normalizeRestoredToolContent(content, toolContentMax)
|
||||
}
|
||||
raw = append(raw, schema.ToolMessage(content, h.ToolCallID, opts...))
|
||||
|
||||
@@ -44,7 +44,7 @@ func TestHistoryToMessagesNormalizesLegacyRawToolOutput(t *testing.T) {
|
||||
|
||||
func TestHistoryToMessagesRestoresModelFacingTraceByteForByte(t *testing.T) {
|
||||
mw := &config.MultiAgentEinoMiddlewareConfig{
|
||||
ReductionMaxLengthForTrunc: 128,
|
||||
ReductionMaxLengthForTrunc: 4096,
|
||||
LatestUserMessageMaxRunes: 64,
|
||||
}
|
||||
userContent := strings.Repeat("model-facing-user-", 100)
|
||||
@@ -66,6 +66,24 @@ func TestHistoryToMessagesRestoresModelFacingTraceByteForByte(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHistoryToMessagesCapsOversizedModelFacingToolTrace(t *testing.T) {
|
||||
mw := &config.MultiAgentEinoMiddlewareConfig{ReductionMaxLengthForTrunc: 128}
|
||||
h := []agent.ChatMessage{
|
||||
{Role: "assistant", ModelFacingTrace: true, ToolCalls: []agent.ToolCall{{ID: "t1", Type: "function", Function: agent.FunctionCall{Name: "exec"}}}},
|
||||
{Role: "tool", ToolCallID: "t1", ToolName: "exec", Content: strings.Repeat("model-facing-tool-", 1000), ModelFacingTrace: true},
|
||||
}
|
||||
msgs := historyToMessages(h, nil, mw)
|
||||
if len(msgs) != 2 {
|
||||
t.Fatalf("len=%d", len(msgs))
|
||||
}
|
||||
if len(msgs[1].Content) > 128 {
|
||||
t.Fatalf("restored model-facing tool bytes=%d, want <=128", len(msgs[1].Content))
|
||||
}
|
||||
if !strings.Contains(msgs[1].Content, "legacy tool output discarded") {
|
||||
t.Fatalf("missing cap marker: %q", msgs[1].Content)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHistoryToMessagesNeverReinjectsRawOversizedUserFallback(t *testing.T) {
|
||||
appCfg := &config.Config{OpenAI: config.OpenAIConfig{MaxTotalTokens: 10000}}
|
||||
mw := &config.MultiAgentEinoMiddlewareConfig{LatestUserMessageMaxRunes: 8000}
|
||||
|
||||
Reference in New Issue
Block a user