mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-14 14:17:40 +00:00
fix(collaboration): harden delegated task isolation (#1486)
* feat(collaboration): isolate delegated artifacts and child runs Isolate delegated inputs and outputs behind secure artifact exchange lifecycles. Scope Agent Link tasks by tenant and root agent, and enforce delegation spawn-tree boundaries. Add process-wide child-run admission and preserve logical media paths across native, MCP, and sandbox execution. * fix(collaboration): harden delegated task isolation Enforce tenant and root-agent task scope across migrations and stores. Add exactly-once async completion delivery, delegated sandbox boundaries, and confined artifact and media recovery across runtime surfaces. * fix(collaboration): recover interrupted async tasks * fix(collaboration): normalize persisted child-run status --------- Co-authored-by: ntduc <ntduc@cpp.ai.vn>
This commit is contained in:
1 parent
496b7ffce6
commit
bb7712a9ff
186 files changed
+18858
-1233
No files matched your search
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/nextlevelbuilder/goclaw/internal/i18n"
|
||||
"github.com/nextlevelbuilder/goclaw/internal/providers"
|
||||
"github.com/nextlevelbuilder/goclaw/internal/store"
|
||||
"github.com/nextlevelbuilder/goclaw/internal/tools"
|
||||
)
|
||||
|
||||
// isUserFilePopulated checks if USER.md has been filled with actual user data
|
||||
@@ -48,7 +47,7 @@ func (l *Loop) finalizeRun(
|
||||
// BEFORE sanitize strips them. Covers cases where a tool returned its
|
||||
// artifact via the ForLLM MEDIA: prefix but the agent relayed it as plain
|
||||
// text (e.g. PDF from exec/weasyprint, TTS mp3 paths the LLM quotes back).
|
||||
if extracted := extractMediaFromContent(rs.finalContent, tools.ToolWorkspaceFromCtx(ctx)); len(extracted) > 0 {
|
||||
if extracted := extractMediaFromContent(rs.finalContent, l.mediaEgressRoots(ctx)); len(extracted) > 0 {
|
||||
rs.mediaResults = append(rs.mediaResults, extracted...)
|
||||
}
|
||||
|
||||
@@ -67,8 +66,12 @@ func (l *Loop) finalizeRun(
|
||||
rs.finalContent += "\n\n---\n_" + i18n.T(locale, i18n.MsgSkillNudgePostscript) + "_"
|
||||
}
|
||||
|
||||
// 7. Fallback for empty content
|
||||
if rs.finalContent == "" {
|
||||
// 7. Fallback only when there is no other deliverable output. Media-only
|
||||
// runs must remain media-only instead of gaining a visible "..." caption.
|
||||
hasDeliverableOutput := len(rs.mediaResults) > 0 ||
|
||||
len(req.ForwardMedia) > 0 ||
|
||||
req.ContentSuffix != ""
|
||||
if rs.finalContent == "" && !hasDeliverableOutput {
|
||||
if len(rs.asyncToolCalls) > 0 {
|
||||
rs.finalContent = "..."
|
||||
} else {
|
||||
@@ -200,6 +203,9 @@ func (l *Loop) finalizeRun(
|
||||
slog.Info("agent loop: NO_REPLY detected, suppressing delivery",
|
||||
"agent", l.id, "session", req.SessionKey)
|
||||
rs.finalContent = ""
|
||||
if req.ContentSuffix != "" {
|
||||
rs.finalContent = deduplicateMediaSuffix("", req.ContentSuffix)
|
||||
}
|
||||
}
|
||||
|
||||
// 9. Maybe summarize
|
||||
|
||||
Reference in new issue
Block a user