@@ -4,6 +4,7 @@ const resolveFeishuAccountMock = vi.hoisted(() => vi.fn());
44const getFeishuRuntimeMock = vi . hoisted ( ( ) => vi . fn ( ) ) ;
55const sendMessageFeishuMock = vi . hoisted ( ( ) => vi . fn ( ) ) ;
66const sendMarkdownCardFeishuMock = vi . hoisted ( ( ) => vi . fn ( ) ) ;
7+ const sendStructuredCardFeishuMock = vi . hoisted ( ( ) => vi . fn ( ) ) ;
78const sendMediaFeishuMock = vi . hoisted ( ( ) => vi . fn ( ) ) ;
89const createFeishuClientMock = vi . hoisted ( ( ) => vi . fn ( ) ) ;
910const resolveReceiveIdTypeMock = vi . hoisted ( ( ) => vi . fn ( ) ) ;
@@ -17,6 +18,7 @@ vi.mock("./runtime.js", () => ({ getFeishuRuntime: getFeishuRuntimeMock }));
1718vi . mock ( "./send.js" , ( ) => ( {
1819 sendMessageFeishu : sendMessageFeishuMock ,
1920 sendMarkdownCardFeishu : sendMarkdownCardFeishuMock ,
21+ sendStructuredCardFeishu : sendStructuredCardFeishuMock ,
2022} ) ) ;
2123vi . mock ( "./media.js" , ( ) => ( { sendMediaFeishu : sendMediaFeishuMock } ) ) ;
2224vi . mock ( "./client.js" , ( ) => ( { createFeishuClient : createFeishuClientMock } ) ) ;
@@ -56,6 +58,7 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
5658 vi . clearAllMocks ( ) ;
5759 streamingInstances . length = 0 ;
5860 sendMediaFeishuMock . mockResolvedValue ( undefined ) ;
61+ sendStructuredCardFeishuMock . mockResolvedValue ( undefined ) ;
5962
6063 resolveFeishuAccountMock . mockReturnValue ( {
6164 accountId : "main" ,
@@ -255,11 +258,17 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
255258
256259 expect ( streamingInstances ) . toHaveLength ( 1 ) ;
257260 expect ( streamingInstances [ 0 ] . start ) . toHaveBeenCalledTimes ( 1 ) ;
258- expect ( streamingInstances [ 0 ] . start ) . toHaveBeenCalledWith ( "oc_chat" , "chat_id" , {
259- replyToMessageId : undefined ,
260- replyInThread : undefined ,
261- rootId : "om_root_topic" ,
262- } ) ;
261+ expect ( streamingInstances [ 0 ] . start ) . toHaveBeenCalledWith (
262+ "oc_chat" ,
263+ "chat_id" ,
264+ expect . objectContaining ( {
265+ replyToMessageId : undefined ,
266+ replyInThread : undefined ,
267+ rootId : "om_root_topic" ,
268+ header : { title : "agent" , template : "blue" } ,
269+ note : "Agent: agent" ,
270+ } ) ,
271+ ) ;
263272 expect ( streamingInstances [ 0 ] . close ) . toHaveBeenCalledTimes ( 1 ) ;
264273 expect ( sendMessageFeishuMock ) . not . toHaveBeenCalled ( ) ;
265274 expect ( sendMarkdownCardFeishuMock ) . not . toHaveBeenCalled ( ) ;
@@ -275,7 +284,9 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
275284 expect ( streamingInstances ) . toHaveLength ( 1 ) ;
276285 expect ( streamingInstances [ 0 ] . start ) . toHaveBeenCalledTimes ( 1 ) ;
277286 expect ( streamingInstances [ 0 ] . close ) . toHaveBeenCalledTimes ( 1 ) ;
278- expect ( streamingInstances [ 0 ] . close ) . toHaveBeenCalledWith ( "```md\npartial answer\n```" ) ;
287+ expect ( streamingInstances [ 0 ] . close ) . toHaveBeenCalledWith ( "```md\npartial answer\n```" , {
288+ note : "Agent: agent" ,
289+ } ) ;
279290 } ) ;
280291
281292 it ( "delivers distinct final payloads after streaming close" , async ( ) => {
@@ -287,9 +298,16 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
287298
288299 expect ( streamingInstances ) . toHaveLength ( 2 ) ;
289300 expect ( streamingInstances [ 0 ] . close ) . toHaveBeenCalledTimes ( 1 ) ;
290- expect ( streamingInstances [ 0 ] . close ) . toHaveBeenCalledWith ( "```md\n完整回复第一段\n```" ) ;
301+ expect ( streamingInstances [ 0 ] . close ) . toHaveBeenCalledWith ( "```md\n完整回复第一段\n```" , {
302+ note : "Agent: agent" ,
303+ } ) ;
291304 expect ( streamingInstances [ 1 ] . close ) . toHaveBeenCalledTimes ( 1 ) ;
292- expect ( streamingInstances [ 1 ] . close ) . toHaveBeenCalledWith ( "```md\n完整回复第一段 + 第二段\n```" ) ;
305+ expect ( streamingInstances [ 1 ] . close ) . toHaveBeenCalledWith (
306+ "```md\n完整回复第一段 + 第二段\n```" ,
307+ {
308+ note : "Agent: agent" ,
309+ } ,
310+ ) ;
293311 expect ( sendMessageFeishuMock ) . not . toHaveBeenCalled ( ) ;
294312 expect ( sendMarkdownCardFeishuMock ) . not . toHaveBeenCalled ( ) ;
295313 } ) ;
@@ -303,7 +321,9 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
303321
304322 expect ( streamingInstances ) . toHaveLength ( 1 ) ;
305323 expect ( streamingInstances [ 0 ] . close ) . toHaveBeenCalledTimes ( 1 ) ;
306- expect ( streamingInstances [ 0 ] . close ) . toHaveBeenCalledWith ( "```md\n同一条回复\n```" ) ;
324+ expect ( streamingInstances [ 0 ] . close ) . toHaveBeenCalledWith ( "```md\n同一条回复\n```" , {
325+ note : "Agent: agent" ,
326+ } ) ;
307327 expect ( sendMessageFeishuMock ) . not . toHaveBeenCalled ( ) ;
308328 expect ( sendMarkdownCardFeishuMock ) . not . toHaveBeenCalled ( ) ;
309329 } ) ;
@@ -367,7 +387,9 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
367387
368388 expect ( streamingInstances ) . toHaveLength ( 1 ) ;
369389 expect ( streamingInstances [ 0 ] . close ) . toHaveBeenCalledTimes ( 1 ) ;
370- expect ( streamingInstances [ 0 ] . close ) . toHaveBeenCalledWith ( "hellolo world" ) ;
390+ expect ( streamingInstances [ 0 ] . close ) . toHaveBeenCalledWith ( "hellolo world" , {
391+ note : "Agent: agent" ,
392+ } ) ;
371393 } ) ;
372394
373395 it ( "sends media-only payloads as attachments" , async ( ) => {
@@ -436,7 +458,7 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
436458 ) ;
437459 } ) ;
438460
439- it ( "passes replyInThread to sendMarkdownCardFeishu for card text" , async ( ) => {
461+ it ( "passes replyInThread to sendStructuredCardFeishu for card text" , async ( ) => {
440462 resolveFeishuAccountMock . mockReturnValue ( {
441463 accountId : "main" ,
442464 appId : "app_id" ,
@@ -454,7 +476,7 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
454476 } ) ;
455477 await options . deliver ( { text : "card text" } , { kind : "final" } ) ;
456478
457- expect ( sendMarkdownCardFeishuMock ) . toHaveBeenCalledWith (
479+ expect ( sendStructuredCardFeishuMock ) . toHaveBeenCalledWith (
458480 expect . objectContaining ( {
459481 replyToMessageId : "om_msg" ,
460482 replyInThread : true ,
@@ -591,10 +613,16 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
591613 await options . deliver ( { text : "```ts\nconst x = 1\n```" } , { kind : "final" } ) ;
592614
593615 expect ( streamingInstances ) . toHaveLength ( 1 ) ;
594- expect ( streamingInstances [ 0 ] . start ) . toHaveBeenCalledWith ( "oc_chat" , "chat_id" , {
595- replyToMessageId : "om_msg" ,
596- replyInThread : true ,
597- } ) ;
616+ expect ( streamingInstances [ 0 ] . start ) . toHaveBeenCalledWith (
617+ "oc_chat" ,
618+ "chat_id" ,
619+ expect . objectContaining ( {
620+ replyToMessageId : "om_msg" ,
621+ replyInThread : true ,
622+ header : { title : "agent" , template : "blue" } ,
623+ note : "Agent: agent" ,
624+ } ) ,
625+ ) ;
598626 } ) ;
599627
600628 it ( "disables streaming for thread replies and keeps reply metadata" , async ( ) => {
@@ -608,7 +636,7 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
608636 await options . deliver ( { text : "```ts\nconst x = 1\n```" } , { kind : "final" } ) ;
609637
610638 expect ( streamingInstances ) . toHaveLength ( 0 ) ;
611- expect ( sendMarkdownCardFeishuMock ) . toHaveBeenCalledWith (
639+ expect ( sendStructuredCardFeishuMock ) . toHaveBeenCalledWith (
612640 expect . objectContaining ( {
613641 replyToMessageId : "om_msg" ,
614642 replyInThread : true ,
0 commit comments