agentlang 0.9.7 → 0.9.8
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/out/runtime/module.d.ts +19 -0
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +81 -2
- package/out/runtime/module.js.map +1 -1
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +21 -4
- package/out/runtime/modules/ai.js.map +1 -1
- package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/database.js +60 -15
- package/out/runtime/resolvers/sqldb/database.js.map +1 -1
- package/package.json +1 -1
- package/src/runtime/module.ts +100 -1
- package/src/runtime/modules/ai.ts +26 -3
- package/src/runtime/resolvers/sqldb/database.ts +66 -17
package/src/runtime/module.ts
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
DefaultModules,
|
|
32
32
|
encryptPassword,
|
|
33
33
|
escapeFqName,
|
|
34
|
+
escapeSpecialChars,
|
|
34
35
|
findAllPrePostTriggerSchema,
|
|
35
36
|
findMetaSchema,
|
|
36
37
|
findUqCompositeAttributes,
|
|
@@ -1161,7 +1162,16 @@ export class Agent extends Record {
|
|
|
1161
1162
|
if (!skip && value !== null && value !== undefined) {
|
|
1162
1163
|
let v = value;
|
|
1163
1164
|
const isf = key == 'flows';
|
|
1164
|
-
|
|
1165
|
+
const isDocs = key == 'documents';
|
|
1166
|
+
if (isDocs) {
|
|
1167
|
+
const raw = isString(v) ? v : `${v}`;
|
|
1168
|
+
const items = raw
|
|
1169
|
+
.split(',')
|
|
1170
|
+
.map((entry: string) => entry.trim())
|
|
1171
|
+
.filter((entry: string) => entry.length > 0)
|
|
1172
|
+
.map((entry: string) => entry.replace(/\\/g, '\\\\').replace(/"/g, '\\"'));
|
|
1173
|
+
v = `[${items.map((entry: string) => `"${entry}"`).join(', ')}]`;
|
|
1174
|
+
} else if (isf || key == 'tools') {
|
|
1165
1175
|
if (isf || v.indexOf(',') > 0 || v.indexOf('/') > 0) v = `[${v}]`;
|
|
1166
1176
|
else v = `"${v}"`;
|
|
1167
1177
|
} else if (isString(v)) {
|
|
@@ -1885,6 +1895,42 @@ export class GlossaryEntry extends ModuleEntry {
|
|
|
1885
1895
|
}
|
|
1886
1896
|
}
|
|
1887
1897
|
|
|
1898
|
+
export type ModuleDocument = {
|
|
1899
|
+
title: string;
|
|
1900
|
+
url: string;
|
|
1901
|
+
};
|
|
1902
|
+
|
|
1903
|
+
export class DocumentEntry extends ModuleEntry {
|
|
1904
|
+
private doc: ModuleDocument;
|
|
1905
|
+
|
|
1906
|
+
constructor(title: string, moduleName: string, url: string) {
|
|
1907
|
+
super(title, moduleName);
|
|
1908
|
+
this.doc = { title, url };
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
getUrl(): string {
|
|
1912
|
+
return this.doc.url;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
getTitle(): string {
|
|
1916
|
+
return this.doc.title;
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
override toString(): string {
|
|
1920
|
+
const escapedTitle = escapeSpecialChars(this.doc.title);
|
|
1921
|
+
const escapedUrl = escapeSpecialChars(this.doc.url);
|
|
1922
|
+
return `{${DefaultModuleName}.ai/doc {\n title "${escapedTitle}",\n url "${escapedUrl}"\n}}`;
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
get url(): string {
|
|
1926
|
+
return this.doc.url;
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
set url(value: string) {
|
|
1930
|
+
this.doc.url = value;
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1888
1934
|
function statementLabel(stmt: Statement | undefined): string {
|
|
1889
1935
|
if (stmt === undefined) return '';
|
|
1890
1936
|
let lbl: string | undefined = undefined;
|
|
@@ -2472,6 +2518,48 @@ export class Module {
|
|
|
2472
2518
|
return this;
|
|
2473
2519
|
}
|
|
2474
2520
|
|
|
2521
|
+
addDocument(title: string, url: string): Module {
|
|
2522
|
+
if (this.hasEntry(title)) {
|
|
2523
|
+
const existing = this.getEntry(title);
|
|
2524
|
+
if (existing instanceof DocumentEntry) {
|
|
2525
|
+
const doc = existing as DocumentEntry;
|
|
2526
|
+
doc.url = url;
|
|
2527
|
+
return this;
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
|
|
2531
|
+
const docEntry = new DocumentEntry(title, this.name, url);
|
|
2532
|
+
this.addEntry(docEntry);
|
|
2533
|
+
return this;
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2536
|
+
getDocument(title: string): string | undefined {
|
|
2537
|
+
if (this.hasEntry(title)) {
|
|
2538
|
+
const entry = this.getEntry(title);
|
|
2539
|
+
if (entry instanceof DocumentEntry) {
|
|
2540
|
+
return (entry as DocumentEntry).url;
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
return undefined;
|
|
2544
|
+
}
|
|
2545
|
+
|
|
2546
|
+
getAllDocuments(): DocumentEntry[] {
|
|
2547
|
+
return this.entries.filter((e: ModuleEntry) => {
|
|
2548
|
+
return e instanceof DocumentEntry;
|
|
2549
|
+
}) as DocumentEntry[];
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
removeDocument(title: string): Module {
|
|
2553
|
+
for (let i = 0; i < this.entries.length; ++i) {
|
|
2554
|
+
const entry = this.entries[i];
|
|
2555
|
+
if (entry.name === title && entry instanceof DocumentEntry) {
|
|
2556
|
+
this.entries.splice(i, 1);
|
|
2557
|
+
break;
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
return this;
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2475
2563
|
addRetry(retry: Retry): Module {
|
|
2476
2564
|
this.addEntry(retry);
|
|
2477
2565
|
return this;
|
|
@@ -2734,6 +2822,17 @@ export class Module {
|
|
|
2734
2822
|
|
|
2735
2823
|
let GlobalRetries: Array<Retry> | undefined = undefined;
|
|
2736
2824
|
|
|
2825
|
+
const DocumentAliasMap: Map<string, string> = new Map();
|
|
2826
|
+
|
|
2827
|
+
export function registerDocumentAlias(name: string, title: string): void {
|
|
2828
|
+
if (!name || !title) return;
|
|
2829
|
+
DocumentAliasMap.set(name, title);
|
|
2830
|
+
}
|
|
2831
|
+
|
|
2832
|
+
export function resolveDocumentAliases(names: string[]): string[] {
|
|
2833
|
+
return names.map((name: string) => DocumentAliasMap.get(name) ?? name);
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2737
2836
|
export function addGlobalRetry(r: Retry): Retry {
|
|
2738
2837
|
if (GlobalRetries === undefined) {
|
|
2739
2838
|
GlobalRetries = new Array<Retry>();
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
newInstanceAttributes,
|
|
32
32
|
Record,
|
|
33
33
|
Retry,
|
|
34
|
+
resolveDocumentAliases,
|
|
34
35
|
} from '../module.js';
|
|
35
36
|
import { provider } from '../agents/registry.js';
|
|
36
37
|
import {
|
|
@@ -73,6 +74,27 @@ export const AgentLearnerType = 'learner';
|
|
|
73
74
|
|
|
74
75
|
const AgentEvalType = 'eval';
|
|
75
76
|
|
|
77
|
+
function buildEmbeddingConfig(): object {
|
|
78
|
+
const config: any = {
|
|
79
|
+
provider: process.env.AGENTLANG_EMBEDDING_PROVIDER || 'openai',
|
|
80
|
+
model: process.env.AGENTLANG_EMBEDDING_MODEL || 'text-embedding-3-small',
|
|
81
|
+
chunkSize: 1000,
|
|
82
|
+
chunkOverlap: 200,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
if (process.env.AGENTLANG_EMBEDDING_CHUNKSIZE) {
|
|
86
|
+
config.chunkSize = parseInt(process.env.AGENTLANG_EMBEDDING_CHUNKSIZE, 1000);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (process.env.AGENTLANG_EMBEDDING_CHUNKOVERLAP) {
|
|
90
|
+
config.chunkOverlap = parseInt(process.env.AGENTLANG_EMBEDDING_CHUNKOVERLAP, 200);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return config;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const embeddingConfig = JSON.stringify(buildEmbeddingConfig());
|
|
97
|
+
|
|
76
98
|
export default `module ${CoreAIModuleName}
|
|
77
99
|
|
|
78
100
|
import "./modules/ai.js" @as ai
|
|
@@ -116,7 +138,7 @@ workflow saveAgentChatSession {
|
|
|
116
138
|
entity Document {
|
|
117
139
|
title String @id,
|
|
118
140
|
content String,
|
|
119
|
-
@meta {"fullTextSearch": "*"}
|
|
141
|
+
@meta {"fullTextSearch": "*", "embeddingConfig": ${embeddingConfig}}
|
|
120
142
|
}
|
|
121
143
|
|
|
122
144
|
event doc {
|
|
@@ -981,6 +1003,7 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
981
1003
|
if (this.documents && this.documents.length > 0) {
|
|
982
1004
|
try {
|
|
983
1005
|
const docNames = this.documents.split(',').map(d => d.trim());
|
|
1006
|
+
const docTitles = resolveDocumentAliases(docNames);
|
|
984
1007
|
|
|
985
1008
|
const searchQuery = message;
|
|
986
1009
|
|
|
@@ -994,7 +1017,7 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
994
1017
|
const docs: Instance[] = [];
|
|
995
1018
|
for (const doc of semanticResult) {
|
|
996
1019
|
const docTitle = doc.lookup ? doc.lookup('title') : doc.title;
|
|
997
|
-
if (AgentInstance.docTitlesMatch(docTitle,
|
|
1020
|
+
if (AgentInstance.docTitlesMatch(docTitle, docTitles)) {
|
|
998
1021
|
docs.push(
|
|
999
1022
|
doc instanceof Instance
|
|
1000
1023
|
? doc
|
|
@@ -1026,7 +1049,7 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
1026
1049
|
const v: any = result[i];
|
|
1027
1050
|
const docTitle: string | undefined = AgentInstance.getDocumentTitle(v);
|
|
1028
1051
|
|
|
1029
|
-
if (docTitle &&
|
|
1052
|
+
if (docTitle && docTitles.includes(docTitle)) {
|
|
1030
1053
|
if (v instanceof Instance) {
|
|
1031
1054
|
docs.push(v);
|
|
1032
1055
|
}
|
|
@@ -49,6 +49,67 @@ import { AppConfig } from '../../state.js';
|
|
|
49
49
|
|
|
50
50
|
export let defaultDataSource: DataSource | undefined;
|
|
51
51
|
|
|
52
|
+
// Detect browser environment
|
|
53
|
+
function isBrowser(): boolean {
|
|
54
|
+
// window for DOM pages, self+importScripts for web workers
|
|
55
|
+
return (
|
|
56
|
+
(typeof window !== 'undefined' && typeof (window as any).document !== 'undefined') ||
|
|
57
|
+
(typeof self !== 'undefined' && typeof (self as any).importScripts === 'function')
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// SQLite WASM with built-in sqlite-vec for browsers
|
|
62
|
+
// Loaded from CDN - this has sqlite-vec statically compiled in
|
|
63
|
+
let sqliteVecWasmModule: any = null;
|
|
64
|
+
|
|
65
|
+
async function loadSqliteVecWasm(): Promise<any> {
|
|
66
|
+
if (sqliteVecWasmModule) {
|
|
67
|
+
return sqliteVecWasmModule;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
// Use dynamic import with string to prevent bundlers from analyzing
|
|
72
|
+
const cdnUrl = 'https://cdn.jsdelivr.net/npm/sqlite-vec-wasm-demo@latest/sqlite3.mjs';
|
|
73
|
+
const module = await import(/* @vite-ignore */ cdnUrl);
|
|
74
|
+
sqliteVecWasmModule = await module.default();
|
|
75
|
+
return sqliteVecWasmModule;
|
|
76
|
+
} catch (err) {
|
|
77
|
+
logger.warn('Failed to load sqlite-vec WASM:', err);
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Helper to load sqlite-vec based on environment
|
|
83
|
+
async function loadSqliteVec(): Promise<any> {
|
|
84
|
+
// In browser, use WASM version with built-in sqlite-vec
|
|
85
|
+
// In Node.js, use the npm package
|
|
86
|
+
if (isBrowser()) {
|
|
87
|
+
const wasmModule = await loadSqliteVecWasm();
|
|
88
|
+
if (wasmModule) {
|
|
89
|
+
// WASM version has sqlite-vec built-in, no need to call load()
|
|
90
|
+
// Return a compatible interface
|
|
91
|
+
return {
|
|
92
|
+
load: () => {
|
|
93
|
+
// No-op: sqlite-vec is already loaded in WASM version
|
|
94
|
+
logger.info('sqlite-vec WASM loaded (built-in)');
|
|
95
|
+
},
|
|
96
|
+
// Expose the WASM module for direct use if needed
|
|
97
|
+
_wasmModule: wasmModule,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Node.js: use npm package
|
|
104
|
+
try {
|
|
105
|
+
// Use variable to prevent bundlers from statically analyzing this import
|
|
106
|
+
const moduleName = 'sqlite-vec';
|
|
107
|
+
return await import(/* @vite-ignore */ moduleName);
|
|
108
|
+
} catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
52
113
|
export class DbContext {
|
|
53
114
|
txnId: string | undefined;
|
|
54
115
|
authInfo: ResolverAuthInfo;
|
|
@@ -245,11 +306,11 @@ function makeSqliteDataSource(
|
|
|
245
306
|
ds.initialize = async () => {
|
|
246
307
|
const res = await originalInit();
|
|
247
308
|
try {
|
|
248
|
-
const
|
|
309
|
+
const sqliteVec = await loadSqliteVec();
|
|
249
310
|
const driver = ds.driver as any;
|
|
250
311
|
const db = driver.databaseConnection || driver.nativeDatabase;
|
|
251
|
-
if (db) {
|
|
252
|
-
load(db);
|
|
312
|
+
if (db && sqliteVec?.load) {
|
|
313
|
+
sqliteVec.load(db);
|
|
253
314
|
logger.info('sqlite-vec extension loaded successfully');
|
|
254
315
|
}
|
|
255
316
|
} catch (err: any) {
|
|
@@ -303,14 +364,6 @@ async function maybeHandleMigrations(dataSource: DataSource) {
|
|
|
303
364
|
}
|
|
304
365
|
}
|
|
305
366
|
|
|
306
|
-
function isBrowser(): boolean {
|
|
307
|
-
// window for DOM pages, self+importScripts for web workers
|
|
308
|
-
return (
|
|
309
|
-
(typeof window !== 'undefined' && typeof (window as any).document !== 'undefined') ||
|
|
310
|
-
(typeof self !== 'undefined' && typeof (self as any).importScripts === 'function')
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
367
|
function defaultLocateFile(file: string): string {
|
|
315
368
|
// Out-of-the-box: use the official CDN in browsers.
|
|
316
369
|
if (isBrowser()) {
|
|
@@ -395,12 +448,8 @@ export async function isVectorStoreSupported(): Promise<boolean> {
|
|
|
395
448
|
const dbType = getDbType(AppConfig?.store);
|
|
396
449
|
if (dbType === 'postgres') return true;
|
|
397
450
|
if (dbType === 'sqlite') {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
return !!sqliteVecModule;
|
|
401
|
-
} catch {
|
|
402
|
-
return false;
|
|
403
|
-
}
|
|
451
|
+
const sqliteVecModule = await loadSqliteVec();
|
|
452
|
+
return !!sqliteVecModule;
|
|
404
453
|
}
|
|
405
454
|
return false;
|
|
406
455
|
}
|