diff --git a/cmd/picoclaw/internal/onboard/helpers.go b/cmd/picoclaw/internal/onboard/helpers.go index 2294cfa4c..721d74552 100644 --- a/cmd/picoclaw/internal/onboard/helpers.go +++ b/cmd/picoclaw/internal/onboard/helpers.go @@ -146,11 +146,6 @@ func createWorkspaceTemplates(workspace string) { } func copyEmbeddedToTarget(targetDir string) error { - legacyWorkspaceFiles := map[string]struct{}{ - "AGENTS.md": {}, - "IDENTITY.md": {}, - } - // Ensure target directory exists if err := os.MkdirAll(targetDir, 0o755); err != nil { return fmt.Errorf("Failed to create target directory: %w", err) @@ -177,9 +172,6 @@ func copyEmbeddedToTarget(targetDir string) error { if err != nil { return fmt.Errorf("Failed to get relative path for %s: %v\n", path, err) } - if _, skip := legacyWorkspaceFiles[filepath.Base(new_path)]; skip { - return nil - } // Build target file path targetPath := filepath.Join(targetDir, new_path) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 5bb597187..0c79f6daa 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -645,7 +645,11 @@ func (al *AgentLoop) drainBusToSteering(ctx context.Context, activeScope, active if handled, response := al.tryHandlePriorityCommand(ctx, msg); handled { if response != "" { - al.publishResponse(ctx, msg.Channel, msg.ChatID, response) + al.bus.PublishOutbound(ctx, bus.OutboundMessage{ + Channel: msg.Channel, + ChatID: msg.ChatID, + Content: response, + }) } continue } @@ -676,32 +680,20 @@ func (al *AgentLoop) Stop() { al.running.Store(false) } -func (al *AgentLoop) resetMessageToolRound(agent *AgentInstance) { - if agent == nil { - return - } - - if tool, ok := agent.Tools.Get("message"); ok { - if resetter, ok := tool.(interface{ ResetSentInRound() }); ok { - resetter.ResetSentInRound() - } - } -} - func (al *AgentLoop) PublishResponseIfNeeded(ctx context.Context, channel, chatID, response string) { if response == "" { return } alreadySentToSameChat := false - al.GetRegistry().ForEachTool("message", func(tool tools.Tool) { - if alreadySentToSameChat { - return + defaultAgent := al.GetRegistry().GetDefaultAgent() + if defaultAgent != nil { + if tool, ok := defaultAgent.Tools.Get("message"); ok { + if mt, ok := tool.(*tools.MessageTool); ok { + alreadySentToSameChat = mt.HasSentTo(channel, chatID) + } } - if mt, ok := tool.(*tools.MessageTool); ok && mt.HasSentTo(channel, chatID) { - alreadySentToSameChat = true - } - }) + } if alreadySentToSameChat { logger.DebugCF( @@ -712,14 +704,6 @@ func (al *AgentLoop) PublishResponseIfNeeded(ctx context.Context, channel, chatI return } - al.publishResponse(ctx, channel, chatID, response) -} - -func (al *AgentLoop) publishResponse(ctx context.Context, channel, chatID, response string) { - if response == "" { - return - } - al.bus.PublishOutbound(ctx, bus.OutboundMessage{ Channel: channel, ChatID: chatID, @@ -1420,6 +1404,9 @@ func (al *AgentLoop) askSideQuestion( activeSkills..., ) + maxMediaSize := al.GetConfig().Agents.Defaults.GetMaxMediaSize() + messages = resolveMediaRefs(messages, al.mediaStore, maxMediaSize) + activeCandidates, activeModel, usedLight := al.selectCandidates(agent, question, messages) activeProvider := agent.Provider if usedLight && agent.LightProvider != nil { @@ -1511,7 +1498,11 @@ func (al *AgentLoop) processMessage(ctx context.Context, msg bus.InboundMessage) } // Reset message-tool state for this round so we don't skip publishing due to a previous round. - al.resetMessageToolRound(agent) + if tool, ok := agent.Tools.Get("message"); ok { + if resetter, ok := tool.(interface{ ResetSentInRound() }); ok { + resetter.ResetSentInRound() + } + } // Resolve session key from route, while preserving explicit agent-scoped keys. scopeKey := resolveScopeKey(route, msg.SessionKey) @@ -3659,11 +3650,6 @@ func (al *AgentLoop) buildCommandsRuntime(agent *AgentInstance, opts *processOpt rt.ListSkillNames = agent.ContextBuilder.ListSkillNames } rt.AskSideQuestion = func(ctx context.Context, question string) (string, error) { - question = strings.TrimSpace(question) - if question == "" { - return "", fmt.Errorf("Usage: /btw ") - } - return al.askSideQuestion(ctx, agent, opts, question) } rt.GetModelInfo = func() (string, string) { @@ -3810,13 +3796,9 @@ func (al *AgentLoop) tryHandlePriorityCommand(ctx context.Context, msg bus.Inbou SessionKey: resolveScopeKey(route, msg.SessionKey), Channel: msg.Channel, ChatID: msg.ChatID, - MessageID: msg.MessageID, - ReplyToMessageID: inboundMetadata(msg, metadataKeyReplyToMessage), SenderID: msg.SenderID, SenderDisplayName: msg.Sender.DisplayName, - UserMessage: msg.Content, Media: msg.Media, - DefaultResponse: defaultResponse, } response, handled := al.handleCommand(ctx, msg, agent, &opts) diff --git a/pkg/agent/loop_test.go b/pkg/agent/loop_test.go index 4d7c0212e..91558f6ed 100644 --- a/pkg/agent/loop_test.go +++ b/pkg/agent/loop_test.go @@ -300,69 +300,6 @@ func TestProcessMessage_BtwCommandRunsWithoutPersistingHistory(t *testing.T) { } } -func TestPublishResponseIfNeeded_SkipsWhenNonDefaultAgentAlreadySentToChat(t *testing.T) { - tmpDir := t.TempDir() - cfg := &config.Config{ - Agents: config.AgentsConfig{ - Defaults: config.AgentDefaults{ - Workspace: tmpDir, - ModelName: "test-model", - MaxTokens: 4096, - MaxToolIterations: 10, - }, - List: []config.AgentConfig{ - {ID: "main", Default: true}, - {ID: "support"}, - }, - }, - Tools: config.ToolsConfig{ - Message: config.ToolConfig{Enabled: true}, - }, - } - - msgBus := bus.NewMessageBus() - al := NewAgentLoop(cfg, msgBus, &recordingProvider{}) - - supportAgent, ok := al.GetRegistry().GetAgent("support") - if !ok || supportAgent == nil { - t.Fatal("expected support agent") - } - - tool, ok := supportAgent.Tools.Get("message") - if !ok { - t.Fatal("expected message tool on support agent") - } - mt, ok := tool.(*tools.MessageTool) - if !ok { - t.Fatal("expected message tool type") - } - - if result := mt.Execute(context.Background(), map[string]any{ - "channel": "telegram", - "chat_id": "chat-1", - "content": "interim reply", - }); result == nil || result.IsError { - t.Fatalf("message tool setup result = %+v, want successful send", result) - } - - select { - case outbound := <-msgBus.OutboundChan(): - if outbound.Content != "interim reply" { - t.Fatalf("expected setup outbound %q, got %#v", "interim reply", outbound) - } - default: - t.Fatal("expected interim outbound from message tool setup") - } - - al.PublishResponseIfNeeded(context.Background(), "telegram", "chat-1", "final reply") - - select { - case outbound := <-msgBus.OutboundChan(): - t.Fatalf("expected final reply to be suppressed, got outbound %#v", outbound) - default: - } -} - func TestHandleCommand_UseCommandRejectsUnknownSkill(t *testing.T) { tmpDir := t.TempDir() cfg := &config.Config{ diff --git a/pkg/agent/steering.go b/pkg/agent/steering.go index 863badd03..ad6613e8c 100644 --- a/pkg/agent/steering.go +++ b/pkg/agent/steering.go @@ -346,7 +346,11 @@ func (al *AgentLoop) Continue(ctx context.Context, sessionKey, channel, chatID s return "", fmt.Errorf("no agent available for session %q", sessionKey) } - al.resetMessageToolRound(agent) + if tool, ok := agent.Tools.Get("message"); ok { + if resetter, ok := tool.(interface{ ResetSentInRound() }); ok { + resetter.ResetSentInRound() + } + } return al.continueWithSteeringMessages(ctx, agent, sessionKey, channel, chatID, steeringMsgs) }