@agent-native/creative-context 0.5.4 → 0.5.6

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,7 +1,2 @@
1
- import type { EmbeddingFamily } from "./types.js";
2
- export declare function createGeminiEmbeddingFamily(apiKey: string, dimensions?: number): EmbeddingFamily;
3
- export declare function createCohereEmbeddingFamily(apiKey: string, dimensions?: number): EmbeddingFamily;
4
- export declare function createVoyageEmbeddingFamily(apiKey: string): EmbeddingFamily;
5
- export declare function availableEmbeddingFamilies(): Promise<EmbeddingFamily[]>;
6
- export declare function defaultEmbeddingFamily(families: readonly EmbeddingFamily[]): EmbeddingFamily | null;
1
+ export * from "@agent-native/core/embeddings";
7
2
  //# sourceMappingURL=providers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/embeddings/providers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,YAAY,CAAC;AAkEpB,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,EACd,UAAU,SAAqB,GAC9B,eAAe,CAsCjB;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,EACd,UAAU,SAAqB,GAC9B,eAAe,CA6CjB;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAyC3E;AAED,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAW7E;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,SAAS,eAAe,EAAE,GACnC,eAAe,GAAG,IAAI,CAExB"}
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/embeddings/providers.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC"}
@@ -1,176 +1,2 @@
1
- import { readBoundedResponseBytes } from "@agent-native/core/ingestion";
2
- import { resolveSecret } from "@agent-native/core/server";
3
- const DEFAULT_DIMENSIONS = 1024;
4
- function dataUrl(image) {
5
- return `data:${image.mimeType};base64,${image.base64}`;
6
- }
7
- function normalizedInput(input) {
8
- const text = input.text?.trim();
9
- const images = input.images ?? [];
10
- if (!text && images.length === 0) {
11
- throw new Error("Embedding input needs text, an image, or both.");
12
- }
13
- return { text, images };
14
- }
15
- async function postJson(url, headers, body, providerModel) {
16
- const controller = new AbortController();
17
- const timeout = setTimeout(() => controller.abort(), 30_000);
18
- try {
19
- const response = await fetch(url, {
20
- method: "POST",
21
- headers: { "Content-Type": "application/json", ...headers },
22
- body: JSON.stringify(body),
23
- signal: controller.signal,
24
- });
25
- if (!response.ok) {
26
- throw new Error(`Embedding provider ${providerModel} failed with status ${response.status}.`);
27
- }
28
- const bytes = await readBoundedResponseBytes(response, 1_000_000);
29
- return JSON.parse(new TextDecoder().decode(bytes));
30
- }
31
- catch (error) {
32
- if (controller.signal.aborted) {
33
- throw new Error(`Embedding provider ${providerModel} timed out.`);
34
- }
35
- throw error;
36
- }
37
- finally {
38
- clearTimeout(timeout);
39
- }
40
- }
41
- function numberVectors(value) {
42
- if (!Array.isArray(value))
43
- throw new Error("Embedding response was malformed.");
44
- return value.map((vector) => {
45
- if (!Array.isArray(vector) ||
46
- vector.some((entry) => !Number.isFinite(entry))) {
47
- throw new Error("Embedding response contained an invalid vector.");
48
- }
49
- return vector.map(Number);
50
- });
51
- }
52
- export function createGeminiEmbeddingFamily(apiKey, dimensions = DEFAULT_DIMENSIONS) {
53
- const model = "gemini-embedding-2";
54
- return {
55
- id: `gemini:${model}:${dimensions}`,
56
- provider: "gemini",
57
- model,
58
- version: "stable-2026-04",
59
- dimensions,
60
- supportedImageMimeTypes: ["image/png", "image/jpeg"],
61
- async embed(inputs, purpose) {
62
- const vectors = [];
63
- for (const raw of inputs) {
64
- const input = normalizedInput(raw);
65
- const instruction = purpose === "query"
66
- ? "task: search result | query:"
67
- : "title: none | text:";
68
- const parts = [
69
- { text: `${instruction} ${input.text ?? ""}`.trim() },
70
- ...input.images.map((image) => ({
71
- inlineData: { mimeType: image.mimeType, data: image.base64 },
72
- })),
73
- ];
74
- const result = await postJson(`https://generativelanguage.googleapis.com/v1beta/models/${model}:embedContent`, { "x-goog-api-key": apiKey }, {
75
- content: { parts },
76
- output_dimensionality: dimensions,
77
- }, `gemini/${model}`);
78
- const embedding = result.embedding;
79
- vectors.push(...numberVectors([embedding?.values]));
80
- }
81
- return vectors;
82
- },
83
- };
84
- }
85
- export function createCohereEmbeddingFamily(apiKey, dimensions = DEFAULT_DIMENSIONS) {
86
- const model = "embed-v4.0";
87
- return {
88
- id: `cohere:${model}:${dimensions}`,
89
- provider: "cohere",
90
- model,
91
- version: "v4.0",
92
- dimensions,
93
- supportedImageMimeTypes: [
94
- "image/png",
95
- "image/jpeg",
96
- "image/webp",
97
- "image/gif",
98
- ],
99
- async embed(inputs, purpose) {
100
- const contentInputs = inputs.map((raw) => {
101
- const input = normalizedInput(raw);
102
- return {
103
- content: [
104
- ...(input.text ? [{ type: "text", text: input.text }] : []),
105
- ...input.images.map((image) => ({
106
- type: "image_url",
107
- image_url: { url: dataUrl(image) },
108
- })),
109
- ],
110
- };
111
- });
112
- const result = await postJson("https://api.cohere.com/v2/embed", { Authorization: `Bearer ${apiKey}` }, {
113
- model,
114
- inputs: contentInputs,
115
- input_type: purpose === "query" ? "search_query" : "search_document",
116
- embedding_types: ["float"],
117
- output_dimension: dimensions,
118
- }, `cohere/${model}`);
119
- const embeddings = result.embeddings;
120
- return numberVectors(embeddings?.float ?? embeddings?.float_);
121
- },
122
- };
123
- }
124
- export function createVoyageEmbeddingFamily(apiKey) {
125
- const model = "voyage-multimodal-3.5";
126
- return {
127
- id: `voyage:${model}:1024`,
128
- provider: "voyage",
129
- model,
130
- version: "3.5",
131
- dimensions: 1024,
132
- supportedImageMimeTypes: [
133
- "image/png",
134
- "image/jpeg",
135
- "image/webp",
136
- "image/gif",
137
- ],
138
- async embed(inputs, purpose) {
139
- const voyageInputs = inputs.map((raw) => {
140
- const input = normalizedInput(raw);
141
- return {
142
- content: [
143
- ...(input.text ? [{ type: "text", text: input.text }] : []),
144
- ...input.images.map((image) => ({
145
- type: "image_base64",
146
- image_base64: dataUrl(image),
147
- })),
148
- ],
149
- };
150
- });
151
- const result = await postJson("https://api.voyageai.com/v1/multimodalembeddings", { Authorization: `Bearer ${apiKey}` }, {
152
- model,
153
- inputs: voyageInputs,
154
- input_type: purpose,
155
- truncation: true,
156
- }, `voyage/${model}`);
157
- return numberVectors(result.embeddings);
158
- },
159
- };
160
- }
161
- export async function availableEmbeddingFamilies() {
162
- const [gemini, cohere, voyage] = await Promise.all([
163
- resolveSecret("GEMINI_API_KEY").catch(() => null),
164
- resolveSecret("COHERE_API_KEY").catch(() => null),
165
- resolveSecret("VOYAGE_API_KEY").catch(() => null),
166
- ]);
167
- return [
168
- ...(gemini ? [createGeminiEmbeddingFamily(gemini)] : []),
169
- ...(cohere ? [createCohereEmbeddingFamily(cohere)] : []),
170
- ...(voyage ? [createVoyageEmbeddingFamily(voyage)] : []),
171
- ];
172
- }
173
- export function defaultEmbeddingFamily(families) {
174
- return families.length === 1 ? (families[0] ?? null) : null;
175
- }
1
+ export * from "@agent-native/core/embeddings";
176
2
  //# sourceMappingURL=providers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/embeddings/providers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/embeddings/providers.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC"}
