nolo-cli 0.16.0-alpha.12 → 0.16.0-alpha.14

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.
Files changed (69) hide show
  1. package/{_executeModel-LGHYA5XS.js → _executeModel-UU2JO5OB.js} +16 -15
  2. package/{agentDeleteCommand-PBIUC4FT.js → agentDeleteCommand-L6JRXPYK.js} +10 -10
  3. package/{agentEmailCommands-KC2QCPQV.js → agentEmailCommands-FE3GY3T5.js} +19 -18
  4. package/{agentListCommands-N64PHBXM.js → agentListCommands-ZWSAIC4W.js} +11 -11
  5. package/{agentMachineCommands-P7S5WAVA.js → agentMachineCommands-VWQ2GZBY.js} +10 -10
  6. package/{agentRecordCommands-JKZR2TZJ.js → agentRecordCommands-PYVZMRZM.js} +19 -18
  7. package/{agentRunCommand-2ELKCBWR.js → agentRunCommand-3ADJ2J5U.js} +24 -20
  8. package/{agentRunControl-6ADXVYMR.js → agentRunControl-YVLQ4BW5.js} +24 -1
  9. package/{agentRuntimeLocal-T6YECTNF.js → agentRuntimeLocal-LXTR6SAU.js} +7 -7
  10. package/{agentSlice-NXLMDKR7.js → agentSlice-TI6ECUGN.js} +1 -1
  11. package/{appDeleteCommands-D6B6Z4ZQ.js → appDeleteCommands-QIS37SXE.js} +11 -11
  12. package/{appDeployCommands-YMO5FK4T.js → appDeployCommands-WBHB7T5B.js} +11 -11
  13. package/{appDeployStatusCommands-EO5DWWPQ.js → appDeployStatusCommands-A3OUV6GO.js} +11 -11
  14. package/{appGetCommands-6SMZ3URQ.js → appGetCommands-LCVYIH63.js} +11 -11
  15. package/{appListCommands-RZXSWR2G.js → appListCommands-PC7QOBUO.js} +11 -11
  16. package/{chunk-4LXOVZ4W.js → chunk-2OK7P5XF.js} +54 -13
  17. package/{chunk-MSA4JAOZ.js → chunk-2ZLEOGS5.js} +1 -1
  18. package/{chunk-KKY4B2Q2.js → chunk-4PWB7JRR.js} +4 -1
  19. package/{chunk-VHXXRWNL.js → chunk-5QJFYG2N.js} +15 -5
  20. package/{chunk-F3UOACU4.js → chunk-64IEIMN4.js} +1 -1
  21. package/{chunk-XEWUC53Z.js → chunk-6IGLIDDE.js} +21 -9
  22. package/{chunk-AS3ZQ3O2.js → chunk-7OBMZCRD.js} +1 -1
  23. package/{chunk-QLUFR47U.js → chunk-AL2V7U3E.js} +1 -1
  24. package/{chunk-22NGXGN3.js → chunk-BOBNE3XT.js} +2 -2
  25. package/{chunk-MYMMNKYL.js → chunk-E5CLOOG5.js} +153 -6
  26. package/{chunk-ZXQ52OY2.js → chunk-ECGTEOC2.js} +3 -3
  27. package/chunk-FKXFCYVO.js +221 -0
  28. package/{chunk-6KBBMW4D.js → chunk-FTNTMGXT.js} +1 -1
  29. package/{chunk-6CRACQXW.js → chunk-GFPESFS6.js} +2 -2
  30. package/{chunk-47QUPRHO.js → chunk-GM37ZF7R.js} +2 -2
  31. package/{chunk-A7O4KKLZ.js → chunk-HGDFFA6T.js} +2 -2
  32. package/{chunk-C4MMO7W4.js → chunk-NZBK3ZET.js} +1 -1
  33. package/{chunk-JTMNCCWF.js → chunk-OSIJVBXP.js} +2 -2
  34. package/{chunk-OVBVEXZ7.js → chunk-PFW2ZEON.js} +53 -1
  35. package/{chunk-BXXECNBU.js → chunk-Q6B6XJBG.js} +15 -6
  36. package/{chunk-GPELDE6I.js → chunk-SOW2GCA5.js} +1 -1
  37. package/{chunk-HSASSW4L.js → chunk-TUWPYUVR.js} +7 -7
  38. package/{chunk-EQTZPEID.js → chunk-U3DCTSPN.js} +31 -49
  39. package/{chunk-D4NCEGGR.js → chunk-URVWRKFU.js} +166 -242
  40. package/{chunk-WBA6SIBB.js → chunk-UUDRNDC7.js} +1 -1
  41. package/{chunk-2WXMU64E.js → chunk-W63ZTRQU.js} +3 -3
  42. package/{chunk-ZH62XNZE.js → chunk-W6OKITU6.js} +678 -39
  43. package/{chunk-PU4LXVAC.js → chunk-XG7CSGP3.js} +1 -1
  44. package/{chunk-XRSPI6CP.js → chunk-YZXEEGKV.js} +1 -1
  45. package/{chunk-RIF3XLXK.js → chunk-ZDDHKIWB.js} +8 -4
  46. package/{createAgentAutomationAction-RKWIMKHW.js → createAgentAutomationAction-N4ZB7VX2.js} +3 -3
  47. package/{createDialogAction-VN7MEBS3.js → createDialogAction-KF6HXCCZ.js} +4 -4
  48. package/{createPageAction-JBUWBHHC.js → createPageAction-FXWSJONZ.js} +3 -3
  49. package/{dialogCommands-DFY5HJ6M.js → dialogCommands-ULS6HV5V.js} +11 -11
  50. package/{dialogSlice-NNYBU35K.js → dialogSlice-K32QLYS7.js} +3 -3
  51. package/{docCreateCommands-5L76YTI2.js → docCreateCommands-RZTRTRU4.js} +10 -10
  52. package/{docDeleteCommands-3GASP3VR.js → docDeleteCommands-FU36A663.js} +11 -11
  53. package/{docReadCommands-ALA77AZM.js → docReadCommands-IX4JXD4X.js} +10 -10
  54. package/{docStore-DR22GGF3.js → docStore-L6HBNJ3R.js} +4 -4
  55. package/{docUpdateCommands-6AZGXE5M.js → docUpdateCommands-W4OCR55Z.js} +10 -10
  56. package/{handleSendMessageAction-FHITDM7H.js → handleSendMessageAction-MFKKZXV7.js} +3 -3
  57. package/index.js +45 -45
  58. package/{machineCommands-3B4IHHVK.js → machineCommands-4MFLZERH.js} +18 -17
  59. package/{machineWsRunDispatch-AXZ6OL3V.js → machineWsRunDispatch-AAHRNKIR.js} +18 -17
  60. package/package.json +1 -1
  61. package/{readlineWorkspace-DBZCXS7Y.js → readlineWorkspace-7OPITHTN.js} +38 -29
  62. package/{runAgentClientLoop-AB7PQ3TB.js → runAgentClientLoop-HRWV7KE2.js} +12 -11
  63. package/{setPrimaryDialogAgentAction-IIVDCY5C.js → setPrimaryDialogAgentAction-57GRIGX5.js} +16 -8
  64. package/{skillDiscovery-6M2BZUFN.js → skillDiscovery-KJWT7JBU.js} +3 -3
  65. package/{spaceCommands-AB2D7A2R.js → spaceCommands-GMMQTMHK.js} +10 -10
  66. package/{spaceSlice-TEJDCU6A.js → spaceSlice-V2P5TTQU.js} +3 -3
  67. package/{streamAgentChatTurn-NZ3HLAXS.js → streamAgentChatTurn-ZANOYOUR.js} +64 -43
  68. package/{tools-M4USUF3R.js → tools-YHZP6NXU.js} +8 -7
  69. package/{updateDialogTitleAction-SMPQVKWT.js → updateDialogTitleAction-IKTPGPPE.js} +3 -3
