@wenathlan/extension 1.1.56 → 1.1.57

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
@@ -2649,6 +2649,119 @@ var sessionmemory = class {
2649
2649
  async setdryruntoggle(enabled) {
2650
2650
  return this.adapter.set("mcpdryruntoggle", enabled);
2651
2651
  }
2652
+ /** Returns every user configured provider config of the 1.1.57 llm integration; the api keys stay behind their storage id references, never inside these records. */
2653
+ async getproviders() {
2654
+ return await this.adapter.get("llmproviders") ?? [];
2655
+ }
2656
+ /** Replaces the stored provider config set after one save, test or removal. */
2657
+ async setproviders(providers) {
2658
+ return this.adapter.set("llmproviders", providers);
2659
+ }
2660
+ /** Returns the user configured local model endpoint of the browser reachable inference. */
2661
+ async getlocalmodel() {
2662
+ return this.adapter.get("llmlocalmodel");
2663
+ }
2664
+ /** Stores the local model endpoint config after one save or health check. */
2665
+ async setlocalmodel(config) {
2666
+ return this.adapter.set("llmlocalmodel", config);
2667
+ }
2668
+ /** Returns every model route entry of the routing table, newest update first. */
2669
+ async getmodelroutes() {
2670
+ return await this.adapter.get("llmmodelroutes") ?? [];
2671
+ }
2672
+ /** Replaces the stored routing table after one route edit. */
2673
+ async setmodelroutes(routes) {
2674
+ return this.adapter.set("llmmodelroutes", routes);
2675
+ }
2676
+ /** Appends one revision entry to the model route revision history so every routing change stays queryable for audit. */
2677
+ async addmodelrouterevision(route) {
2678
+ await this.adapter.set("llmmodelroutehistory", [route, ...await this.adapter.get("llmmodelroutehistory") ?? []].slice(0, 200));
2679
+ }
2680
+ /** Returns the model route revision history, newest first. */
2681
+ async getmodelroutehistory() {
2682
+ return await this.adapter.get("llmmodelroutehistory") ?? [];
2683
+ }
2684
+ /** Records one usage entry of a model call with its run and step ids; the newest call reads first and an absent retention keeps every record. */
2685
+ async addusagerecord(record2) {
2686
+ await this.adapter.set("llmusage", [record2, ...await this.adapter.get("llmusage") ?? []]);
2687
+ }
2688
+ /** Returns every stored usage record of model calls, newest first. */
2689
+ async getusagerecords() {
2690
+ return await this.adapter.get("llmusage") ?? [];
2691
+ }
2692
+ /** Returns the token and cost totals per period: the run, the step, the since floor and the until ceiling stay optional filters over the stored usage records. */
2693
+ async getusage(filter = {}) {
2694
+ const records = (await this.getusagerecords()).filter((record2) => (filter.runid === void 0 || record2.runid === filter.runid) && (filter.stepid === void 0 || record2.stepid === filter.stepid) && (filter.since === void 0 || record2.at >= filter.since) && (filter.until === void 0 || record2.at <= filter.until));
2695
+ return records.reduce((totals, record2) => ({ prompttokens: totals.prompttokens + record2.prompttokens, completiontokens: totals.completiontokens + record2.completiontokens, totaltokens: totals.totaltokens + record2.totaltokens, cost: totals.cost + record2.cost, calls: totals.calls + 1 }), { prompttokens: 0, completiontokens: 0, totaltokens: 0, cost: 0, calls: 0 });
2696
+ }
2697
+ /** Stores one model drafted plan for review and audit; newer drafts read first. */
2698
+ async addplandraft(draft) {
2699
+ await this.adapter.set("llmplandrafts", [draft, ...await this.adapter.get("llmplandrafts") ?? []]);
2700
+ }
2701
+ /** Replaces the stored draft set after one review decision. */
2702
+ async setplandrafts(drafts) {
2703
+ return this.adapter.set("llmplandrafts", drafts);
2704
+ }
2705
+ /** Returns every stored model drafted plan, newest first. */
2706
+ async getplandrafts() {
2707
+ return await this.adapter.get("llmplandrafts") ?? [];
2708
+ }
2709
+ /** Stores one replan record for the fresh review and the audit history; newer replans read first. */
2710
+ async addreplan(replan) {
2711
+ await this.adapter.set("llmreplans", [replan, ...await this.adapter.get("llmreplans") ?? []]);
2712
+ }
2713
+ /** Replaces the stored replan set after one fresh review decision. */
2714
+ async setreplans(replans) {
2715
+ return this.adapter.set("llmreplans", replans);
2716
+ }
2717
+ /** Returns every stored replan record, newest first. */
2718
+ async getreplans() {
2719
+ return await this.adapter.get("llmreplans") ?? [];
2720
+ }
2721
+ /** Stores one reflection note of an executed step under the recent note window of 100 records. */
2722
+ async addreflectnote(note) {
2723
+ await this.adapter.set("llmreflectnotes", [note, ...await this.adapter.get("llmreflectnotes") ?? []].slice(0, 100));
2724
+ }
2725
+ /** Returns the stored reflection notes, newest first. */
2726
+ async getreflectnotes() {
2727
+ return await this.adapter.get("llmreflectnotes") ?? [];
2728
+ }
2729
+ /** Replaces the stored prompt template library after one save or removal; every version with its change notes stays stored. */
2730
+ async setprompttemplates(templates) {
2731
+ return this.adapter.set("llmprompttemplates", templates);
2732
+ }
2733
+ /** Returns the stored prompt template library with every version, newest first. */
2734
+ async getprompttemplates() {
2735
+ return await this.adapter.get("llmprompttemplates") ?? [];
2736
+ }
2737
+ /** Returns the stored cost budget of the runs; the run scoped budget wins over the shared one when both exist. */
2738
+ async getcostbudget(runid) {
2739
+ const budgets = await this.adapter.get("llmcostbudgets") ?? [];
2740
+ return budgets.find((budget) => runid !== void 0 && budget.runid === runid) ?? budgets.find((budget) => budget.runid === void 0);
2741
+ }
2742
+ /** Stores one cost budget; a run scoped budget replaces the earlier budget of its run while the shared budget replaces the shared one. */
2743
+ async setcostbudget(budget) {
2744
+ const budgets = await this.adapter.get("llmcostbudgets") ?? [];
2745
+ const kept = budgets.filter((candidate) => candidate.runid !== budget.runid);
2746
+ await this.adapter.set("llmcostbudgets", [budget, ...kept]);
2747
+ }
2748
+ /** Returns the latest parsed natural language command with its intent badge payload. */
2749
+ async getcommandparse() {
2750
+ return this.adapter.get("llmcommandparse");
2751
+ }
2752
+ /** Stores the latest parsed natural language command. */
2753
+ async setcommandparse(parse) {
2754
+ return this.adapter.set("llmcommandparse", parse);
2755
+ }
2756
+ /** Returns the recent guard refusal notices of invalid or refused model output, newest first under a window of 50. */
2757
+ async getguardnotices() {
2758
+ return await this.adapter.get("llmguardnotices") ?? [];
2759
+ }
2760
+ /** Records one guard refusal notice for the panel; the verdict reason explains the parse failure and its retries. */
2761
+ async addguardnotice(output) {
2762
+ if (output.verdict === "valid") return;
2763
+ await this.adapter.set("llmguardnotices", [output, ...await this.getguardnotices()].slice(0, 50));
2764
+ }
2652
2765
  };
2653
2766
  function mediakindof(record2) {
2654
2767
  if ("pages" in record2) return "pdf";
@@ -4767,12 +4880,6 @@ async function callgraphql(input) {
4767
4880
  }
4768
4881
  }
4769
4882
 
4770
- // version.ts
4771
- var packageversion = "1.1.56";
4772
-
4773
- // types.ts
4774
- var protocolversion = packageversion;
4775
-
4776
4883
  // socketbus.ts
4777
4884
  var socketkinds = ["opensocket", "sendmessage", "waitmessage", "subscribesse", "longpoll"];
4778
4885
  function channelorigin(url) {
@@ -7309,8 +7416,8 @@ function validatetimelinegrammar(step, options) {
7309
7416
  watchwindow = reviewed.window;
7310
7417
  }
7311
7418
  }
7312
- const budgetcheck = debugwaitbudgetallowed(watchwindow, typeof options.wait === "number" ? options.wait : void 0);
7313
- if (!budgetcheck.allowed) return budgetcheck;
7419
+ const budgetcheck2 = debugwaitbudgetallowed(watchwindow, typeof options.wait === "number" ? options.wait : void 0);
7420
+ if (!budgetcheck2.allowed) return budgetcheck2;
7314
7421
  if (options.level !== void 0 && !loglevels.includes(options.level)) return { allowed: false, reason: `The reviewed level floor must be one of ${loglevels.join(", ")}.` };
