@agentproto/runtime 5.11.1 → 5.12.0
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/config-schema.mjs.map +1 -1
- package/dist/config.mjs.map +1 -1
- package/dist/daemon-tool-names.d.ts +6 -0
- package/dist/daemon-tool-names.mjs +276 -0
- package/dist/daemon-tool-names.mjs.map +1 -0
- package/dist/index.d.ts +11 -3
- package/dist/index.mjs +403 -42
- package/dist/index.mjs.map +1 -1
- package/dist/session-presence.mjs.map +1 -1
- package/dist/{sessions-Cv4XNQXv.d.ts → sessions-BoZpBAdm.d.ts} +1 -1
- package/dist/user-presets.d.ts +1 -1
- package/package.json +23 -17
package/dist/index.mjs
CHANGED
|
@@ -10389,6 +10389,20 @@ function buildDaemonSelfMountEntry(daemonMcpUrl, opts) {
|
|
|
10389
10389
|
ref += `${ref.includes("?") ? "&" : "?"}callerSessionId=${encodeURIComponent(opts.callerSessionId)}`;
|
|
10390
10390
|
return { name: "agentproto", transport: "http", ref };
|
|
10391
10391
|
}
|
|
10392
|
+
function stampDaemonCallerSessionId(mcpServers, opts) {
|
|
10393
|
+
if (!mcpServers) return void 0;
|
|
10394
|
+
const daemonQ = `${opts.daemonMcpUrl}?`;
|
|
10395
|
+
return mcpServers.map((entry) => {
|
|
10396
|
+
if (entry.transport !== "http" || typeof entry.ref !== "string") return entry;
|
|
10397
|
+
const targetsDaemon = entry.ref === opts.daemonMcpUrl || entry.ref.startsWith(daemonQ);
|
|
10398
|
+
if (!targetsDaemon || entry.ref.includes("callerSessionId=")) return entry;
|
|
10399
|
+
const sep7 = entry.ref.includes("?") ? "&" : "?";
|
|
10400
|
+
return {
|
|
10401
|
+
...entry,
|
|
10402
|
+
ref: `${entry.ref}${sep7}callerSessionId=${encodeURIComponent(opts.callerSessionId)}`
|
|
10403
|
+
};
|
|
10404
|
+
});
|
|
10405
|
+
}
|
|
10392
10406
|
function slugifyMcpImportName(alias, fallbackId) {
|
|
10393
10407
|
const slug = alias.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
10394
10408
|
return slug || fallbackId;
|
|
@@ -10935,16 +10949,9 @@ async function spawnAgentSession(deps2, input) {
|
|
|
10935
10949
|
}
|
|
10936
10950
|
}
|
|
10937
10951
|
if (daemonMcpUrl && mcpServers) {
|
|
10938
|
-
|
|
10939
|
-
|
|
10940
|
-
|
|
10941
|
-
const targetsDaemon = entry.ref === daemonMcpUrl || entry.ref.startsWith(daemonQ);
|
|
10942
|
-
if (!targetsDaemon || entry.ref.includes("callerSessionId=")) return entry;
|
|
10943
|
-
const sep7 = entry.ref.includes("?") ? "&" : "?";
|
|
10944
|
-
return {
|
|
10945
|
-
...entry,
|
|
10946
|
-
ref: `${entry.ref}${sep7}callerSessionId=${encodeURIComponent(mintedSessionId)}`
|
|
10947
|
-
};
|
|
10952
|
+
mcpServers = stampDaemonCallerSessionId(mcpServers, {
|
|
10953
|
+
daemonMcpUrl,
|
|
10954
|
+
callerSessionId: mintedSessionId
|
|
10948
10955
|
});
|
|
10949
10956
|
}
|
|
10950
10957
|
if (mcpServers === void 0 && parentSessionId && buildOrchestratorMcp && input.orchestrator !== false && input.sandbox === void 0) {
|
|
@@ -17288,8 +17295,16 @@ var init_session_end_reason = __esm({
|
|
|
17288
17295
|
// `registry.closeWithOutcome`, never a plain `kill()`.
|
|
17289
17296
|
"steward-completed",
|
|
17290
17297
|
// verdict:"done" — the steward closed it as finished work.
|
|
17291
|
-
"steward-abandoned"
|
|
17298
|
+
"steward-abandoned",
|
|
17292
17299
|
// verdict other than "done" — the steward closed it as not completed.
|
|
17300
|
+
// `restartAgentSession` (session-restart-core.ts) minted a fresh-id
|
|
17301
|
+
// continuation while this row was still alive (running/starting) — the
|
|
17302
|
+
// OLD row is superseded (see its `continuedTo`) and closed cleanly here,
|
|
17303
|
+
// never left running alongside its replacement. Deliberate, not a crash:
|
|
17304
|
+
// never eligible for `restart-scheduler.ts`'s crash-restart (status is
|
|
17305
|
+
// "killed", not "error") and never triggers `notifyParentOnCrash`
|
|
17306
|
+
// (`supervisor-notify.ts` gates on `status:"error"`/`reason:"crashed"`).
|
|
17307
|
+
"restarted"
|
|
17293
17308
|
];
|
|
17294
17309
|
PROVIDER_LIMIT_ERROR_RE = /\bhit your (?:session|usage) limit\b/i;
|
|
17295
17310
|
}
|
|
@@ -26383,7 +26398,11 @@ var DELIBERATE_END_REASONS = /* @__PURE__ */ new Set([
|
|
|
26383
26398
|
"operator-completed",
|
|
26384
26399
|
"operator-stopped",
|
|
26385
26400
|
"steward-completed",
|
|
26386
|
-
"steward-abandoned"
|
|
26401
|
+
"steward-abandoned",
|
|
26402
|
+
// Superseded by a fresh-id restart continuation (session-restart-core.ts)
|
|
26403
|
+
// while still alive — never auto-revive the OLD row, it already has a
|
|
26404
|
+
// living replacement (`continuedTo`).
|
|
26405
|
+
"restarted"
|
|
26387
26406
|
]);
|
|
26388
26407
|
var POLLABLE_STATUSES = /* @__PURE__ */ new Set(["active", "orphaned"]);
|
|
26389
26408
|
function agentprotoHome3() {
|
|
@@ -26601,8 +26620,16 @@ function createSentinelRuntime(opts) {
|
|
|
26601
26620
|
try {
|
|
26602
26621
|
await opts.registry.sendMessage(msg, { source: "sentinel", origin: sentinel.id });
|
|
26603
26622
|
} catch (err) {
|
|
26604
|
-
if (
|
|
26605
|
-
|
|
26623
|
+
if (err instanceof SessionNotAliveError) {
|
|
26624
|
+
await handleDeadSession(sentinel, event, msg);
|
|
26625
|
+
return;
|
|
26626
|
+
}
|
|
26627
|
+
if (opts.sessionInfo && !opts.isSessionAlive(target.sessionId) && !opts.sessionInfo(target.sessionId)) {
|
|
26628
|
+
parkEvent(sentinel, event, `target session ${target.sessionId} no longer exists`);
|
|
26629
|
+
markOrphaned(sentinel);
|
|
26630
|
+
return;
|
|
26631
|
+
}
|
|
26632
|
+
throw err;
|
|
26606
26633
|
}
|
|
26607
26634
|
}
|
|
26608
26635
|
function checkSubjectTerminalExpiry(sentinel, event) {
|
|
@@ -26820,6 +26847,8 @@ function createSentinelRuntime(opts) {
|
|
|
26820
26847
|
// src/session-restart-core.ts
|
|
26821
26848
|
init_resume_strategies();
|
|
26822
26849
|
init_spawn_defaults();
|
|
26850
|
+
init_session_spawn();
|
|
26851
|
+
init_session_continue_fresh();
|
|
26823
26852
|
init_launch_config();
|
|
26824
26853
|
init_resume_context_digest();
|
|
26825
26854
|
init_eligibility_manifest();
|
|
@@ -27123,9 +27152,25 @@ async function restartAgentSession(registry, resolveAgentAdapter, prev, opts = {
|
|
|
27123
27152
|
authSpec = resumeAuth.authSpec;
|
|
27124
27153
|
authEcho = resumeAuth.authEcho;
|
|
27125
27154
|
}
|
|
27155
|
+
const buildRestartMcpServers = (newSessionId) => {
|
|
27156
|
+
if (!opts.daemonMcpUrl) {
|
|
27157
|
+
if (prev.mcpServers && prev.mcpServers.length > 0) {
|
|
27158
|
+
console.warn(
|
|
27159
|
+
`[restartAgentSession] no daemonMcpUrl wired for restart of ${prev.id} \u2014 carrying mcpServers forward WITHOUT re-stamping callerSessionId (the restarted session ${newSessionId} will keep speaking to the daemon under the OLD session's identity).`
|
|
27160
|
+
);
|
|
27161
|
+
}
|
|
27162
|
+
return prev.mcpServers;
|
|
27163
|
+
}
|
|
27164
|
+
const stripped = stripOwnCallerStamp(prev.mcpServers, prev.id);
|
|
27165
|
+
return stampDaemonCallerSessionId(stripped, {
|
|
27166
|
+
daemonMcpUrl: opts.daemonMcpUrl,
|
|
27167
|
+
callerSessionId: newSessionId
|
|
27168
|
+
});
|
|
27169
|
+
};
|
|
27126
27170
|
const spawnWithResume = async (resumeSessionId) => {
|
|
27127
27171
|
let liveSessionId;
|
|
27128
27172
|
const restartedSessionId = mintSessionId();
|
|
27173
|
+
const restartMcpServers = buildRestartMcpServers(restartedSessionId);
|
|
27129
27174
|
if (sandboxId !== void 0) {
|
|
27130
27175
|
return spawnInSandbox(sandboxId, restartedSessionId);
|
|
27131
27176
|
}
|
|
@@ -27168,7 +27213,7 @@ async function restartAgentSession(registry, resolveAgentAdapter, prev, opts = {
|
|
|
27168
27213
|
// Legacy AIP-45 mode: prefer an explicit override; otherwise carry the
|
|
27169
27214
|
// prior descriptor's mode forward so a plain restart preserves it.
|
|
27170
27215
|
...effMode ? { mode: effMode } : {},
|
|
27171
|
-
...
|
|
27216
|
+
...restartMcpServers ? { mcpServers: restartMcpServers } : {},
|
|
27172
27217
|
...authSpec ? { auth: authSpec } : {},
|
|
27173
27218
|
...launchConfig.options ? { options: launchConfig.options } : {},
|
|
27174
27219
|
// Spawn-time guarantees survive a restart: the adapter runs under the
|
|
@@ -27202,7 +27247,7 @@ async function restartAgentSession(registry, resolveAgentAdapter, prev, opts = {
|
|
|
27202
27247
|
...resolved.authDescriptor?.provider !== void 0 ? { adapterProvider: resolved.authDescriptor.provider } : {},
|
|
27203
27248
|
...resolved.authDescriptor?.modelDerivedApiKey !== void 0 ? { modelDerivedApiKey: resolved.authDescriptor.modelDerivedApiKey } : {},
|
|
27204
27249
|
...prev.label ? { label: prev.label } : {},
|
|
27205
|
-
...
|
|
27250
|
+
...restartMcpServers ? { mcpServers: restartMcpServers } : {},
|
|
27206
27251
|
...prevBoundary ? { meta: boundaryMeta(prevBoundary) } : {},
|
|
27207
27252
|
...effModel ? { model: effModel } : {},
|
|
27208
27253
|
// Decomposed config-axis echoes (SPEC §3.7) — carried forward from `prev`
|
|
@@ -27228,6 +27273,16 @@ async function restartAgentSession(registry, resolveAgentAdapter, prev, opts = {
|
|
|
27228
27273
|
...prev.origin ? { origin: prev.origin } : {},
|
|
27229
27274
|
...prev.parentSessionId ? { parentSessionId: prev.parentSessionId } : {},
|
|
27230
27275
|
...prev.depth !== void 0 ? { depth: prev.depth } : {},
|
|
27276
|
+
// Immutable spawn-time flags survive a restart exactly like
|
|
27277
|
+
// `continueAgentSessionFresh` carries `keepAlive`/`notifyParentOnCrash`
|
|
27278
|
+
// forward (session-continue-fresh.ts) — these are never axes a restart
|
|
27279
|
+
// overrides, only inherited, so dropping them here is what let a
|
|
27280
|
+
// persistent supervisor's restart silently become idle-reapable and
|
|
27281
|
+
// lose its crash-detect opt-ins.
|
|
27282
|
+
...prev.keepAlive ? { keepAlive: true } : {},
|
|
27283
|
+
...prev.notifyParentOnCrash ? { notifyParentOnCrash: true } : {},
|
|
27284
|
+
...prev.sentinelAutoWatch === false ? { sentinelAutoWatch: false } : {},
|
|
27285
|
+
...prev.restartPolicy ? { restartPolicy: prev.restartPolicy } : {},
|
|
27231
27286
|
// Verifiability echo (never the credential) — see the auth
|
|
27232
27287
|
// resolution block above. Absent when no credential resolved,
|
|
27233
27288
|
// same as session-spawn.ts.
|
|
@@ -27264,6 +27319,7 @@ async function restartAgentSession(registry, resolveAgentAdapter, prev, opts = {
|
|
|
27264
27319
|
`restartAgentSession: sandbox provider "${providerSlug}" not found \u2014 cannot re-attach sandbox "${boxSandboxId}".`
|
|
27265
27320
|
);
|
|
27266
27321
|
}
|
|
27322
|
+
const sandboxMcpServers = buildRestartMcpServers(restartedSessionId);
|
|
27267
27323
|
const spec = { provider: providerSlug, config: {} };
|
|
27268
27324
|
const lifecyclePolicy = resolveLifecyclePolicy(spec, true);
|
|
27269
27325
|
let host;
|
|
@@ -27293,7 +27349,7 @@ async function restartAgentSession(registry, resolveAgentAdapter, prev, opts = {
|
|
|
27293
27349
|
} : {},
|
|
27294
27350
|
...effEffort ? { effort: effEffort } : {},
|
|
27295
27351
|
...prev.label ? { label: prev.label } : {},
|
|
27296
|
-
...
|
|
27352
|
+
...sandboxMcpServers ? { mcpServers: toBoxMcpServerMounts(sandboxMcpServers) } : {},
|
|
27297
27353
|
...authSpec ? { auth: sandboxAuthForBox(authSpec) } : {}
|
|
27298
27354
|
});
|
|
27299
27355
|
remoteSessionId = remoteDesc.id;
|
|
@@ -27322,7 +27378,7 @@ async function restartAgentSession(registry, resolveAgentAdapter, prev, opts = {
|
|
|
27322
27378
|
...resolved?.authDescriptor?.provider !== void 0 ? { adapterProvider: resolved.authDescriptor.provider } : {},
|
|
27323
27379
|
...resolved?.authDescriptor?.modelDerivedApiKey !== void 0 ? { modelDerivedApiKey: resolved.authDescriptor.modelDerivedApiKey } : {},
|
|
27324
27380
|
...prev.label ? { label: prev.label } : {},
|
|
27325
|
-
...
|
|
27381
|
+
...sandboxMcpServers ? { mcpServers: sandboxMcpServers } : {},
|
|
27326
27382
|
...effModel ? { model: effModel } : {},
|
|
27327
27383
|
...effEffort ? { effort: effEffort } : {},
|
|
27328
27384
|
...effPosture !== void 0 ? { posture: effPosture } : {},
|
|
@@ -27333,6 +27389,10 @@ async function restartAgentSession(registry, resolveAgentAdapter, prev, opts = {
|
|
|
27333
27389
|
...prev.origin ? { origin: prev.origin } : {},
|
|
27334
27390
|
...prev.parentSessionId ? { parentSessionId: prev.parentSessionId } : {},
|
|
27335
27391
|
...prev.depth !== void 0 ? { depth: prev.depth } : {},
|
|
27392
|
+
...prev.keepAlive ? { keepAlive: true } : {},
|
|
27393
|
+
...prev.notifyParentOnCrash ? { notifyParentOnCrash: true } : {},
|
|
27394
|
+
...prev.sentinelAutoWatch === false ? { sentinelAutoWatch: false } : {},
|
|
27395
|
+
...prev.restartPolicy ? { restartPolicy: prev.restartPolicy } : {},
|
|
27336
27396
|
...authEcho?.fingerprint ? {
|
|
27337
27397
|
auth: {
|
|
27338
27398
|
mode: authEcho.authMode,
|
|
@@ -27374,6 +27434,9 @@ async function restartAgentSession(registry, resolveAgentAdapter, prev, opts = {
|
|
|
27374
27434
|
digestRecovered = result.hasContent;
|
|
27375
27435
|
}
|
|
27376
27436
|
}
|
|
27437
|
+
if (sandboxId === void 0) {
|
|
27438
|
+
registry.kill(prev.id, "SIGTERM", "restarted");
|
|
27439
|
+
}
|
|
27377
27440
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
27378
27441
|
const emit = (axis, value) => {
|
|
27379
27442
|
registry.emitConfigChanged({
|
|
@@ -32562,7 +32625,8 @@ function registerSessionTools(rawServer, opts) {
|
|
|
32562
32625
|
forceAgentResume: true,
|
|
32563
32626
|
overrides,
|
|
32564
32627
|
...listCatalogModels ? { listCatalogModels } : {},
|
|
32565
|
-
...opts.resolveSandboxProvider ? { resolveSandboxProvider: opts.resolveSandboxProvider } : {}
|
|
32628
|
+
...opts.resolveSandboxProvider ? { resolveSandboxProvider: opts.resolveSandboxProvider } : {},
|
|
32629
|
+
...opts.daemonMcpUrl ? { daemonMcpUrl: opts.daemonMcpUrl } : {}
|
|
32566
32630
|
});
|
|
32567
32631
|
return {
|
|
32568
32632
|
content: [
|
|
@@ -32772,7 +32836,8 @@ function registerSessionTools(rawServer, opts) {
|
|
|
32772
32836
|
}
|
|
32773
32837
|
}
|
|
32774
32838
|
const restarted = await restartAgentSession(registry, resolveAgentAdapter, prev, {
|
|
32775
|
-
...opts.resolveSandboxProvider ? { resolveSandboxProvider: opts.resolveSandboxProvider } : {}
|
|
32839
|
+
...opts.resolveSandboxProvider ? { resolveSandboxProvider: opts.resolveSandboxProvider } : {},
|
|
32840
|
+
...opts.daemonMcpUrl ? { daemonMcpUrl: opts.daemonMcpUrl } : {}
|
|
32776
32841
|
});
|
|
32777
32842
|
return {
|
|
32778
32843
|
content: [
|
|
@@ -39190,10 +39255,273 @@ async function handleSentinelInbound(hookKey, req, deps2) {
|
|
|
39190
39255
|
|
|
39191
39256
|
// src/sentinel-tools.ts
|
|
39192
39257
|
init_session_message();
|
|
39193
|
-
|
|
39258
|
+
var SESSION_SLUG = "session";
|
|
39259
|
+
var SESSION_DEFAULT_TYPES = [
|
|
39260
|
+
"session.turn.ended",
|
|
39261
|
+
"session.awaiting_input",
|
|
39262
|
+
"session.exited"
|
|
39263
|
+
];
|
|
39264
|
+
var SESSION_SUBJECT_RE = /^session:(.+)$/;
|
|
39265
|
+
function parseSessionSubject(subject) {
|
|
39266
|
+
return SESSION_SUBJECT_RE.exec(subject)?.[1];
|
|
39267
|
+
}
|
|
39268
|
+
var RING_CAP = 2e3;
|
|
39269
|
+
var ringsByBus = /* @__PURE__ */ new WeakMap();
|
|
39270
|
+
function appendEvent(ring, event) {
|
|
39271
|
+
const seq = ring.nextSeq++;
|
|
39272
|
+
ring.entries.push({ seq, event });
|
|
39273
|
+
if (ring.entries.length > RING_CAP) ring.entries.splice(0, ring.entries.length - RING_CAP);
|
|
39274
|
+
return seq;
|
|
39275
|
+
}
|
|
39276
|
+
function parseCursor(cursor) {
|
|
39277
|
+
if (!cursor) return void 0;
|
|
39278
|
+
const i = cursor.lastIndexOf(":");
|
|
39279
|
+
if (i < 0) return void 0;
|
|
39280
|
+
const seq = Number(cursor.slice(i + 1));
|
|
39281
|
+
return Number.isFinite(seq) ? { epoch: cursor.slice(0, i), seq } : void 0;
|
|
39282
|
+
}
|
|
39283
|
+
function formatCursor(ring, seq) {
|
|
39284
|
+
return `${ring.epoch}:${seq}`;
|
|
39285
|
+
}
|
|
39286
|
+
function mintEventId(parts) {
|
|
39287
|
+
return `evt_${createHash("sha256").update(parts.join("|")).digest("hex").slice(0, 24)}`;
|
|
39288
|
+
}
|
|
39289
|
+
function truncate3(text13, max = 200) {
|
|
39290
|
+
const flat = text13.replace(/\s+/g, " ").trim();
|
|
39291
|
+
return flat.length <= max ? flat : `${flat.slice(0, max - 1)}\u2026`;
|
|
39292
|
+
}
|
|
39293
|
+
function makeEvent2(input) {
|
|
39294
|
+
return {
|
|
39295
|
+
specversion: "1.0",
|
|
39296
|
+
id: mintEventId(input.idParts),
|
|
39297
|
+
source: `//agentproto.local/sentinel/${SESSION_SLUG}`,
|
|
39298
|
+
type: input.type,
|
|
39299
|
+
subject: input.subject,
|
|
39300
|
+
time: input.time,
|
|
39301
|
+
datacontenttype: "application/json",
|
|
39302
|
+
data: input.data,
|
|
39303
|
+
summary: input.summary,
|
|
39304
|
+
subjects: [input.subject],
|
|
39305
|
+
terminal: input.terminal
|
|
39306
|
+
};
|
|
39307
|
+
}
|
|
39308
|
+
function eventsForSessionEvent(ev) {
|
|
39309
|
+
switch (ev.type) {
|
|
39310
|
+
case "session:turn-end": {
|
|
39311
|
+
const subject = `session:${ev.sessionId}`;
|
|
39312
|
+
const who = ev.label ? `${ev.label} (${ev.sessionId})` : ev.sessionId;
|
|
39313
|
+
if (ev.awaitingInput) {
|
|
39314
|
+
const question = ev.question?.text;
|
|
39315
|
+
return [
|
|
39316
|
+
makeEvent2({
|
|
39317
|
+
idParts: [ev.sessionId, "awaiting_input", ev.ts],
|
|
39318
|
+
type: "session.awaiting_input",
|
|
39319
|
+
subject,
|
|
39320
|
+
time: ev.ts,
|
|
39321
|
+
terminal: false,
|
|
39322
|
+
data: { sessionId: ev.sessionId, ...question ? { question } : {} },
|
|
39323
|
+
summary: `${who} is awaiting input${question ? `: ${truncate3(question)}` : ""}`
|
|
39324
|
+
})
|
|
39325
|
+
];
|
|
39326
|
+
}
|
|
39327
|
+
const detail = ev.error ?? (ev.reason && ev.reason !== "completed" ? ev.reason : void 0);
|
|
39328
|
+
return [
|
|
39329
|
+
makeEvent2({
|
|
39330
|
+
idParts: [ev.sessionId, "turn-end", ev.ts],
|
|
39331
|
+
type: "session.turn.ended",
|
|
39332
|
+
subject,
|
|
39333
|
+
time: ev.ts,
|
|
39334
|
+
terminal: false,
|
|
39335
|
+
data: {
|
|
39336
|
+
sessionId: ev.sessionId,
|
|
39337
|
+
...ev.reason ? { reason: ev.reason } : {},
|
|
39338
|
+
...ev.error ? { error: ev.error } : {}
|
|
39339
|
+
},
|
|
39340
|
+
summary: `${who} ended a turn${detail ? `: ${truncate3(detail)}` : ""}`
|
|
39341
|
+
})
|
|
39342
|
+
];
|
|
39343
|
+
}
|
|
39344
|
+
case "session:awaiting-input": {
|
|
39345
|
+
const subject = `session:${ev.sessionId}`;
|
|
39346
|
+
const who = ev.label ? `${ev.label} (${ev.sessionId})` : ev.sessionId;
|
|
39347
|
+
const question = ev.question?.text;
|
|
39348
|
+
return [
|
|
39349
|
+
makeEvent2({
|
|
39350
|
+
idParts: [ev.sessionId, "awaiting_input", ev.ts],
|
|
39351
|
+
type: "session.awaiting_input",
|
|
39352
|
+
subject,
|
|
39353
|
+
time: ev.ts,
|
|
39354
|
+
terminal: false,
|
|
39355
|
+
data: { sessionId: ev.sessionId, ...question ? { question } : {} },
|
|
39356
|
+
summary: `${who} is awaiting input${question ? `: ${truncate3(question)}` : ""}`
|
|
39357
|
+
})
|
|
39358
|
+
];
|
|
39359
|
+
}
|
|
39360
|
+
case "session:exited": {
|
|
39361
|
+
const subject = `session:${ev.sessionId}`;
|
|
39362
|
+
const who = ev.label ? `${ev.label} (${ev.sessionId})` : ev.sessionId;
|
|
39363
|
+
return [
|
|
39364
|
+
makeEvent2({
|
|
39365
|
+
idParts: [ev.sessionId, "exited", ev.ts],
|
|
39366
|
+
type: "session.exited",
|
|
39367
|
+
subject,
|
|
39368
|
+
time: ev.ts,
|
|
39369
|
+
terminal: true,
|
|
39370
|
+
data: {
|
|
39371
|
+
sessionId: ev.sessionId,
|
|
39372
|
+
status: ev.status,
|
|
39373
|
+
...ev.exitCode !== void 0 ? { exitCode: ev.exitCode } : {},
|
|
39374
|
+
...ev.reason ? { reason: ev.reason } : {}
|
|
39375
|
+
},
|
|
39376
|
+
summary: `${who} exited (${ev.reason ?? ev.status})`
|
|
39377
|
+
})
|
|
39378
|
+
];
|
|
39379
|
+
}
|
|
39380
|
+
default:
|
|
39381
|
+
return [];
|
|
39382
|
+
}
|
|
39383
|
+
}
|
|
39384
|
+
function getRing(bus) {
|
|
39385
|
+
const existing = ringsByBus.get(bus);
|
|
39386
|
+
if (existing) return existing;
|
|
39387
|
+
const ring = { epoch: randomUUID(), entries: [], nextSeq: 0 };
|
|
39388
|
+
ringsByBus.set(bus, ring);
|
|
39389
|
+
bus.onAny((ev) => {
|
|
39390
|
+
for (const event of eventsForSessionEvent(ev)) appendEvent(ring, event);
|
|
39391
|
+
});
|
|
39392
|
+
return ring;
|
|
39393
|
+
}
|
|
39394
|
+
function identityOf(handle) {
|
|
39395
|
+
const state = handle.state;
|
|
39396
|
+
return typeof state?.sessionId === "string" ? state.sessionId : handle.remoteId;
|
|
39397
|
+
}
|
|
39398
|
+
function synthesizeExitEvent(ring, subject, sessionId, tag, info, goneReason) {
|
|
39399
|
+
const data = info ? {
|
|
39400
|
+
sessionId,
|
|
39401
|
+
status: info.status ?? "exited",
|
|
39402
|
+
...info.exitCode !== void 0 ? { exitCode: info.exitCode } : {},
|
|
39403
|
+
...info.endedReason ? { reason: info.endedReason } : {}
|
|
39404
|
+
} : { sessionId, status: "exited", ...goneReason ? { reason: goneReason } : {} };
|
|
39405
|
+
const summary = info ? `${info.label ?? sessionId} had already exited${info.endedReason ? ` (${info.endedReason})` : ""}` : `${sessionId} no longer exists${goneReason ? ` (${goneReason})` : ""}`;
|
|
39406
|
+
appendEvent(
|
|
39407
|
+
ring,
|
|
39408
|
+
makeEvent2({
|
|
39409
|
+
idParts: [sessionId, "exited", tag],
|
|
39410
|
+
type: "session.exited",
|
|
39411
|
+
subject,
|
|
39412
|
+
time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
39413
|
+
terminal: true,
|
|
39414
|
+
data,
|
|
39415
|
+
summary
|
|
39416
|
+
})
|
|
39417
|
+
);
|
|
39418
|
+
}
|
|
39419
|
+
function resyncIfStale(ring, handle, sessionId, subject, getSession, tag, goneTag) {
|
|
39420
|
+
const parsed = parseCursor(handle.cursor);
|
|
39421
|
+
if (parsed && parsed.epoch === ring.epoch) return parsed.seq;
|
|
39422
|
+
const lastSeq = ring.nextSeq - 1;
|
|
39423
|
+
const info = getSession(sessionId);
|
|
39424
|
+
if (!info) {
|
|
39425
|
+
synthesizeExitEvent(ring, subject, sessionId, goneTag, void 0, "session no longer exists");
|
|
39426
|
+
} else if (!info.alive) {
|
|
39427
|
+
synthesizeExitEvent(ring, subject, sessionId, tag, info);
|
|
39428
|
+
}
|
|
39429
|
+
return lastSeq;
|
|
39430
|
+
}
|
|
39431
|
+
function sessionSentinelProvider(deps2) {
|
|
39432
|
+
return {
|
|
39433
|
+
slug: SESSION_SLUG,
|
|
39434
|
+
name: "Session Lifecycle",
|
|
39435
|
+
version: "0.1.0",
|
|
39436
|
+
description: "In-process sentinel over this daemon's own session lifecycle \u2014 turn-end, awaiting-input, exit. No credentials, no external system: the subject IS another session (`session:<id>`).",
|
|
39437
|
+
requiresSetup: false,
|
|
39438
|
+
capabilities: {
|
|
39439
|
+
subjects: [SESSION_SLUG],
|
|
39440
|
+
push: false,
|
|
39441
|
+
poll: true,
|
|
39442
|
+
durable: false,
|
|
39443
|
+
needsPublicUrl: false,
|
|
39444
|
+
requiresAuth: false,
|
|
39445
|
+
typicalLatencyMs: 15e3
|
|
39446
|
+
},
|
|
39447
|
+
async check() {
|
|
39448
|
+
return true;
|
|
39449
|
+
},
|
|
39450
|
+
async create(spec, _delivery) {
|
|
39451
|
+
if (spec.match.length !== 1) {
|
|
39452
|
+
throw new Error(`${SESSION_SLUG}: exactly one match clause is supported (one sentinel per session)`);
|
|
39453
|
+
}
|
|
39454
|
+
const subject = spec.match[0].subject;
|
|
39455
|
+
const sessionId = parseSessionSubject(subject);
|
|
39456
|
+
if (!sessionId) {
|
|
39457
|
+
throw new Error(`${SESSION_SLUG}: subject "${subject}" is not a "session:<id>" subject`);
|
|
39458
|
+
}
|
|
39459
|
+
const info = deps2.getSession(sessionId);
|
|
39460
|
+
if (!info) {
|
|
39461
|
+
throw new Error(`${SESSION_SLUG}: no session "${sessionId}"`);
|
|
39462
|
+
}
|
|
39463
|
+
const ring = getRing(deps2.sessionEvents);
|
|
39464
|
+
const lastSeq = ring.nextSeq - 1;
|
|
39465
|
+
if (!info.alive) {
|
|
39466
|
+
synthesizeExitEvent(ring, subject, sessionId, "already-ended-at-create", info);
|
|
39467
|
+
}
|
|
39468
|
+
return { provider: SESSION_SLUG, remoteId: sessionId, cursor: formatCursor(ring, lastSeq), state: { sessionId } };
|
|
39469
|
+
},
|
|
39470
|
+
async attach(handle, _delivery) {
|
|
39471
|
+
const sessionId = identityOf(handle);
|
|
39472
|
+
if (!sessionId) return { ...handle };
|
|
39473
|
+
const subject = `session:${sessionId}`;
|
|
39474
|
+
const ring = getRing(deps2.sessionEvents);
|
|
39475
|
+
const lastSeq = resyncIfStale(
|
|
39476
|
+
ring,
|
|
39477
|
+
handle,
|
|
39478
|
+
sessionId,
|
|
39479
|
+
subject,
|
|
39480
|
+
deps2.getSession,
|
|
39481
|
+
"already-ended-at-attach",
|
|
39482
|
+
"gone-at-attach"
|
|
39483
|
+
);
|
|
39484
|
+
return { ...handle, cursor: formatCursor(ring, lastSeq) };
|
|
39485
|
+
},
|
|
39486
|
+
async cancel(_handle) {
|
|
39487
|
+
},
|
|
39488
|
+
async status(handle) {
|
|
39489
|
+
const sessionId = identityOf(handle);
|
|
39490
|
+
if (!sessionId) return { ok: false, detail: "no session identity on handle" };
|
|
39491
|
+
const info = deps2.getSession(sessionId);
|
|
39492
|
+
if (!info) return { ok: false, detail: `session "${sessionId}" no longer exists` };
|
|
39493
|
+
return { ok: true };
|
|
39494
|
+
},
|
|
39495
|
+
async poll(handle, limit) {
|
|
39496
|
+
const sessionId = identityOf(handle);
|
|
39497
|
+
if (!sessionId) return { events: [], cursor: handle.cursor ?? "" };
|
|
39498
|
+
const ring = getRing(deps2.sessionEvents);
|
|
39499
|
+
const subject = `session:${sessionId}`;
|
|
39500
|
+
const lastSeq = resyncIfStale(
|
|
39501
|
+
ring,
|
|
39502
|
+
handle,
|
|
39503
|
+
sessionId,
|
|
39504
|
+
subject,
|
|
39505
|
+
deps2.getSession,
|
|
39506
|
+
"already-ended-at-poll",
|
|
39507
|
+
"gone-at-poll"
|
|
39508
|
+
);
|
|
39509
|
+
const matching = ring.entries.filter((e) => e.seq > lastSeq && e.event.subject === subject);
|
|
39510
|
+
const slice = matching.slice(0, limit);
|
|
39511
|
+
const cursor = slice.length > 0 ? formatCursor(ring, slice[slice.length - 1].seq) : formatCursor(ring, lastSeq);
|
|
39512
|
+
return { events: slice.map((e) => e.event), cursor };
|
|
39513
|
+
},
|
|
39514
|
+
defaultTypes(subject) {
|
|
39515
|
+
return parseSessionSubject(subject) ? [...SESSION_DEFAULT_TYPES] : [];
|
|
39516
|
+
}
|
|
39517
|
+
};
|
|
39518
|
+
}
|
|
39519
|
+
|
|
39520
|
+
// src/sentinel-tools.ts
|
|
39521
|
+
function resolveUntil(input, defaultsToTerminal) {
|
|
39194
39522
|
if (input === "never") return { kind: "never" };
|
|
39195
39523
|
if (input === "subject_terminal") return { kind: "subject_terminal" };
|
|
39196
|
-
return
|
|
39524
|
+
return defaultsToTerminal ? { kind: "subject_terminal" } : { kind: "never" };
|
|
39197
39525
|
}
|
|
39198
39526
|
async function createSentinelWatch(deps2, input) {
|
|
39199
39527
|
if (!input.subject && !input.prUrl) {
|
|
@@ -39215,7 +39543,8 @@ async function createSentinelWatch(deps2, input) {
|
|
|
39215
39543
|
} else {
|
|
39216
39544
|
subject = input.subject;
|
|
39217
39545
|
}
|
|
39218
|
-
const
|
|
39546
|
+
const sessionSubject = !prSugar && parseSessionSubject(subject) !== void 0;
|
|
39547
|
+
const until = resolveUntil(input.until, prSugar || sessionSubject);
|
|
39219
39548
|
const sessionId = input.sessionId ?? deps2.defaultSessionId;
|
|
39220
39549
|
if (!sessionId) {
|
|
39221
39550
|
return {
|
|
@@ -39227,10 +39556,10 @@ async function createSentinelWatch(deps2, input) {
|
|
|
39227
39556
|
if (!deps2.isSessionAlive(sessionId)) {
|
|
39228
39557
|
return { ok: false, error: "session_not_alive", message: `session "${sessionId}" is not alive` };
|
|
39229
39558
|
}
|
|
39230
|
-
const providerSlug = input.provider ?? await autoSelectProviderSlug({
|
|
39559
|
+
const providerSlug = input.provider ?? (sessionSubject ? SESSION_SLUG : await autoSelectProviderSlug({
|
|
39231
39560
|
resolveProvider: deps2.resolveProvider,
|
|
39232
39561
|
...deps2.publicUrl ? { publicUrl: deps2.publicUrl } : {}
|
|
39233
|
-
});
|
|
39562
|
+
}));
|
|
39234
39563
|
const provider = await deps2.resolveProvider(providerSlug);
|
|
39235
39564
|
if (!provider) {
|
|
39236
39565
|
return { ok: false, error: "unknown_provider", message: `provider "${providerSlug}" is not available` };
|
|
@@ -39303,15 +39632,15 @@ function registerSentinelTools(server, opts) {
|
|
|
39303
39632
|
const { store, runtime, resolveProvider, isSessionAlive, callerSessionId, activeIntervalMs } = opts;
|
|
39304
39633
|
server.tool(
|
|
39305
39634
|
"sentinel_watch",
|
|
39306
|
-
"Watch a
|
|
39635
|
+
"Watch a subject \u2014 a GitHub PR/repo (default) or ANOTHER SESSION's own lifecycle \u2014 and deliver matching events as a `system`/`notice` message into a session's AIP-46 inbox. Provide either `prUrl` (sugar: `https://github.com/o/r/pull/N` -> subject `github:o/r#N`, the default PR type set, and `until: subject_terminal`) or a raw `subject`: a GitHub one (`github:o/r#N`, `github:o/r`), or `session:<id>` to watch another session \u2014 woken on its turn-end, awaiting-input, or exit, even if it never calls `message_parent`, with the watch self-expiring once it exits (`until` defaults to `subject_terminal` for this scheme too). Prefer this over `session_follow` for a single, known target that should auto-expire on exit; prefer `session_follow` for a broad selector (`all`/`cwdPrefix`) with coalesced digests across many sessions. `sessionId` (the DELIVERY target) defaults to the calling session \u2014 distinct from the `<id>` inside a `session:<id>` subject (the WATCHED session). `provider` picks the backend: `local-gh` (poll every ~15-60s over the host's authenticated `gh` CLI, zero infra), `webhook` (near-real-time push via a GitHub repo hook; needs a public daemon URL \u2014 a named tunnel or AGENTPROTO_PUBLIC_URL \u2014 and a `gh` token with admin:repo_hook), `agentpush` (hosted, durable subscription: events queue server-side across daemon downtime; needs an agentpush API key; one subject per sentinel) or `session` (in-process, zero infra, no credentials \u2014 the only backend that understands a `session:<id>` subject, and picked automatically for one); see `list_sentinel_adapters` for readiness. Omitted for a GitHub subject, it defaults to `agentpush` when set up, else `webhook` when a stable public URL exists and webhook is ready, else `local-gh`.",
|
|
39307
39636
|
{
|
|
39308
|
-
subject: z.string().optional().describe('Raw subject, e.g. "github:owner/repo#42". Mutually exclusive with prUrl.'),
|
|
39637
|
+
subject: z.string().optional().describe('Raw subject, e.g. "github:owner/repo#42" or "session:sess_abc123". Mutually exclusive with prUrl.'),
|
|
39309
39638
|
prUrl: z.string().optional().describe("https://github.com/owner/repo/pull/N \u2014 sugar for subject+types+until."),
|
|
39310
|
-
sessionId: z.string().optional().describe("
|
|
39639
|
+
sessionId: z.string().optional().describe("Delivery target session. Defaults to the calling session."),
|
|
39311
39640
|
types: z.array(z.string()).optional().describe("Type globs. Defaults to the provider's defaultTypes(subject)."),
|
|
39312
39641
|
urgency: urgencyField2.optional().describe('Inbox delivery urgency. Default "next-turn".'),
|
|
39313
|
-
until: untilField.optional().describe('Lifetime. Default "subject_terminal" for prUrl, "never" for
|
|
39314
|
-
provider: z.string().optional().describe('Provider slug: "local-gh", "webhook" or "
|
|
39642
|
+
until: untilField.optional().describe('Lifetime. Default "subject_terminal" for prUrl and for a "session:<id>" subject, "never" for any other raw subject.'),
|
|
39643
|
+
provider: z.string().optional().describe('Provider slug: "local-gh", "webhook", "agentpush" or "session". Default for a GitHub subject: "agentpush" when set up, else "webhook" when a stable public URL is configured and webhook is ready, else "local-gh". A "session:<id>" subject always defaults to "session".')
|
|
39315
39644
|
},
|
|
39316
39645
|
async (input) => {
|
|
39317
39646
|
const result = await createSentinelWatch(
|
|
@@ -39593,7 +39922,7 @@ function registerSessionFollowTools(server, opts) {
|
|
|
39593
39922
|
const { store, hasSession, callerSessionId } = opts;
|
|
39594
39923
|
server.tool(
|
|
39595
39924
|
"session_follow",
|
|
39596
|
-
"Wake a session (the follower, default: you) when OTHER sessions end a turn, await input, exit/crash, or get a PR opened/merged \u2014 no polling. `selector` picks sessions: `sessionIds`, `all: true` (evaluated at event time, so sessions spawned later are covered; root sessions only unless `rootOnly: false`), or `cwdPrefix`. `exclude` removes ids/labels. Events are coalesced within `batchMs` into one automatic digest message that never interrupts a busy follower. Your own events
|
|
39925
|
+
"Wake a session (the follower, default: you) when OTHER sessions end a turn, await input, exit/crash, or get a PR opened/merged \u2014 no polling. `selector` picks sessions: `sessionIds`, `all: true` (evaluated at event time, so sessions spawned later are covered; root sessions only unless `rootOnly: false`), or `cwdPrefix`. `exclude` removes ids/labels. Events are coalesced within `batchMs` into one automatic digest message that never interrupts a busy follower. Your own events are never delivered to you; your descendants' only with `excludeFollowerChildren: false`. Upserts by `key` when given. Survives daemon restarts.",
|
|
39597
39926
|
{
|
|
39598
39927
|
follower: z.string().optional().describe("Session to wake. Defaults to the calling session."),
|
|
39599
39928
|
key: z.string().optional().describe("Stable key: re-posting the same key updates that follow in place."),
|
|
@@ -39602,7 +39931,9 @@ function registerSessionFollowTools(server, opts) {
|
|
|
39602
39931
|
events: z.array(z.enum(FOLLOW_EVENTS)).optional().describe("Event kinds to deliver. Default: all of turn-end, awaiting-input, exited, crashed, pr-opened, pr-merged."),
|
|
39603
39932
|
batchMs: z.number().int().optional().describe("Coalescing window in ms. Default 15000."),
|
|
39604
39933
|
skipEmptyTurns: z.boolean().optional().describe("Drop silent no-op turns. Default true."),
|
|
39605
|
-
excludeFollowerChildren: z.boolean().optional().describe(
|
|
39934
|
+
excludeFollowerChildren: z.boolean().optional().describe(
|
|
39935
|
+
"Ignore the follower's own descendants. Default true. `false` delivers them (any depth, even under `rootOnly`) \u2014 what a supervisor wants for its own children."
|
|
39936
|
+
)
|
|
39606
39937
|
},
|
|
39607
39938
|
async (input) => {
|
|
39608
39939
|
const result = upsertSessionFollow(
|
|
@@ -43678,7 +44009,7 @@ function nextFireDate(cronInstance) {
|
|
|
43678
44009
|
return cronInstance.nextRun() ?? null;
|
|
43679
44010
|
}
|
|
43680
44011
|
function createCronScheduler(opts) {
|
|
43681
|
-
const { sessionEvents, registry, resolveAgentAdapter, dispatchTool, workspace } = opts;
|
|
44012
|
+
const { sessionEvents, registry, resolveAgentAdapter, daemonMcpUrl, dispatchTool, workspace } = opts;
|
|
43682
44013
|
const observeTurn = opts.observeTurn;
|
|
43683
44014
|
const observeTimeoutMs = opts.observeTimeoutMs ?? DEFAULT_OBSERVE_TIMEOUT_MS;
|
|
43684
44015
|
const persistPath = opts.persistPath ?? DEFAULT_PERSIST_PATH3();
|
|
@@ -43781,7 +44112,10 @@ function createCronScheduler(opts) {
|
|
|
43781
44112
|
// result, which only an agent-cli session has — never let
|
|
43782
44113
|
// decideRestartStrategy hand back a PTY-native resume (e.g.
|
|
43783
44114
|
// claude-code's `claude --resume`) here.
|
|
43784
|
-
{
|
|
44115
|
+
{
|
|
44116
|
+
forceAgentResume: true,
|
|
44117
|
+
...daemonMcpUrl ? { daemonMcpUrl } : {}
|
|
44118
|
+
}
|
|
43785
44119
|
);
|
|
43786
44120
|
action.sessionId = restarted.desc.id;
|
|
43787
44121
|
await registry.sendPrompt(restarted.desc.id, action.prompt);
|
|
@@ -54580,7 +54914,8 @@ async function handleSessions(req, res, path, registry, resolveAgentAdapter, pty
|
|
|
54580
54914
|
const restarted = await restartAgentSession(registry, resolveAgentAdapter, prev, {
|
|
54581
54915
|
forceAgentResume: true,
|
|
54582
54916
|
overrides,
|
|
54583
|
-
...listCatalogModels ? { listCatalogModels } : {}
|
|
54917
|
+
...listCatalogModels ? { listCatalogModels } : {},
|
|
54918
|
+
...daemonMcpUrl ? { daemonMcpUrl } : {}
|
|
54584
54919
|
});
|
|
54585
54920
|
json3(200, {
|
|
54586
54921
|
...sessionDescriptorForHttp(restarted.desc),
|
|
@@ -57868,7 +58203,10 @@ var BUILTIN_SENTINEL_PROVIDERS = {
|
|
|
57868
58203
|
[WEBHOOK_SLUG]: () => webhookSentinelProvider(),
|
|
57869
58204
|
[AGENTPUSH_SLUG]: (creds) => agentpushSentinelProvider({ creds })
|
|
57870
58205
|
};
|
|
57871
|
-
var BUILTIN_SENTINEL_SLUGS = [LOCAL_GH_SLUG, WEBHOOK_SLUG, AGENTPUSH_SLUG];
|
|
58206
|
+
var BUILTIN_SENTINEL_SLUGS = [LOCAL_GH_SLUG, WEBHOOK_SLUG, AGENTPUSH_SLUG, SESSION_SLUG];
|
|
58207
|
+
function configureSessionSentinelProvider(deps2) {
|
|
58208
|
+
BUILTIN_SENTINEL_PROVIDERS[SESSION_SLUG] = () => sessionSentinelProvider(deps2);
|
|
58209
|
+
}
|
|
57872
58210
|
var slugToCamel3 = (slug) => slug.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
57873
58211
|
function isSentinelProvider(x) {
|
|
57874
58212
|
if (!x || typeof x !== "object") return false;
|
|
@@ -58673,11 +59011,11 @@ function followCoversSession(follow, sessionId, desc, registry, eventLabel) {
|
|
|
58673
59011
|
if (follow.exclude?.sessionIds?.includes(sessionId)) return false;
|
|
58674
59012
|
const label = desc?.label ?? eventLabel;
|
|
58675
59013
|
if (label && follow.exclude?.labels?.includes(label)) return false;
|
|
58676
|
-
|
|
58677
|
-
|
|
58678
|
-
}
|
|
59014
|
+
const ownDescendant = descendsFrom(registry, desc, follow.follower);
|
|
59015
|
+
if (ownDescendant && follow.excludeFollowerChildren) return false;
|
|
58679
59016
|
const sel = follow.selector;
|
|
58680
59017
|
if (sel.sessionIds?.includes(sessionId)) return true;
|
|
59018
|
+
if (ownDescendant && (sel.all === true || sel.cwdPrefix !== void 0 && sel.cwdPrefix !== "")) return true;
|
|
58681
59019
|
const broad = sel.all === true || sel.cwdPrefix !== void 0 && sel.cwdPrefix !== "";
|
|
58682
59020
|
if (!broad) return false;
|
|
58683
59021
|
if (sel.cwdPrefix && !cwdUnder(desc?.cwd, sel.cwdPrefix)) return false;
|
|
@@ -66451,6 +66789,13 @@ var SENTINEL_CATALOG = [
|
|
|
66451
66789
|
description: "Hosted event subscriptions over agentpush \u2014 GitHub App installs, Telegram, generic hooks. Events queue server-side and survive daemon downtime; delivered by poll (default, no public URL) or push. Needs an agentpush workspace API key (`setup_sentinel_provider`, or an imported `agentpush` MCP alias).",
|
|
66452
66790
|
packageName: "@agentproto/runtime",
|
|
66453
66791
|
hint: "any source \xB7 durable \xB7 needs API key"
|
|
66792
|
+
},
|
|
66793
|
+
{
|
|
66794
|
+
slug: SESSION_SLUG,
|
|
66795
|
+
name: "Session Lifecycle",
|
|
66796
|
+
description: 'In-process watcher over this daemon\'s own session lifecycle (turn-end, awaiting-input, exit) for a "session:<id>" subject. No credentials, no external system \u2014 wired up by the daemon itself, not configurable via `setup_sentinel_provider`.',
|
|
66797
|
+
packageName: "@agentproto/runtime",
|
|
66798
|
+
hint: "session \xB7 zero-infra \xB7 in-process"
|
|
66454
66799
|
}
|
|
66455
66800
|
];
|
|
66456
66801
|
function toSentinelInfo(handle) {
|
|
@@ -67102,7 +67447,8 @@ function makeRestartForRouting(deps2, config) {
|
|
|
67102
67447
|
}
|
|
67103
67448
|
const restarted = await restartPreferInPlace(deps2.sessions, deps2.resolveAgentAdapter, desc, {
|
|
67104
67449
|
forceAgentResume: true,
|
|
67105
|
-
allowDeliberateEnd: config.allowDeliberateEnd
|
|
67450
|
+
allowDeliberateEnd: config.allowDeliberateEnd,
|
|
67451
|
+
...deps2.daemonMcpUrl ? { daemonMcpUrl: deps2.daemonMcpUrl } : {}
|
|
67106
67452
|
});
|
|
67107
67453
|
return restarted.desc.id;
|
|
67108
67454
|
};
|
|
@@ -67393,6 +67739,20 @@ async function createGateway(opts) {
|
|
|
67393
67739
|
}
|
|
67394
67740
|
} : {}
|
|
67395
67741
|
});
|
|
67742
|
+
configureSessionSentinelProvider({
|
|
67743
|
+
sessionEvents,
|
|
67744
|
+
getSession: (sessionId) => {
|
|
67745
|
+
const desc = sessions.get(sessionId);
|
|
67746
|
+
if (!desc) return void 0;
|
|
67747
|
+
return {
|
|
67748
|
+
alive: desc.alive === true,
|
|
67749
|
+
status: desc.status,
|
|
67750
|
+
...desc.label ? { label: desc.label } : {},
|
|
67751
|
+
...desc.endedReason ? { endedReason: desc.endedReason } : {},
|
|
67752
|
+
...desc.exitCode !== void 0 ? { exitCode: desc.exitCode } : {}
|
|
67753
|
+
};
|
|
67754
|
+
}
|
|
67755
|
+
});
|
|
67396
67756
|
const restartScheduler = createRestartScheduler({ registry: sessions, sessionEvents });
|
|
67397
67757
|
const supervisor = createCompletionPolicySupervisor({
|
|
67398
67758
|
registry: sessions,
|
|
@@ -67434,6 +67794,7 @@ async function createGateway(opts) {
|
|
|
67434
67794
|
const cronScheduler = createCronScheduler({
|
|
67435
67795
|
sessionEvents,
|
|
67436
67796
|
registry: sessions,
|
|
67797
|
+
daemonMcpUrl,
|
|
67437
67798
|
...opts.resolveAgentAdapter ? { resolveAgentAdapter: opts.resolveAgentAdapter } : {},
|
|
67438
67799
|
...opts.listAgentAdapters ? { listAgentAdapters: opts.listAgentAdapters } : {},
|
|
67439
67800
|
getAuthProfile: getAuthProfile,
|
|
@@ -67609,11 +67970,11 @@ async function createGateway(opts) {
|
|
|
67609
67970
|
return desc.processAlive !== false;
|
|
67610
67971
|
};
|
|
67611
67972
|
const restartSentinelSession = makeRestartForRouting(
|
|
67612
|
-
{ sessions, resolveAgentAdapter: opts.resolveAgentAdapter },
|
|
67973
|
+
{ sessions, resolveAgentAdapter: opts.resolveAgentAdapter, daemonMcpUrl },
|
|
67613
67974
|
{ name: "restartSentinelSession", allowDeliberateEnd: false }
|
|
67614
67975
|
);
|
|
67615
67976
|
const restartInboundSession = makeRestartForRouting(
|
|
67616
|
-
{ sessions, resolveAgentAdapter: opts.resolveAgentAdapter },
|
|
67977
|
+
{ sessions, resolveAgentAdapter: opts.resolveAgentAdapter, daemonMcpUrl },
|
|
67617
67978
|
{ name: "restartInboundSession", allowDeliberateEnd: true }
|
|
67618
67979
|
);
|
|
67619
67980
|
const sentinelRuntime = createSentinelRuntime({
|