Files
goclaw/internal/tools/sessions_send.go
T
viettranx bdb60de7ae chore: upgrade Go 1.25 → 1.26 and apply go fix modernizations
- 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
2026-03-10 00:09:15 +07:00

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()
}