@agentconnect.md/daemon 1.0.0-rc.317 → 1.0.0-rc.319
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/{acp-host-4pA0zUPK.js → acp-host-Dsm0i9DH.js} +33 -9
- package/dist/acp-host-Dsm0i9DH.js.map +1 -0
- package/dist/{chat-CrvRQ2nJ.js → chat-Cq-5NzYK.js} +2 -2
- package/dist/{chat-CrvRQ2nJ.js.map → chat-Cq-5NzYK.js.map} +1 -1
- package/dist/index.js +3 -3
- package/dist/{login-D616mgOs.js → login-DGoYSqbc.js} +2 -2
- package/dist/{login-D616mgOs.js.map → login-DGoYSqbc.js.map} +1 -1
- package/dist/{run-foreground-B4hOtHPl.js → run-foreground-BRT8VM8Q.js} +266 -78
- package/dist/{run-foreground-B4hOtHPl.js.map → run-foreground-BRT8VM8Q.js.map} +1 -1
- package/dist/run-foreground-D9FG37zf.js +2 -0
- package/package.json +1 -1
- package/dist/acp-host-4pA0zUPK.js.map +0 -1
- package/dist/run-foreground-CaCF2xaQ.js +0 -2
|
@@ -6,7 +6,7 @@ import { C as _coercedNumber, T as NEVER, a as array, d as literal, f as looseOb
|
|
|
6
6
|
import { a as RELAY_DAEMON_WS_PATH, c as SHARED_CONFIG_ACTION_ID, d as encode, f as MAX_FRAME_BYTES, g as ZodIssueCode, h as RESERVED_MCP_SERVER_NAME, i as RELAY_DAEMON_SUBPROTOCOL, l as buildEnvelope, n as gitRepoLabel, o as buildRelayDaemonFrame, r as normalizeGitUrl, s as decodeRelayDaemonFrame, u as decodeEnvelope } from "./dist-BG425zHm.js";
|
|
7
7
|
import { a as agentChildEnv, c as persistRelays, i as selectAgent, n as findAgentFiles, o as loadConfig, r as loadAgents, s as persistDaemonId } from "./load-agents-CROyMyq9.js";
|
|
8
8
|
import { l as resolveRoot, o as mcpSocketPath, u as statePath } from "./paths-DEcUO8lC.js";
|
|
9
|
-
import { C as cachedRuntimeVersions, S as cachedRuntimeNames, _ as resolveInMemoryDir, a as prepareWorkspace, b as MEMORY_TOOL_NAMES, c as sessionGitEnv, d as memoryKindOf, f as memoryProviderFor, g as listMemory, h as MemoryTooLargeError, i as prefetchWorkspace, l as simpleGit, m as MemoryPathError, n as turnFailureReason, o as initGitInjection, p as MemoryConflictError, r as installedRuntimes, s as probeGitVersion, t as AcpHost, u as createMemoryProvider, v as writeMemoryFile, w as resolveRuntimes, x as toolsForIntegrations, y as ALL_TOOL_NAMES } from "./acp-host-
|
|
9
|
+
import { C as cachedRuntimeVersions, S as cachedRuntimeNames, _ as resolveInMemoryDir, a as prepareWorkspace, b as MEMORY_TOOL_NAMES, c as sessionGitEnv, d as memoryKindOf, f as memoryProviderFor, g as listMemory, h as MemoryTooLargeError, i as prefetchWorkspace, l as simpleGit, m as MemoryPathError, n as turnFailureReason, o as initGitInjection, p as MemoryConflictError, r as installedRuntimes, s as probeGitVersion, t as AcpHost, u as createMemoryProvider, v as writeMemoryFile, w as resolveRuntimes, x as toolsForIntegrations, y as ALL_TOOL_NAMES } from "./acp-host-Dsm0i9DH.js";
|
|
10
10
|
import { i as GitCredentialCache, n as gitcredSocketPath, r as writeGitcredShim, t as GitCredServer } from "./gitcred-server-Bu-Svl7L.js";
|
|
11
11
|
import { B as ToolListChangedNotificationSchema, D as ListPromptsResultSchema, E as ListChangedOptionsBaseSchema, F as PromptListChangedNotificationSchema, G as isZ4Schema, H as isJSONRPCRequest, I as ReadResourceResultSchema, J as encodeFrame, K as safeParse, L as ResourceListChangedNotificationSchema, M as ListToolsResultSchema, O as ListResourceTemplatesResultSchema, P as McpError, R as SUPPORTED_PROTOCOL_VERSIONS, S as InitializeResultSchema, T as LATEST_PROTOCOL_VERSION, U as isJSONRPCResultResponse, V as isInitializedNotification, W as getObjectShape, _ as ElicitResultSchema, a as AjvJsonSchemaValidator, b as GetPromptResultSchema, c as mergeCapabilities, d as CompleteResultSchema, f as CreateMessageRequestSchema, g as ElicitRequestSchema, h as CreateTaskResultSchema, i as assertToolsCallTaskCapability, k as ListResourcesResultSchema, m as CreateMessageResultWithToolsSchema, n as serializeMessage, o as require_fast_deep_equal, p as CreateMessageResultSchema, q as decodeFrames, r as assertClientRequestTaskCapability, s as Protocol, t as ReadBuffer, u as CallToolResultSchema, v as EmptyResultSchema, w as JSONRPCMessageSchema, y as ErrorCode } from "./stdio-DnS8WcXi.js";
|
|
12
12
|
import { createRequire } from "node:module";
|
|
@@ -6381,7 +6381,7 @@ var LocalStore = class {
|
|
|
6381
6381
|
seq INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
6382
6382
|
channel TEXT NOT NULL, thread TEXT NOT NULL, ts TEXT,
|
|
6383
6383
|
sender TEXT NOT NULL, kind TEXT NOT NULL, text TEXT NOT NULL,
|
|
6384
|
-
tool_call_id TEXT, body TEXT
|
|
6384
|
+
tool_call_id TEXT, body TEXT, recipient TEXT
|
|
6385
6385
|
);
|
|
6386
6386
|
CREATE INDEX IF NOT EXISTS transcript_thread_seq ON transcript (channel, thread, seq);
|
|
6387
6387
|
-- Dedup conversational rows by platform ts (double-fired inbound / redelivery);
|
|
@@ -6480,6 +6480,13 @@ var LocalStore = class {
|
|
|
6480
6480
|
this.migrateSessionMutes();
|
|
6481
6481
|
this.migrateInboxLoopGuardCounted();
|
|
6482
6482
|
this.migrateTranscriptToolBody();
|
|
6483
|
+
this.migrateTranscriptRecipient();
|
|
6484
|
+
}
|
|
6485
|
+
/** Add the `transcript.recipient` column (the agent a row was delivered to) to a
|
|
6486
|
+
* pre-existing DB. Legacy rows have NULL recipient, so they surface in a session view
|
|
6487
|
+
* only via `sender` — acceptable (pre-migration history predates per-agent scoping). */
|
|
6488
|
+
migrateTranscriptRecipient() {
|
|
6489
|
+
if (!this.db.prepare("PRAGMA table_info(transcript)").all().some((c) => c.name === "recipient")) this.db.exec("ALTER TABLE transcript ADD COLUMN recipient TEXT");
|
|
6483
6490
|
}
|
|
6484
6491
|
/** Backfill the durable mute tombstones from the legacy sessions.muted column.
|
|
6485
6492
|
* Both writes in setSessionMuted stay transactional, so this idempotent sync cannot
|
|
@@ -6574,6 +6581,11 @@ var LocalStore = class {
|
|
|
6574
6581
|
getSessionByAcpId(acpSessionId) {
|
|
6575
6582
|
return this.db.prepare("SELECT * FROM sessions WHERE acpSessionId = ?").get(acpSessionId);
|
|
6576
6583
|
}
|
|
6584
|
+
/** Agent-scoped ACP id lookup for callbacks from one runtime process. ACP ids
|
|
6585
|
+
* are runtime-owned and need not be globally unique across agents. */
|
|
6586
|
+
getSessionByAcpIdForAgent(agentId, acpSessionId) {
|
|
6587
|
+
return this.db.prepare("SELECT * FROM sessions WHERE agentId = ? AND acpSessionId = ?").get(agentId, acpSessionId);
|
|
6588
|
+
}
|
|
6577
6589
|
/**
|
|
6578
6590
|
* One newest-first page of a thread's full transcript (all kinds), for `session/history`.
|
|
6579
6591
|
* Pages backward via `beforeSeq` (the lowest seq already seen; null ⇒ newest page).
|
|
@@ -6587,6 +6599,20 @@ var LocalStore = class {
|
|
|
6587
6599
|
hasMore
|
|
6588
6600
|
};
|
|
6589
6601
|
}
|
|
6602
|
+
/** Like {@link transcriptPage} but scoped to what ONE agent's session actually received +
|
|
6603
|
+
* produced: rows delivered TO it (`recipient = agentId`) or sent BY it (`sender = agentId`).
|
|
6604
|
+
* Used by the console session view so it shows the agent's real conversation, not the whole
|
|
6605
|
+
* shared (channel, thread) thread — which matters now that agent-call turns are
|
|
6606
|
+
* context-isolated and a callee only ever saw the message handed to it. Other participants'
|
|
6607
|
+
* cross-talk in the same thread is correctly excluded. */
|
|
6608
|
+
transcriptPageForAgent(channel, thread, agentId, beforeSeq, limit) {
|
|
6609
|
+
const rows = beforeSeq !== null ? this.db.prepare("SELECT * FROM transcript WHERE channel = ? AND thread = ? AND (recipient = ? OR sender = ?) AND seq < ? ORDER BY seq DESC LIMIT ?").all(channel, thread, agentId, agentId, beforeSeq, limit + 1) : this.db.prepare("SELECT * FROM transcript WHERE channel = ? AND thread = ? AND (recipient = ? OR sender = ?) ORDER BY seq DESC LIMIT ?").all(channel, thread, agentId, agentId, limit + 1);
|
|
6610
|
+
const hasMore = rows.length > limit;
|
|
6611
|
+
return {
|
|
6612
|
+
rows: hasMore ? rows.slice(0, limit) : rows,
|
|
6613
|
+
hasMore
|
|
6614
|
+
};
|
|
6615
|
+
}
|
|
6590
6616
|
upsertSession(rec) {
|
|
6591
6617
|
this.db.prepare(`INSERT INTO sessions
|
|
6592
6618
|
(key, agentId, platform, channel, thread, acpSessionId, state, lastDeliveredTs, updatedAt, muted, triggeredBy)
|
|
@@ -6635,7 +6661,7 @@ var LocalStore = class {
|
|
|
6635
6661
|
throw err;
|
|
6636
6662
|
}
|
|
6637
6663
|
}
|
|
6638
|
-
/** Human-facing session title from the
|
|
6664
|
+
/** Human-facing session title from ACP or the AgentConnect title tool (latest
|
|
6639
6665
|
* wins; null clears per ACP semantics). No-op on an unknown key. */
|
|
6640
6666
|
setSessionTitle(key, title) {
|
|
6641
6667
|
this.db.prepare("UPDATE sessions SET title = ? WHERE key = ?").run(title, key);
|
|
@@ -6779,7 +6805,10 @@ var LocalStore = class {
|
|
|
6779
6805
|
return rows;
|
|
6780
6806
|
}
|
|
6781
6807
|
appendTranscript(e) {
|
|
6782
|
-
this.db.prepare("INSERT OR IGNORE INTO transcript (channel, thread, ts, sender, kind, text) VALUES (@channel, @thread, @ts, @sender, @kind, @text)").run(
|
|
6808
|
+
this.db.prepare("INSERT OR IGNORE INTO transcript (channel, thread, ts, sender, kind, text, recipient) VALUES (@channel, @thread, @ts, @sender, @kind, @text, @recipient)").run({
|
|
6809
|
+
...e,
|
|
6810
|
+
recipient: e.recipient ?? null
|
|
6811
|
+
});
|
|
6783
6812
|
}
|
|
6784
6813
|
/** First sight of a tool call: insert its kind='tool' row (title in `text`, the
|
|
6785
6814
|
* serialized ToolBody in `body`). INSERT OR IGNORE so a re-fired first update is a
|
|
@@ -6817,10 +6846,10 @@ var LocalStore = class {
|
|
|
6817
6846
|
return this.db.prepare("SELECT * FROM transcript WHERE channel = ? AND thread = ? AND kind = 'text' AND ts > ? ORDER BY ts ASC").all(channel, thread, sinceTs);
|
|
6818
6847
|
}
|
|
6819
6848
|
/** The earliest inbound (non-agent) `text` message in a thread — the triggering user
|
|
6820
|
-
* message. Used as a session-title fallback when
|
|
6821
|
-
*
|
|
6822
|
-
*
|
|
6823
|
-
*
|
|
6849
|
+
* message. Used as a session-title fallback when neither ACP nor the title tool
|
|
6850
|
+
* supplied one. Before the first meaningful request, this avoids showing only
|
|
6851
|
+
* "Session <id>". Returns undefined when the thread holds no non-agent text row
|
|
6852
|
+
* yet. Indexed by (channel, thread, seq). */
|
|
6824
6853
|
firstMessageText(channel, thread, agentId) {
|
|
6825
6854
|
return this.db.prepare("SELECT text FROM transcript WHERE channel = ? AND thread = ? AND kind = 'text' AND sender != ? ORDER BY seq ASC LIMIT 1").get(channel, thread, agentId)?.text;
|
|
6826
6855
|
}
|
|
@@ -7251,7 +7280,7 @@ var SessionManager = class {
|
|
|
7251
7280
|
const dormant = this.deps.store.closedSessionAgents(channel, thread);
|
|
7252
7281
|
return dormant.length === 1 ? dormant[0] : null;
|
|
7253
7282
|
}
|
|
7254
|
-
async handle(agentId, msg, signal) {
|
|
7283
|
+
async handle(agentId, msg, signal, integrationId) {
|
|
7255
7284
|
const agent = this.deps.agentById(agentId);
|
|
7256
7285
|
if (!agent) throw new Error(`unknown agent ${agentId}`);
|
|
7257
7286
|
this.deps.memory.ensure({ agentId }, agent.name);
|
|
@@ -7264,6 +7293,7 @@ var SessionManager = class {
|
|
|
7264
7293
|
thread,
|
|
7265
7294
|
ts,
|
|
7266
7295
|
sender: msg.sender.id,
|
|
7296
|
+
recipient: agentId,
|
|
7267
7297
|
kind: "text",
|
|
7268
7298
|
text: mention ? `${msg.text}\n${mention}`.trim() : msg.text
|
|
7269
7299
|
});
|
|
@@ -7281,7 +7311,12 @@ You keep a persistent memory across sessions; below is its INDEX. Your context i
|
|
|
7281
7311
|
`- Source: ${msg.platform}`,
|
|
7282
7312
|
`- Channel: ${msg.channel}`,
|
|
7283
7313
|
...channelName ? [`- Channel name: ${channelName}`] : [],
|
|
7284
|
-
...agent.description ? ["", agent.description] : []
|
|
7314
|
+
...agent.description ? ["", agent.description] : [],
|
|
7315
|
+
...this.deps.mcpServersFor ? [
|
|
7316
|
+
"",
|
|
7317
|
+
"# Session naming",
|
|
7318
|
+
"Before sending your first substantive answer, after you understand the first meaningful user request (not a greeting or acknowledgement), call `setSessionTitle` with a concise, specific title. Call it again only if the task focus materially changes. Do not mention this housekeeping action."
|
|
7319
|
+
] : []
|
|
7285
7320
|
].join("\n");
|
|
7286
7321
|
const sessionContext = [
|
|
7287
7322
|
agentMeta,
|
|
@@ -7297,7 +7332,9 @@ You keep a persistent memory across sessions; below is its INDEX. Your context i
|
|
|
7297
7332
|
agent,
|
|
7298
7333
|
platform: msg.platform,
|
|
7299
7334
|
channel: msg.channel,
|
|
7300
|
-
thread
|
|
7335
|
+
thread,
|
|
7336
|
+
...integrationId !== void 0 ? { integrationId } : {},
|
|
7337
|
+
isDm: msg.isDm
|
|
7301
7338
|
}) ?? [];
|
|
7302
7339
|
const acpSessionId = await abortable(() => host.newSession(cwd, mcpServers, effortOverride, metaContext), signal);
|
|
7303
7340
|
created = true;
|
|
@@ -7321,7 +7358,9 @@ You keep a persistent memory across sessions; below is its INDEX. Your context i
|
|
|
7321
7358
|
agent,
|
|
7322
7359
|
platform: msg.platform,
|
|
7323
7360
|
channel: msg.channel,
|
|
7324
|
-
thread
|
|
7361
|
+
thread,
|
|
7362
|
+
...integrationId !== void 0 ? { integrationId } : {},
|
|
7363
|
+
isDm: msg.isDm
|
|
7325
7364
|
}) ?? [];
|
|
7326
7365
|
let resumed = false;
|
|
7327
7366
|
if (host.loadSupported?.()) {
|
|
@@ -7354,6 +7393,7 @@ You keep a persistent memory across sessions; below is its INDEX. Your context i
|
|
|
7354
7393
|
thread,
|
|
7355
7394
|
ts: h.ts,
|
|
7356
7395
|
sender: h.sender,
|
|
7396
|
+
recipient: agentId,
|
|
7357
7397
|
kind: "text",
|
|
7358
7398
|
text: h.text
|
|
7359
7399
|
});
|
|
@@ -7539,6 +7579,21 @@ function guessMimeFromUrl(url) {
|
|
|
7539
7579
|
*/
|
|
7540
7580
|
async function executeTool(ctx, name, args, deps) {
|
|
7541
7581
|
if (deps.canRun && !deps.canRun(ctx)) throw new Error("this agent turn has been stopped");
|
|
7582
|
+
if (name === "setSessionTitle") {
|
|
7583
|
+
const title = requireString(args, "title").replace(/\s+/g, " ").trim();
|
|
7584
|
+
if (!title) throw new Error("missing required string argument: title");
|
|
7585
|
+
if ([...title].length > 80) throw new Error("session title must be at most 80 characters");
|
|
7586
|
+
await deps.setSessionTitle({
|
|
7587
|
+
agentId: ctx.agentId,
|
|
7588
|
+
platform: ctx.platform,
|
|
7589
|
+
...ctx.integrationId !== void 0 ? { integrationId: ctx.integrationId } : {},
|
|
7590
|
+
isDm: ctx.isDm,
|
|
7591
|
+
channel: ctx.channel,
|
|
7592
|
+
thread: ctx.thread,
|
|
7593
|
+
title
|
|
7594
|
+
});
|
|
7595
|
+
return { mcpContent: [] };
|
|
7596
|
+
}
|
|
7542
7597
|
if (name === "listMemory" || name === "readMemory" || name === "writeMemory") {
|
|
7543
7598
|
const scope = { agentId: ctx.agentId };
|
|
7544
7599
|
try {
|
|
@@ -198561,7 +198616,7 @@ function createSessionReader(store, workspaceUrlFor) {
|
|
|
198561
198616
|
messages: []
|
|
198562
198617
|
};
|
|
198563
198618
|
const before = req.cursor != null && Number.isFinite(Number(req.cursor)) ? Number(req.cursor) : null;
|
|
198564
|
-
const { rows, hasMore } = store.
|
|
198619
|
+
const { rows, hasMore } = store.transcriptPageForAgent(rec.channel, rec.thread, rec.agentId, before, req.limit);
|
|
198565
198620
|
const ordered = rows.slice().reverse();
|
|
198566
198621
|
const names = store.getDisplayNames(ordered.flatMap((r) => [r.sender, ...mentionedUserIds(r.text)]));
|
|
198567
198622
|
const built = ordered.map((r) => {
|
|
@@ -215458,7 +215513,10 @@ const IDLE_FLUSH_MS = 2e3;
|
|
|
215458
215513
|
/** Public Web App console origin used for session deep links when neither a local
|
|
215459
215514
|
* `webAppUrl` config nor a CP-provided one is set — so "View session" always resolves. */
|
|
215460
215515
|
const DEFAULT_WEB_APP_URL = "https://app.agentconnect.md";
|
|
215461
|
-
/**
|
|
215516
|
+
/** ACP session ids are scoped to one agent runtime, not globally unique. */
|
|
215517
|
+
function pendingTurnKey(agentId, acpSessionId) {
|
|
215518
|
+
return JSON.stringify([agentId, acpSessionId]);
|
|
215519
|
+
}
|
|
215462
215520
|
/** Cap on agent→agent hop depth (design §2.4/§4.5) — reject a `messageAgent` that
|
|
215463
215521
|
* would push the outgoing hopCount past this, so an A↔B wake loop can't run away. */
|
|
215464
215522
|
const MAX_AGENT_CALL_HOPS = 8;
|
|
@@ -215590,6 +215648,9 @@ var Daemon = class Daemon {
|
|
|
215590
215648
|
activeDispatchesByAgent = /* @__PURE__ */ new Map();
|
|
215591
215649
|
activeDispatchDoneByKey = /* @__PURE__ */ new Map();
|
|
215592
215650
|
activeReplyConnectionUses = /* @__PURE__ */ new Map();
|
|
215651
|
+
sessionDeliveryBindings = /* @__PURE__ */ new Map();
|
|
215652
|
+
sessionInitializationsByAgent = /* @__PURE__ */ new Map();
|
|
215653
|
+
earlySessionMetadata = /* @__PURE__ */ new Map();
|
|
215593
215654
|
hostStopping = /* @__PURE__ */ new Map();
|
|
215594
215655
|
idleSweepTimer;
|
|
215595
215656
|
cancelTimers = /* @__PURE__ */ new Map();
|
|
@@ -215713,6 +215774,7 @@ var Daemon = class Daemon {
|
|
|
215713
215774
|
const active = this.activeGateEntries.get(key);
|
|
215714
215775
|
return !this.paused(ctx.agentId) && active !== void 0 && !active.cancelledReason;
|
|
215715
215776
|
},
|
|
215777
|
+
setSessionTitle: (req) => this.setSessionTitleFromTool(req),
|
|
215716
215778
|
gatewayFor: (integrationId) => this.connByIntegration.get(integrationId) ?? this.tgConnByIntegration.get(integrationId) ?? this.dcConnByIntegration.get(integrationId),
|
|
215717
215779
|
channelAgents: (req) => {
|
|
215718
215780
|
const client = this.cpClient;
|
|
@@ -215741,16 +215803,16 @@ var Daemon = class Daemon {
|
|
|
215741
215803
|
hostFor: (agentId) => this.ensureHostAsync(agentId),
|
|
215742
215804
|
agentById: (id) => this.agents.get(id),
|
|
215743
215805
|
memory: this.memory,
|
|
215744
|
-
mcpServersFor: ({ agent, platform, channel, thread }) => {
|
|
215806
|
+
mcpServersFor: ({ agent, platform, channel, thread, integrationId, isDm }) => {
|
|
215745
215807
|
const servers = [];
|
|
215746
215808
|
let tools = toolsForIntegrations(agent.integrations);
|
|
215747
215809
|
if (memoryKindOf(agent) === "native") tools = tools.filter((t) => !MEMORY_TOOL_NAMES.has(t.name));
|
|
215748
|
-
const integrationId = agent.integrations[0]?.id;
|
|
215749
215810
|
if (tools.length > 0) {
|
|
215750
215811
|
const token = this.mcp.register({
|
|
215751
215812
|
agentId: agent.id,
|
|
215752
215813
|
platform,
|
|
215753
215814
|
...integrationId ? { integrationId } : {},
|
|
215815
|
+
isDm,
|
|
215754
215816
|
channel,
|
|
215755
215817
|
thread,
|
|
215756
215818
|
tools
|
|
@@ -216651,7 +216713,7 @@ var Daemon = class Daemon {
|
|
|
216651
216713
|
const host = this.hosts.get(rec.agentId);
|
|
216652
216714
|
if (!acpSessionId || !host?.hasSession(acpSessionId)) return;
|
|
216653
216715
|
host.setSessionModel(acpSessionId, model).then((applied) => {
|
|
216654
|
-
const p = this.pending.get(acpSessionId);
|
|
216716
|
+
const p = this.pending.get(pendingTurnKey(rec.agentId, acpSessionId));
|
|
216655
216717
|
if (applied && p) this.emitStatusBar(p);
|
|
216656
216718
|
}).catch((err) => this.log.warn(`set-model failed: ${err.message}`));
|
|
216657
216719
|
}
|
|
@@ -216717,7 +216779,7 @@ var Daemon = class Daemon {
|
|
|
216717
216779
|
* (model / effort / fast) is reflected. No-op when the session is idle. */
|
|
216718
216780
|
refreshStatusBarForKey(key) {
|
|
216719
216781
|
const rec = this.store.getSession(key);
|
|
216720
|
-
const p = rec?.acpSessionId ? this.pending.get(rec.acpSessionId) : void 0;
|
|
216782
|
+
const p = rec?.acpSessionId ? this.pending.get(pendingTurnKey(rec.agentId, rec.acpSessionId)) : void 0;
|
|
216721
216783
|
if (p) this.emitStatusBar(p);
|
|
216722
216784
|
}
|
|
216723
216785
|
/** Set a session's Slack output verbosity by its local key. Purely daemon-side (no ACP):
|
|
@@ -216733,8 +216795,8 @@ var Daemon = class Daemon {
|
|
|
216733
216795
|
* the conversation's in-flight turn like `!cancel` (no mute; follow-ups still dispatch).
|
|
216734
216796
|
* Resolved by conversationId (the op carries no agentId). No-op when idle. */
|
|
216735
216797
|
handleWebchatCancel(conversationId) {
|
|
216736
|
-
for (const
|
|
216737
|
-
this.interruptTurn(p.agentId, p.sessionKey, "cancel", acpSessionId);
|
|
216798
|
+
for (const p of this.pending.values()) if (p.webchat?.conversationId === conversationId) {
|
|
216799
|
+
this.interruptTurn(p.agentId, p.sessionKey, "cancel", p.acpSessionId);
|
|
216738
216800
|
return;
|
|
216739
216801
|
}
|
|
216740
216802
|
for (const [key, entry] of this.activeGateEntries) if (entry.webchat?.conversationId === conversationId) {
|
|
@@ -218036,9 +218098,9 @@ var Daemon = class Daemon {
|
|
|
218036
218098
|
entry.cancelledReason = "loop protection";
|
|
218037
218099
|
targets.set(key, { agentId: entry.agentId });
|
|
218038
218100
|
}
|
|
218039
|
-
for (const
|
|
218101
|
+
for (const pending of this.pending.values()) if (pending.loopGuardScope === scope) targets.set(pending.sessionKey, {
|
|
218040
218102
|
agentId: pending.agentId,
|
|
218041
|
-
acpSessionId
|
|
218103
|
+
acpSessionId: pending.acpSessionId
|
|
218042
218104
|
});
|
|
218043
218105
|
for (const [key, queued] of this.serialQueue) {
|
|
218044
218106
|
const entry = queued.find((candidate) => loopGuardScope(candidate.msg) === scope);
|
|
@@ -218345,10 +218407,26 @@ var Daemon = class Daemon {
|
|
|
218345
218407
|
const conv = msg.platform === "telegram" ? new TelegramConverger(mode) : msg.platform === "discord" ? new DiscordConverger(mode) : new OutputConverger(mode);
|
|
218346
218408
|
this.showActivity(replyConn, msg.channel, statusThread, wasRunning ? "is thinking…" : "is starting up…");
|
|
218347
218409
|
const releaseReplyConn = this.holdReplyConnection(replyConn);
|
|
218410
|
+
const previousDeliveryBinding = this.sessionDeliveryBindings.get(key);
|
|
218411
|
+
const deliveryBinding = {
|
|
218412
|
+
agentId,
|
|
218413
|
+
platform: msg.platform,
|
|
218414
|
+
...integrationId !== void 0 ? { integrationId } : {},
|
|
218415
|
+
isDm: msg.isDm
|
|
218416
|
+
};
|
|
218417
|
+
this.sessionDeliveryBindings.set(key, deliveryBinding);
|
|
218418
|
+
this.sessionInitializationsByAgent.set(agentId, (this.sessionInitializationsByAgent.get(agentId) ?? 0) + 1);
|
|
218419
|
+
const restoreDeliveryBinding = () => {
|
|
218420
|
+
if (this.sessionDeliveryBindings.get(key) !== deliveryBinding) return;
|
|
218421
|
+
if (previousDeliveryBinding) this.sessionDeliveryBindings.set(key, previousDeliveryBinding);
|
|
218422
|
+
else this.sessionDeliveryBindings.delete(key);
|
|
218423
|
+
};
|
|
218348
218424
|
let handled;
|
|
218349
218425
|
try {
|
|
218350
|
-
handled = await this.sessions.handle(agentId, msg, entry.initAbort.signal);
|
|
218426
|
+
handled = await this.sessions.handle(agentId, msg, entry.initAbort.signal, integrationId);
|
|
218351
218427
|
} catch (err) {
|
|
218428
|
+
this.finishSessionInitialization(agentId);
|
|
218429
|
+
restoreDeliveryBinding();
|
|
218352
218430
|
const interrupted = this.dispatchGateReason(entry);
|
|
218353
218431
|
try {
|
|
218354
218432
|
this.store.setSessionState(key, "idle", this.clock.now());
|
|
@@ -218372,6 +218450,8 @@ var Daemon = class Daemon {
|
|
|
218372
218450
|
const { sessionId, blocks, created } = handled;
|
|
218373
218451
|
const initializedGate = this.dispatchGateReason(entry);
|
|
218374
218452
|
if (initializedGate) {
|
|
218453
|
+
this.finishSessionInitialization(agentId);
|
|
218454
|
+
restoreDeliveryBinding();
|
|
218375
218455
|
const interruptedSession = this.store.getSession(key);
|
|
218376
218456
|
if (created && interruptedSession?.acpSessionId === sessionId) this.store.upsertSession({
|
|
218377
218457
|
...interruptedSession,
|
|
@@ -218395,6 +218475,7 @@ var Daemon = class Daemon {
|
|
|
218395
218475
|
channel: msg.channel,
|
|
218396
218476
|
thread: statusThread
|
|
218397
218477
|
});
|
|
218478
|
+
this.finishSessionInitialization(agentId, sessionId);
|
|
218398
218479
|
let resolveDone;
|
|
218399
218480
|
const done = new Promise((r) => resolveDone = r);
|
|
218400
218481
|
const pendingWebchat = webchat ? Object.assign(webchat, {
|
|
@@ -218427,7 +218508,7 @@ var Daemon = class Daemon {
|
|
|
218427
218508
|
deferredFinalTranscript: false
|
|
218428
218509
|
} } : {}
|
|
218429
218510
|
};
|
|
218430
|
-
this.pending.set(sessionId, p);
|
|
218511
|
+
this.pending.set(pendingTurnKey(agentId, sessionId), p);
|
|
218431
218512
|
if (callMeta) this.activeTurnCallMeta.set(key, callMeta);
|
|
218432
218513
|
let finalPhase = "end";
|
|
218433
218514
|
try {
|
|
@@ -218546,12 +218627,12 @@ var Daemon = class Daemon {
|
|
|
218546
218627
|
}
|
|
218547
218628
|
throw err;
|
|
218548
218629
|
} finally {
|
|
218549
|
-
this.clearCancelBackstop(sessionId);
|
|
218630
|
+
this.clearCancelBackstop(agentId, sessionId);
|
|
218550
218631
|
if (p.outputSuppressed) await p.applyChain.catch(() => {});
|
|
218551
218632
|
releaseReplyConn();
|
|
218552
218633
|
this.clearIdle(p);
|
|
218553
|
-
this.releasePermissions(sessionId);
|
|
218554
|
-
this.releaseElicits(sessionId);
|
|
218634
|
+
this.releasePermissions(agentId, sessionId);
|
|
218635
|
+
this.releaseElicits(agentId, sessionId);
|
|
218555
218636
|
if (callMeta) this.activeTurnCallMeta.delete(key);
|
|
218556
218637
|
const githubFinal = p.github && !p.outputSuppressed && finalPhase === "end" ? p.github.collector.finalText(true) : void 0;
|
|
218557
218638
|
if (p.github?.deferredFinalTranscript && githubFinal?.trim()) this.store.appendTranscript({
|
|
@@ -218563,7 +218644,7 @@ var Daemon = class Daemon {
|
|
|
218563
218644
|
text: githubFinal
|
|
218564
218645
|
});
|
|
218565
218646
|
if (p.github && !p.outputSuppressed) await p.github.poster.publish(githubFinal).catch((err) => this.log.warn(`github poster: final publish failed (${formatErr(err)})`));
|
|
218566
|
-
this.pending.delete(sessionId);
|
|
218647
|
+
this.pending.delete(pendingTurnKey(agentId, sessionId));
|
|
218567
218648
|
this.store.setSessionState(key, "idle", this.clock.now());
|
|
218568
218649
|
this.emitSessionMetadataSnapshot({
|
|
218569
218650
|
sessionId,
|
|
@@ -218601,9 +218682,8 @@ var Daemon = class Daemon {
|
|
|
218601
218682
|
else e.reject(new FailStopError(key));
|
|
218602
218683
|
}
|
|
218603
218684
|
}
|
|
218604
|
-
const
|
|
218605
|
-
const liveSessionId =
|
|
218606
|
-
const live = livePair?.[1];
|
|
218685
|
+
const live = acpSessionId ? this.pending.get(pendingTurnKey(agentId, acpSessionId)) : [...this.pending.values()].find((pending) => pending.sessionKey === key);
|
|
218686
|
+
const liveSessionId = acpSessionId ?? live?.acpSessionId;
|
|
218607
218687
|
if (live) {
|
|
218608
218688
|
live.outputSuppressed ??= reason;
|
|
218609
218689
|
this.clearIdle(live);
|
|
@@ -218626,8 +218706,8 @@ var Daemon = class Daemon {
|
|
|
218626
218706
|
if (activeEntry && active) this.armColdCancelBackstop(agentId, key, reason, active);
|
|
218627
218707
|
return;
|
|
218628
218708
|
}
|
|
218629
|
-
this.releasePermissions(liveSessionId);
|
|
218630
|
-
this.releaseElicits(liveSessionId);
|
|
218709
|
+
this.releasePermissions(agentId, liveSessionId);
|
|
218710
|
+
this.releaseElicits(agentId, liveSessionId);
|
|
218631
218711
|
this.store.setSessionState(key, "cancelling", this.clock.now());
|
|
218632
218712
|
this.hosts.get(agentId)?.cancel(liveSessionId).catch((err) => this.log.error(`command ${reason}: cancel failed: ${err.message}`));
|
|
218633
218713
|
this.armCancelBackstop(agentId, liveSessionId, key, reason);
|
|
@@ -218644,7 +218724,7 @@ var Daemon = class Daemon {
|
|
|
218644
218724
|
entry.cancelledReason = reason;
|
|
218645
218725
|
targets.set(key, void 0);
|
|
218646
218726
|
}
|
|
218647
|
-
for (const
|
|
218727
|
+
for (const p of this.pending.values()) if (p.agentId === agentId) targets.set(p.sessionKey, p.acpSessionId);
|
|
218648
218728
|
for (const [key, queued] of this.serialQueue) if (queued.some((entry) => entry.agentId === agentId) && !targets.has(key)) targets.set(key, this.store.getSession(key)?.acpSessionId ?? void 0);
|
|
218649
218729
|
if (targets.size > 0) this.log.info(`${reason}: interrupting ${targets.size} active session(s) for agent "${agentId}"`);
|
|
218650
218730
|
for (const [key, acpSessionId] of targets) this.interruptTurn(agentId, key, reason, acpSessionId, { dropQueued: true });
|
|
@@ -218655,21 +218735,23 @@ var Daemon = class Daemon {
|
|
|
218655
218735
|
* can't be stuck in `cancelling` forever. dispatch's finally clears this timer
|
|
218656
218736
|
* the moment the turn yields on its own. */
|
|
218657
218737
|
armCancelBackstop(agentId, acpSessionId, key, reason) {
|
|
218658
|
-
this.clearCancelBackstop(acpSessionId);
|
|
218738
|
+
this.clearCancelBackstop(agentId, acpSessionId);
|
|
218659
218739
|
const ms = this.cfg.limits.cancelBackstopMs;
|
|
218660
|
-
|
|
218661
|
-
|
|
218662
|
-
|
|
218740
|
+
const pendingKey = pendingTurnKey(agentId, acpSessionId);
|
|
218741
|
+
this.cancelTimers.set(pendingKey, this.clock.setTimeout(() => {
|
|
218742
|
+
this.cancelTimers.delete(pendingKey);
|
|
218743
|
+
if (!this.pending.has(pendingKey)) return;
|
|
218663
218744
|
this.log.warn(`${reason}: agent "${agentId}" ignored session/cancel for ${ms}ms — force-stopping host (session ${acpSessionId})`);
|
|
218664
218745
|
this.stopHost(agentId, 0).catch((err) => this.log.error(`${reason}: force-stop failed for agent "${agentId}": ${formatErr(err)}`));
|
|
218665
218746
|
this.store.setSessionState(key, "idle", this.clock.now());
|
|
218666
218747
|
}, ms));
|
|
218667
218748
|
}
|
|
218668
|
-
clearCancelBackstop(acpSessionId) {
|
|
218669
|
-
const
|
|
218749
|
+
clearCancelBackstop(agentId, acpSessionId) {
|
|
218750
|
+
const key = pendingTurnKey(agentId, acpSessionId);
|
|
218751
|
+
const t = this.cancelTimers.get(key);
|
|
218670
218752
|
if (t !== void 0) {
|
|
218671
218753
|
this.clock.clearTimeout(t);
|
|
218672
|
-
this.cancelTimers.delete(
|
|
218754
|
+
this.cancelTimers.delete(key);
|
|
218673
218755
|
}
|
|
218674
218756
|
}
|
|
218675
218757
|
armColdCancelBackstop(agentId, key, reason, active) {
|
|
@@ -218998,7 +219080,7 @@ var Daemon = class Daemon {
|
|
|
218998
219080
|
if (row?.threadUrl !== void 0) event.threadUrl = row.threadUrl;
|
|
218999
219081
|
const agent = this.agents.get(input.agentId);
|
|
219000
219082
|
if (agent?.runtime) event.runtime = agent.runtime;
|
|
219001
|
-
const storeKey = this.store.
|
|
219083
|
+
const storeKey = this.store.getSessionByAcpIdForAgent(input.agentId, input.sessionId)?.key;
|
|
219002
219084
|
const model = (storeKey ? this.store.getModelOverride(storeKey) : void 0) ?? agent?.runtimeOverrides?.model;
|
|
219003
219085
|
if (model !== void 0) event.model = model;
|
|
219004
219086
|
const effort = (storeKey ? this.store.getEffortOverride(storeKey) : void 0) ?? agent?.reasoningEffort;
|
|
@@ -219151,6 +219233,7 @@ var Daemon = class Daemon {
|
|
|
219151
219233
|
if (p.idleTimer) clearTimeout(p.idleTimer);
|
|
219152
219234
|
p.idleTimer = void 0;
|
|
219153
219235
|
}
|
|
219236
|
+
/** In-flight rendering state keyed by (agentId, ACP sessionId). */
|
|
219154
219237
|
pending = /* @__PURE__ */ new Map();
|
|
219155
219238
|
/**
|
|
219156
219239
|
* DAEMON-PRIVATE trusted call metadata of the CURRENTLY in-flight turn, keyed by the
|
|
@@ -219173,7 +219256,7 @@ var Daemon = class Daemon {
|
|
|
219173
219256
|
* promise stays pending until the user taps a button (handlePermissionChoice) or the
|
|
219174
219257
|
* turn is cancelled/ends (releasePermissions).
|
|
219175
219258
|
*/
|
|
219176
|
-
async onAcpPermission(
|
|
219259
|
+
async onAcpPermission(agentId, sessionId, params) {
|
|
219177
219260
|
if (isBuiltinSystemTool(params)) {
|
|
219178
219261
|
const allow = params.options.find((o) => o.kind === "allow_always" || o.kind === "allow_once");
|
|
219179
219262
|
if (allow) return { outcome: {
|
|
@@ -219181,7 +219264,7 @@ var Daemon = class Daemon {
|
|
|
219181
219264
|
optionId: allow.optionId
|
|
219182
219265
|
} };
|
|
219183
219266
|
}
|
|
219184
|
-
const p = this.pending.get(sessionId);
|
|
219267
|
+
const p = this.pending.get(pendingTurnKey(agentId, sessionId));
|
|
219185
219268
|
if (!p) return void 0;
|
|
219186
219269
|
if (p.outputSuppressed) return { outcome: { outcome: "cancelled" } };
|
|
219187
219270
|
const conn = p.conn;
|
|
@@ -219192,6 +219275,7 @@ var Daemon = class Daemon {
|
|
|
219192
219275
|
let resolveResult;
|
|
219193
219276
|
const result = new Promise((resolve) => resolveResult = resolve);
|
|
219194
219277
|
this.pendingPerms.set(requestId, {
|
|
219278
|
+
agentId,
|
|
219195
219279
|
sessionId,
|
|
219196
219280
|
params,
|
|
219197
219281
|
conn,
|
|
@@ -219230,9 +219314,9 @@ var Daemon = class Daemon {
|
|
|
219230
219314
|
/** Resolve every outstanding permission request for a session as `cancelled` — ACP
|
|
219231
219315
|
* requires this when a prompt turn is cancelled, and it also unblocks a turn whose
|
|
219232
219316
|
* card the user abandoned. Edits each card to a neutral cancelled state. */
|
|
219233
|
-
releasePermissions(sessionId) {
|
|
219317
|
+
releasePermissions(agentId, sessionId) {
|
|
219234
219318
|
for (const [id, rec] of this.pendingPerms) {
|
|
219235
|
-
if (rec.sessionId !== sessionId) continue;
|
|
219319
|
+
if (rec.agentId !== agentId || rec.sessionId !== sessionId) continue;
|
|
219236
219320
|
this.pendingPerms.delete(id);
|
|
219237
219321
|
if (rec.ts) rec.conn.updateBlocks(rec.channel, rec.ts, buildPermissionResolvedCard(rec.params, "Cancelled", void 0), "Permission cancelled").catch(() => {});
|
|
219238
219322
|
rec.resolve({ outcome: { outcome: "cancelled" } });
|
|
@@ -219247,8 +219331,8 @@ var Daemon = class Daemon {
|
|
|
219247
219331
|
* Slack, or the form has no field we can render inline. Stays pending until the user
|
|
219248
219332
|
* taps a button (handleElicitChoice) or the turn ends/cancels (releaseElicits).
|
|
219249
219333
|
*/
|
|
219250
|
-
async onAcpElicit(
|
|
219251
|
-
const p = this.pending.get(sessionId);
|
|
219334
|
+
async onAcpElicit(agentId, sessionId, params) {
|
|
219335
|
+
const p = this.pending.get(pendingTurnKey(agentId, sessionId));
|
|
219252
219336
|
if (!p) return void 0;
|
|
219253
219337
|
if (p.outputSuppressed) return { action: "cancel" };
|
|
219254
219338
|
const conn = p.conn;
|
|
@@ -219262,6 +219346,7 @@ var Daemon = class Daemon {
|
|
|
219262
219346
|
let resolveResult;
|
|
219263
219347
|
const result = new Promise((resolve) => resolveResult = resolve);
|
|
219264
219348
|
this.pendingElicits.set(requestId, {
|
|
219349
|
+
agentId,
|
|
219265
219350
|
sessionId,
|
|
219266
219351
|
params,
|
|
219267
219352
|
propName: target.propName,
|
|
@@ -219309,9 +219394,9 @@ var Daemon = class Daemon {
|
|
|
219309
219394
|
}
|
|
219310
219395
|
/** Resolve every outstanding elicitation for a session as `cancel` — ACP's cancellation
|
|
219311
219396
|
* contract, and it unblocks a turn whose card the user abandoned. */
|
|
219312
|
-
releaseElicits(sessionId) {
|
|
219397
|
+
releaseElicits(agentId, sessionId) {
|
|
219313
219398
|
for (const [id, rec] of this.pendingElicits) {
|
|
219314
|
-
if (rec.sessionId !== sessionId) continue;
|
|
219399
|
+
if (rec.agentId !== agentId || rec.sessionId !== sessionId) continue;
|
|
219315
219400
|
this.pendingElicits.delete(id);
|
|
219316
219401
|
if (rec.ts) rec.conn.updateBlocks(rec.channel, rec.ts, buildElicitationResolvedCard(rec.params, ":hourglass: Cancelled"), "Cancelled").catch(() => {});
|
|
219317
219402
|
rec.resolve({ action: "cancel" });
|
|
@@ -219335,11 +219420,105 @@ var Daemon = class Daemon {
|
|
|
219335
219420
|
this.log.debug(`${late ? "late " : ""}usage report emit failed (session ${sessionId}): ${err.message}`);
|
|
219336
219421
|
}
|
|
219337
219422
|
}
|
|
219338
|
-
|
|
219339
|
-
|
|
219423
|
+
bufferEarlySessionMetadata(agentId, sessionId, update) {
|
|
219424
|
+
if ((this.sessionInitializationsByAgent.get(agentId) ?? 0) === 0) return false;
|
|
219425
|
+
const key = pendingTurnKey(agentId, sessionId);
|
|
219426
|
+
const entry = this.earlySessionMetadata.get(key) ?? {
|
|
219427
|
+
agentId,
|
|
219428
|
+
sessionId,
|
|
219429
|
+
updates: []
|
|
219430
|
+
};
|
|
219431
|
+
const previous = entry.updates.findIndex((candidate) => candidate.sessionUpdate === update.sessionUpdate);
|
|
219432
|
+
if (previous >= 0) entry.updates[previous] = update;
|
|
219433
|
+
else entry.updates.push(update);
|
|
219434
|
+
this.earlySessionMetadata.set(key, entry);
|
|
219435
|
+
return true;
|
|
219436
|
+
}
|
|
219437
|
+
/** Complete one SessionManager initialization and replay any metadata the ACP
|
|
219438
|
+
* adapter emitted before its local session row existed. Leftover unknown ids
|
|
219439
|
+
* are discarded once the agent has no other initialization in flight. */
|
|
219440
|
+
finishSessionInitialization(agentId, sessionId) {
|
|
219441
|
+
if (sessionId) {
|
|
219442
|
+
const key = pendingTurnKey(agentId, sessionId);
|
|
219443
|
+
const entry = this.earlySessionMetadata.get(key);
|
|
219444
|
+
this.earlySessionMetadata.delete(key);
|
|
219445
|
+
if (entry) for (const update of entry.updates) this.onAcpUpdate(agentId, sessionId, update);
|
|
219446
|
+
}
|
|
219447
|
+
const remaining = Math.max(0, (this.sessionInitializationsByAgent.get(agentId) ?? 1) - 1);
|
|
219448
|
+
if (remaining > 0) {
|
|
219449
|
+
this.sessionInitializationsByAgent.set(agentId, remaining);
|
|
219450
|
+
return;
|
|
219451
|
+
}
|
|
219452
|
+
this.sessionInitializationsByAgent.delete(agentId);
|
|
219453
|
+
for (const [key, entry] of this.earlySessionMetadata) if (entry.agentId === agentId) this.earlySessionMetadata.delete(key);
|
|
219454
|
+
}
|
|
219455
|
+
/** Persist one authoritative title and push the CP metadata projection. */
|
|
219456
|
+
persistSessionTitle(rec, title) {
|
|
219457
|
+
this.store.setSessionTitle(rec.key, title);
|
|
219458
|
+
if (!rec.acpSessionId) return;
|
|
219459
|
+
this.emitSessionMetadataSnapshot({
|
|
219460
|
+
sessionId: rec.acpSessionId,
|
|
219461
|
+
agentId: rec.agentId,
|
|
219462
|
+
phase: "plan",
|
|
219463
|
+
platform: rec.platform,
|
|
219464
|
+
channel: rec.channel,
|
|
219465
|
+
thread: rec.thread
|
|
219466
|
+
});
|
|
219467
|
+
}
|
|
219468
|
+
/** Rename a Slack app-DM through the exact integration that delivered this
|
|
219469
|
+
* session. The connection lease prevents reconcile from closing it mid-call. */
|
|
219470
|
+
async setSlackTitleForBinding(rec, binding, title) {
|
|
219471
|
+
if (binding.agentId !== rec.agentId || binding.platform !== "slack" || rec.platform !== "slack" || !binding.isDm || !binding.integrationId || !title) return;
|
|
219472
|
+
const conn = this.connByIntegration.get(binding.integrationId);
|
|
219473
|
+
if (!conn) return;
|
|
219474
|
+
const release = this.holdReplyConnection(conn);
|
|
219475
|
+
try {
|
|
219476
|
+
await conn.setTitle(rec.channel, rec.thread, title);
|
|
219477
|
+
} catch (err) {
|
|
219478
|
+
this.log.debug(`session title: Slack update failed (${formatErr(err)})`);
|
|
219479
|
+
} finally {
|
|
219480
|
+
release();
|
|
219481
|
+
}
|
|
219482
|
+
}
|
|
219483
|
+
/** MCP callback for runtimes (notably Codex ACP) that do not generate semantic
|
|
219484
|
+
* ACP session titles themselves. The tool input contains only the title; every
|
|
219485
|
+
* coordinate and delivery route was captured in the trusted SessionContext. */
|
|
219486
|
+
async setSessionTitleFromTool(req) {
|
|
219487
|
+
const key = sessionKey(req.platform, req.channel, req.thread, req.agentId);
|
|
219488
|
+
const rec = this.store.getSession(key);
|
|
219489
|
+
if (!rec?.acpSessionId) throw new Error("the current session is not addressable yet");
|
|
219490
|
+
const binding = this.sessionDeliveryBindings.get(key) ?? {
|
|
219491
|
+
agentId: req.agentId,
|
|
219492
|
+
platform: req.platform,
|
|
219493
|
+
...req.integrationId !== void 0 ? { integrationId: req.integrationId } : {},
|
|
219494
|
+
isDm: req.isDm
|
|
219495
|
+
};
|
|
219496
|
+
this.persistSessionTitle(rec, req.title);
|
|
219497
|
+
const p = this.pending.get(pendingTurnKey(rec.agentId, rec.acpSessionId));
|
|
219498
|
+
if (p && p.sessionKey === key && !p.outputSuppressed) {
|
|
219499
|
+
if (p.webchat) this.emitWebchatUpdate(p, {
|
|
219500
|
+
sessionUpdate: "session_info_update",
|
|
219501
|
+
title: req.title
|
|
219502
|
+
});
|
|
219503
|
+
if (p.platform === "slack" && p.isDm && p.conn) {
|
|
219504
|
+
this.enqueueApply(p, {
|
|
219505
|
+
kind: "set-title",
|
|
219506
|
+
text: req.title
|
|
219507
|
+
});
|
|
219508
|
+
await p.applyChain;
|
|
219509
|
+
return;
|
|
219510
|
+
}
|
|
219511
|
+
}
|
|
219512
|
+
await this.setSlackTitleForBinding(rec, binding, req.title);
|
|
219513
|
+
}
|
|
219514
|
+
onAcpUpdate(agentId, sessionId, update) {
|
|
219515
|
+
const p = this.pending.get(pendingTurnKey(agentId, sessionId));
|
|
219340
219516
|
if (p?.outputSuppressed) return;
|
|
219517
|
+
const isEarlyMetadata = update?.sessionUpdate === "usage_update" || update?.sessionUpdate === "session_info_update" && update.title !== void 0;
|
|
219518
|
+
const detachedRec = !p && isEarlyMetadata ? this.store.getSessionByAcpIdForAgent(agentId, sessionId) : void 0;
|
|
219519
|
+
if (!p && isEarlyMetadata && !detachedRec && this.bufferEarlySessionMetadata(agentId, sessionId, update)) return;
|
|
219341
219520
|
if (update?.sessionUpdate === "usage_update") {
|
|
219342
|
-
const rec = p ? void 0 :
|
|
219521
|
+
const rec = p ? void 0 : detachedRec;
|
|
219343
219522
|
const key = p?.sessionKey ?? rec?.key;
|
|
219344
219523
|
if (key) {
|
|
219345
219524
|
if (p && update.cost?.amount !== void 0) p.runtimeCostReported = true;
|
|
@@ -219355,23 +219534,22 @@ var Daemon = class Daemon {
|
|
|
219355
219534
|
} else if (rec) this.emitStoredUsageReport(sessionId, rec.agentId, rec.platform, rec.channel, key, true);
|
|
219356
219535
|
}
|
|
219357
219536
|
}
|
|
219358
|
-
if (!p) return;
|
|
219359
219537
|
if (update?.sessionUpdate === "session_info_update" && update.title !== void 0) {
|
|
219360
|
-
this.store.
|
|
219361
|
-
|
|
219362
|
-
|
|
219363
|
-
|
|
219364
|
-
|
|
219365
|
-
|
|
219366
|
-
|
|
219367
|
-
|
|
219368
|
-
|
|
219369
|
-
|
|
219370
|
-
|
|
219371
|
-
|
|
219372
|
-
|
|
219373
|
-
});
|
|
219538
|
+
const rec = p ? this.store.getSession(p.sessionKey) : detachedRec;
|
|
219539
|
+
if (rec?.agentId === agentId && rec.acpSessionId === sessionId) {
|
|
219540
|
+
this.persistSessionTitle(rec, update.title);
|
|
219541
|
+
const slackTitle = typeof update.title === "string" ? update.title.trim() : "";
|
|
219542
|
+
if (p?.platform === "slack" && p.isDm && slackTitle) this.enqueueApply(p, {
|
|
219543
|
+
kind: "set-title",
|
|
219544
|
+
text: slackTitle
|
|
219545
|
+
});
|
|
219546
|
+
else if (!p && slackTitle) {
|
|
219547
|
+
const binding = this.sessionDeliveryBindings.get(rec.key);
|
|
219548
|
+
if (binding) this.setSlackTitleForBinding(rec, binding, slackTitle);
|
|
219549
|
+
}
|
|
219550
|
+
}
|
|
219374
219551
|
}
|
|
219552
|
+
if (!p) return;
|
|
219375
219553
|
const isHeadlessGithubFinal = p.github !== void 0 && p.platform === "hook" && update?.sessionUpdate === "agent_message_chunk" && update?._meta?.codex?.phase === "final_answer";
|
|
219376
219554
|
if (p.github) {
|
|
219377
219555
|
p.github.collector.onUpdate(update);
|
|
@@ -219591,12 +219769,22 @@ var Daemon = class Daemon {
|
|
|
219591
219769
|
const host = this.hosts.get(agentId);
|
|
219592
219770
|
this.hosts.delete(agentId);
|
|
219593
219771
|
this.hostStartedAt.delete(agentId);
|
|
219594
|
-
|
|
219772
|
+
const clearDeliveryBindings = () => {
|
|
219773
|
+
for (const [key, binding] of this.sessionDeliveryBindings) if (binding.agentId === agentId) this.sessionDeliveryBindings.delete(key);
|
|
219774
|
+
};
|
|
219775
|
+
if (!host) {
|
|
219776
|
+
clearDeliveryBindings();
|
|
219777
|
+
return;
|
|
219778
|
+
}
|
|
219595
219779
|
const stop = Promise.resolve(host.stop(deadlineMs)).finally(() => {
|
|
219596
219780
|
if (this.hostStopping.get(agentId) === stop) this.hostStopping.delete(agentId);
|
|
219597
219781
|
});
|
|
219598
219782
|
this.hostStopping.set(agentId, stop);
|
|
219599
|
-
|
|
219783
|
+
try {
|
|
219784
|
+
await stop;
|
|
219785
|
+
} finally {
|
|
219786
|
+
clearDeliveryBindings();
|
|
219787
|
+
}
|
|
219600
219788
|
}
|
|
219601
219789
|
/** Recurring idle sweep (§7.2/§7.3): reap idle adapter children and TTL-close
|
|
219602
219790
|
* idle sessions. Driven by the injected Clock so a FakeClock advances it in tests. */
|
|
@@ -219689,10 +219877,10 @@ var Daemon = class Daemon {
|
|
|
219689
219877
|
})));
|
|
219690
219878
|
const res = await this.raceDeadline(work, deadlineMs);
|
|
219691
219879
|
settled = true;
|
|
219692
|
-
if (res === "timeout") for (const
|
|
219880
|
+
if (res === "timeout") for (const p of this.pending.values()) {
|
|
219693
219881
|
if (!match(p)) continue;
|
|
219694
|
-
this.log.warn(`drain[${scope.kind}]: cancelling straggler turn (session ${
|
|
219695
|
-
await this.hosts.get(p.agentId)?.cancel(
|
|
219882
|
+
this.log.warn(`drain[${scope.kind}]: cancelling straggler turn (session ${p.acpSessionId})`);
|
|
219883
|
+
await this.hosts.get(p.agentId)?.cancel(p.acpSessionId).catch(() => {});
|
|
219696
219884
|
}
|
|
219697
219885
|
return {
|
|
219698
219886
|
matched: [...matched.values()],
|
|
@@ -219801,11 +219989,11 @@ var Daemon = class Daemon {
|
|
|
219801
219989
|
entry.initAbort.abort(/* @__PURE__ */ new Error("daemon shutdown deadline"));
|
|
219802
219990
|
forceAgents.add(entry.agentId);
|
|
219803
219991
|
}
|
|
219804
|
-
for (const
|
|
219992
|
+
for (const p of this.pending.values()) {
|
|
219805
219993
|
p.outputSuppressed ??= "shutdown";
|
|
219806
|
-
this.releasePermissions(
|
|
219807
|
-
this.releaseElicits(
|
|
219808
|
-
this.hosts.get(p.agentId)?.cancel(
|
|
219994
|
+
this.releasePermissions(p.agentId, p.acpSessionId);
|
|
219995
|
+
this.releaseElicits(p.agentId, p.acpSessionId);
|
|
219996
|
+
this.hosts.get(p.agentId)?.cancel(p.acpSessionId).catch(() => {});
|
|
219809
219997
|
}
|
|
219810
219998
|
const forceStops = [...forceAgents].filter((id) => !coldAgents.has(id)).map(stopFailClosed);
|
|
219811
219999
|
await Promise.all([
|
|
@@ -220485,4 +220673,4 @@ async function runForeground(opts, deps = {}) {
|
|
|
220485
220673
|
//#endregion
|
|
220486
220674
|
export { ClientTransport as i, CP_SUBPROTOCOL as n, CP_WS_PATH as r, runForeground as t };
|
|
220487
220675
|
|
|
220488
|
-
//# sourceMappingURL=run-foreground-
|
|
220676
|
+
//# sourceMappingURL=run-foreground-BRT8VM8Q.js.map
|