mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-11 02:46:45 +08:00
* feat(server): let web chat read back history via `multica chat history` When an agent's provider session resume fails on a web chat / Feishu task, the daemon injected SessionContinuityNoticeUnrecoverable, making the agent reply "this is a new session, no memory". But the conversation was never lost — it is persisted in chat_message, and the agent just had no command to read it back (only Slack had a history reader). Make `multica chat history` serve the stored chat_message transcript for any non-Slack session (web chat, Feishu), reusing the existing task-token authorization and the shared response shape. Route web chat / Feishu continuity notices to a new variant that tells the agent to read the transcript back instead of scripting a "new session" disclosure, and teach the Feishu channel prompt the read-back command. - handler/chat_history.go: GetChatChannelHistory falls back to chatMessageHistory (ListChatMessages, oldest-first, default recent 30) on ErrNoSlackSession. - execenv: add SessionContinuityNoticeChatTranscript; keep Unrecoverable for channels Multica stores no transcript for (e.g. WeCom). - prompt.go: route web chat / Feishu to the transcript notice; Feishu channel awareness teaches `multica chat history`. - tests: update surface/notice matrix, Feishu prompt policy, add handler transcript fallback tests. Co-Authored-By: Claude Fable 5 <[email protected]> * test(server): fix transcript read-back test to insert a real assistant row The insertChatVisibilityMessage helper hardcodes role='user', so the "assistant reply" row in TestGetChatHistory_NoSlackBindingReadsStoredTranscript was actually stored as a user message and the handler (correctly) returned role "user". Add an insertChatMessageRole helper and use it for the assistant row so the role-mapping assertion is meaningful. Co-Authored-By: Claude Fable 5 <[email protected]> * refactor(server): treat WeCom as a readable transcript surface for session continuity WeCom is fully wired on main: it persists the conversation to chat_message and stamps ChatChannelType="wecom", so `multica chat history` reads it back just like Feishu's. Stop routing it to the Unrecoverable fallback; give it the transcript notice and the `multica chat history` history command, symmetric with Feishu (no thread reader, no upload). Co-Authored-By: Claude Fable 5 <[email protected]> * fix(server): make transcript read-back reachable and honor the paging contract Addresses review on the web-chat history read-back feature. - GetChatChannelHistory no longer dead-ends on "no channel integration" when SlackHistory is nil: a no-Slack deployment (the exact target of this feature) now serves the stored chat_message transcript directly, and Slack-backed sessions still go through the Slack reader. - chatMessageHistory swaps ListChatMessages for ListChatMessagesPage, honoring the ?before cursor (encoded as created_at|id) and clamping ?limit (default 30, max 50), and advertises NextCursor on a full page so an agent can page back without re-reading the recent window. Author now uses the channel vocabulary (Bot / User) instead of the raw role string. - Adds a single SurfacePersistsTranscript predicate (web chat, Feishu, WeCom, DingTalk) as the one source of truth for "which surfaces are readable", shared by the continuity-notice router, the chat-prompt history copy, and the surface list — closing the DingTalk gap where the notice said "read it back" but the prompt said "no history reader for dingtalk". Tests: nil-reader-with-rows regression, transcript paging without duplicates or gaps, Author/TS pins, and DingTalk cases in the surface/notice and prompt tables. Co-Authored-By: Claude Fable 5 <[email protected]> * test(server): fix transcript paging test assertion The paging test wrongly asserted messages are strictly oldest-first ACROSS pages, but paging to older messages means each later page is older than the previous one — the sequence is not monotonic. The handler was correct; the assertion was wrong. Now it checks the real invariants: each page is oldest-first, and the union of all pages is exactly the transcript with no duplicates or gaps. Co-Authored-By: Claude Fable 5 <[email protected]> * fix(server): stop telling transcript surfaces their history is not in Multica The channel-awareness block opened with "This conversation and its history live in <platform>, NOT in Multica" for every channel type, and the very next line told a Feishu/WeCom/DingTalk agent that Multica stores the conversation and hands it `multica chat history` to read it back. An agent that believes the first sentence has no reason to run the command in the second. Only the useful half — do not go hunting through issues and comments — is unconditional now. Where the conversation actually lives moved into each branch: Slack keeps the original wording (true there), transcript surfaces say the conversation happens on the platform and Multica stores a transcript of it, and the defensive fallback keeps both claims for a surface that really has no reader. Co-authored-by: multica-agent <[email protected]> * fix(server): name the channel a served transcript came from HistoryPage.ChannelType is documented as empty ONLY for a session bound to no channel, but the transcript branch never set it. A WeCom/Feishu/DingTalk session that HAD messages therefore reported channel_type "" — telling the agent it was in a web-only chat — while the same session's empty read already named the platform. One endpoint, two answers, decided by whether the session happened to have messages. Reuses the existing sessionChannelType helper, so the transcript path inherits its refusal to guess: a binding read that fails for any reason other than "no such row" is reported rather than silently answered as web-only. That failure now returns the same status as the empty-read path does for the same cause, instead of the 502 reserved for a failed channel read. Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: qiushihao279-cloud <[email protected]> Co-authored-by: Claude Fable 5 <[email protected]> Co-authored-by: Bohan-J <[email protected]> Co-authored-by: multica-agent <[email protected]>