Commit graph

75 commits

Author SHA1 Message Date
xmanrui
149f435216 fix: trim redundant quoted message metadata 2026-09-03 03:11:14 +08:00
xmanrui
34f217cafc Merge pull request #122 and harden reply stall detection
Resolve the current main conflict, treat reply timeouts as inactivity windows, and confirm liveness through Harness instead of sticky interaction ownership.
2026-09-03 02:14:01 +08:00
xmanrui
2b6f4bdfb0 fix(feishu): preserve interaction card reply semantics 2026-09-03 01:12:51 +08:00
xmanrui
d4e1bd3cab Merge main into feat/feishu-interaction-cards
# Conflicts:
#	lib/index.js
2026-09-03 01:00:04 +08:00
xmanrui
3240632bef Merge main into agent/issue-88 and resolve workspace aliases 2026-09-03 00:47:38 +08:00
xmanrui
37ec6abb06 feat: support limiting session list results 2026-09-02 03:01:44 +08:00
xmanrui
94e114b9b3 fix: preserve quoted message context across channels 2026-09-02 01:27:35 +08:00
C3H3-AI
b5378500ca fix(feishu): bind card decisions to the actor and reject stale cards
Address review feedback on the interaction cards:

1. Bind card decisions to the initiating actor. The card-action operator
   (operatorOpenId) is now passed into the approval and question handlers:
   - submitByApprovalId receives { actor } so another allowed group member
     cannot approve/reject someone else's approval;
   - the answer branch requires pending.actor === operator.

2. Include the question index in the answer button action and validate it
   against the current pending question, so a stale card from an earlier
   question in a multi-question interaction cannot be applied to the next one.

3. When both the card send and the plain-text fallback fail, the error is no
   longer swallowed: it propagates so the interaction is not marked as
   presented and the existing retry/reconnect behaviour can run.

Adds regression tests for all three cases.
2026-09-02 00:18:50 +08:00
C3H3-AI
0b42ea9889 feat(feishu): interactive approval and question cards with buttons
Render Harness approval and single-choice question interactions as
interactive Feishu cards with approve/reject and answer buttons,
matching the already-available interactionCards behaviour. Cards are now
the default; set DSH_IM_INTERACTION_CARDS=0 (or interactionCards=false)
to keep the plain-text reply flow.

- bridge.mjs: approve:/reject:/answer: card actions, interactionCards
  option, gated approval render hook, interactive question presentation,
  and operationArguments/printableText helpers; refactor the inline
  question answer into #submitQuestionAnswer so both text replies and
  card buttons share one path.
- feishu-cards.mjs: approvalCard (approve/reject) and questionCard
  (option buttons) templates.
- feishu-runtime.mjs: default interactionCards from env (on).
- harness-approval.mjs: optional channel render hook + submitByApprovalId.
- i18n-en: add the new card t() keys.
- Tests: pin the plain-text reply flow in state-machine suites that
  drive it, and add dedicated card tests for the default approve/reject,
  answer buttons, and the text fallback. Full suite shows no new
  failures versus upstream.
2026-09-02 00:18:37 +08:00
C3H3-AI
955c2217fd fix(feishu): renew the reply wait window while the turn is active
A long-running Harness task was falsely reported as MODEL_REPLY_TIMEOUT
after the fixed 10-minute deadline even though the backend was still
working. Replace the hard wall-clock deadline with an activity-based
stall window: the wait renews whenever the turn produces new events, the
control ownership is active, or (mid-turn with no new events) Harness
still reports the session as running. Only a genuine stall with no
progress for the whole timeoutMs window fails fast.

This is the shared harness-client layer, exercised end-to-end by the
Feishu channel (which already exposes HARNESS_REPLY_TIMEOUT_MS); other
channels inherit the same fix.

