Add files via upload

This commit is contained in:
公明
2026-07-10 18:56:33 +08:00
committed by GitHub
parent 1b64f5d8a0
commit 2995847e0e
7 changed files with 88 additions and 8 deletions
+2 -1
View File
@@ -200,6 +200,7 @@ func runEinoADKAgentLoop(ctx context.Context, args *einoADKRunLoopArgs, baseMsgs
markPendingWithMonitor := func(tc toolCallPendingInfo) {
markPending(tc)
beginEinoADKFilesystemToolMonitor(
ctx,
args.FilesystemMonitorAgent,
args.FilesystemMonitorRecord,
args.MCPExecutionBinder,
@@ -342,7 +343,7 @@ func runEinoADKAgentLoop(ctx context.Context, args *einoADKRunLoopArgs, baseMsgs
toolCallID = tid
}
recordPendingExecuteStdoutDup(toolName, content, isErr)
recordEinoADKFilesystemToolMonitor(args.FilesystemMonitorAgent, args.FilesystemMonitorRecord, args.MCPExecutionBinder, toolName, toolCallID, runAccumulatedMsgs, content, isErr)
recordEinoADKFilesystemToolMonitor(ctx, args.FilesystemMonitorAgent, args.FilesystemMonitorRecord, args.MCPExecutionBinder, toolName, toolCallID, runAccumulatedMsgs, content, isErr)
if args.FilesystemMonitorAgent != nil && args.MCPExecutionBinder != nil {
if execID := args.MCPExecutionBinder.ExecutionID(toolCallID); execID != "" {
args.FilesystemMonitorAgent.UpdateMCPExecutionDisplayResult(execID, content)
+4 -3
View File
@@ -1,6 +1,7 @@
package multiagent
import (
"context"
"fmt"
"cyberstrike-ai/internal/agent"
@@ -9,7 +10,7 @@ import (
// newEinoExecuteMonitorCallbacks 在 Eino filesystem execute 开始/结束时写入 MCP 监控库并 recorder(executionId)
// 与 CallTool 路径一致,使监控页能展示「执行中」状态。
func newEinoExecuteMonitorCallbacks(ag *agent.Agent, recorder einomcp.ExecutionRecorder) (
func newEinoExecuteMonitorCallbacks(ctx context.Context, ag *agent.Agent, recorder einomcp.ExecutionRecorder) (
begin func(toolCallID, command string) string,
finish func(executionID, toolCallID, command, stdout string, success bool, invokeErr error),
) {
@@ -18,7 +19,7 @@ func newEinoExecuteMonitorCallbacks(ag *agent.Agent, recorder einomcp.ExecutionR
return ""
}
args := map[string]interface{}{"command": command}
id := ag.BeginLocalToolExecution("execute", args)
id := ag.BeginLocalToolExecution(ctx, "execute", args)
if id != "" && recorder != nil {
recorder(id, toolCallID)
}
@@ -37,7 +38,7 @@ func newEinoExecuteMonitorCallbacks(ag *agent.Agent, recorder einomcp.ExecutionR
}
}
args := map[string]interface{}{"command": command}
id := ag.FinishLocalToolExecution(executionID, "execute", args, stdout, err)
id := ag.FinishLocalToolExecution(ctx, executionID, "execute", args, stdout, err)
if id != "" && recorder != nil && executionID == "" {
recorder(id, toolCallID)
}
@@ -1,6 +1,7 @@
package multiagent
import (
"context"
"encoding/json"
"errors"
"strings"
@@ -65,6 +66,7 @@ func toolCallArgsFromAccumulated(msgs []adk.Message, toolCallID, expectToolName
// beginEinoADKFilesystemToolMonitor 在 Eino ADK filesystem 工具开始调用时写入 running 状态。
func beginEinoADKFilesystemToolMonitor(
ctx context.Context,
ag *agent.Agent,
rec einomcp.ExecutionRecorder,
binder *MCPExecutionBinder,
@@ -85,7 +87,7 @@ func beginEinoADKFilesystemToolMonitor(
return
}
storedName := "eino_fs::" + strings.ToLower(name)
id := ag.BeginLocalToolExecution(storedName, map[string]interface{}{})
id := ag.BeginLocalToolExecution(ctx, storedName, map[string]interface{}{})
if id == "" {
return
}
@@ -97,6 +99,7 @@ func beginEinoADKFilesystemToolMonitor(
// recordEinoADKFilesystemToolMonitor 将 Eino ADK filesystem 中间件工具结果写入 MCP 监控(与 execute / MCP 桥芯片一致)。
func recordEinoADKFilesystemToolMonitor(
ctx context.Context,
ag *agent.Agent,
rec einomcp.ExecutionRecorder,
binder *MCPExecutionBinder,
@@ -131,7 +134,7 @@ func recordEinoADKFilesystemToolMonitor(
if binder != nil {
execID = binder.ExecutionID(toolCallID)
}
id := ag.FinishLocalToolExecution(execID, storedName, args, resultText, invErr)
id := ag.FinishLocalToolExecution(ctx, execID, storedName, args, resultText, invErr)
if id != "" && execID == "" {
rec(id, toolCallID)
}
+2 -1
View File
@@ -82,7 +82,7 @@ func RunEinoSingleChatModelAgent(
}
toolInvokeNotify := einomcp.NewToolInvokeNotifyHolder()
einoExecBegin, einoExecFinish := newEinoExecuteMonitorCallbacks(ag, recorder)
einoExecBegin, einoExecFinish := newEinoExecuteMonitorCallbacks(ctx, ag, recorder)
mainDefs := ag.ToolsForRole(roleTools)
mainTools, err := einomcp.ToolsFromDefinitions(ag, holder, mainDefs, recorder, nil, toolInvokeNotify, einoSingleAgentName)
if err != nil {
@@ -162,6 +162,7 @@ func RunEinoSingleChatModelAgent(
Tools: mainToolsForCfg,
UnknownToolsHandler: einomcp.UnknownToolReminderHandler(),
ToolCallMiddlewares: []compose.ToolMiddleware{
localToolRBACMiddleware(),
hitlToolCallMiddleware(),
softRecoveryToolMiddleware(),
},
@@ -0,0 +1,50 @@
package multiagent
import (
"context"
"strings"
"cyberstrike-ai/internal/authctx"
"github.com/cloudwego/eino/compose"
"github.com/cloudwego/eino/schema"
)
func isLocalPrivilegeTool(name string) bool {
switch strings.ToLower(strings.TrimSpace(name)) {
case "execute", "ls", "read_file", "write_file", "edit_file", "glob", "grep":
return true
default:
return false
}
}
func localToolPermissionDenied(ctx context.Context, name string) bool {
if !isLocalPrivilegeTool(name) {
return false
}
principal, ok := authctx.PrincipalFromContext(ctx)
return !ok || !principal.HasPermission("agent:local-execute")
}
func localToolRBACMiddleware() compose.ToolMiddleware {
denied := "Permission denied: agent:local-execute is required for local filesystem and shell tools."
return compose.ToolMiddleware{
Invokable: func(next compose.InvokableToolEndpoint) compose.InvokableToolEndpoint {
return func(ctx context.Context, input *compose.ToolInput) (*compose.ToolOutput, error) {
if input != nil && localToolPermissionDenied(ctx, input.Name) {
return &compose.ToolOutput{Result: denied}, nil
}
return next(ctx, input)
}
},
Streamable: func(next compose.StreamableToolEndpoint) compose.StreamableToolEndpoint {
return func(ctx context.Context, input *compose.ToolInput) (*compose.StreamToolOutput, error) {
if input != nil && localToolPermissionDenied(ctx, input.Name) {
return &compose.StreamToolOutput{Result: schema.StreamReaderFromArray([]string{denied})}, nil
}
return next(ctx, input)
}
},
}
}
@@ -0,0 +1,22 @@
package multiagent
import (
"context"
"testing"
"cyberstrike-ai/internal/authctx"
)
func TestLocalToolPermissionIsSeparateFromAgentExecution(t *testing.T) {
agentOnly := authctx.WithPrincipal(context.Background(), authctx.NewPrincipal("robot:u1", "robot", "own", map[string]bool{"agent:execute": true}))
if !localToolPermissionDenied(agentOnly, "execute") || !localToolPermissionDenied(agentOnly, "read_file") {
t.Fatal("agent:execute alone authorized local privileged tools")
}
local := authctx.WithPrincipal(context.Background(), authctx.NewPrincipal("u1", "user", "assigned", map[string]bool{"agent:local-execute": true}))
if localToolPermissionDenied(local, "execute") || localToolPermissionDenied(local, "write_file") {
t.Fatal("agent:local-execute was not honored")
}
if localToolPermissionDenied(agentOnly, "record_vulnerability") {
t.Fatal("non-local tool was incorrectly denied")
}
}
+3 -1
View File
@@ -135,7 +135,7 @@ func RunDeepAgent(
mcpIDs = append(mcpIDs, id)
mcpIDsMu.Unlock()
}
einoExecBegin, einoExecFinish := newEinoExecuteMonitorCallbacks(ag, recorder)
einoExecBegin, einoExecFinish := newEinoExecuteMonitorCallbacks(ctx, ag, recorder)
// 与单代理流式一致:在 response_start / response_delta 的 data 中带当前 mcpExecutionIds,供主聊天绑定复制与展示。
snapshotMCPIDs := func() []string {
@@ -279,6 +279,7 @@ func RunDeepAgent(
Tools: subToolsForCfg,
UnknownToolsHandler: einomcp.UnknownToolReminderHandler(),
ToolCallMiddlewares: []compose.ToolMiddleware{
localToolRBACMiddleware(),
hitlToolCallMiddleware(),
softRecoveryToolMiddleware(),
},
@@ -438,6 +439,7 @@ func RunDeepAgent(
Tools: mainToolsForCfg,
UnknownToolsHandler: einomcp.UnknownToolReminderHandler(),
ToolCallMiddlewares: []compose.ToolMiddleware{
localToolRBACMiddleware(),
hitlToolCallMiddleware(),
softRecoveryToolMiddleware(),
},