@@ -77,11 +77,13 @@ function createRuntimeEnv(): RuntimeEnv {
7777}
7878
7979async function dispatchMessage ( params : { cfg : ClawdbotConfig ; event : FeishuMessageEvent } ) {
80+ const runtime = createRuntimeEnv ( ) ;
8081 await handleFeishuMessage ( {
8182 cfg : params . cfg ,
8283 event : params . event ,
83- runtime : createRuntimeEnv ( ) ,
84+ runtime,
8485 } ) ;
86+ return runtime ;
8587}
8688
8789describe ( "buildFeishuAgentBody" , ( ) => {
@@ -147,6 +149,8 @@ describe("handleFeishuMessage command authorization", () => {
147149 beforeEach ( ( ) => {
148150 vi . clearAllMocks ( ) ;
149151 mockShouldComputeCommandAuthorized . mockReset ( ) . mockReturnValue ( true ) ;
152+ mockGetMessageFeishu . mockReset ( ) . mockResolvedValue ( null ) ;
153+ mockListFeishuThreadMessages . mockReset ( ) . mockResolvedValue ( [ ] ) ;
150154 mockReadSessionUpdatedAt . mockReturnValue ( undefined ) ;
151155 mockResolveStorePath . mockReturnValue ( "/tmp/feishu-sessions.json" ) ;
152156 mockResolveAgentRoute . mockReturnValue ( {
@@ -1841,6 +1845,76 @@ describe("handleFeishuMessage command authorization", () => {
18411845 ) ;
18421846 } ) ;
18431847
1848+ it ( "keeps sender-scoped thread history when the inbound event and thread history use different sender ids" , async ( ) => {
1849+ mockShouldComputeCommandAuthorized . mockReturnValue ( false ) ;
1850+ mockGetMessageFeishu . mockResolvedValue ( {
1851+ messageId : "om_topic_root" ,
1852+ chatId : "oc-group" ,
1853+ content : "root starter" ,
1854+ contentType : "text" ,
1855+ threadId : "omt_topic_1" ,
1856+ } ) ;
1857+ mockListFeishuThreadMessages . mockResolvedValue ( [
1858+ {
1859+ messageId : "om_bot_reply" ,
1860+ senderId : "app_1" ,
1861+ senderType : "app" ,
1862+ content : "assistant reply" ,
1863+ contentType : "text" ,
1864+ createTime : 1710000000000 ,
1865+ } ,
1866+ {
1867+ messageId : "om_follow_up" ,
1868+ senderId : "user_topic_1" ,
1869+ senderType : "user" ,
1870+ content : "follow-up question" ,
1871+ contentType : "text" ,
1872+ createTime : 1710000001000 ,
1873+ } ,
1874+ ] ) ;
1875+
1876+ const cfg : ClawdbotConfig = {
1877+ channels : {
1878+ feishu : {
1879+ groups : {
1880+ "oc-group" : {
1881+ requireMention : false ,
1882+ groupSessionScope : "group_topic_sender" ,
1883+ } ,
1884+ } ,
1885+ } ,
1886+ } ,
1887+ } as ClawdbotConfig ;
1888+
1889+ const event : FeishuMessageEvent = {
1890+ sender : {
1891+ sender_id : {
1892+ open_id : "ou-topic-user" ,
1893+ user_id : "user_topic_1" ,
1894+ } ,
1895+ } ,
1896+ message : {
1897+ message_id : "om_topic_followup_mixed_ids" ,
1898+ root_id : "om_topic_root" ,
1899+ chat_id : "oc-group" ,
1900+ chat_type : "group" ,
1901+ message_type : "text" ,
1902+ content : JSON . stringify ( { text : "current turn" } ) ,
1903+ } ,
1904+ } ;
1905+
1906+ await dispatchMessage ( { cfg, event } ) ;
1907+
1908+ expect ( mockFinalizeInboundContext ) . toHaveBeenCalledWith (
1909+ expect . objectContaining ( {
1910+ ThreadStarterBody : "root starter" ,
1911+ ThreadHistoryBody : "assistant reply\n\nfollow-up question" ,
1912+ ThreadLabel : "Feishu thread in oc-group" ,
1913+ MessageThreadId : "om_topic_root" ,
1914+ } ) ,
1915+ ) ;
1916+ } ) ;
1917+
18441918 it ( "does not dispatch twice for the same image message_id (concurrent dedupe)" , async ( ) => {
18451919 mockShouldComputeCommandAuthorized . mockReturnValue ( false ) ;
18461920
0 commit comments