Merge pull request #6 from dimonb/codex/reply-routing-tool
Fix lint issues after reply routing merge
This commit is contained in:
commit
c1718da019
10 changed files with 83 additions and 39 deletions
|
|
@ -896,7 +896,7 @@ func resolveFinalResponse(
|
||||||
if hasDirective {
|
if hasDirective {
|
||||||
directiveMode = strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(directive, "[[reply:"), "]]"))
|
directiveMode = strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(directive, "[[reply:"), "]]"))
|
||||||
}
|
}
|
||||||
directiveStatus := "none"
|
var directiveStatus string
|
||||||
switch {
|
switch {
|
||||||
case !hasDirective:
|
case !hasDirective:
|
||||||
directiveStatus = "none"
|
directiveStatus = "none"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ func TestWriteCompactionSummaryCreatesTimestampedFile(t *testing.T) {
|
||||||
|
|
||||||
workspace := t.TempDir()
|
workspace := t.TempDir()
|
||||||
store := NewMemoryStore(workspace)
|
store := NewMemoryStore(workspace)
|
||||||
timestamp := time.Date(2026, time.March, 8, 14, 5, 9, 0, time.Local)
|
timestamp := time.Date(2026, time.March, 8, 14, 5, 9, 0, time.UTC)
|
||||||
|
|
||||||
path, err := store.WriteCompactionSummary(timestamp, "# Summary\n\nBody")
|
path, err := store.WriteCompactionSummary(timestamp, "# Summary\n\nBody")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -142,12 +142,16 @@ func (m *Manager) preSend(ctx context.Context, name string, msg bus.OutboundMess
|
||||||
if msg.ReplyToMessageID != "" {
|
if msg.ReplyToMessageID != "" {
|
||||||
if deleter, ok := ch.(MessageDeleter); ok {
|
if deleter, ok := ch.(MessageDeleter); ok {
|
||||||
if err := deleter.DeleteMessage(ctx, msg.ChatID, entry.id); err != nil {
|
if err := deleter.DeleteMessage(ctx, msg.ChatID, entry.id); err != nil {
|
||||||
logger.WarnCF("manager", "Failed to delete placeholder before reply-targeted send", map[string]any{
|
logger.WarnCF(
|
||||||
"channel": name,
|
"manager",
|
||||||
"chat_id": msg.ChatID,
|
"Failed to delete placeholder before reply-targeted send",
|
||||||
"placeholder_id": entry.id,
|
map[string]any{
|
||||||
"error": err.Error(),
|
"channel": name,
|
||||||
})
|
"chat_id": msg.ChatID,
|
||||||
|
"placeholder_id": entry.id,
|
||||||
|
"error": err.Error(),
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,6 @@ func TestSendMessageWithID_FallsBackToBusWithoutError(t *testing.T) {
|
||||||
ChatID: "1",
|
ChatID: "1",
|
||||||
Content: "hello",
|
Content: "hello",
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected nil error for async fallback, got %v", err)
|
t.Fatalf("expected nil error for async fallback, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,14 +61,6 @@ func resolveTelegramForumThreadID(isForum bool, messageThreadID int) (int, bool)
|
||||||
return messageThreadID, true
|
return messageThreadID, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t telegramTarget) chatIDString() string {
|
|
||||||
return strconv.FormatInt(t.ChatID, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t telegramTarget) topicChatID() string {
|
|
||||||
return buildTelegramTopicChatID(t.ChatID, t.MessageThreadID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t telegramTarget) messageThreadIDForSend() (int, bool) {
|
func (t telegramTarget) messageThreadIDForSend() (int, bool) {
|
||||||
if t.MessageThreadID <= 0 || t.MessageThreadID == telegramGeneralTopicID {
|
if t.MessageThreadID <= 0 || t.MessageThreadID == telegramGeneralTopicID {
|
||||||
return 0, false
|
return 0, false
|
||||||
|
|
|
||||||
|
|
@ -782,7 +782,12 @@ func parseTelegramMessageIDs(messageID string) ([]int, error) {
|
||||||
return ids, nil
|
return ids, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TelegramChannel) editHTMLChunk(ctx context.Context, chatID int64, messageID int, htmlContent, mdFallback string) error {
|
func (c *TelegramChannel) editHTMLChunk(
|
||||||
|
ctx context.Context,
|
||||||
|
chatID int64,
|
||||||
|
messageID int,
|
||||||
|
htmlContent, mdFallback string,
|
||||||
|
) error {
|
||||||
editMsg := tu.EditMessageText(tu.ID(chatID), messageID, htmlContent)
|
editMsg := tu.EditMessageText(tu.ID(chatID), messageID, htmlContent)
|
||||||
editMsg.ParseMode = telego.ModeHTML
|
editMsg.ParseMode = telego.ModeHTML
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,10 @@ func TestSendMessageWithID_ShortMessage_SingleCall(t *testing.T) {
|
||||||
}
|
}
|
||||||
ch := newTestChannel(t, caller)
|
ch := newTestChannel(t, caller)
|
||||||
|
|
||||||
msgID, err := ch.SendMessageWithID(context.Background(), bus.OutboundMessage{ChatID: "12345", Content: "Hello, world!"})
|
msgID, err := ch.SendMessageWithID(context.Background(), bus.OutboundMessage{
|
||||||
|
ChatID: "12345",
|
||||||
|
Content: "Hello, world!",
|
||||||
|
})
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "1", msgID)
|
assert.Equal(t, "1", msgID)
|
||||||
|
|
@ -253,7 +256,10 @@ func TestSendMessageWithID_HTMLFallback_PerChunk(t *testing.T) {
|
||||||
}
|
}
|
||||||
ch := newTestChannel(t, caller)
|
ch := newTestChannel(t, caller)
|
||||||
|
|
||||||
msgID, err := ch.SendMessageWithID(context.Background(), bus.OutboundMessage{ChatID: "12345", Content: "Hello **world**"})
|
msgID, err := ch.SendMessageWithID(
|
||||||
|
context.Background(),
|
||||||
|
bus.OutboundMessage{ChatID: "12345", Content: "Hello **world**"},
|
||||||
|
)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "1", msgID)
|
assert.Equal(t, "1", msgID)
|
||||||
|
|
@ -306,10 +312,18 @@ func TestSendMessageWithID_MarkdownShortButHTMLLong_MultipleCalls(t *testing.T)
|
||||||
markdownContent := strings.Repeat("**a** ", 600)
|
markdownContent := strings.Repeat("**a** ", 600)
|
||||||
assert.LessOrEqual(t, len([]rune(markdownContent)), 4000)
|
assert.LessOrEqual(t, len([]rune(markdownContent)), 4000)
|
||||||
|
|
||||||
msgID, err := ch.SendMessageWithID(context.Background(), bus.OutboundMessage{ChatID: "12345", Content: markdownContent})
|
msgID, err := ch.SendMessageWithID(
|
||||||
|
context.Background(),
|
||||||
|
bus.OutboundMessage{ChatID: "12345", Content: markdownContent},
|
||||||
|
)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Greater(t, len(caller.calls), 1, "markdown-short but HTML-long message should be split into multiple SendMessage calls")
|
assert.Greater(
|
||||||
|
t,
|
||||||
|
len(caller.calls),
|
||||||
|
1,
|
||||||
|
"markdown-short but HTML-long message should be split into multiple SendMessage calls",
|
||||||
|
)
|
||||||
assert.Equal(t, "1,2", msgID)
|
assert.Equal(t, "1,2", msgID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -458,7 +472,10 @@ func TestSendMessageWithID_InvalidChatID(t *testing.T) {
|
||||||
}
|
}
|
||||||
ch := newTestChannel(t, caller)
|
ch := newTestChannel(t, caller)
|
||||||
|
|
||||||
msgID, err := ch.SendMessageWithID(context.Background(), bus.OutboundMessage{ChatID: "not-a-number", Content: "Hello"})
|
msgID, err := ch.SendMessageWithID(
|
||||||
|
context.Background(),
|
||||||
|
bus.OutboundMessage{ChatID: "not-a-number", Content: "Hello"},
|
||||||
|
)
|
||||||
|
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Empty(t, msgID)
|
assert.Empty(t, msgID)
|
||||||
|
|
|
||||||
|
|
@ -703,8 +703,8 @@ type ToolsConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type TaskToolConfig struct {
|
type TaskToolConfig struct {
|
||||||
ToolConfig `envPrefix:"PICOCLAW_TOOLS_TASK_TOOL_"`
|
ToolConfig ` envPrefix:"PICOCLAW_TOOLS_TASK_TOOL_"`
|
||||||
Icons TaskToolIconsConfig `json:"icons"`
|
Icons TaskToolIconsConfig ` json:"icons"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TaskToolIconsConfig struct {
|
type TaskToolIconsConfig struct {
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,10 @@ func (t *MessageTool) Execute(ctx context.Context, args map[string]any) *ToolRes
|
||||||
|
|
||||||
currentChannel := ToolChannel(ctx)
|
currentChannel := ToolChannel(ctx)
|
||||||
currentChatID := ToolChatID(ctx)
|
currentChatID := ToolChatID(ctx)
|
||||||
|
sameTarget := currentChannel != "" &&
|
||||||
|
currentChatID != "" &&
|
||||||
|
channel == currentChannel &&
|
||||||
|
chatID == currentChatID
|
||||||
replyMode, _ := args["reply_mode"].(string)
|
replyMode, _ := args["reply_mode"].(string)
|
||||||
replyMode = strings.ToLower(strings.TrimSpace(replyMode))
|
replyMode = strings.ToLower(strings.TrimSpace(replyMode))
|
||||||
explicitReplyTo, _ := args["reply_to_message_id"].(string)
|
explicitReplyTo, _ := args["reply_to_message_id"].(string)
|
||||||
|
|
@ -106,7 +110,7 @@ func (t *MessageTool) Execute(ctx context.Context, args map[string]any) *ToolRes
|
||||||
"reply_to_message_id": explicitReplyTo,
|
"reply_to_message_id": explicitReplyTo,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if currentChannel != "" && currentChatID != "" && channel == currentChannel && chatID == currentChatID {
|
if sameTarget {
|
||||||
logger.InfoCF("tool", "Message tool targeting current conversation", map[string]any{
|
logger.InfoCF("tool", "Message tool targeting current conversation", map[string]any{
|
||||||
"channel": channel,
|
"channel": channel,
|
||||||
"chat_id": chatID,
|
"chat_id": chatID,
|
||||||
|
|
@ -150,7 +154,7 @@ func (t *MessageTool) Execute(ctx context.Context, args map[string]any) *ToolRes
|
||||||
"chat_id": chatID,
|
"chat_id": chatID,
|
||||||
"content_len": len(content),
|
"content_len": len(content),
|
||||||
"reply_to_message_id": replyToMessageID,
|
"reply_to_message_id": replyToMessageID,
|
||||||
"same_target": currentChannel != "" && currentChatID != "" && channel == currentChannel && chatID == currentChatID,
|
"same_target": sameTarget,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Silent: user already received the message directly
|
// Silent: user already received the message directly
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ type TaskTool struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTaskTool(taskManager *session.TaskManager, icons config.TaskToolIconsConfig) *TaskTool {
|
func NewTaskTool(taskManager *session.TaskManager, icons config.TaskToolIconsConfig) *TaskTool {
|
||||||
|
|
||||||
return &TaskTool{
|
return &TaskTool{
|
||||||
taskManager: taskManager,
|
taskManager: taskManager,
|
||||||
icons: icons,
|
icons: icons,
|
||||||
|
|
@ -130,15 +129,22 @@ func (t *TaskTool) Execute(ctx context.Context, args map[string]any) *ToolResult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TaskTool) handleCreatePlan(ctx context.Context, sessionKey, channel, chatID string, args map[string]any) *ToolResult {
|
func (t *TaskTool) handleCreatePlan(
|
||||||
tasksRaw, ok := args["tasks"].([]interface{})
|
ctx context.Context,
|
||||||
|
sessionKey, channel, chatID string,
|
||||||
|
args map[string]any,
|
||||||
|
) *ToolResult {
|
||||||
|
tasksRaw, ok := args["tasks"].([]any)
|
||||||
if !ok || len(tasksRaw) == 0 {
|
if !ok || len(tasksRaw) == 0 {
|
||||||
return &ToolResult{ForLLM: "tasktool: tasks array is required and cannot be empty for 'create_plan'", IsError: true}
|
return &ToolResult{
|
||||||
|
ForLLM: "tasktool: tasks array is required and cannot be empty for 'create_plan'",
|
||||||
|
IsError: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var parsedTasks []session.Task
|
var parsedTasks []session.Task
|
||||||
for i, raw := range tasksRaw {
|
for i, raw := range tasksRaw {
|
||||||
taskMap, ok := raw.(map[string]interface{})
|
taskMap, ok := raw.(map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
return &ToolResult{ForLLM: fmt.Sprintf("tasktool: invalid task at index %d", i), IsError: true}
|
return &ToolResult{ForLLM: fmt.Sprintf("tasktool: invalid task at index %d", i), IsError: true}
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +156,10 @@ func (t *TaskTool) handleCreatePlan(ctx context.Context, sessionKey, channel, ch
|
||||||
|
|
||||||
desc, ok := taskMap["description"].(string)
|
desc, ok := taskMap["description"].(string)
|
||||||
if !ok || desc == "" {
|
if !ok || desc == "" {
|
||||||
return &ToolResult{ForLLM: fmt.Sprintf("tasktool: missing description for task at index %d", i), IsError: true}
|
return &ToolResult{
|
||||||
|
ForLLM: fmt.Sprintf("tasktool: missing description for task at index %d", i),
|
||||||
|
IsError: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedTasks = append(parsedTasks, session.Task{
|
parsedTasks = append(parsedTasks, session.Task{
|
||||||
|
|
@ -236,7 +245,11 @@ func (t *TaskTool) handleResendPlan(ctx context.Context, sessionKey, channel, ch
|
||||||
return t.newPlanResult(summary, content, delivered, deliveryErr)
|
return t.newPlanResult(summary, content, delivered, deliveryErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TaskTool) handleUpdateTask(ctx context.Context, sessionKey, channel, chatID string, args map[string]any) *ToolResult {
|
func (t *TaskTool) handleUpdateTask(
|
||||||
|
ctx context.Context,
|
||||||
|
sessionKey, channel, chatID string,
|
||||||
|
args map[string]any,
|
||||||
|
) *ToolResult {
|
||||||
taskID, _ := args["task_id"].(string)
|
taskID, _ := args["task_id"].(string)
|
||||||
if taskID == "" {
|
if taskID == "" {
|
||||||
return &ToolResult{ForLLM: "tasktool: task_id is required for 'update_task'", IsError: true}
|
return &ToolResult{ForLLM: "tasktool: task_id is required for 'update_task'", IsError: true}
|
||||||
|
|
@ -331,15 +344,25 @@ func (t *TaskTool) newPlanResult(summary, content string, delivered bool, delive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
forLLM := summary
|
|
||||||
if deliveryErr != nil {
|
if deliveryErr != nil {
|
||||||
forLLM = fmt.Sprintf("%s\nAutomatic delivery failed (%v). Respond to the user with the following plan content:\n\n%s", summary, deliveryErr, content)
|
return &ToolResult{
|
||||||
} else {
|
ForLLM: fmt.Sprintf(
|
||||||
forLLM = fmt.Sprintf("%s\nAutomatic delivery is unavailable in this context. Respond to the user with the following plan content:\n\n%s", summary, content)
|
"%s\nAutomatic delivery failed (%v). Respond to the user with the following plan content:\n\n%s",
|
||||||
|
summary,
|
||||||
|
deliveryErr,
|
||||||
|
content,
|
||||||
|
),
|
||||||
|
ForUser: content,
|
||||||
|
Silent: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ToolResult{
|
return &ToolResult{
|
||||||
ForLLM: forLLM,
|
ForLLM: fmt.Sprintf(
|
||||||
|
"%s\nAutomatic delivery is unavailable in this context. Respond to the user with the following plan content:\n\n%s",
|
||||||
|
summary,
|
||||||
|
content,
|
||||||
|
),
|
||||||
ForUser: content,
|
ForUser: content,
|
||||||
Silent: false,
|
Silent: false,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue