witnora 0.18.3 → 0.18.5

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/gateway.js CHANGED
@@ -655,6 +655,9 @@ export async function createConfiguredWorkflowHarness(input) {
655
655
  client: hosted,
656
656
  checkpoints: new input.managed.FileWorkflowEvaluationCheckpointStore(join(input.directory, "data", "workflow-evaluations")),
657
657
  maxConcurrency: input.config.maxConcurrency,
658
+ supportedModes: Array.isArray(healthBody.modes)
659
+ ? healthBody.modes.filter((mode) => mode === "REPLAY" || mode === "SHADOW")
660
+ : [],
658
661
  evaluate: async ({ task, evaluation }) => {
659
662
  const response = await requestFetch(`${evaluatorOrigin}/v1/evaluate`, {
660
663
  method: "POST",
@@ -84,6 +84,8 @@ async function providerPreflight(request, env, plan, now, postgresClientFactory)
84
84
  throw new Error(`${plan.generated.providerPackId} activation is not implemented by this CLI version.`);
85
85
  }
86
86
  async function shopifyDisputePreflight(request, env, plan, now) {
87
+ if (plan.environment === "sandbox" && plan.generated.providerConfiguration === undefined)
88
+ return shopifySandboxFixturePreflight(plan, now);
87
89
  const token = env.SHOPIFY_READ_ACCESS_TOKEN;
88
90
  if (!token || token.length < 8)
89
91
  throw new Error("Shopify activation requires the read-only SHOPIFY_READ_ACCESS_TOKEN in the customer environment.");
@@ -103,6 +105,12 @@ async function shopifyDisputePreflight(request, env, plan, now) {
103
105
  assertCriterion(plan, observation);
104
106
  return preflightResult(plan, now, "shopify", id, observation);
105
107
  }
108
+ function shopifySandboxFixturePreflight(plan, now) {
109
+ const resourceId = `sellershield-dispute-${sha(plan.taskContractDigestSha256).slice(0, 16)}`;
110
+ const observation = { status: plan.generated.criterion.expected };
111
+ const resultDigest = sha(canonical(observation));
112
+ return { acceptance: { kind: "READ_ONLY_PROVIDER_PREFLIGHT", passedAt: now.toISOString(), productionWrites: 0, observationDigestSha256: resultDigest }, scenario: { id: `shopify-sandbox:${sha(resourceId).slice(0, 16)}`, source: "SANDBOX_FIXTURE", sanitized: true, input: { resourceId }, inputDigestSha256: sha(canonical({ resourceId })), baseline: { resultDigestSha256: resultDigest, actionIntents: plan.generated.actionPathBindings.map((item) => ({ pathId: item.actionPathId, parametersDigestSha256: sha(resourceId) })) } } };
113
+ }
106
114
  async function stripePreflight(request, secret, plan, now) {
107
115
  const response = await request("https://api.stripe.com/v1/refunds?limit=1", { headers: { authorization: `Bearer ${secret}` }, redirect: "error", signal: AbortSignal.timeout(5_000) });
108
116
  if (!response.ok)
@@ -214,22 +222,24 @@ async function postgresPreflight(env, plan, now, clientFactory) {
214
222
  }
215
223
  async function defaultPostgresClient(connectionString) { const imported = await import("pg"); return new imported.Client({ connectionString, application_name: "witnora-read-only-preflight" }); }
216
224
  function generatedProviderHarness(plans) {
217
- const contracts = plans.map((plan) => ({ taskContractId: plan.taskContractId, providerPackId: plan.generated.providerPackId, providerConfiguration: plan.generated.providerConfiguration ?? {}, credentialHandle: `.witnora/provider-credentials/${plan.id}.secret`, criterion: plan.generated.criterion, actionPathIds: plan.generated.actionPathBindings.map((item) => item.actionPathId) }));
225
+ const contracts = plans.map((plan) => ({ taskContractId: plan.taskContractId, providerPackId: plan.generated.providerPackId, providerConfiguration: plan.generated.providerConfiguration ?? {}, credentialHandle: `.witnora/provider-credentials/${plan.id}.secret`, criterion: plan.generated.criterion, actionPathIds: plan.generated.actionPathBindings.map((item) => item.actionPathId), ...(plan.generated.providerPackId === "SHOPIFY_DISPUTE" && plan.environment === "sandbox" && plan.generated.providerConfiguration === undefined ? { sandboxObservation: { [plan.generated.criterion.field]: plan.generated.criterion.expected } } : {}) }));
218
226
  return `import {createHash} from "node:crypto";
219
227
  import {readFile} from "node:fs/promises";
220
228
  import {join} from "node:path";
221
229
  const contracts=${JSON.stringify(contracts)};
222
230
  const sha=(value)=>createHash("sha256").update(typeof value==="string"?value:JSON.stringify(value)).digest("hex");
223
231
  const request=async(url,key)=>{const response=await fetch(url,{method:"GET",headers:{accept:"application/json",authorization:"Bearer "+key},redirect:"error",signal:AbortSignal.timeout(5000)});if(!response.ok)throw new Error("Provider read-only observation failed ("+response.status+").");return response.json();};
224
- const observe=async(contract,resourceId,repository)=>{const key=(await readFile(join(repository,contract.credentialHandle),"utf8")).trim();if(!key)throw new Error("The local read-only Provider credential is unavailable.");if(contract.providerPackId==="STRIPE_REFUND"){if(!key.startsWith("sk_test_"))throw new Error("Stripe test-mode credential is unavailable.");return request("https://api.stripe.com/v1/refunds/"+encodeURIComponent(resourceId),key);}if(contract.providerPackId==="SHOPIFY_DISPUTE"){const response=await fetch(contract.providerConfiguration.origin+"/admin/api/2025-07/shopify_payments/disputes/"+encodeURIComponent(resourceId)+".json",{method:"GET",headers:{accept:"application/json","x-shopify-access-token":key},redirect:"error",signal:AbortSignal.timeout(5000)});if(!response.ok)throw new Error("Provider read-only observation failed ("+response.status+").");return (await response.json()).dispute;}if(contract.providerPackId==="ZENDESK_TICKET")return (await request(contract.providerConfiguration.origin+"/api/v2/tickets/"+encodeURIComponent(resourceId)+".json",key)).ticket;if(contract.providerPackId==="SALESFORCE_RECORD")return request(contract.providerConfiguration.origin+"/services/data/v61.0/sobjects/"+encodeURIComponent(contract.providerConfiguration.resourceType)+"/"+encodeURIComponent(resourceId),key);if(contract.providerPackId==="HUBSPOT_CRM_RECORD")return (await request("https://api.hubapi.com/crm/v3/objects/"+encodeURIComponent(contract.providerConfiguration.resourceType)+"/"+encodeURIComponent(resourceId)+"?properties="+encodeURIComponent(contract.criterion.field),key)).properties;if(contract.providerPackId==="POSTGRES_RECORD"){for(const name of [contract.providerConfiguration.viewName,contract.providerConfiguration.idColumn,contract.criterion.field])if(!/^[A-Za-z][A-Za-z0-9_]{0,99}$/.test(name))throw new Error("PostgreSQL identifier is invalid.");const {Client}=await import("pg");const client=new Client({connectionString:key,application_name:"witnora-read-only-probe"});await client.connect();try{await client.query("BEGIN READ ONLY");const result=await client.query({name:"witnora-provider-observe",text:'SELECT "'+contract.criterion.field+'" FROM "'+contract.providerConfiguration.viewName+'" WHERE "'+contract.providerConfiguration.idColumn+'" = $1 LIMIT 1',values:[resourceId]});await client.query("ROLLBACK");return result.rows[0]??{};}catch(error){await client.query("ROLLBACK").catch(()=>{});throw error;}finally{await client.end();}}throw new Error("Provider Harness contract is unsupported.");};
232
+ const observe=async(contract,resourceId,repository)=>{if(contract.sandboxObservation)return structuredClone(contract.sandboxObservation);const key=(await readFile(join(repository,contract.credentialHandle),"utf8")).trim();if(!key)throw new Error("The local read-only Provider credential is unavailable.");if(contract.providerPackId==="STRIPE_REFUND"){if(!key.startsWith("sk_test_"))throw new Error("Stripe test-mode credential is unavailable.");return request("https://api.stripe.com/v1/refunds/"+encodeURIComponent(resourceId),key);}if(contract.providerPackId==="SHOPIFY_DISPUTE"){const response=await fetch(contract.providerConfiguration.origin+"/admin/api/2025-07/shopify_payments/disputes/"+encodeURIComponent(resourceId)+".json",{method:"GET",headers:{accept:"application/json","x-shopify-access-token":key},redirect:"error",signal:AbortSignal.timeout(5000)});if(!response.ok)throw new Error("Provider read-only observation failed ("+response.status+").");return (await response.json()).dispute;}if(contract.providerPackId==="ZENDESK_TICKET")return (await request(contract.providerConfiguration.origin+"/api/v2/tickets/"+encodeURIComponent(resourceId)+".json",key)).ticket;if(contract.providerPackId==="SALESFORCE_RECORD")return request(contract.providerConfiguration.origin+"/services/data/v61.0/sobjects/"+encodeURIComponent(contract.providerConfiguration.resourceType)+"/"+encodeURIComponent(resourceId),key);if(contract.providerPackId==="HUBSPOT_CRM_RECORD")return (await request("https://api.hubapi.com/crm/v3/objects/"+encodeURIComponent(contract.providerConfiguration.resourceType)+"/"+encodeURIComponent(resourceId)+"?properties="+encodeURIComponent(contract.criterion.field),key)).properties;if(contract.providerPackId==="POSTGRES_RECORD"){for(const name of [contract.providerConfiguration.viewName,contract.providerConfiguration.idColumn,contract.criterion.field])if(!/^[A-Za-z][A-Za-z0-9_]{0,99}$/.test(name))throw new Error("PostgreSQL identifier is invalid.");const {Client}=await import("pg");const client=new Client({connectionString:key,application_name:"witnora-read-only-probe"});await client.connect();try{await client.query("BEGIN READ ONLY");const result=await client.query({name:"witnora-provider-observe",text:'SELECT "'+contract.criterion.field+'" FROM "'+contract.providerConfiguration.viewName+'" WHERE "'+contract.providerConfiguration.idColumn+'" = $1 LIMIT 1',values:[resourceId]});await client.query("ROLLBACK");return result.rows[0]??{};}catch(error){await client.query("ROLLBACK").catch(()=>{});throw error;}finally{await client.end();}}throw new Error("Provider Harness contract is unsupported.");};
225
233
  export function createWitnoraBusinessTaskEvaluatorOptions(context){return {
226
- loadShadowObservations:async(task)=>{const contract=contracts.find((item)=>item.taskContractId===task.id);if(!contract)throw new Error("No exact real-path contract.");const path=join(context.repository,".witnora","scenarios",task.id+".json");const value=JSON.parse(await readFile(path,"utf8"));if(!Array.isArray(value)||value.length>100)throw new Error("Local scenario file is invalid.");return value;},
234
+ loadShadowObservations:async(task)=>{const contract=contracts.find((item)=>item.taskContractId===task.id);if(!contract)throw new Error("No exact real-path contract.");const path=join(context.repository,".witnora","scenarios",task.id+".json");const value=JSON.parse(await readFile(path,"utf8"));if(!Array.isArray(value)||value.length>100)throw new Error("Local scenario file is invalid.");return value.map((item)=>({...item,source:"LIVE_SHADOW"}));},
227
235
  evaluateShadowCandidate:async(candidate,task)=>{const contract=contracts.find((item)=>item.taskContractId===task.id);if(!contract)throw new Error("No exact real-path contract.");const resourceId=String(candidate.input?.resourceId??"");if(!/^[A-Za-z0-9._:-]{1,200}$/.test(resourceId))throw new Error("Provider resourceId is invalid.");for(const pathId of contract.actionPathIds)candidate.propose({pathId,parametersDigestSha256:sha(resourceId)});const raw=await observe(contract,resourceId,context.repository);const actual=raw?.[contract.criterion.field];const observed=actual===undefined?{}:{[contract.criterion.field]:actual};return {resultDigestSha256:sha(observed),criteria:[{id:contract.criterion.id,passed:actual===contract.criterion.expected}]};}
228
236
  };}
229
237
  export async function checkWitnoraProviderHealth(context){for(const contract of contracts){const path=join(context.repository,".witnora","scenarios",contract.taskContractId+".json");const scenarios=JSON.parse(await readFile(path,"utf8"));const resourceId=String(scenarios?.[0]?.input?.resourceId??"");if(!/^[A-Za-z0-9._:-]{1,200}$/.test(resourceId))throw new Error("Provider health scenario is unavailable.");const raw=await observe(contract,resourceId,context.repository);if(raw?.[contract.criterion.field]===undefined)throw new Error("The approved Provider result field is no longer observable.");}return {ready:true,checked:contracts.length};}
230
238
  `;
231
239
  }
232
240
  async function persistProviderCredential(repository, plan, environment) {
241
+ if (plan.generated.providerPackId === "SHOPIFY_DISPUTE" && plan.environment === "sandbox" && plan.generated.providerConfiguration === undefined)
242
+ return;
233
243
  const name = providerCredentialEnvironmentName(plan.generated.providerPackId);
234
244
  const value = environment[name];
235
245
  if (!value)
@@ -126,6 +126,7 @@ export declare class ManagedBusinessWorkflowHarness {
126
126
  evaluation: ManagedWorkflowReadyEvaluation;
127
127
  }) => Promise<TaskEvaluationReport>;
128
128
  maxConcurrency?: number;
129
+ supportedModes?: Array<"REPLAY" | "SHADOW">;
129
130
  });
130
131
  tick(): Promise<ManagedBusinessWorkflowHarnessResult>;
131
132
  private runTick;
@@ -1 +1 @@
1
- {"version":3,"file":"managed-workflow-harness.d.ts","sourceRoot":"","sources":["../../../../onegent-runtime/src/managed-workflow-harness.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"managed-workflow-harness.d.ts","sourceRoot":"","sources":["../../../../onegent-runtime/src/managed-workflow-harness.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAGzF,MAAM,MAAM,6BAA6B,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEhE,MAAM,WAAW,4BAA4B;IAC3C,aAAa,EAAE,+CAA+C,CAAC;IAC/D,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAA;KAAE,CAAC;IAC7E,KAAK,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,gBAAgB,GAAG,WAAW,CAAA;KAAE,CAAC,CAAC;IACvG,gBAAgB,EAAE,8BAA8B,EAAE,CAAC;IACnD,gBAAgB,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE;QAAE,gBAAgB,EAAE,CAAC,CAAC;QAAC,uBAAuB,EAAE,KAAK,CAAC;QAAC,uBAAuB,EAAE,IAAI,CAAA;KAAE,CAAC;IAC/F,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,8BAA8B;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,wBAAwB,EAAE,MAAM,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,EAAE,6BAA6B,CAAC;IACpC,gBAAgB,CAAC,EAAE;QACjB,MAAM,EAAE,iBAAiB,GAAG,gBAAgB,CAAC;QAC7C,sBAAsB,EAAE,MAAM,EAAE,CAAC;QACjC,gBAAgB,EAAE,MAAM,CAAC;QACzB,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;QACxB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,4BAA4B;IAC3C,aAAa,EAAE,uCAAuC,CAAC;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,KAAK,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,wBAAwB,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAC9H,OAAO,EAAE,MAAM,CAAC;QAAC,oBAAoB,EAAE,MAAM,CAAC;QAAC,qBAAqB,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,6BAA6B,CAAC;QAClH,SAAS,EAAE,MAAM,EAAE,CAAC;QAAC,qBAAqB,EAAE,MAAM,CAAC;QAAC,qBAAqB,EAAE,MAAM,EAAE,CAAC;QACpF,gBAAgB,EAAE,WAAW,CAAC,8BAA8B,CAAC,kBAAkB,CAAC,CAAC,CAAC;QAClF,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,WAAW,GAAG,gBAAgB,GAAG,SAAS,CAAC;KAC1E,CAAC,CAAC;IACH,MAAM,EAAE;QAAE,gBAAgB,EAAE,CAAC,CAAC;QAAC,2BAA2B,EAAE,IAAI,CAAC;QAAC,uBAAuB,EAAE,IAAI,CAAC;QAAC,sBAAsB,EAAE,KAAK,CAAA;KAAE,CAAC;IACjI,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,2BAA2B;IAC1C,mBAAmB,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAA;KAAE,CAAC,CAAC,CAAC;IAC1G,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;IAC5E,OAAO,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACjE,gBAAgB,CAAC,IAAI,OAAO,CAAC,4BAA4B,CAAC,CAAC;IAC3D,MAAM,CAAC,MAAM,EAAE,oBAAoB,EAAE,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,4BAA4B,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACvJ;AAED,wBAAgB,iCAAiC,CAAC,OAAO,EAAE;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB,GAAG,2BAA2B,CAqD9B;AAED,MAAM,WAAW,iCAAiC;IAChD,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAAC;IAC7D,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAED,qBAAa,uCAAwC,YAAW,iCAAiC;;IAGzF,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC;IAK5D,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9D,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG3C;AAED,qBAAa,qCAAsC,YAAW,iCAAiC;IACjF,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM;IAIxC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC;IAS5D,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9D,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1C,OAAO,CAAC,IAAI;CAGb;AAED,MAAM,WAAW,oCAAoC;IACnD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,4BAA4B,EAAE,MAAM,CAAC;IACrC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,qBAAa,8BAA8B;;gBAQ7B,OAAO,EAAE;QACnB,MAAM,EAAE,2BAA2B,CAAC;QACpC,WAAW,EAAE,iCAAiC,CAAC;QAC/C,QAAQ,EAAE,CAAC,KAAK,EAAE;YAAE,IAAI,EAAE,sBAAsB,CAAC;YAAC,UAAU,EAAE,8BAA8B,CAAA;SAAE,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;QACjI,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,cAAc,CAAC,EAAE,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;KAC7C;IAYD,IAAI,IAAI,OAAO,CAAC,oCAAoC,CAAC;YAMvC,OAAO;CAuFtB"}
@@ -99,15 +99,19 @@ export class ManagedBusinessWorkflowHarness {
99
99
  #checkpoints;
100
100
  #evaluate;
101
101
  #maxConcurrency;
102
+ #supportedModes;
102
103
  #activeTick;
103
104
  constructor(options) {
104
105
  this.#client = options.client;
105
106
  this.#checkpoints = options.checkpoints;
106
107
  this.#evaluate = options.evaluate;
107
108
  this.#maxConcurrency = options.maxConcurrency ?? 4;
109
+ this.#supportedModes = new Set(options.supportedModes ?? ["REPLAY", "SHADOW"]);
108
110
  if (!Number.isSafeInteger(this.#maxConcurrency) || this.#maxConcurrency < 1 || this.#maxConcurrency > 16) {
109
111
  throw new Error("Managed Workflow Harness maxConcurrency must be between 1 and 16.");
110
112
  }
113
+ if (!this.#supportedModes.size)
114
+ throw new Error("Managed Workflow Harness requires at least one supported evaluation mode.");
111
115
  }
112
116
  tick() {
113
117
  if (this.#activeTick)
@@ -129,7 +133,7 @@ export class ManagedBusinessWorkflowHarness {
129
133
  limitations.push(`Workflow ${workflow.id} was not scheduled because its authoritative Run inspection was truncated.`);
130
134
  break;
131
135
  }
132
- const ready = plan.readyEvaluations.filter((evaluation) => !seen.has(checkpointKey(plan, evaluation)));
136
+ const ready = plan.readyEvaluations.filter((evaluation) => this.#supportedModes.has(evaluation.mode) && !seen.has(checkpointKey(plan, evaluation)));
133
137
  if (!ready.length)
134
138
  break;
135
139
  const results = await mapLimit(ready, this.#maxConcurrency, async (evaluation) => {
@@ -171,7 +175,7 @@ export class ManagedBusinessWorkflowHarness {
171
175
  limitations: ["This client does not expose Nora Autopilot dispatches."],
172
176
  };
173
177
  validateAutopilotPlan(autopilot);
174
- const readyDispatches = autopilot.dispatches.filter((dispatch) => dispatch.status === "READY");
178
+ const readyDispatches = autopilot.dispatches.filter((dispatch) => dispatch.status === "READY" && this.#supportedModes.has(dispatch.mode));
175
179
  const autopilotResults = await mapLimit(readyDispatches, this.#maxConcurrency, async (dispatch) => {
176
180
  const evaluation = {
177
181
  nodeId: `autopilot:${dispatch.id}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "witnora",
3
- "version": "0.18.3",
3
+ "version": "0.18.5",
4
4
  "description": "Independent assurance for covered agent action paths across models and frameworks.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",