Unified Agent + reusable Go agent core.
0
fork

Configure Feed

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

refactor: remove dead telegram helper utilities

Lyric 9f7e70f3 b1f8cd9a

-328
-324
internal/channelruntime/telegram/runtime_helpers.go
··· 8 8 "io" 9 9 "net/http" 10 10 "regexp" 11 - "sort" 12 11 "strconv" 13 12 "strings" 14 13 "time" 15 - "unicode" 16 - "unicode/utf8" 17 14 18 15 "github.com/google/uuid" 19 16 "github.com/quailyquaily/mistermorph/contacts" ··· 127 124 } 128 125 } 129 126 130 - func mentionUsersSnapshot(known map[string]string, limit int) []string { 131 - if len(known) == 0 { 132 - return nil 133 - } 134 - out := make([]string, 0, len(known)) 135 - for _, username := range known { 136 - out = append(out, username) 137 - } 138 - sort.Slice(out, func(i, j int) bool { 139 - return strings.ToLower(out[i]) < strings.ToLower(out[j]) 140 - }) 141 - if limit > 0 && len(out) > limit { 142 - out = out[:limit] 143 - } 144 - return out 145 - } 146 - 147 127 func isGroupChat(chatType string) bool { 148 128 chatType = strings.ToLower(strings.TrimSpace(chatType)) 149 129 return chatType == "group" || chatType == "supergroup" ··· 231 211 _ = username 232 212 _ = now 233 213 return nil 234 - } 235 - 236 - func clampUnit(v float64) float64 { 237 - if v < 0 { 238 - return 0 239 - } 240 - if v > 1 { 241 - return 1 242 - } 243 - return v 244 214 } 245 215 246 216 func telegramMemoryContactID(username string, userID int64) string { ··· 528 498 return item 529 499 } 530 500 531 - func newTelegramSystemHistoryItem(chatID int64, chatType string, text string, sentAt time.Time, botUser string) chathistory.ChatHistoryItem { 532 - item := newTelegramOutboundAgentHistoryItem(chatID, chatType, text, sentAt, botUser) 533 - item.Kind = chathistory.KindSystem 534 - return item 535 - } 536 - 537 501 func dedupeNonEmptyStrings(values []string) []string { 538 502 if len(values) == 0 { 539 503 return nil ··· 554 518 return out 555 519 } 556 520 557 - func stripBotMentions(text, botUser string) string { 558 - text = strings.TrimSpace(text) 559 - if text == "" || botUser == "" { 560 - return text 561 - } 562 - mention := "@" + botUser 563 - // Remove common mention patterns (case-insensitive). 564 - lower := strings.ToLower(text) 565 - idx := strings.Index(lower, strings.ToLower(mention)) 566 - if idx >= 0 { 567 - text = strings.TrimSpace(text[:idx] + text[idx+len(mention):]) 568 - } 569 - return strings.TrimSpace(text) 570 - } 571 - 572 - func truncateOneLine(s string, max int) string { 573 - s = strings.TrimSpace(s) 574 - if s == "" { 575 - return `""` 576 - } 577 - s = strings.ReplaceAll(s, "\r", " ") 578 - s = strings.ReplaceAll(s, "\n", " ") 579 - s = strings.ReplaceAll(s, "\t", " ") 580 - s = strings.Join(strings.Fields(s), " ") 581 - if max <= 0 || len(s) <= max { 582 - return s 583 - } 584 - if max <= 3 { 585 - return s[:max] 586 - } 587 - return s[:max-3] + "..." 588 - } 589 - 590 521 func buildReplyContext(msg *telegramMessage) string { 591 522 if msg == nil { 592 523 return "" ··· 620 551 return string(runes[:max-3]) + "..." 621 552 } 622 553 623 - type telegramAliasSmartMatch struct { 624 - Alias string 625 - TaskText string 626 - } 627 - 628 - func matchAddressedAliasSmart(text string, aliases []string, aliasPrefixMaxChars int) (telegramAliasSmartMatch, bool) { 629 - text = strings.TrimSpace(text) 630 - if text == "" { 631 - return telegramAliasSmartMatch{}, false 632 - } 633 - if aliasPrefixMaxChars <= 0 { 634 - aliasPrefixMaxChars = 24 635 - } 636 - 637 - prefixStart := skipLeadingAddressingJunk(text) 638 - 639 - bestIdx := -1 640 - best := telegramAliasSmartMatch{} 641 - 642 - for _, alias := range aliases { 643 - alias = strings.TrimSpace(alias) 644 - if alias == "" { 645 - continue 646 - } 647 - 648 - searchFrom := 0 649 - for { 650 - idx := indexOfAlias(text, alias, searchFrom) 651 - if idx < 0 { 652 - break 653 - } 654 - searchFrom = idx + 1 655 - 656 - if idx < prefixStart { 657 - continue 658 - } 659 - if !isAliasAddressingCandidate(text, prefixStart, idx, aliasPrefixMaxChars) { 660 - continue 661 - } 662 - 663 - after := idx + len(alias) 664 - if after < 0 || after > len(text) { 665 - continue 666 - } 667 - rest := trimLeadingSeparators(text[after:]) 668 - if rest == "" { 669 - continue 670 - } 671 - if !looksLikeRequest(rest) { 672 - continue 673 - } 674 - 675 - if bestIdx < 0 || idx < bestIdx { 676 - bestIdx = idx 677 - best = telegramAliasSmartMatch{Alias: alias, TaskText: rest} 678 - } 679 - } 680 - } 681 - 682 - if bestIdx < 0 { 683 - return telegramAliasSmartMatch{}, false 684 - } 685 - return best, true 686 - } 687 - 688 - func anyAliasContains(text string, aliases []string) (string, bool) { 689 - text = strings.TrimSpace(text) 690 - if text == "" { 691 - return "", false 692 - } 693 - for _, alias := range aliases { 694 - alias = strings.TrimSpace(alias) 695 - if alias == "" { 696 - continue 697 - } 698 - if indexOfAlias(text, alias, 0) >= 0 { 699 - return alias, true 700 - } 701 - } 702 - return "", false 703 - } 704 - 705 - func isAliasAddressingCandidate(text string, prefixStart int, aliasIdx int, aliasPrefixMaxChars int) bool { 706 - if aliasIdx < 0 || aliasIdx > len(text) { 707 - return false 708 - } 709 - if prefixStart < 0 { 710 - prefixStart = 0 711 - } 712 - if prefixStart > aliasIdx { 713 - return false 714 - } 715 - 716 - prefix := text[prefixStart:aliasIdx] 717 - if aliasPrefixMaxChars > 0 && utf8.RuneCountInString(prefix) > aliasPrefixMaxChars { 718 - return false 719 - } 720 - 721 - prefixTrim := strings.TrimSpace(prefix) 722 - if prefixTrim == "" { 723 - return true 724 - } 725 - return looksLikeGreeting(prefixTrim) 726 - } 727 - 728 - func looksLikeGreeting(s string) bool { 729 - s = strings.TrimSpace(s) 730 - if s == "" { 731 - return false 732 - } 733 - s = strings.ToLower(s) 734 - s = strings.Trim(s, " \t\r\n,.;:!?,。!?:;、-—()[]{}<>\"'") 735 - switch s { 736 - case "hi", "hey", "yo", "hello", "sup", "hola", "bonjour", "ciao", "嗨", "你好", "哈喽", "喂": 737 - return true 738 - default: 739 - return false 740 - } 741 - } 742 - 743 - func looksLikeRequest(s string) bool { 744 - s = strings.TrimSpace(s) 745 - if s == "" { 746 - return false 747 - } 748 - if strings.ContainsAny(s, "??") { 749 - return true 750 - } 751 - 752 - lower := strings.ToLower(s) 753 - for _, p := range []string{ 754 - "please", "pls", "plz", 755 - "help", "can you", "could you", "would you", 756 - "tell me", "explain", "summarize", "translate", "write", 757 - "generate", "make", "create", "list", "show", 758 - "why", "how", "what", 759 - } { 760 - if strings.HasPrefix(lower, p) { 761 - return true 762 - } 763 - } 764 - 765 - for _, p := range []string{ 766 - "请", "麻烦", "帮", "帮我", "能不能", "可以", "能否", 767 - "给我", "告诉我", "解释", "总结", "列出", "写", "生成", "翻译", 768 - "查", "看", "做", "分析", "推荐", "对比", 769 - "为什么", "怎么", "如何", "是什么", 770 - } { 771 - if strings.HasPrefix(s, p) || strings.Contains(s, p) { 772 - return true 773 - } 774 - } 775 - 776 - return false 777 - } 778 - 779 - func trimLeadingSeparators(s string) string { 780 - s = strings.TrimSpace(s) 781 - for s != "" { 782 - r, size := utf8.DecodeRuneInString(s) 783 - if r == utf8.RuneError && size == 1 { 784 - break 785 - } 786 - if unicode.IsSpace(r) || unicode.IsPunct(r) || unicode.IsSymbol(r) { 787 - s = strings.TrimSpace(s[size:]) 788 - continue 789 - } 790 - break 791 - } 792 - return strings.TrimSpace(s) 793 - } 794 - 795 - func skipLeadingAddressingJunk(s string) int { 796 - i := 0 797 - for i < len(s) { 798 - r, size := utf8.DecodeRuneInString(s[i:]) 799 - if r == utf8.RuneError && size == 1 { 800 - return i 801 - } 802 - if unicode.IsSpace(r) || unicode.IsPunct(r) || unicode.IsSymbol(r) { 803 - i += size 804 - continue 805 - } 806 - break 807 - } 808 - return i 809 - } 810 - 811 554 func sliceByUTF16(s string, offset, length int) string { 812 555 if offset < 0 { 813 556 offset = 0 ··· 845 588 } 846 589 } 847 590 return len(s) 848 - } 849 - 850 - func indexOfAlias(text, alias string, start int) int { 851 - if start < 0 { 852 - start = 0 853 - } 854 - if start >= len(text) { 855 - return -1 856 - } 857 - if alias == "" { 858 - return -1 859 - } 860 - if isASCII(alias) { 861 - return indexFoldASCII(text, alias, start) 862 - } 863 - if i := strings.Index(text[start:], alias); i >= 0 { 864 - return start + i 865 - } 866 - return -1 867 - } 868 - 869 - func isASCII(s string) bool { 870 - for i := 0; i < len(s); i++ { 871 - if s[i] >= 0x80 { 872 - return false 873 - } 874 - } 875 - return true 876 - } 877 - 878 - func indexFoldASCII(text, sub string, start int) int { 879 - if start < 0 { 880 - start = 0 881 - } 882 - if len(sub) == 0 { 883 - return -1 884 - } 885 - if start+len(sub) > len(text) { 886 - return -1 887 - } 888 - 889 - needle := make([]byte, len(sub)) 890 - for i := 0; i < len(sub); i++ { 891 - needle[i] = lowerASCII(sub[i]) 892 - } 893 - 894 - hay := []byte(text) 895 - for i := start; i+len(needle) <= len(hay); i++ { 896 - ok := true 897 - for j := range len(needle) { 898 - if lowerASCII(hay[i+j]) != needle[j] { 899 - ok = false 900 - break 901 - } 902 - } 903 - if ok { 904 - return i 905 - } 906 - } 907 - return -1 908 - } 909 - 910 - func lowerASCII(b byte) byte { 911 - if b >= 'A' && b <= 'Z' { 912 - return b + ('a' - 'A') 913 - } 914 - return b 915 591 } 916 592 917 593 func (api *telegramAPI) sendChatAction(ctx context.Context, chatID int64, action string) error {
-4
internal/channelruntime/telegram/telegram_api.go
··· 517 517 return strings.Contains(msg, "message is not modified") 518 518 } 519 519 520 - func (api *telegramAPI) sendMessageChunked(ctx context.Context, chatID int64, text string) error { 521 - return api.sendMessageChunkedReply(ctx, chatID, text, 0) 522 - } 523 - 524 520 func (api *telegramAPI) sendMessageChunkedReply(ctx context.Context, chatID int64, text string, replyToMessageID int64) error { 525 521 _, err := api.sendMessageChunkedReplyWithFirstMessageID(ctx, chatID, text, replyToMessageID) 526 522 return err