7315
7422
  if (options.sources !== void 0) {
7316
7423
  if (!Array.isArray(options.sources) || options.sources.length === 0 || !options.sources.every((source) => timelinesources.includes(source))) return { allowed: false, reason: `The reviewed source filters must be a non-empty list of the reviewed timeline sources: ${timelinesources.join(", ")}.` };
@@ -7903,8 +8010,8 @@ function validatecdpgrammar(step, options) {
7903
8010
  const allowlist = cdpallowlistof(options.allowlist);
7904
8011
  if (!allowlist || !allowlist.domains.every((domain) => options.domains.includes(domain))) return { allowed: false, reason: "The reviewed method allowlist must stay inside the enabled domains of the attach." };
7905
8012
  }
7906
- const budgetcheck = debugwaitbudgetallowed(typeof options.wait === "number" ? options.wait : void 0, void 0);
7907
- if (!budgetcheck.allowed) return budgetcheck;
8013
+ const budgetcheck2 = debugwaitbudgetallowed(typeof options.wait === "number" ? options.wait : void 0, void 0);
8014
+ if (!budgetcheck2.allowed) return budgetcheck2;
7908
8015
  return { allowed: true };
7909
8016
  }
7910
8017
  if (kind === "detachcdp") return { allowed: true };
@@ -7928,8 +8035,8 @@ function validatecdpgrammar(step, options) {
7928
8035
  }
7929
8036
  }
7930
8037
  if (watchwindow === void 0) return { allowed: false, reason: "The event watch needs a reviewed lifetime window before any domain event is observed." };
7931
- const budgetcheck = debugwaitbudgetallowed(watchwindow, typeof options.wait === "number" ? options.wait : void 0);
7932
- if (!budgetcheck.allowed) return budgetcheck;
8038
+ const budgetcheck2 = debugwaitbudgetallowed(watchwindow, typeof options.wait === "number" ? options.wait : void 0);
8039
+ if (!budgetcheck2.allowed) return budgetcheck2;
7933
8040
  return { allowed: true };
7934
8041
  }
