@slock-ai/daemon 0.55.7-play.20260602150229 → 0.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-OV4XD66N.js → chunk-4H5XFLYA.js} +246 -177
- package/dist/core.js +2 -6
- package/dist/index.js +3 -5
- package/package.json +1 -1
- package/dist/drivers/piSdkRunner.js +0 -96
|
@@ -939,10 +939,12 @@ var actionCardActionSchema = z.discriminatedUnion("type", [
|
|
|
939
939
|
]);
|
|
940
940
|
|
|
941
941
|
// ../shared/src/agentInbox.ts
|
|
942
|
-
function formatAgentInboxDelta(rows) {
|
|
943
|
-
|
|
942
|
+
function formatAgentInboxDelta(rows, options = {}) {
|
|
943
|
+
const totalPendingMessages = options.totalPendingMessages;
|
|
944
|
+
const header = typeof totalPendingMessages === "number" ? `Inbox update: ${totalPendingMessages} unread message${totalPendingMessages === 1 ? "" : "s"} total; ${rows.length === 0 ? "no" : rows.length} changed target${rows.length === 1 ? "" : "s"}` : `Inbox update: ${rows.length} changed target${rows.length === 1 ? "" : "s"}`;
|
|
945
|
+
if (rows.length === 0) return typeof totalPendingMessages === "number" ? header : "Inbox update: no pending targets";
|
|
944
946
|
return [
|
|
945
|
-
|
|
947
|
+
header,
|
|
946
948
|
...rows.map((row) => `${row.target} ${formatAgentInboxRowDetails(row)}`)
|
|
947
949
|
].join("\n");
|
|
948
950
|
}
|
|
@@ -1305,6 +1307,7 @@ function buildPrompt(config, variant, opts) {
|
|
|
1305
1307
|
const sendCmd = isCli ? "`slock message send`" : `\`${t("send_message")}\``;
|
|
1306
1308
|
const readCmd = isCli ? "`slock message read`" : `\`${t("read_history")}\``;
|
|
1307
1309
|
const checkCmd = isCli ? "`slock message check`" : `\`${t("check_messages")}\``;
|
|
1310
|
+
const inboxCheckCmd = isCli ? "`slock inbox check`" : checkCmd;
|
|
1308
1311
|
const taskClaimCmd = isCli ? "`slock task claim`" : `\`${t("claim_tasks")}\``;
|
|
1309
1312
|
const taskCreateCmd = isCli ? "`slock task create`" : `\`${t("create_tasks")}\``;
|
|
1310
1313
|
const taskUpdateCmd = isCli ? "`slock task update`" : `\`${t("update_task_status")}\``;
|
|
@@ -1785,14 +1788,14 @@ You may develop a specialized role over time through your interactions. Embrace
|
|
|
1785
1788
|
|
|
1786
1789
|
## Message Notifications
|
|
1787
1790
|
|
|
1788
|
-
While you are working, the daemon may write a batched
|
|
1791
|
+
While you are working, the daemon may write a batched, content-free inbox update into your current turn.
|
|
1789
1792
|
|
|
1790
1793
|
How to handle these:
|
|
1791
|
-
- Treat the notification as a signal that new Slock messages are waiting; it does not include the message content.
|
|
1792
|
-
-
|
|
1793
|
-
- If
|
|
1794
|
+
- Treat the notification as a non-urgent signal that new Slock messages are waiting; it does not include the message content and does not require an immediate interruption.
|
|
1795
|
+
- Keep working until a natural breakpoint. If you then choose to inspect pending targets, call ${inboxCheckCmd}; use ${checkCmd} / ${readCmd} when you choose to inspect message content.
|
|
1796
|
+
- If a message you explicitly read is higher priority, pivot to it. If not, continue your current work.`;
|
|
1794
1797
|
} else {
|
|
1795
|
-
const notifyExample = isCli ? `\`[Slock inbox notice:
|
|
1798
|
+
const notifyExample = isCli ? `\`[Slock inbox notice:\\nInbox update: N unread messages total; M changed targets\\n#channel pending: K messages ...]\`` : `\`[Slock inbox notice:\\nInbox update: N unread messages total; M changed targets\\n#channel pending: K messages ...]\``;
|
|
1796
1799
|
prompt += `
|
|
1797
1800
|
|
|
1798
1801
|
## Message Notifications
|
|
@@ -1802,9 +1805,9 @@ While you are busy (executing tools, thinking, etc.), new messages may arrive. W
|
|
|
1802
1805
|
${notifyExample}
|
|
1803
1806
|
|
|
1804
1807
|
How to handle these:
|
|
1805
|
-
-
|
|
1806
|
-
-
|
|
1807
|
-
-
|
|
1808
|
+
- The notice is target-scoped and content-free. Its header may show total unread/pending count, while detail rows list the targets changed by this update; it never includes message bodies.
|
|
1809
|
+
- Do not interrupt the current step just because a notice arrived. At a natural breakpoint, call ${inboxCheckCmd} if you choose to inspect pending targets, or use ${checkCmd} / ${readCmd} when you choose to inspect message content.
|
|
1810
|
+
- If a message you explicitly read is higher priority, you may pivot to it. If not, continue your current work.`;
|
|
1808
1811
|
}
|
|
1809
1812
|
}
|
|
1810
1813
|
if (config.description) {
|
|
@@ -1858,19 +1861,6 @@ function listLegacySlockStatePaths(slockHome = resolveSlockHome(), homeDir = os.
|
|
|
1858
1861
|
return candidates.filter((candidate) => existsSync(candidate.path));
|
|
1859
1862
|
}
|
|
1860
1863
|
|
|
1861
|
-
// src/authEnv.ts
|
|
1862
|
-
var DAEMON_API_KEY_ENV = "SLOCK_MACHINE_API_KEY";
|
|
1863
|
-
var SLOCK_AGENT_TOKEN_ENV = "SLOCK_AGENT_TOKEN";
|
|
1864
|
-
function scrubDaemonAuthEnv(env) {
|
|
1865
|
-
delete env[DAEMON_API_KEY_ENV];
|
|
1866
|
-
return env;
|
|
1867
|
-
}
|
|
1868
|
-
function scrubDaemonChildEnv(env) {
|
|
1869
|
-
delete env[DAEMON_API_KEY_ENV];
|
|
1870
|
-
delete env[SLOCK_AGENT_TOKEN_ENV];
|
|
1871
|
-
return env;
|
|
1872
|
-
}
|
|
1873
|
-
|
|
1874
1864
|
// src/agentCredentialProxy.ts
|
|
1875
1865
|
import { randomBytes } from "crypto";
|
|
1876
1866
|
import http from "http";
|
|
@@ -3026,9 +3016,7 @@ var LOOPBACK_NO_PROXY = "127.0.0.1,localhost";
|
|
|
3026
3016
|
var CLI_TRANSPORT_TRACE_DIR_ENV = "SLOCK_CLI_TRANSPORT_TRACE_DIR";
|
|
3027
3017
|
var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
3028
3018
|
var RAW_CREDENTIAL_ENV_DENYLIST = [
|
|
3029
|
-
"
|
|
3030
|
-
"SLOCK_AGENT_CREDENTIAL_KEY",
|
|
3031
|
-
"SLOCK_AGENT_CREDENTIAL_KEY_FILE"
|
|
3019
|
+
"SLOCK_AGENT_CREDENTIAL_KEY"
|
|
3032
3020
|
];
|
|
3033
3021
|
var cachedOpencliBinPath;
|
|
3034
3022
|
function resolveOpencliBinPath() {
|
|
@@ -3243,7 +3231,7 @@ exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(opencliBinPath)} "
|
|
|
3243
3231
|
...agentCredentialProxy ? {} : { SLOCK_AGENT_TOKEN_FILE: tokenFile },
|
|
3244
3232
|
PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
|
|
3245
3233
|
};
|
|
3246
|
-
|
|
3234
|
+
delete spawnEnv.SLOCK_AGENT_TOKEN;
|
|
3247
3235
|
for (const key of RAW_CREDENTIAL_ENV_DENYLIST) {
|
|
3248
3236
|
delete spawnEnv[key];
|
|
3249
3237
|
}
|
|
@@ -3672,7 +3660,7 @@ function resolveCommandOnWindows(command, env, execFileSyncFn, existsSyncFn) {
|
|
|
3672
3660
|
}
|
|
3673
3661
|
function resolveCommandOnPath(command, deps = {}) {
|
|
3674
3662
|
const platform = deps.platform ?? process.platform;
|
|
3675
|
-
const env =
|
|
3663
|
+
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
3676
3664
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
3677
3665
|
const existsSyncFn = deps.existsSyncFn ?? existsSync2;
|
|
3678
3666
|
if (platform === "win32") {
|
|
@@ -3698,7 +3686,7 @@ function firstExistingPath(candidates, deps = {}) {
|
|
|
3698
3686
|
return null;
|
|
3699
3687
|
}
|
|
3700
3688
|
function readCommandVersion(command, args = [], deps = {}) {
|
|
3701
|
-
const env =
|
|
3689
|
+
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
3702
3690
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
3703
3691
|
try {
|
|
3704
3692
|
const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
|
|
@@ -5161,11 +5149,11 @@ function detectCursorModels(runCommand = runCursorModelsCommand) {
|
|
|
5161
5149
|
return parseCursorModelsOutput(String(result.stdout || ""));
|
|
5162
5150
|
}
|
|
5163
5151
|
function buildCursorModelProbeEnv(deps = {}) {
|
|
5164
|
-
return
|
|
5152
|
+
return withWindowsUserEnvironment({
|
|
5165
5153
|
...deps.env ?? process.env,
|
|
5166
5154
|
FORCE_COLOR: "0",
|
|
5167
5155
|
NO_COLOR: "1"
|
|
5168
|
-
}, deps)
|
|
5156
|
+
}, deps);
|
|
5169
5157
|
}
|
|
5170
5158
|
function runCursorModelsCommand() {
|
|
5171
5159
|
return spawnSync("cursor-agent", ["models"], {
|
|
@@ -5221,7 +5209,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
|
|
|
5221
5209
|
}
|
|
5222
5210
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
|
|
5223
5211
|
const existsSyncFn = deps.existsSyncFn ?? existsSync5;
|
|
5224
|
-
const env =
|
|
5212
|
+
const env = deps.env ?? process.env;
|
|
5225
5213
|
const winPath = path8.win32;
|
|
5226
5214
|
let geminiEntry = null;
|
|
5227
5215
|
try {
|
|
@@ -5393,16 +5381,13 @@ var GeminiDriver = class {
|
|
|
5393
5381
|
// src/drivers/kimi.ts
|
|
5394
5382
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
5395
5383
|
import { spawn as spawn7 } from "child_process";
|
|
5396
|
-
import {
|
|
5384
|
+
import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
5397
5385
|
import os3 from "os";
|
|
5398
5386
|
import path9 from "path";
|
|
5399
5387
|
var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
|
|
5400
5388
|
var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
|
|
5401
5389
|
var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
|
|
5402
5390
|
var KIMI_MCP_FILE = ".slock-kimi-mcp.json";
|
|
5403
|
-
var KIMI_GENERATED_CONFIG_FILE = ".slock-kimi-config.toml";
|
|
5404
|
-
var SLOCK_KIMI_CONFIG_CONTENT_ENV = "SLOCK_KIMI_CONFIG_CONTENT";
|
|
5405
|
-
var SLOCK_KIMI_CONFIG_FILE_ENV = "SLOCK_KIMI_CONFIG_FILE";
|
|
5406
5391
|
function parseToolArguments(raw) {
|
|
5407
5392
|
if (typeof raw !== "string") return raw;
|
|
5408
5393
|
try {
|
|
@@ -5411,73 +5396,6 @@ function parseToolArguments(raw) {
|
|
|
5411
5396
|
return raw;
|
|
5412
5397
|
}
|
|
5413
5398
|
}
|
|
5414
|
-
function readKimiConfigSource(home = os3.homedir(), env = process.env) {
|
|
5415
|
-
const inlineConfig = env[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
5416
|
-
if (inlineConfig && inlineConfig.trim()) {
|
|
5417
|
-
return {
|
|
5418
|
-
raw: inlineConfig,
|
|
5419
|
-
explicitPath: null,
|
|
5420
|
-
sourcePath: SLOCK_KIMI_CONFIG_CONTENT_ENV
|
|
5421
|
-
};
|
|
5422
|
-
}
|
|
5423
|
-
const explicitPath = env[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
5424
|
-
const configPath = explicitPath && explicitPath.trim() ? explicitPath : path9.join(home, ".kimi", "config.toml");
|
|
5425
|
-
try {
|
|
5426
|
-
return {
|
|
5427
|
-
raw: readFileSync3(configPath, "utf8"),
|
|
5428
|
-
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
5429
|
-
sourcePath: configPath
|
|
5430
|
-
};
|
|
5431
|
-
} catch {
|
|
5432
|
-
return {
|
|
5433
|
-
raw: null,
|
|
5434
|
-
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
5435
|
-
sourcePath: configPath
|
|
5436
|
-
};
|
|
5437
|
-
}
|
|
5438
|
-
}
|
|
5439
|
-
function buildKimiSpawnEnv(env = process.env) {
|
|
5440
|
-
const spawnEnv = { ...env, FORCE_COLOR: "0", NO_COLOR: "1" };
|
|
5441
|
-
delete spawnEnv[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
5442
|
-
delete spawnEnv[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
5443
|
-
return scrubDaemonChildEnv(spawnEnv);
|
|
5444
|
-
}
|
|
5445
|
-
function buildKimiEffectiveEnv(ctx, overrideEnv) {
|
|
5446
|
-
return {
|
|
5447
|
-
...process.env,
|
|
5448
|
-
...ctx.config.envVars || {},
|
|
5449
|
-
...overrideEnv || {}
|
|
5450
|
-
};
|
|
5451
|
-
}
|
|
5452
|
-
function buildKimiLaunchOptions(ctx, opts = {}) {
|
|
5453
|
-
const env = buildKimiEffectiveEnv(ctx, opts.env);
|
|
5454
|
-
const source = readKimiConfigSource(opts.home ?? os3.homedir(), env);
|
|
5455
|
-
const args = [];
|
|
5456
|
-
let configFilePath = null;
|
|
5457
|
-
let configContent = null;
|
|
5458
|
-
if (source.explicitPath) {
|
|
5459
|
-
configFilePath = source.explicitPath;
|
|
5460
|
-
} else if (source.raw !== null && source.sourcePath === SLOCK_KIMI_CONFIG_CONTENT_ENV) {
|
|
5461
|
-
configFilePath = path9.join(ctx.workingDirectory, KIMI_GENERATED_CONFIG_FILE);
|
|
5462
|
-
configContent = source.raw;
|
|
5463
|
-
if (opts.writeGeneratedConfig !== false) {
|
|
5464
|
-
writeFileSync6(configFilePath, source.raw, { encoding: "utf8", mode: 384 });
|
|
5465
|
-
chmodSync(configFilePath, 384);
|
|
5466
|
-
}
|
|
5467
|
-
}
|
|
5468
|
-
if (configFilePath) {
|
|
5469
|
-
args.push("--config-file", configFilePath);
|
|
5470
|
-
}
|
|
5471
|
-
if (ctx.config.model && ctx.config.model !== "default") {
|
|
5472
|
-
args.push("--model", ctx.config.model);
|
|
5473
|
-
}
|
|
5474
|
-
return {
|
|
5475
|
-
args,
|
|
5476
|
-
env: buildKimiSpawnEnv(env),
|
|
5477
|
-
configFilePath,
|
|
5478
|
-
configContent
|
|
5479
|
-
};
|
|
5480
|
-
}
|
|
5481
5399
|
function resolveKimiSpawn(commandArgs, deps = {}) {
|
|
5482
5400
|
return {
|
|
5483
5401
|
command: resolveCommandOnPath("kimi", deps) ?? "kimi",
|
|
@@ -5501,25 +5419,7 @@ var KimiDriver = class {
|
|
|
5501
5419
|
};
|
|
5502
5420
|
model = {
|
|
5503
5421
|
detectedModelsVerifiedAs: "launchable",
|
|
5504
|
-
toLaunchSpec: (modelId
|
|
5505
|
-
if (!ctx) return { args: ["--model", modelId] };
|
|
5506
|
-
const launchCtx = {
|
|
5507
|
-
...ctx,
|
|
5508
|
-
config: {
|
|
5509
|
-
...ctx.config,
|
|
5510
|
-
model: modelId
|
|
5511
|
-
}
|
|
5512
|
-
};
|
|
5513
|
-
const launch = buildKimiLaunchOptions(launchCtx, {
|
|
5514
|
-
home: opts?.home,
|
|
5515
|
-
writeGeneratedConfig: false
|
|
5516
|
-
});
|
|
5517
|
-
return {
|
|
5518
|
-
args: launch.args,
|
|
5519
|
-
env: launch.env,
|
|
5520
|
-
configFiles: launch.configFilePath ? [launch.configFilePath] : void 0
|
|
5521
|
-
};
|
|
5522
|
-
}
|
|
5422
|
+
toLaunchSpec: (modelId) => ({ args: ["--model", modelId] })
|
|
5523
5423
|
};
|
|
5524
5424
|
supportsStdinNotification = true;
|
|
5525
5425
|
mcpToolPrefix = "";
|
|
@@ -5573,7 +5473,6 @@ var KimiDriver = class {
|
|
|
5573
5473
|
}
|
|
5574
5474
|
}
|
|
5575
5475
|
}), "utf8");
|
|
5576
|
-
const launch = buildKimiLaunchOptions(ctx);
|
|
5577
5476
|
const args = [
|
|
5578
5477
|
"--wire",
|
|
5579
5478
|
"--yolo",
|
|
@@ -5582,16 +5481,15 @@ var KimiDriver = class {
|
|
|
5582
5481
|
"--mcp-config-file",
|
|
5583
5482
|
mcpConfigPath,
|
|
5584
5483
|
"--session",
|
|
5585
|
-
this.sessionId
|
|
5586
|
-
...launch.args
|
|
5484
|
+
this.sessionId
|
|
5587
5485
|
];
|
|
5588
5486
|
const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
|
|
5589
5487
|
if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
|
|
5590
5488
|
args.push("--model", launchRuntimeFields.model);
|
|
5591
5489
|
}
|
|
5592
5490
|
const spawnEnv = (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
|
|
5593
|
-
const
|
|
5594
|
-
const proc = spawn7(
|
|
5491
|
+
const launch = resolveKimiSpawn(args);
|
|
5492
|
+
const proc = spawn7(launch.command, launch.args, {
|
|
5595
5493
|
cwd: ctx.workingDirectory,
|
|
5596
5494
|
stdio: ["pipe", "pipe", "pipe"],
|
|
5597
5495
|
env: spawnEnv,
|
|
@@ -5599,7 +5497,7 @@ var KimiDriver = class {
|
|
|
5599
5497
|
// and has an 8191-character command-line limit. Kimi's official
|
|
5600
5498
|
// installer/uv entrypoint is an executable, so launch it directly and
|
|
5601
5499
|
// keep prompts on stdin / files instead of routing through cmd.exe.
|
|
5602
|
-
shell:
|
|
5500
|
+
shell: launch.shell
|
|
5603
5501
|
});
|
|
5604
5502
|
proc.stdin?.write(JSON.stringify({
|
|
5605
5503
|
jsonrpc: "2.0",
|
|
@@ -5713,9 +5611,14 @@ var KimiDriver = class {
|
|
|
5713
5611
|
return detectKimiModels();
|
|
5714
5612
|
}
|
|
5715
5613
|
};
|
|
5716
|
-
function detectKimiModels(home = os3.homedir()
|
|
5717
|
-
const
|
|
5718
|
-
|
|
5614
|
+
function detectKimiModels(home = os3.homedir()) {
|
|
5615
|
+
const configPath = path9.join(home, ".kimi", "config.toml");
|
|
5616
|
+
let raw;
|
|
5617
|
+
try {
|
|
5618
|
+
raw = readFileSync3(configPath, "utf8");
|
|
5619
|
+
} catch {
|
|
5620
|
+
return null;
|
|
5621
|
+
}
|
|
5719
5622
|
const models = [];
|
|
5720
5623
|
const sectionRe = /^\s*\[models(?:\.([^\]]+)|"\.[^"]+"|\."[^"]+")\s*\]\s*$/gm;
|
|
5721
5624
|
const lineRe = /^\s*\[models\.(.+?)\s*\]\s*$/gm;
|
|
@@ -5979,7 +5882,7 @@ function runOpenCodeModelsCommand(home, deps = {}) {
|
|
|
5979
5882
|
const platform = deps.platform ?? process.platform;
|
|
5980
5883
|
const spawnSyncFn = deps.spawnSyncFn ?? spawnSync2;
|
|
5981
5884
|
const result = spawnSyncFn("opencode", ["models"], {
|
|
5982
|
-
env:
|
|
5885
|
+
env: { ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" },
|
|
5983
5886
|
encoding: "utf8",
|
|
5984
5887
|
timeout: 5e3,
|
|
5985
5888
|
shell: platform === "win32"
|
|
@@ -6786,7 +6689,9 @@ import { createHash as createHash2 } from "crypto";
|
|
|
6786
6689
|
var MAX_RUNTIME_ERROR_MESSAGE_EXCERPT_CHARS = 4096;
|
|
6787
6690
|
var RUNTIME_AUTH_ACTION_REQUIRED_PATTERNS = [
|
|
6788
6691
|
/access token could not be refreshed/i,
|
|
6692
|
+
/\btoken_(?:revoked|invalidated)\b/i,
|
|
6789
6693
|
/refresh token was already used/i,
|
|
6694
|
+
/access token.*invalidated/i,
|
|
6790
6695
|
/authentication token has been invalidated/i,
|
|
6791
6696
|
/logged out or signed in to another account/i,
|
|
6792
6697
|
/not logged in/i,
|
|
@@ -6868,6 +6773,9 @@ function classifyRuntimeError(message, httpStatus) {
|
|
|
6868
6773
|
return "ProviderApiError";
|
|
6869
6774
|
}
|
|
6870
6775
|
if (isRuntimeAuthActionRequiredText(message)) return "AuthError";
|
|
6776
|
+
if (/\bmodel\b.*\bnot supported\b/i.test(message) || /\bunsupported\b.*\bmodel\b/i.test(message) || /\bmodel\b.*\bnot available\b/i.test(message)) {
|
|
6777
|
+
return "ModelConfigError";
|
|
6778
|
+
}
|
|
6871
6779
|
if (/\b(?:ETIMEDOUT|timeout|timed out)\b/i.test(message)) return "TimeoutError";
|
|
6872
6780
|
if (/\b(?:ECONNRESET|EPIPE|ECONNREFUSED|ENOTFOUND|EAI_AGAIN)\b/i.test(message) || /\bUnable to connect to API\b/i.test(message)) {
|
|
6873
6781
|
return "ProviderConnectionError";
|
|
@@ -6900,6 +6808,8 @@ function classifyRuntimeErrorReason(runtimeErrorClass) {
|
|
|
6900
6808
|
return "auth_failed";
|
|
6901
6809
|
case "NotFoundError":
|
|
6902
6810
|
return "not_found";
|
|
6811
|
+
case "ModelConfigError":
|
|
6812
|
+
return "model_config_error";
|
|
6903
6813
|
case "ProviderServerError":
|
|
6904
6814
|
return "provider_server_error";
|
|
6905
6815
|
case "ProviderApiError":
|
|
@@ -7901,7 +7811,7 @@ function classifyTerminalFailure(ap) {
|
|
|
7901
7811
|
for (const text of candidates) {
|
|
7902
7812
|
const diagnostics = buildRuntimeErrorDiagnosticEnvelope(text);
|
|
7903
7813
|
const lower = text.toLowerCase();
|
|
7904
|
-
if (lower.includes("usage limit") || lower.includes("quota exceeded") || lower.includes("quota limit") || lower.includes("budget limit exceeded") || lower.includes("usage not included in your plan") || lower.includes("modelnotfounderror") || lower.includes("requested entity was not found") || lower.includes("model deprecated") || lower.includes("model not found") || diagnostics.spanAttrs.runtime_error_action_required === true || isProviderStreamFailureText(text) || isRuntimeStartTimeoutText(text)) {
|
|
7814
|
+
if (lower.includes("usage limit") || lower.includes("quota exceeded") || lower.includes("quota limit") || lower.includes("budget limit exceeded") || lower.includes("usage not included in your plan") || lower.includes("modelnotfounderror") || lower.includes("requested entity was not found") || lower.includes("model deprecated") || lower.includes("model not found") || lower.includes("model is not supported") || lower.includes("unsupported model") || /\bmodel\b.*\bnot supported\b/i.test(text) || diagnostics.spanAttrs.runtime_error_action_required === true || isProviderStreamFailureText(text) || isRuntimeStartTimeoutText(text)) {
|
|
7905
7815
|
const actionRequired = diagnostics.spanAttrs.runtime_error_action_required === true;
|
|
7906
7816
|
return {
|
|
7907
7817
|
detail: actionRequired ? formatRuntimeLoginRequiredMessage(ap.driver.id) : text,
|
|
@@ -7911,6 +7821,16 @@ function classifyTerminalFailure(ap) {
|
|
|
7911
7821
|
}
|
|
7912
7822
|
return null;
|
|
7913
7823
|
}
|
|
7824
|
+
function classifyStickyTerminalFailure(ap) {
|
|
7825
|
+
const terminalFailure = classifyTerminalFailure(ap);
|
|
7826
|
+
if (!terminalFailure) return null;
|
|
7827
|
+
if (terminalFailure.actionRequired) return terminalFailure;
|
|
7828
|
+
if (/\bmodel\b.*\bnot supported\b/i.test(terminalFailure.detail)) return terminalFailure;
|
|
7829
|
+
if (/\bunsupported\b.*\bmodel\b/i.test(terminalFailure.detail)) return terminalFailure;
|
|
7830
|
+
if (isProviderStreamFailureText(terminalFailure.detail)) return null;
|
|
7831
|
+
if (isRuntimeStartTimeoutText(terminalFailure.detail)) return null;
|
|
7832
|
+
return null;
|
|
7833
|
+
}
|
|
7914
7834
|
function isProviderStreamFailureText(text) {
|
|
7915
7835
|
return /stream closed before response\.completed|error decoding response body/i.test(text);
|
|
7916
7836
|
}
|
|
@@ -8170,17 +8090,17 @@ function sanitizeRuntimeTelemetryPayloadAttrs(attrs) {
|
|
|
8170
8090
|
return sanitized;
|
|
8171
8091
|
}
|
|
8172
8092
|
function getMessageDeliveryText(driver) {
|
|
8173
|
-
return driver.supportsStdinNotification ? "New
|
|
8093
|
+
return driver.supportsStdinNotification ? "New inbox updates may be delivered to you automatically while your process stays alive." : "The daemon will automatically restart you with an inbox update when new messages arrive.";
|
|
8174
8094
|
}
|
|
8175
8095
|
function getBusyDeliveryNote(driver) {
|
|
8176
8096
|
if (!driver.supportsStdinNotification) return "";
|
|
8177
8097
|
if (driver.busyDeliveryMode === "direct") {
|
|
8178
|
-
return "\n\nNote: While you are busy, the daemon may write batched
|
|
8098
|
+
return "\n\nNote: While you are busy, the daemon may write batched content-free inbox updates into your active turn. Finish your current step, then check the inbox or read messages at a natural breakpoint.";
|
|
8179
8099
|
}
|
|
8180
8100
|
if (driver.busyDeliveryMode === "gated") {
|
|
8181
|
-
return "\n\nNote: While you are busy, the daemon may write batched
|
|
8101
|
+
return "\n\nNote: While you are busy, the daemon may write batched content-free inbox updates into your active turn at runtime-observed safe boundaries. Finish your current step, then check the inbox or read messages at a natural breakpoint.";
|
|
8182
8102
|
}
|
|
8183
|
-
return "\n\nNote: While you are busy, you may receive [Slock inbox notice: ...] messages. Finish your current step, then
|
|
8103
|
+
return "\n\nNote: While you are busy, you may receive [Slock inbox notice: ...] messages. Finish your current step, then check the inbox or read messages at a natural breakpoint.";
|
|
8184
8104
|
}
|
|
8185
8105
|
var NATIVE_STANDING_PROMPT_STARTUP_INPUT = (
|
|
8186
8106
|
// Claude Code 2.1.114 treats "follow your system prompt" style user turns as
|
|
@@ -8735,6 +8655,8 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8735
8655
|
const standingPrompt = driver.buildSystemPrompt(runtimeConfig, agentId);
|
|
8736
8656
|
let prompt;
|
|
8737
8657
|
let promptSource;
|
|
8658
|
+
let wakeMessageDeliveredAsInboxUpdate = false;
|
|
8659
|
+
const startingInboxMessages = this.startingInboxes.get(agentId) || [];
|
|
8738
8660
|
if (runtimeConfig.runtimeProfileControl && !wakeMessage) {
|
|
8739
8661
|
prompt = driver.supportsNativeStandingPrompt ? NATIVE_STANDING_PROMPT_STARTUP_INPUT : formatRuntimeProfileControlStartupInput(runtimeConfig.runtimeProfileControl, driver);
|
|
8740
8662
|
promptSource = "runtime_profile_control";
|
|
@@ -8744,13 +8666,15 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8744
8666
|
promptSource = "resume_prompt";
|
|
8745
8667
|
} else if (wakeMessage) {
|
|
8746
8668
|
const runtimeProfileControlPrompt = formatRuntimeProfileControlPrompt([wakeMessage]);
|
|
8747
|
-
|
|
8748
|
-
|
|
8749
|
-
|
|
8750
|
-
|
|
8751
|
-
|
|
8669
|
+
if (runtimeProfileControlPrompt) {
|
|
8670
|
+
prompt = runtimeProfileControlPrompt;
|
|
8671
|
+
} else {
|
|
8672
|
+
wakeMessageDeliveredAsInboxUpdate = true;
|
|
8673
|
+
prompt = this.formatInboxUpdateRuntimeInput([wakeMessage, ...startingInboxMessages], driver);
|
|
8674
|
+
}
|
|
8675
|
+
promptSource = runtimeProfileControlPrompt ? "runtime_profile_control_message" : "wake_inbox_update";
|
|
8752
8676
|
if (!runtimeProfileControlPrompt && unreadSummary && Object.keys(unreadSummary).length > 0) {
|
|
8753
|
-
const otherUnread = Object.entries(unreadSummary)
|
|
8677
|
+
const otherUnread = Object.entries(unreadSummary);
|
|
8754
8678
|
if (otherUnread.length > 0) {
|
|
8755
8679
|
prompt += `
|
|
8756
8680
|
|
|
@@ -8761,18 +8685,9 @@ You also have unread messages in other channels:`;
|
|
|
8761
8685
|
}
|
|
8762
8686
|
prompt += `
|
|
8763
8687
|
|
|
8764
|
-
Use
|
|
8688
|
+
Use the inbox/read commands at a natural breakpoint if you choose to inspect those targets.`;
|
|
8765
8689
|
}
|
|
8766
8690
|
}
|
|
8767
|
-
if (!runtimeProfileControlPrompt) {
|
|
8768
|
-
prompt += `
|
|
8769
|
-
|
|
8770
|
-
Respond as appropriate \u2014 ${dynamicReplyInstruction(driver)}, or take action as needed. Complete ALL your work before stopping.
|
|
8771
|
-
${RESPONSE_TARGET_HINT}
|
|
8772
|
-
|
|
8773
|
-
IMPORTANT: If the message requires multi-step work (e.g. research, code changes, testing), complete ALL steps before stopping. Sending a progress update does NOT mean your task is done \u2014 only stop when you have NO more work to do. ${getMessageDeliveryText(driver)}`;
|
|
8774
|
-
prompt += getBusyDeliveryNote(driver);
|
|
8775
|
-
}
|
|
8776
8691
|
} else if (isResume && unreadSummary && Object.keys(unreadSummary).length > 0) {
|
|
8777
8692
|
prompt = `You have unread messages from while you were offline:`;
|
|
8778
8693
|
for (const [ch, count] of Object.entries(unreadSummary)) {
|
|
@@ -8847,7 +8762,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8847
8762
|
const agentProcess = {
|
|
8848
8763
|
process: proc,
|
|
8849
8764
|
driver,
|
|
8850
|
-
inbox:
|
|
8765
|
+
inbox: wakeMessageDeliveredAsInboxUpdate && wakeMessage ? [wakeMessage, ...startingInboxMessages] : startingInboxMessages,
|
|
8851
8766
|
config: runtimeConfig,
|
|
8852
8767
|
sessionId: runtimeConfig.sessionId || null,
|
|
8853
8768
|
launchId: launchId || null,
|
|
@@ -8890,7 +8805,9 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8890
8805
|
if (runtimeConfig.runtimeProfileControl) {
|
|
8891
8806
|
this.ackInjectedRuntimeProfileControl(agentId, runtimeConfig.runtimeProfileControl, agentProcess.launchId);
|
|
8892
8807
|
}
|
|
8893
|
-
if (
|
|
8808
|
+
if (wakeMessageDeliveredAsInboxUpdate) {
|
|
8809
|
+
this.recordInboxUpdateProjection(agentId, agentProcess, agentProcess.inbox, "spawn_wake_inbox_update", "wake", prompt);
|
|
8810
|
+
} else if (wakeMessage) {
|
|
8894
8811
|
this.consumeVisibleMessages(agentId, { messages: [wakeMessage], source: "spawn_wake_message" });
|
|
8895
8812
|
this.ackInjectedRuntimeProfileMessages(agentId, [wakeMessage], agentProcess.launchId);
|
|
8896
8813
|
}
|
|
@@ -8991,8 +8908,9 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8991
8908
|
const finalSignal = ap.exitSignal ?? signal;
|
|
8992
8909
|
const startupTimeoutTermination = ap.expectedTerminationReason === "startup_timeout";
|
|
8993
8910
|
const expectedTermination = Boolean(ap.expectedTerminationReason);
|
|
8994
|
-
const
|
|
8995
|
-
const
|
|
8911
|
+
const stickyTerminalFailureDetail = classifyStickyTerminalFailure(ap);
|
|
8912
|
+
const processEndedCleanly = !stickyTerminalFailureDetail && (finalCode === 0 || expectedTermination && !ap.lastRuntimeError);
|
|
8913
|
+
const terminalFailureDetail = processEndedCleanly ? null : stickyTerminalFailureDetail ?? classifyTerminalFailure(ap);
|
|
8996
8914
|
const resumeRecoveryReason = resumeSessionRecoveryReason(ap);
|
|
8997
8915
|
const shouldColdStartResumeSession = resumeRecoveryReason !== null;
|
|
8998
8916
|
const summary = summarizeCrash(finalCode, finalSignal);
|
|
@@ -9475,13 +9393,36 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9475
9393
|
}));
|
|
9476
9394
|
return true;
|
|
9477
9395
|
}
|
|
9396
|
+
const stickyTerminalFailure = classifyStickyTerminalFailure(ap);
|
|
9397
|
+
if (stickyTerminalFailure) {
|
|
9398
|
+
ap.inbox.push(message);
|
|
9399
|
+
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
9400
|
+
outcome: "queued_terminal_runtime_error",
|
|
9401
|
+
accepted: true,
|
|
9402
|
+
process_present: true,
|
|
9403
|
+
runtime: ap.config.runtime,
|
|
9404
|
+
session_id_present: Boolean(ap.sessionId),
|
|
9405
|
+
launchId: ap.launchId || void 0,
|
|
9406
|
+
is_idle: ap.isIdle,
|
|
9407
|
+
inbox_count: ap.inbox.length
|
|
9408
|
+
}));
|
|
9409
|
+
this.sendAgentStatus(agentId, "inactive", ap.launchId);
|
|
9410
|
+
this.broadcastActivity(agentId, "error", stickyTerminalFailure.detail);
|
|
9411
|
+
return true;
|
|
9412
|
+
}
|
|
9478
9413
|
if (ap.isIdle && ap.driver.supportsStdinNotification && ap.sessionId) {
|
|
9479
|
-
|
|
9480
|
-
nextMessages.
|
|
9414
|
+
ap.inbox.push(message);
|
|
9415
|
+
const nextMessages = [...ap.inbox];
|
|
9481
9416
|
this.commitApmIdleState(agentId, ap, false);
|
|
9482
|
-
this.startRuntimeTrace(agentId, ap, "stdin-idle-delivery",
|
|
9417
|
+
this.startRuntimeTrace(agentId, ap, "stdin-idle-delivery", [message]);
|
|
9483
9418
|
this.broadcastActivity(agentId, "working", "Message received");
|
|
9484
|
-
const stdinAccepted = this.
|
|
9419
|
+
const stdinAccepted = this.deliverInboxUpdateViaStdin(
|
|
9420
|
+
agentId,
|
|
9421
|
+
ap,
|
|
9422
|
+
[message],
|
|
9423
|
+
"idle",
|
|
9424
|
+
"stdin_idle_delivery"
|
|
9425
|
+
);
|
|
9485
9426
|
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
9486
9427
|
outcome: "stdin_idle_delivery",
|
|
9487
9428
|
accepted: true,
|
|
@@ -10496,7 +10437,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10496
10437
|
return written;
|
|
10497
10438
|
}
|
|
10498
10439
|
case "deliver_stdin": {
|
|
10499
|
-
const messages = ap.inbox
|
|
10440
|
+
const messages = [...ap.inbox];
|
|
10500
10441
|
ap.notifications.clear();
|
|
10501
10442
|
if (messages.length === 0) {
|
|
10502
10443
|
this.recordApmGatedSteeringEffectTrace(agentId, ap, effect, {
|
|
@@ -10514,7 +10455,22 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10514
10455
|
});
|
|
10515
10456
|
}
|
|
10516
10457
|
this.broadcastActivity(agentId, "working", "Message received");
|
|
10517
|
-
const
|
|
10458
|
+
const runtimeProfileMessages = messages.filter((message) => runtimeProfileNotificationFromMessage(message));
|
|
10459
|
+
const ordinaryMessages = messages.filter((message) => !runtimeProfileNotificationFromMessage(message));
|
|
10460
|
+
let accepted = true;
|
|
10461
|
+
if (runtimeProfileMessages.length > 0) {
|
|
10462
|
+
ap.inbox.splice(0, ap.inbox.length, ...ordinaryMessages);
|
|
10463
|
+
accepted = this.deliverMessagesViaStdin(agentId, ap, runtimeProfileMessages, effect.stdinMode);
|
|
10464
|
+
}
|
|
10465
|
+
if (ordinaryMessages.length > 0) {
|
|
10466
|
+
accepted = this.deliverInboxUpdateViaStdin(
|
|
10467
|
+
agentId,
|
|
10468
|
+
ap,
|
|
10469
|
+
ordinaryMessages,
|
|
10470
|
+
effect.stdinMode,
|
|
10471
|
+
`stdin_${effect.stdinMode}_delivery`
|
|
10472
|
+
) && accepted;
|
|
10473
|
+
}
|
|
10518
10474
|
this.recordApmGatedSteeringEffectTrace(agentId, ap, effect, {
|
|
10519
10475
|
outcome: accepted ? "written" : "not_written",
|
|
10520
10476
|
delivered_messages_count: messages.length
|
|
@@ -10826,30 +10782,41 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10826
10782
|
this.flushPendingTrajectory(agentId);
|
|
10827
10783
|
if (ap) {
|
|
10828
10784
|
if (event.sessionId) ap.sessionId = event.sessionId;
|
|
10785
|
+
const stickyTerminalFailure = classifyStickyTerminalFailure(ap);
|
|
10829
10786
|
const reduction = reduceApmGatedTurnEnd(ap.gatedSteering, {
|
|
10830
|
-
inboxLength: ap.inbox.length,
|
|
10787
|
+
inboxLength: stickyTerminalFailure ? 0 : ap.inbox.length,
|
|
10831
10788
|
supportsStdinNotification: ap.driver.supportsStdinNotification,
|
|
10832
10789
|
hasSession: Boolean(ap.sessionId),
|
|
10833
10790
|
terminateProcessOnTurnEnd: ap.driver.terminateProcessOnTurnEnd === true
|
|
10834
10791
|
});
|
|
10835
10792
|
this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "turn_end" });
|
|
10836
10793
|
const deliverStdinEffect = reduction.effects.find((effect) => effect.kind === "deliver_stdin");
|
|
10794
|
+
if (stickyTerminalFailure) {
|
|
10795
|
+
this.sendAgentStatus(agentId, "inactive", ap.launchId);
|
|
10796
|
+
}
|
|
10837
10797
|
if (deliverStdinEffect) {
|
|
10838
10798
|
if (!this.executeApmGatedSteeringEffect(agentId, ap, deliverStdinEffect)) {
|
|
10839
10799
|
this.commitApmIdleState(agentId, ap, true);
|
|
10840
|
-
|
|
10800
|
+
if (stickyTerminalFailure) {
|
|
10801
|
+
this.broadcastActivity(agentId, "error", stickyTerminalFailure.detail);
|
|
10802
|
+
} else {
|
|
10803
|
+
this.broadcastActivity(agentId, "online", "Idle");
|
|
10804
|
+
}
|
|
10841
10805
|
}
|
|
10842
10806
|
} else {
|
|
10843
|
-
if (
|
|
10807
|
+
if (stickyTerminalFailure) {
|
|
10808
|
+
this.broadcastActivity(agentId, "error", stickyTerminalFailure.detail);
|
|
10809
|
+
} else if (ap.lastRuntimeError) {
|
|
10844
10810
|
this.broadcastActivity(agentId, "error", ap.lastRuntimeError);
|
|
10845
10811
|
} else {
|
|
10846
10812
|
this.broadcastActivity(agentId, "online", "Idle");
|
|
10847
10813
|
}
|
|
10848
10814
|
}
|
|
10849
|
-
this.endRuntimeTrace(ap, "ok", {
|
|
10850
|
-
outcome: "turn-completed",
|
|
10815
|
+
this.endRuntimeTrace(ap, stickyTerminalFailure ? "error" : "ok", {
|
|
10816
|
+
outcome: stickyTerminalFailure ? "runtime-error-with-turn-end" : "turn-completed",
|
|
10817
|
+
...stickyTerminalFailure ? { terminalRuntimeError: true } : {},
|
|
10851
10818
|
...runtimeTraceCounterAttrs(ap),
|
|
10852
|
-
...this.finalizeRuntimeProfileTurnControl(agentId, ap, "turn_end")
|
|
10819
|
+
...this.finalizeRuntimeProfileTurnControl(agentId, ap, stickyTerminalFailure ? "runtime_error" : "turn_end")
|
|
10853
10820
|
});
|
|
10854
10821
|
if (ap.driver.terminateProcessOnTurnEnd) {
|
|
10855
10822
|
logger.info(`[Agent ${agentId}] Turn completed; terminating ${ap.driver.id} process`);
|
|
@@ -10907,6 +10874,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10907
10874
|
...this.finalizeRuntimeProfileTurnControl(agentId, ap, "runtime_error")
|
|
10908
10875
|
});
|
|
10909
10876
|
if (ap.driver.supportsStdinNotification && terminalFailure) {
|
|
10877
|
+
const stickyTerminalFailure = classifyStickyTerminalFailure(ap);
|
|
10910
10878
|
if (terminalFailure.actionRequired) {
|
|
10911
10879
|
logger.warn(`[Agent ${agentId}] ${ap.driver.id} auth requires user action; terminating runtime process`);
|
|
10912
10880
|
try {
|
|
@@ -10919,6 +10887,10 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10919
10887
|
const reason = err instanceof Error ? err.message : String(err);
|
|
10920
10888
|
logger.warn(`[Agent ${agentId}] Failed to terminate ${ap.driver.id} after auth error: ${reason}`);
|
|
10921
10889
|
}
|
|
10890
|
+
} else if (stickyTerminalFailure) {
|
|
10891
|
+
ap.notifications.clear();
|
|
10892
|
+
this.sendAgentStatus(agentId, "inactive", ap.launchId);
|
|
10893
|
+
logger.warn(`[Agent ${agentId}] ${ap.driver.id} terminal runtime error requires explicit recovery`);
|
|
10922
10894
|
} else {
|
|
10923
10895
|
ap.notifications.clear();
|
|
10924
10896
|
logger.info(`[Agent ${agentId}] Marked ${ap.driver.id} wakeable after terminal runtime error`);
|
|
@@ -11025,9 +10997,10 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11025
10997
|
}
|
|
11026
10998
|
const inboxCount = ap.inbox.length;
|
|
11027
10999
|
if (inboxCount === 0) return false;
|
|
11028
|
-
const
|
|
11000
|
+
const changedMessages = ap.inbox.slice(Math.max(0, ap.inbox.length - count));
|
|
11001
|
+
const inboxRows = projectAgentInboxSnapshot(changedMessages);
|
|
11029
11002
|
const notification = `[Slock inbox notice:
|
|
11030
|
-
${formatAgentInboxDelta(inboxRows)}]`;
|
|
11003
|
+
${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
|
|
11031
11004
|
const notificationByteCount = Buffer.byteLength(notification, "utf8");
|
|
11032
11005
|
const projectionAttrs = this.inboxProjectionTraceAttrs(inboxRows, inboxCount);
|
|
11033
11006
|
this.recordDaemonTrace("daemon.agent.inbox_projection.delta", {
|
|
@@ -11081,6 +11054,104 @@ ${formatAgentInboxDelta(inboxRows)}]`;
|
|
|
11081
11054
|
return false;
|
|
11082
11055
|
}
|
|
11083
11056
|
}
|
|
11057
|
+
formatInboxUpdateRuntimeInput(messages, driver, totalPendingMessages = messages.length) {
|
|
11058
|
+
const rows = projectAgentInboxSnapshot(messages);
|
|
11059
|
+
return [
|
|
11060
|
+
"[Slock inbox notice:",
|
|
11061
|
+
formatAgentInboxDelta(rows, { totalPendingMessages }),
|
|
11062
|
+
"]"
|
|
11063
|
+
].join("\n");
|
|
11064
|
+
}
|
|
11065
|
+
recordInboxUpdateProjection(agentId, ap, messages, source, mode, renderedInput, totalPendingMessages = messages.length) {
|
|
11066
|
+
const rows = projectAgentInboxSnapshot(messages);
|
|
11067
|
+
const projectionAttrs = this.inboxProjectionTraceAttrs(rows, totalPendingMessages);
|
|
11068
|
+
this.recordDaemonTrace("daemon.agent.inbox_projection.delta", {
|
|
11069
|
+
agentId,
|
|
11070
|
+
source,
|
|
11071
|
+
...projectionAttrs
|
|
11072
|
+
});
|
|
11073
|
+
this.recordDaemonTrace("daemon.agent.inbox_update.pushed", {
|
|
11074
|
+
agentId,
|
|
11075
|
+
runtime: ap.config.runtime,
|
|
11076
|
+
model: ap.config.model,
|
|
11077
|
+
launchId: ap.launchId || void 0,
|
|
11078
|
+
mode,
|
|
11079
|
+
notification_byte_count: Buffer.byteLength(renderedInput, "utf8"),
|
|
11080
|
+
cursors_advanced: "none",
|
|
11081
|
+
...projectionAttrs
|
|
11082
|
+
});
|
|
11083
|
+
return projectionAttrs;
|
|
11084
|
+
}
|
|
11085
|
+
deliverInboxUpdateViaStdin(agentId, ap, messages, mode, source) {
|
|
11086
|
+
if (messages.length === 0) return true;
|
|
11087
|
+
const prompt = this.formatInboxUpdateRuntimeInput(messages, ap.driver, ap.inbox.length);
|
|
11088
|
+
const projectionAttrs = this.recordInboxUpdateProjection(agentId, ap, messages, source, mode, prompt, ap.inbox.length);
|
|
11089
|
+
const inputTraceAttrs = buildRuntimeInputTraceAttrs({
|
|
11090
|
+
source,
|
|
11091
|
+
prompt,
|
|
11092
|
+
messages,
|
|
11093
|
+
sessionIdPresent: Boolean(ap.sessionId),
|
|
11094
|
+
nativeStandingPrompt: Boolean(ap.driver.supportsNativeStandingPrompt)
|
|
11095
|
+
});
|
|
11096
|
+
this.recordRuntimeTraceEvent(agentId, ap, "runtime.input.prepared", inputTraceAttrs);
|
|
11097
|
+
const encoded = ap.driver.encodeStdinMessage(prompt, ap.sessionId, { mode });
|
|
11098
|
+
if (!encoded) {
|
|
11099
|
+
if (mode === "idle") {
|
|
11100
|
+
this.commitApmIdleState(agentId, ap, true);
|
|
11101
|
+
}
|
|
11102
|
+
logger.warn(
|
|
11103
|
+
`[Agent ${agentId}] Failed to encode ${mode} inbox update; ${messages.length === 1 ? "message remains" : "messages remain"} pending`
|
|
11104
|
+
);
|
|
11105
|
+
this.recordDaemonTrace("daemon.agent.stdin_delivery", {
|
|
11106
|
+
agentId,
|
|
11107
|
+
launchId: ap.launchId || void 0,
|
|
11108
|
+
runtime: ap.config.runtime,
|
|
11109
|
+
model: ap.config.model,
|
|
11110
|
+
mode,
|
|
11111
|
+
messages_count: messages.length,
|
|
11112
|
+
session_id_present: Boolean(ap.sessionId),
|
|
11113
|
+
inbox_count: ap.inbox.length,
|
|
11114
|
+
pending_notification_count: ap.notifications.pendingCount,
|
|
11115
|
+
busy_delivery_mode: ap.driver.busyDeliveryMode,
|
|
11116
|
+
supports_stdin_notification: ap.driver.supportsStdinNotification,
|
|
11117
|
+
...this.messagesTraceAttrs(messages),
|
|
11118
|
+
...inputTraceAttrs,
|
|
11119
|
+
...projectionAttrs,
|
|
11120
|
+
outcome: "encode_failed",
|
|
11121
|
+
requeued_messages_count: 0,
|
|
11122
|
+
cursors_advanced: "none"
|
|
11123
|
+
}, "error");
|
|
11124
|
+
return false;
|
|
11125
|
+
}
|
|
11126
|
+
const senders = [...new Set(messages.map((message) => `@${message.sender_name}`))].join(", ");
|
|
11127
|
+
logger.info(
|
|
11128
|
+
`[Agent ${agentId}] Delivering ${mode} inbox update for ${messages.length === 1 ? "message" : `${messages.length} messages`} from ${senders}`
|
|
11129
|
+
);
|
|
11130
|
+
if (this.containsOrdinaryInboxMessage(messages)) {
|
|
11131
|
+
ap.lastRuntimeError = null;
|
|
11132
|
+
}
|
|
11133
|
+
ap.process.stdin?.write(encoded + "\n");
|
|
11134
|
+
this.recordDaemonTrace("daemon.agent.stdin_delivery", {
|
|
11135
|
+
agentId,
|
|
11136
|
+
launchId: ap.launchId || void 0,
|
|
11137
|
+
runtime: ap.config.runtime,
|
|
11138
|
+
model: ap.config.model,
|
|
11139
|
+
mode,
|
|
11140
|
+
messages_count: messages.length,
|
|
11141
|
+
session_id_present: Boolean(ap.sessionId),
|
|
11142
|
+
inbox_count: ap.inbox.length,
|
|
11143
|
+
pending_notification_count: ap.notifications.pendingCount,
|
|
11144
|
+
busy_delivery_mode: ap.driver.busyDeliveryMode,
|
|
11145
|
+
supports_stdin_notification: ap.driver.supportsStdinNotification,
|
|
11146
|
+
...this.messagesTraceAttrs(messages),
|
|
11147
|
+
...inputTraceAttrs,
|
|
11148
|
+
...projectionAttrs,
|
|
11149
|
+
outcome: "written",
|
|
11150
|
+
stdin_write_attempted: true,
|
|
11151
|
+
cursors_advanced: "none"
|
|
11152
|
+
});
|
|
11153
|
+
return true;
|
|
11154
|
+
}
|
|
11084
11155
|
/** Deliver a message to an agent via stdin, formatting it the same way as the MCP bridge */
|
|
11085
11156
|
deliverMessagesViaStdin(agentId, ap, messages, mode) {
|
|
11086
11157
|
if (messages.length === 0) return true;
|
|
@@ -12134,7 +12205,7 @@ var DEFAULT_TRACE_UPLOAD_URL = "https://slock-trace-upload.botiverse.dev";
|
|
|
12134
12205
|
var RUNNER_CREDENTIAL_SCOPES = ["send", "read", "mentions", "tasks", "reactions", "server", "channels", "knowledge"];
|
|
12135
12206
|
var RUNNER_CREDENTIAL_MINT_MAX_ATTEMPTS2 = 3;
|
|
12136
12207
|
var RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2 = 250;
|
|
12137
|
-
var DAEMON_CLI_USAGE =
|
|
12208
|
+
var DAEMON_CLI_USAGE = "Usage: slock-daemon --server-url <url> --api-key <key>";
|
|
12138
12209
|
var RunnerCredentialMintError2 = class extends Error {
|
|
12139
12210
|
code;
|
|
12140
12211
|
retryable;
|
|
@@ -12170,9 +12241,9 @@ function runnerCredentialErrorDetail2(error) {
|
|
|
12170
12241
|
async function waitForRunnerCredentialRetry2() {
|
|
12171
12242
|
await new Promise((resolve) => setTimeout(resolve, RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2));
|
|
12172
12243
|
}
|
|
12173
|
-
function parseDaemonCliArgs(args
|
|
12244
|
+
function parseDaemonCliArgs(args) {
|
|
12174
12245
|
let serverUrl = "";
|
|
12175
|
-
let apiKey =
|
|
12246
|
+
let apiKey = "";
|
|
12176
12247
|
for (let i = 0; i < args.length; i++) {
|
|
12177
12248
|
if (args[i] === "--server-url" && args[i + 1]) serverUrl = args[++i];
|
|
12178
12249
|
if (args[i] === "--api-key" && args[i + 1]) apiKey = args[++i];
|
|
@@ -12939,8 +13010,6 @@ var DaemonCore = class {
|
|
|
12939
13010
|
};
|
|
12940
13011
|
|
|
12941
13012
|
export {
|
|
12942
|
-
DAEMON_API_KEY_ENV,
|
|
12943
|
-
scrubDaemonAuthEnv,
|
|
12944
13013
|
resolveWorkspaceDirectoryPath,
|
|
12945
13014
|
scanWorkspaceDirectories,
|
|
12946
13015
|
deleteWorkspaceDirectory,
|
package/dist/core.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
DAEMON_API_KEY_ENV,
|
|
3
2
|
DAEMON_CLI_USAGE,
|
|
4
3
|
DaemonCore,
|
|
5
4
|
deleteWorkspaceDirectory,
|
|
@@ -9,14 +8,12 @@ import {
|
|
|
9
8
|
resolveChatBridgePath,
|
|
10
9
|
resolveSlockCliPath,
|
|
11
10
|
resolveWorkspaceDirectoryPath,
|
|
12
|
-
scanWorkspaceDirectories
|
|
13
|
-
|
|
14
|
-
} from "./chunk-OV4XD66N.js";
|
|
11
|
+
scanWorkspaceDirectories
|
|
12
|
+
} from "./chunk-4H5XFLYA.js";
|
|
15
13
|
import {
|
|
16
14
|
subscribeDaemonLogs
|
|
17
15
|
} from "./chunk-M2KQBJR3.js";
|
|
18
16
|
export {
|
|
19
|
-
DAEMON_API_KEY_ENV,
|
|
20
17
|
DAEMON_CLI_USAGE,
|
|
21
18
|
DaemonCore,
|
|
22
19
|
deleteWorkspaceDirectory,
|
|
@@ -27,6 +24,5 @@ export {
|
|
|
27
24
|
resolveSlockCliPath,
|
|
28
25
|
resolveWorkspaceDirectoryPath,
|
|
29
26
|
scanWorkspaceDirectories,
|
|
30
|
-
scrubDaemonAuthEnv,
|
|
31
27
|
subscribeDaemonLogs
|
|
32
28
|
};
|
package/dist/index.js
CHANGED
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
import {
|
|
3
3
|
DAEMON_CLI_USAGE,
|
|
4
4
|
DaemonCore,
|
|
5
|
-
parseDaemonCliArgs
|
|
6
|
-
|
|
7
|
-
} from "./chunk-OV4XD66N.js";
|
|
5
|
+
parseDaemonCliArgs
|
|
6
|
+
} from "./chunk-4H5XFLYA.js";
|
|
8
7
|
import "./chunk-M2KQBJR3.js";
|
|
9
8
|
|
|
10
9
|
// src/index.ts
|
|
11
|
-
var parsedArgs = parseDaemonCliArgs(process.argv.slice(2)
|
|
12
|
-
scrubDaemonAuthEnv(process.env);
|
|
10
|
+
var parsedArgs = parseDaemonCliArgs(process.argv.slice(2));
|
|
13
11
|
if (!parsedArgs) {
|
|
14
12
|
console.error(DAEMON_CLI_USAGE);
|
|
15
13
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
// src/drivers/piSdkRunner.ts
|
|
2
|
-
import { readFile } from "fs/promises";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import {
|
|
5
|
-
AuthStorage,
|
|
6
|
-
createAgentSessionFromServices,
|
|
7
|
-
createAgentSessionServices,
|
|
8
|
-
SessionManager
|
|
9
|
-
} from "@earendil-works/pi-coding-agent";
|
|
10
|
-
function writeJson(value) {
|
|
11
|
-
process.stdout.write(`${JSON.stringify(value)}
|
|
12
|
-
`);
|
|
13
|
-
}
|
|
14
|
-
function parseArgs(argv) {
|
|
15
|
-
const index = argv.indexOf("--config");
|
|
16
|
-
const configPath = index >= 0 ? argv[index + 1] : void 0;
|
|
17
|
-
if (!configPath) throw new Error("Missing --config <path>");
|
|
18
|
-
return { configPath };
|
|
19
|
-
}
|
|
20
|
-
function resolveConfiguredModel(modelId, modelRegistry) {
|
|
21
|
-
if (!modelId) return void 0;
|
|
22
|
-
const [provider, ...rest] = modelId.split("/");
|
|
23
|
-
const providerScopedId = rest.join("/");
|
|
24
|
-
if (provider && providerScopedId) {
|
|
25
|
-
const exact = modelRegistry.find(provider, providerScopedId);
|
|
26
|
-
if (exact) return exact;
|
|
27
|
-
}
|
|
28
|
-
return modelRegistry.getAll().find(
|
|
29
|
-
(model) => model.id === modelId || `${model.provider}/${model.id}` === modelId || (providerScopedId ? model.id === providerScopedId : false)
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
async function createSessionManager(config) {
|
|
33
|
-
if (!config.sessionId) return SessionManager.create(config.cwd, config.sessionDir);
|
|
34
|
-
const localSessions = await SessionManager.list(config.cwd, config.sessionDir);
|
|
35
|
-
const match = localSessions.find((session) => session.id.startsWith(config.sessionId));
|
|
36
|
-
if (match) return SessionManager.open(match.path, config.sessionDir);
|
|
37
|
-
return SessionManager.create(config.cwd, config.sessionDir);
|
|
38
|
-
}
|
|
39
|
-
async function run() {
|
|
40
|
-
const { configPath } = parseArgs(process.argv.slice(2));
|
|
41
|
-
const config = JSON.parse(await readFile(configPath, "utf8"));
|
|
42
|
-
const authStorage = AuthStorage.create(path.join(config.agentDir, "auth.json"));
|
|
43
|
-
const services = await createAgentSessionServices({
|
|
44
|
-
cwd: config.cwd,
|
|
45
|
-
agentDir: config.agentDir,
|
|
46
|
-
authStorage,
|
|
47
|
-
resourceLoaderOptions: {
|
|
48
|
-
appendSystemPrompt: [config.standingPrompt],
|
|
49
|
-
noContextFiles: true,
|
|
50
|
-
noExtensions: true,
|
|
51
|
-
noPromptTemplates: true,
|
|
52
|
-
noSkills: true,
|
|
53
|
-
noThemes: true
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
for (const diagnostic of services.diagnostics) {
|
|
57
|
-
const line = `[Pi SDK] ${diagnostic.type}: ${diagnostic.message}`;
|
|
58
|
-
if (diagnostic.type === "error") throw new Error(line);
|
|
59
|
-
process.stderr.write(`${line}
|
|
60
|
-
`);
|
|
61
|
-
}
|
|
62
|
-
const sessionManager = await createSessionManager(config);
|
|
63
|
-
const model = resolveConfiguredModel(config.model, services.modelRegistry);
|
|
64
|
-
if (config.model && !model) {
|
|
65
|
-
throw new Error(`Configured Pi model '${config.model}' was not found in Pi model registry.`);
|
|
66
|
-
}
|
|
67
|
-
const { session } = await createAgentSessionFromServices({
|
|
68
|
-
services,
|
|
69
|
-
sessionManager,
|
|
70
|
-
model
|
|
71
|
-
});
|
|
72
|
-
const header = session.sessionManager.getHeader();
|
|
73
|
-
if (header) writeJson(header);
|
|
74
|
-
const unsubscribe = session.subscribe((event) => writeJson(event));
|
|
75
|
-
try {
|
|
76
|
-
await session.prompt(config.prompt);
|
|
77
|
-
} finally {
|
|
78
|
-
unsubscribe();
|
|
79
|
-
session.dispose();
|
|
80
|
-
await services.settingsManager.flush();
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
run().catch((error) => {
|
|
84
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
85
|
-
writeJson({
|
|
86
|
-
type: "message_end",
|
|
87
|
-
message: {
|
|
88
|
-
role: "assistant",
|
|
89
|
-
content: [],
|
|
90
|
-
stopReason: "error",
|
|
91
|
-
errorMessage: message
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
writeJson({ type: "turn_end" });
|
|
95
|
-
process.exitCode = 1;
|
|
96
|
-
});
|