oasis_test 0.1.110 → 0.1.111

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 +159 -8
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -171332,6 +171332,79 @@ var init_orphan_sweep = __esm({
171332
171332
  }
171333
171333
  });
171334
171334
 
171335
+ // ../server/src/zero-output-breaker.ts
171336
+ async function scanZeroOutputBreaker(deps) {
171337
+ const tripped = [];
171338
+ const skipped = [];
171339
+ const countEnabled = deps.threshold > 0;
171340
+ const costEnabled = (deps.costThresholdMicros ?? 0) > 0;
171341
+ if (!countEnabled && !costEnabled) return { tripped, skipped };
171342
+ const sinceIso = new Date(deps.now - deps.windowMs).toISOString();
171343
+ const runs = await deps.listRecentZeroOutputRuns(sinceIso);
171344
+ const buckets = /* @__PURE__ */ new Map();
171345
+ for (const r of runs) {
171346
+ if (r.artifactId === null) continue;
171347
+ if (!deps.actions.has(r.action ?? "")) continue;
171348
+ const startedMs = Date.parse(r.startedAt);
171349
+ if (!Number.isFinite(startedMs)) continue;
171350
+ const b2 = buckets.get(r.artifactId);
171351
+ if (!b2) {
171352
+ buckets.set(r.artifactId, {
171353
+ count: 1,
171354
+ costUsdMicros: r.costUsdMicros ?? 0,
171355
+ latestRunId: r.id,
171356
+ latestStartedMs: startedMs
171357
+ });
171358
+ } else {
171359
+ b2.count += 1;
171360
+ b2.costUsdMicros += r.costUsdMicros ?? 0;
171361
+ if (startedMs >= b2.latestStartedMs) {
171362
+ b2.latestStartedMs = startedMs;
171363
+ b2.latestRunId = r.id;
171364
+ }
171365
+ }
171366
+ }
171367
+ for (const [artifactId, b2] of buckets) {
171368
+ const hitCount = countEnabled && b2.count >= deps.threshold;
171369
+ const hitCost = costEnabled && b2.costUsdMicros >= (deps.costThresholdMicros ?? 0);
171370
+ if (!hitCount && !hitCost) continue;
171371
+ if (deps.isHeld(artifactId) || deps.hasOpenEscalation?.(artifactId)) {
171372
+ skipped.push(artifactId);
171373
+ continue;
171374
+ }
171375
+ const closingRemark = await deps.closingRemarkOf(b2.latestRunId).catch(() => null);
171376
+ await deps.trip({
171377
+ artifactId,
171378
+ count: b2.count,
171379
+ costUsdMicros: b2.costUsdMicros,
171380
+ windowMs: deps.windowMs,
171381
+ latestRunId: b2.latestRunId,
171382
+ closingRemark
171383
+ });
171384
+ tripped.push(artifactId);
171385
+ deps.log?.(
171386
+ `[zero-output-breaker] ${artifactId}\uFF1A\u6700\u8FD1 ${Math.round(deps.windowMs / 6e4)} \u5206\u949F\u5185\u7D2F\u8BA1 ${b2.count} \u6B21\u96F6\u4EA7\u51FA\uFF08\u7EA6 $${(b2.costUsdMicros / 1e6).toFixed(1)}\uFF09\u2192 hold + \u6295\u9012\u6536\u4EF6\u7BB1`
171387
+ );
171388
+ }
171389
+ return { tripped, skipped };
171390
+ }
171391
+ function formatZeroOutputNotice(t) {
171392
+ const usd2 = (t.costUsdMicros / 1e6).toFixed(1);
171393
+ const mins = Math.round(t.windowMs / 6e4);
171394
+ const remark = t.closingRemark && t.closingRemark.trim() ? `
171395
+
171396
+ \u6700\u8FD1\u4E00\u6B21\u8FD0\u884C\u7684\u6536\u5C3E\u53D1\u8A00\uFF08\u5F80\u5F80\u76F4\u63A5\u5199\u7740\u5361\u5728\u54EA\uFF09\uFF1A
171397
+ ${t.closingRemark.trim()}` : "";
171398
+ return `\u8FD9\u4E2A\u4EA7\u7269\u5728\u6700\u8FD1 ${mins} \u5206\u949F\u5185\u88AB\u53CD\u590D\u53EB\u9192\u3001\u7D2F\u8BA1\u6709 ${t.count} \u6B21\u8FD0\u884C**\u4EC0\u4E48\u90FD\u6CA1\u4EA4\u51FA\u6765**\uFF08\u8FD9\u4E9B\u7A7A\u8DD1\u7D2F\u8BA1\u82B1\u8D39\u7EA6 $${usd2}\uFF09\uFF0C\u5DF2\u81EA\u52A8\u6682\u505C\u6D3E\u53D1\u4EE5\u6B62\u635F\u3002
171399
+
171400
+ \u8FD9\u4E0D\u662F\u5728\u5224\u67D0\u4E00\u6B21\u8FD0\u884C\u5931\u8D25\u2014\u2014\u662F\u540C\u4E00\u4E2A\u4EA7\u7269\u5728\u8FD9\u6BB5\u65F6\u95F4\u91CC\u53CD\u590D\u96F6\u4EA7\u51FA\u3002\u65E0\u8BBA\u6BCF\u4E00\u6B21\u9000\u51FA\u591A\u4E48\u300C\u6B63\u5E38\u300D\uFF0C\u53CD\u590D\u5230\u8FD9\u4E2A\u6B21\u6570\u901A\u5E38\u610F\u5473\u7740\u5B83\u5361\u5728\u4E00\u4E2A\u53CD\u590D\u91CD\u8BD5\u4E5F\u8FC7\u4E0D\u53BB\u7684\u574E\u4E0A\uFF08\u7F3A\u51ED\u636E\u3001\u4E0A\u6E38\u670D\u52A1\u8FDE\u4E0D\u4E0A\u3001\u6216\u649E\u4E0A\u4E86\u522B\u7684\u6B7B\u5FAA\u73AF\uFF09\u3002\u8BF7\u770B\u4E00\u773C\u6839\u56E0\uFF1B\u5904\u7406\u5B8C\u7528 \`oasis release\` \u6062\u590D\u6D3E\u53D1\u3002` + remark;
171401
+ }
171402
+ var init_zero_output_breaker = __esm({
171403
+ "../server/src/zero-output-breaker.ts"() {
171404
+ "use strict";
171405
+ }
171406
+ });
171407
+
171335
171408
  // ../server/src/session-exit-outcome.ts