Adds two regression tests: a long-running turn with periodic activity
completes instead of timing out, and a genuinely stalled turn still
fails with harness-reply-timeout.
2026-09-02 00:17:18 +08:00
evanfang0054
1a165822ac fix(feishu): rotate the streaming card before presenting in-turn interactions 2026-09-01 17:53:42 +08:00
evanfang0054
bf03b7e696 feat(feishu): add stream card rotation to keep answers below mid-turn interactions 2026-09-01 17:53:42 +08:00
yusuke8h
65c1c55f1a fix: [Feature] 为工作区命令增加 /ws、/wsl 和 /workspaces 别名 (#88) 2026-09-01 17:03:48 +09:00
xmanrui
959e5b9ad2 fix(feishu): document numbered workspace switching 2026-09-01 15:47:27 +08:00
xmanrui
840e5aa857 feat: add unified IM access policies 2026-09-01 10:46:41 +08:00
evanfang0054
fb3d6750c3 test(feishu): cover card-action and watch-completion topic threading 2026-09-01 10:02:11 +08:00
evanfang0054
adc0a89f13 fix(feishu): honor NO_PROXY before proxying the long connection
webSocketProxyUrl() picks up https_proxy/HTTPS_PROXY/http_proxy/
HTTP_PROXY and forces the Feishu WSS long connection through the proxy,
without consulting NO_PROXY/no_proxy. With a local proxy exported in
the shell (Clash/V2Ray setups), every long-connection attempt is
rejected by Feishu's server and the runtime force-closes and retries
in a loop, so the bot never reaches a stable connected state.

Resolve NO_PROXY/no_proxy for the long-connection endpoints
(open.feishu.cn / open.larksuite.com) before falling back to the proxy
env: exact host, parent-domain (.cn, feishu.cn) and * entries follow
the common NO_PROXY semantics.

- production.mjs: NO_PROXY gate in front of the proxy lookup
- feishu-proxy.test.mjs: NO_PROXY exclusion and fallthrough cases
- lib/index.js: regenerated host bundle
2026-09-01 09:46:49 +08:00
evanfang0054
fd6e0af81b feat(feishu): thread command replies, cards, and approvals to the triggering message
Plain command replies (menu cards, session/workspace/watch lists, /new,
/status, /compact, /archived, model and preset commands) and Harness
approval prompts were sent as fresh messages keyed only by chat_id, so
in topic groups they landed in the group's default area instead of the
topic the conversation belongs to.

Deliver them as replies to the triggering message, mirroring how stream
answers already thread:

- #sendCard accepts { replyTo } and replies interactively, falling back
  to a plain card when the referenced message is gone
- command replies, status text, menu/session/workspace/watch cards,
  approval prompts and resolved-question notices all carry the
  triggering message id
- batch-input failure notices follow the same rule

- bridge.test.mjs: /new in a topic group must thread the confirmation
  text and the menu card to the command message
- lib/index.js: regenerated host bundle
2026-08-31 20:06:04 +08:00
evanfang0054
3b810fea6b fix(feishu): present Harness questions as threaded replies in topic groups
Regular answers reuse the stream card, which is created through the
reply API targeting the triggering message, so they land in the right
Feishu thread. Pending Harness questions (ask_user_question) were sent
through a fresh message.create with only the chat_id, so in topic
groups they appeared in the group's default area instead of the topic
the conversation belongs to.

Thread question delivery the same way as answers:

- #send accepts { replyTo } and uses im.v1.message.reply, falling back
  to a plain message when the referenced one is gone
- the triggering message id now travels into the interaction context
  and pending state, and #presentInteraction replies to it
- resolved-question notices reply to the user's answer message

- bridge.test.mjs: assert the question is delivered via the reply API
  targeting the triggering message inside a topic group
- lib/index.js: regenerated host bundle
2026-08-31 17:12:55 +08:00
evanfang0054
da4114dfe3 feat(feishu): isolate Harness sessions per topic in topic groups
conversationKey derived the group session key from chat_id alone, so in
Feishu topic groups every topic shared one Harness session: context,
/new, pending approvals, and batch-input state all leaked across topics.

Append the event's thread_id to the session key when present. Topic
groups stamp every message with a thread_id, so each topic now maps to
its own group:<chat_id>🧵<thread_id> session. Regular group chats
carry no thread_id and keep the single shared group:<chat_id> key; p2p
keys are untouched.

- message-utils.mjs: thread-aware conversationKey
- message-utils.test.mjs: topic isolation + regular-group fallback cases
- lib/index.js: regenerated host bundle
2026-08-31 13:54:35 +08:00
xmanrui
347acceffb fix(feishu): integrate slash command permissions 2026-08-31 01:21:38 +08:00
C3H3-AI
64ba1463a8 feat(feishu): register native Slash Command panel on startup
The Feishu bot now calls the app_slash_commands OpenAPI at startup to register its common commands (menu, new, help, status, compact, sessionlist, workspacelist, watch, unwatch, watchlist, archived) as native Slash Commands, so typing / in a Feishu direct-message input box pops the command panel and tapping a command triggers it.

The command list is owned and pushed by dsh-im; it does not depend on the dsh/Harness backend. Registration is best-effort and runs asynchronously, so it never blocks the long-connection startup or message delivery when the app lacks the application:app_slash_command:read/write scopes.

Adds src/channels/feishu/slash-command-registry.mjs (manifest, list/create/delete, idempotent sync), wires it into feishu-runtime.mjs (slashCommands config flag + status fields), and covers it with tests.
2026-08-30 23:40:59 +08:00
xmanrui
31792d7bc8 feat: add stable proactive delivery 2026-08-30 11:24:53 +08:00
MikhailB
98c1e48271 feat: add session and preset list aliases 2026-08-30 02:34:40 +03:00
xmanrui
6c6d4af936 fix(feishu): preserve long streaming replies
Keep a bounded streaming preview, then deliver the complete final answer across multiple cards. Preserve all provider message IDs and cover long snapshots and Unicode boundaries with regression tests.

Fixes #78
2026-08-28 10:50:35 +08:00
xmanrui
f0b6b38b45 fix: use in-process Harness API for local plugin connections 2026-08-28 01:24:17 +08:00
xmanrui
1ce8126edb feat(settings): move IM bot to top-level menu
Remove the legacy Plugins-tab registrations, keep the channel-logo navigation, and harden upgrade/package verification.
2026-08-25 22:42:41 +08:00
Evilh2019
adeab2dec8
fix(feishu): treat single-text-paragraph posts as commands (#57)
Treat attachment-free Feishu rich-text posts containing bot commands like ordinary text commands instead of forwarding them to the Harness.

Co-authored-by: OpenClaw Agent <agent@openclaw.ai>
2026-08-25 19:28:20 +08:00
xmanrui
da01e3acee feat: add status reactions across messaging channels 2026-08-25 17:12:28 +08:00
xmanrui
7cbed3aefb fix: surface actionable channel message errors 2026-08-25 14:54:50 +08:00
xmanrui
c5becbe379 feat: add plugin version command 2026-08-25 12:25:01 +08:00
xmanrui
10ca7eec2c fix(feishu): complete permissions repair flow 2026-08-25 04:25:21 +08:00
xmanrui
068cf57259 feat: add private chat batch input commands 2026-08-25 02:39:31 +08:00
xmanrui
9e39333ff6 feat: add reasoning effort commands 2026-08-25 00:41:44 +08:00
xmanrui
bd9c58cf9e fix(feishu): stabilize post-merge card workflows 2026-08-24 18:49:32 +08:00
xmanrui
9d1dc71794 fix(feishu): harden interactive card flows 2026-08-24 18:49:32 +08:00
C3H3-AI
45f55f73eb fix(feishu): streamline menu card layout and update help card
- Move preset/model/archive controls from settings card to main menu
- Arrange 4 dropdowns in 2x2 grid with external icons
- Align steer and archive side by side
- Replace #showSettingsCard with #sendMenuCard for preset/model/archive updates
- Add #sendMenuCard after 'new' button action for consistency
- Update help card to reflect current menu layout (12 items)
- Clean up duplicate sessionlist entries in menuHelpText
- Add missing English dictionary entries
2026-08-24 09:46:32 +08:00
C3H3-AI
044ab74c28 merge: integrate upstream v2.0.0 (files, images, i18n) into feishu-card-system
- Resolve conflicts in feishu-cards.mjs / bridge.mjs / control-command.mjs / lib
- Keep card-system enhancements: menuCard/settingsCard/presetCard/modelCard, /m newCard, card form submit, model select
- Adopt upstream i18n t() wrapping + file/image delivery + inbound files
- Add missing English dictionary entries for new feishu card strings
- Rebuild lib (package now 2.0.0)
2026-08-24 07:22:50 +08:00
xmanrui
3ec5f1eca7 feat: add native image delivery across channels 2026-08-24 03:25:38 +08:00
xmanrui
ade50210f0 fix(qq): prevent turn feed message spam 2026-08-24 00:48:21 +08:00
jonah.fu
46acf5a425 Merge upstream/main: inbound files across channels + v1.3.0
Resolve qq-bridge.mjs by keeping the inbound-file support (hasFiles,
files passthrough) and dropping the upstream stream session, which
this branch replaces with the discrete turn-feed notices.
2026-08-23 22:46:44 +08:00
jonah.fu
e1bc9dd0d0 feat(qq): stream the full turn feed as discrete messages
Show what the agent is actually doing during a turn, the way Claude
Code does: interim explanation text, every Tool call, and the error
detail when a tool fails, each as its own pushed message before the
final markdown answer.

- HarnessReplyTracker.consume now returns every frame of a polling
  batch in order (same-batch text frames collapse to the latest)
  instead of dropping all but the last event, which silently ate
  tool-call frames that shared a batch with their result
- tool frames carry callId; status frames carry the correlated
  toolName and a flattened error text parsed from the tool/result
  error payload (message, or name: code)
- the QQ bridge holds interim step text until the next tool call
  (or the end of the turn) pushes it, emits 'Tool call <name>' per
  call, emits 'Tool call <name>\nError: <reason>' for failures, and
  skips re-sending interim text that already equals the final answer

Other channels keep their existing behaviour: the status frame still
reads '正在整理结果…' and they ignore the new optional fields.
2026-08-23 22:39:29 +08:00
xmanrui
0a26d7df92 feat: support inbound files across all channels 2026-08-23 22:39:26 +08:00
xmanrui
d472dd5a75 feat: add native result-file delivery 2026-08-23 20:02:06 +08:00
C3H3-AI
7a6e84cb89 fix(feishu): align menu number-fallback test with emoji label and bind-flows
The menu card renders the repair fallback as **5**<emoji>修复, so the two assertions that matched **5**修复 are broadened to tolerate the marker emoji. The number-reply on a later session page now reads the last text confirmation instead of assuming the last outgoing message is text, since #bindSession refreshes the menu card after binding. Rebuild bundle.
2026-08-23 09:41:38 +08:00
C3H3-AI
0241a32ec5 fix(feishu): conform card form submission and model select to upstream
- read form data from action.form_value (Card 2.0) instead of formValue

- wrap custom steer input and submit in a form container with submit button

- reuse runModelCommand for dropdown model picks so IDs with multiple / keep working

- pass key when sending the help card so back-to-menu stays valid

- compute initial_index from {value} option arrays

- add in-flight tests for menu stop, steer dropdown, and steer form
2026-08-23 07:11:17 +08:00
C3H3-AI
7d2c93da86 feat(feishu): expand menu card buttons and keep repair number-only
Add stop/compact/settings/watchlist buttons to the hub menu card, route repair through the numeric fallback (reply 6) without an extra button, and sync the menu help and card-structure test assertions. Rebuild the lib bundle so the published artifact carries the changes.
2026-08-23 06:16:26 +08:00
xmanrui
eadfc7372f fix(ui): unify channel card feedback layout 2026-08-22 18:27:19 +08:00
xmanrui
f7d2fe7047 fix(feishu): honor proxy settings for REST and WebSocket 2026-08-22 14:45:25 +08:00
xmanrui
eea29fe296 feat: add agent preset chat commands 2026-08-22 04:04:44 +08:00