feat(feishu): auto-fetch Lark docx URLs into agent context

When a user pastes a Lark or Feishu docx URL in chat, the channel
now detects the URL and fetches the document's raw text via the
Lark Docs API, injecting the content into the agent input inline
so the model can reason over the linked doc without a tool call.

- New Channel.resolveLarkDocs pipeline step runs before reply
  context fetch in handleMessageEvent (step 7a)
- LarkClient.GetDocRawContent calls /open-apis/docx/v1/documents
  /{id}/raw_content with the existing tenant access token;
  permission and not-found errors map to ErrDocAccessDenied
- Per-channel LRU cache (128 entries, 5 min TTL) dedupes repeat
  URL references within the window; soft failures are NOT cached
  so permission grants become visible immediately
- Rune-safe content truncation at 8000 runes handles CJK docs
  without splitting mid-rune
- Bounded concurrency (max 3 parallel fetches) and a per-message
  cap of 10 doc URLs act as spam guards
- Tight URL regex anchors the hostname class so a lazy match
  cannot bypass via query-string embedding
- 18 new unit tests cover URL extraction edge cases, cache LRU
  and TTL semantics, Lark API error code mapping, resolver
  end-to-end with nil cache, access denied soft failure,
  per-message cap, and UTF-8 truncation

Required Lark app permission: docx:document:readonly, plus
per-document access grant from the doc owner.

Partial fix for #818 (Phase 2 of 3 — thread reply + writer
commands are tracked separately).
This commit is contained in:
viettranx committed 2026-04-11 21:26:12 +07:00
1 parent bf272d8dbf
commit 1bdd291fac
12 files changed
+956 -3

No files matched your search

+21
View File
@@ -376,6 +376,27 @@ When a message is sent inside a Lark thread (detected via the `thread_id` field
- **Graceful fallback**: If the reply endpoint fails (e.g., thread root deleted), the channel falls back to `SendMessage()` for the regular chat
- **Applies to**: Text, card, image, and file messages
### Document URL Auto-Fetch
When a user pastes a Lark docx (document) URL in a message, the channel automatically fetches the document raw text and injects it into the agent prompt for context.
**URL detection**: Regex pattern matches `https://*.larksuite.com/docx/<id>` and `*.feishu.cn/docx/<id>` URLs.
**Auto-fetch behavior**:
- Document content fetched via Lark API `GET /open-apis/docx/v1/documents/{id}/raw_content`
- Content injected as `[Lark Doc: <url>] ... [End of Lark Doc]` markers around the raw text
- Rune-safe truncation at 8000 runes per document to respect token budgets
- Results cached per channel instance with LRU eviction (128 entries, 5-minute TTL)
**Access control**: Requires bot app to have `docx:document:readonly` permission **and** document owner must explicitly grant the bot access to each document. If access is denied or document not found, a visible inline marker appears: `[Lark Doc X: access denied — grant the bot app read permission on this document]`
**Safeguards**:
- Limited to docx documents only (sheets, base, wiki deferred)
- Maximum 10 document fetches per inbound message (spam protection)
- Soft-fail on API errors (no outbound message blocks)
**Configuration**: No new config flags. Supported document type and cache tunables (8000 rune limit, 10-URL cap, 5-min TTL, 128-entry cache) are hardcoded.
---
## 7. Discord
+11 -1
View File
@@ -34,11 +34,21 @@ All notable changes to GoClaw Gateway are documented here. Format follows [Keep
### Fixed
#### Feishu/Lark Thread Reply Routing — Issue #818 (2026-04-11)
#### Feishu/Lark Thread Reply Routing — Issue #818 Phase 1 (2026-04-11)
- **Thread detection**: Inbound messages with `thread_id` now properly route responses back to the same Feishu thread via `/open-apis/im/v1/messages/{id}/reply` endpoint
- **Metadata propagation**: New `feishu_reply_target_id` metadata key added to `routingMetaKeys` allowlist so all outbound messages (text, cards, files, reactions) land in the correct thread
- **Graceful fallback**: If thread root is deleted, channel falls back to regular `SendMessage()` for robustness
### Added
#### Feishu/Lark Document URL Auto-Fetch — Issue #818 Phase 2 (2026-04-11)
- **Automatic docx fetching**: Users paste Lark docx URLs in chat; channel auto-detects and fetches raw text via `/open-apis/docx/v1/documents/{id}/raw_content`
- **Transparent context injection**: Document content embedded as `[Lark Doc: URL] ... [End of Lark Doc]` markers, visible to agent for reasoning
- **Smart caching**: LRU cache per channel instance (128 entries, 5-minute TTL) reduces redundant API calls
- **Rune-safe truncation**: 8000-rune limit per document prevents token budget overrun
- **Access control**: Requires bot app `docx:document:readonly` permission + per-document grant from owner. Access denied displays inline marker with grant instructions
- **Safeguards**: Docx-only (sheets/base/wiki deferred), max 10 URLs per message, soft-fail on errors (no message blocks)
### Testing
#### Test Coverage Improvement — Wave 1-3 (2026-04-11)