oasis_test_v2 2.2.43 → 2.2.45

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 (2) hide show
  1. package/dist/index.js +336 -154
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1509,8 +1509,8 @@ function trimRoundSummariesForReturn(summaries, recentRounds = DELEGATION_RETURN
1509
1509
  const cut = Math.max(0, summaries.length - keep);
1510
1510
  return summaries.map((summary, index2) => {
1511
1511
  if (index2 >= cut) return { round: summary.round, text: summary.text, truncated: false };
1512
- const firstLine2 = summary.text.split("\n").map((line) => line.trim()).find((line) => line.length > 0) ?? "";
1513
- return { round: summary.round, text: firstLine2, truncated: true };
1512
+ const firstLine3 = summary.text.split("\n").map((line) => line.trim()).find((line) => line.length > 0) ?? "";
1513
+ return { round: summary.round, text: firstLine3, truncated: true };
1514
1514
  });
1515
1515
  }
1516
1516
  function collectDelegationArtifacts(roundSummaries) {
@@ -3918,7 +3918,7 @@ var init_claude_code = __esm({
3918
3918
  const liveEventCbs = [];
3919
3919
  let eventSeq = 0;
3920
3920
  let lastResult;
3921
- const stderrTail = [];
3921
+ const stderrTail2 = [];
3922
3922
  const STDERR_MAX_LINES = 40;
3923
3923
  const STDERR_MAX_BYTES = 4e3;
3924
3924
  const usageAcc = newClaudeUsageAcc();
@@ -3991,11 +3991,11 @@ var init_claude_code = __esm({
3991
3991
  out.write(line + "\n");
3992
3992
  } catch {
3993
3993
  }
3994
- stderrTail.push(line);
3995
- while (stderrTail.length > STDERR_MAX_LINES) stderrTail.shift();
3996
- let total = stderrTail.reduce((n, l) => n + l.length + 1, 0);
3997
- while (total > STDERR_MAX_BYTES && stderrTail.length > 1) {
3998
- total -= stderrTail.shift().length + 1;
3994
+ stderrTail2.push(line);
3995
+ while (stderrTail2.length > STDERR_MAX_LINES) stderrTail2.shift();
3996
+ let total = stderrTail2.reduce((n, l) => n + l.length + 1, 0);
3997
+ while (total > STDERR_MAX_BYTES && stderrTail2.length > 1) {
3998
+ total -= stderrTail2.shift().length + 1;
3999
3999
  }
4000
4000
  });
4001
4001
  const callbacks = [];
@@ -4025,7 +4025,7 @@ var init_claude_code = __esm({
4025
4025
  if (exited) return;
4026
4026
  let reason = killReason ?? classifyExit(lastResult);
4027
4027
  const resultErrors = Array.isArray(lastResult?.errors) ? lastResult.errors.map(String) : [];
4028
- const resumeErrText = [stderrTail.join("\n"), String(lastResult?.result ?? ""), ...resultErrors].join("\n");
4028
+ const resumeErrText = [stderrTail2.join("\n"), String(lastResult?.result ?? ""), ...resultErrors].join("\n");
4029
4029
  if (!killReason && job.resumeRuntimeSession && reason !== "clean" && isSessionNotFoundError(resumeErrText)) {
4030
4030
  reason = "session-not-found";
4031
4031
  }
@@ -4059,7 +4059,7 @@ var init_claude_code = __esm({
4059
4059
  const composed = [subtype && `[${subtype}]`, body2].filter(Boolean).join(" ").trim();
4060
4060
  if (composed) errorParts.push(composed);
4061
4061
  }
4062
- if (stderrTail.length) errorParts.push(stderrTail.join("\n").trim());
4062
+ if (stderrTail2.length) errorParts.push(stderrTail2.join("\n").trim());
4063
4063
  const errorMessage = isError ? errorParts.filter(Boolean).join("\n---\n").slice(-4e3).trim() || void 0 : void 0;
4064
4064
  exited = {
4065
4065
  code: killReason ? null : code2,
@@ -4880,7 +4880,7 @@ async function listModels(runtime, executablePath) {
4880
4880
  case "claude-code":
4881
4881
  return claudeStaticModels();
4882
4882
  case "codex":
4883
- return withFallback(runtime, executablePath, () => discoverCodexModels(executablePath), codexStaticModels);
4883
+ return discoverCodexCatalog(executablePath);
4884
4884
  case "gemini":
4885
4885
  return withFallback(runtime, executablePath, async () => await discoverACPModels(executablePath ?? "gemini", "gemini", ["--acp"]) ?? [], geminiStaticModels);
4886
4886
  case "copilot":
@@ -5024,22 +5024,9 @@ function codebuddyStaticModels() {
5024
5024
  function cursorStaticModels() {
5025
5025
  return [{ id: "default[]", label: "Auto", provider: "cursor", default: true }];
5026
5026
  }
5027
- async function isModelValid(runtime, modelId, executablePath) {
5028
- try {
5029
- const models = await listModels(runtime, executablePath);
5030
- if (models.length === 0) return true;
5031
- return models.some((m2) => m2.id === modelId);
5032
- } catch {
5033
- return true;
5034
- }
5035
- }
5036
- async function defaultModelFor(runtime, executablePath) {
5037
- try {
5038
- const models = await listModels(runtime, executablePath);
5039
- return models.find((m2) => m2.default)?.id;
5040
- } catch {
5041
- return void 0;
5042
- }
5027
+ function resolveDispatchModel(candidate, catalog) {
5028
+ if (catalog.length === 0 || catalog.some((m2) => m2.id === candidate)) return { model: candidate, replaced: false };
5029
+ return { model: catalog.find((m2) => m2.default)?.id, replaced: true };
5043
5030
  }
5044
5031
  async function discoverOpenCodeModels(bin) {
5045
5032
  const out = await runCapture(bin ?? "opencode", ["models"]);
@@ -5055,7 +5042,163 @@ async function discoverOpenCodeModels(bin) {
5055
5042
  }
5056
5043
  return models;
5057
5044
  }
5058
- async function discoverCodexModels(bin) {
5045
+ async function discoverCodexCatalog(bin) {
5046
+ const probed = { customProvider: false };
5047
+ const models = await cachedDiscovery(discoveryCacheKey("codex", bin), async () => {
5048
+ const catalog = codexCatalogFromAppServer(await probeCodexAppServer(bin ?? "codex"));
5049
+ if (!catalog) return discoverCodexBundledModels(bin);
5050
+ probed.customProvider = catalog.customProvider;
5051
+ return catalog.models;
5052
+ });
5053
+ return models.length > 0 || probed.customProvider ? models : codexStaticModels();
5054
+ }
5055
+ function codexCatalogFromAppServer(probe) {
5056
+ const config2 = probe?.config;
5057
+ if (!probe || !config2) return null;
5058
+ const providerId = config2.modelProvider?.trim() || "openai";
5059
+ const customProvider = providerId.toLowerCase() !== "openai";
5060
+ if (!customProvider && !probe.models) return null;
5061
+ const provider = customProvider ? config2.providerName?.trim() || providerId : "OpenAI";
5062
+ const listApplies = !customProvider || Boolean(config2.modelCatalogJson);
5063
+ const listed = listApplies ? probe.models ?? [] : [];
5064
+ const configured = config2.model?.trim();
5065
+ const defaultId = configured || listed.find((m2) => m2.isDefault)?.id;
5066
+ const models = listed.map((m2) => ({ id: m2.id, label: m2.label, provider }));
5067
+ if (configured && !models.some((m2) => m2.id === configured)) models.push({ id: configured, label: configured, provider });
5068
+ return { models: models.map((m2) => m2.id === defaultId ? { ...m2, default: true } : m2), customProvider };
5069
+ }
5070
+ async function probeCodexAppServer(bin, timeoutMs = 15e3) {
5071
+ let dir;
5072
+ try {
5073
+ dir = (0, import_node_fs2.mkdtempSync)((0, import_node_path3.join)((0, import_node_os2.tmpdir)(), "oasis-codex-models-"));
5074
+ } catch {
5075
+ return null;
5076
+ }
5077
+ let child;
5078
+ try {
5079
+ child = (0, import_node_child_process5.spawn)(bin, ["app-server", "--stdio", "-c", "allow_login_shell=false"], {
5080
+ cwd: dir,
5081
+ stdio: ["pipe", "pipe", "ignore"],
5082
+ env: { ...process.env }
5083
+ });
5084
+ } catch {
5085
+ (0, import_node_fs2.rmSync)(dir, { recursive: true, force: true });
5086
+ return null;
5087
+ }
5088
+ return await new Promise((resolve10) => {
5089
+ let settled = false;
5090
+ let config2;
5091
+ const listed = [];
5092
+ let listState = "pending";
5093
+ let nextId = 3;
5094
+ const MAX_PAGES = 20;
5095
+ let pages = 0;
5096
+ const finish = (value2) => {
5097
+ if (settled) return;
5098
+ settled = true;
5099
+ clearTimeout(timer);
5100
+ try {
5101
+ child.stdin?.end();
5102
+ } catch {
5103
+ }
5104
+ try {
5105
+ child.kill("SIGKILL");
5106
+ } catch {
5107
+ }
5108
+ try {
5109
+ (0, import_node_fs2.rmSync)(dir, { recursive: true, force: true });
5110
+ } catch {
5111
+ }
5112
+ resolve10(value2);
5113
+ };
5114
+ const maybeFinish = () => {
5115
+ if (config2 === void 0 || listState === "pending") return;
5116
+ finish({ config: config2, models: listState === "done" ? listed : null });
5117
+ };
5118
+ const timer = setTimeout(() => finish(null), timeoutMs);
5119
+ const send = (id, method, params) => {
5120
+ try {
5121
+ child.stdin?.write(`${JSON.stringify({ jsonrpc: "2.0", id, method, params })}
5122
+ `);
5123
+ } catch {
5124
+ finish(null);
5125
+ }
5126
+ };
5127
+ child.on("error", () => finish(null));
5128
+ child.stdin?.on("error", () => finish(null));
5129
+ child.on("close", () => finish(null));
5130
+ let buf = "";
5131
+ child.stdout?.on("data", (chunk) => {
5132
+ if (settled) return;
5133
+ buf += chunk.toString("utf8");
5134
+ let nl;
5135
+ while ((nl = buf.indexOf("\n")) >= 0) {
5136
+ const line = buf.slice(0, nl).trim();
5137
+ buf = buf.slice(nl + 1);
5138
+ if (!line) continue;
5139
+ let msg;
5140
+ try {
5141
+ msg = JSON.parse(line);
5142
+ } catch {
5143
+ continue;
5144
+ }
5145
+ if (typeof msg.id !== "number") continue;
5146
+ if (msg.id === 1) {
5147
+ if (msg.error !== void 0) {
5148
+ finish(null);
5149
+ return;
5150
+ }
5151
+ send(2, "config/read", { cwd: dir });
5152
+ send(nextId, "model/list", {});
5153
+ continue;
5154
+ }
5155
+ if (msg.id === 2) {
5156
+ config2 = msg.error !== void 0 ? null : parseCodexConfigRead(msg.result);
5157
+ maybeFinish();
5158
+ continue;
5159
+ }
5160
+ if (msg.id === nextId && listState === "pending") {
5161
+ if (msg.error !== void 0) {
5162
+ listState = "failed";
5163
+ } else {
5164
+ const page = msg.result ?? {};
5165
+ for (const m2 of page.data ?? []) {
5166
+ const id = typeof m2.model === "string" && m2.model ? m2.model : typeof m2.id === "string" ? m2.id : "";
5167
+ if (!id || m2.hidden === true || listed.some((x2) => x2.id === id)) continue;
5168
+ listed.push({ id, label: typeof m2.displayName === "string" && m2.displayName ? m2.displayName : id, isDefault: m2.isDefault === true });
5169
+ }
5170
+ pages += 1;
5171
+ if (typeof page.nextCursor === "string" && page.nextCursor && pages < MAX_PAGES) {
5172
+ nextId += 1;
5173
+ send(nextId, "model/list", { cursor: page.nextCursor });
5174
+ continue;
5175
+ }
5176
+ listState = "done";
5177
+ }
5178
+ maybeFinish();
5179
+ }
5180
+ }
5181
+ });
5182
+ send(1, "initialize", { clientInfo: { name: "oasis-model-discovery", version: "0.1.0" }, capabilities: {} });
5183
+ });
5184
+ }
5185
+ function parseCodexConfigRead(result) {
5186
+ const config2 = (result ?? {}).config ?? {};
5187
+ const str5 = (v2) => typeof v2 === "string" && v2.trim() ? v2.trim() : void 0;
5188
+ const model = str5(config2["model"]);
5189
+ const modelProvider = str5(config2["model_provider"]);
5190
+ const modelCatalogJson = str5(config2["model_catalog_json"]);
5191
+ const providers = config2["model_providers"];
5192
+ const entry = modelProvider && providers && typeof providers === "object" ? providers[modelProvider] : void 0;
5193
+ const providerName = entry && typeof entry === "object" ? str5(entry["name"]) : void 0;
5194
+ return {
5195
+ ...model ? { model } : {},
5196
+ ...modelProvider ? { modelProvider } : {},
5197
+ ...providerName ? { providerName } : {},
5198
+ ...modelCatalogJson ? { modelCatalogJson } : {}
5199
+ };
5200
+ }
5201
+ async function discoverCodexBundledModels(bin) {
5059
5202
  const out = await runCapture(bin ?? "codex", ["debug", "models", "--bundled"]);
5060
5203
  if (out === void 0) return [];
5061
5204
  try {
@@ -5256,6 +5399,7 @@ async function discoverACPModels(bin, provider, args = ["acp"], timeoutMs = 12e3
5256
5399
  };
5257
5400
  const watchdog = setTimeout(fail, timeoutMs);
5258
5401
  child.on("error", fail);
5402
+ child.stdin?.on("error", fail);
5259
5403
  child.on("exit", () => {
5260
5404
  if (!settled) fail();
5261
5405
  });
@@ -5476,7 +5620,7 @@ async function runProtocolSession(job, cfg) {
5476
5620
  let eventSeq = 0;
5477
5621
  let runtimeSessionId;
5478
5622
  const pendingTurnMessages = [];
5479
- const stderrTail = [];
5623
+ const stderrTail2 = [];
5480
5624
  const finish = (info) => {
5481
5625
  if (exited) return;
5482
5626
  closing = true;
@@ -5563,8 +5707,8 @@ async function runProtocolSession(job, cfg) {
5563
5707
  child.stderr.on("data", (chunk) => {
5564
5708
  const text6 = chunk.toString("utf8");
5565
5709
  transcript.write(text6);
5566
- stderrTail.push(text6.trim());
5567
- while (stderrTail.length > 40) stderrTail.shift();
5710
+ stderrTail2.push(text6.trim());
5711
+ while (stderrTail2.length > 40) stderrTail2.shift();
5568
5712
  });
5569
5713
  const timer = setTimeout(() => {
5570
5714
  killReason ??= "timeout";
@@ -5584,7 +5728,7 @@ async function runProtocolSession(job, cfg) {
5584
5728
  const info = {
5585
5729
  code: killReason ? null : code2,
5586
5730
  reason,
5587
- ...reason === "error" && stderrTail.length ? { errorMessage: stderrTail.join("\n").slice(-4e3) } : {}
5731
+ ...reason === "error" && stderrTail2.length ? { errorMessage: stderrTail2.join("\n").slice(-4e3) } : {}
5588
5732
  };
5589
5733
  finish(!killReason && cfg.processExitInfo ? cfg.processExitInfo(info, state) : info);
5590
5734
  }
@@ -6287,8 +6431,8 @@ ${task}` : task;
6287
6431
  }
6288
6432
  if (method === "turn/completed") {
6289
6433
  const turn = record2(params?.turn);
6290
- const failure = typeof turn?.id === "string" ? state.errorsByTurn.get(turn.id) : void 0;
6291
- if (params?.threadId !== state.threadId || turn?.id !== state.turnId || turn?.status !== "completed" || turn.error || failure && !failure.willRetry) return [];
6434
+ const failure2 = typeof turn?.id === "string" ? state.errorsByTurn.get(turn.id) : void 0;
6435
+ if (params?.threadId !== state.threadId || turn?.id !== state.turnId || turn?.status !== "completed" || turn.error || failure2 && !failure2.willRetry) return [];
6292
6436
  return [{ ...base, itemId: "turn-end", itemType: "control", operation: "completed", payload: { code: "output_block_completed" } }];
6293
6437
  }
6294
6438
  return [];
@@ -6340,8 +6484,8 @@ ${task}` : task;
6340
6484
  if (params?.threadId !== state.threadId || !state.turnId || turn?.id !== state.turnId) return void 0;
6341
6485
  state.active = false;
6342
6486
  if (turn.status === "interrupted") return { code: null, reason: "cancelled" };
6343
- const failure = state.errorsByTurn.get(state.turnId);
6344
- const error2 = turn.error ?? (turn.status === "failed" || !failure?.willRetry ? failure?.error : void 0);
6487
+ const failure2 = state.errorsByTurn.get(state.turnId);
6488
+ const error2 = turn.error ?? (turn.status === "failed" || !failure2?.willRetry ? failure2?.error : void 0);
6345
6489
  if (turn.status === "completed" && !error2) return { code: 0, reason: "clean" };
6346
6490
  return { code: 1, reason: "error", errorMessage: codexTurnErrorMessage(error2) };
6347
6491
  },
@@ -6540,15 +6684,15 @@ ${task}` : task;
6540
6684
  for (const cb of telemetryCbs) cb(full);
6541
6685
  }
6542
6686
  };
6543
- const stderrTail = [];
6687
+ const stderrTail2 = [];
6544
6688
  const STDERR_MAX_LINES = 40;
6545
6689
  const STDERR_MAX_BYTES = 4e3;
6546
6690
  const pushStderrTail = (line) => {
6547
- stderrTail.push(line);
6548
- while (stderrTail.length > STDERR_MAX_LINES) stderrTail.shift();
6549
- let total = stderrTail.reduce((n, l) => n + l.length + 1, 0);
6550
- while (total > STDERR_MAX_BYTES && stderrTail.length > 1) {
6551
- total -= stderrTail.shift().length + 1;
6691
+ stderrTail2.push(line);
6692
+ while (stderrTail2.length > STDERR_MAX_LINES) stderrTail2.shift();
6693
+ let total = stderrTail2.reduce((n, l) => n + l.length + 1, 0);
6694
+ while (total > STDERR_MAX_BYTES && stderrTail2.length > 1) {
6695
+ total -= stderrTail2.shift().length + 1;
6552
6696
  }
6553
6697
  };
6554
6698
  const stdoutErrorLines = [];
@@ -6633,8 +6777,8 @@ ${task}` : task;
6633
6777
  const runtimeSessionId = telemetry.sessionId ?? resumeSessionId;
6634
6778
  const sawStreamError = streamErrorMessages.length > 0;
6635
6779
  const isError = !killReason && (code2 !== 0 || sawStreamError);
6636
- const errorMessage = isError ? [...streamErrorMessages, ...stdoutErrorLines, ...stderrTail].join("\n").trim().slice(-4e3) || void 0 : void 0;
6637
- const sessionNotFound = !killReason && isResume && isSessionNotFoundError([...streamErrorMessages, ...stdoutErrorLines, ...stderrTail].join("\n"));
6780
+ const errorMessage = isError ? [...streamErrorMessages, ...stdoutErrorLines, ...stderrTail2].join("\n").trim().slice(-4e3) || void 0 : void 0;
6781
+ const sessionNotFound = !killReason && isResume && isSessionNotFoundError([...streamErrorMessages, ...stdoutErrorLines, ...stderrTail2].join("\n"));
6638
6782
  const reason = killReason ? killReason : sessionNotFound ? "session-not-found" : sawStreamError ? "error" : code2 === 0 ? "clean" : "error";
6639
6783
  finish({
6640
6784
  code: killReason ? null : code2,
@@ -7187,10 +7331,10 @@ function parseArgsJSON(argsText) {
7187
7331
  return { text: t };
7188
7332
  }
7189
7333
  }
7190
- function composeAcpErrorMessage(rpcError, stderrTail) {
7334
+ function composeAcpErrorMessage(rpcError, stderrTail2) {
7191
7335
  const parts = [];
7192
7336
  if (rpcError && rpcError.trim()) parts.push(rpcError.trim());
7193
- if (stderrTail.length) parts.push(stderrTail.join("\n").trim());
7337
+ if (stderrTail2.length) parts.push(stderrTail2.join("\n").trim());
7194
7338
  const combined = parts.filter(Boolean).join("\n---\n").slice(-4e3).trim();
7195
7339
  return combined || void 0;
7196
7340
  }
@@ -7344,7 +7488,7 @@ ${note}` : note };
7344
7488
  killReason ??= "timeout";
7345
7489
  child.kill("SIGKILL");
7346
7490
  }, job.limits.wallClockMs);
7347
- const stderrTail = [];
7491
+ const stderrTail2 = [];
7348
7492
  const STDERR_MAX_LINES = 40;
7349
7493
  const STDERR_MAX_BYTES = 4e3;
7350
7494
  let turnMessage = "";
@@ -7359,11 +7503,11 @@ ${note}` : note };
7359
7503
  turnStderr.push(line);
7360
7504
  if (turnStderr.length > PROMPT_TURN_STDERR_MAX_LINES) turnStderr.shift();
7361
7505
  }
7362
- stderrTail.push(line);
7363
- while (stderrTail.length > STDERR_MAX_LINES) stderrTail.shift();
7364
- let total = stderrTail.reduce((n, l) => n + l.length + 1, 0);
7365
- while (total > STDERR_MAX_BYTES && stderrTail.length > 1) {
7366
- total -= stderrTail.shift().length + 1;
7506
+ stderrTail2.push(line);
7507
+ while (stderrTail2.length > STDERR_MAX_LINES) stderrTail2.shift();
7508
+ let total = stderrTail2.reduce((n, l) => n + l.length + 1, 0);
7509
+ while (total > STDERR_MAX_BYTES && stderrTail2.length > 1) {
7510
+ total -= stderrTail2.shift().length + 1;
7367
7511
  }
7368
7512
  });
7369
7513
  let lastRpcError;
@@ -7435,7 +7579,7 @@ ${note}` : note };
7435
7579
  });
7436
7580
  child.on("error", (err) => {
7437
7581
  clearTimeout(timer);
7438
- finish({ code: null, reason: "error", transcriptRef, errorMessage: composeAcpErrorMessage(err instanceof Error ? err.message : String(err), stderrTail) });
7582
+ finish({ code: null, reason: "error", transcriptRef, errorMessage: composeAcpErrorMessage(err instanceof Error ? err.message : String(err), stderrTail2) });
7439
7583
  });
7440
7584
  child.on("exit", (code2) => {
7441
7585
  clearTimeout(timer);
@@ -7445,7 +7589,7 @@ ${note}` : note };
7445
7589
  code: killReason ? null : code2,
7446
7590
  reason: killReason ?? (code2 === 0 ? "clean" : "error"),
7447
7591
  transcriptRef,
7448
- ...isError ? { errorMessage: composeAcpErrorMessage(lastRpcError, stderrTail) } : {}
7592
+ ...isError ? { errorMessage: composeAcpErrorMessage(lastRpcError, stderrTail2) } : {}
7449
7593
  });
7450
7594
  });
7451
7595
  });
@@ -7553,14 +7697,14 @@ ${task}` : task;
7553
7697
  inflightAppendBatch = [];
7554
7698
  }
7555
7699
  closingForExit = true;
7556
- let failure;
7700
+ let failure2;
7557
7701
  if (cfg.classifyPromptFailure) {
7558
7702
  await new Promise((r) => setTimeout(r, PROMPT_FAILURE_STDERR_SETTLE_MS));
7559
- failure = cfg.classifyPromptFailure({ message: turnMessage, stderrLines: [...turnStderr], result: promptResult });
7703
+ failure2 = cfg.classifyPromptFailure({ message: turnMessage, stderrLines: [...turnStderr], result: promptResult });
7560
7704
  }
7561
7705
  const usage = buildReportedUsage(client.usage, actualModel, cfg.inputTokensIncludeCacheRead === true);
7562
7706
  if (!exited) {
7563
- finish(failure ? { code: null, reason: failure.reason, errorMessage: failure.errorMessage, transcriptRef, usage, model: actualModel } : { code: 0, reason: "clean", transcriptRef, usage, model: actualModel });
7707
+ finish(failure2 ? { code: null, reason: failure2.reason, errorMessage: failure2.errorMessage, transcriptRef, usage, model: actualModel } : { code: 0, reason: "clean", transcriptRef, usage, model: actualModel });
7564
7708
  }
7565
7709
  child.kill("SIGTERM");
7566
7710
  } catch (err) {
@@ -7568,7 +7712,7 @@ ${task}` : task;
7568
7712
  if (!exited) {
7569
7713
  const reason = killReason ?? "error";
7570
7714
  const usage = buildReportedUsage(client.usage, actualModel, cfg.inputTokensIncludeCacheRead === true);
7571
- finish({ code: null, reason, transcriptRef, usage, model: actualModel, ...killReason ? {} : { errorMessage: composeAcpErrorMessage(lastRpcError, stderrTail) } });
7715
+ finish({ code: null, reason, transcriptRef, usage, model: actualModel, ...killReason ? {} : { errorMessage: composeAcpErrorMessage(lastRpcError, stderrTail2) } });
7572
7716
  }
7573
7717
  } finally {
7574
7718
  await readerDone;
@@ -7956,35 +8100,67 @@ var init_acp = __esm({
7956
8100
 
7957
8101
  // ../adapters/src/hermes/prompt-failure.ts
7958
8102
  function classifyHermesPromptFailure(turn) {
7959
- if (promptResultHasUsage(turn.result)) return void 0;
7960
- const failed = failureFromMessage(turn.message) ?? failureFromStderr(turn.stderrLines);
7961
- if (!failed) return void 0;
7962
- return {
7963
- reason: QUOTA_RE.test(failed.summary) ? "rate-limit" : "error",
7964
- errorMessage: `API call failed after ${failed.retries} retries: ${failed.summary}`
7965
- };
8103
+ const errors = mainAgentErrorRecords(turn.stderrLines);
8104
+ if (promptResultHasUsage(turn.result)) {
8105
+ const gaveUp = errors.filter((r) => API_GAVE_UP_RE.test(r));
8106
+ return gaveUp.length > 0 ? failure(clip(gaveUp.slice(-MAX_ERROR_RECORDS).join("\n"))) : void 0;
8107
+ }
8108
+ const failedSentence = FAILED_SENTENCE_RE.test(turn.message) ? firstLine(turn.message) : void 0;
8109
+ const silent = turn.message.trim() === "";
8110
+ if (errors.length === 0 && !failedSentence && !silent) return void 0;
8111
+ return failure(errors.length > 0 ? clip(errors.slice(-MAX_ERROR_RECORDS).join("\n")) : failedSentence ?? `hermes \u672C\u8F6E\u6CA1\u6709\u6B63\u5E38\u6536\u5C3E\uFF08\u54CD\u5E94\u4E0D\u5E26\u7528\u91CF\uFF09\uFF0C\u6CA1\u6709\u8F93\u51FA\uFF0Cstderr \u4E5F\u6CA1\u6709 ERROR \u65E5\u5FD7\u3002${stderrTail(turn.stderrLines)}`);
7966
8112
  }
7967
- function promptResultHasUsage(result) {
7968
- return typeof result === "object" && result !== null && result.usage != null;
8113
+ function failure(errorMessage) {
8114
+ return { reason: QUOTA_RE.test(errorMessage) ? "rate-limit" : "error", errorMessage };
7969
8115
  }
7970
- function failureFromMessage(message) {
7971
- const m2 = MESSAGE_RE.exec(message);
7972
- return m2 ? { retries: m2[1], summary: m2[2].trim() } : void 0;
8116
+ function promptResultHasUsage(result) {
8117
+ if (typeof result !== "object" || result === null) return false;
8118
+ return USAGE_KEYS.some((k2) => result[k2] != null);
7973
8119
  }
7974
- function failureFromStderr(lines) {
7975
- for (let i = lines.length - 1; i >= 0; i--) {
7976
- const m2 = STDERR_RE.exec(lines[i]);
7977
- if (m2) return { retries: m2[1], summary: m2[2].trim() };
8120
+ function mainAgentErrorRecords(lines) {
8121
+ const records = [];
8122
+ let current = null;
8123
+ const flush = () => {
8124
+ if (current) records.push(current.join("\n").trimEnd());
8125
+ current = null;
8126
+ };
8127
+ for (const line of lines) {
8128
+ const m2 = LOG_RECORD_RE.exec(line);
8129
+ if (m2) {
8130
+ flush();
8131
+ const [, level, text6] = m2;
8132
+ if ((level === "ERROR" || level === "CRITICAL") && !SUBAGENT_PREFIX_RE.test(text6)) current = [text6];
8133
+ } else if (current) {
8134
+ current.push(line);
8135
+ }
7978
8136
  }
7979
- return void 0;
8137
+ flush();
8138
+ return records.filter((r) => r.trim() !== "");
8139
+ }
8140
+ function firstLine(text6) {
8141
+ return text6.trim().split("\n")[0].trim();
7980
8142
  }
7981
- var QUOTA_RE, MESSAGE_RE, STDERR_RE;
8143
+ function clip(text6) {
8144
+ return text6.length > MAX_ERROR_CHARS ? `\u2026${text6.slice(-MAX_ERROR_CHARS)}` : text6;
8145
+ }
8146
+ function stderrTail(lines) {
8147
+ const tail = lines.filter((l) => l.trim() !== "").slice(-10).join("\n");
8148
+ return tail ? `
8149
+ stderr \u672B\u5C3E\uFF1A
8150
+ ${clip(tail)}` : "";
8151
+ }
8152
+ var QUOTA_RE, API_GAVE_UP_RE, FAILED_SENTENCE_RE, LOG_RECORD_RE, SUBAGENT_PREFIX_RE, MAX_ERROR_RECORDS, MAX_ERROR_CHARS, USAGE_KEYS;
7982
8153
  var init_prompt_failure = __esm({
7983
8154
  "../adapters/src/hermes/prompt-failure.ts"() {
7984
8155
  "use strict";
7985
8156
  QUOTA_RE = /\b429\b|rate.?limit|usage limit|quota|too many requests/i;
7986
- MESSAGE_RE = /^\s*API call failed after (\d+) retries: (.+)/;
7987
- STDERR_RE = /(?:^|:\s)API call failed after (\d+) retries\. (.+?)(?:\s\|\sprovider=.*)?$/;
8157
+ API_GAVE_UP_RE = /^(?:Non-retryable client error: |API call failed after \d+ retries\. )/;
8158
+ FAILED_SENTENCE_RE = /^\s*API call failed after \d+ retries: /;
8159
+ LOG_RECORD_RE = /^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:[,.]\d+)?\s+\[([A-Z]+)\]\s+[\w.-]+:\s?(.*)$/;
8160
+ SUBAGENT_PREFIX_RE = /^\[subagent-\d+\]\s/;
8161
+ MAX_ERROR_RECORDS = 5;
8162
+ MAX_ERROR_CHARS = 4e3;
8163
+ USAGE_KEYS = ["usage", "token_usage", "tokenUsage", "tokens", "usageMetadata", "usage_metadata"];
7988
8164
  }
7989
8165
  });
7990
8166
 
@@ -8026,7 +8202,7 @@ var init_hermes = __esm({
8026
8202
  // skills.external_dirs 配成该 env → hermes 每 session 发现各自技能。见
8027
8203
  // packages/adapters/docs/modules/07-skills-delivery.md 与 connect-script.ts。
8028
8204
  injectSkillsDirEnv: "OASIS_HERMES_SKILLS_DIR",
8029
- // 重试用尽时 hermes 照样回 end_turn,只发一句「API call failed after N retries」——见 prompt-failure.ts。
8205
+ // hermes 的 ACP 层不转发失败:API 没成功照样回 end_turn,原因只在 stderr 的 ERROR 日志里——见 prompt-failure.ts。
8030
8206
  classifyPromptFailure: classifyHermesPromptFailure,
8031
8207
  ...this.opts.syncSkills ? { syncSkills: this.opts.syncSkills } : {}
8032
8208
  });
@@ -8662,17 +8838,17 @@ async function runStreamJson(job, cfg) {
8662
8838
  );
8663
8839
  let killReason = null;
8664
8840
  let seq = 0;
8665
- const stderrTail = [];
8841
+ const stderrTail2 = [];
8666
8842
  const stderrRl = readline4.createInterface({ input: child.stderr });
8667
8843
  stderrRl.on("line", (line) => {
8668
8844
  try {
8669
8845
  transcriptOut.write(line + "\n");
8670
8846
  } catch {
8671
8847
  }
8672
- stderrTail.push(line);
8673
- while (stderrTail.length > 40) stderrTail.shift();
8674
- let total = stderrTail.reduce((n, l) => n + l.length + 1, 0);
8675
- while (total > 4e3 && stderrTail.length > 1) total -= stderrTail.shift().length + 1;
8848
+ stderrTail2.push(line);
8849
+ while (stderrTail2.length > 40) stderrTail2.shift();
8850
+ let total = stderrTail2.reduce((n, l) => n + l.length + 1, 0);
8851
+ while (total > 4e3 && stderrTail2.length > 1) total -= stderrTail2.shift().length + 1;
8676
8852
  });
8677
8853
  const rl = readline4.createInterface({ input: child.stdout });
8678
8854
  rl.on("line", (line) => {
@@ -8698,7 +8874,7 @@ async function runStreamJson(job, cfg) {
8698
8874
  child.on("exit", (code2) => {
8699
8875
  clearTimeout(timer);
8700
8876
  const isError = !killReason && typeof code2 === "number" && code2 !== 0;
8701
- const errorMessage = isError ? stderrTail.join("\n").trim().slice(-4e3) || void 0 : void 0;
8877
+ const errorMessage = isError ? stderrTail2.join("\n").trim().slice(-4e3) || void 0 : void 0;
8702
8878
  finish({
8703
8879
  code: killReason ? null : code2,
8704
8880
  reason: killReason ?? (code2 === 0 ? "clean" : "error"),
@@ -8774,17 +8950,17 @@ async function runOneShotText(job, cfg) {
8774
8950
  const text6 = chunk.toString("utf8");
8775
8951
  for (const cb of outputCbs) cb(text6);
8776
8952
  });
8777
- const stderrTail = [];
8953
+ const stderrTail2 = [];
8778
8954
  const stderrRl = readline4.createInterface({ input: child.stderr });
8779
8955
  stderrRl.on("line", (line) => {
8780
8956
  try {
8781
8957
  transcriptOut.write(line + "\n");
8782
8958
  } catch {
8783
8959
  }
8784
- stderrTail.push(line);
8785
- while (stderrTail.length > 40) stderrTail.shift();
8786
- let total = stderrTail.reduce((n, l) => n + l.length + 1, 0);
8787
- while (total > 4e3 && stderrTail.length > 1) total -= stderrTail.shift().length + 1;
8960
+ stderrTail2.push(line);
8961
+ while (stderrTail2.length > 40) stderrTail2.shift();
8962
+ let total = stderrTail2.reduce((n, l) => n + l.length + 1, 0);
8963
+ while (total > 4e3 && stderrTail2.length > 1) total -= stderrTail2.shift().length + 1;
8788
8964
  });
8789
8965
  const killChild = () => {
8790
8966
  if (containerized) killContainerBestEffort(containerized.containerName, containerized.mode);
@@ -8801,7 +8977,7 @@ async function runOneShotText(job, cfg) {
8801
8977
  child.on("exit", (code2) => {
8802
8978
  clearTimeout(timer);
8803
8979
  const isError = !killReason && typeof code2 === "number" && code2 !== 0;
8804
- const errorMessage = isError ? stderrTail.join("\n").trim().slice(-4e3) || void 0 : void 0;
8980
+ const errorMessage = isError ? stderrTail2.join("\n").trim().slice(-4e3) || void 0 : void 0;
8805
8981
  finish({
8806
8982
  code: killReason ? null : code2,
8807
8983
  reason: killReason ?? (code2 === 0 ? "clean" : "error"),
@@ -187843,22 +188019,22 @@ var init_network_maintenance = __esm({
187843
188019
  });
187844
188020
  if (!saved.committed) throw new KnowledgeMaintenanceProcessingError(`\u77E5\u8BC6\u7F51\u7EDC\u4EFB\u52A1 ${taskKey} \u7ED3\u679C\u68C0\u67E5\u70B9\u63D0\u4EA4\u51B2\u7A81`, true);
187845
188021
  },
187846
- onTaskFailed: async (taskKey, failure) => {
188022
+ onTaskFailed: async (taskKey, failure2) => {
187847
188023
  const current = (await store.list(scope2, "maintenance_task")).find((task) => task.maintenanceRunId === run.id && task.taskKey === taskKey);
187848
188024
  if (!current || current.status === "succeeded") return;
187849
- const retryable = failure.kind === "runtime" && isRetryableKnowledgeMaintenanceError(failure.cause ?? new Error(failure.message));
188025
+ const retryable = failure2.kind === "runtime" && isRetryableKnowledgeMaintenanceError(failure2.cause ?? new Error(failure2.message));
187850
188026
  const now = this.iso();
187851
- const output = failure.rawOutput ? this.snapshot(ctx, "maintenance_task_output", stableJson2(failure.rawOutput), projectId2, run.spaceId, `snapshot:maintenance-task-output:${run.id}:${taskKey}:${current.retryCount}`) : void 0;
188027
+ const output = failure2.rawOutput ? this.snapshot(ctx, "maintenance_task_output", stableJson2(failure2.rawOutput), projectId2, run.spaceId, `snapshot:maintenance-task-output:${run.id}:${taskKey}:${current.retryCount}`) : void 0;
187852
188028
  const failed = {
187853
188029
  ...current,
187854
- ...failure.sessionId ? { sessionId: failure.sessionId } : {},
188030
+ ...failure2.sessionId ? { sessionId: failure2.sessionId } : {},
187855
188031
  status: retryable ? "failed_transient" : "failed_deterministic",
187856
188032
  ...output ? { outputSnapshotRef: output.ref, outputHash: output.contentHash } : {},
187857
188033
  validationStatus: "failed",
187858
- ...failure.validationError ? { validationError: failure.validationError } : {},
187859
- error: failure.message.slice(0, 2e3),
188034
+ ...failure2.validationError ? { validationError: failure2.validationError } : {},
188035
+ error: failure2.message.slice(0, 2e3),
187860
188036
  completedAt: now,
187861
- ...failure.kind === "deterministic" ? { validatedAt: now } : {},
188037
+ ...failure2.kind === "deterministic" ? { validatedAt: now } : {},
187862
188038
  updatedAt: now
187863
188039
  };
187864
188040
  const saved = await store.transact(scope2, {
@@ -188039,9 +188215,9 @@ var init_network_maintenance = __esm({
188039
188215
  if (!result.committed) throw new Error("\u7EF4\u62A4\u5206\u6790\u7ED3\u679C\u63D0\u4EA4\u51B2\u7A81");
188040
188216
  return ready;
188041
188217
  } catch (error2) {
188042
- const failure = maintenanceFailure(error2);
188218
+ const failure2 = maintenanceFailure(error2);
188043
188219
  const latestTasks = (await store.list(scope2, "maintenance_task")).filter((task) => task.maintenanceRunId === run.id);
188044
- const validationIssue = failure.retryable ? void 0 : validationIssueForFailure(error2, latestTasks);
188220
+ const validationIssue = failure2.retryable ? void 0 : validationIssueForFailure(error2, latestTasks);
188045
188221
  const repairTaskKeys = new Set(validationIssue?.taskKeys ?? []);
188046
188222
  const now = this.iso();
188047
188223
  const invalidatedTasks = latestTasks.flatMap((task) => {
@@ -188059,8 +188235,8 @@ var init_network_maintenance = __esm({
188059
188235
  const failed = {
188060
188236
  ...processing,
188061
188237
  status: "failed",
188062
- errorCode: failure.retryable ? "ANALYSIS_TRANSIENT_FAILED" : "ANALYSIS_OR_VALIDATION_FAILED",
188063
- error: failure.message.slice(0, 2e3),
188238
+ errorCode: failure2.retryable ? "ANALYSIS_TRANSIENT_FAILED" : "ANALYSIS_OR_VALIDATION_FAILED",
188239
+ error: failure2.message.slice(0, 2e3),
188064
188240
  ...validationIssue ? { validationIssues: [validationIssue] } : { validationIssues: void 0 },
188065
188241
  retryCount: processing.retryCount + 1,
188066
188242
  updatedAt: now
@@ -188077,7 +188253,7 @@ var init_network_maintenance = __esm({
188077
188253
  const latest = await store.get(scope2, "maintenance_run", run.id);
188078
188254
  if (latest && ["awaiting_review", "approved", "publishing", "active"].includes(latest.status)) return latest;
188079
188255
  }
188080
- throw failure;
188256
+ throw failure2;
188081
188257
  }
188082
188258
  }
188083
188259
  async validateAndMaterializeAnalysis(ctx, store, scope2, run, input, analysis, options = {}) {
@@ -188876,10 +189052,10 @@ var init_network_maintenance = __esm({
188876
189052
  run = activationRun;
188877
189053
  return await this.activateGeneration(ctx, store, scope2, run, generation, space, connection);
188878
189054
  } catch (error2) {
188879
- const failure = maintenanceFailure(error2);
188880
- const message = failure.message.slice(0, 2e3);
189055
+ const failure2 = maintenanceFailure(error2);
189056
+ const message = failure2.message.slice(0, 2e3);
188881
189057
  const activation = Boolean(run.stagedAt || run.activationStartedAt);
188882
- const errorCode = activation ? failure.retryable ? "GENERATION_ACTIVATION_TRANSIENT_FAILED" : "GENERATION_ACTIVATION_FAILED" : failure.retryable ? "GENERATION_TRANSIENT_FAILED" : "GENERATION_STAGE_FAILED";
189058
+ const errorCode = activation ? failure2.retryable ? "GENERATION_ACTIVATION_TRANSIENT_FAILED" : "GENERATION_ACTIVATION_FAILED" : failure2.retryable ? "GENERATION_TRANSIENT_FAILED" : "GENERATION_STAGE_FAILED";
188883
189059
  const failedRun = { ...run, status: "failed", errorCode, error: message, retryCount: run.retryCount + 1, updatedAt: this.iso() };
188884
189060
  const failedGeneration = { ...generation, status: "failed", failureCode: errorCode, error: message, updatedAt: this.iso() };
188885
189061
  const saved = await store.transact(scope2, {
@@ -188894,7 +189070,7 @@ var init_network_maintenance = __esm({
188894
189070
  const latest = await store.get(scope2, "maintenance_run", run.id);
188895
189071
  if (latest?.status === "active") return latest;
188896
189072
  }
188897
- throw failure;
189073
+ throw failure2;
188898
189074
  }
188899
189075
  }
188900
189076
  async activateGeneration(ctx, store, scope2, run, generation, space, connection) {
@@ -197921,7 +198097,7 @@ var init_knowledge2 = __esm({
197921
198097
  });
197922
198098
 
197923
198099
  // ../server/src/domains/delegations/parent-conversation.ts
197924
- function firstLine(content3) {
198100
+ function firstLine2(content3) {
197925
198101
  const line = content3.split("\n").map((s2) => s2.trim()).find((s2) => s2.length > 0);
197926
198102
  if (!line) return null;
197927
198103
  return line.length > FIRST_LINE_MAX ? `${line.slice(0, FIRST_LINE_MAX)}\u2026` : line;
@@ -197954,7 +198130,7 @@ function buildParentConversationSnapshot(messages, opts) {
197954
198130
  lines.push(`## \u66F4\u65E9\u7684 ${olderCount} \u8F6E\uFF08\u6BCF\u6761\u53EA\u7559\u9996\u884C\uFF09`, "");
197955
198131
  for (let i = 0; i < fullFrom; i++) {
197956
198132
  for (const m2 of turns[i]) {
197957
- const head = firstLine(m2.content);
198133
+ const head = firstLine2(m2.content);
197958
198134
  if (head) lines.push(`- **${ROLE_LABEL[m2.role]}**\uFF1A${head}`);
197959
198135
  }
197960
198136
  }
@@ -198300,8 +198476,8 @@ function roundRecorded(summaries, dispatchSeq) {
198300
198476
  return summaries.some((s2) => s2.dispatchSeq === void 0 ? s2.round === dispatchSeq + 1 : s2.dispatchSeq === dispatchSeq);
198301
198477
  }
198302
198478
  function taskHeadline(task) {
198303
- const firstLine2 = task.split("\n").map((s2) => s2.trim()).find((s2) => s2.length > 0) ?? "";
198304
- const sentence = firstLine2.split(/[。!?.!?]/)[0]?.trim() || firstLine2;
198479
+ const firstLine3 = task.split("\n").map((s2) => s2.trim()).find((s2) => s2.length > 0) ?? "";
198480
+ const sentence = firstLine3.split(/[。!?.!?]/)[0]?.trim() || firstLine3;
198305
198481
  return sentence.length > TITLE_TASK_CHARS ? sentence.slice(0, TITLE_TASK_CHARS) : sentence;
198306
198482
  }
198307
198483
  function actorSlug(actorId) {
@@ -224294,7 +224470,7 @@ var init_list_usage = __esm({
224294
224470
  });
224295
224471
 
224296
224472
  // ../server/src/domains/actors/activity.ts
224297
- function clip(text6) {
224473
+ function clip2(text6) {
224298
224474
  const s2 = typeof text6 === "string" ? text6.trim() : "";
224299
224475
  return s2.length > CLIP ? `${s2.slice(0, CLIP)}\u2026` : s2;
224300
224476
  }
@@ -224317,9 +224493,9 @@ function eventSummary(ev) {
224317
224493
  return { summary: `\u6539\u56FE${parts.length ? `\uFF1A${parts.join("\u3001")}` : ""}`, detail: p2.addNodes?.[0]?.title };
224318
224494
  }
224319
224495
  case "plan.update_spec":
224320
- return { summary: `\u6539\u4EFB\u52A1\u89C4\u683C${p2.title ? `\uFF1A${clip(p2.title)}` : ""}` };
224496
+ return { summary: `\u6539\u4EFB\u52A1\u89C4\u683C${p2.title ? `\uFF1A${clip2(p2.title)}` : ""}` };
224321
224497
  case "plan.add_node":
224322
- return { summary: `\u65B0\u5EFA\u8282\u70B9${p2.title ? `\uFF1A${clip(p2.title)}` : ""}` };
224498
+ return { summary: `\u65B0\u5EFA\u8282\u70B9${p2.title ? `\uFF1A${clip2(p2.title)}` : ""}` };
224323
224499
  case "plan.delete_node":
224324
224500
  return { summary: "\u5220\u9664\u8282\u70B9" };
224325
224501
  case "plan.add_edge":
@@ -224337,7 +224513,7 @@ function eventSummary(ev) {
224337
224513
  case "work.create":
224338
224514
  return { summary: "\u6D3E\u6D3B" };
224339
224515
  case "work.kill":
224340
- return { summary: `\u505C\u6D3E${p2.reason ? `\uFF1A${clip(p2.reason)}` : ""}` };
224516
+ return { summary: `\u505C\u6D3E${p2.reason ? `\uFF1A${clip2(p2.reason)}` : ""}` };
224341
224517
  case "work.response":
224342
224518
  return { summary: p2.outcome === "failed" ? "\u4EA4\u7A3F\uFF08\u5931\u8D25\uFF09" : "\u4EA4\u7A3F" };
224343
224519
  case "work.timeout":
@@ -224349,41 +224525,41 @@ function eventSummary(ev) {
224349
224525
  case "review.create":
224350
224526
  return { summary: "\u5F00\u8BC4\u5BA1" };
224351
224527
  case "review.response":
224352
- return { summary: p2.verdict === "approve" ? "\u8BC4\u5BA1\u901A\u8FC7" : `\u8BC4\u5BA1\u6253\u56DE${p2.note ? `\uFF1A${clip(p2.note)}` : ""}` };
224528
+ return { summary: p2.verdict === "approve" ? "\u8BC4\u5BA1\u901A\u8FC7" : `\u8BC4\u5BA1\u6253\u56DE${p2.note ? `\uFF1A${clip2(p2.note)}` : ""}` };
224353
224529
  case "review.kill":
224354
- return { summary: `\u505C\u8BC4\u5BA1${p2.reason ? `\uFF1A${clip(p2.reason)}` : ""}` };
224530
+ return { summary: `\u505C\u8BC4\u5BA1${p2.reason ? `\uFF1A${clip2(p2.reason)}` : ""}` };
224355
224531
  case "review.timeout":
224356
224532
  return { summary: "\u8BC4\u5BA1\u8D85\u65F6" };
224357
224533
  case "issue.create": {
224358
224534
  switch (p2.issueKind) {
224359
224535
  case "gap":
224360
- return { summary: `\u62A5\u544A gap\uFF1A${clip(p2.body) || "\uFF08\u65E0\u63CF\u8FF0\uFF09"}`, detail: ev.issueId ? `issueId=${ev.issueId}` : void 0 };
224536
+ return { summary: `\u62A5\u544A gap\uFF1A${clip2(p2.body) || "\uFF08\u65E0\u63CF\u8FF0\uFF09"}`, detail: ev.issueId ? `issueId=${ev.issueId}` : void 0 };
224361
224537
  case "escalation":
224362
- return { summary: `\u4E0A\u62A5\u9700\u4EBA\u4ECB\u5165\uFF1A${clip(p2.body) || "\uFF08\u65E0\u539F\u56E0\uFF09"}` };
224538
+ return { summary: `\u4E0A\u62A5\u9700\u4EBA\u4ECB\u5165\uFF1A${clip2(p2.body) || "\uFF08\u65E0\u539F\u56E0\uFF09"}` };
224363
224539
  case "change_request":
224364
- return { summary: `\u53D8\u66F4\u8BF7\u6C42\uFF1A${clip(p2.body) || "\uFF08\u65E0\u63CF\u8FF0\uFF09"}` };
224540
+ return { summary: `\u53D8\u66F4\u8BF7\u6C42\uFF1A${clip2(p2.body) || "\uFF08\u65E0\u63CF\u8FF0\uFF09"}` };
224365
224541
  default:
224366
- return { summary: `\u6279\u6CE8\uFF1A${clip(p2.body) || "\uFF08\u7A7A\uFF09"}` };
224542
+ return { summary: `\u6279\u6CE8\uFF1A${clip2(p2.body) || "\uFF08\u7A7A\uFF09"}` };
224367
224543
  }
224368
224544
  }
224369
224545
  case "issue.reply":
224370
- return { summary: `\u56DE\u590D\u6279\u6CE8\uFF1A${clip(p2.body) || "\uFF08\u7A7A\uFF09"}` };
224546
+ return { summary: `\u56DE\u590D\u6279\u6CE8\uFF1A${clip2(p2.body) || "\uFF08\u7A7A\uFF09"}` };
224371
224547
  case "issue.resolve":
224372
- return { summary: `${p2.state === "resolved" ? "\u89E3\u9664" : "\u5173\u95ED"}${p2.note ? `\uFF1A${clip(p2.note)}` : ""}` };
224548
+ return { summary: `${p2.state === "resolved" ? "\u89E3\u9664" : "\u5173\u95ED"}${p2.note ? `\uFF1A${clip2(p2.note)}` : ""}` };
224373
224549
  case "issue.resolution_proposed":
224374
- return { summary: `\u63D0\u51FA\u5904\u7F6E\u65B9\u6848\uFF1A${clip(p2.proposal) || "\uFF08\u65E0\uFF09"}` };
224550
+ return { summary: `\u63D0\u51FA\u5904\u7F6E\u65B9\u6848\uFF1A${clip2(p2.proposal) || "\uFF08\u65E0\uFF09"}` };
224375
224551
  case "issue.resolution_rejected":
224376
224552
  return { summary: "\u9A73\u56DE\u5904\u7F6E\u65B9\u6848" };
224377
224553
  case "workorder.created":
224378
- return { summary: `\u5EFA\u5DE5\u5355${p2.title ? `\uFF1A${clip(p2.title)}` : ""}` };
224554
+ return { summary: `\u5EFA\u5DE5\u5355${p2.title ? `\uFF1A${clip2(p2.title)}` : ""}` };
224379
224555
  case "workorder.meta_changed":
224380
224556
  return { summary: "\u4FEE\u6539\u5DE5\u5355\u4FE1\u606F" };
224381
224557
  case "workorder.root_set":
224382
224558
  return { summary: "\u8BBE\u5B9A\u6839\u8282\u70B9" };
224383
224559
  case "workorder.sealed":
224384
- return { summary: `\u5C01\u5B58${p2.reason ? `\uFF1A${clip(p2.reason)}` : ""}${p2.note ? `\uFF1A${clip(p2.note)}` : ""}` };
224560
+ return { summary: `\u5C01\u5B58${p2.reason ? `\uFF1A${clip2(p2.reason)}` : ""}${p2.note ? `\uFF1A${clip2(p2.note)}` : ""}` };
224385
224561
  case "workorder.paused":
224386
- return { summary: `\u6682\u505C\u6D3E\u53D1${p2.reason ? `\uFF1A${clip(p2.reason)}` : ""}` };
224562
+ return { summary: `\u6682\u505C\u6D3E\u53D1${p2.reason ? `\uFF1A${clip2(p2.reason)}` : ""}` };
224387
224563
  case "workorder.resumed":
224388
224564
  return { summary: "\u6062\u590D\u6D3E\u53D1" };
224389
224565
  case "work.started":
@@ -224411,27 +224587,27 @@ function summarize3(kind, payload2) {
224411
224587
  switch (kind) {
224412
224588
  case "report_gap":
224413
224589
  return {
224414
- summary: `\u62A5\u544A gap\uFF1A${clip(p2.description) || "\uFF08\u65E0\u63CF\u8FF0\uFF09"}`,
224590
+ summary: `\u62A5\u544A gap\uFF1A${clip2(p2.description) || "\uFF08\u65E0\u63CF\u8FF0\uFF09"}`,
224415
224591
  ...p2.gapId ? { detail: `gapId=${p2.gapId}${p2.part ? `\uFF0Cpart=${p2.part}` : ""}` } : {}
224416
224592
  };
224417
224593
  case "resolve_gap":
224418
- return { summary: `\u89E3\u9664 gap\uFF1A${clip(p2.note) || "\uFF08\u65E0\u8BF4\u660E\uFF09"}`, ...p2.gapId ? { detail: `gapId=${p2.gapId}` } : {} };
224594
+ return { summary: `\u89E3\u9664 gap\uFF1A${clip2(p2.note) || "\uFF08\u65E0\u8BF4\u660E\uFF09"}`, ...p2.gapId ? { detail: `gapId=${p2.gapId}` } : {} };
224419
224595
  case "escalate":
224420
- return { summary: `\u4E0A\u62A5\u9700\u4EBA\u4ECB\u5165\uFF1A${clip(p2.reason) || "\uFF08\u65E0\u539F\u56E0\uFF09"}` };
224596
+ return { summary: `\u4E0A\u62A5\u9700\u4EBA\u4ECB\u5165\uFF1A${clip2(p2.reason) || "\uFF08\u65E0\u539F\u56E0\uFF09"}` };
224421
224597
  case "resolve_escalation":
224422
- return { summary: `\u5173\u95ED\u4E0A\u62A5${p2.note ? `\uFF1A${clip(p2.note)}` : ""}` };
224598
+ return { summary: `\u5173\u95ED\u4E0A\u62A5${p2.note ? `\uFF1A${clip2(p2.note)}` : ""}` };
224423
224599
  case "submit_review":
224424
- return { summary: `${p2.verdict === "approve" ? "\u8BC4\u5BA1\u901A\u8FC7" : "\u8BC4\u5BA1\u6253\u56DE"}${p2.note ? `\uFF1A${clip(p2.note)}` : ""}` };
224600
+ return { summary: `${p2.verdict === "approve" ? "\u8BC4\u5BA1\u901A\u8FC7" : "\u8BC4\u5BA1\u6253\u56DE"}${p2.note ? `\uFF1A${clip2(p2.note)}` : ""}` };
224425
224601
  case "propose_revision":
224426
- return { summary: `\u63D0\u4EA4\u7248\u672C\uFF1A${clip(p2.reason) || "\uFF08\u65E0\u8BF4\u660E\uFF09"}` };
224602
+ return { summary: `\u63D0\u4EA4\u7248\u672C\uFF1A${clip2(p2.reason) || "\uFF08\u65E0\u8BF4\u660E\uFF09"}` };
224427
224603
  case "merge":
224428
224604
  return { summary: "\u5408\u5E76\u7248\u672C\u4E3A\u5F53\u524D" };
224429
224605
  case "conclude":
224430
- return { summary: `\u6536\u5C3E\uFF08\u91CC\u7A0B\u7891\uFF09${p2.note ? `\uFF1A${clip(p2.note)}` : ""}` };
224606
+ return { summary: `\u6536\u5C3E\uFF08\u91CC\u7A0B\u7891\uFF09${p2.note ? `\uFF1A${clip2(p2.note)}` : ""}` };
224431
224607
  case "seal":
224432
- return { summary: `\u5C01\u5B58${p2.reason ? `\uFF1A${clip(p2.reason)}` : ""}${p2.note ? `\uFF1A${clip(p2.note)}` : ""}` };
224608
+ return { summary: `\u5C01\u5B58${p2.reason ? `\uFF1A${clip2(p2.reason)}` : ""}${p2.note ? `\uFF1A${clip2(p2.note)}` : ""}` };
224433
224609
  case "annotate":
224434
- return { summary: `${p2.blocks ? "\u6253\u56DE\u6279\u6CE8\uFF08\u963B\u585E\uFF09" : "\u6279\u6CE8"}\uFF1A${clip(p2.body) || "\uFF08\u7A7A\uFF09"}` };
224610
+ return { summary: `${p2.blocks ? "\u6253\u56DE\u6279\u6CE8\uFF08\u963B\u585E\uFF09" : "\u6279\u6CE8"}\uFF1A${clip2(p2.body) || "\uFF08\u7A7A\uFF09"}` };
224435
224611
  case "resolve_annotation":
224436
224612
  return { summary: "\u89E3\u9664\u6279\u6CE8" };
224437
224613
  case "spawn_artifact":
@@ -224441,9 +224617,9 @@ function summarize3(kind, payload2) {
224441
224617
  case "assign_owner":
224442
224618
  return { summary: "\u53D8\u66F4\u8282\u70B9 owner" };
224443
224619
  case "propose_intervention":
224444
- return { summary: `\u8D77\u8349\u6539\u56FE\u63D0\u6848${p2.reason ? `\uFF1A${clip(p2.reason)}` : ""}` };
224620
+ return { summary: `\u8D77\u8349\u6539\u56FE\u63D0\u6848${p2.reason ? `\uFF1A${clip2(p2.reason)}` : ""}` };
224445
224621
  case "reject_intervention":
224446
- return { summary: `\u9A73\u56DE\u6539\u56FE\u63D0\u6848${p2.reason ? `\uFF1A${clip(p2.reason)}` : ""}` };
224622
+ return { summary: `\u9A73\u56DE\u6539\u56FE\u63D0\u6848${p2.reason ? `\uFF1A${clip2(p2.reason)}` : ""}` };
224447
224623
  default:
224448
224624
  return { summary: kind };
224449
224625
  }
@@ -229487,8 +229663,8 @@ async function buildChatPreview(chatStore, sessionId, who) {
229487
229663
  const lastUser = [...msgs].reverse().find((m2) => m2.role === "user" && m2.content.trim().length > 0);
229488
229664
  const lastAsst = [...msgs].reverse().find((m2) => m2.role === "assistant" && m2.content.trim().length > 0);
229489
229665
  const lines = [];
229490
- if (lastUser) lines.push({ label: "\u4F60", text: clip2(lastUser.content) });
229491
- if (lastAsst) lines.push({ label: who, text: clip2(lastAsst.content) });
229666
+ if (lastUser) lines.push({ label: "\u4F60", text: clip3(lastUser.content) });
229667
+ if (lastAsst) lines.push({ label: who, text: clip3(lastAsst.content) });
229492
229668
  return lines.length ? { lines } : void 0;
229493
229669
  }
229494
229670
  async function buildChatInbox(chatStore, markers, me, resolveActor, excludeChildSessions) {
@@ -229522,14 +229698,14 @@ async function buildChatInbox(chatStore, markers, me, resolveActor, excludeChild
229522
229698
  }
229523
229699
  return out;
229524
229700
  }
229525
- var PREVIEW_MAX_CHARS, PREVIEW_FETCH_CAP, clip2;
229701
+ var PREVIEW_MAX_CHARS, PREVIEW_FETCH_CAP, clip3;
229526
229702
  var init_inbox_chat = __esm({
229527
229703
  "../server/src/domains/collab/inbox-chat.ts"() {
229528
229704
  "use strict";
229529
229705
  init_src();
229530
229706
  PREVIEW_MAX_CHARS = 200;
229531
229707
  PREVIEW_FETCH_CAP = 25;
229532
- clip2 = (s2) => {
229708
+ clip3 = (s2) => {
229533
229709
  const t = (s2 ?? "").trim();
229534
229710
  return t.length > PREVIEW_MAX_CHARS ? `${t.slice(0, PREVIEW_MAX_CHARS)}\u2026` : t;
229535
229711
  };
@@ -264268,7 +264444,9 @@ function buildChatExitError(info) {
264268
264444
  if (!detail && info.transcriptRef) detail = transcriptTail(info.transcriptRef);
264269
264445
  }
264270
264446
  const firstDetailLine = detail.split("\n").map((line) => line.trim()).find(Boolean) ?? "";
264271
- const summary = (info.reason ? SUMMARY_BY_REASON[info.reason] : void 0) ?? (firstDetailLine ? `\u5BF9\u8BDD\u5931\u8D25\uFF1A${firstDetailLine.slice(0, 200)}` : `\u5BF9\u8BDD\u5931\u8D25\uFF08${genericLine}\uFF09`);
264447
+ const firstErrorLine = info.errorMessage?.split("\n").map((line) => line.trim()).find(Boolean) ?? "";
264448
+ const fixed = info.reason ? SUMMARY_BY_REASON[info.reason] : void 0;
264449
+ const summary = fixed ? firstErrorLine && info.reason !== "cancelled" && info.reason !== "timeout" ? `${fixed}\uFF1A${firstErrorLine.slice(0, 200)}` : fixed : firstDetailLine ? `\u5BF9\u8BDD\u5931\u8D25\uFF1A${firstDetailLine.slice(0, 200)}` : `\u5BF9\u8BDD\u5931\u8D25\uFF08${genericLine}\uFF09`;
264272
264450
  const chatExit = {
264273
264451
  ...info.reason ? { reason: info.reason } : {},
264274
264452
  summary,
@@ -270063,6 +270241,9 @@ async function startServe(opts) {
270063
270241
  // actor→runtime→default 模型解析(内部字段;非用户 per-session 选择)。
270064
270242
  // 决策 0032 预派发校验:候选 model 不在该 runtime 的模型目录里 → 不烧会话,
270065
270243
  // 回退目录默认并留 warn(曾因 actor 存了残缺 id "claude-sonnet",CLI 秒拒、节点熔断卡死)。
270244
+ // 目录用**绑定那台节点**的(resolveRuntimeModels,与控制台下拉、会话级校验同一份):控制面本机
270245
+ // 的 isModelValid 看的是控制面自己的 CLI 配置,跨机时回落静态 GPT 目录,会把节点上配好的
270246
+ // deepseek-flash 判无效、悄悄换成 gpt-6-astra 派出去(Bug 0209)。
270066
270247
  resolveModel: async (actorId) => {
270067
270248
  const actors2 = await runActors();
270068
270249
  const binding = await actors2.service.resolveBinding()(actorId);
@@ -270073,13 +270254,14 @@ async function startServe(opts) {
270073
270254
  candidate = runtimeCfg?.model;
270074
270255
  }
270075
270256
  if (!candidate) return void 0;
270076
- const kind = binding ? traceRuntimeKind(binding.runtimeKind) : void 0;
270077
- if (kind && kind !== "custom" && !await isModelValid(kind, candidate)) {
270078
- const fallback = await defaultModelFor(kind);
270079
- console.warn(`[dispatch] ${actorId} \u914D\u7F6E\u7684\u6A21\u578B '${candidate}' \u5BF9 runtime ${kind} \u65E0\u6548\uFF0C\u56DE\u9000 ${fallback ?? "CLI \u9ED8\u8BA4"}\uFF08\u51B3\u7B56 0032\uFF09`);
270080
- return fallback;
270081
- }
270082
- return candidate;
270257
+ if (!binding || traceRuntimeKind(binding.runtimeKind) === "custom") return candidate;
270258
+ const runtimeId = `runtime:${binding.nodeId}:${binding.runtimeKind}`;
270259
+ const catalog = await resolveRuntimeModels({ nodeStore, registry: registryStore, nodeReportedModels }, runtimeId).catch(() => []);
270260
+ const checked = resolveDispatchModel(candidate, catalog);
270261
+ if (checked.replaced) {
270262
+ console.warn(`[dispatch] ${actorId} \u914D\u7F6E\u7684\u6A21\u578B '${candidate}' \u4E0D\u5728 ${runtimeId} \u7684\u5019\u9009\u91CC\uFF0C\u56DE\u9000 ${checked.model ?? "CLI \u9ED8\u8BA4"}\uFF08\u51B3\u7B56 0032\uFF09`);
270263
+ }
270264
+ return checked.model;
270083
270265
  },
270084
270266
  // ADR「agent CLI 启动参数员工级可配置化」:每次派发解析员工 actor_configs.extraArgs 下发(形态同 resolveModel)。
270085
270267
  // 只读员工配置,不叠 runtime 默认、不做「没有员工就找 runtime」回退(ADR §3.3 / §4-A)。
@@ -274822,9 +275004,9 @@ var GROUP_ORDER = [
274822
275004
  "\u5B58\u91CF\u7BA1\u7406"
274823
275005
  ];
274824
275006
  function indexSummary(description) {
274825
- const firstLine2 = description.split("\n")[0] ?? "";
274826
- const dot = firstLine2.indexOf("\u3002");
274827
- const head = dot >= 0 ? firstLine2.slice(0, dot + 1) : firstLine2;
275007
+ const firstLine3 = description.split("\n")[0] ?? "";
275008
+ const dot = firstLine3.indexOf("\u3002");
275009
+ const head = dot >= 0 ? firstLine3.slice(0, dot + 1) : firstLine3;
274828
275010
  return head.replace(/\*\*/g, "").trim();
274829
275011
  }
274830
275012
  function buildCommandIndex() {
@@ -278701,7 +278883,7 @@ function shimScript() {
278701
278883
  }
278702
278884
 
278703
278885
  // src/index.ts
278704
- var PKG_VERSION = true ? "2.2.43" : "dev";
278886
+ var PKG_VERSION = true ? "2.2.45" : "dev";
278705
278887
  var LOCAL_BIN = localBin();
278706
278888
  var NPM_PREFIX = npmPrefix();
278707
278889
  var INSTANCE = DEFAULT_INSTANCE;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test_v2",
3
- "version": "2.2.43",
3
+ "version": "2.2.45",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"
@@ -26,6 +26,6 @@
26
26
  "node": ">=20"
27
27
  },
28
28
  "oasisRelease": {
29
- "sourceHead": "34968cfc5b0889a75157d9e05acecc3540285932"
29
+ "sourceHead": "c27918782543065f65990ee2acc32b3da89bba06"
30
30
  }
31
31
  }