mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-07-06 12:37:56 +02:00
Add files via upload
This commit is contained in:
@@ -44,11 +44,20 @@ func (h *AgentHandler) MultiAgentLoopStream(c *gin.Context) {
|
|||||||
|
|
||||||
c.Header("X-Accel-Buffering", "no")
|
c.Header("X-Accel-Buffering", "no")
|
||||||
|
|
||||||
|
// 用于在 sendEvent 中判断是否为用户主动停止导致的取消。
|
||||||
|
// 注意:baseCtx 会在后面创建;该变量用于闭包提前捕获引用。
|
||||||
|
var baseCtx context.Context
|
||||||
|
|
||||||
clientDisconnected := false
|
clientDisconnected := false
|
||||||
sendEvent := func(eventType, message string, data interface{}) {
|
sendEvent := func(eventType, message string, data interface{}) {
|
||||||
if clientDisconnected {
|
if clientDisconnected {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 用户主动停止时,Eino 可能仍会并发上报 eventType=="error"。
|
||||||
|
// 为避免 UI 看到“取消错误 + cancelled 文案”两条回复,这里直接丢弃取消对应的 error。
|
||||||
|
if eventType == "error" && baseCtx != nil && errors.Is(context.Cause(baseCtx), ErrTaskCancelled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
select {
|
select {
|
||||||
case <-c.Request.Context().Done():
|
case <-c.Request.Context().Done():
|
||||||
clientDisconnected = true
|
clientDisconnected = true
|
||||||
@@ -135,7 +144,6 @@ func (h *AgentHandler) MultiAgentLoopStream(c *gin.Context) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
h.logger.Error("Eino DeepAgent 执行失败", zap.Error(runErr))
|
|
||||||
cause := context.Cause(baseCtx)
|
cause := context.Cause(baseCtx)
|
||||||
if errors.Is(cause, ErrTaskCancelled) {
|
if errors.Is(cause, ErrTaskCancelled) {
|
||||||
taskStatus = "cancelled"
|
taskStatus = "cancelled"
|
||||||
@@ -153,6 +161,7 @@ func (h *AgentHandler) MultiAgentLoopStream(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h.logger.Error("Eino DeepAgent 执行失败", zap.Error(runErr))
|
||||||
taskStatus = "failed"
|
taskStatus = "failed"
|
||||||
h.tasks.UpdateTaskStatus(conversationID, taskStatus)
|
h.tasks.UpdateTaskStatus(conversationID, taskStatus)
|
||||||
errMsg := "执行失败: " + runErr.Error()
|
errMsg := "执行失败: " + runErr.Error()
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package multiagent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/cloudwego/eino/adk"
|
||||||
|
"github.com/cloudwego/eino/components/tool"
|
||||||
|
)
|
||||||
|
|
||||||
|
// noNestedTaskMiddleware 禁止在已经处于 task(sub-agent) 执行链中再次调用 task,
|
||||||
|
// 避免子代理再次委派子代理造成的无限委派/递归。
|
||||||
|
//
|
||||||
|
// 通过在 ctx 中设置临时标记来实现嵌套检测:外层 task 调用会先标记 ctx,
|
||||||
|
// 子代理内再调用 task 时会命中该标记并拒绝。
|
||||||
|
type noNestedTaskMiddleware struct {
|
||||||
|
adk.BaseChatModelAgentMiddleware
|
||||||
|
}
|
||||||
|
|
||||||
|
type nestedTaskCtxKey struct{}
|
||||||
|
|
||||||
|
func newNoNestedTaskMiddleware() adk.ChatModelAgentMiddleware {
|
||||||
|
return &noNestedTaskMiddleware{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *noNestedTaskMiddleware) WrapInvokableToolCall(
|
||||||
|
ctx context.Context,
|
||||||
|
endpoint adk.InvokableToolCallEndpoint,
|
||||||
|
tCtx *adk.ToolContext,
|
||||||
|
) (adk.InvokableToolCallEndpoint, error) {
|
||||||
|
if tCtx == nil || strings.TrimSpace(tCtx.Name) == "" {
|
||||||
|
return endpoint, nil
|
||||||
|
}
|
||||||
|
// Deep 内置 task 工具名固定为 "task";为兼容可能的大小写/空白,仅做不区分大小写匹配。
|
||||||
|
if !strings.EqualFold(strings.TrimSpace(tCtx.Name), "task") {
|
||||||
|
return endpoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已在 task 执行链中:拒绝继续委派,直接报错让上层快速终止。
|
||||||
|
if ctx != nil {
|
||||||
|
if v, ok := ctx.Value(nestedTaskCtxKey{}).(bool); ok && v {
|
||||||
|
return func(ctx context.Context, argumentsInJSON string, opts ...tool.Option) (string, error) {
|
||||||
|
// Important: return a tool result text (not an error) to avoid hard-stopping the whole multi-agent run.
|
||||||
|
// The nested task is still prevented from spawning another sub-agent, so recursion is avoided.
|
||||||
|
_ = argumentsInJSON
|
||||||
|
_ = opts
|
||||||
|
return "Nested task delegation is forbidden (already inside a sub-agent delegation chain) to avoid infinite delegation. Please continue the work using the current agent's tools.", nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记当前 task 调用链,确保子代理内的再次 task 调用能检测到嵌套。
|
||||||
|
return func(ctx context.Context, argumentsInJSON string, opts ...tool.Option) (string, error) {
|
||||||
|
ctx2 := ctx
|
||||||
|
if ctx2 == nil {
|
||||||
|
ctx2 = context.Background()
|
||||||
|
}
|
||||||
|
ctx2 = context.WithValue(ctx2, nestedTaskCtxKey{}, true)
|
||||||
|
return endpoint(ctx2, argumentsInJSON, opts...)
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
@@ -252,7 +252,11 @@ func RunDeepAgent(
|
|||||||
WithoutGeneralSubAgent: ma.WithoutGeneralSubAgent,
|
WithoutGeneralSubAgent: ma.WithoutGeneralSubAgent,
|
||||||
WithoutWriteTodos: ma.WithoutWriteTodos,
|
WithoutWriteTodos: ma.WithoutWriteTodos,
|
||||||
MaxIteration: deepMaxIter,
|
MaxIteration: deepMaxIter,
|
||||||
Handlers: []adk.ChatModelAgentMiddleware{mainSumMw},
|
// 防止 sub-agent 再调用 task(再委派 sub-agent),形成无限委派链。
|
||||||
|
Handlers: []adk.ChatModelAgentMiddleware{
|
||||||
|
newNoNestedTaskMiddleware(),
|
||||||
|
mainSumMw,
|
||||||
|
},
|
||||||
ToolsConfig: adk.ToolsConfig{
|
ToolsConfig: adk.ToolsConfig{
|
||||||
ToolsNodeConfig: compose.ToolsNodeConfig{
|
ToolsNodeConfig: compose.ToolsNodeConfig{
|
||||||
Tools: mainTools,
|
Tools: mainTools,
|
||||||
|
|||||||
Reference in New Issue
Block a user