@@ -8,7 +8,7 @@ import {
8
8
  buildLocalAgentLookupKeys,
9
9
  normalizeAgentHandle,
10
10
  shouldReadAgentKeyRemotely
11
- } from "./chunk-PU4LXVAC.js";
11
+ } from "./chunk-XG7CSGP3.js";
12
12
  import {
13
13
  LOCAL_CODEX_AGENT_ID,
14
14
  LOCAL_CODEX_AGENT_KEY,
@@ -21,7 +21,7 @@ import {
21
21
  import {
22
22
  inlineImageUrlsForCustomProvider,
23
23
  prepareTools
24
- } from "./chunk-47QUPRHO.js";
24
+ } from "./chunk-GM37ZF7R.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
- resolveRunLabel
53
- } from "./chunk-D4NCEGGR.js";
44
+ resolveEffectiveEnabledPacks
45
+ } from "./chunk-URVWRKFU.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-4LXOVZ4W.js";
57
+ } from "./chunk-2OK7P5XF.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-ZXQ52OY2.js";
63
+ } from "./chunk-ECGTEOC2.js";
72
64
  import {
73
65
  buildAgentRuntimeDialogWritePlan,
74
66
  buildLocalWorkspaceOpenAiTools,
@@ -82,7 +74,7 @@ import {
82
74
  parseSseDataLineObject,
83
75
  readOpenAiCompatibleSseCompletion,
84
76
  resolveOpenAiCompatibleProviderConfig
85
- } from "./chunk-VHXXRWNL.js";
77
+ } from "./chunk-5QJFYG2N.js";
86
78
  import {
87
79
  buildPlatformChatCompletionRequest,
88
80
  canUsePlatformChatProvider,
@@ -97,7 +89,7 @@ import {
97
89
  } from "./chunk-OIQPORYI.js";
98
90
  import {
99
91
  summarizeToolArguments
100
- } from "./chunk-RIF3XLXK.js";
92
+ } from "./chunk-ZDDHKIWB.js";
101
93
  import {
102
94
  convertMessagesToResponsesInput,
103
95
  toResponsesTools
@@ -112,7 +104,7 @@ import {
112
104
  canonicalizeToolNames,
113
105
  parseNoloWorkspaceToolArguments,
114
106
  resolveRuntimeToolSurfaceForAgent
115
- } from "./chunk-JTMNCCWF.js";
107
+ } from "./chunk-OSIJVBXP.js";
116
108
  import {
117
109
  clipCompactText
118
110
  } from "./chunk-5MMAK75Q.js";
@@ -138,9 +130,22 @@ import {
138
130
  checkStaleRun,
139
131
  finalizeRunRecord,
140
132
  findRunRecord,
141
- listRunRecords,
133
+ gcRunRecords,
134
+ queryRunRecords,
142
135
  spawnLocalBackgroundRun
143
- } from "./chunk-MYMMNKYL.js";
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
@@ -1786,7 +1970,10 @@ var LOCAL_SERVER_WEB_TOOL_NAMES = ["fetchWebpage", "exa_search"];
1786
1970
  var LOCAL_SERVER_WEB_TOOL_NAME_SET = new Set(
1787
1971
  LOCAL_SERVER_WEB_TOOL_NAMES
1788
1972
  );
