@ordewell/core 0.4.22 → 0.4.23

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/dist/index.js CHANGED
@@ -5589,10 +5589,10 @@ function checkModelAndModeValidity(runner, assignedModel, taskMode, catalog) {
5589
5589
  const models = catalog.modelsByRunner[runner];
5590
5590
  if (models) {
5591
5591
  const modelId = assignedModel.modelId;
5592
- if (!models.some((m) => m.modelId === modelId)) {
5592
+ const allowed = effectiveAllowlist(catalog.perRunnerAllowlist?.[runner], runner, catalog.modelsByRunner);
5593
+ if (!models.some((m) => m.modelId === modelId) && !allowed?.includes(modelId)) {
5593
5594
  return { ok: false, error: `Runner "${runner}" does not offer model "${modelId}"` };
5594
5595
  }
5595
- const allowed = effectiveAllowlist(catalog.perRunnerAllowlist?.[runner], runner, catalog.modelsByRunner);
5596
5596
  if (allowed && !allowed.includes(modelId)) {
5597
5597
  return { ok: false, error: `Model "${modelId}" is excluded by the allowlist for runner "${runner}"` };
5598
5598
  }
@@ -13314,7 +13314,6 @@ var Session = class {
13314
13314
  approvalPolicy;
13315
13315
  fetcher;
13316
13316
  settingsFn;
13317
- currentAllowlist = {};
13318
13317
  /** Last discovered model catalog — lets sync plan commits clamp thinking efforts to real variants. */
13319
13318
  modelsCache = {};
13320
13319
  unsubObserver = null;
@@ -13519,7 +13518,6 @@ var Session = class {
13519
13518
  this.beginFreshPlan();
13520
13519
  this.approvalPolicy.reset();
13521
13520
  this.modelsCache = {};
13522
- this.currentAllowlist = {};
13523
13521
  this.remintSessionId();
13524
13522
  }
13525
13523
  runnerModesFor(runners) {
@@ -13529,17 +13527,41 @@ var Session = class {
13529
13527
  * The catalog a model/task-mode edit is checked against — the same
13530
13528
  * discovered models and manifest modes the per-turn catalog block shows the
13531
13529
  * planner, so a refusal here can never name something invalid that the
13532
- * planner was never told about. `modelsCache` is read live, not filtered by
13533
- * the allowlist here — {@link checkModelAndModeValidity} narrows by
13530
+ * planner was never told about. The catalog is not filtered by the
13531
+ * allowlist here — {@link checkModelAndModeValidity} narrows by
13534
13532
  * allowlist itself, the same way `coerceAssignments` does.
13535
13533
  */
13536
13534
  editCatalog() {
13537
13535
  return {
13538
- modelsByRunner: this.modelsCache,
13536
+ modelsByRunner: this.models(),
13539
13537
  runnerModes: this.runnerModesFor(this.plan?.runners ?? []),
13540
- perRunnerAllowlist: this.settingsFn().modelAllowlist ?? this.currentAllowlist
13538
+ perRunnerAllowlist: this.allowlist()
13541
13539
  };
13542
13540
  }
13541
+ /**
13542
+ * The allowlist in force right now. Unset means no restriction — falling
13543
+ * back to the one planning started under would keep a restriction the user
13544
+ * has since cleared.
13545
+ */
13546
+ allowlist() {
13547
+ return this.settingsFn().modelAllowlist ?? {};
13548
+ }
13549
+ /**
13550
+ * The discovered catalog as the resolver holds it now, per runner, with this
13551
+ * session's own discovery as the fallback where the resolver has nothing
13552
+ * cached. The resolver's cache outlives this session's snapshot in both
13553
+ * directions — an allowlist picker re-discovers into it mid-session — and a
13554
+ * model allowed after that must reach the planner with its real label and
13555
+ * variants, not as an id-only stub. Never triggers discovery itself.
13556
+ */
13557
+ models() {
13558
+ const out = { ...this.modelsCache };
13559
+ for (const runner of /* @__PURE__ */ new Set([...Object.keys(out), ...this.plan?.runners ?? []])) {
13560
+ const cached2 = this.modelResolver.getCachedRunnerModels(runner);
13561
+ if (cached2.length > 0) out[runner] = cached2;
13562
+ }
13563
+ return out;
13564
+ }
13543
13565
  get planState() {
13544
13566
  return this.plan;
13545
13567
  }
@@ -13677,8 +13699,7 @@ var Session = class {
13677
13699
  this.modelsCache = modelsByRunner;
13678
13700
  const runnerModes = this.runnerModesFor(chosenRunners);
13679
13701
  const { verificationEnabled, modelAllowlist } = this.settingsFn();
13680
- this.currentAllowlist = modelAllowlist ?? {};
13681
- const filteredModels = filterModelsForPrompt(modelsByRunner, this.currentAllowlist);
13702
+ const filteredModels = filterModelsForPrompt(modelsByRunner, modelAllowlist ?? {});
13682
13703
  const now = (/* @__PURE__ */ new Date()).toISOString();
13683
13704
  this.plan = {
13684
13705
  tasks: [],
@@ -13803,12 +13824,12 @@ ${TASK_QUERY_ANSWER_OR_OPS}` : answer,
13803
13824
  */
13804
13825
  taskQueryAnswer(query) {
13805
13826
  const runners = this.plan?.runners ?? [];
13806
- const allowlist = this.settingsFn().modelAllowlist ?? this.currentAllowlist;
13827
+ const allowlist = this.allowlist();
13807
13828
  return renderTaskQueryAnswer(query, this.store.planTasks, {
13808
13829
  runners,
13809
13830
  // Allowlist-filtered like the always-on block: a read must not offer a
13810
13831
  // model the planner is forbidden to assign.
13811
- models: filterModelsForPrompt(this.modelsCache, allowlist),
13832
+ models: filterModelsForPrompt(this.models(), allowlist),
13812
13833
  modes: this.runnerModesFor(runners),
13813
13834
  autonomousDefault: this.config.autonomousMode
13814
13835
  });
@@ -13869,7 +13890,7 @@ The plan is unchanged. Rephrase the request, or adjust the tasks manually.`,
13869
13890
  *
13870
13891
  * Built from the allowlist-filtered view (`filterModelsForPrompt`), the same
13871
13892
  * one the system prompt used — a restricted allowlist stays a hard bound on
13872
- * every turn, not just the first. `this.modelsCache` itself is never
13893
+ * every turn, not just the first. {@link models} itself is never
13873
13894
  * filtered: `coerceAssignments` needs the full discovered catalog alongside
13874
13895
  * the allowlist to resolve labels and clamp effort to real variants.
13875
13896
  *
@@ -13879,8 +13900,8 @@ The plan is unchanged. Rephrase the request, or adjust the tasks manually.`,
13879
13900
  */
13880
13901
  catalogBlock() {
13881
13902
  if (!this.plan) return null;
13882
- const allowlist = this.settingsFn().modelAllowlist ?? this.currentAllowlist;
13883
- const filteredModels = filterModelsForPrompt(this.modelsCache, allowlist);
13903
+ const allowlist = this.allowlist();
13904
+ const filteredModels = filterModelsForPrompt(this.models(), allowlist);
13884
13905
  const runnerModes = this.runnerModesFor(this.plan.runners);
13885
13906
  const autonomousDefault = this.config.autonomousMode;
13886
13907
  const modelLines = this.plan.runners.map((runner) => {
@@ -13964,8 +13985,8 @@ Execution is RUNNING${locked.length ? ` \u2014 these tasks are locked: ${locked.
13964
13985
  const plan = this.mutatePlan(
13965
13986
  () => {
13966
13987
  this.plan.researchLog = [...this.plan.researchLog ?? [], ...turn.researchLog];
13967
- const allowlist = this.settingsFn().modelAllowlist ?? this.currentAllowlist;
13968
- const coerced = coerceAssignments(result.tasks, allowlist, this.plan.runners, this.modelsCache);
13988
+ const allowlist = this.allowlist();
13989
+ const coerced = coerceAssignments(result.tasks, allowlist, this.plan.runners, this.models());
13969
13990
  if (this.orchestrator.isRunning) {
13970
13991
  this.orchestrator.reconcilePlan(coerced, this.plan.runners);
13971
13992
  } else {
@@ -13997,8 +14018,7 @@ Execution is RUNNING${locked.length ? ` \u2014 these tasks are locked: ${locked.
13997
14018
  this.modelsCache = modelsByRunner;
13998
14019
  const runnerModes = this.runnerModesFor(runners);
13999
14020
  const { verificationEnabled, modelAllowlist } = this.settingsFn();
14000
- this.currentAllowlist = modelAllowlist ?? {};
14001
- const filteredModels = filterModelsForPrompt(modelsByRunner, this.currentAllowlist);
14021
+ const filteredModels = filterModelsForPrompt(modelsByRunner, modelAllowlist ?? {});
14002
14022
  const goal = this.goal || priorHistory.find((m) => m.role === "user")?.content || userMessage;
14003
14023
  return this.aiService.startConversation({
14004
14024
  goal,
@@ -14046,8 +14066,8 @@ Execution is RUNNING${locked.length ? ` \u2014 these tasks are locked: ${locked.
14046
14066
  return this.mutatePlan(() => {
14047
14067
  this.plan.researchLog = [...this.plan.researchLog ?? [], ...turn.researchLog];
14048
14068
  this.capturePrd(turn.text);
14049
- const allowlist = this.settingsFn().modelAllowlist ?? this.currentAllowlist;
14050
- const coerced = coerceAssignments(turn.tasks, allowlist, this.plan.runners, this.modelsCache);
14069
+ const allowlist = this.allowlist();
14070
+ const coerced = coerceAssignments(turn.tasks, allowlist, this.plan.runners, this.models());
14051
14071
  this.orchestrator.loadPlan(coerced, this.plan.runners);
14052
14072
  this.store.resetForRun({ preserveCompleted: false });
14053
14073
  this.appendTranscript("assistant", `Plan generated with ${coerced.length} task${coerced.length === 1 ? "" : "s"}.`, now, "plan_generated");
@@ -14298,7 +14318,7 @@ Execution is RUNNING${locked.length ? ` \u2014 these tasks are locked: ${locked.
14298
14318
  const allowed = effectiveAllowlist(
14299
14319
  this.settingsFn().modelAllowlist?.[runner],
14300
14320
  runner,
14301
- { ...this.modelsCache, [runner]: catalog.models }
14321
+ { ...this.models(), [runner]: catalog.models }
14302
14322
  );
14303
14323
  if (!allowed) return catalog;
14304
14324
  const models = catalog.models.filter((m) => allowed.includes(m.modelId));