From d3bf6bc90a80fbb9d316700a170c6e290266b757 Mon Sep 17 00:00:00 2001 From: BBQ <35603386+HoneyBBQ@users.noreply.github.com> Date: Thu, 9 Apr 2026 14:36:11 +0800 Subject: [PATCH] fix(channel,attachment): channel quality refactor & attachment pipeline fixes (#349) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(channel): add DingTalk channel adapter - Add DingTalk channel adapter (`internal/channel/adapters/dingtalk/`) using dingtalk-stream-sdk-go, supporting inbound message receiving and outbound text/markdown reply - Register DingTalk adapter in cmd/agent and cmd/memoh - Add go.mod dependency: github.com/memohai/dingtalk-stream-sdk-go - Add Dingtalk and Wecom SVG icons and Vue components to @memohai/icon - Refactor existing icon components to remove redundant inline wrappers - Add `channelTypeDisplayName` util for consistent channel label resolution - Add DingTalk/WeCom i18n entries (en/zh) for types and typesShort - Extend channel-icon, bot-channels, channel-settings-panel to support dingtalk/wecom - Use channelTypeDisplayName in profile page to replace ad-hoc i18n lookup * fix(channel,attachment): channel quality refactor & attachment pipeline fixes Channel module: - Fix RemoveAdapter not cleaning connectionMeta (stale status leak) - Fix preparedAttachmentTypeFromMime misclassifying image/gif - Fix sleepWithContext time.After goroutine/timer leak - Export IsDataURL/IsHTTPURL/IsDataPath, dedup across packages - Cache OutboundPolicy in managerOutboundStream to avoid repeated lookups - Split OutboundAttachmentStore: extract ContainerAttachmentIngester interface - Add ManagerOption funcs (WithInboundQueueSize, WithInboundWorkers, WithRefreshInterval) - Add thread-safety docs on OutboundStream / managerOutboundStream - Add debug logs on successful send/edit paths - Expand outbound_prepare_test.go with 21 new cases - Convert no-receiver adapter helpers to package-level funcs; drop unused params DingTalk adapter: - Implement AttachmentResolver: download inbound media via /v1.0/robot/messageFiles/download - Fix pure-image inbound messages failing due to missing resolver Attachment pipeline: - Fix images invisible to LLM in pipeline (DCP) path: inject InlineImages into last user message when cfg.Query is empty - Fix public_url fallback: skip direct URL-to-LLM when ContentHash is set, always prefer inlined persisted asset - Inject path: carry ImageParts through agent.InjectMessage; inline persisted attachments in resolver inject goroutine so mid-stream images reach the model - Fix ResolveMime for images: prefer content-sniffed MIME over platform-declared MIME (fixes Feishu sending image/png header for actual JPEG content → API 400) --- .../web/src/components/channel-icon/index.vue | 4 + apps/web/src/i18n/locales/en.json | 9 + apps/web/src/i18n/locales/zh.json | 9 + .../pages/bots/components/bot-channels.vue | 12 +- .../components/channel-settings-panel.vue | 12 +- apps/web/src/pages/profile/index.vue | 6 +- apps/web/src/utils/channel-type-label.ts | 20 + cmd/agent/main.go | 54 +- cmd/memoh/serve.go | 44 +- go.mod | 1 + go.sum | 2 + internal/agent/agent.go | 13 +- internal/agent/types.go | 3 + internal/attachment/normalize.go | 12 +- internal/attachment/normalize_test.go | 74 +- internal/channel/adapter.go | 19 +- internal/channel/adapters/dingtalk/client.go | 326 ++++++++ internal/channel/adapters/dingtalk/config.go | 167 ++++ .../channel/adapters/dingtalk/descriptor.go | 7 + .../channel/adapters/dingtalk/dingtalk.go | 447 +++++++++++ internal/channel/adapters/dingtalk/inbound.go | 389 ++++++++++ .../channel/adapters/dingtalk/outbound.go | 200 +++++ internal/channel/adapters/dingtalk/stream.go | 153 ++++ internal/channel/adapters/discord/discord.go | 108 +-- .../channel/adapters/discord/discord_test.go | 34 +- internal/channel/adapters/discord/stream.go | 16 +- .../channel/adapters/discord/stream_test.go | 2 +- internal/channel/adapters/feishu/feishu.go | 103 +-- .../feishu/feishu_integration_test.go | 14 +- internal/channel/adapters/feishu/stream.go | 44 +- internal/channel/adapters/local/hub.go | 6 +- internal/channel/adapters/local/hub_test.go | 2 +- internal/channel/adapters/local/web.go | 9 +- internal/channel/adapters/matrix/matrix.go | 141 +--- .../channel/adapters/matrix/matrix_test.go | 33 +- internal/channel/adapters/matrix/stream.go | 10 +- .../channel/adapters/matrix/stream_test.go | 34 +- internal/channel/adapters/qq/send.go | 150 +--- internal/channel/adapters/qq/send_test.go | 87 ++- internal/channel/adapters/qq/stream.go | 69 +- internal/channel/adapters/qq/stream_test.go | 90 ++- internal/channel/adapters/telegram/stream.go | 24 +- .../channel/adapters/telegram/stream_test.go | 42 +- .../channel/adapters/telegram/telegram.go | 122 +-- .../adapters/telegram/telegram_test.go | 102 +-- .../wecom/adapter_integration_test.go | 14 +- internal/channel/adapters/wecom/outbound.go | 155 +++- .../channel/adapters/wecom/outbound_test.go | 72 ++ internal/channel/adapters/wecom/wecom.go | 57 +- internal/channel/adapters/weixin/weixin.go | 78 +- internal/channel/channeltest/store.go | 181 +++++ internal/channel/connection.go | 36 +- internal/channel/inbound/channel.go | 242 ++---- internal/channel/inbound/channel_test.go | 39 +- internal/channel/inbound/dispatcher.go | 13 +- internal/channel/inbound_test.go | 15 +- internal/channel/manager.go | 49 +- internal/channel/manager_integration_test.go | 4 +- internal/channel/outbound.go | 110 ++- internal/channel/outbound_prepare.go | 648 ++++++++++++++++ internal/channel/outbound_prepare_test.go | 724 ++++++++++++++++++ internal/channel/outbound_test.go | 37 +- internal/channel/prepared_outbound.go | 109 +++ internal/channel/types.go | 14 + internal/conversation/flow/resolver.go | 31 +- .../conversation/flow/resolver_attachments.go | 47 +- internal/media/service.go | 6 + internal/messaging/executor.go | 52 +- internal/messaging/executor_test.go | 22 +- internal/pipeline/rendering.go | 10 - packages/icons/icons/dingtalk.svg | 1 + packages/icons/icons/wecom.svg | 1 + packages/icons/scripts/manifest.ts | 2 + packages/icons/src/icons/Dingtalk.vue | 22 + packages/icons/src/icons/Wecom.vue | 18 + packages/icons/src/index.ts | 2 + 76 files changed, 4851 insertions(+), 1185 deletions(-) create mode 100644 apps/web/src/utils/channel-type-label.ts create mode 100644 internal/channel/adapters/dingtalk/client.go create mode 100644 internal/channel/adapters/dingtalk/config.go create mode 100644 internal/channel/adapters/dingtalk/descriptor.go create mode 100644 internal/channel/adapters/dingtalk/dingtalk.go create mode 100644 internal/channel/adapters/dingtalk/inbound.go create mode 100644 internal/channel/adapters/dingtalk/outbound.go create mode 100644 internal/channel/adapters/dingtalk/stream.go create mode 100644 internal/channel/channeltest/store.go create mode 100644 internal/channel/outbound_prepare.go create mode 100644 internal/channel/outbound_prepare_test.go create mode 100644 internal/channel/prepared_outbound.go create mode 100644 packages/icons/icons/dingtalk.svg create mode 100644 packages/icons/icons/wecom.svg create mode 100644 packages/icons/src/icons/Dingtalk.vue create mode 100644 packages/icons/src/icons/Wecom.vue diff --git a/apps/web/src/components/channel-icon/index.vue b/apps/web/src/components/channel-icon/index.vue index 4f201499..91d79d58 100644 --- a/apps/web/src/components/channel-icon/index.vue +++ b/apps/web/src/components/channel-icon/index.vue @@ -14,12 +14,14 @@ diff --git a/packages/icons/src/icons/Wecom.vue b/packages/icons/src/icons/Wecom.vue new file mode 100644 index 00000000..d30cfdc2 --- /dev/null +++ b/packages/icons/src/icons/Wecom.vue @@ -0,0 +1,18 @@ + + + diff --git a/packages/icons/src/index.ts b/packages/icons/src/index.ts index 63d0e2dd..24d607c7 100644 --- a/packages/icons/src/index.ts +++ b/packages/icons/src/index.ts @@ -17,6 +17,7 @@ export { default as Cohere } from './icons/Cohere.vue' export { default as CohereColor } from './icons/CohereColor.vue' export { default as Deepseek } from './icons/Deepseek.vue' export { default as DeepseekColor } from './icons/DeepseekColor.vue' +export { default as Dingtalk } from './icons/Dingtalk.vue' export { default as Discord } from './icons/Discord.vue' export { default as Doubao } from './icons/Doubao.vue' export { default as DoubaoColor } from './icons/DoubaoColor.vue' @@ -80,6 +81,7 @@ export { default as VertexaiColor } from './icons/VertexaiColor.vue' export { default as Volcengine } from './icons/Volcengine.vue' export { default as VolcengineColor } from './icons/VolcengineColor.vue' export { default as Wechat } from './icons/Wechat.vue' +export { default as Wecom } from './icons/Wecom.vue' export { default as Xai } from './icons/Xai.vue' export { default as Yandex } from './icons/Yandex.vue' export { default as Yi } from './icons/Yi.vue'