@slock-ai/daemon 0.53.2 → 0.54.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat-bridge.js +3 -5
- package/dist/{chunk-KNMCE6WB.js → chunk-VOZJ2ELH.js} +10 -1
- package/dist/{chunk-UIJF67BT.js → chunk-X366KJGT.js} +231 -68
- package/dist/cli/index.js +497 -56
- package/dist/cli/package.json +5 -0
- package/dist/core.js +2 -2
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/dist/chat-bridge.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
daemonFetch,
|
|
4
4
|
executeJsonRequest
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-VOZJ2ELH.js";
|
|
6
6
|
|
|
7
7
|
// src/chat-bridge.ts
|
|
8
8
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -47,9 +47,7 @@ var runtimeActionHeaders = {
|
|
|
47
47
|
...launchId ? { "X-Agent-Launch-Id": launchId } : {}
|
|
48
48
|
};
|
|
49
49
|
function bridgeFetch(url, init = {}) {
|
|
50
|
-
|
|
51
|
-
const requestInit = dispatcher ? { ...init, dispatcher } : init;
|
|
52
|
-
return fetch(url, requestInit);
|
|
50
|
+
return daemonFetch(url, init);
|
|
53
51
|
}
|
|
54
52
|
var server = new McpServer({
|
|
55
53
|
name: "chat",
|
|
@@ -207,6 +207,15 @@ function buildFetchDispatcher(targetUrl, env) {
|
|
|
207
207
|
return dispatcher;
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
// src/daemonFetch.ts
|
|
211
|
+
function withDaemonFetchProxy(input, init = {}, env = process.env) {
|
|
212
|
+
const dispatcher = buildFetchDispatcher(input.toString(), env);
|
|
213
|
+
return dispatcher ? { ...init, dispatcher } : init;
|
|
214
|
+
}
|
|
215
|
+
function daemonFetch(input, init, env = process.env) {
|
|
216
|
+
return fetch(input, withDaemonFetchProxy(input, init, env));
|
|
217
|
+
}
|
|
218
|
+
|
|
210
219
|
export {
|
|
211
220
|
subscribeDaemonLogs,
|
|
212
221
|
logger,
|
|
@@ -214,5 +223,5 @@ export {
|
|
|
214
223
|
executeJsonRequest,
|
|
215
224
|
executeResponseRequest,
|
|
216
225
|
buildWebSocketOptions,
|
|
217
|
-
|
|
226
|
+
daemonFetch
|
|
218
227
|
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS,
|
|
3
3
|
buildWebSocketOptions,
|
|
4
|
+
daemonFetch,
|
|
4
5
|
executeJsonRequest,
|
|
5
6
|
executeResponseRequest,
|
|
6
7
|
logger
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-VOZJ2ELH.js";
|
|
8
9
|
|
|
9
10
|
// src/core.ts
|
|
10
11
|
import path16 from "path";
|
|
@@ -609,13 +610,16 @@ var agentCreateOperationSchema = z.object({
|
|
|
609
610
|
name: z.string().trim().min(1).max(60),
|
|
610
611
|
description: z.string().trim().max(500).optional(),
|
|
611
612
|
/**
|
|
612
|
-
*
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
*
|
|
613
|
+
* Optional computer placement contract. Agents may only set this when the
|
|
614
|
+
* human request is explicitly computer-bound; server prepare resolves the
|
|
615
|
+
* name/UUID and stores the UUID-only form. `suggestedComputer` preselects
|
|
616
|
+
* the dialog when available; `requiredComputer` prevents silent fallback to
|
|
617
|
+
* any other computer.
|
|
618
|
+
*
|
|
619
|
+
* Runtime / model / reasoning effort remain human-picked technical fields.
|
|
618
620
|
*/
|
|
621
|
+
suggestedComputer: idOrHandleSchema.optional(),
|
|
622
|
+
requiredComputer: idOrHandleSchema.optional(),
|
|
619
623
|
draftHint: draftHintSchema
|
|
620
624
|
});
|
|
621
625
|
var channelAddMemberOperationSchema = z.object({
|
|
@@ -1501,7 +1505,7 @@ async function handleProxyRequest(req, res) {
|
|
|
1501
1505
|
headers.set("content-type", "application/json");
|
|
1502
1506
|
headers.set("content-length", String(Buffer.byteLength(prepared.bodyText)));
|
|
1503
1507
|
}
|
|
1504
|
-
const upstream = await
|
|
1508
|
+
const upstream = await daemonFetch(target, {
|
|
1505
1509
|
method,
|
|
1506
1510
|
headers,
|
|
1507
1511
|
body,
|
|
@@ -1518,15 +1522,12 @@ async function handleProxyRequest(req, res) {
|
|
|
1518
1522
|
res.writeHead(upstream.status, responseHeadersForLocalProxy(upstream));
|
|
1519
1523
|
if (upstream.body) {
|
|
1520
1524
|
const reader = upstream.body.getReader();
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
res.write(Buffer.from(value));
|
|
1526
|
-
}
|
|
1527
|
-
} finally {
|
|
1528
|
-
res.end();
|
|
1525
|
+
while (true) {
|
|
1526
|
+
const { done, value } = await reader.read();
|
|
1527
|
+
if (done) break;
|
|
1528
|
+
res.write(Buffer.from(value));
|
|
1529
1529
|
}
|
|
1530
|
+
res.end();
|
|
1530
1531
|
} else {
|
|
1531
1532
|
res.end();
|
|
1532
1533
|
}
|
|
@@ -1536,13 +1537,21 @@ async function handleProxyRequest(req, res) {
|
|
|
1536
1537
|
`[Agent Credential Proxy] request failed (agent=${registration.agentId}, launch=${registration.launchId ?? "none"}, method=${failure.method}, path=${failure.pathname}, query_keys=${failure.queryKeys.join(",") || "none"}): ${failure.errorName}: ${failure.errorMessage}`
|
|
1537
1538
|
);
|
|
1538
1539
|
registration.inboxCoordinator?.recordProxyFailure?.(failure);
|
|
1539
|
-
res
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1540
|
+
writeProxyFailureResponse(res, failure);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
function writeProxyFailureResponse(res, failure) {
|
|
1544
|
+
if (res.writableEnded) return;
|
|
1545
|
+
if (res.headersSent) {
|
|
1546
|
+
res.destroy();
|
|
1547
|
+
return;
|
|
1545
1548
|
}
|
|
1549
|
+
res.writeHead(502, { "content-type": "application/json" });
|
|
1550
|
+
res.end(JSON.stringify({
|
|
1551
|
+
error: "failed to proxy local agent request",
|
|
1552
|
+
code: "agent_proxy_failed",
|
|
1553
|
+
detail: failure.errorMessage
|
|
1554
|
+
}));
|
|
1546
1555
|
}
|
|
1547
1556
|
function proxyFailureForError(method, target, err) {
|
|
1548
1557
|
const queryKeys = target ? [.../* @__PURE__ */ new Set([...target.searchParams.keys()])].sort() : [];
|
|
@@ -1739,7 +1748,7 @@ async function loadRecentTargetMessages(registration, headers, target) {
|
|
|
1739
1748
|
const historyHeaders = new Headers(headers);
|
|
1740
1749
|
historyHeaders.delete("content-length");
|
|
1741
1750
|
historyHeaders.delete("content-type");
|
|
1742
|
-
const res = await
|
|
1751
|
+
const res = await daemonFetch(historyUrl, { method: "GET", headers: historyHeaders });
|
|
1743
1752
|
if (!res.ok) return [];
|
|
1744
1753
|
const parsed = await res.json().catch(() => null);
|
|
1745
1754
|
return Array.isArray(parsed?.messages) ? normalizeVisibleMessages(parsed.messages, target) : [];
|
|
@@ -1942,6 +1951,9 @@ var shellSingleQuote = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
|
|
|
1942
1951
|
var powershellSingleQuote = (value) => `'${value.replace(/'/g, "''")}'`;
|
|
1943
1952
|
var DEFAULT_ACTIVE_CAPABILITIES = "send,read,mentions,tasks,reactions,server,channels";
|
|
1944
1953
|
var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
1954
|
+
var RAW_CREDENTIAL_ENV_DENYLIST = [
|
|
1955
|
+
"SLOCK_AGENT_CREDENTIAL_KEY"
|
|
1956
|
+
];
|
|
1945
1957
|
var cachedOpencliBinPath;
|
|
1946
1958
|
function resolveOpencliBinPath() {
|
|
1947
1959
|
if (cachedOpencliBinPath !== void 0) return cachedOpencliBinPath;
|
|
@@ -2123,8 +2135,9 @@ exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(opencliBinPath)} "
|
|
|
2123
2135
|
PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
|
|
2124
2136
|
};
|
|
2125
2137
|
delete spawnEnv.SLOCK_AGENT_TOKEN;
|
|
2126
|
-
|
|
2127
|
-
|
|
2138
|
+
for (const key of RAW_CREDENTIAL_ENV_DENYLIST) {
|
|
2139
|
+
delete spawnEnv[key];
|
|
2140
|
+
}
|
|
2128
2141
|
delete spawnEnv.SLOCK_AGENT_PROXY_URL;
|
|
2129
2142
|
delete spawnEnv.SLOCK_AGENT_PROXY_TOKEN;
|
|
2130
2143
|
delete spawnEnv.SLOCK_AGENT_PROXY_TOKEN_FILE;
|
|
@@ -2148,6 +2161,118 @@ import path3 from "path";
|
|
|
2148
2161
|
function normalizeExecOutput(raw) {
|
|
2149
2162
|
return Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw ?? "");
|
|
2150
2163
|
}
|
|
2164
|
+
var WINDOWS_ENVIRONMENT_SCRIPT = [
|
|
2165
|
+
"& {",
|
|
2166
|
+
" $result = [ordered]@{}",
|
|
2167
|
+
" foreach ($scope in @('Machine', 'User')) {",
|
|
2168
|
+
" $scopeEnv = [Environment]::GetEnvironmentVariables($scope)",
|
|
2169
|
+
" $scopeObj = [ordered]@{}",
|
|
2170
|
+
" foreach ($key in $scopeEnv.Keys) {",
|
|
2171
|
+
" $value = $scopeEnv[$key]",
|
|
2172
|
+
" if ($null -ne $value) { $scopeObj[$key] = [string]$value }",
|
|
2173
|
+
" }",
|
|
2174
|
+
" $result[$scope] = $scopeObj",
|
|
2175
|
+
" }",
|
|
2176
|
+
" $result | ConvertTo-Json -Compress -Depth 3",
|
|
2177
|
+
"}"
|
|
2178
|
+
].join(" ");
|
|
2179
|
+
function normalizeProcessEnv(value) {
|
|
2180
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
2181
|
+
const env = {};
|
|
2182
|
+
for (const [key, rawValue] of Object.entries(value)) {
|
|
2183
|
+
if (rawValue !== void 0 && rawValue !== null) {
|
|
2184
|
+
env[key] = String(rawValue);
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
return env;
|
|
2188
|
+
}
|
|
2189
|
+
function readWindowsMachineUserEnvironment(env, execFileSyncFn) {
|
|
2190
|
+
try {
|
|
2191
|
+
const output = normalizeExecOutput(execFileSyncFn("powershell.exe", [
|
|
2192
|
+
"-NoProfile",
|
|
2193
|
+
"-NonInteractive",
|
|
2194
|
+
"-Command",
|
|
2195
|
+
WINDOWS_ENVIRONMENT_SCRIPT
|
|
2196
|
+
], {
|
|
2197
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
2198
|
+
env,
|
|
2199
|
+
timeout: 5e3
|
|
2200
|
+
}));
|
|
2201
|
+
const parsed = JSON.parse(output || "{}");
|
|
2202
|
+
return {
|
|
2203
|
+
machine: normalizeProcessEnv(parsed.Machine),
|
|
2204
|
+
user: normalizeProcessEnv(parsed.User)
|
|
2205
|
+
};
|
|
2206
|
+
} catch {
|
|
2207
|
+
return null;
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
function findEnvKey(env, name) {
|
|
2211
|
+
if (!env) return null;
|
|
2212
|
+
const lowerName = name.toLowerCase();
|
|
2213
|
+
const keys = Object.keys(env);
|
|
2214
|
+
for (let index = keys.length - 1; index >= 0; index -= 1) {
|
|
2215
|
+
const key = keys[index];
|
|
2216
|
+
if (key.toLowerCase() === lowerName) return key;
|
|
2217
|
+
}
|
|
2218
|
+
return null;
|
|
2219
|
+
}
|
|
2220
|
+
function getEnvValue(env, name) {
|
|
2221
|
+
const key = findEnvKey(env, name);
|
|
2222
|
+
return key ? env?.[key] : void 0;
|
|
2223
|
+
}
|
|
2224
|
+
function setEnvValue(env, key, value) {
|
|
2225
|
+
const existingKey = findEnvKey(env, key);
|
|
2226
|
+
if (existingKey && existingKey !== key) {
|
|
2227
|
+
delete env[existingKey];
|
|
2228
|
+
}
|
|
2229
|
+
env[key] = value;
|
|
2230
|
+
}
|
|
2231
|
+
function mergeWindowsPathSegments(values) {
|
|
2232
|
+
const segments = [];
|
|
2233
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2234
|
+
for (const value of values) {
|
|
2235
|
+
if (!value) continue;
|
|
2236
|
+
for (const rawSegment of value.split(";")) {
|
|
2237
|
+
const segment = rawSegment.trim();
|
|
2238
|
+
if (!segment) continue;
|
|
2239
|
+
const key = segment.toLowerCase();
|
|
2240
|
+
if (seen.has(key)) continue;
|
|
2241
|
+
seen.add(key);
|
|
2242
|
+
segments.push(segment);
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
return segments.length > 0 ? segments.join(";") : void 0;
|
|
2246
|
+
}
|
|
2247
|
+
function mergeWindowsEnvironmentScopes(baseEnv, scopes) {
|
|
2248
|
+
const merged = {};
|
|
2249
|
+
const layers = [scopes.machine ?? {}, scopes.user ?? {}, baseEnv];
|
|
2250
|
+
for (const layer of layers) {
|
|
2251
|
+
for (const [key, value] of Object.entries(layer)) {
|
|
2252
|
+
if (value === void 0 || key.toLowerCase() === "path") continue;
|
|
2253
|
+
setEnvValue(merged, key, value);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
const pathKey = findEnvKey(baseEnv, "Path") ?? findEnvKey(scopes.machine, "Path") ?? findEnvKey(scopes.user, "Path") ?? "Path";
|
|
2257
|
+
const pathValue = mergeWindowsPathSegments([
|
|
2258
|
+
getEnvValue(baseEnv, "Path"),
|
|
2259
|
+
getEnvValue(scopes.machine, "Path"),
|
|
2260
|
+
getEnvValue(scopes.user, "Path")
|
|
2261
|
+
]);
|
|
2262
|
+
if (pathValue) {
|
|
2263
|
+
merged[pathKey] = pathValue;
|
|
2264
|
+
}
|
|
2265
|
+
return merged;
|
|
2266
|
+
}
|
|
2267
|
+
function withWindowsUserEnvironment(env, deps = {}) {
|
|
2268
|
+
const platform = deps.platform ?? process.platform;
|
|
2269
|
+
if (platform !== "win32") return env;
|
|
2270
|
+
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
2271
|
+
const reader = deps.windowsEnvironmentReaderFn ?? readWindowsMachineUserEnvironment;
|
|
2272
|
+
const scopes = reader(env, execFileSyncFn);
|
|
2273
|
+
if (!scopes) return env;
|
|
2274
|
+
return mergeWindowsEnvironmentScopes(env, scopes);
|
|
2275
|
+
}
|
|
2151
2276
|
function resolveCommandOnWindows(command, env, execFileSyncFn, existsSyncFn) {
|
|
2152
2277
|
const script = "& {$cmd = Get-Command -Name $args[0] -ErrorAction Stop | Select-Object -First 1; if ($cmd.Path) { $cmd.Path } elseif ($cmd.Source) { $cmd.Source } elseif ($cmd.Definition) { $cmd.Definition } }";
|
|
2153
2278
|
try {
|
|
@@ -2185,7 +2310,7 @@ function resolveCommandOnWindows(command, env, execFileSyncFn, existsSyncFn) {
|
|
|
2185
2310
|
}
|
|
2186
2311
|
function resolveCommandOnPath(command, deps = {}) {
|
|
2187
2312
|
const platform = deps.platform ?? process.platform;
|
|
2188
|
-
const env = deps.env ?? process.env;
|
|
2313
|
+
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
2189
2314
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
2190
2315
|
const existsSyncFn = deps.existsSyncFn ?? existsSync2;
|
|
2191
2316
|
if (platform === "win32") {
|
|
@@ -2211,7 +2336,7 @@ function firstExistingPath(candidates, deps = {}) {
|
|
|
2211
2336
|
return null;
|
|
2212
2337
|
}
|
|
2213
2338
|
function readCommandVersion(command, args = [], deps = {}) {
|
|
2214
|
-
const env = deps.env ?? process.env;
|
|
2339
|
+
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
2215
2340
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
2216
2341
|
try {
|
|
2217
2342
|
const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
|
|
@@ -2488,6 +2613,7 @@ var ClaudeDriver = class {
|
|
|
2488
2613
|
const detail = parts.join(" | ") || fallback;
|
|
2489
2614
|
events.push({ kind: "error", message: detail });
|
|
2490
2615
|
};
|
|
2616
|
+
const isProviderApiFailureText = (value, hasToolUse) => !hasToolUse && /^\s*API Error:/i.test(value) && (/\b(?:ECONNRESET|EPIPE|ETIMEDOUT|ECONNREFUSED|ENOTFOUND|EAI_AGAIN)\b/i.test(value) || /\bUnable to connect to API\b/i.test(value) || /\b(?:timed out|timeout)\b/i.test(value) || /\b5\d{2}\b/.test(value));
|
|
2491
2617
|
switch (event.type) {
|
|
2492
2618
|
case "system":
|
|
2493
2619
|
if (event.subtype === "init" && event.session_id) {
|
|
@@ -2503,11 +2629,16 @@ var ClaudeDriver = class {
|
|
|
2503
2629
|
case "assistant": {
|
|
2504
2630
|
const content = event.message?.content;
|
|
2505
2631
|
if (Array.isArray(content)) {
|
|
2632
|
+
const hasToolUse = content.some((block) => block?.type === "tool_use");
|
|
2506
2633
|
for (const block of content) {
|
|
2507
2634
|
if (block.type === "thinking" && block.thinking) {
|
|
2508
2635
|
events.push({ kind: "thinking", text: block.thinking });
|
|
2509
2636
|
} else if (block.type === "text" && block.text) {
|
|
2510
|
-
|
|
2637
|
+
if (isProviderApiFailureText(block.text, hasToolUse)) {
|
|
2638
|
+
events.push({ kind: "error", message: block.text });
|
|
2639
|
+
} else {
|
|
2640
|
+
events.push({ kind: "text", text: block.text });
|
|
2641
|
+
}
|
|
2511
2642
|
} else if (block.type === "tool_use") {
|
|
2512
2643
|
events.push({ kind: "tool_call", name: block.name || "unknown_tool", input: block.input });
|
|
2513
2644
|
}
|
|
@@ -2821,6 +2952,11 @@ var CodexDriver = class {
|
|
|
2821
2952
|
sessionAnnounced = false;
|
|
2822
2953
|
streamedAgentMessageIds = /* @__PURE__ */ new Set();
|
|
2823
2954
|
streamedReasoningIds = /* @__PURE__ */ new Set();
|
|
2955
|
+
/**
|
|
2956
|
+
* Post-tool window where the app-server may not yet accept stdin steering.
|
|
2957
|
+
* Gate busy-mode delivery until turn/completed or next progress.
|
|
2958
|
+
*/
|
|
2959
|
+
steeringGateActive = false;
|
|
2824
2960
|
async spawn(ctx) {
|
|
2825
2961
|
ensureGitRepoForCodex(ctx.workingDirectory);
|
|
2826
2962
|
const { spawnEnv } = await prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
@@ -2835,6 +2971,7 @@ var CodexDriver = class {
|
|
|
2835
2971
|
this.sessionAnnounced = false;
|
|
2836
2972
|
this.streamedAgentMessageIds.clear();
|
|
2837
2973
|
this.streamedReasoningIds.clear();
|
|
2974
|
+
this.steeringGateActive = false;
|
|
2838
2975
|
const args = ["app-server", "--listen", "stdio://"];
|
|
2839
2976
|
args.push(...this.buildRuntimeActionsConfigArgs(ctx));
|
|
2840
2977
|
const { command, args: spawnArgs } = resolveCodexSpawn(args);
|
|
@@ -2908,6 +3045,7 @@ var CodexDriver = class {
|
|
|
2908
3045
|
if (typeof turnId === "string") {
|
|
2909
3046
|
this.activeTurnId = turnId;
|
|
2910
3047
|
}
|
|
3048
|
+
this.steeringGateActive = false;
|
|
2911
3049
|
events.push({ kind: "thinking", text: "" });
|
|
2912
3050
|
break;
|
|
2913
3051
|
}
|
|
@@ -2918,6 +3056,7 @@ var CodexDriver = class {
|
|
|
2918
3056
|
this.streamedAgentMessageIds.add(itemId);
|
|
2919
3057
|
}
|
|
2920
3058
|
if (typeof delta === "string" && delta.length > 0) {
|
|
3059
|
+
this.steeringGateActive = false;
|
|
2921
3060
|
events.push({ kind: "text", text: delta });
|
|
2922
3061
|
}
|
|
2923
3062
|
break;
|
|
@@ -2930,6 +3069,7 @@ var CodexDriver = class {
|
|
|
2930
3069
|
this.streamedReasoningIds.add(itemId);
|
|
2931
3070
|
}
|
|
2932
3071
|
if (typeof delta === "string" && delta.length > 0) {
|
|
3072
|
+
this.steeringGateActive = false;
|
|
2933
3073
|
events.push({ kind: "thinking", text: delta });
|
|
2934
3074
|
}
|
|
2935
3075
|
break;
|
|
@@ -2946,6 +3086,7 @@ var CodexDriver = class {
|
|
|
2946
3086
|
if (isCompleted && typeof item.id === "string" && !this.streamedReasoningIds.has(item.id)) {
|
|
2947
3087
|
const text = joinReasoningText(item);
|
|
2948
3088
|
if (text) {
|
|
3089
|
+
this.steeringGateActive = false;
|
|
2949
3090
|
events.push({ kind: "thinking", text });
|
|
2950
3091
|
}
|
|
2951
3092
|
}
|
|
@@ -2955,6 +3096,7 @@ var CodexDriver = class {
|
|
|
2955
3096
|
break;
|
|
2956
3097
|
case "agentMessage":
|
|
2957
3098
|
if (isCompleted && typeof item.id === "string" && !this.streamedAgentMessageIds.has(item.id) && typeof item.text === "string" && item.text.length > 0) {
|
|
3099
|
+
this.steeringGateActive = false;
|
|
2958
3100
|
events.push({ kind: "text", text: item.text });
|
|
2959
3101
|
}
|
|
2960
3102
|
if (isCompleted && typeof item.id === "string") {
|
|
@@ -2967,6 +3109,7 @@ var CodexDriver = class {
|
|
|
2967
3109
|
}
|
|
2968
3110
|
if (isCompleted) {
|
|
2969
3111
|
events.push({ kind: "tool_output", name: "shell" });
|
|
3112
|
+
this.steeringGateActive = true;
|
|
2970
3113
|
}
|
|
2971
3114
|
break;
|
|
2972
3115
|
case "contextCompaction":
|
|
@@ -2996,17 +3139,24 @@ var CodexDriver = class {
|
|
|
2996
3139
|
if (isCompleted) {
|
|
2997
3140
|
const toolName = item.server === "chat" ? `${this.mcpToolPrefix}${item.tool}` : `${this.mcpToolPrefix.replace(/_$/, "")}_${item.server}_${item.tool}`;
|
|
2998
3141
|
events.push({ kind: "tool_output", name: toolName });
|
|
3142
|
+
this.steeringGateActive = true;
|
|
2999
3143
|
}
|
|
3000
3144
|
break;
|
|
3001
3145
|
case "collabAgentToolCall":
|
|
3002
3146
|
if (isStarted) {
|
|
3003
3147
|
events.push({ kind: "tool_call", name: "collab_tool_call", input: { tool: item.tool, prompt: item.prompt } });
|
|
3004
3148
|
}
|
|
3149
|
+
if (isCompleted) {
|
|
3150
|
+
this.steeringGateActive = true;
|
|
3151
|
+
}
|
|
3005
3152
|
break;
|
|
3006
3153
|
case "webSearch":
|
|
3007
3154
|
if (isStarted) {
|
|
3008
3155
|
events.push({ kind: "tool_call", name: "web_search", input: { query: item.query } });
|
|
3009
3156
|
}
|
|
3157
|
+
if (isCompleted) {
|
|
3158
|
+
this.steeringGateActive = true;
|
|
3159
|
+
}
|
|
3010
3160
|
break;
|
|
3011
3161
|
}
|
|
3012
3162
|
break;
|
|
@@ -3019,6 +3169,7 @@ var CodexDriver = class {
|
|
|
3019
3169
|
this.activeTurnId = null;
|
|
3020
3170
|
this.streamedAgentMessageIds.clear();
|
|
3021
3171
|
this.streamedReasoningIds.clear();
|
|
3172
|
+
this.steeringGateActive = false;
|
|
3022
3173
|
events.push({ kind: "turn_end", sessionId: this.threadId || void 0 });
|
|
3023
3174
|
break;
|
|
3024
3175
|
}
|
|
@@ -3038,7 +3189,7 @@ var CodexDriver = class {
|
|
|
3038
3189
|
if (!this.threadId) return null;
|
|
3039
3190
|
const mode = opts?.mode || "busy";
|
|
3040
3191
|
if (mode === "busy") {
|
|
3041
|
-
if (!this.activeTurnId) return null;
|
|
3192
|
+
if (!this.activeTurnId || this.steeringGateActive) return null;
|
|
3042
3193
|
return JSON.stringify({
|
|
3043
3194
|
jsonrpc: "2.0",
|
|
3044
3195
|
id: this.nextRequestId(),
|
|
@@ -3452,8 +3603,9 @@ var CopilotDriver = class {
|
|
|
3452
3603
|
import { spawn as spawn5, spawnSync } from "child_process";
|
|
3453
3604
|
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync2, existsSync as existsSync5 } from "fs";
|
|
3454
3605
|
import path7 from "path";
|
|
3455
|
-
async function buildCursorSpawnEnv(ctx) {
|
|
3456
|
-
|
|
3606
|
+
async function buildCursorSpawnEnv(ctx, deps = {}) {
|
|
3607
|
+
const { spawnEnv } = await prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
3608
|
+
return withWindowsUserEnvironment(spawnEnv, deps);
|
|
3457
3609
|
}
|
|
3458
3610
|
var CursorDriver = class {
|
|
3459
3611
|
id = "cursor";
|
|
@@ -3637,9 +3789,16 @@ function detectCursorModels(runCommand = runCursorModelsCommand) {
|
|
|
3637
3789
|
if (result.error || result.status !== 0) return null;
|
|
3638
3790
|
return parseCursorModelsOutput(String(result.stdout || ""));
|
|
3639
3791
|
}
|
|
3792
|
+
function buildCursorModelProbeEnv(deps = {}) {
|
|
3793
|
+
return withWindowsUserEnvironment({
|
|
3794
|
+
...deps.env ?? process.env,
|
|
3795
|
+
FORCE_COLOR: "0",
|
|
3796
|
+
NO_COLOR: "1"
|
|
3797
|
+
}, deps);
|
|
3798
|
+
}
|
|
3640
3799
|
function runCursorModelsCommand() {
|
|
3641
3800
|
return spawnSync("cursor-agent", ["models"], {
|
|
3642
|
-
env:
|
|
3801
|
+
env: buildCursorModelProbeEnv(),
|
|
3643
3802
|
encoding: "utf8",
|
|
3644
3803
|
timeout: 5e3
|
|
3645
3804
|
});
|
|
@@ -4777,9 +4936,13 @@ function buildRuntimeErrorDiagnosticEnvelope(message) {
|
|
|
4777
4936
|
const { value: excerpt, truncated } = truncateDiagnosticText(scrubbed, MAX_RUNTIME_ERROR_MESSAGE_EXCERPT_CHARS);
|
|
4778
4937
|
const httpStatus = extractHttpStatus(rawMessage);
|
|
4779
4938
|
const runtimeErrorClass = classifyRuntimeError(rawMessage, httpStatus);
|
|
4939
|
+
const runtimeErrorReason = classifyRuntimeErrorReason(runtimeErrorClass);
|
|
4780
4940
|
const runtimeErrorAction = classifyRuntimeErrorAction(rawMessage, runtimeErrorClass);
|
|
4781
4941
|
const fingerprint = fingerprintRuntimeError(scrubbed);
|
|
4782
4942
|
const spanAttrs = {
|
|
4943
|
+
turn_outcome: "failed",
|
|
4944
|
+
turn_subtype: "runtime_error",
|
|
4945
|
+
turn_reason: runtimeErrorReason,
|
|
4783
4946
|
runtime_error_class: runtimeErrorClass,
|
|
4784
4947
|
runtime_error_action: runtimeErrorAction,
|
|
4785
4948
|
runtime_error_action_required: runtimeErrorAction !== "none",
|
|
@@ -4831,7 +4994,10 @@ function classifyRuntimeError(message, httpStatus) {
|
|
|
4831
4994
|
return "ProviderApiError";
|
|
4832
4995
|
}
|
|
4833
4996
|
if (isRuntimeAuthActionRequiredText(message)) return "AuthError";
|
|
4834
|
-
if (/\
|
|
4997
|
+
if (/\b(?:ETIMEDOUT|timeout|timed out)\b/i.test(message)) return "TimeoutError";
|
|
4998
|
+
if (/\b(?:ECONNRESET|EPIPE|ECONNREFUSED|ENOTFOUND|EAI_AGAIN)\b/i.test(message) || /\bUnable to connect to API\b/i.test(message)) {
|
|
4999
|
+
return "ProviderConnectionError";
|
|
5000
|
+
}
|
|
4835
5001
|
if (/stream closed before response\.completed|error decoding response body/i.test(message)) return "ProviderStreamError";
|
|
4836
5002
|
if (/\brate.?limit|too many requests\b/i.test(message)) return "RateLimitError";
|
|
4837
5003
|
if (/\bnot found\b/i.test(message)) return "NotFoundError";
|
|
@@ -4846,6 +5012,28 @@ function classifyRuntimeErrorAction(message, runtimeErrorClass) {
|
|
|
4846
5012
|
function isRuntimeAuthActionRequiredText(text) {
|
|
4847
5013
|
return RUNTIME_AUTH_ACTION_REQUIRED_PATTERNS.some((pattern) => pattern.test(text));
|
|
4848
5014
|
}
|
|
5015
|
+
function classifyRuntimeErrorReason(runtimeErrorClass) {
|
|
5016
|
+
switch (runtimeErrorClass) {
|
|
5017
|
+
case "ProviderConnectionError":
|
|
5018
|
+
return "provider_connection_error";
|
|
5019
|
+
case "TimeoutError":
|
|
5020
|
+
return "provider_timeout";
|
|
5021
|
+
case "ProviderStreamError":
|
|
5022
|
+
return "provider_stream_error";
|
|
5023
|
+
case "RateLimitError":
|
|
5024
|
+
return "rate_limited";
|
|
5025
|
+
case "AuthError":
|
|
5026
|
+
return "auth_failed";
|
|
5027
|
+
case "NotFoundError":
|
|
5028
|
+
return "not_found";
|
|
5029
|
+
case "ProviderServerError":
|
|
5030
|
+
return "provider_server_error";
|
|
5031
|
+
case "ProviderApiError":
|
|
5032
|
+
return "provider_api_error";
|
|
5033
|
+
default:
|
|
5034
|
+
return "unclassified_runtime_error";
|
|
5035
|
+
}
|
|
5036
|
+
}
|
|
4849
5037
|
function runtimeDisplayName(runtimeId) {
|
|
4850
5038
|
switch (runtimeId) {
|
|
4851
5039
|
case "antigravity":
|
|
@@ -5272,10 +5460,10 @@ For new channels, new agents, and adding members to an existing channel, post an
|
|
|
5272
5460
|
|
|
5273
5461
|
- Use \`slock action prepare --target <onboarding-channel>\` and pipe an \`ActionCardAction\` JSON. Identity references are handles (\`@alice\` / \`@scout\` / \`#general\` \u2014 bare names work too), never UUIDs. Server resolves at prepare time.
|
|
5274
5462
|
- \`{type: "channel:create", name, visibility: "public" | "private", description?, initialHumans?: ["@alice"], initialAgents?: ["@scout"], draftHint?}\`
|
|
5275
|
-
- \`{type: "agent:create", name, description?, draftHint?}\`
|
|
5463
|
+
- \`{type: "agent:create", name, description?, suggestedComputer?, requiredComputer?, draftHint?}\`
|
|
5276
5464
|
- \`{type: "channel:add_member", channel: "#existing-channel", humans?: ["@alice"], agents?: ["@scout"], draftHint?}\` \u2014 at least one of humans / agents must be non-empty
|
|
5277
5465
|
- The owner clicks the button on the card; the matching dialog opens **prefilled with your values** (editable, deselectable for add_member). They review, adjust, and submit; the action is committed under their identity.
|
|
5278
|
-
-
|
|
5466
|
+
- Runtime / model / reasoning effort are NOT yours to prefill on \`agent:create\`. If the human request explicitly binds the agent to a computer, use a structured \`requiredComputer\` (or \`suggestedComputer\` for a soft preference) instead of burying the constraint in \`draftHint\`; otherwise stay on semantic intent (name + description).
|
|
5279
5467
|
- For \`channel:add_member\`, only suggest people who are actually likely candidates (already in the server, relevant to the channel's topic). The owner will deselect anyone they don't want \u2014 make their default-yes list useful, not exhaustive.
|
|
5280
5468
|
- Do not just describe or list copyable specs once action cards are available \u2014 the human input cost should land at "click the card, review, submit", not "copy this name into the dialog yourself".
|
|
5281
5469
|
- Do not imply the resource has been created or members added until the card flips to "Done".
|
|
@@ -5528,7 +5716,7 @@ Do not copy these answers verbatim.
|
|
|
5528
5716
|
- When the owner agrees to a new agent or channel, **post an action card** with \`slock action prepare\`. The card lives inline in chat; the owner clicks the action button, the matching create dialog opens prefilled with your values (editable), and the resource is created under their identity when they submit.
|
|
5529
5717
|
- v1 supports three action types via \`slock action prepare --target '<channel>' <<'SLOCKACTION' { ... } SLOCKACTION\`:
|
|
5530
5718
|
- \`{type: "channel:create", name, visibility: "public" | "private", description?, initialHumans?: ["@alice"], initialAgents?: ["@scout"], draftHint?}\`
|
|
5531
|
-
- \`{type: "agent:create", name, description?, draftHint?}\` \u2014 runtime / model /
|
|
5719
|
+
- \`{type: "agent:create", name, description?, suggestedComputer?, requiredComputer?, draftHint?}\` \u2014 runtime / model / reasoning effort are the owner's call. Use \`requiredComputer\` only when the owner explicitly says the new agent must run on that computer; use \`suggestedComputer\` for a soft preference.
|
|
5532
5720
|
- \`{type: "channel:add_member", channel: "#existing-channel", humans?: ["@alice"], agents?: ["@scout"], draftHint?}\` \u2014 at least one of humans / agents must be non-empty. The owner clicks "Add Members" on the card; an AddMembers dialog opens with your suggested list (each row toggleable) and the owner submits to actually add them.
|
|
5533
5721
|
|
|
5534
5722
|
- **Identity references are handles, not UUIDs.** Use \`@alice\` / \`@scout\` / \`#general\` (or bare \`alice\` / \`scout\` / \`general\`). The server resolves to UUIDs at prepare time. If a handle doesn't match a real human / agent / channel in this server you get a 422 INVALID_HANDLE error pointing at the field \u2014 fix the handle and retry. You should never see or write UUIDs in action card payloads.
|
|
@@ -5539,7 +5727,7 @@ Do not copy these answers verbatim.
|
|
|
5539
5727
|
|
|
5540
5728
|
### Guardrail
|
|
5541
5729
|
- Do not imply you already created agents or channels unless the card state is \`executed\`.
|
|
5542
|
-
- Do not prefill
|
|
5730
|
+
- Do not prefill runtime / model / reasoning effort on \`agent:create\`. Computer placement is only allowed as the structured \`suggestedComputer\` / \`requiredComputer\` field when the owner's request includes that placement; never rely on \`draftHint\` for a computer constraint.
|
|
5543
5731
|
- If the action type the user wants is not yet supported (e.g. \`channel:add_member\`), say so plainly and offer the manual UI path; do not invent action types the schema does not accept.
|
|
5544
5732
|
`;
|
|
5545
5733
|
}
|
|
@@ -6886,7 +7074,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6886
7074
|
}
|
|
6887
7075
|
async requestManagedRunnerCredentialOnce(agentId, config) {
|
|
6888
7076
|
const url = new URL(`/internal/computer/runners/${encodeURIComponent(agentId)}/credentials`, this.serverUrl);
|
|
6889
|
-
const res = await
|
|
7077
|
+
const res = await daemonFetch(url, {
|
|
6890
7078
|
method: "POST",
|
|
6891
7079
|
headers: {
|
|
6892
7080
|
Authorization: `Bearer ${this.daemonApiKey}`,
|
|
@@ -6984,7 +7172,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6984
7172
|
`/internal/computer/runners/${encodeURIComponent(agentId)}/credentials/${encodeURIComponent(credentialId)}`,
|
|
6985
7173
|
this.serverUrl
|
|
6986
7174
|
);
|
|
6987
|
-
void
|
|
7175
|
+
void daemonFetch(url, {
|
|
6988
7176
|
method: "DELETE",
|
|
6989
7177
|
headers: {
|
|
6990
7178
|
Authorization: `Bearer ${this.daemonApiKey}`,
|
|
@@ -7065,14 +7253,6 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
7065
7253
|
});
|
|
7066
7254
|
logger.info(`[Agent ${agentId}] Queued runtime profile ${kind} ${key} during startup`);
|
|
7067
7255
|
}
|
|
7068
|
-
splitRuntimeProfileControlBatch(messages) {
|
|
7069
|
-
const controlMessages = messages.filter((message) => runtimeProfileNotificationFromMessage(message));
|
|
7070
|
-
if (controlMessages.length === 0 || controlMessages.length === messages.length) {
|
|
7071
|
-
return { nextMessages: messages, deferredMessages: [] };
|
|
7072
|
-
}
|
|
7073
|
-
const deferredMessages = messages.filter((message) => !runtimeProfileNotificationFromMessage(message));
|
|
7074
|
-
return { nextMessages: controlMessages, deferredMessages };
|
|
7075
|
-
}
|
|
7076
7256
|
containsOrdinaryInboxMessage(messages) {
|
|
7077
7257
|
return messages.some((message) => !runtimeProfileNotificationFromMessage(message));
|
|
7078
7258
|
}
|
|
@@ -8602,7 +8782,6 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8602
8782
|
...runtimeTraceCounterAttrs(ap)
|
|
8603
8783
|
});
|
|
8604
8784
|
this.endRuntimeTrace(ap, "error", {
|
|
8605
|
-
outcome: "runtime-error",
|
|
8606
8785
|
...runtimeErrorDiagnostics.spanAttrs,
|
|
8607
8786
|
...runtimeTraceCounterAttrs(ap),
|
|
8608
8787
|
...this.finalizeRuntimeProfileTurnControl(agentId, ap, "runtime_error")
|
|
@@ -8775,22 +8954,6 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8775
8954
|
return true;
|
|
8776
8955
|
}
|
|
8777
8956
|
}
|
|
8778
|
-
const split = this.splitRuntimeProfileControlBatch(messages);
|
|
8779
|
-
if (split.deferredMessages.length > 0) {
|
|
8780
|
-
ap.inbox.unshift(...split.deferredMessages);
|
|
8781
|
-
ap.pendingNotificationCount += split.deferredMessages.length;
|
|
8782
|
-
messages = split.nextMessages;
|
|
8783
|
-
this.recordDaemonTrace("daemon.agent.runtime_profile.split_batch", {
|
|
8784
|
-
agentId,
|
|
8785
|
-
launchId: ap.launchId || void 0,
|
|
8786
|
-
runtime: ap.config.runtime,
|
|
8787
|
-
mode,
|
|
8788
|
-
delivered_control_messages_count: messages.length,
|
|
8789
|
-
deferred_messages_count: split.deferredMessages.length,
|
|
8790
|
-
inbox_count: ap.inbox.length,
|
|
8791
|
-
pending_notification_count: ap.pendingNotificationCount
|
|
8792
|
-
});
|
|
8793
|
-
}
|
|
8794
8957
|
const traceAttrs = {
|
|
8795
8958
|
agentId,
|
|
8796
8959
|
launchId: ap.launchId || void 0,
|
|
@@ -9474,7 +9637,7 @@ async function requestDaemonScopeAttestation({
|
|
|
9474
9637
|
apiKey,
|
|
9475
9638
|
scope,
|
|
9476
9639
|
metadata,
|
|
9477
|
-
fetchImpl =
|
|
9640
|
+
fetchImpl = daemonFetch,
|
|
9478
9641
|
timeoutMs = DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS
|
|
9479
9642
|
}) {
|
|
9480
9643
|
const { response, data } = await executeJsonRequest(
|
|
@@ -9507,7 +9670,7 @@ async function createDirectUploadSession({
|
|
|
9507
9670
|
createPath = "/api/uploads",
|
|
9508
9671
|
body,
|
|
9509
9672
|
attestationMetadata,
|
|
9510
|
-
fetchImpl =
|
|
9673
|
+
fetchImpl = daemonFetch,
|
|
9511
9674
|
timeoutMs = DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS
|
|
9512
9675
|
}) {
|
|
9513
9676
|
const capability = await requestDaemonScopeAttestation({
|
|
@@ -9549,7 +9712,7 @@ async function uploadWithSignedCapability({
|
|
|
9549
9712
|
createBody,
|
|
9550
9713
|
attestationMetadata,
|
|
9551
9714
|
uploadBody,
|
|
9552
|
-
fetchImpl =
|
|
9715
|
+
fetchImpl = daemonFetch,
|
|
9553
9716
|
timeoutMs = DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS
|
|
9554
9717
|
}) {
|
|
9555
9718
|
const { capability, response: session } = await createDirectUploadSession({
|
|
@@ -10173,7 +10336,7 @@ var DaemonCore = class {
|
|
|
10173
10336
|
}
|
|
10174
10337
|
async requestRunnerCredentialOnce(agentId, config) {
|
|
10175
10338
|
const url = new URL(`/internal/computer/runners/${encodeURIComponent(agentId)}/credentials`, this.options.serverUrl);
|
|
10176
|
-
const res = await
|
|
10339
|
+
const res = await daemonFetch(url, {
|
|
10177
10340
|
method: "POST",
|
|
10178
10341
|
headers: {
|
|
10179
10342
|
"Authorization": `Bearer ${this.options.apiKey}`,
|