@claudexor/orchestrator 3.6.0 → 3.8.0

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.
@@ -16,7 +16,7 @@ import { runPlannerAttempt as executePlannerAttempt, } from "./plannerAttempt.js
16
16
  import { HarnessRunSpec, ModeKind as ModeKindSchema, QuotaSnapshot as QuotaSnapshotSchema, isBlocking, makeOutcomeFacts, normalizeUserOutputSchema, strictifyOutputSchema, estimateEffectiveAuthRoute, } from "@claudexor/schema";
17
17
  import { globalConfigDir, loadConfig } from "@claudexor/config";
18
18
  import { acceptedTryOutput, AnswerAssembly, CLAUDEXOR_BROWSER_ARTIFACT_SUBDIR, countsAsAgentProgress, HarnessUnavailableError, summarizeDiffPaths as diffStats, withInactivityWatchdog, } from "@claudexor/core";
19
- import { assertRouteModelsAllowed } from "./modelGovernance.js";
19
+ import { assertRouteModelsAllowed, runModelGovernedRoute } from "./modelGovernance.js";
20
20
  import { authModeForCredentialRoute, authModeForPreference } from "./auth-route-classification.js";
21
21
  import { governRouteEffort } from "./effortGovernance.js";
22
22
  import { isFullAccess, RequestRequirementsResolver } from "./requestRequirements.js";
@@ -850,7 +850,7 @@ export class Orchestrator {
850
850
  }
851
851
  }
852
852
  // Strict pre-run model gate (INV-104) — see modelGovernance.ts.
853
- await assertRouteModelsAllowed(out, input.models, this.execRootOf(input));
853
+ await assertRouteModelsAllowed(out, input.models, this.execRootOf(input), (id) => routeContext ? (routeContext.envForHarness?.(id) ?? routeContext.env) : undefined);
854
854
  return out;
855
855
  }
856
856
  /**
@@ -1523,7 +1523,7 @@ export class Orchestrator {
1523
1523
  const rateLimitStart = telemetry.rateLimits.length;
1524
1524
  let rawPatch = null;
1525
1525
  try {
1526
- const watched = withInactivityWatchdog(adapter.run(runSpec), {
1526
+ const watched = withInactivityWatchdog(runModelGovernedRoute(routed, runSpec), {
1527
1527
  timeoutMs: inactivityMs,
1528
1528
  countsAsProgress: countsAsAgentProgress,
1529
1529
  onTimeout: () => {
@@ -4032,15 +4032,14 @@ export class Orchestrator {
4032
4032
  store.writeYaml(join(paths.contextDir, "task.yaml"), contract);
4033
4033
  log.emit("task.contract.created", { task_contract_hash: hashJson(contract) });
4034
4034
  // W3.3: ONE resolved read-only context — the routing point-probe and every
4035
- // planner spawn consume the SAME scoped env (see routeContext.ts). The
4036
- // probe home stays a disposable throwaway even for a thread lane turn (auth
4037
- // truth is home-independent); only the planner spawn swaps in the durable
4038
- // per-lane home below so its recorded native session survives.
4039
- const roHome = resolveReadOnlyRouteContext(this.execRootOf(input));
4035
+ // planner spawn consume the SAME scoped env (see routeContext.ts).
4040
4036
  // A thread PLAN turn is a chat turn (INV-034): plan candidates are distinct
4041
- // harnesses run sequentially, so each records its own lane's native session
4042
- // and the next lane turn resumes it via `sessionSpecFields.resume_session_id`.
4037
+ // harnesses run sequentially. Doctor, model inventory, and spawn share each
4038
+ // lane's durable HOME; the disposable context remains the non-thread fallback.
4043
4039
  const laneRun = Boolean(input.threadId);
4040
+ const roHome = resolveReadOnlyRouteContext(this.execRootOf(input), laneRun
4041
+ ? (id) => this.laneHomeEnvFor(input, id, input.credentialProfileId ?? null)
4042
+ : undefined);
4044
4043
  let adapters;
4045
4044
  try {
4046
4045
  adapters = await this.resolveCandidateAdapters({ ...input, n: undefined }, "plan", ledger, log, roHome, runId);
@@ -4401,17 +4400,13 @@ export class Orchestrator {
4401
4400
  : Math.min(Math.max(input.n ?? 2, 1), 3);
4402
4401
  // W3.3: ONE resolved read-only context — the routing point-probe and every
4403
4402
  // read-only attempt spawn consume the SAME scoped env (see routeContext.ts).
4404
- // The point-probe home is a disposable throwaway even for a thread lane
4405
- // turn: readiness auth truth is home-INDEPENDENT (credentials come from the
4406
- // profile/keychain/default store, never the scoped home), so the probe and
4407
- // the run share the same auth source; only the ACTUAL spawn swaps in the
4408
- // durable per-lane home below so the recorded native session survives.
4409
- const roHome = resolveReadOnlyRouteContext(this.execRootOf(input));
4410
4403
  // A thread ASK turn is a chat turn: its native session is recorded per lane
4411
- // and the next lane turn resumes it (INV-034). Deep-scan (multi-scout
4412
- // research) and orchestrate (tool-belt planner, not the user's chat) are
4413
- // NOT lane chat turns — they keep the disposable home and record nothing.
4404
+ // and the next lane turn resumes it (INV-034). Its doctor/model/spawn path
4405
+ // shares that lane HOME; deep-scan and one-shot asks keep the disposable one.
4414
4406
  const laneRun = Boolean(input.threadId) && opts.mode === "ask" && !opts.deepScan;
4407
+ const roHome = resolveReadOnlyRouteContext(this.execRootOf(input), laneRun
4408
+ ? (id) => this.laneHomeEnvFor(input, id, input.credentialProfileId ?? null)
4409
+ : undefined);
4415
4410
  let adapters;
4416
4411
  try {
4417
4412
  adapters = await this.resolveCandidateAdapters({ ...input, prompt, n: width }, opts.intent, ledger, log, roHome, runId,
@@ -4707,7 +4702,7 @@ export class Orchestrator {
4707
4702
  ...(knobs.ignored.length > 0 ? { ignored_settings: knobs.ignored } : {}),
4708
4703
  });
4709
4704
  try {
4710
- const watchedReport = withInactivityWatchdog(adapter.run(runSpec), {
4705
+ const watchedReport = withInactivityWatchdog(runModelGovernedRoute(routed, runSpec), {
4711
4706
  timeoutMs: harnessInactivityTimeoutMs(this.config(input.repoRoot)),
4712
4707
  countsAsProgress: countsAsAgentProgress,
4713
4708
  onTimeout: () => {