171336
171409
  function isHealthySessionExit(info) {
171337
171410
  return info.code === 0 && (info.reason === void 0 || info.reason === "clean");
@@ -188101,6 +188174,7 @@ var init_src9 = __esm({
188101
188174
  init_roles_seed();
188102
188175
  init_liveness();
188103
188176
  init_orphan_sweep();
188177
+ init_zero_output_breaker();
188104
188178
  init_dispatch_exit_reconcile();
188105
188179
  init_session_exit_outcome();
188106
188180
  init_api_activity();
@@ -197829,6 +197903,7 @@ ${st.detail}
197829
197903
  let coordTimer;
197830
197904
  let livenessTimer;
197831
197905
  let orphanSweepTimer;
197906
+ let zeroOutputBreakerTimer;
197832
197907
  if (opts.dispatch) {
197833
197908
  const coordinator = new CoordinatorWorker({
197834
197909
  kernel,
@@ -198018,6 +198093,80 @@ ${st.detail}
198018
198093
  }).catch((err) => console.error(`[orphan-sweep] tick \u5931\u8D25: ${String(err)}`));
198019
198094
  }, orphanIntervalMs);
198020
198095
  }
198096
+ const zbFlag = (process.env["OASIS_ZERO_OUTPUT_BREAKER"] ?? "").trim().toLowerCase();
198097
+ const zbDisabledByEnv = ["0", "false", "off"].includes(zbFlag);
198098
+ const envInt = (name) => {
198099
+ const raw = process.env[name];
198100
+ if (raw === void 0 || raw.trim() === "") return void 0;
198101
+ const n = Number(raw.trim());
198102
+ return Number.isFinite(n) && n >= 0 ? n : void 0;
198103
+ };
198104
+ const zbEnabled = opts.zeroOutputBreaker?.enabled ?? !zbDisabledByEnv;
198105
+ const zbIntervalMs = opts.zeroOutputBreaker?.intervalMs ?? 3e4;
198106
+ const zbWindowMs = opts.zeroOutputBreaker?.windowMs ?? (envInt("OASIS_ZERO_OUTPUT_BREAKER_WINDOW_MIN") ?? 30) * 6e4;
198107
+ const zbThreshold = opts.zeroOutputBreaker?.threshold ?? envInt("OASIS_ZERO_OUTPUT_BREAKER_N") ?? 5;
198108
+ const zbCostThresholdMicros = opts.zeroOutputBreaker?.costThresholdMicros ?? (envInt("OASIS_ZERO_OUTPUT_BREAKER_COST_USD") ?? 0) * 1e6;
198109
+ if (zbEnabled && zbIntervalMs > 0 && (zbThreshold > 0 || zbCostThresholdMicros > 0)) {
198110
+ const zbActions = /* @__PURE__ */ new Set(["produce", "review"]);
198111
+ const listRecentZeroOutputRuns = async (sinceIso) => {
198112
+ const page = await traceStore.listRuns({ status: "no-output", from: sinceIso, limit: 1e3 });
198113
+ if (page.nextCursor) console.warn("[zero-output-breaker] no-output run \u8D85 1000 \u6761\u672A\u7FFB\u9875\uFF0C\u672C\u62CD\u53EA\u626B\u9996\u9875");
198114
+ return page.items.map((r) => ({
198115
+ id: r.id,
198116
+ artifactId: r.artifactId,
198117
+ action: r.action,
198118
+ startedAt: r.startedAt,
198119
+ costUsdMicros: r.usage?.costUsdMicros ?? null
198120
+ }));
198121
+ };
198122
+ const latestClosingRemark = async (runId) => {
198123
+ try {
198124
+ let afterSeq = 0;
198125
+ let last = null;
198126
+ let scanned = 0;
198127
+ for (; ; ) {
198128
+ const rows = await traceStore.listEvents(runId, { afterSeq, limit: 500 });
198129
+ if (rows.length === 0) break;
198130
+ for (const e of rows) {
198131
+ if (e.stream !== "model") continue;
198132
+ const payload = e.payload && typeof e.payload === "object" && !Array.isArray(e.payload) ? e.payload : {};
198133
+ const raw = payload["raw"] && typeof payload["raw"] === "object" && !Array.isArray(payload["raw"]) ? payload["raw"] : {};
198134
+ const kind = payload["kind"] ?? raw["kind"];
198135
+ if (kind === "thought") continue;
198136
+ const text = typeof raw["text"] === "string" ? raw["text"] : typeof e.message === "string" ? e.message : null;
198137
+ if (text && text.trim()) last = text;
198138
+ }
198139
+ afterSeq = rows[rows.length - 1].seq;
198140
+ scanned += rows.length;
198141
+ if (rows.length < 500 || scanned >= 5e3) break;
198142
+ }
198143
+ return last ? last.trim().slice(0, 500) : null;
198144
+ } catch {
198145
+ return null;
198146
+ }
198147
+ };
198148
+ zeroOutputBreakerTimer = setInterval(() => {
198149
+ void scanZeroOutputBreaker({
198150
+ now: Date.now(),
198151
+ windowMs: zbWindowMs,
198152
+ threshold: zbThreshold,
198153
+ costThresholdMicros: zbCostThresholdMicros,
198154
+ actions: zbActions,
198155
+ listRecentZeroOutputRuns,
198156
+ isHeld: (artifactId) => isHeld(kernel.model, artifactId),
198157
+ hasOpenEscalation: (artifactId) => unresolvedEscalationsOf(kernel.model, artifactId).length > 0,
198158
+ closingRemarkOf: latestClosingRemark,
198159
+ // 复用 SLA 同一止损出口:escalate(进收件箱)+ hold(source:"sla",挡派发不锁内容)+ 去重。
198160
+ trip: (t) => escalateHold(t.artifactId, formatZeroOutputNotice(t), "\u96F6\u4EA7\u51FA\u4FDD\u9669\u4E1D"),
198161
+ log: (m2) => console.log(m2)
198162
+ }).catch((err) => console.error(`[zero-output-breaker] tick \u5931\u8D25: ${String(err)}`));
198163
+ }, zbIntervalMs);
198164
+ console.log(
198165
+ `[serve] \u96F6\u4EA7\u51FA\u4FDD\u9669\u4E1D\uFF1A\u7A97\u53E3 ${Math.round(zbWindowMs / 6e4)}min\u3001N=${zbThreshold}${zbCostThresholdMicros > 0 ? `\u3001\u82B1\u8D39\u9608\u503C $${(zbCostThresholdMicros / 1e6).toFixed(0)}` : ""}\u3001\u5468\u671F ${Math.round(zbIntervalMs / 1e3)}s`
198166
+ );
198167
+ } else {
198168
+ console.log("[serve] \u96F6\u4EA7\u51FA\u4FDD\u9669\u4E1D\uFF1A\u5DF2\u5173\u95ED");
198169
+ }
198021
198170
  }
