@@ -965,6 +965,43 @@ describe("dispatchTelegramMessage draft streaming", () => {
965965 } ) ;
966966 } ) ;
967967
968+ it ( "emits hooks when flushing a buffered final answer after skipped reasoning" , async ( ) => {
969+ const { answerDraftStream } = setupDraftStreams ( { answerMessageId : 2001 } ) ;
970+ const context = createContext ( ) ;
971+ context . ctxPayload . SessionKey = "agent:default:telegram:direct:123" ;
972+ loadSessionStore . mockReturnValue ( {
973+ "agent:default:telegram:direct:123" : { sessionId : "s1" } ,
974+ } ) ;
975+ deliverInboundReplyWithMessageSendContext . mockResolvedValueOnce ( {
976+ status : "handled_no_send" ,
977+ } ) ;
978+ dispatchReplyWithBufferedBlockDispatcher . mockImplementation ( async ( { dispatcherOptions } ) => {
979+ await dispatcherOptions . deliver (
980+ { text : "<think>Hidden reasoning</think>Visible answer" } ,
981+ { kind : "final" } ,
982+ ) ;
983+ return { queuedFinal : true } ;
984+ } ) ;
985+
986+ await dispatchWithContext ( { context } ) ;
987+
988+ expect ( answerDraftStream . update ) . toHaveBeenCalledWith ( "Visible answer" ) ;
989+ expect ( answerDraftStream . stop ) . toHaveBeenCalled ( ) ;
990+ expectRecordFields ( mockCallArg ( emitInternalMessageSentHook ) , {
991+ content : "Visible answer" ,
992+ messageId : 2001 ,
993+ } ) ;
994+ const transcriptCall = expectRecordFields ( mockCallArg ( appendSessionTranscriptMessage ) , {
995+ transcriptPath : "/tmp/session.jsonl" ,
996+ } ) ;
997+ expectRecordFields ( transcriptCall . message , {
998+ role : "assistant" ,
999+ provider : "openclaw" ,
1000+ model : "delivery-mirror" ,
1001+ content : [ { type : "text" , text : "Visible answer" } ] ,
1002+ } ) ;
1003+ } ) ;
1004+
9681005 it ( "does not mirror non-final tool progress into the session transcript" , async ( ) => {
9691006 const context = createContext ( ) ;
9701007 context . ctxPayload . SessionKey = "agent:default:telegram:direct:123" ;
0 commit comments