@teleporthq/teleport-plugin-next-workflows 0.43.53 → 0.43.55
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/__tests__/ai-chat-rag-sql-parameterization.test.ts +237 -0
- package/__tests__/ai-embedding-optional.test.ts +77 -0
- package/__tests__/ai-model-capabilities.test.ts +234 -0
- package/__tests__/ai-provider-coverage.test.ts +183 -0
- package/__tests__/cart-clear-db-mirror.test.ts +45 -0
- package/__tests__/cart-get-total-storefront-tax.test.ts +165 -0
- package/__tests__/cron-route-loop-templateparams.test.ts +15 -6
- package/__tests__/data-create-item-order-notification.test.ts +33 -0
- package/__tests__/ecommerce-customhandler-rewriter.test.ts +1 -1
- package/__tests__/internal-request-headers.test.ts +159 -0
- package/__tests__/order-details-route.test.ts +238 -0
- package/__tests__/resolve-config-template-params.test.ts +174 -0
- package/__tests__/utility-nodes.test.ts +27 -11
- package/dist/cjs/api-route-generator.d.ts.map +1 -1
- package/dist/cjs/api-route-generator.js +27 -15
- package/dist/cjs/api-route-generator.js.map +1 -1
- package/dist/cjs/ecommerce/order-details-route.d.ts +18 -0
- package/dist/cjs/ecommerce/order-details-route.d.ts.map +1 -0
- package/dist/cjs/ecommerce/order-details-route.js +172 -0
- package/dist/cjs/ecommerce/order-details-route.js.map +1 -0
- package/dist/cjs/ecommerce-customhandler-rewriter.d.ts +1 -1
- package/dist/cjs/ecommerce-customhandler-rewriter.d.ts.map +1 -1
- package/dist/cjs/ecommerce-customhandler-rewriter.js +20 -4
- package/dist/cjs/ecommerce-customhandler-rewriter.js.map +1 -1
- package/dist/cjs/executor-generator.d.ts.map +1 -1
- package/dist/cjs/executor-generator.js +69 -11
- package/dist/cjs/executor-generator.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-custom-prompt.js +1 -1
- package/dist/cjs/nodes/ai/ai-custom-prompt.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-detect-language.js +1 -1
- package/dist/cjs/nodes/ai/ai-detect-language.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-generate-text-embedding.d.ts.map +1 -1
- package/dist/cjs/nodes/ai/ai-generate-text-embedding.js +47 -4
- package/dist/cjs/nodes/ai/ai-generate-text-embedding.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-provider-utils.d.ts +2 -0
- package/dist/cjs/nodes/ai/ai-provider-utils.d.ts.map +1 -1
- package/dist/cjs/nodes/ai/ai-provider-utils.js +195 -106
- package/dist/cjs/nodes/ai/ai-provider-utils.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-sentiment-analysis.js +1 -1
- package/dist/cjs/nodes/ai/ai-sentiment-analysis.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-summarization.js +1 -1
- package/dist/cjs/nodes/ai/ai-summarization.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-text-classifier.js +1 -1
- package/dist/cjs/nodes/ai/ai-text-classifier.js.map +1 -1
- package/dist/cjs/nodes/ai/ai-text-transform.js +1 -1
- package/dist/cjs/nodes/ai/ai-text-transform.js.map +1 -1
- package/dist/cjs/nodes/cart/cart-clear.d.ts.map +1 -1
- package/dist/cjs/nodes/cart/cart-clear.js +40 -0
- package/dist/cjs/nodes/cart/cart-clear.js.map +1 -1
- package/dist/cjs/nodes/cart/cart-get-total.d.ts.map +1 -1
- package/dist/cjs/nodes/cart/cart-get-total.js +56 -15
- package/dist/cjs/nodes/cart/cart-get-total.js.map +1 -1
- package/dist/cjs/nodes/data/data-count.d.ts.map +1 -1
- package/dist/cjs/nodes/data/data-count.js +6 -1
- package/dist/cjs/nodes/data/data-count.js.map +1 -1
- package/dist/cjs/nodes/data/data-create-item.d.ts.map +1 -1
- package/dist/cjs/nodes/data/data-create-item.js +45 -9
- package/dist/cjs/nodes/data/data-create-item.js.map +1 -1
- package/dist/cjs/nodes/data/data-delete-item.d.ts.map +1 -1
- package/dist/cjs/nodes/data/data-delete-item.js +7 -4
- package/dist/cjs/nodes/data/data-delete-item.js.map +1 -1
- package/dist/cjs/nodes/data/data-raw-query.d.ts.map +1 -1
- package/dist/cjs/nodes/data/data-raw-query.js +7 -1
- package/dist/cjs/nodes/data/data-raw-query.js.map +1 -1
- package/dist/cjs/nodes/data/data-select.d.ts.map +1 -1
- package/dist/cjs/nodes/data/data-select.js +6 -1
- package/dist/cjs/nodes/data/data-select.js.map +1 -1
- package/dist/cjs/nodes/data/data-update-item.d.ts.map +1 -1
- package/dist/cjs/nodes/data/data-update-item.js +7 -4
- package/dist/cjs/nodes/data/data-update-item.js.map +1 -1
- package/dist/cjs/nodes/utility/utility-hybrid-search.js +2 -2
- package/dist/cjs/nodes/utility/utility-hybrid-search.js.map +1 -1
- package/dist/cjs/nodes/utility/utility-semantic-search.js +1 -1
- package/dist/cjs/nodes/utility/utility-semantic-search.js.map +1 -1
- package/dist/cjs/nodes/utility/utility-similarity-scoring.d.ts.map +1 -1
- package/dist/cjs/nodes/utility/utility-similarity-scoring.js +49 -3
- package/dist/cjs/nodes/utility/utility-similarity-scoring.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
- package/dist/cjs/workflow-project-plugin.js +10 -4
- package/dist/cjs/workflow-project-plugin.js.map +1 -1
- package/dist/esm/api-route-generator.d.ts.map +1 -1
- package/dist/esm/api-route-generator.js +27 -15
- package/dist/esm/api-route-generator.js.map +1 -1
- package/dist/esm/ecommerce/order-details-route.d.ts +18 -0
- package/dist/esm/ecommerce/order-details-route.d.ts.map +1 -0
- package/dist/esm/ecommerce/order-details-route.js +167 -0
- package/dist/esm/ecommerce/order-details-route.js.map +1 -0
- package/dist/esm/ecommerce-customhandler-rewriter.d.ts +1 -1
- package/dist/esm/ecommerce-customhandler-rewriter.d.ts.map +1 -1
- package/dist/esm/ecommerce-customhandler-rewriter.js +20 -4
- package/dist/esm/ecommerce-customhandler-rewriter.js.map +1 -1
- package/dist/esm/executor-generator.d.ts.map +1 -1
- package/dist/esm/executor-generator.js +69 -11
- package/dist/esm/executor-generator.js.map +1 -1
- package/dist/esm/nodes/ai/ai-custom-prompt.js +1 -1
- package/dist/esm/nodes/ai/ai-custom-prompt.js.map +1 -1
- package/dist/esm/nodes/ai/ai-detect-language.js +1 -1
- package/dist/esm/nodes/ai/ai-detect-language.js.map +1 -1
- package/dist/esm/nodes/ai/ai-generate-text-embedding.d.ts.map +1 -1
- package/dist/esm/nodes/ai/ai-generate-text-embedding.js +47 -4
- package/dist/esm/nodes/ai/ai-generate-text-embedding.js.map +1 -1
- package/dist/esm/nodes/ai/ai-provider-utils.d.ts +2 -0
- package/dist/esm/nodes/ai/ai-provider-utils.d.ts.map +1 -1
- package/dist/esm/nodes/ai/ai-provider-utils.js +194 -105
- package/dist/esm/nodes/ai/ai-provider-utils.js.map +1 -1
- package/dist/esm/nodes/ai/ai-sentiment-analysis.js +1 -1
- package/dist/esm/nodes/ai/ai-sentiment-analysis.js.map +1 -1
- package/dist/esm/nodes/ai/ai-summarization.js +1 -1
- package/dist/esm/nodes/ai/ai-summarization.js.map +1 -1
- package/dist/esm/nodes/ai/ai-text-classifier.js +1 -1
- package/dist/esm/nodes/ai/ai-text-classifier.js.map +1 -1
- package/dist/esm/nodes/ai/ai-text-transform.js +1 -1
- package/dist/esm/nodes/ai/ai-text-transform.js.map +1 -1
- package/dist/esm/nodes/cart/cart-clear.d.ts.map +1 -1
- package/dist/esm/nodes/cart/cart-clear.js +40 -0
- package/dist/esm/nodes/cart/cart-clear.js.map +1 -1
- package/dist/esm/nodes/cart/cart-get-total.d.ts.map +1 -1
- package/dist/esm/nodes/cart/cart-get-total.js +56 -15
- package/dist/esm/nodes/cart/cart-get-total.js.map +1 -1
- package/dist/esm/nodes/data/data-count.d.ts.map +1 -1
- package/dist/esm/nodes/data/data-count.js +6 -1
- package/dist/esm/nodes/data/data-count.js.map +1 -1
- package/dist/esm/nodes/data/data-create-item.d.ts.map +1 -1
- package/dist/esm/nodes/data/data-create-item.js +45 -9
- package/dist/esm/nodes/data/data-create-item.js.map +1 -1
- package/dist/esm/nodes/data/data-delete-item.d.ts.map +1 -1
- package/dist/esm/nodes/data/data-delete-item.js +7 -4
- package/dist/esm/nodes/data/data-delete-item.js.map +1 -1
- package/dist/esm/nodes/data/data-raw-query.d.ts.map +1 -1
- package/dist/esm/nodes/data/data-raw-query.js +7 -1
- package/dist/esm/nodes/data/data-raw-query.js.map +1 -1
- package/dist/esm/nodes/data/data-select.d.ts.map +1 -1
- package/dist/esm/nodes/data/data-select.js +6 -1
- package/dist/esm/nodes/data/data-select.js.map +1 -1
- package/dist/esm/nodes/data/data-update-item.d.ts.map +1 -1
- package/dist/esm/nodes/data/data-update-item.js +7 -4
- package/dist/esm/nodes/data/data-update-item.js.map +1 -1
- package/dist/esm/nodes/utility/utility-hybrid-search.js +2 -2
- package/dist/esm/nodes/utility/utility-hybrid-search.js.map +1 -1
- package/dist/esm/nodes/utility/utility-semantic-search.js +1 -1
- package/dist/esm/nodes/utility/utility-semantic-search.js.map +1 -1
- package/dist/esm/nodes/utility/utility-similarity-scoring.d.ts.map +1 -1
- package/dist/esm/nodes/utility/utility-similarity-scoring.js +49 -3
- package/dist/esm/nodes/utility/utility-similarity-scoring.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
- package/dist/esm/workflow-project-plugin.js +10 -4
- package/dist/esm/workflow-project-plugin.js.map +1 -1
- package/package.json +4 -4
- package/src/api-route-generator.ts +27 -15
- package/src/ecommerce/order-details-route.ts +195 -0
- package/src/ecommerce-customhandler-rewriter.ts +24 -4
- package/src/executor-generator.ts +69 -11
- package/src/nodes/ai/ai-custom-prompt.ts +2 -2
- package/src/nodes/ai/ai-detect-language.ts +2 -2
- package/src/nodes/ai/ai-generate-text-embedding.ts +49 -4
- package/src/nodes/ai/ai-provider-utils.ts +216 -106
- package/src/nodes/ai/ai-sentiment-analysis.ts +2 -2
- package/src/nodes/ai/ai-summarization.ts +2 -2
- package/src/nodes/ai/ai-text-classifier.ts +2 -2
- package/src/nodes/ai/ai-text-transform.ts +2 -2
- package/src/nodes/cart/cart-clear.ts +40 -0
- package/src/nodes/cart/cart-get-total.ts +61 -17
- package/src/nodes/data/data-count.ts +6 -1
- package/src/nodes/data/data-create-item.ts +45 -9
- package/src/nodes/data/data-delete-item.ts +6 -0
- package/src/nodes/data/data-raw-query.ts +8 -1
- package/src/nodes/data/data-select.ts +6 -1
- package/src/nodes/data/data-update-item.ts +6 -0
- package/src/nodes/utility/utility-hybrid-search.ts +2 -2
- package/src/nodes/utility/utility-semantic-search.ts +1 -1
- package/src/nodes/utility/utility-similarity-scoring.ts +56 -3
- package/src/workflow-project-plugin.ts +10 -4
|
@@ -501,6 +501,35 @@ function resolveConfig(config, context) {
|
|
|
501
501
|
resolved[key] = resolveScalarValue(val, context);
|
|
502
502
|
}
|
|
503
503
|
}
|
|
504
|
+
// Component-bodied email nodes carry their merge values as \`templateParams\`
|
|
505
|
+
// and their body/subject as \`{{token}}\` templates. Filling them HERE — the one
|
|
506
|
+
// function every execution path funnels a node config through — is what makes
|
|
507
|
+
// the fill unmissable.
|
|
508
|
+
//
|
|
509
|
+
// It used to be pasted at the individual call sites instead, and it was only
|
|
510
|
+
// ever pasted at three of the sixteen: the client executor, and the loop-body
|
|
511
|
+
// + main loops of the cron/webhook route. The MAIN loop of
|
|
512
|
+
// \`generateServerSegmentAPIRoute\` — which is where every ordinary page
|
|
513
|
+
// workflow's email node actually executes — never had it, so withdrawal
|
|
514
|
+
// confirmations, withdrawal owner notifications, review notifications,
|
|
515
|
+
// order notifications and the password-reset email all shipped with their
|
|
516
|
+
// tokens verbatim: literal "{{customerName}}" in the body, "{{orderNumber}}"
|
|
517
|
+
// in the subject, and \`href="{{resetUrl}}"\` on the reset button (an invalid
|
|
518
|
+
// relative URL, which mail clients drop — so the button had no link at all).
|
|
519
|
+
// The abandoned-cart reminder was the only one that worked, because its send
|
|
520
|
+
// node sits inside a loop body AND on a cron route: the two paths that had
|
|
521
|
+
// the paste.
|
|
522
|
+
//
|
|
523
|
+
// Runs after resolution on purpose: \`templateParams[].value\` is itself a
|
|
524
|
+
// workflow-context ref that the loop above has just resolved.
|
|
525
|
+
if (Array.isArray(resolved.templateParams)) {
|
|
526
|
+
if (typeof resolved.body === 'string') {
|
|
527
|
+
resolved.body = applyTemplateParams(resolved.body, resolved.templateParams);
|
|
528
|
+
}
|
|
529
|
+
if (typeof resolved.subject === 'string') {
|
|
530
|
+
resolved.subject = applyTemplateParams(resolved.subject, resolved.templateParams);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
504
533
|
return resolved;
|
|
505
534
|
}
|
|
506
535
|
|
|
@@ -809,17 +838,9 @@ async function executeNodes(nodes, edges, context, nodeHandlers, workflowConfig,
|
|
|
809
838
|
throw new Error(configError);
|
|
810
839
|
}
|
|
811
840
|
|
|
812
|
-
//
|
|
813
|
-
//
|
|
814
|
-
//
|
|
815
|
-
if (resolvedConfig && Array.isArray(resolvedConfig.templateParams)) {
|
|
816
|
-
if (typeof resolvedConfig.body === 'string') {
|
|
817
|
-
resolvedConfig.body = applyTemplateParams(resolvedConfig.body, resolvedConfig.templateParams);
|
|
818
|
-
}
|
|
819
|
-
if (typeof resolvedConfig.subject === 'string') {
|
|
820
|
-
resolvedConfig.subject = applyTemplateParams(resolvedConfig.subject, resolvedConfig.templateParams);
|
|
821
|
-
}
|
|
822
|
-
}
|
|
841
|
+
// NOTE: the component-bodied email fill used to live here. It now runs
|
|
842
|
+
// inside resolveConfig itself, so every execution path gets it exactly
|
|
843
|
+
// once — see the comment there.
|
|
823
844
|
|
|
824
845
|
if (node.type === 'general-if-statement') {
|
|
825
846
|
const condResult = evaluateCondition(resolvedConfig, context);
|
|
@@ -1217,7 +1238,44 @@ function collectBranchNodes(startId, allNodes, edges, excludeParentId) {
|
|
|
1217
1238
|
return ids;
|
|
1218
1239
|
}
|
|
1219
1240
|
|
|
1241
|
+
/**
|
|
1242
|
+
* Headers a server-side node must send when this deployment calls its OWN API
|
|
1243
|
+
* routes over HTTP (every data node does: \`fetch(__baseUrl + '/api/data/…')\`).
|
|
1244
|
+
*
|
|
1245
|
+
* ⛔ Without them, a deployment behind Vercel Deployment Protection answers its
|
|
1246
|
+
* own request with 401 "Protected deployment". The page renders — the visitor's
|
|
1247
|
+
* browser holds the bypass cookie — but every data node silently returns
|
|
1248
|
+
* \`{ rows: [] }\`, so the app looks alive while nothing reads or writes. On the
|
|
1249
|
+
* shipped AI-chat store this made the whole knowledge base invisible: the RAG
|
|
1250
|
+
* search returned zero rows for every question and the assistant answered "I
|
|
1251
|
+
* don't have enough information in my knowledge base" every single time.
|
|
1252
|
+
*
|
|
1253
|
+
* Two credentials, in order of what actually exists at the time:
|
|
1254
|
+
* - the visitor's own cookies, which already carried them past the protection
|
|
1255
|
+
* to reach this route. Forwarding them makes the self-call exactly as
|
|
1256
|
+
* authorized as the page load was, and nothing more.
|
|
1257
|
+
* - \`VERCEL_AUTOMATION_BYPASS_SECRET\`, the only thing that works when there is
|
|
1258
|
+
* no browser behind the request (a cron trigger, an inbound webhook).
|
|
1259
|
+
*
|
|
1260
|
+
* Same-origin only: these go to \`__baseUrl\`, which is derived from this
|
|
1261
|
+
* request's own host, so no credential is forwarded anywhere else.
|
|
1262
|
+
*/
|
|
1263
|
+
function internalRequestHeaders(req) {
|
|
1264
|
+
const headers = {};
|
|
1265
|
+
if (req && req.headers && req.headers.cookie) {
|
|
1266
|
+
headers.cookie = req.headers.cookie;
|
|
1267
|
+
}
|
|
1268
|
+
const bypassSecret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
|
|
1269
|
+
if (bypassSecret) {
|
|
1270
|
+
headers['x-vercel-protection-bypass'] = bypassSecret;
|
|
1271
|
+
// Tells Vercel not to hand the bypass back to the caller as a cookie.
|
|
1272
|
+
headers['x-vercel-set-bypass-cookie'] = 'false';
|
|
1273
|
+
}
|
|
1274
|
+
return headers;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1220
1277
|
module.exports = {
|
|
1278
|
+
internalRequestHeaders,
|
|
1221
1279
|
resolveValue,
|
|
1222
1280
|
resolveSecret,
|
|
1223
1281
|
resolveConfig,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
|
|
8
8
|
declare function __ai_resolveTextField(val: any): string
|
|
9
9
|
declare function __ai_resolveToken(token: any): string
|
|
10
|
-
declare function
|
|
10
|
+
declare function __ai_resolveProvider(config: any): string
|
|
11
11
|
declare function __ai_clampTemperature(temp: any, provider: string): number
|
|
12
12
|
declare function __ai_callProvider(params: any): Promise<any>
|
|
13
13
|
declare function __ai_handleStreamingCall(
|
|
@@ -40,7 +40,7 @@ async function ai_custom_prompt(
|
|
|
40
40
|
return { error: true, message: err.message, code: 'authentication_error' }
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
const provider =
|
|
43
|
+
const provider = __ai_resolveProvider(config)
|
|
44
44
|
temperature = __ai_clampTemperature(temperature, provider)
|
|
45
45
|
|
|
46
46
|
let systemMessage = config.systemMessage ? __ai_resolveTextField(config.systemMessage) : undefined
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
|
|
8
8
|
declare function __ai_resolveTextField(val: any): string
|
|
9
9
|
declare function __ai_resolveToken(token: any): string
|
|
10
|
-
declare function
|
|
10
|
+
declare function __ai_resolveProvider(config: any): string
|
|
11
11
|
declare function __ai_clampTemperature(temp: any, provider: string): number
|
|
12
12
|
declare function __ai_callProvider(params: any): Promise<any>
|
|
13
13
|
declare function __ai_parseJSON(text: any): any
|
|
@@ -40,7 +40,7 @@ async function ai_detect_language(
|
|
|
40
40
|
return { error: true, message: err.message, code: 'authentication_error' }
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
const provider =
|
|
43
|
+
const provider = __ai_resolveProvider(config)
|
|
44
44
|
const temperature = __ai_clampTemperature(0, provider)
|
|
45
45
|
|
|
46
46
|
let systemPrompt
|
|
@@ -4,17 +4,55 @@ import { generateAIProviderUtils, AI_PROVIDER_DEPENDENCIES } from './ai-provider
|
|
|
4
4
|
declare function __ai_resolveTextField(val: any): string
|
|
5
5
|
declare function __ai_resolveToken(token: any): string
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Text embeddings, always through OpenAI's embeddings API.
|
|
9
|
+
*
|
|
10
|
+
* ## `config.optional`
|
|
11
|
+
*
|
|
12
|
+
* A node result carrying `error: true` is FATAL — `isFatalNodeResult` in the
|
|
13
|
+
* executor throws on it and the whole workflow stops. That is right for a
|
|
14
|
+
* pipeline whose output is the embedding, and wrong for one where the
|
|
15
|
+
* embedding only powers a nice-to-have branch.
|
|
16
|
+
*
|
|
17
|
+
* The AI Assistant Chat is the second case: its retrieval is a hybrid of a
|
|
18
|
+
* vector search and a keyword search running in parallel, and the keyword half
|
|
19
|
+
* answers perfectly well on its own. A chat whose provider is Anthropic or
|
|
20
|
+
* Google may legitimately have no OpenAI key at all (embeddings are OpenAI-only
|
|
21
|
+
* because that is what the knowledge base was indexed with), and that must
|
|
22
|
+
* degrade to keyword-only search rather than break every message.
|
|
23
|
+
*
|
|
24
|
+
* With `optional: true` the node reports failure as data — `skipped: true` plus
|
|
25
|
+
* an empty `embedding` — so downstream nodes can branch on it. Consumers must
|
|
26
|
+
* check `embedding.length` before using it, which the chat's semantic-query
|
|
27
|
+
* builder already does.
|
|
28
|
+
*/
|
|
7
29
|
async function ai_generate_text_embedding(config: any, context: Record<string, unknown>) {
|
|
30
|
+
const optional = config.optional === true
|
|
31
|
+
|
|
32
|
+
function fail(message: string, code: string) {
|
|
33
|
+
if (optional) {
|
|
34
|
+
return {
|
|
35
|
+
embedding: [],
|
|
36
|
+
vectorLiteral: '',
|
|
37
|
+
dimensions: 0,
|
|
38
|
+
skipped: true,
|
|
39
|
+
skipReason: message,
|
|
40
|
+
code,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return { error: true, message, code }
|
|
44
|
+
}
|
|
45
|
+
|
|
8
46
|
const text = __ai_resolveTextField(config.text)
|
|
9
47
|
if (!text) {
|
|
10
|
-
return
|
|
48
|
+
return fail('Text to embed is required', 'missing_text')
|
|
11
49
|
}
|
|
12
50
|
|
|
13
51
|
let token
|
|
14
52
|
try {
|
|
15
53
|
token = __ai_resolveToken(config.token)
|
|
16
54
|
} catch (err: any) {
|
|
17
|
-
return
|
|
55
|
+
return fail(err.message, 'authentication_error')
|
|
18
56
|
}
|
|
19
57
|
|
|
20
58
|
const model = config.model || 'text-embedding-3-small'
|
|
@@ -40,12 +78,19 @@ async function ai_generate_text_embedding(config: any, context: Record<string, u
|
|
|
40
78
|
|
|
41
79
|
const embeddingData = response.data && response.data[0]
|
|
42
80
|
if (!embeddingData || !embeddingData.embedding) {
|
|
43
|
-
return
|
|
81
|
+
return fail('No embedding returned from API', 'empty_response')
|
|
44
82
|
}
|
|
45
83
|
|
|
46
84
|
const usage = response.usage || {}
|
|
47
85
|
return {
|
|
48
86
|
embedding: embeddingData.embedding,
|
|
87
|
+
// pgvector's literal form, ready to bind as a `$N` param and cast with
|
|
88
|
+
// `::vector`. The raw `embedding` array cannot do that job: a JS array
|
|
89
|
+
// bound as a query parameter is serialized as a Postgres ARRAY literal
|
|
90
|
+
// (`{0.1,0.2}`), which no cast turns into a vector. Without this field a
|
|
91
|
+
// vector search has to assemble its SQL in a general-custom-js node —
|
|
92
|
+
// whose output is relayed to the browser, leaking the schema.
|
|
93
|
+
vectorLiteral: '[' + embeddingData.embedding.join(',') + ']',
|
|
49
94
|
model: response.model || model,
|
|
50
95
|
dimensions: embeddingData.embedding.length,
|
|
51
96
|
usage: {
|
|
@@ -54,7 +99,7 @@ async function ai_generate_text_embedding(config: any, context: Record<string, u
|
|
|
54
99
|
},
|
|
55
100
|
}
|
|
56
101
|
} catch (err: any) {
|
|
57
|
-
return
|
|
102
|
+
return fail(err.message || String(err), 'provider_error')
|
|
58
103
|
}
|
|
59
104
|
}
|
|
60
105
|
|