orion-super-agent-dev 0.1.23 → 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 = {
@@ -29213,8 +29218,20 @@ var require_duetEntry = __commonJS({
29213
29218
  value: "router",
29214
29219
  label: "Router decides",
29215
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."
29216
29226
  }
29217
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
+ }
29218
29235
  function duetEntryLabel2(entry) {
29219
29236
  return exports2.DUET_ENTRY_OPTIONS.find((option) => option.value === entry)?.label ?? entry;
29220
29237
  }
@@ -29222,7 +29239,7 @@ var require_duetEntry = __commonJS({
29222
29239
  if (typeof raw !== "string")
29223
29240
  return null;
29224
29241
  const value = raw.trim();
29225
- return value === "planner" || value === "router" ? value : null;
29242
+ return value === "planner" || value === "router" || value === "executor" ? value : null;
29226
29243
  }
29227
29244
  exports2.DUET_HANDOFF_TOOL = "hand_off";
29228
29245
  exports2.DUET_HANDOFF_CAPABILITY = "duet_handoff";
@@ -29345,6 +29362,69 @@ var require_duetEntry = __commonJS({
29345
29362
  }
29346
29363
  });
29347
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
+
29348
29428
  // ../packages/orion-client-core/dist/duetRouterModel.js
29349
29429
  var require_duetRouterModel = __commonJS({
29350
29430
  "../packages/orion-client-core/dist/duetRouterModel.js"(exports2) {
@@ -29400,7 +29480,6 @@ var require_duetRouterModel = __commonJS({
29400
29480
  exports2.classifyWithHeads = classifyWithHeads;
29401
29481
  exports2.createDuetRouter = createDuetRouter;
29402
29482
  exports2.createTransformersDuetRouterEncoder = createTransformersDuetRouterEncoder;
29403
- exports2.effectiveDuetEntry = effectiveDuetEntry;
29404
29483
  exports2.duetRouterDisplayName = duetRouterDisplayName2;
29405
29484
  exports2.duetRouterStatusLine = duetRouterStatusLine2;
29406
29485
  exports2.duetRouterDowngradeNote = duetRouterDowngradeNote;
@@ -29412,6 +29491,8 @@ var require_duetRouterModel = __commonJS({
29412
29491
  var fs15 = __importStar(__require("node:fs/promises"));
29413
29492
  var os9 = __importStar(__require("node:os"));
29414
29493
  var path14 = __importStar(__require("node:path"));
29494
+ var duetEntry_js_1 = require_duetEntry();
29495
+ var duetExecutorGateStatus_js_1 = require_duetExecutorGateStatus();
29415
29496
  exports2.DUET_ROUTER_WIRE_KEY = "duet_router";
29416
29497
  exports2.DUET_ROUTER_BUNDLE_FORMAT = "orion-router-bundle.v1";
29417
29498
  exports2.DUET_ROUTER_MODEL_ID = "orion/orion-pe-router-1.0";
@@ -29425,13 +29506,16 @@ var require_duetRouterModel = __commonJS({
29425
29506
  ];
29426
29507
  function duetRouterWireForSegment(verdict) {
29427
29508
  return {
29509
+ source: verdict.source,
29428
29510
  model: verdict.model,
29429
29511
  version: verdict.version,
29430
29512
  verdict: verdict.verdict,
29431
29513
  p_plan: round6(verdict.pPlan),
29432
29514
  asks_for_plan: verdict.asksForPlan,
29433
29515
  high_risk: verdict.highRisk,
29434
- reason: verdict.reason
29516
+ reason: verdict.reason,
29517
+ ...verdict.margin !== void 0 ? { margin: round6(verdict.margin) } : {},
29518
+ ...verdict.mode !== void 0 ? { mode: verdict.mode } : {}
29435
29519
  };
29436
29520
  }
29437
29521
  function orionModelsDir(homeDir = os9.homedir()) {
@@ -29662,6 +29746,7 @@ var require_duetRouterModel = __commonJS({
29662
29746
  if (!vector)
29663
29747
  throw new Error("router encoder returned no vector");
29664
29748
  return {
29749
+ source: "orion_router",
29665
29750
  ...classifyWithHeads(vector, bundle),
29666
29751
  model: bundle.name,
29667
29752
  version: bundle.version,
@@ -29731,11 +29816,6 @@ var require_duetRouterModel = __commonJS({
29731
29816
  }
29732
29817
  };
29733
29818
  }
29734
- function effectiveDuetEntry(setting, routerState) {
29735
- if (setting === "router" && routerState !== "ready")
29736
- return { entry: "planner", downgraded: true };
29737
- return { entry: setting, downgraded: false };
29738
- }
29739
29819
  function duetRouterDisplayName2(name2, version) {
29740
29820
  const trimmed = name2.trim();
29741
29821
  const v2 = version.trim();
@@ -29757,7 +29837,9 @@ var require_duetRouterModel = __commonJS({
29757
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})` : ""}`;
29758
29838
  return `Router decides needs the Orion router model and ${why} \u2014 this turn ran through the planner instead.`;
29759
29839
  }
29760
- function duetEntryOptionAvailability2(entry, status) {
29840
+ function duetEntryOptionAvailability2(entry, status, executorStatus = null) {
29841
+ if (entry === "executor")
29842
+ return (0, duetExecutorGateStatus_js_1.executorGateOptionAvailability)(executorStatus);
29761
29843
  if (entry !== "router" || status === null || status.state === "ready")
29762
29844
  return { disabled: false, note: null };
29763
29845
  return {
@@ -29797,6 +29879,7 @@ var require_duetRouterModel = __commonJS({
29797
29879
  let router = null;
29798
29880
  let building = null;
29799
29881
  let noted = false;
29882
+ let executorNoted = false;
29800
29883
  const status = async (o = {}) => {
29801
29884
  const now2 = Date.now();
29802
29885
  if (!o.refresh && cached !== null && now2 - cached.at < exports2.DUET_ROUTER_STATUS_TTL_MS)
@@ -29808,11 +29891,18 @@ var require_duetRouterModel = __commonJS({
29808
29891
  const downgrade = (why) => {
29809
29892
  const note = noted ? null : duetRouterDowngradeNote(why);
29810
29893
  noted = true;
29811
- return { ...effectiveDuetEntry("router", why.state), verdict: null, note };
29894
+ return { ...(0, duetEntry_js_1.effectiveDuetEntry)("router", why.state), verdict: null, note };
29812
29895
  };
29813
29896
  return {
29814
29897
  status,
29815
- 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
+ }
29816
29906
  if (setting !== "router")
29817
29907
  return { entry: setting, verdict: null, note: null };
29818
29908
  if (text.trim() === "")
@@ -29846,6 +29936,8 @@ var require_duetRouterModel = __commonJS({
29846
29936
  invalidate() {
29847
29937
  cached = null;
29848
29938
  noted = false;
29939
+ executorNoted = false;
29940
+ opts.executorGate?.invalidate();
29849
29941
  const live = router;
29850
29942
  router = null;
29851
29943
  building = null;
@@ -30164,6 +30256,7 @@ var require_duetPlan = __commonJS({
30164
30256
  exports2.duetReplanFollowupPrompt = duetReplanFollowupPrompt2;
30165
30257
  exports2.recordDuetTurnOutcome = recordDuetTurnOutcome;
30166
30258
  exports2.foldDuetTurnEnd = foldDuetTurnEnd2;
30259
+ var duetEntry_js_1 = require_duetEntry();
30167
30260
  exports2.DUET_PLAN_MAX_LEN = 65536;
30168
30261
  exports2.DUET_PLAN_MAX_VERSION = 1e4;
30169
30262
  exports2.DUET_PLAN_GRANTS = ["default", "workspace_write"];
@@ -30306,7 +30399,7 @@ var require_duetPlan = __commonJS({
30306
30399
  return false;
30307
30400
  const noPlan = duetPlanWireForSegment(record) === void 0;
30308
30401
  if (noPlan) {
30309
- if (entry !== "router")
30402
+ if (!(0, duetEntry_js_1.isModelRoutedEntry)(entry))
30310
30403
  return false;
30311
30404
  if (highRiskRequest(text))
30312
30405
  return false;
@@ -30320,7 +30413,7 @@ var require_duetPlan = __commonJS({
30320
30413
  return false;
30321
30414
  if (record.userNegativeFeedback)
30322
30415
  return false;
30323
- if (entry !== "router")
30416
+ if (!(0, duetEntry_js_1.isModelRoutedEntry)(entry))
30324
30417
  return continuationRequest(text);
30325
30418
  return verdict ? verdict.verdict === "execute" : true;
30326
30419
  }
@@ -35269,11 +35362,12 @@ var require_customProviders = __commonJS({
35269
35362
  };
35270
35363
  }();
35271
35364
  Object.defineProperty(exports2, "__esModule", { value: true });
35272
- 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;
35273
35366
  exports2.customProviderSettingsPath = customProviderSettingsPath;
35274
35367
  exports2.clampContextWindow = clampContextWindow;
35275
35368
  exports2.normalizeModelConfig = normalizeModelConfig;
35276
35369
  exports2.normalizeRoutingModels = normalizeRoutingModels;
35370
+ exports2.normalizeExecutorGate = normalizeExecutorGate;
35277
35371
  exports2.loadCustomProviders = loadCustomProviders3;
35278
35372
  exports2.getCustomProvider = getCustomProvider2;
35279
35373
  exports2.saveCustomProvider = saveCustomProvider3;
@@ -35303,6 +35397,9 @@ var require_customProviders = __commonJS({
35303
35397
  exports2.MIN_CONTEXT_WINDOW = 1024;
35304
35398
  exports2.MAX_CONTEXT_WINDOW = 2e6;
35305
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;
35306
35403
  var CUSTOM_REF_PREFIX = "custom:";
35307
35404
  var FILE_TIERS = ["user", "project", "local"];
35308
35405
  function customProviderSettingsPath(tier, opts = {}) {
@@ -35372,6 +35469,16 @@ var require_customProviders = __commonJS({
35372
35469
  }
35373
35470
  return Object.keys(out2).length > 0 ? out2 : void 0;
35374
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
+ }
35375
35482
  function toEntry(name2, raw) {
35376
35483
  if (typeof raw !== "object" || raw === null || Array.isArray(raw))
35377
35484
  return null;
@@ -35397,6 +35504,9 @@ var require_customProviders = __commonJS({
35397
35504
  const routingModels = normalizeRoutingModels(value[exports2.ROUTING_MODELS_KEY]);
35398
35505
  if (routingModels !== void 0)
35399
35506
  entry.routingModels = routingModels;
35507
+ const executorGate = normalizeExecutorGate(value[exports2.EXECUTOR_GATE_KEY]);
35508
+ if (executorGate !== void 0)
35509
+ entry.executorGate = executorGate;
35400
35510
  return entry;
35401
35511
  }
35402
35512
  async function readTier(tier, opts) {
@@ -35667,7 +35777,8 @@ var require_customProviders = __commonJS({
35667
35777
  // keyless is valid — local servers ignore auth
35668
35778
  wire: entry.wire,
35669
35779
  ...entry.modelConfig ? { modelConfig: entry.modelConfig } : {},
35670
- ...entry.routingModels ? { routingModels: entry.routingModels } : {}
35780
+ ...entry.routingModels ? { routingModels: entry.routingModels } : {},
35781
+ ...entry.executorGate ? { executorGate: entry.executorGate } : {}
35671
35782
  };
35672
35783
  routingByRef.set(provider, routing);
35673
35784
  while (routingByRef.size > ROUTING_CACHE_MAX) {
@@ -35783,6 +35894,7 @@ var require_customProviders = __commonJS({
35783
35894
  const wire = { ...routing };
35784
35895
  delete wire.modelConfig;
35785
35896
  delete wire.routingModels;
35897
+ delete wire.executorGate;
35786
35898
  const declared = routing.modelConfig?.[modelId];
35787
35899
  if (declared === void 0)
35788
35900
  return wire;
@@ -36018,75 +36130,9 @@ var require_duetRouterInstall = __commonJS({
36018
36130
  }
36019
36131
  });
36020
36132
 
36021
- // ../packages/orion-client-core/dist/runs/common.js
36022
- var require_common = __commonJS({
36023
- "../packages/orion-client-core/dist/runs/common.js"(exports2) {
36024
- "use strict";
36025
- Object.defineProperty(exports2, "__esModule", { value: true });
36026
- exports2.mintRunId = mintRunId;
36027
- exports2.runsRootFor = runsRootFor2;
36028
- exports2.readJsonFile = readJsonFile;
36029
- exports2.writeJsonFile = writeJsonFile;
36030
- exports2.ensureDirFor = ensureDirFor;
36031
- exports2.listDirNames = listDirNames;
36032
- exports2.dayKey = dayKey;
36033
- exports2.clipTail = clipTail;
36034
- var fs_1 = __require("fs");
36035
- var os_1 = __require("os");
36036
- var path_1 = __require("path");
36037
- var atomicWrite_js_1 = require_atomicWrite();
36038
- var experienceStore_js_1 = require_experienceStore();
36039
- var ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
36040
- var ID_SUFFIX_LEN = 6;
36041
- function mintRunId(prefix, nowMs = Date.now(), rand = Math.random) {
36042
- let suffix = "";
36043
- for (let i2 = 0; i2 < ID_SUFFIX_LEN; i2 += 1) {
36044
- suffix += ID_ALPHABET[Math.floor(rand() * ID_ALPHABET.length) % ID_ALPHABET.length];
36045
- }
36046
- return `${prefix}_${String(nowMs).padStart(13, "0")}_${suffix}`;
36047
- }
36048
- function runsRootFor2(kind, workspaceRoot, home = (0, os_1.homedir)()) {
36049
- return (0, path_1.join)((0, experienceStore_js_1.projectDirFor)(workspaceRoot, home), "runs", kind);
36050
- }
36051
- async function readJsonFile(path14) {
36052
- try {
36053
- const raw = await fs_1.promises.readFile(path14, "utf8");
36054
- return JSON.parse(raw);
36055
- } catch {
36056
- return null;
36057
- }
36058
- }
36059
- async function writeJsonFile(path14, value) {
36060
- await ensureDirFor(path14);
36061
- await (0, atomicWrite_js_1.atomicWriteFile)(path14, JSON.stringify(value, null, 2));
36062
- }
36063
- async function ensureDirFor(path14) {
36064
- await fs_1.promises.mkdir((0, path_1.dirname)(path14), { recursive: true });
36065
- }
36066
- async function listDirNames(path14) {
36067
- try {
36068
- return await fs_1.promises.readdir(path14);
36069
- } catch {
36070
- return [];
36071
- }
36072
- }
36073
- function dayKey(nowMs = Date.now()) {
36074
- const d2 = new Date(nowMs);
36075
- const month = `${d2.getMonth() + 1}`.padStart(2, "0");
36076
- const day = `${d2.getDate()}`.padStart(2, "0");
36077
- return `${d2.getFullYear()}-${month}-${day}`;
36078
- }
36079
- function clipTail(text, max) {
36080
- if (text.length <= max)
36081
- return text;
36082
- return `\u2026${text.slice(text.length - (max - 1))}`;
36083
- }
36084
- }
36085
- });
36086
-
36087
- // ../packages/orion-client-core/dist/customProviderModels.js
36088
- var require_customProviderModels = __commonJS({
36089
- "../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) {
36090
36136
  "use strict";
36091
36137
  var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m2, k, k2) {
36092
36138
  if (k2 === void 0) k2 = k;
@@ -36126,291 +36172,240 @@ var require_customProviderModels = __commonJS({
36126
36172
  };
36127
36173
  }();
36128
36174
  Object.defineProperty(exports2, "__esModule", { value: true });
36129
- exports2.CATALOG_GC_MS = exports2.CATALOG_TTL_MS = exports2.CATALOG_SCHEMA_VERSION = void 0;
36130
- exports2.catalogPathFor = catalogPathFor;
36131
- exports2.endpointCatalog = endpointCatalog2;
36132
- exports2.findProbedModel = findProbedModel;
36133
- exports2.resolveModelSettings = resolveModelSettings2;
36134
- exports2.catalogModelIds = catalogModelIds2;
36135
- exports2.clearEndpointCatalog = clearEndpointCatalog3;
36136
- exports2.endpointModelViews = endpointModelViews2;
36137
- 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;
36138
36188
  var node_crypto_1 = __require("node:crypto");
36189
+ var fs15 = __importStar(__require("node:fs/promises"));
36139
36190
  var os9 = __importStar(__require("node:os"));
36140
36191
  var path14 = __importStar(__require("node:path"));
36141
- var customProviders_1 = require_customProviders();
36142
- var common_1 = require_common();
36143
- exports2.CATALOG_SCHEMA_VERSION = 1;
36144
- exports2.CATALOG_TTL_MS = 9e5;
36145
- exports2.CATALOG_GC_MS = 45 * 24 * 60 * 60 * 1e3;
36146
- function catalogPathFor(baseUrl, homeDir = os9.homedir()) {
36147
- const digest = (0, node_crypto_1.createHash)("sha256").update(normalizeBaseUrl(baseUrl)).digest("hex").slice(0, 16);
36148
- 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");
36149
36200
  }
36150
- function normalizeBaseUrl(baseUrl) {
36151
- return baseUrl.trim().replace(/\/+$/, "");
36201
+ function newDecisionId() {
36202
+ return (0, node_crypto_1.randomUUID)();
36152
36203
  }
36153
- async function readRecordFromDisk(baseUrl) {
36154
- const record = await (0, common_1.readJsonFile)(catalogPathFor(baseUrl));
36155
- if (record === null)
36156
- return null;
36157
- if (record.version !== exports2.CATALOG_SCHEMA_VERSION)
36158
- return null;
36159
- if (normalizeBaseUrl(record.baseUrl ?? "") !== normalizeBaseUrl(baseUrl))
36160
- return null;
36161
- if (!Array.isArray(record.models))
36162
- return null;
36163
- 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);
36164
36208
  }
36165
- var sweptThisProcess = false;
36166
- async function gcEndpointCatalogs(now2, homeDir = os9.homedir()) {
36167
- if (sweptThisProcess)
36168
- return;
36169
- sweptThisProcess = true;
36170
- try {
36171
- const dir = path14.dirname(catalogPathFor("x", homeDir));
36172
- const fs15 = await Promise.resolve().then(() => __importStar(__require("node:fs/promises")));
36173
- for (const name2 of await fs15.readdir(dir)) {
36174
- if (!name2.endsWith(".json"))
36175
- continue;
36176
- const file = path14.join(dir, name2);
36177
- try {
36178
- const record = await (0, common_1.readJsonFile)(file);
36179
- const age = typeof record?.fetchedAt === "number" ? now2 - record.fetchedAt : now2 - (await fs15.stat(file)).mtimeMs;
36180
- if (age > exports2.CATALOG_GC_MS)
36181
- await fs15.rm(file, { force: true });
36182
- } catch {
36183
- }
36184
- }
36185
- } catch {
36186
- }
36209
+ function tokens(text) {
36210
+ return new Set(text.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 1));
36187
36211
  }
36188
- async function writeRecordToDisk(record) {
36189
- try {
36190
- await (0, common_1.writeJsonFile)(catalogPathFor(record.baseUrl), record);
36191
- } catch {
36192
- }
36193
- 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;
36194
36221
  }
36195
- var memory = /* @__PURE__ */ new Map();
36196
- var inFlight2 = /* @__PURE__ */ new Map();
36197
- function depsWith(deps2) {
36198
- return {
36199
- now: deps2.now ?? (() => Date.now()),
36200
- probe: deps2.probe ?? customProviders_1.probeModels,
36201
- readRecord: deps2.readRecord ?? readRecordFromDisk,
36202
- writeRecord: deps2.writeRecord ?? writeRecordToDisk
36203
- };
36222
+ function lexicalSimilarity(a, b2) {
36223
+ return Math.round(jaccard(tokens(a), tokens(b2)) * 1e3) / 1e3;
36204
36224
  }
36205
- async function probeAndStore(entry, d2) {
36206
- const key = normalizeBaseUrl(entry.baseUrl);
36207
- const existing = inFlight2.get(key);
36208
- if (existing !== void 0)
36209
- return existing;
36210
- const run3 = (async () => {
36211
- const models = await d2.probe(entry.baseUrl, await (0, customProviders_1.resolveApiKey)(entry));
36212
- if (models === null || models.length === 0)
36213
- return models;
36214
- const record = {
36215
- version: exports2.CATALOG_SCHEMA_VERSION,
36216
- baseUrl: entry.baseUrl,
36217
- fetchedAt: d2.now(),
36218
- models
36219
- };
36220
- memory.set(key, record);
36221
- await d2.writeRecord(record);
36222
- return models;
36223
- })().finally(() => inFlight2.delete(key));
36224
- inFlight2.set(key, run3);
36225
- 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;
36226
36228
  }
36227
- async function endpointCatalog2(entry, options = {}) {
36228
- const d2 = depsWith(options);
36229
- const key = normalizeBaseUrl(entry.baseUrl);
36230
- let record = memory.get(key) ?? null;
36231
- if (record === null) {
36232
- record = await d2.readRecord(entry.baseUrl);
36233
- if (record !== null)
36234
- memory.set(key, record);
36235
- }
36236
- if (options.cachedOnly === true)
36237
- return record?.models ?? [];
36238
- const fresh = record !== null && d2.now() - record.fetchedAt < exports2.CATALOG_TTL_MS;
36239
- if (record !== null && fresh && options.force !== true)
36240
- return record.models;
36241
- if (record !== null) {
36242
- void probeAndStore(entry, d2).catch(() => void 0);
36243
- return record.models;
36244
- }
36245
- return await probeAndStore(entry, d2) ?? [];
36229
+ var MODE_CACHE_TTL_MS = 5e3;
36230
+ var modeCache = /* @__PURE__ */ new Map();
36231
+ function clearDuetRoutingLogCache() {
36232
+ modeCache.clear();
36246
36233
  }
36247
- function findProbedModel(models, id) {
36248
- return models.find((model) => model.id === id);
36234
+ function coerceMode(raw) {
36235
+ return raw === "full" || raw === "head" || raw === "off" ? raw : null;
36249
36236
  }
36250
- function resolveModelSettings2(entry, modelId, catalog = []) {
36251
- const declared = entry.modelConfig?.[modelId];
36252
- const probed = findProbedModel(catalog, modelId);
36253
- const resolved = {};
36254
- const contextWindow = declared?.contextWindow ?? probed?.contextWindow;
36255
- if (contextWindow !== void 0)
36256
- resolved.contextWindow = contextWindow;
36257
- const maxOutputTokens = declared?.maxOutputTokens ?? probed?.maxOutputTokens;
36258
- if (maxOutputTokens !== void 0)
36259
- resolved.maxOutputTokens = maxOutputTokens;
36260
- if (probed?.reasoning !== void 0)
36261
- resolved.reasoning = probed.reasoning;
36262
- for (const knob of ["temperature", "topP", "topK", "repetitionPenalty"]) {
36263
- const value = declared?.[knob];
36264
- if (typeof value === "number")
36265
- 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;
36266
36245
  }
36267
- return resolved;
36268
- }
36269
- function catalogModelIds2(entry, catalog) {
36270
- return entry.models?.length ? entry.models : catalog.map((model) => model.id);
36271
36246
  }
36272
- function clearEndpointCatalog3(baseUrl) {
36273
- if (baseUrl === void 0) {
36274
- memory.clear();
36275
- inFlight2.clear();
36276
- sweptThisProcess = false;
36277
- 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;
36278
36260
  }
36279
- const key = normalizeBaseUrl(baseUrl);
36280
- memory.delete(key);
36281
- inFlight2.delete(key);
36261
+ modeCache.set(key, { at: Date.now(), mode });
36262
+ return mode;
36282
36263
  }
36283
- async function endpointModelViews2(entry, options = {}) {
36284
- const catalog = await endpointCatalog2(entry, options);
36285
- const pinned = new Set(entry.models ?? []);
36286
- const ids = [...pinned, ...catalog.map((model) => model.id).filter((id) => !pinned.has(id))];
36287
- return ids.map((id) => {
36288
- const resolved = resolveModelSettings2(entry, id, catalog);
36289
- const declared = entry.modelConfig?.[id];
36290
- const view = { id, pinned: pinned.has(id) };
36291
- if (resolved.contextWindow !== void 0)
36292
- view.contextWindow = resolved.contextWindow;
36293
- if (resolved.maxOutputTokens !== void 0)
36294
- view.maxOutputTokens = resolved.maxOutputTokens;
36295
- if (resolved.reasoning !== void 0)
36296
- view.reasoning = resolved.reasoning;
36297
- if (declared?.contextWindow !== void 0 || declared?.maxOutputTokens !== void 0) {
36298
- view.source = "user";
36299
- } else if (view.contextWindow !== void 0 || view.maxOutputTokens !== void 0) {
36300
- view.source = "endpoint";
36301
- }
36302
- return view;
36303
- });
36264
+ function head(text, max) {
36265
+ return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
36304
36266
  }
36305
- async function updateCustomProviderModels2(name2, update, tier = "user", opts = {}) {
36306
- const entry = await (0, customProviders_1.getCustomProvider)(name2, opts);
36307
- if (entry === null)
36308
- return false;
36309
- const next = { ...entry };
36310
- if (update.models !== void 0) {
36311
- if (update.models.length)
36312
- next.models = update.models;
36313
- else
36314
- 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) };
36315
36274
  }
36316
- if (update.modelConfig !== void 0) {
36317
- 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);
36318
- if (kept.length)
36319
- next.modelConfig = Object.fromEntries(kept);
36320
- else
36321
- 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 {
36322
36294
  }
36323
- await (0, customProviders_1.saveCustomProvider)(next, tier, opts);
36324
- clearEndpointCatalog3(entry.baseUrl);
36325
- return true;
36295
+ await fs15.appendFile(file, `${JSON.stringify(redacted)}
36296
+ `, "utf8");
36326
36297
  }
36327
- }
36328
- });
36329
-
36330
- // ../packages/orion-client-core/dist/duetExecutorCatalog.js
36331
- var require_duetExecutorCatalog = __commonJS({
36332
- "../packages/orion-client-core/dist/duetExecutorCatalog.js"(exports2) {
36333
- "use strict";
36334
- Object.defineProperty(exports2, "__esModule", { value: true });
36335
- exports2.LOCAL_EXECUTOR_READ_BUDGET_MS = void 0;
36336
- exports2.localExecutorOptions = localExecutorOptions2;
36337
- exports2.duetExecutorChoiceFor = duetExecutorChoiceFor2;
36338
- exports2.isLocalExecutorChoice = isLocalExecutorChoice;
36339
- exports2.resolveDuetExecutorChoice = resolveDuetExecutorChoice2;
36340
- var customProviders_js_1 = require_customProviders();
36341
- var customProviderModels_js_1 = require_customProviderModels();
36342
- exports2.LOCAL_EXECUTOR_READ_BUDGET_MS = 3e3;
36343
- async function localExecutorOptions2(input = {}) {
36344
- const { catalog, timeoutMs, ...opts } = input;
36345
- 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;
36346
36309
  try {
36347
- entries = await (0, customProviders_js_1.loadCustomProviders)(opts);
36310
+ text = await fs15.readFile(duetRoutingLogPath2(opts), "utf8");
36348
36311
  } catch {
36349
36312
  return [];
36350
36313
  }
36351
- if (entries.length === 0)
36352
- return [];
36353
- 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;
36354
36318
  try {
36355
- const views = await (0, customProviderModels_js_1.endpointModelViews)(entry, options);
36356
- return views.map((view) => {
36357
- const option = {
36358
- provider: `custom:${entry.name}`,
36359
- endpoint: entry.name,
36360
- model: view.id,
36361
- pinned: view.pinned
36362
- };
36363
- if (view.contextWindow !== void 0)
36364
- option.contextWindow = view.contextWindow;
36365
- if (view.maxOutputTokens !== void 0)
36366
- option.maxOutputTokens = view.maxOutputTokens;
36367
- return option;
36368
- });
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
+ }
36369
36323
  } catch {
36370
- return [];
36371
36324
  }
36372
- })).then((perEndpoint) => perEndpoint.flat());
36373
- const full = read(catalog ?? {});
36374
- const budget = timeoutMs ?? exports2.LOCAL_EXECUTOR_READ_BUDGET_MS;
36375
- if (catalog?.cachedOnly === true || budget <= 0)
36376
- return full;
36377
- let timer;
36378
- const fallback = new Promise((resolve5) => {
36379
- timer = setTimeout(() => resolve5(read({ ...catalog, cachedOnly: true })), budget);
36380
- });
36381
- try {
36382
- return await Promise.race([full, fallback]);
36383
- } finally {
36384
- if (timer !== void 0)
36385
- clearTimeout(timer);
36386
- void full.catch(() => void 0);
36387
36325
  }
36326
+ return rows;
36388
36327
  }
36389
- function duetExecutorChoiceFor2(option) {
36390
- return {
36391
- provider: option.provider,
36392
- model: option.model,
36393
- ...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 }
36394
36343
  };
36395
- }
36396
- function isLocalExecutorChoice(choice) {
36397
- return typeof choice?.provider === "string" && choice.provider.startsWith("custom:");
36398
- }
36399
- async function resolveDuetExecutorChoice2(choice, input = {}) {
36400
- if (!isLocalExecutorChoice(choice) || choice.contextWindow !== void 0)
36401
- return choice;
36402
- const found = (await localExecutorOptions2(input)).find((option) => option.provider === choice.provider && option.model === choice.model);
36403
- return found === void 0 ? choice : { ...choice, ...duetExecutorChoiceFor2(found), ...choice.effort ? { effort: choice.effort } : {} };
36404
- }
36405
- }
36406
- });
36407
-
36408
- // ../packages/orion-client-core/dist/duetRoutingSignals.js
36409
- var require_duetRoutingSignals = __commonJS({
36410
- "../packages/orion-client-core/dist/duetRoutingSignals.js"(exports2) {
36411
- "use strict";
36412
- Object.defineProperty(exports2, "__esModule", { value: true });
36413
- 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;
36414
36409
  exports2.cosineSimilarity = cosineSimilarity;
36415
36410
  exports2.normalizeRerankScores = normalizeRerankScores;
36416
36411
  exports2.buildJudgeMessages = buildJudgeMessages;
@@ -36584,276 +36579,6 @@ Does this message invalidate any plan assumption or require architectural re-pla
36584
36579
  }
36585
36580
  });
36586
36581
 
36587
- // ../packages/orion-client-core/dist/duetRoutingLog.js
36588
- var require_duetRoutingLog = __commonJS({
36589
- "../packages/orion-client-core/dist/duetRoutingLog.js"(exports2) {
36590
- "use strict";
36591
- var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m2, k, k2) {
36592
- if (k2 === void 0) k2 = k;
36593
- var desc = Object.getOwnPropertyDescriptor(m2, k);
36594
- if (!desc || ("get" in desc ? !m2.__esModule : desc.writable || desc.configurable)) {
36595
- desc = { enumerable: true, get: function() {
36596
- return m2[k];
36597
- } };
36598
- }
36599
- Object.defineProperty(o, k2, desc);
36600
- } : function(o, m2, k, k2) {
36601
- if (k2 === void 0) k2 = k;
36602
- o[k2] = m2[k];
36603
- });
36604
- var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v2) {
36605
- Object.defineProperty(o, "default", { enumerable: true, value: v2 });
36606
- } : function(o, v2) {
36607
- o["default"] = v2;
36608
- });
36609
- var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
36610
- var ownKeys = function(o) {
36611
- ownKeys = Object.getOwnPropertyNames || function(o2) {
36612
- var ar = [];
36613
- for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
36614
- return ar;
36615
- };
36616
- return ownKeys(o);
36617
- };
36618
- return function(mod2) {
36619
- if (mod2 && mod2.__esModule) return mod2;
36620
- var result = {};
36621
- if (mod2 != null) {
36622
- for (var k = ownKeys(mod2), i2 = 0; i2 < k.length; i2++) if (k[i2] !== "default") __createBinding(result, mod2, k[i2]);
36623
- }
36624
- __setModuleDefault(result, mod2);
36625
- return result;
36626
- };
36627
- }();
36628
- Object.defineProperty(exports2, "__esModule", { value: true });
36629
- 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;
36630
- exports2.duetRoutingLogPath = duetRoutingLogPath2;
36631
- exports2.newDecisionId = newDecisionId;
36632
- exports2.sessionKey = sessionKey;
36633
- exports2.lexicalSimilarity = lexicalSimilarity;
36634
- exports2.planDiffRatio = planDiffRatio;
36635
- exports2.clearDuetRoutingLogCache = clearDuetRoutingLogCache;
36636
- exports2.duetRoutingLogMode = duetRoutingLogMode2;
36637
- exports2.redactRowForMode = redactRowForMode;
36638
- exports2.appendDuetRoutingRow = appendDuetRoutingRow;
36639
- exports2.readDuetRoutingLog = readDuetRoutingLog2;
36640
- exports2.summarizeDuetRoutingLog = summarizeDuetRoutingLog2;
36641
- exports2.formatDuetRoutingLogSummary = formatDuetRoutingLogSummary2;
36642
- var node_crypto_1 = __require("node:crypto");
36643
- var fs15 = __importStar(__require("node:fs/promises"));
36644
- var os9 = __importStar(__require("node:os"));
36645
- var path14 = __importStar(__require("node:path"));
36646
- var settingsPaths_js_1 = require_settingsPaths();
36647
- exports2.DUET_ROUTING_LOG_SCHEMA = 3;
36648
- exports2.DUET_ROUTING_LOG_MAX_BYTES = 5 * 1024 * 1024;
36649
- exports2.DUET_ROUTING_LOG_HEAD_CHARS = 200;
36650
- exports2.DUET_ROUTING_LOG_KEY = "duetRoutingLog";
36651
- exports2.DUET_ROUTING_LOG_DEFAULT_MODE = "full";
36652
- function duetRoutingLogPath2(opts = {}) {
36653
- return path14.join(opts.homeDir ?? os9.homedir(), ".orion", "duet-routing-decisions.jsonl");
36654
- }
36655
- function newDecisionId() {
36656
- return (0, node_crypto_1.randomUUID)();
36657
- }
36658
- function sessionKey(sessionId) {
36659
- if (sessionId === void 0 || sessionId === "")
36660
- return void 0;
36661
- return (0, node_crypto_1.createHash)("sha256").update(sessionId).digest("hex").slice(0, 12);
36662
- }
36663
- function tokens(text) {
36664
- return new Set(text.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 1));
36665
- }
36666
- function jaccard(a, b2) {
36667
- if (a.size === 0 && b2.size === 0)
36668
- return 1;
36669
- let inter = 0;
36670
- for (const t of a)
36671
- if (b2.has(t))
36672
- inter += 1;
36673
- const union = a.size + b2.size - inter;
36674
- return union === 0 ? 0 : inter / union;
36675
- }
36676
- function lexicalSimilarity(a, b2) {
36677
- return Math.round(jaccard(tokens(a), tokens(b2)) * 1e3) / 1e3;
36678
- }
36679
- function planDiffRatio(before, after) {
36680
- const lines = (plan) => new Set(plan.split(/\r?\n/).map((l3) => l3.trim()).filter((l3) => l3 !== ""));
36681
- return Math.round((1 - jaccard(lines(before), lines(after))) * 1e3) / 1e3;
36682
- }
36683
- var MODE_CACHE_TTL_MS = 5e3;
36684
- var modeCache = /* @__PURE__ */ new Map();
36685
- function clearDuetRoutingLogCache() {
36686
- modeCache.clear();
36687
- }
36688
- function coerceMode(raw) {
36689
- return raw === "full" || raw === "head" || raw === "off" ? raw : null;
36690
- }
36691
- async function readTierMode(file) {
36692
- if (file === null)
36693
- return null;
36694
- try {
36695
- const parsed = JSON.parse(await fs15.readFile(file, "utf8"));
36696
- return coerceMode(parsed?.[exports2.DUET_ROUTING_LOG_KEY]?.mode);
36697
- } catch {
36698
- return null;
36699
- }
36700
- }
36701
- async function duetRoutingLogMode2(opts = {}) {
36702
- const home = opts.homeDir ?? os9.homedir();
36703
- const ws = opts.workspaceRoot ?? null;
36704
- const key = `${home}\0${ws ?? ""}`;
36705
- const hit = modeCache.get(key);
36706
- if (hit !== void 0 && Date.now() - hit.at < MODE_CACHE_TTL_MS)
36707
- return hit.mode;
36708
- let mode = exports2.DUET_ROUTING_LOG_DEFAULT_MODE;
36709
- const tiers = ["user", "project", "local"];
36710
- for (const tier of tiers) {
36711
- const found = await readTierMode((0, settingsPaths_js_1.settingsFilePath)(tier, { homeDir: home, workspaceRoot: ws }));
36712
- if (found !== null)
36713
- mode = found;
36714
- }
36715
- modeCache.set(key, { at: Date.now(), mode });
36716
- return mode;
36717
- }
36718
- function head(text, max) {
36719
- return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
36720
- }
36721
- function redactRowForMode(row, mode) {
36722
- if (mode === "off")
36723
- return null;
36724
- if (mode === "full")
36725
- return row;
36726
- if (row.kind === "planner") {
36727
- return row.brief === void 0 ? row : { ...row, brief: head(row.brief, exports2.DUET_ROUTING_LOG_HEAD_CHARS) };
36728
- }
36729
- if (row.kind !== "decision")
36730
- return row;
36731
- return {
36732
- ...row,
36733
- prompt: head(row.prompt, exports2.DUET_ROUTING_LOG_HEAD_CHARS),
36734
- assumptions: row.assumptions.map((a) => ({ id: a.id, text: head(a.text, 100) }))
36735
- };
36736
- }
36737
- var writeQueues = /* @__PURE__ */ new Map();
36738
- async function writeRow(row, file, opts) {
36739
- const redacted = redactRowForMode(row, await duetRoutingLogMode2(opts));
36740
- if (redacted === null)
36741
- return;
36742
- await fs15.mkdir(path14.dirname(file), { recursive: true });
36743
- try {
36744
- const stat = await fs15.stat(file);
36745
- if (stat.size >= exports2.DUET_ROUTING_LOG_MAX_BYTES)
36746
- await fs15.rename(file, `${file}.1`);
36747
- } catch {
36748
- }
36749
- await fs15.appendFile(file, `${JSON.stringify(redacted)}
36750
- `, "utf8");
36751
- }
36752
- async function appendDuetRoutingRow(row, opts = {}) {
36753
- const file = duetRoutingLogPath2(opts);
36754
- const previous = writeQueues.get(file) ?? Promise.resolve();
36755
- const next = previous.then(() => writeRow(row, file, opts)).catch(() => void 0);
36756
- writeQueues.set(file, next);
36757
- await next;
36758
- if (writeQueues.get(file) === next)
36759
- writeQueues.delete(file);
36760
- }
36761
- async function readDuetRoutingLog2(opts = {}) {
36762
- let text;
36763
- try {
36764
- text = await fs15.readFile(duetRoutingLogPath2(opts), "utf8");
36765
- } catch {
36766
- return [];
36767
- }
36768
- const rows = [];
36769
- for (const line of text.split("\n")) {
36770
- if (line.trim() === "")
36771
- continue;
36772
- try {
36773
- const parsed = JSON.parse(line);
36774
- if (parsed.kind === "decision" || parsed.kind === "turn_end" || parsed.kind === "followup" || parsed.kind === "planner") {
36775
- rows.push(parsed);
36776
- }
36777
- } catch {
36778
- }
36779
- }
36780
- return rows;
36781
- }
36782
- function summarizeDuetRoutingLog2(rows) {
36783
- const summary = {
36784
- decisions: 0,
36785
- routes: { plan: 0, execute: 0 },
36786
- stage1PlanReasons: {},
36787
- advisorEvaluated: 0,
36788
- advisorFlagged: {},
36789
- turnEnds: { completed: 0, error: 0, cancelled: 0 },
36790
- followups: 0,
36791
- missedEscalations: 0,
36792
- flaggedWithoutNewPlan: 0,
36793
- flaggedBarelyChanged: 0,
36794
- repeats: 0,
36795
- entries: { planner: 0, router: 0 },
36796
- plannerVerdicts: { hand_off: 0, plan: 0 }
36797
- };
36798
- const decisions = /* @__PURE__ */ new Map();
36799
- for (const row of rows) {
36800
- if (row.kind !== "decision")
36801
- continue;
36802
- decisions.set(row.id, row);
36803
- summary.decisions += 1;
36804
- summary.routes[row.route] += 1;
36805
- summary.entries[row.entry ?? "router"] += 1;
36806
- if (row.stage1.verdict === "plan") {
36807
- summary.stage1PlanReasons[row.stage1.reason] = (summary.stage1PlanReasons[row.stage1.reason] ?? 0) + 1;
36808
- }
36809
- if (row.advisor !== null) {
36810
- summary.advisorEvaluated += 1;
36811
- if (row.advisor.reason !== null) {
36812
- summary.advisorFlagged[row.advisor.reason] = (summary.advisorFlagged[row.advisor.reason] ?? 0) + 1;
36813
- }
36814
- }
36815
- }
36816
- for (const row of rows) {
36817
- if (row.kind === "turn_end") {
36818
- summary.turnEnds[row.outcome] += 1;
36819
- } else if (row.kind === "planner") {
36820
- summary.plannerVerdicts[row.verdict] += 1;
36821
- } else if (row.kind === "followup") {
36822
- summary.followups += 1;
36823
- const decided = decisions.get(row.decisionId);
36824
- if (row.nextPromptSimilarity !== null && row.nextPromptSimilarity >= 0.8)
36825
- summary.repeats += 1;
36826
- if (decided === void 0)
36827
- continue;
36828
- if (decided.route === "execute" && (row.replanActor || row.nextExplicitPlanRequest)) {
36829
- summary.missedEscalations += 1;
36830
- }
36831
- if (decided.advisor?.flagged) {
36832
- if (!row.planVersionChanged)
36833
- summary.flaggedWithoutNewPlan += 1;
36834
- else if (row.planDiffRatio !== null && row.planDiffRatio < 0.1)
36835
- summary.flaggedBarelyChanged += 1;
36836
- }
36837
- }
36838
- }
36839
- return summary;
36840
- }
36841
- function formatDuetRoutingLogSummary2(summary, file, mode) {
36842
- const byKey = (m2) => Object.entries(m2).sort((a, b2) => b2[1] - a[1]).map(([k, n]) => `${k} ${n}`).join(", ") || "none";
36843
- return [
36844
- `Duet routing journal: ${file} (mode: ${mode})`,
36845
- `decisions ${summary.decisions} \u2014 plan ${summary.routes.plan}, execute ${summary.routes.execute}`,
36846
- `entry: planner ${summary.entries.planner}, router ${summary.entries.router}`,
36847
- `planner verdicts: handed off ${summary.plannerVerdicts.hand_off}, planned ${summary.plannerVerdicts.plan}`,
36848
- `stage-1 plan rules: ${byKey(summary.stage1PlanReasons)}`,
36849
- `advisor evaluated ${summary.advisorEvaluated}; flagged: ${byKey(summary.advisorFlagged)}`,
36850
- `turn ends \u2014 completed ${summary.turnEnds.completed}, error ${summary.turnEnds.error}, cancelled ${summary.turnEnds.cancelled}`,
36851
- `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}`
36852
- ];
36853
- }
36854
- }
36855
- });
36856
-
36857
36582
  // ../packages/orion-client-core/dist/duetRoutingAdvisor.js
36858
36583
  var require_duetRoutingAdvisor = __commonJS({
36859
36584
  "../packages/orion-client-core/dist/duetRoutingAdvisor.js"(exports2) {
@@ -37165,303 +36890,1196 @@ var require_duetRoutingAdvisor = __commonJS({
37165
36890
  state.backoffUntil = now2() + exports2.DUET_ADVISOR_FAILURE_BACKOFF_MS;
37166
36891
  return candidate;
37167
36892
  }
37168
- function sinkFor(log, homeDir, workspaceRoot) {
37169
- if (log === null)
36893
+ function sinkFor(log, homeDir, workspaceRoot) {
36894
+ if (log === null)
36895
+ return null;
36896
+ if (log !== void 0)
36897
+ return log;
36898
+ return (row) => (0, duetRoutingLog_js_1.appendDuetRoutingRow)(row, { homeDir, workspaceRoot: workspaceRoot ?? null });
36899
+ }
36900
+ function emit(sink, row) {
36901
+ if (sink === null)
36902
+ return;
36903
+ try {
36904
+ void Promise.resolve(sink(row)).catch(() => void 0);
36905
+ } catch {
36906
+ }
36907
+ }
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)
37170
37834
  return null;
37171
- if (log !== void 0)
37172
- return log;
37173
- return (row) => (0, duetRoutingLog_js_1.appendDuetRoutingRow)(row, { homeDir, workspaceRoot: workspaceRoot ?? 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;
37174
37842
  }
37175
- function emit(sink, row) {
37176
- if (sink === null)
37843
+ var sweptThisProcess = false;
37844
+ async function gcEndpointCatalogs(now2, homeDir = os9.homedir()) {
37845
+ if (sweptThisProcess)
37177
37846
  return;
37847
+ sweptThisProcess = true;
37178
37848
  try {
37179
- void Promise.resolve(sink(row)).catch(() => void 0);
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
+ }
37180
37863
  } catch {
37181
37864
  }
37182
37865
  }
37183
- function stage1Verdict(record, text, entry) {
37184
- if ((0, duetPlan_js_1.explicitPlanRequest)(text))
37185
- return { verdict: "plan", reason: "explicit_plan_request" };
37186
- if (record === null) {
37187
- if ((0, duetPlan_js_1.highRiskRequest)(text))
37188
- return { verdict: "plan", reason: "plan_invalid" };
37189
- return entry === "planner" ? { verdict: "plan", reason: "planner_entry" } : { verdict: "execute", reason: "no_plan" };
37190
- }
37191
- if (record.scopeChanged)
37192
- return { verdict: "plan", reason: "scope_changed" };
37193
- if (record.architectureDecisionRequired) {
37194
- return { verdict: "plan", reason: "architecture_decision_required" };
37195
- }
37196
- if (record.planningFailures >= 2)
37197
- return { verdict: "plan", reason: "failed_attempts" };
37198
- if (record.userNegativeFeedback)
37199
- return { verdict: "plan", reason: "negative_feedback" };
37200
- if (entry === "planner") {
37201
- return (0, duetPlan_js_1.continuationRequest)(text) ? { verdict: "execute", reason: "continuation" } : { verdict: "plan", reason: "planner_entry" };
37866
+ async function writeRecordToDisk(record) {
37867
+ try {
37868
+ await (0, common_1.writeJsonFile)(catalogPathFor(record.baseUrl), record);
37869
+ } catch {
37202
37870
  }
37203
- return { verdict: "execute", reason: "plan_valid" };
37871
+ void gcEndpointCatalogs(record.fetchedAt);
37204
37872
  }
37205
- function executorContext(workspaceRoot) {
37206
- const choice = (0, duetMode_js_1.duetExecutorWireForSegment)(workspaceRoot);
37207
- const local = choice !== void 0 && (0, customProviders_js_1.isCustomProviderRef)(choice.provider);
37208
- const models = local ? (0, customProviders_js_1.endpointRoutingFor)(choice.provider)?.routingModels : void 0;
37873
+ var memory = /* @__PURE__ */ new Map();
37874
+ var inFlight2 = /* @__PURE__ */ new Map();
37875
+ function depsWith(deps2) {
37209
37876
  return {
37210
- executor: local ? "local" : "platform",
37211
- routingModels: {
37212
- embeddings: models?.embeddings !== void 0,
37213
- rerank: models?.rerank !== void 0,
37214
- judge: models?.judge !== void 0
37215
- }
37877
+ now: deps2.now ?? (() => Date.now()),
37878
+ probe: deps2.probe ?? customProviders_1.probeModels,
37879
+ readRecord: deps2.readRecord ?? readRecordFromDisk,
37880
+ writeRecord: deps2.writeRecord ?? writeRecordToDisk
37216
37881
  };
37217
37882
  }
37218
- function followupRow(last, standing, text, at) {
37219
- const versionChanged = standing !== null && standing.version !== last.planVersion;
37220
- return {
37221
- kind: "followup",
37222
- v: duetRoutingLog_js_1.DUET_ROUTING_LOG_SCHEMA,
37223
- decisionId: last.decisionId,
37224
- at,
37225
- planVersionChanged: versionChanged,
37226
- newPlanVersion: versionChanged ? standing.version : null,
37227
- planDiffRatio: versionChanged && last.planText !== null ? (0, duetRoutingLog_js_1.planDiffRatio)(last.planText, standing.plan) : null,
37228
- replanActor: standing !== null && standing.scopeChanged && !last.scopeChanged,
37229
- nextPromptSimilarity: text === "" ? null : (0, duetRoutingLog_js_1.lexicalSimilarity)(last.prompt, text),
37230
- nextExplicitPlanRequest: text !== "" && (0, duetPlan_js_1.explicitPlanRequest)(text),
37231
- planningFailuresDelta: standing === null ? 0 : standing.planningFailures - last.planningFailures,
37232
- executorFailuresDelta: standing === null ? 0 : standing.executorFailures - last.executorFailures,
37233
- planGone: last.planVersion > 0 && standing === null
37234
- };
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;
37235
37904
  }
37236
- function journalDuetTurnEnd2(state, end, opts = {}) {
37237
- const last = state.last;
37238
- if (last === null)
37239
- return;
37240
- emit(sinkFor(opts.log, opts.homeDir, opts.workspaceRoot), {
37241
- kind: "turn_end",
37242
- v: duetRoutingLog_js_1.DUET_ROUTING_LOG_SCHEMA,
37243
- decisionId: last.decisionId,
37244
- at: (/* @__PURE__ */ new Date()).toISOString(),
37245
- outcome: end.outcome,
37246
- executionLeg: end.executionLeg
37247
- });
37905
+ async function endpointCatalog2(entry, options = {}) {
37906
+ const d2 = depsWith(options);
37907
+ const key = normalizeBaseUrl(entry.baseUrl);
37908
+ let record = memory.get(key) ?? null;
37909
+ if (record === null) {
37910
+ record = await d2.readRecord(entry.baseUrl);
37911
+ if (record !== null)
37912
+ memory.set(key, record);
37913
+ }
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;
37922
+ }
37923
+ return await probeAndStore(entry, d2) ?? [];
37248
37924
  }
37249
- function journalDuetPlannerVerdict2(state, verdict, opts = {}) {
37250
- const last = state.last;
37251
- if (last === null)
37925
+ function findProbedModel(models, id) {
37926
+ return models.find((model) => model.id === id);
37927
+ }
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;
37946
+ }
37947
+ function catalogModelIds2(entry, catalog) {
37948
+ return entry.models?.length ? entry.models : catalog.map((model) => model.id);
37949
+ }
37950
+ function clearEndpointCatalog3(baseUrl) {
37951
+ if (baseUrl === void 0) {
37952
+ memory.clear();
37953
+ inFlight2.clear();
37954
+ sweptThisProcess = false;
37252
37955
  return;
37253
- emit(sinkFor(opts.log, opts.homeDir, opts.workspaceRoot), {
37254
- kind: "planner",
37255
- v: duetRoutingLog_js_1.DUET_ROUTING_LOG_SCHEMA,
37256
- decisionId: last.decisionId,
37257
- at: (/* @__PURE__ */ new Date()).toISOString(),
37258
- verdict: verdict.verdict,
37259
- ...verdict.verdict === "hand_off" ? { brief: verdict.brief } : {}
37260
- });
37956
+ }
37957
+ const key = normalizeBaseUrl(baseUrl);
37958
+ memory.delete(key);
37959
+ inFlight2.delete(key);
37261
37960
  }
37262
- async function adviseDuetRoute2(input) {
37263
- const { state } = input;
37264
- const now2 = input.now ?? Date.now;
37265
- const started = now2();
37266
- const at = new Date(started).toISOString();
37267
- const record = input.record ?? null;
37268
- const entry = input.entry ?? "router";
37269
- const routerVerdict = input.routerVerdict ? {
37270
- model: input.routerVerdict.model,
37271
- version: input.routerVerdict.version,
37272
- verdict: input.routerVerdict.verdict,
37273
- pPlan: Math.round(input.routerVerdict.pPlan * 1e6) / 1e6,
37274
- asksForPlan: input.routerVerdict.asksForPlan,
37275
- highRisk: input.routerVerdict.highRisk,
37276
- reason: input.routerVerdict.reason,
37277
- latencyMs: input.routerVerdict.latencyMs
37278
- } : null;
37279
- const sink = sinkFor(input.log, input.homeDir, input.workspaceRoot);
37280
- try {
37281
- const text = input.text.trim();
37282
- const standing = (0, duetPlan_js_1.duetPlanWireForSegment)(record) !== void 0 ? record : null;
37283
- if (state.last !== null) {
37284
- emit(sink, followupRow(state.last, standing, text, at));
37285
- state.last = null;
37286
- }
37287
- const journal = (stage12, advisor, route, assumptions2) => {
37288
- const id = (0, duetRoutingLog_js_1.newDecisionId)();
37289
- const session = (0, duetRoutingLog_js_1.sessionKey)(input.sessionId);
37290
- emit(sink, {
37291
- kind: "decision",
37292
- v: duetRoutingLog_js_1.DUET_ROUTING_LOG_SCHEMA,
37293
- id,
37294
- at,
37295
- ...session !== void 0 ? { session } : {},
37296
- entry,
37297
- planVersion: standing?.version ?? 0,
37298
- turnUnderVersion: state.turnsUnderVersion,
37299
- prompt: text,
37300
- assumptions: assumptions2,
37301
- ...executorContext(input.workspaceRoot),
37302
- stage1: stage12,
37303
- router: routerVerdict,
37304
- advisor: advisor === null ? null : {
37305
- stage: advisor.stage,
37306
- signals: advisor.signals,
37307
- guards: advisor.guards,
37308
- flagged: advisor.flagged,
37309
- reason: advisor.reason
37310
- },
37311
- route,
37312
- latencyMs: Math.max(0, now2() - started)
37313
- });
37314
- state.last = {
37315
- decisionId: id,
37316
- prompt: text,
37317
- route,
37318
- planVersion: standing?.version ?? 0,
37319
- planText: standing?.plan ?? null,
37320
- scopeChanged: standing?.scopeChanged ?? false,
37321
- planningFailures: standing?.planningFailures ?? 0,
37322
- executorFailures: standing?.executorFailures ?? 0
37323
- };
37324
- };
37325
- if (standing === null) {
37326
- resetForVersion(state, null);
37327
- if (text !== "") {
37328
- const stage12 = stage1Verdict(null, text, entry);
37329
- journal(stage12, null, stage12.verdict, []);
37330
- }
37331
- return untouched(record);
37332
- }
37333
- const plan = standing;
37334
- if (state.planVersion !== plan.version)
37335
- resetForVersion(state, plan.version);
37336
- state.turnsUnderVersion += 1;
37337
- if (text === "")
37338
- return untouched(record);
37339
- const assumptions = parsePlanAssumptions(plan.plan);
37340
- const stage1 = stage1Verdict(plan, text, entry);
37341
- if (stage1.verdict === "plan") {
37342
- journal(stage1, null, "plan", assumptions);
37343
- return untouched(record);
37344
- }
37345
- if (entry === "planner") {
37346
- journal(stage1, null, "execute", assumptions);
37347
- return untouched(record);
37348
- }
37349
- const decision = {
37350
- at,
37351
- planVersion: plan.version,
37352
- turnUnderVersion: state.turnsUnderVersion,
37353
- text: text.length > DECISION_TEXT_HEAD ? `${text.slice(0, DECISION_TEXT_HEAD - 1)}\u2026` : text,
37354
- stage: "cues",
37355
- signals: {},
37356
- guards: {},
37357
- flagged: null,
37358
- reason: null,
37359
- latencyMs: 0
37360
- };
37361
- let candidate = null;
37362
- const feedbackCue = negativeFeedbackCueIn(text);
37363
- const negationCue = negationCueIn(text);
37364
- if (feedbackCue !== null)
37365
- decision.signals.feedbackCue = feedbackCue;
37366
- if (negationCue !== null)
37367
- decision.signals.negationCue = negationCue;
37368
- if (feedbackCue !== null) {
37369
- candidate = { flag: "user_negative_feedback", reason: "negative_feedback_cue", ids: [] };
37370
- }
37371
- if (candidate === null) {
37372
- const endpoint = await advisorEndpoint(input.workspaceRoot);
37373
- const models = endpoint?.routing.routingModels;
37374
- if (endpoint !== null && models !== void 0) {
37375
- candidate = await semanticStages({
37376
- plan,
37377
- assumptions,
37378
- text,
37379
- negationCue,
37380
- dial: { baseUrl: endpoint.routing.baseUrl, apiKey: endpoint.routing.apiKey },
37381
- models,
37382
- executorModel: endpoint.executorModel,
37383
- state,
37384
- decision,
37385
- fetchImpl: input.fetchImpl
37386
- }, now2);
37387
- }
37388
- }
37389
- if (candidate !== null && state.turnsUnderVersion < exports2.DUET_ADVISOR_THRESHOLDS.cooldownTurns) {
37390
- decision.guards.cooldown = true;
37391
- candidate = null;
37392
- }
37393
- let advised = plan;
37394
- if (candidate !== null) {
37395
- advised = candidate.flag === "user_negative_feedback" ? { ...plan, userNegativeFeedback: true } : { ...plan, architectureDecisionRequired: true };
37396
- decision.flagged = candidate.flag;
37397
- 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";
37398
37979
  }
37399
- decision.latencyMs = Math.max(0, now2() - started);
37400
- journal(stage1, decision, decision.flagged !== null ? "plan" : "execute", assumptions);
37401
- return {
37402
- record: advised,
37403
- flagged: decision.flagged,
37404
- reason: decision.reason,
37405
- assumptionIds: candidate?.ids ?? [],
37406
- decision,
37407
- note: duetRoutingAdviceNote(decision.reason, candidate?.ids ?? [])
37408
- };
37409
- } catch {
37410
- return untouched(record);
37411
- }
37980
+ return view;
37981
+ });
37412
37982
  }
37413
- function round3(value) {
37414
- 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;
37415
38004
  }
37416
- 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;
37417
38024
  try {
37418
- const choice = await (0, duetMode_js_1.loadDuetExecutor)({ workspaceRoot: workspaceRoot ?? null });
37419
- if (choice === null || !(0, customProviders_js_1.isCustomProviderRef)(choice.provider))
37420
- return { kind: "platform" };
37421
- const name2 = (0, customProviders_js_1.parseCustomProviderRef)(choice.provider) ?? "";
37422
- const entry = await (0, customProviders_js_1.getCustomProvider)(name2, { workspaceRoot: workspaceRoot ?? null });
37423
- if (entry === null)
37424
- return { kind: "missing", name: name2 };
37425
- return {
37426
- kind: "local",
37427
- name: name2,
37428
- loopback: (0, customProviders_js_1.isLoopbackEndpoint)(entry.baseUrl),
37429
- embeddings: entry.routingModels?.embeddings !== void 0,
37430
- rerank: entry.routingModels?.rerank !== void 0,
37431
- judge: entry.routingModels?.judge ?? null
37432
- };
38025
+ entries = await (0, customProviders_js_1.loadCustomProviders)(opts);
37433
38026
  } catch {
37434
- return { kind: "platform" };
38027
+ return [];
37435
38028
  }
37436
- }
37437
- function duetRoutingSummaryLine2(summary) {
37438
- switch (summary.kind) {
37439
- case "platform":
37440
- return "Duet routing: rules only \u2014 a local executor with routing models unlocks re-ask detection and plan-assumption checks.";
37441
- case "missing":
37442
- return "Duet routing: rules only.";
37443
- case "local": {
37444
- const { name: name2, loopback, embeddings, rerank } = summary;
37445
- if (!embeddings && !rerank) {
37446
- 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).`;
37447
- }
37448
- if (!loopback) {
37449
- return `Duet routing: rules only \u2014 semantic checks run only against a loopback endpoint, and '${name2}' is not one.`;
37450
- }
37451
- const parts2 = [];
37452
- const via = [];
37453
- if (embeddings) {
37454
- parts2.push("re-ask detection");
37455
- via.push("embeddings");
37456
- }
37457
- if (rerank) {
37458
- parts2.push("plan-assumption checks");
37459
- via.push("rerank");
37460
- }
37461
- 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 [];
37462
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);
37463
38065
  }
37464
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
+ }
37465
38083
  }
37466
38084
  });
37467
38085
 
@@ -70770,6 +71388,8 @@ var require_dist = __commonJS({
70770
71388
  __exportStar(require_duetEntry(), exports2);
70771
71389
  __exportStar(require_duetRouterModel(), exports2);
70772
71390
  __exportStar(require_duetRouterInstall(), exports2);
71391
+ __exportStar(require_duetExecutorGate(), exports2);
71392
+ __exportStar(require_duetExecutorGateStatus(), exports2);
70773
71393
  __exportStar(require_duetPlan(), exports2);
70774
71394
  __exportStar(require_duetPlanners(), exports2);
70775
71395
  __exportStar(require_repoIdentity(), exports2);
@@ -91458,18 +92078,20 @@ ${(0, import_client_core20.duetRoutingSummaryLine)(await (0, import_client_core2
91458
92078
  kind: "local",
91459
92079
  name: "duet-entry",
91460
92080
  aliases: ["entry"],
91461
- description: "Choose who decides plan vs execute in Duet mode \u2014 the planner, or the router",
91462
- keywords: ["duet", "planner", "router", "plan", "execute", "hand off"],
91463
- 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]",
91464
92084
  run: async (args2, ctx) => {
91465
92085
  const workspaceRoot = ctx.config?.workspaceRoot;
91466
92086
  const typed = (0, import_client_core20.normalizeDuetEntry)(args2);
91467
92087
  const routerStatus = await (0, import_client_core20.describeDuetRouterModel)().catch(() => null);
92088
+ const executorStatus = await (0, import_client_core20.describeDuetExecutorGateCached)({ workspaceRoot }).catch(() => null);
91468
92089
  const save = async (entry) => {
91469
- const availability = (0, import_client_core20.duetEntryOptionAvailability)(entry, routerStatus);
92090
+ const availability = (0, import_client_core20.duetEntryOptionAvailability)(entry, routerStatus, executorStatus);
91470
92091
  if (availability.disabled) {
91471
92092
  ctx.print(`${(0, import_client_core20.duetEntryLabel)(entry)}: ${availability.note ?? "unavailable"}`, "warning");
91472
- 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");
91473
92095
  return;
91474
92096
  }
91475
92097
  await (0, import_client_core20.setDuetEntry)(entry);
@@ -91481,7 +92103,7 @@ ${(0, import_client_core20.duetRoutingSummaryLine)(await (0, import_client_core2
91481
92103
  return;
91482
92104
  }
91483
92105
  if (args2.trim() !== "") {
91484
- ctx.print("Usage: /duet-entry [planner|router]", "warning");
92106
+ ctx.print("Usage: /duet-entry [planner|router|executor]", "warning");
91485
92107
  return;
91486
92108
  }
91487
92109
  const active = await (0, import_client_core20.loadDuetEntry)({ workspaceRoot });
@@ -91491,7 +92113,7 @@ ${(0, import_client_core20.duetRoutingSummaryLine)(await (0, import_client_core2
91491
92113
  kind: "select",
91492
92114
  title: `${import_client_core20.DUET_ENTRY_INFO.label} \xB7 current: ${(0, import_client_core20.duetEntryLabel)(active)}`,
91493
92115
  options: import_client_core20.DUET_ENTRY_OPTIONS.map((option) => {
91494
- const availability = (0, import_client_core20.duetEntryOptionAvailability)(option.value, routerStatus);
92116
+ const availability = (0, import_client_core20.duetEntryOptionAvailability)(option.value, routerStatus, executorStatus);
91495
92117
  return {
91496
92118
  label: option.label,
91497
92119
  value: option.value,
@@ -111165,7 +111787,7 @@ function OrionRing() {
111165
111787
 
111166
111788
  // src/services/version.ts
111167
111789
  function tuiVersion() {
111168
- return "0.1.23".length > 0 ? "0.1.23" : null;
111790
+ return "0.1.24".length > 0 ? "0.1.24" : null;
111169
111791
  }
111170
111792
 
111171
111793
  // src/components/layout/WelcomeCard.tsx
@@ -118253,6 +118875,11 @@ async function main() {
118253
118875
  const duetAdvisorState = (0, import_client_core49.createDuetAdvisorState)();
118254
118876
  const duetRouterGate = (0, import_client_core49.createDuetRouterGate)({
118255
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
+ }),
118256
118883
  onError: (stage, error) => (
118257
118884
  // Same breadcrumb the IDE and the Power App leave (the log redirect captures it, so it
118258
118885
  // never corrupts the alt screen): without it a load or classify failure is invisible
@@ -119226,7 +119853,11 @@ async function main() {
119226
119853
  if (appStore.getState().mode === "duet") {
119227
119854
  const routed = await duetRouterGate.prepareTurn(
119228
119855
  (0, import_client_core49.duetEntryWireForSegment)(config.workspaceRoot),
119229
- 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 }
119230
119861
  );
119231
119862
  duetEntry = routed.entry;
119232
119863
  duetRouterVerdict = routed.verdict;