@@ -21,10 +21,13 @@ import { getDefaultCalendarAdapter, resetCalendarAdapterForTests } from "@atlas/
2121
2222import { handleTelegramWebhook } from "@/lib/server/telegram-webhook" ;
2323
24- const { sendTelegramMessageMock, routeTurnWithResponsesMock } = vi . hoisted ( ( ) => ( {
24+ const { editTelegramMessageMock, sendTelegramMessageMock, sendTelegramChatActionMock, routeTurnWithResponsesMock } =
25+ vi . hoisted ( ( ) => ( {
26+ editTelegramMessageMock : vi . fn ( ) ,
2527 sendTelegramMessageMock : vi . fn ( ) ,
28+ sendTelegramChatActionMock : vi . fn ( ) ,
2629 routeTurnWithResponsesMock : vi . fn ( )
27- } ) ) ;
30+ } ) ) ;
2831
2932vi . mock ( "@atlas/integrations" , async ( ) => {
3033 const actual = await vi . importActual < typeof import ( "@atlas/integrations" ) > ( "@atlas/integrations" ) ;
@@ -62,7 +65,9 @@ vi.mock("@atlas/integrations", async () => {
6265 }
6366 ]
6467 } ) ,
68+ editTelegramMessage : editTelegramMessageMock ,
6569 routeTurnWithResponses : routeTurnWithResponsesMock ,
70+ sendTelegramChatAction : sendTelegramChatActionMock ,
6671 sendTelegramMessage : sendTelegramMessageMock
6772 } ;
6873} ) ;
@@ -122,7 +127,9 @@ beforeEach(async () => {
122127 process . env . GOOGLE_LINK_TOKEN_SECRET = "google-link-secret" ;
123128 process . env . GOOGLE_CALENDAR_TOKEN_ENCRYPTION_KEY = Buffer . alloc ( 32 , 7 ) . toString ( "base64" ) ;
124129 resetCalendarAdapterForTests ( ) ;
130+ editTelegramMessageMock . mockReset ( ) ;
125131 sendTelegramMessageMock . mockReset ( ) ;
132+ sendTelegramChatActionMock . mockReset ( ) ;
126133 routeTurnWithResponsesMock . mockReset ( ) ;
127134 routeTurnWithResponsesMock . mockResolvedValue ( {
128135 route : "mutation" ,
@@ -140,6 +147,19 @@ beforeEach(async () => {
140147 text : "Captured and scheduled Review launch checklist."
141148 }
142149 } ) ;
150+ editTelegramMessageMock . mockImplementation ( async ( { chatId, messageId, text } ) => ( {
151+ ok : true ,
152+ result : {
153+ message_id : messageId ,
154+ date : 1_700_000_001 ,
155+ chat : {
156+ id : chatId ,
157+ type : "private"
158+ } ,
159+ text
160+ }
161+ } ) ) ;
162+ sendTelegramChatActionMock . mockResolvedValue ( undefined ) ;
143163 resetIncomingTelegramIngressStoreForTests ( ) ;
144164 resetInboxProcessingStoreForTests ( ) ;
145165 resetGoogleCalendarConnectionStoreForTests ( ) ;
@@ -422,7 +442,7 @@ describe("telegram webhook route", () => {
422442 outcome : "planned"
423443 } ,
424444 outboundDelivery : {
425- status : "sent " ,
445+ status : "edited " ,
426446 attempts : 1
427447 }
428448 } ) ;
@@ -440,9 +460,18 @@ describe("telegram webhook route", () => {
440460 expect ( listPlannerRunsForTests ( ) ) . toHaveLength ( 1 ) ;
441461 expect ( listTasksForTests ( ) ) . toHaveLength ( 1 ) ;
442462 expect ( listScheduleBlocksForTests ( ) ) . toHaveLength ( 1 ) ;
463+ expect ( sendTelegramChatActionMock ) . toHaveBeenCalledWith ( {
464+ chatId : "999" ,
465+ action : "typing"
466+ } ) ;
443467 expect ( sendTelegramMessageMock ) . toHaveBeenCalledTimes ( 1 ) ;
444468 expect ( sendTelegramMessageMock ) . toHaveBeenCalledWith ( {
445469 chatId : "999" ,
470+ text : "Checking your schedule"
471+ } ) ;
472+ expect ( editTelegramMessageMock ) . toHaveBeenCalledWith ( {
473+ chatId : "999" ,
474+ messageId : 88 ,
446475 text : expect . stringContaining ( "Scheduled 'Review launch checklist'" )
447476 } ) ;
448477 } ) ;
@@ -489,14 +518,15 @@ describe("telegram webhook route", () => {
489518 outcome : "planned"
490519 } ,
491520 outboundDelivery : {
492- status : "sent " ,
521+ status : "edited " ,
493522 attempts : 1
494523 }
495524 } ) ;
496525 expect ( listPlannerRunsForTests ( ) ) . toHaveLength ( 1 ) ;
497526 expect ( listTasksForTests ( ) ) . toHaveLength ( 1 ) ;
498527 expect ( listScheduleBlocksForTests ( ) ) . toHaveLength ( 1 ) ;
499528 expect ( sendTelegramMessageMock ) . toHaveBeenCalledTimes ( 1 ) ;
529+ expect ( editTelegramMessageMock ) . toHaveBeenCalledTimes ( 1 ) ;
500530 } ) ;
501531
502532 it ( "treats confirmed mutation turns as write-capable when recovery finds one concrete proposal" , async ( ) => {
@@ -628,8 +658,14 @@ describe("telegram webhook route", () => {
628658 expect ( listPlannerRunsForTests ( ) ) . toHaveLength ( 1 ) ;
629659 expect ( listTasksForTests ( ) ) . toHaveLength ( 1 ) ;
630660 expect ( sendTelegramMessageMock ) . toHaveBeenCalledTimes ( 1 ) ;
631- expect ( sendTelegramMessageMock ) . toHaveBeenCalledWith (
661+ expect ( sendTelegramMessageMock ) . toHaveBeenCalledWith ( {
662+ chatId : "999" ,
663+ text : "Applying that"
664+ } ) ;
665+ expect ( editTelegramMessageMock ) . toHaveBeenCalledWith (
632666 expect . objectContaining ( {
667+ chatId : "999" ,
668+ messageId : 88 ,
633669 text : expect . stringContaining ( "Scheduled 'Dentist reminder'" )
634670 } )
635671 ) ;
@@ -695,6 +731,7 @@ describe("telegram webhook route", () => {
695731 }
696732 ) ;
697733 sendTelegramMessageMock . mockClear ( ) ;
734+ editTelegramMessageMock . mockClear ( ) ;
698735
699736 const response = await handleTelegramWebhook (
700737 buildRequest ( {
@@ -752,8 +789,10 @@ describe("telegram webhook route", () => {
752789 } )
753790 } )
754791 ) ;
755- expect ( sendTelegramMessageMock ) . toHaveBeenCalledWith (
792+ expect ( editTelegramMessageMock ) . toHaveBeenCalledWith (
756793 expect . objectContaining ( {
794+ chatId : "999" ,
795+ messageId : 88 ,
757796 text : expect . stringContaining ( "Moved it to" )
758797 } )
759798 ) ;
@@ -818,6 +857,7 @@ describe("telegram webhook route", () => {
818857 }
819858 ) ;
820859 sendTelegramMessageMock . mockClear ( ) ;
860+ editTelegramMessageMock . mockClear ( ) ;
821861
822862 const response = await handleTelegramWebhook (
823863 buildRequest ( {
@@ -885,8 +925,10 @@ describe("telegram webhook route", () => {
885925 externalCalendarEventId : null ,
886926 externalCalendarId : null
887927 } ) ;
888- expect ( sendTelegramMessageMock ) . toHaveBeenCalledWith (
928+ expect ( editTelegramMessageMock ) . toHaveBeenCalledWith (
889929 expect . objectContaining ( {
930+ chatId : "999" ,
931+ messageId : 88 ,
890932 text : "Marked 'Journaling session' as done."
891933 } )
892934 ) ;
@@ -949,6 +991,17 @@ describe("telegram webhook route", () => {
949991 expect ( listPlannerRunsForTests ( ) ) . toHaveLength ( 0 ) ;
950992 expect ( listTasksForTests ( ) ) . toHaveLength ( 0 ) ;
951993 expect ( listScheduleBlocksForTests ( ) ) . toHaveLength ( 0 ) ;
994+ expect ( sendTelegramMessageMock ) . toHaveBeenCalledWith ( {
995+ chatId : "999" ,
996+ text : "Applying that"
997+ } ) ;
998+ expect ( editTelegramMessageMock ) . toHaveBeenCalledWith (
999+ expect . objectContaining ( {
1000+ chatId : "999" ,
1001+ messageId : 88 ,
1002+ text : "I have two recent proposals in view. Which one do you want me to apply?"
1003+ } )
1004+ ) ;
9521005 } ) ;
9531006
9541007 it ( "keeps conversation turns non-writing" , async ( ) => {
@@ -1116,7 +1169,7 @@ describe("telegram webhook route", () => {
11161169 reply : "Let's sort the week by deadline and energy first."
11171170 } ,
11181171 outboundDelivery : {
1119- status : "sent " ,
1172+ status : "edited " ,
11201173 attempts : 1
11211174 }
11221175 } ) ;
@@ -1200,8 +1253,15 @@ describe("telegram webhook route", () => {
12001253 } ) ;
12011254 expect ( sendTelegramMessageMock ) . toHaveBeenCalledWith ( {
12021255 chatId : "999" ,
1203- text : "Let's sort the week by deadline and energy first. "
1256+ text : "Thinking "
12041257 } ) ;
1258+ expect ( editTelegramMessageMock ) . toHaveBeenCalledWith (
1259+ expect . objectContaining ( {
1260+ chatId : "999" ,
1261+ messageId : 88 ,
1262+ text : "Let's sort the week by deadline and energy first."
1263+ } )
1264+ ) ;
12051265 } finally {
12061266 vi . useRealTimers ( ) ;
12071267 }
@@ -1256,7 +1316,7 @@ describe("telegram webhook route", () => {
12561316 reply : "We can explore tomorrow morning options first, then I can make the change after you confirm."
12571317 } ,
12581318 outboundDelivery : {
1259- status : "sent " ,
1319+ status : "edited " ,
12601320 attempts : 1
12611321 }
12621322 } ) ;
@@ -1281,8 +1341,15 @@ describe("telegram webhook route", () => {
12811341 expect ( sendTelegramMessageMock ) . toHaveBeenCalledTimes ( 1 ) ;
12821342 expect ( sendTelegramMessageMock ) . toHaveBeenCalledWith ( {
12831343 chatId : "999" ,
1284- text : "We can explore tomorrow morning options first, then I can make the change after you confirm. "
1344+ text : "Thinking "
12851345 } ) ;
1346+ expect ( editTelegramMessageMock ) . toHaveBeenCalledWith (
1347+ expect . objectContaining ( {
1348+ chatId : "999" ,
1349+ messageId : 88 ,
1350+ text : "We can explore tomorrow morning options first, then I can make the change after you confirm."
1351+ } )
1352+ ) ;
12861353 } ) ;
12871354
12881355 it ( "falls back to recent turns when summary generation fails" , async ( ) => {
@@ -1341,6 +1408,10 @@ describe("telegram webhook route", () => {
13411408 expect ( listPlannerRunsForTests ( ) ) . toHaveLength ( 0 ) ;
13421409 expect ( listTasksForTests ( ) ) . toHaveLength ( 0 ) ;
13431410 expect ( listScheduleBlocksForTests ( ) ) . toHaveLength ( 0 ) ;
1411+ expect ( sendTelegramMessageMock ) . toHaveBeenCalledWith ( {
1412+ chatId : "999" ,
1413+ text : "Thinking"
1414+ } ) ;
13441415 } ) ;
13451416
13461417 it ( "keeps write-adjacent conversation replies hedged instead of making hard system claims" , async ( ) => {
@@ -1394,13 +1465,25 @@ describe("telegram webhook route", () => {
13941465 expect ( listPlannerRunsForTests ( ) ) . toHaveLength ( 0 ) ;
13951466 expect ( listTasksForTests ( ) ) . toHaveLength ( 0 ) ;
13961467 expect ( listScheduleBlocksForTests ( ) ) . toHaveLength ( 0 ) ;
1468+ expect ( sendTelegramMessageMock ) . toHaveBeenCalledWith ( {
1469+ chatId : "999" ,
1470+ text : "Thinking"
1471+ } ) ;
1472+ expect ( editTelegramMessageMock ) . toHaveBeenCalledWith (
1473+ expect . objectContaining ( {
1474+ chatId : "999" ,
1475+ messageId : 88 ,
1476+ text :
1477+ "From our recent exchange, it sounds like you mean the dentist reminder, but I am not treating that as confirmed state."
1478+ } )
1479+ ) ;
13971480 } ) ;
13981481
13991482 it ( "retries once when Telegram follow-up delivery fails before succeeding" , async ( ) => {
14001483 process . env . TELEGRAM_WEBHOOK_SECRET = "test-webhook-secret" ;
14011484 sendTelegramMessageMock
14021485 . mockRejectedValueOnce ( new Error ( "temporary network error" ) )
1403- . mockResolvedValueOnce ( {
1486+ . mockResolvedValue ( {
14041487 ok : true ,
14051488 result : {
14061489 message_id : 89 ,
@@ -1443,11 +1526,12 @@ describe("telegram webhook route", () => {
14431526 expect ( response . body ) . toMatchObject ( {
14441527 accepted : true ,
14451528 outboundDelivery : {
1446- status : "sent " ,
1529+ status : "edited " ,
14471530 attempts : 2
14481531 }
14491532 } ) ;
14501533 expect ( sendTelegramMessageMock ) . toHaveBeenCalledTimes ( 2 ) ;
1534+ expect ( editTelegramMessageMock ) . toHaveBeenCalledTimes ( 1 ) ;
14511535 expect ( listOutgoingBotEventsForTests ( ) ) . toHaveLength ( 1 ) ;
14521536 } ) ;
14531537
@@ -1493,7 +1577,7 @@ describe("telegram webhook route", () => {
14931577 error : "telegram unavailable"
14941578 }
14951579 } ) ;
1496- expect ( sendTelegramMessageMock ) . toHaveBeenCalledTimes ( 2 ) ;
1580+ expect ( sendTelegramMessageMock ) . toHaveBeenCalledTimes ( 4 ) ;
14971581 expect ( listOutgoingBotEventsForTests ( ) ) . toHaveLength ( 1 ) ;
14981582 expect ( listOutgoingBotEventsForTests ( ) [ 0 ] ?. retryState ) . toBe ( "failed" ) ;
14991583 } ) ;
0 commit comments