mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-05 02:18:46 +02:00
Add files via upload
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -315,10 +316,12 @@ func runEinoADKAgentLoop(ctx context.Context, args *einoADKRunLoopArgs, baseMsgs
|
|||||||
if len(preview) > 200 {
|
if len(preview) > 200 {
|
||||||
preview = preview[:200] + "..."
|
preview = preview[:200] + "..."
|
||||||
}
|
}
|
||||||
|
backgroundRunning := isErr && isMCPBackgroundWaitResult(content)
|
||||||
|
displayIsErr := isErr && !backgroundRunning
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"toolName": toolName,
|
"toolName": toolName,
|
||||||
"success": !isErr,
|
"success": !displayIsErr,
|
||||||
"isError": isErr,
|
"isError": displayIsErr,
|
||||||
"result": content,
|
"result": content,
|
||||||
"resultPreview": preview,
|
"resultPreview": preview,
|
||||||
"agentFacing": true, // 与 reduction 后送入 ChatModel 的正文一致,供前端展示
|
"agentFacing": true, // 与 reduction 后送入 ChatModel 的正文一致,供前端展示
|
||||||
@@ -327,6 +330,13 @@ func runEinoADKAgentLoop(ctx context.Context, args *einoADKRunLoopArgs, baseMsgs
|
|||||||
"einoRole": einoRoleTag(agentName),
|
"einoRole": einoRoleTag(agentName),
|
||||||
"source": "eino",
|
"source": "eino",
|
||||||
}
|
}
|
||||||
|
if backgroundRunning {
|
||||||
|
data["status"] = "background_running"
|
||||||
|
data["modelFacingIsError"] = isErr
|
||||||
|
if execID := mcpExecutionIDFromWaitResult(content); execID != "" {
|
||||||
|
data["executionId"] = execID
|
||||||
|
}
|
||||||
|
}
|
||||||
tid := strings.TrimSpace(toolCallID)
|
tid := strings.TrimSpace(toolCallID)
|
||||||
if tid == "" {
|
if tid == "" {
|
||||||
if inferred, ok := popNextPendingForAgent(agentName); ok {
|
if inferred, ok := popNextPendingForAgent(agentName); ok {
|
||||||
@@ -347,8 +357,8 @@ func runEinoADKAgentLoop(ctx context.Context, args *einoADKRunLoopArgs, baseMsgs
|
|||||||
data["toolCallId"] = tid
|
data["toolCallId"] = tid
|
||||||
toolCallID = tid
|
toolCallID = tid
|
||||||
}
|
}
|
||||||
recordPendingExecuteStdoutDup(toolName, content, isErr)
|
recordPendingExecuteStdoutDup(toolName, content, displayIsErr)
|
||||||
recordEinoADKFilesystemToolMonitor(ctx, args.FilesystemMonitorAgent, args.FilesystemMonitorRecord, args.MCPExecutionBinder, toolName, toolCallID, runAccumulatedMsgs, content, isErr)
|
recordEinoADKFilesystemToolMonitor(ctx, args.FilesystemMonitorAgent, args.FilesystemMonitorRecord, args.MCPExecutionBinder, toolName, toolCallID, runAccumulatedMsgs, content, displayIsErr)
|
||||||
if args.FilesystemMonitorAgent != nil && args.MCPExecutionBinder != nil {
|
if args.FilesystemMonitorAgent != nil && args.MCPExecutionBinder != nil {
|
||||||
if execID := args.MCPExecutionBinder.ExecutionID(toolCallID); execID != "" {
|
if execID := args.MCPExecutionBinder.ExecutionID(toolCallID); execID != "" {
|
||||||
args.FilesystemMonitorAgent.UpdateMCPExecutionDisplayResult(execID, content)
|
args.FilesystemMonitorAgent.UpdateMCPExecutionDisplayResult(execID, content)
|
||||||
@@ -1242,6 +1252,40 @@ func einoToolResultIsError(toolName, content string) bool {
|
|||||||
return false
|
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 去掉工具错误前缀,返回展示/持久化正文。
|
// einoToolResultBody 去掉工具错误前缀,返回展示/持久化正文。
|
||||||
func einoToolResultBody(content string) string {
|
func einoToolResultBody(content string) string {
|
||||||
if strings.HasPrefix(content, einomcp.ToolErrorPrefix) {
|
if strings.HasPrefix(content, einomcp.ToolErrorPrefix) {
|
||||||
|
|||||||
@@ -112,3 +112,41 @@ func TestFriendlyEinoExecuteInvokeTail(t *testing.T) {
|
|||||||
t.Fatal("unexpected error should get tail")
|
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))
|
opts = append(opts, schema.WithToolName(tn))
|
||||||
}
|
}
|
||||||
content := h.Content
|
content := h.Content
|
||||||
if !h.ModelFacingTrace {
|
if !h.ModelFacingTrace || (toolContentMax > 0 && len(content) > toolContentMax) {
|
||||||
content = normalizeRestoredToolContent(content, toolContentMax)
|
content = normalizeRestoredToolContent(content, toolContentMax)
|
||||||
}
|
}
|
||||||
raw = append(raw, schema.ToolMessage(content, h.ToolCallID, opts...))
|
raw = append(raw, schema.ToolMessage(content, h.ToolCallID, opts...))
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func TestHistoryToMessagesNormalizesLegacyRawToolOutput(t *testing.T) {
|
|||||||
|
|
||||||
func TestHistoryToMessagesRestoresModelFacingTraceByteForByte(t *testing.T) {
|
func TestHistoryToMessagesRestoresModelFacingTraceByteForByte(t *testing.T) {
|
||||||
mw := &config.MultiAgentEinoMiddlewareConfig{
|
mw := &config.MultiAgentEinoMiddlewareConfig{
|
||||||
ReductionMaxLengthForTrunc: 128,
|
ReductionMaxLengthForTrunc: 4096,
|
||||||
LatestUserMessageMaxRunes: 64,
|
LatestUserMessageMaxRunes: 64,
|
||||||
}
|
}
|
||||||
userContent := strings.Repeat("model-facing-user-", 100)
|
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) {
|
func TestHistoryToMessagesNeverReinjectsRawOversizedUserFallback(t *testing.T) {
|
||||||
appCfg := &config.Config{OpenAI: config.OpenAIConfig{MaxTotalTokens: 10000}}
|
appCfg := &config.Config{OpenAI: config.OpenAIConfig{MaxTotalTokens: 10000}}
|
||||||
mw := &config.MultiAgentEinoMiddlewareConfig{LatestUserMessageMaxRunes: 8000}
|
mw := &config.MultiAgentEinoMiddlewareConfig{LatestUserMessageMaxRunes: 8000}
|
||||||
|
|||||||
Reference in New Issue
Block a user