@nextblock-cms/cortex 0.18.1 → 0.18.3

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.
@@ -1,3 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("ai"),T="https://openrouter.ai/api/v1",C="openrouter/free",u=["qwen/qwen3-next-80b-a3b-instruct:free","nvidia/nemotron-3-super-120b-a12b:free","nvidia/nemotron-nano-9b-v2:free"],x=["tools","structured_outputs"],P={frequencyPenalty:"frequency_penalty",logitBias:"logit_bias",presencePenalty:"presence_penalty",seed:"seed",stopSequences:"stop",temperature:"temperature",topK:"top_k",topP:"top_p"},L={defaultFreeRouter:C,defaultStructuredOutputModel:u[0],defaultToolCallingModel:u[0],freeFallbacks:u,structuredJsonPreferred:u,toolCallingPreferred:u};class m extends Error{attempts;constructor(t,n,r){super(t),this.name="CortexAiRoutingError",this.attempts=n,this.cause=r}}function R(e){return Array.from(new Set(e.filter(Boolean)))}function c(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function p(e){return typeof e=="string"&&e.trim()?e.trim():null}function A(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"&&t.trim().length>0):[]}function f(e){const t=typeof e=="number"?e:Number(e);return Number.isFinite(t)?t:null}function b(e){const t=c(e);return t?Object.fromEntries(Object.entries(t).filter(([,n])=>n!=null).map(([n,r])=>[n,String(r)])):{}}function I(e){const t=new Set(e);return x.every(n=>t.has(n))}function D(e){const t=c(e.architecture);return A(t?.output_modalities).includes("text")}function F(e){if(e==null)return null;if(typeof e=="number")return e>1e10?e:e*1e3;if(typeof e=="string"&&e.trim()){const t=Date.parse(e);return Number.isFinite(t)?t:null}return null}function w(e,t){const n=F(e);return n!==null&&n<=t.getTime()}function q(e){const t=c(e.top_provider);return f(e.context_length)??f(e.contextLength)??f(t?.context_length)??null}function k(e){const t=e.expiration_date??e.expirationDate;return typeof t=="string"&&t.trim()?t.trim():null}function S(e){return!!(e&&u.includes(e))}function N(e){const t=c(e);if(!t)return null;const n=p(t.modelId),r=p(t.name),s=A(t.supportedParameters),i=p(t.updatedAt);return!n||!r||!i||!I(s)?null:{contextLength:f(t.contextLength),modelId:n,name:r,pricing:b(t.pricing),supportedParameters:s,updatedAt:i}}function U(e,t=new Date){return{contextLength:e.contextLength,modelId:e.id,name:e.name,pricing:e.pricing,supportedParameters:[...e.supportedParameters],updatedAt:t.toISOString()}}function j(e,t=new Date){const n=c(e),r=Array.isArray(e)?e:Array.isArray(n?.data)?n.data:[],s=[];for(const i of r){const o=c(i),l=p(o?.id),a=p(o?.name),O=A(o?.supported_parameters);!o||!l||!a||!D(o)||w(o.expiration_date,t)||!I(O)||s.push({contextLength:q(o),created:f(o.created),expirationDate:k(o),id:l,name:a,pricing:b(o.pricing),supportedParameters:O})}return s.sort((i,o)=>i.name.localeCompare(o.name))}function X(e){return R([e?.modelId||u[0],...e?.fallbackModelIds||u])}function B(e){const t=e.requestedModelId?.trim()||null;if(e.credentialSource==="env")return{credentialSource:e.credentialSource,ignoredRequestedModelId:t&&!S(t)?t:null,modelIds:[...u],modelSelection:null};const n=R(e.fallbackModelIds?.length?e.fallbackModelIds:u),r=e.credentialSource==="stored"?e.selectedModel?.modelId||n[0]:t||e.selectedModel?.modelId||n[0];return{credentialSource:e.credentialSource,ignoredRequestedModelId:e.credentialSource==="stored"&&t&&t!==r?t:null,modelIds:R([r,...n]),modelSelection:e.selectedModel||null}}function K(e,t){const n=t.modelSelection;if(!n||n.modelId!==t.modelId)return e;const r=new Set(n.supportedParameters),s=Object.entries(P).filter(([o,l])=>o in e&&!r.has(l)).map(([o])=>o);if(s.length===0)return e;const i={...e};for(const o of s)delete i[o];return i}function E(e,t){if(!e||typeof e!="object"||!(t in e))return null;const n=e[t],r=typeof n=="number"?n:Number(n);return Number.isFinite(r)?r:null}function M(e){if(h.APICallError.isInstance(e))return e.statusCode??null;const t=E(e,"statusCode")??E(e,"status");if(t)return t;if(e&&typeof e=="object"&&"response"in e){const n=e.response,r=E(n,"status");if(r)return r}return e&&typeof e=="object"&&"cause"in e?M(e.cause):null}function _(e){return M(e)===429}function d(e){if(!e)return"";if(e instanceof Error){const t="cause"in e?d(e.cause):"";return[e.message,t].filter(Boolean).join(`
2
- `)}if(typeof e=="object"){const t=e;return["message","error","text","cause"].map(n=>d(t[n])).filter(Boolean).join(`
3
- `)}return String(e)}function y(e){return _(e)?!0:/No endpoints found|no longer available|not available as a free model|transitioned to a paid model/i.test(d(e))}function g(e,t=900){const n=e.replace(/\s+/g," ").trim();return n.length>t?`${n.slice(0,t-1).trimEnd()}...`:n}function G(e){const t=d(e);return t?g(t):"Unknown OpenRouter error."}function Y(e,t="Cortex AI request failed."){if(e instanceof m){const n=e.attempts.map(o=>o.errorMessage).filter(o=>!!o?.trim()),r=n[0],s=n[n.length-1],i=g(d(e.cause));return r&&s&&r!==s?`First model error: ${r} Last model error: ${s}`:s||r||i||e.message}return g(d(e))||t}async function $(e){const t=R(e.modelIds),n=e.shouldRetry||y;let r=[],s=null;for(const i of t)try{const o=await e.execute(i);return r=[...r,{modelId:i,rateLimited:!1,status:"success"}],{attempts:r,modelId:i,result:o}}catch(o){const l=_(o),a=n(o);if(s=o,r=[...r,{errorMessage:G(o),modelId:i,rateLimited:l,status:l?"rate_limited":a?"retried":"failed"}],!a)throw new m(`OpenRouter request failed for model "${i}".`,r,o)}throw new m("OpenRouter fallback exhausted all configured Cortex AI models.",r,s)}exports.CORTEX_AI_FREE_MODEL_FALLBACK_REGISTRY=u;exports.CORTEX_AI_MODEL_REGISTRY=L;exports.CORTEX_AI_OPENROUTER_BASE_URL=T;exports.CORTEX_AI_OPENROUTER_FREE_ROUTER_MODEL=C;exports.CORTEX_AI_REQUIRED_MODEL_PARAMETERS=x;exports.CortexAiRoutingError=m;exports.buildCortexAiModelFallbackChain=X;exports.buildCortexAiRoutingPolicy=B;exports.createCortexAiStoredModelSelection=U;exports.filterCortexAiCompatibleOpenRouterModels=j;exports.getHttpStatusCode=M;exports.isCortexAiFreeModelId=S;exports.isOpenRouterRateLimitError=_;exports.isOpenRouterRecoverableRoutingError=y;exports.omitUnsupportedCortexAiModelOptions=K;exports.runWithCortexAiModelFallback=$;exports.safeParseCortexAiModelSelection=N;exports.summarizeCortexAiRoutingError=Y;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const D=require("ai"),N="https://openrouter.ai/api/v1",b="openrouter/free",u=["nvidia/nemotron-3-super-120b-a12b:free","nvidia/nemotron-3-ultra-550b-a55b:free","thinkingmachines/inkling:free","nex-agi/nex-n2.5-pro:free","poolside/laguna-s-2.1:free","thinkingmachines/inkling-small:free","inclusionai/ling-3.0-flash-vl:free"],x=["tools","structured_outputs"],k={frequencyPenalty:"frequency_penalty",logitBias:"logit_bias",presencePenalty:"presence_penalty",seed:"seed",stopSequences:"stop",temperature:"temperature",topK:"top_k",topP:"top_p"},F={defaultFreeRouter:b,defaultStructuredOutputModel:u[0],defaultToolCallingModel:u[0],freeFallbacks:u,structuredJsonPreferred:u,toolCallingPreferred:u};class R extends Error{attempts;constructor(t,r,n){super(t),this.name="CortexAiRoutingError",this.attempts=r,this.cause=n}}function m(e){return Array.from(new Set(e.filter(Boolean)))}function c(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function d(e){return typeof e=="string"&&e.trim()?e.trim():null}function A(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"&&t.trim().length>0):[]}function f(e){const t=typeof e=="number"?e:Number(e);return Number.isFinite(t)?t:null}function C(e){const t=c(e);return t?Object.fromEntries(Object.entries(t).filter(([,r])=>r!=null).map(([r,n])=>[r,String(n)])):{}}function I(e){const t=new Set(e);return x.every(r=>t.has(r))}function w(e){const t=c(e.architecture);return A(t?.output_modalities).includes("text")}function U(e){if(e==null)return null;if(typeof e=="number")return e>1e10?e:e*1e3;if(typeof e=="string"&&e.trim()){const t=Date.parse(e);return Number.isFinite(t)?t:null}return null}function B(e,t){const r=U(e);return r!==null&&r<=t.getTime()}function q(e){const t=c(e.top_provider);return f(e.context_length)??f(e.contextLength)??f(t?.context_length)??null}function X(e){const t=e.expiration_date??e.expirationDate;return typeof t=="string"&&t.trim()?t.trim():null}function y(e){return!!(e&&u.includes(e))}function j(e){const t=c(e);if(!t)return null;const r=d(t.modelId),n=d(t.name),i=A(t.supportedParameters),s=d(t.updatedAt);return!r||!n||!s||!I(i)?null:{contextLength:f(t.contextLength),modelId:r,name:n,pricing:C(t.pricing),supportedParameters:i,updatedAt:s}}function G(e,t=new Date){return{contextLength:e.contextLength,modelId:e.id,name:e.name,pricing:e.pricing,supportedParameters:[...e.supportedParameters],updatedAt:t.toISOString()}}function K(e,t=new Date){const r=c(e),n=Array.isArray(e)?e:Array.isArray(r?.data)?r.data:[],i=[];for(const s of n){const o=c(s),l=d(o?.id),a=d(o?.name),M=A(o?.supported_parameters);!o||!l||!a||!w(o)||B(o.expiration_date,t)||!I(M)||i.push({contextLength:q(o),created:f(o.created),expirationDate:X(o),id:l,name:a,pricing:C(o.pricing),supportedParameters:M})}return i.sort((s,o)=>s.name.localeCompare(o.name))}function Y(e){return m([e?.modelId||u[0],...e?.fallbackModelIds||u])}function $(e){const t=e.requestedModelId?.trim()||null;if(e.credentialSource==="env")return{credentialSource:e.credentialSource,ignoredRequestedModelId:t&&!y(t)?t:null,modelIds:[...u],modelSelection:null};const r=m(e.fallbackModelIds?.length?e.fallbackModelIds:u),n=e.credentialSource==="stored"?e.selectedModel?.modelId||r[0]:t||e.selectedModel?.modelId||r[0];return{credentialSource:e.credentialSource,ignoredRequestedModelId:e.credentialSource==="stored"&&t&&t!==n?t:null,modelIds:m([n,...r]),modelSelection:e.selectedModel||null}}function z(e,t){const r=t.modelSelection;if(!r||r.modelId!==t.modelId)return e;const n=new Set(r.supportedParameters),i=Object.entries(k).filter(([o,l])=>o in e&&!n.has(l)).map(([o])=>o);if(i.length===0)return e;const s={...e};for(const o of i)delete s[o];return s}function p(e,t){if(!e||typeof e!="object"||!(t in e))return null;const r=e[t],n=typeof r=="number"?r:Number(r);return Number.isFinite(n)?n:null}function _(e){if(D.APICallError.isInstance(e))return e.statusCode??null;const t=p(e,"statusCode")??p(e,"status");if(t)return t;if(e&&typeof e=="object"&&"response"in e){const r=e.response,n=p(r,"status");if(n)return n}return e&&typeof e=="object"&&"cause"in e?_(e.cause):null}function h(e){return e!==null&&Number.isInteger(e)&&e>=100&&e<=599}function S(e){if(typeof e!="string"||!e.trim().startsWith("{"))return null;try{return c(JSON.parse(e))}catch{return null}}function T(e,t=0){const r=c(e);if(!r||t>8)return null;const n=[r,c(r.data),S(r.responseBody),S(r.text)];for(const i of n){const s=c(i?.error),o=p(s,"code")??p(s,"status");if(h(o))return o}return T(r.cause,t+1)}function O(e){const t=_(e);return h(t)?t:T(e)}function P(e){return O(e)===429}const H=["message","error","text","responseBody","data","cause"];function E(e,t=0){if(!e||t>8)return"";if(typeof e!="object")return String(e);const r=e,n=e instanceof Error?[e.message]:[];for(const i of H)i==="message"&&e instanceof Error||n.push(E(r[i],t+1));return Array.from(new Set(n.filter(Boolean))).join(`
2
+ `)}const J=/No endpoints found|no longer available|not available as a free model|transitioned to a paid model|unavailable for free|paid version is available|is not a valid model ID/i,W=/not found|does not exist|unknown model|no such model/i;function L(e){const t=O(e);if(t===429||t===404)return!0;const r=E(e);return J.test(r)?!0:t===400&&W.test(r)}function g(e,t=900){const r=e.replace(/\s+/g," ").trim();return r.length>t?`${r.slice(0,t-1).trimEnd()}...`:r}function Q(e){const t=E(e);return t?g(t):"Unknown OpenRouter error."}function V(e,t="Cortex AI request failed."){if(e instanceof R){const r=e.attempts.map(o=>o.errorMessage).filter(o=>!!o?.trim()),n=r[0],i=r[r.length-1],s=g(E(e.cause));return n&&i&&n!==i?`First model error: ${n} Last model error: ${i}`:i||n||s||e.message}return g(E(e))||t}async function Z(e){const t=m(e.modelIds),r=e.shouldRetry||L;let n=[],i=null;for(const s of t)try{const o=await e.execute(s);return n=[...n,{modelId:s,rateLimited:!1,status:"success"}],{attempts:n,modelId:s,result:o}}catch(o){const l=P(o),a=r(o);if(i=o,n=[...n,{errorMessage:Q(o),modelId:s,rateLimited:l,status:l?"rate_limited":a?"retried":"failed"}],!a)throw new R(`OpenRouter request failed for model "${s}".`,n,o)}throw new R("OpenRouter fallback exhausted all configured Cortex AI models.",n,i)}exports.CORTEX_AI_FREE_MODEL_FALLBACK_REGISTRY=u;exports.CORTEX_AI_MODEL_REGISTRY=F;exports.CORTEX_AI_OPENROUTER_BASE_URL=N;exports.CORTEX_AI_OPENROUTER_FREE_ROUTER_MODEL=b;exports.CORTEX_AI_REQUIRED_MODEL_PARAMETERS=x;exports.CortexAiRoutingError=R;exports.buildCortexAiModelFallbackChain=Y;exports.buildCortexAiRoutingPolicy=$;exports.createCortexAiStoredModelSelection=G;exports.filterCortexAiCompatibleOpenRouterModels=K;exports.getHttpStatusCode=_;exports.getOpenRouterErrorStatus=O;exports.isCortexAiFreeModelId=y;exports.isOpenRouterRateLimitError=P;exports.isOpenRouterRecoverableRoutingError=L;exports.omitUnsupportedCortexAiModelOptions=z;exports.runWithCortexAiModelFallback=Z;exports.safeParseCortexAiModelSelection=j;exports.summarizeCortexAiRoutingError=V;
@@ -1,14 +1,31 @@
1
1
  export declare const CORTEX_AI_OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
2
2
  export declare const CORTEX_AI_OPENROUTER_FREE_ROUTER_MODEL = "openrouter/free";
3
- export declare const CORTEX_AI_FREE_MODEL_FALLBACK_REGISTRY: readonly ["qwen/qwen3-next-80b-a3b-instruct:free", "nvidia/nemotron-3-super-120b-a12b:free", "nvidia/nemotron-nano-9b-v2:free"];
3
+ /**
4
+ * Free OpenRouter models Cortex AI falls through, best first.
5
+ *
6
+ * Last checked against the live catalog (`GET /api/v1/models`): 2026-09-15.
7
+ *
8
+ * Membership rule: the id ends with `:free`, is present in the catalog with
9
+ * `tools` in `supported_parameters` (tool calling is mandatory), has no
10
+ * `expiration_date`, is a general-purpose text model of roughly 100B+ total
11
+ * parameters (no content-safety, finance, health or vision-only builds), and
12
+ * ranks by total parameters, weekly usage, context length, release date and
13
+ * `structured_outputs` support. The first entry doubles as
14
+ * `defaultStructuredOutputModel`, so it must support `structured_outputs`.
15
+ *
16
+ * `ai-model-registry.test.ts` asserts the shape of this list (`:free` suffix,
17
+ * unique ids) without touching the network; re-verify membership against the
18
+ * live catalog whenever OpenRouter answers "unavailable for free" for an entry.
19
+ */
20
+ export declare const CORTEX_AI_FREE_MODEL_FALLBACK_REGISTRY: readonly ["nvidia/nemotron-3-super-120b-a12b:free", "nvidia/nemotron-3-ultra-550b-a55b:free", "thinkingmachines/inkling:free", "nex-agi/nex-n2.5-pro:free", "poolside/laguna-s-2.1:free", "thinkingmachines/inkling-small:free", "inclusionai/ling-3.0-flash-vl:free"];
4
21
  export declare const CORTEX_AI_REQUIRED_MODEL_PARAMETERS: readonly ["tools", "structured_outputs"];
5
22
  export declare const CORTEX_AI_MODEL_REGISTRY: {
6
23
  readonly defaultFreeRouter: "openrouter/free";
7
- readonly defaultStructuredOutputModel: "qwen/qwen3-next-80b-a3b-instruct:free";
8
- readonly defaultToolCallingModel: "qwen/qwen3-next-80b-a3b-instruct:free";
9
- readonly freeFallbacks: readonly ["qwen/qwen3-next-80b-a3b-instruct:free", "nvidia/nemotron-3-super-120b-a12b:free", "nvidia/nemotron-nano-9b-v2:free"];
10
- readonly structuredJsonPreferred: readonly ["qwen/qwen3-next-80b-a3b-instruct:free", "nvidia/nemotron-3-super-120b-a12b:free", "nvidia/nemotron-nano-9b-v2:free"];
11
- readonly toolCallingPreferred: readonly ["qwen/qwen3-next-80b-a3b-instruct:free", "nvidia/nemotron-3-super-120b-a12b:free", "nvidia/nemotron-nano-9b-v2:free"];
24
+ readonly defaultStructuredOutputModel: "nvidia/nemotron-3-super-120b-a12b:free";
25
+ readonly defaultToolCallingModel: "nvidia/nemotron-3-super-120b-a12b:free";
26
+ readonly freeFallbacks: readonly ["nvidia/nemotron-3-super-120b-a12b:free", "nvidia/nemotron-3-ultra-550b-a55b:free", "thinkingmachines/inkling:free", "nex-agi/nex-n2.5-pro:free", "poolside/laguna-s-2.1:free", "thinkingmachines/inkling-small:free", "inclusionai/ling-3.0-flash-vl:free"];
27
+ readonly structuredJsonPreferred: readonly ["nvidia/nemotron-3-super-120b-a12b:free", "nvidia/nemotron-3-ultra-550b-a55b:free", "thinkingmachines/inkling:free", "nex-agi/nex-n2.5-pro:free", "poolside/laguna-s-2.1:free", "thinkingmachines/inkling-small:free", "inclusionai/ling-3.0-flash-vl:free"];
28
+ readonly toolCallingPreferred: readonly ["nvidia/nemotron-3-super-120b-a12b:free", "nvidia/nemotron-3-ultra-550b-a55b:free", "thinkingmachines/inkling:free", "nex-agi/nex-n2.5-pro:free", "poolside/laguna-s-2.1:free", "thinkingmachines/inkling-small:free", "inclusionai/ling-3.0-flash-vl:free"];
12
29
  };
13
30
  export type CortexAiOpenRouterModelId = typeof CORTEX_AI_OPENROUTER_FREE_ROUTER_MODEL | (typeof CORTEX_AI_FREE_MODEL_FALLBACK_REGISTRY)[number] | (string & {});
14
31
  export type CortexAiRoutingCredentialSource = 'env' | 'manual' | 'stored';
@@ -65,6 +82,12 @@ export declare function omitUnsupportedCortexAiModelOptions<TOptions extends Rec
65
82
  modelSelection?: CortexAiStoredModelSelection | null;
66
83
  }): TOptions;
67
84
  export declare function getHttpStatusCode(error: unknown): number | null;
85
+ /**
86
+ * HTTP status of an OpenRouter failure, reading the transport status first
87
+ * (`APICallError.statusCode`, `response.status`, `cause.status`) and the JSON
88
+ * body's `error.code` second. `null` when nothing numeric is present.
89
+ */
90
+ export declare function getOpenRouterErrorStatus(error: unknown): number | null;
68
91
  export declare function isOpenRouterRateLimitError(error: unknown): boolean;
69
92
  export declare function isOpenRouterRecoverableRoutingError(error: unknown): boolean;
70
93
  export declare function summarizeCortexAiRoutingError(error: unknown, fallbackMessage?: string): string;
@@ -1,9 +1,20 @@
1
- import { APICallError as y } from "ai";
2
- const N = "https://openrouter.ai/api/v1", O = "openrouter/free", u = [
3
- "qwen/qwen3-next-80b-a3b-instruct:free",
1
+ import { APICallError as h } from "ai";
2
+ const $ = "https://openrouter.ai/api/v1", C = "openrouter/free", u = [
3
+ // 120B/12B hybrid MoE; tools + structured_outputs; NVIDIA-hosted; 262K ctx.
4
4
  "nvidia/nemotron-3-super-120b-a12b:free",
5
- "nvidia/nemotron-nano-9b-v2:free"
6
- ], S = ["tools", "structured_outputs"], h = {
5
+ // 550B/55B; most-used free model (3.77T tokens/week); 1M ctx; tools only.
6
+ "nvidia/nemotron-3-ultra-550b-a55b:free",
7
+ // 975B/41B; 1M ctx; 99.98% uptime; SWE-bench Verified 77.6; tools only.
8
+ "thinkingmachines/inkling:free",
9
+ // Newest (2026-09-08); tools + structured_outputs; 469B tokens/week; size undisclosed.
10
+ "nex-agi/nex-n2.5-pro:free",
11
+ // 118B/8B coding-agent model; 1.26T tokens/week; 99.99% uptime; tools only.
12
+ "poolside/laguna-s-2.1:free",
13
+ // 276B/12B; 1M ctx; 99.99% uptime; tools only.
14
+ "thinkingmachines/inkling-small:free",
15
+ // 124B/5.5B general + vision model (2026-09-10); 329B tokens/week; tools only.
16
+ "inclusionai/ling-3.0-flash-vl:free"
17
+ ], P = ["tools", "structured_outputs"], T = {
7
18
  frequencyPenalty: "frequency_penalty",
8
19
  logitBias: "logit_bias",
9
20
  presencePenalty: "presence_penalty",
@@ -12,51 +23,51 @@ const N = "https://openrouter.ai/api/v1", O = "openrouter/free", u = [
12
23
  temperature: "temperature",
13
24
  topK: "top_k",
14
25
  topP: "top_p"
15
- }, j = {
16
- defaultFreeRouter: O,
26
+ }, J = {
27
+ defaultFreeRouter: C,
17
28
  defaultStructuredOutputModel: u[0],
18
29
  defaultToolCallingModel: u[0],
19
30
  freeFallbacks: u,
20
31
  structuredJsonPreferred: u,
21
32
  toolCallingPreferred: u
22
33
  };
23
- class R extends Error {
34
+ class E extends Error {
24
35
  attempts;
25
36
  constructor(t, n, r) {
26
37
  super(t), this.name = "CortexAiRoutingError", this.attempts = n, this.cause = r;
27
38
  }
28
39
  }
29
- function m(e) {
40
+ function g(e) {
30
41
  return Array.from(new Set(e.filter(Boolean)));
31
42
  }
32
- function l(e) {
43
+ function c(e) {
33
44
  return e && typeof e == "object" && !Array.isArray(e) ? e : null;
34
45
  }
35
- function f(e) {
46
+ function d(e) {
36
47
  return typeof e == "string" && e.trim() ? e.trim() : null;
37
48
  }
38
- function E(e) {
49
+ function A(e) {
39
50
  return Array.isArray(e) ? e.filter((t) => typeof t == "string" && t.trim().length > 0) : [];
40
51
  }
41
- function p(e) {
52
+ function f(e) {
42
53
  const t = typeof e == "number" ? e : Number(e);
43
54
  return Number.isFinite(t) ? t : null;
44
55
  }
45
- function _(e) {
46
- const t = l(e);
56
+ function O(e) {
57
+ const t = c(e);
47
58
  return t ? Object.fromEntries(
48
59
  Object.entries(t).filter(([, n]) => n != null).map(([n, r]) => [n, String(r)])
49
60
  ) : {};
50
61
  }
51
- function b(e) {
62
+ function S(e) {
52
63
  const t = new Set(e);
53
- return S.every((n) => t.has(n));
64
+ return P.every((n) => t.has(n));
54
65
  }
55
- function C(e) {
56
- const t = l(e.architecture);
57
- return E(t?.output_modalities).includes("text");
66
+ function L(e) {
67
+ const t = c(e.architecture);
68
+ return A(t?.output_modalities).includes("text");
58
69
  }
59
- function P(e) {
70
+ function N(e) {
60
71
  if (e == null)
61
72
  return null;
62
73
  if (typeof e == "number")
@@ -67,36 +78,36 @@ function P(e) {
67
78
  }
68
79
  return null;
69
80
  }
70
- function L(e, t) {
71
- const n = P(e);
81
+ function k(e, t) {
82
+ const n = N(e);
72
83
  return n !== null && n <= t.getTime();
73
84
  }
74
- function T(e) {
75
- const t = l(e.top_provider);
76
- return p(e.context_length) ?? p(e.contextLength) ?? p(t?.context_length) ?? null;
85
+ function D(e) {
86
+ const t = c(e.top_provider);
87
+ return f(e.context_length) ?? f(e.contextLength) ?? f(t?.context_length) ?? null;
77
88
  }
78
89
  function w(e) {
79
90
  const t = e.expiration_date ?? e.expirationDate;
80
91
  return typeof t == "string" && t.trim() ? t.trim() : null;
81
92
  }
82
- function D(e) {
93
+ function F(e) {
83
94
  return !!(e && u.includes(e));
84
95
  }
85
- function B(e) {
86
- const t = l(e);
96
+ function Y(e) {
97
+ const t = c(e);
87
98
  if (!t)
88
99
  return null;
89
- const n = f(t.modelId), r = f(t.name), s = E(t.supportedParameters), i = f(t.updatedAt);
90
- return !n || !r || !i || !b(s) ? null : {
91
- contextLength: p(t.contextLength),
100
+ const n = d(t.modelId), r = d(t.name), s = A(t.supportedParameters), i = d(t.updatedAt);
101
+ return !n || !r || !i || !S(s) ? null : {
102
+ contextLength: f(t.contextLength),
92
103
  modelId: n,
93
104
  name: r,
94
- pricing: _(t.pricing),
105
+ pricing: O(t.pricing),
95
106
  supportedParameters: s,
96
107
  updatedAt: i
97
108
  };
98
109
  }
99
- function U(e, t = /* @__PURE__ */ new Date()) {
110
+ function z(e, t = /* @__PURE__ */ new Date()) {
100
111
  return {
101
112
  contextLength: e.contextLength,
102
113
  modelId: e.id,
@@ -106,52 +117,52 @@ function U(e, t = /* @__PURE__ */ new Date()) {
106
117
  updatedAt: t.toISOString()
107
118
  };
108
119
  }
109
- function X(e, t = /* @__PURE__ */ new Date()) {
110
- const n = l(e), r = Array.isArray(e) ? e : Array.isArray(n?.data) ? n.data : [], s = [];
120
+ function H(e, t = /* @__PURE__ */ new Date()) {
121
+ const n = c(e), r = Array.isArray(e) ? e : Array.isArray(n?.data) ? n.data : [], s = [];
111
122
  for (const i of r) {
112
- const o = l(i), c = f(o?.id), a = f(o?.name), A = E(o?.supported_parameters);
113
- !o || !c || !a || !C(o) || L(o.expiration_date, t) || !b(A) || s.push({
114
- contextLength: T(o),
115
- created: p(o.created),
123
+ const o = c(i), l = d(o?.id), a = d(o?.name), M = A(o?.supported_parameters);
124
+ !o || !l || !a || !L(o) || k(o.expiration_date, t) || !S(M) || s.push({
125
+ contextLength: D(o),
126
+ created: f(o.created),
116
127
  expirationDate: w(o),
117
- id: c,
128
+ id: l,
118
129
  name: a,
119
- pricing: _(o.pricing),
120
- supportedParameters: A
130
+ pricing: O(o.pricing),
131
+ supportedParameters: M
121
132
  });
122
133
  }
123
134
  return s.sort((i, o) => i.name.localeCompare(o.name));
124
135
  }
125
- function K(e) {
126
- return m([
136
+ function W(e) {
137
+ return g([
127
138
  e?.modelId || u[0],
128
139
  ...e?.fallbackModelIds || u
129
140
  ]);
130
141
  }
131
- function $(e) {
142
+ function Q(e) {
132
143
  const t = e.requestedModelId?.trim() || null;
133
144
  if (e.credentialSource === "env")
134
145
  return {
135
146
  credentialSource: e.credentialSource,
136
- ignoredRequestedModelId: t && !D(t) ? t : null,
147
+ ignoredRequestedModelId: t && !F(t) ? t : null,
137
148
  modelIds: [...u],
138
149
  modelSelection: null
139
150
  };
140
- const n = m(
151
+ const n = g(
141
152
  e.fallbackModelIds?.length ? e.fallbackModelIds : u
142
153
  ), r = e.credentialSource === "stored" ? e.selectedModel?.modelId || n[0] : t || e.selectedModel?.modelId || n[0];
143
154
  return {
144
155
  credentialSource: e.credentialSource,
145
156
  ignoredRequestedModelId: e.credentialSource === "stored" && t && t !== r ? t : null,
146
- modelIds: m([r, ...n]),
157
+ modelIds: g([r, ...n]),
147
158
  modelSelection: e.selectedModel || null
148
159
  };
149
160
  }
150
- function z(e, t) {
161
+ function V(e, t) {
151
162
  const n = t.modelSelection;
152
163
  if (!n || n.modelId !== t.modelId)
153
164
  return e;
154
- const r = new Set(n.supportedParameters), s = Object.entries(h).filter(([o, c]) => o in e && !r.has(c)).map(([o]) => o);
165
+ const r = new Set(n.supportedParameters), s = Object.entries(T).filter(([o, l]) => o in e && !r.has(l)).map(([o]) => o);
155
166
  if (s.length === 0)
156
167
  return e;
157
168
  const i = { ...e };
@@ -159,65 +170,98 @@ function z(e, t) {
159
170
  delete i[o];
160
171
  return i;
161
172
  }
162
- function g(e, t) {
173
+ function p(e, t) {
163
174
  if (!e || typeof e != "object" || !(t in e))
164
175
  return null;
165
176
  const n = e[t], r = typeof n == "number" ? n : Number(n);
166
177
  return Number.isFinite(r) ? r : null;
167
178
  }
168
- function x(e) {
169
- if (y.isInstance(e))
179
+ function y(e) {
180
+ if (h.isInstance(e))
170
181
  return e.statusCode ?? null;
171
- const t = g(e, "statusCode") ?? g(e, "status");
182
+ const t = p(e, "statusCode") ?? p(e, "status");
172
183
  if (t)
173
184
  return t;
174
185
  if (e && typeof e == "object" && "response" in e) {
175
- const n = e.response, r = g(n, "status");
186
+ const n = e.response, r = p(n, "status");
176
187
  if (r)
177
188
  return r;
178
189
  }
179
- return e && typeof e == "object" && "cause" in e ? x(e.cause) : null;
190
+ return e && typeof e == "object" && "cause" in e ? y(e.cause) : null;
180
191
  }
181
- function I(e) {
182
- return x(e) === 429;
192
+ function b(e) {
193
+ return e !== null && Number.isInteger(e) && e >= 100 && e <= 599;
183
194
  }
184
- function d(e) {
185
- if (!e)
186
- return "";
187
- if (e instanceof Error) {
188
- const t = "cause" in e ? d(e.cause) : "";
189
- return [e.message, t].filter(Boolean).join(`
190
- `);
195
+ function _(e) {
196
+ if (typeof e != "string" || !e.trim().startsWith("{"))
197
+ return null;
198
+ try {
199
+ return c(JSON.parse(e));
200
+ } catch {
201
+ return null;
191
202
  }
192
- if (typeof e == "object") {
193
- const t = e;
194
- return ["message", "error", "text", "cause"].map((n) => d(t[n])).filter(Boolean).join(`
195
- `);
203
+ }
204
+ function x(e, t = 0) {
205
+ const n = c(e);
206
+ if (!n || t > 8)
207
+ return null;
208
+ const r = [
209
+ n,
210
+ c(n.data),
211
+ _(n.responseBody),
212
+ _(n.text)
213
+ ];
214
+ for (const s of r) {
215
+ const i = c(s?.error), o = p(i, "code") ?? p(i, "status");
216
+ if (b(o))
217
+ return o;
196
218
  }
197
- return String(e);
219
+ return x(n.cause, t + 1);
220
+ }
221
+ function I(e) {
222
+ const t = y(e);
223
+ return b(t) ? t : x(e);
198
224
  }
199
225
  function q(e) {
200
- return I(e) ? !0 : /No endpoints found|no longer available|not available as a free model|transitioned to a paid model/i.test(
201
- d(e)
202
- );
226
+ return I(e) === 429;
227
+ }
228
+ const B = ["message", "error", "text", "responseBody", "data", "cause"];
229
+ function m(e, t = 0) {
230
+ if (!e || t > 8)
231
+ return "";
232
+ if (typeof e != "object")
233
+ return String(e);
234
+ const n = e, r = e instanceof Error ? [e.message] : [];
235
+ for (const s of B)
236
+ s === "message" && e instanceof Error || r.push(m(n[s], t + 1));
237
+ return Array.from(new Set(r.filter(Boolean))).join(`
238
+ `);
239
+ }
240
+ const U = /No endpoints found|no longer available|not available as a free model|transitioned to a paid model|unavailable for free|paid version is available|is not a valid model ID/i, j = /not found|does not exist|unknown model|no such model/i;
241
+ function X(e) {
242
+ const t = I(e);
243
+ if (t === 429 || t === 404)
244
+ return !0;
245
+ const n = m(e);
246
+ return U.test(n) ? !0 : t === 400 && j.test(n);
203
247
  }
204
- function M(e, t = 900) {
248
+ function R(e, t = 900) {
205
249
  const n = e.replace(/\s+/g, " ").trim();
206
250
  return n.length > t ? `${n.slice(0, t - 1).trimEnd()}...` : n;
207
251
  }
208
- function F(e) {
209
- const t = d(e);
210
- return t ? M(t) : "Unknown OpenRouter error.";
252
+ function G(e) {
253
+ const t = m(e);
254
+ return t ? R(t) : "Unknown OpenRouter error.";
211
255
  }
212
- function G(e, t = "Cortex AI request failed.") {
213
- if (e instanceof R) {
214
- const n = e.attempts.map((o) => o.errorMessage).filter((o) => !!o?.trim()), r = n[0], s = n[n.length - 1], i = M(d(e.cause));
256
+ function Z(e, t = "Cortex AI request failed.") {
257
+ if (e instanceof E) {
258
+ const n = e.attempts.map((o) => o.errorMessage).filter((o) => !!o?.trim()), r = n[0], s = n[n.length - 1], i = R(m(e.cause));
215
259
  return r && s && r !== s ? `First model error: ${r} Last model error: ${s}` : s || r || i || e.message;
216
260
  }
217
- return M(d(e)) || t;
261
+ return R(m(e)) || t;
218
262
  }
219
- async function Y(e) {
220
- const t = m(e.modelIds), n = e.shouldRetry || q;
263
+ async function v(e) {
264
+ const t = g(e.modelIds), n = e.shouldRetry || X;
221
265
  let r = [], s = null;
222
266
  for (const i of t)
223
267
  try {
@@ -235,23 +279,23 @@ async function Y(e) {
235
279
  result: o
236
280
  };
237
281
  } catch (o) {
238
- const c = I(o), a = n(o);
282
+ const l = q(o), a = n(o);
239
283
  if (s = o, r = [
240
284
  ...r,
241
285
  {
242
- errorMessage: F(o),
286
+ errorMessage: G(o),
243
287
  modelId: i,
244
- rateLimited: c,
245
- status: c ? "rate_limited" : a ? "retried" : "failed"
288
+ rateLimited: l,
289
+ status: l ? "rate_limited" : a ? "retried" : "failed"
246
290
  }
247
291
  ], !a)
248
- throw new R(
292
+ throw new E(
249
293
  `OpenRouter request failed for model "${i}".`,
250
294
  r,
251
295
  o
252
296
  );
253
297
  }
254
- throw new R(
298
+ throw new E(
255
299
  "OpenRouter fallback exhausted all configured Cortex AI models.",
256
300
  r,
257
301
  s
@@ -259,21 +303,22 @@ async function Y(e) {
259
303
  }
260
304
  export {
261
305
  u as CORTEX_AI_FREE_MODEL_FALLBACK_REGISTRY,
262
- j as CORTEX_AI_MODEL_REGISTRY,
263
- N as CORTEX_AI_OPENROUTER_BASE_URL,
264
- O as CORTEX_AI_OPENROUTER_FREE_ROUTER_MODEL,
265
- S as CORTEX_AI_REQUIRED_MODEL_PARAMETERS,
266
- R as CortexAiRoutingError,
267
- K as buildCortexAiModelFallbackChain,
268
- $ as buildCortexAiRoutingPolicy,
269
- U as createCortexAiStoredModelSelection,
270
- X as filterCortexAiCompatibleOpenRouterModels,
271
- x as getHttpStatusCode,
272
- D as isCortexAiFreeModelId,
273
- I as isOpenRouterRateLimitError,
274
- q as isOpenRouterRecoverableRoutingError,
275
- z as omitUnsupportedCortexAiModelOptions,
276
- Y as runWithCortexAiModelFallback,
277
- B as safeParseCortexAiModelSelection,
278
- G as summarizeCortexAiRoutingError
306
+ J as CORTEX_AI_MODEL_REGISTRY,
307
+ $ as CORTEX_AI_OPENROUTER_BASE_URL,
308
+ C as CORTEX_AI_OPENROUTER_FREE_ROUTER_MODEL,
309
+ P as CORTEX_AI_REQUIRED_MODEL_PARAMETERS,
310
+ E as CortexAiRoutingError,
311
+ W as buildCortexAiModelFallbackChain,
312
+ Q as buildCortexAiRoutingPolicy,
313
+ z as createCortexAiStoredModelSelection,
314
+ H as filterCortexAiCompatibleOpenRouterModels,
315
+ y as getHttpStatusCode,
316
+ I as getOpenRouterErrorStatus,
317
+ F as isCortexAiFreeModelId,
318
+ q as isOpenRouterRateLimitError,
319
+ X as isOpenRouterRecoverableRoutingError,
320
+ V as omitUnsupportedCortexAiModelOptions,
321
+ v as runWithCortexAiModelFallback,
322
+ Y as safeParseCortexAiModelSelection,
323
+ Z as summarizeCortexAiRoutingError
279
324
  };
@@ -1,6 +1,6 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const k=require("./ai-global-agent-tools.cjs.js"),x=require("./block-content-schemas.cjs.js");require("./zod-config.cjs.js");const v=require("zod"),n={create_cms_page:"write",create_cms_post:"write",create_cms_product:"write",create_custom_block:"write",delete_cms_item:"write",delete_custom_block:"write",describe_database_schema:"read",execute_cms_action_plan:"write",execute_database_action_plan:"write",execute_database_mutation:"write",fetch_ecommerce_stats:"read",fetch_url_content:"read",finish_site_build:"write",get_site_overview:"read",insert_content_block:"write",list_custom_blocks:"read",list_media:"read",list_product_categories:"read",list_site_script_revisions:"read",list_site_scripts:"read",list_site_themes:"read",manage_language:"write",manage_product_category:"write",manage_product_variants:"write",manage_site_script:"write",manage_site_theme:"write",prepare_delete_cms_item:"read",publish_content_draft:"write",read_current_cms_item:"read",read_database_records:"read",reset_site_content:"write",revert_site_script:"write",rewrite_page_draft:"write",save_site_brief:"write",search_documentation:"read",search_stock_photos:"read",set_content_images:"write",start_site_build:"write",translate_content_bulk:"write",translate_page:"write",update_cms_item_field:"write",upload_media:"write",update_content_block:"write",update_current_cms_fields:"write",update_custom_block:"write",update_footer:"write",update_global_css:"write",update_navigation_bar:"write",update_section_column_block:"write",update_site_identity:"write"},s={generate_jsonb_layout:{canonical:"rewrite_page_draft",description:"Generate a complete, strictly-validated JSONB block layout and write it into a target page or post. Blocks are normalized and validated against the NextBlock block schema, then staged as a Live Draft on the target record — nothing goes live until an editor publishes the draft, and publishing snapshots a revision so the change is reversible. Use for whole-page builds and redesigns. Alias of `rewrite_page_draft`.",title:"Generate JSONB layout"},get_database_schema:{canonical:"describe_database_schema",description:"Return the current CMS database structure: every table Cortex AI may read or mutate, its columns, primary keys, and whether it is read-only. Pair with `list_custom_blocks` for the active data-defined block definitions and with the `cortex://schema/blocks` resource for the built-in block types. Read-only. Alias of `describe_database_schema`.",title:"Get database schema"},query_site_analytics:{canonical:"fetch_ecommerce_stats",description:"Query quantitative site analytics: revenue, order counts, order-status breakdowns, and top-selling products over a time range. Read-only. For inventory levels and post/page metrics that this report does not cover, use `read_database_records` against the `products`, `product_variants`, `posts`, or `pages` tables. Alias of `fetch_ecommerce_stats`.",title:"Query site analytics"},search_stock_media:{canonical:"search_stock_photos",description:"Search free stock media (Pexels, then Unsplash) for contextually relevant imagery, returning direct image URLs with dimensions, alt text, and photographer attribution. Drop a returned `url` straight into an image block's `external_url` or a section background. Read-only and zero cost. Requires a stock provider key in CMS Settings → Cortex AI. Alias of `search_stock_photos`.",title:"Search stock media"},update_site_navigation:{canonical:"update_navigation_bar",description:'Alter the public site navigation: header menu items and their nested child hierarchy, per locale. Use mode "append" to add links while preserving the existing menu, "update" to rename or re-point one link, and "replace" only when rebuilding the whole menu. For footer links and copyright use `update_footer`. Alias of `update_navigation_bar`.',title:"Update site navigation"}};function h(e){return e in s?s[e].canonical:e in n?e:null}function b(e){const t=h(e);return t?n[t]:null}function c(e,t){const r=b(t);return r?r==="read"?e.length>0:e.includes("write"):!1}function g(e){return e.split("_").map((r,a)=>a===0?r.charAt(0).toUpperCase()+r.slice(1):r).join(" ")}function _(e){const t={additionalProperties:!1,type:"object"};if(!e||typeof e!="object")return t;try{const r=v.z.toJSONSchema(e,{cycles:"ref",io:"input",reused:"inline",target:"draft-2020-12",unrepresentable:"any"});return delete r.$schema,r.type==="object"?r:t}catch{return t}}function l(e){return k.createCortexGlobalAgentTools(e)}function C(e){const t=Object.keys(l(e)),r=Object.keys(n);return{missingFromRegistry:r.filter(a=>!t.includes(a)),unclassified:t.filter(a=>!r.includes(a))}}function T(e){const t=l(e.context),r=[];for(const[a,i]of Object.entries(t))!(a in n)||!c(e.scopes,a)||r.push({description:i.description??`Cortex AI ${g(a)} tool.`,inputSchema:_(i.inputSchema),name:a,title:g(a)});for(const[a,i]of Object.entries(s)){const o=t[i.canonical];!o||!c(e.scopes,a)||r.push({description:i.description,inputSchema:_(o.inputSchema),name:a,title:i.title})}return r.sort((a,i)=>a.name.localeCompare(i.name))}function m(e,t){return{content:[{text:e,type:"text"}],isError:t}}function S(e){return e.issues.map(t=>`${t.path.length>0?t.path.join("."):"(root)"}: ${t.message}`).join("; ")}class p extends Error{constructor(t){super(`Unknown tool: ${t}`),this.name="CortexMcpUnknownToolError"}}class f extends Error{constructor(t){super(`Tool "${t}" requires the "write" scope. This MCP token is read-only — mint a read+write token in CMS Settings → Cortex AI.`),this.name="CortexMcpForbiddenToolError"}}async function M(e){const t=h(e.name);if(!t)throw new p(e.name);if(!c(e.scopes,e.name))throw new f(e.name);const a=l(e.context)[t];if(!a||typeof a.execute!="function")throw new p(e.name);const i=e.args&&typeof e.args=="object"?e.args:{};if(a.inputSchema&&typeof a.inputSchema.safeParse=="function"){const o=a.inputSchema.safeParse(i);if(!o.success)return m(`Invalid arguments for "${e.name}": ${S(o.error)}`,!0)}try{const o=await a.execute(i),u=JSON.stringify(o??{success:!0},null,2),d=o&&typeof o=="object"&&!Array.isArray(o)?o:null,w=d?.success===!1;return{content:[{text:u,type:"text"}],isError:w,...d?{structuredContent:d}:{}}}catch(o){const u=o instanceof Error?o.message:String(o);return m(`Tool "${e.name}" failed: ${u}`,!0)}}const O=[{description:"The CMS database structure Cortex AI can read and mutate: tables, columns, primary keys, and read-only flags.",mimeType:"application/json",name:"database-schema",title:"NextBlock database schema",uri:"cortex://schema/database"},{description:"The built-in NextBlock block types available when composing page, post, and product layouts.",mimeType:"application/json",name:"block-types",title:"NextBlock block types",uri:"cortex://schema/blocks"},{description:"Data-defined custom block definitions registered in this workspace, keyed by the slug used as a block instance `block_type`.",mimeType:"application/json",name:"custom-blocks",title:"NextBlock custom block definitions",uri:"cortex://schema/custom-blocks"}];async function R(e){const t=l(e.context);if(e.uri==="cortex://schema/database"){const r=await t.describe_database_schema?.execute?.({includeReadOnly:!0});return{mimeType:"application/json",text:JSON.stringify(r??{},null,2),uri:e.uri}}if(e.uri==="cortex://schema/blocks")return{mimeType:"application/json",text:JSON.stringify({blockTypes:x.availableCortexAiBlockTypes},null,2),uri:e.uri};if(e.uri==="cortex://schema/custom-blocks"){const r=await t.list_custom_blocks?.execute?.({});return{mimeType:"application/json",text:JSON.stringify(r??{},null,2),uri:e.uri}}return null}const y=[{arguments:[{description:'Everything known about the client and the site they want: business, audience, goals, pages (or "one landing page"), languages, brand, contact details. Leave blank to be asked.',name:"brief",required:!1}],description:"Build (or rebuild) the whole NextBlock site from a brief: remove the sample content, set the identity and theme, create and publish every page, the menus, the footer, and the translations.",name:"build-site",title:"Build the whole site"},{arguments:[{description:"What the page is for, and any brand or tone notes.",name:"brief",required:!0},{description:'Slug of the page or post to rewrite, e.g. "home".',name:"slug",required:!0}],description:"Build or redesign a NextBlock page from a brief, following the section-based layout recipe, and stage it as a reviewable Live Draft.",name:"build-page",title:"Build a NextBlock page"},{arguments:[{description:"Source URL to draw structure and copy from.",name:"url",required:!0},{description:"Slug of the page to write the result into.",name:"slug",required:!0}],description:"Read an external page and rebuild an equivalent NextBlock page from it, reusing its imagery where available.",name:"clone-from-url",title:"Rebuild a page from a URL"},{arguments:[{description:'Target language code, e.g. "fr".',name:"languageCode",required:!0},{description:"Slug of the page or post to translate.",name:"slug",required:!0}],description:"Translate an existing page or post into another language, preserving its layout and imagery.",name:"translate-content",title:"Translate a page or post"}],N={"build-site":e=>["Build the whole NextBlock site for this client.","",e.brief?.trim()?`Brief:
2
- ${e.brief}`:"No brief was given: first ask, in one short numbered list, about the business and what it does, the audience and the one action visitors should take, the site shape (one landing page or which pages), the languages, brand colours and tone, contact details, and whether existing content is kept.","","Process:","1. Call get_site_overview to see what exists, the active languages, and whether the NextBlock demo content is still present. Record what you know with save_site_brief.","2. Present the plan (what is removed, every page with its sections, menus, footer, theme, languages) and call start_site_build with `summary`, `brief`, and `reset` (keepLanguages = the languages wanted) unless existing content is kept. Over MCP the host approves the call; there is no chat confirmation.",'3. Build: update_site_identity; manage_language as needed; manage_site_theme with the brand colours; search_stock_media for imagery when available; rewrite the empty "home" page with generate_jsonb_layout then publish_content_draft; create_cms_page (status "published") for every other page; update_site_navigation (mode "replace") and update_footer for every language; translate_content_bulk for each extra language.',"4. Call finish_site_build with a summary, then report every page with its URL.","Write real copy from the brief, never placeholders. Every page must exist in every active language."].join(`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const k=require("./ai-global-agent-tools.cjs.js"),x=require("./block-content-schemas.cjs.js");require("./zod-config.cjs.js");const v=require("zod"),n={create_cms_page:"write",create_cms_post:"write",create_cms_product:"write",create_custom_block:"write",delete_cms_item:"write",delete_custom_block:"write",describe_database_schema:"read",execute_cms_action_plan:"write",execute_database_action_plan:"write",execute_database_mutation:"write",fetch_ecommerce_stats:"read",fetch_url_content:"read",finish_site_build:"write",get_site_overview:"read",insert_content_block:"write",list_custom_blocks:"read",list_media:"read",list_product_categories:"read",list_site_script_revisions:"read",list_site_scripts:"read",list_site_themes:"read",manage_language:"write",manage_product_category:"write",manage_product_variants:"write",manage_site_script:"write",manage_site_theme:"write",prepare_delete_cms_item:"read",publish_content_draft:"write",read_current_cms_item:"read",read_database_records:"read",reset_site_content:"write",revert_site_script:"write",rewrite_page_draft:"write",save_site_brief:"write",search_documentation:"read",search_stock_photos:"read",set_content_images:"write",start_site_build:"write",translate_content_bulk:"write",translate_page:"write",update_cms_item_field:"write",upload_media:"write",update_content_block:"write",update_current_cms_fields:"write",update_custom_block:"write",update_footer:"write",update_global_css:"write",update_navigation_bar:"write",update_section_column_block:"write",update_site_identity:"write"},s={generate_jsonb_layout:{canonical:"rewrite_page_draft",description:"Generate a complete, strictly-validated JSONB block layout and write it into a target page or post. Blocks are normalized and validated against the NextBlock block schema, then staged as a Live Draft on the target record — nothing goes live until an editor publishes the draft, and publishing snapshots a revision so the change is reversible. Use for whole-page builds and redesigns. Alias of `rewrite_page_draft`.",title:"Generate JSONB layout"},get_database_schema:{canonical:"describe_database_schema",description:"Return the current CMS database structure: every table Cortex AI may read or mutate, its columns, primary keys, and whether it is read-only. Pair with `list_custom_blocks` for the active data-defined block definitions and with the `cortex://schema/blocks` resource for the built-in block types. Read-only. Alias of `describe_database_schema`.",title:"Get database schema"},query_site_analytics:{canonical:"fetch_ecommerce_stats",description:"Query quantitative site analytics: revenue, order counts, order-status breakdowns, and top-selling products over a time range. Read-only. For inventory levels and post/page metrics that this report does not cover, use `read_database_records` against the `products`, `product_variants`, `posts`, or `pages` tables. Alias of `fetch_ecommerce_stats`.",title:"Query site analytics"},search_stock_media:{canonical:"search_stock_photos",description:"Search free stock media (Pexels, then Unsplash) for contextually relevant imagery, returning direct image URLs with dimensions, alt text, and photographer attribution. Drop a returned `url` straight into an image block's `external_url` or a section background. Read-only and zero cost. Requires a stock provider key in CMS Settings → Cortex AI. Alias of `search_stock_photos`.",title:"Search stock media"},update_site_navigation:{canonical:"update_navigation_bar",description:'Alter the public site navigation: header menu items and their nested child hierarchy, per locale. Use mode "append" to add links while preserving the existing menu, "update" to rename or re-point one link, and "replace" only when rebuilding the whole menu. For footer links and copyright use `update_footer`. Alias of `update_navigation_bar`.',title:"Update site navigation"}};function h(e){return e in s?s[e].canonical:e in n?e:null}function b(e){const t=h(e);return t?n[t]:null}function c(e,t){const r=b(t);return r?r==="read"?e.length>0:e.includes("write"):!1}function g(e){return e.split("_").map((r,a)=>a===0?r.charAt(0).toUpperCase()+r.slice(1):r).join(" ")}function _(e){const t={additionalProperties:!1,type:"object"};if(!e||typeof e!="object")return t;try{const r=v.z.toJSONSchema(e,{cycles:"ref",io:"input",reused:"inline",target:"draft-2020-12",unrepresentable:"any"});return delete r.$schema,r.type==="object"?r:t}catch{return t}}function l(e){return k.createCortexGlobalAgentTools(e)}function C(e){const t=Object.keys(l(e)),r=Object.keys(n);return{missingFromRegistry:r.filter(a=>!t.includes(a)),unclassified:t.filter(a=>!r.includes(a))}}function T(e){const t=l(e.context),r=[];for(const[a,i]of Object.entries(t))!(a in n)||!c(e.scopes,a)||r.push({description:i.description??`Cortex AI ${g(a)} tool.`,inputSchema:_(i.inputSchema),name:a,title:g(a)});for(const[a,i]of Object.entries(s)){const o=t[i.canonical];!o||!c(e.scopes,a)||r.push({description:i.description,inputSchema:_(o.inputSchema),name:a,title:i.title})}return r.sort((a,i)=>a.name.localeCompare(i.name))}function m(e,t){return{content:[{text:e,type:"text"}],isError:t}}function S(e){return e.issues.map(t=>`${t.path.length>0?t.path.join("."):"(root)"}: ${t.message}`).join("; ")}class p extends Error{constructor(t){super(`Unknown tool: ${t}`),this.name="CortexMcpUnknownToolError"}}class f extends Error{constructor(t){super(`Tool "${t}" requires the "write" scope. This MCP token is read-only — mint a read+write token in CMS Settings → Cortex AI.`),this.name="CortexMcpForbiddenToolError"}}async function M(e){const t=h(e.name);if(!t)throw new p(e.name);if(!c(e.scopes,e.name))throw new f(e.name);const a=l(e.context)[t];if(!a||typeof a.execute!="function")throw new p(e.name);const i=e.args&&typeof e.args=="object"?e.args:{};if(a.inputSchema&&typeof a.inputSchema.safeParse=="function"){const o=a.inputSchema.safeParse(i);if(!o.success)return m(`Invalid arguments for "${e.name}": ${S(o.error)}`,!0)}try{const o=await a.execute(i),u=JSON.stringify(o??{success:!0},null,2),d=o&&typeof o=="object"&&!Array.isArray(o)?o:null,w=d?.success===!1;return{content:[{text:u,type:"text"}],isError:w,...d?{structuredContent:d}:{}}}catch(o){const u=o instanceof Error?o.message:String(o);return m(`Tool "${e.name}" failed: ${u}`,!0)}}const O=[{description:"The CMS database structure Cortex AI can read and mutate: tables, columns, primary keys, and read-only flags.",mimeType:"application/json",name:"database-schema",title:"NextBlock database schema",uri:"cortex://schema/database"},{description:"The built-in NextBlock block types available when composing page, post, and product layouts.",mimeType:"application/json",name:"block-types",title:"NextBlock block types",uri:"cortex://schema/blocks"},{description:"Data-defined custom block definitions registered in this workspace, keyed by the slug used as a block instance `block_type`.",mimeType:"application/json",name:"custom-blocks",title:"NextBlock custom block definitions",uri:"cortex://schema/custom-blocks"}];async function R(e){const t=l(e.context);if(e.uri==="cortex://schema/database"){const r=await t.describe_database_schema?.execute?.({includeReadOnly:!0});return{mimeType:"application/json",text:JSON.stringify(r??{},null,2),uri:e.uri}}if(e.uri==="cortex://schema/blocks")return{mimeType:"application/json",text:JSON.stringify({blockTypes:x.availableCortexAiBlockTypes},null,2),uri:e.uri};if(e.uri==="cortex://schema/custom-blocks"){const r=await t.list_custom_blocks?.execute?.({});return{mimeType:"application/json",text:JSON.stringify(r??{},null,2),uri:e.uri}}return null}const y=[{arguments:[{description:'Everything known about the client and the site they want: business, audience, goals, pages (or "one landing page"), languages, brand, contact details. Leave blank to be asked.',name:"brief",required:!1}],description:"Build (or rebuild) the whole NextBlock site from a brief: remove the sample content, set the identity and theme, create and publish every page, the menus, the footer, and the translations.",name:"build-site",title:"Build the whole site"},{arguments:[{description:"What the page is for, and any brand or tone notes.",name:"brief",required:!0},{description:'Slug of the page or post to rewrite, e.g. "home".',name:"slug",required:!0}],description:"Build or redesign a NextBlock page from a brief, following the section-based layout recipe, and stage it as a reviewable Live Draft.",name:"build-page",title:"Build a NextBlock page"},{arguments:[{description:"Source URL to draw structure and copy from.",name:"url",required:!0},{description:"Slug of the page to write the result into.",name:"slug",required:!0}],description:"Read an external page and rebuild an equivalent NextBlock page from it, reusing its imagery where available.",name:"clone-from-url",title:"Rebuild a page from a URL"},{arguments:[{description:'Target language code, e.g. "fr".',name:"languageCode",required:!0},{description:"Slug of the page or post to translate.",name:"slug",required:!0}],description:"Translate an existing page or post into another language, preserving its layout and imagery.",name:"translate-content",title:"Translate a page or post"}],j={"build-site":e=>["Build the whole NextBlock site for this client.","",e.brief?.trim()?`Brief:
2
+ ${e.brief}`:"A site brief may already be saved (get_site_overview returns it under `brief`): if it is, use it and skip the questions; otherwise ask, in one short numbered list, about the business and what it does, the audience and the one action visitors should take, the site shape (one landing page or which pages), the languages, brand colours and tone, contact details, and whether existing content is kept.","","Process:","1. Call get_site_overview to see what exists, the active languages, and whether the NextBlock demo content is still present. Record what you know with save_site_brief.","2. Present the plan (what is removed, every page with its sections, menus, footer, theme, languages) and call start_site_build with `summary`, `brief`, and `reset` (keepLanguages = the languages wanted) unless existing content is kept. Over MCP the host approves the call; there is no chat confirmation.",'3. Build: update_site_identity; manage_language as needed; manage_site_theme with the brand colours; search_stock_media for imagery when available; rewrite the empty "home" page with generate_jsonb_layout then publish_content_draft; create_cms_page (status "published") for every other page; update_site_navigation (mode "replace") and update_footer for every language; translate_content_bulk for each extra language.',"4. Call finish_site_build with a summary, then report every page with its URL.","Write real copy from the brief, never placeholders. Every page must exist in every active language."].join(`
3
3
  `),"build-page":e=>[`Build the NextBlock page with slug "${e.slug??"<slug>"}" from this brief:`,"",e.brief??"<brief>","","Process:","1. Call get_database_schema and read_current_cms_item (or read_database_records on `pages`) to ground yourself in what exists.",'2. Compose the page from `section` blocks: one column entry per grid track, the first section a hero, alternating none / theme:"muted" / theme:"primary" backgrounds for rhythm. Use discrete heading blocks rather than <h2> inside text HTML.',"3. Call search_stock_media for real photography; copy each photo's attribution fields onto the image block.","4. Write the result with generate_jsonb_layout. It stages a Live Draft — tell the user to preview and publish it."].join(`
4
4
  `),"clone-from-url":e=>[`Rebuild the NextBlock page "${e.slug??"<slug>"}" based on ${e.url??"<url>"}.`,"","Process:","1. Call fetch_url_content on the URL first. Use its headings, text, and mainImage — never invent an image URL.","2. Map the source structure onto NextBlock `section` blocks; do not copy its markup verbatim.","3. Write the result with generate_jsonb_layout so it lands as a reviewable Live Draft."].join(`
5
5
  `),"translate-content":e=>[`Translate the page or post "${e.slug??"<slug>"}" into "${e.languageCode??"<languageCode>"}".`,"","Use the translate_page tool: it copies layout, structure, and imagery automatically and links the copy to the original translation group. Supply only the text translations — every visible string, including headings, paragraph text, button labels, image alt text, and captions. Do not rebuild the layout and do not search for new imagery."].join(`
6
- `)};function j(e){const t=y.find(a=>a.name===e.name),r=N[e.name];return!t||!r?null:{description:t.description,messages:[{content:{text:r(e.args??{}),type:"text"},role:"user"}]}}exports.CORTEX_MCP_PROMPTS=y;exports.CORTEX_MCP_RESOURCES=O;exports.CORTEX_MCP_TOOL_ALIASES=s;exports.CORTEX_MCP_TOOL_KINDS=n;exports.CortexMcpForbiddenToolError=f;exports.CortexMcpUnknownToolError=p;exports.assertCortexMcpToolCoverage=C;exports.buildCortexMcpToolDefinitions=T;exports.callCortexMcpTool=M;exports.cortexMcpScopesAllow=c;exports.getCortexMcpPrompt=j;exports.getCortexMcpToolKind=b;exports.readCortexMcpResource=R;exports.resolveCortexMcpToolName=h;
6
+ `)};function N(e){const t=y.find(a=>a.name===e.name),r=j[e.name];return!t||!r?null:{description:t.description,messages:[{content:{text:r(e.args??{}),type:"text"},role:"user"}]}}exports.CORTEX_MCP_PROMPTS=y;exports.CORTEX_MCP_RESOURCES=O;exports.CORTEX_MCP_TOOL_ALIASES=s;exports.CORTEX_MCP_TOOL_KINDS=n;exports.CortexMcpForbiddenToolError=f;exports.CortexMcpUnknownToolError=p;exports.assertCortexMcpToolCoverage=C;exports.buildCortexMcpToolDefinitions=T;exports.callCortexMcpTool=M;exports.cortexMcpScopesAllow=c;exports.getCortexMcpPrompt=N;exports.getCortexMcpToolKind=b;exports.readCortexMcpResource=R;exports.resolveCortexMcpToolName=h;
@@ -1,4 +1,4 @@
1
- import { createCortexGlobalAgentTools as b } from "./ai-global-agent-tools.es.js";
1
+ import { createCortexGlobalAgentTools as f } from "./ai-global-agent-tools.es.js";
2
2
  import { availableCortexAiBlockTypes as y } from "./block-content-schemas.es.js";
3
3
  import "./zod-config.es.js";
4
4
  import { z as w } from "zod";
@@ -112,7 +112,7 @@ function h(e) {
112
112
  }
113
113
  }
114
114
  function s(e) {
115
- return b(e);
115
+ return f(e);
116
116
  }
117
117
  function M(e) {
118
118
  const t = Object.keys(s(e)), a = Object.keys(o);
@@ -178,10 +178,10 @@ async function O(e) {
178
178
  );
179
179
  }
180
180
  try {
181
- const i = await r.execute(n), c = JSON.stringify(i ?? { success: !0 }, null, 2), l = i && typeof i == "object" && !Array.isArray(i) ? i : null, f = l?.success === !1;
181
+ const i = await r.execute(n), c = JSON.stringify(i ?? { success: !0 }, null, 2), l = i && typeof i == "object" && !Array.isArray(i) ? i : null, b = l?.success === !1;
182
182
  return {
183
183
  content: [{ text: c, type: "text" }],
184
- isError: f,
184
+ isError: b,
185
185
  ...l ? { structuredContent: l } : {}
186
186
  };
187
187
  } catch (i) {
@@ -283,7 +283,7 @@ const C = [
283
283
  "Build the whole NextBlock site for this client.",
284
284
  "",
285
285
  e.brief?.trim() ? `Brief:
286
- ${e.brief}` : "No brief was given: first ask, in one short numbered list, about the business and what it does, the audience and the one action visitors should take, the site shape (one landing page or which pages), the languages, brand colours and tone, contact details, and whether existing content is kept.",
286
+ ${e.brief}` : "A site brief may already be saved (get_site_overview returns it under `brief`): if it is, use it and skip the questions; otherwise ask, in one short numbered list, about the business and what it does, the audience and the one action visitors should take, the site shape (one landing page or which pages), the languages, brand colours and tone, contact details, and whether existing content is kept.",
287
287
  "",
288
288
  "Process:",
289
289
  "1. Call get_site_overview to see what exists, the active languages, and whether the NextBlock demo content is still present. Record what you know with save_site_brief.",