Files
goclaw/cmd/gateway_delegate.go
T
Duc Nguyenandntduc bb7712a9ff 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>
2026-07-30 14:17:40 +07:00

55 lines
1.8 KiB
Go

package cmd
import (
"context"
"fmt"
"time"
"github.com/google/uuid"
"github.com/nextlevelbuilder/goclaw/internal/agent"
"github.com/nextlevelbuilder/goclaw/internal/bus"
"github.com/nextlevelbuilder/goclaw/internal/sandbox"
"github.com/nextlevelbuilder/goclaw/internal/tools"
)
// buildAgentLinkRunRequest preserves the origin's authorization-bearing
// identity while keeping delegation on its internal delivery channel.
func buildAgentLinkRunRequest(req tools.DelegateRequest, sessionKey string) agent.RunRequest {
return agent.RunRequest{
RunID: uuid.New().String(),
SessionKey: sessionKey,
Message: req.Task,
UserID: req.UserID,
SenderID: req.SenderID,
Role: req.Role,
Channel: "delegate",
ChannelType: req.ChannelType,
ChatID: req.ChatID,
PeerKind: req.PeerKind,
RunKind: "delegate",
DelegationID: req.DelegationID,
ParentAgentID: req.FromAgentKey,
WorkspaceChannel: req.Channel,
WorkspaceChatID: req.ChatID,
DelegateInputsPath: req.DelegateInputsPath,
DelegateOutputsPath: req.DelegateOutputsPath,
}
}
// Agent Link artifacts are published from the exchange manifest. Raw delegate
// media paths point into B's ephemeral workspace and must never cross back to A.
func agentMediaToBusFiles(_ []agent.MediaResult) []bus.MediaFile { return nil }
func releaseDelegationSandbox(ctx context.Context, manager sandbox.Manager, sessionKey string) error {
if manager == nil {
return nil
}
cleanupCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 10*time.Second)
defer cancel()
if err := manager.Release(cleanupCtx, sessionKey); err != nil {
return fmt.Errorf("delegation sandbox release failed")
}
return nil
}