1789
- var LOCAL_SERVER_MEMORY_TOOL_NAMES = ["rememberMemory"];
1973
+ var LOCAL_SERVER_MEMORY_TOOL_NAMES = [
1974
+ "queryMemory",
1975
+ "rememberMemory"
1976
+ ];
1790
1977
  var LOCAL_SERVER_MEMORY_TOOL_NAME_SET = new Set(
1791
1978
  LOCAL_SERVER_MEMORY_TOOL_NAMES
1792
1979
  );
@@ -2018,6 +2205,27 @@ function buildServerPlatformToolExecutors(args) {
2018
2205
  }
2019
2206
  ])
2020
2207
  );
2208
+ const queryMemory = async (call) => {
2209
+ const parsed = parseNoloWorkspaceToolArguments(call.arguments);
2210
+ const query = typeof parsed.query === "string" ? parsed.query.trim() : "";
2211
+ if (!query) {
2212
+ return {
2213
+ content: JSON.stringify({ error: "queryMemory \u9700\u8981\u975E\u7A7A query\u3002" }),
2214
+ metadata: { serverPlatformTool: true, memoryRead: false }
2215
+ };
2216
+ }
2217
+ const body = { userInput: query };
2218
+ if (args.agentKey) body.agentKey = args.agentKey;
2219
+ const memorySubjectId = typeof call.runtimeContext?.memorySubjectId === "string" ? call.runtimeContext.memorySubjectId.trim() : args.memorySubjectId?.trim();
2220
+ if (memorySubjectId) body.memorySubjectId = memorySubjectId;
2221
+ const raw = await postServer("/api/memory/query", body, {
2222
+ retryTransient: true
2223
+ });
2224
+ return {
2225
+ content: raw,
2226
+ metadata: { serverPlatformTool: true, memoryRead: true }
2227
+ };
2228
+ };
2021
2229
  const rememberMemory = async (call) => {
2022
2230
  const parsed = parseNoloWorkspaceToolArguments(call.arguments);
2023
2231
  const content = typeof parsed.content === "string" ? parsed.content.trim() : "";
@@ -2036,6 +2244,8 @@ function buildServerPlatformToolExecutors(args) {
2036
2244
  source: "agent-inferred"
2037
2245
  };
2038
2246
  if (args.agentKey) body.agentKey = args.agentKey;
2247
+ const memorySubjectId = typeof call.runtimeContext?.memorySubjectId === "string" ? call.runtimeContext.memorySubjectId.trim() : args.memorySubjectId?.trim();
2248
+ if (memorySubjectId) body.memorySubjectId = memorySubjectId;
2039
2249
  const raw = await postServer("/api/memory/remember", body, {
2040
2250
  retryTransient: true
2041
2251
  });
@@ -2044,11 +2254,11 @@ function buildServerPlatformToolExecutors(args) {
2044
2254
  metadata: { serverPlatformTool: true, memoryWrite: true }
2045
2255
  };
2046
2256
  };
2047
- return { ...tableExecutors, ...webExecutors, rememberMemory };
2257
+ return { ...tableExecutors, ...webExecutors, queryMemory, rememberMemory };
2048
2258
  }
2049
2259
 
2050
2260
  // packages/cli/client/cliAgentRunToolExecutors.ts
2051
- import { existsSync, readFileSync } from "node:fs";
2261
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
2052
2262
 
2053
2263
  // packages/cli/client/agentRunSnapshot.ts