@@ -1,19 +1,2 @@
1
- export type EmbeddingInputPurpose = "query" | "document";
2
- export interface EmbeddingImageInput {
3
- mimeType: "image/png" | "image/jpeg" | "image/webp" | "image/gif";
4
- base64: string;
5
- }
6
- export interface MultimodalEmbeddingInput {
7
- text?: string;
8
- images?: EmbeddingImageInput[];
9
- }
10
- export interface EmbeddingFamily {
11
- id: string;
12
- provider: "gemini" | "cohere" | "voyage" | (string & {});
13
- model: string;
14
- version: string;
15
- dimensions: number;
16
- supportedImageMimeTypes?: readonly EmbeddingImageInput["mimeType"][];
17
- embed(inputs: readonly MultimodalEmbeddingInput[], purpose: EmbeddingInputPurpose): Promise<number[][]>;
18
- }
1
+ export type { EmbeddingFamily, EmbeddingImageInput, EmbeddingInputPurpose, MultimodalEmbeddingInput, } from "@agent-native/core/embeddings";
19
2
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/embeddings/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,UAAU,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,WAAW,GAAG,YAAY,GAAG,YAAY,GAAG,WAAW,CAAC;IAClE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB,CAAC,EAAE,SAAS,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC;IACrE,KAAK,CACH,MAAM,EAAE,SAAS,wBAAwB,EAAE,EAC3C,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;CACxB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/embeddings/types.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,+BAA+B,CAAC"}
@@ -1,15 +1,2 @@
1
- export interface RankedCandidate<T> {
2
- key: string;
3
- value: T;
4
- score: number;
5
- reason?: string;
6
- }
7
- export interface FusedCandidate<T> extends RankedCandidate<T> {
8
- laneRanks: Record<string, number>;
9
- reasons: string[];
10
- }
11
- export declare function reciprocalRankFusion<T>(lanes: Readonly<Record<string, readonly RankedCandidate<T>[]>>, options?: {
12
- rankConstant?: number;
13
- limit?: number;
14
- }): FusedCandidate<T>[];
1
+ export * from "@agent-native/core/search";
15
2
  //# sourceMappingURL=fusion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fusion.d.ts","sourceRoot":"","sources":["../../src/search/fusion.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc,CAAC,CAAC,CAAE,SAAQ,eAAe,CAAC,CAAC,CAAC;IAC3D,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAC9D,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GACtD,cAAc,CAAC,CAAC,CAAC,EAAE,CAuBrB"}
