Skip to content

Commit cf7bd63

Browse files
committed
fix vectorDBInstance not returning texts properly.
support mode embedding models for Google Gemini. add vectordb documentation
1 parent 3d1410e commit cf7bd63

File tree

7 files changed

+405
-98
lines changed

7 files changed

+405
-98
lines changed

examples/01-agent-code-skill/04.1-chat-planner-coder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Agent, Chat, Component, Model, TAgentMode, TLLMEvent } from '@smythos/sdk';
22
import chalk from 'chalk';
33
import * as readline from 'readline';
4-
import { EmitUnit, PluginBase, TokenLoom } from 'tokenloom';
4+
import { EmitUnit, PluginAPI, PluginBase, TokenLoom } from 'tokenloom';
55

66
//Show the tasks list and status to the user at every step before performing the tasks, and also give a tasks status summary after tasks.
77
//When you display the tasks list to a user show it in a concise way with a summary and checkboxes for each task.

examples/05-VectorDB-with-agent/01-upsert-and-search.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const pineconeSettings = {
1616
indexName: 'demo-vec',
1717
apiKey: process.env.PINECONE_API_KEY,
1818
embeddings: Model.OpenAI('text-embedding-3-large'),
19+
//you can also use Model.GoogleAI('gemini-embedding-001', { dimensions: 1024 })
1920
};
2021

