Unified Agent + reusable Go agent core.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: remove maep support from bus and todo

Lyric 47973337 a06501ce

+52 -41
+1 -1
contacts/bus_state.go
··· 45 45 func normalizeBusChannel(channel string) (string, error) { 46 46 value := strings.ToLower(strings.TrimSpace(channel)) 47 47 switch value { 48 - case channels.Telegram, channels.MAEP, channels.Slack, channels.Discord: 48 + case channels.Telegram, channels.Slack, channels.Discord: 49 49 return value, nil 50 50 default: 51 51 return "", fmt.Errorf("unsupported bus channel: %q", channel)
+5 -6
contacts/file_store_test.go
··· 99 99 100 100 lastAttemptAt := now.Add(1 * time.Minute) 101 101 if err := store.PutBusOutboxRecord(ctx, BusOutboxRecord{ 102 - Channel: ChannelMAEP, 102 + Channel: ChannelTelegram, 103 103 IdempotencyKey: "manual:k1", 104 - ContactID: "maep:a", 105 - PeerID: "12D3KooWA", 104 + ContactID: "tg:1001", 106 105 ItemID: "item-1", 107 106 ContentType: "text/plain", 108 107 PayloadBase64: "aGVsbG8", ··· 114 113 }); err != nil { 115 114 t.Fatalf("PutBusOutboxRecord() error = %v", err) 116 115 } 117 - outbox, ok, err := store.GetBusOutboxRecord(ctx, ChannelMAEP, "manual:k1") 116 + outbox, ok, err := store.GetBusOutboxRecord(ctx, ChannelTelegram, "manual:k1") 118 117 if err != nil { 119 118 t.Fatalf("GetBusOutboxRecord() error = %v", err) 120 119 } ··· 135 134 } 136 135 if err := os.WriteFile( 137 136 filepath.Join(root, "bus_outbox.json"), 138 - []byte("{\"version\":1,\"records\":[{\"channel\":\"maep\",\"idempotency_key\":\"k\",\"status\":\"sent\",\"attempts\":1,\"created_at\":\"2026-02-08T12:00:00Z\",\"updated_at\":\"2026-02-08T12:00:00Z\",\"sent_at\":\"2026-02-08T12:00:00Z\",\"unknown\":\"x\"}]}\n"), 137 + []byte("{\"version\":1,\"records\":[{\"channel\":\"telegram\",\"idempotency_key\":\"k\",\"status\":\"sent\",\"attempts\":1,\"created_at\":\"2026-02-08T12:00:00Z\",\"updated_at\":\"2026-02-08T12:00:00Z\",\"sent_at\":\"2026-02-08T12:00:00Z\",\"unknown\":\"x\"}]}\n"), 139 138 0o600, 140 139 ); err != nil { 141 140 t.Fatalf("WriteFile() error = %v", err) 142 141 } 143 - if _, _, err := store.GetBusOutboxRecord(ctx, ChannelMAEP, "k"); err == nil { 142 + if _, _, err := store.GetBusOutboxRecord(ctx, ChannelTelegram, "k"); err == nil { 144 143 t.Fatalf("GetBusOutboxRecord() expected decode error for unknown field") 145 144 } 146 145 }
+2 -3
contacts/outbox_state_machine_test.go
··· 111 111 112 112 func testOutboxBase() BusOutboxRecord { 113 113 return BusOutboxRecord{ 114 - Channel: ChannelMAEP, 114 + Channel: ChannelTelegram, 115 115 IdempotencyKey: "manual:k1", 116 - ContactID: "maep:c1", 117 - PeerID: "12D3KooW...", 116 + ContactID: "tg:1001", 118 117 ItemID: "item-1", 119 118 ContentType: "text/plain", 120 119 PayloadBase64: "aGVsbG8",
-4
internal/todo/contact_snapshot.go
··· 124 124 if item.TGPrivateChatID > 0 { 125 125 candidates = append(candidates, "tg:"+strconv.FormatInt(item.TGPrivateChatID, 10)) 126 126 } 127 - if nodeID := strings.TrimSpace(item.MAEPNodeID); nodeID != "" { 128 - candidates = append(candidates, nodeID) 129 - } 130 127 for _, candidate := range candidates { 131 128 if candidate == "" { 132 129 continue ··· 168 165 appendID(fmt.Sprintf("tg:%d", groupID)) 169 166 } 170 167 } 171 - appendID(item.MAEPNodeID) 172 168 return dedupeSortedStrings(ids) 173 169 } 174 170
+11 -10
internal/todo/contact_snapshot_test.go
··· 27 27 } 28 28 29 29 _, err = svc.UpsertContact(context.Background(), contacts.Contact{ 30 - ContactID: "maep:12D3KooWAlicePeer", 31 - ContactNickname: "Alice", 32 - Kind: contacts.KindAgent, 33 - Channel: contacts.ChannelMAEP, 34 - MAEPNodeID: "maep:12D3KooWAlicePeer", 30 + ContactID: "slack:T001:D002", 31 + ContactNickname: "Alice", 32 + Kind: contacts.KindHuman, 33 + Channel: contacts.ChannelSlack, 34 + SlackTeamID: "T001", 35 + SlackDMChannelID: "D002", 35 36 }, now) 36 37 if err != nil { 37 38 t.Fatalf("UpsertContact(alice) error = %v", err) ··· 56 57 if !foundJohn { 57 58 t.Fatalf("expected John snapshot item") 58 59 } 59 - for _, id := range []string{"tg:1001", "maep:12D3KooWAlicePeer"} { 60 + for _, id := range []string{"tg:1001", "slack:T001:D002"} { 60 61 if !snap.HasReachableID(id) { 61 62 t.Fatalf("expected reachable id %q", id) 62 63 } ··· 65 66 66 67 func TestValidateReachableReferences(t *testing.T) { 67 68 snap := ContactSnapshot{ 68 - ReachableIDs: []string{"maep:12D3KooWJohn", "tg:1001"}, 69 + ReachableIDs: []string{"slack:T001:D002", "tg:1001"}, 69 70 } 70 71 71 72 if err := ValidateReachableReferences("提醒 [John](tg:1001) 明天确认", snap); err != nil { 72 73 t.Fatalf("ValidateReachableReferences(snapshot tg id) error = %v", err) 73 74 } 74 - if err := ValidateReachableReferences("提醒 [John](maep:12D3KooWJohn) 明天确认", snap); err != nil { 75 + if err := ValidateReachableReferences("提醒 [John](slack:T001:D002) 明天确认", snap); err != nil { 75 76 t.Fatalf("ValidateReachableReferences(snapshot id) error = %v", err) 76 77 } 77 78 err := ValidateReachableReferences("提醒 [John](maep:unknown) 明天确认", snap) 78 - if err == nil || !strings.Contains(strings.ToLower(err.Error()), "not reachable") { 79 - t.Fatalf("expected not reachable error, got %v", err) 79 + if err == nil || !strings.Contains(strings.ToLower(err.Error()), "invalid reference id") { 80 + t.Fatalf("expected invalid reference id error, got %v", err) 80 81 } 81 82 }
+3 -5
internal/todo/ops.go
··· 14 14 var ( 15 15 refIDPatternA = regexp.MustCompile(`^tg:-?\d+$`) 16 16 refIDPatternB = regexp.MustCompile(`^tg:@[A-Za-z0-9_]+$`) 17 - refIDPatternC = regexp.MustCompile(`^maep:[A-Za-z0-9._-]+$`) 18 - refIDPatternD = regexp.MustCompile(`^slack:[A-Za-z0-9._:-]+$`) 19 - refIDPatternE = regexp.MustCompile(`^discord:[A-Za-z0-9._:-]+$`) 17 + refIDPatternC = regexp.MustCompile(`^slack:[A-Za-z0-9._:-]+$`) 18 + refIDPatternD = regexp.MustCompile(`^discord:[A-Za-z0-9._:-]+$`) 20 19 ) 21 20 22 21 func (s *Store) Add(ctx context.Context, raw string) (UpdateResult, error) { ··· 260 259 if refIDPatternA.MatchString(ref) || 261 260 refIDPatternB.MatchString(ref) || 262 261 refIDPatternC.MatchString(ref) || 263 - refIDPatternD.MatchString(ref) || 264 - refIDPatternE.MatchString(ref) { 262 + refIDPatternD.MatchString(ref) { 265 263 return true 266 264 } 267 265 return false
+19 -2
internal/todo/ops_test.go
··· 50 50 now := time.Date(2026, 2, 9, 10, 0, 0, 0, time.UTC) 51 51 store.Now = func() time.Time { return now } 52 52 53 - addRes, err := store.Add(context.Background(), "帮 [John](tg:1001) 发消息给 [Momo](maep:12D3KooWPeer)") 53 + addRes, err := store.Add(context.Background(), "帮 [John](tg:1001) 发消息给 [Momo](slack:T111:D222)") 54 54 if err != nil { 55 55 t.Fatalf("Add() error = %v", err) 56 56 } ··· 62 62 } 63 63 64 64 now = now.Add(30 * time.Minute) 65 - completeRes, err := store.Complete(context.Background(), "发消息给 [Momo](maep:12D3KooWPeer)") 65 + completeRes, err := store.Complete(context.Background(), "发消息给 [Momo](slack:T111:D222)") 66 66 if err != nil { 67 67 t.Fatalf("Complete() error = %v", err) 68 68 } ··· 98 98 t.Fatalf("unexpected error: %v", err) 99 99 } 100 100 } 101 + 102 + func TestStoreAddRejectsMAEPReferenceID(t *testing.T) { 103 + root := t.TempDir() 104 + store := NewStore(filepath.Join(root, "TODO.md"), filepath.Join(root, "TODO.DONE.md")) 105 + store.Semantics = stubSemantics{} 106 + store.Now = func() time.Time { 107 + return time.Date(2026, 2, 9, 10, 0, 0, 0, time.UTC) 108 + } 109 + 110 + _, err := store.Add(context.Background(), "提醒 [Momo](maep:12D3KooWPeer) 明天回复") 111 + if err == nil { 112 + t.Fatalf("expected Add() to fail for maep reference id") 113 + } 114 + if !strings.Contains(strings.ToLower(err.Error()), "invalid reference id") { 115 + t.Fatalf("unexpected error: %v", err) 116 + } 117 + }
+1 -1
internal/todo/reference_llm.go
··· 124 124 "Attach IDs as `[Name](id)` where id is from allowed_ids, example input:", 125 125 "Notice $SPEAKER to tell Alice invites Bob to the meeting of Lucy.", 126 126 "and rewritten content (assume the $SPEAKER is 'Lyric'): ", 127 - "Notice [Lyric](tg:98765) to tell [Alice](tg:12345) invites [Bob](maep:a1b2c3d4e5) to the meeting of [Lucy](tg:@lucy).", 127 + "Notice [Lyric](tg:98765) to tell [Alice](tg:12345) invites [Bob](slack:T123:D456) to the meeting of [Lucy](tg:@lucy).", 128 128 "If any person in `people` cannot be uniquely resolved to one allowed id, keep it in the rewritten content in the same form", 129 129 "Never invent IDs that are not listed in allowed_ids.", 130 130 "Preserve original language and intent. Keep the sentence natural.",
+10 -9
tools/builtin/todo_tools_test.go
··· 42 42 43 43 client := &stubTodoToolLLMClient{ 44 44 replies: []string{ 45 - `{"status":"ok","rewritten_content":"提醒 [John](tg:1001) 和 [Momo](maep:12D3KooWPeer) 对齐消息内容"}`, 45 + `{"status":"ok","rewritten_content":"提醒 [John](tg:1001) 和 [Momo](slack:T001:D002) 对齐消息内容"}`, 46 46 `{"status":"matched","index":0}`, 47 47 }, 48 48 } 49 49 update := NewTodoUpdateToolWithLLM(true, wip, done, contactsDir, client, "gpt-5.2") 50 50 out, err := update.Execute(context.Background(), map[string]any{ 51 51 "action": "add", 52 - "content": "提醒 [John](tg:1001) 和 [Momo](maep:12D3KooWPeer) 对齐消息内容", 52 + "content": "提醒 [John](tg:1001) 和 [Momo](slack:T001:D002) 对齐消息内容", 53 53 "people": []any{"John", "Momo"}, 54 54 }) 55 55 if err != nil { ··· 236 236 client := &stubTodoToolLLMClient{ 237 237 replies: []string{ 238 238 `{"status":"ok","rewritten_content":"提醒 [John](tg:1001) 准备一版草稿"}`, 239 - `{"status":"ok","rewritten_content":"提醒 [John](tg:1001) 和 [Momo](maep:12D3KooWPeer) 确认草稿"}`, 239 + `{"status":"ok","rewritten_content":"提醒 [John](tg:1001) 和 [Momo](slack:T001:D002) 确认草稿"}`, 240 240 `{"keep_indices":[0,1]}`, 241 241 `{"status":"ambiguous","candidate_indices":[0,1]}`, 242 242 }, ··· 253 253 } 254 254 _, err = update.Execute(context.Background(), map[string]any{ 255 255 "action": "add", 256 - "content": "提醒 [John](tg:1001) 和 [Momo](maep:12D3KooWPeer) 确认草稿", 256 + "content": "提醒 [John](tg:1001) 和 [Momo](slack:T001:D002) 确认草稿", 257 257 "people": []any{"John", "Momo"}, 258 258 }) 259 259 if err != nil { ··· 426 426 t.Fatalf("seed john contact error = %v", err) 427 427 } 428 428 _, err = svc.UpsertContact(context.Background(), contacts.Contact{ 429 - ContactID: "maep:12D3KooWPeer", 430 - ContactNickname: "Momo", 431 - Kind: contacts.KindAgent, 432 - Channel: contacts.ChannelMAEP, 433 - MAEPNodeID: "maep:12D3KooWPeer", 429 + ContactID: "slack:T001:D002", 430 + ContactNickname: "Momo", 431 + Kind: contacts.KindHuman, 432 + Channel: contacts.ChannelSlack, 433 + SlackTeamID: "T001", 434 + SlackDMChannelID: "D002", 434 435 }, now) 435 436 if err != nil { 436 437 t.Fatalf("seed momo contact error = %v", err)