mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-06-10 10:10:49 +00:00
bdb60de7ae
- Update go.mod and Dockerfile to Go 1.26 - Apply `go fix ./...` stdlib modernizations across 170+ files - Add `go fix` to post-implementation checklist in CLAUDE.md - Fix go fix misapplied rewrite in loop_history.go
117 lines
3.2 KiB
Go
117 lines
3.2 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/bus"
|
|
"github.com/nextlevelbuilder/goclaw/internal/store"
|
|
)
|
|
|
|
// ============================================================
|
|
// sessions_send
|
|
// ============================================================
|
|
|
|
type SessionsSendTool struct {
|
|
sessions store.SessionStore
|
|
msgBus *bus.MessageBus
|
|
}
|
|
|
|
func NewSessionsSendTool() *SessionsSendTool { return &SessionsSendTool{} }
|
|
|
|
func (t *SessionsSendTool) SetSessionStore(s store.SessionStore) { t.sessions = s }
|
|
func (t *SessionsSendTool) SetMessageBus(b *bus.MessageBus) { t.msgBus = b }
|
|
|
|
func (t *SessionsSendTool) Name() string { return "sessions_send" }
|
|
func (t *SessionsSendTool) Description() string {
|
|
return "Send a message into another session. Use session_key or label to identify the target."
|
|
}
|
|
|
|
func (t *SessionsSendTool) Parameters() map[string]any {
|
|
return map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"session_key": map[string]any{
|
|
"type": "string",
|
|
"description": "Target session key",
|
|
},
|
|
"label": map[string]any{
|
|
"type": "string",
|
|
"description": "Target session label (alternative to session_key)",
|
|
},
|
|
"message": map[string]any{
|
|
"type": "string",
|
|
"description": "Message to send",
|
|
},
|
|
},
|
|
"required": []string{"message"},
|
|
}
|
|
}
|
|
|
|
func (t *SessionsSendTool) Execute(ctx context.Context, args map[string]any) *Result {
|
|
if t.sessions == nil {
|
|
return ErrorResult("session store not available")
|
|
}
|
|
if t.msgBus == nil {
|
|
return ErrorResult("message bus not available")
|
|
}
|
|
|
|
sessionKey, _ := args["session_key"].(string)
|
|
label, _ := args["label"].(string)
|
|
message, _ := args["message"].(string)
|
|
|
|
if message == "" {
|
|
return ErrorResult("message is required")
|
|
}
|
|
if sessionKey == "" && label == "" {
|
|
return ErrorResult("either session_key or label is required")
|
|
}
|
|
|
|
agentID := resolveAgentIDString(ctx)
|
|
|
|
// Resolve by label if needed
|
|
if sessionKey == "" && label != "" {
|
|
sessions := t.sessions.List(agentID)
|
|
for _, s := range sessions {
|
|
// Check if label matches by loading session data
|
|
data := t.sessions.GetOrCreate(s.Key)
|
|
if data.Label == label {
|
|
sessionKey = s.Key
|
|
break
|
|
}
|
|
}
|
|
if sessionKey == "" {
|
|
return ErrorResult(fmt.Sprintf("no session found with label: %s", label))
|
|
}
|
|
}
|
|
|
|
// Security: validate target session belongs to same agent
|
|
if agentID != "" && !strings.HasPrefix(sessionKey, "agent:"+agentID+":") {
|
|
return ErrorResult("access denied: target session belongs to a different agent")
|
|
}
|
|
|
|
// Publish as an inbound message (same mechanism as channels)
|
|
t.msgBus.PublishInbound(bus.InboundMessage{
|
|
Channel: "system",
|
|
SenderID: "session_send_tool",
|
|
ChatID: sessionKey,
|
|
Content: message,
|
|
PeerKind: "direct",
|
|
})
|
|
|
|
return SilentResult(fmt.Sprintf(`{"status":"accepted","session_key":"%s"}`, sessionKey))
|
|
}
|
|
|
|
// ============================================================
|
|
// helpers
|
|
// ============================================================
|
|
|
|
func resolveAgentIDString(ctx context.Context) string {
|
|
id := store.AgentIDFromContext(ctx)
|
|
if id.String() == "00000000-0000-0000-0000-000000000000" {
|
|
return "" // no agent ID in context
|
|
}
|
|
return id.String()
|
|
}
|