@openacp/cli 2026.331.2 → 2026.331.4
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 +333 -138
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +23 -5
- package/dist/index.js +195 -63
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1056,7 +1056,7 @@ interface IChannelAdapter {
|
|
|
1056
1056
|
createSessionThread(sessionId: string, name: string): Promise<string>;
|
|
1057
1057
|
renameSessionThread(sessionId: string, newName: string): Promise<void>;
|
|
1058
1058
|
deleteSessionThread?(sessionId: string): Promise<void>;
|
|
1059
|
-
archiveSessionTopic?(sessionId: string): Promise<
|
|
1059
|
+
archiveSessionTopic?(sessionId: string): Promise<void>;
|
|
1060
1060
|
stripTTSBlock?(sessionId: string): Promise<void>;
|
|
1061
1061
|
sendSkillCommands?(sessionId: string, commands: AgentCommand[]): Promise<void>;
|
|
1062
1062
|
cleanupSkillCommands?(sessionId: string): Promise<void>;
|
|
@@ -1084,7 +1084,7 @@ declare abstract class ChannelAdapter<TCore = unknown> implements IChannelAdapte
|
|
|
1084
1084
|
sendSkillCommands(_sessionId: string, _commands: AgentCommand[]): Promise<void>;
|
|
1085
1085
|
cleanupSkillCommands(_sessionId: string): Promise<void>;
|
|
1086
1086
|
cleanupSessionState(_sessionId: string): Promise<void>;
|
|
1087
|
-
archiveSessionTopic(_sessionId: string): Promise<
|
|
1087
|
+
archiveSessionTopic(_sessionId: string): Promise<void>;
|
|
1088
1088
|
}
|
|
1089
1089
|
|
|
1090
1090
|
declare function nodeToWebWritable(nodeStream: NodeJS.WritableStream): WritableStream<Uint8Array>;
|
|
@@ -2014,6 +2014,14 @@ interface EventBusEvents {
|
|
|
2014
2014
|
attachments?: unknown[];
|
|
2015
2015
|
}) => void;
|
|
2016
2016
|
"usage:recorded": (data: UsageRecordEvent) => void;
|
|
2017
|
+
"session:agentSwitch": (data: {
|
|
2018
|
+
sessionId: string;
|
|
2019
|
+
fromAgent: string;
|
|
2020
|
+
toAgent: string;
|
|
2021
|
+
status: "starting" | "succeeded" | "failed";
|
|
2022
|
+
resumed?: boolean;
|
|
2023
|
+
error?: string;
|
|
2024
|
+
}) => void;
|
|
2017
2025
|
}
|
|
2018
2026
|
declare class EventBus extends TypedEmitter<EventBusEvents> {
|
|
2019
2027
|
}
|
|
@@ -2174,8 +2182,9 @@ declare class SessionFactory {
|
|
|
2174
2182
|
private sessionManager;
|
|
2175
2183
|
private speechServiceAccessor;
|
|
2176
2184
|
private eventBus;
|
|
2185
|
+
private instanceRoot?;
|
|
2177
2186
|
middlewareChain?: MiddlewareChain;
|
|
2178
|
-
constructor(agentManager: AgentManager, sessionManager: SessionManager, speechServiceAccessor: SpeechService | (() => SpeechService), eventBus: EventBus);
|
|
2187
|
+
constructor(agentManager: AgentManager, sessionManager: SessionManager, speechServiceAccessor: SpeechService | (() => SpeechService), eventBus: EventBus, instanceRoot?: string | undefined);
|
|
2179
2188
|
private get speechService();
|
|
2180
2189
|
create(params: SessionCreateParams): Promise<Session>;
|
|
2181
2190
|
wireSideEffects(session: Session, deps: SideEffectDeps): void;
|
|
@@ -2409,7 +2418,6 @@ declare class OpenACPCore {
|
|
|
2409
2418
|
stop(): Promise<void>;
|
|
2410
2419
|
archiveSession(sessionId: string): Promise<{
|
|
2411
2420
|
ok: true;
|
|
2412
|
-
newThreadId: string;
|
|
2413
2421
|
} | {
|
|
2414
2422
|
ok: false;
|
|
2415
2423
|
error: string;
|
|
@@ -3155,6 +3163,16 @@ declare class TelegramAdapter extends MessagingAdapter {
|
|
|
3155
3163
|
assistantTopicId?: number;
|
|
3156
3164
|
}) => Promise<void>);
|
|
3157
3165
|
start(): Promise<void>;
|
|
3166
|
+
/**
|
|
3167
|
+
* Retry an async operation with exponential backoff.
|
|
3168
|
+
* Used for Telegram API calls that may fail due to transient network issues.
|
|
3169
|
+
*/
|
|
3170
|
+
private retryWithBackoff;
|
|
3171
|
+
/**
|
|
3172
|
+
* Register Telegram commands in the background with retries.
|
|
3173
|
+
* Non-critical — bot works fine without autocomplete commands.
|
|
3174
|
+
*/
|
|
3175
|
+
private registerCommandsWithRetry;
|
|
3158
3176
|
stop(): Promise<void>;
|
|
3159
3177
|
private renderCommandResponse;
|
|
3160
3178
|
private toCallbackData;
|
|
@@ -3193,7 +3211,7 @@ declare class TelegramAdapter extends MessagingAdapter {
|
|
|
3193
3211
|
cleanupSkillCommands(sessionId: string): Promise<void>;
|
|
3194
3212
|
cleanupSessionState(sessionId: string): Promise<void>;
|
|
3195
3213
|
stripTTSBlock(sessionId: string): Promise<void>;
|
|
3196
|
-
archiveSessionTopic(sessionId: string): Promise<
|
|
3214
|
+
archiveSessionTopic(sessionId: string): Promise<void>;
|
|
3197
3215
|
}
|
|
3198
3216
|
|
|
3199
3217
|
export { ActivityTracker, type AdapterCapabilities, type AgentCapabilities, AgentCatalog, type AgentCommand, type AgentDefinition, type AgentDistribution, type AgentEvent, AgentInstance, type AgentListItem, AgentManager, AgentStore, type AgentSwitchEntry, type ApiConfig, ApiServer, type Attachment, type AuthMethod, type AuthenticateRequest, type AvailabilityResult, BaseRenderer, type BridgeDeps, CONFIG_REGISTRY, ChannelAdapter, type ChannelConfig, type CleanupResult, type CommandArgs, type CommandDef, CommandRegistry, type CommandResponse, type Config, type ConfigFieldDef, ConfigManager$1 as ConfigManager, type ConfigOption, type ConfigSelectChoice, type ConfigSelectGroup, type ContentBlock, ContextManager, type ContextOptions, type ContextProvider, type ContextQuery, type ContextResult, type ContextService, type SessionInfo as ContextSessionInfo, type DeleteTopicResult, DisplaySpecBuilder, type DisplayVerbosity, DoctorEngine, type DoctorReport, DraftManager, EntireProvider, EventBus, type EventBusEvents, FileService, type FileServiceInterface, GroqSTT, type IChannelAdapter, type IRenderer, type IncomingMessage, type InstallContext, type InstallProgress, type InstallResult, type InstalledAgent, KIND_ICONS, type ListItem, type Logger$1 as Logger, type LoggingConfig, type McpServerConfig, type MenuOption, MessageTransformer, MessagingAdapter, type MessagingAdapterConfig, type MigrateContext, type ModelInfo, type NewSessionResponse, NotificationManager, type NotificationMessage, type NotificationService, OpenACPCore, type OpenACPPlugin, type OutgoingMessage, type OutputMode, OutputModeResolver, PRODUCT_GUIDE, type PendingFix, PermissionGate, type PermissionOption, type PermissionRequest, type PlanEntry, type PluginContext, type PluginPermission, type PluginStorage, PromptQueue, type PromptResponse, type RegistryAgent, type RegistryBinaryTarget, type RegistryDistribution, type RenderedMessage, SSEManager, STATUS_ICONS, type STTOptions, type STTProvider$1 as STTProvider, type STTResult, SecurityGuard, type SecurityService, SendQueue, Session, SessionBridge, type SessionCreateParams, type SessionEvents, SessionFactory, type SessionListItem, type SessionListResponse, type SessionListResult, SessionManager, type SessionMode, type SessionModeState, type SessionModelState, type SessionRecord, type SessionStatus, type SetConfigOptionValue, type SettingsAPI, type SideEffectDeps, type SpeechProviderConfig, SpeechService, type SpeechServiceConfig, type SpeechServiceInterface, StaticServer, StderrCapture, type StopReason, StreamAdapter, type TTSOptions, type TTSProvider$1 as TTSProvider, type TTSResult, TelegramAdapter, type TelegramPlatformData, type TerminalIO, ThoughtBuffer, type ThoughtDisplaySpec, type ToolCallMeta, ToolCallTracker, type ToolCardSnapshot, ToolCardState, type ToolCardStateConfig, type ToolDisplaySpec, type ToolEntry, ToolStateMap, type ToolUpdateMeta, type TopicInfo, TopicManager, type TunnelServiceInterface, TypedEmitter, type UsageConfig, type UsageRecord, type UsageRecordEvent, type UsageService, type ViewerLinks, cleanupOldSessionLogs, createChildLogger, createSessionLogger, expandHome, extractContentText, formatTokens, formatToolSummary, formatToolTitle, getConfigValue, getFieldDef, getPidPath, getSafeFields, getStatus, initLogger, installAutoStart, isAutoStartInstalled, isAutoStartSupported, isHotReloadable, log, nodeToWebReadable, nodeToWebWritable, progressBar, resolveOptions, resolveToolIcon, runConfigEditor, setLogLevel, shutdownLogger, splitMessage, startDaemon, stopDaemon, stripCodeFences, truncateContent, uninstallAutoStart };
|
package/dist/index.js
CHANGED
|
@@ -105,7 +105,7 @@ function initLogger(config) {
|
|
|
105
105
|
target: "pino-pretty",
|
|
106
106
|
options: {
|
|
107
107
|
colorize: true,
|
|
108
|
-
translateTime: "HH:
|
|
108
|
+
translateTime: "SYS:HH:MM:ss",
|
|
109
109
|
ignore: "pid,hostname",
|
|
110
110
|
singleLine: true
|
|
111
111
|
},
|
|
@@ -2383,7 +2383,6 @@ var ChannelAdapter = class {
|
|
|
2383
2383
|
async cleanupSessionState(_sessionId) {
|
|
2384
2384
|
}
|
|
2385
2385
|
async archiveSessionTopic(_sessionId) {
|
|
2386
|
-
return "";
|
|
2387
2386
|
}
|
|
2388
2387
|
};
|
|
2389
2388
|
|
|
@@ -4742,13 +4741,17 @@ var SessionBridge = class {
|
|
|
4742
4741
|
}
|
|
4743
4742
|
};
|
|
4744
4743
|
this.session.on("status_change", this.statusChangeHandler);
|
|
4745
|
-
this.namedHandler = (name) => {
|
|
4746
|
-
this.deps.sessionManager.
|
|
4744
|
+
this.namedHandler = async (name) => {
|
|
4745
|
+
const record = this.deps.sessionManager.getSessionRecord(this.session.id);
|
|
4746
|
+
const alreadyNamed = !!record?.name;
|
|
4747
|
+
await this.deps.sessionManager.patchRecord(this.session.id, { name });
|
|
4747
4748
|
this.deps.eventBus?.emit("session:updated", {
|
|
4748
4749
|
sessionId: this.session.id,
|
|
4749
4750
|
name
|
|
4750
4751
|
});
|
|
4751
|
-
|
|
4752
|
+
if (!alreadyNamed) {
|
|
4753
|
+
await this.adapter.renameSessionThread(this.session.id, name);
|
|
4754
|
+
}
|
|
4752
4755
|
};
|
|
4753
4756
|
this.session.on("named", this.namedHandler);
|
|
4754
4757
|
this.promptCountHandler = (count) => {
|
|
@@ -4762,11 +4765,12 @@ var SessionBridge = class {
|
|
|
4762
4765
|
init_log();
|
|
4763
4766
|
var log7 = createChildLogger({ module: "session-factory" });
|
|
4764
4767
|
var SessionFactory = class {
|
|
4765
|
-
constructor(agentManager, sessionManager, speechServiceAccessor, eventBus) {
|
|
4768
|
+
constructor(agentManager, sessionManager, speechServiceAccessor, eventBus, instanceRoot) {
|
|
4766
4769
|
this.agentManager = agentManager;
|
|
4767
4770
|
this.sessionManager = sessionManager;
|
|
4768
4771
|
this.speechServiceAccessor = speechServiceAccessor;
|
|
4769
4772
|
this.eventBus = eventBus;
|
|
4773
|
+
this.instanceRoot = instanceRoot;
|
|
4770
4774
|
}
|
|
4771
4775
|
middlewareChain;
|
|
4772
4776
|
get speechService() {
|
|
@@ -4793,14 +4797,73 @@ var SessionFactory = class {
|
|
|
4793
4797
|
channelId: result.channelId
|
|
4794
4798
|
};
|
|
4795
4799
|
}
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
createParams.
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4800
|
+
let agentInstance;
|
|
4801
|
+
try {
|
|
4802
|
+
agentInstance = createParams.resumeAgentSessionId ? await this.agentManager.resume(
|
|
4803
|
+
createParams.agentName,
|
|
4804
|
+
createParams.workingDirectory,
|
|
4805
|
+
createParams.resumeAgentSessionId
|
|
4806
|
+
) : await this.agentManager.spawn(
|
|
4807
|
+
createParams.agentName,
|
|
4808
|
+
createParams.workingDirectory
|
|
4809
|
+
);
|
|
4810
|
+
} catch (err) {
|
|
4811
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4812
|
+
const guidanceLines = [
|
|
4813
|
+
`\u274C Failed to start agent "${createParams.agentName}": ${message}`,
|
|
4814
|
+
"",
|
|
4815
|
+
"Run the agent CLI once in a terminal for this OpenACP instance to complete login or setup."
|
|
4816
|
+
];
|
|
4817
|
+
if (this.instanceRoot) {
|
|
4818
|
+
guidanceLines.push(
|
|
4819
|
+
"",
|
|
4820
|
+
"Copy and run this command in your terminal:",
|
|
4821
|
+
` cd "${this.instanceRoot}" && openacp agents run ${createParams.agentName}`
|
|
4822
|
+
);
|
|
4823
|
+
} else {
|
|
4824
|
+
guidanceLines.push(
|
|
4825
|
+
"",
|
|
4826
|
+
"Copy and run this command in your terminal (same project where you started OpenACP):",
|
|
4827
|
+
` openacp agents run ${createParams.agentName}`
|
|
4828
|
+
);
|
|
4829
|
+
}
|
|
4830
|
+
guidanceLines.push(
|
|
4831
|
+
"",
|
|
4832
|
+
"After setup completes, retry creating the session here."
|
|
4833
|
+
);
|
|
4834
|
+
const guidance = {
|
|
4835
|
+
type: "system_message",
|
|
4836
|
+
message: guidanceLines.join("\n")
|
|
4837
|
+
};
|
|
4838
|
+
const failedSession = new Session({
|
|
4839
|
+
id: createParams.existingSessionId,
|
|
4840
|
+
channelId: createParams.channelId,
|
|
4841
|
+
agentName: createParams.agentName,
|
|
4842
|
+
workingDirectory: createParams.workingDirectory,
|
|
4843
|
+
// Dummy agent instance — will never be prompted
|
|
4844
|
+
agentInstance: {
|
|
4845
|
+
sessionId: "",
|
|
4846
|
+
prompt: async () => {
|
|
4847
|
+
},
|
|
4848
|
+
cancel: async () => {
|
|
4849
|
+
},
|
|
4850
|
+
destroy: async () => {
|
|
4851
|
+
},
|
|
4852
|
+
on: () => {
|
|
4853
|
+
},
|
|
4854
|
+
off: () => {
|
|
4855
|
+
}
|
|
4856
|
+
},
|
|
4857
|
+
speechService: this.speechService
|
|
4858
|
+
});
|
|
4859
|
+
this.sessionManager.registerSession(failedSession);
|
|
4860
|
+
failedSession.emit("agent_event", guidance);
|
|
4861
|
+
this.eventBus.emit("agent:event", {
|
|
4862
|
+
sessionId: failedSession.id,
|
|
4863
|
+
event: guidance
|
|
4864
|
+
});
|
|
4865
|
+
throw err;
|
|
4866
|
+
}
|
|
4804
4867
|
agentInstance.middlewareChain = this.middlewareChain;
|
|
4805
4868
|
const session = new Session({
|
|
4806
4869
|
id: createParams.existingSessionId,
|
|
@@ -6313,7 +6376,8 @@ var OpenACPCore = class {
|
|
|
6313
6376
|
this.agentManager,
|
|
6314
6377
|
this.sessionManager,
|
|
6315
6378
|
() => this.speechService,
|
|
6316
|
-
this.eventBus
|
|
6379
|
+
this.eventBus,
|
|
6380
|
+
ctx?.root
|
|
6317
6381
|
);
|
|
6318
6382
|
this.lifecycleManager = new LifecycleManager({
|
|
6319
6383
|
serviceRegistry: new ServiceRegistry(),
|
|
@@ -6365,8 +6429,19 @@ var OpenACPCore = class {
|
|
|
6365
6429
|
this.agentCatalog.refreshRegistryIfStale().catch((err) => {
|
|
6366
6430
|
log12.warn({ err }, "Background registry refresh failed");
|
|
6367
6431
|
});
|
|
6368
|
-
|
|
6369
|
-
|
|
6432
|
+
const failures = [];
|
|
6433
|
+
for (const [name, adapter] of this.adapters.entries()) {
|
|
6434
|
+
try {
|
|
6435
|
+
await adapter.start();
|
|
6436
|
+
} catch (err) {
|
|
6437
|
+
log12.error({ err, adapter: name }, `Adapter "${name}" failed to start`);
|
|
6438
|
+
failures.push({ name, error: err });
|
|
6439
|
+
}
|
|
6440
|
+
}
|
|
6441
|
+
if (failures.length > 0 && failures.length === this.adapters.size) {
|
|
6442
|
+
throw new Error(
|
|
6443
|
+
`All adapters failed to start: ${failures.map((f) => f.name).join(", ")}`
|
|
6444
|
+
);
|
|
6370
6445
|
}
|
|
6371
6446
|
}
|
|
6372
6447
|
async stop() {
|
|
@@ -6397,20 +6472,9 @@ var OpenACPCore = class {
|
|
|
6397
6472
|
if (!adapter) return { ok: false, error: "Adapter not found for session" };
|
|
6398
6473
|
if (!adapter.archiveSessionTopic) return { ok: false, error: "Adapter does not support topic archiving" };
|
|
6399
6474
|
try {
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
const platform2 = {};
|
|
6404
|
-
if (session.channelId === "telegram") {
|
|
6405
|
-
platform2.topicId = Number(newThreadId);
|
|
6406
|
-
} else {
|
|
6407
|
-
platform2.threadId = newThreadId;
|
|
6408
|
-
}
|
|
6409
|
-
await this.sessionManager.patchRecord(sessionId, { platform: platform2 });
|
|
6410
|
-
} catch (patchErr) {
|
|
6411
|
-
log12.warn({ err: patchErr, sessionId }, "Failed to update session record after archive \u2014 session will work but may not survive restart");
|
|
6412
|
-
}
|
|
6413
|
-
return { ok: true, newThreadId };
|
|
6475
|
+
await adapter.archiveSessionTopic(session.id);
|
|
6476
|
+
await this.sessionManager.cancelSession(sessionId);
|
|
6477
|
+
return { ok: true };
|
|
6414
6478
|
} catch (err) {
|
|
6415
6479
|
session.archiving = false;
|
|
6416
6480
|
return { ok: false, error: err.message };
|
|
@@ -6717,6 +6781,21 @@ var OpenACPCore = class {
|
|
|
6717
6781
|
const caps = getAgentCapabilities(toAgent);
|
|
6718
6782
|
const canResume = !!(lastEntry && caps.supportsResume && lastEntry.promptCount === 0);
|
|
6719
6783
|
const resumed = canResume;
|
|
6784
|
+
const startEvent = {
|
|
6785
|
+
type: "system_message",
|
|
6786
|
+
message: `Switching from ${fromAgent} to ${toAgent}...`
|
|
6787
|
+
};
|
|
6788
|
+
session.emit("agent_event", startEvent);
|
|
6789
|
+
this.eventBus.emit("agent:event", {
|
|
6790
|
+
sessionId,
|
|
6791
|
+
event: startEvent
|
|
6792
|
+
});
|
|
6793
|
+
this.eventBus.emit("session:agentSwitch", {
|
|
6794
|
+
sessionId,
|
|
6795
|
+
fromAgent,
|
|
6796
|
+
toAgent,
|
|
6797
|
+
status: "starting"
|
|
6798
|
+
});
|
|
6720
6799
|
const bridge = this.bridges.get(sessionId);
|
|
6721
6800
|
if (bridge) bridge.disconnect();
|
|
6722
6801
|
const switchAdapter = this.adapters.get(session.channelId);
|
|
@@ -6751,7 +6830,40 @@ var OpenACPCore = class {
|
|
|
6751
6830
|
return instance;
|
|
6752
6831
|
}
|
|
6753
6832
|
});
|
|
6833
|
+
const successEvent = {
|
|
6834
|
+
type: "system_message",
|
|
6835
|
+
message: resumed ? `Switched to ${toAgent} (resumed previous session).` : `Switched to ${toAgent} (new session).`
|
|
6836
|
+
};
|
|
6837
|
+
session.emit("agent_event", successEvent);
|
|
6838
|
+
this.eventBus.emit("agent:event", {
|
|
6839
|
+
sessionId,
|
|
6840
|
+
event: successEvent
|
|
6841
|
+
});
|
|
6842
|
+
this.eventBus.emit("session:agentSwitch", {
|
|
6843
|
+
sessionId,
|
|
6844
|
+
fromAgent,
|
|
6845
|
+
toAgent,
|
|
6846
|
+
status: "succeeded",
|
|
6847
|
+
resumed
|
|
6848
|
+
});
|
|
6754
6849
|
} catch (err) {
|
|
6850
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
6851
|
+
const failedEvent = {
|
|
6852
|
+
type: "system_message",
|
|
6853
|
+
message: `Failed to switch to ${toAgent}: ${errorMessage}`
|
|
6854
|
+
};
|
|
6855
|
+
session.emit("agent_event", failedEvent);
|
|
6856
|
+
this.eventBus.emit("agent:event", {
|
|
6857
|
+
sessionId,
|
|
6858
|
+
event: failedEvent
|
|
6859
|
+
});
|
|
6860
|
+
this.eventBus.emit("session:agentSwitch", {
|
|
6861
|
+
sessionId,
|
|
6862
|
+
fromAgent,
|
|
6863
|
+
toAgent,
|
|
6864
|
+
status: "failed",
|
|
6865
|
+
error: errorMessage
|
|
6866
|
+
});
|
|
6755
6867
|
try {
|
|
6756
6868
|
let rollbackInstance;
|
|
6757
6869
|
try {
|
|
@@ -13901,7 +14013,7 @@ async function handleArchive(ctx, core) {
|
|
|
13901
14013
|
return;
|
|
13902
14014
|
}
|
|
13903
14015
|
await ctx.reply(
|
|
13904
|
-
"\u26A0\uFE0F <b>Archive this session?</b>\n\nThis will:\n\u2022
|
|
14016
|
+
"\u26A0\uFE0F <b>Archive this session?</b>\n\nThis will:\n\u2022 Stop the agent session\n\u2022 Delete this topic permanently\n\n<i>This cannot be undone.</i>",
|
|
13905
14017
|
{
|
|
13906
14018
|
parse_mode: "HTML",
|
|
13907
14019
|
reply_markup: new InlineKeyboard3().text("\u{1F5D1} Yes, archive", `ar:yes:${identifier}`).text("\u274C Cancel", `ar:no:${identifier}`)
|
|
@@ -13922,18 +14034,7 @@ async function handleArchiveConfirm(ctx, core, chatId) {
|
|
|
13922
14034
|
return;
|
|
13923
14035
|
}
|
|
13924
14036
|
const result = await core.archiveSession(identifier);
|
|
13925
|
-
if (result.ok) {
|
|
13926
|
-
const adapter = core.adapters.get("telegram");
|
|
13927
|
-
if (adapter) {
|
|
13928
|
-
try {
|
|
13929
|
-
await adapter.sendMessage(identifier, {
|
|
13930
|
-
type: "text",
|
|
13931
|
-
text: "Chat history cleared. Session is still active \u2014 send a message to continue."
|
|
13932
|
-
});
|
|
13933
|
-
} catch {
|
|
13934
|
-
}
|
|
13935
|
-
}
|
|
13936
|
-
} else {
|
|
14037
|
+
if (!result.ok) {
|
|
13937
14038
|
try {
|
|
13938
14039
|
await ctx.editMessageText(`Failed to archive: <code>${escapeHtml(result.error)}</code>`, { parse_mode: "HTML" });
|
|
13939
14040
|
} catch {
|
|
@@ -16703,27 +16804,28 @@ var TelegramAdapter = class extends MessagingAdapter {
|
|
|
16703
16804
|
}
|
|
16704
16805
|
return prev(method, payload, signal);
|
|
16705
16806
|
});
|
|
16706
|
-
|
|
16707
|
-
scope: { type: "chat", chat_id: this.telegramConfig.chatId }
|
|
16708
|
-
});
|
|
16807
|
+
this.registerCommandsWithRetry();
|
|
16709
16808
|
this.bot.use((ctx, next) => {
|
|
16710
16809
|
const chatId = ctx.chat?.id ?? ctx.callbackQuery?.message?.chat?.id;
|
|
16711
16810
|
if (chatId !== this.telegramConfig.chatId) return;
|
|
16712
16811
|
return next();
|
|
16713
16812
|
});
|
|
16714
|
-
const topics = await
|
|
16715
|
-
|
|
16716
|
-
|
|
16717
|
-
|
|
16718
|
-
|
|
16719
|
-
|
|
16720
|
-
|
|
16721
|
-
|
|
16722
|
-
|
|
16723
|
-
|
|
16724
|
-
|
|
16813
|
+
const topics = await this.retryWithBackoff(
|
|
16814
|
+
() => ensureTopics(
|
|
16815
|
+
this.bot,
|
|
16816
|
+
this.telegramConfig.chatId,
|
|
16817
|
+
this.telegramConfig,
|
|
16818
|
+
async (updates) => {
|
|
16819
|
+
if (this.saveTopicIds) {
|
|
16820
|
+
await this.saveTopicIds(updates);
|
|
16821
|
+
} else {
|
|
16822
|
+
await this.core.configManager.save({
|
|
16823
|
+
channels: { telegram: updates }
|
|
16824
|
+
});
|
|
16825
|
+
}
|
|
16725
16826
|
}
|
|
16726
|
-
|
|
16827
|
+
),
|
|
16828
|
+
"ensureTopics"
|
|
16727
16829
|
);
|
|
16728
16830
|
this.notificationTopicId = topics.notificationTopicId;
|
|
16729
16831
|
this.assistantTopicId = topics.assistantTopicId;
|
|
@@ -16971,6 +17073,40 @@ var TelegramAdapter = class extends MessagingAdapter {
|
|
|
16971
17073
|
});
|
|
16972
17074
|
}
|
|
16973
17075
|
}
|
|
17076
|
+
/**
|
|
17077
|
+
* Retry an async operation with exponential backoff.
|
|
17078
|
+
* Used for Telegram API calls that may fail due to transient network issues.
|
|
17079
|
+
*/
|
|
17080
|
+
async retryWithBackoff(fn, label, maxRetries = 5, baseDelayMs = 2e3) {
|
|
17081
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
17082
|
+
try {
|
|
17083
|
+
return await fn();
|
|
17084
|
+
} catch (err) {
|
|
17085
|
+
if (attempt === maxRetries) throw err;
|
|
17086
|
+
const delay = baseDelayMs * Math.pow(2, attempt - 1);
|
|
17087
|
+
log31.warn(
|
|
17088
|
+
{ err, attempt, maxRetries, delayMs: delay, operation: label },
|
|
17089
|
+
`${label} failed, retrying in ${delay}ms`
|
|
17090
|
+
);
|
|
17091
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
17092
|
+
}
|
|
17093
|
+
}
|
|
17094
|
+
throw new Error("unreachable");
|
|
17095
|
+
}
|
|
17096
|
+
/**
|
|
17097
|
+
* Register Telegram commands in the background with retries.
|
|
17098
|
+
* Non-critical — bot works fine without autocomplete commands.
|
|
17099
|
+
*/
|
|
17100
|
+
registerCommandsWithRetry() {
|
|
17101
|
+
this.retryWithBackoff(
|
|
17102
|
+
() => this.bot.api.setMyCommands(STATIC_COMMANDS, {
|
|
17103
|
+
scope: { type: "chat", chat_id: this.telegramConfig.chatId }
|
|
17104
|
+
}),
|
|
17105
|
+
"setMyCommands"
|
|
17106
|
+
).catch((err) => {
|
|
17107
|
+
log31.warn({ err }, "Failed to register Telegram commands after retries (non-critical)");
|
|
17108
|
+
});
|
|
17109
|
+
}
|
|
16974
17110
|
async stop() {
|
|
16975
17111
|
for (const tracker of this.sessionTrackers.values()) {
|
|
16976
17112
|
tracker.destroy();
|
|
@@ -17687,10 +17823,6 @@ Task completed.
|
|
|
17687
17823
|
this.sessionTrackers.delete(session.id);
|
|
17688
17824
|
}
|
|
17689
17825
|
await deleteSessionTopic(this.bot, chatId, oldTopicId);
|
|
17690
|
-
const topicName = session.name ?? `Session ${session.id.slice(0, 6)}`;
|
|
17691
|
-
const newTopicId = await createSessionTopic(this.bot, chatId, topicName);
|
|
17692
|
-
session.archiving = false;
|
|
17693
|
-
return String(newTopicId);
|
|
17694
17826
|
}
|
|
17695
17827
|
};
|
|
17696
17828
|
export {
|