2054
2264
  function readString(value) {
@@ -2135,6 +2345,276 @@ function parseAgentRunEvent(event) {
2135
2345
  return { kind: "status", snapshot };
2136
2346
  }
2137
2347
 
2348
+ // packages/ai/tools/agent/batchAggregation.ts
2349
+ var DEFAULT_BATCH_TIMEOUT_MS = 30 * 60 * 1e3;
2350
+ var MAX_ERROR_SUMMARY_CHARS = 120;
2351
+ var MAX_FAILURE_LINES = 10;
2352
+ function isFailureStatus(status) {
2353
+ return isAgentRunTerminalStatus(status) && status !== "done";
2354
+ }
2355
+ function isOrphanedStatus(status) {
2356
+ return status === "orphaned";
2357
+ }
2358
+ function toEpochMs(iso) {
2359
+ if (!iso) return void 0;
2360
+ const ms = Date.parse(iso);
2361
+ return Number.isFinite(ms) ? ms : void 0;
2362
+ }
2363
+ function isOverTimeout(run, nowMs, timeoutMs) {
2364
+ const startedMs = toEpochMs(run.startedAt);
2365
+ if (startedMs === void 0) return false;
2366
+ return nowMs - startedMs >= timeoutMs;
2367
+ }
2368
+ function truncateErrorSummary(text, max = MAX_ERROR_SUMMARY_CHARS) {
2369
+ if (!text) return "";
2370
+ const collapsed = text.replace(/\s+/g, " ").trim();
2371
+ if (collapsed.length <= max) return collapsed;
2372
+ return `${collapsed.slice(0, max - 1)}\u2026`;
2373
+ }
2374
+ function formatFailureLine(run) {
2375
+ const label = shortRunId(run.runId);
2376
+ const agent = run.agentName ? ` (${run.agentName})` : "";
2377
+ const error = truncateErrorSummary(run.errorSummary);
2378
+ return error ? `\u5931\u8D25: ${label}${agent} \u2014 ${error}` : `\u5931\u8D25: ${label}${agent}`;
2379
+ }
2380
+ function formatBatchSummary(batchId, counts, runs, reason) {
2381
+ const failures = runs.filter((r) => isFailureStatus(r.status));
2382
+ const unfinished = runs.filter((r) => !isAgentRunTerminalStatus(r.status));
2383
+ if (reason === "timeout") {
2384
+ const lines2 = [
2385
+ `\u6279\u6B21 ${batchId}: \u8D85\u65F6\u672A\u6536\u655B \u2014 ${counts.running} \u4E2A\u672A\u5B8C\u6210`
2386
+ ];
2387
+ for (const run of unfinished.slice(0, MAX_FAILURE_LINES)) {
2388
+ const agent = run.agentName ? ` (${run.agentName})` : "";
2389
+ lines2.push(`\u672A\u5B8C\u6210: ${shortRunId(run.runId)}${agent}`);
2390
+ }
2391
+ const rest2 = unfinished.length - MAX_FAILURE_LINES;
2392
+ if (rest2 > 0) lines2.push(`\u2026 \u53CA\u53E6\u5916 ${rest2} \u4E2A\u672A\u5B8C\u6210`);
2393
+ return lines2.join("\n");
2394
+ }
2395
+ const tail = counts.running > 0 ? `, ${counts.running} \u4ECD\u5728\u8DD1` : "";
2396
+ const lines = [
2397
+ `\u6279\u6B21 ${batchId}: ${counts.success + counts.failed}/${counts.total} \u5B8C\u6210 \u2014 ${counts.success} \u6210\u529F, ${counts.failed} \u5931\u8D25${tail}`
2398
+ ];
2399
+ for (const run of failures.slice(0, MAX_FAILURE_LINES)) {
2400
+ lines.push(formatFailureLine(run));
2401
+ }
2402
+ const rest = failures.length - MAX_FAILURE_LINES;
2403
+ if (rest > 0) lines.push(`\u2026 \u53CA\u53E6\u5916 ${rest} \u4E2A\u5931\u8D25`);
2404
+ return lines.join("\n");
2405
+ }
2406
+ function aggregateBatch(input) {
2407
+ const { batchId, runs, now } = input;
2408
+ const timeoutMs = input.timeoutMs ?? DEFAULT_BATCH_TIMEOUT_MS;
2409
+ const notified = new Set(input.notifiedReasons ?? []);
2410
+ const nowMs = toEpochMs(now) ?? 0;
2411
+ let success = 0;
2412
+ let failed = 0;
2413
+ let orphaned = 0;
2414
+ let running = 0;
2415
+ const unfinished = [];
2416
+ let timedOut = false;
2417
+ for (const run of runs) {
2418
+ if (isAgentRunTerminalStatus(run.status)) {
2419
+ if (run.status === "done") success += 1;
2420
+ else {
2421
+ failed += 1;
2422
+ if (isOrphanedStatus(run.status)) orphaned += 1;
2423
+ }
2424
+ } else {
2425
+ running += 1;
2426
+ unfinished.push(run.runId);
2427
+ if (isOverTimeout(run, nowMs, timeoutMs)) timedOut = true;
2428
+ }
2429
+ }
2430
+ const converged = running === 0;
2431
+ let newWakeReasons = [];
2432
+ if (failed > 0 && !notified.has("failure")) {
2433
+ newWakeReasons = ["failure"];
2434
+ } else if (converged && !notified.has("converged")) {
2435
+ newWakeReasons = ["converged"];
2436
+ } else if (timedOut && !notified.has("timeout")) {
2437
+ newWakeReasons = ["timeout"];
2438
+ }
2439
+ const counts = {
2440
+ total: runs.length,
2441
+ success,
2442
+ failed,
2443
+ orphaned,
2444
+ running
2445
+ };
2446
+ const summary = newWakeReasons.length > 0 ? formatBatchSummary(batchId, counts, runs, newWakeReasons[0]) : "";
2447
+ return {
2448
+ batchId,
2449
+ converged,
2450
+ timedOut,
2451
+ counts,
2452
+ newWakeReasons,
2453
+ unfinished,
2454
+ summary
2455
+ };
2456
+ }
2457
+
2458
+ // packages/ai/tools/agent/runtimeTodo.ts
2459
+ var TODO_REVIEW_BLOCK = "BLOCK";
2460
+ function deriveTodoStatus(input) {
2461
+ const { todo, runs } = input;
2462
+ if (todo.status === "abandoned") {
2463
+ return { status: "abandoned" };
2464
+ }
2465
+ if (runs.length === 0) {
2466
+ return { status: todo.status };
2467
+ }
2468
+ if (runs.some((r) => !isAgentRunTerminalStatus(r.status))) {
2469
+ return { status: "running", latestRun: latestRun(runs) };
2470
+ }
2471
+ const latest = latestRun(runs);
2472
+ if (latest?.reviewVerdict === TODO_REVIEW_BLOCK) {
2473
+ return {
2474
+ status: "blocked",
2475
+ latestRun: latest,
2476
+ blockedReason: clipSummary(latest.reviewReason, MAX_ERROR_SUMMARY_CHARS)
2477
+ };
2478
+ }
2479
+ if (latest?.status === "done") {
2480
+ return { status: "done", latestRun: latest };
2481
+ }
2482
+ return { status: "pending", latestRun: latest };
2483
+ }
2484
+ function toEpochMs2(iso) {
2485
+ if (!iso) return void 0;
2486
+ const ms = Date.parse(iso);
2487
+ return Number.isFinite(ms) ? ms : void 0;
2488
+ }
2489
+ function latestRun(runs) {
2490
+ let latest;
2491
+ let latestScore = -1;
2492
+ for (const run of runs) {
2493
+ const score = toEpochMs2(run.finishedAt) ?? toEpochMs2(run.startedAt) ?? -1;
2494
+ if (latest === void 0 || score >= latestScore) {
2495
+ latest = run;
2496
+ latestScore = score;
2497
+ }
2498
+ }
2499
+ return latest;
2500
+ }
2501
+ function clipSummary(text, max) {
2502
+ if (!text) return void 0;
2503
+ const folded = text.replace(/\s+/g, " ").trim();
2504
+ if (folded.length === 0) return void 0;
2505
+ return folded.length > max ? `${folded.slice(0, max - 1)}\u2026` : folded;
2506
+ }
2507
+
2508
+ // packages/cli/client/fileSystemStores.ts
2509
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2510
+ import { homedir as nodeHomedir } from "node:os";
2511
+ import { dirname, join } from "node:path";
2512
+ var nodeFs = {
2513
+ mkdirSync,
2514
+ writeFileSync,
2515
+ readFileSync,
2516
+ existsSync
2517
+ };
2518
+ function resolveNoloHome(env, homedir) {
2519
+ const custom = env?.NOLO_HOME;
2520
+ if (custom && custom.trim()) return custom.trim();
2521
+ return join(homedir(), ".nolo");
2522
+ }
2523
+ function ensureDir(dir, fs) {
2524
+ fs.mkdirSync(dir, { recursive: true });
2525
+ }
2526
+ function readJson(path, fs) {
2527
+ if (!fs.existsSync(path)) return void 0;
2528
+ try {
2529
+ const raw = fs.readFileSync(path, "utf8");
2530
+ return JSON.parse(String(raw));
2531
+ } catch {
2532
+ return void 0;
2533
+ }
2534
+ }
2535
+ function writeJson(path, data, fs) {
2536
+ fs.writeFileSync(path, JSON.stringify(data, null, 2));
2537
+ }
2538
+ function createFileSystemCircuitBreakerStore(opts = {}) {
2539
+ const env = opts.env ?? process.env;
2540
+ const homedir = opts.homedir ?? nodeHomedir;
2541
+ const fs = opts.fs ?? nodeFs;
2542
+ const filePath = opts.filePath ?? join(resolveNoloHome(env, homedir), "breakers.json");
2543
+ const loadMap = () => {
2544
+ const data = readJson(filePath, fs);
2545
+ const map = /* @__PURE__ */ new Map();
2546
+ if (data?.entries) {
2547
+ for (const entry of data.entries) {
2548
+ if (entry && typeof entry.target === "string") map.set(entry.target, entry);
2549
+ }
2550
+ }
2551
+ return map;
2552
+ };
2553
+ const persist = (map) => {
2554
+ ensureDir(dirname(filePath), fs);
2555
+ writeJson(filePath, { entries: [...map.values()] }, fs);
2556
+ };
2557
+ return {
2558
+ get(target) {
2559
+ return loadMap().get(target);
2560
+ },
2561
+ set(entry) {
2562
+ const map = loadMap();
2563
+ map.set(entry.target, entry);
2564
+ persist(map);
2565
+ },
2566
+ clear(target) {
2567
+ const map = loadMap();
2568
+ map.delete(target);
2569
+ persist(map);
2570
+ },
2571
+ clearAll() {
2572
+ persist(/* @__PURE__ */ new Map());
2573
+ }
2574
+ };
2575
+ }
2576
+ function createFileSystemTodoStore(opts = {}) {
2577
+ const env = opts.env ?? process.env;
2578
+ const homedir = opts.homedir ?? nodeHomedir;
2579
+ const fs = opts.fs ?? nodeFs;
2580
+ const filePath = opts.filePath ?? join(resolveNoloHome(env, homedir), "todos.json");
2581
+ const loadMap = () => {
2582
+ const data = readJson(filePath, fs);
2583
+ const map = /* @__PURE__ */ new Map();
2584
+ if (data?.todos) {
2585
+ for (const todo of data.todos) {
2586
+ if (todo && typeof todo.id === "string") map.set(todo.id, todo);
2587
+ }
2588
+ }
2589
+ return map;
2590
+ };
2591
+ const persist = (map) => {
2592
+ ensureDir(dirname(filePath), fs);
2593
+ writeJson(filePath, { todos: [...map.values()] }, fs);
2594
+ };
2595
+ return {
2596
+ async getTodo(id) {
2597
+ return loadMap().get(id);
2598
+ },
2599
+ async listTodos(filter) {
2600
+ const all = [...loadMap().values()];
2601
+ if (!filter?.statuses || filter.statuses.length === 0) return all;
2602
+ const wanted = new Set(filter.statuses);
2603
+ return all.filter((t2) => wanted.has(t2.status));
2604
+ },
2605
+ async putTodo(todo) {
2606
+ const map = loadMap();
2607
+ map.set(todo.id, todo);
2608
+ persist(map);
2609
+ },
2610
+ async deleteTodo(id) {
2611
+ const map = loadMap();
2612
+ map.delete(id);
2613
+ persist(map);
2614
+ }
2615
+ };
2616
+ }
2617
+
2138
2618
  // packages/cli/client/cliAgentRunToolExecutors.ts
2139
2619
  var noopOutput = { write: () => {
2140
2620
  } };
@@ -2145,7 +2625,7 @@ var parseCallArgs = (call) => {
2145
2625
  return {};
2146
2626
  }
2147
2627
  };
