@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.
- package/dist/{chunk-4H5XFLYA.js → chunk-RIBO24KM.js} +736 -368
- package/dist/core.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
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
|
-
|
|
6263
|
-
|
|
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
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
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
|
-
|
|
6283
|
-
return this;
|
|
6410
|
+
get currentSessionId() {
|
|
6411
|
+
return this.mappingState.sessionId;
|
|
6284
6412
|
}
|
|
6285
|
-
|
|
6286
|
-
return this;
|
|
6413
|
+
get exitCode() {
|
|
6414
|
+
return this.exitInfo?.code ?? null;
|
|
6287
6415
|
}
|
|
6288
|
-
|
|
6289
|
-
this.
|
|
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
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
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
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
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
|
-
}
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
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
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
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
|
|
6335
|
-
|
|
6336
|
-
this.
|
|
6337
|
-
this.exitCode = code;
|
|
6338
|
-
this.signalCode = signal;
|
|
6524
|
+
async disposeSession() {
|
|
6525
|
+
const unsubscribe = this.unsubscribe;
|
|
6526
|
+
this.unsubscribe = null;
|
|
6339
6527
|
try {
|
|
6340
|
-
|
|
6341
|
-
|
|
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
|
-
|
|
6348
|
-
} catch {
|
|
6534
|
+
session?.dispose();
|
|
6535
|
+
} catch (error) {
|
|
6536
|
+
this.events.emit("stderr", piErrorMessage(error));
|
|
6349
6537
|
}
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
this.
|
|
6353
|
-
this.
|
|
6354
|
-
|
|
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
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
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
|
-
|
|
6395
|
-
this.sessionId = ctx.config.sessionId ||
|
|
6396
|
-
|
|
6397
|
-
|
|
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
|
-
|
|
6453
|
-
|
|
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
|
-
|
|
6527
|
-
return
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
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
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
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
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
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.
|
|
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.
|
|
8137
|
+
processPidPresent: typeof ap.runtime.pid === "number",
|
|
7936
8138
|
busyDeliveryMode: ap.driver.busyDeliveryMode,
|
|
7937
8139
|
supportsStdinNotification: ap.driver.supportsStdinNotification,
|
|
7938
|
-
gatedPhase: ap.
|
|
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
|
-
|
|
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
|
|
8669
|
-
|
|
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
|
|
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
|
-
|
|
8757
|
-
|
|
8758
|
-
|
|
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
|
-
|
|
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
|
-
|
|
8833
|
-
|
|
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
|
-
|
|
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
|
-
|
|
9082
|
+
runtime.on("exit", ({ code, signal }) => {
|
|
8874
9083
|
const current = this.agents.get(agentId);
|
|
8875
|
-
if (current && current.
|
|
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.
|
|
9099
|
+
...this.runtimeExitTraceAttrs.get(runtime)
|
|
8891
9100
|
});
|
|
8892
9101
|
logger.info(`[Agent ${agentId}] Process exited with code ${code}${signal ? ` (signal ${signal})` : ""}`);
|
|
8893
9102
|
});
|
|
8894
|
-
|
|
9103
|
+
runtime.on("close", ({ code, signal }) => {
|
|
8895
9104
|
if (this.agents.has(agentId)) {
|
|
8896
9105
|
const ap = this.agents.get(agentId);
|
|
8897
|
-
if (ap.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
9306
|
-
clearTimeout(
|
|
9554
|
+
ap.runtime.on("exit", () => {
|
|
9555
|
+
clearTimeout(timeoutTimer);
|
|
9307
9556
|
resolve();
|
|
9308
9557
|
});
|
|
9309
|
-
if (ap.
|
|
9310
|
-
clearTimeout(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
10140
|
-
this.
|
|
10141
|
-
...this.
|
|
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
|
|
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.
|
|
10475
|
+
if (!current || current !== ap || current.runtime !== runtimeAtSignal || current.expectedTerminationReason !== "stalled_recovery") {
|
|
10153
10476
|
return;
|
|
10154
10477
|
}
|
|
10155
|
-
this.
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
11147
|
+
this.runtimeExitTraceAttrs.set(ap.runtime, {
|
|
10825
11148
|
stop_source: "turn_end",
|
|
10826
11149
|
expectedTerminationReason: "turn_end"
|
|
10827
11150
|
});
|
|
10828
|
-
ap.
|
|
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.
|
|
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.
|
|
11204
|
+
this.runtimeExitTraceAttrs.set(ap.runtime, {
|
|
10882
11205
|
stop_source: "runtime_auth_error",
|
|
10883
11206
|
runtime_error_class: "AuthError"
|
|
10884
11207
|
});
|
|
10885
|
-
ap.
|
|
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
|
|
11013
|
-
|
|
11014
|
-
|
|
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.
|
|
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
|
|
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
|
|
11098
|
-
|
|
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:
|
|
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:
|
|
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
|
|
11216
|
-
|
|
11217
|
-
|
|
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:
|
|
11228
|
-
|
|
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
|
-
|
|
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, {
|
|
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) {
|