@openacp/cli 2026.401.2 → 2026.401.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +217 -79
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.js +188 -61
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -291,6 +291,7 @@ interface SessionRecord<P = Record<string, unknown>> {
|
|
|
291
291
|
interface TelegramPlatformData {
|
|
292
292
|
topicId: number;
|
|
293
293
|
skillMsgId?: number;
|
|
294
|
+
controlMsgId?: number;
|
|
294
295
|
}
|
|
295
296
|
interface UsageRecord {
|
|
296
297
|
id: string;
|
|
@@ -2016,6 +2017,9 @@ interface EventBusEvents {
|
|
|
2016
2017
|
attachments?: unknown[];
|
|
2017
2018
|
}) => void;
|
|
2018
2019
|
"usage:recorded": (data: UsageRecordEvent) => void;
|
|
2020
|
+
"session:configChanged": (data: {
|
|
2021
|
+
sessionId: string;
|
|
2022
|
+
}) => void;
|
|
2019
2023
|
"session:agentSwitch": (data: {
|
|
2020
2024
|
sessionId: string;
|
|
2021
2025
|
fromAgent: string;
|
|
@@ -3243,6 +3247,12 @@ declare class TelegramAdapter extends MessagingAdapter {
|
|
|
3243
3247
|
private callbackCounter;
|
|
3244
3248
|
/** Pending skill commands queued when session.threadId was not yet set */
|
|
3245
3249
|
private _pendingSkillCommands;
|
|
3250
|
+
/** Control message IDs per session (for updating status text/buttons) */
|
|
3251
|
+
private controlMsgIds;
|
|
3252
|
+
/** Store control message ID in memory + persist to session record */
|
|
3253
|
+
private storeControlMsgId;
|
|
3254
|
+
/** Get control message ID (from Map, with fallback to session record) */
|
|
3255
|
+
private getControlMsgId;
|
|
3246
3256
|
private getThreadId;
|
|
3247
3257
|
private getOrCreateTracker;
|
|
3248
3258
|
constructor(core: OpenACPCore, config: TelegramChannelConfig, saveTopicIds?: (updates: {
|
|
@@ -3284,6 +3294,12 @@ declare class TelegramAdapter extends MessagingAdapter {
|
|
|
3284
3294
|
protected handleUsage(sessionId: string, content: OutgoingMessage, verbosity: DisplayVerbosity): Promise<void>;
|
|
3285
3295
|
protected handleAttachment(sessionId: string, content: OutgoingMessage): Promise<void>;
|
|
3286
3296
|
protected handleSessionEnd(sessionId: string, _content: OutgoingMessage): Promise<void>;
|
|
3297
|
+
protected handleConfigUpdate(sessionId: string, _content: OutgoingMessage): Promise<void>;
|
|
3298
|
+
/**
|
|
3299
|
+
* Edit the pinned control message to reflect current session state
|
|
3300
|
+
* (model, thought level, mode, bypass status).
|
|
3301
|
+
*/
|
|
3302
|
+
updateControlMessage(sessionId: string): Promise<void>;
|
|
3287
3303
|
protected handleError(sessionId: string, content: OutgoingMessage): Promise<void>;
|
|
3288
3304
|
protected handleSystem(sessionId: string, content: OutgoingMessage): Promise<void>;
|
|
3289
3305
|
sendPermissionRequest(sessionId: string, request: PermissionRequest): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -295,6 +295,7 @@ function resolveInstanceRoot(opts) {
|
|
|
295
295
|
if (opts.global) return path2.join(os2.homedir(), ".openacp");
|
|
296
296
|
const localRoot = path2.join(cwd, ".openacp");
|
|
297
297
|
if (fs2.existsSync(localRoot)) return localRoot;
|
|
298
|
+
if (process.env.OPENACP_INSTANCE_ROOT) return process.env.OPENACP_INSTANCE_ROOT;
|
|
298
299
|
return null;
|
|
299
300
|
}
|
|
300
301
|
function getGlobalRoot() {
|
|
@@ -12317,31 +12318,38 @@ init_log();
|
|
|
12317
12318
|
import { InlineKeyboard } from "grammy";
|
|
12318
12319
|
init_log();
|
|
12319
12320
|
var log18 = createChildLogger({ module: "telegram-cmd-admin" });
|
|
12321
|
+
function isBypassActive(session) {
|
|
12322
|
+
const modeOpt = session.getConfigByCategory("mode");
|
|
12323
|
+
return modeOpt?.type === "select" && isPermissionBypass(String(modeOpt.currentValue)) || !!session.clientOverrides.bypassPermissions;
|
|
12324
|
+
}
|
|
12320
12325
|
function setupDangerousModeCallbacks(bot, core) {
|
|
12321
12326
|
bot.callbackQuery(/^d:/, async (ctx) => {
|
|
12322
12327
|
const sessionId = ctx.callbackQuery.data.slice(2);
|
|
12323
12328
|
const session = core.sessionManager.getSession(sessionId);
|
|
12324
12329
|
if (session) {
|
|
12325
|
-
const
|
|
12326
|
-
|
|
12327
|
-
log18.info(
|
|
12328
|
-
{ sessionId, dangerousMode: newDangerousMode2 },
|
|
12329
|
-
"Bypass permissions toggled via button"
|
|
12330
|
-
);
|
|
12331
|
-
core.sessionManager.patchRecord(sessionId, { clientOverrides: session.clientOverrides }).catch(() => {
|
|
12332
|
-
});
|
|
12333
|
-
const toastText2 = newDangerousMode2 ? "\u2620\uFE0F Bypass enabled \u2014 permissions auto-approved" : "\u{1F510} Bypass disabled \u2014 approvals required";
|
|
12330
|
+
const wantOn = !isBypassActive(session);
|
|
12331
|
+
const toastText2 = wantOn ? "\u2620\uFE0F Bypass Permissions enabled \u2014 permissions auto-approved" : "\u{1F510} Bypass Permissions disabled \u2014 approvals required";
|
|
12334
12332
|
try {
|
|
12335
12333
|
await ctx.answerCallbackQuery({ text: toastText2 });
|
|
12336
12334
|
} catch {
|
|
12337
12335
|
}
|
|
12336
|
+
const registry = core.lifecycleManager?.serviceRegistry?.get("command-registry");
|
|
12337
|
+
if (registry) {
|
|
12338
|
+
await registry.execute(wantOn ? "/bypass on" : "/bypass off", {
|
|
12339
|
+
raw: wantOn ? "on" : "off",
|
|
12340
|
+
sessionId,
|
|
12341
|
+
channelId: "telegram",
|
|
12342
|
+
userId: String(ctx.from?.id ?? ""),
|
|
12343
|
+
reply: async () => {
|
|
12344
|
+
}
|
|
12345
|
+
}).catch(() => {
|
|
12346
|
+
});
|
|
12347
|
+
}
|
|
12348
|
+
log18.info({ sessionId, wantOn }, "Bypass permissions toggled via button");
|
|
12338
12349
|
try {
|
|
12339
|
-
await ctx.
|
|
12340
|
-
|
|
12341
|
-
|
|
12342
|
-
newDangerousMode2,
|
|
12343
|
-
session.voiceMode === "on"
|
|
12344
|
-
)
|
|
12350
|
+
await ctx.editMessageText(buildSessionStatusText(session), {
|
|
12351
|
+
parse_mode: "HTML",
|
|
12352
|
+
reply_markup: buildSessionControlKeyboard(sessionId, isBypassActive(session), session.voiceMode === "on")
|
|
12345
12353
|
});
|
|
12346
12354
|
} catch {
|
|
12347
12355
|
}
|
|
@@ -12364,7 +12372,7 @@ function setupDangerousModeCallbacks(bot, core) {
|
|
|
12364
12372
|
{ sessionId, dangerousMode: newDangerousMode },
|
|
12365
12373
|
"Bypass permissions toggled via button (store-only, session not in memory)"
|
|
12366
12374
|
);
|
|
12367
|
-
const toastText = newDangerousMode ? "\u2620\uFE0F Bypass enabled \u2014 permissions auto-approved" : "\u{1F510} Bypass disabled \u2014 approvals required";
|
|
12375
|
+
const toastText = newDangerousMode ? "\u2620\uFE0F Bypass Permissions enabled \u2014 permissions auto-approved" : "\u{1F510} Bypass Permissions disabled \u2014 approvals required";
|
|
12368
12376
|
try {
|
|
12369
12377
|
await ctx.answerCallbackQuery({ text: toastText });
|
|
12370
12378
|
} catch {
|
|
@@ -12424,7 +12432,7 @@ async function handleEnableDangerous(ctx, core) {
|
|
|
12424
12432
|
});
|
|
12425
12433
|
}
|
|
12426
12434
|
await ctx.reply(
|
|
12427
|
-
`\u2620\uFE0F <b>Bypass enabled</b>
|
|
12435
|
+
`\u2620\uFE0F <b>Bypass Permissions enabled</b>
|
|
12428
12436
|
|
|
12429
12437
|
All permission requests will be auto-approved \u2014 the agent can run any action without asking.
|
|
12430
12438
|
|
|
@@ -12475,19 +12483,42 @@ async function handleDisableDangerous(ctx, core) {
|
|
|
12475
12483
|
});
|
|
12476
12484
|
}
|
|
12477
12485
|
await ctx.reply(
|
|
12478
|
-
"\u{1F510} <b>Bypass disabled</b>\n\nYou will be asked to approve risky actions.",
|
|
12486
|
+
"\u{1F510} <b>Bypass Permissions disabled</b>\n\nYou will be asked to approve risky actions.",
|
|
12479
12487
|
{ parse_mode: "HTML" }
|
|
12480
12488
|
);
|
|
12481
12489
|
}
|
|
12482
12490
|
function buildSessionControlKeyboard(sessionId, dangerousMode, voiceMode) {
|
|
12483
12491
|
return new InlineKeyboard().text(
|
|
12484
|
-
dangerousMode ? "\u{1F510} Disable Bypass" : "\u2620\uFE0F Enable Bypass",
|
|
12492
|
+
dangerousMode ? "\u{1F510} Disable Bypass Permissions" : "\u2620\uFE0F Enable Bypass Permissions",
|
|
12485
12493
|
`d:${sessionId}`
|
|
12486
12494
|
).row().text(
|
|
12487
12495
|
voiceMode ? "\u{1F50A} Text to Speech" : "\u{1F507} Text to Speech",
|
|
12488
12496
|
`v:${sessionId}`
|
|
12489
12497
|
);
|
|
12490
12498
|
}
|
|
12499
|
+
function buildSessionStatusText(session, heading = "\u2705 New chat (same agent & workspace)") {
|
|
12500
|
+
const lines = [heading];
|
|
12501
|
+
lines.push(`<b>Agent:</b> ${escapeHtml(session.agentName)}`);
|
|
12502
|
+
lines.push(`<b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>`);
|
|
12503
|
+
const modelOpt = session.getConfigByCategory("model");
|
|
12504
|
+
if (modelOpt && modelOpt.type === "select") {
|
|
12505
|
+
const choice = modelOpt.options.flatMap((o) => "group" in o ? o.options : [o]).find((c2) => c2.value === modelOpt.currentValue);
|
|
12506
|
+
lines.push(`<b>Model:</b> ${escapeHtml(choice?.name ?? modelOpt.currentValue)}`);
|
|
12507
|
+
}
|
|
12508
|
+
const thoughtOpt = session.getConfigByCategory("thought_level");
|
|
12509
|
+
if (thoughtOpt && thoughtOpt.type === "select") {
|
|
12510
|
+
const choice = thoughtOpt.options.flatMap((o) => "group" in o ? o.options : [o]).find((c2) => c2.value === thoughtOpt.currentValue);
|
|
12511
|
+
lines.push(`<b>Thinking:</b> ${escapeHtml(choice?.name ?? thoughtOpt.currentValue)}`);
|
|
12512
|
+
}
|
|
12513
|
+
const modeOpt = session.getConfigByCategory("mode");
|
|
12514
|
+
if (isBypassActive(session)) {
|
|
12515
|
+
lines.push(`<b>Mode:</b> \u2620\uFE0F Bypass Permissions enabled`);
|
|
12516
|
+
} else if (modeOpt && modeOpt.type === "select") {
|
|
12517
|
+
const choice = modeOpt.options.flatMap((o) => "group" in o ? o.options : [o]).find((c2) => c2.value === modeOpt.currentValue);
|
|
12518
|
+
lines.push(`<b>Mode:</b> ${escapeHtml(choice?.name ?? modeOpt.currentValue)}`);
|
|
12519
|
+
}
|
|
12520
|
+
return lines.join("\n");
|
|
12521
|
+
}
|
|
12491
12522
|
function setupTTSCallbacks(bot, core) {
|
|
12492
12523
|
bot.callbackQuery(/^v:/, async (ctx) => {
|
|
12493
12524
|
const sessionId = ctx.callbackQuery.data.slice(2);
|
|
@@ -12518,12 +12549,14 @@ function setupTTSCallbacks(bot, core) {
|
|
|
12518
12549
|
} catch {
|
|
12519
12550
|
}
|
|
12520
12551
|
try {
|
|
12521
|
-
|
|
12522
|
-
|
|
12523
|
-
|
|
12524
|
-
|
|
12525
|
-
|
|
12526
|
-
|
|
12552
|
+
const keyboard = buildSessionControlKeyboard(
|
|
12553
|
+
sessionId,
|
|
12554
|
+
isBypassActive(session),
|
|
12555
|
+
newMode === "on"
|
|
12556
|
+
);
|
|
12557
|
+
await ctx.editMessageText(buildSessionStatusText(session), {
|
|
12558
|
+
parse_mode: "HTML",
|
|
12559
|
+
reply_markup: keyboard
|
|
12527
12560
|
});
|
|
12528
12561
|
} catch {
|
|
12529
12562
|
}
|
|
@@ -12747,14 +12780,14 @@ function cleanupPending(userId) {
|
|
|
12747
12780
|
function botFromCtx(ctx) {
|
|
12748
12781
|
return { api: ctx.api };
|
|
12749
12782
|
}
|
|
12750
|
-
async function handleNew(ctx, core, chatId, assistant) {
|
|
12783
|
+
async function handleNew(ctx, core, chatId, assistant, onControlMessage) {
|
|
12751
12784
|
const rawMatch = ctx.match;
|
|
12752
12785
|
const matchStr = typeof rawMatch === "string" ? rawMatch : "";
|
|
12753
12786
|
const args = matchStr.split(" ").filter(Boolean);
|
|
12754
12787
|
const agentName = args[0];
|
|
12755
12788
|
const workspace = args[1];
|
|
12756
12789
|
if (agentName && workspace) {
|
|
12757
|
-
await createSessionDirect(ctx, core, chatId, agentName, workspace);
|
|
12790
|
+
await createSessionDirect(ctx, core, chatId, agentName, workspace, onControlMessage);
|
|
12758
12791
|
return;
|
|
12759
12792
|
}
|
|
12760
12793
|
const currentThreadId = ctx.message?.message_thread_id;
|
|
@@ -12832,7 +12865,7 @@ async function startConfirmStep(ctx, chatId, userId, agentName, workspace) {
|
|
|
12832
12865
|
timer: setTimeout(() => pendingNewSessions.delete(userId), PENDING_TIMEOUT_MS)
|
|
12833
12866
|
});
|
|
12834
12867
|
}
|
|
12835
|
-
async function createSessionDirect(ctx, core, chatId, agentName, workspace) {
|
|
12868
|
+
async function createSessionDirect(ctx, core, chatId, agentName, workspace, onControlMessage) {
|
|
12836
12869
|
log19.info({ userId: ctx.from?.id, agentName, workspace }, "New session command (direct)");
|
|
12837
12870
|
let threadId;
|
|
12838
12871
|
try {
|
|
@@ -12850,19 +12883,19 @@ async function createSessionDirect(ctx, core, chatId, agentName, workspace) {
|
|
|
12850
12883
|
await ctx.api.editForumTopic(chatId, threadId, { name: finalName });
|
|
12851
12884
|
} catch {
|
|
12852
12885
|
}
|
|
12853
|
-
await ctx.api.sendMessage(
|
|
12886
|
+
const controlMsg = await ctx.api.sendMessage(
|
|
12854
12887
|
chatId,
|
|
12855
|
-
`\u2705 <b>Session started</b
|
|
12856
|
-
<b>Agent:</b> ${escapeHtml(session.agentName)}
|
|
12857
|
-
<b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>
|
|
12858
|
-
|
|
12859
|
-
This is your coding session \u2014 chat here to work with the agent.`,
|
|
12888
|
+
buildSessionStatusText(session, `\u2705 <b>Session started</b>`),
|
|
12860
12889
|
{
|
|
12861
12890
|
message_thread_id: threadId,
|
|
12862
12891
|
parse_mode: "HTML",
|
|
12863
12892
|
reply_markup: buildSessionControlKeyboard(session.id, false, false)
|
|
12864
12893
|
}
|
|
12865
12894
|
);
|
|
12895
|
+
onControlMessage?.(session.id, controlMsg.message_id);
|
|
12896
|
+
await core.sessionManager.patchRecord(session.id, {
|
|
12897
|
+
platform: { topicId: threadId }
|
|
12898
|
+
});
|
|
12866
12899
|
return threadId ?? null;
|
|
12867
12900
|
} catch (err) {
|
|
12868
12901
|
log19.error({ err }, "Session creation failed");
|
|
@@ -12877,7 +12910,7 @@ This is your coding session \u2014 chat here to work with the agent.`,
|
|
|
12877
12910
|
return null;
|
|
12878
12911
|
}
|
|
12879
12912
|
}
|
|
12880
|
-
async function handleNewChat(ctx, core, chatId) {
|
|
12913
|
+
async function handleNewChat(ctx, core, chatId, onControlMessage) {
|
|
12881
12914
|
const threadId = ctx.message?.message_thread_id;
|
|
12882
12915
|
if (!threadId) {
|
|
12883
12916
|
await ctx.reply(
|
|
@@ -12932,17 +12965,19 @@ async function handleNewChat(ctx, core, chatId) {
|
|
|
12932
12965
|
await core.sessionManager.patchRecord(session.id, { platform: {
|
|
12933
12966
|
topicId: newThreadId
|
|
12934
12967
|
} });
|
|
12935
|
-
await ctx.api.sendMessage(
|
|
12968
|
+
const controlMsg = await ctx.api.sendMessage(
|
|
12936
12969
|
chatId,
|
|
12937
|
-
`\u2705 New chat (same agent & workspace)
|
|
12938
|
-
<b>Agent:</b> ${escapeHtml(session.agentName)}
|
|
12939
|
-
<b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>`,
|
|
12970
|
+
buildSessionStatusText(session, `\u2705 New chat (same agent & workspace)`),
|
|
12940
12971
|
{
|
|
12941
12972
|
message_thread_id: newThreadId,
|
|
12942
12973
|
parse_mode: "HTML",
|
|
12943
12974
|
reply_markup: buildSessionControlKeyboard(session.id, false, false)
|
|
12944
12975
|
}
|
|
12945
12976
|
);
|
|
12977
|
+
onControlMessage?.(session.id, controlMsg.message_id);
|
|
12978
|
+
await core.sessionManager.patchRecord(session.id, {
|
|
12979
|
+
platform: { topicId: newThreadId }
|
|
12980
|
+
});
|
|
12946
12981
|
} catch (err) {
|
|
12947
12982
|
if (newThreadId) {
|
|
12948
12983
|
try {
|
|
@@ -13935,7 +13970,7 @@ Choose the repo that has Entire checkpoints enabled:`;
|
|
|
13935
13970
|
timer: setTimeout(() => pendingResumes.delete(userId), PENDING_TIMEOUT_MS2)
|
|
13936
13971
|
});
|
|
13937
13972
|
}
|
|
13938
|
-
async function executeResume(ctx, core, chatId, query, repoPath) {
|
|
13973
|
+
async function executeResume(ctx, core, chatId, query, repoPath, onControlMessage) {
|
|
13939
13974
|
const provider = await core.contextManager.getProvider(repoPath);
|
|
13940
13975
|
if (!provider) {
|
|
13941
13976
|
await ctx.reply(
|
|
@@ -13993,22 +14028,23 @@ Repo: <code>${escapeHtml(repoPath)}</code>`,
|
|
|
13993
14028
|
{ parse_mode: "HTML" }
|
|
13994
14029
|
);
|
|
13995
14030
|
}
|
|
13996
|
-
|
|
13997
|
-
chatId,
|
|
13998
|
-
`\u2705 <b>Session resumed with context</b>
|
|
13999
|
-
<b>Agent:</b> ${escapeHtml(session.agentName)}
|
|
14000
|
-
<b>Workspace:</b> <code>${escapeHtml(session.workingDirectory)}</code>
|
|
14031
|
+
const resumeHeading = `\u2705 <b>Session resumed with context</b>
|
|
14001
14032
|
<b>Sessions loaded:</b> ${sessionCount}
|
|
14002
14033
|
<b>Mode:</b> ${escapeHtml(mode)}
|
|
14003
|
-
<b>~Tokens:</b> ${tokens.toLocaleString()}
|
|
14004
|
-
|
|
14005
|
-
|
|
14034
|
+
<b>~Tokens:</b> ${tokens.toLocaleString()}`;
|
|
14035
|
+
const controlMsg = await ctx.api.sendMessage(
|
|
14036
|
+
chatId,
|
|
14037
|
+
buildSessionStatusText(session, resumeHeading),
|
|
14006
14038
|
{
|
|
14007
14039
|
message_thread_id: threadId,
|
|
14008
14040
|
parse_mode: "HTML",
|
|
14009
14041
|
reply_markup: buildSessionControlKeyboard(session.id, false, false)
|
|
14010
14042
|
}
|
|
14011
14043
|
);
|
|
14044
|
+
onControlMessage?.(session.id, controlMsg.message_id);
|
|
14045
|
+
await core.sessionManager.patchRecord(session.id, {
|
|
14046
|
+
platform: { topicId: threadId }
|
|
14047
|
+
});
|
|
14012
14048
|
} catch (err) {
|
|
14013
14049
|
log21.error({ err }, "Resume session creation failed");
|
|
14014
14050
|
if (threadId) {
|
|
@@ -14021,7 +14057,7 @@ Context is ready \u2014 chat here to continue working with the agent.`,
|
|
|
14021
14057
|
await ctx.reply(`\u274C ${escapeHtml(message)}`, { parse_mode: "HTML" });
|
|
14022
14058
|
}
|
|
14023
14059
|
}
|
|
14024
|
-
async function handleResume(ctx, core, chatId, assistant) {
|
|
14060
|
+
async function handleResume(ctx, core, chatId, assistant, onControlMessage) {
|
|
14025
14061
|
const rawMatch = ctx.match;
|
|
14026
14062
|
const matchStr = typeof rawMatch === "string" ? rawMatch : "";
|
|
14027
14063
|
const parsed = parseResumeArgs(matchStr);
|
|
@@ -14046,7 +14082,7 @@ Usage examples:
|
|
|
14046
14082
|
if (!userId) return;
|
|
14047
14083
|
await showWorkspacePicker(ctx, core, chatId, userId, query);
|
|
14048
14084
|
}
|
|
14049
|
-
async function handlePendingResumeInput(ctx, core, chatId, assistantTopicId) {
|
|
14085
|
+
async function handlePendingResumeInput(ctx, core, chatId, assistantTopicId, onControlMessage) {
|
|
14050
14086
|
const userId = ctx.from?.id;
|
|
14051
14087
|
if (!userId) return false;
|
|
14052
14088
|
const pending = pendingResumes.get(userId);
|
|
@@ -14066,10 +14102,10 @@ async function handlePendingResumeInput(ctx, core, chatId, assistantTopicId) {
|
|
|
14066
14102
|
}
|
|
14067
14103
|
const resolved = core.configManager.resolveWorkspace(workspace);
|
|
14068
14104
|
cleanupPending2(userId);
|
|
14069
|
-
await executeResume(ctx, core, chatId, pending.query, resolved);
|
|
14105
|
+
await executeResume(ctx, core, chatId, pending.query, resolved, onControlMessage);
|
|
14070
14106
|
return true;
|
|
14071
14107
|
}
|
|
14072
|
-
function setupResumeCallbacks(bot, core, chatId) {
|
|
14108
|
+
function setupResumeCallbacks(bot, core, chatId, onControlMessage) {
|
|
14073
14109
|
bot.callbackQuery(/^m:resume:/, async (ctx) => {
|
|
14074
14110
|
const data = ctx.callbackQuery.data;
|
|
14075
14111
|
const userId = ctx.from?.id;
|
|
@@ -14088,7 +14124,7 @@ function setupResumeCallbacks(bot, core, chatId) {
|
|
|
14088
14124
|
await ctx.api.editMessageText(chatId, pending.messageId, `\u23F3 Using <code>${escapeHtml(resolved)}</code>...`, { parse_mode: "HTML" });
|
|
14089
14125
|
} catch {
|
|
14090
14126
|
}
|
|
14091
|
-
await executeResume(ctx, core, chatId, pending.query, resolved);
|
|
14127
|
+
await executeResume(ctx, core, chatId, pending.query, resolved, onControlMessage);
|
|
14092
14128
|
return;
|
|
14093
14129
|
}
|
|
14094
14130
|
if (data === "m:resume:ws:custom") {
|
|
@@ -14119,7 +14155,7 @@ Or just the folder name (will use workspace baseDir)`,
|
|
|
14119
14155
|
await ctx.api.editMessageText(chatId, pending.messageId, `\u23F3 Using <code>${escapeHtml(resolved)}</code>...`, { parse_mode: "HTML" });
|
|
14120
14156
|
} catch {
|
|
14121
14157
|
}
|
|
14122
|
-
await executeResume(ctx, core, chatId, pending.query, resolved);
|
|
14158
|
+
await executeResume(ctx, core, chatId, pending.query, resolved, onControlMessage);
|
|
14123
14159
|
return;
|
|
14124
14160
|
}
|
|
14125
14161
|
});
|
|
@@ -14722,8 +14758,9 @@ Switch to <b>${escapeHtml(agentName)}</b> anyway?`,
|
|
|
14722
14758
|
init_menu();
|
|
14723
14759
|
init_menu();
|
|
14724
14760
|
function setupCommands(bot, core, chatId, assistant) {
|
|
14725
|
-
|
|
14726
|
-
bot.command("
|
|
14761
|
+
const onControlMessage = assistant?.setControlMessage;
|
|
14762
|
+
bot.command("new", (ctx) => handleNew(ctx, core, chatId, assistant, onControlMessage));
|
|
14763
|
+
bot.command("newchat", (ctx) => handleNewChat(ctx, core, chatId, onControlMessage));
|
|
14727
14764
|
bot.command("cancel", (ctx) => handleCancel(ctx, core, assistant));
|
|
14728
14765
|
bot.command("status", (ctx) => handleStatus(ctx, core));
|
|
14729
14766
|
bot.command("sessions", (ctx) => handleTopics(ctx, core));
|
|
@@ -14744,12 +14781,12 @@ function setupCommands(bot, core, chatId, assistant) {
|
|
|
14744
14781
|
bot.command("text_to_speech", (ctx) => handleTTS(ctx, core));
|
|
14745
14782
|
bot.command("verbosity", (ctx) => handleVerbosity(ctx, core));
|
|
14746
14783
|
bot.command("outputmode", (ctx) => handleOutputMode(ctx, core));
|
|
14747
|
-
bot.command("resume", (ctx) => handleResume(ctx, core, chatId, assistant));
|
|
14784
|
+
bot.command("resume", (ctx) => handleResume(ctx, core, chatId, assistant, onControlMessage));
|
|
14748
14785
|
bot.command("switch", (ctx) => handleSwitch(ctx, core));
|
|
14749
14786
|
}
|
|
14750
|
-
function setupAllCallbacks(bot, core, chatId, systemTopicIds, getAssistantSession) {
|
|
14787
|
+
function setupAllCallbacks(bot, core, chatId, systemTopicIds, getAssistantSession, onControlMessage) {
|
|
14751
14788
|
setupNewSessionCallbacks(bot, core, chatId);
|
|
14752
|
-
setupResumeCallbacks(bot, core, chatId);
|
|
14789
|
+
setupResumeCallbacks(bot, core, chatId, onControlMessage);
|
|
14753
14790
|
setupSessionCallbacks(bot, core, chatId, systemTopicIds);
|
|
14754
14791
|
setupSettingsCallbacks(bot, core, getAssistantSession ?? (() => void 0));
|
|
14755
14792
|
setupDoctorCallbacks(bot);
|
|
@@ -16128,6 +16165,29 @@ var TelegramAdapter = class extends MessagingAdapter {
|
|
|
16128
16165
|
callbackCounter = 0;
|
|
16129
16166
|
/** Pending skill commands queued when session.threadId was not yet set */
|
|
16130
16167
|
_pendingSkillCommands = /* @__PURE__ */ new Map();
|
|
16168
|
+
/** Control message IDs per session (for updating status text/buttons) */
|
|
16169
|
+
controlMsgIds = /* @__PURE__ */ new Map();
|
|
16170
|
+
/** Store control message ID in memory + persist to session record */
|
|
16171
|
+
storeControlMsgId(sessionId, msgId) {
|
|
16172
|
+
this.storeControlMsgId(sessionId, msgId);
|
|
16173
|
+
this.core.sessionManager.patchRecord(sessionId, {
|
|
16174
|
+
platform: { controlMsgId: msgId }
|
|
16175
|
+
}).catch(() => {
|
|
16176
|
+
});
|
|
16177
|
+
}
|
|
16178
|
+
/** Get control message ID (from Map, with fallback to session record) */
|
|
16179
|
+
getControlMsgId(sessionId) {
|
|
16180
|
+
let msgId = this.controlMsgIds.get(sessionId);
|
|
16181
|
+
if (!msgId) {
|
|
16182
|
+
const record = this.core.sessionManager.getSessionRecord(sessionId);
|
|
16183
|
+
const platform2 = record?.platform;
|
|
16184
|
+
if (platform2?.controlMsgId) {
|
|
16185
|
+
msgId = platform2.controlMsgId;
|
|
16186
|
+
this.storeControlMsgId(sessionId, msgId);
|
|
16187
|
+
}
|
|
16188
|
+
}
|
|
16189
|
+
return msgId;
|
|
16190
|
+
}
|
|
16131
16191
|
getThreadId(sessionId) {
|
|
16132
16192
|
const threadId = this._sessionThreadIds.get(sessionId);
|
|
16133
16193
|
if (threadId === void 0) {
|
|
@@ -16334,7 +16394,26 @@ var TelegramAdapter = class extends MessagingAdapter {
|
|
|
16334
16394
|
});
|
|
16335
16395
|
await ctx.answerCallbackQuery();
|
|
16336
16396
|
if (response.type !== "silent") {
|
|
16337
|
-
|
|
16397
|
+
if (response.type === "menu") {
|
|
16398
|
+
const keyboard = response.options.map((opt) => [
|
|
16399
|
+
{
|
|
16400
|
+
text: `${opt.label}${opt.hint ? ` \u2014 ${opt.hint}` : ""}`,
|
|
16401
|
+
callback_data: this.toCallbackData(opt.command)
|
|
16402
|
+
}
|
|
16403
|
+
]);
|
|
16404
|
+
try {
|
|
16405
|
+
await ctx.editMessageText(response.title, {
|
|
16406
|
+
reply_markup: { inline_keyboard: keyboard }
|
|
16407
|
+
});
|
|
16408
|
+
} catch {
|
|
16409
|
+
}
|
|
16410
|
+
} else if (response.type === "text" || response.type === "error") {
|
|
16411
|
+
const text3 = response.type === "text" ? response.text : `\u274C ${response.message}`;
|
|
16412
|
+
try {
|
|
16413
|
+
await ctx.editMessageText(text3, { parse_mode: "Markdown" });
|
|
16414
|
+
} catch {
|
|
16415
|
+
}
|
|
16416
|
+
}
|
|
16338
16417
|
}
|
|
16339
16418
|
} catch {
|
|
16340
16419
|
await ctx.answerCallbackQuery({ text: "Command failed" });
|
|
@@ -16364,6 +16443,9 @@ var TelegramAdapter = class extends MessagingAdapter {
|
|
|
16364
16443
|
topicId: this.assistantTopicId,
|
|
16365
16444
|
enqueuePrompt: (p) => this.assistantSession.enqueuePrompt(p)
|
|
16366
16445
|
};
|
|
16446
|
+
},
|
|
16447
|
+
(sessionId, msgId) => {
|
|
16448
|
+
this.storeControlMsgId(sessionId, msgId);
|
|
16367
16449
|
}
|
|
16368
16450
|
);
|
|
16369
16451
|
setupCommands(
|
|
@@ -16373,6 +16455,9 @@ var TelegramAdapter = class extends MessagingAdapter {
|
|
|
16373
16455
|
{
|
|
16374
16456
|
topicId: this.assistantTopicId,
|
|
16375
16457
|
getSession: () => this.assistantSession,
|
|
16458
|
+
setControlMessage: (sessionId, msgId) => {
|
|
16459
|
+
this.storeControlMsgId(sessionId, msgId);
|
|
16460
|
+
},
|
|
16376
16461
|
respawn: async () => {
|
|
16377
16462
|
if (this.assistantSession) {
|
|
16378
16463
|
await this.assistantSession.destroy();
|
|
@@ -16436,6 +16521,10 @@ var TelegramAdapter = class extends MessagingAdapter {
|
|
|
16436
16521
|
}
|
|
16437
16522
|
);
|
|
16438
16523
|
});
|
|
16524
|
+
this.core.eventBus.on("session:configChanged", ({ sessionId }) => {
|
|
16525
|
+
this.updateControlMessage(sessionId).catch(() => {
|
|
16526
|
+
});
|
|
16527
|
+
});
|
|
16439
16528
|
this.setupRoutes();
|
|
16440
16529
|
this.bot.start({
|
|
16441
16530
|
allowed_updates: ["message", "callback_query"],
|
|
@@ -16640,7 +16729,10 @@ ${lines.join("\n")}`;
|
|
|
16640
16729
|
ctx,
|
|
16641
16730
|
this.core,
|
|
16642
16731
|
this.telegramConfig.chatId,
|
|
16643
|
-
this.assistantTopicId
|
|
16732
|
+
this.assistantTopicId,
|
|
16733
|
+
(sessionId2, msgId) => {
|
|
16734
|
+
this.storeControlMsgId(sessionId2, msgId);
|
|
16735
|
+
}
|
|
16644
16736
|
)) {
|
|
16645
16737
|
return;
|
|
16646
16738
|
}
|
|
@@ -17019,6 +17111,41 @@ Task completed.
|
|
|
17019
17111
|
);
|
|
17020
17112
|
}
|
|
17021
17113
|
}
|
|
17114
|
+
async handleConfigUpdate(sessionId, _content) {
|
|
17115
|
+
await this.updateControlMessage(sessionId);
|
|
17116
|
+
}
|
|
17117
|
+
/**
|
|
17118
|
+
* Edit the pinned control message to reflect current session state
|
|
17119
|
+
* (model, thought level, mode, bypass status).
|
|
17120
|
+
*/
|
|
17121
|
+
async updateControlMessage(sessionId) {
|
|
17122
|
+
const session = this.core.sessionManager.getSession(sessionId);
|
|
17123
|
+
if (!session) return;
|
|
17124
|
+
const controlMsgId = this.getControlMsgId(sessionId);
|
|
17125
|
+
if (!controlMsgId) return;
|
|
17126
|
+
const threadId = Number(session.threadId);
|
|
17127
|
+
if (!threadId || isNaN(threadId)) return;
|
|
17128
|
+
const text3 = buildSessionStatusText(session);
|
|
17129
|
+
const keyboard = buildSessionControlKeyboard(
|
|
17130
|
+
sessionId,
|
|
17131
|
+
isBypassActive(session),
|
|
17132
|
+
session.voiceMode === "on"
|
|
17133
|
+
);
|
|
17134
|
+
try {
|
|
17135
|
+
await this.bot.api.editMessageText(
|
|
17136
|
+
this.telegramConfig.chatId,
|
|
17137
|
+
controlMsgId,
|
|
17138
|
+
text3,
|
|
17139
|
+
{ parse_mode: "HTML" }
|
|
17140
|
+
);
|
|
17141
|
+
await this.bot.api.editMessageReplyMarkup(
|
|
17142
|
+
this.telegramConfig.chatId,
|
|
17143
|
+
controlMsgId,
|
|
17144
|
+
{ reply_markup: keyboard }
|
|
17145
|
+
);
|
|
17146
|
+
} catch {
|
|
17147
|
+
}
|
|
17148
|
+
}
|
|
17022
17149
|
async handleError(sessionId, content) {
|
|
17023
17150
|
this.getTracer(sessionId)?.log("telegram", { action: "handle:error", sessionId, text: content.text });
|
|
17024
17151
|
const threadId = this.getThreadId(sessionId);
|