@@ -13,6 +13,7 @@ import type { TelegramGetChat } from "./bot/types.js";
1313import { buildTelegramOpaqueCallbackData } from "./native-command-callback-data.js" ;
1414const harness = await import ( "./bot.create-telegram-bot.test-harness.js" ) ;
1515const pluginStateTestRuntime = await import ( "openclaw/plugin-sdk/plugin-state-test-runtime" ) ;
16+ const pluginRuntime = await import ( "openclaw/plugin-sdk/plugin-runtime" ) ;
1617const conversationRuntime = await import ( "openclaw/plugin-sdk/conversation-runtime" ) ;
1718const configMutation = await import ( "openclaw/plugin-sdk/config-mutation" ) ;
1819const sessionStoreRuntime = await import ( "openclaw/plugin-sdk/session-store-runtime" ) ;
@@ -233,6 +234,7 @@ describe("createTelegramBot", () => {
233234 } ) ;
234235 afterEach ( ( ) => {
235236 pluginStateTestRuntime . resetPluginStateStoreForTests ( ) ;
237+ pluginRuntime . clearPluginInteractiveHandlers ( ) ;
236238 if ( previousStateDir === undefined ) {
237239 delete process . env . OPENCLAW_STATE_DIR ;
238240 } else {
@@ -246,6 +248,7 @@ describe("createTelegramBot", () => {
246248 previousStateDir = process . env . OPENCLAW_STATE_DIR ;
247249 process . env . OPENCLAW_STATE_DIR = createTelegramBotTestStateDir ( ) ;
248250 resetTelegramForumFlagCacheForTest ( ) ;
251+ pluginRuntime . clearPluginInteractiveHandlers ( ) ;
249252 clearAccountThrottlersForTest ( ) ;
250253 throttlerSpy . mockReset ( ) ;
251254 setTelegramBotRuntimeForTest (
@@ -1280,6 +1283,56 @@ describe("createTelegramBot", () => {
12801283 expect ( answerCallbackQuerySpy ) . toHaveBeenCalledWith ( "cbq-1" ) ;
12811284 } ) ;
12821285
1286+ it ( "routes plugin callback_query payloads to plugin handlers without fallback callback_data text" , async ( ) => {
1287+ const pluginHandler = vi . fn ( async ( ctx ) => {
1288+ expect ( ctx . callback . namespace ) . toBe ( "code-agent" ) ;
1289+ expect ( ctx . callback . payload ) . toBe ( "approve-123" ) ;
1290+ await ctx . respond . clearButtons ( ) ;
1291+ return { handled : true } ;
1292+ } ) ;
1293+ expect (
1294+ pluginRuntime . registerPluginInteractiveHandler ( "openclaw-code-agent" , {
1295+ channel : "telegram" ,
1296+ namespace : "code-agent" ,
1297+ handler : pluginHandler ,
1298+ } ) ,
1299+ ) . toEqual ( { ok : true } ) ;
1300+
1301+ createTelegramBot ( { token : "tok" } ) ;
1302+ const callbackHandler = requireValue (
1303+ onSpy . mock . calls . find ( ( call ) => call [ 0 ] === "callback_query" ) ?. [ 1 ] as
1304+ | ( ( ctx : Record < string , unknown > ) => Promise < void > )
1305+ | undefined ,
1306+ "callback_query handler" ,
1307+ ) ;
1308+
1309+ await callbackHandler ( {
1310+ callbackQuery : {
1311+ id : "cbq-plugin-1" ,
1312+ data : "code-agent:approve-123" ,
1313+ from : { id : 9 , first_name : "Ada" , username : "ada_bot" } ,
1314+ message : {
1315+ chat : { id : 1234 , type : "private" } ,
1316+ date : 1736380800 ,
1317+ message_id : 10 ,
1318+ reply_markup : {
1319+ inline_keyboard : [ [ { text : "Approve" , callback_data : "code-agent:approve-123" } ] ] ,
1320+ } ,
1321+ text : "Approve this code-agent action?" ,
1322+ } ,
1323+ } ,
1324+ me : { username : "openclaw_bot" } ,
1325+ getFile : async ( ) => ( { download : async ( ) => new Uint8Array ( ) } ) ,
1326+ } ) ;
1327+
1328+ expect ( pluginHandler ) . toHaveBeenCalledTimes ( 1 ) ;
1329+ expect ( replySpy ) . not . toHaveBeenCalled ( ) ;
1330+ expect ( editMessageReplyMarkupSpy ) . toHaveBeenCalledWith ( 1234 , 10 , {
1331+ reply_markup : { inline_keyboard : [ ] } ,
1332+ } ) ;
1333+ expect ( answerCallbackQuerySpy ) . toHaveBeenCalledWith ( "cbq-plugin-1" ) ;
1334+ } ) ;
1335+
12831336 it ( "preserves raw slash callback_query payloads as command text" , async ( ) => {
12841337 createTelegramBot ( { token : "tok" } ) ;
12851338 const callbackHandler = requireValue (
0 commit comments