7935
8042
  if (kind === "setbreakpoint") {
@@ -7966,8 +8073,8 @@ function validateprofilegrammar(step, options) {
7966
8073
  if (flowspecof(options.flow) === void 0) return { allowed: false, reason: `The flow measurement needs a reviewed flow spec with its mark prefix, step window and metric list of the reviewed metric set: navigation, paint, lcp, fid, interaction, blocking.` };
7967
8074
  const watch = options.watch && typeof options.watch === "object" && !Array.isArray(options.watch) ? options.watch : {};
7968
8075
  if (typeof watch.window !== "number" || !Number.isFinite(watch.window) || watch.window < 0) return { allowed: false, reason: "The flow measurement needs a reviewed watch window of zero or more milliseconds." };
7969
- const budgetcheck = debugwaitbudgetallowed(watch.window, typeof options.wait === "number" ? options.wait : void 0);
7970
- if (!budgetcheck.allowed) return budgetcheck;
8076
+ const budgetcheck2 = debugwaitbudgetallowed(watch.window, typeof options.wait === "number" ? options.wait : void 0);
8077
+ if (!budgetcheck2.allowed) return budgetcheck2;
7971
8078
  return { allowed: true };
7972
8079
  }
7973
8080
  if (kind === "heapshot") {
@@ -7984,16 +8091,16 @@ function validateprofilegrammar(step, options) {
7984
8091
  if (kind === "profilecpu") {
7985
8092
  const profile = options.profile && typeof options.profile === "object" && !Array.isArray(options.profile) ? options.profile : void 0;
7986
8093
  if (!profile || typeof profile.duration !== "number" || !Number.isFinite(profile.duration) || profile.duration < 0) return { allowed: false, reason: "The cpu profile needs a reviewed duration of zero or more milliseconds." };
7987
- const budgetcheck = debugwaitbudgetallowed(profile.duration, typeof options.wait === "number" ? options.wait : void 0);
7988
- if (!budgetcheck.allowed) return budgetcheck;
8094
+ const budgetcheck2 = debugwaitbudgetallowed(profile.duration, typeof options.wait === "number" ? options.wait : void 0);
8095
+ if (!budgetcheck2.allowed) return budgetcheck2;
7989
8096
  return { allowed: true };
7990
8097
  }
7991
8098
  if (kind === "watchshifts") {
7992
8099
  const watch = options.watch && typeof options.watch === "object" && !Array.isArray(options.watch) ? options.watch : {};
7993
8100
  if (typeof watch.window !== "number" || !Number.isFinite(watch.window) || watch.window < 0) return { allowed: false, reason: "The layout shift watch needs a reviewed observation window of zero or more milliseconds; the window stays a user choice with no code ceiling." };
7994
8101
  if (options.threshold !== void 0 && (typeof options.threshold !== "number" || !Number.isFinite(options.threshold) || options.threshold < 0)) return { allowed: false, reason: "The reviewed shift score threshold must be zero or a positive number." };
7995
- const budgetcheck = debugwaitbudgetallowed(watch.window, typeof options.wait === "number" ? options.wait : void 0);
7996
- if (!budgetcheck.allowed) return budgetcheck;
8102
+ const budgetcheck2 = debugwaitbudgetallowed(watch.window, typeof options.wait === "number" ? options.wait : void 0);
8103
+ if (!budgetcheck2.allowed) return budgetcheck2;
7997
8104
  return { allowed: true };
7998
8105
  }
7999
8106
  if (kind === "traceload") {
@@ -8001,8 +8108,8 @@ function validateprofilegrammar(step, options) {
8001
8108
  if (!trace || !Array.isArray(trace.categories) || trace.categories.length === 0 || !trace.categories.every((category) => typeof category === "string" && tracecategories.includes(category))) return { allowed: false, reason: `The trace record needs a non-empty reviewed category list of the reviewed category grammar: ${tracecategories.join(", ")}.` };
8002
8109
  if (typeof trace.window !== "number" || !Number.isFinite(trace.window) || trace.window < 0) return { allowed: false, reason: "The trace record needs a reviewed window of zero or more milliseconds and stops at the reviewed window end." };
8003
8110
  if (trace.exporttarget !== void 0 && trace.exporttarget !== "memory" && trace.exporttarget !== "download") return { allowed: false, reason: "The trace export target must be memory or download." };
8004
- const budgetcheck = debugwaitbudgetallowed(trace.window, typeof options.wait === "number" ? options.wait : void 0);
8005
- if (!budgetcheck.allowed) return budgetcheck;
8111
+ const budgetcheck2 = debugwaitbudgetallowed(trace.window, typeof options.wait === "number" ? options.wait : void 0);
8112
+ if (!budgetcheck2.allowed) return budgetcheck2;
8006
8113
  return { allowed: true };
8007
8114
  }
8008
8115
  if (kind === "annotatetrace" || kind === "replaytrace") {
@@ -8984,6 +9091,439 @@ function approvaltimeoutvalid(timeout) {
8984
9091
  if (timeout.ontimeout !== "refuse") return { allowed: false, reason: "The documented disposition of an unanswered approval gate is refusal." };
8985
9092
  return { allowed: true };
8986
9093
  }
9094
+ function providervalid(config) {
9095
+ if (config.name.trim() === "") return { allowed: false, reason: "The provider config needs its name." };
9096
+ if (config.endpoint.trim() === "") return { allowed: false, reason: "The provider config needs the user configured endpoint url; no default endpoint ever applies." };
9097
+ let parsed;
9098
+ try {
9099
+ parsed = new URL(config.endpoint);
9100
+ } catch {
9101
+ return { allowed: false, reason: "The provider endpoint must be a well-formed url." };
9102
+ }
9103
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return { allowed: false, reason: "The provider endpoint must speak http or https." };
9104
+ if (config.models.length === 0) return { allowed: false, reason: "The provider config needs at least one user configured model name." };
9105
+ if (config.models.some((model) => model.trim() === "")) return { allowed: false, reason: "Every provider model name must stay non-empty free text." };
9106
+ if (config.style !== "chatcompletions" && config.style !== "responses" && config.style !== "messages" && config.style !== "gemini") return { allowed: false, reason: "The provider protocol shape must be one of the four wire shapes the user picks." };
9107
+ if (config.authref !== void 0 && config.authref.storageid.trim() === "") return { allowed: false, reason: "The provider auth reference needs the storage id of the stored key; the key material never enters the config." };
9108
+ return { allowed: true };
9109
+ }
9110
+ function provideregressgrade(input) {
9111
+ const valid = providervalid(input.provider);
9112
+ if (!valid.allowed) return valid;
9113
+ return { allowed: true, reason: input.local ? "The model call stays on the local machine endpoint and grades as the local data egress preference." : "The model call leaves the browser for the user configured endpoint and grades as a data egress event with its endpoint, model and token counts in the audit trail." };
9114
+ }
9115
+ function egressconsentgate(input) {
9116
+ if (input.pagecontent !== void 0 && input.pagecontent.trim() !== "" && input.granted !== true) return { allowed: false, reason: "The model call carries page content the user has not granted, so the content stays in the browser and the call refuses." };
9117
+ return { allowed: true };
9118
+ }
9119
+ function localsensitivegrade(input) {
9120
+ if (input.sensitive && !input.local) return { allowed: true, reason: "The sensitive extraction prefers the local model endpoint; the user keeps the choice of the remote provider." };
9121
+ return { allowed: true, reason: input.local ? "The local model endpoint satisfies the sensitive extraction preference." : "The extraction stays non-sensitive and every configured endpoint serves it." };
9122
+ }
9123
+ function plandraftreviewgate(draft) {
9124
+ if (draft.state !== "approved") return { allowed: false, reason: "The model drafted plan stays unreviewed; the human review approves the draft before any step executes." };
9125
+ if (draft.steps.length === 0) return { allowed: false, reason: "The model drafted plan carries no step, so nothing executes." };
9126
+ return { allowed: true };
9127
+ }
9128
+ function replanreviewgate(replan) {
9129
+ if (replan.state !== "approved") return { allowed: false, reason: "The replanned tail stays unreviewed; the fresh review approves the changed steps before any of them executes." };
9130
+ if (replan.tail.some((step) => step.freshreview !== true)) return { allowed: false, reason: "Every revised step of a replan must carry the fresh review marker." };
9131
+ return { allowed: true };
9132
+ }
9133
+ function costbudgetvalid(budget) {
9134
+ if (budget.maxtokens !== void 0 && (!Number.isFinite(budget.maxtokens) || budget.maxtokens <= 0)) return { allowed: false, reason: "The token ceiling of a cost budget must stay a positive user value." };
9135
+ if (budget.maxcost !== void 0 && (!Number.isFinite(budget.maxcost) || budget.maxcost <= 0)) return { allowed: false, reason: "The cost ceiling of a cost budget must stay a positive user value." };
9136
+ if (budget.maxcost !== void 0 && (budget.currency === void 0 || budget.currency.trim() === "")) return { allowed: false, reason: "The cost ceiling of a cost budget needs its currency unit." };
9137
+ if (budget.maxtokens === void 0 && budget.maxcost === void 0) return { allowed: false, reason: "The cost budget needs at least one ceiling the user configured; an absent budget stays the documented unbounded choice." };
9138
+ return { allowed: true };
9139
+ }
9140
+ function guardverdictgate(output) {
9141
+ if (output.verdict === "invalid") return { allowed: false, reason: output.reason ?? "The guardrails marked the model output invalid." };
9142
+ if (output.verdict === "refused") return { allowed: false, reason: output.reason ?? "The model refused the request, so nothing executes." };
9143
+ return { allowed: true };
9144
+ }
9145
+ function draftriskof(step) {
9146
+ try {
9147
+ return resolvedrisk({ id: step.id, kind: step.kind, ...step.target !== void 0 ? { target: step.target } : {}, ...step.value !== void 0 ? { value: step.value } : {}, summary: step.summary, risk: "sensitive" });
9148
+ } catch {
9149
+ return "sensitive";
9150
+ }
9151
+ }
9152
+ function planlint(draft, origin) {
9153
+ const findings = [];
9154
+ if (draft.goal.trim() === "") findings.push("The drafted plan carries no goal.");
9155
+ if (draft.steps.length === 0) findings.push("The drafted plan carries no step.");
9156
+ for (const step of draft.steps) {
9157
+ const mapped = { id: step.id, kind: step.kind, ...step.target !== void 0 ? { target: step.target } : {}, ...step.value !== void 0 ? { value: step.value } : {}, summary: step.summary, risk: draftriskof(step) };
9158
+ const verdict = validatestep(mapped, origin);
9159
+ if (!verdict.allowed) findings.push(`The drafted step ${step.id || "without id"} of kind ${step.kind || "unknown"} violates the action grammar: ${verdict.reason ?? "the step failed its grammar check."}`);
9160
+ }
9161
+ return findings;
9162
+ }
9163
+
9164
+ // llm.ts
9165
+ var defaultrefusalmarkers = ["i cannot", "i can't", "i'm unable", "refusal:", "cannot comply"];
9166
+ function buildrequest(input) {
9167
+ const headers = { "content-type": "application/json" };
9168
+ let url = input.provider.endpoint;
9169
+ const style = input.provider.style;
9170
+ if (style === "chatcompletions") {
9171
+ if (input.apikey !== void 0 && input.apikey.trim() !== "") headers.authorization = `Bearer ${input.apikey}`;
9172
+ const body2 = { model: input.model, messages: input.messages.map((message) => ({ role: message.role, content: message.content })), ...input.temperature !== void 0 ? { temperature: input.temperature } : {}, ...input.maxtokens !== void 0 ? { max_tokens: input.maxtokens } : {}, ...input.stream === true ? { stream: true } : {} };
9173
+ return { url, method: "POST", headers: { ...headers, ...input.provider.headers ?? {} }, body: JSON.stringify(body2) };
9174
+ }
9175
+ if (style === "responses") {
9176
+ if (input.apikey !== void 0 && input.apikey.trim() !== "") headers.authorization = `Bearer ${input.apikey}`;
9177
+ const system2 = input.messages.filter((message) => message.role === "system").map((message) => message.content).join("\n");
9178
+ const turns2 = input.messages.filter((message) => message.role !== "system").map((message) => ({ role: message.role === "assistant" ? "assistant" : "user", content: message.content }));
9179
+ const body2 = { model: input.model, input: turns2, ...system2.trim() !== "" ? { instructions: system2 } : {}, ...input.temperature !== void 0 ? { temperature: input.temperature } : {}, ...input.maxtokens !== void 0 ? { max_output_tokens: input.maxtokens } : {}, ...input.stream === true ? { stream: true } : {} };
9180
+ return { url, method: "POST", headers: { ...headers, ...input.provider.headers ?? {} }, body: JSON.stringify(body2) };
9181
+ }
9182
+ if (style === "messages") {
9183
+ if (input.apikey !== void 0 && input.apikey.trim() !== "") headers["x-api-key"] = input.apikey;
9184
+ const system2 = input.messages.filter((message) => message.role === "system").map((message) => message.content).join("\n");
9185
+ const turns2 = input.messages.filter((message) => message.role !== "system").map((message) => ({ role: message.role, content: message.content }));
9186
+ const body2 = { model: input.model, messages: turns2, ...system2.trim() !== "" ? { system: system2 } : {}, ...input.temperature !== void 0 ? { temperature: input.temperature } : {}, ...input.maxtokens !== void 0 ? { max_tokens: input.maxtokens } : {}, ...input.stream === true ? { stream: true } : {} };
9187
+ return { url, method: "POST", headers: { ...headers, ...input.provider.headers ?? {} }, body: JSON.stringify(body2) };
9188
+ }
9189
+ if (input.apikey !== void 0 && input.apikey.trim() !== "") url = `${url}${url.includes("?") ? "&" : "?"}key=${encodeURIComponent(input.apikey)}`;
9190
+ const system = input.messages.filter((message) => message.role === "system").map((message) => message.content).join("\n");
9191
+ const turns = input.messages.filter((message) => message.role !== "system").map((message) => ({ role: message.role === "assistant" ? "model" : "user", parts: [{ text: message.content }] }));
9192
+ const body = { contents: turns, ...system.trim() !== "" ? { systemInstruction: { parts: [{ text: system }] } } : {}, ...input.temperature !== void 0 ? { generationConfig: { temperature: input.temperature, ...input.maxtokens !== void 0 ? { maxOutputTokens: input.maxtokens } : {} } } : input.maxtokens !== void 0 ? { generationConfig: { maxOutputTokens: input.maxtokens } } : {} };
9193
+ return { url, method: "POST", headers: { ...headers, ...input.provider.headers ?? {} }, body: JSON.stringify(body) };
9194
+ }
9195
+ function numberof(value) {
9196
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
9197
+ }
9198
+ function parsecompletion(style, body) {
9199
+ let parsed;
9200
+ try {
9201
+ parsed = JSON.parse(body);
9202
+ } catch {
9203
+ return { reason: "The provider answer is not json." };
9204
+ }
9205
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return { reason: "The provider answer is not a json object." };
9206
+ const record2 = parsed;
9207
+ if (style === "chatcompletions") {
9208
+ const choice = Array.isArray(record2.choices) ? record2.choices[0] : void 0;
9209
+ const message = choice !== void 0 && choice.message !== void 0 && typeof choice.message === "object" ? choice.message : void 0;
9210
+ if (message === void 0 || typeof message.content !== "string") return { reason: "The chat completions answer carries no message content." };
9211
+ const usage2 = record2.usage !== void 0 && typeof record2.usage === "object" ? record2.usage : void 0;
9212
+ const prompttokens2 = usage2 !== void 0 ? numberof(usage2.prompt_tokens) : void 0;
9213
+ const completiontokens2 = usage2 !== void 0 ? numberof(usage2.completion_tokens) : void 0;
9214
+ const totaltokens2 = usage2 !== void 0 ? numberof(usage2.total_tokens) : void 0;
9215
+ return { text: message.content, ...prompttokens2 !== void 0 || completiontokens2 !== void 0 || totaltokens2 !== void 0 ? { usage: { prompttokens: prompttokens2 ?? 0, completiontokens: completiontokens2 ?? 0, totaltokens: totaltokens2 ?? (prompttokens2 ?? 0) + (completiontokens2 ?? 0) } } : {} };
9216
+ }
9217
+ if (style === "responses") {
9218
+ const direct = typeof record2.output_text === "string" ? record2.output_text : void 0;
9219
+ let text2 = direct;
9220
+ if (text2 === void 0 && Array.isArray(record2.output)) {
9221
+ const parts2 = [];
9222
+ for (const item of record2.output) {
9223
+ if (item && typeof item === "object" && Array.isArray(item.content)) {
9224
+ for (const part of item.content) {
9225
+ if (part && typeof part === "object" && part.type === "output_text" && typeof part.text === "string") parts2.push(part.text);
9226
+ }
9227
+ }
9228
+ }
9229
+ if (parts2.length > 0) text2 = parts2.join("");
9230
+ }
9231
+ if (text2 === void 0) return { reason: "The responses answer carries no output text." };
9232
+ const usage2 = record2.usage !== void 0 && typeof record2.usage === "object" ? record2.usage : void 0;
9233
+ const prompttokens2 = usage2 !== void 0 ? numberof(usage2.input_tokens) : void 0;
9234
+ const completiontokens2 = usage2 !== void 0 ? numberof(usage2.output_tokens) : void 0;
9235
+ const totaltokens2 = usage2 !== void 0 ? numberof(usage2.total_tokens) : void 0;
9236
+ return { text: text2, ...prompttokens2 !== void 0 || completiontokens2 !== void 0 || totaltokens2 !== void 0 ? { usage: { prompttokens: prompttokens2 ?? 0, completiontokens: completiontokens2 ?? 0, totaltokens: totaltokens2 ?? (prompttokens2 ?? 0) + (completiontokens2 ?? 0) } } : {} };
9237
+ }
9238
+ if (style === "messages") {
9239
+ const parts2 = [];
9240
+ if (Array.isArray(record2.content)) {
9241
+ for (const part of record2.content) {
9242
+ if (part && typeof part === "object" && part.type === "text" && typeof part.text === "string") parts2.push(part.text);
9243
+ }
9244
+ }
9245
+ if (parts2.length === 0) return { reason: "The messages answer carries no text block." };
9246
+ const usage2 = record2.usage !== void 0 && typeof record2.usage === "object" ? record2.usage : void 0;
9247
+ const prompttokens2 = usage2 !== void 0 ? numberof(usage2.input_tokens) : void 0;
9248
+ const completiontokens2 = usage2 !== void 0 ? numberof(usage2.output_tokens) : void 0;
9249
+ return { text: parts2.join(""), ...prompttokens2 !== void 0 || completiontokens2 !== void 0 ? { usage: { prompttokens: prompttokens2 ?? 0, completiontokens: completiontokens2 ?? 0, totaltokens: (prompttokens2 ?? 0) + (completiontokens2 ?? 0) } } : {} };
9250
+ }
9251
+ const candidate = Array.isArray(record2.candidates) ? record2.candidates[0] : void 0;
9252
+ const content = candidate !== void 0 && candidate.content !== void 0 && typeof candidate.content === "object" ? candidate.content.parts : void 0;
9253
+ const parts = [];
9254
+ if (Array.isArray(content)) {
9255
+ for (const part of content) {
9256
+ if (part && typeof part === "object" && typeof part.text === "string") parts.push(part.text);
9257
+ }
9258
+ }
9259
+ if (parts.length === 0) return { reason: "The gemini answer carries no candidate text." };
9260
+ const usage = record2.usageMetadata !== void 0 && typeof record2.usageMetadata === "object" ? record2.usageMetadata : void 0;
9261
+ const prompttokens = usage !== void 0 ? numberof(usage.promptTokenCount) : void 0;
9262
+ const completiontokens = usage !== void 0 ? numberof(usage.candidatesTokenCount) : void 0;
9263
+ const totaltokens = usage !== void 0 ? numberof(usage.totalTokenCount) : void 0;
9264
+ return { text: parts.join(""), ...prompttokens !== void 0 || completiontokens !== void 0 || totaltokens !== void 0 ? { usage: { prompttokens: prompttokens ?? 0, completiontokens: completiontokens ?? 0, totaltokens: totaltokens ?? (prompttokens ?? 0) + (completiontokens ?? 0) } } : {} };
9265
+ }
9266
+ function islocalorigin(url) {
9267
+ try {
9268
+ const host = new URL(url).hostname.toLowerCase();
9269
+ return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.endsWith(".localhost");
9270
+ } catch {
9271
+ return false;
9272
+ }
9273
+ }
9274
+ async function callmodel(input) {
9275
+ if (input.provider.endpoint.trim() === "") throw new Error("The provider needs the user configured endpoint url before any call leaves.");
9276
+ if (input.provider.authref !== void 0 && (input.apikey === void 0 || input.apikey.trim() === "")) throw new Error(`The provider ${input.provider.name} references the stored key ${input.provider.authref.name} and the call needs the resolved key material.`);
9277
+ const consent = egressconsentgate({ ...input.pagecontent !== void 0 ? { pagecontent: input.pagecontent } : {}, granted: input.pagegrant === true });
9278
+ if (!consent.allowed) throw new Error(consent.reason ?? "The page content stayed ungranted and the call refused.");
9279
+ const shaped = buildrequest({ provider: input.provider, model: input.model, messages: input.messages, ...input.apikey !== void 0 ? { apikey: input.apikey } : {}, ...input.temperature !== void 0 ? { temperature: input.temperature } : {}, ...input.maxtokens !== void 0 ? { maxtokens: input.maxtokens } : {}, ...input.stream === true ? { stream: true } : {} });
9280
+ const transport = await sendfetch({ request: { url: shaped.url, method: shaped.method, headers: shaped.headers, body: shaped.body }, ...input.options !== void 0 ? { options: input.options } : {}, transport: input.transport, ...input.sleep !== void 0 ? { sleep: input.sleep } : {}, ...input.now !== void 0 ? { now: input.now } : {} });
9281
+ const parsed = parsecompletion(input.provider.style, transport.body);
9282
+ if (parsed.text === void 0) throw new Error(parsed.reason ?? "The provider answer did not parse.");
9283
+ return { text: parsed.text, ...parsed.usage !== void 0 ? { usage: parsed.usage } : {}, request: shaped };
9284
+ }
9285
+ async function calllocal(input) {
9286
+ if (input.local.endpoint.trim() === "") throw new Error("The local model needs the user configured endpoint url before any call runs.");
9287
+ if (!islocalorigin(input.local.endpoint)) throw new Error("The local model endpoint must stay a local machine address; the call never leaves the machine.");
9288
+ const provider = { id: "local", name: "The local model endpoint", endpoint: input.local.endpoint, style: input.local.style, models: [input.local.model], status: "available", createdat: 0 };
9289
+ return callmodel({ provider, model: input.local.model, messages: input.messages, ...input.apikey !== void 0 ? { apikey: input.apikey } : {}, ...input.temperature !== void 0 ? { temperature: input.temperature } : {}, ...input.maxtokens !== void 0 ? { maxtokens: input.maxtokens } : {}, ...input.options !== void 0 ? { options: input.options } : {}, transport: input.transport, ...input.sleep !== void 0 ? { sleep: input.sleep } : {}, ...input.now !== void 0 ? { now: input.now } : {} });
9290
+ }
9291
+ function streamdelta(style, event) {
9292
+ let parsed;
9293
+ try {
9294
+ parsed = JSON.parse(event);
9295
+ } catch {
9296
+ return "";
9297
+ }
9298
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return "";
9299
+ const record2 = parsed;
9300
+ if (style === "chatcompletions") {
9301
+ const choice = Array.isArray(record2.choices) ? record2.choices[0] : void 0;
9302
+ const delta = choice !== void 0 && choice.delta !== void 0 && typeof choice.delta === "object" ? choice.delta.content : void 0;
9303
+ return typeof delta === "string" ? delta : "";
9304
+ }
9305
+ if (style === "responses") {
9306
+ if (record2.type === "response.output_text.delta" && typeof record2.delta === "string") return record2.delta;
9307
+ return "";
9308
+ }
9309
+ if (style === "messages") {
9310
+ if (record2.type === "content_block_delta" && record2.delta !== void 0 && typeof record2.delta === "object" && typeof record2.delta.text === "string") return record2.delta.text;
9311
+ return "";
9312
+ }
9313
+ const candidate = Array.isArray(record2.candidates) ? record2.candidates[0] : void 0;
9314
+ const content = candidate !== void 0 && candidate.content !== void 0 && typeof candidate.content === "object" ? candidate.content.parts : void 0;
9315
+ if (!Array.isArray(content)) return "";
9316
+ const parts = [];
9317
+ for (const part of content) {
9318
+ if (part && typeof part === "object" && typeof part.text === "string") parts.push(part.text);
9319
+ }
9320
+ return parts.join("");
9321
+ }
9322
+ function parsestream(style, body) {
9323
+ const tokens = [];
9324
+ let seq = 0;
9325
+ let done = false;
9326
+ for (const line of body.split(/\r?\n/)) {
9327
+ const trimmed = line.trim();
9328
+ if (trimmed === "") continue;
9329
+ if (!trimmed.startsWith("data:")) continue;
9330
+ const payload = trimmed.slice(5).trim();
9331
+ if (payload === "[DONE]") {
9332
+ done = true;
9333
+ continue;
9334
+ }
9335
+ const text2 = streamdelta(style, payload);
9336
+ if (text2 === "") continue;
9337
+ seq += 1;
9338
+ tokens.push({ seq, text: text2, done: false });
9339
+ }
9340
+ if (tokens.length > 0 && done) tokens[tokens.length - 1] = { ...tokens[tokens.length - 1], done: true };
9341
+ return tokens;
9342
+ }
9343
+ async function streammodel(input) {
9344
+ if (input.provider.endpoint.trim() === "") throw new Error("The provider needs the user configured endpoint url before any call leaves.");
9345
+ if (input.provider.authref !== void 0 && (input.apikey === void 0 || input.apikey.trim() === "")) throw new Error(`The provider ${input.provider.name} references the stored key ${input.provider.authref.name} and the call needs the resolved key material.`);
9346
+ const consent = egressconsentgate({ ...input.pagecontent !== void 0 ? { pagecontent: input.pagecontent } : {}, granted: input.pagegrant === true });
9347
+ if (!consent.allowed) throw new Error(consent.reason ?? "The page content stayed ungranted and the call refused.");
9348
+ const shaped = buildrequest({ provider: input.provider, model: input.model, messages: input.messages, ...input.apikey !== void 0 ? { apikey: input.apikey } : {}, ...input.temperature !== void 0 ? { temperature: input.temperature } : {}, ...input.maxtokens !== void 0 ? { maxtokens: input.maxtokens } : {}, stream: true });
9349
+ const transport = await sendfetch({ request: { url: shaped.url, method: shaped.method, headers: shaped.headers, body: shaped.body }, ...input.options !== void 0 ? { options: input.options } : {}, transport: input.transport, ...input.sleep !== void 0 ? { sleep: input.sleep } : {}, ...input.now !== void 0 ? { now: input.now } : {} });
9350
+ const tokens = parsestream(input.provider.style, transport.body);
9351
+ if (tokens.length === 0) return { text: transport.body, tokens: 0, request: shaped };
9352
+ return { text: tokens.map((token) => token.text).join(""), tokens: tokens.length, request: shaped };
9353
+ }
9354
+ var commandguard = { schema: { intent: { type: "string", required: true }, entities: { type: "array", required: true }, confidence: { type: "number", required: true } }, retries: 1 };
9355
+ function classifyintent(text2) {
9356
+ const words = text2.toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
9357
+ if (words.length === 0) return { intent: "ask", confidence: 0 };
9358
+ const scores = { navigate: 0, extract: 0, fill: 0, monitor: 0, automate: 0, ask: 0 };
9359
+ const keywords = [
9360
+ ["navigate", ["go", "open", "visit", "navigate", "browse", "url", "site", "page", "to"]],
9361
+ ["extract", ["extract", "scrape", "collect", "read", "gather", "copy", "table", "data", "text"]],
9362
+ ["fill", ["fill", "type", "enter", "form", "submit", "login", "sign", "checkout", "field"]],
9363
+ ["monitor", ["watch", "monitor", "observe", "track", "alert", "notify", "poll", "changes"]],
9364
+ ["automate", ["automate", "workflow", "repeat", "every", "schedule", "batch", "pipeline", "steps", "then"]],
9365
+ ["ask", ["what", "who", "when", "where", "why", "how", "explain", "summarize", "ask", "question", "tell"]]
9366
+ ];
9367
+ for (const [intent, list] of keywords) for (const word of list) if (words.includes(word)) scores[intent] += 1;
9368
+ let best = "ask";
9369
+ let bestscore = scores.ask;
9370
+ for (const [intent] of keywords) if (scores[intent] > bestscore) {
9371
+ best = intent;
9372
+ bestscore = scores[intent];
9373
+ }
9374
+ const total = Object.values(scores).reduce((sum, value) => sum + value, 0);
9375
+ const confidence = bestscore === 0 ? 0.1 : Math.min(1, Math.round((bestscore / total * 0.6 + Math.min(bestscore / 3, 1) * 0.4) * 100) / 100);
9376
+ return { intent: best, confidence };
9377
+ }
9378
+ async function parsecommand(input) {
9379
+ if (input.text.trim() === "") return { reason: "The command parse needs the natural language text." };
9380
+ const guard = input.guard ?? commandguard;
9381
+ const answer = await callmodel({ provider: input.provider, model: input.model, messages: [{ role: "system", content: "Parse the user command into json with the fields intent (one of navigate, extract, fill, monitor, automate, ask), entities (an array of { name, value } objects) and confidence (a number between 0 and 1). Answer with the json object only." }, { role: "user", content: input.text }], ...input.apikey !== void 0 ? { apikey: input.apikey } : {}, transport: input.transport, ...input.sleep !== void 0 ? { sleep: input.sleep } : {}, ...input.now !== void 0 ? { now: input.now } : {} });
9382
+ const output = guardoutput({ guard, attempts: [answer.text] });
9383
+ if (output.verdict !== "valid" || output.parsed === void 0) return { output, reason: output.reason ?? "The command answer failed its guard." };
9384
+ const parsed = output.parsed;
9385
+ if (typeof parsed.intent !== "string") return { output, reason: "The command answer carries no intent." };
9386
+ const intents = ["navigate", "extract", "fill", "monitor", "automate", "ask"];
9387
+ if (!intents.includes(parsed.intent)) return { output, reason: `The intent ${parsed.intent} is not one of the intent kinds.` };
9388
+ const entities = Array.isArray(parsed.entities) ? parsed.entities.filter((entity) => entity !== null && typeof entity === "object" && !Array.isArray(entity) && typeof entity.name === "string" && typeof entity.value === "string") : [];
9389
+ const confidence = typeof parsed.confidence === "number" && Number.isFinite(parsed.confidence) ? Math.min(1, Math.max(0, parsed.confidence)) : 0;
9390
+ return { parse: { text: input.text, intent: parsed.intent, entities, confidence, model: input.model, providerid: input.provider.id, parsedat: (input.now ?? Date.now)() }, output };
9391
+ }
9392
+ async function draftplan(input) {
9393
+ if (input.goal.trim() === "") return { reason: "The plan draft needs the goal." };
9394
+ const lessons = input.lessons ?? [];
9395
+ const answer = await callmodel({ provider: input.provider, model: input.model, messages: [{ role: "system", content: `Draft a browser agent plan as json with the fields goal (string), steps (an array of { kind, target, value, summary } objects using browser action kinds) and openquestions (an array of strings for what stays unclear).${lessons.length > 0 ? ` The running lessons of the earlier steps: ${lessons.join(" | ")}.` : ""} Answer with the json object only.` }, { role: "user", content: input.goal }], ...input.apikey !== void 0 ? { apikey: input.apikey } : {}, transport: input.transport, ...input.sleep !== void 0 ? { sleep: input.sleep } : {}, ...input.now !== void 0 ? { now: input.now } : {} });
9396
+ const guard = { schema: { goal: { type: "string", required: true }, steps: { type: "array", required: true }, openquestions: { type: "array" } }, retries: 1 };
9397
+ const output = guardoutput({ guard, attempts: [answer.text] });
9398
+ if (output.verdict !== "valid" || output.parsed === void 0) return { output, reason: output.reason ?? "The plan draft answer failed its guard." };
9399
+ const parsed = output.parsed;
9400
+ const rawsteps = Array.isArray(parsed.steps) ? parsed.steps : [];
9401
+ const steps = rawsteps.filter((step) => step !== null && typeof step === "object" && !Array.isArray(step)).map((step, index) => ({ id: `step${index + 1}`, kind: typeof step.kind === "string" ? step.kind : "", ...typeof step.target === "string" && step.target.trim() !== "" ? { target: step.target } : {}, ...typeof step.value === "string" && step.value.trim() !== "" ? { value: step.value } : {}, summary: typeof step.summary === "string" ? step.summary : "" }));
9402
+ const openquestions = Array.isArray(parsed.openquestions) ? parsed.openquestions.filter((question) => typeof question === "string") : [];
9403
+ const draft = { id: randomid(), goal: typeof parsed.goal === "string" && parsed.goal.trim() !== "" ? parsed.goal : input.goal, steps, openquestions, providerid: input.provider.id, model: input.model, state: "draft", lintfindings: [], createdat: (input.now ?? Date.now)() };
9404
+ draft.lintfindings = planlint(draft, input.origin ?? "");
9405
+ return { draft, output };
9406
+ }
9407
+ async function replannonfail(input) {
9408
+ if (input.reason.trim() === "") return { reason: "The replan needs the failure reason." };
9409
+ const completed = input.draft.steps.filter((step) => input.completedstepids.includes(step.id));
9410
+ const failed = input.draft.steps.filter((step) => input.failedstepids.includes(step.id));
9411
+ const lessons = input.lessons ?? [];
9412
+ const answer = await callmodel({ provider: input.provider, model: input.model, messages: [{ role: "system", content: `The plan ${input.draft.goal} failed at the steps ${failed.map((step) => step.summary).join("; ") || "unknown"} with the reason: ${input.reason}. The completed steps stay: ${completed.map((step) => step.summary).join("; ") || "none"}.${lessons.length > 0 ? ` The running lessons: ${lessons.join(" | ")}.` : ""} Draft the revised tail steps of the plan as json with the field steps (an array of { kind, target, value, summary } objects using browser action kinds). Answer with the json object only.` }, { role: "user", content: input.draft.goal }], ...input.apikey !== void 0 ? { apikey: input.apikey } : {}, transport: input.transport, ...input.sleep !== void 0 ? { sleep: input.sleep } : {}, ...input.now !== void 0 ? { now: input.now } : {} });
9413
+ const guard = { schema: { steps: { type: "array", required: true } }, retries: 1 };
9414
+ const output = guardoutput({ guard, attempts: [answer.text] });
9415
+ if (output.verdict !== "valid" || output.parsed === void 0) return { output, reason: output.reason ?? "The replan answer failed its guard." };
9416
+ const rawsteps = Array.isArray(output.parsed.steps) ? output.parsed.steps : [];
9417
+ const tail = rawsteps.filter((step) => step !== null && typeof step === "object" && !Array.isArray(step)).map((step, index) => ({ id: `tail${index + 1}`, kind: typeof step.kind === "string" ? step.kind : "", ...typeof step.target === "string" && step.target.trim() !== "" ? { target: step.target } : {}, ...typeof step.value === "string" && step.value.trim() !== "" ? { value: step.value } : {}, summary: typeof step.summary === "string" ? step.summary : "", freshreview: true }));
9418
+ const replan = { id: randomid(), draftid: input.draft.id, completedstepids: [...input.completedstepids], failedstepids: [...input.failedstepids], tail, reason: input.reason, providerid: input.provider.id, model: input.model, state: "pending", createdat: (input.now ?? Date.now)() };
9419
+ return { replan, output };
9420
+ }
9421
+ async function reflectstep(input) {
9422
+ if (input.outcome.trim() === "") return { reason: "The reflection needs the step outcome." };
9423
+ const lessons = input.lessons ?? [];
9424
+ const answer = await callmodel({ provider: input.provider, model: input.model, messages: [{ role: "system", content: `Reflect on the executed step ${input.stepid} of the run ${input.runid} with the outcome: ${input.outcome}.${lessons.length > 0 ? ` The running lessons of the earlier steps: ${lessons.join(" | ")}.` : ""} Answer as json with the fields outcome (string), lesson (string) and advice (string) for the next step. Answer with the json object only.` }, { role: "user", content: input.outcome }], ...input.apikey !== void 0 ? { apikey: input.apikey } : {}, transport: input.transport, ...input.sleep !== void 0 ? { sleep: input.sleep } : {}, ...input.now !== void 0 ? { now: input.now } : {} });
9425
+ const guard = { schema: { outcome: { type: "string", required: true }, lesson: { type: "string", required: true }, advice: { type: "string", required: true } }, retries: 1 };
9426
+ const output = guardoutput({ guard, attempts: [answer.text] });
9427
+ if (output.verdict !== "valid" || output.parsed === void 0) return { output, reason: output.reason ?? "The reflection answer failed its guard." };
9428
+ const parsed = output.parsed;
9429
+ if (typeof parsed.lesson !== "string" || typeof parsed.advice !== "string") return { output, reason: "The reflection answer carries no lesson or advice." };
9430
+ const note = { id: randomid(), runid: input.runid, stepid: input.stepid, outcome: typeof parsed.outcome === "string" ? parsed.outcome : input.outcome, lesson: parsed.lesson, advice: parsed.advice, providerid: input.provider.id, model: input.model, createdat: (input.now ?? Date.now)() };
9431
+ return { note, output };
9432
+ }
9433
+ function reflectionsummary(notes) {
9434
+ const latest = /* @__PURE__ */ new Map();
9435
+ for (const note of notes) latest.set(note.stepid, note);
9436
+ const lessons = [...latest.values()].sort((one, two) => one.createdat - two.createdat).map((note) => note.lesson);
9437
+ return lessons.length === 0 ? "" : lessons.join(" | ");
9438
+ }
9439
+ function stripguardrails(text2) {
9440
+ const fenced = text2.match(/```(?:[a-z]*)\s*\r?\n?([\s\S]*?)```/i);
9441
+ const candidate = fenced !== null ? fenced[1] ?? "" : text2;
9442
+ const start = candidate.indexOf("{");
9443
+ const end = candidate.lastIndexOf("}");
9444
+ if (start >= 0 && end > start) return candidate.slice(start, end + 1);
9445
+ const arraystart = candidate.indexOf("[");
9446
+ const arrayend = candidate.lastIndexOf("]");
9447
+ if (arraystart >= 0 && arrayend > arraystart) return candidate.slice(arraystart, arrayend + 1);
9448
+ return candidate.trim();
9449
+ }
9450
+ function parseoutput(input) {
9451
+ const raw = input.text;
9452
+ const stripped = stripguardrails(raw);
9453
+ const markers = input.guard.refusalmarkers ?? defaultrefusalmarkers;
9454
+ const lowered = stripped.toLowerCase();
9455
+ for (const marker of markers) if (marker.trim() !== "" && lowered.includes(marker.toLowerCase())) return { raw, verdict: "refused", reason: `The model answer carries the refusal marker ${marker}.`, attempts: 1 };
9456
+ let parsed;
9457
+ try {
9458
+ parsed = JSON.parse(stripped);
9459
+ } catch {
9460
+ return { raw, verdict: "invalid", reason: "The model answer is not json after the guardrail strip.", attempts: 1 };
9461
+ }
9462
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return { raw, verdict: "invalid", reason: "The model answer is not a json object.", attempts: 1 };
9463
+ const record2 = parsed;
9464
+ for (const [name, field] of Object.entries(input.guard.schema)) {
9465
+ const value = record2[name];
9466
+ if (value === void 0 || value === null) {
9467
+ if (field.required === true) return { raw, verdict: "invalid", reason: `The required field ${name} of the expected schema is missing.`, attempts: 1 };
9468
+ continue;
9469
+ }
9470
+ const actual = Array.isArray(value) ? "array" : typeof value;
9471
+ if (actual !== field.type) return { raw, verdict: "invalid", reason: `The field ${name} carries a ${actual} value where the schema asks a ${field.type}.`, attempts: 1 };
9472
+ }
9473
+ return { raw, parsed: record2, verdict: "valid", attempts: 1 };
9474
+ }
9475
+ function guardoutput(input) {
9476
+ const limit = Math.max(1, Math.floor(input.guard.retries) + 1);
9477
+ const attempts = input.attempts.slice(0, limit);
9478
+ let last;
9479
+ for (let index = 0; index < attempts.length; index += 1) {
9480
+ const output = parseoutput({ guard: input.guard, text: attempts[index] ?? "" });
9481
+ last = { ...output, attempts: index + 1 };
9482
+ if (output.verdict === "valid") return last;
9483
+ if (output.verdict === "refused") return { ...output, attempts: index + 1 };
9484
+ }
9485
+ const exhausted = last === void 0 ? { raw: "", verdict: "invalid", reason: "The model answer never arrived.", attempts: 0 } : { ...last, verdict: "invalid", reason: `${last.reason ?? "The model answer failed its guard."} Every retry attempt failed, so the guard refuses the output and nothing executes.` };
9486
+ return exhausted;
9487
+ }
9488
+ function toolbriefof(tool) {
9489
+ return { tool: tool.name, summary: `${tool.name}: ${tool.description.split(".")[0] ?? tool.description}.`, description: tool.description, risk: tool.risk, parameters: Object.entries(tool.inputschema.properties).map(([name, property]) => ({ name, type: property.type, description: property.description, required: property.required === true })) };
9490
+ }
9491
+ function rendertoolbriefs(tools) {
9492
+ const blocks = tools.map((tool) => {
9493
+ const brief = toolbriefof(tool);
9494
+ const parameters = brief.parameters.map((parameter) => ` - name: ${parameter.name}
9495
+ type: ${parameter.type}
9496
+ required: ${parameter.required ? "true" : "false"}
9497
+ description: ${parameter.description}`).join("\n");
9498
+ return ` - tool: ${brief.tool}
9499
+ summary: ${brief.summary}
9500
+ risk: ${brief.risk}
9501
+ parameters:
9502
+ ${parameters}`;
9503
+ });
9504
+ return `tools:
9505
+ ${blocks.join("\n")}
9506
+ consent: every tool with side effects executes only the approved plan step it names; a proposal without the approved step stays refused.`;
9507
+ }
9508
+ function addusage(records, record2) {
9509
+ return [record2, ...records];
9510
+ }
9511
+ function usagetotals(records, filter = {}) {
9512
+ const kept = records.filter((record2) => (filter.runid === void 0 || record2.runid === filter.runid) && (filter.stepid === void 0 || record2.stepid === filter.stepid) && (filter.since === void 0 || record2.at >= filter.since) && (filter.until === void 0 || record2.at <= filter.until));
9513
+ return kept.reduce((totals, record2) => ({ prompttokens: totals.prompttokens + record2.prompttokens, completiontokens: totals.completiontokens + record2.completiontokens, totaltokens: totals.totaltokens + record2.totaltokens, cost: totals.cost + record2.cost, calls: totals.calls + 1 }), { prompttokens: 0, completiontokens: 0, totaltokens: 0, cost: 0, calls: 0 });
9514
+ }
9515
+ function budgetcheck(input) {
9516
+ if (input.budget === void 0) return { allowed: true, halted: false, asksuser: false };
9517
+ if (input.budget.maxtokens !== void 0 && Number.isFinite(input.budget.maxtokens) && input.totals.totaltokens >= input.budget.maxtokens) return { allowed: false, halted: true, asksuser: true, reason: `The run reached the user configured token ceiling of ${input.budget.maxtokens} and halts until the user answers.` };
9518
+ if (input.budget.maxcost !== void 0 && Number.isFinite(input.budget.maxcost) && input.totals.cost >= input.budget.maxcost) return { allowed: false, halted: true, asksuser: true, reason: `The run reached the user configured cost ceiling of ${input.budget.maxcost} and halts until the user answers.` };
9519
+ return { allowed: true, halted: false, asksuser: false };
9520
+ }
9521
+
9522
+ // version.ts
9523
+ var packageversion = "1.1.57";
9524
+
9525
+ // types.ts
9526
+ var protocolversion = packageversion;
8987
9527
 
8988
9528
  // agentstream.ts
8989
9529
  function listprompts() {
@@ -9576,6 +10116,92 @@ function streamsummaries(raw) {
9576
10116
  });
9577
10117
  }
9578
10118
 
10119
+ // modelroute.ts
10120
+ function routevalid(route) {
10121
+ if (route.kind.trim() === "") return { allowed: false, reason: "The model route needs its task kind." };
10122
+ if (route.providerid.trim() === "") return { allowed: false, reason: "The model route needs the provider it routes to." };
10123
+ if (route.model.trim() === "") return { allowed: false, reason: "The model route needs the model name it routes to." };
10124
+ const hasfallbackprovider = route.fallbackproviderid !== void 0 && route.fallbackproviderid.trim() !== "";
10125
+ const hasfallbackmodel = route.fallbackmodel !== void 0 && route.fallbackmodel.trim() !== "";
10126
+ if (hasfallbackprovider !== hasfallbackmodel) return { allowed: false, reason: "The fallback of a model route needs its provider and its model together." };
10127
+ return { allowed: true };
10128
+ }
10129
+ function routesfor(routes, kind) {
10130
+ return routes.filter((route) => route.kind === kind).sort((one, two) => two.revision - one.revision);
10131
+ }
10132
+ function resolveroute(input) {
10133
+ const candidates = routesfor(input.routes, input.kind);
10134
+ if (candidates.length === 0) return { reason: `No model route configures the task kind ${input.kind}; the user picks the provider and model pair.` };
10135
+ for (const route of candidates) {
10136
+ if (!routevalid(route).allowed) continue;
10137
+ const provider = input.providers.find((candidate) => candidate.id === route.providerid);
10138
+ if (provider === void 0) return { reason: `The route of ${input.kind} names the missing provider ${route.providerid}.` };
10139
+ if (provider.status === "unavailable") return { reason: `The provider ${provider.name} of the route of ${input.kind} stays marked unavailable from its last failure.` };
10140
+ if (!provider.models.includes(route.model)) return { reason: `The route of ${input.kind} names the model ${route.model} outside the model list of ${provider.name}.` };
10141
+ return { route, provider, model: route.model };
10142
+ }
10143
+ return { reason: `Every route of the task kind ${input.kind} failed its validation.` };
10144
+ }
10145
+ function markprovider(input) {
10146
+ return input.providers.map((provider) => provider.id === input.providerid ? { ...provider, status: input.available ? "available" : "unavailable", lastcheckedat: input.now } : provider);
10147
+ }
10148
+ function fallbackroute(input) {
10149
+ const candidates = routesfor(input.routes, input.kind);
10150
+ const primary = candidates.find((route) => routevalid(route).allowed);
10151
+ if (primary === void 0) return { reason: `No valid route configures the task kind ${input.kind}, so no fallback applies.` };
10152
+ if (primary.fallbackproviderid === void 0 || primary.fallbackmodel === void 0) return { reason: `The route of ${input.kind} carries no user configured fallback pair.` };
10153
+ const provider = input.providers.find((candidate) => candidate.id === primary.fallbackproviderid);
10154
+ if (provider === void 0) return { reason: `The fallback names the missing provider ${primary.fallbackproviderid}.` };
10155
+ if (provider.status === "unavailable") return { reason: `The fallback provider ${provider.name} stays marked unavailable from its last failure.` };
10156
+ if (!provider.models.includes(primary.fallbackmodel)) return { reason: `The fallback names the model ${primary.fallbackmodel} outside the model list of ${provider.name}.` };
10157
+ return { route: primary, provider, model: primary.fallbackmodel };
10158
+ }
10159
+ function bumprevision(route, now) {
10160
+ return { ...route, revision: route.revision + 1, updatedat: now };
10161
+ }
10162
+
10163
+ // promptlibrary.ts
10164
+ function templatevariables(body) {
10165
+ const names = [];
10166
+ for (const match of body.matchAll(/\{\{\s*([a-z0-9]+)\s*\}\}/g)) {
10167
+ const name = match[1] ?? "";
10168
+ if (name !== "" && !names.includes(name)) names.push(name);
10169
+ }
10170
+ return names;
10171
+ }
10172
+ function rendertemplate(input) {
10173
+ if (input.sensitive === true && (input.consentnotice === void 0 || input.consentnotice.trim() === "")) return { reason: "The sensitive flow needs its consent notice before the template renders." };
10174
+ const variables = input.variables ?? {};
10175
+ const missing = input.template.variables.filter((name) => variables[name] === void 0 || variables[name] === null || typeof variables[name] === "string" && variables[name].trim() === "");
10176
+ if (missing.length > 0) return { reason: `The template variables ${missing.join(", ")} stay empty.` };
10177
+ let text2 = input.template.body.replace(/\{\{\s*([a-z0-9]+)\s*\}\}/g, (whole, name) => {
10178
+ const value = variables[name];
10179
+ if (value === void 0 || value === null) return whole;
10180
+ return typeof value === "string" ? value : JSON.stringify(value);
10181
+ });
10182
+ if (input.sensitive === true && input.consentnotice !== void 0) text2 = `${text2}
10183
+ Consent notice: ${input.consentnotice}`;
10184
+ return { text: text2 };
10185
+ }
10186
+ function savetemplate(input) {
10187
+ const existing = input.templates.filter((template) => template.name === input.name);
10188
+ const version = existing.length === 0 ? 1 : Math.max(...existing.map((template) => template.version)) + 1;
10189
+ const record2 = { id: randomid(), name: input.name, body: input.body, variables: templatevariables(input.body), version, ...input.notes !== void 0 && input.notes.trim() !== "" ? { notes: input.notes } : {}, createdat: input.now };
10190
+ return [record2, ...input.templates];
10191
+ }
10192
+ function latesttemplate(templates, name) {
10193
+ const versions = templates.filter((template) => template.name === name);
10194
+ return versions.length === 0 ? void 0 : versions.reduce((newest, template) => template.version > newest.version ? template : newest);
10195
+ }
10196
+ function searchtemplates(templates, query) {
10197
+ const term = query.trim().toLowerCase();
10198
+ const matches = term === "" ? templates : templates.filter((template) => template.name.toLowerCase().includes(term) || template.body.toLowerCase().includes(term) || (template.notes ?? "").toLowerCase().includes(term) || template.variables.some((variable) => variable.toLowerCase().includes(term)));
10199
+ return [...matches].sort((one, two) => two.version - one.version || two.createdat - one.createdat);
10200
+ }
10201
+ function removetemplate(templates, name) {
10202
+ return templates.filter((template) => template.name !== name);
10203
+ }
10204
+
9579
10205
  // protocol.ts
9580
10206
  function record(value) {
9581
10207
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Protocol message must be an object.");
@@ -10291,6 +10917,12 @@ function mockreport(mocks) {
10291
10917
  function idempotencyreport(records, now) {
10292
10918
  return { version: protocolversion, records: records.map((record2) => ({ key: record2.key, clientid: record2.clientid, tool: record2.tool, createdat: record2.createdat, expiresat: record2.expiresat, live: now < record2.expiresat })) };
10293
10919
  }
10920
+ function modelproposal(input) {
10921
+ return { version: protocolversion, modelproposal: { draftid: input.draft.id, goal: input.draft.goal, steps: input.draft.steps.map((step) => ({ id: step.id, kind: step.kind, ...step.target !== void 0 ? { target: step.target } : {}, ...step.value !== void 0 ? { value: step.value } : {}, summary: step.summary, ...step.freshreview === true ? { freshreview: true } : {} })), openquestions: input.draft.openquestions, lintfindings: input.draft.lintfindings, providerid: input.draft.providerid, model: input.draft.model, state: input.draft.state, createdat: input.draft.createdat } };
10922
+ }
10923
+ function modeloutcome(input) {
10924
+ return { version: protocolversion, modeloutcome: { ...input.runid !== void 0 && input.runid.trim() !== "" ? { runid: input.runid } : {}, usage: input.totals, guards: input.outputs.map((output) => ({ verdict: output.verdict, ...output.reason !== void 0 ? { reason: output.reason } : {}, attempts: output.attempts })) } };
10925
+ }
10294
10926
 
10295
10927
  // workfloweditor.ts
10296
10928
  var palettecategories = ["actions", "controlflow", "waits", "variables", "triggers"];
@@ -10999,6 +11631,7 @@ export {
10999
11631
  activelayers,
11000
11632
  addedge,
11001
11633
  addnode,
11634
+ addusage,
11002
11635
  agentgrammarvalid,
11003
11636
  agentpresetof,
11004
11637
  allowlistcovers,
@@ -11050,14 +11683,19 @@ export {
11050
11683
  breakpointceilingof,
11051
11684
  breakpointinputof,
11052
11685
  browserpermissions,
11686
+ budgetcheck,
11053
11687
  buildname,
11054
11688
  buildpdf,
11689
+ buildrequest,
11055
11690
  buildsheet,
11056
11691
  buildsteplibrary,
11057
11692
  buildstitchplan,
11058
11693
  buildtoolcatalog,
11694
+ bumprevision,
11059
11695
  callgraphql,
11696
+ calllocal,
11060
11697
  calllogreport,
11698
+ callmodel,
11061
11699
  callrest,
11062
11700
  callsreport,
11063
11701
  cancelframes,
@@ -11089,9 +11727,11 @@ export {
11089
11727
  channelorigin,
11090
11728
  checkallowlist,
11091
11729
  choosebranch,
11730
+ classifyintent,
11092
11731
  closechannel,
11093
11732
  closeidlechannels,
11094
11733
  collectmessages,
11734
+ commandguard,
11095
11735
  composeworkflow,
11096
11736
  conditionof,
11097
11737
  confirmmanualrun,
@@ -11112,6 +11752,7 @@ export {
11112
11752
  cookiegate,
11113
11753
  cookierecordof,
11114
11754
  correlationid,
11755
+ costbudgetvalid,
11115
11756
  cpusnap,
11116
11757
  crashinterrupted,
11117
11758
  cronnext,
@@ -11133,6 +11774,7 @@ export {
11133
11774
  defaultmcpconfig,
11134
11775
  defaultmcpport,
11135
11776
  defaultpairinglifetimems,
11777
+ defaultrefusalmarkers,
11136
11778
  defaulttokenlifetimems,
11137
11779
  defaulttriggercooldown,
11138
11780
  delayjitter,
@@ -11147,6 +11789,7 @@ export {
11147
11789
  dispatchtool,
11148
11790
  domainkinds,
11149
11791
  downloadreport,
11792
+ draftplan,
11150
11793
  drainqueue,
11151
11794
  dryrunprojection,
11152
11795
  dryrunreport,
@@ -11154,6 +11797,7 @@ export {
11154
11797
  editorsavegate,
11155
11798
  editorstate,
11156
11799
  editstep,
11800
+ egressconsentgate,
11157
11801
  emugate,
11158
11802
  emulationkinds,
11159
11803
  emulationreport,
@@ -11187,6 +11831,7 @@ export {
11187
11831
  extractionreport,
11188
11832
  extractvalues,
11189
11833
  failureclass,
11834
+ fallbackroute,
11190
11835
  familyofkind,
11191
11836
  fetchoptionsof,
11192
11837
  fetchrequestof,
@@ -11209,6 +11854,8 @@ export {
11209
11854
  groupselect,
11210
11855
  growsampleof,
11211
11856
  growthtrend,
11857
+ guardoutput,
11858
+ guardverdictgate,
11212
11859
  handleframe,
11213
11860
  headerfilterof,
11214
11861
  headeruleof,
@@ -11239,6 +11886,7 @@ export {
11239
11886
  isdebugkind,
11240
11887
  isemulationkind,
11241
11888
  isformkind,
11889
+ islocalorigin,
11242
11890
  isnetwatchkind,
11243
11891
  isprofilekind,
11244
11892
  issessionkind,
@@ -11254,6 +11902,7 @@ export {
11254
11902
  jsonpathrulesof,
11255
11903
  lapseframes,
11256
11904
  lapseplanof,
11905
+ latesttemplate,
11257
11906
  launchbridge,
11258
11907
  layernames,
11259
11908
  layoutreport,
@@ -11264,6 +11913,7 @@ export {
11264
11913
  listtools,
11265
11914
  loadworkflow,
11266
11915
  localhostbind,
11916
+ localsensitivegrade,
11267
11917
  locationconsentcovers,
11268
11918
  locationconsentgate,
11269
11919
  locationpresetof,
@@ -11276,6 +11926,7 @@ export {
11276
11926
  mapresponse,
11277
11927
  mapurlof,
11278
11928
  markbreakpoint,
11929
+ markprovider,
11279
11930
  matchmessage,
11280
11931
  matchurl,
11281
11932
  matchurlpattern,
@@ -11289,6 +11940,8 @@ export {
11289
11940
  mockfor,
11290
11941
  mockreport,
11291
11942
  mockspecof,
11943
+ modeloutcome,
11944
+ modelproposal,
11292
11945
  multipartchunks,
11293
11946
  multipartpayloadof,
11294
11947
  namespaceof,
@@ -11327,10 +11980,14 @@ export {
11327
11980
  palettecategories,
11328
11981
  palettenodes,
11329
11982
  parallelof,
11983
+ parsecommand,
11984
+ parsecompletion,
11330
11985
  parseframe,
11331
11986
  parsehtmlbody,
11987
+ parseoutput,
11332
11988
  parseproposal,
11333
11989
  parsessetext,
11990
+ parsestream,
11334
11991
  parsetokens,
11335
11992
  parsewire,
11336
11993
  parseworkflowproposal,
@@ -11353,6 +12010,8 @@ export {
11353
12010
  permissionstatevalid,
11354
12011
  ping,
11355
12012
  planallowlist,
12013
+ plandraftreviewgate,
12014
+ planlint,
11356
12015
  pollcursorof,
11357
12016
  polldecision,
11358
12017
  pollurl,
@@ -11367,6 +12026,8 @@ export {
11367
12026
  promptreport,
11368
12027
  protocolversion,
11369
12028
  provenancereport,
12029
+ provideregressgrade,
12030
+ providervalid,
11370
12031
  proxygate,
11371
12032
  proxyrouteof,
11372
12033
  publishmessage,
@@ -11390,6 +12051,8 @@ export {
11390
12051
  redactparams,
11391
12052
  redeempairingcode,
11392
12053
  redoedit,
12054
+ reflectionsummary,
12055
+ reflectstep,
11393
12056
  regexextract,
11394
12057
  regexruleof,
11395
12058
  regionsteps,
@@ -11397,9 +12060,14 @@ export {
11397
12060
  relayframe,
11398
12061
  removeedge,
11399
12062
  removenode,
12063
+ removetemplate,
11400
12064
  renderminimap,
12065
+ rendertemplate,
12066
+ rendertoolbriefs,
11401
12067
  reordersteps,
11402
12068
  repeatuntilof,
12069
+ replannonfail,
12070
+ replanreviewgate,
11403
12071
  replaytrace,
11404
12072
  replayurl,
11405
12073
  requestbody,
@@ -11407,6 +12075,7 @@ export {
11407
12075
  resolutionverdict,
11408
12076
  resolveapproval,
11409
12077
  resolvedrisk,
12078
+ resolveroute,
11410
12079
  resolvetool,
11411
12080
  resolvevariable,
11412
12081
  resourcedeltareport,
@@ -11428,6 +12097,8 @@ export {
11428
12097
  rewritesourcelocation,
11429
12098
  rotatelogs,
11430
12099
  rotationruleof,
12100
+ routesfor,
12101
+ routevalid,
11431
12102
  rpcerrorcodeof,
11432
12103
  rpcerrornumbers,
11433
12104
  rpcerrorof,
@@ -11450,6 +12121,7 @@ export {
11450
12121
  runworkflow,
11451
12122
  safetyresponse,
11452
12123
  samplingframes,
12124
+ savetemplate,
11453
12125
  saveworkflow,
11454
12126
  scaledrect,
11455
12127
  schedulecron,
@@ -11460,6 +12132,7 @@ export {
11460
12132
  searchqueryof,
11461
12133
  searchsessionrecords,
11462
12134
  searchsteps,
12135
+ searchtemplates,
11463
12136
  seededrandom,
11464
12137
  selectorresponse,
11465
12138
  sendcdpcommand,
@@ -11504,8 +12177,11 @@ export {
11504
12177
  steptemplateof,
11505
12178
  stepwindows,
11506
12179
  streamchunkframe,
12180
+ streamdelta,
12181
+ streammodel,
11507
12182
  streamsummaries,
11508
12183
  streamwindowof,
12184
+ stripguardrails,
11509
12185
  structurederrorreport,
11510
12186
  submitreviewgranted,
11511
12187
  subscriptionframes,
@@ -11518,6 +12194,7 @@ export {
11518
12194
  teardowncdpsession,
11519
12195
  teardownplanof,
11520
12196
  templateurl,
12197
+ templatevariables,
11521
12198
  thumbdirectiveof,
11522
12199
  thumbgeometry,
11523
12200
  timelinecounts,
@@ -11533,6 +12210,7 @@ export {
11533
12210
  tokenhashprefix,
11534
12211
  tokenreport,
11535
12212
  tokenrequest,
12213
+ toolbriefof,
11536
12214
  toolcallevent,
11537
12215
  toolcallframe,
11538
12216
  toolcatalogversion,
@@ -11567,6 +12245,7 @@ export {
11567
12245
  unwrapgraphql,
11568
12246
  updaterule,
11569
12247
  urlencodeform,
12248
+ usagetotals,
11570
12249
  validatebreakpointcondition,
11571
12250
  validatecontrolpayload,
11572
12251
  validatefieldmatch,