agentlang 0.9.6 → 0.9.7
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/cli/main.d.ts.map +1 -1
- package/out/cli/main.js +8 -3
- package/out/cli/main.js.map +1 -1
- package/out/extension/main.cjs +250 -250
- package/out/extension/main.cjs.map +2 -2
- package/out/language/generated/ast.js +1 -0
- package/out/language/generated/ast.js.map +1 -1
- package/out/language/main.cjs +2420 -776
- package/out/language/main.cjs.map +4 -4
- package/out/runtime/docs.d.ts.map +1 -1
- package/out/runtime/docs.js +109 -7
- package/out/runtime/docs.js.map +1 -1
- package/out/runtime/embeddings/chunker.d.ts +9 -0
- package/out/runtime/embeddings/chunker.d.ts.map +1 -0
- package/out/runtime/embeddings/chunker.js +41 -0
- package/out/runtime/embeddings/chunker.js.map +1 -0
- package/out/runtime/embeddings/index.d.ts +6 -0
- package/out/runtime/embeddings/index.d.ts.map +1 -0
- package/out/runtime/embeddings/index.js +6 -0
- package/out/runtime/embeddings/index.js.map +1 -0
- package/out/runtime/embeddings/openai.d.ts +15 -0
- package/out/runtime/embeddings/openai.d.ts.map +1 -0
- package/out/runtime/embeddings/openai.js +34 -0
- package/out/runtime/embeddings/openai.js.map +1 -0
- package/out/runtime/embeddings/provider.d.ts +20 -0
- package/out/runtime/embeddings/provider.d.ts.map +1 -0
- package/out/runtime/embeddings/provider.js +17 -0
- package/out/runtime/embeddings/provider.js.map +1 -0
- package/out/runtime/embeddings/registry.d.ts +3 -0
- package/out/runtime/embeddings/registry.d.ts.map +1 -0
- package/out/runtime/embeddings/registry.js +16 -0
- package/out/runtime/embeddings/registry.js.map +1 -0
- package/out/runtime/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +8 -4
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/module.d.ts +5 -2
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +14 -6
- package/out/runtime/module.js.map +1 -1
- package/out/runtime/modules/ai.d.ts +2 -0
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +62 -16
- package/out/runtime/modules/ai.js.map +1 -1
- package/out/runtime/resolvers/sqldb/database.d.ts +1 -1
- package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/database.js +127 -46
- package/out/runtime/resolvers/sqldb/database.js.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.d.ts +21 -1
- package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.js +176 -45
- package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
- package/package.json +188 -185
- package/public/pdf.worker.mjs +65152 -0
- package/src/cli/main.ts +7 -2
- package/src/language/generated/ast.ts +1 -1
- package/src/runtime/docs.ts +120 -9
- package/src/runtime/embeddings/chunker.ts +50 -0
- package/src/runtime/embeddings/index.ts +5 -0
- package/src/runtime/embeddings/openai.ts +49 -0
- package/src/runtime/embeddings/provider.ts +37 -0
- package/src/runtime/embeddings/registry.ts +17 -0
- package/src/runtime/interpreter.ts +16 -12
- package/src/runtime/module.ts +48 -39
- package/src/runtime/modules/ai.ts +76 -19
- package/src/runtime/resolvers/sqldb/database.ts +133 -51
- package/src/runtime/resolvers/sqldb/impl.ts +235 -58
- package/out/setupClassic.d.ts +0 -98
- package/out/setupClassic.d.ts.map +0 -1
- package/out/setupClassic.js +0 -38
- package/out/setupClassic.js.map +0 -1
- package/out/setupCommon.d.ts +0 -2
- package/out/setupCommon.d.ts.map +0 -1
- package/out/setupCommon.js +0 -33
- package/out/setupCommon.js.map +0 -1
- package/out/setupExtended.d.ts +0 -40
- package/out/setupExtended.d.ts.map +0 -1
- package/out/setupExtended.js +0 -67
- package/out/setupExtended.js.map +0 -1
package/src/cli/main.ts
CHANGED
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
setRuntimeMode_init_schema,
|
|
39
39
|
setRuntimeMode_migration,
|
|
40
40
|
setRuntimeMode_prod,
|
|
41
|
+
setRuntimeMode_test,
|
|
41
42
|
setRuntimeMode_undo_migration,
|
|
42
43
|
updateEndpoints,
|
|
43
44
|
} from '../runtime/defs.js';
|
|
@@ -216,8 +217,12 @@ async function internDynamicModule(name: string, definition: string): Promise<st
|
|
|
216
217
|
setInternDynamicModuleFn(internDynamicModule);
|
|
217
218
|
|
|
218
219
|
export const runModule = async (fileName: string, releaseDb: boolean = false): Promise<void> => {
|
|
219
|
-
if (isRuntimeMode_dev()
|
|
220
|
-
|
|
220
|
+
if (isRuntimeMode_dev()) {
|
|
221
|
+
if (process.env.NODE_ENV === 'production') {
|
|
222
|
+
setRuntimeMode_prod();
|
|
223
|
+
} else if (process.env.NODE_ENV === 'test') {
|
|
224
|
+
setRuntimeMode_test();
|
|
225
|
+
}
|
|
221
226
|
}
|
|
222
227
|
const r: boolean = await runPreInitTasks();
|
|
223
228
|
if (!r) {
|
package/src/runtime/docs.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { getFileSystem } from '../utils/fs-utils.js';
|
|
2
1
|
import { logger } from './logger.js';
|
|
2
|
+
import { isNodeEnv } from '../utils/runtime.js';
|
|
3
|
+
import { getFileSystem } from '../utils/fs-utils.js';
|
|
3
4
|
|
|
4
5
|
const DocFetchers = new Map<string, Function>();
|
|
5
6
|
|
|
@@ -25,6 +26,39 @@ export async function fetchDoc(url: string): Promise<string | undefined> {
|
|
|
25
26
|
else return undefined;
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
let PDFParse: any = null;
|
|
30
|
+
let pdfWorkerSet = false;
|
|
31
|
+
|
|
32
|
+
async function getPDFParse() {
|
|
33
|
+
if (!PDFParse) {
|
|
34
|
+
const pdfModule = await import('pdf-parse');
|
|
35
|
+
PDFParse = pdfModule.PDFParse;
|
|
36
|
+
|
|
37
|
+
// Set up web worker for browser
|
|
38
|
+
if (!isNodeEnv && !pdfWorkerSet && PDFParse.setWorker) {
|
|
39
|
+
// Worker is served from public/ directory
|
|
40
|
+
PDFParse.setWorker('/pdf.worker.mjs');
|
|
41
|
+
pdfWorkerSet = true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return PDFParse;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function parsePdfBuffer(buffer: Uint8Array): Promise<string> {
|
|
48
|
+
try {
|
|
49
|
+
const PDFParseClass = await getPDFParse();
|
|
50
|
+
const parser = new PDFParseClass({
|
|
51
|
+
data: buffer,
|
|
52
|
+
verbosity: 0,
|
|
53
|
+
});
|
|
54
|
+
const data = await parser.getText();
|
|
55
|
+
return data.text;
|
|
56
|
+
} catch (error: any) {
|
|
57
|
+
logger.error(`Failed to parse PDF: ${error.message}`);
|
|
58
|
+
throw new Error(`PDF parsing failed: ${error.message}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
28
62
|
async function httpFetcher(url: string): Promise<string | undefined> {
|
|
29
63
|
try {
|
|
30
64
|
const response = await fetch(url, {
|
|
@@ -32,12 +66,24 @@ async function httpFetcher(url: string): Promise<string | undefined> {
|
|
|
32
66
|
});
|
|
33
67
|
|
|
34
68
|
if (!response.ok) {
|
|
35
|
-
logger.error(
|
|
36
|
-
`Failed to fetch document ${url}, HTTP error! status: ${response.status} ${response.text} ${response.statusText}`
|
|
37
|
-
);
|
|
69
|
+
logger.error(`Failed to fetch document ${url}, HTTP error! status: ${response.status}`);
|
|
38
70
|
return undefined;
|
|
39
71
|
}
|
|
40
|
-
|
|
72
|
+
|
|
73
|
+
const contentType = response.headers.get('content-type') || '';
|
|
74
|
+
const content = await response.arrayBuffer();
|
|
75
|
+
|
|
76
|
+
const lowerUrl = url.toLowerCase();
|
|
77
|
+
|
|
78
|
+
// Process based on content type or file extension
|
|
79
|
+
if (contentType.includes('application/pdf') || lowerUrl.endsWith('.pdf')) {
|
|
80
|
+
return await parsePdfBuffer(new Uint8Array(content));
|
|
81
|
+
} else if (contentType.includes('text/markdown') || lowerUrl.endsWith('.md')) {
|
|
82
|
+
return new TextDecoder().decode(content);
|
|
83
|
+
} else {
|
|
84
|
+
// Default to text
|
|
85
|
+
return new TextDecoder().decode(content);
|
|
86
|
+
}
|
|
41
87
|
} catch (reason: any) {
|
|
42
88
|
logger.error(`Failed to fetch document ${url}: ${reason}`);
|
|
43
89
|
}
|
|
@@ -45,11 +91,76 @@ async function httpFetcher(url: string): Promise<string | undefined> {
|
|
|
45
91
|
}
|
|
46
92
|
|
|
47
93
|
async function fetchFile(path: string): Promise<string> {
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
94
|
+
const lowerPath = path.toLowerCase();
|
|
95
|
+
|
|
96
|
+
if (lowerPath.endsWith('.pdf')) {
|
|
97
|
+
return await fetchPdfFile(path);
|
|
98
|
+
} else if (
|
|
99
|
+
lowerPath.endsWith('.md') ||
|
|
100
|
+
lowerPath.endsWith('.markdown') ||
|
|
101
|
+
lowerPath.endsWith('.mdown')
|
|
102
|
+
) {
|
|
103
|
+
return await fetchMarkdownFile(path);
|
|
104
|
+
} else {
|
|
105
|
+
// Default: plain text
|
|
106
|
+
return await fetchTextFile(path);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function fetchPdfFile(path: string): Promise<string> {
|
|
111
|
+
try {
|
|
112
|
+
const fs = await getFileSystem();
|
|
113
|
+
|
|
114
|
+
if (isNodeEnv && path.startsWith('.')) {
|
|
115
|
+
path = `${process.cwd()}${path.substring(1)}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const content = await fs.readFile(path);
|
|
119
|
+
|
|
120
|
+
let buffer: Uint8Array;
|
|
121
|
+
if (typeof content === 'string') {
|
|
122
|
+
buffer = new TextEncoder().encode(content);
|
|
123
|
+
} else if (Buffer.isBuffer(content)) {
|
|
124
|
+
buffer = new Uint8Array(content);
|
|
125
|
+
} else {
|
|
126
|
+
buffer = new Uint8Array(Buffer.from(content));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return await parsePdfBuffer(buffer);
|
|
130
|
+
} catch (error: any) {
|
|
131
|
+
logger.error(`Failed to read PDF file ${path}: ${error.message}`);
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function fetchMarkdownFile(path: string): Promise<string> {
|
|
137
|
+
try {
|
|
138
|
+
const fs = await getFileSystem();
|
|
139
|
+
|
|
140
|
+
if (isNodeEnv && path.startsWith('.')) {
|
|
141
|
+
path = `${process.cwd()}${path.substring(1)}`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return await fs.readFile(path);
|
|
145
|
+
} catch (error: any) {
|
|
146
|
+
logger.error(`Failed to read Markdown file ${path}: ${error.message}`);
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function fetchTextFile(path: string): Promise<string> {
|
|
152
|
+
try {
|
|
153
|
+
const fs = await getFileSystem();
|
|
154
|
+
|
|
155
|
+
if (isNodeEnv && path.startsWith('.')) {
|
|
156
|
+
path = `${process.cwd()}${path.substring(1)}`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return await fs.readFile(path);
|
|
160
|
+
} catch (error: any) {
|
|
161
|
+
logger.error(`Failed to read text file ${path}: ${error.message}`);
|
|
162
|
+
throw error;
|
|
51
163
|
}
|
|
52
|
-
return fs.readFile(path);
|
|
53
164
|
}
|
|
54
165
|
|
|
55
166
|
registerDocFetcher('http', httpFetcher);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export class TextChunker {
|
|
2
|
+
private chunkSize: number;
|
|
3
|
+
private chunkOverlap: number;
|
|
4
|
+
private separators: string[] = ['\n\n', '\n', '. ', ' ', ''];
|
|
5
|
+
|
|
6
|
+
constructor(chunkSize: number = 1000, chunkOverlap: number = 200) {
|
|
7
|
+
this.chunkSize = chunkSize;
|
|
8
|
+
this.chunkOverlap = chunkOverlap;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
splitText(text: string): string[] {
|
|
12
|
+
if (text.length <= this.chunkSize) {
|
|
13
|
+
return [text];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const chunks: string[] = [];
|
|
17
|
+
let start = 0;
|
|
18
|
+
|
|
19
|
+
while (start < text.length) {
|
|
20
|
+
let end = Math.min(start + this.chunkSize, text.length);
|
|
21
|
+
|
|
22
|
+
if (end < text.length) {
|
|
23
|
+
end = this.findBestSplitPoint(text, start, end);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
chunks.push(text.substring(start, end));
|
|
27
|
+
start = end - this.chunkOverlap;
|
|
28
|
+
|
|
29
|
+
if (start < 0) start = 0;
|
|
30
|
+
if (start >= text.length - this.chunkOverlap) {
|
|
31
|
+
if (start < text.length) {
|
|
32
|
+
chunks.push(text.substring(start));
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return chunks;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private findBestSplitPoint(text: string, start: number, end: number): number {
|
|
42
|
+
for (const sep of this.separators) {
|
|
43
|
+
const lastSep = text.lastIndexOf(sep, end);
|
|
44
|
+
if (lastSep > start) {
|
|
45
|
+
return Math.min(lastSep + sep.length, end);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return end;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { EmbeddingProvider, EmbeddingProviderConfig } from './provider.js';
|
|
2
|
+
export { EmbeddingService } from '../resolvers/sqldb/impl.js';
|
|
3
|
+
export { TextChunker } from './chunker.js';
|
|
4
|
+
export { embeddingProvider, getDefaultEmbeddingProvider } from './registry.js';
|
|
5
|
+
export { OpenAIEmbeddingProvider, OpenAIEmbeddingConfig } from './openai.js';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { OpenAIEmbeddings } from '@langchain/openai';
|
|
2
|
+
import { EmbeddingProvider, EmbeddingProviderConfig } from './provider.js';
|
|
3
|
+
import { getLocalEnv } from '../auth/defs.js';
|
|
4
|
+
|
|
5
|
+
export interface OpenAIEmbeddingConfig extends EmbeddingProviderConfig {
|
|
6
|
+
model?: string;
|
|
7
|
+
dimensions?: number;
|
|
8
|
+
maxRetries?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class OpenAIEmbeddingProvider extends EmbeddingProvider {
|
|
12
|
+
private openaiConfig: OpenAIEmbeddingConfig;
|
|
13
|
+
|
|
14
|
+
constructor(config?: EmbeddingProviderConfig) {
|
|
15
|
+
super(config || {});
|
|
16
|
+
this.openaiConfig = (this.config as OpenAIEmbeddingConfig) || {};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
protected createEmbeddings(): OpenAIEmbeddings {
|
|
20
|
+
const config: any = {
|
|
21
|
+
apiKey: this.resolveApiKey(),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
if (this.openaiConfig.model) {
|
|
25
|
+
config.model = this.openaiConfig.model;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (this.openaiConfig.dimensions) {
|
|
29
|
+
config.dimensions = this.openaiConfig.dimensions;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (this.openaiConfig.maxRetries !== undefined) {
|
|
33
|
+
config.maxRetries = this.openaiConfig.maxRetries;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return new OpenAIEmbeddings(config);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
protected resolveApiKey(): string {
|
|
40
|
+
if (this.openaiConfig.apiKey) {
|
|
41
|
+
return this.openaiConfig.apiKey;
|
|
42
|
+
}
|
|
43
|
+
return process.env.AGENTLANG_OPENAI_KEY || getLocalEnv('AGENTLANG_OPENAI_KEY') || '';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
getProviderName(): string {
|
|
47
|
+
return 'openai';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Embeddings } from '@langchain/core/embeddings';
|
|
2
|
+
|
|
3
|
+
export interface EmbeddingProviderConfig {
|
|
4
|
+
chunkSize?: number;
|
|
5
|
+
chunkOverlap?: number;
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
model?: string;
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export abstract class EmbeddingProvider {
|
|
12
|
+
protected config: EmbeddingProviderConfig;
|
|
13
|
+
protected embeddings: Embeddings;
|
|
14
|
+
|
|
15
|
+
constructor(config: EmbeddingProviderConfig = {}) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
this.embeddings = this.createEmbeddings();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
protected abstract createEmbeddings(): Embeddings;
|
|
21
|
+
protected abstract resolveApiKey(): string;
|
|
22
|
+
|
|
23
|
+
abstract getProviderName(): string;
|
|
24
|
+
|
|
25
|
+
async embedText(text: string): Promise<number[]> {
|
|
26
|
+
return await this.embeddings.embedQuery(text);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getConfig(): EmbeddingProviderConfig {
|
|
30
|
+
return { ...this.config };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
updateConfig(newConfig: Partial<EmbeddingProviderConfig>): void {
|
|
34
|
+
this.config = { ...this.config, ...newConfig };
|
|
35
|
+
this.embeddings = this.createEmbeddings();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { OpenAIEmbeddingProvider } from './openai.js';
|
|
2
|
+
|
|
3
|
+
const EmbeddingProviders = new Map().set('openai', OpenAIEmbeddingProvider);
|
|
4
|
+
|
|
5
|
+
export function embeddingProvider(service: string): any {
|
|
6
|
+
const requestedService = service.toLowerCase();
|
|
7
|
+
const provider = EmbeddingProviders.get(requestedService);
|
|
8
|
+
if (provider) {
|
|
9
|
+
return provider;
|
|
10
|
+
} else {
|
|
11
|
+
throw new Error(`No embedding provider found for ${service}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function getDefaultEmbeddingProvider(): string {
|
|
16
|
+
return 'openai';
|
|
17
|
+
}
|
|
@@ -32,8 +32,8 @@ import {
|
|
|
32
32
|
WhereSpec,
|
|
33
33
|
} from '../language/generated/ast.js';
|
|
34
34
|
import {
|
|
35
|
-
maybeInstanceAsString,
|
|
36
35
|
defineAgentEvent,
|
|
36
|
+
Event,
|
|
37
37
|
getOneOfRef,
|
|
38
38
|
getRelationship,
|
|
39
39
|
getWorkflow,
|
|
@@ -46,15 +46,15 @@ import {
|
|
|
46
46
|
isEntityInstance,
|
|
47
47
|
isEventInstance,
|
|
48
48
|
isInstanceOfType,
|
|
49
|
+
isOneToOneBetweenRelationship,
|
|
49
50
|
isTimer,
|
|
50
51
|
makeInstance,
|
|
52
|
+
maybeInstanceAsString,
|
|
51
53
|
newInstanceAttributes,
|
|
52
54
|
PlaceholderRecordEntry,
|
|
53
55
|
Relationship,
|
|
54
|
-
Workflow,
|
|
55
56
|
setMetaAttributes,
|
|
56
|
-
|
|
57
|
-
isOneToOneBetweenRelationship,
|
|
57
|
+
Workflow,
|
|
58
58
|
} from './module.js';
|
|
59
59
|
import { JoinInfo, Resolver, WhereClause } from './resolvers/interface.js';
|
|
60
60
|
import { ResolverAuthInfo } from './resolvers/authinfo.js';
|
|
@@ -65,26 +65,26 @@ import {
|
|
|
65
65
|
escapeFqName,
|
|
66
66
|
escapeQueryName,
|
|
67
67
|
fqNameFromPath,
|
|
68
|
+
isCoreModule,
|
|
68
69
|
isFqName,
|
|
69
70
|
isPath,
|
|
70
71
|
isString,
|
|
71
72
|
makeCoreModuleName,
|
|
72
73
|
makeFqName,
|
|
74
|
+
nameToPath,
|
|
73
75
|
Path,
|
|
76
|
+
preprocessRawConfig,
|
|
74
77
|
QuerySuffix,
|
|
75
78
|
restoreSpecialChars,
|
|
76
|
-
nameToPath,
|
|
77
79
|
splitRefs,
|
|
78
|
-
isCoreModule,
|
|
79
|
-
preprocessRawConfig,
|
|
80
80
|
} from './util.js';
|
|
81
81
|
import { getResolver, getResolverNameForPath } from './resolvers/registry.js';
|
|
82
82
|
import { parseStatement, parseWorkflow } from '../language/parser.js';
|
|
83
83
|
import { ActiveSessionInfo, AdminSession, AdminUserId } from './auth/defs.js';
|
|
84
84
|
import {
|
|
85
|
-
AgentInstance,
|
|
86
85
|
AgentEntityName,
|
|
87
86
|
AgentFqName,
|
|
87
|
+
AgentInstance,
|
|
88
88
|
findAgentByName,
|
|
89
89
|
normalizeGeneratedCode,
|
|
90
90
|
} from './modules/ai.js';
|
|
@@ -1755,11 +1755,15 @@ async function handleDocEvent(inst: Instance, env: Environment): Promise<void> {
|
|
|
1755
1755
|
const s = await fetchDoc(inst.lookup('url'));
|
|
1756
1756
|
if (s) {
|
|
1757
1757
|
const title = inst.lookup('title');
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1758
|
+
const doc = makeInstance(
|
|
1759
|
+
CoreAIModuleName,
|
|
1760
|
+
'Document',
|
|
1761
|
+
newInstanceAttributes().set('title', title).set('content', s)
|
|
1762
1762
|
);
|
|
1763
|
+
await computeExprAttributes(doc, undefined, undefined, env);
|
|
1764
|
+
await setMetaAttributes(doc.attributes, env);
|
|
1765
|
+
const res: Resolver = await getResolverForPath('Document', CoreAIModuleName, env);
|
|
1766
|
+
await res.createInstance(doc);
|
|
1763
1767
|
}
|
|
1764
1768
|
}
|
|
1765
1769
|
|
package/src/runtime/module.ts
CHANGED
|
@@ -1,57 +1,57 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
AttributeDefinition,
|
|
4
|
+
Expr,
|
|
5
|
+
FlowDefinition,
|
|
6
|
+
FlowEntry,
|
|
6
7
|
FnCall,
|
|
7
|
-
|
|
8
|
+
isLiteral,
|
|
8
9
|
isRelNodes,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
NodeDefinition,
|
|
12
|
-
RecordSchemaDefinition,
|
|
10
|
+
KvPair,
|
|
11
|
+
Literal,
|
|
13
12
|
MapEntry,
|
|
14
|
-
isLiteral,
|
|
15
13
|
MetaDefinition,
|
|
14
|
+
NodeDefinition,
|
|
16
15
|
PrePostTriggerDefinition,
|
|
17
|
-
|
|
18
|
-
Expr,
|
|
19
|
-
RbacSpecEntry,
|
|
20
|
-
RbacSpecEntries,
|
|
16
|
+
PropertyDefinition,
|
|
21
17
|
RbacOpr,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
RbacSpecEntries,
|
|
19
|
+
RbacSpecEntry,
|
|
20
|
+
RecordSchemaDefinition,
|
|
21
|
+
RelNodes,
|
|
22
|
+
Statement,
|
|
23
|
+
TriggerEntry,
|
|
25
24
|
WorkflowDirectives,
|
|
25
|
+
WorkflowHeader,
|
|
26
26
|
} from '../language/generated/ast.js';
|
|
27
27
|
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
isString,
|
|
31
|
-
isNumber,
|
|
32
|
-
isBoolean,
|
|
33
|
-
isFqName,
|
|
34
|
-
makeFqName,
|
|
28
|
+
asCrudType,
|
|
29
|
+
CrudType,
|
|
35
30
|
DefaultModuleName,
|
|
36
31
|
DefaultModules,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
now,
|
|
40
|
-
findMetaSchema,
|
|
32
|
+
encryptPassword,
|
|
33
|
+
escapeFqName,
|
|
41
34
|
findAllPrePostTriggerSchema,
|
|
42
|
-
|
|
43
|
-
asCrudType,
|
|
44
|
-
isPath,
|
|
35
|
+
findMetaSchema,
|
|
45
36
|
findUqCompositeAttributes,
|
|
46
|
-
escapeFqName,
|
|
47
|
-
encryptPassword,
|
|
48
|
-
splitFqName,
|
|
49
|
-
splitRefs,
|
|
50
37
|
forceAsFqName,
|
|
51
|
-
|
|
38
|
+
isBoolean,
|
|
39
|
+
isFqName,
|
|
40
|
+
isMinusZero,
|
|
41
|
+
isNumber,
|
|
42
|
+
isPath,
|
|
43
|
+
isString,
|
|
44
|
+
joinStatements,
|
|
45
|
+
makeFqName,
|
|
52
46
|
nameContainsSepEscape,
|
|
47
|
+
nameToPath,
|
|
48
|
+
now,
|
|
49
|
+
Path,
|
|
53
50
|
registerInitFunction,
|
|
54
51
|
ScratchModuleName,
|
|
52
|
+
splitFqName,
|
|
53
|
+
splitRefs,
|
|
54
|
+
validateIdFormat,
|
|
55
55
|
} from './util.js';
|
|
56
56
|
import { parseStatement } from '../language/parser.js';
|
|
57
57
|
import { ActiveSessionInfo, AdminSession } from './auth/defs.js';
|
|
@@ -513,7 +513,10 @@ export class Record extends ModuleEntry {
|
|
|
513
513
|
}
|
|
514
514
|
|
|
515
515
|
getFullTextSearchAttributes(): string[] | undefined {
|
|
516
|
-
|
|
516
|
+
let fts: string[] | string | undefined = this.getMeta('fullTextSearchAttributes');
|
|
517
|
+
if (!fts) {
|
|
518
|
+
fts = this.getMeta('fullTextSearch');
|
|
519
|
+
}
|
|
517
520
|
if (fts) {
|
|
518
521
|
if (fts instanceof Array) {
|
|
519
522
|
return fts as string[];
|
|
@@ -527,6 +530,14 @@ export class Record extends ModuleEntry {
|
|
|
527
530
|
}
|
|
528
531
|
}
|
|
529
532
|
|
|
533
|
+
getEmbeddingConfig(): { [key: string]: any } | undefined {
|
|
534
|
+
const config = this.getMeta('embeddingConfig');
|
|
535
|
+
if (config && typeof config === 'object') {
|
|
536
|
+
return config as { [key: string]: any };
|
|
537
|
+
}
|
|
538
|
+
return undefined;
|
|
539
|
+
}
|
|
540
|
+
|
|
530
541
|
private resetUserAttrs() {
|
|
531
542
|
this.userAttrNames = undefined;
|
|
532
543
|
this.userAttrsSchema = undefined;
|
|
@@ -2496,7 +2507,7 @@ export class Module {
|
|
|
2496
2507
|
|
|
2497
2508
|
private getEntryIndex(entryName: string): number {
|
|
2498
2509
|
return this.entries.findIndex((v: ModuleEntry) => {
|
|
2499
|
-
return v.name
|
|
2510
|
+
return v.name === entryName;
|
|
2500
2511
|
});
|
|
2501
2512
|
}
|
|
2502
2513
|
|
|
@@ -2782,8 +2793,6 @@ export function removeModule(name: string): boolean {
|
|
|
2782
2793
|
return false;
|
|
2783
2794
|
}
|
|
2784
2795
|
|
|
2785
|
-
addModule(DefaultModuleName);
|
|
2786
|
-
addRecord('env', DefaultModuleName);
|
|
2787
2796
|
addModule(ScratchModuleName);
|
|
2788
2797
|
|
|
2789
2798
|
export function getModuleNames(): string[] {
|
|
@@ -60,7 +60,6 @@ import {
|
|
|
60
60
|
newAgentScenario,
|
|
61
61
|
PlannerInstructions,
|
|
62
62
|
} from '../agents/common.js';
|
|
63
|
-
import { PathAttributeNameQuery } from '../defs.js';
|
|
64
63
|
import { logger } from '../logger.js';
|
|
65
64
|
import { FlowStep } from '../agents/flows.js';
|
|
66
65
|
import Handlebars from 'handlebars';
|
|
@@ -980,34 +979,92 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
980
979
|
|
|
981
980
|
private async maybeAddRelevantDocuments(message: string, env: Environment): Promise<string> {
|
|
982
981
|
if (this.documents && this.documents.length > 0) {
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
const
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
const
|
|
990
|
-
`{${CoreAIModuleName}/Document {
|
|
982
|
+
try {
|
|
983
|
+
const docNames = this.documents.split(',').map(d => d.trim());
|
|
984
|
+
|
|
985
|
+
const searchQuery = message;
|
|
986
|
+
|
|
987
|
+
try {
|
|
988
|
+
const semanticResult: any[] = await parseHelper(
|
|
989
|
+
`{${CoreAIModuleName}/Document {content? "${searchQuery.replace(/"/g, '\\"')}"}}`,
|
|
991
990
|
env
|
|
992
991
|
);
|
|
993
|
-
|
|
994
|
-
|
|
992
|
+
|
|
993
|
+
if (semanticResult && semanticResult.length > 0) {
|
|
994
|
+
const docs: Instance[] = [];
|
|
995
|
+
for (const doc of semanticResult) {
|
|
996
|
+
const docTitle = doc.lookup ? doc.lookup('title') : doc.title;
|
|
997
|
+
if (AgentInstance.docTitlesMatch(docTitle, docNames)) {
|
|
998
|
+
docs.push(
|
|
999
|
+
doc instanceof Instance
|
|
1000
|
+
? doc
|
|
1001
|
+
: Instance.newWithAttributes(doc, new Map(Object.entries(doc)))
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
if (docs.length > 0) {
|
|
1007
|
+
return message.concat('\n\nRelevant context from documents:\n').concat(
|
|
1008
|
+
docs
|
|
1009
|
+
.map((v: Instance) => {
|
|
1010
|
+
return `Document: ${v.lookup('title')}\n${v.lookup('content') as string}`;
|
|
1011
|
+
})
|
|
1012
|
+
.join('\n\n---\n\n')
|
|
1013
|
+
);
|
|
1014
|
+
}
|
|
995
1015
|
}
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
docs
|
|
1000
|
-
.map((v: Instance) => {
|
|
1001
|
-
return v.lookup('content');
|
|
1002
|
-
})
|
|
1003
|
-
.join('\n')
|
|
1016
|
+
} catch (semanticErr) {
|
|
1017
|
+
logger.debug(
|
|
1018
|
+
`Semantic search is not available, falling back to title-based filtering: ${semanticErr}`
|
|
1004
1019
|
);
|
|
1005
1020
|
}
|
|
1021
|
+
|
|
1022
|
+
const result: any[] = await parseHelper(`{${CoreAIModuleName}/Document? {}}`, env);
|
|
1023
|
+
if (result && result.length > 0) {
|
|
1024
|
+
const docs: Instance[] = [];
|
|
1025
|
+
for (let i = 0; i < result.length; ++i) {
|
|
1026
|
+
const v: any = result[i];
|
|
1027
|
+
const docTitle: string | undefined = AgentInstance.getDocumentTitle(v);
|
|
1028
|
+
|
|
1029
|
+
if (docTitle && docNames.includes(docTitle)) {
|
|
1030
|
+
if (v instanceof Instance) {
|
|
1031
|
+
docs.push(v);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
if (docs.length > 0) {
|
|
1037
|
+
return message.concat('\n\nRelevant context from documents:\n').concat(
|
|
1038
|
+
docs
|
|
1039
|
+
.map((v: Instance) => {
|
|
1040
|
+
return v.lookup('content') as string;
|
|
1041
|
+
})
|
|
1042
|
+
.join('\n\n')
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
} catch (err) {
|
|
1047
|
+
logger.debug(`Error retrieving documents: ${err}`);
|
|
1006
1048
|
}
|
|
1007
1049
|
}
|
|
1008
1050
|
return message;
|
|
1009
1051
|
}
|
|
1010
1052
|
|
|
1053
|
+
private static docTitlesMatch(title: string | undefined, docNames: string[]): boolean {
|
|
1054
|
+
return title !== undefined && docNames.includes(title);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
private static getDocumentTitle(doc: any): string | undefined {
|
|
1058
|
+
if (typeof doc.lookup === 'function') {
|
|
1059
|
+
return doc.lookup('title') as string | undefined;
|
|
1060
|
+
} else if (doc.attributes) {
|
|
1061
|
+
return doc.attributes.get('title') as string | undefined;
|
|
1062
|
+
} else if (doc.title) {
|
|
1063
|
+
return doc.title;
|
|
1064
|
+
}
|
|
1065
|
+
return undefined;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1011
1068
|
private static ToolsCache = new Map<string, string>();
|
|
1012
1069
|
|
|
1013
1070
|
private toolsAsString(): string {
|