orion-super-agent-dev 0.1.22 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/out/main.js CHANGED
@@ -29178,6 +29178,8 @@ var require_duetEntry = __commonJS({
29178
29178
  }();
29179
29179
  Object.defineProperty(exports2, "__esModule", { value: true });
29180
29180
  exports2.DUET_HANDOFF_BRIEF_MAX_CHARS = exports2.DUET_HANDOFF_CAPABILITY = exports2.DUET_HANDOFF_TOOL = exports2.DUET_ENTRY_OPTIONS = exports2.DUET_ENTRY_INFO = exports2.DUET_ENTRY_KEY = exports2.DUET_ENTRY_DEFAULT = exports2.DUET_ENTRIES = void 0;
29181
+ exports2.isModelRoutedEntry = isModelRoutedEntry;
29182
+ exports2.effectiveDuetEntry = effectiveDuetEntry;
29181
29183
  exports2.duetEntryLabel = duetEntryLabel2;
29182
29184
  exports2.normalizeDuetEntry = normalizeDuetEntry2;
29183
29185
  exports2.duetHandoffBrief = duetHandoffBrief2;
@@ -29193,7 +29195,10 @@ var require_duetEntry = __commonJS({
29193
29195
  var path14 = __importStar(__require("node:path"));
29194
29196
  var atomicWrite_js_1 = require_atomicWrite();
29195
29197
  var settingsPaths_js_1 = require_settingsPaths();
29196
- exports2.DUET_ENTRIES = ["planner", "router"];
29198
+ exports2.DUET_ENTRIES = ["planner", "router", "executor"];
29199
+ function isModelRoutedEntry(entry) {
29200
+ return entry === "router" || entry === "executor";
29201
+ }
29197
29202
  exports2.DUET_ENTRY_DEFAULT = "planner";
29198
29203
  exports2.DUET_ENTRY_KEY = "duetEntry";
29199
29204
  exports2.DUET_ENTRY_INFO = {
@@ -29206,14 +29211,27 @@ var require_duetEntry = __commonJS({
29206
29211
  {
29207
29212
  value: "planner",
29208
29213
  label: "Planner decides",
29209
- description: "Every request goes to the planning model first; it hands simple requests to the executor with a brief and writes a plan for the rest. Recommended."
29214
+ // A few words each — these render as one-line row descriptions in the pickers.
29215
+ description: "Plans first, or hands off. Recommended."
29210
29216
  },
29211
29217
  {
29212
29218
  value: "router",
29213
29219
  label: "Router decides",
29214
- description: "Rules (plus local routing models, when set up) choose plan or execute; the planner runs only when routed to. No planner call on routine requests."
29220
+ description: "Local model routes. No planner call."
29221
+ },
29222
+ {
29223
+ value: "executor",
29224
+ label: "Executor decides",
29225
+ description: "Your local executor routes. No planner call, no download."
29215
29226
  }
29216
29227
  ];
29228
+ function effectiveDuetEntry(setting, routerState, executorState) {
29229
+ if (setting === "router" && routerState !== "ready")
29230
+ return { entry: "planner", downgraded: true };
29231
+ if (setting === "executor" && executorState !== "ready")
29232
+ return { entry: "planner", downgraded: true };
29233
+ return { entry: setting, downgraded: false };
29234
+ }
29217
29235
  function duetEntryLabel2(entry) {
29218
29236
  return exports2.DUET_ENTRY_OPTIONS.find((option) => option.value === entry)?.label ?? entry;
29219
29237
  }
@@ -29221,7 +29239,7 @@ var require_duetEntry = __commonJS({
29221
29239
  if (typeof raw !== "string")
29222
29240
  return null;
29223
29241
  const value = raw.trim();
29224
- return value === "planner" || value === "router" ? value : null;
29242
+ return value === "planner" || value === "router" || value === "executor" ? value : null;
29225
29243
  }
29226
29244
  exports2.DUET_HANDOFF_TOOL = "hand_off";
29227
29245
  exports2.DUET_HANDOFF_CAPABILITY = "duet_handoff";
@@ -29344,6 +29362,69 @@ var require_duetEntry = __commonJS({
29344
29362
  }
29345
29363
  });
29346
29364
 
29365
+ // ../packages/orion-client-core/dist/duetExecutorGateStatus.js
29366
+ var require_duetExecutorGateStatus = __commonJS({
29367
+ "../packages/orion-client-core/dist/duetExecutorGateStatus.js"(exports2) {
29368
+ "use strict";
29369
+ Object.defineProperty(exports2, "__esModule", { value: true });
29370
+ exports2.executorGateStatusLine = executorGateStatusLine2;
29371
+ exports2.executorGateDowngradeNote = executorGateDowngradeNote;
29372
+ exports2.executorGateOptionAvailability = executorGateOptionAvailability;
29373
+ function unavailableWhy(reason, problem) {
29374
+ switch (reason) {
29375
+ case "not_resolved":
29376
+ return "its endpoint is not configured";
29377
+ case "not_loopback":
29378
+ return "it is not on this machine";
29379
+ case "unreachable":
29380
+ return "it is not answering";
29381
+ case "no_completions":
29382
+ return "it has no /v1/completions route";
29383
+ case "thinking":
29384
+ return "it answers with thinking on (load it with thinking off)";
29385
+ case "unparseable":
29386
+ return "it did not answer E or P";
29387
+ case "error":
29388
+ return `the gate call failed (${problem})`;
29389
+ }
29390
+ }
29391
+ function executorGateStatusLine2(status) {
29392
+ switch (status.state) {
29393
+ case "ready":
29394
+ return `Executor gate: ${status.target.model} on '${status.target.name}' \xB7 ${status.mode} \xB7 threshold ${status.threshold} \xB7 ${status.calibration.passed}/${status.calibration.total} scenarios \xB7 ready`;
29395
+ case "miscalibrated":
29396
+ return `Executor gate: ${status.target.model} on '${status.target.name}' misrouted ${status.calibration.failed.length} of ${status.calibration.total} probe scenarios (${status.mode}, threshold ${status.threshold}) \u2014 tune executorGate.threshold on that endpoint.`;
29397
+ case "platform":
29398
+ return "Executor gate: needs a local executor \u2014 the Duet executor is a platform model.";
29399
+ case "unavailable":
29400
+ return `Executor gate: not available \u2014 ${unavailableWhy(status.reason, status.problem)}.`;
29401
+ }
29402
+ }
29403
+ function executorGateDowngradeNote(status) {
29404
+ const why = status.state === "platform" ? "the Duet executor is a platform model" : status.state === "unavailable" ? unavailableWhy(status.reason, status.problem) : "it could not run";
29405
+ return `Executor decides needs a local executor that answers a one-token routing question and ${why} \u2014 this turn ran through the planner instead.`;
29406
+ }
29407
+ function executorGateOptionAvailability(status) {
29408
+ if (status === null || status.state === "ready")
29409
+ return { disabled: false, note: null };
29410
+ switch (status.state) {
29411
+ case "platform":
29412
+ return { disabled: true, note: "Needs a local executor (the Duet executor is a platform model)." };
29413
+ case "miscalibrated":
29414
+ return {
29415
+ disabled: true,
29416
+ note: `The executor's routing gate failed calibration (${status.calibration.passed}/${status.calibration.total}) \u2014 see the Duet card.`
29417
+ };
29418
+ case "unavailable":
29419
+ return {
29420
+ disabled: true,
29421
+ note: `Needs a local executor that answers /v1/completions (${unavailableWhy(status.reason, status.problem)}).`
29422
+ };
29423
+ }
29424
+ }
29425
+ }
29426
+ });
29427
+
29347
29428
  // ../packages/orion-client-core/dist/duetRouterModel.js
29348
29429
  var require_duetRouterModel = __commonJS({
29349
29430
  "../packages/orion-client-core/dist/duetRouterModel.js"(exports2) {
@@ -29399,7 +29480,6 @@ var require_duetRouterModel = __commonJS({
29399
29480
  exports2.classifyWithHeads = classifyWithHeads;
29400
29481
  exports2.createDuetRouter = createDuetRouter;
29401
29482
  exports2.createTransformersDuetRouterEncoder = createTransformersDuetRouterEncoder;
29402
- exports2.effectiveDuetEntry = effectiveDuetEntry;
29403
29483
  exports2.duetRouterDisplayName = duetRouterDisplayName2;
29404
29484
  exports2.duetRouterStatusLine = duetRouterStatusLine2;
29405
29485
  exports2.duetRouterDowngradeNote = duetRouterDowngradeNote;
@@ -29411,6 +29491,8 @@ var require_duetRouterModel = __commonJS({
29411
29491
  var fs15 = __importStar(__require("node:fs/promises"));
29412
29492
  var os9 = __importStar(__require("node:os"));
29413
29493
  var path14 = __importStar(__require("node:path"));
29494
+ var duetEntry_js_1 = require_duetEntry();
29495
+ var duetExecutorGateStatus_js_1 = require_duetExecutorGateStatus();
29414
29496
  exports2.DUET_ROUTER_WIRE_KEY = "duet_router";
29415
29497
  exports2.DUET_ROUTER_BUNDLE_FORMAT = "orion-router-bundle.v1";
29416
29498
  exports2.DUET_ROUTER_MODEL_ID = "orion/orion-pe-router-1.0";
@@ -29424,13 +29506,16 @@ var require_duetRouterModel = __commonJS({
29424
29506
  ];
29425
29507
  function duetRouterWireForSegment(verdict) {
29426
29508
  return {
29509
+ source: verdict.source,
29427
29510
  model: verdict.model,
29428
29511
  version: verdict.version,
29429
29512
  verdict: verdict.verdict,
29430
29513
  p_plan: round6(verdict.pPlan),
29431
29514
  asks_for_plan: verdict.asksForPlan,
29432
29515
  high_risk: verdict.highRisk,
29433
- reason: verdict.reason
29516
+ reason: verdict.reason,
29517
+ ...verdict.margin !== void 0 ? { margin: round6(verdict.margin) } : {},
29518
+ ...verdict.mode !== void 0 ? { mode: verdict.mode } : {}
29434
29519
  };
29435
29520
  }
29436
29521
  function orionModelsDir(homeDir = os9.homedir()) {
@@ -29661,6 +29746,7 @@ var require_duetRouterModel = __commonJS({
29661
29746
  if (!vector)
29662
29747
  throw new Error("router encoder returned no vector");
29663
29748
  return {
29749
+ source: "orion_router",
29664
29750
  ...classifyWithHeads(vector, bundle),
29665
29751
  model: bundle.name,
29666
29752
  version: bundle.version,
@@ -29682,6 +29768,7 @@ var require_duetRouterModel = __commonJS({
29682
29768
  loading = (async () => {
29683
29769
  mod2.env.localModelPath = modelsDir;
29684
29770
  mod2.env.allowLocalModels = true;
29771
+ mod2.env.allowRemoteModels = false;
29685
29772
  const tokenizer = await mod2.AutoTokenizer.from_pretrained(modelId);
29686
29773
  let model;
29687
29774
  if (opts.dtype) {
@@ -29729,11 +29816,6 @@ var require_duetRouterModel = __commonJS({
29729
29816
  }
29730
29817
  };
29731
29818
  }
29732
- function effectiveDuetEntry(setting, routerState) {
29733
- if (setting === "router" && routerState !== "ready")
29734
- return { entry: "planner", downgraded: true };
29735
- return { entry: setting, downgraded: false };
29736
- }
29737
29819
  function duetRouterDisplayName2(name2, version) {
29738
29820
  const trimmed = name2.trim();
29739
29821
  const v2 = version.trim();
@@ -29755,7 +29837,9 @@ var require_duetRouterModel = __commonJS({
29755
29837
  const why = status.state === "missing" ? "it is not installed" : status.state === "invalid" ? `it is unusable (${status.problem})` : `it failed to load${"problem" in status && status.problem ? ` (${status.problem})` : ""}`;
29756
29838
  return `Router decides needs the Orion router model and ${why} \u2014 this turn ran through the planner instead.`;
29757
29839
  }
29758
- function duetEntryOptionAvailability2(entry, status) {
29840
+ function duetEntryOptionAvailability2(entry, status, executorStatus = null) {
29841
+ if (entry === "executor")
29842
+ return (0, duetExecutorGateStatus_js_1.executorGateOptionAvailability)(executorStatus);
29759
29843
  if (entry !== "router" || status === null || status.state === "ready")
29760
29844
  return { disabled: false, note: null };
29761
29845
  return {
@@ -29795,6 +29879,7 @@ var require_duetRouterModel = __commonJS({
29795
29879
  let router = null;
29796
29880
  let building = null;
29797
29881
  let noted = false;
29882
+ let executorNoted = false;
29798
29883
  const status = async (o = {}) => {
29799
29884
  const now2 = Date.now();
29800
29885
  if (!o.refresh && cached !== null && now2 - cached.at < exports2.DUET_ROUTER_STATUS_TTL_MS)
@@ -29806,11 +29891,18 @@ var require_duetRouterModel = __commonJS({
29806
29891
  const downgrade = (why) => {
29807
29892
  const note = noted ? null : duetRouterDowngradeNote(why);
29808
29893
  noted = true;
29809
- return { ...effectiveDuetEntry("router", why.state), verdict: null, note };
29894
+ return { ...(0, duetEntry_js_1.effectiveDuetEntry)("router", why.state), verdict: null, note };
29810
29895
  };
29811
29896
  return {
29812
29897
  status,
29813
- async prepareTurn(setting, text) {
29898
+ async prepareTurn(setting, text, ctx = {}) {
29899
+ if (setting === "executor") {
29900
+ if (opts.executorGate !== void 0)
29901
+ return opts.executorGate.prepareTurn(text, ctx);
29902
+ const note = executorNoted ? null : (0, duetExecutorGateStatus_js_1.executorGateDowngradeNote)({ state: "unavailable", reason: "error", problem: "this host has no executor gate" });
29903
+ executorNoted = true;
29904
+ return { ...(0, duetEntry_js_1.effectiveDuetEntry)("executor", void 0, "unavailable"), verdict: null, note };
29905
+ }
29814
29906
  if (setting !== "router")
29815
29907
  return { entry: setting, verdict: null, note: null };
29816
29908
  if (text.trim() === "")
@@ -29844,6 +29936,8 @@ var require_duetRouterModel = __commonJS({
29844
29936
  invalidate() {
29845
29937
  cached = null;
29846
29938
  noted = false;
29939
+ executorNoted = false;
29940
+ opts.executorGate?.invalidate();
29847
29941
  const live = router;
29848
29942
  router = null;
29849
29943
  building = null;
@@ -30162,6 +30256,7 @@ var require_duetPlan = __commonJS({
30162
30256
  exports2.duetReplanFollowupPrompt = duetReplanFollowupPrompt2;
30163
30257
  exports2.recordDuetTurnOutcome = recordDuetTurnOutcome;
30164
30258
  exports2.foldDuetTurnEnd = foldDuetTurnEnd2;
30259
+ var duetEntry_js_1 = require_duetEntry();
30165
30260
  exports2.DUET_PLAN_MAX_LEN = 65536;
30166
30261
  exports2.DUET_PLAN_MAX_VERSION = 1e4;
30167
30262
  exports2.DUET_PLAN_GRANTS = ["default", "workspace_write"];
@@ -30304,7 +30399,7 @@ var require_duetPlan = __commonJS({
30304
30399
  return false;
30305
30400
  const noPlan = duetPlanWireForSegment(record) === void 0;
30306
30401
  if (noPlan) {
30307
- if (entry !== "router")
30402
+ if (!(0, duetEntry_js_1.isModelRoutedEntry)(entry))
30308
30403
  return false;
30309
30404
  if (highRiskRequest(text))
30310
30405
  return false;
@@ -30318,7 +30413,7 @@ var require_duetPlan = __commonJS({
30318
30413
  return false;
30319
30414
  if (record.userNegativeFeedback)
30320
30415
  return false;
30321
- if (entry !== "router")
30416
+ if (!(0, duetEntry_js_1.isModelRoutedEntry)(entry))
30322
30417
  return continuationRequest(text);
30323
30418
  return verdict ? verdict.verdict === "execute" : true;
30324
30419
  }
@@ -35267,11 +35362,12 @@ var require_customProviders = __commonJS({
35267
35362
  };
35268
35363
  }();
35269
35364
  Object.defineProperty(exports2, "__esModule", { value: true });
35270
- exports2.EXECUTOR_LIVENESS_TIMEOUT_MS = exports2.EXECUTOR_LIVENESS_TTL_MS = exports2.PROBE_TIMEOUT_MS = exports2.ROUTING_MODELS_KEY = exports2.MAX_CONTEXT_WINDOW = exports2.MIN_CONTEXT_WINDOW = void 0;
35365
+ exports2.EXECUTOR_LIVENESS_TIMEOUT_MS = exports2.EXECUTOR_LIVENESS_TTL_MS = exports2.PROBE_TIMEOUT_MS = exports2.EXECUTOR_GATE_THRESHOLD_BOUND = exports2.EXECUTOR_GATE_DEFAULT_THRESHOLD = exports2.EXECUTOR_GATE_KEY = exports2.ROUTING_MODELS_KEY = exports2.MAX_CONTEXT_WINDOW = exports2.MIN_CONTEXT_WINDOW = void 0;
35271
35366
  exports2.customProviderSettingsPath = customProviderSettingsPath;
35272
35367
  exports2.clampContextWindow = clampContextWindow;
35273
35368
  exports2.normalizeModelConfig = normalizeModelConfig;
35274
35369
  exports2.normalizeRoutingModels = normalizeRoutingModels;
35370
+ exports2.normalizeExecutorGate = normalizeExecutorGate;
35275
35371
  exports2.loadCustomProviders = loadCustomProviders3;
35276
35372
  exports2.getCustomProvider = getCustomProvider2;
35277
35373
  exports2.saveCustomProvider = saveCustomProvider3;
@@ -35301,6 +35397,9 @@ var require_customProviders = __commonJS({
35301
35397
  exports2.MIN_CONTEXT_WINDOW = 1024;
35302
35398
  exports2.MAX_CONTEXT_WINDOW = 2e6;
35303
35399
  exports2.ROUTING_MODELS_KEY = "routingModels";
35400
+ exports2.EXECUTOR_GATE_KEY = "executorGate";
35401
+ exports2.EXECUTOR_GATE_DEFAULT_THRESHOLD = 0;
35402
+ exports2.EXECUTOR_GATE_THRESHOLD_BOUND = 20;
35304
35403
  var CUSTOM_REF_PREFIX = "custom:";
35305
35404
  var FILE_TIERS = ["user", "project", "local"];
35306
35405
  function customProviderSettingsPath(tier, opts = {}) {
@@ -35370,6 +35469,16 @@ var require_customProviders = __commonJS({
35370
35469
  }
35371
35470
  return Object.keys(out2).length > 0 ? out2 : void 0;
35372
35471
  }
35472
+ function normalizeExecutorGate(raw) {
35473
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw))
35474
+ return void 0;
35475
+ const threshold = raw.threshold;
35476
+ if (typeof threshold !== "number" || !Number.isFinite(threshold))
35477
+ return void 0;
35478
+ return {
35479
+ threshold: Math.max(-exports2.EXECUTOR_GATE_THRESHOLD_BOUND, Math.min(exports2.EXECUTOR_GATE_THRESHOLD_BOUND, threshold))
35480
+ };
35481
+ }
35373
35482
  function toEntry(name2, raw) {
35374
35483
  if (typeof raw !== "object" || raw === null || Array.isArray(raw))
35375
35484
  return null;
@@ -35395,6 +35504,9 @@ var require_customProviders = __commonJS({
35395
35504
  const routingModels = normalizeRoutingModels(value[exports2.ROUTING_MODELS_KEY]);
35396
35505
  if (routingModels !== void 0)
35397
35506
  entry.routingModels = routingModels;
35507
+ const executorGate = normalizeExecutorGate(value[exports2.EXECUTOR_GATE_KEY]);
35508
+ if (executorGate !== void 0)
35509
+ entry.executorGate = executorGate;
35398
35510
  return entry;
35399
35511
  }
35400
35512
  async function readTier(tier, opts) {
@@ -35665,7 +35777,8 @@ var require_customProviders = __commonJS({
35665
35777
  // keyless is valid — local servers ignore auth
35666
35778
  wire: entry.wire,
35667
35779
  ...entry.modelConfig ? { modelConfig: entry.modelConfig } : {},
35668
- ...entry.routingModels ? { routingModels: entry.routingModels } : {}
35780
+ ...entry.routingModels ? { routingModels: entry.routingModels } : {},
35781
+ ...entry.executorGate ? { executorGate: entry.executorGate } : {}
35669
35782
  };
35670
35783
  routingByRef.set(provider, routing);
35671
35784
  while (routingByRef.size > ROUTING_CACHE_MAX) {
@@ -35781,6 +35894,7 @@ var require_customProviders = __commonJS({
35781
35894
  const wire = { ...routing };
35782
35895
  delete wire.modelConfig;
35783
35896
  delete wire.routingModels;
35897
+ delete wire.executorGate;
35784
35898
  const declared = routing.modelConfig?.[modelId];
35785
35899
  if (declared === void 0)
35786
35900
  return wire;
@@ -36016,75 +36130,9 @@ var require_duetRouterInstall = __commonJS({
36016
36130
  }
36017
36131
  });
36018
36132
 
36019
- // ../packages/orion-client-core/dist/runs/common.js
36020
- var require_common = __commonJS({
36021
- "../packages/orion-client-core/dist/runs/common.js"(exports2) {
36022
- "use strict";
36023
- Object.defineProperty(exports2, "__esModule", { value: true });
36024
- exports2.mintRunId = mintRunId;
36025
- exports2.runsRootFor = runsRootFor2;
36026
- exports2.readJsonFile = readJsonFile;
36027
- exports2.writeJsonFile = writeJsonFile;
36028
- exports2.ensureDirFor = ensureDirFor;
36029
- exports2.listDirNames = listDirNames;
36030
- exports2.dayKey = dayKey;
36031
- exports2.clipTail = clipTail;
36032
- var fs_1 = __require("fs");
36033
- var os_1 = __require("os");
36034
- var path_1 = __require("path");
36035
- var atomicWrite_js_1 = require_atomicWrite();
36036
- var experienceStore_js_1 = require_experienceStore();
36037
- var ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
36038
- var ID_SUFFIX_LEN = 6;
36039
- function mintRunId(prefix, nowMs = Date.now(), rand = Math.random) {
36040
- let suffix = "";
36041
- for (let i2 = 0; i2 < ID_SUFFIX_LEN; i2 += 1) {
36042
- suffix += ID_ALPHABET[Math.floor(rand() * ID_ALPHABET.length) % ID_ALPHABET.length];
36043
- }
36044
- return `${prefix}_${String(nowMs).padStart(13, "0")}_${suffix}`;
36045
- }
36046
- function runsRootFor2(kind, workspaceRoot, home = (0, os_1.homedir)()) {
36047
- return (0, path_1.join)((0, experienceStore_js_1.projectDirFor)(workspaceRoot, home), "runs", kind);
36048
- }
36049
- async function readJsonFile(path14) {
36050
- try {
36051
- const raw = await fs_1.promises.readFile(path14, "utf8");
36052
- return JSON.parse(raw);
36053
- } catch {
36054
- return null;
36055
- }
36056
- }
36057
- async function writeJsonFile(path14, value) {
36058
- await ensureDirFor(path14);
36059
- await (0, atomicWrite_js_1.atomicWriteFile)(path14, JSON.stringify(value, null, 2));
36060
- }
36061
- async function ensureDirFor(path14) {
36062
- await fs_1.promises.mkdir((0, path_1.dirname)(path14), { recursive: true });
36063
- }
36064
- async function listDirNames(path14) {
36065
- try {
36066
- return await fs_1.promises.readdir(path14);
36067
- } catch {
36068
- return [];
36069
- }
36070
- }
36071
- function dayKey(nowMs = Date.now()) {
36072
- const d2 = new Date(nowMs);
36073
- const month = `${d2.getMonth() + 1}`.padStart(2, "0");
36074
- const day = `${d2.getDate()}`.padStart(2, "0");
36075
- return `${d2.getFullYear()}-${month}-${day}`;
36076
- }
36077
- function clipTail(text, max) {
36078
- if (text.length <= max)
36079
- return text;
36080
- return `\u2026${text.slice(text.length - (max - 1))}`;
36081
- }
36082
- }
36083
- });
36084
-
36085
- // ../packages/orion-client-core/dist/customProviderModels.js
36086
- var require_customProviderModels = __commonJS({
36087
- "../packages/orion-client-core/dist/customProviderModels.js"(exports2) {
36133
+ // ../packages/orion-client-core/dist/duetRoutingLog.js
36134
+ var require_duetRoutingLog = __commonJS({
36135
+ "../packages/orion-client-core/dist/duetRoutingLog.js"(exports2) {
36088
36136
  "use strict";
36089
36137
  var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m2, k, k2) {
36090
36138
  if (k2 === void 0) k2 = k;
@@ -36124,291 +36172,240 @@ var require_customProviderModels = __commonJS({
36124
36172
  };
36125
36173
  }();
36126
36174
  Object.defineProperty(exports2, "__esModule", { value: true });
36127
- exports2.CATALOG_GC_MS = exports2.CATALOG_TTL_MS = exports2.CATALOG_SCHEMA_VERSION = void 0;
36128
- exports2.catalogPathFor = catalogPathFor;
36129
- exports2.endpointCatalog = endpointCatalog2;
36130
- exports2.findProbedModel = findProbedModel;
36131
- exports2.resolveModelSettings = resolveModelSettings2;
36132
- exports2.catalogModelIds = catalogModelIds2;
36133
- exports2.clearEndpointCatalog = clearEndpointCatalog3;
36134
- exports2.endpointModelViews = endpointModelViews2;
36135
- exports2.updateCustomProviderModels = updateCustomProviderModels2;
36175
+ exports2.DUET_ROUTING_LOG_DEFAULT_MODE = exports2.DUET_ROUTING_LOG_KEY = exports2.DUET_ROUTING_LOG_HEAD_CHARS = exports2.DUET_ROUTING_LOG_MAX_BYTES = exports2.DUET_ROUTING_LOG_SCHEMA = void 0;
36176
+ exports2.duetRoutingLogPath = duetRoutingLogPath2;
36177
+ exports2.newDecisionId = newDecisionId;
36178
+ exports2.sessionKey = sessionKey;
36179
+ exports2.lexicalSimilarity = lexicalSimilarity;
36180
+ exports2.planDiffRatio = planDiffRatio;
36181
+ exports2.clearDuetRoutingLogCache = clearDuetRoutingLogCache;
36182
+ exports2.duetRoutingLogMode = duetRoutingLogMode2;
36183
+ exports2.redactRowForMode = redactRowForMode;
36184
+ exports2.appendDuetRoutingRow = appendDuetRoutingRow;
36185
+ exports2.readDuetRoutingLog = readDuetRoutingLog2;
36186
+ exports2.summarizeDuetRoutingLog = summarizeDuetRoutingLog2;
36187
+ exports2.formatDuetRoutingLogSummary = formatDuetRoutingLogSummary2;
36136
36188
  var node_crypto_1 = __require("node:crypto");
36189
+ var fs15 = __importStar(__require("node:fs/promises"));
36137
36190
  var os9 = __importStar(__require("node:os"));
36138
36191
  var path14 = __importStar(__require("node:path"));
36139
- var customProviders_1 = require_customProviders();
36140
- var common_1 = require_common();
36141
- exports2.CATALOG_SCHEMA_VERSION = 1;
36142
- exports2.CATALOG_TTL_MS = 9e5;
36143
- exports2.CATALOG_GC_MS = 45 * 24 * 60 * 60 * 1e3;
36144
- function catalogPathFor(baseUrl, homeDir = os9.homedir()) {
36145
- const digest = (0, node_crypto_1.createHash)("sha256").update(normalizeBaseUrl(baseUrl)).digest("hex").slice(0, 16);
36146
- return path14.join(homeDir, ".orion", "cache", "models", `${digest}.json`);
36192
+ var settingsPaths_js_1 = require_settingsPaths();
36193
+ exports2.DUET_ROUTING_LOG_SCHEMA = 3;
36194
+ exports2.DUET_ROUTING_LOG_MAX_BYTES = 5 * 1024 * 1024;
36195
+ exports2.DUET_ROUTING_LOG_HEAD_CHARS = 200;
36196
+ exports2.DUET_ROUTING_LOG_KEY = "duetRoutingLog";
36197
+ exports2.DUET_ROUTING_LOG_DEFAULT_MODE = "full";
36198
+ function duetRoutingLogPath2(opts = {}) {
36199
+ return path14.join(opts.homeDir ?? os9.homedir(), ".orion", "duet-routing-decisions.jsonl");
36147
36200
  }
36148
- function normalizeBaseUrl(baseUrl) {
36149
- return baseUrl.trim().replace(/\/+$/, "");
36201
+ function newDecisionId() {
36202
+ return (0, node_crypto_1.randomUUID)();
36150
36203
  }
36151
- async function readRecordFromDisk(baseUrl) {
36152
- const record = await (0, common_1.readJsonFile)(catalogPathFor(baseUrl));
36153
- if (record === null)
36154
- return null;
36155
- if (record.version !== exports2.CATALOG_SCHEMA_VERSION)
36156
- return null;
36157
- if (normalizeBaseUrl(record.baseUrl ?? "") !== normalizeBaseUrl(baseUrl))
36158
- return null;
36159
- if (!Array.isArray(record.models))
36160
- return null;
36161
- return record;
36204
+ function sessionKey(sessionId) {
36205
+ if (sessionId === void 0 || sessionId === "")
36206
+ return void 0;
36207
+ return (0, node_crypto_1.createHash)("sha256").update(sessionId).digest("hex").slice(0, 12);
36162
36208
  }
36163
- var sweptThisProcess = false;
36164
- async function gcEndpointCatalogs(now2, homeDir = os9.homedir()) {
36165
- if (sweptThisProcess)
36166
- return;
36167
- sweptThisProcess = true;
36168
- try {
36169
- const dir = path14.dirname(catalogPathFor("x", homeDir));
36170
- const fs15 = await Promise.resolve().then(() => __importStar(__require("node:fs/promises")));
36171
- for (const name2 of await fs15.readdir(dir)) {
36172
- if (!name2.endsWith(".json"))
36173
- continue;
36174
- const file = path14.join(dir, name2);
36175
- try {
36176
- const record = await (0, common_1.readJsonFile)(file);
36177
- const age = typeof record?.fetchedAt === "number" ? now2 - record.fetchedAt : now2 - (await fs15.stat(file)).mtimeMs;
36178
- if (age > exports2.CATALOG_GC_MS)
36179
- await fs15.rm(file, { force: true });
36180
- } catch {
36181
- }
36182
- }
36183
- } catch {
36184
- }
36209
+ function tokens(text) {
36210
+ return new Set(text.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 1));
36185
36211
  }
36186
- async function writeRecordToDisk(record) {
36187
- try {
36188
- await (0, common_1.writeJsonFile)(catalogPathFor(record.baseUrl), record);
36189
- } catch {
36190
- }
36191
- void gcEndpointCatalogs(record.fetchedAt);
36212
+ function jaccard(a, b2) {
36213
+ if (a.size === 0 && b2.size === 0)
36214
+ return 1;
36215
+ let inter = 0;
36216
+ for (const t of a)
36217
+ if (b2.has(t))
36218
+ inter += 1;
36219
+ const union = a.size + b2.size - inter;
36220
+ return union === 0 ? 0 : inter / union;
36192
36221
  }
36193
- var memory = /* @__PURE__ */ new Map();
36194
- var inFlight2 = /* @__PURE__ */ new Map();
36195
- function depsWith(deps2) {
36196
- return {
36197
- now: deps2.now ?? (() => Date.now()),
36198
- probe: deps2.probe ?? customProviders_1.probeModels,
36199
- readRecord: deps2.readRecord ?? readRecordFromDisk,
36200
- writeRecord: deps2.writeRecord ?? writeRecordToDisk
36201
- };
36222
+ function lexicalSimilarity(a, b2) {
36223
+ return Math.round(jaccard(tokens(a), tokens(b2)) * 1e3) / 1e3;
36202
36224
  }
36203
- async function probeAndStore(entry, d2) {
36204
- const key = normalizeBaseUrl(entry.baseUrl);
36205
- const existing = inFlight2.get(key);
36206
- if (existing !== void 0)
36207
- return existing;
36208
- const run3 = (async () => {
36209
- const models = await d2.probe(entry.baseUrl, await (0, customProviders_1.resolveApiKey)(entry));
36210
- if (models === null || models.length === 0)
36211
- return models;
36212
- const record = {
36213
- version: exports2.CATALOG_SCHEMA_VERSION,
36214
- baseUrl: entry.baseUrl,
36215
- fetchedAt: d2.now(),
36216
- models
36217
- };
36218
- memory.set(key, record);
36219
- await d2.writeRecord(record);
36220
- return models;
36221
- })().finally(() => inFlight2.delete(key));
36222
- inFlight2.set(key, run3);
36223
- return run3;
36225
+ function planDiffRatio(before, after) {
36226
+ const lines = (plan) => new Set(plan.split(/\r?\n/).map((l3) => l3.trim()).filter((l3) => l3 !== ""));
36227
+ return Math.round((1 - jaccard(lines(before), lines(after))) * 1e3) / 1e3;
36224
36228
  }
36225
- async function endpointCatalog2(entry, options = {}) {
36226
- const d2 = depsWith(options);
36227
- const key = normalizeBaseUrl(entry.baseUrl);
36228
- let record = memory.get(key) ?? null;
36229
- if (record === null) {
36230
- record = await d2.readRecord(entry.baseUrl);
36231
- if (record !== null)
36232
- memory.set(key, record);
36233
- }
36234
- if (options.cachedOnly === true)
36235
- return record?.models ?? [];
36236
- const fresh = record !== null && d2.now() - record.fetchedAt < exports2.CATALOG_TTL_MS;
36237
- if (record !== null && fresh && options.force !== true)
36238
- return record.models;
36239
- if (record !== null) {
36240
- void probeAndStore(entry, d2).catch(() => void 0);
36241
- return record.models;
36242
- }
36243
- return await probeAndStore(entry, d2) ?? [];
36229
+ var MODE_CACHE_TTL_MS = 5e3;
36230
+ var modeCache = /* @__PURE__ */ new Map();
36231
+ function clearDuetRoutingLogCache() {
36232
+ modeCache.clear();
36244
36233
  }
36245
- function findProbedModel(models, id) {
36246
- return models.find((model) => model.id === id);
36234
+ function coerceMode(raw) {
36235
+ return raw === "full" || raw === "head" || raw === "off" ? raw : null;
36247
36236
  }
36248
- function resolveModelSettings2(entry, modelId, catalog = []) {
36249
- const declared = entry.modelConfig?.[modelId];
36250
- const probed = findProbedModel(catalog, modelId);
36251
- const resolved = {};
36252
- const contextWindow = declared?.contextWindow ?? probed?.contextWindow;
36253
- if (contextWindow !== void 0)
36254
- resolved.contextWindow = contextWindow;
36255
- const maxOutputTokens = declared?.maxOutputTokens ?? probed?.maxOutputTokens;
36256
- if (maxOutputTokens !== void 0)
36257
- resolved.maxOutputTokens = maxOutputTokens;
36258
- if (probed?.reasoning !== void 0)
36259
- resolved.reasoning = probed.reasoning;
36260
- for (const knob of ["temperature", "topP", "topK", "repetitionPenalty"]) {
36261
- const value = declared?.[knob];
36262
- if (typeof value === "number")
36263
- resolved[knob] = value;
36237
+ async function readTierMode(file) {
36238
+ if (file === null)
36239
+ return null;
36240
+ try {
36241
+ const parsed = JSON.parse(await fs15.readFile(file, "utf8"));
36242
+ return coerceMode(parsed?.[exports2.DUET_ROUTING_LOG_KEY]?.mode);
36243
+ } catch {
36244
+ return null;
36264
36245
  }
36265
- return resolved;
36266
- }
36267
- function catalogModelIds2(entry, catalog) {
36268
- return entry.models?.length ? entry.models : catalog.map((model) => model.id);
36269
36246
  }
36270
- function clearEndpointCatalog3(baseUrl) {
36271
- if (baseUrl === void 0) {
36272
- memory.clear();
36273
- inFlight2.clear();
36274
- sweptThisProcess = false;
36275
- return;
36247
+ async function duetRoutingLogMode2(opts = {}) {
36248
+ const home = opts.homeDir ?? os9.homedir();
36249
+ const ws = opts.workspaceRoot ?? null;
36250
+ const key = `${home}\0${ws ?? ""}`;
36251
+ const hit = modeCache.get(key);
36252
+ if (hit !== void 0 && Date.now() - hit.at < MODE_CACHE_TTL_MS)
36253
+ return hit.mode;
36254
+ let mode = exports2.DUET_ROUTING_LOG_DEFAULT_MODE;
36255
+ const tiers = ["user", "project", "local"];
36256
+ for (const tier of tiers) {
36257
+ const found = await readTierMode((0, settingsPaths_js_1.settingsFilePath)(tier, { homeDir: home, workspaceRoot: ws }));
36258
+ if (found !== null)
36259
+ mode = found;
36276
36260
  }
36277
- const key = normalizeBaseUrl(baseUrl);
36278
- memory.delete(key);
36279
- inFlight2.delete(key);
36261
+ modeCache.set(key, { at: Date.now(), mode });
36262
+ return mode;
36280
36263
  }
36281
- async function endpointModelViews2(entry, options = {}) {
36282
- const catalog = await endpointCatalog2(entry, options);
36283
- const pinned = new Set(entry.models ?? []);
36284
- const ids = [...pinned, ...catalog.map((model) => model.id).filter((id) => !pinned.has(id))];
36285
- return ids.map((id) => {
36286
- const resolved = resolveModelSettings2(entry, id, catalog);
36287
- const declared = entry.modelConfig?.[id];
36288
- const view = { id, pinned: pinned.has(id) };
36289
- if (resolved.contextWindow !== void 0)
36290
- view.contextWindow = resolved.contextWindow;
36291
- if (resolved.maxOutputTokens !== void 0)
36292
- view.maxOutputTokens = resolved.maxOutputTokens;
36293
- if (resolved.reasoning !== void 0)
36294
- view.reasoning = resolved.reasoning;
36295
- if (declared?.contextWindow !== void 0 || declared?.maxOutputTokens !== void 0) {
36296
- view.source = "user";
36297
- } else if (view.contextWindow !== void 0 || view.maxOutputTokens !== void 0) {
36298
- view.source = "endpoint";
36299
- }
36300
- return view;
36301
- });
36264
+ function head(text, max) {
36265
+ return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
36302
36266
  }
36303
- async function updateCustomProviderModels2(name2, update, tier = "user", opts = {}) {
36304
- const entry = await (0, customProviders_1.getCustomProvider)(name2, opts);
36305
- if (entry === null)
36306
- return false;
36307
- const next = { ...entry };
36308
- if (update.models !== void 0) {
36309
- if (update.models.length)
36310
- next.models = update.models;
36311
- else
36312
- delete next.models;
36267
+ function redactRowForMode(row, mode) {
36268
+ if (mode === "off")
36269
+ return null;
36270
+ if (mode === "full")
36271
+ return row;
36272
+ if (row.kind === "planner") {
36273
+ return row.brief === void 0 ? row : { ...row, brief: head(row.brief, exports2.DUET_ROUTING_LOG_HEAD_CHARS) };
36313
36274
  }
36314
- if (update.modelConfig !== void 0) {
36315
- const kept = Object.entries(update.modelConfig).map(([id, raw]) => [id, (0, customProviders_1.normalizeModelConfig)(raw)]).filter(([, value]) => value !== void 0 && Object.keys(value).length > 0);
36316
- if (kept.length)
36317
- next.modelConfig = Object.fromEntries(kept);
36318
- else
36319
- delete next.modelConfig;
36275
+ if (row.kind !== "decision")
36276
+ return row;
36277
+ return {
36278
+ ...row,
36279
+ prompt: head(row.prompt, exports2.DUET_ROUTING_LOG_HEAD_CHARS),
36280
+ assumptions: row.assumptions.map((a) => ({ id: a.id, text: head(a.text, 100) }))
36281
+ };
36282
+ }
36283
+ var writeQueues = /* @__PURE__ */ new Map();
36284
+ async function writeRow(row, file, opts) {
36285
+ const redacted = redactRowForMode(row, await duetRoutingLogMode2(opts));
36286
+ if (redacted === null)
36287
+ return;
36288
+ await fs15.mkdir(path14.dirname(file), { recursive: true });
36289
+ try {
36290
+ const stat = await fs15.stat(file);
36291
+ if (stat.size >= exports2.DUET_ROUTING_LOG_MAX_BYTES)
36292
+ await fs15.rename(file, `${file}.1`);
36293
+ } catch {
36320
36294
  }
36321
- await (0, customProviders_1.saveCustomProvider)(next, tier, opts);
36322
- clearEndpointCatalog3(entry.baseUrl);
36323
- return true;
36295
+ await fs15.appendFile(file, `${JSON.stringify(redacted)}
36296
+ `, "utf8");
36324
36297
  }
36325
- }
36326
- });
36327
-
36328
- // ../packages/orion-client-core/dist/duetExecutorCatalog.js
36329
- var require_duetExecutorCatalog = __commonJS({
36330
- "../packages/orion-client-core/dist/duetExecutorCatalog.js"(exports2) {
36331
- "use strict";
36332
- Object.defineProperty(exports2, "__esModule", { value: true });
36333
- exports2.LOCAL_EXECUTOR_READ_BUDGET_MS = void 0;
36334
- exports2.localExecutorOptions = localExecutorOptions2;
36335
- exports2.duetExecutorChoiceFor = duetExecutorChoiceFor2;
36336
- exports2.isLocalExecutorChoice = isLocalExecutorChoice;
36337
- exports2.resolveDuetExecutorChoice = resolveDuetExecutorChoice2;
36338
- var customProviders_js_1 = require_customProviders();
36339
- var customProviderModels_js_1 = require_customProviderModels();
36340
- exports2.LOCAL_EXECUTOR_READ_BUDGET_MS = 3e3;
36341
- async function localExecutorOptions2(input = {}) {
36342
- const { catalog, timeoutMs, ...opts } = input;
36343
- let entries;
36298
+ async function appendDuetRoutingRow(row, opts = {}) {
36299
+ const file = duetRoutingLogPath2(opts);
36300
+ const previous = writeQueues.get(file) ?? Promise.resolve();
36301
+ const next = previous.then(() => writeRow(row, file, opts)).catch(() => void 0);
36302
+ writeQueues.set(file, next);
36303
+ await next;
36304
+ if (writeQueues.get(file) === next)
36305
+ writeQueues.delete(file);
36306
+ }
36307
+ async function readDuetRoutingLog2(opts = {}) {
36308
+ let text;
36344
36309
  try {
36345
- entries = await (0, customProviders_js_1.loadCustomProviders)(opts);
36310
+ text = await fs15.readFile(duetRoutingLogPath2(opts), "utf8");
36346
36311
  } catch {
36347
36312
  return [];
36348
36313
  }
36349
- if (entries.length === 0)
36350
- return [];
36351
- const read = (options) => Promise.all(entries.map(async (entry) => {
36314
+ const rows = [];
36315
+ for (const line of text.split("\n")) {
36316
+ if (line.trim() === "")
36317
+ continue;
36352
36318
  try {
36353
- const views = await (0, customProviderModels_js_1.endpointModelViews)(entry, options);
36354
- return views.map((view) => {
36355
- const option = {
36356
- provider: `custom:${entry.name}`,
36357
- endpoint: entry.name,
36358
- model: view.id,
36359
- pinned: view.pinned
36360
- };
36361
- if (view.contextWindow !== void 0)
36362
- option.contextWindow = view.contextWindow;
36363
- if (view.maxOutputTokens !== void 0)
36364
- option.maxOutputTokens = view.maxOutputTokens;
36365
- return option;
36366
- });
36319
+ const parsed = JSON.parse(line);
36320
+ if (parsed.kind === "decision" || parsed.kind === "turn_end" || parsed.kind === "followup" || parsed.kind === "planner") {
36321
+ rows.push(parsed);
36322
+ }
36367
36323
  } catch {
36368
- return [];
36369
36324
  }
36370
- })).then((perEndpoint) => perEndpoint.flat());
36371
- const full = read(catalog ?? {});
36372
- const budget = timeoutMs ?? exports2.LOCAL_EXECUTOR_READ_BUDGET_MS;
36373
- if (catalog?.cachedOnly === true || budget <= 0)
36374
- return full;
36375
- let timer;
36376
- const fallback = new Promise((resolve5) => {
36377
- timer = setTimeout(() => resolve5(read({ ...catalog, cachedOnly: true })), budget);
36378
- });
36379
- try {
36380
- return await Promise.race([full, fallback]);
36381
- } finally {
36382
- if (timer !== void 0)
36383
- clearTimeout(timer);
36384
- void full.catch(() => void 0);
36385
36325
  }
36326
+ return rows;
36386
36327
  }
36387
- function duetExecutorChoiceFor2(option) {
36388
- return {
36389
- provider: option.provider,
36390
- model: option.model,
36391
- ...option.contextWindow !== void 0 ? { contextWindow: option.contextWindow } : {}
36328
+ function summarizeDuetRoutingLog2(rows) {
36329
+ const summary = {
36330
+ decisions: 0,
36331
+ routes: { plan: 0, execute: 0 },
36332
+ stage1PlanReasons: {},
36333
+ advisorEvaluated: 0,
36334
+ advisorFlagged: {},
36335
+ turnEnds: { completed: 0, error: 0, cancelled: 0 },
36336
+ followups: 0,
36337
+ missedEscalations: 0,
36338
+ flaggedWithoutNewPlan: 0,
36339
+ flaggedBarelyChanged: 0,
36340
+ repeats: 0,
36341
+ entries: { planner: 0, router: 0, executor: 0 },
36342
+ plannerVerdicts: { hand_off: 0, plan: 0 }
36392
36343
  };
36393
- }
36394
- function isLocalExecutorChoice(choice) {
36395
- return typeof choice?.provider === "string" && choice.provider.startsWith("custom:");
36396
- }
36397
- async function resolveDuetExecutorChoice2(choice, input = {}) {
36398
- if (!isLocalExecutorChoice(choice) || choice.contextWindow !== void 0)
36399
- return choice;
36400
- const found = (await localExecutorOptions2(input)).find((option) => option.provider === choice.provider && option.model === choice.model);
36401
- return found === void 0 ? choice : { ...choice, ...duetExecutorChoiceFor2(found), ...choice.effort ? { effort: choice.effort } : {} };
36402
- }
36403
- }
36404
- });
36405
-
36406
- // ../packages/orion-client-core/dist/duetRoutingSignals.js
36407
- var require_duetRoutingSignals = __commonJS({
36408
- "../packages/orion-client-core/dist/duetRoutingSignals.js"(exports2) {
36409
- "use strict";
36410
- Object.defineProperty(exports2, "__esModule", { value: true });
36411
- exports2.ROUTING_JUDGE_MAX_TOKENS = exports2.ROUTING_JUDGE_TIMEOUT_MS = exports2.ROUTING_SIGNAL_TIMEOUT_MS = void 0;
36344
+ const decisions = /* @__PURE__ */ new Map();
36345
+ for (const row of rows) {
36346
+ if (row.kind !== "decision")
36347
+ continue;
36348
+ decisions.set(row.id, row);
36349
+ summary.decisions += 1;
36350
+ summary.routes[row.route] += 1;
36351
+ summary.entries[row.entry ?? "router"] += 1;
36352
+ if (row.stage1.verdict === "plan") {
36353
+ summary.stage1PlanReasons[row.stage1.reason] = (summary.stage1PlanReasons[row.stage1.reason] ?? 0) + 1;
36354
+ }
36355
+ if (row.advisor !== null) {
36356
+ summary.advisorEvaluated += 1;
36357
+ if (row.advisor.reason !== null) {
36358
+ summary.advisorFlagged[row.advisor.reason] = (summary.advisorFlagged[row.advisor.reason] ?? 0) + 1;
36359
+ }
36360
+ }
36361
+ }
36362
+ for (const row of rows) {
36363
+ if (row.kind === "turn_end") {
36364
+ summary.turnEnds[row.outcome] += 1;
36365
+ } else if (row.kind === "planner") {
36366
+ summary.plannerVerdicts[row.verdict] += 1;
36367
+ } else if (row.kind === "followup") {
36368
+ summary.followups += 1;
36369
+ const decided = decisions.get(row.decisionId);
36370
+ if (row.nextPromptSimilarity !== null && row.nextPromptSimilarity >= 0.8)
36371
+ summary.repeats += 1;
36372
+ if (decided === void 0)
36373
+ continue;
36374
+ if (decided.route === "execute" && (row.replanActor || row.nextExplicitPlanRequest)) {
36375
+ summary.missedEscalations += 1;
36376
+ }
36377
+ if (decided.advisor?.flagged) {
36378
+ if (!row.planVersionChanged)
36379
+ summary.flaggedWithoutNewPlan += 1;
36380
+ else if (row.planDiffRatio !== null && row.planDiffRatio < 0.1)
36381
+ summary.flaggedBarelyChanged += 1;
36382
+ }
36383
+ }
36384
+ }
36385
+ return summary;
36386
+ }
36387
+ function formatDuetRoutingLogSummary2(summary, file, mode) {
36388
+ const byKey = (m2) => Object.entries(m2).sort((a, b2) => b2[1] - a[1]).map(([k, n]) => `${k} ${n}`).join(", ") || "none";
36389
+ return [
36390
+ `Duet routing journal: ${file} (mode: ${mode})`,
36391
+ `decisions ${summary.decisions} \u2014 plan ${summary.routes.plan}, execute ${summary.routes.execute}`,
36392
+ `entry: planner ${summary.entries.planner}, router ${summary.entries.router}, executor ${summary.entries.executor}`,
36393
+ `planner verdicts: handed off ${summary.plannerVerdicts.hand_off}, planned ${summary.plannerVerdicts.plan}`,
36394
+ `stage-1 plan rules: ${byKey(summary.stage1PlanReasons)}`,
36395
+ `advisor evaluated ${summary.advisorEvaluated}; flagged: ${byKey(summary.advisorFlagged)}`,
36396
+ `turn ends \u2014 completed ${summary.turnEnds.completed}, error ${summary.turnEnds.error}, cancelled ${summary.turnEnds.cancelled}`,
36397
+ `follow-ups ${summary.followups} \u2014 missed escalations ${summary.missedEscalations}, flagged without a new plan ${summary.flaggedWithoutNewPlan}, flagged but barely changed ${summary.flaggedBarelyChanged}, repeats ${summary.repeats}`
36398
+ ];
36399
+ }
36400
+ }
36401
+ });
36402
+
36403
+ // ../packages/orion-client-core/dist/duetRoutingSignals.js
36404
+ var require_duetRoutingSignals = __commonJS({
36405
+ "../packages/orion-client-core/dist/duetRoutingSignals.js"(exports2) {
36406
+ "use strict";
36407
+ Object.defineProperty(exports2, "__esModule", { value: true });
36408
+ exports2.ROUTING_JUDGE_MAX_TOKENS = exports2.ROUTING_JUDGE_TIMEOUT_MS = exports2.ROUTING_SIGNAL_TIMEOUT_MS = void 0;
36412
36409
  exports2.cosineSimilarity = cosineSimilarity;
36413
36410
  exports2.normalizeRerankScores = normalizeRerankScores;
36414
36411
  exports2.buildJudgeMessages = buildJudgeMessages;
@@ -36582,276 +36579,6 @@ Does this message invalidate any plan assumption or require architectural re-pla
36582
36579
  }
36583
36580
  });
36584
36581
 
36585
- // ../packages/orion-client-core/dist/duetRoutingLog.js
36586
- var require_duetRoutingLog = __commonJS({
36587
- "../packages/orion-client-core/dist/duetRoutingLog.js"(exports2) {
36588
- "use strict";
36589
- var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m2, k, k2) {
36590
- if (k2 === void 0) k2 = k;
36591
- var desc = Object.getOwnPropertyDescriptor(m2, k);
36592
- if (!desc || ("get" in desc ? !m2.__esModule : desc.writable || desc.configurable)) {
36593
- desc = { enumerable: true, get: function() {
36594
- return m2[k];
36595
- } };
36596
- }
36597
- Object.defineProperty(o, k2, desc);
36598
- } : function(o, m2, k, k2) {
36599
- if (k2 === void 0) k2 = k;
36600
- o[k2] = m2[k];
36601
- });
36602
- var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v2) {
36603
- Object.defineProperty(o, "default", { enumerable: true, value: v2 });
36604
- } : function(o, v2) {
36605
- o["default"] = v2;
36606
- });
36607
- var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
36608
- var ownKeys = function(o) {
36609
- ownKeys = Object.getOwnPropertyNames || function(o2) {
36610
- var ar = [];
36611
- for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
36612
- return ar;
36613
- };
36614
- return ownKeys(o);
36615
- };
36616
- return function(mod2) {
36617
- if (mod2 && mod2.__esModule) return mod2;
36618
- var result = {};
36619
- if (mod2 != null) {
36620
- for (var k = ownKeys(mod2), i2 = 0; i2 < k.length; i2++) if (k[i2] !== "default") __createBinding(result, mod2, k[i2]);
36621
- }
36622
- __setModuleDefault(result, mod2);
36623
- return result;
36624
- };
36625
- }();
36626
- Object.defineProperty(exports2, "__esModule", { value: true });
36627
- exports2.DUET_ROUTING_LOG_DEFAULT_MODE = exports2.DUET_ROUTING_LOG_KEY = exports2.DUET_ROUTING_LOG_HEAD_CHARS = exports2.DUET_ROUTING_LOG_MAX_BYTES = exports2.DUET_ROUTING_LOG_SCHEMA = void 0;
36628
- exports2.duetRoutingLogPath = duetRoutingLogPath2;
36629
- exports2.newDecisionId = newDecisionId;
36630
- exports2.sessionKey = sessionKey;
36631
- exports2.lexicalSimilarity = lexicalSimilarity;
36632
- exports2.planDiffRatio = planDiffRatio;
36633
- exports2.clearDuetRoutingLogCache = clearDuetRoutingLogCache;
36634
- exports2.duetRoutingLogMode = duetRoutingLogMode2;
36635
- exports2.redactRowForMode = redactRowForMode;
36636
- exports2.appendDuetRoutingRow = appendDuetRoutingRow;
36637
- exports2.readDuetRoutingLog = readDuetRoutingLog2;
36638
- exports2.summarizeDuetRoutingLog = summarizeDuetRoutingLog2;
36639
- exports2.formatDuetRoutingLogSummary = formatDuetRoutingLogSummary2;
36640
- var node_crypto_1 = __require("node:crypto");
36641
- var fs15 = __importStar(__require("node:fs/promises"));
36642
- var os9 = __importStar(__require("node:os"));
36643
- var path14 = __importStar(__require("node:path"));
36644
- var settingsPaths_js_1 = require_settingsPaths();
36645
- exports2.DUET_ROUTING_LOG_SCHEMA = 3;
36646
- exports2.DUET_ROUTING_LOG_MAX_BYTES = 5 * 1024 * 1024;
36647
- exports2.DUET_ROUTING_LOG_HEAD_CHARS = 200;
36648
- exports2.DUET_ROUTING_LOG_KEY = "duetRoutingLog";
36649
- exports2.DUET_ROUTING_LOG_DEFAULT_MODE = "full";
36650
- function duetRoutingLogPath2(opts = {}) {
36651
- return path14.join(opts.homeDir ?? os9.homedir(), ".orion", "duet-routing-decisions.jsonl");
36652
- }
36653
- function newDecisionId() {
36654
- return (0, node_crypto_1.randomUUID)();
36655
- }
36656
- function sessionKey(sessionId) {
36657
- if (sessionId === void 0 || sessionId === "")
36658
- return void 0;
36659
- return (0, node_crypto_1.createHash)("sha256").update(sessionId).digest("hex").slice(0, 12);
36660
- }
36661
- function tokens(text) {
36662
- return new Set(text.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 1));
36663
- }
36664
- function jaccard(a, b2) {
36665
- if (a.size === 0 && b2.size === 0)
36666
- return 1;
36667
- let inter = 0;
36668
- for (const t of a)
36669
- if (b2.has(t))
36670
- inter += 1;
36671
- const union = a.size + b2.size - inter;
36672
- return union === 0 ? 0 : inter / union;
36673
- }
36674
- function lexicalSimilarity(a, b2) {
36675
- return Math.round(jaccard(tokens(a), tokens(b2)) * 1e3) / 1e3;
36676
- }
36677
- function planDiffRatio(before, after) {
36678
- const lines = (plan) => new Set(plan.split(/\r?\n/).map((l3) => l3.trim()).filter((l3) => l3 !== ""));
36679
- return Math.round((1 - jaccard(lines(before), lines(after))) * 1e3) / 1e3;
36680
- }
36681
- var MODE_CACHE_TTL_MS = 5e3;
36682
- var modeCache = /* @__PURE__ */ new Map();
36683
- function clearDuetRoutingLogCache() {
36684
- modeCache.clear();
36685
- }
36686
- function coerceMode(raw) {
36687
- return raw === "full" || raw === "head" || raw === "off" ? raw : null;
36688
- }
36689
- async function readTierMode(file) {
36690
- if (file === null)
36691
- return null;
36692
- try {
36693
- const parsed = JSON.parse(await fs15.readFile(file, "utf8"));
36694
- return coerceMode(parsed?.[exports2.DUET_ROUTING_LOG_KEY]?.mode);
36695
- } catch {
36696
- return null;
36697
- }
36698
- }
36699
- async function duetRoutingLogMode2(opts = {}) {
36700
- const home = opts.homeDir ?? os9.homedir();
36701
- const ws = opts.workspaceRoot ?? null;
36702
- const key = `${home}\0${ws ?? ""}`;
36703
- const hit = modeCache.get(key);
36704
- if (hit !== void 0 && Date.now() - hit.at < MODE_CACHE_TTL_MS)
36705
- return hit.mode;
36706
- let mode = exports2.DUET_ROUTING_LOG_DEFAULT_MODE;
36707
- const tiers = ["user", "project", "local"];
36708
- for (const tier of tiers) {
36709
- const found = await readTierMode((0, settingsPaths_js_1.settingsFilePath)(tier, { homeDir: home, workspaceRoot: ws }));
36710
- if (found !== null)
36711
- mode = found;
36712
- }
36713
- modeCache.set(key, { at: Date.now(), mode });
36714
- return mode;
36715
- }
36716
- function head(text, max) {
36717
- return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
36718
- }
36719
- function redactRowForMode(row, mode) {
36720
- if (mode === "off")
36721
- return null;
36722
- if (mode === "full")
36723
- return row;
36724
- if (row.kind === "planner") {
36725
- return row.brief === void 0 ? row : { ...row, brief: head(row.brief, exports2.DUET_ROUTING_LOG_HEAD_CHARS) };
36726
- }
36727
- if (row.kind !== "decision")
36728
- return row;
36729
- return {
36730
- ...row,
36731
- prompt: head(row.prompt, exports2.DUET_ROUTING_LOG_HEAD_CHARS),
36732
- assumptions: row.assumptions.map((a) => ({ id: a.id, text: head(a.text, 100) }))
36733
- };
36734
- }
36735
- var writeQueues = /* @__PURE__ */ new Map();
36736
- async function writeRow(row, file, opts) {
36737
- const redacted = redactRowForMode(row, await duetRoutingLogMode2(opts));
36738
- if (redacted === null)
36739
- return;
36740
- await fs15.mkdir(path14.dirname(file), { recursive: true });
36741
- try {
36742
- const stat = await fs15.stat(file);
36743
- if (stat.size >= exports2.DUET_ROUTING_LOG_MAX_BYTES)
36744
- await fs15.rename(file, `${file}.1`);
36745
- } catch {
36746
- }
36747
- await fs15.appendFile(file, `${JSON.stringify(redacted)}
36748
- `, "utf8");
36749
- }
36750
- async function appendDuetRoutingRow(row, opts = {}) {
36751
- const file = duetRoutingLogPath2(opts);
36752
- const previous = writeQueues.get(file) ?? Promise.resolve();
36753
- const next = previous.then(() => writeRow(row, file, opts)).catch(() => void 0);
36754
- writeQueues.set(file, next);
36755
- await next;
36756
- if (writeQueues.get(file) === next)
36757
- writeQueues.delete(file);
36758
- }
36759
- async function readDuetRoutingLog2(opts = {}) {
36760
- let text;
36761
- try {
36762
- text = await fs15.readFile(duetRoutingLogPath2(opts), "utf8");
36763
- } catch {
36764
- return [];
36765
- }
36766
- const rows = [];
36767
- for (const line of text.split("\n")) {
36768
- if (line.trim() === "")
36769
- continue;
36770
- try {
36771
- const parsed = JSON.parse(line);
36772
- if (parsed.kind === "decision" || parsed.kind === "turn_end" || parsed.kind === "followup" || parsed.kind === "planner") {
36773
- rows.push(parsed);
36774
- }
36775
- } catch {
36776
- }
36777
- }
36778
- return rows;
36779
- }
36780
- function summarizeDuetRoutingLog2(rows) {
36781
- const summary = {
36782
- decisions: 0,
36783
- routes: { plan: 0, execute: 0 },
36784
- stage1PlanReasons: {},
36785
- advisorEvaluated: 0,
36786
- advisorFlagged: {},
36787
- turnEnds: { completed: 0, error: 0, cancelled: 0 },
36788
- followups: 0,
36789
- missedEscalations: 0,
36790
- flaggedWithoutNewPlan: 0,
36791
- flaggedBarelyChanged: 0,
36792
- repeats: 0,
36793
- entries: { planner: 0, router: 0 },
36794
- plannerVerdicts: { hand_off: 0, plan: 0 }
36795
- };
36796
- const decisions = /* @__PURE__ */ new Map();
36797
- for (const row of rows) {
36798
- if (row.kind !== "decision")
36799
- continue;
36800
- decisions.set(row.id, row);
36801
- summary.decisions += 1;
36802
- summary.routes[row.route] += 1;
36803
- summary.entries[row.entry ?? "router"] += 1;
36804
- if (row.stage1.verdict === "plan") {
36805
- summary.stage1PlanReasons[row.stage1.reason] = (summary.stage1PlanReasons[row.stage1.reason] ?? 0) + 1;
36806
- }
36807
- if (row.advisor !== null) {
36808
- summary.advisorEvaluated += 1;
36809
- if (row.advisor.reason !== null) {
36810
- summary.advisorFlagged[row.advisor.reason] = (summary.advisorFlagged[row.advisor.reason] ?? 0) + 1;
36811
- }
36812
- }
36813
- }
36814
- for (const row of rows) {
36815
- if (row.kind === "turn_end") {
36816
- summary.turnEnds[row.outcome] += 1;
36817
- } else if (row.kind === "planner") {
36818
- summary.plannerVerdicts[row.verdict] += 1;
36819
- } else if (row.kind === "followup") {
36820
- summary.followups += 1;
36821
- const decided = decisions.get(row.decisionId);
36822
- if (row.nextPromptSimilarity !== null && row.nextPromptSimilarity >= 0.8)
36823
- summary.repeats += 1;
36824
- if (decided === void 0)
36825
- continue;
36826
- if (decided.route === "execute" && (row.replanActor || row.nextExplicitPlanRequest)) {
36827
- summary.missedEscalations += 1;
36828
- }
36829
- if (decided.advisor?.flagged) {
36830
- if (!row.planVersionChanged)
36831
- summary.flaggedWithoutNewPlan += 1;
36832
- else if (row.planDiffRatio !== null && row.planDiffRatio < 0.1)
36833
- summary.flaggedBarelyChanged += 1;
36834
- }
36835
- }
36836
- }
36837
- return summary;
36838
- }
36839
- function formatDuetRoutingLogSummary2(summary, file, mode) {
36840
- const byKey = (m2) => Object.entries(m2).sort((a, b2) => b2[1] - a[1]).map(([k, n]) => `${k} ${n}`).join(", ") || "none";
36841
- return [
36842
- `Duet routing journal: ${file} (mode: ${mode})`,
36843
- `decisions ${summary.decisions} \u2014 plan ${summary.routes.plan}, execute ${summary.routes.execute}`,
36844
- `entry: planner ${summary.entries.planner}, router ${summary.entries.router}`,
36845
- `planner verdicts: handed off ${summary.plannerVerdicts.hand_off}, planned ${summary.plannerVerdicts.plan}`,
36846
- `stage-1 plan rules: ${byKey(summary.stage1PlanReasons)}`,
36847
- `advisor evaluated ${summary.advisorEvaluated}; flagged: ${byKey(summary.advisorFlagged)}`,
36848
- `turn ends \u2014 completed ${summary.turnEnds.completed}, error ${summary.turnEnds.error}, cancelled ${summary.turnEnds.cancelled}`,
36849
- `follow-ups ${summary.followups} \u2014 missed escalations ${summary.missedEscalations}, flagged without a new plan ${summary.flaggedWithoutNewPlan}, flagged but barely changed ${summary.flaggedBarelyChanged}, repeats ${summary.repeats}`
36850
- ];
36851
- }
36852
- }
36853
- });
36854
-
36855
36582
  // ../packages/orion-client-core/dist/duetRoutingAdvisor.js
36856
36583
  var require_duetRoutingAdvisor = __commonJS({
36857
36584
  "../packages/orion-client-core/dist/duetRoutingAdvisor.js"(exports2) {
@@ -37178,288 +36905,1181 @@ var require_duetRoutingAdvisor = __commonJS({
37178
36905
  } catch {
37179
36906
  }
37180
36907
  }
37181
- function stage1Verdict(record, text, entry) {
37182
- if ((0, duetPlan_js_1.explicitPlanRequest)(text))
37183
- return { verdict: "plan", reason: "explicit_plan_request" };
36908
+ function scorerReason(verdict, highRisk) {
36909
+ const base = verdict.source === "executor_gate" ? "executor_gate" : "router_model";
36910
+ return highRisk ? `${base}_high_risk` : base;
36911
+ }
36912
+ function stage1Verdict(record, text, entry, verdict = null) {
36913
+ if ((0, duetPlan_js_1.explicitPlanRequest)(text))
36914
+ return { verdict: "plan", reason: "explicit_plan_request" };
36915
+ if (record === null) {
36916
+ if ((0, duetPlan_js_1.highRiskRequest)(text))
36917
+ return { verdict: "plan", reason: "plan_invalid" };
36918
+ if (entry === "planner")
36919
+ return { verdict: "plan", reason: "planner_entry" };
36920
+ if (verdict?.verdict === "plan")
36921
+ return { verdict: "plan", reason: scorerReason(verdict, false) };
36922
+ if (verdict?.highRisk)
36923
+ return { verdict: "plan", reason: scorerReason(verdict, true) };
36924
+ return { verdict: "execute", reason: "no_plan" };
36925
+ }
36926
+ if (record.scopeChanged)
36927
+ return { verdict: "plan", reason: "scope_changed" };
36928
+ if (record.architectureDecisionRequired) {
36929
+ return { verdict: "plan", reason: "architecture_decision_required" };
36930
+ }
36931
+ if (record.planningFailures >= 2)
36932
+ return { verdict: "plan", reason: "failed_attempts" };
36933
+ if (record.userNegativeFeedback)
36934
+ return { verdict: "plan", reason: "negative_feedback" };
36935
+ if (entry === "planner") {
36936
+ return (0, duetPlan_js_1.continuationRequest)(text) ? { verdict: "execute", reason: "continuation" } : { verdict: "plan", reason: "planner_entry" };
36937
+ }
36938
+ if (verdict?.verdict === "plan")
36939
+ return { verdict: "plan", reason: scorerReason(verdict, false) };
36940
+ return { verdict: "execute", reason: "plan_valid" };
36941
+ }
36942
+ function executorContext(workspaceRoot) {
36943
+ const choice = (0, duetMode_js_1.duetExecutorWireForSegment)(workspaceRoot);
36944
+ const local = choice !== void 0 && (0, customProviders_js_1.isCustomProviderRef)(choice.provider);
36945
+ const models = local ? (0, customProviders_js_1.endpointRoutingFor)(choice.provider)?.routingModels : void 0;
36946
+ return {
36947
+ executor: local ? "local" : "platform",
36948
+ routingModels: {
36949
+ embeddings: models?.embeddings !== void 0,
36950
+ rerank: models?.rerank !== void 0,
36951
+ judge: models?.judge !== void 0
36952
+ }
36953
+ };
36954
+ }
36955
+ function followupRow(last, standing, text, at) {
36956
+ const versionChanged = standing !== null && standing.version !== last.planVersion;
36957
+ return {
36958
+ kind: "followup",
36959
+ v: duetRoutingLog_js_1.DUET_ROUTING_LOG_SCHEMA,
36960
+ decisionId: last.decisionId,
36961
+ at,
36962
+ planVersionChanged: versionChanged,
36963
+ newPlanVersion: versionChanged ? standing.version : null,
36964
+ planDiffRatio: versionChanged && last.planText !== null ? (0, duetRoutingLog_js_1.planDiffRatio)(last.planText, standing.plan) : null,
36965
+ replanActor: standing !== null && standing.scopeChanged && !last.scopeChanged,
36966
+ nextPromptSimilarity: text === "" ? null : (0, duetRoutingLog_js_1.lexicalSimilarity)(last.prompt, text),
36967
+ nextExplicitPlanRequest: text !== "" && (0, duetPlan_js_1.explicitPlanRequest)(text),
36968
+ planningFailuresDelta: standing === null ? 0 : standing.planningFailures - last.planningFailures,
36969
+ executorFailuresDelta: standing === null ? 0 : standing.executorFailures - last.executorFailures,
36970
+ planGone: last.planVersion > 0 && standing === null
36971
+ };
36972
+ }
36973
+ function journalDuetTurnEnd2(state, end, opts = {}) {
36974
+ const last = state.last;
36975
+ if (last === null)
36976
+ return;
36977
+ emit(sinkFor(opts.log, opts.homeDir, opts.workspaceRoot), {
36978
+ kind: "turn_end",
36979
+ v: duetRoutingLog_js_1.DUET_ROUTING_LOG_SCHEMA,
36980
+ decisionId: last.decisionId,
36981
+ at: (/* @__PURE__ */ new Date()).toISOString(),
36982
+ outcome: end.outcome,
36983
+ executionLeg: end.executionLeg
36984
+ });
36985
+ }
36986
+ function journalDuetPlannerVerdict2(state, verdict, opts = {}) {
36987
+ const last = state.last;
36988
+ if (last === null)
36989
+ return;
36990
+ emit(sinkFor(opts.log, opts.homeDir, opts.workspaceRoot), {
36991
+ kind: "planner",
36992
+ v: duetRoutingLog_js_1.DUET_ROUTING_LOG_SCHEMA,
36993
+ decisionId: last.decisionId,
36994
+ at: (/* @__PURE__ */ new Date()).toISOString(),
36995
+ verdict: verdict.verdict,
36996
+ ...verdict.verdict === "hand_off" ? { brief: verdict.brief } : {}
36997
+ });
36998
+ }
36999
+ async function adviseDuetRoute2(input) {
37000
+ const { state } = input;
37001
+ const now2 = input.now ?? Date.now;
37002
+ const started = now2();
37003
+ const at = new Date(started).toISOString();
37004
+ const record = input.record ?? null;
37005
+ const entry = input.entry ?? "router";
37006
+ const routerVerdict = input.routerVerdict ? {
37007
+ model: input.routerVerdict.model,
37008
+ version: input.routerVerdict.version,
37009
+ verdict: input.routerVerdict.verdict,
37010
+ pPlan: Math.round(input.routerVerdict.pPlan * 1e6) / 1e6,
37011
+ asksForPlan: input.routerVerdict.asksForPlan,
37012
+ highRisk: input.routerVerdict.highRisk,
37013
+ reason: input.routerVerdict.reason,
37014
+ latencyMs: input.routerVerdict.latencyMs,
37015
+ source: input.routerVerdict.source,
37016
+ ...input.routerVerdict.margin !== void 0 ? { margin: Math.round(input.routerVerdict.margin * 1e6) / 1e6 } : {},
37017
+ ...input.routerVerdict.mode !== void 0 ? { mode: input.routerVerdict.mode } : {}
37018
+ } : null;
37019
+ const sink = sinkFor(input.log, input.homeDir, input.workspaceRoot);
37020
+ try {
37021
+ const text = input.text.trim();
37022
+ const standing = (0, duetPlan_js_1.duetPlanWireForSegment)(record) !== void 0 ? record : null;
37023
+ if (state.last !== null) {
37024
+ emit(sink, followupRow(state.last, standing, text, at));
37025
+ state.last = null;
37026
+ }
37027
+ const journal = (stage12, advisor, route, assumptions2) => {
37028
+ const id = (0, duetRoutingLog_js_1.newDecisionId)();
37029
+ const session = (0, duetRoutingLog_js_1.sessionKey)(input.sessionId);
37030
+ emit(sink, {
37031
+ kind: "decision",
37032
+ v: duetRoutingLog_js_1.DUET_ROUTING_LOG_SCHEMA,
37033
+ id,
37034
+ at,
37035
+ ...session !== void 0 ? { session } : {},
37036
+ entry,
37037
+ planVersion: standing?.version ?? 0,
37038
+ turnUnderVersion: state.turnsUnderVersion,
37039
+ prompt: text,
37040
+ assumptions: assumptions2,
37041
+ ...executorContext(input.workspaceRoot),
37042
+ stage1: stage12,
37043
+ router: routerVerdict,
37044
+ advisor: advisor === null ? null : {
37045
+ stage: advisor.stage,
37046
+ signals: advisor.signals,
37047
+ guards: advisor.guards,
37048
+ flagged: advisor.flagged,
37049
+ reason: advisor.reason
37050
+ },
37051
+ route,
37052
+ latencyMs: Math.max(0, now2() - started)
37053
+ });
37054
+ state.last = {
37055
+ decisionId: id,
37056
+ prompt: text,
37057
+ route,
37058
+ planVersion: standing?.version ?? 0,
37059
+ planText: standing?.plan ?? null,
37060
+ scopeChanged: standing?.scopeChanged ?? false,
37061
+ planningFailures: standing?.planningFailures ?? 0,
37062
+ executorFailures: standing?.executorFailures ?? 0
37063
+ };
37064
+ };
37065
+ if (standing === null) {
37066
+ resetForVersion(state, null);
37067
+ if (text !== "") {
37068
+ const stage12 = stage1Verdict(null, text, entry, input.routerVerdict ?? null);
37069
+ journal(stage12, null, stage12.verdict, []);
37070
+ }
37071
+ return untouched(record);
37072
+ }
37073
+ const plan = standing;
37074
+ if (state.planVersion !== plan.version)
37075
+ resetForVersion(state, plan.version);
37076
+ state.turnsUnderVersion += 1;
37077
+ if (text === "")
37078
+ return untouched(record);
37079
+ const assumptions = parsePlanAssumptions(plan.plan);
37080
+ const stage1 = stage1Verdict(plan, text, entry, input.routerVerdict ?? null);
37081
+ if (stage1.verdict === "plan") {
37082
+ journal(stage1, null, "plan", assumptions);
37083
+ return untouched(record);
37084
+ }
37085
+ if (entry === "planner") {
37086
+ journal(stage1, null, "execute", assumptions);
37087
+ return untouched(record);
37088
+ }
37089
+ const decision = {
37090
+ at,
37091
+ planVersion: plan.version,
37092
+ turnUnderVersion: state.turnsUnderVersion,
37093
+ text: text.length > DECISION_TEXT_HEAD ? `${text.slice(0, DECISION_TEXT_HEAD - 1)}\u2026` : text,
37094
+ stage: "cues",
37095
+ signals: {},
37096
+ guards: {},
37097
+ flagged: null,
37098
+ reason: null,
37099
+ latencyMs: 0
37100
+ };
37101
+ let candidate = null;
37102
+ const feedbackCue = negativeFeedbackCueIn(text);
37103
+ const negationCue = negationCueIn(text);
37104
+ if (feedbackCue !== null)
37105
+ decision.signals.feedbackCue = feedbackCue;
37106
+ if (negationCue !== null)
37107
+ decision.signals.negationCue = negationCue;
37108
+ if (feedbackCue !== null) {
37109
+ candidate = { flag: "user_negative_feedback", reason: "negative_feedback_cue", ids: [] };
37110
+ }
37111
+ if (candidate === null) {
37112
+ const endpoint = await advisorEndpoint(input.workspaceRoot);
37113
+ const models = endpoint?.routing.routingModels;
37114
+ if (endpoint !== null && models !== void 0) {
37115
+ candidate = await semanticStages({
37116
+ plan,
37117
+ assumptions,
37118
+ text,
37119
+ negationCue,
37120
+ dial: { baseUrl: endpoint.routing.baseUrl, apiKey: endpoint.routing.apiKey },
37121
+ models,
37122
+ executorModel: endpoint.executorModel,
37123
+ state,
37124
+ decision,
37125
+ fetchImpl: input.fetchImpl
37126
+ }, now2);
37127
+ }
37128
+ }
37129
+ if (candidate !== null && state.turnsUnderVersion < exports2.DUET_ADVISOR_THRESHOLDS.cooldownTurns) {
37130
+ decision.guards.cooldown = true;
37131
+ candidate = null;
37132
+ }
37133
+ let advised = plan;
37134
+ if (candidate !== null) {
37135
+ advised = candidate.flag === "user_negative_feedback" ? { ...plan, userNegativeFeedback: true } : { ...plan, architectureDecisionRequired: true };
37136
+ decision.flagged = candidate.flag;
37137
+ decision.reason = candidate.reason;
37138
+ }
37139
+ decision.latencyMs = Math.max(0, now2() - started);
37140
+ journal(stage1, decision, decision.flagged !== null ? "plan" : "execute", assumptions);
37141
+ return {
37142
+ record: advised,
37143
+ flagged: decision.flagged,
37144
+ reason: decision.reason,
37145
+ assumptionIds: candidate?.ids ?? [],
37146
+ decision,
37147
+ note: duetRoutingAdviceNote(decision.reason, candidate?.ids ?? [])
37148
+ };
37149
+ } catch {
37150
+ return untouched(record);
37151
+ }
37152
+ }
37153
+ function round3(value) {
37154
+ return Math.round(value * 1e3) / 1e3;
37155
+ }
37156
+ async function describeDuetRouting2(workspaceRoot) {
37157
+ try {
37158
+ const choice = await (0, duetMode_js_1.loadDuetExecutor)({ workspaceRoot: workspaceRoot ?? null });
37159
+ if (choice === null || !(0, customProviders_js_1.isCustomProviderRef)(choice.provider))
37160
+ return { kind: "platform" };
37161
+ const name2 = (0, customProviders_js_1.parseCustomProviderRef)(choice.provider) ?? "";
37162
+ const entry = await (0, customProviders_js_1.getCustomProvider)(name2, { workspaceRoot: workspaceRoot ?? null });
37163
+ if (entry === null)
37164
+ return { kind: "missing", name: name2 };
37165
+ return {
37166
+ kind: "local",
37167
+ name: name2,
37168
+ loopback: (0, customProviders_js_1.isLoopbackEndpoint)(entry.baseUrl),
37169
+ embeddings: entry.routingModels?.embeddings !== void 0,
37170
+ rerank: entry.routingModels?.rerank !== void 0,
37171
+ judge: entry.routingModels?.judge ?? null
37172
+ };
37173
+ } catch {
37174
+ return { kind: "platform" };
37175
+ }
37176
+ }
37177
+ function duetRoutingSummaryLine2(summary) {
37178
+ switch (summary.kind) {
37179
+ case "platform":
37180
+ return "Duet routing: rules only \u2014 a local executor with routing models unlocks re-ask detection and plan-assumption checks.";
37181
+ case "missing":
37182
+ return "Duet routing: rules only.";
37183
+ case "local": {
37184
+ const { name: name2, loopback, embeddings, rerank } = summary;
37185
+ if (!embeddings && !rerank) {
37186
+ return `Duet routing: rules only \u2014 add routingModels to '${name2}' to unlock re-ask detection and plan-assumption checks (the /local-ai skill can set this up).`;
37187
+ }
37188
+ if (!loopback) {
37189
+ return `Duet routing: rules only \u2014 semantic checks run only against a loopback endpoint, and '${name2}' is not one.`;
37190
+ }
37191
+ const parts2 = [];
37192
+ const via = [];
37193
+ if (embeddings) {
37194
+ parts2.push("re-ask detection");
37195
+ via.push("embeddings");
37196
+ }
37197
+ if (rerank) {
37198
+ parts2.push("plan-assumption checks");
37199
+ via.push("rerank");
37200
+ }
37201
+ return `Duet routing: rules + ${parts2.join(" + ")} (${via.join(" + ")} on '${name2}').`;
37202
+ }
37203
+ }
37204
+ }
37205
+ }
37206
+ });
37207
+
37208
+ // ../packages/orion-client-core/dist/duetExecutorGate.js
37209
+ var require_duetExecutorGate = __commonJS({
37210
+ "../packages/orion-client-core/dist/duetExecutorGate.js"(exports2) {
37211
+ "use strict";
37212
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m2, k, k2) {
37213
+ if (k2 === void 0) k2 = k;
37214
+ var desc = Object.getOwnPropertyDescriptor(m2, k);
37215
+ if (!desc || ("get" in desc ? !m2.__esModule : desc.writable || desc.configurable)) {
37216
+ desc = { enumerable: true, get: function() {
37217
+ return m2[k];
37218
+ } };
37219
+ }
37220
+ Object.defineProperty(o, k2, desc);
37221
+ } : function(o, m2, k, k2) {
37222
+ if (k2 === void 0) k2 = k;
37223
+ o[k2] = m2[k];
37224
+ });
37225
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v2) {
37226
+ Object.defineProperty(o, "default", { enumerable: true, value: v2 });
37227
+ } : function(o, v2) {
37228
+ o["default"] = v2;
37229
+ });
37230
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
37231
+ var ownKeys = function(o) {
37232
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
37233
+ var ar = [];
37234
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
37235
+ return ar;
37236
+ };
37237
+ return ownKeys(o);
37238
+ };
37239
+ return function(mod2) {
37240
+ if (mod2 && mod2.__esModule) return mod2;
37241
+ var result = {};
37242
+ if (mod2 != null) {
37243
+ for (var k = ownKeys(mod2), i2 = 0; i2 < k.length; i2++) if (k[i2] !== "default") __createBinding(result, mod2, k[i2]);
37244
+ }
37245
+ __setModuleDefault(result, mod2);
37246
+ return result;
37247
+ };
37248
+ }();
37249
+ Object.defineProperty(exports2, "__esModule", { value: true });
37250
+ exports2.EXECUTOR_GATE_PROBE_SCENARIOS = exports2.EXECUTOR_GATE_MIN_CALIBRATION = exports2.EXECUTOR_GATE_MISSING_LOGPROB = exports2.EXECUTOR_GATE_PLAN_HEAD_CHARS = exports2.EXECUTOR_GATE_REQUEST_MAX_CHARS = exports2.EXECUTOR_GATE_STATUS_TTL_MS = exports2.EXECUTOR_GATE_TIMEOUT_MS = exports2.EXECUTOR_GATE_PROMPT_VERSION = exports2.EXECUTOR_GATE_SOURCE = void 0;
37251
+ exports2.resolveExecutorGateTarget = resolveExecutorGateTarget;
37252
+ exports2.resolveExecutorGateTargetFromSettings = resolveExecutorGateTargetFromSettings;
37253
+ exports2.executorGateStateFrom = executorGateStateFrom;
37254
+ exports2.renderExecutorGatePrompt = renderExecutorGatePrompt;
37255
+ exports2.executorGateLetterOf = executorGateLetterOf;
37256
+ exports2.parseExecutorGateResponse = parseExecutorGateResponse;
37257
+ exports2.decideExecutorGate = decideExecutorGate;
37258
+ exports2.askExecutorGate = askExecutorGate;
37259
+ exports2.executorGateProbeState = executorGateProbeState;
37260
+ exports2.probeExecutorGate = probeExecutorGate;
37261
+ exports2.describeDuetExecutorGate = describeDuetExecutorGate;
37262
+ exports2.clearDuetExecutorGateCache = clearDuetExecutorGateCache;
37263
+ exports2.describeDuetExecutorGateCached = describeDuetExecutorGateCached2;
37264
+ exports2.createDuetExecutorGate = createDuetExecutorGate2;
37265
+ var os9 = __importStar(__require("node:os"));
37266
+ var customProviders_js_1 = require_customProviders();
37267
+ var duetMode_js_1 = require_duetMode();
37268
+ var duetPlan_js_1 = require_duetPlan();
37269
+ var duetRoutingAdvisor_js_1 = require_duetRoutingAdvisor();
37270
+ var duetEntry_js_1 = require_duetEntry();
37271
+ var duetExecutorGateStatus_js_1 = require_duetExecutorGateStatus();
37272
+ exports2.EXECUTOR_GATE_SOURCE = "executor_gate";
37273
+ exports2.EXECUTOR_GATE_PROMPT_VERSION = "1";
37274
+ exports2.EXECUTOR_GATE_TIMEOUT_MS = 8e3;
37275
+ exports2.EXECUTOR_GATE_STATUS_TTL_MS = 5 * 6e4;
37276
+ exports2.EXECUTOR_GATE_REQUEST_MAX_CHARS = 2e3;
37277
+ exports2.EXECUTOR_GATE_PLAN_HEAD_CHARS = 1200;
37278
+ exports2.EXECUTOR_GATE_MISSING_LOGPROB = -30;
37279
+ exports2.EXECUTOR_GATE_MIN_CALIBRATION = 3;
37280
+ var DEFAULT_RESOLVE_DEPS = {
37281
+ choice: (workspaceRoot) => (0, duetMode_js_1.duetExecutorWireForSegment)(workspaceRoot),
37282
+ routing: (provider) => (0, customProviders_js_1.endpointRoutingFor)(provider),
37283
+ alive: (workspaceRoot) => (0, customProviders_js_1.duetExecutorEndpointForSegment)(workspaceRoot) !== void 0
37284
+ };
37285
+ function resolveExecutorGateTarget(workspaceRoot, deps2 = DEFAULT_RESOLVE_DEPS) {
37286
+ try {
37287
+ const choice = deps2.choice(workspaceRoot);
37288
+ if (choice === void 0 || !(0, customProviders_js_1.isCustomProviderRef)(choice.provider))
37289
+ return { state: "platform" };
37290
+ const name2 = (0, customProviders_js_1.parseCustomProviderRef)(choice.provider) ?? "";
37291
+ const routing = deps2.routing(choice.provider);
37292
+ if (routing === void 0) {
37293
+ return { state: "unavailable", reason: "not_resolved", problem: "the executor's endpoint is not configured", name: name2 };
37294
+ }
37295
+ if (!(0, customProviders_js_1.isLoopbackEndpoint)(routing.baseUrl)) {
37296
+ return { state: "unavailable", reason: "not_loopback", problem: "the executor is not on this machine", name: name2 };
37297
+ }
37298
+ if (!deps2.alive(workspaceRoot)) {
37299
+ return { state: "unavailable", reason: "unreachable", problem: "the executor is not answering", name: name2 };
37300
+ }
37301
+ return {
37302
+ state: "ready",
37303
+ target: {
37304
+ name: routing.name,
37305
+ baseUrl: routing.baseUrl,
37306
+ ...routing.apiKey ? { apiKey: routing.apiKey } : {},
37307
+ model: choice.model,
37308
+ threshold: routing.executorGate?.threshold ?? customProviders_js_1.EXECUTOR_GATE_DEFAULT_THRESHOLD
37309
+ }
37310
+ };
37311
+ } catch {
37312
+ return { state: "unavailable", reason: "error", problem: "the executor could not be resolved" };
37313
+ }
37314
+ }
37315
+ async function resolveExecutorGateTargetFromSettings(opts) {
37316
+ try {
37317
+ const tiers = { workspaceRoot: opts.workspaceRoot ?? null, ...opts.homeDir ? { homeDir: opts.homeDir } : {} };
37318
+ const choice = await (0, duetMode_js_1.loadDuetExecutor)(tiers);
37319
+ if (choice === null || !(0, customProviders_js_1.isCustomProviderRef)(choice.provider))
37320
+ return { state: "platform" };
37321
+ const name2 = (0, customProviders_js_1.parseCustomProviderRef)(choice.provider) ?? "";
37322
+ const entry = await (0, customProviders_js_1.getCustomProvider)(name2, tiers);
37323
+ if (entry === null) {
37324
+ return { state: "unavailable", reason: "not_resolved", problem: "the executor's endpoint is not configured", name: name2 };
37325
+ }
37326
+ if (!(0, customProviders_js_1.isLoopbackEndpoint)(entry.baseUrl)) {
37327
+ return { state: "unavailable", reason: "not_loopback", problem: "the executor is not on this machine", name: name2 };
37328
+ }
37329
+ const apiKey = await (0, customProviders_js_1.resolveApiKey)(entry);
37330
+ if (!await (0, customProviders_js_1.endpointIsReachable)(entry.baseUrl, apiKey, opts.fetchImpl)) {
37331
+ return { state: "unavailable", reason: "unreachable", problem: "the executor is not answering", name: name2 };
37332
+ }
37333
+ return {
37334
+ state: "ready",
37335
+ target: {
37336
+ name: entry.name,
37337
+ baseUrl: entry.baseUrl,
37338
+ ...apiKey ? { apiKey } : {},
37339
+ model: choice.model,
37340
+ threshold: entry.executorGate?.threshold ?? customProviders_js_1.EXECUTOR_GATE_DEFAULT_THRESHOLD
37341
+ }
37342
+ };
37343
+ } catch {
37344
+ return { state: "unavailable", reason: "error", problem: "the executor could not be resolved" };
37345
+ }
37346
+ }
37347
+ function clipCodePoints(text, max) {
37348
+ const points = Array.from(text);
37349
+ return points.length <= max ? text : `${points.slice(0, max - 1).join("")}\u2026`;
37350
+ }
37351
+ function executorGateStateFrom(record, request) {
37352
+ const standing = record != null && (0, duetPlan_js_1.duetPlanWireForSegment)(record) !== void 0 ? record : null;
37353
+ return {
37354
+ planVersion: standing?.version ?? 0,
37355
+ planValid: standing !== null,
37356
+ planHead: standing === null ? "" : clipCodePoints(standing.plan.trim(), exports2.EXECUTOR_GATE_PLAN_HEAD_CHARS),
37357
+ assumptions: standing === null ? [] : (0, duetRoutingAdvisor_js_1.parsePlanAssumptions)(standing.plan).map((a) => ({ id: a.id, text: a.text })),
37358
+ planningFailures: standing?.planningFailures ?? 0,
37359
+ executorFailures: standing?.executorFailures ?? 0,
37360
+ scopeChanged: standing?.scopeChanged ?? false,
37361
+ architectureDecisionRequired: standing?.architectureDecisionRequired ?? false,
37362
+ userNegativeFeedback: standing?.userNegativeFeedback ?? false,
37363
+ request: clipCodePoints(request.trim(), exports2.EXECUTOR_GATE_REQUEST_MAX_CHARS)
37364
+ };
37365
+ }
37366
+ function stableJson(value) {
37367
+ const sort = (v2) => {
37368
+ if (Array.isArray(v2))
37369
+ return v2.map(sort);
37370
+ if (typeof v2 === "object" && v2 !== null) {
37371
+ return Object.fromEntries(Object.keys(v2).sort().map((k) => [k, sort(v2[k])]));
37372
+ }
37373
+ return v2;
37374
+ };
37375
+ return JSON.stringify(sort(value));
37376
+ }
37377
+ function renderExecutorGatePrompt(state) {
37378
+ const taskState = stableJson({
37379
+ plan_version: state.planVersion,
37380
+ plan_valid: state.planValid,
37381
+ planning_failures: state.planningFailures,
37382
+ executor_failures: state.executorFailures,
37383
+ flags: {
37384
+ scope_changed: state.scopeChanged,
37385
+ architecture_decision_required: state.architectureDecisionRequired,
37386
+ user_negative_feedback: state.userNegativeFeedback
37387
+ }
37388
+ });
37389
+ const capsule = stableJson({ assumptions: state.assumptions });
37390
+ const unresolved = state.executorFailures > 0 || state.planningFailures > 0 ? `${state.executorFailures} executor failure(s) and ${state.planningFailures} planning failure(s) under this plan` : "none";
37391
+ const corrections = state.userNegativeFeedback ? "the user pushed back on the current approach" : "none";
37392
+ return [
37393
+ "Routing gate for a coding agent. Decide if the current turn can be executed",
37394
+ "with the existing plan, or needs a new plan from the senior planner.",
37395
+ "",
37396
+ "E = EXECUTION_ONLY - the current plan is valid and local execution continues",
37397
+ "P = PLAN_REQUIRED - a new or revised plan would materially help",
37398
+ "",
37399
+ "Prefer E unless planning is genuinely needed.",
37400
+ "",
37401
+ "--- TASK STATE ---",
37402
+ taskState,
37403
+ "--- CONTEXT CAPSULE ---",
37404
+ capsule,
37405
+ "--- CURRENT PLAN ---",
37406
+ state.planHead === "" ? "(none)" : state.planHead,
37407
+ "--- UNRESOLVED ERRORS ---",
37408
+ unresolved,
37409
+ "--- RECENT USER CORRECTIONS ---",
37410
+ corrections,
37411
+ "--- LATEST USER REQUEST ---",
37412
+ state.request,
37413
+ "",
37414
+ "Answer with exactly one letter, E or P.",
37415
+ "Answer:"
37416
+ ].join("\n");
37417
+ }
37418
+ function executorGateLetterOf(token) {
37419
+ const bare2 = token.replace(/^[\s▁Ġ]+/u, "").replace(/\s+$/u, "");
37420
+ return bare2 === "E" || bare2 === "P" ? bare2 : null;
37421
+ }
37422
+ function topLogprobs(choice) {
37423
+ const lp = choice.logprobs;
37424
+ if (typeof lp !== "object" || lp === null)
37425
+ return null;
37426
+ const out2 = {};
37427
+ const add = (token, logprob) => {
37428
+ if (typeof token === "string" && typeof logprob === "number" && Number.isFinite(logprob)) {
37429
+ out2[token] = Math.max(out2[token] ?? Number.NEGATIVE_INFINITY, logprob);
37430
+ }
37431
+ };
37432
+ const legacy = lp.top_logprobs;
37433
+ if (Array.isArray(legacy) && typeof legacy[0] === "object" && legacy[0] !== null && !Array.isArray(legacy[0])) {
37434
+ for (const [token, logprob] of Object.entries(legacy[0]))
37435
+ add(token, logprob);
37436
+ }
37437
+ const content = lp.content;
37438
+ if (Array.isArray(content) && typeof content[0] === "object" && content[0] !== null) {
37439
+ const first = content[0];
37440
+ add(first.token, first.logprob);
37441
+ if (Array.isArray(first.top_logprobs)) {
37442
+ for (const row of first.top_logprobs) {
37443
+ add(row?.token, row?.logprob);
37444
+ }
37445
+ }
37446
+ }
37447
+ const tokens = lp.tokens;
37448
+ const tokenLogprobs = lp.token_logprobs;
37449
+ if (Array.isArray(tokens) && Array.isArray(tokenLogprobs))
37450
+ add(tokens[0], tokenLogprobs[0]);
37451
+ return Object.keys(out2).length > 0 ? out2 : null;
37452
+ }
37453
+ function parseExecutorGateResponse(body2) {
37454
+ const choice = body2?.choices?.[0];
37455
+ if (typeof choice !== "object" || choice === null) {
37456
+ return { ok: false, reason: "unparseable", problem: "the completions response carried no choice" };
37457
+ }
37458
+ const c3 = choice;
37459
+ const message = c3.message;
37460
+ const raw = typeof c3.text === "string" ? c3.text : typeof message?.content === "string" ? message.content : "";
37461
+ const trimmed = raw.trim();
37462
+ if (trimmed.startsWith("<")) {
37463
+ return {
37464
+ ok: false,
37465
+ reason: "thinking",
37466
+ problem: `the executor answered with thinking on (it began "${trimmed.slice(0, 8)}")`
37467
+ };
37468
+ }
37469
+ const letter = executorGateLetterOf(raw);
37470
+ const top = topLogprobs(c3);
37471
+ if (top !== null) {
37472
+ let logE = null;
37473
+ let logP = null;
37474
+ for (const [token, logprob] of Object.entries(top)) {
37475
+ const l3 = executorGateLetterOf(token);
37476
+ if (l3 === "E")
37477
+ logE = Math.max(logE ?? Number.NEGATIVE_INFINITY, logprob);
37478
+ if (l3 === "P")
37479
+ logP = Math.max(logP ?? Number.NEGATIVE_INFINITY, logprob);
37480
+ }
37481
+ if (logE !== null || logP !== null) {
37482
+ return {
37483
+ ok: true,
37484
+ answer: {
37485
+ mode: "logprob",
37486
+ letter,
37487
+ logE: logE ?? exports2.EXECUTOR_GATE_MISSING_LOGPROB,
37488
+ logP: logP ?? exports2.EXECUTOR_GATE_MISSING_LOGPROB,
37489
+ raw
37490
+ }
37491
+ };
37492
+ }
37493
+ }
37494
+ if (letter !== null)
37495
+ return { ok: true, answer: { mode: "greedy", letter, logE: null, logP: null, raw } };
37496
+ return {
37497
+ ok: false,
37498
+ reason: "unparseable",
37499
+ problem: `the executor answered "${trimmed.slice(0, 16)}", not E or P`
37500
+ };
37501
+ }
37502
+ function decideExecutorGate(answer, threshold) {
37503
+ if (answer.mode === "logprob" && answer.logE !== null && answer.logP !== null) {
37504
+ const margin = answer.logP - answer.logE;
37505
+ return { plan: margin >= threshold, margin, pPlan: 1 / (1 + Math.exp(-margin)) };
37506
+ }
37507
+ if (answer.letter === null)
37508
+ return null;
37509
+ return { plan: answer.letter === "P", margin: null, pPlan: answer.letter === "P" ? 1 : 0 };
37510
+ }
37511
+ async function askExecutorGate(target, prompt, opts = {}) {
37512
+ const started = Date.now();
37513
+ const doFetch = opts.fetchImpl ?? fetch;
37514
+ const headers = { "Content-Type": "application/json" };
37515
+ if (target.apiKey)
37516
+ headers.Authorization = `Bearer ${target.apiKey}`;
37517
+ try {
37518
+ const res = await doFetch(`${target.baseUrl.replace(/\/+$/, "")}/completions`, {
37519
+ method: "POST",
37520
+ headers,
37521
+ body: JSON.stringify({
37522
+ model: target.model,
37523
+ prompt,
37524
+ max_tokens: 1,
37525
+ temperature: 0,
37526
+ logprobs: 5,
37527
+ stream: false
37528
+ }),
37529
+ signal: AbortSignal.timeout(opts.timeoutMs ?? exports2.EXECUTOR_GATE_TIMEOUT_MS)
37530
+ });
37531
+ const latencyMs = Date.now() - started;
37532
+ if (res.status === 404 || res.status === 405 || res.status === 501) {
37533
+ return {
37534
+ ok: false,
37535
+ reason: "no_completions",
37536
+ problem: `the executor has no completions route (${res.status})`,
37537
+ latencyMs
37538
+ };
37539
+ }
37540
+ if (!res.ok)
37541
+ return { ok: false, reason: "error", problem: `the executor answered ${res.status}`, latencyMs };
37542
+ const parsed = parseExecutorGateResponse(await res.json());
37543
+ if (!parsed.ok)
37544
+ return { ok: false, reason: parsed.reason, problem: parsed.problem, latencyMs };
37545
+ return { ok: true, answer: parsed.answer, latencyMs };
37546
+ } catch (e) {
37547
+ const timedOut = e instanceof Error && e.name === "TimeoutError";
37548
+ return {
37549
+ ok: false,
37550
+ reason: "error",
37551
+ problem: timedOut ? "the gate call timed out" : `the gate call failed (${e instanceof Error ? e.message : String(e)})`,
37552
+ latencyMs: Date.now() - started
37553
+ };
37554
+ }
37555
+ }
37556
+ exports2.EXECUTOR_GATE_PROBE_SCENARIOS = [
37557
+ { request: "Create this application with auth, billing and audit logging", expect: "P" },
37558
+ { request: "Implement the next endpoint", expect: "E" },
37559
+ { request: "We can no longer use the current authentication architecture", expect: "P" },
37560
+ { request: "continue", expect: "E" }
37561
+ ];
37562
+ function executorGateProbeState(request) {
37563
+ return {
37564
+ planVersion: 3,
37565
+ planValid: true,
37566
+ planHead: "# Plan: orders-service (FastAPI)\n1. Add POST /orders and GET /orders/{id}\n2. Wire the billing call behind a feature flag\n3. Tests for both endpoints",
37567
+ assumptions: [
37568
+ { id: "A1", text: "the service keeps its central authentication middleware" },
37569
+ { id: "A2", text: "billing stays behind the existing Stripe client" }
37570
+ ],
37571
+ planningFailures: 0,
37572
+ executorFailures: 0,
37573
+ scopeChanged: false,
37574
+ architectureDecisionRequired: false,
37575
+ userNegativeFeedback: false,
37576
+ request
37577
+ };
37578
+ }
37579
+ async function probeExecutorGate(target, opts = {}) {
37580
+ const started = Date.now();
37581
+ let mode = null;
37582
+ const failed = [];
37583
+ for (const scenario of exports2.EXECUTOR_GATE_PROBE_SCENARIOS) {
37584
+ const asked = await askExecutorGate(target, renderExecutorGatePrompt(executorGateProbeState(scenario.request)), opts);
37585
+ if (!asked.ok)
37586
+ return { state: "unavailable", reason: asked.reason, problem: asked.problem, name: target.name };
37587
+ mode ??= asked.answer.mode;
37588
+ const decision = decideExecutorGate(asked.answer, target.threshold);
37589
+ if (decision === null || (decision.plan ? "P" : "E") !== scenario.expect)
37590
+ failed.push(scenario.request);
37591
+ }
37592
+ const calibration = {
37593
+ passed: exports2.EXECUTOR_GATE_PROBE_SCENARIOS.length - failed.length,
37594
+ total: exports2.EXECUTOR_GATE_PROBE_SCENARIOS.length,
37595
+ failed
37596
+ };
37597
+ const common = {
37598
+ target: { name: target.name, model: target.model },
37599
+ mode: mode ?? "greedy",
37600
+ threshold: target.threshold,
37601
+ calibration,
37602
+ latencyMs: Date.now() - started
37603
+ };
37604
+ return calibration.passed >= exports2.EXECUTOR_GATE_MIN_CALIBRATION ? { state: "ready", ...common } : { state: "miscalibrated", ...common };
37605
+ }
37606
+ async function describeDuetExecutorGate(opts = {}) {
37607
+ const resolved = await resolveExecutorGateTargetFromSettings(opts);
37608
+ if (resolved.state !== "ready")
37609
+ return resolved;
37610
+ return probeExecutorGate(resolved.target, { fetchImpl: opts.fetchImpl, timeoutMs: opts.timeoutMs });
37611
+ }
37612
+ var describeCache = /* @__PURE__ */ new Map();
37613
+ function clearDuetExecutorGateCache() {
37614
+ describeCache.clear();
37615
+ }
37616
+ async function describeDuetExecutorGateCached2(opts = {}) {
37617
+ const now2 = opts.now ?? Date.now;
37618
+ const key = `${opts.homeDir ?? os9.homedir()}\0${opts.workspaceRoot ?? ""}`;
37619
+ const hit = describeCache.get(key);
37620
+ if (!opts.refresh && hit !== void 0 && now2() - hit.at < (opts.ttlMs ?? exports2.EXECUTOR_GATE_STATUS_TTL_MS)) {
37621
+ return hit.status;
37622
+ }
37623
+ const status = await describeDuetExecutorGate(opts);
37624
+ describeCache.set(key, { at: now2(), status });
37625
+ return status;
37626
+ }
37627
+ function createDuetExecutorGate2(opts = {}) {
37628
+ const now2 = opts.now ?? Date.now;
37629
+ const ttl = opts.statusTtlMs ?? exports2.EXECUTOR_GATE_STATUS_TTL_MS;
37630
+ let cached = null;
37631
+ let noted = false;
37632
+ const downgrade = (why) => {
37633
+ const note = noted ? null : (0, duetExecutorGateStatus_js_1.executorGateDowngradeNote)(why);
37634
+ noted = true;
37635
+ return { ...(0, duetEntry_js_1.effectiveDuetEntry)("executor", void 0, "unavailable"), verdict: null, note };
37636
+ };
37637
+ return {
37638
+ async status(o = {}) {
37639
+ const resolved = await resolveExecutorGateTargetFromSettings({
37640
+ workspaceRoot: o.workspaceRoot,
37641
+ ...opts.homeDir ? { homeDir: opts.homeDir } : {},
37642
+ fetchImpl: opts.fetchImpl
37643
+ });
37644
+ if (resolved.state !== "ready")
37645
+ return resolved;
37646
+ const key = `${resolved.target.baseUrl} ${resolved.target.model} ${resolved.target.threshold}`;
37647
+ if (!o.refresh && cached !== null && cached.key === key && now2() - cached.at < ttl)
37648
+ return cached.status;
37649
+ const status = await probeExecutorGate(resolved.target, { fetchImpl: opts.fetchImpl, timeoutMs: opts.timeoutMs });
37650
+ cached = { at: now2(), key, status };
37651
+ return status;
37652
+ },
37653
+ async prepareTurn(text, ctx) {
37654
+ if (text.trim() === "")
37655
+ return { entry: "executor", verdict: null, note: null };
37656
+ const resolved = resolveExecutorGateTarget(ctx.workspaceRoot, opts.resolveDeps);
37657
+ if (resolved.state !== "ready") {
37658
+ opts.onError?.("resolve", resolved.state === "platform" ? "platform executor" : resolved.problem);
37659
+ return downgrade(resolved);
37660
+ }
37661
+ const { target } = resolved;
37662
+ const prompt = renderExecutorGatePrompt(executorGateStateFrom(ctx.record, text));
37663
+ const asked = await askExecutorGate(target, prompt, { fetchImpl: opts.fetchImpl, timeoutMs: opts.timeoutMs });
37664
+ if (!asked.ok) {
37665
+ opts.onError?.("ask", asked.problem);
37666
+ return downgrade({ state: "unavailable", reason: asked.reason, problem: asked.problem });
37667
+ }
37668
+ const decision = decideExecutorGate(asked.answer, target.threshold);
37669
+ if (decision === null) {
37670
+ const said = asked.answer.raw.trim();
37671
+ opts.onError?.("ask", `undecidable answer "${said}"`);
37672
+ return downgrade({ state: "unavailable", reason: "unparseable", problem: `the executor answered "${said}"` });
37673
+ }
37674
+ noted = false;
37675
+ const verdict = {
37676
+ source: exports2.EXECUTOR_GATE_SOURCE,
37677
+ verdict: decision.plan ? "plan" : "execute",
37678
+ pPlan: decision.pPlan,
37679
+ asksForPlan: false,
37680
+ highRisk: false,
37681
+ reason: exports2.EXECUTOR_GATE_SOURCE,
37682
+ model: target.model,
37683
+ version: exports2.EXECUTOR_GATE_PROMPT_VERSION,
37684
+ latencyMs: asked.latencyMs,
37685
+ mode: asked.answer.mode,
37686
+ ...decision.margin !== null ? { margin: decision.margin } : {}
37687
+ };
37688
+ return { entry: "executor", verdict, note: null };
37689
+ },
37690
+ invalidate() {
37691
+ cached = null;
37692
+ noted = false;
37693
+ }
37694
+ };
37695
+ }
37696
+ }
37697
+ });
37698
+
37699
+ // ../packages/orion-client-core/dist/runs/common.js
37700
+ var require_common = __commonJS({
37701
+ "../packages/orion-client-core/dist/runs/common.js"(exports2) {
37702
+ "use strict";
37703
+ Object.defineProperty(exports2, "__esModule", { value: true });
37704
+ exports2.mintRunId = mintRunId;
37705
+ exports2.runsRootFor = runsRootFor2;
37706
+ exports2.readJsonFile = readJsonFile;
37707
+ exports2.writeJsonFile = writeJsonFile;
37708
+ exports2.ensureDirFor = ensureDirFor;
37709
+ exports2.listDirNames = listDirNames;
37710
+ exports2.dayKey = dayKey;
37711
+ exports2.clipTail = clipTail;
37712
+ var fs_1 = __require("fs");
37713
+ var os_1 = __require("os");
37714
+ var path_1 = __require("path");
37715
+ var atomicWrite_js_1 = require_atomicWrite();
37716
+ var experienceStore_js_1 = require_experienceStore();
37717
+ var ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
37718
+ var ID_SUFFIX_LEN = 6;
37719
+ function mintRunId(prefix, nowMs = Date.now(), rand = Math.random) {
37720
+ let suffix = "";
37721
+ for (let i2 = 0; i2 < ID_SUFFIX_LEN; i2 += 1) {
37722
+ suffix += ID_ALPHABET[Math.floor(rand() * ID_ALPHABET.length) % ID_ALPHABET.length];
37723
+ }
37724
+ return `${prefix}_${String(nowMs).padStart(13, "0")}_${suffix}`;
37725
+ }
37726
+ function runsRootFor2(kind, workspaceRoot, home = (0, os_1.homedir)()) {
37727
+ return (0, path_1.join)((0, experienceStore_js_1.projectDirFor)(workspaceRoot, home), "runs", kind);
37728
+ }
37729
+ async function readJsonFile(path14) {
37730
+ try {
37731
+ const raw = await fs_1.promises.readFile(path14, "utf8");
37732
+ return JSON.parse(raw);
37733
+ } catch {
37734
+ return null;
37735
+ }
37736
+ }
37737
+ async function writeJsonFile(path14, value) {
37738
+ await ensureDirFor(path14);
37739
+ await (0, atomicWrite_js_1.atomicWriteFile)(path14, JSON.stringify(value, null, 2));
37740
+ }
37741
+ async function ensureDirFor(path14) {
37742
+ await fs_1.promises.mkdir((0, path_1.dirname)(path14), { recursive: true });
37743
+ }
37744
+ async function listDirNames(path14) {
37745
+ try {
37746
+ return await fs_1.promises.readdir(path14);
37747
+ } catch {
37748
+ return [];
37749
+ }
37750
+ }
37751
+ function dayKey(nowMs = Date.now()) {
37752
+ const d2 = new Date(nowMs);
37753
+ const month = `${d2.getMonth() + 1}`.padStart(2, "0");
37754
+ const day = `${d2.getDate()}`.padStart(2, "0");
37755
+ return `${d2.getFullYear()}-${month}-${day}`;
37756
+ }
37757
+ function clipTail(text, max) {
37758
+ if (text.length <= max)
37759
+ return text;
37760
+ return `\u2026${text.slice(text.length - (max - 1))}`;
37761
+ }
37762
+ }
37763
+ });
37764
+
37765
+ // ../packages/orion-client-core/dist/customProviderModels.js
37766
+ var require_customProviderModels = __commonJS({
37767
+ "../packages/orion-client-core/dist/customProviderModels.js"(exports2) {
37768
+ "use strict";
37769
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m2, k, k2) {
37770
+ if (k2 === void 0) k2 = k;
37771
+ var desc = Object.getOwnPropertyDescriptor(m2, k);
37772
+ if (!desc || ("get" in desc ? !m2.__esModule : desc.writable || desc.configurable)) {
37773
+ desc = { enumerable: true, get: function() {
37774
+ return m2[k];
37775
+ } };
37776
+ }
37777
+ Object.defineProperty(o, k2, desc);
37778
+ } : function(o, m2, k, k2) {
37779
+ if (k2 === void 0) k2 = k;
37780
+ o[k2] = m2[k];
37781
+ });
37782
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v2) {
37783
+ Object.defineProperty(o, "default", { enumerable: true, value: v2 });
37784
+ } : function(o, v2) {
37785
+ o["default"] = v2;
37786
+ });
37787
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
37788
+ var ownKeys = function(o) {
37789
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
37790
+ var ar = [];
37791
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
37792
+ return ar;
37793
+ };
37794
+ return ownKeys(o);
37795
+ };
37796
+ return function(mod2) {
37797
+ if (mod2 && mod2.__esModule) return mod2;
37798
+ var result = {};
37799
+ if (mod2 != null) {
37800
+ for (var k = ownKeys(mod2), i2 = 0; i2 < k.length; i2++) if (k[i2] !== "default") __createBinding(result, mod2, k[i2]);
37801
+ }
37802
+ __setModuleDefault(result, mod2);
37803
+ return result;
37804
+ };
37805
+ }();
37806
+ Object.defineProperty(exports2, "__esModule", { value: true });
37807
+ exports2.CATALOG_GC_MS = exports2.CATALOG_TTL_MS = exports2.CATALOG_SCHEMA_VERSION = void 0;
37808
+ exports2.catalogPathFor = catalogPathFor;
37809
+ exports2.endpointCatalog = endpointCatalog2;
37810
+ exports2.findProbedModel = findProbedModel;
37811
+ exports2.resolveModelSettings = resolveModelSettings2;
37812
+ exports2.catalogModelIds = catalogModelIds2;
37813
+ exports2.clearEndpointCatalog = clearEndpointCatalog3;
37814
+ exports2.endpointModelViews = endpointModelViews2;
37815
+ exports2.updateCustomProviderModels = updateCustomProviderModels2;
37816
+ var node_crypto_1 = __require("node:crypto");
37817
+ var os9 = __importStar(__require("node:os"));
37818
+ var path14 = __importStar(__require("node:path"));
37819
+ var customProviders_1 = require_customProviders();
37820
+ var common_1 = require_common();
37821
+ exports2.CATALOG_SCHEMA_VERSION = 1;
37822
+ exports2.CATALOG_TTL_MS = 9e5;
37823
+ exports2.CATALOG_GC_MS = 45 * 24 * 60 * 60 * 1e3;
37824
+ function catalogPathFor(baseUrl, homeDir = os9.homedir()) {
37825
+ const digest = (0, node_crypto_1.createHash)("sha256").update(normalizeBaseUrl(baseUrl)).digest("hex").slice(0, 16);
37826
+ return path14.join(homeDir, ".orion", "cache", "models", `${digest}.json`);
37827
+ }
37828
+ function normalizeBaseUrl(baseUrl) {
37829
+ return baseUrl.trim().replace(/\/+$/, "");
37830
+ }
37831
+ async function readRecordFromDisk(baseUrl) {
37832
+ const record = await (0, common_1.readJsonFile)(catalogPathFor(baseUrl));
37833
+ if (record === null)
37834
+ return null;
37835
+ if (record.version !== exports2.CATALOG_SCHEMA_VERSION)
37836
+ return null;
37837
+ if (normalizeBaseUrl(record.baseUrl ?? "") !== normalizeBaseUrl(baseUrl))
37838
+ return null;
37839
+ if (!Array.isArray(record.models))
37840
+ return null;
37841
+ return record;
37842
+ }
37843
+ var sweptThisProcess = false;
37844
+ async function gcEndpointCatalogs(now2, homeDir = os9.homedir()) {
37845
+ if (sweptThisProcess)
37846
+ return;
37847
+ sweptThisProcess = true;
37848
+ try {
37849
+ const dir = path14.dirname(catalogPathFor("x", homeDir));
37850
+ const fs15 = await Promise.resolve().then(() => __importStar(__require("node:fs/promises")));
37851
+ for (const name2 of await fs15.readdir(dir)) {
37852
+ if (!name2.endsWith(".json"))
37853
+ continue;
37854
+ const file = path14.join(dir, name2);
37855
+ try {
37856
+ const record = await (0, common_1.readJsonFile)(file);
37857
+ const age = typeof record?.fetchedAt === "number" ? now2 - record.fetchedAt : now2 - (await fs15.stat(file)).mtimeMs;
37858
+ if (age > exports2.CATALOG_GC_MS)
37859
+ await fs15.rm(file, { force: true });
37860
+ } catch {
37861
+ }
37862
+ }
37863
+ } catch {
37864
+ }
37865
+ }
37866
+ async function writeRecordToDisk(record) {
37867
+ try {
37868
+ await (0, common_1.writeJsonFile)(catalogPathFor(record.baseUrl), record);
37869
+ } catch {
37870
+ }
37871
+ void gcEndpointCatalogs(record.fetchedAt);
37872
+ }
37873
+ var memory = /* @__PURE__ */ new Map();
37874
+ var inFlight2 = /* @__PURE__ */ new Map();
37875
+ function depsWith(deps2) {
37876
+ return {
37877
+ now: deps2.now ?? (() => Date.now()),
37878
+ probe: deps2.probe ?? customProviders_1.probeModels,
37879
+ readRecord: deps2.readRecord ?? readRecordFromDisk,
37880
+ writeRecord: deps2.writeRecord ?? writeRecordToDisk
37881
+ };
37882
+ }
37883
+ async function probeAndStore(entry, d2) {
37884
+ const key = normalizeBaseUrl(entry.baseUrl);
37885
+ const existing = inFlight2.get(key);
37886
+ if (existing !== void 0)
37887
+ return existing;
37888
+ const run3 = (async () => {
37889
+ const models = await d2.probe(entry.baseUrl, await (0, customProviders_1.resolveApiKey)(entry));
37890
+ if (models === null || models.length === 0)
37891
+ return models;
37892
+ const record = {
37893
+ version: exports2.CATALOG_SCHEMA_VERSION,
37894
+ baseUrl: entry.baseUrl,
37895
+ fetchedAt: d2.now(),
37896
+ models
37897
+ };
37898
+ memory.set(key, record);
37899
+ await d2.writeRecord(record);
37900
+ return models;
37901
+ })().finally(() => inFlight2.delete(key));
37902
+ inFlight2.set(key, run3);
37903
+ return run3;
37904
+ }
37905
+ async function endpointCatalog2(entry, options = {}) {
37906
+ const d2 = depsWith(options);
37907
+ const key = normalizeBaseUrl(entry.baseUrl);
37908
+ let record = memory.get(key) ?? null;
37184
37909
  if (record === null) {
37185
- if ((0, duetPlan_js_1.highRiskRequest)(text))
37186
- return { verdict: "plan", reason: "plan_invalid" };
37187
- return entry === "planner" ? { verdict: "plan", reason: "planner_entry" } : { verdict: "execute", reason: "no_plan" };
37188
- }
37189
- if (record.scopeChanged)
37190
- return { verdict: "plan", reason: "scope_changed" };
37191
- if (record.architectureDecisionRequired) {
37192
- return { verdict: "plan", reason: "architecture_decision_required" };
37910
+ record = await d2.readRecord(entry.baseUrl);
37911
+ if (record !== null)
37912
+ memory.set(key, record);
37193
37913
  }
37194
- if (record.planningFailures >= 2)
37195
- return { verdict: "plan", reason: "failed_attempts" };
37196
- if (record.userNegativeFeedback)
37197
- return { verdict: "plan", reason: "negative_feedback" };
37198
- if (entry === "planner") {
37199
- return (0, duetPlan_js_1.continuationRequest)(text) ? { verdict: "execute", reason: "continuation" } : { verdict: "plan", reason: "planner_entry" };
37914
+ if (options.cachedOnly === true)
37915
+ return record?.models ?? [];
37916
+ const fresh = record !== null && d2.now() - record.fetchedAt < exports2.CATALOG_TTL_MS;
37917
+ if (record !== null && fresh && options.force !== true)
37918
+ return record.models;
37919
+ if (record !== null) {
37920
+ void probeAndStore(entry, d2).catch(() => void 0);
37921
+ return record.models;
37200
37922
  }
37201
- return { verdict: "execute", reason: "plan_valid" };
37923
+ return await probeAndStore(entry, d2) ?? [];
37202
37924
  }
37203
- function executorContext(workspaceRoot) {
37204
- const choice = (0, duetMode_js_1.duetExecutorWireForSegment)(workspaceRoot);
37205
- const local = choice !== void 0 && (0, customProviders_js_1.isCustomProviderRef)(choice.provider);
37206
- const models = local ? (0, customProviders_js_1.endpointRoutingFor)(choice.provider)?.routingModels : void 0;
37207
- return {
37208
- executor: local ? "local" : "platform",
37209
- routingModels: {
37210
- embeddings: models?.embeddings !== void 0,
37211
- rerank: models?.rerank !== void 0,
37212
- judge: models?.judge !== void 0
37213
- }
37214
- };
37925
+ function findProbedModel(models, id) {
37926
+ return models.find((model) => model.id === id);
37215
37927
  }
37216
- function followupRow(last, standing, text, at) {
37217
- const versionChanged = standing !== null && standing.version !== last.planVersion;
37218
- return {
37219
- kind: "followup",
37220
- v: duetRoutingLog_js_1.DUET_ROUTING_LOG_SCHEMA,
37221
- decisionId: last.decisionId,
37222
- at,
37223
- planVersionChanged: versionChanged,
37224
- newPlanVersion: versionChanged ? standing.version : null,
37225
- planDiffRatio: versionChanged && last.planText !== null ? (0, duetRoutingLog_js_1.planDiffRatio)(last.planText, standing.plan) : null,
37226
- replanActor: standing !== null && standing.scopeChanged && !last.scopeChanged,
37227
- nextPromptSimilarity: text === "" ? null : (0, duetRoutingLog_js_1.lexicalSimilarity)(last.prompt, text),
37228
- nextExplicitPlanRequest: text !== "" && (0, duetPlan_js_1.explicitPlanRequest)(text),
37229
- planningFailuresDelta: standing === null ? 0 : standing.planningFailures - last.planningFailures,
37230
- executorFailuresDelta: standing === null ? 0 : standing.executorFailures - last.executorFailures,
37231
- planGone: last.planVersion > 0 && standing === null
37232
- };
37928
+ function resolveModelSettings2(entry, modelId, catalog = []) {
37929
+ const declared = entry.modelConfig?.[modelId];
37930
+ const probed = findProbedModel(catalog, modelId);
37931
+ const resolved = {};
37932
+ const contextWindow = declared?.contextWindow ?? probed?.contextWindow;
37933
+ if (contextWindow !== void 0)
37934
+ resolved.contextWindow = contextWindow;
37935
+ const maxOutputTokens = declared?.maxOutputTokens ?? probed?.maxOutputTokens;
37936
+ if (maxOutputTokens !== void 0)
37937
+ resolved.maxOutputTokens = maxOutputTokens;
37938
+ if (probed?.reasoning !== void 0)
37939
+ resolved.reasoning = probed.reasoning;
37940
+ for (const knob of ["temperature", "topP", "topK", "repetitionPenalty"]) {
37941
+ const value = declared?.[knob];
37942
+ if (typeof value === "number")
37943
+ resolved[knob] = value;
37944
+ }
37945
+ return resolved;
37233
37946
  }
37234
- function journalDuetTurnEnd2(state, end, opts = {}) {
37235
- const last = state.last;
37236
- if (last === null)
37237
- return;
37238
- emit(sinkFor(opts.log, opts.homeDir, opts.workspaceRoot), {
37239
- kind: "turn_end",
37240
- v: duetRoutingLog_js_1.DUET_ROUTING_LOG_SCHEMA,
37241
- decisionId: last.decisionId,
37242
- at: (/* @__PURE__ */ new Date()).toISOString(),
37243
- outcome: end.outcome,
37244
- executionLeg: end.executionLeg
37245
- });
37947
+ function catalogModelIds2(entry, catalog) {
37948
+ return entry.models?.length ? entry.models : catalog.map((model) => model.id);
37246
37949
  }
37247
- function journalDuetPlannerVerdict2(state, verdict, opts = {}) {
37248
- const last = state.last;
37249
- if (last === null)
37950
+ function clearEndpointCatalog3(baseUrl) {
37951
+ if (baseUrl === void 0) {
37952
+ memory.clear();
37953
+ inFlight2.clear();
37954
+ sweptThisProcess = false;
37250
37955
  return;
37251
- emit(sinkFor(opts.log, opts.homeDir, opts.workspaceRoot), {
37252
- kind: "planner",
37253
- v: duetRoutingLog_js_1.DUET_ROUTING_LOG_SCHEMA,
37254
- decisionId: last.decisionId,
37255
- at: (/* @__PURE__ */ new Date()).toISOString(),
37256
- verdict: verdict.verdict,
37257
- ...verdict.verdict === "hand_off" ? { brief: verdict.brief } : {}
37258
- });
37956
+ }
37957
+ const key = normalizeBaseUrl(baseUrl);
37958
+ memory.delete(key);
37959
+ inFlight2.delete(key);
37259
37960
  }
37260
- async function adviseDuetRoute2(input) {
37261
- const { state } = input;
37262
- const now2 = input.now ?? Date.now;
37263
- const started = now2();
37264
- const at = new Date(started).toISOString();
37265
- const record = input.record ?? null;
37266
- const entry = input.entry ?? "router";
37267
- const routerVerdict = input.routerVerdict ? {
37268
- model: input.routerVerdict.model,
37269
- version: input.routerVerdict.version,
37270
- verdict: input.routerVerdict.verdict,
37271
- pPlan: Math.round(input.routerVerdict.pPlan * 1e6) / 1e6,
37272
- asksForPlan: input.routerVerdict.asksForPlan,
37273
- highRisk: input.routerVerdict.highRisk,
37274
- reason: input.routerVerdict.reason,
37275
- latencyMs: input.routerVerdict.latencyMs
37276
- } : null;
37277
- const sink = sinkFor(input.log, input.homeDir, input.workspaceRoot);
37278
- try {
37279
- const text = input.text.trim();
37280
- const standing = (0, duetPlan_js_1.duetPlanWireForSegment)(record) !== void 0 ? record : null;
37281
- if (state.last !== null) {
37282
- emit(sink, followupRow(state.last, standing, text, at));
37283
- state.last = null;
37284
- }
37285
- const journal = (stage12, advisor, route, assumptions2) => {
37286
- const id = (0, duetRoutingLog_js_1.newDecisionId)();
37287
- const session = (0, duetRoutingLog_js_1.sessionKey)(input.sessionId);
37288
- emit(sink, {
37289
- kind: "decision",
37290
- v: duetRoutingLog_js_1.DUET_ROUTING_LOG_SCHEMA,
37291
- id,
37292
- at,
37293
- ...session !== void 0 ? { session } : {},
37294
- entry,
37295
- planVersion: standing?.version ?? 0,
37296
- turnUnderVersion: state.turnsUnderVersion,
37297
- prompt: text,
37298
- assumptions: assumptions2,
37299
- ...executorContext(input.workspaceRoot),
37300
- stage1: stage12,
37301
- router: routerVerdict,
37302
- advisor: advisor === null ? null : {
37303
- stage: advisor.stage,
37304
- signals: advisor.signals,
37305
- guards: advisor.guards,
37306
- flagged: advisor.flagged,
37307
- reason: advisor.reason
37308
- },
37309
- route,
37310
- latencyMs: Math.max(0, now2() - started)
37311
- });
37312
- state.last = {
37313
- decisionId: id,
37314
- prompt: text,
37315
- route,
37316
- planVersion: standing?.version ?? 0,
37317
- planText: standing?.plan ?? null,
37318
- scopeChanged: standing?.scopeChanged ?? false,
37319
- planningFailures: standing?.planningFailures ?? 0,
37320
- executorFailures: standing?.executorFailures ?? 0
37321
- };
37322
- };
37323
- if (standing === null) {
37324
- resetForVersion(state, null);
37325
- if (text !== "") {
37326
- const stage12 = stage1Verdict(null, text, entry);
37327
- journal(stage12, null, stage12.verdict, []);
37328
- }
37329
- return untouched(record);
37330
- }
37331
- const plan = standing;
37332
- if (state.planVersion !== plan.version)
37333
- resetForVersion(state, plan.version);
37334
- state.turnsUnderVersion += 1;
37335
- if (text === "")
37336
- return untouched(record);
37337
- const assumptions = parsePlanAssumptions(plan.plan);
37338
- const stage1 = stage1Verdict(plan, text, entry);
37339
- if (stage1.verdict === "plan") {
37340
- journal(stage1, null, "plan", assumptions);
37341
- return untouched(record);
37342
- }
37343
- if (entry === "planner") {
37344
- journal(stage1, null, "execute", assumptions);
37345
- return untouched(record);
37346
- }
37347
- const decision = {
37348
- at,
37349
- planVersion: plan.version,
37350
- turnUnderVersion: state.turnsUnderVersion,
37351
- text: text.length > DECISION_TEXT_HEAD ? `${text.slice(0, DECISION_TEXT_HEAD - 1)}\u2026` : text,
37352
- stage: "cues",
37353
- signals: {},
37354
- guards: {},
37355
- flagged: null,
37356
- reason: null,
37357
- latencyMs: 0
37358
- };
37359
- let candidate = null;
37360
- const feedbackCue = negativeFeedbackCueIn(text);
37361
- const negationCue = negationCueIn(text);
37362
- if (feedbackCue !== null)
37363
- decision.signals.feedbackCue = feedbackCue;
37364
- if (negationCue !== null)
37365
- decision.signals.negationCue = negationCue;
37366
- if (feedbackCue !== null) {
37367
- candidate = { flag: "user_negative_feedback", reason: "negative_feedback_cue", ids: [] };
37368
- }
37369
- if (candidate === null) {
37370
- const endpoint = await advisorEndpoint(input.workspaceRoot);
37371
- const models = endpoint?.routing.routingModels;
37372
- if (endpoint !== null && models !== void 0) {
37373
- candidate = await semanticStages({
37374
- plan,
37375
- assumptions,
37376
- text,
37377
- negationCue,
37378
- dial: { baseUrl: endpoint.routing.baseUrl, apiKey: endpoint.routing.apiKey },
37379
- models,
37380
- executorModel: endpoint.executorModel,
37381
- state,
37382
- decision,
37383
- fetchImpl: input.fetchImpl
37384
- }, now2);
37385
- }
37386
- }
37387
- if (candidate !== null && state.turnsUnderVersion < exports2.DUET_ADVISOR_THRESHOLDS.cooldownTurns) {
37388
- decision.guards.cooldown = true;
37389
- candidate = null;
37390
- }
37391
- let advised = plan;
37392
- if (candidate !== null) {
37393
- advised = candidate.flag === "user_negative_feedback" ? { ...plan, userNegativeFeedback: true } : { ...plan, architectureDecisionRequired: true };
37394
- decision.flagged = candidate.flag;
37395
- decision.reason = candidate.reason;
37961
+ async function endpointModelViews2(entry, options = {}) {
37962
+ const catalog = await endpointCatalog2(entry, options);
37963
+ const pinned = new Set(entry.models ?? []);
37964
+ const ids = [...pinned, ...catalog.map((model) => model.id).filter((id) => !pinned.has(id))];
37965
+ return ids.map((id) => {
37966
+ const resolved = resolveModelSettings2(entry, id, catalog);
37967
+ const declared = entry.modelConfig?.[id];
37968
+ const view = { id, pinned: pinned.has(id) };
37969
+ if (resolved.contextWindow !== void 0)
37970
+ view.contextWindow = resolved.contextWindow;
37971
+ if (resolved.maxOutputTokens !== void 0)
37972
+ view.maxOutputTokens = resolved.maxOutputTokens;
37973
+ if (resolved.reasoning !== void 0)
37974
+ view.reasoning = resolved.reasoning;
37975
+ if (declared?.contextWindow !== void 0 || declared?.maxOutputTokens !== void 0) {
37976
+ view.source = "user";
37977
+ } else if (view.contextWindow !== void 0 || view.maxOutputTokens !== void 0) {
37978
+ view.source = "endpoint";
37396
37979
  }
37397
- decision.latencyMs = Math.max(0, now2() - started);
37398
- journal(stage1, decision, decision.flagged !== null ? "plan" : "execute", assumptions);
37399
- return {
37400
- record: advised,
37401
- flagged: decision.flagged,
37402
- reason: decision.reason,
37403
- assumptionIds: candidate?.ids ?? [],
37404
- decision,
37405
- note: duetRoutingAdviceNote(decision.reason, candidate?.ids ?? [])
37406
- };
37407
- } catch {
37408
- return untouched(record);
37409
- }
37980
+ return view;
37981
+ });
37410
37982
  }
37411
- function round3(value) {
37412
- return Math.round(value * 1e3) / 1e3;
37983
+ async function updateCustomProviderModels2(name2, update, tier = "user", opts = {}) {
37984
+ const entry = await (0, customProviders_1.getCustomProvider)(name2, opts);
37985
+ if (entry === null)
37986
+ return false;
37987
+ const next = { ...entry };
37988
+ if (update.models !== void 0) {
37989
+ if (update.models.length)
37990
+ next.models = update.models;
37991
+ else
37992
+ delete next.models;
37993
+ }
37994
+ if (update.modelConfig !== void 0) {
37995
+ const kept = Object.entries(update.modelConfig).map(([id, raw]) => [id, (0, customProviders_1.normalizeModelConfig)(raw)]).filter(([, value]) => value !== void 0 && Object.keys(value).length > 0);
37996
+ if (kept.length)
37997
+ next.modelConfig = Object.fromEntries(kept);
37998
+ else
37999
+ delete next.modelConfig;
38000
+ }
38001
+ await (0, customProviders_1.saveCustomProvider)(next, tier, opts);
38002
+ clearEndpointCatalog3(entry.baseUrl);
38003
+ return true;
37413
38004
  }
37414
- async function describeDuetRouting2(workspaceRoot) {
38005
+ }
38006
+ });
38007
+
38008
+ // ../packages/orion-client-core/dist/duetExecutorCatalog.js
38009
+ var require_duetExecutorCatalog = __commonJS({
38010
+ "../packages/orion-client-core/dist/duetExecutorCatalog.js"(exports2) {
38011
+ "use strict";
38012
+ Object.defineProperty(exports2, "__esModule", { value: true });
38013
+ exports2.LOCAL_EXECUTOR_READ_BUDGET_MS = void 0;
38014
+ exports2.localExecutorOptions = localExecutorOptions2;
38015
+ exports2.duetExecutorChoiceFor = duetExecutorChoiceFor2;
38016
+ exports2.isLocalExecutorChoice = isLocalExecutorChoice;
38017
+ exports2.resolveDuetExecutorChoice = resolveDuetExecutorChoice2;
38018
+ var customProviders_js_1 = require_customProviders();
38019
+ var customProviderModels_js_1 = require_customProviderModels();
38020
+ exports2.LOCAL_EXECUTOR_READ_BUDGET_MS = 3e3;
38021
+ async function localExecutorOptions2(input = {}) {
38022
+ const { catalog, timeoutMs, ...opts } = input;
38023
+ let entries;
37415
38024
  try {
37416
- const choice = await (0, duetMode_js_1.loadDuetExecutor)({ workspaceRoot: workspaceRoot ?? null });
37417
- if (choice === null || !(0, customProviders_js_1.isCustomProviderRef)(choice.provider))
37418
- return { kind: "platform" };
37419
- const name2 = (0, customProviders_js_1.parseCustomProviderRef)(choice.provider) ?? "";
37420
- const entry = await (0, customProviders_js_1.getCustomProvider)(name2, { workspaceRoot: workspaceRoot ?? null });
37421
- if (entry === null)
37422
- return { kind: "missing", name: name2 };
37423
- return {
37424
- kind: "local",
37425
- name: name2,
37426
- loopback: (0, customProviders_js_1.isLoopbackEndpoint)(entry.baseUrl),
37427
- embeddings: entry.routingModels?.embeddings !== void 0,
37428
- rerank: entry.routingModels?.rerank !== void 0,
37429
- judge: entry.routingModels?.judge ?? null
37430
- };
38025
+ entries = await (0, customProviders_js_1.loadCustomProviders)(opts);
37431
38026
  } catch {
37432
- return { kind: "platform" };
38027
+ return [];
37433
38028
  }
37434
- }
37435
- function duetRoutingSummaryLine2(summary) {
37436
- switch (summary.kind) {
37437
- case "platform":
37438
- return "Duet routing: rules only \u2014 a local executor with routing models unlocks re-ask detection and plan-assumption checks.";
37439
- case "missing":
37440
- return "Duet routing: rules only.";
37441
- case "local": {
37442
- const { name: name2, loopback, embeddings, rerank } = summary;
37443
- if (!embeddings && !rerank) {
37444
- return `Duet routing: rules only \u2014 add routingModels to '${name2}' to unlock re-ask detection and plan-assumption checks (the /local-ai skill can set this up).`;
37445
- }
37446
- if (!loopback) {
37447
- return `Duet routing: rules only \u2014 semantic checks run only against a loopback endpoint, and '${name2}' is not one.`;
37448
- }
37449
- const parts2 = [];
37450
- const via = [];
37451
- if (embeddings) {
37452
- parts2.push("re-ask detection");
37453
- via.push("embeddings");
37454
- }
37455
- if (rerank) {
37456
- parts2.push("plan-assumption checks");
37457
- via.push("rerank");
37458
- }
37459
- return `Duet routing: rules + ${parts2.join(" + ")} (${via.join(" + ")} on '${name2}').`;
38029
+ if (entries.length === 0)
38030
+ return [];
38031
+ const read = (options) => Promise.all(entries.map(async (entry) => {
38032
+ try {
38033
+ const views = await (0, customProviderModels_js_1.endpointModelViews)(entry, options);
38034
+ return views.map((view) => {
38035
+ const option = {
38036
+ provider: `custom:${entry.name}`,
38037
+ endpoint: entry.name,
38038
+ model: view.id,
38039
+ pinned: view.pinned
38040
+ };
38041
+ if (view.contextWindow !== void 0)
38042
+ option.contextWindow = view.contextWindow;
38043
+ if (view.maxOutputTokens !== void 0)
38044
+ option.maxOutputTokens = view.maxOutputTokens;
38045
+ return option;
38046
+ });
38047
+ } catch {
38048
+ return [];
37460
38049
  }
38050
+ })).then((perEndpoint) => perEndpoint.flat());
38051
+ const full = read(catalog ?? {});
38052
+ const budget = timeoutMs ?? exports2.LOCAL_EXECUTOR_READ_BUDGET_MS;
38053
+ if (catalog?.cachedOnly === true || budget <= 0)
38054
+ return full;
38055
+ let timer;
38056
+ const fallback = new Promise((resolve5) => {
38057
+ timer = setTimeout(() => resolve5(read({ ...catalog, cachedOnly: true })), budget);
38058
+ });
38059
+ try {
38060
+ return await Promise.race([full, fallback]);
38061
+ } finally {
38062
+ if (timer !== void 0)
38063
+ clearTimeout(timer);
38064
+ void full.catch(() => void 0);
37461
38065
  }
37462
38066
  }
38067
+ function duetExecutorChoiceFor2(option) {
38068
+ return {
38069
+ provider: option.provider,
38070
+ model: option.model,
38071
+ ...option.contextWindow !== void 0 ? { contextWindow: option.contextWindow } : {}
38072
+ };
38073
+ }
38074
+ function isLocalExecutorChoice(choice) {
38075
+ return typeof choice?.provider === "string" && choice.provider.startsWith("custom:");
38076
+ }
38077
+ async function resolveDuetExecutorChoice2(choice, input = {}) {
38078
+ if (!isLocalExecutorChoice(choice) || choice.contextWindow !== void 0)
38079
+ return choice;
38080
+ const found = (await localExecutorOptions2(input)).find((option) => option.provider === choice.provider && option.model === choice.model);
38081
+ return found === void 0 ? choice : { ...choice, ...duetExecutorChoiceFor2(found), ...choice.effort ? { effort: choice.effort } : {} };
38082
+ }
37463
38083
  }
37464
38084
  });
37465
38085
 
@@ -48283,9 +48903,9 @@ var require_toolText = __commonJS({
48283
48903
  const ambiguous = content.indexOf(needle, index + 1) >= 0;
48284
48904
  return { matchStr: needle, index, ambiguous };
48285
48905
  };
48286
- const literal = tryOne(oldStr);
48287
- if (literal)
48288
- return literal;
48906
+ const literal2 = tryOne(oldStr);
48907
+ if (literal2)
48908
+ return literal2;
48289
48909
  const stripped = stripLineNumberPrefixes(oldStr);
48290
48910
  if (stripped !== oldStr) {
48291
48911
  const viaStripped = tryOne(stripped);
@@ -48605,7 +49225,7 @@ var require_transcript = __commonJS({
48605
49225
  exports2.shiftSegments = shiftSegments;
48606
49226
  exports2.formatTranscript = formatTranscript;
48607
49227
  var TS_RE = /^(\d{2,}):(\d{2}):(\d{2})[.,](\d{3})\s+-->\s+(\d{2,}):(\d{2}):(\d{2})[.,](\d{3})/;
48608
- var TAG_RE = /<[^>]+>/g;
49228
+ var TAG_RE2 = /<[^>]+>/g;
48609
49229
  function toSeconds(h, m2, s, ms) {
48610
49230
  return Number(h) * 3600 + Number(m2) * 60 + Number(s) + Number(ms) / 1e3;
48611
49231
  }
@@ -48624,7 +49244,7 @@ var require_transcript = __commonJS({
48624
49244
  i2 += 1;
48625
49245
  const cueLines = [];
48626
49246
  while (i2 < lines.length && lines[i2].trim()) {
48627
- const cleaned = lines[i2].replace(TAG_RE, "").trim();
49247
+ const cleaned = lines[i2].replace(TAG_RE2, "").trim();
48628
49248
  if (cleaned)
48629
49249
  cueLines.push(cleaned);
48630
49250
  i2 += 1;
@@ -55679,14 +56299,14 @@ var require_extractor = __commonJS({
55679
56299
  }
55680
56300
  return "";
55681
56301
  }
55682
- function moduleNameFromSourceLiteral(literal) {
55683
- const stripped = literal.replace(/^['"]|['"]$/g, "");
56302
+ function moduleNameFromSourceLiteral(literal2) {
56303
+ const stripped = literal2.replace(/^['"]|['"]$/g, "");
55684
56304
  const parts2 = stripped.split(/[\\/]/);
55685
56305
  const last = parts2[parts2.length - 1] || stripped;
55686
56306
  return last.replace(/\.(d\.)?ts$/, "").replace(/\.js$/, "");
55687
56307
  }
55688
- function moduleSpecFromSourceLiteral(literal) {
55689
- return literal.replace(/^['"]|['"]$/g, "");
56308
+ function moduleSpecFromSourceLiteral(literal2) {
56309
+ return literal2.replace(/^['"]|['"]$/g, "");
55690
56310
  }
55691
56311
  function extractFromMatches(matches, path14, allLines) {
55692
56312
  const symbols = [];
@@ -61183,15 +61803,15 @@ var require_ruleMatcher = __commonJS({
61183
61803
  home: input.home
61184
61804
  }))
61185
61805
  });
61186
- const literal = trips(input.literal);
61806
+ const literal2 = trips(input.literal);
61187
61807
  for (const form of input.resolvedForms) {
61188
61808
  if (form === input.literal)
61189
61809
  continue;
61190
61810
  const resolved = trips(form);
61191
- if (resolved.protected && !literal.protected) {
61811
+ if (resolved.protected && !literal2.protected) {
61192
61812
  return `refused: ${input.literal} resolves to ${form}, a protected path \u2014 address the real target directly so the write can be reviewed`;
61193
61813
  }
61194
- if (resolved.deny && !literal.deny) {
61814
+ if (resolved.deny && !literal2.deny) {
61195
61815
  return `refused: ${input.literal} resolves to ${form}, which a permission rule denies`;
61196
61816
  }
61197
61817
  }
@@ -62553,13 +63173,13 @@ var require_toolExecutor = __commonJS({
62553
63173
  const fileNormalized = fileContent.replace(/\s+/g, " ");
62554
63174
  const normIdx = fileNormalized.indexOf(oldNormalized);
62555
63175
  if (normIdx >= 0 && oldNormalized.length > 0) {
62556
- const literal = findFuzzyLiteralSlice(fileContent, oldStr);
62557
- if (literal) {
63176
+ const literal2 = findFuzzyLiteralSlice(fileContent, oldStr);
63177
+ if (literal2) {
62558
63178
  return [
62559
63179
  `old_string not found in ${path15} \u2014 but a whitespace-different version exists.`,
62560
63180
  `Likely cause: invented indentation/tabs/spaces. Use the exact bytes from the file:`,
62561
63181
  "---",
62562
- clipLines(literal, 8),
63182
+ clipLines(literal2, 8),
62563
63183
  "---",
62564
63184
  `Re-read the file with read_file if needed and retry edit_file with the literal text above.`
62565
63185
  ].join("\n");
@@ -70768,6 +71388,8 @@ var require_dist = __commonJS({
70768
71388
  __exportStar(require_duetEntry(), exports2);
70769
71389
  __exportStar(require_duetRouterModel(), exports2);
70770
71390
  __exportStar(require_duetRouterInstall(), exports2);
71391
+ __exportStar(require_duetExecutorGate(), exports2);
71392
+ __exportStar(require_duetExecutorGateStatus(), exports2);
70771
71393
  __exportStar(require_duetPlan(), exports2);
70772
71394
  __exportStar(require_duetPlanners(), exports2);
70773
71395
  __exportStar(require_repoIdentity(), exports2);
@@ -84445,12 +85067,12 @@ function reorderBidi(characters) {
84445
85067
  if (!needsBidi() || characters.length === 0) {
84446
85068
  return characters;
84447
85069
  }
84448
- const plainText = characters.map((c3) => c3.value).join("");
84449
- if (!hasRTLCharacters(plainText)) {
85070
+ const plainText2 = characters.map((c3) => c3.value).join("");
85071
+ if (!hasRTLCharacters(plainText2)) {
84450
85072
  return characters;
84451
85073
  }
84452
85074
  const bidi = getBidi();
84453
- const { levels } = bidi.getEmbeddingLevels(plainText, "auto");
85075
+ const { levels } = bidi.getEmbeddingLevels(plainText2, "auto");
84454
85076
  const charLevels = [];
84455
85077
  let offset = 0;
84456
85078
  for (let i2 = 0; i2 < characters.length; i2++) {
@@ -85238,14 +85860,14 @@ function applyStylesToWrappedText(wrappedPlain, segments, charToSegment, origina
85238
85860
  }
85239
85861
  return resultLines.join("\n");
85240
85862
  }
85241
- function wrapWithSoftWrap(plainText, maxWidth, textWrap) {
85863
+ function wrapWithSoftWrap(plainText2, maxWidth, textWrap) {
85242
85864
  if (textWrap !== "wrap" && textWrap !== "wrap-trim") {
85243
85865
  return {
85244
- wrapped: wrapText(plainText, maxWidth, textWrap),
85866
+ wrapped: wrapText(plainText2, maxWidth, textWrap),
85245
85867
  softWrap: void 0
85246
85868
  };
85247
85869
  }
85248
- const origLines = plainText.split("\n");
85870
+ const origLines = plainText2.split("\n");
85249
85871
  const outLines = [];
85250
85872
  const softWrap = [];
85251
85873
  for (const orig of origLines) {
@@ -85361,16 +85983,16 @@ function renderNodeToOutput(node, output, {
85361
85983
  node,
85362
85984
  inheritedBackgroundColor ? { backgroundColor: inheritedBackgroundColor } : void 0
85363
85985
  );
85364
- const plainText = segments.map((s) => s.text).join("");
85365
- if (plainText.length > 0) {
85986
+ const plainText2 = segments.map((s) => s.text).join("");
85987
+ if (plainText2.length > 0) {
85366
85988
  const maxWidth = Math.min(get_max_width_default(yogaNode), output.width - x2);
85367
85989
  const textWrap = node.style.textWrap ?? "wrap";
85368
- const needsWrapping = widestLine(plainText) > maxWidth;
85990
+ const needsWrapping = widestLine(plainText2) > maxWidth;
85369
85991
  let text;
85370
85992
  let softWrap;
85371
85993
  if (needsWrapping && segments.length === 1) {
85372
85994
  const segment = segments[0];
85373
- const w2 = wrapWithSoftWrap(plainText, maxWidth, textWrap);
85995
+ const w2 = wrapWithSoftWrap(plainText2, maxWidth, textWrap);
85374
85996
  softWrap = w2.softWrap;
85375
85997
  text = w2.wrapped.split("\n").map((line) => {
85376
85998
  let styled = applyTextStyles(line, segment.styles);
@@ -85380,14 +86002,14 @@ function renderNodeToOutput(node, output, {
85380
86002
  return styled;
85381
86003
  }).join("\n");
85382
86004
  } else if (needsWrapping) {
85383
- const w2 = wrapWithSoftWrap(plainText, maxWidth, textWrap);
86005
+ const w2 = wrapWithSoftWrap(plainText2, maxWidth, textWrap);
85384
86006
  softWrap = w2.softWrap;
85385
86007
  const charToSegment = buildCharToSegmentMap(segments);
85386
86008
  text = applyStylesToWrappedText(
85387
86009
  w2.wrapped,
85388
86010
  segments,
85389
86011
  charToSegment,
85390
- plainText,
86012
+ plainText2,
85391
86013
  textWrap === "wrap-trim"
85392
86014
  );
85393
86015
  } else {
@@ -89545,7 +90167,7 @@ function fmtTok(n) {
89545
90167
  }
89546
90168
  function pct(part, whole) {
89547
90169
  if (whole <= 0) return "0%";
89548
- const v2 = (part / whole * 100).toFixed(1).replace(/\.0$/, "");
90170
+ const v2 = Math.min(100, part / whole * 100).toFixed(1).replace(/\.0$/, "");
89549
90171
  return `${v2}%`;
89550
90172
  }
89551
90173
  function gridRows(allocation) {
@@ -90740,6 +91362,12 @@ async function resolveListedModel(ctx, model) {
90740
91362
  return void 0;
90741
91363
  }
90742
91364
  }
91365
+ function windowShrinkAdvisory(heldTokens, ceiling, triggerRatio) {
91366
+ if (!(heldTokens > 0) || !(ceiling > 0)) return null;
91367
+ if (heldTokens < ceiling * triggerRatio) return null;
91368
+ const k = (n) => `${Math.round(n / 1e3)}k`;
91369
+ return `This conversation holds ~${k(heldTokens)} tokens against a ${k(ceiling)} window \u2014 it will be compacted automatically on your next message (original ask and recent turns kept verbatim, the middle summarized). Run /compact to do it now.`;
91370
+ }
90743
91371
  async function applyModel(ctx, sid, modelId, provider, label, contextWindow) {
90744
91372
  if (provider && provider !== ctx.appStore.getState().provider) {
90745
91373
  await ctx.bridge.rpc("set_provider", { session_id: sid, provider }).catch(() => void 0);
@@ -90756,6 +91384,12 @@ async function applyModel(ctx, sid, modelId, provider, label, contextWindow) {
90756
91384
  // (A missing/zero window leaves the current value so we never blank the gauge.)
90757
91385
  contextWindow: s.contextWindowOverride == null && contextWindow && contextWindow > 0 ? contextWindow : s.contextWindow
90758
91386
  }));
91387
+ {
91388
+ const s = ctx.appStore.getState();
91389
+ const ceiling = s.contextWindowOverride ?? (contextWindow && contextWindow > 0 ? contextWindow : 0);
91390
+ const advisory = windowShrinkAdvisory(s.contextTokens, ceiling, s.contextTriggerRatio);
91391
+ if (advisory) ctx.print(advisory, "warning");
91392
+ }
90759
91393
  try {
90760
91394
  saveConfig({ model: modelId, provider: ctx.appStore.getState().provider });
90761
91395
  } catch {
@@ -91444,18 +92078,20 @@ ${(0, import_client_core20.duetRoutingSummaryLine)(await (0, import_client_core2
91444
92078
  kind: "local",
91445
92079
  name: "duet-entry",
91446
92080
  aliases: ["entry"],
91447
- description: "Choose who decides plan vs execute in Duet mode \u2014 the planner, or the router",
91448
- keywords: ["duet", "planner", "router", "plan", "execute", "hand off"],
91449
- argumentHint: "[planner|router]",
92081
+ description: "Choose who decides plan vs execute in Duet mode \u2014 the planner, the router, or your executor",
92082
+ keywords: ["duet", "planner", "router", "executor", "plan", "execute", "hand off"],
92083
+ argumentHint: "[planner|router|executor]",
91450
92084
  run: async (args2, ctx) => {
91451
92085
  const workspaceRoot = ctx.config?.workspaceRoot;
91452
92086
  const typed = (0, import_client_core20.normalizeDuetEntry)(args2);
91453
92087
  const routerStatus = await (0, import_client_core20.describeDuetRouterModel)().catch(() => null);
92088
+ const executorStatus = await (0, import_client_core20.describeDuetExecutorGateCached)({ workspaceRoot }).catch(() => null);
91454
92089
  const save = async (entry) => {
91455
- const availability = (0, import_client_core20.duetEntryOptionAvailability)(entry, routerStatus);
92090
+ const availability = (0, import_client_core20.duetEntryOptionAvailability)(entry, routerStatus, executorStatus);
91456
92091
  if (availability.disabled) {
91457
92092
  ctx.print(`${(0, import_client_core20.duetEntryLabel)(entry)}: ${availability.note ?? "unavailable"}`, "warning");
91458
- if (routerStatus !== null) ctx.print((0, import_client_core20.duetRouterStatusLine)(routerStatus), "info");
92093
+ if (entry === "router" && routerStatus !== null) ctx.print((0, import_client_core20.duetRouterStatusLine)(routerStatus), "info");
92094
+ if (entry === "executor" && executorStatus !== null) ctx.print((0, import_client_core20.executorGateStatusLine)(executorStatus), "info");
91459
92095
  return;
91460
92096
  }
91461
92097
  await (0, import_client_core20.setDuetEntry)(entry);
@@ -91467,7 +92103,7 @@ ${(0, import_client_core20.duetRoutingSummaryLine)(await (0, import_client_core2
91467
92103
  return;
91468
92104
  }
91469
92105
  if (args2.trim() !== "") {
91470
- ctx.print("Usage: /duet-entry [planner|router]", "warning");
92106
+ ctx.print("Usage: /duet-entry [planner|router|executor]", "warning");
91471
92107
  return;
91472
92108
  }
91473
92109
  const active = await (0, import_client_core20.loadDuetEntry)({ workspaceRoot });
@@ -91477,7 +92113,7 @@ ${(0, import_client_core20.duetRoutingSummaryLine)(await (0, import_client_core2
91477
92113
  kind: "select",
91478
92114
  title: `${import_client_core20.DUET_ENTRY_INFO.label} \xB7 current: ${(0, import_client_core20.duetEntryLabel)(active)}`,
91479
92115
  options: import_client_core20.DUET_ENTRY_OPTIONS.map((option) => {
91480
- const availability = (0, import_client_core20.duetEntryOptionAvailability)(option.value, routerStatus);
92116
+ const availability = (0, import_client_core20.duetEntryOptionAvailability)(option.value, routerStatus, executorStatus);
91481
92117
  return {
91482
92118
  label: option.label,
91483
92119
  value: option.value,
@@ -92215,6 +92851,11 @@ ${(0, import_client_core20.duetRoutingSummaryLine)(await (0, import_client_core2
92215
92851
  contextWindowOverride: cw
92216
92852
  }));
92217
92853
  ctx.print(`Context window: ${cw ?? "model default"}`, "success");
92854
+ if (cw) {
92855
+ const s2 = ctx.appStore.getState();
92856
+ const advisory = windowShrinkAdvisory(s2.contextTokens, cw, s2.contextTriggerRatio);
92857
+ if (advisory) ctx.print(advisory, "warning");
92858
+ }
92218
92859
  }
92219
92860
  },
92220
92861
  {
@@ -93317,6 +93958,7 @@ function initialAppState(partial) {
93317
93958
  contextTokens: 0,
93318
93959
  contextWindow: 0,
93319
93960
  contextWindowOverride: null,
93961
+ contextTriggerRatio: 0.9,
93320
93962
  contextBreakdown: null,
93321
93963
  signedIn: false,
93322
93964
  accountTier: null,
@@ -93793,6 +94435,10 @@ function renderLane(transcript, app, ev) {
93793
94435
  ...s,
93794
94436
  contextTokens: typeof d2.tokens === "number" ? d2.tokens : s.contextTokens,
93795
94437
  contextWindow: typeof d2.window === "number" ? d2.window : s.contextWindow,
94438
+ // The backend's enforcement threshold rides the event; a garbage or absent
94439
+ // ratio keeps the previous value (0.9 default) rather than skewing the
94440
+ // shrink advisory.
94441
+ contextTriggerRatio: typeof d2.trigger_ratio === "number" && Number.isFinite(d2.trigger_ratio) && d2.trigger_ratio > 0 && d2.trigger_ratio <= 1 ? d2.trigger_ratio : s.contextTriggerRatio,
93796
94442
  contextBreakdown: d2.breakdown && typeof d2.breakdown === "object" ? d2.breakdown : s.contextBreakdown
93797
94443
  }));
93798
94444
  break;
@@ -109734,10 +110380,19 @@ function GradientText({
109734
110380
  var EOL = "\n";
109735
110381
  var BLOCKQUOTE_BAR = "\u2502";
109736
110382
  var configured = false;
110383
+ var DEL_RULE = /^~~(?=[^\s~])([\s\S]*?[^\s~])~~(?=[^~]|$)/;
109737
110384
  function configureMarked() {
109738
110385
  if (configured) return;
109739
110386
  configured = true;
109740
- g.use({ tokenizer: { del: () => void 0 } });
110387
+ g.use({
110388
+ tokenizer: {
110389
+ del(src) {
110390
+ const cap = DEL_RULE.exec(src);
110391
+ if (!cap) return void 0;
110392
+ return { type: "del", raw: cap[0], text: cap[1], tokens: this.lexer.inlineTokens(cap[1]) };
110393
+ }
110394
+ }
110395
+ });
109741
110396
  }
109742
110397
  function gradientHeading(text) {
109743
110398
  const chars = [...text];
@@ -109827,6 +110482,8 @@ function formatToken(token, theme, listDepth = 0, orderedListNumber = null, pare
109827
110482
  return import_chalk3.default.italic(kids(token, 0, null, parent));
109828
110483
  case "strong":
109829
110484
  return import_chalk3.default.bold(kids(token, 0, null, parent));
110485
+ case "del":
110486
+ return import_chalk3.default.strikethrough(kids(token, 0, null, parent));
109830
110487
  case "heading": {
109831
110488
  const t = token;
109832
110489
  const grad = gradientHeading((0, import_strip_ansi2.default)(kids(token)));
@@ -109892,11 +110549,197 @@ function formatToken(token, theme, listDepth = 0, orderedListNumber = null, pare
109892
110549
  }
109893
110550
  case "escape":
109894
110551
  return token.text;
110552
+ case "html":
110553
+ return token.text;
109895
110554
  default:
109896
110555
  return "";
109897
110556
  }
109898
110557
  }
109899
110558
 
110559
+ // src/components/markdown/inlineHtml.ts
110560
+ var STYLE_TAGS = {
110561
+ b: "strong",
110562
+ strong: "strong",
110563
+ i: "em",
110564
+ em: "em",
110565
+ del: "del",
110566
+ s: "del",
110567
+ strike: "del",
110568
+ code: "codespan",
110569
+ kbd: "codespan"
110570
+ };
110571
+ var TRANSPARENT_TAGS = /* @__PURE__ */ new Set([
110572
+ "u",
110573
+ "ins",
110574
+ "mark",
110575
+ "small",
110576
+ "sub",
110577
+ "sup",
110578
+ "abbr",
110579
+ "cite",
110580
+ "q",
110581
+ "samp",
110582
+ "var",
110583
+ "tt",
110584
+ "span",
110585
+ "summary",
110586
+ "details"
110587
+ ]);
110588
+ var TAG_RE = /^<(\/?)([A-Za-z][A-Za-z0-9-]*)((?:\s+[A-Za-z_:][-\w.:]*(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'=<>`]+))?)*)\s*(\/?)>$/;
110589
+ function parseTag(raw) {
110590
+ const m2 = TAG_RE.exec(raw.trim());
110591
+ if (!m2) return null;
110592
+ return { close: m2[1] === "/", name: m2[2].toLowerCase(), attrs: m2[3] ?? "", selfClosing: m2[4] === "/" };
110593
+ }
110594
+ function attr(attrs, name2) {
110595
+ const m2 = new RegExp(`${name2}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s>]+))`, "i").exec(attrs);
110596
+ return m2 ? m2[1] ?? m2[2] ?? m2[3] : void 0;
110597
+ }
110598
+ function plainText(tokens) {
110599
+ return tokens.map((t) => {
110600
+ const tk = t;
110601
+ if (tk.tokens?.length) return plainText(tk.tokens);
110602
+ return tk.text ?? tk.raw ?? "";
110603
+ }).join("");
110604
+ }
110605
+ function literal(raw) {
110606
+ return { type: "text", raw, text: raw };
110607
+ }
110608
+ function foldInlineTokens(tokens) {
110609
+ const out2 = [];
110610
+ let i2 = 0;
110611
+ while (i2 < tokens.length) {
110612
+ const t = tokens[i2];
110613
+ if (t.type !== "html") {
110614
+ const container = t;
110615
+ if (container.tokens?.length) container.tokens = foldInlineTokens(container.tokens);
110616
+ out2.push(t);
110617
+ i2 += 1;
110618
+ continue;
110619
+ }
110620
+ const raw = t.raw;
110621
+ if (raw.startsWith("<!--")) {
110622
+ i2 += 1;
110623
+ continue;
110624
+ }
110625
+ const tag = parseTag(raw);
110626
+ if (!tag) {
110627
+ out2.push(literal(raw));
110628
+ i2 += 1;
110629
+ continue;
110630
+ }
110631
+ if (tag.name === "br" || tag.name === "hr") {
110632
+ out2.push({ type: "br", raw });
110633
+ i2 += 1;
110634
+ continue;
110635
+ }
110636
+ if (tag.name === "wbr") {
110637
+ i2 += 1;
110638
+ continue;
110639
+ }
110640
+ if (tag.name === "img" && !tag.close) {
110641
+ const src = attr(tag.attrs, "src");
110642
+ const alt = attr(tag.attrs, "alt");
110643
+ out2.push(src ? { type: "image", raw, href: src, text: alt ?? src, title: null } : literal(raw));
110644
+ i2 += 1;
110645
+ continue;
110646
+ }
110647
+ const style2 = STYLE_TAGS[tag.name];
110648
+ const transparent = TRANSPARENT_TAGS.has(tag.name);
110649
+ const isLink = tag.name === "a";
110650
+ if (tag.close || tag.selfClosing || !style2 && !transparent && !isLink) {
110651
+ out2.push(literal(raw));
110652
+ i2 += 1;
110653
+ continue;
110654
+ }
110655
+ let depth = 0;
110656
+ let close = -1;
110657
+ for (let j2 = i2 + 1; j2 < tokens.length; j2++) {
110658
+ const tj = tokens[j2];
110659
+ if (tj.type !== "html") continue;
110660
+ const pj = parseTag(tj.raw);
110661
+ if (!pj || pj.name !== tag.name) continue;
110662
+ if (pj.close) {
110663
+ if (depth === 0) {
110664
+ close = j2;
110665
+ break;
110666
+ }
110667
+ depth -= 1;
110668
+ } else if (!pj.selfClosing) {
110669
+ depth += 1;
110670
+ }
110671
+ }
110672
+ if (close === -1) {
110673
+ out2.push(literal(raw));
110674
+ i2 += 1;
110675
+ continue;
110676
+ }
110677
+ const inner = foldInlineTokens(tokens.slice(i2 + 1, close));
110678
+ const seg2 = tokens.slice(i2, close + 1).map((x2) => x2.raw ?? "").join("");
110679
+ if (style2 === "codespan") {
110680
+ out2.push({ type: "codespan", raw: seg2, text: plainText(inner) });
110681
+ } else if (style2) {
110682
+ out2.push({ type: style2, raw: seg2, text: plainText(inner), tokens: inner });
110683
+ } else if (isLink) {
110684
+ const href = attr(tag.attrs, "href");
110685
+ if (href && /^(https?:|mailto:)/i.test(href)) {
110686
+ out2.push({ type: "link", raw: seg2, href, title: null, text: plainText(inner), tokens: inner });
110687
+ } else {
110688
+ out2.push(...inner);
110689
+ }
110690
+ } else {
110691
+ out2.push(...inner);
110692
+ }
110693
+ i2 = close + 1;
110694
+ }
110695
+ return out2;
110696
+ }
110697
+ function htmlBlockToText(raw) {
110698
+ let s = raw.replace(/<!--[\s\S]*?(?:-->|$)/g, "");
110699
+ s = s.replace(/<\s*br\s*\/?>/gi, "\n");
110700
+ s = s.replace(/<li[^>]*>/gi, "\u2022 ");
110701
+ s = s.replace(/<\/(li|p|div|tr|ul|ol|table|details|summary|blockquote|dt|dd|dl|h[1-6])>/gi, "\n");
110702
+ s = s.replace(/<\/(td|th)>/gi, " ");
110703
+ s = s.replace(
110704
+ /<\/?(b|strong|i|em|u|ins|s|del|strike|mark|kbd|code|small|sub|sup|abbr|cite|q|samp|var|tt|p|div|ul|ol|table|thead|tbody|tfoot|tr|td|th|caption|colgroup|col|details|summary|figure|figcaption|a|img|span|pre|hr|wbr|blockquote|dl|dt|dd|h[1-6])(\s[^>]*)?\/?>/gi,
110705
+ ""
110706
+ );
110707
+ return s.replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
110708
+ }
110709
+ function foldMarkdownTokens(tokens) {
110710
+ const out2 = [];
110711
+ for (const t of tokens) {
110712
+ if (t.type === "html") {
110713
+ const text = htmlBlockToText(t.raw);
110714
+ if (text) {
110715
+ out2.push({ type: "paragraph", raw: t.raw, text, tokens: [literal(text)] });
110716
+ }
110717
+ continue;
110718
+ }
110719
+ if (t.type === "table") {
110720
+ const table = t;
110721
+ for (const cell2 of table.header) cell2.tokens = foldInlineTokens(cell2.tokens ?? []);
110722
+ for (const row of table.rows) for (const cell2 of row) cell2.tokens = foldInlineTokens(cell2.tokens ?? []);
110723
+ out2.push(t);
110724
+ continue;
110725
+ }
110726
+ if (t.type === "list") {
110727
+ for (const item of t.items) item.tokens = foldMarkdownTokens(item.tokens ?? []);
110728
+ out2.push(t);
110729
+ continue;
110730
+ }
110731
+ if (t.type === "blockquote") {
110732
+ t.tokens = foldMarkdownTokens(t.tokens ?? []);
110733
+ out2.push(t);
110734
+ continue;
110735
+ }
110736
+ const container = t;
110737
+ if (container.tokens?.length) container.tokens = foldInlineTokens(container.tokens);
110738
+ out2.push(t);
110739
+ }
110740
+ return out2;
110741
+ }
110742
+
109900
110743
  // src/components/markdown/Markdown.tsx
109901
110744
  var import_jsx_runtime19 = __toESM(require_jsx_runtime(), 1);
109902
110745
  var MIN_COL = 3;
@@ -109960,7 +110803,7 @@ function Markdown({ text, width }) {
109960
110803
  const theme = useTheme();
109961
110804
  const contentWidth = width ?? (process.stdout.columns ?? 80) - 2;
109962
110805
  const elements = import_react19.default.useMemo(() => {
109963
- const tokens = g.lexer(text);
110806
+ const tokens = foldMarkdownTokens(g.lexer(text));
109964
110807
  const out2 = [];
109965
110808
  let nonTable = "";
109966
110809
  const flush = () => {
@@ -110944,7 +111787,7 @@ function OrionRing() {
110944
111787
 
110945
111788
  // src/services/version.ts
110946
111789
  function tuiVersion() {
110947
- return "0.1.22".length > 0 ? "0.1.22" : null;
111790
+ return "0.1.24".length > 0 ? "0.1.24" : null;
110948
111791
  }
110949
111792
 
110950
111793
  // src/components/layout/WelcomeCard.tsx
@@ -118032,6 +118875,11 @@ async function main() {
118032
118875
  const duetAdvisorState = (0, import_client_core49.createDuetAdvisorState)();
118033
118876
  const duetRouterGate = (0, import_client_core49.createDuetRouterGate)({
118034
118877
  loadEncoder: (0, import_client_core49.createDefaultDuetRouterEncoder)(),
118878
+ // "Executor decides": the same gate object owns the executor's one-token scorer, so the
118879
+ // turn path below has ONE call whichever entry is set (`duetExecutorGate.ts`).
118880
+ executorGate: (0, import_client_core49.createDuetExecutorGate)({
118881
+ onError: (stage, problem) => console.error(`[duet-executor-gate] ${stage} failed: ${problem}`)
118882
+ }),
118035
118883
  onError: (stage, error) => (
118036
118884
  // Same breadcrumb the IDE and the Power App leave (the log redirect captures it, so it
118037
118885
  // never corrupts the alt screen): without it a load or classify failure is invisible
@@ -119005,7 +119853,11 @@ async function main() {
119005
119853
  if (appStore.getState().mode === "duet") {
119006
119854
  const routed = await duetRouterGate.prepareTurn(
119007
119855
  (0, import_client_core49.duetEntryWireForSegment)(config.workspaceRoot),
119008
- routerText
119856
+ routerText,
119857
+ // What the executor gate's prompt is built from: the standing record as it stands
119858
+ // BEFORE the advisor runs (the advisor may flag it for this turn; the gate asks the
119859
+ // executor about the request under the plan the user actually approved).
119860
+ { workspaceRoot: config.workspaceRoot, record: appStore.getState().duetPlan }
119009
119861
  );
119010
119862
  duetEntry = routed.entry;
119011
119863
  duetRouterVerdict = routed.verdict;