1
+ {"version":3,"file":"fusion.d.ts","sourceRoot":"","sources":["../../src/search/fusion.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC"}
@@ -1,25 +1,2 @@
1
- export function reciprocalRankFusion(lanes, options = {}) {
2
- const rankConstant = Math.max(1, options.rankConstant ?? 60);
3
- const fused = new Map();
4
- for (const [lane, candidates] of Object.entries(lanes)) {
5
- candidates.forEach((candidate, index) => {
6
- const rank = index + 1;
7
- const current = fused.get(candidate.key) ?? {
8
- ...candidate,
9
- score: 0,
10
- laneRanks: {},
11
- reasons: [],
12
- };
13
- current.score += 1 / (rankConstant + rank);
14
- current.laneRanks[lane] = rank;
15
- if (candidate.reason && !current.reasons.includes(candidate.reason)) {
16
- current.reasons.push(candidate.reason);
17
- }
18
- fused.set(candidate.key, current);
19
- });
20
- }
21
- return [...fused.values()]
22
- .sort((a, b) => b.score - a.score || a.key.localeCompare(b.key))
23
- .slice(0, Math.max(1, options.limit ?? 40));
24
- }
1
+ export * from "@agent-native/core/search";
25
2
  //# sourceMappingURL=fusion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fusion.js","sourceRoot":"","sources":["../../src/search/fusion.ts"],"names":[],"mappings":"AAYA,MAAM,UAAU,oBAAoB,CAClC,KAA8D,EAC9D,OAAO,GAA8C,EAAE;IAEvD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,IAAI,GAAG,EAA6B,CAAC;IACnD,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACvD,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE;YACtC,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC;YACvB,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI;gBAC1C,GAAG,SAAS;gBACZ,KAAK,EAAE,CAAC;gBACR,SAAS,EAAE,EAAE;gBACb,OAAO,EAAE,EAAE;aACZ,CAAC;YACF,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;YAC3C,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;YAC/B,IAAI,SAAS,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;gBACpE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACzC,CAAC;YACD,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;SACvB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;SAC/D,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;AAChD,CAAC"}
1
+ {"version":3,"file":"fusion.js","sourceRoot":"","sources":["../../src/search/fusion.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC"}
@@ -1,22 +1,2 @@
1
- import type { DbExec } from "@agent-native/core/db";
2
- export interface PostgresFtsHit {
3
- chunkId: string;
4
- itemVersionId: string;
5
- score: number;
6
- }
7
- export declare function ensurePostgresFts(db: DbExec): Promise<boolean>;
8
- export declare function upsertPostgresFtsDocument(db: DbExec, input: {
9
- chunkId: string;
10
- itemVersionId: string;
11
- title: string;
12
- summary?: string | null;
13
- body: string;
14
- updatedAt?: string;
15
- }): Promise<boolean>;
16
- export declare function queryPostgresFts(db: DbExec, input: {
17
- query: string;
18
- allowedChunkIds?: readonly string[];
19
- limit?: number;
20
- }): Promise<PostgresFtsHit[]>;
21
- export declare function deletePostgresFtsDocuments(db: DbExec, chunkIds: readonly string[]): Promise<number>;
1
+ export * from "@agent-native/core/search";
22
2
  //# sourceMappingURL=postgres-fts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"postgres-fts.d.ts","sourceRoot":"","sources":["../../src/search/postgres-fts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAKpD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAcpE;AAED,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,MAAM,EACV,KAAK,EAAE;IACL,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACA,OAAO,CAAC,OAAO,CAAC,CA4BlB;AAED,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE;IACL,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACA,OAAO,CAAC,cAAc,EAAE,CAAC,CAuB3B;AAED,wBAAsB,0BAA0B,CAC9C,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,OAAO,CAAC,MAAM,CAAC,CASjB"}
1
+ {"version":3,"file":"postgres-fts.d.ts","sourceRoot":"","sources":["../../src/search/postgres-fts.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC"}
@@ -1,83 +1,2 @@
1
- import { isPostgres } from "@agent-native/core/db";
2
- const FTS_TABLE = "creative_context_search_documents";
3
- export async function ensurePostgresFts(db) {
4
- if (!isPostgres())
5
- return false;
6
- await db.execute(`
7
- CREATE TABLE IF NOT EXISTS ${FTS_TABLE} (
8
- chunk_id TEXT PRIMARY KEY,
9
- item_version_id TEXT NOT NULL,
10
- document TSVECTOR NOT NULL,
11
- updated_at TEXT NOT NULL
12
- )
13
- `);
14
- await db.execute(`CREATE INDEX IF NOT EXISTS creative_context_search_documents_gin ON ${FTS_TABLE} USING GIN (document)`);
15
- return true;
16
- }
17
- export async function upsertPostgresFtsDocument(db, input) {
18
- if (!(await ensurePostgresFts(db)))
19
- return false;
20
- await db.execute({
21
- sql: `
22
- INSERT INTO ${FTS_TABLE} (chunk_id, item_version_id, document, updated_at)
23
- VALUES (
24
- ?,
25
- ?,
26
- setweight(to_tsvector('simple', ?), 'A') ||
27
- setweight(to_tsvector('simple', ?), 'B') ||
28
- setweight(to_tsvector('simple', ?), 'C'),
29
- ?
30
- )
31
- ON CONFLICT (chunk_id) DO UPDATE SET
32
- item_version_id = EXCLUDED.item_version_id,
33
- document = EXCLUDED.document,
34
- updated_at = EXCLUDED.updated_at
35
- `,
36
- args: [
37
- input.chunkId,
38
- input.itemVersionId,
39
- input.title,
40
- input.summary ?? "",
41
- input.body,
42
- input.updatedAt ?? new Date().toISOString(),
43
- ],
44
- });
45
- return true;
46
- }
47
- export async function queryPostgresFts(db, input) {
48
- if (!isPostgres() || input.allowedChunkIds?.length === 0)
49
- return [];
50
- await ensurePostgresFts(db);
51
- const placeholders = input.allowedChunkIds?.map(() => "?").join(", ");
52
- const accessClause = placeholders ? `chunk_id IN (${placeholders}) AND` : "";
53
- const limit = Math.max(1, Math.min(200, Math.floor(input.limit ?? 40)));
54
- const result = await db.execute({
55
- sql: `
56
- SELECT chunk_id, item_version_id,
57
- ts_rank_cd(document, websearch_to_tsquery('simple', ?)) AS score
58
- FROM ${FTS_TABLE}
59
- WHERE ${accessClause}
60
- document @@ websearch_to_tsquery('simple', ?)
61
- ORDER BY score DESC, chunk_id ASC
62
- LIMIT ?
63
- `,
64
- args: [input.query, ...(input.allowedChunkIds ?? []), input.query, limit],
65
- });
66
- return result.rows.map((row) => ({
67
- chunkId: String(row.chunk_id),
68
- itemVersionId: String(row.item_version_id),
69
- score: Number(row.score),
70
- }));
71
- }
72
- export async function deletePostgresFtsDocuments(db, chunkIds) {
73
- if (!isPostgres() || chunkIds.length === 0)
74
- return 0;
75
- await ensurePostgresFts(db);
76
- const placeholders = chunkIds.map(() => "?").join(", ");
77
- const result = await db.execute({
78
- sql: `DELETE FROM ${FTS_TABLE} WHERE chunk_id IN (${placeholders})`,
79
- args: [...chunkIds],
80
- });
81
- return result.rowsAffected;
82
- }
1
+ export * from "@agent-native/core/search";
83
2
  //# sourceMappingURL=postgres-fts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"postgres-fts.js","sourceRoot":"","sources":["../../src/search/postgres-fts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"postgres-fts.js","sourceRoot":"","sources":["../../src/search/postgres-fts.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC"}
@@ -1,28 +1,2 @@
1
- import type { DbExec } from "@agent-native/core/db";
2
- export declare const PGVECTOR_REQUIRED_MESSAGE = "Visual search requires Postgres with the pgvector extension in the configured DATABASE_URL database.";
3
- export interface PgVectorHit {
4
- vectorKey: string;
5
- embeddingSetId: string;
6
- score: number;
7
- }
8
- export declare function assertPgVectorAvailable(postgres?: boolean): void;
9
- export declare function ensurePgVectorIndex(db: DbExec, dimensions: number, postgres?: boolean): Promise<void>;
10
- export declare function upsertPgVector(db: DbExec, input: {
11
- vectorKey: string;
12
- embeddingSetId: string;
13
- dimensions: number;
14
- vector: readonly number[];
15
- updatedAt?: string;
16
- }, postgres?: boolean): Promise<void>;
17
- export declare function deletePgVectors(db: DbExec, input: {
18
- dimensions: number;
19
- vectorKeys: readonly string[];
20
- }, postgres?: boolean): Promise<number>;
21
- export declare function queryPgVectorIndex(db: DbExec, input: {
22
- embeddingSetId: string;
23
- dimensions: number;
24
- vector: readonly number[];
25
- limit?: number;
26
- allowedVectorKeys: readonly string[];
27
- }, postgres?: boolean): Promise<PgVectorHit[]>;
1
+ export * from "@agent-native/core/search";
28
2
  //# sourceMappingURL=pgvector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pgvector.d.ts","sourceRoot":"","sources":["../../src/vector/pgvector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAGpD,eAAO,MAAM,yBAAyB,yGACkE,CAAC;AAEzG,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf;AA+BD,wBAAgB,uBAAuB,CAAC,QAAQ,UAAe,GAAG,IAAI,CAErE;AAED,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,MAAM,EAClB,QAAQ,UAAe,GACtB,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED,wBAAsB,cAAc,CAClC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,EACD,QAAQ,UAAe,GACtB,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED,wBAAsB,eAAe,CACnC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE;IACL,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B,EACD,QAAQ,UAAe,GACtB,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC,EACD,QAAQ,UAAe,GACtB,OAAO,CAAC,WAAW,EAAE,CAAC,CA+BxB"}
1
+ {"version":3,"file":"pgvector.d.ts","sourceRoot":"","sources":["../../src/vector/pgvector.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC"}
@@ -1,117 +1,2 @@
1
- import { isPostgres } from "@agent-native/core/db";
2
- export const PGVECTOR_REQUIRED_MESSAGE = "Visual search requires Postgres with the pgvector extension in the configured DATABASE_URL database.";
3
- function checkedDimensions(value) {
4
- if (!Number.isInteger(value) || value < 1 || value > 16_000) {
5
- throw new Error("Embedding dimensions must be an integer from 1 to 16000.");
6
- }
7
- return value;
8
- }
9
- function vectorTable(dimensions) {
10
- return `creative_context_vectors_${checkedDimensions(dimensions)}`;
11
- }
12
- function vectorIndex(dimensions) {
13
- return `creative_context_vectors_${checkedDimensions(dimensions)}_hnsw`;
14
- }
15
- function vectorLiteral(vector, dimensions) {
16
- if (vector.length !== dimensions) {
17
- throw new Error(`Embedding has ${vector.length} values; expected ${dimensions}.`);
18
- }
19
- for (const value of vector) {
20
- if (!Number.isFinite(value)) {
21
- throw new Error("Embedding vectors may contain only finite numbers.");
22
- }
23
- }
24
- return `[${vector.join(",")}]`;
25
- }
26
- export function assertPgVectorAvailable(postgres = isPostgres()) {
27
- if (!postgres)
28
- throw new Error(PGVECTOR_REQUIRED_MESSAGE);
29
- }
30
- export async function ensurePgVectorIndex(db, dimensions, postgres = isPostgres()) {
31
- assertPgVectorAvailable(postgres);
32
- const table = vectorTable(dimensions);
33
- const index = vectorIndex(dimensions);
34
- try {
35
- await db.execute("CREATE EXTENSION IF NOT EXISTS vector");
36
- await db.execute(`
37
- CREATE TABLE IF NOT EXISTS ${table} (
38
- vector_key TEXT PRIMARY KEY,
39
- embedding_set_id TEXT NOT NULL,
40
- embedding vector(${checkedDimensions(dimensions)}) NOT NULL,
41
- updated_at TEXT NOT NULL
42
- )
43
- `);
44
- await db.execute(`CREATE INDEX IF NOT EXISTS ${index} ON ${table} USING hnsw (embedding vector_cosine_ops)`);
45
- }
46
- catch (error) {
47
- throw new Error(PGVECTOR_REQUIRED_MESSAGE, { cause: error });
48
- }
49
- }
50
- export async function upsertPgVector(db, input, postgres = isPostgres()) {
51
- assertPgVectorAvailable(postgres);
52
- await ensurePgVectorIndex(db, input.dimensions, postgres);
53
- const table = vectorTable(input.dimensions);
54
- await db.execute({
55
- sql: `
56
- INSERT INTO ${table} (vector_key, embedding_set_id, embedding, updated_at)
57
- VALUES (?, ?, ?::vector, ?)
58
- ON CONFLICT (vector_key) DO UPDATE SET
59
- embedding_set_id = EXCLUDED.embedding_set_id,
60
- embedding = EXCLUDED.embedding,
61
- updated_at = EXCLUDED.updated_at
62
- `,
63
- args: [
64
- input.vectorKey,
65
- input.embeddingSetId,
66
- vectorLiteral(input.vector, input.dimensions),
67
- input.updatedAt ?? new Date().toISOString(),
68
- ],
69
- });
70
- }
71
- export async function deletePgVectors(db, input, postgres = isPostgres()) {
72
- assertPgVectorAvailable(postgres);
73
- if (input.vectorKeys.length === 0)
74
- return 0;
75
- const table = vectorTable(input.dimensions);
76
- const placeholders = input.vectorKeys.map(() => "?").join(", ");
77
- const result = await db.execute({
78
- sql: `DELETE FROM ${table} WHERE vector_key IN (${placeholders})`,
79
- args: [...input.vectorKeys],
80
- });
81
- return result.rowsAffected;
82
- }
83
- export async function queryPgVectorIndex(db, input, postgres = isPostgres()) {
84
- assertPgVectorAvailable(postgres);
85
- const limit = Math.max(1, Math.min(200, Math.floor(input.limit ?? 40)));
86
- const allowed = input.allowedVectorKeys;
87
- if (allowed.length === 0)
88
- return [];
89
- const table = vectorTable(input.dimensions);
90
- const literal = vectorLiteral(input.vector, input.dimensions);
91
- const allowedSql = allowed.length
92
- ? ` AND vector_key IN (${allowed.map(() => "?").join(", ")})`
93
- : "";
94
- try {
95
- await db.execute("SET hnsw.iterative_scan = strict_order");
96
- }
97
- catch {
98
- // pgvector before iterative scans still supports the filtered exact query.
99
- }
100
- const result = await db.execute({
101
- sql: `
102
- SELECT vector_key, embedding_set_id,
103
- 1 - (embedding <=> ?::vector) AS score
104
- FROM ${table}
105
- WHERE embedding_set_id = ?${allowedSql}
106
- ORDER BY embedding <=> ?::vector
107
- LIMIT ?
108
- `,
109
- args: [literal, input.embeddingSetId, ...allowed, literal, limit],
110
- });
111
- return result.rows.map((row) => ({
112
- vectorKey: String(row.vector_key),
113
- embeddingSetId: String(row.embedding_set_id),
114
- score: Number(row.score),
115
- }));
116
- }
1
+ export * from "@agent-native/core/search";
117
2
  //# sourceMappingURL=pgvector.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pgvector.js","sourceRoot":"","sources":["../../src/vector/pgvector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,MAAM,CAAC,MAAM,yBAAyB,GACpC,sGAAsG,CAAC;AAQzG,SAAS,iBAAiB,CAAC,KAAa;IACtC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,MAAM,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,WAAW,CAAC,UAAkB;IACrC,OAAO,4BAA4B,iBAAiB,CAAC,UAAU,CAAC,EAAE,CAAC;AACrE,CAAC;AAED,SAAS,WAAW,CAAC,UAAkB;IACrC,OAAO,4BAA4B,iBAAiB,CAAC,UAAU,CAAC,OAAO,CAAC;AAC1E,CAAC;AAED,SAAS,aAAa,CAAC,MAAyB,EAAE,UAAkB;IAClE,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,iBAAiB,MAAM,CAAC,MAAM,qBAAqB,UAAU,GAAG,CACjE,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,QAAQ,GAAG,UAAU,EAAE;IAC7D,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,EAAU,EACV,UAAkB,EAClB,QAAQ,GAAG,UAAU,EAAE;IAEvB,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC;QAC1D,MAAM,EAAE,CAAC,OAAO,CAAC;mCACc,KAAK;;;2BAGb,iBAAiB,CAAC,UAAU,CAAC;;;KAGnD,CAAC,CAAC;QACH,MAAM,EAAE,CAAC,OAAO,CACd,8BAA8B,KAAK,OAAO,KAAK,2CAA2C,CAC3F,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,yBAAyB,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAU,EACV,KAMC,EACD,QAAQ,GAAG,UAAU,EAAE;IAEvB,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAClC,MAAM,mBAAmB,CAAC,EAAE,EAAE,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,EAAE,CAAC,OAAO,CAAC;QACf,GAAG,EAAE;oBACW,KAAK;;;;;;KAMpB;QACD,IAAI,EAAE;YACJ,KAAK,CAAC,SAAS;YACf,KAAK,CAAC,cAAc;YACpB,aAAa,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC;YAC7C,KAAK,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SAC5C;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,EAAU,EACV,KAGC,EACD,QAAQ,GAAG,UAAU,EAAE;IAEvB,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAClC,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;QAC9B,GAAG,EAAE,eAAe,KAAK,yBAAyB,YAAY,GAAG;QACjE,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC;KAC5B,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,YAAY,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,EAAU,EACV,KAMC,EACD,QAAQ,GAAG,UAAU,EAAE;IAEvB,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,KAAK,CAAC,iBAAiB,CAAC;IACxC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC9D,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM;QAC/B,CAAC,CAAC,uBAAuB,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;QAC7D,CAAC,CAAC,EAAE,CAAC;IACP,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,2EAA2E;IAC7E,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;QAC9B,GAAG,EAAE;;;aAGI,KAAK;kCACgB,UAAU;;;KAGvC;QACD,IAAI,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC;KAClE,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC/B,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;QACjC,cAAc,EAAE,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC;QAC5C,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;KACzB,CAAC,CAAC,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"pgvector.js","sourceRoot":"","sources":["../../src/vector/pgvector.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/creative-context",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "Shared creative context ingestion, versioning, search, brand DNA, and context-pack primitives for agent-native apps.",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -54,8 +54,8 @@
54
54
  "react-dom": "^19.2.7",
55
55
  "typescript-7": "npm:typescript@^7.0.2",
56
56
  "vitest": "^4.1.5",
57
- "@agent-native/toolkit": "0.5.1",
58
- "@agent-native/core": "0.110.0"
57
+ "@agent-native/core": "0.113.0",
58
+ "@agent-native/toolkit": "0.7.0"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@agent-native/core": ">=0.8.0",
@@ -1,228 +1 @@
1
- import { readBoundedResponseBytes } from "@agent-native/core/ingestion";
2
- import { resolveSecret } from "@agent-native/core/server";
3
-
4
- import type {
5
- EmbeddingFamily,
6
- EmbeddingImageInput,
7
- EmbeddingInputPurpose,
8
- MultimodalEmbeddingInput,
9
- } from "./types.js";
10
-
11
- const DEFAULT_DIMENSIONS = 1024;
12
-
13
- function dataUrl(image: EmbeddingImageInput): string {
14
- return `data:${image.mimeType};base64,${image.base64}`;
15
- }
16
-
17
- function normalizedInput(input: MultimodalEmbeddingInput) {
18
- const text = input.text?.trim();
19
- const images = input.images ?? [];
20
- if (!text && images.length === 0) {
21
- throw new Error("Embedding input needs text, an image, or both.");
22
- }
23
- return { text, images };
24
- }
25
-
26
- async function postJson(
27
- url: string,
28
- headers: Record<string, string>,
29
- body: unknown,
30
- providerModel: string,
31
- ): Promise<Record<string, unknown>> {
32
- const controller = new AbortController();
33
- const timeout = setTimeout(() => controller.abort(), 30_000);
34
- try {
35
- const response = await fetch(url, {
36
- method: "POST",
37
- headers: { "Content-Type": "application/json", ...headers },
38
- body: JSON.stringify(body),
39
- signal: controller.signal,
40
- });
41
- if (!response.ok) {
42
- throw new Error(
43
- `Embedding provider ${providerModel} failed with status ${response.status}.`,
44
- );
45
- }
46
- const bytes = await readBoundedResponseBytes(response, 1_000_000);
47
- return JSON.parse(new TextDecoder().decode(bytes)) as Record<
48
- string,
49
- unknown
50
- >;
51
- } catch (error) {
52
- if (controller.signal.aborted) {
53
- throw new Error(`Embedding provider ${providerModel} timed out.`);
54
- }
55
- throw error;
56
- } finally {
57
- clearTimeout(timeout);
58
- }
59
- }
60
-
61
- function numberVectors(value: unknown): number[][] {
62
- if (!Array.isArray(value))
63
- throw new Error("Embedding response was malformed.");
64
- return value.map((vector) => {
65
- if (
66
- !Array.isArray(vector) ||
67
- vector.some((entry) => !Number.isFinite(entry))
68
- ) {
69
- throw new Error("Embedding response contained an invalid vector.");
70
- }
71
- return vector.map(Number);
72
- });
73
- }
74
-
75
- export function createGeminiEmbeddingFamily(
76
- apiKey: string,
77
- dimensions = DEFAULT_DIMENSIONS,
78
- ): EmbeddingFamily {
79
- const model = "gemini-embedding-2";
80
- return {
81
- id: `gemini:${model}:${dimensions}`,
82
- provider: "gemini",
83
- model,
84
- version: "stable-2026-04",
85
- dimensions,
86
- supportedImageMimeTypes: ["image/png", "image/jpeg"],
87
- async embed(inputs, purpose) {
88
- const vectors: number[][] = [];
89
- for (const raw of inputs) {
90
- const input = normalizedInput(raw);
91
- const instruction =
92
- purpose === "query"
93
- ? "task: search result | query:"
94
- : "title: none | text:";
95
- const parts: Record<string, unknown>[] = [
96
- { text: `${instruction} ${input.text ?? ""}`.trim() },
97
- ...input.images.map((image) => ({
98
- inlineData: { mimeType: image.mimeType, data: image.base64 },
99
- })),
100
- ];
101
- const result = await postJson(
102
- `https://generativelanguage.googleapis.com/v1beta/models/${model}:embedContent`,
103
- { "x-goog-api-key": apiKey },
104
- {
105
- content: { parts },
106
- output_dimensionality: dimensions,
107
- },
108
- `gemini/${model}`,
109
- );
110
- const embedding = result.embedding as { values?: unknown } | undefined;
111
- vectors.push(...numberVectors([embedding?.values]));
112
- }
113
- return vectors;
114
- },
115
- };
116
- }
117
-
118
- export function createCohereEmbeddingFamily(
119
- apiKey: string,
120
- dimensions = DEFAULT_DIMENSIONS,
121
- ): EmbeddingFamily {
122
- const model = "embed-v4.0";
123
- return {
124
- id: `cohere:${model}:${dimensions}`,
125
- provider: "cohere",
126
- model,
127
- version: "v4.0",
128
- dimensions,
129
- supportedImageMimeTypes: [
130
- "image/png",
131
- "image/jpeg",
132
- "image/webp",
133
- "image/gif",
134
- ],
135
- async embed(inputs, purpose) {
136
- const contentInputs = inputs.map((raw) => {
137
- const input = normalizedInput(raw);
138
- return {
139
- content: [
140
- ...(input.text ? [{ type: "text", text: input.text }] : []),
141
- ...input.images.map((image) => ({
142
- type: "image_url",
143
- image_url: { url: dataUrl(image) },
144
- })),
145
- ],
146
- };
147
- });
148
- const result = await postJson(
149
- "https://api.cohere.com/v2/embed",
150
- { Authorization: `Bearer ${apiKey}` },
151
- {
152
- model,
153
- inputs: contentInputs,
154
- input_type: purpose === "query" ? "search_query" : "search_document",
155
- embedding_types: ["float"],
156
- output_dimension: dimensions,
157
- },
158
- `cohere/${model}`,
159
- );
160
- const embeddings = result.embeddings as
161
- | { float?: unknown; float_?: unknown }
162
- | undefined;
163
- return numberVectors(embeddings?.float ?? embeddings?.float_);
164
- },
165
- };
166
- }
167
-
168
- export function createVoyageEmbeddingFamily(apiKey: string): EmbeddingFamily {
169
- const model = "voyage-multimodal-3.5";
170
- return {
171
- id: `voyage:${model}:1024`,
172
- provider: "voyage",
173
- model,
174
- version: "3.5",
175
- dimensions: 1024,
176
- supportedImageMimeTypes: [
177
- "image/png",
178
- "image/jpeg",
179
- "image/webp",
180
- "image/gif",
181
- ],
182
- async embed(inputs, purpose) {
183
- const voyageInputs = inputs.map((raw) => {
184
- const input = normalizedInput(raw);
185
- return {
186
- content: [
187
- ...(input.text ? [{ type: "text", text: input.text }] : []),
188
- ...input.images.map((image) => ({
189
- type: "image_base64",
190
- image_base64: dataUrl(image),
191
- })),
192
- ],
193
- };
194
- });
195
- const result = await postJson(
196
- "https://api.voyageai.com/v1/multimodalembeddings",
197
- { Authorization: `Bearer ${apiKey}` },
198
- {
199
- model,
200
- inputs: voyageInputs,
201
- input_type: purpose,
202
- truncation: true,
203
- },
204
- `voyage/${model}`,
205
- );
206
- return numberVectors(result.embeddings);
207
- },
208
- };
209
- }
210
-
211
- export async function availableEmbeddingFamilies(): Promise<EmbeddingFamily[]> {
212
- const [gemini, cohere, voyage] = await Promise.all([
213
- resolveSecret("GEMINI_API_KEY").catch(() => null),
214
- resolveSecret("COHERE_API_KEY").catch(() => null),
215
- resolveSecret("VOYAGE_API_KEY").catch(() => null),
216
- ]);
217
- return [
218
- ...(gemini ? [createGeminiEmbeddingFamily(gemini)] : []),
219
- ...(cohere ? [createCohereEmbeddingFamily(cohere)] : []),
220
- ...(voyage ? [createVoyageEmbeddingFamily(voyage)] : []),
221
- ];
222
- }
223
-
224
- export function defaultEmbeddingFamily(
225
- families: readonly EmbeddingFamily[],
226
- ): EmbeddingFamily | null {
227
- return families.length === 1 ? (families[0] ?? null) : null;
228
- }
1
+ export * from "@agent-native/core/embeddings";
@@ -1,24 +1,6 @@
1
- export type EmbeddingInputPurpose = "query" | "document";
2
-
3
- export interface EmbeddingImageInput {
4
- mimeType: "image/png" | "image/jpeg" | "image/webp" | "image/gif";
5
- base64: string;
6
- }
7
-
8
- export interface MultimodalEmbeddingInput {
9
- text?: string;
10
- images?: EmbeddingImageInput[];
11
- }
12
-
13
- export interface EmbeddingFamily {
14
- id: string;
15
- provider: "gemini" | "cohere" | "voyage" | (string & {});
16
- model: string;
17
- version: string;
18
- dimensions: number;
19
- supportedImageMimeTypes?: readonly EmbeddingImageInput["mimeType"][];
20
- embed(
21
- inputs: readonly MultimodalEmbeddingInput[],
22
- purpose: EmbeddingInputPurpose,
23
- ): Promise<number[][]>;
24
- }
1
+ export type {
2
+ EmbeddingFamily,
3
+ EmbeddingImageInput,
4
+ EmbeddingInputPurpose,
5
+ MultimodalEmbeddingInput,
6
+ } from "@agent-native/core/embeddings";
@@ -1,39 +1 @@
1
- export interface RankedCandidate<T> {
2
- key: string;
3
- value: T;
4
- score: number;
5
- reason?: string;
6
- }
7
-
8
- export interface FusedCandidate<T> extends RankedCandidate<T> {
9
- laneRanks: Record<string, number>;
10
- reasons: string[];
11
- }
12
-
13
- export function reciprocalRankFusion<T>(
14
- lanes: Readonly<Record<string, readonly RankedCandidate<T>[]>>,
15
- options: { rankConstant?: number; limit?: number } = {},
16
- ): FusedCandidate<T>[] {
17
- const rankConstant = Math.max(1, options.rankConstant ?? 60);
18
- const fused = new Map<string, FusedCandidate<T>>();
19
- for (const [lane, candidates] of Object.entries(lanes)) {
20
- candidates.forEach((candidate, index) => {
21
- const rank = index + 1;
22
- const current = fused.get(candidate.key) ?? {
23
- ...candidate,
24
- score: 0,
25
- laneRanks: {},
26
- reasons: [],
27
- };
28
- current.score += 1 / (rankConstant + rank);
29
- current.laneRanks[lane] = rank;
30
- if (candidate.reason && !current.reasons.includes(candidate.reason)) {
31
- current.reasons.push(candidate.reason);
32
- }
33
- fused.set(candidate.key, current);
34
- });
35
- }
36
- return [...fused.values()]
37
- .sort((a, b) => b.score - a.score || a.key.localeCompare(b.key))
38
- .slice(0, Math.max(1, options.limit ?? 40));
39
- }
1
+ export * from "@agent-native/core/search";
@@ -21,20 +21,16 @@ describe("Postgres creative-context FTS", () => {
21
21
  it("filters every Postgres candidate through accessible chunk ids", async () => {
22
22
  isPostgres.mockReturnValue(true);
23
23
  const db = {
24
- execute: vi
25
- .fn()
26
- .mockResolvedValueOnce({ rows: [], rowsAffected: 0 })
27
- .mockResolvedValueOnce({ rows: [], rowsAffected: 0 })
28
- .mockResolvedValueOnce({
29
- rows: [{ chunk_id: "allowed", item_version_id: "v1", score: 0.8 }],
30
- rowsAffected: 0,
31
- }),
24
+ execute: vi.fn().mockResolvedValueOnce({
25
+ rows: [{ chunk_id: "allowed", item_version_id: "v1", score: 0.8 }],
26
+ rowsAffected: 0,
27
+ }),
32
28
  };
33
29
  const hits = await queryPostgresFts(db, {
34
30
  query: "pricing slide",
35
31
  allowedChunkIds: ["allowed"],
36
32
  });
37
- const query = db.execute.mock.calls[2]?.[0] as {
33
+ const query = db.execute.mock.calls[0]?.[0] as {
38
34
  sql: string;
39
35
  args: unknown[];
40
36
  };
@@ -46,19 +42,15 @@ describe("Postgres creative-context FTS", () => {
46
42
  it("can search the global FTS index before access-scoped hydration", async () => {
47
43
  isPostgres.mockReturnValue(true);
48
44
  const db = {
49
- execute: vi
50
- .fn()
51
- .mockResolvedValueOnce({ rows: [], rowsAffected: 0 })
52
- .mockResolvedValueOnce({ rows: [], rowsAffected: 0 })
53
- .mockResolvedValueOnce({
54
- rows: [{ chunk_id: "late", item_version_id: "v9", score: 0.9 }],
55
- rowsAffected: 0,
56
- }),
45
+ execute: vi.fn().mockResolvedValueOnce({
46
+ rows: [{ chunk_id: "late", item_version_id: "v9", score: 0.9 }],
47
+ rowsAffected: 0,
48
+ }),
57
49
  };
58
50
  const hits = await queryPostgresFts(db, {
59
51
  query: "pricing slide",
60
52
  });
61
- const query = db.execute.mock.calls[2]?.[0] as {
53
+ const query = db.execute.mock.calls[0]?.[0] as {
62
54
  sql: string;
63
55
  args: unknown[];
64
56
  };
@@ -1,112 +1 @@
1
- import type { DbExec } from "@agent-native/core/db";
2
- import { isPostgres } from "@agent-native/core/db";
3
-
4
- const FTS_TABLE = "creative_context_search_documents";
5
-
6
- export interface PostgresFtsHit {
7
- chunkId: string;
8
- itemVersionId: string;
9
- score: number;
10
- }
11
-
12
- export async function ensurePostgresFts(db: DbExec): Promise<boolean> {
13
- if (!isPostgres()) return false;
14
- await db.execute(`
15
- CREATE TABLE IF NOT EXISTS ${FTS_TABLE} (
16
- chunk_id TEXT PRIMARY KEY,
17
- item_version_id TEXT NOT NULL,
18
- document TSVECTOR NOT NULL,
19
- updated_at TEXT NOT NULL
20
- )
21
- `);
22
- await db.execute(
23
- `CREATE INDEX IF NOT EXISTS creative_context_search_documents_gin ON ${FTS_TABLE} USING GIN (document)`,
24
- );
25
- return true;
26
- }
27
-
28
- export async function upsertPostgresFtsDocument(
29
- db: DbExec,
30
- input: {
31
- chunkId: string;
32
- itemVersionId: string;
33
- title: string;
34
- summary?: string | null;
35
- body: string;
36
- updatedAt?: string;
37
- },
38
- ): Promise<boolean> {
39
- if (!(await ensurePostgresFts(db))) return false;
40
- await db.execute({
41
- sql: `
42
- INSERT INTO ${FTS_TABLE} (chunk_id, item_version_id, document, updated_at)
43
- VALUES (
44
- ?,
45
- ?,
46
- setweight(to_tsvector('simple', ?), 'A') ||
47
- setweight(to_tsvector('simple', ?), 'B') ||
48
- setweight(to_tsvector('simple', ?), 'C'),
49
- ?
50
- )
51
- ON CONFLICT (chunk_id) DO UPDATE SET
52
- item_version_id = EXCLUDED.item_version_id,
53
- document = EXCLUDED.document,
54
- updated_at = EXCLUDED.updated_at
55
- `,
56
- args: [
57
- input.chunkId,
58
- input.itemVersionId,
59
- input.title,
60
- input.summary ?? "",
61
- input.body,
62
- input.updatedAt ?? new Date().toISOString(),
63
- ],
64
- });
65
- return true;
66
- }
67
-
68
- export async function queryPostgresFts(
69
- db: DbExec,
70
- input: {
71
- query: string;
72
- allowedChunkIds?: readonly string[];
73
- limit?: number;
74
- },
75
- ): Promise<PostgresFtsHit[]> {
76
- if (!isPostgres() || input.allowedChunkIds?.length === 0) return [];
77
- await ensurePostgresFts(db);
78
- const placeholders = input.allowedChunkIds?.map(() => "?").join(", ");
79
- const accessClause = placeholders ? `chunk_id IN (${placeholders}) AND` : "";
80
- const limit = Math.max(1, Math.min(200, Math.floor(input.limit ?? 40)));
81
- const result = await db.execute({
82
- sql: `
83
- SELECT chunk_id, item_version_id,
84
- ts_rank_cd(document, websearch_to_tsquery('simple', ?)) AS score
85
- FROM ${FTS_TABLE}
86
- WHERE ${accessClause}
87
- document @@ websearch_to_tsquery('simple', ?)
88
- ORDER BY score DESC, chunk_id ASC
89
- LIMIT ?
90
- `,
91
- args: [input.query, ...(input.allowedChunkIds ?? []), input.query, limit],
92
- });
93
- return result.rows.map((row) => ({
94
- chunkId: String(row.chunk_id),
95
- itemVersionId: String(row.item_version_id),
96
- score: Number(row.score),
97
- }));
98
- }
99
-
100
- export async function deletePostgresFtsDocuments(
101
- db: DbExec,
102
- chunkIds: readonly string[],
103
- ): Promise<number> {
104
- if (!isPostgres() || chunkIds.length === 0) return 0;
105
- await ensurePostgresFts(db);
106
- const placeholders = chunkIds.map(() => "?").join(", ");
107
- const result = await db.execute({
108
- sql: `DELETE FROM ${FTS_TABLE} WHERE chunk_id IN (${placeholders})`,
109
- args: [...chunkIds],
110
- });
111
- return result.rowsAffected;
112
- }
1
+ export * from "@agent-native/core/search";
@@ -29,7 +29,7 @@ describe("pgvector creative-context lane", () => {
29
29
  expect(String(db.execute.mock.calls[1]?.[0])).toContain(
30
30
  "creative_context_vectors_1024",
31
31
  );
32
- expect(String(db.execute.mock.calls[2]?.[0])).toContain("USING hnsw");
32
+ expect(String(db.execute.mock.calls[3]?.[0])).toContain("USING hnsw");
33
33
  });
34
34
 
35
35
  it("binds vector values and validates the selected dimensions", async () => {
@@ -44,7 +44,7 @@ describe("pgvector creative-context lane", () => {
44
44
  },
45
45
  true,
46
46
  );
47
- const write = db.execute.mock.calls[3]?.[0] as {
47
+ const write = db.execute.mock.calls[5]?.[0] as {
48
48
  sql: string;
49
49
  args: unknown[];
50
50
  };
@@ -68,6 +68,23 @@ describe("pgvector creative-context lane", () => {
68
68
  ).rejects.toThrow("expected 2");
69
69
  });
70
70
 
71
+ it("can write a batch after its namespace and dimensions are provisioned", async () => {
72
+ const db = mockDb();
73
+ await ensurePgVectorIndex(db, 3, true);
74
+ await upsertPgVector(
75
+ db,
76
+ {
77
+ vectorKey: "chunk:1",
78
+ embeddingSetId: "set:1",
79
+ dimensions: 3,
80
+ vector: [0.25, 0.5, 0.75],
81
+ },
82
+ { postgres: true, indexInitialized: true },
83
+ );
84
+ expect(db.execute).toHaveBeenCalledTimes(6);
85
+ expect(String(db.execute.mock.calls[5]?.[0].sql)).toContain("INSERT INTO");
86
+ });
87
+
71
88
  it("limits vector results to access-filtered vector keys", async () => {
72
89
  const db = mockDb([
73
90
  { vector_key: "media:1", embedding_set_id: "set:1", score: 0.91 },
@@ -1,164 +1 @@
1
- import type { DbExec } from "@agent-native/core/db";
2
- import { isPostgres } from "@agent-native/core/db";
3
-
4
- export const PGVECTOR_REQUIRED_MESSAGE =
5
- "Visual search requires Postgres with the pgvector extension in the configured DATABASE_URL database.";
6
-
7
- export interface PgVectorHit {
8
- vectorKey: string;
9
- embeddingSetId: string;
10
- score: number;
11
- }
12
-
13
- function checkedDimensions(value: number): number {
14
- if (!Number.isInteger(value) || value < 1 || value > 16_000) {
15
- throw new Error("Embedding dimensions must be an integer from 1 to 16000.");
16
- }
17
- return value;
18
- }
19
-
20
- function vectorTable(dimensions: number): string {
21
- return `creative_context_vectors_${checkedDimensions(dimensions)}`;
22
- }
23
-
24
- function vectorIndex(dimensions: number): string {
25
- return `creative_context_vectors_${checkedDimensions(dimensions)}_hnsw`;
26
- }
27
-
28
- function vectorLiteral(vector: readonly number[], dimensions: number): string {
29
- if (vector.length !== dimensions) {
30
- throw new Error(
31
- `Embedding has ${vector.length} values; expected ${dimensions}.`,
32
- );
33
- }
34
- for (const value of vector) {
35
- if (!Number.isFinite(value)) {
36
- throw new Error("Embedding vectors may contain only finite numbers.");
37
- }
38
- }
39
- return `[${vector.join(",")}]`;
40
- }
41
-
42
- export function assertPgVectorAvailable(postgres = isPostgres()): void {
43
- if (!postgres) throw new Error(PGVECTOR_REQUIRED_MESSAGE);
44
- }
45
-
46
- export async function ensurePgVectorIndex(
47
- db: DbExec,
48
- dimensions: number,
49
- postgres = isPostgres(),
50
- ): Promise<void> {
51
- assertPgVectorAvailable(postgres);
52
- const table = vectorTable(dimensions);
53
- const index = vectorIndex(dimensions);
54
- try {
55
- await db.execute("CREATE EXTENSION IF NOT EXISTS vector");
56
- await db.execute(`
57
- CREATE TABLE IF NOT EXISTS ${table} (
58
- vector_key TEXT PRIMARY KEY,
59
- embedding_set_id TEXT NOT NULL,
60
- embedding vector(${checkedDimensions(dimensions)}) NOT NULL,
61
- updated_at TEXT NOT NULL
62
- )
63
- `);
64
- await db.execute(
65
- `CREATE INDEX IF NOT EXISTS ${index} ON ${table} USING hnsw (embedding vector_cosine_ops)`,
66
- );
67
- } catch (error) {
68
- throw new Error(PGVECTOR_REQUIRED_MESSAGE, { cause: error });
69
- }
70
- }
71
-
72
- export async function upsertPgVector(
73
- db: DbExec,
74
- input: {
75
- vectorKey: string;
76
- embeddingSetId: string;
77
- dimensions: number;
78
- vector: readonly number[];
79
- updatedAt?: string;
80
- },
81
- postgres = isPostgres(),
82
- ): Promise<void> {
83
- assertPgVectorAvailable(postgres);
84
- await ensurePgVectorIndex(db, input.dimensions, postgres);
85
- const table = vectorTable(input.dimensions);
86
- await db.execute({
87
- sql: `
88
- INSERT INTO ${table} (vector_key, embedding_set_id, embedding, updated_at)
89
- VALUES (?, ?, ?::vector, ?)
90
- ON CONFLICT (vector_key) DO UPDATE SET
91
- embedding_set_id = EXCLUDED.embedding_set_id,
92
- embedding = EXCLUDED.embedding,
93
- updated_at = EXCLUDED.updated_at
94
- `,
95
- args: [
96
- input.vectorKey,
97
- input.embeddingSetId,
98
- vectorLiteral(input.vector, input.dimensions),
99
- input.updatedAt ?? new Date().toISOString(),
100
- ],
101
- });
102
- }
103
-
104
- export async function deletePgVectors(
105
- db: DbExec,
106
- input: {
107
- dimensions: number;
108
- vectorKeys: readonly string[];
109
- },
110
- postgres = isPostgres(),
111
- ): Promise<number> {
112
- assertPgVectorAvailable(postgres);
113
- if (input.vectorKeys.length === 0) return 0;
114
- const table = vectorTable(input.dimensions);
115
- const placeholders = input.vectorKeys.map(() => "?").join(", ");
116
- const result = await db.execute({
117
- sql: `DELETE FROM ${table} WHERE vector_key IN (${placeholders})`,
118
- args: [...input.vectorKeys],
119
- });
120
- return result.rowsAffected;
121
- }
122
-
123
- export async function queryPgVectorIndex(
124
- db: DbExec,
125
- input: {
126
- embeddingSetId: string;
127
- dimensions: number;
128
- vector: readonly number[];
129
- limit?: number;
130
- allowedVectorKeys: readonly string[];
131
- },
132
- postgres = isPostgres(),
133
- ): Promise<PgVectorHit[]> {
134
- assertPgVectorAvailable(postgres);
135
- const limit = Math.max(1, Math.min(200, Math.floor(input.limit ?? 40)));
136
- const allowed = input.allowedVectorKeys;
137
- if (allowed.length === 0) return [];
138
- const table = vectorTable(input.dimensions);
139
- const literal = vectorLiteral(input.vector, input.dimensions);
140
- const allowedSql = allowed.length
141
- ? ` AND vector_key IN (${allowed.map(() => "?").join(", ")})`
142
- : "";
143
- try {
144
- await db.execute("SET hnsw.iterative_scan = strict_order");
145
- } catch {
146
- // pgvector before iterative scans still supports the filtered exact query.
147
- }
148
- const result = await db.execute({
149
- sql: `
150
- SELECT vector_key, embedding_set_id,
151
- 1 - (embedding <=> ?::vector) AS score
152
- FROM ${table}
153
- WHERE embedding_set_id = ?${allowedSql}
154
- ORDER BY embedding <=> ?::vector
155
- LIMIT ?
156
- `,
157
- args: [literal, input.embeddingSetId, ...allowed, literal, limit],
158
- });
159
- return result.rows.map((row) => ({
160
- vectorKey: String(row.vector_key),
161
- embeddingSetId: String(row.embedding_set_id),
162
- score: Number(row.score),
163
- }));
164
- }
1
+ export * from "@agent-native/core/search";