picoclaw/pkg
ywj 009a8d702b
Feat/feishu card parsing (#1534)
* feat(feishu): add interactive card message parsing

Add support for parsing inbound Feishu interactive card messages.
When a user sends a card message, the text content is now extracted
and passed to the LLM for processing.

- Add extractCardText() to recursively extract text from card JSON
- Support both JSON 1.0 (legacy) and JSON 2.0 schema formats
- Handle nested elements: header, body, actions, columns
- Extract text from markdown, lark_md, and plain_text elements
- Add comprehensive unit tests for card parsing

Fixes #<issue_number>

💘 Generated with Crush

Assisted-by: GLM-5 via Crush <crush@charm.land>

* feat(feishu): extract and download images from interactive cards

When receiving interactive card messages, extract embedded images
(img_key, src, icon_key) and download them for LLM processing.

- Add extractCardImageKeys() to recursively extract image keys from card JSON
- Support img elements (img_key, src) and icon elements (icon_key)
- Update downloadInboundMedia() to handle MsgTypeInteractive
- Add comprehensive unit tests for image extraction

Images are downloaded and stored via MediaStore, then appended to
the message content as [image: photo] tags for LLM visibility.

💘 Generated with Crush

Assisted-by: GLM-5 via Crush <crush@charm.land>

* fix(feishu): simplify card parsing - pass raw JSON, only extract images

Address review feedback: text extraction cannot exhaustively handle all
card formats (i18n_elements, div.fields, etc.). Pass raw JSON to LLM
instead - same approach as MsgTypePost. Only image extraction remains
as images must be downloaded for LLM to process.

- Remove extractCardText() and helper functions
- extractContent() now returns raw JSON for MsgTypeInteractive
- Keep extractCardImageKeys() for downloading embedded images
- Update tests to expect raw JSON for interactive cards

* fix(feishu): don't append media tags to interactive card JSON

Appending media tags like "[attachment]" to raw JSON content produces
invalid JSON format. For interactive cards, the JSON already contains
image information and media refs are downloaded separately.

- Skip appendMediaTags for MsgTypeInteractive to preserve valid JSON
- Add test case for interactive card with images

* fix(feishu): filter out external URLs from card image extraction

Only Feishu-hosted image keys (img_xxx, icon_xxx) can be downloaded via
the Feishu API. External URLs in src field (https://...) should be
filtered out to avoid download failures.

- Add isFeishuImageKey() to detect Feishu-hosted keys vs external URLs
- Update extractImageKeysRecursive to skip external URLs in src field
- Add tests for external URL filtering and mixed scenarios

* feat(feishu): support downloading external images from interactive cards

Previously only Feishu-hosted images (img_key, icon_key) could be
downloaded. Now external URLs in src field are also downloaded via
HTTP and made available to the LLM.

- extractCardImageKeys now returns two slices: Feishu keys and external URLs
- Add downloadExternalImage to download images from HTTP URLs
- Update downloadInboundMedia to handle both Feishu API and HTTP downloads
- Update tests for new function signature

* fix(feishu): use HTTP client with timeout for external image downloads

Replaced http.DefaultClient with a client that has a 30-second timeout
to prevent hanging on unresponsive external URLs.

Generated with Crush

Assisted-by: GLM-5 via Crush <crush@charm.land>

* fix(feishu): resolve lint errors for shadow and formatting

- Rename err variables to avoid shadowing in downloadExternalImage
- Fix struct field alignment in TestExtractCardImageKeys

Generated with Crush

Assisted-by: GLM-5 via Crush <crush@charm.land>

* refactor(feishu): pass external image URLs to LLM instead of downloading

Instead of downloading external images from interactive cards, pass
the URLs directly to LLM. This reduces network overhead and lets
vision-capable models fetch images as needed.

- Remove downloadExternalImage function
- Append external URLs to card content for LLM processing
- Only download Feishu-hosted images via API

💘 Generated with Crush

Assisted-by: GLM-5 via Crush <crush@charm.land>

* fix(feishu): add blank line between functions for gci formatting

* fix(feishu): keep interactive card content as valid JSON
2026-03-20 12:59:43 +08:00
..
agent Merge pull request #1390 from kiannidev/fix/1323-telegram-endless-typing 2026-03-19 21:52:10 +01:00
auth refactor: centralize environment variable key constants (#1730) 2026-03-18 18:03:24 +08:00
bus fix: Fixed the bug where the bus was closed and consumers had unfinished messages. (#1179) 2026-03-18 00:12:12 +08:00
channels Feat/feishu card parsing (#1534) 2026-03-20 12:59:43 +08:00
commands feat: add /reload to gateway api and command (#1725) 2026-03-19 13:42:36 +08:00
config Feat/wecom aibot processing message config (#1785) 2026-03-20 00:23:40 +08:00
constants refactor: replace bool map with set-style map for internal channels (#472) 2026-02-19 11:48:17 +01:00
credential refactor: centralize environment variable key constants (#1730) 2026-03-18 18:03:24 +08:00
cron feat(cron): refactor scheduler to event-driven model and add unit tests (#1313) 2026-03-18 00:02:51 +08:00
devices fix: address PR #662 review comments (bus drain, context timeouts, onebot leak) 2026-02-23 21:34:37 +08:00
fileutil refactor(pkg): move atomic file write to dedicated fileutil package 2026-02-24 23:57:13 +08:00
gateway refactor[gateway]: just reload the changed channels on reload occurred (#1773) 2026-03-19 15:28:52 +08:00
health feat: add /reload to gateway api and command (#1725) 2026-03-19 13:42:36 +08:00
heartbeat enable dupl check 2026-03-01 18:17:32 +11:00
identity fix(identity): prevent allowlist ID entries from matching usernames (#1406) 2026-03-13 15:41:18 +08:00
logger feat(web): implement macOS app feature and file logger (#1723) 2026-03-18 14:43:58 +08:00
mcp Feat/add tool enable or disable configuration (#1071) 2026-03-05 14:53:26 +08:00
media refactor(media): centralize temp media dir path 2026-03-14 12:01:47 +08:00
memory fix: skip meta json files during session migration (#1340) 2026-03-11 14:29:42 +08:00
migrate feat: telegram use parse mode ModeMarkdownV2 instead of ModeHTML (#1018) 2026-03-18 21:29:21 +08:00
providers feat(provider): add Alibaba Coding Plan and regional Qwen endpoints (#1748) 2026-03-19 22:07:30 +08:00
routing fix(routing): address review feedback on CJK estimation and observability 2026-03-06 13:10:20 +08:00
session fix(security): harden unauthenticated tool-exec paths (#1360) 2026-03-11 19:22:20 +08:00
skills enhance skill installer (#1252) 2026-03-13 14:04:02 +08:00
state fix(security): harden unauthenticated tool-exec paths (#1360) 2026-03-11 19:22:20 +08:00
tools feat(tool): anti cloudflare challenge in web_fetch (#1762) 2026-03-19 17:01:45 +08:00
utils Merge branch 'main' into feat/markdown-output-format-web-fetch 2026-03-17 16:37:22 +01:00
voice Fix lint 2026-03-04 10:21:59 +00:00