@nextblock-cms/cortex 0.20.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client.cjs.js +1 -1
- package/client.es.js +3 -7
- package/index.cjs.js +1 -1
- package/index.es.js +24 -277
- package/lib/ai-block-generation.cjs.js +3 -4
- package/lib/ai-block-generation.es.js +143 -182
- package/lib/ai-client.cjs.js +1 -1
- package/lib/ai-client.d.ts +1 -1
- package/lib/ai-client.es.js +101 -135
- package/lib/ai-config.cjs.js +1 -1
- package/lib/ai-config.es.js +89 -108
- package/lib/ai-cortex-widget-builder.cjs.js +1 -1
- package/lib/ai-cortex-widget-builder.es.js +56 -70
- package/lib/ai-global-agent-content-ops-tools.cjs.js +1 -1
- package/lib/ai-global-agent-content-ops-tools.d.ts +1943 -68
- package/lib/ai-global-agent-content-ops-tools.es.js +185 -199
- package/lib/ai-global-agent-custom-block-tools.cjs.js +1 -1
- package/lib/ai-global-agent-custom-block-tools.d.ts +2160 -95
- package/lib/ai-global-agent-custom-block-tools.es.js +226 -223
- package/lib/ai-global-agent-db-tools.cjs.js +1 -1
- package/lib/ai-global-agent-db-tools.d.ts +2708 -98
- package/lib/ai-global-agent-db-tools.es.js +1013 -986
- package/lib/ai-global-agent-ecommerce.cjs.js +1 -1
- package/lib/ai-global-agent-ecommerce.es.js +3 -7
- package/lib/ai-global-agent-site-tools.cjs.js +2 -3
- package/lib/ai-global-agent-site-tools.d.ts +10695 -500
- package/lib/ai-global-agent-site-tools.es.js +750 -757
- package/lib/ai-global-agent-theming-tools.cjs.js +1 -3
- package/lib/ai-global-agent-theming-tools.d.ts +2905 -105
- package/lib/ai-global-agent-theming-tools.es.js +326 -396
- package/lib/ai-global-agent-tools.cjs.js +2 -2
- package/lib/ai-global-agent-tools.d.ts +4 -2230
- package/lib/ai-global-agent-tools.es.js +3899 -4328
- package/lib/ai-key-crypto.cjs.js +1 -1
- package/lib/ai-key-crypto.es.js +63 -82
- package/lib/ai-key-verification.cjs.js +1 -1
- package/lib/ai-key-verification.es.js +74 -63
- package/lib/ai-model-catalog.cjs.js +1 -1
- package/lib/ai-model-catalog.es.js +18 -22
- package/lib/ai-model-registry.cjs.js +2 -2
- package/lib/ai-model-registry.es.js +246 -309
- package/lib/ai-seo-metadata.cjs.js +2 -3
- package/lib/ai-seo-metadata.es.js +143 -185
- package/lib/ai-vision.cjs.js +2 -2
- package/lib/ai-vision.d.ts +6 -6
- package/lib/ai-vision.es.js +161 -215
- package/lib/block-content-schemas.cjs.js +1 -1
- package/lib/block-content-schemas.es.js +324 -254
- package/lib/cortex-widget-registry.cjs.js +1 -1
- package/lib/cortex-widget-registry.es.js +35 -43
- package/lib/cortex-widget-schema.cjs.js +2 -3
- package/lib/cortex-widget-schema.es.js +280 -309
- package/lib/editor-document-from-html.cjs.js +1 -1
- package/lib/editor-document-from-html.es.js +334 -278
- package/lib/fetch-host-guard.cjs.js +1 -0
- package/lib/fetch-host-guard.d.ts +2 -0
- package/lib/fetch-host-guard.es.js +30 -0
- package/lib/mcp-server.cjs.js +1 -1
- package/lib/mcp-server.es.js +155 -173
- package/lib/mcp-tokens.cjs.js +1 -1
- package/lib/mcp-tokens.es.js +95 -107
- package/lib/mcp-tool-registry.cjs.js +5 -6
- package/lib/mcp-tool-registry.es.js +533 -411
- package/lib/site-brief.cjs.js +2 -2
- package/lib/site-brief.es.js +102 -108
- package/lib/vision-image-download.cjs.js +1 -0
- package/lib/vision-image-download.d.ts +43 -0
- package/lib/vision-image-download.es.js +120 -0
- package/lib/zod-config.cjs.js +1 -1
- package/lib/zod-config.es.js +5 -6
- package/package.json +8 -8
|
@@ -1,193 +1,151 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import "
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
throw new Error(b);
|
|
1
|
+
import { buildCortexAiRoutingPolicy as e, getHttpStatusCode as t, isOpenRouterRecoverableRoutingError as n, omitUnsupportedCortexAiModelOptions as r, runWithCortexAiModelFallback as i } from "./ai-model-registry.es.js";
|
|
2
|
+
import { z as a } from "./zod-config.es.js";
|
|
3
|
+
import { generateText as o } from "ai";
|
|
4
|
+
//#region libs/cortex/src/lib/ai-seo-metadata.ts
|
|
5
|
+
var s = "Cortex AI SEO metadata generation can only be imported from server-side code.";
|
|
6
|
+
function c() {
|
|
7
|
+
if (typeof window < "u") throw Error(s);
|
|
9
8
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}),
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
},
|
|
21
|
-
function
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const o = n.slice(0, t), i = o.search(/\s\S*$/);
|
|
28
|
-
return (i > 0 ? o.slice(0, i) : o).replace(v, "").trim();
|
|
9
|
+
var l = a.strictObject({
|
|
10
|
+
metaDescription: a.string().trim().min(1),
|
|
11
|
+
metaTitle: a.string().trim().min(1),
|
|
12
|
+
ogDescription: a.string().trim().min(1),
|
|
13
|
+
ogTitle: a.string().trim().min(1)
|
|
14
|
+
}), u = {
|
|
15
|
+
metaDescription: 160,
|
|
16
|
+
metaTitle: 60,
|
|
17
|
+
ogDescription: 200,
|
|
18
|
+
ogTitle: 88
|
|
19
|
+
}, d = 6e3, f = 6e4, p = /[\s.,;:!?‐-―\-/\\|&+*_"'([{·•]+$/;
|
|
20
|
+
function m(e, t) {
|
|
21
|
+
let n = e.trim();
|
|
22
|
+
if (t <= 0) return "";
|
|
23
|
+
if (n.length <= t) return n;
|
|
24
|
+
let r = n.slice(0, t), i = r.search(/\s\S*$/);
|
|
25
|
+
return (i > 0 ? r.slice(0, i) : r).replace(p, "").trim();
|
|
29
26
|
}
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
return null;
|
|
27
|
+
function h(e) {
|
|
28
|
+
let t = e.replace(/```[a-zA-Z0-9]*/g, ""), n = t.indexOf("{");
|
|
29
|
+
if (n === -1) return null;
|
|
30
|
+
let r = 0, i = !1, a = !1;
|
|
31
|
+
for (let e = n; e < t.length; e++) {
|
|
32
|
+
let o = t[e];
|
|
33
|
+
if (i) {
|
|
34
|
+
a ? a = !1 : o === "\\" ? a = !0 : o === "\"" && (i = !1);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (o === "\"") {
|
|
38
|
+
i = !0;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (o === "{") {
|
|
42
|
+
r++;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (o === "}" && (r--, r === 0)) return t.slice(n, e + 1);
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
53
48
|
}
|
|
54
|
-
function
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
49
|
+
function g() {
|
|
50
|
+
let e = u;
|
|
51
|
+
return [
|
|
52
|
+
"You are NextBlock Cortex AI, an SEO metadata writer for a content management system.",
|
|
53
|
+
"Return ONLY a single JSON object. No markdown fences, no commentary, no explanation, no trailing prose.",
|
|
54
|
+
"The object must have exactly these four keys, all strings, all non-empty: \"metaDescription\", \"metaTitle\", \"ogDescription\", \"ogTitle\".",
|
|
55
|
+
"Do not add any other key.",
|
|
56
|
+
`metaTitle must be at most ${e.metaTitle} characters and read as a search-result headline for this specific page.`,
|
|
57
|
+
`metaDescription must be at most ${e.metaDescription} characters, summarise what the page actually delivers, and end as a complete thought.`,
|
|
58
|
+
`ogTitle must be at most ${e.ogTitle} characters and may be slightly more conversational than metaTitle, because it is read on a social card rather than in a results list.`,
|
|
59
|
+
`ogDescription must be at most ${e.ogDescription} characters and should invite a click without over-promising.`,
|
|
60
|
+
"Write plain text. No emoji, no surrounding quotation marks, no HTML, no markdown.",
|
|
61
|
+
"Describe only what the supplied content actually contains. Never invent statistics, prices, dates, awards, or claims that are not in the content.",
|
|
62
|
+
"Never keyword-stuff, never repeat the focus keyword more than twice across all four fields, and never pad a field to reach its character budget."
|
|
63
|
+
].join(" ");
|
|
69
64
|
}
|
|
70
|
-
function
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
].filter(Boolean).join(`
|
|
80
|
-
|
|
81
|
-
`);
|
|
65
|
+
function _(e) {
|
|
66
|
+
return [
|
|
67
|
+
"Write SEO metadata for the following page.",
|
|
68
|
+
e.title ? `Page title: ${e.title}` : null,
|
|
69
|
+
e.siteTitle ? `Site name: ${e.siteTitle}. Do not append the site name to metaTitle; the site appends it separately.` : null,
|
|
70
|
+
e.focusKeyword ? `Focus keyword: ${e.focusKeyword}. Use it naturally in metaTitle and metaDescription, at most once each.` : null,
|
|
71
|
+
e.locale ? `Write every field in this locale: ${e.locale}. Match its conventions for capitalisation and punctuation.` : null,
|
|
72
|
+
`Page content:\n${e.content}`
|
|
73
|
+
].filter(Boolean).join("\n\n");
|
|
82
74
|
}
|
|
83
|
-
function
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
c.metaDescription
|
|
100
|
-
),
|
|
101
|
-
metaTitle: d(
|
|
102
|
-
o.metaTitle,
|
|
103
|
-
c.metaTitle
|
|
104
|
-
),
|
|
105
|
-
ogDescription: d(
|
|
106
|
-
o.ogDescription,
|
|
107
|
-
c.ogDescription
|
|
108
|
-
),
|
|
109
|
-
ogTitle: d(
|
|
110
|
-
o.ogTitle,
|
|
111
|
-
c.ogTitle
|
|
112
|
-
)
|
|
113
|
-
};
|
|
75
|
+
function v(e) {
|
|
76
|
+
let t = h(e);
|
|
77
|
+
if (!t) throw Error("Cortex AI returned no JSON object for the SEO metadata request.");
|
|
78
|
+
let n;
|
|
79
|
+
try {
|
|
80
|
+
n = JSON.parse(t);
|
|
81
|
+
} catch (e) {
|
|
82
|
+
throw Error(`Cortex AI returned invalid JSON for the SEO metadata request: ${e instanceof Error ? e.message : String(e)}`);
|
|
83
|
+
}
|
|
84
|
+
let r = l.parse(n);
|
|
85
|
+
return {
|
|
86
|
+
metaDescription: m(r.metaDescription, u.metaDescription),
|
|
87
|
+
metaTitle: m(r.metaTitle, u.metaTitle),
|
|
88
|
+
ogDescription: m(r.ogDescription, u.ogDescription),
|
|
89
|
+
ogTitle: m(r.ogTitle, u.ogTitle)
|
|
90
|
+
};
|
|
114
91
|
}
|
|
115
|
-
function
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const n = e instanceof Error ? e.message : String(e);
|
|
122
|
-
return /NoContentGenerated|No content generated|Provider returned error|no JSON object|invalid JSON|invalid_type|too_small|unrecognized_keys|Invalid input|aborted|abort|timeout|timed out/i.test(
|
|
123
|
-
n
|
|
124
|
-
);
|
|
92
|
+
function y(e) {
|
|
93
|
+
let r = t(e);
|
|
94
|
+
if (r === 401 || r === 402 || r === 403) return !1;
|
|
95
|
+
if (n(e) || r && r >= 500) return !0;
|
|
96
|
+
let i = e instanceof Error ? e.message : String(e);
|
|
97
|
+
return /NoContentGenerated|No content generated|Provider returned error|no JSON object|invalid JSON|invalid_type|too_small|unrecognized_keys|Invalid input|aborted|abort|timeout|timed out/i.test(i);
|
|
125
98
|
}
|
|
126
|
-
async function
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
return {
|
|
177
|
-
attempts: r.attempts.length,
|
|
178
|
-
credentialSource: o.credentialSource,
|
|
179
|
-
metaDescription: r.result.metaDescription,
|
|
180
|
-
metaTitle: r.result.metaTitle,
|
|
181
|
-
modelId: r.modelId,
|
|
182
|
-
ogDescription: r.result.ogDescription,
|
|
183
|
-
ogTitle: r.result.ogTitle
|
|
184
|
-
};
|
|
99
|
+
async function b(t) {
|
|
100
|
+
c();
|
|
101
|
+
let n = m(t.content, d);
|
|
102
|
+
if (!n) throw Error("Cortex AI SEO metadata generation requires non-empty page content.");
|
|
103
|
+
let { createCortexAiOpenRouterClient: a } = await import("./ai-client.es.js"), s = await a({ apiKey: t.apiKey || void 0 }), l = e({
|
|
104
|
+
credentialSource: s.credentialSource,
|
|
105
|
+
requestedModelId: t.modelId,
|
|
106
|
+
selectedModel: s.modelSelection
|
|
107
|
+
}), u = await i({
|
|
108
|
+
modelIds: l.modelIds,
|
|
109
|
+
shouldRetry: y,
|
|
110
|
+
execute: async (e) => {
|
|
111
|
+
let i = new AbortController(), a = setTimeout(() => i.abort(), f), c = () => i.abort();
|
|
112
|
+
t.abortSignal?.addEventListener("abort", c, { once: !0 }), t.abortSignal?.aborted && i.abort();
|
|
113
|
+
try {
|
|
114
|
+
let a = r({
|
|
115
|
+
abortSignal: i.signal,
|
|
116
|
+
maxOutputTokens: 700,
|
|
117
|
+
maxRetries: 0,
|
|
118
|
+
prompt: _({
|
|
119
|
+
content: n,
|
|
120
|
+
focusKeyword: t.focusKeyword?.trim() || null,
|
|
121
|
+
locale: t.locale?.trim() || null,
|
|
122
|
+
siteTitle: t.siteTitle?.trim() || null,
|
|
123
|
+
title: t.title?.trim() || null
|
|
124
|
+
}),
|
|
125
|
+
instructions: g(),
|
|
126
|
+
temperature: .3
|
|
127
|
+
}, {
|
|
128
|
+
modelId: e,
|
|
129
|
+
modelSelection: l.modelSelection
|
|
130
|
+
});
|
|
131
|
+
return v((await o({
|
|
132
|
+
...a,
|
|
133
|
+
model: s.model(e)
|
|
134
|
+
})).text);
|
|
135
|
+
} finally {
|
|
136
|
+
clearTimeout(a), t.abortSignal?.removeEventListener("abort", c);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
attempts: u.attempts.length,
|
|
142
|
+
credentialSource: s.credentialSource,
|
|
143
|
+
metaDescription: u.result.metaDescription,
|
|
144
|
+
metaTitle: u.result.metaTitle,
|
|
145
|
+
modelId: u.modelId,
|
|
146
|
+
ogDescription: u.result.ogDescription,
|
|
147
|
+
ogTitle: u.result.ogTitle
|
|
148
|
+
};
|
|
185
149
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
c as CORTEX_AI_SEO_METADATA_LENGTH_BUDGETS,
|
|
189
|
-
w as cortexAiSeoMetadataOutputSchema,
|
|
190
|
-
x as extractJsonObject,
|
|
191
|
-
j as generateCortexAiSeoMetadata,
|
|
192
|
-
d as truncateOnWordBoundary
|
|
193
|
-
};
|
|
150
|
+
//#endregion
|
|
151
|
+
export { d as CORTEX_AI_SEO_METADATA_CONTENT_BUDGET, u as CORTEX_AI_SEO_METADATA_LENGTH_BUDGETS, l as cortexAiSeoMetadataOutputSchema, h as extractJsonObject, b as generateCortexAiSeoMetadata, m as truncateOnWordBoundary };
|
package/lib/ai-vision.cjs.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
const e=require("./ai-model-registry.cjs.js"),t=require("./ai-seo-metadata.cjs.js");let n=require("ai");var r=`Cortex AI vision generation can only be imported from server-side code.`;function i(){if(typeof window<`u`)throw Error(r)}var a=[`google/gemma-4-31b-it:free`,`google/gemma-4-26b-a4b-it:free`,`google/gemini-2.5-flash-lite`,`qwen/qwen3-vl-32b-instruct`,`openai/gpt-4o-mini`,`google/gemini-2.5-flash`],o=[/(?:^|\/)[^/]*-vl(?:[-:]|$)/i,/vision/i,/(?:^|\/)gemini-/i,/(?:^|\/)gemma-[3-9]/i,/(?:^|\/)gpt-(?:4o|4\.1|5)/i,/(?:^|\/)claude-/i,/(?:^|\/)llama-4/i,/(?:^|\/)pixtral/i,/(?:^|\/)mistral-(?:small|medium|large)-3/i,/(?:^|\/)nova-(?:lite|pro|premier)/i],s=125,c={max:1e3,min:20},l=6e4,u=new Set([`"`,`'`,`«`,`»`,`‘`,`’`,`‚`,`“`,`”`,`„`,"`"]),d=/^(?:here(?:'s|’s| is)\s+)?(?:the\s+)?alt(?:[-\s]?text)?\s*[:–—-]\s*/i,f=/^(?:this\s+is\s+)?(?:an?|the)?\s*(?:image|photo|photograph|picture|pic|graphic|illustration|rendering|render)\s+(?:of|showing|depicting|that\s+shows)\s+/i;function p(e){let t=new Set,n=[];for(let r of e){let e=r?.trim();e&&!t.has(e)&&(t.add(e),n.push(e))}return n}function m(e){let t=e?.trim();return t?a.includes(t)?!0:o.some(e=>e.test(t)):!1}function h(e){let t=e.requestedModelId?.trim()||null,n=e.selectedModel?.modelId?.trim()||null;return{modelIds:p([t,e.credentialSource!==`env`&&n&&m(n)?n:null,...a])}}function g(e){let t=e.trim();for(;t.length>=2&&u.has(t[0])&&u.has(t[t.length-1]);)t=t.slice(1,-1).trim();return t}function _(e){return!e.endsWith(`.`)||e.endsWith(`...`)||e.endsWith(`…`)?e:(e.match(/[.!?](?=\s|$)/g)||[]).length===1?e.slice(0,-1).trimEnd():e}function v(e,n=125){let r=e.replace(/\s+/g,` `).trim(),i=!1;for(let e=0;e<2;e++){r=g(r);let e=r.replace(d,``);e!==r&&(r=e.trim(),i=!0),r=g(r);let t=r.replace(f,``);t!==r&&(r=t.trim(),i=!0)}return i&&r&&(r=r.charAt(0).toUpperCase()+r.slice(1)),t.truncateOnWordBoundary(_(r),n)}function y(e){let t=e.trim();if(!t)throw Error(`Cortex AI alt text generation requires an image URL.`);let n;try{n=new URL(t)}catch{throw Error(`Cortex AI alt text generation requires an absolute http(s) image URL, received "${t}". A storage key or site-relative path must be resolved to a publicly fetchable URL first, because the model provider downloads the image server-side.`)}if(n.protocol!==`http:`&&n.protocol!==`https:`)throw Error(`Cortex AI alt text generation requires an http(s) image URL, received the "${n.protocol}" scheme.`);return n}function b(e){return[`You are NextBlock Cortex AI, writing the alt attribute for an image on a website.`,`You are writing for a person using a screen reader who cannot see the image at all.`,`Describe only what is visibly present in the image: subjects, their appearance, what they are doing, the setting, and any text that appears in the image.`,`Never state or guess anything you cannot see — no names, no locations, no dates, no brands, no emotions, and no backstory unless they are legible in the image itself.`,`Write one short factual description of at most ${e} characters.`,`Do not begin with "image of", "photo of", "picture of", "graphic of", or any similar phrase; the screen reader already announces that this is an image.`,`Do not add a label such as "Alt text:" and do not wrap the description in quotation marks.`,`Do not keyword-stuff, do not list search terms, and do not repeat a word for emphasis.`,`Return plain text only: one line, no markdown, no HTML, no JSON, no commentary, no alternatives to choose between.`,`If surrounding page context is supplied, use it ONLY to disambiguate what you can already see — for example to choose the right word for an object or to know which product is pictured. Never use it to add detail that is not visible in the image.`].join(` `)}function x(e){return[`Write the alt attribute for this image, at most ${e.maxLength} characters.`,e.context?`Surrounding page context, for disambiguation only: ${e.context}`:null].filter(Boolean).join(`
|
|
2
2
|
|
|
3
|
-
`)}function
|
|
3
|
+
`)}function S(t){let n=e.getHttpStatusCode(t);if(n===401||n===402||n===403)return!1;if(e.isOpenRouterRecoverableRoutingError(t)||n&&n>=500)return!0;let r=t instanceof Error?t.message:String(t);return/NoContentGenerated|No content generated|Provider returned error|empty alt text|image|modality|multimodal|not support|unsupported|aborted|abort|timeout|timed out/i.test(r)}async function C(t){i();let r=y(t.imageUrl),a=Number.isFinite(t.maxLength)?Math.round(t.maxLength):125,o=Math.min(c.max,Math.max(c.min,a)),s=t.context?.replace(/\s+/g,` `).trim()||null,{createCortexAiOpenRouterClient:u}=await Promise.resolve().then(()=>require("./ai-client.cjs.js")),d=await u({apiKey:t.apiKey||void 0}),f=h({credentialSource:d.credentialSource,requestedModelId:t.modelId,selectedModel:d.modelSelection}),{downloadCortexVisionImage:p}=await Promise.resolve().then(()=>require("./vision-image-download.cjs.js")),m=await p(r,{abortSignal:t.abortSignal}),g=[{content:[{text:x({context:s,maxLength:o}),type:`text`},{data:m.data,mediaType:m.mediaType,type:`file`}],role:`user`}],_=await e.runWithCortexAiModelFallback({modelIds:f.modelIds,shouldRetry:S,execute:async r=>{let i=new AbortController,a=setTimeout(()=>i.abort(),l),s=()=>i.abort();t.abortSignal?.addEventListener(`abort`,s,{once:!0}),t.abortSignal?.aborted&&i.abort();try{let t=e.omitUnsupportedCortexAiModelOptions({abortSignal:i.signal,maxOutputTokens:400,maxRetries:0,messages:g,instructions:b(o),temperature:.2},{modelId:r,modelSelection:d.modelSelection}),a=v((await(0,n.generateText)({...t,model:d.model(r)})).text,o);if(!a)throw Error(`Cortex AI returned empty alt text.`);return a}finally{clearTimeout(a),t.abortSignal?.removeEventListener(`abort`,s)}}});return{altText:_.result,attempts:_.attempts.length,credentialSource:d.credentialSource,modelId:_.modelId}}exports.CORTEX_AI_DEFAULT_ALT_TEXT_MAX_LENGTH=s,exports.CORTEX_AI_VISION_MODEL_FALLBACK_REGISTRY=a,exports.buildCortexAiVisionRoutingPolicy=h,exports.generateCortexAiAltText=C,exports.isKnownVisionCapableCortexAiModelId=m,exports.normalizeGeneratedAltText=v;
|
package/lib/ai-vision.d.ts
CHANGED
|
@@ -122,12 +122,12 @@ export interface GenerateAltTextResult {
|
|
|
122
122
|
/**
|
|
123
123
|
* Generate an `alt` attribute for an image by actually looking at it.
|
|
124
124
|
*
|
|
125
|
-
* The image is
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
125
|
+
* The image is downloaded once by `downloadCortexVisionImage` (DNS-pinned, private
|
|
126
|
+
* addresses refused, capped at CORTEX_AI_VISION_MAX_IMAGE_BYTES) and attached as an AI SDK
|
|
127
|
+
* file part with its bytes inside a user message. Two consequences are worth knowing at the
|
|
128
|
+
* call site: the URL must be publicly fetchable from the server, and a very large source
|
|
129
|
+
* image inflates the request body on every attempt in the fallback chain, because the
|
|
130
|
+
* provider receives it inline as base64. Passing a resized or CDN-transformed URL is
|
|
131
131
|
* therefore materially cheaper than passing the original upload.
|
|
132
132
|
*/
|
|
133
133
|
export declare function generateCortexAiAltText(params: GenerateAltTextParams): Promise<GenerateAltTextResult>;
|