@slock-ai/daemon 0.56.0 → 0.56.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.
@@ -6145,7 +6145,6 @@ var OpenCodeDriver = class {
6145
6145
  import { randomUUID as randomUUID3 } from "crypto";
6146
6146
  import { EventEmitter } from "events";
6147
6147
  import { mkdirSync as mkdirSync4, readdirSync } from "fs";
6148
- import { PassThrough, Writable } from "stream";
6149
6148
  import path11 from "path";
6150
6149
  import {
6151
6150
  AuthStorage,
@@ -6164,6 +6163,13 @@ var PI_PROVIDER_LABELS = {
6164
6163
  openai: "OpenAI",
6165
6164
  openrouter: "OpenRouter"
6166
6165
  };
6166
+ function createPiSdkEventMappingState(sessionId = null) {
6167
+ return {
6168
+ sessionId,
6169
+ sessionAnnounced: false,
6170
+ sawTextDelta: false
6171
+ };
6172
+ }
6167
6173
  function buildPiSessionDir(workingDirectory) {
6168
6174
  return path11.join(workingDirectory, PI_SESSION_DIR);
6169
6175
  }
@@ -6189,12 +6195,6 @@ function findPiSessionFile(sessionDir, sessionId) {
6189
6195
  const match = entries.find((entry) => entry.endsWith(suffix));
6190
6196
  return match ? path11.join(sessionDir, match) : null;
6191
6197
  }
6192
- function piSdkEventToJsonLine(event) {
6193
- if (event.type === "agent_end") {
6194
- return JSON.stringify({ type: "agent_end" });
6195
- }
6196
- return JSON.stringify(event);
6197
- }
6198
6198
  function detectPiModelsFromRegistry(modelRegistry) {
6199
6199
  const models = [];
6200
6200
  const seen = /* @__PURE__ */ new Set();
@@ -6244,114 +6244,309 @@ function piErrorMessage(error) {
6244
6244
  }
6245
6245
  return "Unknown Pi error";
6246
6246
  }
6247
- var PiSdkProcess = class extends EventEmitter {
6248
- constructor(session) {
6249
- super();
6250
- this.session = session;
6251
- this.stdin = new Writable({
6252
- write: (chunk, _encoding, callback) => {
6253
- this.handleInput(String(chunk)).then(
6254
- () => callback(),
6255
- (error) => {
6256
- this.writeError(error);
6257
- callback();
6258
- }
6259
- );
6247
+ function pushSessionInitIfNeeded(state, events) {
6248
+ if (!state.sessionAnnounced && state.sessionId) {
6249
+ events.push({ kind: "session_init", sessionId: state.sessionId });
6250
+ state.sessionAnnounced = true;
6251
+ }
6252
+ }
6253
+ function mapPiAssistantMessageEvent(assistantEvent, state) {
6254
+ switch (assistantEvent.type) {
6255
+ case "thinking_delta":
6256
+ return typeof assistantEvent.delta === "string" && assistantEvent.delta.length > 0 ? [{ kind: "thinking", text: assistantEvent.delta }] : [];
6257
+ case "text_delta":
6258
+ if (typeof assistantEvent.delta === "string" && assistantEvent.delta.length > 0) {
6259
+ state.sawTextDelta = true;
6260
+ return [{ kind: "text", text: assistantEvent.delta }];
6260
6261
  }
6261
- });
6262
- this.session.subscribe((event) => {
6263
- this.writeStdout(piSdkEventToJsonLine(event));
6264
- });
6262
+ return [];
6263
+ case "text_end":
6264
+ return !state.sawTextDelta && typeof assistantEvent.content === "string" && assistantEvent.content.length > 0 ? [{ kind: "text", text: assistantEvent.content }] : [];
6265
+ case "error":
6266
+ return [{ kind: "error", message: piErrorMessage(assistantEvent.error.errorMessage || assistantEvent.error) }];
6267
+ case "thinking_start":
6268
+ case "thinking_end":
6269
+ case "text_start":
6270
+ case "toolcall_start":
6271
+ case "toolcall_delta":
6272
+ case "toolcall_end":
6273
+ case "start":
6274
+ case "done":
6275
+ return [];
6276
+ default: {
6277
+ const _exhaustive = assistantEvent;
6278
+ return _exhaustive;
6279
+ }
6280
+ }
6281
+ }
6282
+ function mapPiSdkEventToParsedEvents(event, state) {
6283
+ const events = [];
6284
+ pushSessionInitIfNeeded(state, events);
6285
+ switch (event.type) {
6286
+ case "agent_start":
6287
+ case "turn_start":
6288
+ case "turn_end":
6289
+ case "message_end":
6290
+ case "tool_execution_update":
6291
+ case "queue_update":
6292
+ case "session_info_changed":
6293
+ case "thinking_level_changed":
6294
+ case "auto_retry_start":
6295
+ case "auto_retry_end":
6296
+ return events;
6297
+ case "message_start":
6298
+ if (event.message.role === "assistant") {
6299
+ state.sawTextDelta = false;
6300
+ }
6301
+ return events;
6302
+ case "message_update":
6303
+ events.push(...mapPiAssistantMessageEvent(event.assistantMessageEvent, state));
6304
+ return events;
6305
+ case "tool_execution_start":
6306
+ events.push({
6307
+ kind: "tool_call",
6308
+ name: event.toolName || "unknown_tool",
6309
+ input: event.args ?? {}
6310
+ });
6311
+ return events;
6312
+ case "tool_execution_end":
6313
+ events.push({ kind: "tool_output", name: event.toolName || "unknown_tool" });
6314
+ return events;
6315
+ case "compaction_start":
6316
+ events.push({ kind: "compaction_started" });
6317
+ return events;
6318
+ case "compaction_end":
6319
+ events.push({ kind: "compaction_finished" });
6320
+ return events;
6321
+ case "agent_end":
6322
+ events.push({ kind: "turn_end", sessionId: state.sessionId || void 0 });
6323
+ return events;
6324
+ default: {
6325
+ const _exhaustive = event;
6326
+ return _exhaustive;
6327
+ }
6265
6328
  }
6266
- stdout = new PassThrough();
6267
- stderr = new PassThrough();
6268
- stdin;
6269
- pid = void 0;
6270
- exitCode = null;
6271
- signalCode = null;
6272
- killed = false;
6273
- buffer = "";
6274
- closed = false;
6275
- kill(signal = "SIGTERM") {
6276
- if (this.closed) return false;
6277
- this.killed = true;
6278
- this.signalCode = typeof signal === "string" ? signal : null;
6279
- void this.shutdown(null, this.signalCode);
6280
- return true;
6329
+ }
6330
+ var PI_RUNTIME_SESSION_DESCRIPTOR = {
6331
+ transport: "sdk",
6332
+ lifecycle: "sdk_session",
6333
+ input: {
6334
+ initial: "start",
6335
+ idle: "sdk_prompt",
6336
+ busy: "sdk_steer"
6337
+ },
6338
+ readiness: "sdk_ready",
6339
+ turnBoundary: "sdk_event",
6340
+ startPolicy: "immediate",
6341
+ inFlightWake: "steer",
6342
+ busyDelivery: "direct",
6343
+ postTurn: "keep_alive"
6344
+ };
6345
+ async function createPiAgentSessionForContext(ctx, sessionId) {
6346
+ const sessionDir = buildPiSessionDir(ctx.workingDirectory);
6347
+ mkdirSync4(sessionDir, { recursive: true });
6348
+ const spawnEnv = await buildPiSpawnEnv(ctx);
6349
+ const agentDir = spawnEnv.PI_CODING_AGENT_DIR || getAgentDir();
6350
+ const authStorage = AuthStorage.create(path11.join(agentDir, "auth.json"));
6351
+ const modelRegistry = ModelRegistry.create(authStorage, path11.join(agentDir, "models.json"));
6352
+ const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
6353
+ const model = resolvePiModelFromRegistry(launchRuntimeFields.model, modelRegistry);
6354
+ if (launchRuntimeFields.model && launchRuntimeFields.model !== "default" && !model) {
6355
+ throw new Error(`Pi model not found: ${launchRuntimeFields.model}`);
6356
+ }
6357
+ const settingsManager = SettingsManager.inMemory({ compaction: { enabled: false } });
6358
+ const resourceLoader = new DefaultResourceLoader({
6359
+ cwd: ctx.workingDirectory,
6360
+ agentDir,
6361
+ settingsManager,
6362
+ systemPromptOverride: () => ctx.standingPrompt
6363
+ });
6364
+ await resourceLoader.reload();
6365
+ const existingSessionFile = ctx.config.sessionId ? findPiSessionFile(sessionDir, ctx.config.sessionId) : null;
6366
+ const sessionManager = existingSessionFile ? SessionManager.open(existingSessionFile, sessionDir, ctx.workingDirectory) : SessionManager.create(ctx.workingDirectory, sessionDir, { id: sessionId });
6367
+ const { session } = await createAgentSession({
6368
+ cwd: ctx.workingDirectory,
6369
+ agentDir,
6370
+ model,
6371
+ thinkingLevel: launchRuntimeFields.reasoningEffort,
6372
+ authStorage,
6373
+ modelRegistry,
6374
+ resourceLoader,
6375
+ customTools: [
6376
+ createBashTool(ctx.workingDirectory, {
6377
+ spawnHook: (spawnContext) => ({
6378
+ ...spawnContext,
6379
+ env: {
6380
+ ...spawnContext.env,
6381
+ ...spawnEnv
6382
+ }
6383
+ })
6384
+ })
6385
+ ],
6386
+ sessionManager,
6387
+ settingsManager
6388
+ });
6389
+ return session;
6390
+ }
6391
+ var PiSdkRuntimeSession = class {
6392
+ constructor(ctx, setCurrentSessionId, sessionFactory = createPiAgentSessionForContext) {
6393
+ this.ctx = ctx;
6394
+ this.setCurrentSessionId = setCurrentSessionId;
6395
+ this.sessionFactory = sessionFactory;
6396
+ this.mappingState = createPiSdkEventMappingState(ctx.config.sessionId || null);
6397
+ }
6398
+ descriptor = PI_RUNTIME_SESSION_DESCRIPTOR;
6399
+ events = new EventEmitter();
6400
+ mappingState;
6401
+ session = null;
6402
+ unsubscribe = null;
6403
+ started = false;
6404
+ didClose = false;
6405
+ requestedStopReason;
6406
+ exitInfo = null;
6407
+ get pid() {
6408
+ return void 0;
6281
6409
  }
6282
- ref() {
6283
- return this;
6410
+ get currentSessionId() {
6411
+ return this.mappingState.sessionId;
6284
6412
  }
6285
- unref() {
6286
- return this;
6413
+ get exitCode() {
6414
+ return this.exitInfo?.code ?? null;
6287
6415
  }
6288
- async handleInput(chunk) {
6289
- this.buffer += chunk;
6290
- const lines = this.buffer.split("\n");
6291
- this.buffer = lines.pop() || "";
6292
- for (const line of lines) {
6293
- if (!line.trim() || this.closed) continue;
6294
- await this.handleCommand(line);
6295
- }
6416
+ get signalCode() {
6417
+ return this.exitInfo?.signal ?? null;
6296
6418
  }
6297
- async handleCommand(raw) {
6298
- let command;
6299
- try {
6300
- command = JSON.parse(raw);
6301
- } catch (error) {
6302
- this.writeError(error);
6303
- return;
6419
+ get closed() {
6420
+ return this.didClose;
6421
+ }
6422
+ on(event, cb) {
6423
+ this.events.on(event, cb);
6424
+ }
6425
+ async start(input) {
6426
+ if (this.started) {
6427
+ return { ok: false, reason: "runtime_error", error: "runtime session already started" };
6304
6428
  }
6305
- const id = typeof command.id === "string" ? command.id : void 0;
6306
- try {
6307
- if (command.type === "prompt") {
6308
- await this.session.prompt(String(command.message ?? ""));
6309
- this.writeStdout(JSON.stringify({ id, type: "response", command: "prompt", success: true }));
6310
- } else if (command.type === "steer") {
6311
- await this.session.steer(String(command.message ?? ""));
6312
- this.writeStdout(JSON.stringify({ id, type: "response", command: "steer", success: true }));
6313
- } else {
6314
- throw new Error(`Unsupported Pi SDK command: ${command.type || "unknown"}`);
6429
+ if (this.didClose) return { ok: false, reason: "closed" };
6430
+ this.started = true;
6431
+ const sessionId = input.sessionId || this.ctx.config.sessionId || randomUUID3();
6432
+ this.mappingState.sessionId = sessionId;
6433
+ this.setCurrentSessionId(sessionId);
6434
+ const session = await this.sessionFactory({
6435
+ ...this.ctx,
6436
+ config: {
6437
+ ...this.ctx.config,
6438
+ sessionId
6315
6439
  }
6316
- } catch (error) {
6317
- this.writeStdout(JSON.stringify({
6318
- id,
6319
- type: "response",
6320
- command: command.type || "unknown",
6321
- success: false,
6322
- error: piErrorMessage(error)
6323
- }));
6440
+ }, sessionId);
6441
+ this.session = session;
6442
+ this.mappingState.sessionId = session.sessionId;
6443
+ this.setCurrentSessionId(session.sessionId);
6444
+ this.unsubscribe = session.subscribe((event) => {
6445
+ for (const parsed of mapPiSdkEventToParsedEvents(event, this.mappingState)) {
6446
+ this.events.emit("runtime_event", parsed);
6447
+ }
6448
+ });
6449
+ this.emitSessionInit();
6450
+ this.launchPrompt(input.text);
6451
+ return { ok: true, acceptedAs: "prompt" };
6452
+ }
6453
+ send(input) {
6454
+ if (this.didClose) return { ok: false, reason: "closed" };
6455
+ const session = this.session;
6456
+ if (!session) return { ok: false, reason: "closed" };
6457
+ if (input.mode === "busy") {
6458
+ this.deferSdkCall(() => session.steer(input.text));
6459
+ return { ok: true, acceptedAs: "steer" };
6460
+ }
6461
+ if (session.isStreaming) {
6462
+ return { ok: false, reason: "busy_rejected", error: "Pi session is still streaming" };
6463
+ }
6464
+ this.launchPrompt(input.text);
6465
+ return { ok: true, acceptedAs: "prompt" };
6466
+ }
6467
+ async stop(opts) {
6468
+ if (this.didClose) return;
6469
+ this.requestedStopReason = opts?.reason;
6470
+ const signal = opts?.signal ?? "SIGTERM";
6471
+ const session = this.session;
6472
+ if (session?.isStreaming) {
6473
+ try {
6474
+ await session.abort();
6475
+ } catch (error) {
6476
+ this.events.emit("stderr", piErrorMessage(error));
6477
+ }
6478
+ }
6479
+ await this.disposeSession();
6480
+ this.emitExitAndClose(null, signal);
6481
+ }
6482
+ async dispose() {
6483
+ if (this.didClose) return;
6484
+ await this.disposeSession();
6485
+ this.emitExitAndClose(0, null);
6486
+ }
6487
+ emitSessionInit() {
6488
+ const sessionId = this.mappingState.sessionId;
6489
+ if (!sessionId || this.mappingState.sessionAnnounced) return;
6490
+ this.mappingState.sessionAnnounced = true;
6491
+ this.events.emit("runtime_event", { kind: "session_init", sessionId });
6492
+ }
6493
+ launchPrompt(text) {
6494
+ const session = this.session;
6495
+ if (!session) {
6496
+ this.events.emit("runtime_event", {
6497
+ kind: "error",
6498
+ message: "Pi SDK session is not started"
6499
+ });
6500
+ return;
6324
6501
  }
6502
+ this.deferSdkCall(() => session.prompt(text));
6325
6503
  }
6326
- writeStdout(line) {
6327
- if (this.closed) return;
6328
- this.stdout.write(line + "\n");
6329
- }
6330
- writeError(error) {
6331
- if (this.closed) return;
6332
- this.stderr.write(piErrorMessage(error) + "\n");
6504
+ deferSdkCall(invoke) {
6505
+ setImmediate(() => {
6506
+ if (this.didClose) return;
6507
+ try {
6508
+ void invoke().catch((error) => {
6509
+ if (this.didClose) return;
6510
+ this.events.emit("runtime_event", {
6511
+ kind: "error",
6512
+ message: piErrorMessage(error)
6513
+ });
6514
+ });
6515
+ } catch (error) {
6516
+ if (this.didClose) return;
6517
+ this.events.emit("runtime_event", {
6518
+ kind: "error",
6519
+ message: piErrorMessage(error)
6520
+ });
6521
+ }
6522
+ });
6333
6523
  }
6334
- async shutdown(code, signal) {
6335
- if (this.closed) return;
6336
- this.closed = true;
6337
- this.exitCode = code;
6338
- this.signalCode = signal;
6524
+ async disposeSession() {
6525
+ const unsubscribe = this.unsubscribe;
6526
+ this.unsubscribe = null;
6339
6527
  try {
6340
- if (this.session.isStreaming) {
6341
- await this.session.abort();
6342
- }
6343
- } catch (error) {
6344
- this.stderr.write(piErrorMessage(error) + "\n");
6528
+ unsubscribe?.();
6529
+ } catch {
6345
6530
  }
6531
+ const session = this.session;
6532
+ this.session = null;
6346
6533
  try {
6347
- this.session.dispose();
6348
- } catch {
6534
+ session?.dispose();
6535
+ } catch (error) {
6536
+ this.events.emit("stderr", piErrorMessage(error));
6349
6537
  }
6350
- this.stdin.destroy();
6351
- this.stdout.end();
6352
- this.stderr.end();
6353
- this.emit("exit", code, signal);
6354
- this.emit("close", code, signal);
6538
+ }
6539
+ emitExitAndClose(code, signal) {
6540
+ if (this.didClose) return;
6541
+ this.didClose = true;
6542
+ const info = {
6543
+ code,
6544
+ signal,
6545
+ reason: this.requestedStopReason ? "requested" : "runtime_exit"
6546
+ };
6547
+ this.exitInfo = info;
6548
+ this.events.emit("exit", info);
6549
+ this.events.emit("close", info);
6355
6550
  }
6356
6551
  };
6357
6552
  var PiDriver = class {
@@ -6378,10 +6573,9 @@ var PiDriver = class {
6378
6573
  busyDeliveryMode = "direct";
6379
6574
  usesSlockCliForCommunication = true;
6380
6575
  sessionId = null;
6381
- sessionAnnounced = false;
6382
- sawTextDelta = false;
6383
- requestId = 0;
6384
- process = null;
6576
+ get currentSessionId() {
6577
+ return this.sessionId;
6578
+ }
6385
6579
  probe() {
6386
6580
  return {
6387
6581
  available: true,
@@ -6391,144 +6585,20 @@ var PiDriver = class {
6391
6585
  async detectModels() {
6392
6586
  return detectPiModels();
6393
6587
  }
6394
- async spawn(ctx) {
6395
- this.sessionId = ctx.config.sessionId || randomUUID3();
6396
- this.sessionAnnounced = false;
6397
- this.sawTextDelta = false;
6398
- this.requestId = 0;
6399
- const sessionDir = buildPiSessionDir(ctx.workingDirectory);
6400
- mkdirSync4(sessionDir, { recursive: true });
6401
- const spawnEnv = await buildPiSpawnEnv(ctx);
6402
- const agentDir = spawnEnv.PI_CODING_AGENT_DIR || getAgentDir();
6403
- const authStorage = AuthStorage.create(path11.join(agentDir, "auth.json"));
6404
- const modelRegistry = ModelRegistry.create(authStorage, path11.join(agentDir, "models.json"));
6405
- const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
6406
- const model = resolvePiModelFromRegistry(launchRuntimeFields.model, modelRegistry);
6407
- if (launchRuntimeFields.model && launchRuntimeFields.model !== "default" && !model) {
6408
- throw new Error(`Pi model not found: ${launchRuntimeFields.model}`);
6409
- }
6410
- const settingsManager = SettingsManager.inMemory({ compaction: { enabled: false } });
6411
- const resourceLoader = new DefaultResourceLoader({
6412
- cwd: ctx.workingDirectory,
6413
- agentDir,
6414
- settingsManager,
6415
- systemPromptOverride: () => ctx.standingPrompt
6416
- });
6417
- await resourceLoader.reload();
6418
- const existingSessionFile = ctx.config.sessionId ? findPiSessionFile(sessionDir, ctx.config.sessionId) : null;
6419
- const sessionManager = existingSessionFile ? SessionManager.open(existingSessionFile, sessionDir, ctx.workingDirectory) : SessionManager.create(ctx.workingDirectory, sessionDir, { id: this.sessionId });
6420
- const { session } = await createAgentSession({
6421
- cwd: ctx.workingDirectory,
6422
- agentDir,
6423
- model,
6424
- thinkingLevel: launchRuntimeFields.reasoningEffort,
6425
- authStorage,
6426
- modelRegistry,
6427
- resourceLoader,
6428
- customTools: [
6429
- createBashTool(ctx.workingDirectory, {
6430
- spawnHook: (spawnContext) => ({
6431
- ...spawnContext,
6432
- env: {
6433
- ...spawnContext.env,
6434
- ...spawnEnv
6435
- }
6436
- })
6437
- })
6438
- ],
6439
- sessionManager,
6440
- settingsManager
6441
- });
6442
- this.sessionId = session.sessionId;
6443
- const proc = new PiSdkProcess(session);
6444
- this.process = proc;
6445
- setImmediate(() => {
6446
- if (this.process === proc && !proc.killed) {
6447
- this.sendRpcCommand("prompt", { message: ctx.prompt });
6448
- }
6588
+ createSession(ctx) {
6589
+ this.sessionId = ctx.config.sessionId || null;
6590
+ return new PiSdkRuntimeSession(ctx, (sessionId) => {
6591
+ this.sessionId = sessionId;
6449
6592
  });
6450
- return { process: proc };
6451
6593
  }
6452
- parseLine(line) {
6453
- let event;
6454
- try {
6455
- event = JSON.parse(line);
6456
- } catch {
6457
- return [];
6458
- }
6459
- const events = [];
6460
- if (event.type === "session" && event.id) {
6461
- this.sessionId = event.id;
6462
- if (!this.sessionAnnounced) {
6463
- this.sessionAnnounced = true;
6464
- events.push({ kind: "session_init", sessionId: event.id });
6465
- }
6466
- return events;
6467
- }
6468
- if (!this.sessionAnnounced && this.sessionId) {
6469
- events.push({ kind: "session_init", sessionId: this.sessionId });
6470
- this.sessionAnnounced = true;
6471
- }
6472
- if (event.type === "response") {
6473
- if (event.data?.sessionId && event.data.sessionId !== this.sessionId) {
6474
- this.sessionId = event.data.sessionId;
6475
- }
6476
- if (event.success === false) {
6477
- events.push({ kind: "error", message: piErrorMessage(event.error) });
6478
- }
6479
- return events;
6480
- }
6481
- if (event.type === "message_start" && event.message?.role === "assistant") {
6482
- this.sawTextDelta = false;
6483
- return events;
6484
- }
6485
- const assistantEvent = event.assistantMessageEvent;
6486
- if (event.type === "message_update" && assistantEvent) {
6487
- switch (assistantEvent.type) {
6488
- case "thinking_delta":
6489
- if (typeof assistantEvent.delta === "string" && assistantEvent.delta.length > 0) {
6490
- events.push({ kind: "thinking", text: assistantEvent.delta });
6491
- }
6492
- break;
6493
- case "text_delta":
6494
- if (typeof assistantEvent.delta === "string" && assistantEvent.delta.length > 0) {
6495
- this.sawTextDelta = true;
6496
- events.push({ kind: "text", text: assistantEvent.delta });
6497
- }
6498
- break;
6499
- case "thinking_start":
6500
- case "text_start":
6501
- break;
6502
- case "tool_use":
6503
- case "tool_call":
6504
- case "tool_start":
6505
- events.push({
6506
- kind: "tool_call",
6507
- name: assistantEvent.name || assistantEvent.toolName || "unknown_tool",
6508
- input: assistantEvent.input ?? assistantEvent.parameters ?? {}
6509
- });
6510
- break;
6511
- case "text_end":
6512
- if (!this.sawTextDelta && typeof assistantEvent.content === "string" && assistantEvent.content.length > 0) {
6513
- events.push({ kind: "text", text: assistantEvent.content });
6514
- }
6515
- break;
6516
- }
6517
- return events;
6518
- }
6519
- if (event.type === "agent_end") {
6520
- events.push({ kind: "turn_end", sessionId: this.sessionId || void 0 });
6521
- } else if (event.type === "error") {
6522
- events.push({ kind: "error", message: piErrorMessage(event.error ?? event.message) });
6523
- }
6524
- return events;
6594
+ async spawn(_ctx) {
6595
+ throw new Error("PiDriver uses a native RuntimeSession; child-process spawn is unsupported");
6525
6596
  }
6526
- encodeStdinMessage(text, _sessionId, opts) {
6527
- return JSON.stringify({
6528
- id: this.nextRequestId(),
6529
- type: opts?.mode === "idle" ? "prompt" : "steer",
6530
- message: text
6531
- });
6597
+ parseLine(_line) {
6598
+ return [];
6599
+ }
6600
+ encodeStdinMessage(_text, _sessionId, _opts) {
6601
+ return null;
6532
6602
  }
6533
6603
  buildSystemPrompt(config, _agentId) {
6534
6604
  return buildCliTransportSystemPrompt(config, {
@@ -6541,18 +6611,141 @@ var PiDriver = class {
6541
6611
  messageNotificationStyle: "direct"
6542
6612
  });
6543
6613
  }
6544
- nextRequestId() {
6545
- this.requestId += 1;
6546
- return String(this.requestId);
6614
+ };
6615
+
6616
+ // src/drivers/runtimeSession.ts
6617
+ import { EventEmitter as EventEmitter2 } from "events";
6618
+ function descriptorFromDriver(driver) {
6619
+ const lifecycle = driver.lifecycle.kind === "per_turn" ? "turn_based" : "persistent_stream";
6620
+ const idle = driver.supportsStdinNotification ? "stdin" : "unsupported";
6621
+ const busy = driver.supportsStdinNotification ? "stdin_steer" : "unsupported";
6622
+ return {
6623
+ transport: "child_process",
6624
+ lifecycle,
6625
+ input: {
6626
+ initial: "start",
6627
+ idle,
6628
+ busy
6629
+ },
6630
+ readiness: "spawned",
6631
+ turnBoundary: driver.lifecycle.kind === "per_turn" ? "process_exit" : "parsed_event",
6632
+ startPolicy: driver.lifecycle.kind === "per_turn" ? driver.lifecycle.start : "immediate",
6633
+ inFlightWake: driver.lifecycle.inFlightWake,
6634
+ busyDelivery: driver.busyDeliveryMode,
6635
+ postTurn: driver.terminateProcessOnTurnEnd ? "terminate_process" : driver.endStdinOnTurnEnd ? "close_stdin" : "keep_alive"
6636
+ };
6637
+ }
6638
+ var ChildProcessRuntimeSession = class {
6639
+ constructor(driver, ctx) {
6640
+ this.driver = driver;
6641
+ this.ctx = ctx;
6642
+ this.descriptor = descriptorFromDriver(driver);
6547
6643
  }
6548
- sendRpcCommand(type, params) {
6549
- this.process?.stdin?.write(JSON.stringify({
6550
- id: this.nextRequestId(),
6551
- type,
6552
- ...params
6553
- }) + "\n");
6644
+ descriptor;
6645
+ events = new EventEmitter2();
6646
+ process = null;
6647
+ started = false;
6648
+ stdoutBuffer = "";
6649
+ requestedStopReason;
6650
+ get pid() {
6651
+ return this.process?.pid;
6652
+ }
6653
+ get currentSessionId() {
6654
+ return this.driver.currentSessionId;
6655
+ }
6656
+ get exitCode() {
6657
+ return this.process?.exitCode ?? null;
6658
+ }
6659
+ get signalCode() {
6660
+ return this.process?.signalCode ?? null;
6661
+ }
6662
+ get closed() {
6663
+ return this.process ? this.process.exitCode != null || this.process.signalCode != null : false;
6664
+ }
6665
+ on(event, cb) {
6666
+ this.events.on(event, cb);
6667
+ }
6668
+ async start(input) {
6669
+ if (this.started) {
6670
+ return { ok: false, reason: "runtime_error", error: "runtime session already started" };
6671
+ }
6672
+ this.started = true;
6673
+ const launchCtx = {
6674
+ ...this.ctx,
6675
+ prompt: input.text,
6676
+ config: {
6677
+ ...this.ctx.config,
6678
+ sessionId: input.sessionId ?? this.ctx.config.sessionId
6679
+ }
6680
+ };
6681
+ const { process: process2 } = await this.driver.spawn(launchCtx);
6682
+ this.process = process2;
6683
+ this.attachProcess(process2);
6684
+ return { ok: true, acceptedAs: "prompt" };
6685
+ }
6686
+ send(input) {
6687
+ const proc = this.process;
6688
+ if (!proc || this.closed) return { ok: false, reason: "closed" };
6689
+ const encoded = this.driver.encodeStdinMessage(input.text, input.sessionId ?? null, { mode: input.mode });
6690
+ if (!encoded) return { ok: false, reason: "unsupported" };
6691
+ proc.stdin?.write(encoded + "\n");
6692
+ return { ok: true, acceptedAs: input.mode === "busy" ? "steer" : "prompt" };
6693
+ }
6694
+ async stop(opts) {
6695
+ const proc = this.process;
6696
+ if (!proc || this.closed) return;
6697
+ this.requestedStopReason = opts?.reason;
6698
+ proc.kill(opts?.signal ?? "SIGTERM");
6699
+ if (!opts?.forceAfterMs) return;
6700
+ setTimeout(() => {
6701
+ if (!this.closed) {
6702
+ try {
6703
+ proc.kill("SIGKILL");
6704
+ } catch {
6705
+ }
6706
+ }
6707
+ }, opts.forceAfterMs).unref?.();
6708
+ }
6709
+ attachProcess(process2) {
6710
+ process2.stdout?.on("data", (chunk) => {
6711
+ const chunkText = chunk.toString();
6712
+ this.events.emit("stdout", chunkText);
6713
+ this.stdoutBuffer += chunkText;
6714
+ const lines = this.stdoutBuffer.split("\n");
6715
+ this.stdoutBuffer = lines.pop() || "";
6716
+ for (const line of lines) {
6717
+ if (!line.trim()) continue;
6718
+ for (const event of this.driver.parseLine(line)) {
6719
+ this.events.emit("runtime_event", event);
6720
+ }
6721
+ }
6722
+ });
6723
+ process2.stderr?.on("data", (chunk) => {
6724
+ const text = chunk.toString().trim();
6725
+ if (text) this.events.emit("stderr", text);
6726
+ });
6727
+ process2.on("error", (err) => {
6728
+ this.events.emit("error", err);
6729
+ });
6730
+ process2.on("exit", (code, signal) => {
6731
+ this.events.emit("exit", {
6732
+ code,
6733
+ signal,
6734
+ reason: this.requestedStopReason ? "requested" : "runtime_exit"
6735
+ });
6736
+ });
6737
+ process2.on("close", (code, signal) => {
6738
+ this.events.emit("close", {
6739
+ code,
6740
+ signal,
6741
+ reason: this.requestedStopReason ? "requested" : "runtime_exit"
6742
+ });
6743
+ });
6554
6744
  }
6555
6745
  };
6746
+ function createChildProcessRuntimeSession(driver, ctx) {
6747
+ return new ChildProcessRuntimeSession(driver, ctx);
6748
+ }
6556
6749
 
6557
6750
  // src/drivers/index.ts
6558
6751
  var driverFactories = {
@@ -6953,6 +7146,15 @@ var RUNNER_CREDENTIAL_MINT_MAX_ATTEMPTS = 3;
6953
7146
  function assertNeverApmEffect(effect) {
6954
7147
  throw new Error(`Unhandled APM gated steering effect: ${String(effect)}`);
6955
7148
  }
7149
+ function requireImmediateRuntimeSendResult(result, context) {
7150
+ if (typeof result.then === "function") {
7151
+ throw new Error(`RuntimeSession.send returned async result in synchronous APM path: ${context}`);
7152
+ }
7153
+ return result;
7154
+ }
7155
+ function runtimeSendFailureOutcome(result) {
7156
+ return !result.ok && result.reason === "unsupported" ? "encode_failed" : "send_failed";
7157
+ }
6956
7158
  var RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS = 250;
6957
7159
  var WORKSPACE_TEXT_FILE_MAX_BYTES = 1048576;
6958
7160
  var WORKSPACE_IMAGE_PREVIEW_MAX_BYTES = 5 * 1024 * 1024;
@@ -7900,7 +8102,7 @@ function buildRuntimeStallDiagnostic(ap, staleForMs, staleForMinutes) {
7900
8102
  if (ap.lastActivityDetail) {
7901
8103
  context.push(`after ${ap.lastActivityDetail}`);
7902
8104
  }
7903
- if (ap.driver.busyDeliveryMode === "gated") {
8105
+ if (ap.runtime.descriptor.busyDelivery === "gated") {
7904
8106
  context.push(`phase=${ap.gatedSteering.phase}`);
7905
8107
  }
7906
8108
  if (ap.gatedSteering.outstandingToolUses > 0) {
@@ -7932,10 +8134,10 @@ function buildRuntimeStallDiagnostic(ap, staleForMs, staleForMinutes) {
7932
8134
  sessionIdPresent: Boolean(ap.sessionId),
7933
8135
  inboxCount: ap.inbox.length,
7934
8136
  pendingNotificationCount: ap.notifications.pendingCount,
7935
- processPidPresent: typeof ap.process.pid === "number",
8137
+ processPidPresent: typeof ap.runtime.pid === "number",
7936
8138
  busyDeliveryMode: ap.driver.busyDeliveryMode,
7937
8139
  supportsStdinNotification: ap.driver.supportsStdinNotification,
7938
- gatedPhase: ap.driver.busyDeliveryMode === "gated" ? ap.gatedSteering.phase : void 0,
8140
+ gatedPhase: ap.runtime.descriptor.busyDelivery === "gated" ? ap.gatedSteering.phase : void 0,
7939
8141
  outstandingToolUses: ap.gatedSteering.outstandingToolUses,
7940
8142
  compacting: ap.gatedSteering.compacting,
7941
8143
  recentStderrCount: ap.recentStderr.length,
@@ -8078,8 +8280,10 @@ var RUNTIME_TELEMETRY_RESERVED_ATTR_KEYS = /* @__PURE__ */ new Set([
8078
8280
  "runtimeResultId",
8079
8281
  "daemonVersion",
8080
8282
  "daemon_version",
8283
+ "daemon_version_present",
8081
8284
  "computerVersion",
8082
- "computer_version"
8285
+ "computer_version",
8286
+ "computer_version_present"
8083
8287
  ]);
8084
8288
  function sanitizeRuntimeTelemetryPayloadAttrs(attrs) {
8085
8289
  const sanitized = {};
@@ -8136,9 +8340,11 @@ var AgentProcessManager = class _AgentProcessManager {
8136
8340
  stdinNotificationRetryMs;
8137
8341
  cliTransportTraceDir = null;
8138
8342
  deliveryTraceContexts = /* @__PURE__ */ new WeakMap();
8139
- processExitTraceAttrs = /* @__PURE__ */ new WeakMap();
8343
+ runtimeExitTraceAttrs = /* @__PURE__ */ new WeakMap();
8140
8344
  agentVisibleBoundaries = /* @__PURE__ */ new Map();
8141
8345
  agentVisibleMessageIds = /* @__PURE__ */ new Map();
8346
+ daemonVersion;
8347
+ computerVersion;
8142
8348
  constructor(chatBridgePath, sendToServer, daemonApiKey, opts) {
8143
8349
  this.chatBridgePath = chatBridgePath;
8144
8350
  this.slockCliPath = opts.slockCliPath ?? "";
@@ -8150,6 +8356,8 @@ var AgentProcessManager = class _AgentProcessManager {
8150
8356
  this.driverResolver = opts.driverResolver || getDriver;
8151
8357
  this.defaultAgentEnvVarsProvider = opts.defaultAgentEnvVarsProvider || null;
8152
8358
  this.tracer = opts.tracer ?? noopTracer;
8359
+ this.daemonVersion = opts.daemonVersion?.trim() || null;
8360
+ this.computerVersion = opts.computerVersion?.trim() || null;
8153
8361
  this.stdinNotificationRetryMs = Math.max(
8154
8362
  0,
8155
8363
  Math.floor(opts.stdinNotificationRetryMs ?? STDIN_NOTIFICATION_RETRY_DELAY_MS)
@@ -8390,7 +8598,7 @@ var AgentProcessManager = class _AgentProcessManager {
8390
8598
  });
8391
8599
  span.end(status);
8392
8600
  }
8393
- startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId) {
8601
+ startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false) {
8394
8602
  return {
8395
8603
  agentId,
8396
8604
  launchId,
@@ -8399,6 +8607,7 @@ var AgentProcessManager = class _AgentProcessManager {
8399
8607
  session_id_present: Boolean(config.sessionId),
8400
8608
  launch_id_present: Boolean(launchId),
8401
8609
  wake_message_present: Boolean(wakeMessage),
8610
+ wake_message_transient: Boolean(wakeMessage && wakeMessageTransient),
8402
8611
  unread_channels_count: unreadSummary ? Object.keys(unreadSummary).length : 0,
8403
8612
  resume_prompt_present: Boolean(resumePrompt),
8404
8613
  queue_depth: this.agentStartQueue.length,
@@ -8410,6 +8619,9 @@ var AgentProcessManager = class _AgentProcessManager {
8410
8619
  getDeliveryTraceContext(message) {
8411
8620
  return this.deliveryTraceContexts.get(message) ?? {};
8412
8621
  }
8622
+ isTransientDelivery(message) {
8623
+ return this.getDeliveryTraceContext(message).transient === true;
8624
+ }
8413
8625
  deliveryTraceAttrs(agentId, message, attrs = {}) {
8414
8626
  const context = this.getDeliveryTraceContext(message);
8415
8627
  const deliveryCorrelationId = context.deliveryId ?? message.message_id;
@@ -8421,14 +8633,15 @@ var AgentProcessManager = class _AgentProcessManager {
8421
8633
  sender_type: message.sender_type,
8422
8634
  messageId: message.message_id,
8423
8635
  message_id_present: Boolean(message.message_id),
8636
+ transient_delivery: context.transient === true,
8424
8637
  ...attrs
8425
8638
  };
8426
8639
  }
8427
- async startAgent(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId) {
8428
- this.recordDaemonTrace("daemon.agent.start.requested", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId));
8640
+ async startAgent(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false) {
8641
+ this.recordDaemonTrace("daemon.agent.start.requested", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient));
8429
8642
  if (this.agents.has(agentId)) {
8430
8643
  this.recordDaemonTrace("daemon.agent.start.ignored", {
8431
- ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId),
8644
+ ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
8432
8645
  reason: "already_running"
8433
8646
  });
8434
8647
  logger.info(`[Agent ${agentId}] Start ignored (already running)`);
@@ -8436,7 +8649,7 @@ var AgentProcessManager = class _AgentProcessManager {
8436
8649
  }
8437
8650
  if (this.agentsStarting.has(agentId)) {
8438
8651
  this.recordDaemonTrace("daemon.agent.start.ignored", {
8439
- ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId),
8652
+ ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
8440
8653
  reason: "already_starting"
8441
8654
  });
8442
8655
  logger.info(`[Agent ${agentId}] Start ignored (startup in progress)`);
@@ -8444,7 +8657,7 @@ var AgentProcessManager = class _AgentProcessManager {
8444
8657
  }
8445
8658
  if (this.queuedAgentStarts.has(agentId)) {
8446
8659
  this.recordDaemonTrace("daemon.agent.start.ignored", {
8447
- ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId),
8660
+ ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
8448
8661
  reason: "already_queued"
8449
8662
  });
8450
8663
  logger.info(`[Agent ${agentId}] Start ignored (startup already queued)`);
@@ -8455,6 +8668,7 @@ var AgentProcessManager = class _AgentProcessManager {
8455
8668
  agentId,
8456
8669
  config,
8457
8670
  wakeMessage,
8671
+ wakeMessageTransient,
8458
8672
  unreadSummary,
8459
8673
  resumePrompt,
8460
8674
  launchId,
@@ -8463,7 +8677,7 @@ var AgentProcessManager = class _AgentProcessManager {
8463
8677
  };
8464
8678
  this.agentStartQueue.push(item);
8465
8679
  this.queuedAgentStarts.set(agentId, item);
8466
- this.recordDaemonTrace("daemon.agent.start.queued", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId));
8680
+ this.recordDaemonTrace("daemon.agent.start.queued", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient));
8467
8681
  logger.info(
8468
8682
  `[Agent ${agentId}] Start queued (queue=${this.agentStartQueue.length}, active=${this.activeAgentStartCount}, max=${this.maxConcurrentAgentStarts}, interval=${this.agentStartIntervalMs}ms)`
8469
8683
  );
@@ -8480,7 +8694,7 @@ var AgentProcessManager = class _AgentProcessManager {
8480
8694
  const waitMs = shouldRateLimit ? Math.max(0, this.agentStartIntervalMs - elapsed) : 0;
8481
8695
  if (waitMs > 0) {
8482
8696
  this.recordDaemonTrace("daemon.agent.start.rate_limited", {
8483
- ...this.startQueueTraceAttrs(next.agentId, next.config, next.wakeMessage, next.unreadSummary, next.resumePrompt, next.launchId),
8697
+ ...this.startQueueTraceAttrs(next.agentId, next.config, next.wakeMessage, next.unreadSummary, next.resumePrompt, next.launchId, next.wakeMessageTransient),
8484
8698
  wait_ms: waitMs
8485
8699
  });
8486
8700
  this.agentStartPumpTimer = setTimeout(() => {
@@ -8493,7 +8707,7 @@ var AgentProcessManager = class _AgentProcessManager {
8493
8707
  if (!item) return;
8494
8708
  if (this.queuedAgentStarts.get(item.agentId) !== item) {
8495
8709
  this.recordDaemonTrace("daemon.agent.start.skipped", {
8496
- ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId),
8710
+ ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
8497
8711
  reason: "stale_queue_item"
8498
8712
  });
8499
8713
  this.pumpAgentStartQueue();
@@ -8502,7 +8716,7 @@ var AgentProcessManager = class _AgentProcessManager {
8502
8716
  this.queuedAgentStarts.delete(item.agentId);
8503
8717
  if (this.agents.has(item.agentId) || this.agentsStarting.has(item.agentId)) {
8504
8718
  this.recordDaemonTrace("daemon.agent.start.skipped", {
8505
- ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId),
8719
+ ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
8506
8720
  reason: "already_running_or_starting"
8507
8721
  });
8508
8722
  logger.info(`[Agent ${item.agentId}] Queued start skipped (already running or starting)`);
@@ -8516,14 +8730,15 @@ var AgentProcessManager = class _AgentProcessManager {
8516
8730
  logger.info(
8517
8731
  `[Agent ${item.agentId}] Dequeued start (remaining=${this.agentStartQueue.length}, active=${this.activeAgentStartCount})`
8518
8732
  );
8519
- this.recordDaemonTrace("daemon.agent.start.dequeued", this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId));
8733
+ this.recordDaemonTrace("daemon.agent.start.dequeued", this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient));
8520
8734
  this.startAgentNow(
8521
8735
  item.agentId,
8522
8736
  item.config,
8523
8737
  item.wakeMessage,
8524
8738
  item.unreadSummary,
8525
8739
  item.resumePrompt,
8526
- item.launchId
8740
+ item.launchId,
8741
+ item.wakeMessageTransient ?? false
8527
8742
  ).then(() => {
8528
8743
  this.releaseAgentStartSlot(item.agentId, "spawn attempted");
8529
8744
  item.resolve();
@@ -8558,7 +8773,7 @@ var AgentProcessManager = class _AgentProcessManager {
8558
8773
  this.agentStartPumpTimer = null;
8559
8774
  }
8560
8775
  this.recordDaemonTrace("daemon.agent.start.cancelled", {
8561
- ...this.startQueueTraceAttrs(agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId),
8776
+ ...this.startQueueTraceAttrs(agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
8562
8777
  reason
8563
8778
  }, "cancelled");
8564
8779
  logger.info(`[Agent ${agentId}] Queued start cancelled (${reason})`);
@@ -8569,7 +8784,7 @@ var AgentProcessManager = class _AgentProcessManager {
8569
8784
  for (const item of this.agentStartQueue) {
8570
8785
  if (this.queuedAgentStarts.get(item.agentId) === item) {
8571
8786
  this.recordDaemonTrace("daemon.agent.start.cancelled", {
8572
- ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId),
8787
+ ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
8573
8788
  reason
8574
8789
  }, "cancelled");
8575
8790
  logger.info(`[Agent ${item.agentId}] Queued start cancelled (${reason})`);
@@ -8584,10 +8799,10 @@ var AgentProcessManager = class _AgentProcessManager {
8584
8799
  this.agentStartPumpTimer = null;
8585
8800
  }
8586
8801
  }
8587
- async startAgentNow(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId) {
8802
+ async startAgentNow(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false) {
8588
8803
  if (this.agents.has(agentId)) {
8589
8804
  this.recordDaemonTrace("daemon.agent.spawn.skipped", {
8590
- ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId),
8805
+ ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
8591
8806
  reason: "already_running"
8592
8807
  });
8593
8808
  logger.info(`[Agent ${agentId}] Start ignored (already running)`);
@@ -8595,14 +8810,15 @@ var AgentProcessManager = class _AgentProcessManager {
8595
8810
  }
8596
8811
  if (this.agentsStarting.has(agentId)) {
8597
8812
  this.recordDaemonTrace("daemon.agent.spawn.skipped", {
8598
- ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId),
8813
+ ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
8599
8814
  reason: "already_starting"
8600
8815
  });
8601
8816
  logger.info(`[Agent ${agentId}] Start ignored (startup in progress)`);
8602
8817
  return;
8603
8818
  }
8604
8819
  this.agentsStarting.add(agentId);
8605
- this.recordDaemonTrace("daemon.agent.spawn.started", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId));
8820
+ this.recordDaemonTrace("daemon.agent.spawn.started", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient));
8821
+ let agentProcess = null;
8606
8822
  try {
8607
8823
  const driver = this.driverResolver(config.runtime || "claude");
8608
8824
  const legacyWakeRuntimeProfile = wakeMessage ? runtimeProfileNotificationFromMessage(wakeMessage) : null;
@@ -8665,15 +8881,23 @@ var AgentProcessManager = class _AgentProcessManager {
8665
8881
  prompt += getBusyDeliveryNote(driver);
8666
8882
  promptSource = "resume_prompt";
8667
8883
  } else if (wakeMessage) {
8668
- const runtimeProfileControlPrompt = formatRuntimeProfileControlPrompt([wakeMessage]);
8669
- if (runtimeProfileControlPrompt) {
8884
+ const transientWakeMessage = wakeMessageTransient === true;
8885
+ const runtimeProfileControlPrompt = transientWakeMessage ? null : formatRuntimeProfileControlPrompt([wakeMessage]);
8886
+ if (transientWakeMessage) {
8887
+ prompt = `System notice received:
8888
+
8889
+ ${formatIncomingMessage(wakeMessage, driver)}
8890
+
8891
+ Respond as appropriate. Complete all your work before stopping.
8892
+ ${RESPONSE_TARGET_HINT}`;
8893
+ } else if (runtimeProfileControlPrompt) {
8670
8894
  prompt = runtimeProfileControlPrompt;
8671
8895
  } else {
8672
8896
  wakeMessageDeliveredAsInboxUpdate = true;
8673
8897
  prompt = this.formatInboxUpdateRuntimeInput([wakeMessage, ...startingInboxMessages], driver);
8674
8898
  }
8675
- promptSource = runtimeProfileControlPrompt ? "runtime_profile_control_message" : "wake_inbox_update";
8676
- if (!runtimeProfileControlPrompt && unreadSummary && Object.keys(unreadSummary).length > 0) {
8899
+ promptSource = transientWakeMessage ? "transient_wake_message" : runtimeProfileControlPrompt ? "runtime_profile_control_message" : "wake_inbox_update";
8900
+ if (!transientWakeMessage && !runtimeProfileControlPrompt && unreadSummary && Object.keys(unreadSummary).length > 0) {
8677
8901
  const otherUnread = Object.entries(unreadSummary);
8678
8902
  if (otherUnread.length > 0) {
8679
8903
  prompt += `
@@ -8730,7 +8954,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
8730
8954
  this.sendAgentStatus(agentId, "active", launchId || null);
8731
8955
  this.broadcastActivity(agentId, "online", "Process idle");
8732
8956
  this.recordDaemonTrace("daemon.agent.spawn.deferred", {
8733
- ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId),
8957
+ ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
8734
8958
  pending_messages_count: pendingMessages.length,
8735
8959
  reason: "defer_until_concrete_message"
8736
8960
  });
@@ -8740,7 +8964,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
8740
8964
  }
8741
8965
  return;
8742
8966
  }
8743
- const { process: proc } = await driver.spawn({
8967
+ const runtimeContext = {
8744
8968
  agentId,
8745
8969
  config: effectiveConfig,
8746
8970
  standingPrompt,
@@ -8752,15 +8976,10 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
8752
8976
  launchId: launchId || null,
8753
8977
  agentCredentialProxyInboxCoordinator: this.createAgentProxyInboxCoordinator(agentId),
8754
8978
  cliTransportTraceDir: this.cliTransportTraceDir
8755
- });
8756
- this.recordDaemonTrace("daemon.agent.spawn.created", {
8757
- ...this.startQueueTraceAttrs(agentId, effectiveConfig, wakeMessage, unreadSummary, resumePrompt, launchId),
8758
- detached: false,
8759
- new_session: false,
8760
- process_pid_present: typeof proc.pid === "number"
8761
- });
8762
- const agentProcess = {
8763
- process: proc,
8979
+ };
8980
+ const runtime = driver.createSession?.(runtimeContext) ?? createChildProcessRuntimeSession(driver, runtimeContext);
8981
+ agentProcess = {
8982
+ runtime,
8764
8983
  driver,
8765
8984
  inbox: wakeMessageDeliveredAsInboxUpdate && wakeMessage ? [wakeMessage, ...startingInboxMessages] : startingInboxMessages,
8766
8985
  config: runtimeConfig,
@@ -8807,30 +9026,20 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
8807
9026
  }
8808
9027
  if (wakeMessageDeliveredAsInboxUpdate) {
8809
9028
  this.recordInboxUpdateProjection(agentId, agentProcess, agentProcess.inbox, "spawn_wake_inbox_update", "wake", prompt);
8810
- } else if (wakeMessage) {
9029
+ } else if (wakeMessage && !wakeMessageTransient) {
8811
9030
  this.consumeVisibleMessages(agentId, { messages: [wakeMessage], source: "spawn_wake_message" });
8812
9031
  this.ackInjectedRuntimeProfileMessages(agentId, [wakeMessage], agentProcess.launchId);
8813
9032
  }
8814
- let buffer = "";
8815
- proc.stdout?.on("data", (chunk) => {
8816
- const chunkText = chunk.toString();
9033
+ runtime.on("stdout", (chunkText) => {
8817
9034
  const current = this.agents.get(agentId);
8818
9035
  if (current) {
8819
9036
  current.recentStdout = pushRecentStdout(current.recentStdout, chunkText);
8820
9037
  }
8821
- buffer += chunkText;
8822
- const lines = buffer.split("\n");
8823
- buffer = lines.pop() || "";
8824
- for (const line of lines) {
8825
- if (!line.trim()) continue;
8826
- const events = driver.parseLine(line);
8827
- for (const event of events) {
8828
- this.handleParsedEvent(agentId, event, driver);
8829
- }
8830
- }
8831
9038
  });
8832
- proc.stderr?.on("data", (chunk) => {
8833
- const text = chunk.toString().trim();
9039
+ runtime.on("runtime_event", (event) => {
9040
+ this.handleParsedEvent(agentId, event, driver);
9041
+ });
9042
+ runtime.on("stderr", (text) => {
8834
9043
  if (!text) return;
8835
9044
  const current = this.agents.get(agentId);
8836
9045
  if (driver.id === "codex" && isCodexProviderReconnectLog(text)) {
@@ -8855,7 +9064,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
8855
9064
  }
8856
9065
  logger.error(`[Agent ${agentId} stderr]: ${text}`);
8857
9066
  });
8858
- proc.on("error", (err) => {
9067
+ runtime.on("error", (err) => {
8859
9068
  const current = this.agents.get(agentId);
8860
9069
  if (current) {
8861
9070
  current.spawnError = err.message;
@@ -8870,9 +9079,9 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
8870
9079
  }, "error");
8871
9080
  logger.error(`[Agent ${agentId}] Process error: ${err.message}`);
8872
9081
  });
8873
- proc.on("exit", (code, signal) => {
9082
+ runtime.on("exit", ({ code, signal }) => {
8874
9083
  const current = this.agents.get(agentId);
8875
- if (current && current.process === proc) {
9084
+ if (current && current.runtime === runtime) {
8876
9085
  current.exitCode = code;
8877
9086
  current.exitSignal = signal;
8878
9087
  }
@@ -8887,14 +9096,14 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
8887
9096
  runtime_trace_active: Boolean(current?.runtimeTraceSpan),
8888
9097
  inbox_count: current?.inbox.length ?? 0,
8889
9098
  pending_notification_count: current?.notifications.pendingCount ?? 0,
8890
- ...this.processExitTraceAttrs.get(proc)
9099
+ ...this.runtimeExitTraceAttrs.get(runtime)
8891
9100
  });
8892
9101
  logger.info(`[Agent ${agentId}] Process exited with code ${code}${signal ? ` (signal ${signal})` : ""}`);
8893
9102
  });
8894
- proc.on("close", (code, signal) => {
9103
+ runtime.on("close", ({ code, signal }) => {
8895
9104
  if (this.agents.has(agentId)) {
8896
9105
  const ap = this.agents.get(agentId);
8897
- if (ap.process !== proc) return;
9106
+ if (ap.runtime !== runtime) return;
8898
9107
  ap.notifications.clearTimer();
8899
9108
  if (ap.pendingTrajectory?.timer) {
8900
9109
  clearTimeout(ap.pendingTrajectory.timer);
@@ -9035,14 +9244,54 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9035
9244
  }
9036
9245
  }
9037
9246
  });
9247
+ const startResult = await runtime.start({ text: prompt, sessionId: effectiveConfig.sessionId || null });
9248
+ if (!startResult.ok) {
9249
+ throw new Error(`Runtime session failed to start: ${startResult.reason}${startResult.error ? ` (${startResult.error})` : ""}`);
9250
+ }
9251
+ this.recordDaemonTrace("daemon.agent.spawn.created", {
9252
+ ...this.startQueueTraceAttrs(agentId, effectiveConfig, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
9253
+ detached: false,
9254
+ new_session: false,
9255
+ process_pid_present: typeof runtime.pid === "number"
9256
+ });
9038
9257
  this.sendAgentStatus(agentId, "active", launchId || null);
9039
9258
  this.broadcastActivity(agentId, "working", "Starting\u2026");
9040
9259
  this.startRuntimeStartupTimeout(agentId, agentProcess);
9041
9260
  } catch (err) {
9042
9261
  this.agentsStarting.delete(agentId);
9262
+ this.cleanupFailedRuntimeStart(agentId, agentProcess, err);
9043
9263
  throw err;
9044
9264
  }
9045
9265
  }
9266
+ cleanupFailedRuntimeStart(agentId, ap, err) {
9267
+ if (!ap) return;
9268
+ if (this.agents.get(agentId) !== ap) return;
9269
+ ap.notifications.clearTimer();
9270
+ if (ap.pendingTrajectory?.timer) {
9271
+ clearTimeout(ap.pendingTrajectory.timer);
9272
+ ap.pendingTrajectory.timer = null;
9273
+ }
9274
+ if (ap.activityHeartbeat) {
9275
+ clearInterval(ap.activityHeartbeat);
9276
+ ap.activityHeartbeat = null;
9277
+ }
9278
+ if (ap.compactionWatchdog) {
9279
+ clearTimeout(ap.compactionWatchdog);
9280
+ ap.compactionWatchdog = null;
9281
+ }
9282
+ this.clearRuntimeStartupTimeout(ap);
9283
+ this.clearStalledRecoverySigtermWatchdog(ap);
9284
+ this.endRuntimeTrace(ap, "error", {
9285
+ outcome: "runtime-start-failed",
9286
+ failure_detail: err instanceof Error ? err.message : String(err),
9287
+ ...runtimeTraceCounterAttrs(ap),
9288
+ ...this.finalizeRuntimeProfileTurnControl(agentId, ap, "runtime_error")
9289
+ });
9290
+ cleanupAgentCredentialProxy(agentId, ap.launchId);
9291
+ this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
9292
+ this.agents.delete(agentId);
9293
+ this.idleAgentConfigs.delete(agentId);
9294
+ }
9046
9295
  async buildSpawnConfig(agentId, config) {
9047
9296
  const baseConfig = config.serverUrl === this.serverUrl ? config : { ...config, serverUrl: this.serverUrl };
9048
9297
  const runnerConfig = await this.ensureManagedRunnerCredential(agentId, baseConfig);
@@ -9211,7 +9460,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9211
9460
  ap.inbox.push(message);
9212
9461
  if (ap.driver.supportsStdinNotification && ap.sessionId) {
9213
9462
  ap.notifications.add();
9214
- if (ap.driver.busyDeliveryMode === "gated") {
9463
+ if (ap.runtime.descriptor.busyDelivery === "gated") {
9215
9464
  this.recordGatedSteeringEvent(agentId, ap, "buffer", {
9216
9465
  reason: "runtime_profile",
9217
9466
  kind,
@@ -9278,12 +9527,16 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9278
9527
  cleanupAgentCredentialProxy(agentId, ap.launchId);
9279
9528
  this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
9280
9529
  this.agents.delete(agentId);
9281
- this.processExitTraceAttrs.set(ap.process, {
9530
+ this.runtimeExitTraceAttrs.set(ap.runtime, {
9282
9531
  stop_source: silent ? "daemon_internal" : "explicit_request",
9283
9532
  stop_wait_requested: wait,
9284
9533
  stop_silent: silent
9285
9534
  });
9286
- ap.process.kill("SIGTERM");
9535
+ await ap.runtime.stop({
9536
+ signal: "SIGTERM",
9537
+ forceAfterMs: wait ? 5e3 : void 0,
9538
+ reason: silent ? "daemon_internal" : "explicit_request"
9539
+ });
9287
9540
  if (!silent) {
9288
9541
  this.sendRuntimeProfileReportFor(agentId, ap.config, ap.sessionId, ap.launchId);
9289
9542
  this.sendAgentStatus(agentId, "inactive", ap.launchId);
@@ -9292,22 +9545,18 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9292
9545
  }
9293
9546
  if (wait) {
9294
9547
  await new Promise((resolve) => {
9295
- const forceKillTimer = setTimeout(() => {
9548
+ const timeoutTimer = setTimeout(() => {
9296
9549
  if (!silent) {
9297
9550
  logger.warn(`[Agent ${agentId}] Stop timed out; force killing`);
9298
9551
  }
9299
- try {
9300
- ap.process.kill("SIGKILL");
9301
- } catch {
9302
- }
9303
9552
  resolve();
9304
9553
  }, 5e3);
9305
- ap.process.on("exit", () => {
9306
- clearTimeout(forceKillTimer);
9554
+ ap.runtime.on("exit", () => {
9555
+ clearTimeout(timeoutTimer);
9307
9556
  resolve();
9308
9557
  });
9309
- if (ap.process.exitCode !== null || ap.process.signalCode !== null) {
9310
- clearTimeout(forceKillTimer);
9558
+ if (ap.runtime.closed) {
9559
+ clearTimeout(timeoutTimer);
9311
9560
  resolve();
9312
9561
  }
9313
9562
  });
@@ -9317,9 +9566,24 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9317
9566
  if (traceContext.deliveryId) {
9318
9567
  this.deliveryTraceContexts.set(message, traceContext);
9319
9568
  }
9569
+ if (traceContext.transient) {
9570
+ this.deliveryTraceContexts.set(message, traceContext);
9571
+ }
9572
+ const transientDelivery = this.isTransientDelivery(message);
9320
9573
  const ap = this.agents.get(agentId);
9321
9574
  if (!ap) {
9322
9575
  if (this.agentsStarting.has(agentId) || this.queuedAgentStarts.has(agentId)) {
9576
+ if (transientDelivery) {
9577
+ const queuedStart2 = this.queuedAgentStarts.get(agentId);
9578
+ this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
9579
+ outcome: "transient_dropped_during_start",
9580
+ accepted: true,
9581
+ process_present: false,
9582
+ startup_pending: true,
9583
+ launchId: queuedStart2?.launchId
9584
+ }));
9585
+ return true;
9586
+ }
9323
9587
  const queuedStart = this.queuedAgentStarts.get(agentId);
9324
9588
  const pending = this.startingInboxes.get(agentId) || [];
9325
9589
  pending.push(message);
@@ -9337,7 +9601,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9337
9601
  const cached = this.idleAgentConfigs.get(agentId);
9338
9602
  if (cached) {
9339
9603
  const driver = this.driverResolver(cached.config.runtime || "claude");
9340
- if (this.shouldDeferWakeMessage(agentId, driver, message)) {
9604
+ if (!transientDelivery && this.shouldDeferWakeMessage(agentId, driver, message)) {
9341
9605
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
9342
9606
  outcome: "deferred_wake_message",
9343
9607
  accepted: true,
@@ -9360,7 +9624,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9360
9624
  session_id_present: Boolean(cached.sessionId),
9361
9625
  launchId: cached.launchId || void 0
9362
9626
  }));
9363
- return this.startAgent(agentId, cached.config, message, void 0, void 0, cached.launchId || void 0).then(() => true, (err) => {
9627
+ return this.startAgent(agentId, cached.config, message, void 0, void 0, cached.launchId || void 0, transientDelivery).then(() => true, (err) => {
9364
9628
  logger.error(`[Agent ${agentId}] Failed to auto-restart`, err);
9365
9629
  if (this.reportRunnerCredentialMintFailure(agentId, err, cached.launchId, "idle_auto_restart")) {
9366
9630
  return false;
@@ -9370,6 +9634,15 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9370
9634
  });
9371
9635
  }
9372
9636
  logger.warn(`[Agent ${agentId}] Delivery received but no running process or cached idle config exists`);
9637
+ if (transientDelivery) {
9638
+ this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
9639
+ outcome: "transient_dropped_no_process",
9640
+ accepted: true,
9641
+ process_present: false,
9642
+ cached_idle_config_present: false
9643
+ }));
9644
+ return true;
9645
+ }
9373
9646
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
9374
9647
  outcome: "rejected_no_process",
9375
9648
  accepted: false,
@@ -9380,7 +9653,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9380
9653
  this.broadcastActivity(agentId, "offline", "Process unavailable; restart required");
9381
9654
  return false;
9382
9655
  }
9383
- if (this.shouldDeferWakeMessage(agentId, ap.driver, message)) {
9656
+ if (!transientDelivery && this.shouldDeferWakeMessage(agentId, ap.driver, message)) {
9384
9657
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
9385
9658
  outcome: "deferred_wake_message",
9386
9659
  accepted: true,
@@ -9395,6 +9668,19 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9395
9668
  }
9396
9669
  const stickyTerminalFailure = classifyStickyTerminalFailure(ap);
9397
9670
  if (stickyTerminalFailure) {
9671
+ if (transientDelivery) {
9672
+ this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
9673
+ outcome: "transient_dropped_terminal_runtime_error",
9674
+ accepted: true,
9675
+ process_present: true,
9676
+ runtime: ap.config.runtime,
9677
+ session_id_present: Boolean(ap.sessionId),
9678
+ launchId: ap.launchId || void 0,
9679
+ is_idle: ap.isIdle,
9680
+ inbox_count: ap.inbox.length
9681
+ }));
9682
+ return true;
9683
+ }
9398
9684
  ap.inbox.push(message);
9399
9685
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
9400
9686
  outcome: "queued_terminal_runtime_error",
@@ -9411,6 +9697,30 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9411
9697
  return true;
9412
9698
  }
9413
9699
  if (ap.isIdle && ap.driver.supportsStdinNotification && ap.sessionId) {
9700
+ if (transientDelivery) {
9701
+ this.commitApmIdleState(agentId, ap, false);
9702
+ this.startRuntimeTrace(agentId, ap, "stdin-idle-delivery", [message]);
9703
+ this.broadcastActivity(agentId, "working", "Message received");
9704
+ const stdinAccepted2 = this.deliverMessagesViaStdin(
9705
+ agentId,
9706
+ ap,
9707
+ [message],
9708
+ "idle",
9709
+ { transient: true }
9710
+ );
9711
+ this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
9712
+ outcome: "stdin_idle_transient_delivery",
9713
+ accepted: true,
9714
+ process_present: true,
9715
+ runtime: ap.config.runtime,
9716
+ session_id_present: true,
9717
+ launchId: ap.launchId || void 0,
9718
+ stdin_delivery_accepted: stdinAccepted2,
9719
+ delivered_messages_count: 1,
9720
+ inbox_count: ap.inbox.length
9721
+ }));
9722
+ return true;
9723
+ }
9414
9724
  ap.inbox.push(message);
9415
9725
  const nextMessages = [...ap.inbox];
9416
9726
  this.commitApmIdleState(agentId, ap, false);
@@ -9435,6 +9745,19 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9435
9745
  }));
9436
9746
  return true;
9437
9747
  }
9748
+ if (transientDelivery) {
9749
+ this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
9750
+ outcome: "transient_dropped_busy",
9751
+ accepted: true,
9752
+ process_present: true,
9753
+ runtime: ap.config.runtime,
9754
+ session_id_present: Boolean(ap.sessionId),
9755
+ launchId: ap.launchId || void 0,
9756
+ is_idle: ap.isIdle,
9757
+ inbox_count: ap.inbox.length
9758
+ }));
9759
+ return true;
9760
+ }
9438
9761
  ap.inbox.push(message);
9439
9762
  if (this.recoverStaleProcessForQueuedMessageIfNeeded(agentId, ap)) {
9440
9763
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
@@ -9475,7 +9798,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9475
9798
  if (ap.gatedSteering.compacting) {
9476
9799
  ap.notifications.add();
9477
9800
  ap.notifications.clearTimer();
9478
- if (ap.driver.busyDeliveryMode === "gated") {
9801
+ if (ap.runtime.descriptor.busyDelivery === "gated") {
9479
9802
  this.recordGatedSteeringEvent(agentId, ap, "buffer", {
9480
9803
  reason: "compaction_boundary",
9481
9804
  pendingMessages: ap.inbox.length
@@ -9500,7 +9823,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9500
9823
  }));
9501
9824
  return true;
9502
9825
  }
9503
- if (ap.driver.busyDeliveryMode === "gated") {
9826
+ if (ap.runtime.descriptor.busyDelivery === "gated") {
9504
9827
  ap.notifications.add();
9505
9828
  if (!ap.notifications.hasTimer) {
9506
9829
  this.scheduleStdinNotification(agentId, ap, STDIN_NOTIFICATION_INITIAL_DELAY_MS);
@@ -9683,7 +10006,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9683
10006
  traceparent: formatTraceparent(span.context)
9684
10007
  };
9685
10008
  const ap = this.agents.get(agentId);
9686
- if (ap && !(ap.sessionId && ap.driver.supportsStdinNotification && ap.isIdle) && !(ap.sessionId && ap.driver.busyDeliveryMode === "direct")) {
10009
+ if (ap && !(ap.sessionId && ap.driver.supportsStdinNotification && ap.isIdle) && !(ap.sessionId && ap.runtime.descriptor.busyDelivery === "direct")) {
9687
10010
  this.enqueueRuntimeProfileNotification(agentId, ap, message, kind, key);
9688
10011
  span.end("ok", {
9689
10012
  attrs: {
@@ -9713,7 +10036,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
9713
10036
  });
9714
10037
  return written;
9715
10038
  }
9716
- if (ap?.sessionId && ap.driver.busyDeliveryMode === "direct") {
10039
+ if (ap?.sessionId && ap.runtime.descriptor.busyDelivery === "direct") {
9717
10040
  const written = this.deliverMessagesViaStdin(agentId, ap, [message], "busy");
9718
10041
  span.end(written ? "ok" : "error", {
9719
10042
  attrs: {
@@ -10136,23 +10459,23 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
10136
10459
  clearTimeout(ap.stalledRecoverySigtermTimer);
10137
10460
  ap.stalledRecoverySigtermTimer = null;
10138
10461
  }
10139
- mergeProcessExitTraceAttrs(proc, attrs) {
10140
- this.processExitTraceAttrs.set(proc, {
10141
- ...this.processExitTraceAttrs.get(proc) ?? {},
10462
+ mergeRuntimeExitTraceAttrs(runtime, attrs) {
10463
+ this.runtimeExitTraceAttrs.set(runtime, {
10464
+ ...this.runtimeExitTraceAttrs.get(runtime) ?? {},
10142
10465
  ...attrs
10143
10466
  });
10144
10467
  }
10145
10468
  startStalledRecoverySigtermWatchdog(agentId, ap, runtimeLabel, queuedMessagesAtSignal, staleForMs) {
10146
10469
  this.clearStalledRecoverySigtermWatchdog(ap);
10147
10470
  const timeoutMs = stalledRecoverySigtermTimeoutMs();
10148
- const processAtSignal = ap.process;
10471
+ const runtimeAtSignal = ap.runtime;
10149
10472
  ap.stalledRecoverySigtermTimer = setTimeout(() => {
10150
10473
  ap.stalledRecoverySigtermTimer = null;
10151
10474
  const current = this.agents.get(agentId);
10152
- if (!current || current !== ap || current.process !== processAtSignal || current.expectedTerminationReason !== "stalled_recovery") {
10475
+ if (!current || current !== ap || current.runtime !== runtimeAtSignal || current.expectedTerminationReason !== "stalled_recovery") {
10153
10476
  return;
10154
10477
  }
10155
- this.mergeProcessExitTraceAttrs(processAtSignal, {
10478
+ this.mergeRuntimeExitTraceAttrs(runtimeAtSignal, {
10156
10479
  stalled_recovery_sigterm_timeout: true,
10157
10480
  stalled_recovery_sigterm_timeout_ms: timeoutMs
10158
10481
  });
@@ -10166,7 +10489,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
10166
10489
  queued_messages_at_signal: queuedMessagesAtSignal,
10167
10490
  stale_age_ms_at_signal: staleForMs,
10168
10491
  timeout_ms: timeoutMs,
10169
- process_pid_present: typeof processAtSignal.pid === "number",
10492
+ process_pid_present: typeof runtimeAtSignal.pid === "number",
10170
10493
  session_id_present: Boolean(current.sessionId),
10171
10494
  supports_stdin_notification: current.driver.supportsStdinNotification,
10172
10495
  busy_delivery_mode: current.driver.busyDeliveryMode
@@ -10175,7 +10498,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
10175
10498
  `[Agent ${agentId}] Stalled ${runtimeLabel} runtime did not exit after SIGTERM within ${timeoutMs}ms; force killing`
10176
10499
  );
10177
10500
  try {
10178
- processAtSignal.kill("SIGKILL");
10501
+ void runtimeAtSignal.stop({ signal: "SIGKILL", reason: "stalled_recovery_sigterm_timeout" });
10179
10502
  } catch (err) {
10180
10503
  const reason = err instanceof Error ? err.message : String(err);
10181
10504
  this.recordDaemonTrace("daemon.agent.stalled_recovery.sigkill_failed", {
@@ -10361,7 +10684,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
10361
10684
  ap.runtimeProgress.noteRuntimeEvent(eventKind);
10362
10685
  }
10363
10686
  recordGatedSteeringEvent(agentId, ap, event, attrs = {}) {
10364
- if (ap.driver.busyDeliveryMode !== "gated") return;
10687
+ if (ap.runtime.descriptor.busyDelivery !== "gated") return;
10365
10688
  const reduction = reduceApmGatedRecentEvent(ap.gatedSteering, { event });
10366
10689
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState);
10367
10690
  this.recordRuntimeTraceEvent(agentId, ap, `runtime.gated_steering.${event}`, {
@@ -10396,7 +10719,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
10396
10719
  }
10397
10720
  notifyGatedSteeringBoundary(agentId, ap, reason) {
10398
10721
  const readiness = reduceApmGatedFlushReadiness(ap.gatedSteering, {
10399
- isGated: ap.driver.busyDeliveryMode === "gated",
10722
+ isGated: ap.runtime.descriptor.busyDelivery === "gated",
10400
10723
  hasSession: Boolean(ap.sessionId),
10401
10724
  inboxLength: ap.inbox.length,
10402
10725
  reason
@@ -10446,7 +10769,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
10446
10769
  });
10447
10770
  return true;
10448
10771
  }
10449
- if (ap.driver.busyDeliveryMode === "gated") {
10772
+ if (ap.runtime.descriptor.busyDelivery === "gated") {
10450
10773
  const flushReduction = reduceApmGatedFlush(ap.gatedSteering, { reason: effect.reason });
10451
10774
  this.commitGatedSteeringDecisionState(agentId, ap, flushReduction.nextState);
10452
10775
  this.recordGatedSteeringEvent(agentId, ap, "flush", {
@@ -10548,12 +10871,12 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
10548
10871
  this.sendAgentStatus(agentId, "inactive", ap.launchId);
10549
10872
  this.idleAgentConfigs.delete(agentId);
10550
10873
  try {
10551
- this.processExitTraceAttrs.set(ap.process, {
10874
+ this.runtimeExitTraceAttrs.set(ap.runtime, {
10552
10875
  stop_source: "startup_timeout",
10553
10876
  expectedTerminationReason: "startup_timeout",
10554
10877
  timeout_ms: timeoutMs
10555
10878
  });
10556
- ap.process.kill("SIGTERM");
10879
+ void ap.runtime.stop({ signal: "SIGTERM", reason: "startup_timeout" });
10557
10880
  } catch (err) {
10558
10881
  const reason = err instanceof Error ? err.message : String(err);
10559
10882
  logger.warn(`[Agent ${agentId}] Failed to terminate startup-timed-out ${ap.driver.id} process: ${reason}`);
@@ -10639,13 +10962,13 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
10639
10962
  );
10640
10963
  this.broadcastActivity(agentId, "working", `Restarting stalled ${runtimeLabel} runtime for queued message`);
10641
10964
  try {
10642
- this.processExitTraceAttrs.set(ap.process, {
10965
+ this.runtimeExitTraceAttrs.set(ap.runtime, {
10643
10966
  stop_source: "stalled_recovery",
10644
10967
  expectedTerminationReason: "stalled_recovery",
10645
10968
  queued_messages_count: ap.inbox.length
10646
10969
  });
10647
10970
  this.startStalledRecoverySigtermWatchdog(agentId, ap, runtimeLabel, ap.inbox.length, staleForMs);
10648
- ap.process.kill("SIGTERM");
10971
+ void ap.runtime.stop({ signal: "SIGTERM", reason: "stalled_recovery" });
10649
10972
  } catch (err) {
10650
10973
  this.clearStalledRecoverySigtermWatchdog(ap);
10651
10974
  const reason = err instanceof Error ? err.message : String(err);
@@ -10821,11 +11144,11 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
10821
11144
  if (ap.driver.terminateProcessOnTurnEnd) {
10822
11145
  logger.info(`[Agent ${agentId}] Turn completed; terminating ${ap.driver.id} process`);
10823
11146
  try {
10824
- this.processExitTraceAttrs.set(ap.process, {
11147
+ this.runtimeExitTraceAttrs.set(ap.runtime, {
10825
11148
  stop_source: "turn_end",
10826
11149
  expectedTerminationReason: "turn_end"
10827
11150
  });
10828
- ap.process.kill("SIGTERM");
11151
+ void ap.runtime.stop({ signal: "SIGTERM", reason: "turn_end" });
10829
11152
  } catch (err) {
10830
11153
  const reason = err instanceof Error ? err.message : String(err);
10831
11154
  logger.warn(`[Agent ${agentId}] Failed to terminate ${ap.driver.id} after turn_end: ${reason}`);
@@ -10847,7 +11170,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
10847
11170
  if (runtimeErrorDiagnostics.spanAttrs.runtime_error_action_required === true) {
10848
11171
  visibleErrorMessage = formatRuntimeLoginRequiredMessage(ap.driver.id);
10849
11172
  }
10850
- const shouldDisableToolBoundaryFlush = ap.driver.busyDeliveryMode === "gated" && this.isThinkingBlockMutationError(event.message);
11173
+ const shouldDisableToolBoundaryFlush = ap.runtime.descriptor.busyDelivery === "gated" && this.isThinkingBlockMutationError(event.message);
10851
11174
  const terminalFailure = classifyTerminalFailure(ap);
10852
11175
  const reduction = reduceApmGatedError(ap.gatedSteering, {
10853
11176
  disableToolBoundaryFlush: shouldDisableToolBoundaryFlush,
@@ -10878,11 +11201,11 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
10878
11201
  if (terminalFailure.actionRequired) {
10879
11202
  logger.warn(`[Agent ${agentId}] ${ap.driver.id} auth requires user action; terminating runtime process`);
10880
11203
  try {
10881
- this.processExitTraceAttrs.set(ap.process, {
11204
+ this.runtimeExitTraceAttrs.set(ap.runtime, {
10882
11205
  stop_source: "runtime_auth_error",
10883
11206
  runtime_error_class: "AuthError"
10884
11207
  });
10885
- ap.process.kill("SIGTERM");
11208
+ void ap.runtime.stop({ signal: "SIGTERM", reason: "runtime_auth_error" });
10886
11209
  } catch (err) {
10887
11210
  const reason = err instanceof Error ? err.message : String(err);
10888
11211
  logger.warn(`[Agent ${agentId}] Failed to terminate ${ap.driver.id} after auth error: ${reason}`);
@@ -10907,8 +11230,10 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
10907
11230
  recordRuntimeTelemetry(agentId, ap, event) {
10908
11231
  const sessionId = ap.driver.currentSessionId ?? event.sessionId;
10909
11232
  const payloadAttrs = sanitizeRuntimeTelemetryPayloadAttrs(event.attrs);
11233
+ const versionAttrs = this.runtimeTelemetryVersionAttrs();
10910
11234
  const telemetryAttrs = {
10911
11235
  ...payloadAttrs,
11236
+ ...versionAttrs,
10912
11237
  ...event.source ? { source: event.source } : {},
10913
11238
  ...event.usageKind ? { usageKind: event.usageKind } : {},
10914
11239
  ...sessionId ? { sessionId } : {},
@@ -10926,6 +11251,24 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
10926
11251
  ap.runtimeTraceSpan?.addEvent(`runtime.telemetry.${event.name}`, telemetryAttrs);
10927
11252
  this.recordDaemonTrace(`daemon.runtime.telemetry.${event.name}`, attrs);
10928
11253
  }
11254
+ runtimeTelemetryVersionAttrs() {
11255
+ return {
11256
+ ...this.daemonVersion ? {
11257
+ daemonVersion: this.daemonVersion,
11258
+ daemon_version: this.daemonVersion,
11259
+ daemon_version_present: true
11260
+ } : {
11261
+ daemon_version_present: false
11262
+ },
11263
+ ...this.computerVersion ? {
11264
+ computerVersion: this.computerVersion,
11265
+ computer_version: this.computerVersion,
11266
+ computer_version_present: true
11267
+ } : {
11268
+ computer_version_present: false
11269
+ }
11270
+ };
11271
+ }
10929
11272
  sendAgentStatus(agentId, status, launchId) {
10930
11273
  this.sendToServer({ type: "agent:status", agentId, status, launchId: launchId || void 0 });
10931
11274
  }
@@ -11009,9 +11352,11 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
11009
11352
  ...projectionAttrs
11010
11353
  });
11011
11354
  logger.info(`[Agent ${agentId}] Sending stdin inbox update: ${inboxRows.length} changed target(s), ${inboxCount} pending message(s)`);
11012
- const encoded = ap.driver.encodeStdinMessage(notification, ap.sessionId, { mode: "busy" });
11013
- if (encoded) {
11014
- ap.process.stdin?.write(encoded + "\n");
11355
+ const sendResult = requireImmediateRuntimeSendResult(
11356
+ ap.runtime.send({ mode: "busy", text: notification, sessionId: ap.sessionId }),
11357
+ "busy inbox notification"
11358
+ );
11359
+ if (sendResult.ok) {
11015
11360
  this.recordDaemonTrace("daemon.agent.inbox_update.pushed", {
11016
11361
  agentId,
11017
11362
  runtime: ap.config.runtime,
@@ -11036,14 +11381,17 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
11036
11381
  return true;
11037
11382
  } else {
11038
11383
  ap.notifications.add(count);
11039
- const retryScheduled = ap.driver.busyDeliveryMode === "direct" ? this.scheduleStdinNotification(agentId, ap, this.stdinNotificationRetryMs) : false;
11384
+ const retryScheduled = ap.runtime.descriptor.busyDelivery === "direct" ? this.scheduleStdinNotification(agentId, ap, this.stdinNotificationRetryMs) : false;
11385
+ const outcome = runtimeSendFailureOutcome(sendResult);
11040
11386
  this.recordDaemonTrace("daemon.agent.stdin_notification", {
11041
11387
  agentId,
11042
11388
  runtime: ap.config.runtime,
11043
11389
  model: ap.config.model,
11044
11390
  launchId: ap.launchId || void 0,
11045
- outcome: "encode_failed",
11391
+ outcome,
11046
11392
  mode: "busy",
11393
+ failure_reason: sendResult.reason,
11394
+ failure_error: sendResult.error,
11047
11395
  pending_notification_count: count,
11048
11396
  retry_scheduled: retryScheduled,
11049
11397
  notification_timer_present: ap.notifications.hasTimer,
@@ -11094,8 +11442,11 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
11094
11442
  nativeStandingPrompt: Boolean(ap.driver.supportsNativeStandingPrompt)
11095
11443
  });
11096
11444
  this.recordRuntimeTraceEvent(agentId, ap, "runtime.input.prepared", inputTraceAttrs);
11097
- const encoded = ap.driver.encodeStdinMessage(prompt, ap.sessionId, { mode });
11098
- if (!encoded) {
11445
+ const sendResult = requireImmediateRuntimeSendResult(
11446
+ ap.runtime.send({ mode, text: prompt, sessionId: ap.sessionId }),
11447
+ `${mode} inbox update`
11448
+ );
11449
+ if (!sendResult.ok) {
11099
11450
  if (mode === "idle") {
11100
11451
  this.commitApmIdleState(agentId, ap, true);
11101
11452
  }
@@ -11117,7 +11468,9 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
11117
11468
  ...this.messagesTraceAttrs(messages),
11118
11469
  ...inputTraceAttrs,
11119
11470
  ...projectionAttrs,
11120
- outcome: "encode_failed",
11471
+ outcome: runtimeSendFailureOutcome(sendResult),
11472
+ failure_reason: sendResult.reason,
11473
+ failure_error: sendResult.error,
11121
11474
  requeued_messages_count: 0,
11122
11475
  cursors_advanced: "none"
11123
11476
  }, "error");
@@ -11130,7 +11483,6 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
11130
11483
  if (this.containsOrdinaryInboxMessage(messages)) {
11131
11484
  ap.lastRuntimeError = null;
11132
11485
  }
11133
- ap.process.stdin?.write(encoded + "\n");
11134
11486
  this.recordDaemonTrace("daemon.agent.stdin_delivery", {
11135
11487
  agentId,
11136
11488
  launchId: ap.launchId || void 0,
@@ -11153,7 +11505,7 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
11153
11505
  return true;
11154
11506
  }
11155
11507
  /** Deliver a message to an agent via stdin, formatting it the same way as the MCP bridge */
11156
- deliverMessagesViaStdin(agentId, ap, messages, mode) {
11508
+ deliverMessagesViaStdin(agentId, ap, messages, mode, options = {}) {
11157
11509
  if (messages.length === 0) return true;
11158
11510
  const runtimeProfileMigrationMessages = messages.filter((message) => runtimeProfileNotificationFromMessage(message)?.kind === "migration");
11159
11511
  if (runtimeProfileMigrationMessages.length > 0) {
@@ -11191,8 +11543,10 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
11191
11543
  pending_notification_count: ap.notifications.pendingCount,
11192
11544
  busy_delivery_mode: ap.driver.busyDeliveryMode,
11193
11545
  supports_stdin_notification: ap.driver.supportsStdinNotification,
11546
+ transient_delivery: options.transient === true,
11194
11547
  ...this.messagesTraceAttrs(messages)
11195
11548
  };
11549
+ const traceSource = options.transient ? `stdin_${mode}_transient_delivery` : `stdin_${mode}_delivery`;
11196
11550
  const prompt = formatRuntimeProfileControlPrompt(messages) ?? (messages.length === 1 ? `New message received:
11197
11551
 
11198
11552
  ${formatIncomingMessage(messages[0], ap.driver)}
@@ -11205,16 +11559,21 @@ ${messages.map((message) => formatIncomingMessage(message, ap.driver)).join("\n"
11205
11559
  Respond as appropriate. Complete all your work before stopping.
11206
11560
  ${RESPONSE_TARGET_HINT}`);
11207
11561
  const inputTraceAttrs = buildRuntimeInputTraceAttrs({
11208
- source: `stdin_${mode}_delivery`,
11562
+ source: traceSource,
11209
11563
  prompt,
11210
11564
  messages,
11211
11565
  sessionIdPresent: Boolean(ap.sessionId),
11212
11566
  nativeStandingPrompt: Boolean(ap.driver.supportsNativeStandingPrompt)
11213
11567
  });
11214
11568
  this.recordRuntimeTraceEvent(agentId, ap, "runtime.input.prepared", inputTraceAttrs);
11215
- const encoded = ap.driver.encodeStdinMessage(prompt, ap.sessionId, { mode });
11216
- if (!encoded) {
11217
- ap.inbox.unshift(...messages);
11569
+ const sendResult = requireImmediateRuntimeSendResult(
11570
+ ap.runtime.send({ mode, text: prompt, sessionId: ap.sessionId }),
11571
+ `${mode} message delivery`
11572
+ );
11573
+ if (!sendResult.ok) {
11574
+ if (!options.transient) {
11575
+ ap.inbox.unshift(...messages);
11576
+ }
11218
11577
  if (mode === "idle") {
11219
11578
  this.commitApmIdleState(agentId, ap, true);
11220
11579
  }
@@ -11224,12 +11583,16 @@ ${RESPONSE_TARGET_HINT}`);
11224
11583
  this.recordDaemonTrace("daemon.agent.stdin_delivery", {
11225
11584
  ...traceAttrs,
11226
11585
  ...inputTraceAttrs,
11227
- outcome: "encode_failed",
11228
- requeued_messages_count: messages.length
11586
+ outcome: runtimeSendFailureOutcome(sendResult),
11587
+ failure_reason: sendResult.reason,
11588
+ failure_error: sendResult.error,
11589
+ requeued_messages_count: options.transient ? 0 : messages.length
11229
11590
  }, "error");
11230
11591
  return false;
11231
11592
  }
11232
- this.consumeVisibleMessages(agentId, { messages, source: `stdin_${mode}_delivery` });
11593
+ if (!options.transient) {
11594
+ this.consumeVisibleMessages(agentId, { messages, source: traceSource });
11595
+ }
11233
11596
  const senders = [...new Set(messages.map((message) => `@${message.sender_name}`))].join(", ");
11234
11597
  logger.info(
11235
11598
  `[Agent ${agentId}] Delivering ${mode} ${messages.length === 1 ? "message" : `${messages.length} messages`} via stdin from ${senders}`
@@ -11237,7 +11600,6 @@ ${RESPONSE_TARGET_HINT}`);
11237
11600
  if (this.containsOrdinaryInboxMessage(messages)) {
11238
11601
  ap.lastRuntimeError = null;
11239
11602
  }
11240
- ap.process.stdin?.write(encoded + "\n");
11241
11603
  this.ackInjectedRuntimeProfileMessages(agentId, messages, ap.launchId);
11242
11604
  this.recordDaemonTrace("daemon.agent.stdin_delivery", {
11243
11605
  ...traceAttrs,
@@ -12444,7 +12806,9 @@ var DaemonCore = class {
12444
12806
  serverUrl: options.serverUrl,
12445
12807
  defaultAgentEnvVarsProvider: options.defaultAgentEnvVarsProvider,
12446
12808
  slockCliPath: this.slockCliPath,
12447
- tracer: this.tracer
12809
+ tracer: this.tracer,
12810
+ daemonVersion: this.daemonVersion,
12811
+ computerVersion: this.computerVersion
12448
12812
  };
12449
12813
  this.agentManager = options.agentManagerFactory ? options.agentManagerFactory(this.chatBridgePath, (msg) => connection.send(msg), options.apiKey, agentManagerOptions) : new AgentProcessManager(this.chatBridgePath, (msg) => connection.send(msg), options.apiKey, agentManagerOptions);
12450
12814
  const connectionFactory = options.connectionFactory ?? ((connOptions) => new DaemonConnection(connOptions));
@@ -12695,7 +13059,8 @@ var DaemonCore = class {
12695
13059
  msg.wakeMessage,
12696
13060
  msg.unreadSummary,
12697
13061
  msg.resumePrompt,
12698
- msg.launchId
13062
+ msg.launchId,
13063
+ msg.wakeMessageTransient ?? false
12699
13064
  );
12700
13065
  }
12701
13066
  handleMessage(msg) {
@@ -12746,7 +13111,10 @@ var DaemonCore = class {
12746
13111
  logger.info(`[Agent ${msg.agentId}] Delivery received (seq=${msg.seq}, from=@${msg.message.sender_name}, target=${formatChannelTarget(msg)})`);
12747
13112
  try {
12748
13113
  span.addEvent("daemon.receive", { seq: msg.seq, deliveryId: msg.deliveryId });
12749
- const acceptedOrPromise = this.agentManager.deliverMessage(msg.agentId, msg.message, { deliveryId: msg.deliveryId });
13114
+ const acceptedOrPromise = this.agentManager.deliverMessage(msg.agentId, msg.message, {
13115
+ deliveryId: msg.deliveryId,
13116
+ transient: msg.transient ?? false
13117
+ });
12750
13118
  Promise.resolve(acceptedOrPromise).then((accepted) => {
12751
13119
  span.addEvent("daemon.deliver_to_agent_manager", { accepted });
12752
13120
  if (!accepted) {