@wenathlan/extension 1.1.55 → 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
@@ -2544,6 +2544,224 @@ var sessionmemory = class {
2544
2544
  async setstreamchannels(channels) {
2545
2545
  return this.adapter.set("mcpchannels", channels);
2546
2546
  }
2547
+ /** Returns every client event subscription with its kinds and filters, newest first. */
2548
+ async geteventsubscriptions() {
2549
+ return await this.adapter.get("mcpeventsubscriptions") ?? [];
2550
+ }
2551
+ /** Replaces the stored event subscription set after one subscribe, unsubscribe or delivery sweep. */
2552
+ async seteventsubscriptions(subscriptions) {
2553
+ return this.adapter.set("mcpeventsubscriptions", subscriptions);
2554
+ }
2555
+ /** Returns every page state resource watcher with its baseline, newest first. */
2556
+ async getresourcewatches() {
2557
+ return await this.adapter.get("mcpresourcewatches") ?? [];
2558
+ }
2559
+ /** Replaces the stored resource watcher set after one watch, unwatch or delta push. */
2560
+ async setresourcewatches(watches) {
2561
+ return this.adapter.set("mcpresourcewatches", watches);
2562
+ }
2563
+ /** Returns every sampling request with its provenance, newest first. */
2564
+ async getsamplingrequests() {
2565
+ return await this.adapter.get("mcpsampling") ?? [];
2566
+ }
2567
+ /** Replaces the stored sampling request set after one request or answer. */
2568
+ async setsamplingrequests(requests) {
2569
+ return this.adapter.set("mcpsampling", requests);
2570
+ }
2571
+ /** Returns every stored idempotency record for replay, newest first. */
2572
+ async getidempotencyrecords() {
2573
+ return await this.adapter.get("mcpidempotency") ?? [];
2574
+ }
2575
+ /** Replaces the stored idempotency record set after one store or expiry sweep. */
2576
+ async setidempotencyrecords(records) {
2577
+ return this.adapter.set("mcpidempotency", records);
2578
+ }
2579
+ /** Returns every per client rate limit counter with its window and budget. */
2580
+ async getcallratelimits() {
2581
+ return await this.adapter.get("mcpcallratelimits") ?? [];
2582
+ }
2583
+ /** Replaces the stored per client rate limit set after one configuration or counted call. */
2584
+ async setcallratelimits(limits) {
2585
+ return this.adapter.set("mcpcallratelimits", limits);
2586
+ }
2587
+ /** Returns every stored batch call with its per item outcomes, newest first. */
2588
+ async getbatchcalls() {
2589
+ return await this.adapter.get("mcpbatchcalls") ?? [];
2590
+ }
2591
+ /** Upserts one batch call by its id with the per item outcomes riding the record. */
2592
+ async setbatchcall(batch) {
2593
+ await this.adapter.set("mcpbatchcalls", [batch, ...(await this.getbatchcalls()).filter((candidate) => candidate.id !== batch.id)]);
2594
+ }
2595
+ /** Returns every call context of the call runtime, newest first. */
2596
+ async getcallcontexts() {
2597
+ return await this.adapter.get("mcpcallcontexts") ?? [];
2598
+ }
2599
+ /** Replaces the stored call context set after one begin, end or cancellation. */
2600
+ async setcallcontexts(contexts) {
2601
+ return this.adapter.set("mcpcallcontexts", contexts);
2602
+ }
2603
+ /** Returns every stored tool mock for client testing. */
2604
+ async gettoolmocks() {
2605
+ return await this.adapter.get("mcptoolmocks") ?? [];
2606
+ }
2607
+ /** Upserts one tool mock by its tool name or removes it when the canned result is absent. */
2608
+ async settoolmock(mock) {
2609
+ await this.adapter.set("mcptoolmocks", [mock, ...(await this.gettoolmocks()).filter((candidate) => candidate.tool !== mock.tool)]);
2610
+ }
2611
+ /** Removes one tool mock so its tool returns to the real gates. */
2612
+ async removetoolmock(tool) {
2613
+ await this.adapter.set("mcptoolmocks", (await this.gettoolmocks()).filter((candidate) => candidate.tool !== tool));
2614
+ }
2615
+ /** Stores one stream chunk of a progressive tool result under the recent chunk window of 25 records. */
2616
+ async addstreamchunk(chunk) {
2617
+ await this.adapter.set("mcpstreamchunks", [chunk, ...(await this.getstreamchunks()).slice(0, 24)]);
2618
+ }
2619
+ /** Returns the recent stream chunks of progressive tool results, newest first. */
2620
+ async getstreamchunks() {
2621
+ return await this.adapter.get("mcpstreamchunks") ?? [];
2622
+ }
2623
+ /** Replaces the recent stream chunk window after one streaming sweep. */
2624
+ async setstreamchunks(chunks) {
2625
+ return this.adapter.set("mcpstreamchunks", chunks);
2626
+ }
2627
+ /** Returns the audited tool call log under the requested filters: the client, the tool, the outcome, the time floor and the newest bound, all optional. */
2628
+ async getcalllog(filters) {
2629
+ let records = await this.listtoolcalls();
2630
+ if (filters?.clientid !== void 0) records = records.filter((record2) => record2.clientid === filters.clientid);
2631
+ if (filters?.tool !== void 0) records = records.filter((record2) => record2.tool === filters.tool);
2632
+ if (filters?.ok !== void 0) records = records.filter((record2) => record2.ok === filters.ok);
2633
+ if (filters?.since !== void 0) records = records.filter((record2) => record2.at >= (filters.since ?? 0));
2634
+ return filters?.limit !== void 0 ? records.slice(0, filters.limit) : records;
2635
+ }
2636
+ /** Stores one progress notice of a long tool call under the recent notice window of 25 records. */
2637
+ async addprogressnotice(notice) {
2638
+ await this.adapter.set("mcpprogressnotices", [notice, ...(await this.getprogressnotices()).slice(0, 24)]);
2639
+ }
2640
+ /** Returns the recent progress notices of long tool calls, newest first. */
2641
+ async getprogressnotices() {
2642
+ return await this.adapter.get("mcpprogressnotices") ?? [];
2643
+ }
2644
+ /** Returns the tool dry run toggle of the next call: true once the user armed the dry run in the panel. */
2645
+ async getdryruntoggle() {
2646
+ return await this.adapter.get("mcpdryruntoggle") === true;
2647
+ }
2648
+ /** Arms or disarms the tool dry run of the next call. */
2649
+ async setdryruntoggle(enabled) {
2650
+ return this.adapter.set("mcpdryruntoggle", enabled);
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
+ }
2547
2765
  };
