@alook/daemon 0.1.29 → 0.1.31
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/cli/index.js +570 -167
- package/dist/index.js +417 -90
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -119,6 +119,9 @@ function createDefaultAgentDriverHost(options = {}) {
|
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
// agent-driver/dist/adapters/claude/index.js
|
|
123
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
124
|
+
|
|
122
125
|
// agent-driver/dist/controller/process-host.js
|
|
123
126
|
import { EventEmitter } from "events";
|
|
124
127
|
|
|
@@ -698,6 +701,7 @@ class ProcessLane {
|
|
|
698
701
|
admissionSequence = 0;
|
|
699
702
|
activeTerminalReceipt;
|
|
700
703
|
stopPromise;
|
|
704
|
+
pendingInterrupt;
|
|
701
705
|
pendingPromptAdmission;
|
|
702
706
|
constructor(driver, ctx, opts = {}) {
|
|
703
707
|
this.driver = driver;
|
|
@@ -737,12 +741,14 @@ class ProcessLane {
|
|
|
737
741
|
try {
|
|
738
742
|
spawned = await this.driver.spawn(launchCtx);
|
|
739
743
|
} catch (error) {
|
|
744
|
+
this.settlePendingInterrupt(false);
|
|
740
745
|
this.settlePendingPrompt({ ok: false, reason: "runtime_error", error: String(error) });
|
|
741
746
|
throw error;
|
|
742
747
|
}
|
|
743
748
|
const { process: proc } = spawned;
|
|
744
749
|
this.process = proc;
|
|
745
750
|
this.attachProcess(proc);
|
|
751
|
+
this.dispatchPendingInterrupt(proc);
|
|
746
752
|
this.armPendingPromptTimeout();
|
|
747
753
|
if (this.driver.execution.lifetime === "session" && !this.writableStdin(proc)) {
|
|
748
754
|
const rejection = this.stdinUnavailableAdmission();
|
|
@@ -841,6 +847,7 @@ class ProcessLane {
|
|
|
841
847
|
pending.resolve(admission);
|
|
842
848
|
}
|
|
843
849
|
stop(opts = {}) {
|
|
850
|
+
this.settlePendingInterrupt(false);
|
|
844
851
|
this.settlePendingPrompt({ ok: false, reason: "closed", error: "runtime lane stopped before command admission" });
|
|
845
852
|
if (!this.process)
|
|
846
853
|
return Promise.resolve();
|
|
@@ -859,11 +866,39 @@ class ProcessLane {
|
|
|
859
866
|
proc.kill(opts?.signal ?? "SIGTERM");
|
|
860
867
|
}
|
|
861
868
|
}
|
|
862
|
-
async interrupt() {
|
|
869
|
+
async interrupt(input) {
|
|
863
870
|
const proc = this.process;
|
|
864
|
-
if (!proc
|
|
871
|
+
if (!proc) {
|
|
872
|
+
if (!this.started)
|
|
873
|
+
return false;
|
|
874
|
+
if (this.pendingInterrupt)
|
|
875
|
+
return this.pendingInterrupt.promise;
|
|
876
|
+
let resolve;
|
|
877
|
+
let reject;
|
|
878
|
+
const promise = new Promise((res, rej) => {
|
|
879
|
+
resolve = res;
|
|
880
|
+
reject = rej;
|
|
881
|
+
});
|
|
882
|
+
this.pendingInterrupt = { input, promise, resolve, reject };
|
|
883
|
+
return promise;
|
|
884
|
+
}
|
|
885
|
+
if (this.closed)
|
|
865
886
|
return false;
|
|
866
|
-
return
|
|
887
|
+
return this.driver.interrupt(input, proc);
|
|
888
|
+
}
|
|
889
|
+
dispatchPendingInterrupt(proc) {
|
|
890
|
+
const pending = this.pendingInterrupt;
|
|
891
|
+
if (!pending)
|
|
892
|
+
return;
|
|
893
|
+
this.pendingInterrupt = undefined;
|
|
894
|
+
this.driver.interrupt(pending.input, proc).then(pending.resolve, pending.reject);
|
|
895
|
+
}
|
|
896
|
+
settlePendingInterrupt(accepted) {
|
|
897
|
+
const pending = this.pendingInterrupt;
|
|
898
|
+
if (!pending)
|
|
899
|
+
return;
|
|
900
|
+
this.pendingInterrupt = undefined;
|
|
901
|
+
pending.resolve(accepted);
|
|
867
902
|
}
|
|
868
903
|
updateSettings(input) {
|
|
869
904
|
return this.driver.updateSettings?.(input) ?? Promise.resolve({ status: "unsupported" });
|
|
@@ -1200,6 +1235,13 @@ function tryParseJsonLine(line) {
|
|
|
1200
1235
|
|
|
1201
1236
|
// agent-driver/dist/adapters/claude/normalizer.js
|
|
1202
1237
|
var API_ERROR_RE = /API Error:.*(?:Connection error|\b[45]\d{2}\b)/i;
|
|
1238
|
+
var CLAUDE_RESULT_ERROR_CODES = new Map([
|
|
1239
|
+
["error_max_turns", "claude.error_max_turns"],
|
|
1240
|
+
["error_during_execution", "claude.error_during_execution"],
|
|
1241
|
+
["error_max_budget_usd", "claude.error_max_budget_usd"],
|
|
1242
|
+
["error_max_structured_output_retries", "claude.error_max_structured_output_retries"]
|
|
1243
|
+
]);
|
|
1244
|
+
var CLAUDE_INTERRUPT_TERMINAL_REASONS = new Set(["aborted_streaming", "aborted_tools"]);
|
|
1203
1245
|
var CLAUDE_USAGE_COMPONENTS = [
|
|
1204
1246
|
"inputTokens",
|
|
1205
1247
|
"outputTokens",
|
|
@@ -1293,9 +1335,9 @@ class ClaudeEventNormalizer {
|
|
|
1293
1335
|
out.push({ kind: "assistant_reasoning_completed", text: block.thinking ?? "" });
|
|
1294
1336
|
} else if (block?.type === "text") {
|
|
1295
1337
|
const text = block.text ?? "";
|
|
1296
|
-
if (API_ERROR_RE.test(text))
|
|
1297
|
-
out.push({ kind: "error", message: text });
|
|
1298
|
-
else
|
|
1338
|
+
if (API_ERROR_RE.test(text)) {
|
|
1339
|
+
out.push({ kind: "error", code: "claude.api_error", message: text });
|
|
1340
|
+
} else
|
|
1299
1341
|
completedText.push(text);
|
|
1300
1342
|
} else if (block?.type === "tool_use") {
|
|
1301
1343
|
out.push({ kind: "tool_call", name: block.name ?? "unknown_tool", input: block.input });
|
|
@@ -1321,14 +1363,19 @@ class ClaudeEventNormalizer {
|
|
|
1321
1363
|
}
|
|
1322
1364
|
handleResult(event, out) {
|
|
1323
1365
|
const rawOwner = typeof event.user_message_uuid === "string" && event.user_message_uuid.length > 0 ? event.user_message_uuid : null;
|
|
1324
|
-
const
|
|
1366
|
+
const interruptedTerminal = Boolean(this.turnProtocol && !rawOwner && event.subtype === "error_during_execution" && CLAUDE_INTERRUPT_TERMINAL_REASONS.has(event.terminal_reason));
|
|
1367
|
+
const turnOwner = rawOwner ? this.turnProtocol?.claimResult(rawOwner) ?? (this.turnProtocol ? null : `claude:${rawOwner}`) : interruptedTerminal ? this.turnProtocol.claimInterruptedResult() : null;
|
|
1325
1368
|
if (this.turnProtocol && !turnOwner)
|
|
1326
1369
|
return;
|
|
1327
1370
|
const usage = this.buildUsageTelemetry(event, rawOwner);
|
|
1328
1371
|
if (usage)
|
|
1329
1372
|
out.push(usage);
|
|
1330
|
-
if (event.is_error || event.subtype === "error_during_execution") {
|
|
1331
|
-
out.push({
|
|
1373
|
+
if (!interruptedTerminal && (event.is_error || event.subtype === "error_during_execution")) {
|
|
1374
|
+
out.push({
|
|
1375
|
+
kind: "error",
|
|
1376
|
+
code: CLAUDE_RESULT_ERROR_CODES.get(event.subtype) ?? "claude.result_error",
|
|
1377
|
+
message: String(event.result ?? "Claude runtime error")
|
|
1378
|
+
});
|
|
1332
1379
|
}
|
|
1333
1380
|
out.push({
|
|
1334
1381
|
kind: "turn_end",
|
|
@@ -1606,6 +1653,7 @@ class ClaudeTurnProtocol {
|
|
|
1606
1653
|
segmentOwnerUuid = null;
|
|
1607
1654
|
delivered = new Map;
|
|
1608
1655
|
awaitingFollowOn = false;
|
|
1656
|
+
interruptRequested = false;
|
|
1609
1657
|
finalized = false;
|
|
1610
1658
|
beginTurn() {
|
|
1611
1659
|
const uuid = randomUUID4();
|
|
@@ -1614,6 +1662,7 @@ class ClaudeTurnProtocol {
|
|
|
1614
1662
|
this.delivered.clear();
|
|
1615
1663
|
this.delivered.set(uuid, { acknowledged: false, followOn: false });
|
|
1616
1664
|
this.awaitingFollowOn = false;
|
|
1665
|
+
this.interruptRequested = false;
|
|
1617
1666
|
this.finalized = false;
|
|
1618
1667
|
return this.receipt(uuid);
|
|
1619
1668
|
}
|
|
@@ -1640,6 +1689,13 @@ class ClaudeTurnProtocol {
|
|
|
1640
1689
|
return false;
|
|
1641
1690
|
return this.delivered.get(this.rootUuid)?.acknowledged === true;
|
|
1642
1691
|
}
|
|
1692
|
+
hasActiveTurn() {
|
|
1693
|
+
return this.rootUuid !== null && !this.finalized;
|
|
1694
|
+
}
|
|
1695
|
+
noteInterruptRequested() {
|
|
1696
|
+
if (this.hasActiveTurn())
|
|
1697
|
+
this.interruptRequested = true;
|
|
1698
|
+
}
|
|
1643
1699
|
claimResult(userMessageUuid) {
|
|
1644
1700
|
if (this.finalized || !this.rootUuid || userMessageUuid !== this.segmentOwnerUuid)
|
|
1645
1701
|
return null;
|
|
@@ -1656,6 +1712,19 @@ class ClaudeTurnProtocol {
|
|
|
1656
1712
|
this.finalized = true;
|
|
1657
1713
|
return this.receipt(this.rootUuid);
|
|
1658
1714
|
}
|
|
1715
|
+
claimInterruptedResult() {
|
|
1716
|
+
if (this.finalized || !this.rootUuid || !this.interruptRequested)
|
|
1717
|
+
return null;
|
|
1718
|
+
const unacknowledged = [...this.delivered.values()].filter((input) => !input.acknowledged);
|
|
1719
|
+
if (unacknowledged.length > 0) {
|
|
1720
|
+
this.awaitingFollowOn = true;
|
|
1721
|
+
for (const input of unacknowledged)
|
|
1722
|
+
input.followOn = true;
|
|
1723
|
+
return null;
|
|
1724
|
+
}
|
|
1725
|
+
this.finalized = true;
|
|
1726
|
+
return this.receipt(this.rootUuid);
|
|
1727
|
+
}
|
|
1659
1728
|
receipt(uuid) {
|
|
1660
1729
|
return `claude:${uuid}`;
|
|
1661
1730
|
}
|
|
@@ -1681,7 +1750,9 @@ class ClaudeDriver {
|
|
|
1681
1750
|
};
|
|
1682
1751
|
turnProtocol = new ClaudeTurnProtocol;
|
|
1683
1752
|
eventNormalizer = new ClaudeEventNormalizer(this.turnProtocol);
|
|
1753
|
+
pendingInterrupt;
|
|
1684
1754
|
beginTurn() {
|
|
1755
|
+
this.pendingInterrupt = undefined;
|
|
1685
1756
|
const receipt = this.turnProtocol.beginTurn();
|
|
1686
1757
|
this.eventNormalizer.beginTurn();
|
|
1687
1758
|
return receipt;
|
|
@@ -1720,11 +1791,45 @@ class ClaudeDriver {
|
|
|
1720
1791
|
return { process: proc };
|
|
1721
1792
|
}
|
|
1722
1793
|
normalizeLine(line) {
|
|
1723
|
-
|
|
1794
|
+
const events = this.eventNormalizer.normalizeLine(line);
|
|
1795
|
+
this.flushPendingInterrupt();
|
|
1796
|
+
return events;
|
|
1724
1797
|
}
|
|
1725
1798
|
get currentSessionId() {
|
|
1726
1799
|
return this.eventNormalizer.currentSessionId;
|
|
1727
1800
|
}
|
|
1801
|
+
async interrupt(input, process2) {
|
|
1802
|
+
const stdin = process2.stdin;
|
|
1803
|
+
if (!this.turnProtocol.hasActiveTurn() || !stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false)
|
|
1804
|
+
return false;
|
|
1805
|
+
this.turnProtocol.noteInterruptRequested();
|
|
1806
|
+
if (!this.turnProtocol.acceptsTurnWork()) {
|
|
1807
|
+
this.pendingInterrupt ??= { input, process: process2 };
|
|
1808
|
+
return true;
|
|
1809
|
+
}
|
|
1810
|
+
this.writeInterrupt(input, process2);
|
|
1811
|
+
return true;
|
|
1812
|
+
}
|
|
1813
|
+
writeInterrupt(input, process2) {
|
|
1814
|
+
process2.stdin.write(JSON.stringify({
|
|
1815
|
+
type: "control_request",
|
|
1816
|
+
request_id: input.requestId ?? randomUUID5(),
|
|
1817
|
+
request: { subtype: "interrupt" }
|
|
1818
|
+
}) + `
|
|
1819
|
+
`);
|
|
1820
|
+
}
|
|
1821
|
+
flushPendingInterrupt() {
|
|
1822
|
+
const pending = this.pendingInterrupt;
|
|
1823
|
+
if (!pending || !this.turnProtocol.acceptsTurnWork())
|
|
1824
|
+
return;
|
|
1825
|
+
this.pendingInterrupt = undefined;
|
|
1826
|
+
const stdin = pending.process.stdin;
|
|
1827
|
+
if (!stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false)
|
|
1828
|
+
return;
|
|
1829
|
+
try {
|
|
1830
|
+
this.writeInterrupt(pending.input, pending.process);
|
|
1831
|
+
} catch {}
|
|
1832
|
+
}
|
|
1728
1833
|
encodeMessage(text, sessionId, opts) {
|
|
1729
1834
|
const uuid = opts?.mode === "idle" ? this.turnProtocol.rootInputUuid() : this.turnProtocol.steeringInputUuid();
|
|
1730
1835
|
return JSON.stringify({
|
|
@@ -1856,6 +1961,35 @@ import { randomBytes } from "node:crypto";
|
|
|
1856
1961
|
var codexQuotaSourceEpoch = randomBytes(16).toString("base64url");
|
|
1857
1962
|
var codexQuotaSourceGeneration = 0;
|
|
1858
1963
|
var codexAccountFingerprint = null;
|
|
1964
|
+
var CODEX_ERROR_INFO_CODES = new Set([
|
|
1965
|
+
"contextWindowExceeded",
|
|
1966
|
+
"sessionBudgetExceeded",
|
|
1967
|
+
"usageLimitExceeded",
|
|
1968
|
+
"serverOverloaded",
|
|
1969
|
+
"cyberPolicy",
|
|
1970
|
+
"misalignmentPolicyViolation",
|
|
1971
|
+
"internalServerError",
|
|
1972
|
+
"unauthorized",
|
|
1973
|
+
"badRequest",
|
|
1974
|
+
"threadRollbackFailed",
|
|
1975
|
+
"sandboxError",
|
|
1976
|
+
"other",
|
|
1977
|
+
"httpConnectionFailed",
|
|
1978
|
+
"responseStreamConnectionFailed",
|
|
1979
|
+
"responseStreamDisconnected",
|
|
1980
|
+
"responseTooManyFailedAttempts",
|
|
1981
|
+
"activeTurnNotSteerable"
|
|
1982
|
+
]);
|
|
1983
|
+
function snakeCase(value) {
|
|
1984
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
1985
|
+
}
|
|
1986
|
+
function codexErrorInfoCode(value, fallback) {
|
|
1987
|
+
const label = typeof value === "string" ? value : value && typeof value === "object" && !Array.isArray(value) ? Object.keys(value)[0] : undefined;
|
|
1988
|
+
return label && CODEX_ERROR_INFO_CODES.has(label) ? `codex.${snakeCase(label)}` : fallback;
|
|
1989
|
+
}
|
|
1990
|
+
function codexRpcErrorCode(value) {
|
|
1991
|
+
return typeof value === "number" && Number.isSafeInteger(value) ? `codex.rpc.${value}` : "codex.rpc_error";
|
|
1992
|
+
}
|
|
1859
1993
|
function rotateCodexQuotaSource() {
|
|
1860
1994
|
codexQuotaSourceEpoch = randomBytes(16).toString("base64url");
|
|
1861
1995
|
codexQuotaSourceGeneration += 1;
|
|
@@ -2013,7 +2147,11 @@ class CodexEventNormalizer {
|
|
|
2013
2147
|
return this.replaceQuotaSnapshots(msg.result ?? {});
|
|
2014
2148
|
}
|
|
2015
2149
|
if (msg?.error && msg.id !== undefined) {
|
|
2016
|
-
return [{
|
|
2150
|
+
return [{
|
|
2151
|
+
kind: "error",
|
|
2152
|
+
code: codexRpcErrorCode(msg.error?.code),
|
|
2153
|
+
message: msg.error?.message ?? "Codex RPC error"
|
|
2154
|
+
}];
|
|
2017
2155
|
}
|
|
2018
2156
|
if (msg?.result?.thread?.id) {
|
|
2019
2157
|
return this.adoptAndInit(msg.result.thread.id);
|
|
@@ -2082,20 +2220,26 @@ class CodexEventNormalizer {
|
|
|
2082
2220
|
return [];
|
|
2083
2221
|
this.releaseUsageForTurn(params.threadId, params.turn.id);
|
|
2084
2222
|
if (params.turn.status === "failed") {
|
|
2223
|
+
const error = params.turn.error;
|
|
2085
2224
|
return [
|
|
2086
|
-
{
|
|
2225
|
+
{
|
|
2226
|
+
kind: "error",
|
|
2227
|
+
code: codexErrorInfoCode(error?.codexErrorInfo, "codex.turn_failed"),
|
|
2228
|
+
message: error?.message ?? "Codex turn failed"
|
|
2229
|
+
},
|
|
2087
2230
|
{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }
|
|
2088
2231
|
];
|
|
2089
2232
|
}
|
|
2090
|
-
if (params.turn.status === "interrupted") {
|
|
2091
|
-
return [{ kind: "error", message: "Codex turn interrupted" }, { kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
2092
|
-
}
|
|
2093
2233
|
return [{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
2094
2234
|
case "error":
|
|
2095
2235
|
if (params?.willRetry === true) {
|
|
2096
2236
|
return [{ kind: "runtime_recovery", stage: "retrying", source: "codex_stream" }];
|
|
2097
2237
|
}
|
|
2098
|
-
return [{
|
|
2238
|
+
return [{
|
|
2239
|
+
kind: "error",
|
|
2240
|
+
code: codexErrorInfoCode(params?.error?.codexErrorInfo, "codex.error"),
|
|
2241
|
+
message: params?.error?.message ?? params?.message ?? "Codex error"
|
|
2242
|
+
}];
|
|
2099
2243
|
case "thread/tokenUsage/updated":
|
|
2100
2244
|
return [];
|
|
2101
2245
|
case "account/rateLimits/updated":
|
|
@@ -2192,42 +2336,46 @@ class CodexEventNormalizer {
|
|
|
2192
2336
|
}
|
|
2193
2337
|
handleItemStarted(params) {
|
|
2194
2338
|
const t = params?.item?.type ?? params?.type;
|
|
2339
|
+
const callId = this.itemCallId(params);
|
|
2340
|
+
const identity = callId ? { callId } : {};
|
|
2195
2341
|
switch (t) {
|
|
2196
2342
|
case "commandExecution":
|
|
2197
|
-
return [{ kind: "tool_call", name: "shell", input: params?.item }];
|
|
2343
|
+
return [{ kind: "tool_call", ...identity, name: "shell", input: params?.item }];
|
|
2198
2344
|
case "contextCompaction":
|
|
2199
2345
|
return [{ kind: "compaction_started" }];
|
|
2200
2346
|
case "enteredReviewMode":
|
|
2201
2347
|
return [{ kind: "review_started" }];
|
|
2202
2348
|
case "fileChange":
|
|
2203
|
-
return [{ kind: "tool_call", name: "file_change", input: normalizeFileChangeInput(params?.item) }];
|
|
2349
|
+
return [{ kind: "tool_call", ...identity, name: "file_change", input: normalizeFileChangeInput(params?.item) }];
|
|
2204
2350
|
case "mcpToolCall":
|
|
2205
|
-
return [{ kind: "tool_call", name: `mcp_${params?.item?.name ?? "tool"}`, input: params?.item }];
|
|
2351
|
+
return [{ kind: "tool_call", ...identity, name: `mcp_${params?.item?.tool ?? params?.item?.name ?? "tool"}`, input: params?.item }];
|
|
2206
2352
|
case "webSearch":
|
|
2207
|
-
return [{ kind: "tool_call", name: "web_search", input: params?.item }];
|
|
2353
|
+
return [{ kind: "tool_call", ...identity, name: "web_search", input: params?.item }];
|
|
2208
2354
|
case "collabAgentToolCall":
|
|
2209
|
-
return [{ kind: "tool_call", name: "collab_tool_call", input: params?.item }];
|
|
2355
|
+
return [{ kind: "tool_call", ...identity, name: "collab_tool_call", input: params?.item }];
|
|
2210
2356
|
default:
|
|
2211
2357
|
return [];
|
|
2212
2358
|
}
|
|
2213
2359
|
}
|
|
2214
2360
|
handleItemCompleted(params) {
|
|
2215
2361
|
const t = params?.item?.type ?? params?.type;
|
|
2362
|
+
const callId = this.itemCallId(params);
|
|
2363
|
+
const identity = callId ? { callId } : {};
|
|
2216
2364
|
switch (t) {
|
|
2217
2365
|
case "commandExecution":
|
|
2218
|
-
return [{ kind: "tool_output", name: "shell" }];
|
|
2366
|
+
return [{ kind: "tool_output", ...identity, name: "shell" }];
|
|
2219
2367
|
case "contextCompaction":
|
|
2220
2368
|
return [{ kind: "compaction_finished" }];
|
|
2221
2369
|
case "exitedReviewMode":
|
|
2222
2370
|
return [{ kind: "review_finished" }];
|
|
2223
2371
|
case "fileChange":
|
|
2224
|
-
return [{ kind: "tool_output", name: "file_change" }];
|
|
2372
|
+
return [{ kind: "tool_output", ...identity, name: "file_change" }];
|
|
2225
2373
|
case "mcpToolCall":
|
|
2226
|
-
return [{ kind: "tool_output", name: `mcp_${params?.item?.name ?? "tool"}` }];
|
|
2374
|
+
return [{ kind: "tool_output", ...identity, name: `mcp_${params?.item?.tool ?? params?.item?.name ?? "tool"}` }];
|
|
2227
2375
|
case "webSearch":
|
|
2228
|
-
return [{ kind: "tool_output", name: "web_search" }];
|
|
2376
|
+
return [{ kind: "tool_output", ...identity, name: "web_search" }];
|
|
2229
2377
|
case "collabAgentToolCall":
|
|
2230
|
-
return [{ kind: "tool_output", name: "collab_tool_call" }];
|
|
2378
|
+
return [{ kind: "tool_output", ...identity, name: "collab_tool_call" }];
|
|
2231
2379
|
case "agentMessage":
|
|
2232
2380
|
return [{ kind: "assistant_message_completed", text: params?.item?.text ?? "" }];
|
|
2233
2381
|
case "reasoning":
|
|
@@ -2236,6 +2384,10 @@ class CodexEventNormalizer {
|
|
|
2236
2384
|
return [];
|
|
2237
2385
|
}
|
|
2238
2386
|
}
|
|
2387
|
+
itemCallId(params) {
|
|
2388
|
+
const value = params?.item?.id ?? params?.itemId;
|
|
2389
|
+
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
2390
|
+
}
|
|
2239
2391
|
}
|
|
2240
2392
|
|
|
2241
2393
|
// agent-driver/dist/adapters/codex/home.js
|
|
@@ -2706,6 +2858,16 @@ class CodexDriver {
|
|
|
2706
2858
|
get currentSessionId() {
|
|
2707
2859
|
return this.eventNormalizer.currentSessionId;
|
|
2708
2860
|
}
|
|
2861
|
+
async interrupt(_input, process2) {
|
|
2862
|
+
const threadId = this.eventNormalizer.currentSessionId;
|
|
2863
|
+
const turnId = this.eventNormalizer.currentTurnId;
|
|
2864
|
+
const stdin = process2.stdin;
|
|
2865
|
+
if (!threadId || !turnId || !stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false)
|
|
2866
|
+
return false;
|
|
2867
|
+
stdin.write(jsonRpcRequest("turn/interrupt", { threadId, turnId }, this.nextRequestId()) + `
|
|
2868
|
+
`);
|
|
2869
|
+
return true;
|
|
2870
|
+
}
|
|
2709
2871
|
buildTurnStart(threadId, text) {
|
|
2710
2872
|
return jsonRpcRequest("turn/start", { threadId, input: [{ type: "text", text }] }, this.nextRequestId());
|
|
2711
2873
|
}
|
|
@@ -3205,7 +3367,7 @@ class CursorAcpLane {
|
|
|
3205
3367
|
return;
|
|
3206
3368
|
const result = record2(value);
|
|
3207
3369
|
if (!result || typeof result.stopReason !== "string" || !PROMPT_STOP_REASONS.has(result.stopReason)) {
|
|
3208
|
-
this.failPrompt(prompt, new Error("Cursor ACP prompt response did not contain a supported stopReason"));
|
|
3370
|
+
this.failPrompt(prompt, new Error("Cursor ACP prompt response did not contain a supported stopReason"), "cursor.invalid_stop_reason");
|
|
3209
3371
|
return;
|
|
3210
3372
|
}
|
|
3211
3373
|
const terminalOwner = this.terminalOwner ?? prompt.receipt;
|
|
@@ -3218,7 +3380,7 @@ class CursorAcpLane {
|
|
|
3218
3380
|
turnOwner: terminalOwner
|
|
3219
3381
|
});
|
|
3220
3382
|
}
|
|
3221
|
-
failPrompt(prompt, error) {
|
|
3383
|
+
failPrompt(prompt, error, code = "cursor.prompt_failed") {
|
|
3222
3384
|
if (this.currentPromptRequestId !== prompt.requestId)
|
|
3223
3385
|
return;
|
|
3224
3386
|
const terminalOwner = this.terminalOwner ?? prompt.receipt;
|
|
@@ -3227,6 +3389,7 @@ class CursorAcpLane {
|
|
|
3227
3389
|
this.openToolCalls.clear();
|
|
3228
3390
|
this.events.emit("runtime_event", {
|
|
3229
3391
|
kind: "error",
|
|
3392
|
+
code,
|
|
3230
3393
|
message: error instanceof Error ? error.message : String(error)
|
|
3231
3394
|
});
|
|
3232
3395
|
this.events.emit("runtime_event", {
|
|
@@ -3380,9 +3543,10 @@ class CursorAcpLane {
|
|
|
3380
3543
|
this.pending.delete(id);
|
|
3381
3544
|
if (message.error !== undefined) {
|
|
3382
3545
|
const payload = record2(message.error);
|
|
3383
|
-
|
|
3546
|
+
const rpcCode = typeof payload?.code === "number" && Number.isSafeInteger(payload.code) ? payload.code : undefined;
|
|
3547
|
+
this.failPrompt(pending.prompt, new CursorAcpRpcError(pending.method, rpcCode, rpcErrorMessage(message.error)), rpcCode === undefined ? "cursor.rpc_error" : `cursor.rpc.${rpcCode}`);
|
|
3384
3548
|
} else if (!("result" in message)) {
|
|
3385
|
-
this.failPrompt(pending.prompt, new Error("Cursor ACP response omitted result"));
|
|
3549
|
+
this.failPrompt(pending.prompt, new Error("Cursor ACP response omitted result"), "cursor.invalid_response");
|
|
3386
3550
|
} else {
|
|
3387
3551
|
this.completePrompt(pending.prompt, message.result);
|
|
3388
3552
|
}
|
|
@@ -3667,7 +3831,11 @@ function parseModelRef(model) {
|
|
|
3667
3831
|
function messageFromError(value) {
|
|
3668
3832
|
const payload = record3(value);
|
|
3669
3833
|
const message = typeof payload?.message === "string" && payload.message.trim() ? payload.message : undefined;
|
|
3670
|
-
return message
|
|
3834
|
+
return message ?? "OpenCode reported an inconsistent turn outcome";
|
|
3835
|
+
}
|
|
3836
|
+
function codeFromError(value) {
|
|
3837
|
+
const payload = record3(value);
|
|
3838
|
+
return payload?.type === "unknown" ? "opencode.unknown" : "opencode.step_failed";
|
|
3671
3839
|
}
|
|
3672
3840
|
|
|
3673
3841
|
class OpenCodeServiceLane {
|
|
@@ -4335,7 +4503,10 @@ class OpenCodeServiceLane {
|
|
|
4335
4503
|
root.outcomes.push({
|
|
4336
4504
|
seq,
|
|
4337
4505
|
ok: successful,
|
|
4338
|
-
...!successful ? {
|
|
4506
|
+
...!successful ? {
|
|
4507
|
+
code: "opencode.unsupported_finish",
|
|
4508
|
+
message: "OpenCode reported an unsupported final step outcome"
|
|
4509
|
+
} : {}
|
|
4339
4510
|
});
|
|
4340
4511
|
}
|
|
4341
4512
|
const tokens = record3(data.tokens);
|
|
@@ -4364,7 +4535,12 @@ class OpenCodeServiceLane {
|
|
|
4364
4535
|
break;
|
|
4365
4536
|
}
|
|
4366
4537
|
case "session.next.step.failed":
|
|
4367
|
-
root.outcomes.push({
|
|
4538
|
+
root.outcomes.push({
|
|
4539
|
+
seq,
|
|
4540
|
+
ok: false,
|
|
4541
|
+
code: codeFromError(data.error),
|
|
4542
|
+
message: messageFromError(data.error)
|
|
4543
|
+
});
|
|
4368
4544
|
break;
|
|
4369
4545
|
default:
|
|
4370
4546
|
break;
|
|
@@ -4544,11 +4720,11 @@ class OpenCodeServiceLane {
|
|
|
4544
4720
|
return;
|
|
4545
4721
|
const outcome = root.outcomes.filter((item) => item.seq > maxAdmission).sort((left, right) => left.seq - right.seq).at(-1);
|
|
4546
4722
|
if (!root.interrupted && !outcome) {
|
|
4547
|
-
this.settleRoot(root, false, "OpenCode drain settled without a durable turn outcome");
|
|
4723
|
+
this.settleRoot(root, false, "OpenCode drain settled without a durable turn outcome", "opencode.missing_outcome");
|
|
4548
4724
|
return;
|
|
4549
4725
|
}
|
|
4550
4726
|
if (outcome && !outcome.ok) {
|
|
4551
|
-
this.settleRoot(root, false, outcome.message ?? "OpenCode turn failed");
|
|
4727
|
+
this.settleRoot(root, false, outcome.message ?? "OpenCode turn failed", outcome.code ?? "opencode.turn_failed");
|
|
4552
4728
|
return;
|
|
4553
4729
|
}
|
|
4554
4730
|
this.settleRoot(root, true);
|
|
@@ -4574,7 +4750,7 @@ class OpenCodeServiceLane {
|
|
|
4574
4750
|
barrierStillCurrent(root, identity, generation) {
|
|
4575
4751
|
return this.activeRoot === root && root.generation === generation && root.pendingAdmissions === 0 && !root.interruptPending && this.isIdentity(identity) && this.identityMatches();
|
|
4576
4752
|
}
|
|
4577
|
-
settleRoot(root, success, message) {
|
|
4753
|
+
settleRoot(root, success, message, code = "opencode.turn_failed") {
|
|
4578
4754
|
if (this.activeRoot !== root)
|
|
4579
4755
|
return;
|
|
4580
4756
|
this.activeRoot = null;
|
|
@@ -4582,6 +4758,7 @@ class OpenCodeServiceLane {
|
|
|
4582
4758
|
if (!success) {
|
|
4583
4759
|
this.events.emit("runtime_event", {
|
|
4584
4760
|
kind: "error",
|
|
4761
|
+
code,
|
|
4585
4762
|
message: message ?? "OpenCode turn failed"
|
|
4586
4763
|
});
|
|
4587
4764
|
}
|
|
@@ -5097,7 +5274,11 @@ function mapPiSdkEvent(event, sessionId, state) {
|
|
|
5097
5274
|
return [{ kind: "assistant_message_completed", text: d.content ?? "" }];
|
|
5098
5275
|
}
|
|
5099
5276
|
case "error":
|
|
5100
|
-
return [{
|
|
5277
|
+
return [{
|
|
5278
|
+
kind: "error",
|
|
5279
|
+
code: "pi.message_error",
|
|
5280
|
+
message: d.error?.errorMessage ?? "Pi error"
|
|
5281
|
+
}];
|
|
5101
5282
|
default:
|
|
5102
5283
|
return [];
|
|
5103
5284
|
}
|
|
@@ -5685,7 +5866,9 @@ class LogicalAgentSession {
|
|
|
5685
5866
|
interruptedTurnId;
|
|
5686
5867
|
processTurnEnded = false;
|
|
5687
5868
|
stopRequestId;
|
|
5688
|
-
|
|
5869
|
+
anonymousOutstandingToolUses = 0;
|
|
5870
|
+
outstandingToolCallIds = new Set;
|
|
5871
|
+
toolLifecycleMismatchCount = 0;
|
|
5689
5872
|
compacting = false;
|
|
5690
5873
|
reviewing = false;
|
|
5691
5874
|
steeringDeliveries = new Set;
|
|
@@ -5875,6 +6058,9 @@ class LogicalAgentSession {
|
|
|
5875
6058
|
queueDwellCount: this.metricValue(this.queueDwellCount),
|
|
5876
6059
|
queueDwellTotalMs: this.metricValue(this.queueDwellTotalMs),
|
|
5877
6060
|
sseReconnectCount: this.metricValue(this.sseReconnectCount),
|
|
6061
|
+
outstandingToolUses: this.outstandingToolUseCount(),
|
|
6062
|
+
anonymousOutstandingToolUses: this.metricValue(this.anonymousOutstandingToolUses),
|
|
6063
|
+
toolLifecycleMismatchCount: this.metricValue(this.toolLifecycleMismatchCount),
|
|
5878
6064
|
resumeOutcome: this.resumeOutcome,
|
|
5879
6065
|
terminalOwnerKind: this.adapter.execution.terminalOwnership
|
|
5880
6066
|
}
|
|
@@ -6194,15 +6380,36 @@ class LogicalAgentSession {
|
|
|
6194
6380
|
}
|
|
6195
6381
|
return;
|
|
6196
6382
|
case "tool_call":
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6383
|
+
if (!turnId) {
|
|
6384
|
+
this.toolLifecycleMismatchCount += 1;
|
|
6385
|
+
return;
|
|
6386
|
+
}
|
|
6387
|
+
if (!this.startToolUse(event.callId))
|
|
6388
|
+
return;
|
|
6389
|
+
const startedCallId = this.toolCallId(event.callId);
|
|
6390
|
+
this.emit({
|
|
6391
|
+
type: "tool_started",
|
|
6392
|
+
turnId,
|
|
6393
|
+
...startedCallId ? { callId: startedCallId } : {},
|
|
6394
|
+
name: event.name,
|
|
6395
|
+
input: jsonValue(event.input)
|
|
6396
|
+
});
|
|
6200
6397
|
return;
|
|
6201
6398
|
case "tool_output":
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6399
|
+
if (!turnId) {
|
|
6400
|
+
this.toolLifecycleMismatchCount += 1;
|
|
6401
|
+
return;
|
|
6402
|
+
}
|
|
6403
|
+
if (!this.finishToolUse(event.callId))
|
|
6404
|
+
return;
|
|
6405
|
+
const finishedCallId = this.toolCallId(event.callId);
|
|
6406
|
+
this.emit({
|
|
6407
|
+
type: "tool_finished",
|
|
6408
|
+
turnId,
|
|
6409
|
+
...finishedCallId ? { callId: finishedCallId } : {},
|
|
6410
|
+
name: event.name
|
|
6411
|
+
});
|
|
6412
|
+
if (this.outstandingToolUseCount() === 0 && !this.toolBoundaryFlushDisabled)
|
|
6206
6413
|
this.flushSafeBoundaryQueue();
|
|
6207
6414
|
return;
|
|
6208
6415
|
case "compaction_started":
|
|
@@ -6258,7 +6465,7 @@ class LogicalAgentSession {
|
|
|
6258
6465
|
}
|
|
6259
6466
|
case "error":
|
|
6260
6467
|
this.toolBoundaryFlushDisabled = true;
|
|
6261
|
-
this.turnError = driverError("process", "runtime_error", event.message, true);
|
|
6468
|
+
this.turnError = driverError("process", stableErrorCode(event.code, "runtime_error"), event.message, true);
|
|
6262
6469
|
this.emit({
|
|
6263
6470
|
type: "diagnostic",
|
|
6264
6471
|
turnId,
|
|
@@ -6345,7 +6552,7 @@ class LogicalAgentSession {
|
|
|
6345
6552
|
this.activeTurn = undefined;
|
|
6346
6553
|
this.turnError = undefined;
|
|
6347
6554
|
this.interruptedTurnId = undefined;
|
|
6348
|
-
this.
|
|
6555
|
+
this.clearOutstandingToolUses();
|
|
6349
6556
|
this.compacting = false;
|
|
6350
6557
|
this.reviewing = false;
|
|
6351
6558
|
this.toolBoundaryFlushDisabled = false;
|
|
@@ -6369,7 +6576,7 @@ class LogicalAgentSession {
|
|
|
6369
6576
|
return this.safeBoundaryFlush;
|
|
6370
6577
|
}
|
|
6371
6578
|
canFlushSafeBoundaryQueue() {
|
|
6372
|
-
return this.state === "working" && this.behavior.midTurnDelivery === "safe_boundary_queue" && this.
|
|
6579
|
+
return this.state === "working" && this.behavior.midTurnDelivery === "safe_boundary_queue" && this.outstandingToolUseCount() === 0 && !this.compacting && !this.reviewing && this.activeTurn !== undefined && this.lane !== null && this.queued.length > 0;
|
|
6373
6580
|
}
|
|
6374
6581
|
async drainSafeBoundaryQueue() {
|
|
6375
6582
|
while (this.canFlushSafeBoundaryQueue()) {
|
|
@@ -6550,7 +6757,7 @@ class LogicalAgentSession {
|
|
|
6550
6757
|
return "compacting";
|
|
6551
6758
|
if (this.reviewing)
|
|
6552
6759
|
return "reviewing";
|
|
6553
|
-
if (this.
|
|
6760
|
+
if (this.outstandingToolUseCount() > 0)
|
|
6554
6761
|
return "tool_wait";
|
|
6555
6762
|
if (this.activeTurn)
|
|
6556
6763
|
return "working";
|
|
@@ -6560,6 +6767,46 @@ class LogicalAgentSession {
|
|
|
6560
6767
|
const now = this.host.now();
|
|
6561
6768
|
return Number.isFinite(now) && now >= 0 ? now : 0;
|
|
6562
6769
|
}
|
|
6770
|
+
outstandingToolUseCount() {
|
|
6771
|
+
return this.anonymousOutstandingToolUses + this.outstandingToolCallIds.size;
|
|
6772
|
+
}
|
|
6773
|
+
startToolUse(rawCallId) {
|
|
6774
|
+
const callId = this.toolCallId(rawCallId);
|
|
6775
|
+
if (!callId) {
|
|
6776
|
+
this.anonymousOutstandingToolUses += 1;
|
|
6777
|
+
return true;
|
|
6778
|
+
}
|
|
6779
|
+
if (this.outstandingToolCallIds.has(callId)) {
|
|
6780
|
+
this.toolLifecycleMismatchCount += 1;
|
|
6781
|
+
return false;
|
|
6782
|
+
}
|
|
6783
|
+
this.outstandingToolCallIds.add(callId);
|
|
6784
|
+
return true;
|
|
6785
|
+
}
|
|
6786
|
+
finishToolUse(rawCallId) {
|
|
6787
|
+
const callId = this.toolCallId(rawCallId);
|
|
6788
|
+
if (!callId) {
|
|
6789
|
+
if (this.anonymousOutstandingToolUses === 0) {
|
|
6790
|
+
this.toolLifecycleMismatchCount += 1;
|
|
6791
|
+
return false;
|
|
6792
|
+
}
|
|
6793
|
+
this.anonymousOutstandingToolUses -= 1;
|
|
6794
|
+
return true;
|
|
6795
|
+
}
|
|
6796
|
+
if (!this.outstandingToolCallIds.delete(callId)) {
|
|
6797
|
+
this.toolLifecycleMismatchCount += 1;
|
|
6798
|
+
return false;
|
|
6799
|
+
}
|
|
6800
|
+
return true;
|
|
6801
|
+
}
|
|
6802
|
+
clearOutstandingToolUses() {
|
|
6803
|
+
this.anonymousOutstandingToolUses = 0;
|
|
6804
|
+
this.outstandingToolCallIds.clear();
|
|
6805
|
+
}
|
|
6806
|
+
toolCallId(rawCallId) {
|
|
6807
|
+
const callId = rawCallId?.trim();
|
|
6808
|
+
return callId && callId.length <= 1024 ? callId : undefined;
|
|
6809
|
+
}
|
|
6563
6810
|
metricValue(value) {
|
|
6564
6811
|
return Number.isFinite(value) && value >= 0 ? value : 0;
|
|
6565
6812
|
}
|
|
@@ -8054,6 +8301,7 @@ function reduceManager(state, event) {
|
|
|
8054
8301
|
if ((lease.state === "active" || lease.state === "suspect_active") && lease.outstandingToolUses !== undefined) {
|
|
8055
8302
|
const unblockedLease = { ...lease };
|
|
8056
8303
|
delete unblockedLease.outstandingToolUses;
|
|
8304
|
+
delete unblockedLease.outstandingToolCallIds;
|
|
8057
8305
|
a.execution.lease = unblockedLease;
|
|
8058
8306
|
}
|
|
8059
8307
|
});
|
|
@@ -8314,26 +8562,40 @@ function onTurnToolLifecycle(state, event, lifecycle) {
|
|
|
8314
8562
|
const matchesTerminal = lifecycle === "started" && current.state === "none" && current.lastTerminal !== null && sameIdentity(current.lastTerminal.identity, identity);
|
|
8315
8563
|
if (!matchesActive && !matchesTerminal)
|
|
8316
8564
|
return { state, effects: [] };
|
|
8317
|
-
if (lifecycle === "finished" && matchesActive && (current.outstandingToolUses ?? 0) === 0) {
|
|
8318
|
-
return { state, effects: [] };
|
|
8319
|
-
}
|
|
8320
8565
|
return mutate(state, event.agentId, (agent) => {
|
|
8321
8566
|
if (!matchesSession(agent, event.sessionInstanceId))
|
|
8322
8567
|
return;
|
|
8323
8568
|
const lease = agent.execution.lease;
|
|
8569
|
+
const callId = normalizedToolCallId(event.callId);
|
|
8324
8570
|
if ((lease.state === "active" || lease.state === "suspect_active") && sameIdentity(lease.identity, identity)) {
|
|
8325
|
-
const
|
|
8571
|
+
const identified = new Set(lease.outstandingToolCallIds ?? []);
|
|
8572
|
+
const currentCount = lease.outstandingToolUses ?? 0;
|
|
8573
|
+
const anonymousCount = Math.max(0, currentCount - identified.size);
|
|
8574
|
+
if (lifecycle === "started") {
|
|
8575
|
+
if (callId && identified.has(callId))
|
|
8576
|
+
return;
|
|
8577
|
+
if (callId)
|
|
8578
|
+
identified.add(callId);
|
|
8579
|
+
} else if (callId) {
|
|
8580
|
+
if (!identified.delete(callId))
|
|
8581
|
+
return;
|
|
8582
|
+
} else if (anonymousCount === 0) {
|
|
8583
|
+
return;
|
|
8584
|
+
}
|
|
8585
|
+
const outstandingToolUses = currentCount + (lifecycle === "started" ? 1 : -1);
|
|
8326
8586
|
if (outstandingToolUses > 0) {
|
|
8327
8587
|
agent.execution.lease = {
|
|
8328
8588
|
...lease,
|
|
8329
8589
|
lastWorkAt: event.nowMs,
|
|
8330
8590
|
nativeDeadlineAt: event.nowMs + agent.turnSilence.normalBudgetMs,
|
|
8331
8591
|
recoveryExtensionsUsed: 0,
|
|
8332
|
-
outstandingToolUses
|
|
8592
|
+
outstandingToolUses,
|
|
8593
|
+
...identified.size > 0 ? { outstandingToolCallIds: [...identified] } : {}
|
|
8333
8594
|
};
|
|
8334
8595
|
} else {
|
|
8335
8596
|
const unblockedLease = { ...lease };
|
|
8336
8597
|
delete unblockedLease.outstandingToolUses;
|
|
8598
|
+
delete unblockedLease.outstandingToolCallIds;
|
|
8337
8599
|
agent.execution.lease = {
|
|
8338
8600
|
...unblockedLease,
|
|
8339
8601
|
lastWorkAt: event.nowMs,
|
|
@@ -8352,6 +8614,7 @@ function onTurnToolLifecycle(state, event, lifecycle) {
|
|
|
8352
8614
|
nativeDeadlineAt: event.nowMs + agent.turnSilence.normalBudgetMs,
|
|
8353
8615
|
recoveryExtensionsUsed: 0,
|
|
8354
8616
|
outstandingToolUses: 1,
|
|
8617
|
+
...callId ? { outstandingToolCallIds: [callId] } : {},
|
|
8355
8618
|
reason: "work_after_terminal"
|
|
8356
8619
|
};
|
|
8357
8620
|
}
|
|
@@ -8515,6 +8778,10 @@ function identityOf(event) {
|
|
|
8515
8778
|
function sameIdentity(left, right) {
|
|
8516
8779
|
return left.sessionInstanceId === right.sessionInstanceId && left.turnId === right.turnId;
|
|
8517
8780
|
}
|
|
8781
|
+
function normalizedToolCallId(rawCallId) {
|
|
8782
|
+
const callId = rawCallId?.trim();
|
|
8783
|
+
return callId && callId.length <= 1024 ? callId : undefined;
|
|
8784
|
+
}
|
|
8518
8785
|
function leaseIsWorking(lease) {
|
|
8519
8786
|
return lease.state === "active" || lease.state === "suspect_active";
|
|
8520
8787
|
}
|
|
@@ -8594,13 +8861,13 @@ function cliCommandsSection() {
|
|
|
8594
8861
|
"",
|
|
8595
8862
|
"### Messaging",
|
|
8596
8863
|
"",
|
|
8597
|
-
`1. \`${CLI} inbox pull\` — fetch unread messages
|
|
8864
|
+
`1. \`${CLI} inbox pull\` — fetch unread messages and advance their read waterlines.`,
|
|
8598
8865
|
`2. \`${CLI} message send --target <ref> --remind-after <0|Nm|Nh> --stdin\` — send to a ` + `channel, DM, or thread. ` + `The body is required through \`--stdin\` and limited to 1 KiB of UTF-8. ` + `Attach uploaded files with \`--attachment <id>\` (repeatable, order matters). ` + `\`--remind-after\` accepts \`0\`, or a whole-number duration from \`1m\` to \`24h\`.`,
|
|
8599
8866
|
`3. \`${CLI} message attachment upload --target <ref> --file <path>\` — upload a file; ` + `returns an id stable across pending→persisted.`,
|
|
8600
8867
|
`4. \`${CLI} message attachment download --id <id> [--out <path>]\` — download any ` + `attachment you can see (or your own pending uploads).`,
|
|
8601
|
-
`5. \`${CLI} message
|
|
8602
|
-
`6. \`${CLI} message
|
|
8603
|
-
`7. \`${CLI} message
|
|
8868
|
+
`5. \`${CLI} message property set --target <full-message-ref> --json <json>\` — add a supported property value to a message.`,
|
|
8869
|
+
`6. \`${CLI} message property list --target <full-message-ref>\` — list the message's current properties and supported capabilities.`,
|
|
8870
|
+
`7. \`${CLI} message property remove --target <full-message-ref> --json <json>\` — remove a supported property value from a message.`,
|
|
8604
8871
|
`8. \`${CLI} message mark list\` — list every currently visible marked message with its full content.`,
|
|
8605
8872
|
"",
|
|
8606
8873
|
"### Servers",
|
|
@@ -8608,12 +8875,14 @@ function cliCommandsSection() {
|
|
|
8608
8875
|
`1. \`${CLI} server list\` — list your servers.`,
|
|
8609
8876
|
`2. \`${CLI} server member --server <name#discriminator>\` — list a server's members.`,
|
|
8610
8877
|
`3. \`${CLI} server join --invite <link>\` — join via invite link or token.`,
|
|
8878
|
+
`4. \`${CLI} server leave --server <name#NNNN>\` — leave a server you belong to. A server owner cannot leave.`,
|
|
8611
8879
|
"",
|
|
8612
8880
|
"### Channels",
|
|
8613
8881
|
"",
|
|
8614
8882
|
`1. \`${CLI} channel list --server <name#discriminator>\` — list top-level channels, grouped by ` + `category; each is marked \`public\` or \`private\`.`,
|
|
8615
8883
|
`2. \`${CLI} channel history --channel <ref>\` — read a channel's or thread's past messages ` + `(the context you weren't awake for). Page with \`--before N\` / \`--after N\` (seq N as ` + "anchor), `--around N` to center on a message, `--limit N` for page size.",
|
|
8616
8884
|
`3. \`${CLI} channel member --channel <ref>\` — roster of a channel or thread. A private ` + `channel/forum returns its concrete member list; a public one returns a hint pointing at ` + `\`${CLI} server member\` (its audience is the whole server).`,
|
|
8885
|
+
`4. \`${CLI} channel leave --channel <ref>\` — leave a thread or private channel/forum. Public channels require leaving their server; DMs cannot be left.`,
|
|
8617
8886
|
"",
|
|
8618
8887
|
"### Friends",
|
|
8619
8888
|
"",
|
|
@@ -8666,6 +8935,15 @@ function messagingSection() {
|
|
|
8666
8935
|
"Reply where the message came from. Post results in the channel that owns the topic. " + "When uncertain, read history (below) or DM the relevant people.",
|
|
8667
8936
|
"Write every message body in the stdin/heredoc block; never place it directly on the command line.",
|
|
8668
8937
|
"",
|
|
8938
|
+
"### Message properties",
|
|
8939
|
+
"",
|
|
8940
|
+
`Message properties are capabilities determined by the target message's channel type. \`${CLI} ` + "message property list --target <full-message-ref>` returns its current values and supported `capabilities`.",
|
|
8941
|
+
"",
|
|
8942
|
+
`- \`emoji\` works on text-channel, DM, and thread messages. Set or remove your own reaction with ` + `\`{"type":"emoji","value":"\uD83D\uDC4D"}\`; \`list\` shows everyone who reacted. Add: ` + `\`${CLI} message property set --target <full-message-ref> --json '{"type":"emoji","value":"\uD83D\uDC4D"}'\`.`,
|
|
8943
|
+
`- \`tag\` works on forum opener messages. Set or remove named tags with ` + `\`{"type":"tag","value":["bug","ready"]}\`. A forum reply is a thread message, so it ` + `supports \`emoji\`, not \`tag\`. Add: \`${CLI} message property set --target ` + `<full-message-ref> --json '{"type":"tag","value":["bug"]}'\`.`,
|
|
8944
|
+
`- \`mark\` works on every message. Mark outstanding work with \`{"type":"mark","value":true}\`: ` + `\`${CLI} message property set --target <full-message-ref> --json ` + `'{"type":"mark","value":true}'\`. Clear it with the same JSON through ` + `\`message property remove\`. Use \`${CLI} message mark list\` for the one-shot global view ` + `of all currently visible marked messages.`,
|
|
8945
|
+
"- `archived` is a reserved tag meaning the forum post is complete. Setting it hides the " + "post from the normal forum feed; removing it reopens the post.",
|
|
8946
|
+
"",
|
|
8669
8947
|
"### Context refs",
|
|
8670
8948
|
"",
|
|
8671
8949
|
"Path-style refs:",
|
|
@@ -8778,6 +9056,7 @@ function criticalRulesSection() {
|
|
|
8778
9056
|
`- **\`${CLI}\` is the only way to communicate.** Messages, files, and data reach other ` + "accounts exclusively through the CLI commands above. Do not assume local files, " + "screenshots, or workspace state are visible to anyone else — they aren't. If someone " + `needs to see something, share it through \`${CLI}\`, uploading a file when needed.`,
|
|
8779
9057
|
"- **Never expose tokens, keys, or secrets.** Redact credential-like strings from tool output " + "before sharing.",
|
|
8780
9058
|
"- **Match the sender's language.** Reply in the language they wrote in.",
|
|
9059
|
+
`- **Leaving a scope is destructive.** Use \`${CLI} channel leave\` or \`${CLI} server leave\` only after your owner explicitly asks you to leave that exact scope.`,
|
|
8781
9060
|
"- **Channel alignment**: you can't send to a channel with unread messages. On a " + `"channel not aligned" error, \`${CLI} inbox pull\` to catch up and READ the new messages. ` + "Judge if your message is still needed or overlaps with what just landed. Adjust or skip; " + "don't mechanically resend."
|
|
8782
9061
|
].join(`
|
|
8783
9062
|
`);
|
|
@@ -8790,7 +9069,7 @@ function executionModelSection() {
|
|
|
8790
9069
|
"",
|
|
8791
9070
|
"On wake, restore durable context from `memory.md` and the context timeline, then pull your inbox. " + "Follow *Outstanding work marks* below before taking new work.",
|
|
8792
9071
|
"",
|
|
8793
|
-
"`inbox pull` advances your read waterline
|
|
9072
|
+
"`inbox pull` advances your read waterline — pulled messages won't come back in a " + "future pull. A task-bearing message stays durable through its server mark even after the " + "read waterline advances."
|
|
8794
9073
|
].join(`
|
|
8795
9074
|
`);
|
|
8796
9075
|
}
|
|
@@ -8862,9 +9141,9 @@ function workspaceMemorySection(config) {
|
|
|
8862
9141
|
"",
|
|
8863
9142
|
"### Outstanding work marks",
|
|
8864
9143
|
"",
|
|
8865
|
-
"Marks are the durable work queue. If a message requires work beyond an immediate reply, " + `acknowledge it, then run \`${CLI} message
|
|
9144
|
+
"Marks are the durable work queue. If a message requires work beyond an immediate reply, " + `acknowledge it, then run \`${CLI} message property set --target <full-message-ref> ` + `--json '{"type":"mark","value":true}'\` before ` + "starting or queuing. Do not mark a message you answer immediately.",
|
|
8866
9145
|
"",
|
|
8867
|
-
"Keep it marked while the work is active, queued, or blocked; report blockers where the task " + `came from. Run \`${CLI} message
|
|
9146
|
+
"Keep it marked while the work is active, queued, or blocked; report blockers where the task " + `came from. Run \`${CLI} message property remove --target <full-message-ref> ` + `--json '{"type":"mark","value":true}'\` only after ` + "sending the result, or when the request is cancelled or superseded and nothing remains.",
|
|
8868
9147
|
"",
|
|
8869
9148
|
"If `inbox pull` returns a `markedReminder`, run " + `\`${CLI} message mark list\` before taking new work. Do not copy marked tasks into local files.`
|
|
8870
9149
|
].join(`
|
|
@@ -8981,7 +9260,7 @@ function nowLocalISO() {
|
|
|
8981
9260
|
}
|
|
8982
9261
|
|
|
8983
9262
|
// src/manager/managerRuntime.ts
|
|
8984
|
-
import { randomUUID as
|
|
9263
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
8985
9264
|
var SESSION_STOP_GRACE_MS2 = 2000;
|
|
8986
9265
|
function normalizeTerminationCause(value) {
|
|
8987
9266
|
return value === "runtime_error" || value === "killed_stalled" ? value : "other";
|
|
@@ -9218,7 +9497,7 @@ class AgentProcessManager {
|
|
|
9218
9497
|
liveBackendIds = new Map;
|
|
9219
9498
|
activeSpawnState = new Map;
|
|
9220
9499
|
publishedAgentActivity = new Map;
|
|
9221
|
-
traceProcessNonce =
|
|
9500
|
+
traceProcessNonce = randomUUID6();
|
|
9222
9501
|
nextSpawnOrdinal = 1;
|
|
9223
9502
|
nextDaemonTurnOrdinal = 1;
|
|
9224
9503
|
nextDeliveryOrdinal = 1;
|
|
@@ -9494,6 +9773,24 @@ class AgentProcessManager {
|
|
|
9494
9773
|
if (this.sessions.get(agentId) === session)
|
|
9495
9774
|
this.sessions.delete(agentId);
|
|
9496
9775
|
}
|
|
9776
|
+
async interrupt(agentId) {
|
|
9777
|
+
const session = this.sessions.get(agentId);
|
|
9778
|
+
if (!session)
|
|
9779
|
+
return;
|
|
9780
|
+
const result = await session.interrupt({ requestId: randomUUID6(), reason: "owner_request" });
|
|
9781
|
+
if (result.status !== "accepted")
|
|
9782
|
+
return;
|
|
9783
|
+
this.log.info("agent turn interrupt accepted", {
|
|
9784
|
+
agentId,
|
|
9785
|
+
sessionInstanceId: session.sessionInstanceId,
|
|
9786
|
+
turnId: result.turnId
|
|
9787
|
+
});
|
|
9788
|
+
try {
|
|
9789
|
+
this.opts.onBotAuditEvent?.(agentId, { kind: "turn_interrupt", payload: { status: "accepted" } }, this.auditContext(agentId));
|
|
9790
|
+
} catch (err) {
|
|
9791
|
+
this.log.debug("audit emit failed (turn interrupt)", { agentId, err: String(err) });
|
|
9792
|
+
}
|
|
9793
|
+
}
|
|
9497
9794
|
async stopAll() {
|
|
9498
9795
|
if (this.tickTimer) {
|
|
9499
9796
|
clearInterval(this.tickTimer);
|
|
@@ -9991,7 +10288,7 @@ ${this.opts.wakePromptFooter}` : text;
|
|
|
9991
10288
|
case "reset_idle_session": {
|
|
9992
10289
|
const spawnState = this.activeSpawnState.get(effect.agentId);
|
|
9993
10290
|
const completion = {
|
|
9994
|
-
eventId: `bae_${
|
|
10291
|
+
eventId: `bae_${randomUUID6()}`,
|
|
9995
10292
|
occurredAt: new Date(this.now()).toISOString()
|
|
9996
10293
|
};
|
|
9997
10294
|
const persisted = this.forgetSession(effect.agentId, "reset_session", effect.sessionId, completion);
|
|
@@ -10386,11 +10683,12 @@ ${this.opts.wakePromptFooter}` : text;
|
|
|
10386
10683
|
emitErrorAudit(agentId, scope, code, rawMessage) {
|
|
10387
10684
|
if (!this.opts.onBotAuditEvent)
|
|
10388
10685
|
return;
|
|
10686
|
+
const stableCode = /^[A-Za-z0-9_.-]{1,100}$/.test(code) ? code : "runtime_error";
|
|
10389
10687
|
const message = scrubRuntimeErrorDiagnosticText(rawMessage).slice(0, AUDIT_ERROR_MESSAGE_MAX_LEN);
|
|
10390
10688
|
try {
|
|
10391
10689
|
this.opts.onBotAuditEvent(agentId, {
|
|
10392
10690
|
kind: "error",
|
|
10393
|
-
payload: { scope, code, message, model: this.currentModelFor(agentId) }
|
|
10691
|
+
payload: { scope, code: stableCode, message, model: this.currentModelFor(agentId) }
|
|
10394
10692
|
}, {
|
|
10395
10693
|
sessionId: this.liveSessions.get(agentId) ?? null,
|
|
10396
10694
|
launchId: this.launchIds.get(agentId) ?? null
|
|
@@ -10415,18 +10713,18 @@ ${this.opts.wakePromptFooter}` : text;
|
|
|
10415
10713
|
return;
|
|
10416
10714
|
}
|
|
10417
10715
|
const sessionSuperseded = owner.superseded;
|
|
10418
|
-
const
|
|
10419
|
-
if (
|
|
10420
|
-
this.emitErrorAudit(agentId, "runtime",
|
|
10716
|
+
const runtimeError = event.type === "session_failed" ? event.error : event.type === "turn_completed" && event.result.outcome === "failed" ? event.result.error : undefined;
|
|
10717
|
+
if (runtimeError !== undefined && !sessionSuperseded) {
|
|
10718
|
+
this.emitErrorAudit(agentId, "runtime", runtimeError.code, runtimeError.message);
|
|
10421
10719
|
if (this.nonCleanEndMarker.get(agentId)?.cause !== "killed_stalled") {
|
|
10422
|
-
this.nonCleanEndMarker.set(agentId, { cause: "runtime_error", detail:
|
|
10720
|
+
this.nonCleanEndMarker.set(agentId, { cause: "runtime_error", detail: runtimeError.message });
|
|
10423
10721
|
}
|
|
10424
10722
|
const agent = this.state.agents[agentId];
|
|
10425
10723
|
if (agent?.resetting && agent.resettingSince !== null && this.now() - agent.resettingSince >= this.state.resetStuckThresholdMs) {
|
|
10426
10724
|
this.log.warn("runtime error during a stuck reset window", {
|
|
10427
10725
|
agentId,
|
|
10428
10726
|
resettingForMs: this.now() - agent.resettingSince,
|
|
10429
|
-
message:
|
|
10727
|
+
message: runtimeError.message
|
|
10430
10728
|
});
|
|
10431
10729
|
}
|
|
10432
10730
|
}
|
|
@@ -10521,9 +10819,9 @@ ${this.opts.wakePromptFooter}` : text;
|
|
|
10521
10819
|
case "assistant_message_completed":
|
|
10522
10820
|
return { type: "turn_work", turnId: event.turnId };
|
|
10523
10821
|
case "tool_started":
|
|
10524
|
-
return { type: "turn_tool_started", turnId: event.turnId };
|
|
10822
|
+
return { type: "turn_tool_started", turnId: event.turnId, callId: event.callId };
|
|
10525
10823
|
case "tool_finished":
|
|
10526
|
-
return { type: "turn_tool_finished", turnId: event.turnId };
|
|
10824
|
+
return { type: "turn_tool_finished", turnId: event.turnId, callId: event.callId };
|
|
10527
10825
|
case "compaction_started":
|
|
10528
10826
|
case "compaction_finished":
|
|
10529
10827
|
case "review_started":
|
|
@@ -27298,6 +27596,10 @@ var OwnerDiagnosticReportSchema = exports_external.discriminatedUnion("status",
|
|
|
27298
27596
|
// ../shared/src/community-cli-contract.ts
|
|
27299
27597
|
var DM_SERVER = ".dm";
|
|
27300
27598
|
var CONTROL_HEARTBEAT_CAPABILITY = "control-heartbeat-v1";
|
|
27599
|
+
var AgentInterruptRequestSchema = exports_external.strictObject({
|
|
27600
|
+
type: exports_external.literal("agent:interrupt"),
|
|
27601
|
+
agentId: exports_external.string().min(1).max(128)
|
|
27602
|
+
});
|
|
27301
27603
|
function parseRef(ref) {
|
|
27302
27604
|
if (!ref.startsWith("/"))
|
|
27303
27605
|
throw new Error(`ref must start with "/": ${ref}`);
|
|
@@ -27389,6 +27691,7 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
|
|
|
27389
27691
|
type: exports_external.literal("agent:stop"),
|
|
27390
27692
|
agentId: exports_external.string().min(1)
|
|
27391
27693
|
}),
|
|
27694
|
+
AgentInterruptRequestSchema,
|
|
27392
27695
|
exports_external.object({
|
|
27393
27696
|
type: exports_external.literal("agent:reset"),
|
|
27394
27697
|
agentId: exports_external.string().min(1),
|
|
@@ -27787,6 +28090,10 @@ class AgentRouter {
|
|
|
27787
28090
|
}
|
|
27788
28091
|
break;
|
|
27789
28092
|
}
|
|
28093
|
+
case "agent:interrupt": {
|
|
28094
|
+
await this.opts.manager.interrupt(cmd.agentId);
|
|
28095
|
+
break;
|
|
28096
|
+
}
|
|
27790
28097
|
case "agent:stop":
|
|
27791
28098
|
this.log.info("agent:stop received", { agentId: cmd.agentId });
|
|
27792
28099
|
try {
|
|
@@ -27956,10 +28263,11 @@ var DEFAULT_CAPABILITY_RESOLVER = (method, pathname) => {
|
|
|
27956
28263
|
const isMessagesDoor = /\/channels\/[^/]+\/messages(\/|$|\?)/.test(pathname);
|
|
27957
28264
|
if (isMessagesDoor)
|
|
27958
28265
|
return method === "GET" ? "read" : "send";
|
|
28266
|
+
if (/\/messages\/[^/]+\/properties(\/|$|\?)/.test(pathname)) {
|
|
28267
|
+
return method === "GET" ? "read" : "send";
|
|
28268
|
+
}
|
|
27959
28269
|
if (/\/messages\/[^/]+\/reactions\//.test(pathname))
|
|
27960
28270
|
return "send";
|
|
27961
|
-
if ((method === "PUT" || method === "DELETE") && /\/messages\/[^/]+\/marks(\/|$|\?)/.test(pathname))
|
|
27962
|
-
return "send";
|
|
27963
28271
|
if (method === "GET" && /\/users\/me\/marks(\/|$|\?)/.test(pathname))
|
|
27964
28272
|
return "read";
|
|
27965
28273
|
if (method === "GET" && /\/messages\/[^/]+(\?|$)/.test(pathname))
|
|
@@ -28000,6 +28308,12 @@ function isCanonicalChannelScope(channel2) {
|
|
|
28000
28308
|
return false;
|
|
28001
28309
|
}
|
|
28002
28310
|
}
|
|
28311
|
+
function propertyAuditMetadata(method, pathname, requestUrl) {
|
|
28312
|
+
if (method !== "PUT" && method !== "DELETE" || !/^\/api\/community\/messages\/[^/]+\/properties$/.test(pathname))
|
|
28313
|
+
return;
|
|
28314
|
+
const type = new URL2(requestUrl, "http://placeholder").searchParams.get("type");
|
|
28315
|
+
return type === "emoji" || type === "tag" || type === "mark" ? { propertyType: type } : undefined;
|
|
28316
|
+
}
|
|
28003
28317
|
function parseLocalMessageReminderBody(body, agentId) {
|
|
28004
28318
|
let value;
|
|
28005
28319
|
try {
|
|
@@ -28138,7 +28452,12 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28138
28452
|
}
|
|
28139
28453
|
if (onProxyRequest) {
|
|
28140
28454
|
try {
|
|
28141
|
-
|
|
28455
|
+
const method = req.method ?? "GET";
|
|
28456
|
+
const metadata = propertyAuditMetadata(method, pathname, req.url ?? pathname);
|
|
28457
|
+
if (metadata)
|
|
28458
|
+
onProxyRequest(reg.agentId, method, pathname, metadata);
|
|
28459
|
+
else
|
|
28460
|
+
onProxyRequest(reg.agentId, method, pathname);
|
|
28142
28461
|
} catch {}
|
|
28143
28462
|
}
|
|
28144
28463
|
const outHeaders = { ...req.headers };
|
|
@@ -29452,17 +29771,18 @@ var CommunityAgentNapRequestSchema = exports_external.object({
|
|
|
29452
29771
|
message: "handoff is required"
|
|
29453
29772
|
})
|
|
29454
29773
|
});
|
|
29455
|
-
var
|
|
29774
|
+
var CommunityAgentMessagePropertyRequestSchema = exports_external.object({
|
|
29456
29775
|
channel: exports_external.string().min(1),
|
|
29457
29776
|
seq: CommunityAgentPositiveSeqSchema,
|
|
29458
|
-
|
|
29777
|
+
property: exports_external.unknown()
|
|
29459
29778
|
});
|
|
29460
29779
|
var CommunityAgentFriendRequestSchema = exports_external.object({
|
|
29461
29780
|
username: exports_external.string().min(1)
|
|
29462
29781
|
});
|
|
29463
29782
|
var CommunityAgentListFriendsSchema = exports_external.object({});
|
|
29464
29783
|
var AuditLogCliInvocationPayloadSchema = exports_external.object({
|
|
29465
|
-
subcommand: exports_external.string().min(1)
|
|
29784
|
+
subcommand: exports_external.string().min(1),
|
|
29785
|
+
propertyType: exports_external.enum(["emoji", "tag", "mark"]).optional()
|
|
29466
29786
|
});
|
|
29467
29787
|
var AuditLogToolCallPayloadSchema = exports_external.object({
|
|
29468
29788
|
name: exports_external.string().min(1),
|
|
@@ -29473,6 +29793,9 @@ var AuditLogThinkingPayloadSchema = exports_external.object({
|
|
|
29473
29793
|
truncated: exports_external.boolean(),
|
|
29474
29794
|
chars: exports_external.number().int().nonnegative()
|
|
29475
29795
|
});
|
|
29796
|
+
var AuditLogTurnInterruptPayloadSchema = exports_external.object({
|
|
29797
|
+
status: exports_external.literal("accepted")
|
|
29798
|
+
});
|
|
29476
29799
|
var AuditLogWakeTriggerPayloadSchema = exports_external.object({
|
|
29477
29800
|
messageId: exports_external.string().min(1),
|
|
29478
29801
|
channel: exports_external.string().min(1),
|
|
@@ -29505,6 +29828,7 @@ var BotAuditEventSchema = exports_external.discriminatedUnion("kind", [
|
|
|
29505
29828
|
exports_external.object({ kind: exports_external.literal("cli_invocation"), payload: AuditLogCliInvocationPayloadSchema }),
|
|
29506
29829
|
exports_external.object({ kind: exports_external.literal("tool_call"), payload: AuditLogToolCallPayloadSchema }),
|
|
29507
29830
|
exports_external.object({ kind: exports_external.literal("thinking"), payload: AuditLogThinkingPayloadSchema }),
|
|
29831
|
+
exports_external.object({ kind: exports_external.literal("turn_interrupt"), payload: AuditLogTurnInterruptPayloadSchema }),
|
|
29508
29832
|
exports_external.object({ kind: exports_external.literal("wake_trigger"), payload: AuditLogWakeTriggerPayloadSchema }),
|
|
29509
29833
|
exports_external.object({ kind: exports_external.literal("session_reset"), payload: AuditLogSessionResetPayloadSchema }),
|
|
29510
29834
|
exports_external.object({ kind: exports_external.literal("nap"), payload: AuditLogNapPayloadSchema }),
|
|
@@ -29516,6 +29840,7 @@ var BotAuditEventKindSchema = exports_external.enum([
|
|
|
29516
29840
|
"cli_invocation",
|
|
29517
29841
|
"tool_call",
|
|
29518
29842
|
"thinking",
|
|
29843
|
+
"turn_interrupt",
|
|
29519
29844
|
"wake_trigger",
|
|
29520
29845
|
"session_reset",
|
|
29521
29846
|
"nap",
|
|
@@ -30472,7 +30797,7 @@ var communityBotAuditEventSchema = exports_external.strictObject({
|
|
|
30472
30797
|
type: exports_external.literal("community:bot.audit_event"),
|
|
30473
30798
|
botId: string4,
|
|
30474
30799
|
id: string4,
|
|
30475
|
-
kind: exports_external.enum(["cli_invocation", "tool_call", "thinking", "wake_trigger", "session_reset", "nap", "model_changed", "provider_changed", "error"]),
|
|
30800
|
+
kind: exports_external.enum(["cli_invocation", "tool_call", "thinking", "turn_interrupt", "wake_trigger", "session_reset", "nap", "model_changed", "provider_changed", "error"]),
|
|
30476
30801
|
payload: exports_external.unknown(),
|
|
30477
30802
|
sessionId: nullableString.optional(),
|
|
30478
30803
|
launchId: nullableString.optional(),
|
|
@@ -32841,7 +33166,7 @@ class MessageReminderScheduler {
|
|
|
32841
33166
|
}
|
|
32842
33167
|
|
|
32843
33168
|
// src/manager/agentDriverHost.ts
|
|
32844
|
-
import { randomUUID as
|
|
33169
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
32845
33170
|
import { homedir as homedir4 } from "node:os";
|
|
32846
33171
|
import { join as join13 } from "node:path";
|
|
32847
33172
|
|
|
@@ -32997,7 +33322,7 @@ function createDaemonAgentDriverHost(ctx, onRawLine) {
|
|
|
32997
33322
|
onRawLine?.(event.text);
|
|
32998
33323
|
},
|
|
32999
33324
|
now: () => Date.now(),
|
|
33000
|
-
createId: () =>
|
|
33325
|
+
createId: () => randomUUID7()
|
|
33001
33326
|
};
|
|
33002
33327
|
}
|
|
33003
33328
|
|
|
@@ -33076,7 +33401,7 @@ class DaemonSelfSleepScheduler {
|
|
|
33076
33401
|
// src/telemetry/dailyTokenUsage.ts
|
|
33077
33402
|
import { chmod, mkdir, open, readFile as readFile2, rename, rm } from "node:fs/promises";
|
|
33078
33403
|
import { dirname as dirname5, join as join14 } from "node:path";
|
|
33079
|
-
import { randomUUID as
|
|
33404
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
33080
33405
|
var TOKEN_USAGE_WINDOW_DAYS = 30;
|
|
33081
33406
|
var TOKEN_USAGE_RECOVERY_DAYS = 2;
|
|
33082
33407
|
var TOKEN_USAGE_RETENTION_DAYS = TOKEN_USAGE_WINDOW_DAYS + TOKEN_USAGE_RECOVERY_DAYS;
|
|
@@ -33247,7 +33572,7 @@ class DailyTokenUsageStore {
|
|
|
33247
33572
|
async persist() {
|
|
33248
33573
|
const directory = dirname5(this.filePath);
|
|
33249
33574
|
await mkdir(directory, { recursive: true, mode: 448 });
|
|
33250
|
-
const temporary = `${this.filePath}.${
|
|
33575
|
+
const temporary = `${this.filePath}.${randomUUID8()}.tmp`;
|
|
33251
33576
|
try {
|
|
33252
33577
|
const file2 = await open(temporary, "wx", 384);
|
|
33253
33578
|
try {
|
|
@@ -33329,15 +33654,17 @@ function createRuntimeRawLineTap(args) {
|
|
|
33329
33654
|
}
|
|
33330
33655
|
function deriveAuditLogSubcommand(pathname, method) {
|
|
33331
33656
|
const canonical = pathname.split("?")[0] ?? pathname;
|
|
33332
|
-
if (/^\/api\/community\/messages\/[^/]+\/
|
|
33333
|
-
|
|
33334
|
-
|
|
33657
|
+
if (/^\/api\/community\/messages\/[^/]+\/properties$/.test(canonical)) {
|
|
33658
|
+
if (method === "GET")
|
|
33659
|
+
return "messagePropertyList";
|
|
33335
33660
|
if (method === "PUT")
|
|
33336
|
-
return "
|
|
33661
|
+
return "messagePropertySet";
|
|
33337
33662
|
if (method === "DELETE")
|
|
33338
|
-
return "
|
|
33663
|
+
return "messagePropertyRemove";
|
|
33339
33664
|
return null;
|
|
33340
33665
|
}
|
|
33666
|
+
if (/^\/api\/community\/messages\/[^/]+\/reactions\//.test(canonical))
|
|
33667
|
+
return "reactAdd";
|
|
33341
33668
|
if (method === "GET" && /^\/api\/community\/users\/me\/marks$/.test(canonical))
|
|
33342
33669
|
return "markList";
|
|
33343
33670
|
if (/^\/api\/community\/channels\/[^/]+\/messages\/seq\//.test(canonical))
|
|
@@ -33503,14 +33830,14 @@ async function createDaemon(opts) {
|
|
|
33503
33830
|
log2.warn("inbox pull timeline observation failed", { agentId, reason, contentEncoding });
|
|
33504
33831
|
},
|
|
33505
33832
|
onMessageReminderArm: (input) => reminderSchedulerRef?.arm(input) ?? { armed: false, reason: "reminder_scheduler_unavailable" },
|
|
33506
|
-
onProxyRequest: (agentId, method, pathname) => {
|
|
33833
|
+
onProxyRequest: (agentId, method, pathname, metadata) => {
|
|
33507
33834
|
const subcommand = deriveAuditLogSubcommand(pathname, method);
|
|
33508
33835
|
if (!subcommand)
|
|
33509
33836
|
return;
|
|
33510
33837
|
const context = managerRef?.auditContext(agentId);
|
|
33511
33838
|
emitBotAuditEvent(agentId, {
|
|
33512
33839
|
kind: "cli_invocation",
|
|
33513
|
-
payload: { subcommand }
|
|
33840
|
+
payload: { subcommand, ...metadata ? { propertyType: metadata.propertyType } : {} }
|
|
33514
33841
|
}, context);
|
|
33515
33842
|
emitImplicitTypingStopOnSend({
|
|
33516
33843
|
subcommand,
|