@slock-ai/daemon 0.56.0 → 0.56.1-play.20260603140721
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-5EVWI6BL.js} +863 -393
- package/dist/core.js +6 -2
- package/dist/drivers/piSdkRunner.js +96 -0
- package/dist/index.js +5 -3
- package/package.json +1 -1
|
@@ -1861,6 +1861,19 @@ function listLegacySlockStatePaths(slockHome = resolveSlockHome(), homeDir = os.
|
|
|
1861
1861
|
return candidates.filter((candidate) => existsSync(candidate.path));
|
|
1862
1862
|
}
|
|
1863
1863
|
|
|
1864
|
+
// src/authEnv.ts
|
|
1865
|
+
var DAEMON_API_KEY_ENV = "SLOCK_MACHINE_API_KEY";
|
|
1866
|
+
var SLOCK_AGENT_TOKEN_ENV = "SLOCK_AGENT_TOKEN";
|
|
1867
|
+
function scrubDaemonAuthEnv(env) {
|
|
1868
|
+
delete env[DAEMON_API_KEY_ENV];
|
|
1869
|
+
return env;
|
|
1870
|
+
}
|
|
1871
|
+
function scrubDaemonChildEnv(env) {
|
|
1872
|
+
delete env[DAEMON_API_KEY_ENV];
|
|
1873
|
+
delete env[SLOCK_AGENT_TOKEN_ENV];
|
|
1874
|
+
return env;
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1864
1877
|
// src/agentCredentialProxy.ts
|
|
1865
1878
|
import { randomBytes } from "crypto";
|
|
1866
1879
|
import http from "http";
|
|
@@ -3016,7 +3029,9 @@ var LOOPBACK_NO_PROXY = "127.0.0.1,localhost";
|
|
|
3016
3029
|
var CLI_TRANSPORT_TRACE_DIR_ENV = "SLOCK_CLI_TRANSPORT_TRACE_DIR";
|
|
3017
3030
|
var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
3018
3031
|
var RAW_CREDENTIAL_ENV_DENYLIST = [
|
|
3019
|
-
"
|
|
3032
|
+
"SLOCK_AGENT_TOKEN",
|
|
3033
|
+
"SLOCK_AGENT_CREDENTIAL_KEY",
|
|
3034
|
+
"SLOCK_AGENT_CREDENTIAL_KEY_FILE"
|
|
3020
3035
|
];
|
|
3021
3036
|
var cachedOpencliBinPath;
|
|
3022
3037
|
function resolveOpencliBinPath() {
|
|
@@ -3231,7 +3246,7 @@ exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(opencliBinPath)} "
|
|
|
3231
3246
|
...agentCredentialProxy ? {} : { SLOCK_AGENT_TOKEN_FILE: tokenFile },
|
|
3232
3247
|
PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
|
|
3233
3248
|
};
|
|
3234
|
-
|
|
3249
|
+
scrubDaemonChildEnv(spawnEnv);
|
|
3235
3250
|
for (const key of RAW_CREDENTIAL_ENV_DENYLIST) {
|
|
3236
3251
|
delete spawnEnv[key];
|
|
3237
3252
|
}
|
|
@@ -3660,7 +3675,7 @@ function resolveCommandOnWindows(command, env, execFileSyncFn, existsSyncFn) {
|
|
|
3660
3675
|
}
|
|
3661
3676
|
function resolveCommandOnPath(command, deps = {}) {
|
|
3662
3677
|
const platform = deps.platform ?? process.platform;
|
|
3663
|
-
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
3678
|
+
const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
|
|
3664
3679
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
3665
3680
|
const existsSyncFn = deps.existsSyncFn ?? existsSync2;
|
|
3666
3681
|
if (platform === "win32") {
|
|
@@ -3686,7 +3701,7 @@ function firstExistingPath(candidates, deps = {}) {
|
|
|
3686
3701
|
return null;
|
|
3687
3702
|
}
|
|
3688
3703
|
function readCommandVersion(command, args = [], deps = {}) {
|
|
3689
|
-
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
3704
|
+
const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
|
|
3690
3705
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
3691
3706
|
try {
|
|
3692
3707
|
const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
|
|
@@ -5149,11 +5164,11 @@ function detectCursorModels(runCommand = runCursorModelsCommand) {
|
|
|
5149
5164
|
return parseCursorModelsOutput(String(result.stdout || ""));
|
|
5150
5165
|
}
|
|
5151
5166
|
function buildCursorModelProbeEnv(deps = {}) {
|
|
5152
|
-
return withWindowsUserEnvironment({
|
|
5167
|
+
return scrubDaemonChildEnv(withWindowsUserEnvironment({
|
|
5153
5168
|
...deps.env ?? process.env,
|
|
5154
5169
|
FORCE_COLOR: "0",
|
|
5155
5170
|
NO_COLOR: "1"
|
|
5156
|
-
}, deps);
|
|
5171
|
+
}, deps));
|
|
5157
5172
|
}
|
|
5158
5173
|
function runCursorModelsCommand() {
|
|
5159
5174
|
return spawnSync("cursor-agent", ["models"], {
|
|
@@ -5209,7 +5224,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
|
|
|
5209
5224
|
}
|
|
5210
5225
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
|
|
5211
5226
|
const existsSyncFn = deps.existsSyncFn ?? existsSync5;
|
|
5212
|
-
const env = deps.env ?? process.env;
|
|
5227
|
+
const env = scrubDaemonChildEnv({ ...deps.env ?? process.env });
|
|
5213
5228
|
const winPath = path8.win32;
|
|
5214
5229
|
let geminiEntry = null;
|
|
5215
5230
|
try {
|
|
@@ -5381,13 +5396,16 @@ var GeminiDriver = class {
|
|
|
5381
5396
|
// src/drivers/kimi.ts
|
|
5382
5397
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
5383
5398
|
import { spawn as spawn7 } from "child_process";
|
|
5384
|
-
import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
5399
|
+
import { chmodSync, existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
5385
5400
|
import os3 from "os";
|
|
5386
5401
|
import path9 from "path";
|
|
5387
5402
|
var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
|
|
5388
5403
|
var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
|
|
5389
5404
|
var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
|
|
5390
5405
|
var KIMI_MCP_FILE = ".slock-kimi-mcp.json";
|
|
5406
|
+
var KIMI_GENERATED_CONFIG_FILE = ".slock-kimi-config.toml";
|
|
5407
|
+
var SLOCK_KIMI_CONFIG_CONTENT_ENV = "SLOCK_KIMI_CONFIG_CONTENT";
|
|
5408
|
+
var SLOCK_KIMI_CONFIG_FILE_ENV = "SLOCK_KIMI_CONFIG_FILE";
|
|
5391
5409
|
function parseToolArguments(raw) {
|
|
5392
5410
|
if (typeof raw !== "string") return raw;
|
|
5393
5411
|
try {
|
|
@@ -5396,6 +5414,73 @@ function parseToolArguments(raw) {
|
|
|
5396
5414
|
return raw;
|
|
5397
5415
|
}
|
|
5398
5416
|
}
|
|
5417
|
+
function readKimiConfigSource(home = os3.homedir(), env = process.env) {
|
|
5418
|
+
const inlineConfig = env[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
5419
|
+
if (inlineConfig && inlineConfig.trim()) {
|
|
5420
|
+
return {
|
|
5421
|
+
raw: inlineConfig,
|
|
5422
|
+
explicitPath: null,
|
|
5423
|
+
sourcePath: SLOCK_KIMI_CONFIG_CONTENT_ENV
|
|
5424
|
+
};
|
|
5425
|
+
}
|
|
5426
|
+
const explicitPath = env[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
5427
|
+
const configPath = explicitPath && explicitPath.trim() ? explicitPath : path9.join(home, ".kimi", "config.toml");
|
|
5428
|
+
try {
|
|
5429
|
+
return {
|
|
5430
|
+
raw: readFileSync3(configPath, "utf8"),
|
|
5431
|
+
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
5432
|
+
sourcePath: configPath
|
|
5433
|
+
};
|
|
5434
|
+
} catch {
|
|
5435
|
+
return {
|
|
5436
|
+
raw: null,
|
|
5437
|
+
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
5438
|
+
sourcePath: configPath
|
|
5439
|
+
};
|
|
5440
|
+
}
|
|
5441
|
+
}
|
|
5442
|
+
function buildKimiSpawnEnv(env = process.env) {
|
|
5443
|
+
const spawnEnv = { ...env, FORCE_COLOR: "0", NO_COLOR: "1" };
|
|
5444
|
+
delete spawnEnv[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
5445
|
+
delete spawnEnv[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
5446
|
+
return scrubDaemonChildEnv(spawnEnv);
|
|
5447
|
+
}
|
|
5448
|
+
function buildKimiEffectiveEnv(ctx, overrideEnv) {
|
|
5449
|
+
return {
|
|
5450
|
+
...process.env,
|
|
5451
|
+
...ctx.config.envVars || {},
|
|
5452
|
+
...overrideEnv || {}
|
|
5453
|
+
};
|
|
5454
|
+
}
|
|
5455
|
+
function buildKimiLaunchOptions(ctx, opts = {}) {
|
|
5456
|
+
const env = buildKimiEffectiveEnv(ctx, opts.env);
|
|
5457
|
+
const source = readKimiConfigSource(opts.home ?? os3.homedir(), env);
|
|
5458
|
+
const args = [];
|
|
5459
|
+
let configFilePath = null;
|
|
5460
|
+
let configContent = null;
|
|
5461
|
+
if (source.explicitPath) {
|
|
5462
|
+
configFilePath = source.explicitPath;
|
|
5463
|
+
} else if (source.raw !== null && source.sourcePath === SLOCK_KIMI_CONFIG_CONTENT_ENV) {
|
|
5464
|
+
configFilePath = path9.join(ctx.workingDirectory, KIMI_GENERATED_CONFIG_FILE);
|
|
5465
|
+
configContent = source.raw;
|
|
5466
|
+
if (opts.writeGeneratedConfig !== false) {
|
|
5467
|
+
writeFileSync6(configFilePath, source.raw, { encoding: "utf8", mode: 384 });
|
|
5468
|
+
chmodSync(configFilePath, 384);
|
|
5469
|
+
}
|
|
5470
|
+
}
|
|
5471
|
+
if (configFilePath) {
|
|
5472
|
+
args.push("--config-file", configFilePath);
|
|
5473
|
+
}
|
|
5474
|
+
if (ctx.config.model && ctx.config.model !== "default") {
|
|
5475
|
+
args.push("--model", ctx.config.model);
|
|
5476
|
+
}
|
|
5477
|
+
return {
|
|
5478
|
+
args,
|
|
5479
|
+
env: buildKimiSpawnEnv(env),
|
|
5480
|
+
configFilePath,
|
|
5481
|
+
configContent
|
|
5482
|
+
};
|
|
5483
|
+
}
|
|
5399
5484
|
function resolveKimiSpawn(commandArgs, deps = {}) {
|
|
5400
5485
|
return {
|
|
5401
5486
|
command: resolveCommandOnPath("kimi", deps) ?? "kimi",
|
|
@@ -5419,7 +5504,25 @@ var KimiDriver = class {
|
|
|
5419
5504
|
};
|
|
5420
5505
|
model = {
|
|
5421
5506
|
detectedModelsVerifiedAs: "launchable",
|
|
5422
|
-
toLaunchSpec: (modelId) =>
|
|
5507
|
+
toLaunchSpec: (modelId, ctx, opts) => {
|
|
5508
|
+
if (!ctx) return { args: ["--model", modelId] };
|
|
5509
|
+
const launchCtx = {
|
|
5510
|
+
...ctx,
|
|
5511
|
+
config: {
|
|
5512
|
+
...ctx.config,
|
|
5513
|
+
model: modelId
|
|
5514
|
+
}
|
|
5515
|
+
};
|
|
5516
|
+
const launch = buildKimiLaunchOptions(launchCtx, {
|
|
5517
|
+
home: opts?.home,
|
|
5518
|
+
writeGeneratedConfig: false
|
|
5519
|
+
});
|
|
5520
|
+
return {
|
|
5521
|
+
args: launch.args,
|
|
5522
|
+
env: launch.env,
|
|
5523
|
+
configFiles: launch.configFilePath ? [launch.configFilePath] : void 0
|
|
5524
|
+
};
|
|
5525
|
+
}
|
|
5423
5526
|
};
|
|
5424
5527
|
supportsStdinNotification = true;
|
|
5425
5528
|
mcpToolPrefix = "";
|
|
@@ -5473,6 +5576,7 @@ var KimiDriver = class {
|
|
|
5473
5576
|
}
|
|
5474
5577
|
}
|
|
5475
5578
|
}), "utf8");
|
|
5579
|
+
const launch = buildKimiLaunchOptions(ctx);
|
|
5476
5580
|
const args = [
|
|
5477
5581
|
"--wire",
|
|
5478
5582
|
"--yolo",
|
|
@@ -5481,15 +5585,16 @@ var KimiDriver = class {
|
|
|
5481
5585
|
"--mcp-config-file",
|
|
5482
5586
|
mcpConfigPath,
|
|
5483
5587
|
"--session",
|
|
5484
|
-
this.sessionId
|
|
5588
|
+
this.sessionId,
|
|
5589
|
+
...launch.args
|
|
5485
5590
|
];
|
|
5486
5591
|
const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
|
|
5487
5592
|
if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
|
|
5488
5593
|
args.push("--model", launchRuntimeFields.model);
|
|
5489
5594
|
}
|
|
5490
5595
|
const spawnEnv = (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
|
|
5491
|
-
const
|
|
5492
|
-
const proc = spawn7(
|
|
5596
|
+
const spawnTarget = resolveKimiSpawn(args);
|
|
5597
|
+
const proc = spawn7(spawnTarget.command, spawnTarget.args, {
|
|
5493
5598
|
cwd: ctx.workingDirectory,
|
|
5494
5599
|
stdio: ["pipe", "pipe", "pipe"],
|
|
5495
5600
|
env: spawnEnv,
|
|
@@ -5497,7 +5602,7 @@ var KimiDriver = class {
|
|
|
5497
5602
|
// and has an 8191-character command-line limit. Kimi's official
|
|
5498
5603
|
// installer/uv entrypoint is an executable, so launch it directly and
|
|
5499
5604
|
// keep prompts on stdin / files instead of routing through cmd.exe.
|
|
5500
|
-
shell:
|
|
5605
|
+
shell: spawnTarget.shell
|
|
5501
5606
|
});
|
|
5502
5607
|
proc.stdin?.write(JSON.stringify({
|
|
5503
5608
|
jsonrpc: "2.0",
|
|
@@ -5611,14 +5716,9 @@ var KimiDriver = class {
|
|
|
5611
5716
|
return detectKimiModels();
|
|
5612
5717
|
}
|
|
5613
5718
|
};
|
|
5614
|
-
function detectKimiModels(home = os3.homedir()) {
|
|
5615
|
-
const
|
|
5616
|
-
|
|
5617
|
-
try {
|
|
5618
|
-
raw = readFileSync3(configPath, "utf8");
|
|
5619
|
-
} catch {
|
|
5620
|
-
return null;
|
|
5621
|
-
}
|
|
5719
|
+
function detectKimiModels(home = os3.homedir(), opts = {}) {
|
|
5720
|
+
const raw = readKimiConfigSource(home, opts.env).raw;
|
|
5721
|
+
if (raw === null) return null;
|
|
5622
5722
|
const models = [];
|
|
5623
5723
|
const sectionRe = /^\s*\[models(?:\.([^\]]+)|"\.[^"]+"|\."[^"]+")\s*\]\s*$/gm;
|
|
5624
5724
|
const lineRe = /^\s*\[models\.(.+?)\s*\]\s*$/gm;
|
|
@@ -5882,7 +5982,7 @@ function runOpenCodeModelsCommand(home, deps = {}) {
|
|
|
5882
5982
|
const platform = deps.platform ?? process.platform;
|
|
5883
5983
|
const spawnSyncFn = deps.spawnSyncFn ?? spawnSync2;
|
|
5884
5984
|
const result = spawnSyncFn("opencode", ["models"], {
|
|
5885
|
-
env: { ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" },
|
|
5985
|
+
env: scrubDaemonChildEnv({ ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" }),
|
|
5886
5986
|
encoding: "utf8",
|
|
5887
5987
|
timeout: 5e3,
|
|
5888
5988
|
shell: platform === "win32"
|
|
@@ -6145,7 +6245,6 @@ var OpenCodeDriver = class {
|
|
|
6145
6245
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
6146
6246
|
import { EventEmitter } from "events";
|
|
6147
6247
|
import { mkdirSync as mkdirSync4, readdirSync } from "fs";
|
|
6148
|
-
import { PassThrough, Writable } from "stream";
|
|
6149
6248
|
import path11 from "path";
|
|
6150
6249
|
import {
|
|
6151
6250
|
AuthStorage,
|
|
@@ -6164,6 +6263,13 @@ var PI_PROVIDER_LABELS = {
|
|
|
6164
6263
|
openai: "OpenAI",
|
|
6165
6264
|
openrouter: "OpenRouter"
|
|
6166
6265
|
};
|
|
6266
|
+
function createPiSdkEventMappingState(sessionId = null) {
|
|
6267
|
+
return {
|
|
6268
|
+
sessionId,
|
|
6269
|
+
sessionAnnounced: false,
|
|
6270
|
+
sawTextDelta: false
|
|
6271
|
+
};
|
|
6272
|
+
}
|
|
6167
6273
|
function buildPiSessionDir(workingDirectory) {
|
|
6168
6274
|
return path11.join(workingDirectory, PI_SESSION_DIR);
|
|
6169
6275
|
}
|
|
@@ -6189,12 +6295,6 @@ function findPiSessionFile(sessionDir, sessionId) {
|
|
|
6189
6295
|
const match = entries.find((entry) => entry.endsWith(suffix));
|
|
6190
6296
|
return match ? path11.join(sessionDir, match) : null;
|
|
6191
6297
|
}
|
|
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
6298
|
function detectPiModelsFromRegistry(modelRegistry) {
|
|
6199
6299
|
const models = [];
|
|
6200
6300
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -6244,114 +6344,309 @@ function piErrorMessage(error) {
|
|
|
6244
6344
|
}
|
|
6245
6345
|
return "Unknown Pi error";
|
|
6246
6346
|
}
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6347
|
+
function pushSessionInitIfNeeded(state, events) {
|
|
6348
|
+
if (!state.sessionAnnounced && state.sessionId) {
|
|
6349
|
+
events.push({ kind: "session_init", sessionId: state.sessionId });
|
|
6350
|
+
state.sessionAnnounced = true;
|
|
6351
|
+
}
|
|
6352
|
+
}
|
|
6353
|
+
function mapPiAssistantMessageEvent(assistantEvent, state) {
|
|
6354
|
+
switch (assistantEvent.type) {
|
|
6355
|
+
case "thinking_delta":
|
|
6356
|
+
return typeof assistantEvent.delta === "string" && assistantEvent.delta.length > 0 ? [{ kind: "thinking", text: assistantEvent.delta }] : [];
|
|
6357
|
+
case "text_delta":
|
|
6358
|
+
if (typeof assistantEvent.delta === "string" && assistantEvent.delta.length > 0) {
|
|
6359
|
+
state.sawTextDelta = true;
|
|
6360
|
+
return [{ kind: "text", text: assistantEvent.delta }];
|
|
6260
6361
|
}
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6362
|
+
return [];
|
|
6363
|
+
case "text_end":
|
|
6364
|
+
return !state.sawTextDelta && typeof assistantEvent.content === "string" && assistantEvent.content.length > 0 ? [{ kind: "text", text: assistantEvent.content }] : [];
|
|
6365
|
+
case "error":
|
|
6366
|
+
return [{ kind: "error", message: piErrorMessage(assistantEvent.error.errorMessage || assistantEvent.error) }];
|
|
6367
|
+
case "thinking_start":
|
|
6368
|
+
case "thinking_end":
|
|
6369
|
+
case "text_start":
|
|
6370
|
+
case "toolcall_start":
|
|
6371
|
+
case "toolcall_delta":
|
|
6372
|
+
case "toolcall_end":
|
|
6373
|
+
case "start":
|
|
6374
|
+
case "done":
|
|
6375
|
+
return [];
|
|
6376
|
+
default: {
|
|
6377
|
+
const _exhaustive = assistantEvent;
|
|
6378
|
+
return _exhaustive;
|
|
6379
|
+
}
|
|
6380
|
+
}
|
|
6381
|
+
}
|
|
6382
|
+
function mapPiSdkEventToParsedEvents(event, state) {
|
|
6383
|
+
const events = [];
|
|
6384
|
+
pushSessionInitIfNeeded(state, events);
|
|
6385
|
+
switch (event.type) {
|
|
6386
|
+
case "agent_start":
|
|
6387
|
+
case "turn_start":
|
|
6388
|
+
case "turn_end":
|
|
6389
|
+
case "message_end":
|
|
6390
|
+
case "tool_execution_update":
|
|
6391
|
+
case "queue_update":
|
|
6392
|
+
case "session_info_changed":
|
|
6393
|
+
case "thinking_level_changed":
|
|
6394
|
+
case "auto_retry_start":
|
|
6395
|
+
case "auto_retry_end":
|
|
6396
|
+
return events;
|
|
6397
|
+
case "message_start":
|
|
6398
|
+
if (event.message.role === "assistant") {
|
|
6399
|
+
state.sawTextDelta = false;
|
|
6400
|
+
}
|
|
6401
|
+
return events;
|
|
6402
|
+
case "message_update":
|
|
6403
|
+
events.push(...mapPiAssistantMessageEvent(event.assistantMessageEvent, state));
|
|
6404
|
+
return events;
|
|
6405
|
+
case "tool_execution_start":
|
|
6406
|
+
events.push({
|
|
6407
|
+
kind: "tool_call",
|
|
6408
|
+
name: event.toolName || "unknown_tool",
|
|
6409
|
+
input: event.args ?? {}
|
|
6410
|
+
});
|
|
6411
|
+
return events;
|
|
6412
|
+
case "tool_execution_end":
|
|
6413
|
+
events.push({ kind: "tool_output", name: event.toolName || "unknown_tool" });
|
|
6414
|
+
return events;
|
|
6415
|
+
case "compaction_start":
|
|
6416
|
+
events.push({ kind: "compaction_started" });
|
|
6417
|
+
return events;
|
|
6418
|
+
case "compaction_end":
|
|
6419
|
+
events.push({ kind: "compaction_finished" });
|
|
6420
|
+
return events;
|
|
6421
|
+
case "agent_end":
|
|
6422
|
+
events.push({ kind: "turn_end", sessionId: state.sessionId || void 0 });
|
|
6423
|
+
return events;
|
|
6424
|
+
default: {
|
|
6425
|
+
const _exhaustive = event;
|
|
6426
|
+
return _exhaustive;
|
|
6427
|
+
}
|
|
6265
6428
|
}
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6429
|
+
}
|
|
6430
|
+
var PI_RUNTIME_SESSION_DESCRIPTOR = {
|
|
6431
|
+
transport: "sdk",
|
|
6432
|
+
lifecycle: "sdk_session",
|
|
6433
|
+
input: {
|
|
6434
|
+
initial: "start",
|
|
6435
|
+
idle: "sdk_prompt",
|
|
6436
|
+
busy: "sdk_steer"
|
|
6437
|
+
},
|
|
6438
|
+
readiness: "sdk_ready",
|
|
6439
|
+
turnBoundary: "sdk_event",
|
|
6440
|
+
startPolicy: "immediate",
|
|
6441
|
+
inFlightWake: "steer",
|
|
6442
|
+
busyDelivery: "direct",
|
|
6443
|
+
postTurn: "keep_alive"
|
|
6444
|
+
};
|
|
6445
|
+
async function createPiAgentSessionForContext(ctx, sessionId) {
|
|
6446
|
+
const sessionDir = buildPiSessionDir(ctx.workingDirectory);
|
|
6447
|
+
mkdirSync4(sessionDir, { recursive: true });
|
|
6448
|
+
const spawnEnv = await buildPiSpawnEnv(ctx);
|
|
6449
|
+
const agentDir = spawnEnv.PI_CODING_AGENT_DIR || getAgentDir();
|
|
6450
|
+
const authStorage = AuthStorage.create(path11.join(agentDir, "auth.json"));
|
|
6451
|
+
const modelRegistry = ModelRegistry.create(authStorage, path11.join(agentDir, "models.json"));
|
|
6452
|
+
const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
|
|
6453
|
+
const model = resolvePiModelFromRegistry(launchRuntimeFields.model, modelRegistry);
|
|
6454
|
+
if (launchRuntimeFields.model && launchRuntimeFields.model !== "default" && !model) {
|
|
6455
|
+
throw new Error(`Pi model not found: ${launchRuntimeFields.model}`);
|
|
6456
|
+
}
|
|
6457
|
+
const settingsManager = SettingsManager.inMemory({ compaction: { enabled: false } });
|
|
6458
|
+
const resourceLoader = new DefaultResourceLoader({
|
|
6459
|
+
cwd: ctx.workingDirectory,
|
|
6460
|
+
agentDir,
|
|
6461
|
+
settingsManager,
|
|
6462
|
+
systemPromptOverride: () => ctx.standingPrompt
|
|
6463
|
+
});
|
|
6464
|
+
await resourceLoader.reload();
|
|
6465
|
+
const existingSessionFile = ctx.config.sessionId ? findPiSessionFile(sessionDir, ctx.config.sessionId) : null;
|
|
6466
|
+
const sessionManager = existingSessionFile ? SessionManager.open(existingSessionFile, sessionDir, ctx.workingDirectory) : SessionManager.create(ctx.workingDirectory, sessionDir, { id: sessionId });
|
|
6467
|
+
const { session } = await createAgentSession({
|
|
6468
|
+
cwd: ctx.workingDirectory,
|
|
6469
|
+
agentDir,
|
|
6470
|
+
model,
|
|
6471
|
+
thinkingLevel: launchRuntimeFields.reasoningEffort,
|
|
6472
|
+
authStorage,
|
|
6473
|
+
modelRegistry,
|
|
6474
|
+
resourceLoader,
|
|
6475
|
+
customTools: [
|
|
6476
|
+
createBashTool(ctx.workingDirectory, {
|
|
6477
|
+
spawnHook: (spawnContext) => ({
|
|
6478
|
+
...spawnContext,
|
|
6479
|
+
env: {
|
|
6480
|
+
...spawnContext.env,
|
|
6481
|
+
...spawnEnv
|
|
6482
|
+
}
|
|
6483
|
+
})
|
|
6484
|
+
})
|
|
6485
|
+
],
|
|
6486
|
+
sessionManager,
|
|
6487
|
+
settingsManager
|
|
6488
|
+
});
|
|
6489
|
+
return session;
|
|
6490
|
+
}
|
|
6491
|
+
var PiSdkRuntimeSession = class {
|
|
6492
|
+
constructor(ctx, setCurrentSessionId, sessionFactory = createPiAgentSessionForContext) {
|
|
6493
|
+
this.ctx = ctx;
|
|
6494
|
+
this.setCurrentSessionId = setCurrentSessionId;
|
|
6495
|
+
this.sessionFactory = sessionFactory;
|
|
6496
|
+
this.mappingState = createPiSdkEventMappingState(ctx.config.sessionId || null);
|
|
6497
|
+
}
|
|
6498
|
+
descriptor = PI_RUNTIME_SESSION_DESCRIPTOR;
|
|
6499
|
+
events = new EventEmitter();
|
|
6500
|
+
mappingState;
|
|
6501
|
+
session = null;
|
|
6502
|
+
unsubscribe = null;
|
|
6503
|
+
started = false;
|
|
6504
|
+
didClose = false;
|
|
6505
|
+
requestedStopReason;
|
|
6506
|
+
exitInfo = null;
|
|
6507
|
+
get pid() {
|
|
6508
|
+
return void 0;
|
|
6281
6509
|
}
|
|
6282
|
-
|
|
6283
|
-
return this;
|
|
6510
|
+
get currentSessionId() {
|
|
6511
|
+
return this.mappingState.sessionId;
|
|
6284
6512
|
}
|
|
6285
|
-
|
|
6286
|
-
return this;
|
|
6513
|
+
get exitCode() {
|
|
6514
|
+
return this.exitInfo?.code ?? null;
|
|
6287
6515
|
}
|
|
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
|
-
}
|
|
6516
|
+
get signalCode() {
|
|
6517
|
+
return this.exitInfo?.signal ?? null;
|
|
6296
6518
|
}
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6519
|
+
get closed() {
|
|
6520
|
+
return this.didClose;
|
|
6521
|
+
}
|
|
6522
|
+
on(event, cb) {
|
|
6523
|
+
this.events.on(event, cb);
|
|
6524
|
+
}
|
|
6525
|
+
async start(input) {
|
|
6526
|
+
if (this.started) {
|
|
6527
|
+
return { ok: false, reason: "runtime_error", error: "runtime session already started" };
|
|
6304
6528
|
}
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6529
|
+
if (this.didClose) return { ok: false, reason: "closed" };
|
|
6530
|
+
this.started = true;
|
|
6531
|
+
const sessionId = input.sessionId || this.ctx.config.sessionId || randomUUID3();
|
|
6532
|
+
this.mappingState.sessionId = sessionId;
|
|
6533
|
+
this.setCurrentSessionId(sessionId);
|
|
6534
|
+
const session = await this.sessionFactory({
|
|
6535
|
+
...this.ctx,
|
|
6536
|
+
config: {
|
|
6537
|
+
...this.ctx.config,
|
|
6538
|
+
sessionId
|
|
6315
6539
|
}
|
|
6316
|
-
}
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
}
|
|
6540
|
+
}, sessionId);
|
|
6541
|
+
this.session = session;
|
|
6542
|
+
this.mappingState.sessionId = session.sessionId;
|
|
6543
|
+
this.setCurrentSessionId(session.sessionId);
|
|
6544
|
+
this.unsubscribe = session.subscribe((event) => {
|
|
6545
|
+
for (const parsed of mapPiSdkEventToParsedEvents(event, this.mappingState)) {
|
|
6546
|
+
this.events.emit("runtime_event", parsed);
|
|
6547
|
+
}
|
|
6548
|
+
});
|
|
6549
|
+
this.emitSessionInit();
|
|
6550
|
+
this.launchPrompt(input.text);
|
|
6551
|
+
return { ok: true, acceptedAs: "prompt" };
|
|
6552
|
+
}
|
|
6553
|
+
send(input) {
|
|
6554
|
+
if (this.didClose) return { ok: false, reason: "closed" };
|
|
6555
|
+
const session = this.session;
|
|
6556
|
+
if (!session) return { ok: false, reason: "closed" };
|
|
6557
|
+
if (input.mode === "busy") {
|
|
6558
|
+
this.deferSdkCall(() => session.steer(input.text));
|
|
6559
|
+
return { ok: true, acceptedAs: "steer" };
|
|
6560
|
+
}
|
|
6561
|
+
if (session.isStreaming) {
|
|
6562
|
+
return { ok: false, reason: "busy_rejected", error: "Pi session is still streaming" };
|
|
6563
|
+
}
|
|
6564
|
+
this.launchPrompt(input.text);
|
|
6565
|
+
return { ok: true, acceptedAs: "prompt" };
|
|
6566
|
+
}
|
|
6567
|
+
async stop(opts) {
|
|
6568
|
+
if (this.didClose) return;
|
|
6569
|
+
this.requestedStopReason = opts?.reason;
|
|
6570
|
+
const signal = opts?.signal ?? "SIGTERM";
|
|
6571
|
+
const session = this.session;
|
|
6572
|
+
if (session?.isStreaming) {
|
|
6573
|
+
try {
|
|
6574
|
+
await session.abort();
|
|
6575
|
+
} catch (error) {
|
|
6576
|
+
this.events.emit("stderr", piErrorMessage(error));
|
|
6577
|
+
}
|
|
6578
|
+
}
|
|
6579
|
+
await this.disposeSession();
|
|
6580
|
+
this.emitExitAndClose(null, signal);
|
|
6581
|
+
}
|
|
6582
|
+
async dispose() {
|
|
6583
|
+
if (this.didClose) return;
|
|
6584
|
+
await this.disposeSession();
|
|
6585
|
+
this.emitExitAndClose(0, null);
|
|
6586
|
+
}
|
|
6587
|
+
emitSessionInit() {
|
|
6588
|
+
const sessionId = this.mappingState.sessionId;
|
|
6589
|
+
if (!sessionId || this.mappingState.sessionAnnounced) return;
|
|
6590
|
+
this.mappingState.sessionAnnounced = true;
|
|
6591
|
+
this.events.emit("runtime_event", { kind: "session_init", sessionId });
|
|
6592
|
+
}
|
|
6593
|
+
launchPrompt(text) {
|
|
6594
|
+
const session = this.session;
|
|
6595
|
+
if (!session) {
|
|
6596
|
+
this.events.emit("runtime_event", {
|
|
6597
|
+
kind: "error",
|
|
6598
|
+
message: "Pi SDK session is not started"
|
|
6599
|
+
});
|
|
6600
|
+
return;
|
|
6324
6601
|
}
|
|
6602
|
+
this.deferSdkCall(() => session.prompt(text));
|
|
6325
6603
|
}
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6604
|
+
deferSdkCall(invoke) {
|
|
6605
|
+
setImmediate(() => {
|
|
6606
|
+
if (this.didClose) return;
|
|
6607
|
+
try {
|
|
6608
|
+
void invoke().catch((error) => {
|
|
6609
|
+
if (this.didClose) return;
|
|
6610
|
+
this.events.emit("runtime_event", {
|
|
6611
|
+
kind: "error",
|
|
6612
|
+
message: piErrorMessage(error)
|
|
6613
|
+
});
|
|
6614
|
+
});
|
|
6615
|
+
} catch (error) {
|
|
6616
|
+
if (this.didClose) return;
|
|
6617
|
+
this.events.emit("runtime_event", {
|
|
6618
|
+
kind: "error",
|
|
6619
|
+
message: piErrorMessage(error)
|
|
6620
|
+
});
|
|
6621
|
+
}
|
|
6622
|
+
});
|
|
6333
6623
|
}
|
|
6334
|
-
async
|
|
6335
|
-
|
|
6336
|
-
this.
|
|
6337
|
-
this.exitCode = code;
|
|
6338
|
-
this.signalCode = signal;
|
|
6624
|
+
async disposeSession() {
|
|
6625
|
+
const unsubscribe = this.unsubscribe;
|
|
6626
|
+
this.unsubscribe = null;
|
|
6339
6627
|
try {
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
}
|
|
6343
|
-
} catch (error) {
|
|
6344
|
-
this.stderr.write(piErrorMessage(error) + "\n");
|
|
6628
|
+
unsubscribe?.();
|
|
6629
|
+
} catch {
|
|
6345
6630
|
}
|
|
6631
|
+
const session = this.session;
|
|
6632
|
+
this.session = null;
|
|
6346
6633
|
try {
|
|
6347
|
-
|
|
6348
|
-
} catch {
|
|
6634
|
+
session?.dispose();
|
|
6635
|
+
} catch (error) {
|
|
6636
|
+
this.events.emit("stderr", piErrorMessage(error));
|
|
6349
6637
|
}
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
this.
|
|
6353
|
-
this.
|
|
6354
|
-
|
|
6638
|
+
}
|
|
6639
|
+
emitExitAndClose(code, signal) {
|
|
6640
|
+
if (this.didClose) return;
|
|
6641
|
+
this.didClose = true;
|
|
6642
|
+
const info = {
|
|
6643
|
+
code,
|
|
6644
|
+
signal,
|
|
6645
|
+
reason: this.requestedStopReason ? "requested" : "runtime_exit"
|
|
6646
|
+
};
|
|
6647
|
+
this.exitInfo = info;
|
|
6648
|
+
this.events.emit("exit", info);
|
|
6649
|
+
this.events.emit("close", info);
|
|
6355
6650
|
}
|
|
6356
6651
|
};
|
|
6357
6652
|
var PiDriver = class {
|
|
@@ -6378,10 +6673,9 @@ var PiDriver = class {
|
|
|
6378
6673
|
busyDeliveryMode = "direct";
|
|
6379
6674
|
usesSlockCliForCommunication = true;
|
|
6380
6675
|
sessionId = null;
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
process = null;
|
|
6676
|
+
get currentSessionId() {
|
|
6677
|
+
return this.sessionId;
|
|
6678
|
+
}
|
|
6385
6679
|
probe() {
|
|
6386
6680
|
return {
|
|
6387
6681
|
available: true,
|
|
@@ -6391,144 +6685,20 @@ var PiDriver = class {
|
|
|
6391
6685
|
async detectModels() {
|
|
6392
6686
|
return detectPiModels();
|
|
6393
6687
|
}
|
|
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
|
-
}
|
|
6688
|
+
createSession(ctx) {
|
|
6689
|
+
this.sessionId = ctx.config.sessionId || null;
|
|
6690
|
+
return new PiSdkRuntimeSession(ctx, (sessionId) => {
|
|
6691
|
+
this.sessionId = sessionId;
|
|
6449
6692
|
});
|
|
6450
|
-
return { process: proc };
|
|
6451
6693
|
}
|
|
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;
|
|
6694
|
+
async spawn(_ctx) {
|
|
6695
|
+
throw new Error("PiDriver uses a native RuntimeSession; child-process spawn is unsupported");
|
|
6525
6696
|
}
|
|
6526
|
-
|
|
6527
|
-
return
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
});
|
|
6697
|
+
parseLine(_line) {
|
|
6698
|
+
return [];
|
|
6699
|
+
}
|
|
6700
|
+
encodeStdinMessage(_text, _sessionId, _opts) {
|
|
6701
|
+
return null;
|
|
6532
6702
|
}
|
|
6533
6703
|
buildSystemPrompt(config, _agentId) {
|
|
6534
6704
|
return buildCliTransportSystemPrompt(config, {
|
|
@@ -6541,18 +6711,141 @@ var PiDriver = class {
|
|
|
6541
6711
|
messageNotificationStyle: "direct"
|
|
6542
6712
|
});
|
|
6543
6713
|
}
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6714
|
+
};
|
|
6715
|
+
|
|
6716
|
+
// src/drivers/runtimeSession.ts
|
|
6717
|
+
import { EventEmitter as EventEmitter2 } from "events";
|
|
6718
|
+
function descriptorFromDriver(driver) {
|
|
6719
|
+
const lifecycle = driver.lifecycle.kind === "per_turn" ? "turn_based" : "persistent_stream";
|
|
6720
|
+
const idle = driver.supportsStdinNotification ? "stdin" : "unsupported";
|
|
6721
|
+
const busy = driver.supportsStdinNotification ? "stdin_steer" : "unsupported";
|
|
6722
|
+
return {
|
|
6723
|
+
transport: "child_process",
|
|
6724
|
+
lifecycle,
|
|
6725
|
+
input: {
|
|
6726
|
+
initial: "start",
|
|
6727
|
+
idle,
|
|
6728
|
+
busy
|
|
6729
|
+
},
|
|
6730
|
+
readiness: "spawned",
|
|
6731
|
+
turnBoundary: driver.lifecycle.kind === "per_turn" ? "process_exit" : "parsed_event",
|
|
6732
|
+
startPolicy: driver.lifecycle.kind === "per_turn" ? driver.lifecycle.start : "immediate",
|
|
6733
|
+
inFlightWake: driver.lifecycle.inFlightWake,
|
|
6734
|
+
busyDelivery: driver.busyDeliveryMode,
|
|
6735
|
+
postTurn: driver.terminateProcessOnTurnEnd ? "terminate_process" : driver.endStdinOnTurnEnd ? "close_stdin" : "keep_alive"
|
|
6736
|
+
};
|
|
6737
|
+
}
|
|
6738
|
+
var ChildProcessRuntimeSession = class {
|
|
6739
|
+
constructor(driver, ctx) {
|
|
6740
|
+
this.driver = driver;
|
|
6741
|
+
this.ctx = ctx;
|
|
6742
|
+
this.descriptor = descriptorFromDriver(driver);
|
|
6547
6743
|
}
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6744
|
+
descriptor;
|
|
6745
|
+
events = new EventEmitter2();
|
|
6746
|
+
process = null;
|
|
6747
|
+
started = false;
|
|
6748
|
+
stdoutBuffer = "";
|
|
6749
|
+
requestedStopReason;
|
|
6750
|
+
get pid() {
|
|
6751
|
+
return this.process?.pid;
|
|
6752
|
+
}
|
|
6753
|
+
get currentSessionId() {
|
|
6754
|
+
return this.driver.currentSessionId;
|
|
6755
|
+
}
|
|
6756
|
+
get exitCode() {
|
|
6757
|
+
return this.process?.exitCode ?? null;
|
|
6758
|
+
}
|
|
6759
|
+
get signalCode() {
|
|
6760
|
+
return this.process?.signalCode ?? null;
|
|
6761
|
+
}
|
|
6762
|
+
get closed() {
|
|
6763
|
+
return this.process ? this.process.exitCode != null || this.process.signalCode != null : false;
|
|
6764
|
+
}
|
|
6765
|
+
on(event, cb) {
|
|
6766
|
+
this.events.on(event, cb);
|
|
6767
|
+
}
|
|
6768
|
+
async start(input) {
|
|
6769
|
+
if (this.started) {
|
|
6770
|
+
return { ok: false, reason: "runtime_error", error: "runtime session already started" };
|
|
6771
|
+
}
|
|
6772
|
+
this.started = true;
|
|
6773
|
+
const launchCtx = {
|
|
6774
|
+
...this.ctx,
|
|
6775
|
+
prompt: input.text,
|
|
6776
|
+
config: {
|
|
6777
|
+
...this.ctx.config,
|
|
6778
|
+
sessionId: input.sessionId ?? this.ctx.config.sessionId
|
|
6779
|
+
}
|
|
6780
|
+
};
|
|
6781
|
+
const { process: process2 } = await this.driver.spawn(launchCtx);
|
|
6782
|
+
this.process = process2;
|
|
6783
|
+
this.attachProcess(process2);
|
|
6784
|
+
return { ok: true, acceptedAs: "prompt" };
|
|
6785
|
+
}
|
|
6786
|
+
send(input) {
|
|
6787
|
+
const proc = this.process;
|
|
6788
|
+
if (!proc || this.closed) return { ok: false, reason: "closed" };
|
|
6789
|
+
const encoded = this.driver.encodeStdinMessage(input.text, input.sessionId ?? null, { mode: input.mode });
|
|
6790
|
+
if (!encoded) return { ok: false, reason: "unsupported" };
|
|
6791
|
+
proc.stdin?.write(encoded + "\n");
|
|
6792
|
+
return { ok: true, acceptedAs: input.mode === "busy" ? "steer" : "prompt" };
|
|
6793
|
+
}
|
|
6794
|
+
async stop(opts) {
|
|
6795
|
+
const proc = this.process;
|
|
6796
|
+
if (!proc || this.closed) return;
|
|
6797
|
+
this.requestedStopReason = opts?.reason;
|
|
6798
|
+
proc.kill(opts?.signal ?? "SIGTERM");
|
|
6799
|
+
if (!opts?.forceAfterMs) return;
|
|
6800
|
+
setTimeout(() => {
|
|
6801
|
+
if (!this.closed) {
|
|
6802
|
+
try {
|
|
6803
|
+
proc.kill("SIGKILL");
|
|
6804
|
+
} catch {
|
|
6805
|
+
}
|
|
6806
|
+
}
|
|
6807
|
+
}, opts.forceAfterMs).unref?.();
|
|
6808
|
+
}
|
|
6809
|
+
attachProcess(process2) {
|
|
6810
|
+
process2.stdout?.on("data", (chunk) => {
|
|
6811
|
+
const chunkText = chunk.toString();
|
|
6812
|
+
this.events.emit("stdout", chunkText);
|
|
6813
|
+
this.stdoutBuffer += chunkText;
|
|
6814
|
+
const lines = this.stdoutBuffer.split("\n");
|
|
6815
|
+
this.stdoutBuffer = lines.pop() || "";
|
|
6816
|
+
for (const line of lines) {
|
|
6817
|
+
if (!line.trim()) continue;
|
|
6818
|
+
for (const event of this.driver.parseLine(line)) {
|
|
6819
|
+
this.events.emit("runtime_event", event);
|
|
6820
|
+
}
|
|
6821
|
+
}
|
|
6822
|
+
});
|
|
6823
|
+
process2.stderr?.on("data", (chunk) => {
|
|
6824
|
+
const text = chunk.toString().trim();
|
|
6825
|
+
if (text) this.events.emit("stderr", text);
|
|
6826
|
+
});
|
|
6827
|
+
process2.on("error", (err) => {
|
|
6828
|
+
this.events.emit("error", err);
|
|
6829
|
+
});
|
|
6830
|
+
process2.on("exit", (code, signal) => {
|
|
6831
|
+
this.events.emit("exit", {
|
|
6832
|
+
code,
|
|
6833
|
+
signal,
|
|
6834
|
+
reason: this.requestedStopReason ? "requested" : "runtime_exit"
|
|
6835
|
+
});
|
|
6836
|
+
});
|
|
6837
|
+
process2.on("close", (code, signal) => {
|
|
6838
|
+
this.events.emit("close", {
|
|
6839
|
+
code,
|
|
6840
|
+
signal,
|
|
6841
|
+
reason: this.requestedStopReason ? "requested" : "runtime_exit"
|
|
6842
|
+
});
|
|
6843
|
+
});
|
|
6554
6844
|
}
|
|
6555
6845
|
};
|
|
6846
|
+
function createChildProcessRuntimeSession(driver, ctx) {
|
|
6847
|
+
return new ChildProcessRuntimeSession(driver, ctx);
|
|
6848
|
+
}
|
|
6556
6849
|
|
|
6557
6850
|
// src/drivers/index.ts
|
|
6558
6851
|
var driverFactories = {
|
|
@@ -6953,6 +7246,15 @@ var RUNNER_CREDENTIAL_MINT_MAX_ATTEMPTS = 3;
|
|
|
6953
7246
|
function assertNeverApmEffect(effect) {
|
|
6954
7247
|
throw new Error(`Unhandled APM gated steering effect: ${String(effect)}`);
|
|
6955
7248
|
}
|
|
7249
|
+
function requireImmediateRuntimeSendResult(result, context) {
|
|
7250
|
+
if (typeof result.then === "function") {
|
|
7251
|
+
throw new Error(`RuntimeSession.send returned async result in synchronous APM path: ${context}`);
|
|
7252
|
+
}
|
|
7253
|
+
return result;
|
|
7254
|
+
}
|
|
7255
|
+
function runtimeSendFailureOutcome(result) {
|
|
7256
|
+
return !result.ok && result.reason === "unsupported" ? "encode_failed" : "send_failed";
|
|
7257
|
+
}
|
|
6956
7258
|
var RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS = 250;
|
|
6957
7259
|
var WORKSPACE_TEXT_FILE_MAX_BYTES = 1048576;
|
|
6958
7260
|
var WORKSPACE_IMAGE_PREVIEW_MAX_BYTES = 5 * 1024 * 1024;
|
|
@@ -7900,7 +8202,7 @@ function buildRuntimeStallDiagnostic(ap, staleForMs, staleForMinutes) {
|
|
|
7900
8202
|
if (ap.lastActivityDetail) {
|
|
7901
8203
|
context.push(`after ${ap.lastActivityDetail}`);
|
|
7902
8204
|
}
|
|
7903
|
-
if (ap.
|
|
8205
|
+
if (ap.runtime.descriptor.busyDelivery === "gated") {
|
|
7904
8206
|
context.push(`phase=${ap.gatedSteering.phase}`);
|
|
7905
8207
|
}
|
|
7906
8208
|
if (ap.gatedSteering.outstandingToolUses > 0) {
|
|
@@ -7932,10 +8234,10 @@ function buildRuntimeStallDiagnostic(ap, staleForMs, staleForMinutes) {
|
|
|
7932
8234
|
sessionIdPresent: Boolean(ap.sessionId),
|
|
7933
8235
|
inboxCount: ap.inbox.length,
|
|
7934
8236
|
pendingNotificationCount: ap.notifications.pendingCount,
|
|
7935
|
-
processPidPresent: typeof ap.
|
|
8237
|
+
processPidPresent: typeof ap.runtime.pid === "number",
|
|
7936
8238
|
busyDeliveryMode: ap.driver.busyDeliveryMode,
|
|
7937
8239
|
supportsStdinNotification: ap.driver.supportsStdinNotification,
|
|
7938
|
-
gatedPhase: ap.
|
|
8240
|
+
gatedPhase: ap.runtime.descriptor.busyDelivery === "gated" ? ap.gatedSteering.phase : void 0,
|
|
7939
8241
|
outstandingToolUses: ap.gatedSteering.outstandingToolUses,
|
|
7940
8242
|
compacting: ap.gatedSteering.compacting,
|
|
7941
8243
|
recentStderrCount: ap.recentStderr.length,
|
|
@@ -8078,8 +8380,10 @@ var RUNTIME_TELEMETRY_RESERVED_ATTR_KEYS = /* @__PURE__ */ new Set([
|
|
|
8078
8380
|
"runtimeResultId",
|
|
8079
8381
|
"daemonVersion",
|
|
8080
8382
|
"daemon_version",
|
|
8383
|
+
"daemon_version_present",
|
|
8081
8384
|
"computerVersion",
|
|
8082
|
-
"computer_version"
|
|
8385
|
+
"computer_version",
|
|
8386
|
+
"computer_version_present"
|
|
8083
8387
|
]);
|
|
8084
8388
|
function sanitizeRuntimeTelemetryPayloadAttrs(attrs) {
|
|
8085
8389
|
const sanitized = {};
|
|
@@ -8136,9 +8440,11 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8136
8440
|
stdinNotificationRetryMs;
|
|
8137
8441
|
cliTransportTraceDir = null;
|
|
8138
8442
|
deliveryTraceContexts = /* @__PURE__ */ new WeakMap();
|
|
8139
|
-
|
|
8443
|
+
runtimeExitTraceAttrs = /* @__PURE__ */ new WeakMap();
|
|
8140
8444
|
agentVisibleBoundaries = /* @__PURE__ */ new Map();
|
|
8141
8445
|
agentVisibleMessageIds = /* @__PURE__ */ new Map();
|
|
8446
|
+
daemonVersion;
|
|
8447
|
+
computerVersion;
|
|
8142
8448
|
constructor(chatBridgePath, sendToServer, daemonApiKey, opts) {
|
|
8143
8449
|
this.chatBridgePath = chatBridgePath;
|
|
8144
8450
|
this.slockCliPath = opts.slockCliPath ?? "";
|
|
@@ -8150,6 +8456,8 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8150
8456
|
this.driverResolver = opts.driverResolver || getDriver;
|
|
8151
8457
|
this.defaultAgentEnvVarsProvider = opts.defaultAgentEnvVarsProvider || null;
|
|
8152
8458
|
this.tracer = opts.tracer ?? noopTracer;
|
|
8459
|
+
this.daemonVersion = opts.daemonVersion?.trim() || null;
|
|
8460
|
+
this.computerVersion = opts.computerVersion?.trim() || null;
|
|
8153
8461
|
this.stdinNotificationRetryMs = Math.max(
|
|
8154
8462
|
0,
|
|
8155
8463
|
Math.floor(opts.stdinNotificationRetryMs ?? STDIN_NOTIFICATION_RETRY_DELAY_MS)
|
|
@@ -8390,7 +8698,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8390
8698
|
});
|
|
8391
8699
|
span.end(status);
|
|
8392
8700
|
}
|
|
8393
|
-
startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId) {
|
|
8701
|
+
startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false) {
|
|
8394
8702
|
return {
|
|
8395
8703
|
agentId,
|
|
8396
8704
|
launchId,
|
|
@@ -8399,6 +8707,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8399
8707
|
session_id_present: Boolean(config.sessionId),
|
|
8400
8708
|
launch_id_present: Boolean(launchId),
|
|
8401
8709
|
wake_message_present: Boolean(wakeMessage),
|
|
8710
|
+
wake_message_transient: Boolean(wakeMessage && wakeMessageTransient),
|
|
8402
8711
|
unread_channels_count: unreadSummary ? Object.keys(unreadSummary).length : 0,
|
|
8403
8712
|
resume_prompt_present: Boolean(resumePrompt),
|
|
8404
8713
|
queue_depth: this.agentStartQueue.length,
|
|
@@ -8410,6 +8719,9 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8410
8719
|
getDeliveryTraceContext(message) {
|
|
8411
8720
|
return this.deliveryTraceContexts.get(message) ?? {};
|
|
8412
8721
|
}
|
|
8722
|
+
isTransientDelivery(message) {
|
|
8723
|
+
return this.getDeliveryTraceContext(message).transient === true;
|
|
8724
|
+
}
|
|
8413
8725
|
deliveryTraceAttrs(agentId, message, attrs = {}) {
|
|
8414
8726
|
const context = this.getDeliveryTraceContext(message);
|
|
8415
8727
|
const deliveryCorrelationId = context.deliveryId ?? message.message_id;
|
|
@@ -8421,14 +8733,15 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8421
8733
|
sender_type: message.sender_type,
|
|
8422
8734
|
messageId: message.message_id,
|
|
8423
8735
|
message_id_present: Boolean(message.message_id),
|
|
8736
|
+
transient_delivery: context.transient === true,
|
|
8424
8737
|
...attrs
|
|
8425
8738
|
};
|
|
8426
8739
|
}
|
|
8427
|
-
async startAgent(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId) {
|
|
8428
|
-
this.recordDaemonTrace("daemon.agent.start.requested", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId));
|
|
8740
|
+
async startAgent(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false) {
|
|
8741
|
+
this.recordDaemonTrace("daemon.agent.start.requested", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient));
|
|
8429
8742
|
if (this.agents.has(agentId)) {
|
|
8430
8743
|
this.recordDaemonTrace("daemon.agent.start.ignored", {
|
|
8431
|
-
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId),
|
|
8744
|
+
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
|
|
8432
8745
|
reason: "already_running"
|
|
8433
8746
|
});
|
|
8434
8747
|
logger.info(`[Agent ${agentId}] Start ignored (already running)`);
|
|
@@ -8436,7 +8749,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8436
8749
|
}
|
|
8437
8750
|
if (this.agentsStarting.has(agentId)) {
|
|
8438
8751
|
this.recordDaemonTrace("daemon.agent.start.ignored", {
|
|
8439
|
-
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId),
|
|
8752
|
+
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
|
|
8440
8753
|
reason: "already_starting"
|
|
8441
8754
|
});
|
|
8442
8755
|
logger.info(`[Agent ${agentId}] Start ignored (startup in progress)`);
|
|
@@ -8444,7 +8757,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8444
8757
|
}
|
|
8445
8758
|
if (this.queuedAgentStarts.has(agentId)) {
|
|
8446
8759
|
this.recordDaemonTrace("daemon.agent.start.ignored", {
|
|
8447
|
-
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId),
|
|
8760
|
+
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
|
|
8448
8761
|
reason: "already_queued"
|
|
8449
8762
|
});
|
|
8450
8763
|
logger.info(`[Agent ${agentId}] Start ignored (startup already queued)`);
|
|
@@ -8455,6 +8768,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8455
8768
|
agentId,
|
|
8456
8769
|
config,
|
|
8457
8770
|
wakeMessage,
|
|
8771
|
+
wakeMessageTransient,
|
|
8458
8772
|
unreadSummary,
|
|
8459
8773
|
resumePrompt,
|
|
8460
8774
|
launchId,
|
|
@@ -8463,7 +8777,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8463
8777
|
};
|
|
8464
8778
|
this.agentStartQueue.push(item);
|
|
8465
8779
|
this.queuedAgentStarts.set(agentId, item);
|
|
8466
|
-
this.recordDaemonTrace("daemon.agent.start.queued", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId));
|
|
8780
|
+
this.recordDaemonTrace("daemon.agent.start.queued", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient));
|
|
8467
8781
|
logger.info(
|
|
8468
8782
|
`[Agent ${agentId}] Start queued (queue=${this.agentStartQueue.length}, active=${this.activeAgentStartCount}, max=${this.maxConcurrentAgentStarts}, interval=${this.agentStartIntervalMs}ms)`
|
|
8469
8783
|
);
|
|
@@ -8480,7 +8794,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8480
8794
|
const waitMs = shouldRateLimit ? Math.max(0, this.agentStartIntervalMs - elapsed) : 0;
|
|
8481
8795
|
if (waitMs > 0) {
|
|
8482
8796
|
this.recordDaemonTrace("daemon.agent.start.rate_limited", {
|
|
8483
|
-
...this.startQueueTraceAttrs(next.agentId, next.config, next.wakeMessage, next.unreadSummary, next.resumePrompt, next.launchId),
|
|
8797
|
+
...this.startQueueTraceAttrs(next.agentId, next.config, next.wakeMessage, next.unreadSummary, next.resumePrompt, next.launchId, next.wakeMessageTransient),
|
|
8484
8798
|
wait_ms: waitMs
|
|
8485
8799
|
});
|
|
8486
8800
|
this.agentStartPumpTimer = setTimeout(() => {
|
|
@@ -8493,7 +8807,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8493
8807
|
if (!item) return;
|
|
8494
8808
|
if (this.queuedAgentStarts.get(item.agentId) !== item) {
|
|
8495
8809
|
this.recordDaemonTrace("daemon.agent.start.skipped", {
|
|
8496
|
-
...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId),
|
|
8810
|
+
...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
|
|
8497
8811
|
reason: "stale_queue_item"
|
|
8498
8812
|
});
|
|
8499
8813
|
this.pumpAgentStartQueue();
|
|
@@ -8502,7 +8816,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8502
8816
|
this.queuedAgentStarts.delete(item.agentId);
|
|
8503
8817
|
if (this.agents.has(item.agentId) || this.agentsStarting.has(item.agentId)) {
|
|
8504
8818
|
this.recordDaemonTrace("daemon.agent.start.skipped", {
|
|
8505
|
-
...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId),
|
|
8819
|
+
...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
|
|
8506
8820
|
reason: "already_running_or_starting"
|
|
8507
8821
|
});
|
|
8508
8822
|
logger.info(`[Agent ${item.agentId}] Queued start skipped (already running or starting)`);
|
|
@@ -8516,14 +8830,15 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8516
8830
|
logger.info(
|
|
8517
8831
|
`[Agent ${item.agentId}] Dequeued start (remaining=${this.agentStartQueue.length}, active=${this.activeAgentStartCount})`
|
|
8518
8832
|
);
|
|
8519
|
-
this.recordDaemonTrace("daemon.agent.start.dequeued", this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId));
|
|
8833
|
+
this.recordDaemonTrace("daemon.agent.start.dequeued", this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient));
|
|
8520
8834
|
this.startAgentNow(
|
|
8521
8835
|
item.agentId,
|
|
8522
8836
|
item.config,
|
|
8523
8837
|
item.wakeMessage,
|
|
8524
8838
|
item.unreadSummary,
|
|
8525
8839
|
item.resumePrompt,
|
|
8526
|
-
item.launchId
|
|
8840
|
+
item.launchId,
|
|
8841
|
+
item.wakeMessageTransient ?? false
|
|
8527
8842
|
).then(() => {
|
|
8528
8843
|
this.releaseAgentStartSlot(item.agentId, "spawn attempted");
|
|
8529
8844
|
item.resolve();
|
|
@@ -8558,7 +8873,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8558
8873
|
this.agentStartPumpTimer = null;
|
|
8559
8874
|
}
|
|
8560
8875
|
this.recordDaemonTrace("daemon.agent.start.cancelled", {
|
|
8561
|
-
...this.startQueueTraceAttrs(agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId),
|
|
8876
|
+
...this.startQueueTraceAttrs(agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
|
|
8562
8877
|
reason
|
|
8563
8878
|
}, "cancelled");
|
|
8564
8879
|
logger.info(`[Agent ${agentId}] Queued start cancelled (${reason})`);
|
|
@@ -8569,7 +8884,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8569
8884
|
for (const item of this.agentStartQueue) {
|
|
8570
8885
|
if (this.queuedAgentStarts.get(item.agentId) === item) {
|
|
8571
8886
|
this.recordDaemonTrace("daemon.agent.start.cancelled", {
|
|
8572
|
-
...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId),
|
|
8887
|
+
...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
|
|
8573
8888
|
reason
|
|
8574
8889
|
}, "cancelled");
|
|
8575
8890
|
logger.info(`[Agent ${item.agentId}] Queued start cancelled (${reason})`);
|
|
@@ -8584,10 +8899,10 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8584
8899
|
this.agentStartPumpTimer = null;
|
|
8585
8900
|
}
|
|
8586
8901
|
}
|
|
8587
|
-
async startAgentNow(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId) {
|
|
8902
|
+
async startAgentNow(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false) {
|
|
8588
8903
|
if (this.agents.has(agentId)) {
|
|
8589
8904
|
this.recordDaemonTrace("daemon.agent.spawn.skipped", {
|
|
8590
|
-
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId),
|
|
8905
|
+
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
|
|
8591
8906
|
reason: "already_running"
|
|
8592
8907
|
});
|
|
8593
8908
|
logger.info(`[Agent ${agentId}] Start ignored (already running)`);
|
|
@@ -8595,14 +8910,15 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8595
8910
|
}
|
|
8596
8911
|
if (this.agentsStarting.has(agentId)) {
|
|
8597
8912
|
this.recordDaemonTrace("daemon.agent.spawn.skipped", {
|
|
8598
|
-
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId),
|
|
8913
|
+
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
|
|
8599
8914
|
reason: "already_starting"
|
|
8600
8915
|
});
|
|
8601
8916
|
logger.info(`[Agent ${agentId}] Start ignored (startup in progress)`);
|
|
8602
8917
|
return;
|
|
8603
8918
|
}
|
|
8604
8919
|
this.agentsStarting.add(agentId);
|
|
8605
|
-
this.recordDaemonTrace("daemon.agent.spawn.started", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId));
|
|
8920
|
+
this.recordDaemonTrace("daemon.agent.spawn.started", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient));
|
|
8921
|
+
let agentProcess = null;
|
|
8606
8922
|
try {
|
|
8607
8923
|
const driver = this.driverResolver(config.runtime || "claude");
|
|
8608
8924
|
const legacyWakeRuntimeProfile = wakeMessage ? runtimeProfileNotificationFromMessage(wakeMessage) : null;
|
|
@@ -8665,15 +8981,23 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8665
8981
|
prompt += getBusyDeliveryNote(driver);
|
|
8666
8982
|
promptSource = "resume_prompt";
|
|
8667
8983
|
} else if (wakeMessage) {
|
|
8668
|
-
const
|
|
8669
|
-
|
|
8984
|
+
const transientWakeMessage = wakeMessageTransient === true;
|
|
8985
|
+
const runtimeProfileControlPrompt = transientWakeMessage ? null : formatRuntimeProfileControlPrompt([wakeMessage]);
|
|
8986
|
+
if (transientWakeMessage) {
|
|
8987
|
+
prompt = `System notice received:
|
|
8988
|
+
|
|
8989
|
+
${formatIncomingMessage(wakeMessage, driver)}
|
|
8990
|
+
|
|
8991
|
+
Respond as appropriate. Complete all your work before stopping.
|
|
8992
|
+
${RESPONSE_TARGET_HINT}`;
|
|
8993
|
+
} else if (runtimeProfileControlPrompt) {
|
|
8670
8994
|
prompt = runtimeProfileControlPrompt;
|
|
8671
8995
|
} else {
|
|
8672
8996
|
wakeMessageDeliveredAsInboxUpdate = true;
|
|
8673
8997
|
prompt = this.formatInboxUpdateRuntimeInput([wakeMessage, ...startingInboxMessages], driver);
|
|
8674
8998
|
}
|
|
8675
|
-
promptSource = runtimeProfileControlPrompt ? "runtime_profile_control_message" : "wake_inbox_update";
|
|
8676
|
-
if (!runtimeProfileControlPrompt && unreadSummary && Object.keys(unreadSummary).length > 0) {
|
|
8999
|
+
promptSource = transientWakeMessage ? "transient_wake_message" : runtimeProfileControlPrompt ? "runtime_profile_control_message" : "wake_inbox_update";
|
|
9000
|
+
if (!transientWakeMessage && !runtimeProfileControlPrompt && unreadSummary && Object.keys(unreadSummary).length > 0) {
|
|
8677
9001
|
const otherUnread = Object.entries(unreadSummary);
|
|
8678
9002
|
if (otherUnread.length > 0) {
|
|
8679
9003
|
prompt += `
|
|
@@ -8730,7 +9054,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8730
9054
|
this.sendAgentStatus(agentId, "active", launchId || null);
|
|
8731
9055
|
this.broadcastActivity(agentId, "online", "Process idle");
|
|
8732
9056
|
this.recordDaemonTrace("daemon.agent.spawn.deferred", {
|
|
8733
|
-
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId),
|
|
9057
|
+
...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
|
|
8734
9058
|
pending_messages_count: pendingMessages.length,
|
|
8735
9059
|
reason: "defer_until_concrete_message"
|
|
8736
9060
|
});
|
|
@@ -8740,7 +9064,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8740
9064
|
}
|
|
8741
9065
|
return;
|
|
8742
9066
|
}
|
|
8743
|
-
const
|
|
9067
|
+
const runtimeContext = {
|
|
8744
9068
|
agentId,
|
|
8745
9069
|
config: effectiveConfig,
|
|
8746
9070
|
standingPrompt,
|
|
@@ -8752,15 +9076,10 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8752
9076
|
launchId: launchId || null,
|
|
8753
9077
|
agentCredentialProxyInboxCoordinator: this.createAgentProxyInboxCoordinator(agentId),
|
|
8754
9078
|
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,
|
|
9079
|
+
};
|
|
9080
|
+
const runtime = driver.createSession?.(runtimeContext) ?? createChildProcessRuntimeSession(driver, runtimeContext);
|
|
9081
|
+
agentProcess = {
|
|
9082
|
+
runtime,
|
|
8764
9083
|
driver,
|
|
8765
9084
|
inbox: wakeMessageDeliveredAsInboxUpdate && wakeMessage ? [wakeMessage, ...startingInboxMessages] : startingInboxMessages,
|
|
8766
9085
|
config: runtimeConfig,
|
|
@@ -8807,30 +9126,20 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8807
9126
|
}
|
|
8808
9127
|
if (wakeMessageDeliveredAsInboxUpdate) {
|
|
8809
9128
|
this.recordInboxUpdateProjection(agentId, agentProcess, agentProcess.inbox, "spawn_wake_inbox_update", "wake", prompt);
|
|
8810
|
-
} else if (wakeMessage) {
|
|
9129
|
+
} else if (wakeMessage && !wakeMessageTransient) {
|
|
8811
9130
|
this.consumeVisibleMessages(agentId, { messages: [wakeMessage], source: "spawn_wake_message" });
|
|
8812
9131
|
this.ackInjectedRuntimeProfileMessages(agentId, [wakeMessage], agentProcess.launchId);
|
|
8813
9132
|
}
|
|
8814
|
-
|
|
8815
|
-
proc.stdout?.on("data", (chunk) => {
|
|
8816
|
-
const chunkText = chunk.toString();
|
|
9133
|
+
runtime.on("stdout", (chunkText) => {
|
|
8817
9134
|
const current = this.agents.get(agentId);
|
|
8818
9135
|
if (current) {
|
|
8819
9136
|
current.recentStdout = pushRecentStdout(current.recentStdout, chunkText);
|
|
8820
9137
|
}
|
|
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
9138
|
});
|
|
8832
|
-
|
|
8833
|
-
|
|
9139
|
+
runtime.on("runtime_event", (event) => {
|
|
9140
|
+
this.handleParsedEvent(agentId, event, driver);
|
|
9141
|
+
});
|
|
9142
|
+
runtime.on("stderr", (text) => {
|
|
8834
9143
|
if (!text) return;
|
|
8835
9144
|
const current = this.agents.get(agentId);
|
|
8836
9145
|
if (driver.id === "codex" && isCodexProviderReconnectLog(text)) {
|
|
@@ -8855,7 +9164,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8855
9164
|
}
|
|
8856
9165
|
logger.error(`[Agent ${agentId} stderr]: ${text}`);
|
|
8857
9166
|
});
|
|
8858
|
-
|
|
9167
|
+
runtime.on("error", (err) => {
|
|
8859
9168
|
const current = this.agents.get(agentId);
|
|
8860
9169
|
if (current) {
|
|
8861
9170
|
current.spawnError = err.message;
|
|
@@ -8870,9 +9179,9 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8870
9179
|
}, "error");
|
|
8871
9180
|
logger.error(`[Agent ${agentId}] Process error: ${err.message}`);
|
|
8872
9181
|
});
|
|
8873
|
-
|
|
9182
|
+
runtime.on("exit", ({ code, signal }) => {
|
|
8874
9183
|
const current = this.agents.get(agentId);
|
|
8875
|
-
if (current && current.
|
|
9184
|
+
if (current && current.runtime === runtime) {
|
|
8876
9185
|
current.exitCode = code;
|
|
8877
9186
|
current.exitSignal = signal;
|
|
8878
9187
|
}
|
|
@@ -8887,14 +9196,14 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8887
9196
|
runtime_trace_active: Boolean(current?.runtimeTraceSpan),
|
|
8888
9197
|
inbox_count: current?.inbox.length ?? 0,
|
|
8889
9198
|
pending_notification_count: current?.notifications.pendingCount ?? 0,
|
|
8890
|
-
...this.
|
|
9199
|
+
...this.runtimeExitTraceAttrs.get(runtime)
|
|
8891
9200
|
});
|
|
8892
9201
|
logger.info(`[Agent ${agentId}] Process exited with code ${code}${signal ? ` (signal ${signal})` : ""}`);
|
|
8893
9202
|
});
|
|
8894
|
-
|
|
9203
|
+
runtime.on("close", ({ code, signal }) => {
|
|
8895
9204
|
if (this.agents.has(agentId)) {
|
|
8896
9205
|
const ap = this.agents.get(agentId);
|
|
8897
|
-
if (ap.
|
|
9206
|
+
if (ap.runtime !== runtime) return;
|
|
8898
9207
|
ap.notifications.clearTimer();
|
|
8899
9208
|
if (ap.pendingTrajectory?.timer) {
|
|
8900
9209
|
clearTimeout(ap.pendingTrajectory.timer);
|
|
@@ -9035,14 +9344,54 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9035
9344
|
}
|
|
9036
9345
|
}
|
|
9037
9346
|
});
|
|
9347
|
+
const startResult = await runtime.start({ text: prompt, sessionId: effectiveConfig.sessionId || null });
|
|
9348
|
+
if (!startResult.ok) {
|
|
9349
|
+
throw new Error(`Runtime session failed to start: ${startResult.reason}${startResult.error ? ` (${startResult.error})` : ""}`);
|
|
9350
|
+
}
|
|
9351
|
+
this.recordDaemonTrace("daemon.agent.spawn.created", {
|
|
9352
|
+
...this.startQueueTraceAttrs(agentId, effectiveConfig, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
|
|
9353
|
+
detached: false,
|
|
9354
|
+
new_session: false,
|
|
9355
|
+
process_pid_present: typeof runtime.pid === "number"
|
|
9356
|
+
});
|
|
9038
9357
|
this.sendAgentStatus(agentId, "active", launchId || null);
|
|
9039
9358
|
this.broadcastActivity(agentId, "working", "Starting\u2026");
|
|
9040
9359
|
this.startRuntimeStartupTimeout(agentId, agentProcess);
|
|
9041
9360
|
} catch (err) {
|
|
9042
9361
|
this.agentsStarting.delete(agentId);
|
|
9362
|
+
this.cleanupFailedRuntimeStart(agentId, agentProcess, err);
|
|
9043
9363
|
throw err;
|
|
9044
9364
|
}
|
|
9045
9365
|
}
|
|
9366
|
+
cleanupFailedRuntimeStart(agentId, ap, err) {
|
|
9367
|
+
if (!ap) return;
|
|
9368
|
+
if (this.agents.get(agentId) !== ap) return;
|
|
9369
|
+
ap.notifications.clearTimer();
|
|
9370
|
+
if (ap.pendingTrajectory?.timer) {
|
|
9371
|
+
clearTimeout(ap.pendingTrajectory.timer);
|
|
9372
|
+
ap.pendingTrajectory.timer = null;
|
|
9373
|
+
}
|
|
9374
|
+
if (ap.activityHeartbeat) {
|
|
9375
|
+
clearInterval(ap.activityHeartbeat);
|
|
9376
|
+
ap.activityHeartbeat = null;
|
|
9377
|
+
}
|
|
9378
|
+
if (ap.compactionWatchdog) {
|
|
9379
|
+
clearTimeout(ap.compactionWatchdog);
|
|
9380
|
+
ap.compactionWatchdog = null;
|
|
9381
|
+
}
|
|
9382
|
+
this.clearRuntimeStartupTimeout(ap);
|
|
9383
|
+
this.clearStalledRecoverySigtermWatchdog(ap);
|
|
9384
|
+
this.endRuntimeTrace(ap, "error", {
|
|
9385
|
+
outcome: "runtime-start-failed",
|
|
9386
|
+
failure_detail: err instanceof Error ? err.message : String(err),
|
|
9387
|
+
...runtimeTraceCounterAttrs(ap),
|
|
9388
|
+
...this.finalizeRuntimeProfileTurnControl(agentId, ap, "runtime_error")
|
|
9389
|
+
});
|
|
9390
|
+
cleanupAgentCredentialProxy(agentId, ap.launchId);
|
|
9391
|
+
this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
|
|
9392
|
+
this.agents.delete(agentId);
|
|
9393
|
+
this.idleAgentConfigs.delete(agentId);
|
|
9394
|
+
}
|
|
9046
9395
|
async buildSpawnConfig(agentId, config) {
|
|
9047
9396
|
const baseConfig = config.serverUrl === this.serverUrl ? config : { ...config, serverUrl: this.serverUrl };
|
|
9048
9397
|
const runnerConfig = await this.ensureManagedRunnerCredential(agentId, baseConfig);
|
|
@@ -9211,7 +9560,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9211
9560
|
ap.inbox.push(message);
|
|
9212
9561
|
if (ap.driver.supportsStdinNotification && ap.sessionId) {
|
|
9213
9562
|
ap.notifications.add();
|
|
9214
|
-
if (ap.
|
|
9563
|
+
if (ap.runtime.descriptor.busyDelivery === "gated") {
|
|
9215
9564
|
this.recordGatedSteeringEvent(agentId, ap, "buffer", {
|
|
9216
9565
|
reason: "runtime_profile",
|
|
9217
9566
|
kind,
|
|
@@ -9278,12 +9627,16 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9278
9627
|
cleanupAgentCredentialProxy(agentId, ap.launchId);
|
|
9279
9628
|
this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
|
|
9280
9629
|
this.agents.delete(agentId);
|
|
9281
|
-
this.
|
|
9630
|
+
this.runtimeExitTraceAttrs.set(ap.runtime, {
|
|
9282
9631
|
stop_source: silent ? "daemon_internal" : "explicit_request",
|
|
9283
9632
|
stop_wait_requested: wait,
|
|
9284
9633
|
stop_silent: silent
|
|
9285
9634
|
});
|
|
9286
|
-
ap.
|
|
9635
|
+
await ap.runtime.stop({
|
|
9636
|
+
signal: "SIGTERM",
|
|
9637
|
+
forceAfterMs: wait ? 5e3 : void 0,
|
|
9638
|
+
reason: silent ? "daemon_internal" : "explicit_request"
|
|
9639
|
+
});
|
|
9287
9640
|
if (!silent) {
|
|
9288
9641
|
this.sendRuntimeProfileReportFor(agentId, ap.config, ap.sessionId, ap.launchId);
|
|
9289
9642
|
this.sendAgentStatus(agentId, "inactive", ap.launchId);
|
|
@@ -9292,22 +9645,18 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9292
9645
|
}
|
|
9293
9646
|
if (wait) {
|
|
9294
9647
|
await new Promise((resolve) => {
|
|
9295
|
-
const
|
|
9648
|
+
const timeoutTimer = setTimeout(() => {
|
|
9296
9649
|
if (!silent) {
|
|
9297
9650
|
logger.warn(`[Agent ${agentId}] Stop timed out; force killing`);
|
|
9298
9651
|
}
|
|
9299
|
-
try {
|
|
9300
|
-
ap.process.kill("SIGKILL");
|
|
9301
|
-
} catch {
|
|
9302
|
-
}
|
|
9303
9652
|
resolve();
|
|
9304
9653
|
}, 5e3);
|
|
9305
|
-
ap.
|
|
9306
|
-
clearTimeout(
|
|
9654
|
+
ap.runtime.on("exit", () => {
|
|
9655
|
+
clearTimeout(timeoutTimer);
|
|
9307
9656
|
resolve();
|
|
9308
9657
|
});
|
|
9309
|
-
if (ap.
|
|
9310
|
-
clearTimeout(
|
|
9658
|
+
if (ap.runtime.closed) {
|
|
9659
|
+
clearTimeout(timeoutTimer);
|
|
9311
9660
|
resolve();
|
|
9312
9661
|
}
|
|
9313
9662
|
});
|
|
@@ -9317,9 +9666,24 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9317
9666
|
if (traceContext.deliveryId) {
|
|
9318
9667
|
this.deliveryTraceContexts.set(message, traceContext);
|
|
9319
9668
|
}
|
|
9669
|
+
if (traceContext.transient) {
|
|
9670
|
+
this.deliveryTraceContexts.set(message, traceContext);
|
|
9671
|
+
}
|
|
9672
|
+
const transientDelivery = this.isTransientDelivery(message);
|
|
9320
9673
|
const ap = this.agents.get(agentId);
|
|
9321
9674
|
if (!ap) {
|
|
9322
9675
|
if (this.agentsStarting.has(agentId) || this.queuedAgentStarts.has(agentId)) {
|
|
9676
|
+
if (transientDelivery) {
|
|
9677
|
+
const queuedStart2 = this.queuedAgentStarts.get(agentId);
|
|
9678
|
+
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
9679
|
+
outcome: "transient_dropped_during_start",
|
|
9680
|
+
accepted: true,
|
|
9681
|
+
process_present: false,
|
|
9682
|
+
startup_pending: true,
|
|
9683
|
+
launchId: queuedStart2?.launchId
|
|
9684
|
+
}));
|
|
9685
|
+
return true;
|
|
9686
|
+
}
|
|
9323
9687
|
const queuedStart = this.queuedAgentStarts.get(agentId);
|
|
9324
9688
|
const pending = this.startingInboxes.get(agentId) || [];
|
|
9325
9689
|
pending.push(message);
|
|
@@ -9337,7 +9701,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9337
9701
|
const cached = this.idleAgentConfigs.get(agentId);
|
|
9338
9702
|
if (cached) {
|
|
9339
9703
|
const driver = this.driverResolver(cached.config.runtime || "claude");
|
|
9340
|
-
if (this.shouldDeferWakeMessage(agentId, driver, message)) {
|
|
9704
|
+
if (!transientDelivery && this.shouldDeferWakeMessage(agentId, driver, message)) {
|
|
9341
9705
|
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
9342
9706
|
outcome: "deferred_wake_message",
|
|
9343
9707
|
accepted: true,
|
|
@@ -9360,7 +9724,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9360
9724
|
session_id_present: Boolean(cached.sessionId),
|
|
9361
9725
|
launchId: cached.launchId || void 0
|
|
9362
9726
|
}));
|
|
9363
|
-
return this.startAgent(agentId, cached.config, message, void 0, void 0, cached.launchId || void 0).then(() => true, (err) => {
|
|
9727
|
+
return this.startAgent(agentId, cached.config, message, void 0, void 0, cached.launchId || void 0, transientDelivery).then(() => true, (err) => {
|
|
9364
9728
|
logger.error(`[Agent ${agentId}] Failed to auto-restart`, err);
|
|
9365
9729
|
if (this.reportRunnerCredentialMintFailure(agentId, err, cached.launchId, "idle_auto_restart")) {
|
|
9366
9730
|
return false;
|
|
@@ -9370,6 +9734,15 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9370
9734
|
});
|
|
9371
9735
|
}
|
|
9372
9736
|
logger.warn(`[Agent ${agentId}] Delivery received but no running process or cached idle config exists`);
|
|
9737
|
+
if (transientDelivery) {
|
|
9738
|
+
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
9739
|
+
outcome: "transient_dropped_no_process",
|
|
9740
|
+
accepted: true,
|
|
9741
|
+
process_present: false,
|
|
9742
|
+
cached_idle_config_present: false
|
|
9743
|
+
}));
|
|
9744
|
+
return true;
|
|
9745
|
+
}
|
|
9373
9746
|
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
9374
9747
|
outcome: "rejected_no_process",
|
|
9375
9748
|
accepted: false,
|
|
@@ -9380,7 +9753,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9380
9753
|
this.broadcastActivity(agentId, "offline", "Process unavailable; restart required");
|
|
9381
9754
|
return false;
|
|
9382
9755
|
}
|
|
9383
|
-
if (this.shouldDeferWakeMessage(agentId, ap.driver, message)) {
|
|
9756
|
+
if (!transientDelivery && this.shouldDeferWakeMessage(agentId, ap.driver, message)) {
|
|
9384
9757
|
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
9385
9758
|
outcome: "deferred_wake_message",
|
|
9386
9759
|
accepted: true,
|
|
@@ -9395,6 +9768,19 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9395
9768
|
}
|
|
9396
9769
|
const stickyTerminalFailure = classifyStickyTerminalFailure(ap);
|
|
9397
9770
|
if (stickyTerminalFailure) {
|
|
9771
|
+
if (transientDelivery) {
|
|
9772
|
+
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
9773
|
+
outcome: "transient_dropped_terminal_runtime_error",
|
|
9774
|
+
accepted: true,
|
|
9775
|
+
process_present: true,
|
|
9776
|
+
runtime: ap.config.runtime,
|
|
9777
|
+
session_id_present: Boolean(ap.sessionId),
|
|
9778
|
+
launchId: ap.launchId || void 0,
|
|
9779
|
+
is_idle: ap.isIdle,
|
|
9780
|
+
inbox_count: ap.inbox.length
|
|
9781
|
+
}));
|
|
9782
|
+
return true;
|
|
9783
|
+
}
|
|
9398
9784
|
ap.inbox.push(message);
|
|
9399
9785
|
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
9400
9786
|
outcome: "queued_terminal_runtime_error",
|
|
@@ -9411,6 +9797,30 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9411
9797
|
return true;
|
|
9412
9798
|
}
|
|
9413
9799
|
if (ap.isIdle && ap.driver.supportsStdinNotification && ap.sessionId) {
|
|
9800
|
+
if (transientDelivery) {
|
|
9801
|
+
this.commitApmIdleState(agentId, ap, false);
|
|
9802
|
+
this.startRuntimeTrace(agentId, ap, "stdin-idle-delivery", [message]);
|
|
9803
|
+
this.broadcastActivity(agentId, "working", "Message received");
|
|
9804
|
+
const stdinAccepted2 = this.deliverMessagesViaStdin(
|
|
9805
|
+
agentId,
|
|
9806
|
+
ap,
|
|
9807
|
+
[message],
|
|
9808
|
+
"idle",
|
|
9809
|
+
{ transient: true }
|
|
9810
|
+
);
|
|
9811
|
+
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
9812
|
+
outcome: "stdin_idle_transient_delivery",
|
|
9813
|
+
accepted: true,
|
|
9814
|
+
process_present: true,
|
|
9815
|
+
runtime: ap.config.runtime,
|
|
9816
|
+
session_id_present: true,
|
|
9817
|
+
launchId: ap.launchId || void 0,
|
|
9818
|
+
stdin_delivery_accepted: stdinAccepted2,
|
|
9819
|
+
delivered_messages_count: 1,
|
|
9820
|
+
inbox_count: ap.inbox.length
|
|
9821
|
+
}));
|
|
9822
|
+
return true;
|
|
9823
|
+
}
|
|
9414
9824
|
ap.inbox.push(message);
|
|
9415
9825
|
const nextMessages = [...ap.inbox];
|
|
9416
9826
|
this.commitApmIdleState(agentId, ap, false);
|
|
@@ -9435,6 +9845,19 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9435
9845
|
}));
|
|
9436
9846
|
return true;
|
|
9437
9847
|
}
|
|
9848
|
+
if (transientDelivery) {
|
|
9849
|
+
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
9850
|
+
outcome: "transient_dropped_busy",
|
|
9851
|
+
accepted: true,
|
|
9852
|
+
process_present: true,
|
|
9853
|
+
runtime: ap.config.runtime,
|
|
9854
|
+
session_id_present: Boolean(ap.sessionId),
|
|
9855
|
+
launchId: ap.launchId || void 0,
|
|
9856
|
+
is_idle: ap.isIdle,
|
|
9857
|
+
inbox_count: ap.inbox.length
|
|
9858
|
+
}));
|
|
9859
|
+
return true;
|
|
9860
|
+
}
|
|
9438
9861
|
ap.inbox.push(message);
|
|
9439
9862
|
if (this.recoverStaleProcessForQueuedMessageIfNeeded(agentId, ap)) {
|
|
9440
9863
|
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
@@ -9475,7 +9898,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9475
9898
|
if (ap.gatedSteering.compacting) {
|
|
9476
9899
|
ap.notifications.add();
|
|
9477
9900
|
ap.notifications.clearTimer();
|
|
9478
|
-
if (ap.
|
|
9901
|
+
if (ap.runtime.descriptor.busyDelivery === "gated") {
|
|
9479
9902
|
this.recordGatedSteeringEvent(agentId, ap, "buffer", {
|
|
9480
9903
|
reason: "compaction_boundary",
|
|
9481
9904
|
pendingMessages: ap.inbox.length
|
|
@@ -9500,7 +9923,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9500
9923
|
}));
|
|
9501
9924
|
return true;
|
|
9502
9925
|
}
|
|
9503
|
-
if (ap.
|
|
9926
|
+
if (ap.runtime.descriptor.busyDelivery === "gated") {
|
|
9504
9927
|
ap.notifications.add();
|
|
9505
9928
|
if (!ap.notifications.hasTimer) {
|
|
9506
9929
|
this.scheduleStdinNotification(agentId, ap, STDIN_NOTIFICATION_INITIAL_DELAY_MS);
|
|
@@ -9683,7 +10106,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9683
10106
|
traceparent: formatTraceparent(span.context)
|
|
9684
10107
|
};
|
|
9685
10108
|
const ap = this.agents.get(agentId);
|
|
9686
|
-
if (ap && !(ap.sessionId && ap.driver.supportsStdinNotification && ap.isIdle) && !(ap.sessionId && ap.
|
|
10109
|
+
if (ap && !(ap.sessionId && ap.driver.supportsStdinNotification && ap.isIdle) && !(ap.sessionId && ap.runtime.descriptor.busyDelivery === "direct")) {
|
|
9687
10110
|
this.enqueueRuntimeProfileNotification(agentId, ap, message, kind, key);
|
|
9688
10111
|
span.end("ok", {
|
|
9689
10112
|
attrs: {
|
|
@@ -9713,7 +10136,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9713
10136
|
});
|
|
9714
10137
|
return written;
|
|
9715
10138
|
}
|
|
9716
|
-
if (ap?.sessionId && ap.
|
|
10139
|
+
if (ap?.sessionId && ap.runtime.descriptor.busyDelivery === "direct") {
|
|
9717
10140
|
const written = this.deliverMessagesViaStdin(agentId, ap, [message], "busy");
|
|
9718
10141
|
span.end(written ? "ok" : "error", {
|
|
9719
10142
|
attrs: {
|
|
@@ -10136,23 +10559,23 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10136
10559
|
clearTimeout(ap.stalledRecoverySigtermTimer);
|
|
10137
10560
|
ap.stalledRecoverySigtermTimer = null;
|
|
10138
10561
|
}
|
|
10139
|
-
|
|
10140
|
-
this.
|
|
10141
|
-
...this.
|
|
10562
|
+
mergeRuntimeExitTraceAttrs(runtime, attrs) {
|
|
10563
|
+
this.runtimeExitTraceAttrs.set(runtime, {
|
|
10564
|
+
...this.runtimeExitTraceAttrs.get(runtime) ?? {},
|
|
10142
10565
|
...attrs
|
|
10143
10566
|
});
|
|
10144
10567
|
}
|
|
10145
10568
|
startStalledRecoverySigtermWatchdog(agentId, ap, runtimeLabel, queuedMessagesAtSignal, staleForMs) {
|
|
10146
10569
|
this.clearStalledRecoverySigtermWatchdog(ap);
|
|
10147
10570
|
const timeoutMs = stalledRecoverySigtermTimeoutMs();
|
|
10148
|
-
const
|
|
10571
|
+
const runtimeAtSignal = ap.runtime;
|
|
10149
10572
|
ap.stalledRecoverySigtermTimer = setTimeout(() => {
|
|
10150
10573
|
ap.stalledRecoverySigtermTimer = null;
|
|
10151
10574
|
const current = this.agents.get(agentId);
|
|
10152
|
-
if (!current || current !== ap || current.
|
|
10575
|
+
if (!current || current !== ap || current.runtime !== runtimeAtSignal || current.expectedTerminationReason !== "stalled_recovery") {
|
|
10153
10576
|
return;
|
|
10154
10577
|
}
|
|
10155
|
-
this.
|
|
10578
|
+
this.mergeRuntimeExitTraceAttrs(runtimeAtSignal, {
|
|
10156
10579
|
stalled_recovery_sigterm_timeout: true,
|
|
10157
10580
|
stalled_recovery_sigterm_timeout_ms: timeoutMs
|
|
10158
10581
|
});
|
|
@@ -10166,7 +10589,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10166
10589
|
queued_messages_at_signal: queuedMessagesAtSignal,
|
|
10167
10590
|
stale_age_ms_at_signal: staleForMs,
|
|
10168
10591
|
timeout_ms: timeoutMs,
|
|
10169
|
-
process_pid_present: typeof
|
|
10592
|
+
process_pid_present: typeof runtimeAtSignal.pid === "number",
|
|
10170
10593
|
session_id_present: Boolean(current.sessionId),
|
|
10171
10594
|
supports_stdin_notification: current.driver.supportsStdinNotification,
|
|
10172
10595
|
busy_delivery_mode: current.driver.busyDeliveryMode
|
|
@@ -10175,7 +10598,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10175
10598
|
`[Agent ${agentId}] Stalled ${runtimeLabel} runtime did not exit after SIGTERM within ${timeoutMs}ms; force killing`
|
|
10176
10599
|
);
|
|
10177
10600
|
try {
|
|
10178
|
-
|
|
10601
|
+
void runtimeAtSignal.stop({ signal: "SIGKILL", reason: "stalled_recovery_sigterm_timeout" });
|
|
10179
10602
|
} catch (err) {
|
|
10180
10603
|
const reason = err instanceof Error ? err.message : String(err);
|
|
10181
10604
|
this.recordDaemonTrace("daemon.agent.stalled_recovery.sigkill_failed", {
|
|
@@ -10361,7 +10784,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10361
10784
|
ap.runtimeProgress.noteRuntimeEvent(eventKind);
|
|
10362
10785
|
}
|
|
10363
10786
|
recordGatedSteeringEvent(agentId, ap, event, attrs = {}) {
|
|
10364
|
-
if (ap.
|
|
10787
|
+
if (ap.runtime.descriptor.busyDelivery !== "gated") return;
|
|
10365
10788
|
const reduction = reduceApmGatedRecentEvent(ap.gatedSteering, { event });
|
|
10366
10789
|
this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState);
|
|
10367
10790
|
this.recordRuntimeTraceEvent(agentId, ap, `runtime.gated_steering.${event}`, {
|
|
@@ -10396,7 +10819,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10396
10819
|
}
|
|
10397
10820
|
notifyGatedSteeringBoundary(agentId, ap, reason) {
|
|
10398
10821
|
const readiness = reduceApmGatedFlushReadiness(ap.gatedSteering, {
|
|
10399
|
-
isGated: ap.
|
|
10822
|
+
isGated: ap.runtime.descriptor.busyDelivery === "gated",
|
|
10400
10823
|
hasSession: Boolean(ap.sessionId),
|
|
10401
10824
|
inboxLength: ap.inbox.length,
|
|
10402
10825
|
reason
|
|
@@ -10446,7 +10869,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10446
10869
|
});
|
|
10447
10870
|
return true;
|
|
10448
10871
|
}
|
|
10449
|
-
if (ap.
|
|
10872
|
+
if (ap.runtime.descriptor.busyDelivery === "gated") {
|
|
10450
10873
|
const flushReduction = reduceApmGatedFlush(ap.gatedSteering, { reason: effect.reason });
|
|
10451
10874
|
this.commitGatedSteeringDecisionState(agentId, ap, flushReduction.nextState);
|
|
10452
10875
|
this.recordGatedSteeringEvent(agentId, ap, "flush", {
|
|
@@ -10548,12 +10971,12 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10548
10971
|
this.sendAgentStatus(agentId, "inactive", ap.launchId);
|
|
10549
10972
|
this.idleAgentConfigs.delete(agentId);
|
|
10550
10973
|
try {
|
|
10551
|
-
this.
|
|
10974
|
+
this.runtimeExitTraceAttrs.set(ap.runtime, {
|
|
10552
10975
|
stop_source: "startup_timeout",
|
|
10553
10976
|
expectedTerminationReason: "startup_timeout",
|
|
10554
10977
|
timeout_ms: timeoutMs
|
|
10555
10978
|
});
|
|
10556
|
-
ap.
|
|
10979
|
+
void ap.runtime.stop({ signal: "SIGTERM", reason: "startup_timeout" });
|
|
10557
10980
|
} catch (err) {
|
|
10558
10981
|
const reason = err instanceof Error ? err.message : String(err);
|
|
10559
10982
|
logger.warn(`[Agent ${agentId}] Failed to terminate startup-timed-out ${ap.driver.id} process: ${reason}`);
|
|
@@ -10639,13 +11062,13 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10639
11062
|
);
|
|
10640
11063
|
this.broadcastActivity(agentId, "working", `Restarting stalled ${runtimeLabel} runtime for queued message`);
|
|
10641
11064
|
try {
|
|
10642
|
-
this.
|
|
11065
|
+
this.runtimeExitTraceAttrs.set(ap.runtime, {
|
|
10643
11066
|
stop_source: "stalled_recovery",
|
|
10644
11067
|
expectedTerminationReason: "stalled_recovery",
|
|
10645
11068
|
queued_messages_count: ap.inbox.length
|
|
10646
11069
|
});
|
|
10647
11070
|
this.startStalledRecoverySigtermWatchdog(agentId, ap, runtimeLabel, ap.inbox.length, staleForMs);
|
|
10648
|
-
ap.
|
|
11071
|
+
void ap.runtime.stop({ signal: "SIGTERM", reason: "stalled_recovery" });
|
|
10649
11072
|
} catch (err) {
|
|
10650
11073
|
this.clearStalledRecoverySigtermWatchdog(ap);
|
|
10651
11074
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -10821,11 +11244,11 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10821
11244
|
if (ap.driver.terminateProcessOnTurnEnd) {
|
|
10822
11245
|
logger.info(`[Agent ${agentId}] Turn completed; terminating ${ap.driver.id} process`);
|
|
10823
11246
|
try {
|
|
10824
|
-
this.
|
|
11247
|
+
this.runtimeExitTraceAttrs.set(ap.runtime, {
|
|
10825
11248
|
stop_source: "turn_end",
|
|
10826
11249
|
expectedTerminationReason: "turn_end"
|
|
10827
11250
|
});
|
|
10828
|
-
ap.
|
|
11251
|
+
void ap.runtime.stop({ signal: "SIGTERM", reason: "turn_end" });
|
|
10829
11252
|
} catch (err) {
|
|
10830
11253
|
const reason = err instanceof Error ? err.message : String(err);
|
|
10831
11254
|
logger.warn(`[Agent ${agentId}] Failed to terminate ${ap.driver.id} after turn_end: ${reason}`);
|
|
@@ -10847,7 +11270,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10847
11270
|
if (runtimeErrorDiagnostics.spanAttrs.runtime_error_action_required === true) {
|
|
10848
11271
|
visibleErrorMessage = formatRuntimeLoginRequiredMessage(ap.driver.id);
|
|
10849
11272
|
}
|
|
10850
|
-
const shouldDisableToolBoundaryFlush = ap.
|
|
11273
|
+
const shouldDisableToolBoundaryFlush = ap.runtime.descriptor.busyDelivery === "gated" && this.isThinkingBlockMutationError(event.message);
|
|
10851
11274
|
const terminalFailure = classifyTerminalFailure(ap);
|
|
10852
11275
|
const reduction = reduceApmGatedError(ap.gatedSteering, {
|
|
10853
11276
|
disableToolBoundaryFlush: shouldDisableToolBoundaryFlush,
|
|
@@ -10878,11 +11301,11 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10878
11301
|
if (terminalFailure.actionRequired) {
|
|
10879
11302
|
logger.warn(`[Agent ${agentId}] ${ap.driver.id} auth requires user action; terminating runtime process`);
|
|
10880
11303
|
try {
|
|
10881
|
-
this.
|
|
11304
|
+
this.runtimeExitTraceAttrs.set(ap.runtime, {
|
|
10882
11305
|
stop_source: "runtime_auth_error",
|
|
10883
11306
|
runtime_error_class: "AuthError"
|
|
10884
11307
|
});
|
|
10885
|
-
ap.
|
|
11308
|
+
void ap.runtime.stop({ signal: "SIGTERM", reason: "runtime_auth_error" });
|
|
10886
11309
|
} catch (err) {
|
|
10887
11310
|
const reason = err instanceof Error ? err.message : String(err);
|
|
10888
11311
|
logger.warn(`[Agent ${agentId}] Failed to terminate ${ap.driver.id} after auth error: ${reason}`);
|
|
@@ -10907,8 +11330,10 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10907
11330
|
recordRuntimeTelemetry(agentId, ap, event) {
|
|
10908
11331
|
const sessionId = ap.driver.currentSessionId ?? event.sessionId;
|
|
10909
11332
|
const payloadAttrs = sanitizeRuntimeTelemetryPayloadAttrs(event.attrs);
|
|
11333
|
+
const versionAttrs = this.runtimeTelemetryVersionAttrs();
|
|
10910
11334
|
const telemetryAttrs = {
|
|
10911
11335
|
...payloadAttrs,
|
|
11336
|
+
...versionAttrs,
|
|
10912
11337
|
...event.source ? { source: event.source } : {},
|
|
10913
11338
|
...event.usageKind ? { usageKind: event.usageKind } : {},
|
|
10914
11339
|
...sessionId ? { sessionId } : {},
|
|
@@ -10926,6 +11351,24 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10926
11351
|
ap.runtimeTraceSpan?.addEvent(`runtime.telemetry.${event.name}`, telemetryAttrs);
|
|
10927
11352
|
this.recordDaemonTrace(`daemon.runtime.telemetry.${event.name}`, attrs);
|
|
10928
11353
|
}
|
|
11354
|
+
runtimeTelemetryVersionAttrs() {
|
|
11355
|
+
return {
|
|
11356
|
+
...this.daemonVersion ? {
|
|
11357
|
+
daemonVersion: this.daemonVersion,
|
|
11358
|
+
daemon_version: this.daemonVersion,
|
|
11359
|
+
daemon_version_present: true
|
|
11360
|
+
} : {
|
|
11361
|
+
daemon_version_present: false
|
|
11362
|
+
},
|
|
11363
|
+
...this.computerVersion ? {
|
|
11364
|
+
computerVersion: this.computerVersion,
|
|
11365
|
+
computer_version: this.computerVersion,
|
|
11366
|
+
computer_version_present: true
|
|
11367
|
+
} : {
|
|
11368
|
+
computer_version_present: false
|
|
11369
|
+
}
|
|
11370
|
+
};
|
|
11371
|
+
}
|
|
10929
11372
|
sendAgentStatus(agentId, status, launchId) {
|
|
10930
11373
|
this.sendToServer({ type: "agent:status", agentId, status, launchId: launchId || void 0 });
|
|
10931
11374
|
}
|
|
@@ -11009,9 +11452,11 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
|
|
|
11009
11452
|
...projectionAttrs
|
|
11010
11453
|
});
|
|
11011
11454
|
logger.info(`[Agent ${agentId}] Sending stdin inbox update: ${inboxRows.length} changed target(s), ${inboxCount} pending message(s)`);
|
|
11012
|
-
const
|
|
11013
|
-
|
|
11014
|
-
|
|
11455
|
+
const sendResult = requireImmediateRuntimeSendResult(
|
|
11456
|
+
ap.runtime.send({ mode: "busy", text: notification, sessionId: ap.sessionId }),
|
|
11457
|
+
"busy inbox notification"
|
|
11458
|
+
);
|
|
11459
|
+
if (sendResult.ok) {
|
|
11015
11460
|
this.recordDaemonTrace("daemon.agent.inbox_update.pushed", {
|
|
11016
11461
|
agentId,
|
|
11017
11462
|
runtime: ap.config.runtime,
|
|
@@ -11036,14 +11481,17 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
|
|
|
11036
11481
|
return true;
|
|
11037
11482
|
} else {
|
|
11038
11483
|
ap.notifications.add(count);
|
|
11039
|
-
const retryScheduled = ap.
|
|
11484
|
+
const retryScheduled = ap.runtime.descriptor.busyDelivery === "direct" ? this.scheduleStdinNotification(agentId, ap, this.stdinNotificationRetryMs) : false;
|
|
11485
|
+
const outcome = runtimeSendFailureOutcome(sendResult);
|
|
11040
11486
|
this.recordDaemonTrace("daemon.agent.stdin_notification", {
|
|
11041
11487
|
agentId,
|
|
11042
11488
|
runtime: ap.config.runtime,
|
|
11043
11489
|
model: ap.config.model,
|
|
11044
11490
|
launchId: ap.launchId || void 0,
|
|
11045
|
-
outcome
|
|
11491
|
+
outcome,
|
|
11046
11492
|
mode: "busy",
|
|
11493
|
+
failure_reason: sendResult.reason,
|
|
11494
|
+
failure_error: sendResult.error,
|
|
11047
11495
|
pending_notification_count: count,
|
|
11048
11496
|
retry_scheduled: retryScheduled,
|
|
11049
11497
|
notification_timer_present: ap.notifications.hasTimer,
|
|
@@ -11094,8 +11542,11 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
|
|
|
11094
11542
|
nativeStandingPrompt: Boolean(ap.driver.supportsNativeStandingPrompt)
|
|
11095
11543
|
});
|
|
11096
11544
|
this.recordRuntimeTraceEvent(agentId, ap, "runtime.input.prepared", inputTraceAttrs);
|
|
11097
|
-
const
|
|
11098
|
-
|
|
11545
|
+
const sendResult = requireImmediateRuntimeSendResult(
|
|
11546
|
+
ap.runtime.send({ mode, text: prompt, sessionId: ap.sessionId }),
|
|
11547
|
+
`${mode} inbox update`
|
|
11548
|
+
);
|
|
11549
|
+
if (!sendResult.ok) {
|
|
11099
11550
|
if (mode === "idle") {
|
|
11100
11551
|
this.commitApmIdleState(agentId, ap, true);
|
|
11101
11552
|
}
|
|
@@ -11117,7 +11568,9 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
|
|
|
11117
11568
|
...this.messagesTraceAttrs(messages),
|
|
11118
11569
|
...inputTraceAttrs,
|
|
11119
11570
|
...projectionAttrs,
|
|
11120
|
-
outcome:
|
|
11571
|
+
outcome: runtimeSendFailureOutcome(sendResult),
|
|
11572
|
+
failure_reason: sendResult.reason,
|
|
11573
|
+
failure_error: sendResult.error,
|
|
11121
11574
|
requeued_messages_count: 0,
|
|
11122
11575
|
cursors_advanced: "none"
|
|
11123
11576
|
}, "error");
|
|
@@ -11130,7 +11583,6 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
|
|
|
11130
11583
|
if (this.containsOrdinaryInboxMessage(messages)) {
|
|
11131
11584
|
ap.lastRuntimeError = null;
|
|
11132
11585
|
}
|
|
11133
|
-
ap.process.stdin?.write(encoded + "\n");
|
|
11134
11586
|
this.recordDaemonTrace("daemon.agent.stdin_delivery", {
|
|
11135
11587
|
agentId,
|
|
11136
11588
|
launchId: ap.launchId || void 0,
|
|
@@ -11153,7 +11605,7 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
|
|
|
11153
11605
|
return true;
|
|
11154
11606
|
}
|
|
11155
11607
|
/** Deliver a message to an agent via stdin, formatting it the same way as the MCP bridge */
|
|
11156
|
-
deliverMessagesViaStdin(agentId, ap, messages, mode) {
|
|
11608
|
+
deliverMessagesViaStdin(agentId, ap, messages, mode, options = {}) {
|
|
11157
11609
|
if (messages.length === 0) return true;
|
|
11158
11610
|
const runtimeProfileMigrationMessages = messages.filter((message) => runtimeProfileNotificationFromMessage(message)?.kind === "migration");
|
|
11159
11611
|
if (runtimeProfileMigrationMessages.length > 0) {
|
|
@@ -11191,8 +11643,10 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
|
|
|
11191
11643
|
pending_notification_count: ap.notifications.pendingCount,
|
|
11192
11644
|
busy_delivery_mode: ap.driver.busyDeliveryMode,
|
|
11193
11645
|
supports_stdin_notification: ap.driver.supportsStdinNotification,
|
|
11646
|
+
transient_delivery: options.transient === true,
|
|
11194
11647
|
...this.messagesTraceAttrs(messages)
|
|
11195
11648
|
};
|
|
11649
|
+
const traceSource = options.transient ? `stdin_${mode}_transient_delivery` : `stdin_${mode}_delivery`;
|
|
11196
11650
|
const prompt = formatRuntimeProfileControlPrompt(messages) ?? (messages.length === 1 ? `New message received:
|
|
11197
11651
|
|
|
11198
11652
|
${formatIncomingMessage(messages[0], ap.driver)}
|
|
@@ -11205,16 +11659,21 @@ ${messages.map((message) => formatIncomingMessage(message, ap.driver)).join("\n"
|
|
|
11205
11659
|
Respond as appropriate. Complete all your work before stopping.
|
|
11206
11660
|
${RESPONSE_TARGET_HINT}`);
|
|
11207
11661
|
const inputTraceAttrs = buildRuntimeInputTraceAttrs({
|
|
11208
|
-
source:
|
|
11662
|
+
source: traceSource,
|
|
11209
11663
|
prompt,
|
|
11210
11664
|
messages,
|
|
11211
11665
|
sessionIdPresent: Boolean(ap.sessionId),
|
|
11212
11666
|
nativeStandingPrompt: Boolean(ap.driver.supportsNativeStandingPrompt)
|
|
11213
11667
|
});
|
|
11214
11668
|
this.recordRuntimeTraceEvent(agentId, ap, "runtime.input.prepared", inputTraceAttrs);
|
|
11215
|
-
const
|
|
11216
|
-
|
|
11217
|
-
|
|
11669
|
+
const sendResult = requireImmediateRuntimeSendResult(
|
|
11670
|
+
ap.runtime.send({ mode, text: prompt, sessionId: ap.sessionId }),
|
|
11671
|
+
`${mode} message delivery`
|
|
11672
|
+
);
|
|
11673
|
+
if (!sendResult.ok) {
|
|
11674
|
+
if (!options.transient) {
|
|
11675
|
+
ap.inbox.unshift(...messages);
|
|
11676
|
+
}
|
|
11218
11677
|
if (mode === "idle") {
|
|
11219
11678
|
this.commitApmIdleState(agentId, ap, true);
|
|
11220
11679
|
}
|
|
@@ -11224,12 +11683,16 @@ ${RESPONSE_TARGET_HINT}`);
|
|
|
11224
11683
|
this.recordDaemonTrace("daemon.agent.stdin_delivery", {
|
|
11225
11684
|
...traceAttrs,
|
|
11226
11685
|
...inputTraceAttrs,
|
|
11227
|
-
outcome:
|
|
11228
|
-
|
|
11686
|
+
outcome: runtimeSendFailureOutcome(sendResult),
|
|
11687
|
+
failure_reason: sendResult.reason,
|
|
11688
|
+
failure_error: sendResult.error,
|
|
11689
|
+
requeued_messages_count: options.transient ? 0 : messages.length
|
|
11229
11690
|
}, "error");
|
|
11230
11691
|
return false;
|
|
11231
11692
|
}
|
|
11232
|
-
|
|
11693
|
+
if (!options.transient) {
|
|
11694
|
+
this.consumeVisibleMessages(agentId, { messages, source: traceSource });
|
|
11695
|
+
}
|
|
11233
11696
|
const senders = [...new Set(messages.map((message) => `@${message.sender_name}`))].join(", ");
|
|
11234
11697
|
logger.info(
|
|
11235
11698
|
`[Agent ${agentId}] Delivering ${mode} ${messages.length === 1 ? "message" : `${messages.length} messages`} via stdin from ${senders}`
|
|
@@ -11237,7 +11700,6 @@ ${RESPONSE_TARGET_HINT}`);
|
|
|
11237
11700
|
if (this.containsOrdinaryInboxMessage(messages)) {
|
|
11238
11701
|
ap.lastRuntimeError = null;
|
|
11239
11702
|
}
|
|
11240
|
-
ap.process.stdin?.write(encoded + "\n");
|
|
11241
11703
|
this.ackInjectedRuntimeProfileMessages(agentId, messages, ap.launchId);
|
|
11242
11704
|
this.recordDaemonTrace("daemon.agent.stdin_delivery", {
|
|
11243
11705
|
...traceAttrs,
|
|
@@ -12205,7 +12667,7 @@ var DEFAULT_TRACE_UPLOAD_URL = "https://slock-trace-upload.botiverse.dev";
|
|
|
12205
12667
|
var RUNNER_CREDENTIAL_SCOPES = ["send", "read", "mentions", "tasks", "reactions", "server", "channels", "knowledge"];
|
|
12206
12668
|
var RUNNER_CREDENTIAL_MINT_MAX_ATTEMPTS2 = 3;
|
|
12207
12669
|
var RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2 = 250;
|
|
12208
|
-
var DAEMON_CLI_USAGE =
|
|
12670
|
+
var DAEMON_CLI_USAGE = `Usage: slock-daemon --server-url <url> (--api-key <key> or ${DAEMON_API_KEY_ENV}=<key>)`;
|
|
12209
12671
|
var RunnerCredentialMintError2 = class extends Error {
|
|
12210
12672
|
code;
|
|
12211
12673
|
retryable;
|
|
@@ -12241,9 +12703,9 @@ function runnerCredentialErrorDetail2(error) {
|
|
|
12241
12703
|
async function waitForRunnerCredentialRetry2() {
|
|
12242
12704
|
await new Promise((resolve) => setTimeout(resolve, RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2));
|
|
12243
12705
|
}
|
|
12244
|
-
function parseDaemonCliArgs(args) {
|
|
12706
|
+
function parseDaemonCliArgs(args, env = {}) {
|
|
12245
12707
|
let serverUrl = "";
|
|
12246
|
-
let apiKey = "";
|
|
12708
|
+
let apiKey = env[DAEMON_API_KEY_ENV] ?? "";
|
|
12247
12709
|
for (let i = 0; i < args.length; i++) {
|
|
12248
12710
|
if (args[i] === "--server-url" && args[i + 1]) serverUrl = args[++i];
|
|
12249
12711
|
if (args[i] === "--api-key" && args[i + 1]) apiKey = args[++i];
|
|
@@ -12444,7 +12906,9 @@ var DaemonCore = class {
|
|
|
12444
12906
|
serverUrl: options.serverUrl,
|
|
12445
12907
|
defaultAgentEnvVarsProvider: options.defaultAgentEnvVarsProvider,
|
|
12446
12908
|
slockCliPath: this.slockCliPath,
|
|
12447
|
-
tracer: this.tracer
|
|
12909
|
+
tracer: this.tracer,
|
|
12910
|
+
daemonVersion: this.daemonVersion,
|
|
12911
|
+
computerVersion: this.computerVersion
|
|
12448
12912
|
};
|
|
12449
12913
|
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
12914
|
const connectionFactory = options.connectionFactory ?? ((connOptions) => new DaemonConnection(connOptions));
|
|
@@ -12695,7 +13159,8 @@ var DaemonCore = class {
|
|
|
12695
13159
|
msg.wakeMessage,
|
|
12696
13160
|
msg.unreadSummary,
|
|
12697
13161
|
msg.resumePrompt,
|
|
12698
|
-
msg.launchId
|
|
13162
|
+
msg.launchId,
|
|
13163
|
+
msg.wakeMessageTransient ?? false
|
|
12699
13164
|
);
|
|
12700
13165
|
}
|
|
12701
13166
|
handleMessage(msg) {
|
|
@@ -12746,7 +13211,10 @@ var DaemonCore = class {
|
|
|
12746
13211
|
logger.info(`[Agent ${msg.agentId}] Delivery received (seq=${msg.seq}, from=@${msg.message.sender_name}, target=${formatChannelTarget(msg)})`);
|
|
12747
13212
|
try {
|
|
12748
13213
|
span.addEvent("daemon.receive", { seq: msg.seq, deliveryId: msg.deliveryId });
|
|
12749
|
-
const acceptedOrPromise = this.agentManager.deliverMessage(msg.agentId, msg.message, {
|
|
13214
|
+
const acceptedOrPromise = this.agentManager.deliverMessage(msg.agentId, msg.message, {
|
|
13215
|
+
deliveryId: msg.deliveryId,
|
|
13216
|
+
transient: msg.transient ?? false
|
|
13217
|
+
});
|
|
12750
13218
|
Promise.resolve(acceptedOrPromise).then((accepted) => {
|
|
12751
13219
|
span.addEvent("daemon.deliver_to_agent_manager", { accepted });
|
|
12752
13220
|
if (!accepted) {
|
|
@@ -13010,6 +13478,8 @@ var DaemonCore = class {
|
|
|
13010
13478
|
};
|
|
13011
13479
|
|
|
13012
13480
|
export {
|
|
13481
|
+
DAEMON_API_KEY_ENV,
|
|
13482
|
+
scrubDaemonAuthEnv,
|
|
13013
13483
|
resolveWorkspaceDirectoryPath,
|
|
13014
13484
|
scanWorkspaceDirectories,
|
|
13015
13485
|
deleteWorkspaceDirectory,
|