2548
2766
  function mediakindof(record2) {
2549
2767
  if ("pages" in record2) return "pdf";
@@ -4662,12 +4880,6 @@ async function callgraphql(input) {
4662
4880
  }
4663
4881
  }
4664
4882
 
4665
- // version.ts
4666
- var packageversion = "1.1.55";
4667
-
4668
- // types.ts
4669
- var protocolversion = packageversion;
4670
-
4671
4883
  // socketbus.ts
4672
4884
  var socketkinds = ["opensocket", "sendmessage", "waitmessage", "subscribesse", "longpoll"];
4673
4885
  function channelorigin(url) {
@@ -7204,8 +7416,8 @@ function validatetimelinegrammar(step, options) {
7204
7416
  watchwindow = reviewed.window;
7205
7417
  }
7206
7418
  }
7207
- const budgetcheck = debugwaitbudgetallowed(watchwindow, typeof options.wait === "number" ? options.wait : void 0);
7208
- if (!budgetcheck.allowed) return budgetcheck;
7419
+ const budgetcheck2 = debugwaitbudgetallowed(watchwindow, typeof options.wait === "number" ? options.wait : void 0);
7420
+ if (!budgetcheck2.allowed) return budgetcheck2;
7209
7421
  if (options.level !== void 0 && !loglevels.includes(options.level)) return { allowed: false, reason: `The reviewed level floor must be one of ${loglevels.join(", ")}.` };
7210
7422
  if (options.sources !== void 0) {
7211
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(", ")}.` };
@@ -7798,8 +8010,8 @@ function validatecdpgrammar(step, options) {
7798
8010
  const allowlist = cdpallowlistof(options.allowlist);
7799
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." };
7800
8012
  }
7801
- const budgetcheck = debugwaitbudgetallowed(typeof options.wait === "number" ? options.wait : void 0, void 0);
7802
- 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;
7803
8015
  return { allowed: true };
7804
8016
  }
7805
8017
  if (kind === "detachcdp") return { allowed: true };
@@ -7823,8 +8035,8 @@ function validatecdpgrammar(step, options) {
7823
8035
  }
7824
8036
  }
7825
8037
  if (watchwindow === void 0) return { allowed: false, reason: "The event watch needs a reviewed lifetime window before any domain event is observed." };
7826
- const budgetcheck = debugwaitbudgetallowed(watchwindow, typeof options.wait === "number" ? options.wait : void 0);
7827
- if (!budgetcheck.allowed) return budgetcheck;
8038
+ const budgetcheck2 = debugwaitbudgetallowed(watchwindow, typeof options.wait === "number" ? options.wait : void 0);
8039
+ if (!budgetcheck2.allowed) return budgetcheck2;
7828
8040
  return { allowed: true };
7829
8041
  }
7830
8042
  if (kind === "setbreakpoint") {
@@ -7861,8 +8073,8 @@ function validateprofilegrammar(step, options) {
7861
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.` };
7862
8074
  const watch = options.watch && typeof options.watch === "object" && !Array.isArray(options.watch) ? options.watch : {};
7863
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." };
7864
- const budgetcheck = debugwaitbudgetallowed(watch.window, typeof options.wait === "number" ? options.wait : void 0);
7865
- 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;
7866
8078
  return { allowed: true };