2122
async function createAgent() {

examples/06-Storage-no-agent/01-localstorage.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,14 @@ import { Storage } from '@smythos/sdk';
22

33
async function main() {
44
const localStorage = Storage.LocalStorage();
5-
5+
66
await localStorage.write('test.txt', 'Hello, world!');
77

88
const data = await localStorage.read('test.txt');
99

1010
const dataAsString = data.toString();
1111

1212
console.log(dataAsString);
13-
14-
1513
}
1614

17-
main();
15+
main();
Lines changed: 52 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,71 @@
11
// Global type declarations for Node.js environment
22
declare global {
3-
namespace NodeJS {
4-
interface ProcessEnv {
5-
PORT?: string;
6-
ZOOM_SECRET_TOKEN?: string;
7-
ZOOM_CLIENT_ID?: string;
8-
ZOOM_CLIENT_SECRET?: string;
9-
WEBHOOK_PATH?: string;
10-
OPENAI_API_KEY?: string;
11-
ANTHROPIC_API_KEY?: string;
12-
PINECONE_API_KEY?: string;
13-
PINECONE_INDEX_NAME?: string;
14-
AWS_ACCESS_KEY_ID?: string;
15-
AWS_SECRET_ACCESS_KEY?: string;
16-
AWS_REGION?: string;
17-
AWS_S3_BUCKET?: string;
18-
LOG_LEVEL?: string;
3+
namespace NodeJS {
4+
interface ProcessEnv {
5+
PORT?: string;
6+
ZOOM_SECRET_TOKEN?: string;
7+
ZOOM_CLIENT_ID?: string;
8+
ZOOM_CLIENT_SECRET?: string;
9+
WEBHOOK_PATH?: string;
10+
OPENAI_API_KEY?: string;
11+
ANTHROPIC_API_KEY?: string;
12+
PINECONE_API_KEY?: string;
13+
PINECONE_INDEX_NAME?: string;
14+
AWS_ACCESS_KEY_ID?: string;
15+
AWS_SECRET_ACCESS_KEY?: string;
16+
AWS_REGION?: string;
17+
AWS_S3_BUCKET?: string;
18+
LOG_LEVEL?: string;
19+
}
1920
}
20-
}
2121

22-
var process: NodeJS.Process;
23-
var console: Console;
24-
var Buffer: BufferConstructor;
25-
}
26-
27-
// Module declarations for packages that might not have types
28-
declare module '@smythos/sdk' {
29-
export class Agent {
30-
constructor(config: any);
31-
addSkill(skill: any): void;
32-
prompt(message: string): Promise<string>;
33-
llm: any;
34-
storage: any;
35-
vectordb: any;
36-
}
37-
38-
export class Model {
39-
static OpenAI(model: string): any;
40-
static Anthropic(model: string): any;
41-
}
22+
var process: NodeJS.Process;
23+
var console: Console;
24+
var Buffer: BufferConstructor;
4225
}
4326

4427
declare module 'crypto' {
45-
export function createHmac(algorithm: string, key: string): any;
28+
export function createHmac(algorithm: string, key: string): any;
4629
}
4730

4831
declare module 'ws' {
49-
export default class WebSocket {
50-
constructor(url: string, options?: any);
51-
on(event: string, callback: Function): void;
52-
send(data: string): void;
53-
close(): void;
54-
}
32+
export default class WebSocket {
33+
constructor(url: string, options?: any);
34+
on(event: string, callback: Function): void;
35+
send(data: string): void;
36+
close(): void;
37+
}
5538
}
5639

5740
declare module 'express' {
58-
export interface Request {
59-
body: any;
60-
}
61-
62-
export interface Response {
63-
json(data: any): void;
64-
sendStatus(code: number): void;
65-
}
66-
67-
interface Express {
68-
use(middleware: any): void;
69-
post(path: string, handler: any): void;
70-
get(path: string, handler: any): void;
71-
listen(port: string | number, callback?: () => void): void;
72-
}
73-
74-
interface ExpressStatic {
75-
(): Express;
76-
json(): any;
77-
}
78-
79-
const express: ExpressStatic;
80-
export default express;
81-
export { Request, Response };
41+
export interface Request {
42+
body: any;
43+
}
44+
45+
export interface Response {
46+
json(data: any): void;
47+
sendStatus(code: number): void;
48+
}
49+
50+
interface Express {
51+
use(middleware: any): void;
52+
post(path: string, handler: any): void;
53+
get(path: string, handler: any): void;
54+
listen(port: string | number, callback?: () => void): void;
55+
}
56+
57+
interface ExpressStatic {
58+
(): Express;
59+
json(): any;
60+
}
61+
62+
const express: ExpressStatic;
63+
export default express;
64+
export { Request, Response };
8265
}
8366

8467
declare module 'dotenv' {
85-
export function config(): void;
68+
export function config(): void;
8669
}
8770

8871
export {};

packages/core/src/subsystems/IO/VectorDB.service/embed/GoogleEmbedding.ts

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { GoogleGenerativeAI } from '@google/generative-ai';
1+
import { GoogleGenAI } from '@google/genai';
22
import { BaseEmbedding, TEmbeddings } from './BaseEmbedding';
33
import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
44
import { getLLMCredentials } from '@sre/LLMManager/LLM.service/LLMCredentials.helper';
@@ -7,9 +7,10 @@ import { TLLMCredentials, TLLMModel, BasicCredentials } from '@sre/types/LLM.typ
77
const DEFAULT_MODEL = 'gemini-embedding-001';
88

99
export class GoogleEmbeds extends BaseEmbedding {
10-
protected client: GoogleGenerativeAI;
10+
protected client: GoogleGenAI;
1111

12-
public static models = ['gemini-embedding-001'];
12+
// Keep in sync with Gemini API supported embedding models
13+
public static models = ['gemini-embedding-001', 'text-embedding-005', 'text-multilingual-embedding-002'];
1314
public canSpecifyDimensions = true;
1415

1516
constructor(private settings?: Partial<TEmbeddings>) {
@@ -43,7 +44,7 @@ export class GoogleEmbeds extends BaseEmbedding {
4344

4445
protected async embed(texts: string[], candidate: AccessCandidate): Promise<number[][]> {
4546
let apiKey: string | undefined;
46-
47+
4748
// Try to get from credentials first
4849
try {
4950
const modelInfo: TLLMModel = {
@@ -56,37 +57,62 @@ export class GoogleEmbeds extends BaseEmbedding {
5657
} catch (e) {
5758
// If credential system fails, fall back to environment variable
5859
}
59-
60+
6061
// Fall back to environment variable if not found in credentials
6162
if (!apiKey) {
6263
apiKey = process.env.GOOGLE_AI_API_KEY;
6364
}
64-
65+
6566
if (!apiKey) {
6667
throw new Error('Please provide an API key for Google AI embeddings via credentials or GOOGLE_AI_API_KEY environment variable');
6768
}
6869

6970
if (!this.client) {
70-
this.client = new GoogleGenerativeAI(apiKey);
71+
this.client = new GoogleGenAI({ apiKey });
7172
}
7273

7374
try {
74-
const model = this.client.getGenerativeModel({ model: this.model });
75-
76-
const embeddings: number[][] = [];
77-
78-
for (const text of texts) {
79-
const result = await model.embedContent(text);
80-
if (result?.embedding?.values) {
81-
embeddings.push(result.embedding.values);
82-
} else {
83-
throw new Error('Invalid embedding response from Google AI');
84-
}
85-
}
86-
87-
return embeddings;
75+
const outputDimensionality = this.dimensions && Number.isFinite(this.dimensions) ? this.dimensions : undefined;
76+
77+
// Batch request using the new SDK
78+
const res = await this.client.models.embedContent({
79+
model: this.model,
80+
contents: texts,
81+
...(outputDimensionality ? { outputDimensionality } : {}),
82+
});
83+
84+
// The SDK can return either { embedding } for single or { embeddings } for batch
85+
const vectors: number[][] = Array.isArray((res as any).embeddings)
86+
? (res as any).embeddings.map((e: any) => e.values as number[])
87+
: [((res as any).embedding?.values as number[]) || []];
88+
89+
// Enforce dimensions and normalization when requested or when non-3072
90+
const targetDim = outputDimensionality;
91+
const processed = vectors.map((v) => this.postProcessEmbedding(v, targetDim));
92+
93+
return processed;
8894
} catch (e) {
8995
throw new Error(`Google Embeddings API error: ${e.message || e}`);
9096
}
9197
}
92-
}
98+
99+
private postProcessEmbedding(values: number[], targetDim?: number): number[] {
100+
let v = Array.isArray(values) ? values.slice() : [];
101+
if (targetDim && targetDim > 0) {
102+
if (v.length > targetDim) {
103+
// SDK ignored smaller dimension: truncate
104+
v = v.slice(0, targetDim);
105+
} else if (v.length < targetDim) {
106+
// SDK returned shorter vector: pad with zeros
107+
v = v.concat(Array(targetDim - v.length).fill(0));
108+
}
109+
}
110+
// Normalize for non-default 3072 dims (recommended by Google docs)
111+
const needNormalize = (targetDim && targetDim !== 3072) || (!targetDim && v.length !== 3072);
112+
if (needNormalize && v.length > 0) {
113+
const norm = Math.sqrt(v.reduce((acc, x) => acc + x * x, 0));
114+
if (norm > 0) v = v.map((x) => x / norm);
115+
}
116+
return v;
117+
}
118+
}

0 commit comments

Comments
 (0)