- 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
Wrap all user-facing chat text in src/channels with a host-side t()
translator (Chinese is the identity default, so untranslated text is
always sent verbatim in Chinese). English is selected via the host
plugin config `language: en` or the DSH_IM_LANGUAGE environment
variable, and the settings UI keeps following the DSH web locale.
- add src/channels/shared/i18n.mjs with setImHostLanguage/t() and a
Chinese-key -> English dictionary split by area (shared + channels)
- complete the English dictionary for every t() key in src/channels,
including the feishu channel (welcome/help, repair flow, interactive
cards, watch flow) and the shared command/approval/stream text
- wrap previously untranslated chat-facing strings in feishu bridge,
feishu runtime, editable-message-stream, harness-client,
connection-test and image-prompt
- dedupe dictionary entries that existed in multiple channel files and
canonicalize conflicting translations into the shared dictionaries
- extend the i18n unit test to decode string-literal escapes so keys
containing \n are checked correctly
- document the language switch in README.md, README.en.md and
CHANGELOG.md, and rebuild lib/index.js
Added English support for bot chat messages across all nine IM
channels and AI Office without changing any Chinese output.
Real agent turns invoke tools constantly; one 'Tool call X' message
per call flooded the chat with near-zero information. Tool frames now
only flush the pending interim explanation text; successful tool
results stay silent, and failures still push the tool name with the
error detail.
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.
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.
Replace the in-place streaming reply (openStream replace-mode frames)
with discrete pushed messages, so the chat no longer flickers while
the turn is running:
- each tool call pushes one notice message (正在使用X…); status frames
such as '正在整理结果…' and per-token text frames are not pushed
- the final answer arrives as one new markdown message
- a stopped turn still announces '已停止。'; no stream session is
created, so there is nothing to cancel or finalize
The shared Harness client emits a '正在整理结果…' status update after
every tool/result. Pushing each one into the QQ stream message made
multi-tool turns repeatedly flash that notice instead of showing real
progress. Skip status frames in the QQ onUpdate handler so the stream
keeps the last meaningful frame (tool name or generated text), which
matches the official dsh-qqbot behaviour of not pushing tool-noise.
Deliver final Harness answers to QQ as msg_type=2 markdown so bold,
headings, code blocks, lists, and tables render natively in QQ.
- add markdown-reply.mjs: chunk long answers at code-fence/table
boundaries (4500-char limit) and send each chunk with a unique
msg_seq to avoid passive-reply dedup (40054005)
- fall back to plain text per chunk when the platform rejects
markdown, so bots without markdown capability keep working
- route the non-stream final answer path in qq-bridge through the
markdown sender; streaming replies already use markdown content
type, and command/notice texts stay plain
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.
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.
Replace the flat button-only command menu with an information-architected
assistant center: status summary header, session dropdown (current session
pre-selected), workspace/model/preset dropdowns with current value shown,
archive toggle, task control (stop/compact/steer), watch multi-select, and a
collapsed settings panel. All commands expose card or dropdown entry points.