7867
8079
  }
7868
8080
  if (kind === "heapshot") {
@@ -7879,16 +8091,16 @@ function validateprofilegrammar(step, options) {
7879
8091
  if (kind === "profilecpu") {
7880
8092
  const profile = options.profile && typeof options.profile === "object" && !Array.isArray(options.profile) ? options.profile : void 0;
7881
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." };
7882
- const budgetcheck = debugwaitbudgetallowed(profile.duration, typeof options.wait === "number" ? options.wait : void 0);
7883
- 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;
7884
8096
  return { allowed: true };
7885
8097
  }
7886
8098
  if (kind === "watchshifts") {
7887
8099
  const watch = options.watch && typeof options.watch === "object" && !Array.isArray(options.watch) ? options.watch : {};
7888
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." };
7889
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." };
7890
- const budgetcheck = debugwaitbudgetallowed(watch.window, typeof options.wait === "number" ? options.wait : void 0);
7891
- 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;
7892
8104
  return { allowed: true };
7893
8105
  }
7894
8106
  if (kind === "traceload") {
@@ -7896,8 +8108,8 @@ function validateprofilegrammar(step, options) {
7896
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(", ")}.` };
7897
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." };
7898
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." };
7899
- const budgetcheck = debugwaitbudgetallowed(trace.window, typeof options.wait === "number" ? options.wait : void 0);
7900
- 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;
7901
8113
  return { allowed: true };
7902
8114
  }
7903
8115
  if (kind === "annotatetrace" || kind === "replaytrace") {
@@ -8879,6 +9091,481 @@ function approvaltimeoutvalid(timeout) {
8879
9091
  if (timeout.ontimeout !== "refuse") return { allowed: false, reason: "The documented disposition of an unanswered approval gate is refusal." };
8880
9092
  return { allowed: true };
8881
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;
9527
+
9528
+ // agentstream.ts
9529
+ function listprompts() {
9530
+ return [
9531
+ { name: "runreview", description: "Renders the run review prompt that asks the user model to summarize the executed steps of the approved plan behind the consent gates.", arguments: [{ name: "objective", description: "The objective of the approved plan under review.", required: true }, { name: "steps", description: "The executed step summaries the review covers.", required: true }, { name: "tone", description: "The tone of the summary.", default: "plain" }], template: "Review the run of the objective {{objective}}. Summarize the executed steps: {{steps}}. Keep the tone {{tone}} and state every refusal the consent gates raised." },
9532
+ { name: "pagesummary", description: "Renders the page summary prompt that condenses the observed page state of the session tab into the summary the client model asked for.", arguments: [{ name: "url", description: "The url of the observed page.", required: true }, { name: "observations", description: "The observed page state sections the summary condenses.", required: true }], template: "Summarize the page at {{url}} from the observations: {{observations}}. Name nothing the observations leave out." },
9533
+ { name: "failuretriage", description: "Renders the failure triage prompt that classifies a failed tool call through the retry hints of the structured error it produced.", arguments: [{ name: "tool", description: "The namespaced tool that failed.", required: true }, { name: "error", description: "The structured error of the failed call.", required: true }], template: "Triage the failure of the {{tool}} tool: {{error}}. Classify it as retryable, a busy window or a consent refusal and propose the next reviewed step." }
9534
+ ];
9535
+ }
9536
+ function renderprompt(prompt, args) {
9537
+ return prompt.template.replace(/\{\{\s*([a-z0-9]+)\s*\}\}/g, (whole, name) => {
9538
+ const value = args[name];
9539
+ if (value === void 0 || value === null) return whole;
9540
+ return typeof value === "string" ? value : JSON.stringify(value);
9541
+ });
9542
+ }
9543
+ function callprompt(input) {
9544
+ const prompt = listprompts().find((candidate) => candidate.name === input.name);
9545
+ if (prompt === void 0) return { reason: `The server exposes no prompt named ${input.name}.` };
9546
+ const args = input.args ?? {};
9547
+ const findings = [];
9548
+ const resolved = {};
9549
+ for (const argument of prompt.arguments) {
9550
+ const value = args[argument.name];
9551
+ if (value === void 0 || value === null || typeof value === "string" && value.trim() === "") {
9552
+ if (argument.default !== void 0) resolved[argument.name] = argument.default;
9553
+ else if (argument.required === true) findings.push(`The prompt argument ${argument.name} is required and stays empty.`);
9554
+ else resolved[argument.name] = "";
9555
+ } else {
9556
+ resolved[argument.name] = value;
9557
+ }
9558
+ }
9559
+ if (findings.length > 0) return { reason: findings.join(" ") };
9560
+ return { rendered: renderprompt(prompt, resolved), toolcall: { name: `prompts.${prompt.name}`, params: { prompt: prompt.name, arguments: resolved, rendered: renderprompt(prompt, resolved) } } };
9561
+ }
9562
+ function canceltool(input) {
9563
+ const match = input.contexts.find((context2) => context2.callid === input.callid);
9564
+ if (match === void 0) return { contexts: input.contexts, reason: `The cancellation frame names no call context ${input.callid}.` };
9565
+ if (match.state !== "inflight") return { contexts: input.contexts, reason: `The call ${input.callid} already left the in flight state.` };
9566
+ const context = { ...match, state: "cancelled", endedat: input.now, ...input.partial !== void 0 ? { partial: input.partial } : {} };
9567
+ return { contexts: input.contexts.map((candidate) => candidate.callid === input.callid ? context : candidate), context };
9568
+ }
8882
9569
 
8883
9570
  // mcpserver.ts
8884
9571
  var localhostbind = "127.0.0.1";
@@ -8934,7 +9621,10 @@ function servermethods() {
8934
9621
  { method: "ping", handler: "ping", description: "Answers keepalive frames with pong." },
8935
9622
  { method: "tools/list", handler: "listtools", description: "Returns every tool with its version and json schema inputs." },
8936
9623
  { method: "negotiate", handler: "negotiate", description: "Exchanges capability sets with the client." },
8937
- { method: "tools/call", handler: "dispatch", description: "Invokes one tool behind the consent gates." }
9624
+ { method: "tools/call", handler: "dispatch", description: "Invokes one tool behind the consent gates." },
9625
+ { method: "prompts/list", handler: "listprompts", description: "Lists the prompt defs the server exposes as callable tools." },
9626
+ { method: "prompts/call", handler: "callprompt", description: "Renders one prompt and returns its arguments as a tool call." },
9627
+ { method: "calls/cancel", handler: "cancel", description: "Aborts one in flight tool call and preserves its partial result." }
8938
9628
  ];
8939
9629
  }
8940
9630
  function servercapabilities(input) {
@@ -9029,6 +9719,22 @@ async function handleframe(input) {
9029
9719
  const outcome = negotiate({ ...clientcaps !== void 0 ? { client: clientcaps } : {}, server });
9030
9720
  return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, ...outcome.agreed ? { result: outcome.capabilities } : { error: rpcerrorof("params", outcome.mismatch ?? "The capability negotiation did not agree.") } });
9031
9721
  }
9722
+ if (entry.handler === "listprompts") return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, result: { prompts: listprompts() } });
9723
+ if (entry.handler === "callprompt") {
9724
+ const name = typeof params?.name === "string" ? params.name : "";
9725
+ const args = params?.arguments && typeof params.arguments === "object" && !Array.isArray(params.arguments) ? params.arguments : void 0;
9726
+ const called = name === "" ? { reason: "The prompt call needs the prompt name." } : callprompt({ name, ...args !== void 0 ? { args } : {} });
9727
+ if (called.toolcall === void 0) return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, error: rpcerrorof("params", called.reason ?? "The prompt call did not render.") });
9728
+ return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, result: { toolcall: called.toolcall, rendered: called.rendered } });
9729
+ }
9730
+ if (entry.handler === "cancel") {
9731
+ const callid = typeof params?.callid === "string" ? params.callid : "";
9732
+ const reason = typeof params?.reason === "string" ? params.reason : void 0;
9733
+ if (callid.trim() === "") return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, error: rpcerrorof("params", "The cancellation frame needs the call id it aborts.") });
9734
+ const aborted = canceltool({ contexts: input.contexts ?? [], callid, ...reason !== void 0 ? { reason } : {}, now: input.now });
9735
+ if (aborted.context === void 0) return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, error: rpcerrorof("params", aborted.reason ?? "The cancellation frame named no in flight tool call.") });
9736
+ return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, result: { cancelled: true, callid, ...reason !== void 0 ? { reason } : {}, ...aborted.context.partial !== void 0 ? { partial: aborted.context.partial } : {} } });
9737
+ }
9032
9738
  const dispatched = await dispatchtool({ ...params !== void 0 ? { params } : {}, client: input.client, catalog: input.catalog, ...input.session !== void 0 ? { session: input.session } : {}, ...input.plan !== void 0 ? { plan: input.plan } : {}, ...input.scopes !== void 0 ? { scopes: input.scopes } : {}, origin: input.origin, now: input.now, execute: input.execute });
9033
9739
  return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, ...dispatched.error !== void 0 ? { error: dispatched.error } : { result: dispatched.result } });
9034
9740
  }
@@ -9049,7 +9755,7 @@ function framedlog(event, at, fields) {
9049
9755
  return JSON.stringify({ at, event, ...fields ?? {} });
9050
9756
  }
9051
9757
  function toolcallevent(input) {
9052
- return { id: input.id, clientid: input.clientid, tool: input.tool, origin: input.origin, ok: input.ok, ...input.code !== void 0 ? { code: input.code } : {}, at: input.now };
9758
+ return { id: input.id, clientid: input.clientid, tool: input.tool, origin: input.origin, ok: input.ok, ...input.code !== void 0 ? { code: input.code } : {}, at: input.now, ...input.callid !== void 0 ? { callid: input.callid } : {}, ...input.idempotencykey !== void 0 && input.idempotencykey.trim() !== "" ? { idempotencykey: input.idempotencykey } : {}, ...input.dryrun === true ? { dryrun: true } : {}, ...input.mocked === true ? { mocked: true } : {}, ...input.batchid !== void 0 ? { batchid: input.batchid } : {}, ...input.replayed === true ? { replayed: true } : {} };
9053
9759
  }
9054
9760
 
9055
9761
  // httpstream.ts
@@ -9410,6 +10116,92 @@ function streamsummaries(raw) {
9410
10116
  });
9411
10117
  }
9412
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
+
9413
10205
  // protocol.ts
9414
10206
  function record(value) {
9415
10207
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Protocol message must be an object.");
@@ -10065,6 +10857,72 @@ function heartbeatreport(input) {
10065
10857
  const open = input.channels.filter((channel) => channel.closedat === void 0 && input.now - channel.lastbeatat < (input.idlewindow ?? defaultidlewindowms));
10066
10858
  return { version: protocolversion, beats: input.channels.filter((channel) => channel.lastbeatat > channel.openedat).length, open: open.length, dead: input.channels.length - open.length };
10067
10859
  }
10860
+ function subscriptionframes(input) {
10861
+ const subscribe = { jsonrpc: "2.0", id: input.id, method: "events/subscribe", params: { subscriptionid: input.subscription.id, kinds: input.subscription.kinds, ...input.subscription.origin !== void 0 ? { origin: input.subscription.origin } : {}, ...input.subscription.tool !== void 0 ? { tool: input.subscription.tool } : {} } };
10862
+ const unsubscribe = { jsonrpc: "2.0", id: input.id, method: "events/unsubscribe", params: { subscriptionid: input.subscription.id } };
10863
+ return { subscribe, unsubscribe };
10864
+ }
10865
+ function eventnotification(input) {
10866
+ return { jsonrpc: "2.0", method: "events/notify", params: { subscriptionid: input.subscriptionid, kind: input.kind, ...input.origin !== void 0 ? { origin: input.origin } : {}, ...input.tool !== void 0 ? { tool: input.tool } : {}, ...input.payload !== void 0 ? { payload: input.payload } : {}, at: input.now } };
10867
+ }
10868
+ function resourcedeltareport(input) {
10869
+ return { version: protocolversion, watchid: input.watchid, clientid: input.clientid, resource: input.resource, delta: input.delta, at: input.now };
10870
+ }
10871
+ function samplingframes(input) {
10872
+ const request = { jsonrpc: "2.0", id: input.id, method: "sampling/request", params: { samplingid: input.request.id, prompt: input.request.prompt, ...input.request.system !== void 0 ? { system: input.request.system } : {}, ...input.request.pagecontent !== void 0 ? { pagecontent: input.request.pagecontent } : {}, ...input.request.maxtokens !== void 0 ? { maxtokens: input.request.maxtokens } : {} } };
10873
+ const answer = input.request.state === "answered" ? { jsonrpc: "2.0", id: input.id, method: "sampling/answer", params: { samplingid: input.request.id, answer: input.request.answer ?? "" } } : input.request.state === "refused" ? { jsonrpc: "2.0", id: input.id, method: "sampling/answer", params: { samplingid: input.request.id, refused: true } } : { jsonrpc: "2.0", id: input.id, method: "sampling/answer", params: { samplingid: input.request.id, state: "pending" } };
10874
+ return { request, answer };
10875
+ }
10876
+ function promptreport(input) {
10877
+ return { version: protocolversion, prompts: input.prompts.map((prompt) => ({ name: prompt.name, description: prompt.description, arguments: prompt.arguments, template: prompt.template })) };
10878
+ }
10879
+ function promptcallframe(input) {
10880
+ return { jsonrpc: "2.0", id: input.id, method: "prompts/call", params: { name: input.name, arguments: input.args } };
10881
+ }
10882
+ function streamchunkframe(chunk) {
10883
+ return { jsonrpc: "2.0", method: "calls/stream", params: { callid: chunk.callid, seq: chunk.seq, content: chunk.content, done: chunk.done, at: chunk.at } };
10884
+ }
10885
+ function progressnoticeframe(notice) {
10886
+ return { jsonrpc: "2.0", method: "calls/progress", params: { callid: notice.callid, ...notice.percent !== void 0 ? { percent: notice.percent } : {}, message: notice.message, cancellable: notice.cancellable, at: notice.at } };
10887
+ }
10888
+ function cancelframes(input) {
10889
+ const cancel = { jsonrpc: "2.0", id: input.id, method: "calls/cancel", params: { callid: input.frame.callid, ...input.frame.reason !== void 0 ? { reason: input.frame.reason } : {} } };
10890
+ const cancelled = { jsonrpc: "2.0", id: input.id, result: { cancelled: true, callid: input.frame.callid, ...input.frame.reason !== void 0 ? { reason: input.frame.reason } : {}, ...input.partial !== void 0 ? { partial: input.partial } : {} } };
10891
+ return { cancel, cancelled };
10892
+ }
10893
+ function structurederrorreport(input) {
10894
+ return { version: protocolversion, code: input.error.code, message: input.error.message, retryhint: input.error.retryhint, ...input.error.retryafter !== void 0 ? { retryafter: input.error.retryafter } : {}, ...input.usage !== void 0 ? { usage: input.usage } : {} };
10895
+ }
10896
+ function idempotencyreplayframe(input) {
10897
+ return { jsonrpc: "2.0", id: input.id, result: { replayed: true, idempotencykey: input.key, originalat: input.originalat, result: input.result } };
10898
+ }
10899
+ function batchreport(input) {
10900
+ return { version: protocolversion, batchid: input.batch.id, clientid: input.batch.clientid, state: input.batch.state, stoponerror: input.batch.stoponerror, done: input.batch.outcomes.length, total: input.batch.calls.length, outcomes: input.batch.outcomes };
10901
+ }
10902
+ function ratelimitreport(input) {
10903
+ return { version: protocolversion, limits: input.limits.map((limit) => ({ clientid: limit.clientid, windowms: limit.windowms, ...limit.budget !== void 0 ? { budget: limit.budget } : {}, used: limit.used, unbounded: limit.budget === void 0, resetat: limit.windowstartedat + limit.windowms })) };
10904
+ }
10905
+ function calllogreport(input) {
10906
+ return { version: protocolversion, calls: input.calls, filters: input.filters ?? {} };
10907
+ }
10908
+ function inflightreport(input) {
10909
+ return { version: protocolversion, inflight: input.contexts.filter((context) => context.state === "inflight").map((context) => ({ callid: context.callid, clientid: context.clientid, tool: context.tool, startedat: context.startedat, msopen: input.now - context.startedat, chunks: context.chunks, ...context.dryrun === true ? { dryrun: true } : {}, ...context.batchid !== void 0 ? { batchid: context.batchid } : {}, ...context.idempotencykey !== void 0 ? { idempotencykey: context.idempotencykey } : {} })) };
10910
+ }
10911
+ function dryrunreport(dryrun) {
10912
+ return { version: protocolversion, callid: dryrun.callid, tool: dryrun.tool, argsvalid: dryrun.argsvalid, consentok: dryrun.consentok, findings: dryrun.findings, executed: dryrun.executed, mutations: dryrun.mutations };
10913
+ }
10914
+ function mockreport(mocks) {
10915
+ return { version: protocolversion, mocks: mocks.map((mock) => ({ tool: mock.tool, content: mock.result.content, testcontext: mock.testcontext, createdat: mock.createdat })) };
10916
+ }
10917
+ function idempotencyreport(records, now) {
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 })) };
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
+ }
10068
10926
 
10069
10927
  // workfloweditor.ts
10070
10928
  var palettecategories = ["actions", "controlflow", "waits", "variables", "triggers"];
@@ -10773,6 +11631,7 @@ export {
10773
11631
  activelayers,
10774
11632
  addedge,
10775
11633
  addnode,
11634
+ addusage,
10776
11635
  agentgrammarvalid,
10777
11636
  agentpresetof,
10778
11637
  allowlistcovers,
@@ -10805,6 +11664,7 @@ export {
10805
11664
  authreport,
10806
11665
  autointervalof,
10807
11666
  backoffdelay,
11667
+ batchreport,
10808
11668
  bindlocalhost,
10809
11669
  bindparam,
10810
11670
  bindvariables,
@@ -10823,15 +11683,22 @@ export {
10823
11683
  breakpointceilingof,
10824
11684
  breakpointinputof,
10825
11685
  browserpermissions,
11686
+ budgetcheck,
10826
11687
  buildname,
10827
11688
  buildpdf,
11689
+ buildrequest,
10828
11690
  buildsheet,
10829
11691
  buildsteplibrary,
10830
11692
  buildstitchplan,
10831
11693
  buildtoolcatalog,
11694
+ bumprevision,
10832
11695
  callgraphql,
11696
+ calllocal,
11697
+ calllogreport,
11698
+ callmodel,
10833
11699
  callrest,
10834
11700
  callsreport,
11701
+ cancelframes,
10835
11702
  cancellederror,
10836
11703
  cancelrun,
10837
11704
  canexecute,
@@ -10860,9 +11727,11 @@ export {
10860
11727
  channelorigin,
10861
11728
  checkallowlist,
10862
11729
  choosebranch,
11730
+ classifyintent,
10863
11731
  closechannel,
10864
11732
  closeidlechannels,
10865
11733
  collectmessages,
11734
+ commandguard,
10866
11735
  composeworkflow,
10867
11736
  conditionof,
10868
11737
  confirmmanualrun,
@@ -10883,6 +11752,7 @@ export {
10883
11752
  cookiegate,
10884
11753
  cookierecordof,
10885
11754
  correlationid,
11755
+ costbudgetvalid,
10886
11756
  cpusnap,
10887
11757
  crashinterrupted,
10888
11758
  cronnext,
@@ -10904,6 +11774,7 @@ export {
10904
11774
  defaultmcpconfig,
10905
11775
  defaultmcpport,
10906
11776
  defaultpairinglifetimems,
11777
+ defaultrefusalmarkers,
10907
11778
  defaulttokenlifetimems,
10908
11779
  defaulttriggercooldown,
10909
11780
  delayjitter,
@@ -10918,12 +11789,15 @@ export {
10918
11789
  dispatchtool,
10919
11790
  domainkinds,
10920
11791
  downloadreport,
11792
+ draftplan,
10921
11793
  drainqueue,
10922
11794
  dryrunprojection,
11795
+ dryrunreport,
10923
11796
  dryrunworkflow,
10924
11797
  editorsavegate,
10925
11798
  editorstate,
10926
11799
  editstep,
11800
+ egressconsentgate,
10927
11801
  emugate,
10928
11802
  emulationkinds,
10929
11803
  emulationreport,
@@ -10936,6 +11810,7 @@ export {
10936
11810
  errorreportresponse,
10937
11811
  evaluatecondition,
10938
11812
  evaluatetrigger,
11813
+ eventnotification,
10939
11814
  eventresponse,
10940
11815
  eventrulematches,
10941
11816
  exchangesreport,
@@ -10956,6 +11831,7 @@ export {
10956
11831
  extractionreport,
10957
11832
  extractvalues,
10958
11833
  failureclass,
11834
+ fallbackroute,
10959
11835
  familyofkind,
10960
11836
  fetchoptionsof,
10961
11837
  fetchrequestof,
@@ -10978,6 +11854,8 @@ export {
10978
11854
  groupselect,
10979
11855
  growsampleof,
10980
11856
  growthtrend,
11857
+ guardoutput,
11858
+ guardverdictgate,
10981
11859
  handleframe,
10982
11860
  headerfilterof,
10983
11861
  headeruleof,
@@ -10992,12 +11870,15 @@ export {
10992
11870
  httpframepipeline,
10993
11871
  httpkinds,
10994
11872
  httpstreamreport,
11873
+ idempotencyreplayframe,
11874
+ idempotencyreport,
10995
11875
  imagefilterof,
10996
11876
  imagematches,
10997
11877
  imagenames,
10998
11878
  importpresetlibrary,
10999
11879
  importsessionfile,
11000
11880
  importworkflow,
11881
+ inflightreport,
11001
11882
  initialize,
11002
11883
  iscdpkind,
11003
11884
  iscontrolflowkind,
@@ -11005,6 +11886,7 @@ export {
11005
11886
  isdebugkind,
11006
11887
  isemulationkind,
11007
11888
  isformkind,
11889
+ islocalorigin,
11008
11890
  isnetwatchkind,
11009
11891
  isprofilekind,
11010
11892
  issessionkind,
@@ -11020,6 +11902,7 @@ export {
11020
11902
  jsonpathrulesof,
11021
11903
  lapseframes,
11022
11904
  lapseplanof,
11905
+ latesttemplate,
11023
11906
  launchbridge,
11024
11907
  layernames,
11025
11908
  layoutreport,
@@ -11030,6 +11913,7 @@ export {
11030
11913
  listtools,
11031
11914
  loadworkflow,
11032
11915
  localhostbind,
11916
+ localsensitivegrade,
11033
11917
  locationconsentcovers,
11034
11918
  locationconsentgate,
11035
11919
  locationpresetof,
@@ -11042,6 +11926,7 @@ export {
11042
11926
  mapresponse,
11043
11927
  mapurlof,
11044
11928
  markbreakpoint,
11929
+ markprovider,
11045
11930
  matchmessage,
11046
11931
  matchurl,
11047
11932
  matchurlpattern,
@@ -11053,7 +11938,10 @@ export {
11053
11938
  methoddomain,
11054
11939
  minimapfocus,
11055
11940
  mockfor,
11941
+ mockreport,
11056
11942
  mockspecof,
11943
+ modeloutcome,
11944
+ modelproposal,
11057
11945
  multipartchunks,
11058
11946
  multipartpayloadof,
11059
11947
  namespaceof,
@@ -11092,10 +11980,14 @@ export {
11092
11980
  palettecategories,
11093
11981
  palettenodes,
11094
11982
  parallelof,
11983
+ parsecommand,
11984
+ parsecompletion,
11095
11985
  parseframe,
11096
11986
  parsehtmlbody,
11987
+ parseoutput,
11097
11988
  parseproposal,
11098
11989
  parsessetext,
11990
+ parsestream,
11099
11991
  parsetokens,
11100
11992
  parsewire,
11101
11993
  parseworkflowproposal,
@@ -11118,6 +12010,8 @@ export {
11118
12010
  permissionstatevalid,
11119
12011
  ping,
11120
12012
  planallowlist,
12013
+ plandraftreviewgate,
12014
+ planlint,
11121
12015
  pollcursorof,
11122
12016
  polldecision,
11123
12017
  pollurl,
@@ -11127,8 +12021,13 @@ export {
11127
12021
  profilereport,
11128
12022
  profileretentionwindow,
11129
12023
  profilerkinds,
12024
+ progressnoticeframe,
12025
+ promptcallframe,
12026
+ promptreport,
11130
12027
  protocolversion,
11131
12028
  provenancereport,
12029
+ provideregressgrade,
12030
+ providervalid,
11132
12031
  proxygate,
11133
12032
  proxyrouteof,
11134
12033
  publishmessage,
@@ -11139,6 +12038,7 @@ export {
11139
12038
  rankapis,
11140
12039
  ratelimitbudgetallowed,
11141
12040
  ratelimitreadof,
12041
+ ratelimitreport,
11142
12042
  ratelimitwait,
11143
12043
  readpath,
11144
12044
  readstream,
@@ -11151,6 +12051,8 @@ export {
11151
12051
  redactparams,
11152
12052
  redeempairingcode,
11153
12053
  redoedit,
12054
+ reflectionsummary,
12055
+ reflectstep,
11154
12056
  regexextract,
11155
12057
  regexruleof,
11156
12058
  regionsteps,
@@ -11158,9 +12060,14 @@ export {
11158
12060
  relayframe,
11159
12061
  removeedge,
11160
12062
  removenode,
12063
+ removetemplate,
11161
12064
  renderminimap,
12065
+ rendertemplate,
12066
+ rendertoolbriefs,
11162
12067
  reordersteps,
11163
12068
  repeatuntilof,
12069
+ replannonfail,
12070
+ replanreviewgate,
11164
12071
  replaytrace,
11165
12072
  replayurl,
11166
12073
  requestbody,
@@ -11168,8 +12075,10 @@ export {
11168
12075
  resolutionverdict,
11169
12076
  resolveapproval,
11170
12077
  resolvedrisk,
12078
+ resolveroute,
11171
12079
  resolvetool,
11172
12080
  resolvevariable,
12081
+ resourcedeltareport,
11173
12082
  resourcefacts,
11174
12083
  respond,
11175
12084
  restartbridge,
@@ -11188,6 +12097,8 @@ export {
11188
12097
  rewritesourcelocation,
11189
12098
  rotatelogs,
11190
12099
  rotationruleof,
12100
+ routesfor,
12101
+ routevalid,
11191
12102
  rpcerrorcodeof,
11192
12103
  rpcerrornumbers,
11193
12104
  rpcerrorof,
@@ -11209,6 +12120,8 @@ export {
11209
12120
  runwhile,
11210
12121
  runworkflow,
11211
12122
  safetyresponse,
12123
+ samplingframes,
12124
+ savetemplate,
11212
12125
  saveworkflow,
11213
12126
  scaledrect,
11214
12127
  schedulecron,
@@ -11219,6 +12132,7 @@ export {
11219
12132
  searchqueryof,
11220
12133
  searchsessionrecords,
11221
12134
  searchsteps,
12135
+ searchtemplates,
11222
12136
  seededrandom,
11223
12137
  selectorresponse,
11224
12138
  sendcdpcommand,
@@ -11262,9 +12176,15 @@ export {
11262
12176
  stepmodeof,
11263
12177
  steptemplateof,
11264
12178
  stepwindows,
12179
+ streamchunkframe,
12180
+ streamdelta,
12181
+ streammodel,
11265
12182
  streamsummaries,
11266
12183
  streamwindowof,
12184
+ stripguardrails,
12185
+ structurederrorreport,
11267
12186
  submitreviewgranted,
12187
+ subscriptionframes,
11268
12188
  subscriptionoptionsof,
11269
12189
  tabreportresponse,
11270
12190
  targetgate,
@@ -11274,6 +12194,7 @@ export {
11274
12194
  teardowncdpsession,
11275
12195
  teardownplanof,
11276
12196
  templateurl,
12197
+ templatevariables,
11277
12198
  thumbdirectiveof,
11278
12199
  thumbgeometry,
11279
12200
  timelinecounts,
@@ -11289,6 +12210,7 @@ export {
11289
12210
  tokenhashprefix,
11290
12211
  tokenreport,
11291
12212
  tokenrequest,
12213
+ toolbriefof,
11292
12214
  toolcallevent,
11293
12215
  toolcallframe,
11294
12216
  toolcatalogversion,
@@ -11323,6 +12245,7 @@ export {
11323
12245
  unwrapgraphql,
11324
12246
  updaterule,
11325
12247
  urlencodeform,
12248
+ usagetotals,
11326
12249
  validatebreakpointcondition,
11327
12250
  validatecontrolpayload,
11328
12251
  validatefieldmatch,