nolo-cli 0.16.0-alpha.11 → 0.16.0-alpha.13
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/{_executeModel-LGHYA5XS.js → _executeModel-Y43RS7DI.js} +10 -9
- package/{agentEmailCommands-KC2QCPQV.js → agentEmailCommands-AJFG5HBG.js} +10 -9
- package/{agentMachineCommands-P7S5WAVA.js → agentMachineCommands-2ACKQSTE.js} +1 -1
- package/{agentRecordCommands-JKZR2TZJ.js → agentRecordCommands-RQTFDKKJ.js} +10 -9
- package/{agentRunCommand-2ELKCBWR.js → agentRunCommand-FAHV33ML.js} +14 -10
- package/{agentRunControl-6ADXVYMR.js → agentRunControl-YVLQ4BW5.js} +24 -1
- package/{agentSlice-NXLMDKR7.js → agentSlice-XEQOAOC6.js} +1 -1
- package/{chunk-ZH62XNZE.js → chunk-6IZTYSJK.js} +641 -31
- package/{chunk-EQTZPEID.js → chunk-A3S7ITGN.js} +17 -40
- package/{chunk-HSASSW4L.js → chunk-BE3IKV5X.js} +5 -5
- package/{chunk-ZXQ52OY2.js → chunk-COIZN2AL.js} +3 -3
- package/{chunk-MYMMNKYL.js → chunk-E5CLOOG5.js} +153 -6
- package/{chunk-47QUPRHO.js → chunk-EPCM5E6C.js} +1 -1
- package/chunk-FKXFCYVO.js +221 -0
- package/{chunk-2WXMU64E.js → chunk-IQJOXIYF.js} +2 -2
- package/{chunk-4LXOVZ4W.js → chunk-KEPSRWXW.js} +8 -8
- package/{chunk-BXXECNBU.js → chunk-MDNZEE6B.js} +1 -1
- package/{chunk-22NGXGN3.js → chunk-N3IKEYV7.js} +1 -1
- package/{chunk-WBA6SIBB.js → chunk-PFAN32FJ.js} +1 -1
- package/{chunk-XEWUC53Z.js → chunk-QSJNZQFD.js} +4 -4
- package/{chunk-6CRACQXW.js → chunk-SPHXTAG6.js} +2 -2
- package/{chunk-D4NCEGGR.js → chunk-TSGUTKW2.js} +83 -233
- package/{createAgentAutomationAction-RKWIMKHW.js → createAgentAutomationAction-G5ZEEBMB.js} +2 -2
- package/{createDialogAction-VN7MEBS3.js → createDialogAction-3EJL6XK6.js} +3 -3
- package/{createPageAction-JBUWBHHC.js → createPageAction-FIUQXAI4.js} +2 -2
- package/{dialogSlice-NNYBU35K.js → dialogSlice-H24LGUPG.js} +2 -2
- package/{docStore-DR22GGF3.js → docStore-EFEUV2FP.js} +3 -3
- package/{handleSendMessageAction-FHITDM7H.js → handleSendMessageAction-PMKHJZGP.js} +2 -2
- package/index.js +20 -20
- package/{machineCommands-3B4IHHVK.js → machineCommands-U3N22344.js} +10 -9
- package/{machineWsRunDispatch-AXZ6OL3V.js → machineWsRunDispatch-BGYPVQPM.js} +10 -9
- package/package.json +1 -1
- package/{readlineWorkspace-DBZCXS7Y.js → readlineWorkspace-HWYYQ2KL.js} +18 -16
- package/{runAgentClientLoop-AB7PQ3TB.js → runAgentClientLoop-3NESZLYZ.js} +8 -7
- package/{spaceSlice-TEJDCU6A.js → spaceSlice-YBORJR2H.js} +2 -2
- package/{streamAgentChatTurn-NZ3HLAXS.js → streamAgentChatTurn-XAPKGQ6M.js} +10 -9
- package/{tools-M4USUF3R.js → tools-RXIDHJ2C.js} +6 -5
- package/{updateDialogTitleAction-SMPQVKWT.js → updateDialogTitleAction-S7AG3P44.js} +2 -2
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
import {
|
|
22
22
|
inlineImageUrlsForCustomProvider,
|
|
23
23
|
prepareTools
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-EPCM5E6C.js";
|
|
25
25
|
import {
|
|
26
26
|
getAntigravityUserAgent,
|
|
27
27
|
isAntigravityOAuthAgent,
|
|
@@ -30,27 +30,19 @@ import {
|
|
|
30
30
|
} from "./chunk-L6NVTGI7.js";
|
|
31
31
|
import {
|
|
32
32
|
FORCED_TOOLS,
|
|
33
|
-
TASK_PREVIEW_MAX,
|
|
34
33
|
addDefaultLightWebToolsForConfiguredAgents,
|
|
35
34
|
addDefaultSystemCapabilityTools,
|
|
36
35
|
appendEnabledPackPromptPatches,
|
|
37
36
|
applyDisabledTools,
|
|
38
37
|
applySystemBuiltinSkillFilter,
|
|
39
38
|
expandEnabledPacks,
|
|
40
|
-
formatListRunsCard,
|
|
41
|
-
formatNotFoundRunCard,
|
|
42
|
-
formatStartRunCard,
|
|
43
|
-
formatStatusRunCard,
|
|
44
|
-
formatStopRunCard,
|
|
45
|
-
isAgentNameFallback,
|
|
46
39
|
readXPostFunc,
|
|
47
40
|
readXPostFunctionSchema,
|
|
48
41
|
readXhsProfileFunc,
|
|
49
42
|
readXhsProfileFunctionSchema,
|
|
50
43
|
rememberMemoryFunctionSchema,
|
|
51
|
-
resolveEffectiveEnabledPacks
|
|
52
|
-
|
|
53
|
-
} from "./chunk-D4NCEGGR.js";
|
|
44
|
+
resolveEffectiveEnabledPacks
|
|
45
|
+
} from "./chunk-TSGUTKW2.js";
|
|
54
46
|
import {
|
|
55
47
|
createDrainExhaustedResponse,
|
|
56
48
|
isCoreDrainingBody,
|
|
@@ -62,13 +54,13 @@ import {
|
|
|
62
54
|
} from "./chunk-OWOHNGCN.js";
|
|
63
55
|
import {
|
|
64
56
|
prepareTokenUsageData
|
|
65
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-KEPSRWXW.js";
|
|
66
58
|
import {
|
|
67
59
|
BUILTIN_TITLE_LLM_CONFIG
|
|
68
60
|
} from "./chunk-XOIF2TNF.js";
|
|
69
61
|
import {
|
|
70
62
|
fetchServerSyncedCredential
|
|
71
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-COIZN2AL.js";
|
|
72
64
|
import {
|
|
73
65
|
buildAgentRuntimeDialogWritePlan,
|
|
74
66
|
buildLocalWorkspaceOpenAiTools,
|
|
@@ -138,9 +130,22 @@ import {
|
|
|
138
130
|
checkStaleRun,
|
|
139
131
|
finalizeRunRecord,
|
|
140
132
|
findRunRecord,
|
|
141
|
-
|
|
133
|
+
gcRunRecords,
|
|
134
|
+
queryRunRecords,
|
|
142
135
|
spawnLocalBackgroundRun
|
|
143
|
-
} from "./chunk-
|
|
136
|
+
} from "./chunk-E5CLOOG5.js";
|
|
137
|
+
import {
|
|
138
|
+
TASK_PREVIEW_MAX,
|
|
139
|
+
formatListRunsCard,
|
|
140
|
+
formatNotFoundRunCard,
|
|
141
|
+
formatStartRunCard,
|
|
142
|
+
formatStatusRunCard,
|
|
143
|
+
formatStopRunCard,
|
|
144
|
+
isAgentNameFallback,
|
|
145
|
+
isAgentRunTerminalStatus,
|
|
146
|
+
resolveRunLabel,
|
|
147
|
+
shortRunId
|
|
148
|
+
} from "./chunk-FKXFCYVO.js";
|
|
144
149
|
import {
|
|
145
150
|
CliProviderQuotaError,
|
|
146
151
|
executeCli
|
|
@@ -950,6 +955,185 @@ function agentRunCardLabels() {
|
|
|
950
955
|
};
|
|
951
956
|
}
|
|
952
957
|
|
|
958
|
+
// packages/ai/tools/agent/quotaCircuitBreaker.ts
|
|
959
|
+
var QUOTA_ERROR_PATTERNS = [
|
|
960
|
+
/429/,
|
|
961
|
+
/quota/i,
|
|
962
|
+
/rate\s*limit/i,
|
|
963
|
+
/too\s*many\s*requests/i,
|
|
964
|
+
/额度/,
|
|
965
|
+
/上限/,
|
|
966
|
+
/用尽/,
|
|
967
|
+
/CliProviderQuotaError/i
|
|
968
|
+
];
|
|
969
|
+
var AGENT_NOT_FOUND_PATTERNS = [
|
|
970
|
+
/agent[^\n]{0,80}not\s+found/i,
|
|
971
|
+
/agent[^\n]{0,80}not\s+exist/i,
|
|
972
|
+
/agent[^\n]{0,80}不存在/i,
|
|
973
|
+
/agent[^\n]{0,80}未找到/i,
|
|
974
|
+
/AGENT_NOT_FOUND/
|
|
975
|
+
];
|
|
976
|
+
var AUTH_ERROR_PATTERNS = [
|
|
977
|
+
/401/,
|
|
978
|
+
/403/,
|
|
979
|
+
/unauthori[sz]ed/i,
|
|
980
|
+
/authentication\s+failed/i,
|
|
981
|
+
/invalid\s+(api[-\s]?key|token|credential)/i,
|
|
982
|
+
/api[-\s]?key\s+(invalid|missing|not\s+found)/i,
|
|
983
|
+
/token\s*(invalid|expired|失效|过期)/i,
|
|
984
|
+
/未授权/,
|
|
985
|
+
/认证失败/,
|
|
986
|
+
/凭证/
|
|
987
|
+
];
|
|
988
|
+
var NETWORK_ERROR_PATTERNS = [
|
|
989
|
+
/ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENOTFOUND|EHOSTUNREACH|EPIPE/i,
|
|
990
|
+
/getaddrinfo|DNS\s+(error|fail)/i,
|
|
991
|
+
/fetch\s+failed/i,
|
|
992
|
+
/network\s+(error|unreachable|down|disconnected)/i,
|
|
993
|
+
/socket\s+(hang|closed|error)/i,
|
|
994
|
+
/连接失败/,
|
|
995
|
+
/网络错误|网络异常|无法连接/
|
|
996
|
+
];
|
|
997
|
+
function findActiveBreaker(now, table, target) {
|
|
998
|
+
if (!Number.isFinite(now)) return void 0;
|
|
999
|
+
for (const entry of table) {
|
|
1000
|
+
if (entry.target !== target) continue;
|
|
1001
|
+
if (typeof entry.until === "number" && entry.until > now) return entry;
|
|
1002
|
+
}
|
|
1003
|
+
return void 0;
|
|
1004
|
+
}
|
|
1005
|
+
function isCliProviderQuotaErrorShape(error) {
|
|
1006
|
+
if (!error || typeof error !== "object") return false;
|
|
1007
|
+
const e = error;
|
|
1008
|
+
return e.name === "CliProviderQuotaError" || typeof e.message === "string" && e.message.startsWith("[QUOTA_LIMITED:");
|
|
1009
|
+
}
|
|
1010
|
+
function isQuotaExhaustedError(error) {
|
|
1011
|
+
if (!error) return false;
|
|
1012
|
+
if (isCliProviderQuotaErrorShape(error)) return true;
|
|
1013
|
+
if (error instanceof Error) {
|
|
1014
|
+
return QUOTA_ERROR_PATTERNS.some((pattern) => pattern.test(error.message));
|
|
1015
|
+
}
|
|
1016
|
+
if (typeof error === "string") {
|
|
1017
|
+
return QUOTA_ERROR_PATTERNS.some((pattern) => pattern.test(error));
|
|
1018
|
+
}
|
|
1019
|
+
const maybeStatus = error.status;
|
|
1020
|
+
if (typeof maybeStatus === "number" && maybeStatus === 429) return true;
|
|
1021
|
+
const maybeStatusCode = error.statusCode;
|
|
1022
|
+
if (typeof maybeStatusCode === "number" && maybeStatusCode === 429) return true;
|
|
1023
|
+
return false;
|
|
1024
|
+
}
|
|
1025
|
+
function isAgentNotFoundError(error) {
|
|
1026
|
+
if (!error) return false;
|
|
1027
|
+
const e = error;
|
|
1028
|
+
if (e.code === "AGENT_NOT_FOUND") return true;
|
|
1029
|
+
const message = typeof e.message === "string" ? e.message : typeof error === "string" ? error : "";
|
|
1030
|
+
if (AGENT_NOT_FOUND_PATTERNS.some((pattern) => pattern.test(message))) return true;
|
|
1031
|
+
if ((e.status === 404 || e.statusCode === 404) && /agent|不存在|未找到/i.test(message)) {
|
|
1032
|
+
return true;
|
|
1033
|
+
}
|
|
1034
|
+
return false;
|
|
1035
|
+
}
|
|
1036
|
+
function extractMessage(error) {
|
|
1037
|
+
if (typeof error === "string") return error;
|
|
1038
|
+
if (error instanceof Error) return error.message;
|
|
1039
|
+
if (error && typeof error === "object") {
|
|
1040
|
+
const m = error.message;
|
|
1041
|
+
return typeof m === "string" ? m : "";
|
|
1042
|
+
}
|
|
1043
|
+
return "";
|
|
1044
|
+
}
|
|
1045
|
+
function extractStatus(error) {
|
|
1046
|
+
if (!error || typeof error !== "object") return void 0;
|
|
1047
|
+
const e = error;
|
|
1048
|
+
const s = typeof e.status === "number" ? e.status : void 0;
|
|
1049
|
+
const sc = typeof e.statusCode === "number" ? e.statusCode : void 0;
|
|
1050
|
+
return s ?? sc;
|
|
1051
|
+
}
|
|
1052
|
+
function parseResetsInMs(text) {
|
|
1053
|
+
if (!text) return void 0;
|
|
1054
|
+
const unitMs = (n, unit) => {
|
|
1055
|
+
if (/^d/.test(unit)) return n * 24 * 3600 * 1e3;
|
|
1056
|
+
if (/^h/.test(unit)) return n * 3600 * 1e3;
|
|
1057
|
+
if (/^m/.test(unit)) return n * 60 * 1e3;
|
|
1058
|
+
if (/^s/.test(unit)) return n * 1e3;
|
|
1059
|
+
return NaN;
|
|
1060
|
+
};
|
|
1061
|
+
const re = /(\d+)\s*(d(?:ay|ays)?|h(?:r|rs|our|ours)?|m(?:in|ins|inute|inutes)?|s(?:ec|ecs|econd|econds)?)/gi;
|
|
1062
|
+
let totalMs = 0;
|
|
1063
|
+
let matched = false;
|
|
1064
|
+
let m;
|
|
1065
|
+
while ((m = re.exec(text)) !== null) {
|
|
1066
|
+
const ms = unitMs(Number(m[1]), m[2]);
|
|
1067
|
+
if (!Number.isFinite(ms)) continue;
|
|
1068
|
+
totalMs += ms;
|
|
1069
|
+
matched = true;
|
|
1070
|
+
}
|
|
1071
|
+
return matched ? totalMs : void 0;
|
|
1072
|
+
}
|
|
1073
|
+
function extractProvider(error) {
|
|
1074
|
+
if (!error || typeof error !== "object") return void 0;
|
|
1075
|
+
const p = error.provider;
|
|
1076
|
+
if (typeof p === "string" && p.length > 0) return p;
|
|
1077
|
+
const message = extractMessage(error);
|
|
1078
|
+
const tag = /\[QUOTA_LIMITED:([^\]]+)\]/i.exec(message);
|
|
1079
|
+
if (tag?.[1]) return tag[1];
|
|
1080
|
+
return void 0;
|
|
1081
|
+
}
|
|
1082
|
+
function extractRetryAfterHeader(error) {
|
|
1083
|
+
if (!error || typeof error !== "object") return void 0;
|
|
1084
|
+
const headers = error.headers;
|
|
1085
|
+
if (!headers || typeof headers !== "object") return void 0;
|
|
1086
|
+
const raw = headers["retry-after"];
|
|
1087
|
+
if (typeof raw !== "string" && typeof raw !== "number") return void 0;
|
|
1088
|
+
const secs = Number(raw);
|
|
1089
|
+
return Number.isFinite(secs) && secs > 0 ? secs * 1e3 : void 0;
|
|
1090
|
+
}
|
|
1091
|
+
function classifyRunFailure(error) {
|
|
1092
|
+
const message = extractMessage(error);
|
|
1093
|
+
const status = extractStatus(error);
|
|
1094
|
+
const retryAfterMs = extractRetryAfterHeader(error) ?? parseResetsInMs(message);
|
|
1095
|
+
if (isQuotaExhaustedError(error)) {
|
|
1096
|
+
return {
|
|
1097
|
+
reason: "quota",
|
|
1098
|
+
provider: extractProvider(error),
|
|
1099
|
+
// 纯函数不取时钟:resetsAt 由调用方用 now + retryAfterMs 计算后补齐
|
|
1100
|
+
retryAfterMs,
|
|
1101
|
+
message
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
if (isAgentNotFoundError(error)) {
|
|
1105
|
+
return { reason: "agent-not-found", message };
|
|
1106
|
+
}
|
|
1107
|
+
if (isAuthError(error)) {
|
|
1108
|
+
return { reason: "auth", message };
|
|
1109
|
+
}
|
|
1110
|
+
if (isNetworkError(error)) {
|
|
1111
|
+
return { reason: "network", message };
|
|
1112
|
+
}
|
|
1113
|
+
return { reason: "other", message };
|
|
1114
|
+
}
|
|
1115
|
+
function isAuthError(error) {
|
|
1116
|
+
const message = extractMessage(error);
|
|
1117
|
+
const status = extractStatus(error);
|
|
1118
|
+
if (status === 401 || status === 403) return true;
|
|
1119
|
+
return AUTH_ERROR_PATTERNS.some((pattern) => pattern.test(message));
|
|
1120
|
+
}
|
|
1121
|
+
function isNetworkError(error) {
|
|
1122
|
+
const message = extractMessage(error);
|
|
1123
|
+
return NETWORK_ERROR_PATTERNS.some((pattern) => pattern.test(message));
|
|
1124
|
+
}
|
|
1125
|
+
var DEFAULT_QUOTA_BREAKER_MS = 6 * 3600 * 1e3;
|
|
1126
|
+
var DEFAULT_AGENT_NOT_FOUND_BREAKER_MS = 15 * 60 * 1e3;
|
|
1127
|
+
function buildBreakerEntry(now, target, kind, retryAfterMs) {
|
|
1128
|
+
const ttl = kind === "quota" ? typeof retryAfterMs === "number" && retryAfterMs > 0 ? retryAfterMs : DEFAULT_QUOTA_BREAKER_MS : DEFAULT_AGENT_NOT_FOUND_BREAKER_MS;
|
|
1129
|
+
return {
|
|
1130
|
+
target,
|
|
1131
|
+
kind,
|
|
1132
|
+
until: now + ttl,
|
|
1133
|
+
...kind === "quota" && typeof retryAfterMs === "number" ? { resetsAt: now + retryAfterMs } : {}
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
|
|
953
1137
|
// packages/cli/client/localRuntimeDiagnostics.ts
|
|
954
1138
|
import { ulid } from "ulid";
|
|
955
1139
|
var preparedAgentRuntimeCache = /* @__PURE__ */ new Map();
|
|
@@ -989,7 +1173,7 @@ function summarizeOpenAiToolNames(tools) {
|
|
|
989
1173
|
}
|
|
990
1174
|
|
|
991
1175
|
// packages/cli/client/localRuntimeAdapter.ts
|
|
992
|
-
import { dirname, extname, join } from "node:path";
|
|
1176
|
+
import { dirname as dirname2, extname, join as join2 } from "node:path";
|
|
993
1177
|
import { fileURLToPath } from "node:url";
|
|
994
1178
|
|
|
995
1179
|
// packages/core/summarizeEndpoint.ts
|
|
@@ -2048,7 +2232,7 @@ function buildServerPlatformToolExecutors(args) {
|
|
|
2048
2232
|
}
|
|
2049
2233
|
|
|
2050
2234
|
// packages/cli/client/cliAgentRunToolExecutors.ts
|
|
2051
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
2235
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
2052
2236
|
|
|
2053
2237
|
// packages/cli/client/agentRunSnapshot.ts
|
|
2054
2238
|
function readString(value) {
|
|
@@ -2135,6 +2319,276 @@ function parseAgentRunEvent(event) {
|
|
|
2135
2319
|
return { kind: "status", snapshot };
|
|
2136
2320
|
}
|
|
2137
2321
|
|
|
2322
|
+
// packages/ai/tools/agent/batchAggregation.ts
|
|
2323
|
+
var DEFAULT_BATCH_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
2324
|
+
var MAX_ERROR_SUMMARY_CHARS = 120;
|
|
2325
|
+
var MAX_FAILURE_LINES = 10;
|
|
2326
|
+
function isFailureStatus(status) {
|
|
2327
|
+
return isAgentRunTerminalStatus(status) && status !== "done";
|
|
2328
|
+
}
|
|
2329
|
+
function isOrphanedStatus(status) {
|
|
2330
|
+
return status === "orphaned";
|
|
2331
|
+
}
|
|
2332
|
+
function toEpochMs(iso) {
|
|
2333
|
+
if (!iso) return void 0;
|
|
2334
|
+
const ms = Date.parse(iso);
|
|
2335
|
+
return Number.isFinite(ms) ? ms : void 0;
|
|
2336
|
+
}
|
|
2337
|
+
function isOverTimeout(run, nowMs, timeoutMs) {
|
|
2338
|
+
const startedMs = toEpochMs(run.startedAt);
|
|
2339
|
+
if (startedMs === void 0) return false;
|
|
2340
|
+
return nowMs - startedMs >= timeoutMs;
|
|
2341
|
+
}
|
|
2342
|
+
function truncateErrorSummary(text, max = MAX_ERROR_SUMMARY_CHARS) {
|
|
2343
|
+
if (!text) return "";
|
|
2344
|
+
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
2345
|
+
if (collapsed.length <= max) return collapsed;
|
|
2346
|
+
return `${collapsed.slice(0, max - 1)}\u2026`;
|
|
2347
|
+
}
|
|
2348
|
+
function formatFailureLine(run) {
|
|
2349
|
+
const label = shortRunId(run.runId);
|
|
2350
|
+
const agent = run.agentName ? ` (${run.agentName})` : "";
|
|
2351
|
+
const error = truncateErrorSummary(run.errorSummary);
|
|
2352
|
+
return error ? `\u5931\u8D25: ${label}${agent} \u2014 ${error}` : `\u5931\u8D25: ${label}${agent}`;
|
|
2353
|
+
}
|
|
2354
|
+
function formatBatchSummary(batchId, counts, runs, reason) {
|
|
2355
|
+
const failures = runs.filter((r) => isFailureStatus(r.status));
|
|
2356
|
+
const unfinished = runs.filter((r) => !isAgentRunTerminalStatus(r.status));
|
|
2357
|
+
if (reason === "timeout") {
|
|
2358
|
+
const lines2 = [
|
|
2359
|
+
`\u6279\u6B21 ${batchId}: \u8D85\u65F6\u672A\u6536\u655B \u2014 ${counts.running} \u4E2A\u672A\u5B8C\u6210`
|
|
2360
|
+
];
|
|
2361
|
+
for (const run of unfinished.slice(0, MAX_FAILURE_LINES)) {
|
|
2362
|
+
const agent = run.agentName ? ` (${run.agentName})` : "";
|
|
2363
|
+
lines2.push(`\u672A\u5B8C\u6210: ${shortRunId(run.runId)}${agent}`);
|
|
2364
|
+
}
|
|
2365
|
+
const rest2 = unfinished.length - MAX_FAILURE_LINES;
|
|
2366
|
+
if (rest2 > 0) lines2.push(`\u2026 \u53CA\u53E6\u5916 ${rest2} \u4E2A\u672A\u5B8C\u6210`);
|
|
2367
|
+
return lines2.join("\n");
|
|
2368
|
+
}
|
|
2369
|
+
const tail = counts.running > 0 ? `, ${counts.running} \u4ECD\u5728\u8DD1` : "";
|
|
2370
|
+
const lines = [
|
|
2371
|
+
`\u6279\u6B21 ${batchId}: ${counts.success + counts.failed}/${counts.total} \u5B8C\u6210 \u2014 ${counts.success} \u6210\u529F, ${counts.failed} \u5931\u8D25${tail}`
|
|
2372
|
+
];
|
|
2373
|
+
for (const run of failures.slice(0, MAX_FAILURE_LINES)) {
|
|
2374
|
+
lines.push(formatFailureLine(run));
|
|
2375
|
+
}
|
|
2376
|
+
const rest = failures.length - MAX_FAILURE_LINES;
|
|
2377
|
+
if (rest > 0) lines.push(`\u2026 \u53CA\u53E6\u5916 ${rest} \u4E2A\u5931\u8D25`);
|
|
2378
|
+
return lines.join("\n");
|
|
2379
|
+
}
|
|
2380
|
+
function aggregateBatch(input) {
|
|
2381
|
+
const { batchId, runs, now } = input;
|
|
2382
|
+
const timeoutMs = input.timeoutMs ?? DEFAULT_BATCH_TIMEOUT_MS;
|
|
2383
|
+
const notified = new Set(input.notifiedReasons ?? []);
|
|
2384
|
+
const nowMs = toEpochMs(now) ?? 0;
|
|
2385
|
+
let success = 0;
|
|
2386
|
+
let failed = 0;
|
|
2387
|
+
let orphaned = 0;
|
|
2388
|
+
let running = 0;
|
|
2389
|
+
const unfinished = [];
|
|
2390
|
+
let timedOut = false;
|
|
2391
|
+
for (const run of runs) {
|
|
2392
|
+
if (isAgentRunTerminalStatus(run.status)) {
|
|
2393
|
+
if (run.status === "done") success += 1;
|
|
2394
|
+
else {
|
|
2395
|
+
failed += 1;
|
|
2396
|
+
if (isOrphanedStatus(run.status)) orphaned += 1;
|
|
2397
|
+
}
|
|
2398
|
+
} else {
|
|
2399
|
+
running += 1;
|
|
2400
|
+
unfinished.push(run.runId);
|
|
2401
|
+
if (isOverTimeout(run, nowMs, timeoutMs)) timedOut = true;
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
const converged = running === 0;
|
|
2405
|
+
let newWakeReasons = [];
|
|
2406
|
+
if (failed > 0 && !notified.has("failure")) {
|
|
2407
|
+
newWakeReasons = ["failure"];
|
|
2408
|
+
} else if (converged && !notified.has("converged")) {
|
|
2409
|
+
newWakeReasons = ["converged"];
|
|
2410
|
+
} else if (timedOut && !notified.has("timeout")) {
|
|
2411
|
+
newWakeReasons = ["timeout"];
|
|
2412
|
+
}
|
|
2413
|
+
const counts = {
|
|
2414
|
+
total: runs.length,
|
|
2415
|
+
success,
|
|
2416
|
+
failed,
|
|
2417
|
+
orphaned,
|
|
2418
|
+
running
|
|
2419
|
+
};
|
|
2420
|
+
const summary = newWakeReasons.length > 0 ? formatBatchSummary(batchId, counts, runs, newWakeReasons[0]) : "";
|
|
2421
|
+
return {
|
|
2422
|
+
batchId,
|
|
2423
|
+
converged,
|
|
2424
|
+
timedOut,
|
|
2425
|
+
counts,
|
|
2426
|
+
newWakeReasons,
|
|
2427
|
+
unfinished,
|
|
2428
|
+
summary
|
|
2429
|
+
};
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
// packages/ai/tools/agent/runtimeTodo.ts
|
|
2433
|
+
var TODO_REVIEW_BLOCK = "BLOCK";
|
|
2434
|
+
function deriveTodoStatus(input) {
|
|
2435
|
+
const { todo, runs } = input;
|
|
2436
|
+
if (todo.status === "abandoned") {
|
|
2437
|
+
return { status: "abandoned" };
|
|
2438
|
+
}
|
|
2439
|
+
if (runs.length === 0) {
|
|
2440
|
+
return { status: todo.status };
|
|
2441
|
+
}
|
|
2442
|
+
if (runs.some((r) => !isAgentRunTerminalStatus(r.status))) {
|
|
2443
|
+
return { status: "running", latestRun: latestRun(runs) };
|
|
2444
|
+
}
|
|
2445
|
+
const latest = latestRun(runs);
|
|
2446
|
+
if (latest?.reviewVerdict === TODO_REVIEW_BLOCK) {
|
|
2447
|
+
return {
|
|
2448
|
+
status: "blocked",
|
|
2449
|
+
latestRun: latest,
|
|
2450
|
+
blockedReason: clipSummary(latest.reviewReason, MAX_ERROR_SUMMARY_CHARS)
|
|
2451
|
+
};
|
|
2452
|
+
}
|
|
2453
|
+
if (latest?.status === "done") {
|
|
2454
|
+
return { status: "done", latestRun: latest };
|
|
2455
|
+
}
|
|
2456
|
+
return { status: "pending", latestRun: latest };
|
|
2457
|
+
}
|
|
2458
|
+
function toEpochMs2(iso) {
|
|
2459
|
+
if (!iso) return void 0;
|
|
2460
|
+
const ms = Date.parse(iso);
|
|
2461
|
+
return Number.isFinite(ms) ? ms : void 0;
|
|
2462
|
+
}
|
|
2463
|
+
function latestRun(runs) {
|
|
2464
|
+
let latest;
|
|
2465
|
+
let latestScore = -1;
|
|
2466
|
+
for (const run of runs) {
|
|
2467
|
+
const score = toEpochMs2(run.finishedAt) ?? toEpochMs2(run.startedAt) ?? -1;
|
|
2468
|
+
if (latest === void 0 || score >= latestScore) {
|
|
2469
|
+
latest = run;
|
|
2470
|
+
latestScore = score;
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
return latest;
|
|
2474
|
+
}
|
|
2475
|
+
function clipSummary(text, max) {
|
|
2476
|
+
if (!text) return void 0;
|
|
2477
|
+
const folded = text.replace(/\s+/g, " ").trim();
|
|
2478
|
+
if (folded.length === 0) return void 0;
|
|
2479
|
+
return folded.length > max ? `${folded.slice(0, max - 1)}\u2026` : folded;
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
// packages/cli/client/fileSystemStores.ts
|
|
2483
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2484
|
+
import { homedir as nodeHomedir } from "node:os";
|
|
2485
|
+
import { dirname, join } from "node:path";
|
|
2486
|
+
var nodeFs = {
|
|
2487
|
+
mkdirSync,
|
|
2488
|
+
writeFileSync,
|
|
2489
|
+
readFileSync,
|
|
2490
|
+
existsSync
|
|
2491
|
+
};
|
|
2492
|
+
function resolveNoloHome(env, homedir) {
|
|
2493
|
+
const custom = env?.NOLO_HOME;
|
|
2494
|
+
if (custom && custom.trim()) return custom.trim();
|
|
2495
|
+
return join(homedir(), ".nolo");
|
|
2496
|
+
}
|
|
2497
|
+
function ensureDir(dir, fs) {
|
|
2498
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
2499
|
+
}
|
|
2500
|
+
function readJson(path, fs) {
|
|
2501
|
+
if (!fs.existsSync(path)) return void 0;
|
|
2502
|
+
try {
|
|
2503
|
+
const raw = fs.readFileSync(path, "utf8");
|
|
2504
|
+
return JSON.parse(String(raw));
|
|
2505
|
+
} catch {
|
|
2506
|
+
return void 0;
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
function writeJson(path, data, fs) {
|
|
2510
|
+
fs.writeFileSync(path, JSON.stringify(data, null, 2));
|
|
2511
|
+
}
|
|
2512
|
+
function createFileSystemCircuitBreakerStore(opts = {}) {
|
|
2513
|
+
const env = opts.env ?? process.env;
|
|
2514
|
+
const homedir = opts.homedir ?? nodeHomedir;
|
|
2515
|
+
const fs = opts.fs ?? nodeFs;
|
|
2516
|
+
const filePath = opts.filePath ?? join(resolveNoloHome(env, homedir), "breakers.json");
|
|
2517
|
+
const loadMap = () => {
|
|
2518
|
+
const data = readJson(filePath, fs);
|
|
2519
|
+
const map = /* @__PURE__ */ new Map();
|
|
2520
|
+
if (data?.entries) {
|
|
2521
|
+
for (const entry of data.entries) {
|
|
2522
|
+
if (entry && typeof entry.target === "string") map.set(entry.target, entry);
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
return map;
|
|
2526
|
+
};
|
|
2527
|
+
const persist = (map) => {
|
|
2528
|
+
ensureDir(dirname(filePath), fs);
|
|
2529
|
+
writeJson(filePath, { entries: [...map.values()] }, fs);
|
|
2530
|
+
};
|
|
2531
|
+
return {
|
|
2532
|
+
get(target) {
|
|
2533
|
+
return loadMap().get(target);
|
|
2534
|
+
},
|
|
2535
|
+
set(entry) {
|
|
2536
|
+
const map = loadMap();
|
|
2537
|
+
map.set(entry.target, entry);
|
|
2538
|
+
persist(map);
|
|
2539
|
+
},
|
|
2540
|
+
clear(target) {
|
|
2541
|
+
const map = loadMap();
|
|
2542
|
+
map.delete(target);
|
|
2543
|
+
persist(map);
|
|
2544
|
+
},
|
|
2545
|
+
clearAll() {
|
|
2546
|
+
persist(/* @__PURE__ */ new Map());
|
|
2547
|
+
}
|
|
2548
|
+
};
|
|
2549
|
+
}
|
|
2550
|
+
function createFileSystemTodoStore(opts = {}) {
|
|
2551
|
+
const env = opts.env ?? process.env;
|
|
2552
|
+
const homedir = opts.homedir ?? nodeHomedir;
|
|
2553
|
+
const fs = opts.fs ?? nodeFs;
|
|
2554
|
+
const filePath = opts.filePath ?? join(resolveNoloHome(env, homedir), "todos.json");
|
|
2555
|
+
const loadMap = () => {
|
|
2556
|
+
const data = readJson(filePath, fs);
|
|
2557
|
+
const map = /* @__PURE__ */ new Map();
|
|
2558
|
+
if (data?.todos) {
|
|
2559
|
+
for (const todo of data.todos) {
|
|
2560
|
+
if (todo && typeof todo.id === "string") map.set(todo.id, todo);
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
return map;
|
|
2564
|
+
};
|
|
2565
|
+
const persist = (map) => {
|
|
2566
|
+
ensureDir(dirname(filePath), fs);
|
|
2567
|
+
writeJson(filePath, { todos: [...map.values()] }, fs);
|
|
2568
|
+
};
|
|
2569
|
+
return {
|
|
2570
|
+
async getTodo(id) {
|
|
2571
|
+
return loadMap().get(id);
|
|
2572
|
+
},
|
|
2573
|
+
async listTodos(filter) {
|
|
2574
|
+
const all = [...loadMap().values()];
|
|
2575
|
+
if (!filter?.statuses || filter.statuses.length === 0) return all;
|
|
2576
|
+
const wanted = new Set(filter.statuses);
|
|
2577
|
+
return all.filter((t2) => wanted.has(t2.status));
|
|
2578
|
+
},
|
|
2579
|
+
async putTodo(todo) {
|
|
2580
|
+
const map = loadMap();
|
|
2581
|
+
map.set(todo.id, todo);
|
|
2582
|
+
persist(map);
|
|
2583
|
+
},
|
|
2584
|
+
async deleteTodo(id) {
|
|
2585
|
+
const map = loadMap();
|
|
2586
|
+
map.delete(id);
|
|
2587
|
+
persist(map);
|
|
2588
|
+
}
|
|
2589
|
+
};
|
|
2590
|
+
}
|
|
2591
|
+
|
|
2138
2592
|
// packages/cli/client/cliAgentRunToolExecutors.ts
|
|
2139
2593
|
var noopOutput = { write: () => {
|
|
2140
2594
|
} };
|
|
@@ -2145,7 +2599,7 @@ var parseCallArgs = (call) => {
|
|
|
2145
2599
|
return {};
|
|
2146
2600
|
}
|
|
2147
2601
|
};
|
|
2148
|
-
var resolveFs = (deps) => deps.fs ?? { existsSync, readFileSync };
|
|
2602
|
+
var resolveFs = (deps) => deps.fs ?? { existsSync: existsSync2, readFileSync: readFileSync2 };
|
|
2149
2603
|
var tailFile = (logPath, tailLines, fs) => {
|
|
2150
2604
|
if (!fs.existsSync(logPath)) return void 0;
|
|
2151
2605
|
try {
|
|
@@ -2157,6 +2611,10 @@ var tailFile = (logPath, tailLines, fs) => {
|
|
|
2157
2611
|
return void 0;
|
|
2158
2612
|
}
|
|
2159
2613
|
};
|
|
2614
|
+
var resolveBreakerStore = (deps) => deps.breakerStore ?? createFileSystemCircuitBreakerStore({ env: deps.env, homedir: deps.homedir, fs: deps.fs });
|
|
2615
|
+
var resolveTodoStore = (deps) => deps.todoStore ?? createFileSystemTodoStore({ env: deps.env, homedir: deps.homedir, fs: deps.fs });
|
|
2616
|
+
var resolveNowMs = (deps) => typeof deps.nowMs === "function" ? deps.nowMs() : Date.now();
|
|
2617
|
+
var resolveTarget = (deps, agentKey) => typeof deps.resolveProviderTarget === "function" ? deps.resolveProviderTarget(agentKey) : agentKey;
|
|
2160
2618
|
function createCliStartAgentRunExecutor(deps = {}) {
|
|
2161
2619
|
return async (call) => {
|
|
2162
2620
|
const args = parseCallArgs(call);
|
|
@@ -2164,6 +2622,29 @@ function createCliStartAgentRunExecutor(deps = {}) {
|
|
|
2164
2622
|
const task = typeof args.task === "string" ? args.task.trim() : "";
|
|
2165
2623
|
if (!agentKey) throw new Error("startAgentRun: \u7F3A\u5C11 agentKey \u53C2\u6570\u3002");
|
|
2166
2624
|
if (!task) throw new Error("startAgentRun: \u7F3A\u5C11\u6709\u6548\u7684 task \u6587\u672C\u63CF\u8FF0\u3002");
|
|
2625
|
+
const breakerStore = resolveBreakerStore(deps);
|
|
2626
|
+
const target = resolveTarget(deps, agentKey);
|
|
2627
|
+
const nowMs = resolveNowMs(deps);
|
|
2628
|
+
const activeBreaker = findActiveBreaker(
|
|
2629
|
+
nowMs,
|
|
2630
|
+
[breakerStore.get(target)].filter(Boolean),
|
|
2631
|
+
target
|
|
2632
|
+
);
|
|
2633
|
+
if (activeBreaker) {
|
|
2634
|
+
const resetsAt = activeBreaker.resetsAt;
|
|
2635
|
+
return {
|
|
2636
|
+
content: JSON.stringify({
|
|
2637
|
+
rejected: true,
|
|
2638
|
+
reason: "quota",
|
|
2639
|
+
provider: target,
|
|
2640
|
+
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
2641
|
+
message: `provider ${target} \u5904\u4E8E\u7194\u65AD\u671F\uFF08\u914D\u989D\u8017\u5C3D\uFF09\uFF0C\u5EFA\u8BAE\u6539\u6D3E\u5176\u5B83 provider\u3002`
|
|
2642
|
+
}),
|
|
2643
|
+
metadata: {
|
|
2644
|
+
displayData: `Run rejected \xB7 quota breaker active on ${target}`
|
|
2645
|
+
}
|
|
2646
|
+
};
|
|
2647
|
+
}
|
|
2167
2648
|
const message = typeof args.input === "undefined" ? task : `${task}
|
|
2168
2649
|
|
|
2169
2650
|
--- \u9644\u52A0\u8F93\u5165 ---
|
|
@@ -2179,13 +2660,15 @@ ${JSON.stringify(args.input)}`;
|
|
|
2179
2660
|
...args.ephemeral === true ? ["--ephemeral"] : []
|
|
2180
2661
|
];
|
|
2181
2662
|
const agentName = typeof args.agentName === "string" && args.agentName.trim() ? args.agentName.trim() : typeof args.name === "string" && args.name.trim() ? args.name.trim() : void 0;
|
|
2182
|
-
const
|
|
2663
|
+
const batchId = typeof args.batchId === "string" && args.batchId.trim() ? args.batchId.trim() : void 0;
|
|
2664
|
+
const { runId, batchId: resolvedBatchId } = await spawnLocalBackgroundRun(
|
|
2183
2665
|
{
|
|
2184
2666
|
rawArgs,
|
|
2185
2667
|
commandPath: ["agent", "run"],
|
|
2186
2668
|
cliEntrypointPath: deps.cliEntrypoint,
|
|
2187
2669
|
agentKey,
|
|
2188
2670
|
...agentName ? { agentName } : {},
|
|
2671
|
+
...batchId ? { batchId } : {},
|
|
2189
2672
|
cwd: deps.cwd ?? process.cwd(),
|
|
2190
2673
|
message,
|
|
2191
2674
|
output: noopOutput
|
|
@@ -2195,10 +2678,39 @@ ${JSON.stringify(args.input)}`;
|
|
|
2195
2678
|
const displayName = resolveRunLabel({ agentName, agentKey, runId });
|
|
2196
2679
|
const labels = agentRunCardLabels();
|
|
2197
2680
|
const taskPreview = typeof args.task === "string" ? args.task.replace(/\s+/g, " ").trim().slice(0, TASK_PREVIEW_MAX) : "";
|
|
2681
|
+
const trackTodo = typeof args.trackTodo === "boolean" ? args.trackTodo : Boolean(resolvedBatchId);
|
|
2682
|
+
if (trackTodo) {
|
|
2683
|
+
try {
|
|
2684
|
+
const todoStore = resolveTodoStore(deps);
|
|
2685
|
+
const todoId = `todo-${resolvedBatchId}`;
|
|
2686
|
+
const existing = await todoStore.getTodo(todoId);
|
|
2687
|
+
const nowIso = new Date(nowMs).toISOString();
|
|
2688
|
+
const runIds = existing?.runIds ?? [];
|
|
2689
|
+
if (!runIds.includes(runId)) runIds.push(runId);
|
|
2690
|
+
const todo = {
|
|
2691
|
+
id: todoId,
|
|
2692
|
+
title: taskPreview || task.slice(0, 100),
|
|
2693
|
+
status: existing?.status ?? "pending",
|
|
2694
|
+
...existing?.specPath ? { specPath: existing.specPath } : {},
|
|
2695
|
+
...existing?.worktree ? { worktree: existing.worktree } : {},
|
|
2696
|
+
...existing?.branch ? { branch: existing.branch } : {},
|
|
2697
|
+
...deps.cwd ? { worktree: deps.cwd } : {},
|
|
2698
|
+
runIds,
|
|
2699
|
+
deps: existing?.deps ?? [],
|
|
2700
|
+
createdAt: existing?.createdAt ?? nowIso,
|
|
2701
|
+
updatedAt: nowIso
|
|
2702
|
+
};
|
|
2703
|
+
await todoStore.putTodo(todo);
|
|
2704
|
+
} catch {
|
|
2705
|
+
}
|
|
2706
|
+
}
|
|
2198
2707
|
return {
|
|
2199
2708
|
content: JSON.stringify({
|
|
2200
2709
|
runId,
|
|
2201
2710
|
status: "running",
|
|
2711
|
+
// batchId is always returned so the caller can later filter by it —
|
|
2712
|
+
// even when the caller didn't supply one, a fresh id was generated.
|
|
2713
|
+
batchId: resolvedBatchId,
|
|
2202
2714
|
...agentName ? { agentName } : {},
|
|
2203
2715
|
...taskPreview ? { taskPreview } : {}
|
|
2204
2716
|
}),
|
|
@@ -2218,26 +2730,103 @@ function createCliControlAgentRunExecutor(deps = {}) {
|
|
|
2218
2730
|
const action = typeof args.action === "string" ? args.action : "";
|
|
2219
2731
|
const tailLines = typeof args.tailLines === "number" ? args.tailLines : 0;
|
|
2220
2732
|
if (action === "list") {
|
|
2221
|
-
|
|
2733
|
+
gcRunRecords(deps);
|
|
2734
|
+
const { runs: records, total, hasMore } = queryRunRecords(
|
|
2735
|
+
{
|
|
2736
|
+
...typeof args.batchId === "string" && args.batchId.trim() ? { batchId: args.batchId.trim() } : {},
|
|
2737
|
+
...typeof args.status === "string" && args.status.trim() ? { status: args.status.trim() } : typeof args.statusFilter === "string" && args.statusFilter.trim() ? { status: args.statusFilter.trim() } : {},
|
|
2738
|
+
...typeof args.limit === "number" ? { limit: args.limit } : {},
|
|
2739
|
+
...typeof args.offset === "number" ? { offset: args.offset } : {}
|
|
2740
|
+
},
|
|
2741
|
+
deps
|
|
2742
|
+
);
|
|
2222
2743
|
const runs = records.map((record2) => {
|
|
2223
|
-
const reconciled = checkStaleRun(record2.runId, deps) ?? record2;
|
|
2224
2744
|
return {
|
|
2225
|
-
runId:
|
|
2226
|
-
status:
|
|
2227
|
-
agentKey:
|
|
2228
|
-
...
|
|
2229
|
-
|
|
2230
|
-
|
|
2745
|
+
runId: record2.runId,
|
|
2746
|
+
status: record2.status,
|
|
2747
|
+
agentKey: record2.agentKey,
|
|
2748
|
+
...record2.agentName ? { agentName: record2.agentName } : {},
|
|
2749
|
+
...record2.batchId ? { batchId: record2.batchId } : {},
|
|
2750
|
+
pid: record2.pid ?? null,
|
|
2751
|
+
startedAt: record2.startedAt
|
|
2231
2752
|
};
|
|
2232
2753
|
});
|
|
2233
2754
|
const labels2 = agentRunCardLabels();
|
|
2755
|
+
const batchIdArg = typeof args.batchId === "string" && args.batchId.trim() ? args.batchId.trim() : void 0;
|
|
2756
|
+
let batchSummary;
|
|
2757
|
+
if (batchIdArg && records.length > 0) {
|
|
2758
|
+
const batchRuns = records.map((r) => ({
|
|
2759
|
+
runId: r.runId,
|
|
2760
|
+
status: r.status,
|
|
2761
|
+
startedAt: r.startedAt,
|
|
2762
|
+
...r.agentName ? { agentName: r.agentName } : {}
|
|
2763
|
+
}));
|
|
2764
|
+
batchSummary = aggregateBatch({
|
|
2765
|
+
batchId: batchIdArg,
|
|
2766
|
+
runs: batchRuns,
|
|
2767
|
+
now: new Date(resolveNowMs(deps)).toISOString()
|
|
2768
|
+
});
|
|
2769
|
+
}
|
|
2234
2770
|
return {
|
|
2235
|
-
content: JSON.stringify({
|
|
2771
|
+
content: JSON.stringify({
|
|
2772
|
+
runs,
|
|
2773
|
+
count: runs.length,
|
|
2774
|
+
total,
|
|
2775
|
+
hasMore,
|
|
2776
|
+
...batchSummary?.summary ? { batchSummary: batchSummary.summary } : {}
|
|
2777
|
+
}),
|
|
2236
2778
|
metadata: {
|
|
2237
2779
|
displayData: formatListRunsCard(runs, labels2)
|
|
2238
2780
|
}
|
|
2239
2781
|
};
|
|
2240
2782
|
}
|
|
2783
|
+
if (action === "todo") {
|
|
2784
|
+
const todoStore = resolveTodoStore(deps);
|
|
2785
|
+
const statusesRaw = typeof args.status === "string" ? args.status.trim() : void 0;
|
|
2786
|
+
const filter = statusesRaw && statusesRaw !== "all" ? { statuses: statusesRaw.split(",").map((s) => s.trim()).filter(Boolean) } : void 0;
|
|
2787
|
+
const todos = await todoStore.listTodos(filter);
|
|
2788
|
+
const enriched = await Promise.all(
|
|
2789
|
+
todos.map(async (todo) => {
|
|
2790
|
+
const runSummaries = [];
|
|
2791
|
+
for (const rid of todo.runIds) {
|
|
2792
|
+
const rec = findRunRecord(rid, deps);
|
|
2793
|
+
if (!rec) continue;
|
|
2794
|
+
runSummaries.push({
|
|
2795
|
+
runId: rec.runId,
|
|
2796
|
+
status: rec.status,
|
|
2797
|
+
startedAt: rec.startedAt,
|
|
2798
|
+
...rec.agentName ? { agentName: rec.agentName } : {}
|
|
2799
|
+
});
|
|
2800
|
+
}
|
|
2801
|
+
const derived = deriveTodoStatus({
|
|
2802
|
+
todo: { id: todo.id, status: todo.status },
|
|
2803
|
+
runs: runSummaries,
|
|
2804
|
+
now: new Date(resolveNowMs(deps)).toISOString()
|
|
2805
|
+
});
|
|
2806
|
+
return {
|
|
2807
|
+
id: todo.id,
|
|
2808
|
+
title: todo.title,
|
|
2809
|
+
status: derived.status,
|
|
2810
|
+
runIds: todo.runIds,
|
|
2811
|
+
...derived.blockedReason ? { blockedReason: derived.blockedReason } : {},
|
|
2812
|
+
...derived.latestRun ? { latestRunId: derived.latestRun.runId, latestRunStatus: derived.latestRun.status } : {},
|
|
2813
|
+
updatedAt: todo.updatedAt
|
|
2814
|
+
};
|
|
2815
|
+
})
|
|
2816
|
+
);
|
|
2817
|
+
return {
|
|
2818
|
+
content: JSON.stringify({ todos: enriched, count: enriched.length }),
|
|
2819
|
+
metadata: {
|
|
2820
|
+
displayData: formatListRunsCard(
|
|
2821
|
+
enriched.map((t2) => ({
|
|
2822
|
+
agentName: t2.title,
|
|
2823
|
+
status: t2.status
|
|
2824
|
+
})),
|
|
2825
|
+
agentRunCardLabels()
|
|
2826
|
+
)
|
|
2827
|
+
}
|
|
2828
|
+
};
|
|
2829
|
+
}
|
|
2241
2830
|
if (action !== "status" && action !== "stop") {
|
|
2242
2831
|
throw new Error(`controlAgentRun: \u672A\u77E5 action "${action}"\u3002`);
|
|
2243
2832
|
}
|
|
@@ -2256,6 +2845,25 @@ function createCliControlAgentRunExecutor(deps = {}) {
|
|
|
2256
2845
|
const name = resolveRunLabel(reconciled);
|
|
2257
2846
|
const logLines = logTail ? logTail.split("\n") : void 0;
|
|
2258
2847
|
const labels2 = agentRunCardLabels();
|
|
2848
|
+
if (reconciled.status === "failed" || reconciled.status === "orphaned") {
|
|
2849
|
+
try {
|
|
2850
|
+
const failureSource = logTail ?? reconciled.note ?? "";
|
|
2851
|
+
const failureInfo = classifyRunFailure(
|
|
2852
|
+
failureSource || reconciled.status
|
|
2853
|
+
);
|
|
2854
|
+
if (failureInfo.reason === "quota") {
|
|
2855
|
+
const t2 = resolveTarget(deps, reconciled.agentKey);
|
|
2856
|
+
const entry = buildBreakerEntry(
|
|
2857
|
+
resolveNowMs(deps),
|
|
2858
|
+
t2,
|
|
2859
|
+
"quota",
|
|
2860
|
+
failureInfo.retryAfterMs
|
|
2861
|
+
);
|
|
2862
|
+
resolveBreakerStore(deps).set(entry);
|
|
2863
|
+
}
|
|
2864
|
+
} catch {
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2259
2867
|
return {
|
|
2260
2868
|
content: JSON.stringify({
|
|
2261
2869
|
runId: reconciled.runId,
|
|
@@ -10420,9 +11028,9 @@ function createCliCallAgentToolExecutor(deps, ctx) {
|
|
|
10420
11028
|
// packages/cli/client/localRuntimeAdapter.ts
|
|
10421
11029
|
var currentMetaFile = fileURLToPath(import.meta.url);
|
|
10422
11030
|
var isJsBundle = extname(currentMetaFile) === ".js";
|
|
10423
|
-
var SOURCE_CLI_DIR = isJsBundle ?
|
|
10424
|
-
var CLI_DIR = isCompiledBinary() ?
|
|
10425
|
-
var CLI_ENTRYPOINT = isCompiledBinary() ? process.execPath : isJsBundle ? currentMetaFile :
|
|
11031
|
+
var SOURCE_CLI_DIR = isJsBundle ? dirname2(currentMetaFile) : dirname2(dirname2(currentMetaFile));
|
|
11032
|
+
var CLI_DIR = isCompiledBinary() ? dirname2(process.execPath) : SOURCE_CLI_DIR;
|
|
11033
|
+
var CLI_ENTRYPOINT = isCompiledBinary() ? process.execPath : isJsBundle ? currentMetaFile : join2(SOURCE_CLI_DIR, "index.ts");
|
|
10426
11034
|
function createCliLocalRuntimeAdapter(deps) {
|
|
10427
11035
|
const now = deps.now ?? Date.now;
|
|
10428
11036
|
const createId = deps.createId ?? createFallbackId;
|
|
@@ -11262,6 +11870,8 @@ export {
|
|
|
11262
11870
|
t,
|
|
11263
11871
|
toolLabel,
|
|
11264
11872
|
agentRunCardLabels,
|
|
11873
|
+
QUOTA_ERROR_PATTERNS,
|
|
11874
|
+
isQuotaExhaustedError,
|
|
11265
11875
|
clearCliLocalRuntimePreparedAgentCache,
|
|
11266
11876
|
createCliCallAgentToolExecutor,
|
|
11267
11877
|
createCliLocalRuntimeAdapter
|