198022
198171
  const automationScheduler = new AutomationScheduler({
198023
198172
  store: automationStore,
@@ -198050,6 +198199,7 @@ ${st.detail}
198050
198199
  if (coordTimer) clearInterval(coordTimer);
198051
198200
  if (livenessTimer) clearInterval(livenessTimer);
198052
198201
  if (orphanSweepTimer) clearInterval(orphanSweepTimer);
198202
+ if (zeroOutputBreakerTimer) clearInterval(zeroOutputBreakerTimer);
198053
198203
  clearInterval(automationTimer);
198054
198204
  if (boardWatchTimer) clearInterval(boardWatchTimer);
198055
198205
  clearInterval(serverHeartbeatTimer);
@@ -198141,13 +198291,14 @@ var KNOWN2 = [
198141
198291
  { adapter: "antigravity", binary: "agy" }
198142
198292
  ];
198143
198293
  var NATIVE_APPEND_RUNTIMES = /* @__PURE__ */ new Set(["hermes", "gemini", "kimi", "kiro", "reasonix"]);
198144
- function onPath(binary) {
198294
+ function resolveOnPath(binary) {
198145
198295
  try {
198146
198296
  const cmd = process.platform === "win32" ? "where" : "which";
198147
- (0, import_node_child_process15.execFileSync)(cmd, [binary], { stdio: "ignore" });
198148
- return true;
198297
+ const out = (0, import_node_child_process15.execFileSync)(cmd, [binary], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
198298
+ const first = out.split("\n")[0]?.trim();
198299
+ return first || binary;
198149
198300
  } catch {
198150
- return false;
198301
+ return void 0;
198151
198302
  }
198152
198303
  }
198153
198304
  function versionOf(binary) {
@@ -198162,11 +198313,11 @@ function versionOf(binary) {
198162
198313
  }
198163
198314
  }
198164
198315
  function detectRuntimes() {
198165
- return KNOWN2.filter((e) => onPath(e.binary)).map((e) => {
198166
- const version2 = versionOf(e.binary);
198316
+ return KNOWN2.map((e) => ({ ...e, resolved: resolveOnPath(e.binary) })).filter((e) => e.resolved !== void 0).map((e) => {
198317
+ const version2 = versionOf(e.resolved);
198167
198318
  return {
198168
198319
  kind: e.adapter,
198169
- binary: e.binary,
198320
+ binary: e.resolved,
198170
198321
  ...version2 ? { version: version2 } : {},
198171
198322
  ...NATIVE_APPEND_RUNTIMES.has(e.adapter) ? { supportsAppendInput: true } : {}
198172
198323
  };
@@ -203398,7 +203549,7 @@ function syncRuntimeAssets(candidateRoots, binDir) {
203398
203549
  }
203399
203550
 
203400
203551
  // src/index.ts
203401
- var PKG_VERSION = true ? "0.1.110" : "dev";
203552
+ var PKG_VERSION = true ? "0.1.111" : "dev";
203402
203553
  var OASIS_DIR = path28.join(os11.homedir(), ".oasis");
203403
203554
  var CONFIG_FILE = path28.join(OASIS_DIR, "node-config.json");
203404
203555
  var PID_FILE = path28.join(OASIS_DIR, "node.pid");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test",
3
- "version": "0.1.110",
3
+ "version": "0.1.111",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"