2148
- var resolveFs = (deps) => deps.fs ?? { existsSync, readFileSync };
2628
+ var resolveFs = (deps) => deps.fs ?? { existsSync: existsSync2, readFileSync: readFileSync2 };
2149
2629
  var tailFile = (logPath, tailLines, fs) => {
2150
2630
  if (!fs.existsSync(logPath)) return void 0;
2151
2631
  try {
@@ -2157,6 +2637,10 @@ var tailFile = (logPath, tailLines, fs) => {
2157
2637
  return void 0;
2158
2638
  }
2159
2639
  };
2640
+ var resolveBreakerStore = (deps) => deps.breakerStore ?? createFileSystemCircuitBreakerStore({ env: deps.env, homedir: deps.homedir, fs: deps.fs });
2641
+ var resolveTodoStore = (deps) => deps.todoStore ?? createFileSystemTodoStore({ env: deps.env, homedir: deps.homedir, fs: deps.fs });
2642
+ var resolveNowMs = (deps) => typeof deps.nowMs === "function" ? deps.nowMs() : Date.now();
2643
+ var resolveTarget = (deps, agentKey) => typeof deps.resolveProviderTarget === "function" ? deps.resolveProviderTarget(agentKey) : agentKey;
2160
2644
  function createCliStartAgentRunExecutor(deps = {}) {
2161
2645
  return async (call) => {
2162
2646
  const args = parseCallArgs(call);
@@ -2164,6 +2648,29 @@ function createCliStartAgentRunExecutor(deps = {}) {
2164
2648
  const task = typeof args.task === "string" ? args.task.trim() : "";
2165
2649
  if (!agentKey) throw new Error("startAgentRun: \u7F3A\u5C11 agentKey \u53C2\u6570\u3002");
2166
2650
  if (!task) throw new Error("startAgentRun: \u7F3A\u5C11\u6709\u6548\u7684 task \u6587\u672C\u63CF\u8FF0\u3002");
2651
+ const breakerStore = resolveBreakerStore(deps);
2652
+ const target = resolveTarget(deps, agentKey);
2653
+ const nowMs = resolveNowMs(deps);
2654
+ const activeBreaker = findActiveBreaker(
2655
+ nowMs,
2656
+ [breakerStore.get(target)].filter(Boolean),
2657
+ target
2658
+ );
2659
+ if (activeBreaker) {
2660
+ const resetsAt = activeBreaker.resetsAt;
2661
+ return {
2662
+ content: JSON.stringify({
2663
+ rejected: true,
2664
+ reason: "quota",
2665
+ provider: target,
2666
+ ...resetsAt !== void 0 ? { resetsAt } : {},
2667
+ message: `provider ${target} \u5904\u4E8E\u7194\u65AD\u671F\uFF08\u914D\u989D\u8017\u5C3D\uFF09\uFF0C\u5EFA\u8BAE\u6539\u6D3E\u5176\u5B83 provider\u3002`
2668
+ }),
2669
+ metadata: {
2670
+ displayData: `Run rejected \xB7 quota breaker active on ${target}`
2671
+ }
2672
+ };
2673
+ }
2167
2674
  const message = typeof args.input === "undefined" ? task : `${task}
2168
2675
 
2169
2676
  --- \u9644\u52A0\u8F93\u5165 ---
@@ -2179,13 +2686,16 @@ ${JSON.stringify(args.input)}`;
2179
2686
  ...args.ephemeral === true ? ["--ephemeral"] : []
2180
2687
  ];
2181
2688
  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 { runId } = await spawnLocalBackgroundRun(
2689
+ const batchId = typeof args.batchId === "string" && args.batchId.trim() ? args.batchId.trim() : void 0;
2690
+ const { runId, batchId: resolvedBatchId } = await spawnLocalBackgroundRun(
2183
2691
  {
2184
2692
  rawArgs,
2185
2693
  commandPath: ["agent", "run"],
2186
2694
  cliEntrypointPath: deps.cliEntrypoint,
2187
2695
  agentKey,
2188
2696
  ...agentName ? { agentName } : {},
2697
+ ...batchId ? { batchId } : {},
2698
+ ...typeof args.parentDialogId === "string" && args.parentDialogId.trim() ? { parentDialogId: args.parentDialogId.trim() } : {},
2189
2699
  cwd: deps.cwd ?? process.cwd(),
2190
2700
  message,
2191
2701
  output: noopOutput
@@ -2195,10 +2705,39 @@ ${JSON.stringify(args.input)}`;
2195
2705
  const displayName = resolveRunLabel({ agentName, agentKey, runId });
2196
2706
  const labels = agentRunCardLabels();
2197
2707
  const taskPreview = typeof args.task === "string" ? args.task.replace(/\s+/g, " ").trim().slice(0, TASK_PREVIEW_MAX) : "";
2708
+ const trackTodo = typeof args.trackTodo === "boolean" ? args.trackTodo : Boolean(resolvedBatchId);
2709
+ if (trackTodo) {
2710
+ try {
2711
+ const todoStore = resolveTodoStore(deps);
2712
+ const todoId = `todo-${resolvedBatchId}`;
2713
+ const existing = await todoStore.getTodo(todoId);
2714
+ const nowIso = new Date(nowMs).toISOString();
2715
+ const runIds = existing?.runIds ?? [];
2716
+ if (!runIds.includes(runId)) runIds.push(runId);
2717
+ const todo = {
2718
+ id: todoId,
2719
+ title: taskPreview || task.slice(0, 100),
2720
+ status: existing?.status ?? "pending",
2721
+ ...existing?.specPath ? { specPath: existing.specPath } : {},
2722
+ ...existing?.worktree ? { worktree: existing.worktree } : {},
2723
+ ...existing?.branch ? { branch: existing.branch } : {},
2724
+ ...deps.cwd ? { worktree: deps.cwd } : {},
2725
+ runIds,
2726
+ deps: existing?.deps ?? [],
2727
+ createdAt: existing?.createdAt ?? nowIso,
2728
+ updatedAt: nowIso
2729
+ };
2730
+ await todoStore.putTodo(todo);
2731
+ } catch {
2732
+ }
2733
+ }
2198
2734
  return {
2199
2735
  content: JSON.stringify({
2200
2736
  runId,
2201
2737
  status: "running",
2738
+ // batchId is always returned so the caller can later filter by it —
2739
+ // even when the caller didn't supply one, a fresh id was generated.
2740
+ batchId: resolvedBatchId,
2202
2741
  ...agentName ? { agentName } : {},
2203
2742
  ...taskPreview ? { taskPreview } : {}
2204
2743
  }),
@@ -2218,26 +2757,103 @@ function createCliControlAgentRunExecutor(deps = {}) {
2218
2757
  const action = typeof args.action === "string" ? args.action : "";
2219
2758
  const tailLines = typeof args.tailLines === "number" ? args.tailLines : 0;
2220
2759
  if (action === "list") {
2221
- const records = listRunRecords(deps);
2760
+ gcRunRecords(deps);
2761
+ const { runs: records, total, hasMore } = queryRunRecords(
2762
+ {
2763
+ ...typeof args.batchId === "string" && args.batchId.trim() ? { batchId: args.batchId.trim() } : {},
2764
+ ...typeof args.status === "string" && args.status.trim() ? { status: args.status.trim() } : typeof args.statusFilter === "string" && args.statusFilter.trim() ? { status: args.statusFilter.trim() } : {},
2765
+ ...typeof args.limit === "number" ? { limit: args.limit } : {},
2766
+ ...typeof args.offset === "number" ? { offset: args.offset } : {}
2767
+ },
2768
+ deps
2769
+ );
2222
2770
  const runs = records.map((record2) => {
2223
- const reconciled = checkStaleRun(record2.runId, deps) ?? record2;
2224
2771
  return {
2225
- runId: reconciled.runId,
2226
- status: reconciled.status,
2227
- agentKey: reconciled.agentKey,
2228
- ...reconciled.agentName ? { agentName: reconciled.agentName } : {},
2229
- pid: reconciled.pid ?? null,
2230
- startedAt: reconciled.startedAt
2772
+ runId: record2.runId,
2773
+ status: record2.status,
2774
+ agentKey: record2.agentKey,
2775
+ ...record2.agentName ? { agentName: record2.agentName } : {},
2776
+ ...record2.batchId ? { batchId: record2.batchId } : {},
2777
+ pid: record2.pid ?? null,
2778
+ startedAt: record2.startedAt
2231
2779
  };
2232
2780
  });
2233
2781
  const labels2 = agentRunCardLabels();
2782
+ const batchIdArg = typeof args.batchId === "string" && args.batchId.trim() ? args.batchId.trim() : void 0;
2783
+ let batchSummary;
2784
+ if (batchIdArg && records.length > 0) {
2785
+ const batchRuns = records.map((r) => ({
2786
+ runId: r.runId,
2787
+ status: r.status,
2788
+ startedAt: r.startedAt,
2789
+ ...r.agentName ? { agentName: r.agentName } : {}
2790
+ }));
2791
+ batchSummary = aggregateBatch({
2792
+ batchId: batchIdArg,
2793
+ runs: batchRuns,
2794
+ now: new Date(resolveNowMs(deps)).toISOString()
2795
+ });
2796
+ }
2234
2797
  return {
2235
- content: JSON.stringify({ runs, count: runs.length }),
2798
+ content: JSON.stringify({
2799
+ runs,
2800
+ count: runs.length,
2801
+ total,
2802
+ hasMore,
2803
+ ...batchSummary?.summary ? { batchSummary: batchSummary.summary } : {}
2804
+ }),
2236
2805
  metadata: {
2237
2806
  displayData: formatListRunsCard(runs, labels2)
2238
2807
  }
2239
2808
  };
2240
2809
  }
2810
+ if (action === "todo") {
2811
+ const todoStore = resolveTodoStore(deps);
2812
+ const statusesRaw = typeof args.status === "string" ? args.status.trim() : void 0;
2813
+ const filter = statusesRaw && statusesRaw !== "all" ? { statuses: statusesRaw.split(",").map((s) => s.trim()).filter(Boolean) } : void 0;
2814
+ const todos = await todoStore.listTodos(filter);
2815
+ const enriched = await Promise.all(
2816
+ todos.map(async (todo) => {
2817
+ const runSummaries = [];
2818
+ for (const rid of todo.runIds) {
2819
+ const rec = findRunRecord(rid, deps);
2820
+ if (!rec) continue;
2821
+ runSummaries.push({
2822
+ runId: rec.runId,
2823
+ status: rec.status,
2824
+ startedAt: rec.startedAt,
2825
+ ...rec.agentName ? { agentName: rec.agentName } : {}
2826
+ });
2827
+ }
2828
+ const derived = deriveTodoStatus({
2829
+ todo: { id: todo.id, status: todo.status },
2830
+ runs: runSummaries,
2831
+ now: new Date(resolveNowMs(deps)).toISOString()
2832
+ });
2833
+ return {
2834
+ id: todo.id,
2835
+ title: todo.title,
2836
+ status: derived.status,
2837
+ runIds: todo.runIds,
2838
+ ...derived.blockedReason ? { blockedReason: derived.blockedReason } : {},
2839
+ ...derived.latestRun ? { latestRunId: derived.latestRun.runId, latestRunStatus: derived.latestRun.status } : {},
2840
+ updatedAt: todo.updatedAt
2841
+ };
2842
+ })
2843
+ );
2844
+ return {
2845
+ content: JSON.stringify({ todos: enriched, count: enriched.length }),
2846
+ metadata: {
2847
+ displayData: formatListRunsCard(
2848
+ enriched.map((t2) => ({
2849
+ agentName: t2.title,
2850
+ status: t2.status
2851
+ })),
2852
+ agentRunCardLabels()
2853
+ )
2854
+ }
2855
+ };
2856
+ }
2241
2857
  if (action !== "status" && action !== "stop") {
2242
2858
  throw new Error(`controlAgentRun: \u672A\u77E5 action "${action}"\u3002`);
2243
2859
  }
@@ -2256,6 +2872,25 @@ function createCliControlAgentRunExecutor(deps = {}) {
2256
2872
  const name = resolveRunLabel(reconciled);
2257
2873
  const logLines = logTail ? logTail.split("\n") : void 0;
2258
2874
  const labels2 = agentRunCardLabels();
2875
+ if (reconciled.status === "failed" || reconciled.status === "orphaned") {
2876
+ try {
2877
+ const failureSource = logTail ?? reconciled.note ?? "";
2878
+ const failureInfo = classifyRunFailure(
2879
+ failureSource || reconciled.status
2880
+ );
2881
+ if (failureInfo.reason === "quota") {
2882
+ const t2 = resolveTarget(deps, reconciled.agentKey);
2883
+ const entry = buildBreakerEntry(
2884
+ resolveNowMs(deps),
2885
+ t2,
2886
+ "quota",
2887
+ failureInfo.retryAfterMs
2888
+ );
2889
+ resolveBreakerStore(deps).set(entry);
2890
+ }
2891
+ } catch {
2892
+ }
2893
+ }
2259
2894
  return {
2260
2895
  content: JSON.stringify({
2261
2896
  runId: reconciled.runId,
@@ -2379,7 +3014,8 @@ function buildLocalToolExecutors(args) {
2379
3014
  ...buildServerPlatformToolExecutors({
2380
3015
  env: args.env,
2381
3016
  fetchImpl: args.fetchImpl,
2382
- agentKey: args.agentKey
3017
+ agentKey: args.agentKey,
3018
+ memorySubjectId: args.memorySubjectId
2383
3019
  }),
2384
3020
  ...buildCliWorkspaceToolExecutors({
2385
3021
  env: args.env,
@@ -10420,9 +11056,9 @@ function createCliCallAgentToolExecutor(deps, ctx) {
10420
11056
  // packages/cli/client/localRuntimeAdapter.ts
10421
11057
  var currentMetaFile = fileURLToPath(import.meta.url);
10422
11058
  var isJsBundle = extname(currentMetaFile) === ".js";
10423
- var SOURCE_CLI_DIR = isJsBundle ? dirname(currentMetaFile) : dirname(dirname(currentMetaFile));
10424
- var CLI_DIR = isCompiledBinary() ? dirname(process.execPath) : SOURCE_CLI_DIR;
10425
- var CLI_ENTRYPOINT = isCompiledBinary() ? process.execPath : isJsBundle ? currentMetaFile : join(SOURCE_CLI_DIR, "index.ts");
11059
+ var SOURCE_CLI_DIR = isJsBundle ? dirname2(currentMetaFile) : dirname2(dirname2(currentMetaFile));
11060
+ var CLI_DIR = isCompiledBinary() ? dirname2(process.execPath) : SOURCE_CLI_DIR;
11061
+ var CLI_ENTRYPOINT = isCompiledBinary() ? process.execPath : isJsBundle ? currentMetaFile : join2(SOURCE_CLI_DIR, "index.ts");
10426
11062
  function createCliLocalRuntimeAdapter(deps) {
10427
11063
  const now = deps.now ?? Date.now;
10428
11064
  const createId = deps.createId ?? createFallbackId;
@@ -11225,6 +11861,7 @@ function createCliLocalRuntimeAdapter(deps) {
11225
11861
  };
11226
11862
  },
11227
11863
  executeTool: async (call, opts) => {
11864
+ const contextualCall = opts?.runtimeContext ? { ...call, runtimeContext: opts.runtimeContext } : call;
11228
11865
  assertWithinLocalToolBudget({
11229
11866
  toolName: call.name,
11230
11867
  budgets: localToolBudgets,
@@ -11233,7 +11870,7 @@ function createCliLocalRuntimeAdapter(deps) {
11233
11870
  const result = await executeLocalToolWithPolicy({
11234
11871
  env: deps.env,
11235
11872
  agentToolNames: activeAgentToolNames,
11236
- call,
11873
+ call: contextualCall,
11237
11874
  executors: localToolExecutors,
11238
11875
  abortSignal: opts?.abortSignal,
11239
11876
  detachMs: resolveExecShellDetachMs(deps.env),
@@ -11262,6 +11899,8 @@ export {
11262
11899
  t,
11263
11900
  toolLabel,
11264
11901
  agentRunCardLabels,
11902
+ QUOTA_ERROR_PATTERNS,
11903
+ isQuotaExhaustedError,
11265
11904
  clearCliLocalRuntimePreparedAgentCache,
11266
11905
  createCliCallAgentToolExecutor,
11267
11906
  createCliLocalRuntimeAdapter