@openacp/cli 2026.403.8 → 2026.404.1
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/{channel-BL33p1ZP.d.ts → channel-CmTWKnpK.d.ts} +28 -1
- package/dist/cli.js +492 -100
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +58 -11
- package/dist/index.js +420 -51
- package/dist/index.js.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8362,7 +8362,7 @@ var init_commands = __esm({
|
|
|
8362
8362
|
|
|
8363
8363
|
// src/plugins/telegram/permissions.ts
|
|
8364
8364
|
import { InlineKeyboard as InlineKeyboard11 } from "grammy";
|
|
8365
|
-
import { nanoid as
|
|
8365
|
+
import { nanoid as nanoid3 } from "nanoid";
|
|
8366
8366
|
var log30, PermissionHandler;
|
|
8367
8367
|
var init_permissions = __esm({
|
|
8368
8368
|
"src/plugins/telegram/permissions.ts"() {
|
|
@@ -8381,7 +8381,7 @@ var init_permissions = __esm({
|
|
|
8381
8381
|
pending = /* @__PURE__ */ new Map();
|
|
8382
8382
|
async sendPermissionRequest(session, request) {
|
|
8383
8383
|
const threadId = Number(session.threadId);
|
|
8384
|
-
const callbackKey =
|
|
8384
|
+
const callbackKey = nanoid3(8);
|
|
8385
8385
|
this.pending.set(callbackKey, {
|
|
8386
8386
|
sessionId: session.id,
|
|
8387
8387
|
requestId: request.id,
|
|
@@ -11182,6 +11182,7 @@ var AgentInstance = class _AgentInstance extends TypedEmitter {
|
|
|
11182
11182
|
{ sessionId: this.sessionId, exitCode: code, signal },
|
|
11183
11183
|
"Agent process exited"
|
|
11184
11184
|
);
|
|
11185
|
+
if (signal === "SIGINT" || signal === "SIGTERM") return;
|
|
11185
11186
|
if (code !== 0 && code !== null || signal) {
|
|
11186
11187
|
const stderr = this.stderrCapture.getLastLines();
|
|
11187
11188
|
this.emit("agent_event", {
|
|
@@ -11657,7 +11658,7 @@ var AgentManager = class {
|
|
|
11657
11658
|
};
|
|
11658
11659
|
|
|
11659
11660
|
// src/core/sessions/session.ts
|
|
11660
|
-
import { nanoid } from "nanoid";
|
|
11661
|
+
import { nanoid as nanoid2 } from "nanoid";
|
|
11661
11662
|
|
|
11662
11663
|
// src/core/sessions/prompt-queue.ts
|
|
11663
11664
|
var PromptQueue = class {
|
|
@@ -11668,21 +11669,21 @@ var PromptQueue = class {
|
|
|
11668
11669
|
queue = [];
|
|
11669
11670
|
processing = false;
|
|
11670
11671
|
abortController = null;
|
|
11671
|
-
async enqueue(text3, attachments) {
|
|
11672
|
+
async enqueue(text3, attachments, routing) {
|
|
11672
11673
|
if (this.processing) {
|
|
11673
11674
|
return new Promise((resolve6) => {
|
|
11674
|
-
this.queue.push({ text: text3, attachments, resolve: resolve6 });
|
|
11675
|
+
this.queue.push({ text: text3, attachments, routing, resolve: resolve6 });
|
|
11675
11676
|
});
|
|
11676
11677
|
}
|
|
11677
|
-
await this.process(text3, attachments);
|
|
11678
|
+
await this.process(text3, attachments, routing);
|
|
11678
11679
|
}
|
|
11679
|
-
async process(text3, attachments) {
|
|
11680
|
+
async process(text3, attachments, routing) {
|
|
11680
11681
|
this.processing = true;
|
|
11681
11682
|
this.abortController = new AbortController();
|
|
11682
11683
|
const { signal } = this.abortController;
|
|
11683
11684
|
try {
|
|
11684
11685
|
await Promise.race([
|
|
11685
|
-
this.processor(text3, attachments),
|
|
11686
|
+
this.processor(text3, attachments, routing),
|
|
11686
11687
|
new Promise((_, reject) => {
|
|
11687
11688
|
signal.addEventListener("abort", () => reject(new Error("Prompt aborted")), { once: true });
|
|
11688
11689
|
})
|
|
@@ -11700,7 +11701,7 @@ var PromptQueue = class {
|
|
|
11700
11701
|
drainNext() {
|
|
11701
11702
|
const next = this.queue.shift();
|
|
11702
11703
|
if (next) {
|
|
11703
|
-
this.process(next.text, next.attachments).then(next.resolve);
|
|
11704
|
+
this.process(next.text, next.attachments, next.routing).then(next.resolve);
|
|
11704
11705
|
}
|
|
11705
11706
|
}
|
|
11706
11707
|
clear() {
|
|
@@ -11790,6 +11791,33 @@ var PermissionGate = class {
|
|
|
11790
11791
|
// src/core/sessions/session.ts
|
|
11791
11792
|
init_log();
|
|
11792
11793
|
import * as fs10 from "fs";
|
|
11794
|
+
|
|
11795
|
+
// src/core/sessions/turn-context.ts
|
|
11796
|
+
import { nanoid } from "nanoid";
|
|
11797
|
+
function createTurnContext(sourceAdapterId, responseAdapterId) {
|
|
11798
|
+
return {
|
|
11799
|
+
turnId: nanoid(8),
|
|
11800
|
+
sourceAdapterId,
|
|
11801
|
+
responseAdapterId
|
|
11802
|
+
};
|
|
11803
|
+
}
|
|
11804
|
+
function getEffectiveTarget(ctx) {
|
|
11805
|
+
if (ctx.responseAdapterId === null) return null;
|
|
11806
|
+
return ctx.responseAdapterId ?? ctx.sourceAdapterId;
|
|
11807
|
+
}
|
|
11808
|
+
var SYSTEM_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
11809
|
+
"session_end",
|
|
11810
|
+
"system_message",
|
|
11811
|
+
"session_info_update",
|
|
11812
|
+
"config_option_update",
|
|
11813
|
+
"commands_update",
|
|
11814
|
+
"tts_strip"
|
|
11815
|
+
]);
|
|
11816
|
+
function isSystemEvent(event) {
|
|
11817
|
+
return SYSTEM_EVENT_TYPES.has(event.type);
|
|
11818
|
+
}
|
|
11819
|
+
|
|
11820
|
+
// src/core/sessions/session.ts
|
|
11793
11821
|
var moduleLog = createChildLogger({ module: "session" });
|
|
11794
11822
|
var TTS_PROMPT_INSTRUCTION = `
|
|
11795
11823
|
|
|
@@ -11807,7 +11835,15 @@ var VALID_TRANSITIONS = {
|
|
|
11807
11835
|
var Session = class extends TypedEmitter {
|
|
11808
11836
|
id;
|
|
11809
11837
|
channelId;
|
|
11810
|
-
threadId
|
|
11838
|
+
/** @deprecated Use threadIds map directly. Getter returns primary adapter's threadId. */
|
|
11839
|
+
get threadId() {
|
|
11840
|
+
return this.threadIds.get(this.channelId) ?? "";
|
|
11841
|
+
}
|
|
11842
|
+
set threadId(value) {
|
|
11843
|
+
if (value) {
|
|
11844
|
+
this.threadIds.set(this.channelId, value);
|
|
11845
|
+
}
|
|
11846
|
+
}
|
|
11811
11847
|
agentName;
|
|
11812
11848
|
workingDirectory;
|
|
11813
11849
|
agentInstance;
|
|
@@ -11828,14 +11864,21 @@ var Session = class extends TypedEmitter {
|
|
|
11828
11864
|
middlewareChain;
|
|
11829
11865
|
/** Latest commands emitted by the agent — buffered before bridge connects so they're not lost */
|
|
11830
11866
|
latestCommands = null;
|
|
11867
|
+
/** Adapters currently attached to this session (including primary) */
|
|
11868
|
+
attachedAdapters = [];
|
|
11869
|
+
/** Per-adapter thread IDs: adapterId → threadId */
|
|
11870
|
+
threadIds = /* @__PURE__ */ new Map();
|
|
11871
|
+
/** Active turn context — sealed on prompt dequeue, cleared on turn end */
|
|
11872
|
+
activeTurnContext = null;
|
|
11831
11873
|
permissionGate = new PermissionGate();
|
|
11832
11874
|
queue;
|
|
11833
11875
|
speechService;
|
|
11834
11876
|
pendingContext = null;
|
|
11835
11877
|
constructor(opts) {
|
|
11836
11878
|
super();
|
|
11837
|
-
this.id = opts.id ||
|
|
11879
|
+
this.id = opts.id || nanoid2(12);
|
|
11838
11880
|
this.channelId = opts.channelId;
|
|
11881
|
+
this.attachedAdapters = [opts.channelId];
|
|
11839
11882
|
this.agentName = opts.agentName;
|
|
11840
11883
|
this.firstAgent = opts.agentName;
|
|
11841
11884
|
this.workingDirectory = opts.workingDirectory;
|
|
@@ -11845,7 +11888,7 @@ var Session = class extends TypedEmitter {
|
|
|
11845
11888
|
this.log = createSessionLogger(this.id, moduleLog);
|
|
11846
11889
|
this.log.info({ agentName: this.agentName }, "Session created");
|
|
11847
11890
|
this.queue = new PromptQueue(
|
|
11848
|
-
(text3, attachments) => this.processPrompt(text3, attachments),
|
|
11891
|
+
(text3, attachments, routing) => this.processPrompt(text3, attachments, routing),
|
|
11849
11892
|
(err) => {
|
|
11850
11893
|
this.log.error({ err }, "Prompt execution failed");
|
|
11851
11894
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -11853,11 +11896,20 @@ var Session = class extends TypedEmitter {
|
|
|
11853
11896
|
this.emit("agent_event", { type: "error", message: `Prompt execution failed: ${message}` });
|
|
11854
11897
|
}
|
|
11855
11898
|
);
|
|
11856
|
-
this.
|
|
11899
|
+
this.wireCommandsBuffer();
|
|
11900
|
+
}
|
|
11901
|
+
/** Wire a listener on the current agentInstance to buffer commands_update events.
|
|
11902
|
+
* Must be called after every agentInstance replacement (constructor + switchAgent). */
|
|
11903
|
+
commandsBufferCleanup;
|
|
11904
|
+
wireCommandsBuffer() {
|
|
11905
|
+
this.commandsBufferCleanup?.();
|
|
11906
|
+
const handler = (event) => {
|
|
11857
11907
|
if (event.type === "commands_update") {
|
|
11858
11908
|
this.latestCommands = event.commands;
|
|
11859
11909
|
}
|
|
11860
|
-
}
|
|
11910
|
+
};
|
|
11911
|
+
this.agentInstance.on("agent_event", handler);
|
|
11912
|
+
this.commandsBufferCleanup = () => this.agentInstance.off("agent_event", handler);
|
|
11861
11913
|
}
|
|
11862
11914
|
// --- State Machine ---
|
|
11863
11915
|
get status() {
|
|
@@ -11911,7 +11963,7 @@ var Session = class extends TypedEmitter {
|
|
|
11911
11963
|
this.log.info({ voiceMode: mode }, "TTS mode changed");
|
|
11912
11964
|
}
|
|
11913
11965
|
// --- Public API ---
|
|
11914
|
-
async enqueuePrompt(text3, attachments) {
|
|
11966
|
+
async enqueuePrompt(text3, attachments, routing) {
|
|
11915
11967
|
if (this.middlewareChain) {
|
|
11916
11968
|
const payload = { text: text3, attachments, sessionId: this.id };
|
|
11917
11969
|
const result = await this.middlewareChain.execute("agent:beforePrompt", payload, async (p) => p);
|
|
@@ -11919,10 +11971,14 @@ var Session = class extends TypedEmitter {
|
|
|
11919
11971
|
text3 = result.text;
|
|
11920
11972
|
attachments = result.attachments;
|
|
11921
11973
|
}
|
|
11922
|
-
await this.queue.enqueue(text3, attachments);
|
|
11974
|
+
await this.queue.enqueue(text3, attachments, routing);
|
|
11923
11975
|
}
|
|
11924
|
-
async processPrompt(text3, attachments) {
|
|
11976
|
+
async processPrompt(text3, attachments, routing) {
|
|
11925
11977
|
if (this._status === "finished") return;
|
|
11978
|
+
this.activeTurnContext = createTurnContext(
|
|
11979
|
+
routing?.sourceAdapterId ?? this.channelId,
|
|
11980
|
+
routing?.responseAdapterId
|
|
11981
|
+
);
|
|
11926
11982
|
this.promptCount++;
|
|
11927
11983
|
this.emit("prompt_count_changed", this.promptCount);
|
|
11928
11984
|
if (this._status === "initializing" || this._status === "cancelled" || this._status === "error") {
|
|
@@ -11989,6 +12045,7 @@ ${text3}`;
|
|
|
11989
12045
|
this.log.warn({ err }, "TTS post-processing failed");
|
|
11990
12046
|
});
|
|
11991
12047
|
}
|
|
12048
|
+
this.activeTurnContext = null;
|
|
11992
12049
|
if (!this.name) {
|
|
11993
12050
|
await this.autoName();
|
|
11994
12051
|
}
|
|
@@ -12231,6 +12288,7 @@ ${result.text}` : result.text;
|
|
|
12231
12288
|
this.configOptions = [];
|
|
12232
12289
|
this.latestCommands = null;
|
|
12233
12290
|
this.applySpawnResponse(newAgent.initialSessionResponse, newAgent.agentCapabilities);
|
|
12291
|
+
this.wireCommandsBuffer();
|
|
12234
12292
|
this.log.info({ from: this.agentSwitchHistory.at(-1).agentName, to: agentName }, "Agent switched");
|
|
12235
12293
|
}
|
|
12236
12294
|
async destroy() {
|
|
@@ -12698,6 +12756,8 @@ var SessionManager = class {
|
|
|
12698
12756
|
}
|
|
12699
12757
|
getSessionByThread(channelId, threadId) {
|
|
12700
12758
|
for (const session of this.sessions.values()) {
|
|
12759
|
+
const adapterThread = session.threadIds.get(channelId);
|
|
12760
|
+
if (adapterThread === threadId) return session;
|
|
12701
12761
|
if (session.channelId === channelId && session.threadId === threadId) {
|
|
12702
12762
|
return session;
|
|
12703
12763
|
}
|
|
@@ -12765,6 +12825,67 @@ var SessionManager = class {
|
|
|
12765
12825
|
if (channelId) return all.filter((s) => s.channelId === channelId);
|
|
12766
12826
|
return all;
|
|
12767
12827
|
}
|
|
12828
|
+
listAllSessions(channelId) {
|
|
12829
|
+
if (this.store) {
|
|
12830
|
+
let records = this.store.list();
|
|
12831
|
+
if (channelId) records = records.filter((r) => r.channelId === channelId);
|
|
12832
|
+
return records.map((record) => {
|
|
12833
|
+
const live2 = this.sessions.get(record.sessionId);
|
|
12834
|
+
if (live2) {
|
|
12835
|
+
return {
|
|
12836
|
+
id: live2.id,
|
|
12837
|
+
agent: live2.agentName,
|
|
12838
|
+
status: live2.status,
|
|
12839
|
+
name: live2.name ?? null,
|
|
12840
|
+
workspace: live2.workingDirectory,
|
|
12841
|
+
channelId: live2.channelId,
|
|
12842
|
+
createdAt: live2.createdAt.toISOString(),
|
|
12843
|
+
lastActiveAt: record.lastActiveAt ?? null,
|
|
12844
|
+
dangerousMode: live2.clientOverrides.bypassPermissions ?? false,
|
|
12845
|
+
queueDepth: live2.queueDepth,
|
|
12846
|
+
promptRunning: live2.promptRunning,
|
|
12847
|
+
configOptions: live2.configOptions?.length ? live2.configOptions : void 0,
|
|
12848
|
+
capabilities: live2.agentCapabilities ?? null,
|
|
12849
|
+
isLive: true
|
|
12850
|
+
};
|
|
12851
|
+
}
|
|
12852
|
+
return {
|
|
12853
|
+
id: record.sessionId,
|
|
12854
|
+
agent: record.agentName,
|
|
12855
|
+
status: record.status,
|
|
12856
|
+
name: record.name ?? null,
|
|
12857
|
+
workspace: record.workingDir,
|
|
12858
|
+
channelId: record.channelId,
|
|
12859
|
+
createdAt: record.createdAt,
|
|
12860
|
+
lastActiveAt: record.lastActiveAt ?? null,
|
|
12861
|
+
dangerousMode: record.clientOverrides?.bypassPermissions ?? false,
|
|
12862
|
+
queueDepth: 0,
|
|
12863
|
+
promptRunning: false,
|
|
12864
|
+
configOptions: record.acpState?.configOptions,
|
|
12865
|
+
capabilities: record.acpState?.agentCapabilities ?? null,
|
|
12866
|
+
isLive: false
|
|
12867
|
+
};
|
|
12868
|
+
});
|
|
12869
|
+
}
|
|
12870
|
+
let live = Array.from(this.sessions.values());
|
|
12871
|
+
if (channelId) live = live.filter((s) => s.channelId === channelId);
|
|
12872
|
+
return live.map((s) => ({
|
|
12873
|
+
id: s.id,
|
|
12874
|
+
agent: s.agentName,
|
|
12875
|
+
status: s.status,
|
|
12876
|
+
name: s.name ?? null,
|
|
12877
|
+
workspace: s.workingDirectory,
|
|
12878
|
+
channelId: s.channelId,
|
|
12879
|
+
createdAt: s.createdAt.toISOString(),
|
|
12880
|
+
lastActiveAt: null,
|
|
12881
|
+
dangerousMode: s.clientOverrides.bypassPermissions ?? false,
|
|
12882
|
+
queueDepth: s.queueDepth,
|
|
12883
|
+
promptRunning: s.promptRunning,
|
|
12884
|
+
configOptions: s.configOptions?.length ? s.configOptions : void 0,
|
|
12885
|
+
capabilities: s.agentCapabilities ?? null,
|
|
12886
|
+
isLive: true
|
|
12887
|
+
}));
|
|
12888
|
+
}
|
|
12768
12889
|
listRecords(filter) {
|
|
12769
12890
|
if (!this.store) return [];
|
|
12770
12891
|
let records = this.store.list();
|
|
@@ -12787,7 +12908,14 @@ var SessionManager = class {
|
|
|
12787
12908
|
for (const session of this.sessions.values()) {
|
|
12788
12909
|
const record = this.store.get(session.id);
|
|
12789
12910
|
if (record) {
|
|
12790
|
-
await this.store.save({
|
|
12911
|
+
await this.store.save({
|
|
12912
|
+
...record,
|
|
12913
|
+
status: "finished",
|
|
12914
|
+
acpState: session.toAcpStateSnapshot(),
|
|
12915
|
+
clientOverrides: session.clientOverrides,
|
|
12916
|
+
currentPromptCount: session.promptCount,
|
|
12917
|
+
agentSwitchHistory: session.agentSwitchHistory
|
|
12918
|
+
});
|
|
12791
12919
|
}
|
|
12792
12920
|
}
|
|
12793
12921
|
this.store.flush();
|
|
@@ -12797,6 +12925,8 @@ var SessionManager = class {
|
|
|
12797
12925
|
/**
|
|
12798
12926
|
* Forcefully destroy all sessions (kill agent subprocesses).
|
|
12799
12927
|
* Use only when sessions must be fully torn down (e.g. archive).
|
|
12928
|
+
* Unlike shutdownAll(), this does NOT snapshot live session state (acpState, etc.)
|
|
12929
|
+
* because destroyed sessions are terminal and will not be resumed.
|
|
12800
12930
|
*/
|
|
12801
12931
|
async destroyAll() {
|
|
12802
12932
|
if (this.store) {
|
|
@@ -12827,13 +12957,15 @@ init_log();
|
|
|
12827
12957
|
init_bypass_detection();
|
|
12828
12958
|
var log6 = createChildLogger({ module: "session-bridge" });
|
|
12829
12959
|
var SessionBridge = class {
|
|
12830
|
-
constructor(session, adapter, deps) {
|
|
12960
|
+
constructor(session, adapter, deps, adapterId) {
|
|
12831
12961
|
this.session = session;
|
|
12832
12962
|
this.adapter = adapter;
|
|
12833
12963
|
this.deps = deps;
|
|
12964
|
+
this.adapterId = adapterId ?? adapter.name;
|
|
12834
12965
|
}
|
|
12835
12966
|
connected = false;
|
|
12836
12967
|
cleanupFns = [];
|
|
12968
|
+
adapterId;
|
|
12837
12969
|
get tracer() {
|
|
12838
12970
|
return this.session.agentInstance.debugTracer ?? null;
|
|
12839
12971
|
}
|
|
@@ -12864,6 +12996,15 @@ var SessionBridge = class {
|
|
|
12864
12996
|
log6.error({ err, sessionId }, "Error in sendMessage middleware");
|
|
12865
12997
|
}
|
|
12866
12998
|
}
|
|
12999
|
+
/** Determine if this bridge should forward the given event based on turn routing. */
|
|
13000
|
+
shouldForward(event) {
|
|
13001
|
+
if (isSystemEvent(event)) return true;
|
|
13002
|
+
const ctx = this.session.activeTurnContext;
|
|
13003
|
+
if (!ctx) return true;
|
|
13004
|
+
const target = getEffectiveTarget(ctx);
|
|
13005
|
+
if (target === null) return false;
|
|
13006
|
+
return this.adapterId === target;
|
|
13007
|
+
}
|
|
12867
13008
|
connect() {
|
|
12868
13009
|
if (this.connected) return;
|
|
12869
13010
|
this.connected = true;
|
|
@@ -12871,11 +13012,29 @@ var SessionBridge = class {
|
|
|
12871
13012
|
this.session.emit("agent_event", event);
|
|
12872
13013
|
});
|
|
12873
13014
|
this.listen(this.session, "agent_event", (event) => {
|
|
12874
|
-
this.
|
|
13015
|
+
if (this.shouldForward(event)) {
|
|
13016
|
+
this.dispatchAgentEvent(event);
|
|
13017
|
+
} else {
|
|
13018
|
+
this.deps.eventBus?.emit("agent:event", { sessionId: this.session.id, event });
|
|
13019
|
+
}
|
|
13020
|
+
});
|
|
13021
|
+
if (!this.session.agentInstance.onPermissionRequest || this.session.agentInstance.onPermissionRequest.__bridgeId === void 0) {
|
|
13022
|
+
const handler = async (request) => {
|
|
13023
|
+
return this.resolvePermission(request);
|
|
13024
|
+
};
|
|
13025
|
+
handler.__bridgeId = this.adapterId;
|
|
13026
|
+
this.session.agentInstance.onPermissionRequest = handler;
|
|
13027
|
+
}
|
|
13028
|
+
this.listen(this.session, "permission_request", async (request) => {
|
|
13029
|
+
const current = this.session.agentInstance.onPermissionRequest;
|
|
13030
|
+
if (current?.__bridgeId === this.adapterId) return;
|
|
13031
|
+
if (!this.session.permissionGate.isPending) return;
|
|
13032
|
+
try {
|
|
13033
|
+
await this.adapter.sendPermissionRequest(this.session.id, request);
|
|
13034
|
+
} catch (err) {
|
|
13035
|
+
log6.error({ err, sessionId: this.session.id, adapterId: this.adapterId }, "Failed to send permission request to adapter");
|
|
13036
|
+
}
|
|
12875
13037
|
});
|
|
12876
|
-
this.session.agentInstance.onPermissionRequest = async (request) => {
|
|
12877
|
-
return this.resolvePermission(request);
|
|
12878
|
-
};
|
|
12879
13038
|
this.listen(this.session, "status_change", (from, to) => {
|
|
12880
13039
|
this.deps.sessionManager.patchRecord(this.session.id, {
|
|
12881
13040
|
status: to,
|
|
@@ -12916,7 +13075,10 @@ var SessionBridge = class {
|
|
|
12916
13075
|
this.connected = false;
|
|
12917
13076
|
this.cleanupFns.forEach((fn) => fn());
|
|
12918
13077
|
this.cleanupFns = [];
|
|
12919
|
-
this.session.agentInstance.onPermissionRequest
|
|
13078
|
+
const current = this.session.agentInstance.onPermissionRequest;
|
|
13079
|
+
if (current?.__bridgeId === this.adapterId) {
|
|
13080
|
+
this.session.agentInstance.onPermissionRequest = async () => "";
|
|
13081
|
+
}
|
|
12920
13082
|
}
|
|
12921
13083
|
/** Dispatch an agent event through middleware and to the adapter */
|
|
12922
13084
|
async dispatchAgentEvent(event) {
|
|
@@ -13047,8 +13209,10 @@ var SessionBridge = class {
|
|
|
13047
13209
|
this.sendMessage(this.session.id, outgoing);
|
|
13048
13210
|
break;
|
|
13049
13211
|
case "config_option_update":
|
|
13050
|
-
this.session.updateConfigOptions(event.options)
|
|
13051
|
-
|
|
13212
|
+
this.session.updateConfigOptions(event.options).then(() => {
|
|
13213
|
+
this.persistAcpState();
|
|
13214
|
+
}).catch(() => {
|
|
13215
|
+
});
|
|
13052
13216
|
outgoing = this.deps.messageTransformer.transform(event);
|
|
13053
13217
|
this.sendMessage(this.session.id, outgoing);
|
|
13054
13218
|
break;
|
|
@@ -13092,19 +13256,27 @@ var SessionBridge = class {
|
|
|
13092
13256
|
return result.autoResolve;
|
|
13093
13257
|
}
|
|
13094
13258
|
}
|
|
13095
|
-
this.session.emit("permission_request", permReq);
|
|
13096
13259
|
this.deps.eventBus?.emit("permission:request", {
|
|
13097
13260
|
sessionId: this.session.id,
|
|
13098
13261
|
permission: permReq
|
|
13099
13262
|
});
|
|
13100
13263
|
const autoDecision = this.checkAutoApprove(permReq);
|
|
13101
13264
|
if (autoDecision) {
|
|
13265
|
+
this.session.emit("permission_request", permReq);
|
|
13102
13266
|
this.emitAfterResolve(mw, permReq.id, autoDecision, "system", startTime);
|
|
13103
13267
|
return autoDecision;
|
|
13104
13268
|
}
|
|
13105
13269
|
const promise = this.session.permissionGate.setPending(permReq);
|
|
13270
|
+
this.session.emit("permission_request", permReq);
|
|
13106
13271
|
await this.adapter.sendPermissionRequest(this.session.id, permReq);
|
|
13107
13272
|
const optionId = await promise;
|
|
13273
|
+
this.deps.eventBus?.emit("permission:resolved", {
|
|
13274
|
+
sessionId: this.session.id,
|
|
13275
|
+
requestId: permReq.id,
|
|
13276
|
+
decision: optionId,
|
|
13277
|
+
optionId,
|
|
13278
|
+
resolvedBy: this.adapterId
|
|
13279
|
+
});
|
|
13108
13280
|
this.emitAfterResolve(mw, permReq.id, optionId, "user", startTime);
|
|
13109
13281
|
return optionId;
|
|
13110
13282
|
}
|
|
@@ -13298,6 +13470,65 @@ var SessionFactory = class {
|
|
|
13298
13470
|
if (session) return session;
|
|
13299
13471
|
return this.lazyResume(channelId, threadId);
|
|
13300
13472
|
}
|
|
13473
|
+
async getOrResumeById(sessionId) {
|
|
13474
|
+
const live = this.sessionManager.getSession(sessionId);
|
|
13475
|
+
if (live) return live;
|
|
13476
|
+
if (!this.sessionStore || !this.createFullSession) return null;
|
|
13477
|
+
const record = this.sessionStore.get(sessionId);
|
|
13478
|
+
if (!record) return null;
|
|
13479
|
+
if (record.status === "error" || record.status === "cancelled") return null;
|
|
13480
|
+
const existing = this.resumeLocks.get(sessionId);
|
|
13481
|
+
if (existing) return existing;
|
|
13482
|
+
const resumePromise = (async () => {
|
|
13483
|
+
try {
|
|
13484
|
+
const p = record.platform;
|
|
13485
|
+
const existingThreadId = p?.topicId ? String(p.topicId) : p?.threadId;
|
|
13486
|
+
const session = await this.createFullSession({
|
|
13487
|
+
channelId: record.channelId,
|
|
13488
|
+
agentName: record.agentName,
|
|
13489
|
+
workingDirectory: record.workingDir,
|
|
13490
|
+
resumeAgentSessionId: record.agentSessionId,
|
|
13491
|
+
existingSessionId: record.sessionId,
|
|
13492
|
+
initialName: record.name,
|
|
13493
|
+
threadId: existingThreadId
|
|
13494
|
+
});
|
|
13495
|
+
session.activate();
|
|
13496
|
+
if (record.clientOverrides) {
|
|
13497
|
+
session.clientOverrides = record.clientOverrides;
|
|
13498
|
+
} else if (record.dangerousMode) {
|
|
13499
|
+
session.clientOverrides = { bypassPermissions: true };
|
|
13500
|
+
}
|
|
13501
|
+
if (record.firstAgent) session.firstAgent = record.firstAgent;
|
|
13502
|
+
if (record.agentSwitchHistory) session.agentSwitchHistory = record.agentSwitchHistory;
|
|
13503
|
+
if (record.currentPromptCount != null) session.promptCount = record.currentPromptCount;
|
|
13504
|
+
if (record.attachedAdapters) session.attachedAdapters = record.attachedAdapters;
|
|
13505
|
+
if (record.platforms) {
|
|
13506
|
+
for (const [adapterId, platformData] of Object.entries(record.platforms)) {
|
|
13507
|
+
const data = platformData;
|
|
13508
|
+
const tid = adapterId === "telegram" ? String(data.topicId ?? "") : String(data.threadId ?? "");
|
|
13509
|
+
if (tid) session.threadIds.set(adapterId, tid);
|
|
13510
|
+
}
|
|
13511
|
+
}
|
|
13512
|
+
if (record.acpState) {
|
|
13513
|
+
if (record.acpState.configOptions && session.configOptions.length === 0) {
|
|
13514
|
+
session.setInitialConfigOptions(record.acpState.configOptions);
|
|
13515
|
+
}
|
|
13516
|
+
if (record.acpState.agentCapabilities && !session.agentCapabilities) {
|
|
13517
|
+
session.setAgentCapabilities(record.acpState.agentCapabilities);
|
|
13518
|
+
}
|
|
13519
|
+
}
|
|
13520
|
+
log7.info({ sessionId }, "Lazy resume by ID successful");
|
|
13521
|
+
return session;
|
|
13522
|
+
} catch (err) {
|
|
13523
|
+
log7.error({ err, sessionId }, "Lazy resume by ID failed");
|
|
13524
|
+
return null;
|
|
13525
|
+
} finally {
|
|
13526
|
+
this.resumeLocks.delete(sessionId);
|
|
13527
|
+
}
|
|
13528
|
+
})();
|
|
13529
|
+
this.resumeLocks.set(sessionId, resumePromise);
|
|
13530
|
+
return resumePromise;
|
|
13531
|
+
}
|
|
13301
13532
|
async lazyResume(channelId, threadId) {
|
|
13302
13533
|
const store = this.sessionStore;
|
|
13303
13534
|
if (!store || !this.createFullSession) return null;
|
|
@@ -13306,7 +13537,7 @@ var SessionFactory = class {
|
|
|
13306
13537
|
if (existing) return existing;
|
|
13307
13538
|
const record = store.findByPlatform(
|
|
13308
13539
|
channelId,
|
|
13309
|
-
(p) => String(p.topicId) === threadId
|
|
13540
|
+
(p) => String(p.topicId) === threadId || String(p.threadId ?? "") === threadId
|
|
13310
13541
|
);
|
|
13311
13542
|
if (!record) {
|
|
13312
13543
|
log7.debug({ threadId, channelId }, "No session record found for thread");
|
|
@@ -13341,11 +13572,21 @@ var SessionFactory = class {
|
|
|
13341
13572
|
if (record.firstAgent) session.firstAgent = record.firstAgent;
|
|
13342
13573
|
if (record.agentSwitchHistory) session.agentSwitchHistory = record.agentSwitchHistory;
|
|
13343
13574
|
if (record.currentPromptCount != null) session.promptCount = record.currentPromptCount;
|
|
13575
|
+
if (record.attachedAdapters) {
|
|
13576
|
+
session.attachedAdapters = record.attachedAdapters;
|
|
13577
|
+
}
|
|
13578
|
+
if (record.platforms) {
|
|
13579
|
+
for (const [adapterId, platformData] of Object.entries(record.platforms)) {
|
|
13580
|
+
const data = platformData;
|
|
13581
|
+
const tid = adapterId === "telegram" ? String(data.topicId ?? "") : String(data.threadId ?? "");
|
|
13582
|
+
if (tid) session.threadIds.set(adapterId, tid);
|
|
13583
|
+
}
|
|
13584
|
+
}
|
|
13344
13585
|
if (record.acpState) {
|
|
13345
|
-
if (record.acpState.configOptions) {
|
|
13586
|
+
if (record.acpState.configOptions && session.configOptions.length === 0) {
|
|
13346
13587
|
session.setInitialConfigOptions(record.acpState.configOptions);
|
|
13347
13588
|
}
|
|
13348
|
-
if (record.acpState.agentCapabilities) {
|
|
13589
|
+
if (record.acpState.agentCapabilities && !session.agentCapabilities) {
|
|
13349
13590
|
session.setAgentCapabilities(record.acpState.agentCapabilities);
|
|
13350
13591
|
}
|
|
13351
13592
|
}
|
|
@@ -13512,6 +13753,9 @@ var JsonFileSessionStore = class {
|
|
|
13512
13753
|
}
|
|
13513
13754
|
findByPlatform(channelId, predicate) {
|
|
13514
13755
|
for (const record of this.records.values()) {
|
|
13756
|
+
if (record.platforms?.[channelId]) {
|
|
13757
|
+
if (predicate(record.platforms[channelId])) return record;
|
|
13758
|
+
}
|
|
13515
13759
|
if (record.channelId === channelId && predicate(record.platform)) {
|
|
13516
13760
|
return record;
|
|
13517
13761
|
}
|
|
@@ -13578,7 +13822,7 @@ var JsonFileSessionStore = class {
|
|
|
13578
13822
|
return;
|
|
13579
13823
|
}
|
|
13580
13824
|
for (const [id, record] of Object.entries(raw.sessions)) {
|
|
13581
|
-
this.records.set(id, record);
|
|
13825
|
+
this.records.set(id, this.migrateRecord(record));
|
|
13582
13826
|
}
|
|
13583
13827
|
log8.debug({ count: this.records.size }, "Loaded session records");
|
|
13584
13828
|
} catch (err) {
|
|
@@ -13589,6 +13833,19 @@ var JsonFileSessionStore = class {
|
|
|
13589
13833
|
}
|
|
13590
13834
|
}
|
|
13591
13835
|
}
|
|
13836
|
+
/** Migrate old SessionRecord format to new multi-adapter format. */
|
|
13837
|
+
migrateRecord(record) {
|
|
13838
|
+
if (!record.platforms && record.platform && typeof record.platform === "object") {
|
|
13839
|
+
const platformData = record.platform;
|
|
13840
|
+
if (Object.keys(platformData).length > 0) {
|
|
13841
|
+
record.platforms = { [record.channelId]: platformData };
|
|
13842
|
+
}
|
|
13843
|
+
}
|
|
13844
|
+
if (!record.attachedAdapters) {
|
|
13845
|
+
record.attachedAdapters = [record.channelId];
|
|
13846
|
+
}
|
|
13847
|
+
return record;
|
|
13848
|
+
}
|
|
13592
13849
|
cleanup() {
|
|
13593
13850
|
const cutoff = Date.now() - this.ttlDays * 24 * 60 * 60 * 1e3;
|
|
13594
13851
|
let removed = 0;
|
|
@@ -13667,8 +13924,15 @@ var AgentSwitchHandler = class {
|
|
|
13667
13924
|
toAgent,
|
|
13668
13925
|
status: "starting"
|
|
13669
13926
|
});
|
|
13670
|
-
const
|
|
13671
|
-
|
|
13927
|
+
const sessionBridgeKeys = this.deps.getSessionBridgeKeys(sessionId);
|
|
13928
|
+
const hadBridges = sessionBridgeKeys.length > 0;
|
|
13929
|
+
for (const key of sessionBridgeKeys) {
|
|
13930
|
+
const bridge = bridges.get(key);
|
|
13931
|
+
if (bridge) {
|
|
13932
|
+
bridges.delete(key);
|
|
13933
|
+
bridge.disconnect();
|
|
13934
|
+
}
|
|
13935
|
+
}
|
|
13672
13936
|
const switchAdapter = adapters.get(session.channelId);
|
|
13673
13937
|
if (switchAdapter?.sendSkillCommands) {
|
|
13674
13938
|
await switchAdapter.sendSkillCommands(session.id, []);
|
|
@@ -13745,9 +14009,11 @@ var AgentSwitchHandler = class {
|
|
|
13745
14009
|
session.agentInstance = oldInstance;
|
|
13746
14010
|
session.agentName = fromAgent;
|
|
13747
14011
|
session.agentSessionId = oldInstance.sessionId;
|
|
13748
|
-
const
|
|
13749
|
-
|
|
13750
|
-
|
|
14012
|
+
for (const adapterId of session.attachedAdapters) {
|
|
14013
|
+
const adapter = adapters.get(adapterId);
|
|
14014
|
+
if (adapter) {
|
|
14015
|
+
createBridge(session, adapter, adapterId).connect();
|
|
14016
|
+
}
|
|
13751
14017
|
}
|
|
13752
14018
|
log9.warn({ sessionId, fromAgent, toAgent, err }, "Agent switch failed, rolled back to previous agent");
|
|
13753
14019
|
} catch (rollbackErr) {
|
|
@@ -13756,10 +14022,14 @@ var AgentSwitchHandler = class {
|
|
|
13756
14022
|
}
|
|
13757
14023
|
throw err;
|
|
13758
14024
|
}
|
|
13759
|
-
if (
|
|
13760
|
-
const
|
|
13761
|
-
|
|
13762
|
-
|
|
14025
|
+
if (hadBridges) {
|
|
14026
|
+
for (const adapterId of session.attachedAdapters) {
|
|
14027
|
+
const adapter = adapters.get(adapterId);
|
|
14028
|
+
if (adapter) {
|
|
14029
|
+
createBridge(session, adapter, adapterId).connect();
|
|
14030
|
+
} else {
|
|
14031
|
+
log9.warn({ sessionId, adapterId }, "Adapter not available during switch reconnect, skipping bridge");
|
|
14032
|
+
}
|
|
13763
14033
|
}
|
|
13764
14034
|
}
|
|
13765
14035
|
await sessionManager.patchRecord(sessionId, {
|
|
@@ -15212,7 +15482,7 @@ var OpenACPCore = class {
|
|
|
15212
15482
|
sessionManager;
|
|
15213
15483
|
messageTransformer;
|
|
15214
15484
|
adapters = /* @__PURE__ */ new Map();
|
|
15215
|
-
/** sessionId → SessionBridge — tracks active bridges for disconnect/reconnect
|
|
15485
|
+
/** "adapterId:sessionId" → SessionBridge — tracks active bridges for disconnect/reconnect */
|
|
15216
15486
|
bridges = /* @__PURE__ */ new Map();
|
|
15217
15487
|
/** Set by main.ts — triggers graceful shutdown with restart exit code */
|
|
15218
15488
|
requestRestart = null;
|
|
@@ -15308,7 +15578,8 @@ var OpenACPCore = class {
|
|
|
15308
15578
|
eventBus: this.eventBus,
|
|
15309
15579
|
adapters: this.adapters,
|
|
15310
15580
|
bridges: this.bridges,
|
|
15311
|
-
createBridge: (session, adapter) => this.createBridge(session, adapter),
|
|
15581
|
+
createBridge: (session, adapter, adapterId) => this.createBridge(session, adapter, adapterId),
|
|
15582
|
+
getSessionBridgeKeys: (sessionId) => this.getSessionBridgeKeys(sessionId),
|
|
15312
15583
|
getMiddlewareChain: () => this.lifecycleManager?.middlewareChain,
|
|
15313
15584
|
getService: (name) => this.lifecycleManager.serviceRegistry.get(name)
|
|
15314
15585
|
});
|
|
@@ -15488,7 +15759,7 @@ User message:
|
|
|
15488
15759
|
${text3}`;
|
|
15489
15760
|
}
|
|
15490
15761
|
}
|
|
15491
|
-
await session.enqueuePrompt(text3, message.attachments);
|
|
15762
|
+
await session.enqueuePrompt(text3, message.attachments, message.routing);
|
|
15492
15763
|
}
|
|
15493
15764
|
// --- Unified Session Creation Pipeline ---
|
|
15494
15765
|
async createSession(params) {
|
|
@@ -15515,6 +15786,12 @@ ${text3}`;
|
|
|
15515
15786
|
platform2.threadId = session.threadId;
|
|
15516
15787
|
}
|
|
15517
15788
|
}
|
|
15789
|
+
const platforms = {
|
|
15790
|
+
...existingRecord?.platforms ?? {}
|
|
15791
|
+
};
|
|
15792
|
+
if (session.threadId) {
|
|
15793
|
+
platforms[params.channelId] = params.channelId === "telegram" ? { topicId: Number(session.threadId) || session.threadId } : { threadId: session.threadId };
|
|
15794
|
+
}
|
|
15518
15795
|
await this.sessionManager.patchRecord(session.id, {
|
|
15519
15796
|
sessionId: session.id,
|
|
15520
15797
|
agentSessionId: session.agentSessionId,
|
|
@@ -15526,6 +15803,7 @@ ${text3}`;
|
|
|
15526
15803
|
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15527
15804
|
name: session.name,
|
|
15528
15805
|
platform: platform2,
|
|
15806
|
+
platforms,
|
|
15529
15807
|
firstAgent: session.firstAgent,
|
|
15530
15808
|
currentPromptCount: session.promptCount,
|
|
15531
15809
|
agentSwitchHistory: session.agentSwitchHistory,
|
|
@@ -15533,7 +15811,7 @@ ${text3}`;
|
|
|
15533
15811
|
acpState: session.toAcpStateSnapshot()
|
|
15534
15812
|
}, { immediate: true });
|
|
15535
15813
|
if (adapter) {
|
|
15536
|
-
const bridge = this.createBridge(session, adapter);
|
|
15814
|
+
const bridge = this.createBridge(session, adapter, session.channelId);
|
|
15537
15815
|
bridge.connect();
|
|
15538
15816
|
adapter.flushPendingSkillCommands?.(session.id).catch((err) => {
|
|
15539
15817
|
log16.warn({ err, sessionId: session.id }, "Failed to flush pending skill commands");
|
|
@@ -15672,9 +15950,14 @@ ${text3}`;
|
|
|
15672
15950
|
} else {
|
|
15673
15951
|
adoptPlatform.threadId = session.threadId;
|
|
15674
15952
|
}
|
|
15953
|
+
const adoptPlatforms = {};
|
|
15954
|
+
if (session.threadId) {
|
|
15955
|
+
adoptPlatforms[adapterChannelId] = adapterChannelId === "telegram" ? { topicId: Number(session.threadId) || session.threadId } : { threadId: session.threadId };
|
|
15956
|
+
}
|
|
15675
15957
|
await this.sessionManager.patchRecord(session.id, {
|
|
15676
15958
|
originalAgentSessionId: agentSessionId,
|
|
15677
|
-
platform: adoptPlatform
|
|
15959
|
+
platform: adoptPlatform,
|
|
15960
|
+
platforms: adoptPlatforms
|
|
15678
15961
|
});
|
|
15679
15962
|
return {
|
|
15680
15963
|
ok: true,
|
|
@@ -15696,18 +15979,101 @@ ${text3}`;
|
|
|
15696
15979
|
async getOrResumeSession(channelId, threadId) {
|
|
15697
15980
|
return this.sessionFactory.getOrResume(channelId, threadId);
|
|
15698
15981
|
}
|
|
15982
|
+
async getOrResumeSessionById(sessionId) {
|
|
15983
|
+
return this.sessionFactory.getOrResumeById(sessionId);
|
|
15984
|
+
}
|
|
15985
|
+
async attachAdapter(sessionId, adapterId) {
|
|
15986
|
+
const session = this.sessionManager.getSession(sessionId);
|
|
15987
|
+
if (!session) throw new Error(`Session ${sessionId} not found`);
|
|
15988
|
+
const adapter = this.adapters.get(adapterId);
|
|
15989
|
+
if (!adapter) throw new Error(`Adapter "${adapterId}" not found or not running`);
|
|
15990
|
+
if (session.attachedAdapters.includes(adapterId)) {
|
|
15991
|
+
const existingThread = session.threadIds.get(adapterId) ?? session.id;
|
|
15992
|
+
return { threadId: existingThread };
|
|
15993
|
+
}
|
|
15994
|
+
const threadId = await adapter.createSessionThread(
|
|
15995
|
+
session.id,
|
|
15996
|
+
session.name ?? `Session ${session.id.slice(0, 6)}`
|
|
15997
|
+
);
|
|
15998
|
+
session.threadIds.set(adapterId, threadId);
|
|
15999
|
+
session.attachedAdapters.push(adapterId);
|
|
16000
|
+
const bridge = this.createBridge(session, adapter, adapterId);
|
|
16001
|
+
bridge.connect();
|
|
16002
|
+
await this.sessionManager.patchRecord(session.id, {
|
|
16003
|
+
attachedAdapters: session.attachedAdapters,
|
|
16004
|
+
platforms: this.buildPlatformsFromSession(session)
|
|
16005
|
+
});
|
|
16006
|
+
return { threadId };
|
|
16007
|
+
}
|
|
16008
|
+
async detachAdapter(sessionId, adapterId) {
|
|
16009
|
+
const session = this.sessionManager.getSession(sessionId);
|
|
16010
|
+
if (!session) throw new Error(`Session ${sessionId} not found`);
|
|
16011
|
+
if (adapterId === session.channelId) {
|
|
16012
|
+
throw new Error("Cannot detach primary adapter (channelId)");
|
|
16013
|
+
}
|
|
16014
|
+
if (!session.attachedAdapters.includes(adapterId)) {
|
|
16015
|
+
return;
|
|
16016
|
+
}
|
|
16017
|
+
const adapter = this.adapters.get(adapterId);
|
|
16018
|
+
if (adapter) {
|
|
16019
|
+
try {
|
|
16020
|
+
await adapter.sendMessage(session.id, {
|
|
16021
|
+
type: "system_message",
|
|
16022
|
+
text: "Session detached from this adapter."
|
|
16023
|
+
});
|
|
16024
|
+
} catch {
|
|
16025
|
+
}
|
|
16026
|
+
}
|
|
16027
|
+
const key = this.bridgeKey(adapterId, session.id);
|
|
16028
|
+
const bridge = this.bridges.get(key);
|
|
16029
|
+
if (bridge) {
|
|
16030
|
+
bridge.disconnect();
|
|
16031
|
+
this.bridges.delete(key);
|
|
16032
|
+
}
|
|
16033
|
+
session.attachedAdapters = session.attachedAdapters.filter((a) => a !== adapterId);
|
|
16034
|
+
session.threadIds.delete(adapterId);
|
|
16035
|
+
await this.sessionManager.patchRecord(session.id, {
|
|
16036
|
+
attachedAdapters: session.attachedAdapters,
|
|
16037
|
+
platforms: this.buildPlatformsFromSession(session)
|
|
16038
|
+
});
|
|
16039
|
+
}
|
|
16040
|
+
buildPlatformsFromSession(session) {
|
|
16041
|
+
const platforms = {};
|
|
16042
|
+
for (const [adapterId, threadId] of session.threadIds) {
|
|
16043
|
+
if (adapterId === "telegram") {
|
|
16044
|
+
platforms.telegram = { topicId: Number(threadId) || threadId };
|
|
16045
|
+
} else {
|
|
16046
|
+
platforms[adapterId] = { threadId };
|
|
16047
|
+
}
|
|
16048
|
+
}
|
|
16049
|
+
return platforms;
|
|
16050
|
+
}
|
|
15699
16051
|
// --- Event Wiring ---
|
|
16052
|
+
/** Composite bridge key: "adapterId:sessionId" */
|
|
16053
|
+
bridgeKey(adapterId, sessionId) {
|
|
16054
|
+
return `${adapterId}:${sessionId}`;
|
|
16055
|
+
}
|
|
16056
|
+
/** Get all bridge keys for a session (regardless of adapter) */
|
|
16057
|
+
getSessionBridgeKeys(sessionId) {
|
|
16058
|
+
const keys = [];
|
|
16059
|
+
for (const key of this.bridges.keys()) {
|
|
16060
|
+
if (key.endsWith(`:${sessionId}`)) keys.push(key);
|
|
16061
|
+
}
|
|
16062
|
+
return keys;
|
|
16063
|
+
}
|
|
15700
16064
|
/** Connect a session bridge for the given session (used by AssistantManager) */
|
|
15701
16065
|
connectSessionBridge(session) {
|
|
15702
16066
|
const adapter = this.adapters.get(session.channelId);
|
|
15703
16067
|
if (!adapter) return;
|
|
15704
|
-
const bridge = this.createBridge(session, adapter);
|
|
16068
|
+
const bridge = this.createBridge(session, adapter, session.channelId);
|
|
15705
16069
|
bridge.connect();
|
|
15706
16070
|
}
|
|
15707
16071
|
/** Create a SessionBridge for the given session and adapter.
|
|
15708
|
-
* Disconnects any existing bridge for the same session first. */
|
|
15709
|
-
createBridge(session, adapter) {
|
|
15710
|
-
const
|
|
16072
|
+
* Disconnects any existing bridge for the same adapter+session first. */
|
|
16073
|
+
createBridge(session, adapter, adapterId) {
|
|
16074
|
+
const id = adapterId ?? adapter.name;
|
|
16075
|
+
const key = this.bridgeKey(id, session.id);
|
|
16076
|
+
const existing = this.bridges.get(key);
|
|
15711
16077
|
if (existing) {
|
|
15712
16078
|
existing.disconnect();
|
|
15713
16079
|
}
|
|
@@ -15718,8 +16084,8 @@ ${text3}`;
|
|
|
15718
16084
|
eventBus: this.eventBus,
|
|
15719
16085
|
fileService: this.fileService,
|
|
15720
16086
|
middlewareChain: this.lifecycleManager?.middlewareChain
|
|
15721
|
-
});
|
|
15722
|
-
this.bridges.set(
|
|
16087
|
+
}, id);
|
|
16088
|
+
this.bridges.set(key, bridge);
|
|
15723
16089
|
return bridge;
|
|
15724
16090
|
}
|
|
15725
16091
|
};
|
|
@@ -17754,12 +18120,14 @@ export {
|
|
|
17754
18120
|
createApiServerService,
|
|
17755
18121
|
createChildLogger,
|
|
17756
18122
|
createSessionLogger,
|
|
18123
|
+
createTurnContext,
|
|
17757
18124
|
expandHome3 as expandHome,
|
|
17758
18125
|
extractContentText,
|
|
17759
18126
|
formatTokens,
|
|
17760
18127
|
formatToolSummary,
|
|
17761
18128
|
formatToolTitle,
|
|
17762
18129
|
getConfigValue,
|
|
18130
|
+
getEffectiveTarget,
|
|
17763
18131
|
getFieldDef,
|
|
17764
18132
|
getPidPath,
|
|
17765
18133
|
getSafeFields,
|
|
@@ -17769,6 +18137,7 @@ export {
|
|
|
17769
18137
|
isAutoStartInstalled,
|
|
17770
18138
|
isAutoStartSupported,
|
|
17771
18139
|
isHotReloadable,
|
|
18140
|
+
isSystemEvent,
|
|
17772
18141
|
log,
|
|
17773
18142
|
nodeToWebReadable,
|
|
17774
18143
|
nodeToWebWritable,
|