agentlang 0.10.2 → 0.10.3
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/README.md +7 -14
- package/out/api/http.d.ts +4 -0
- package/out/api/http.d.ts.map +1 -1
- package/out/api/http.js +171 -26
- package/out/api/http.js.map +1 -1
- package/out/cli/main.d.ts.map +1 -1
- package/out/cli/main.js +3 -0
- 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/agentlang-validator.d.ts.map +1 -1
- package/out/language/agentlang-validator.js +4 -0
- package/out/language/agentlang-validator.js.map +1 -1
- package/out/language/error-reporter.d.ts +53 -0
- package/out/language/error-reporter.d.ts.map +1 -0
- package/out/language/error-reporter.js +879 -0
- package/out/language/error-reporter.js.map +1 -0
- package/out/language/generated/ast.d.ts +51 -1
- package/out/language/generated/ast.d.ts.map +1 -1
- package/out/language/generated/ast.js +40 -0
- package/out/language/generated/ast.js.map +1 -1
- package/out/language/generated/grammar.d.ts.map +1 -1
- package/out/language/generated/grammar.js +286 -190
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/main.cjs +828 -694
- package/out/language/main.cjs.map +3 -3
- package/out/language/parser.d.ts +4 -2
- package/out/language/parser.d.ts.map +1 -1
- package/out/language/parser.js +30 -97
- package/out/language/parser.js.map +1 -1
- package/out/language/syntax.d.ts +2 -0
- package/out/language/syntax.d.ts.map +1 -1
- package/out/language/syntax.js +6 -0
- package/out/language/syntax.js.map +1 -1
- package/out/runtime/api.d.ts.map +1 -1
- package/out/runtime/api.js +22 -0
- package/out/runtime/api.js.map +1 -1
- package/out/runtime/defs.d.ts +1 -0
- package/out/runtime/defs.d.ts.map +1 -1
- package/out/runtime/defs.js +2 -1
- package/out/runtime/defs.js.map +1 -1
- package/out/runtime/document-retriever.d.ts +24 -0
- package/out/runtime/document-retriever.d.ts.map +1 -0
- package/out/runtime/document-retriever.js +258 -0
- package/out/runtime/document-retriever.js.map +1 -0
- package/out/runtime/embeddings/chunker.d.ts +18 -0
- package/out/runtime/embeddings/chunker.d.ts.map +1 -1
- package/out/runtime/embeddings/chunker.js +47 -15
- package/out/runtime/embeddings/chunker.js.map +1 -1
- package/out/runtime/embeddings/openai.d.ts.map +1 -1
- package/out/runtime/embeddings/openai.js +22 -9
- package/out/runtime/embeddings/openai.js.map +1 -1
- package/out/runtime/embeddings/provider.d.ts +1 -0
- package/out/runtime/embeddings/provider.d.ts.map +1 -1
- package/out/runtime/embeddings/provider.js +20 -1
- package/out/runtime/embeddings/provider.js.map +1 -1
- package/out/runtime/integration-client.d.ts +21 -0
- package/out/runtime/integration-client.d.ts.map +1 -0
- package/out/runtime/integration-client.js +112 -0
- package/out/runtime/integration-client.js.map +1 -0
- package/out/runtime/integrations.d.ts.map +1 -1
- package/out/runtime/integrations.js +20 -9
- package/out/runtime/integrations.js.map +1 -1
- package/out/runtime/interpreter.d.ts +1 -0
- package/out/runtime/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +152 -17
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/loader.d.ts.map +1 -1
- package/out/runtime/loader.js +70 -7
- package/out/runtime/loader.js.map +1 -1
- package/out/runtime/logger.d.ts.map +1 -1
- package/out/runtime/logger.js +8 -1
- package/out/runtime/logger.js.map +1 -1
- package/out/runtime/module.d.ts +10 -0
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +68 -3
- package/out/runtime/module.js.map +1 -1
- package/out/runtime/modules/ai.d.ts +9 -2
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +219 -67
- package/out/runtime/modules/ai.js.map +1 -1
- package/out/runtime/resolvers/interface.d.ts +4 -0
- package/out/runtime/resolvers/interface.d.ts.map +1 -1
- package/out/runtime/resolvers/interface.js +14 -1
- package/out/runtime/resolvers/interface.js.map +1 -1
- package/out/runtime/resolvers/sqldb/database.d.ts +2 -0
- package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/database.js +142 -126
- package/out/runtime/resolvers/sqldb/database.js.map +1 -1
- package/out/runtime/resolvers/sqldb/dbutil.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/dbutil.js +8 -0
- package/out/runtime/resolvers/sqldb/dbutil.js.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.d.ts +1 -0
- package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.js +7 -0
- package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
- package/out/runtime/resolvers/vector/lancedb-store.d.ts +16 -0
- package/out/runtime/resolvers/vector/lancedb-store.d.ts.map +1 -0
- package/out/runtime/resolvers/vector/lancedb-store.js +159 -0
- package/out/runtime/resolvers/vector/lancedb-store.js.map +1 -0
- package/out/runtime/resolvers/vector/types.d.ts +32 -0
- package/out/runtime/resolvers/vector/types.d.ts.map +1 -0
- package/out/runtime/resolvers/vector/types.js +2 -0
- package/out/runtime/resolvers/vector/types.js.map +1 -0
- package/out/runtime/services/documentFetcher.d.ts.map +1 -1
- package/out/runtime/services/documentFetcher.js +21 -6
- package/out/runtime/services/documentFetcher.js.map +1 -1
- package/out/runtime/state.d.ts +19 -1
- package/out/runtime/state.d.ts.map +1 -1
- package/out/runtime/state.js +36 -1
- package/out/runtime/state.js.map +1 -1
- package/out/syntaxes/agentlang.monarch.js +1 -1
- package/out/syntaxes/agentlang.monarch.js.map +1 -1
- package/package.json +19 -19
- package/src/api/http.ts +197 -37
- package/src/cli/main.ts +3 -0
- package/src/language/agentlang-validator.ts +3 -0
- package/src/language/agentlang.langium +3 -1
- package/src/language/error-reporter.ts +1028 -0
- package/src/language/generated/ast.ts +62 -0
- package/src/language/generated/grammar.ts +286 -190
- package/src/language/parser.ts +31 -100
- package/src/language/syntax.ts +8 -0
- package/src/runtime/api.ts +31 -0
- package/src/runtime/defs.ts +2 -1
- package/src/runtime/document-retriever.ts +311 -0
- package/src/runtime/embeddings/chunker.ts +52 -14
- package/src/runtime/embeddings/openai.ts +27 -9
- package/src/runtime/embeddings/provider.ts +22 -1
- package/src/runtime/integration-client.ts +158 -0
- package/src/runtime/integrations.ts +20 -11
- package/src/runtime/interpreter.ts +142 -12
- package/src/runtime/loader.ts +83 -5
- package/src/runtime/logger.ts +12 -1
- package/src/runtime/module.ts +78 -3
- package/src/runtime/modules/ai.ts +263 -76
- package/src/runtime/resolvers/interface.ts +19 -1
- package/src/runtime/resolvers/sqldb/database.ts +158 -130
- package/src/runtime/resolvers/sqldb/dbutil.ts +8 -0
- package/src/runtime/resolvers/sqldb/impl.ts +8 -0
- package/src/runtime/resolvers/vector/lancedb-store.ts +187 -0
- package/src/runtime/resolvers/vector/types.ts +39 -0
- package/src/runtime/services/documentFetcher.ts +21 -6
- package/src/runtime/state.ts +40 -1
- package/src/syntaxes/agentlang.monarch.ts +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { OpenAIEmbeddings } from '@langchain/openai';
|
|
2
2
|
import { EmbeddingProvider, EmbeddingProviderConfig } from './provider.js';
|
|
3
3
|
import { getLocalEnv } from '../auth/defs.js';
|
|
4
|
+
import { logger } from '../logger.js';
|
|
4
5
|
|
|
5
6
|
export interface OpenAIEmbeddingConfig extends EmbeddingProviderConfig {
|
|
6
7
|
model?: string;
|
|
@@ -14,6 +15,9 @@ export class OpenAIEmbeddingProvider extends EmbeddingProvider {
|
|
|
14
15
|
constructor(config?: EmbeddingProviderConfig) {
|
|
15
16
|
super(config || {});
|
|
16
17
|
this.openaiConfig = (this.config as OpenAIEmbeddingConfig) || {};
|
|
18
|
+
logger.debug(
|
|
19
|
+
`[OPENAI-EMBEDDING] Provider created with model: ${this.openaiConfig.model || 'default'}`
|
|
20
|
+
);
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
protected createEmbeddings(): OpenAIEmbeddings {
|
|
@@ -21,26 +25,40 @@ export class OpenAIEmbeddingProvider extends EmbeddingProvider {
|
|
|
21
25
|
apiKey: this.resolveApiKey(),
|
|
22
26
|
};
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
// Use this.config directly since this.openaiConfig is not initialized yet
|
|
29
|
+
// during parent constructor (super() calls createEmbeddings before child init)
|
|
30
|
+
const openaiConfig = (this.config as OpenAIEmbeddingConfig) || {};
|
|
31
|
+
|
|
32
|
+
if (openaiConfig?.model) {
|
|
33
|
+
config.model = openaiConfig.model;
|
|
26
34
|
}
|
|
27
35
|
|
|
28
|
-
if (
|
|
29
|
-
config.dimensions =
|
|
36
|
+
if (openaiConfig?.dimensions) {
|
|
37
|
+
config.dimensions = openaiConfig.dimensions;
|
|
30
38
|
}
|
|
31
39
|
|
|
32
|
-
if (
|
|
33
|
-
config.maxRetries =
|
|
40
|
+
if (openaiConfig?.maxRetries !== undefined) {
|
|
41
|
+
config.maxRetries = openaiConfig.maxRetries;
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
return new OpenAIEmbeddings(config);
|
|
37
45
|
}
|
|
38
46
|
|
|
39
47
|
protected resolveApiKey(): string {
|
|
40
|
-
|
|
41
|
-
|
|
48
|
+
// Use this.config directly since this.openaiConfig may not be initialized yet
|
|
49
|
+
// during constructor (createEmbeddings is called during super())
|
|
50
|
+
const config = this.openaiConfig || (this.config as OpenAIEmbeddingConfig) || {};
|
|
51
|
+
if (config.apiKey) {
|
|
52
|
+
return config.apiKey;
|
|
53
|
+
}
|
|
54
|
+
const envKey = process.env.AGENTLANG_OPENAI_KEY || getLocalEnv('AGENTLANG_OPENAI_KEY');
|
|
55
|
+
if (envKey) {
|
|
56
|
+
return envKey;
|
|
42
57
|
}
|
|
43
|
-
|
|
58
|
+
logger.warn(
|
|
59
|
+
`[OPENAI-EMBEDDING] No API key found! Set AGENTLANG_OPENAI_KEY environment variable.`
|
|
60
|
+
);
|
|
61
|
+
return '';
|
|
44
62
|
}
|
|
45
63
|
|
|
46
64
|
getProviderName(): string {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Embeddings } from '@langchain/core/embeddings';
|
|
2
|
+
import { logger } from '../logger.js';
|
|
2
3
|
|
|
3
4
|
export interface EmbeddingProviderConfig {
|
|
4
5
|
chunkSize?: number;
|
|
@@ -23,7 +24,27 @@ export abstract class EmbeddingProvider {
|
|
|
23
24
|
abstract getProviderName(): string;
|
|
24
25
|
|
|
25
26
|
async embedText(text: string): Promise<number[]> {
|
|
26
|
-
|
|
27
|
+
logger.debug(`[EMBEDDING-PROVIDER] embedText called (${text.length} chars)`);
|
|
28
|
+
const startTime = Date.now();
|
|
29
|
+
const result = await this.embeddings.embedQuery(text);
|
|
30
|
+
const duration = Date.now() - startTime;
|
|
31
|
+
logger.debug(
|
|
32
|
+
`[EMBEDDING-PROVIDER] embedText completed in ${duration}ms (${result.length} dimensions)`
|
|
33
|
+
);
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async embedTexts(texts: string[]): Promise<number[][]> {
|
|
38
|
+
if (texts.length === 0) return [];
|
|
39
|
+
if (texts.length === 1) return [await this.embedText(texts[0])];
|
|
40
|
+
logger.debug(`[EMBEDDING-PROVIDER] embedTexts called (${texts.length} texts)`);
|
|
41
|
+
const startTime = Date.now();
|
|
42
|
+
const results = await this.embeddings.embedDocuments(texts);
|
|
43
|
+
const duration = Date.now() - startTime;
|
|
44
|
+
logger.debug(
|
|
45
|
+
`[EMBEDDING-PROVIDER] embedTexts completed in ${duration}ms (${texts.length} texts, ${results[0]?.length || 0} dimensions)`
|
|
46
|
+
);
|
|
47
|
+
return results;
|
|
27
48
|
}
|
|
28
49
|
|
|
29
50
|
getConfig(): EmbeddingProviderConfig {
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
let host: string | undefined;
|
|
2
|
+
let headers: Record<string, string> | undefined;
|
|
3
|
+
|
|
4
|
+
export function configureIntegrationClient(h: string, hdrs?: Record<string, string>): void {
|
|
5
|
+
host = h;
|
|
6
|
+
headers = hdrs;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function isIntegrationClientConfigured(): boolean {
|
|
10
|
+
return host !== undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function getIntegrationAuthHeaders(
|
|
14
|
+
integrationName: string
|
|
15
|
+
): Promise<Record<string, string>> {
|
|
16
|
+
if (!host) {
|
|
17
|
+
throw new Error('Integration client not configured — call configureIntegrationClient() first');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const url = `${host}/integmanager.auth/authHeaders/${encodeURIComponent(integrationName)}`;
|
|
21
|
+
const response = await fetch(url, {
|
|
22
|
+
method: 'GET',
|
|
23
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`Failed to get auth headers for integration "${integrationName}": ${response.status} ${response.statusText}`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const data = await response.json();
|
|
33
|
+
// The response is either the entity directly or wrapped in an array
|
|
34
|
+
const result = Array.isArray(data) ? data[0] : data;
|
|
35
|
+
return result?.headers ?? {};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function refreshIntegrationAuth(integrationName: string): Promise<void> {
|
|
39
|
+
if (!host) {
|
|
40
|
+
throw new Error('Integration client not configured — call configureIntegrationClient() first');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const url = `${host}/integmanager.auth/authRefresh`;
|
|
44
|
+
const response = await fetch(url, {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
47
|
+
body: JSON.stringify({ integrationName }),
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (!response.ok) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`Failed to refresh auth for integration "${integrationName}": ${response.status} ${response.statusText}`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function integrationAuthFetch(
|
|
58
|
+
integrationName: string,
|
|
59
|
+
url: string | URL,
|
|
60
|
+
options: RequestInit = {}
|
|
61
|
+
): Promise<Response> {
|
|
62
|
+
const authHeaders = await getIntegrationAuthHeaders(integrationName);
|
|
63
|
+
const mergedHeaders = { ...authHeaders, ...((options.headers as Record<string, string>) || {}) };
|
|
64
|
+
return fetch(url, { ...options, headers: mergedHeaders });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// --- OAuth consent flow helpers ---
|
|
68
|
+
|
|
69
|
+
export async function getOAuthAuthorizeUrl(
|
|
70
|
+
integrationName: string,
|
|
71
|
+
redirectUri: string
|
|
72
|
+
): Promise<{ authorizationUrl: string; state: string }> {
|
|
73
|
+
if (!host) {
|
|
74
|
+
throw new Error('Integration client not configured — call configureIntegrationClient() first');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const params = new URLSearchParams({
|
|
78
|
+
action: 'authorize',
|
|
79
|
+
integrationName,
|
|
80
|
+
redirectUri,
|
|
81
|
+
});
|
|
82
|
+
const url = `${host}/integmanager.auth/oauthFlow?${params.toString()}`;
|
|
83
|
+
const response = await fetch(url, {
|
|
84
|
+
method: 'GET',
|
|
85
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`Failed to get OAuth authorize URL for "${integrationName}": ${response.status} ${response.statusText}`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const data = await response.json();
|
|
95
|
+
const result = Array.isArray(data) ? data[0] : data;
|
|
96
|
+
return { authorizationUrl: result.authorizationUrl, state: result.state };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function exchangeOAuthCode(
|
|
100
|
+
integrationName: string,
|
|
101
|
+
code: string,
|
|
102
|
+
state: string
|
|
103
|
+
): Promise<{ accessToken: string; refreshToken: string; expiresIn: number; tokenType: string }> {
|
|
104
|
+
if (!host) {
|
|
105
|
+
throw new Error('Integration client not configured — call configureIntegrationClient() first');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const url = `${host}/integmanager.auth/oauthFlow`;
|
|
109
|
+
const response = await fetch(url, {
|
|
110
|
+
method: 'POST',
|
|
111
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
112
|
+
body: JSON.stringify({ action: 'exchange', integrationName, code, state }),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Failed to exchange OAuth code for "${integrationName}": ${response.status} ${response.statusText}`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const data = await response.json();
|
|
122
|
+
const result = Array.isArray(data) ? data[0] : data;
|
|
123
|
+
return {
|
|
124
|
+
accessToken: result.accessToken,
|
|
125
|
+
refreshToken: result.refreshToken,
|
|
126
|
+
expiresIn: result.expiresIn,
|
|
127
|
+
tokenType: result.tokenType,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function getIntegrationAccessToken(
|
|
132
|
+
integrationName: string
|
|
133
|
+
): Promise<{ accessToken: string; expiresIn: number; tokenType: string }> {
|
|
134
|
+
if (!host) {
|
|
135
|
+
throw new Error('Integration client not configured — call configureIntegrationClient() first');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const params = new URLSearchParams({ integrationName });
|
|
139
|
+
const url = `${host}/integmanager.auth/oauthToken?${params.toString()}`;
|
|
140
|
+
const response = await fetch(url, {
|
|
141
|
+
method: 'GET',
|
|
142
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
if (!response.ok) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`Failed to get access token for "${integrationName}": ${response.status} ${response.statusText}`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const data = await response.json();
|
|
152
|
+
const result = Array.isArray(data) ? data[0] : data;
|
|
153
|
+
return {
|
|
154
|
+
accessToken: result.accessToken,
|
|
155
|
+
expiresIn: result.expiresIn,
|
|
156
|
+
tokenType: result.tokenType,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { Instance } from './module.js';
|
|
2
1
|
import { isString } from './util.js';
|
|
3
2
|
|
|
4
|
-
const Integrations = new Map<string,
|
|
3
|
+
const Integrations = new Map<string, any>();
|
|
5
4
|
|
|
6
5
|
const IntegManagerModel = 'integmanager.core';
|
|
7
6
|
|
|
@@ -16,7 +15,8 @@ export async function prepareIntegrations(
|
|
|
16
15
|
const keys = [...integConfig.keys()];
|
|
17
16
|
for (let i = 0; i < keys.length; ++i) {
|
|
18
17
|
const configName = keys[i];
|
|
19
|
-
const
|
|
18
|
+
const entry = integConfig.get(configName);
|
|
19
|
+
const configPath = typeof entry === 'string' ? entry : entry?.config;
|
|
20
20
|
if (configPath) {
|
|
21
21
|
const apiUrl = mkApiUrl(integManagerHost, configPath);
|
|
22
22
|
try {
|
|
@@ -35,9 +35,6 @@ export async function prepareIntegrations(
|
|
|
35
35
|
const data = await response.json();
|
|
36
36
|
if (data.length > 0) {
|
|
37
37
|
const inst: any = data[0].config;
|
|
38
|
-
if (inst.type == 'custom' && isString(inst.parameter)) {
|
|
39
|
-
inst.parameter = new Map(Object.entries(JSON.parse(inst.parameter)));
|
|
40
|
-
}
|
|
41
38
|
Integrations.set(configName, inst);
|
|
42
39
|
} else {
|
|
43
40
|
console.error(`Integration not found for ${configPath}`);
|
|
@@ -84,14 +81,26 @@ function mkApiUrl(integManagerHost: string, configPath: string): string {
|
|
|
84
81
|
const parts = configPath.split('/');
|
|
85
82
|
const integId = parts[0];
|
|
86
83
|
const configId = parts[1];
|
|
87
|
-
return `${integManagerHost}/${IntegManagerModel}/integration/${integId}/integrationConfig/config/${configId}`;
|
|
84
|
+
return `${integManagerHost}/${IntegManagerModel}/integration/${integId}/integrationConfig/config/${configId}?tree=true`;
|
|
88
85
|
}
|
|
89
86
|
|
|
90
87
|
export function getIntegrationConfig(name: string, configName: string): any {
|
|
91
88
|
const config: any = Integrations.get(name);
|
|
92
|
-
if (config)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
89
|
+
if (!config) return undefined;
|
|
90
|
+
if (config.parameter == null) return undefined;
|
|
91
|
+
|
|
92
|
+
if (config.parameter instanceof Map) {
|
|
93
|
+
return Object.fromEntries(config.parameter).get(configName);
|
|
94
|
+
}
|
|
95
|
+
if (isString(config.parameter)) {
|
|
96
|
+
try {
|
|
97
|
+
return JSON.parse(config.parameter)[configName];
|
|
98
|
+
} catch {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (typeof config.parameter === 'object') {
|
|
103
|
+
return config.parameter[configName];
|
|
96
104
|
}
|
|
105
|
+
return undefined;
|
|
97
106
|
}
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
isEntityInstance,
|
|
48
48
|
isEventInstance,
|
|
49
49
|
isInstanceOfType,
|
|
50
|
+
getAllBetweenRelationshipsForEntity,
|
|
50
51
|
isOneToOneBetweenRelationship,
|
|
51
52
|
isTimer,
|
|
52
53
|
makeInstance,
|
|
@@ -65,6 +66,7 @@ import {
|
|
|
65
66
|
DefaultModuleName,
|
|
66
67
|
escapeFqName,
|
|
67
68
|
escapeQueryName,
|
|
69
|
+
firstAliasSpec,
|
|
68
70
|
fqNameFromPath,
|
|
69
71
|
isCoreModule,
|
|
70
72
|
isFqName,
|
|
@@ -77,6 +79,7 @@ import {
|
|
|
77
79
|
preprocessRawConfig,
|
|
78
80
|
QuerySuffix,
|
|
79
81
|
restoreSpecialChars,
|
|
82
|
+
splitFqName,
|
|
80
83
|
splitRefs,
|
|
81
84
|
} from './util.js';
|
|
82
85
|
import { getResolver, getResolverNameForPath } from './resolvers/registry.js';
|
|
@@ -88,9 +91,12 @@ import {
|
|
|
88
91
|
} from '../language/parser.js';
|
|
89
92
|
import { ActiveSessionInfo, AdminSession, AdminUserId } from './auth/defs.js';
|
|
90
93
|
import {
|
|
94
|
+
AgentCancelledException,
|
|
91
95
|
AgentEntityName,
|
|
92
96
|
AgentFqName,
|
|
93
97
|
AgentInstance,
|
|
98
|
+
checkCancelled,
|
|
99
|
+
clearCancellation,
|
|
94
100
|
findAgentByName,
|
|
95
101
|
normalizeGeneratedCode,
|
|
96
102
|
saveFlowStepResult,
|
|
@@ -1133,10 +1139,11 @@ export async function evaluateStatement(stmt: Statement, env: Environment): Prom
|
|
|
1133
1139
|
handlersPushed = env.pushHandlers(handlers);
|
|
1134
1140
|
}
|
|
1135
1141
|
await evaluatePattern(stmt.pattern, env);
|
|
1142
|
+
let skipOuterAlias = false;
|
|
1136
1143
|
if (hasHints) {
|
|
1137
|
-
await maybeHandleEmpty(hints, env);
|
|
1144
|
+
skipOuterAlias = await maybeHandleEmpty(hints, env);
|
|
1138
1145
|
}
|
|
1139
|
-
if (hasHints) {
|
|
1146
|
+
if (hasHints && !skipOuterAlias) {
|
|
1140
1147
|
maybeBindStatementResultToAlias(hints, env);
|
|
1141
1148
|
}
|
|
1142
1149
|
await maybeHandleNotFound(handlers, env);
|
|
@@ -1165,7 +1172,7 @@ async function maybeHandleNotFound(handlers: CatchHandlers | undefined, env: Env
|
|
|
1165
1172
|
}
|
|
1166
1173
|
}
|
|
1167
1174
|
|
|
1168
|
-
async function maybeHandleEmpty(hints: RuntimeHint[], env: Environment) {
|
|
1175
|
+
async function maybeHandleEmpty(hints: RuntimeHint[], env: Environment): Promise<boolean> {
|
|
1169
1176
|
const lastResult: Result = env.getLastResult();
|
|
1170
1177
|
if (
|
|
1171
1178
|
lastResult === null ||
|
|
@@ -1177,10 +1184,17 @@ async function maybeHandleEmpty(hints: RuntimeHint[], env: Environment) {
|
|
|
1177
1184
|
const newEnv = new Environment('empty-env', env).unsetEventExecutor();
|
|
1178
1185
|
await evaluateStatement(rh.emptySpec.stmt, newEnv);
|
|
1179
1186
|
env.setLastResult(newEnv.getLastResult());
|
|
1187
|
+
// If inner statement has its own @as, propagate binding to parent env
|
|
1188
|
+
const innerAlias = firstAliasSpec(rh.emptySpec.stmt);
|
|
1189
|
+
if (innerAlias) {
|
|
1190
|
+
maybeBindStatementResultToAlias(rh.emptySpec.stmt.hints, env);
|
|
1191
|
+
return true; // signal: skip outer @as
|
|
1192
|
+
}
|
|
1180
1193
|
break;
|
|
1181
1194
|
}
|
|
1182
1195
|
}
|
|
1183
1196
|
}
|
|
1197
|
+
return false;
|
|
1184
1198
|
}
|
|
1185
1199
|
|
|
1186
1200
|
async function maybeHandleError(
|
|
@@ -1571,6 +1585,12 @@ function maybeSetQueryClauses(inst: Instance, qopts: ExtractedQueryOptions) {
|
|
|
1571
1585
|
if (qopts.orderByClause) {
|
|
1572
1586
|
inst.setOrderBy(qopts.orderByClause.colNames, qopts.orderByClause.order === '@desc');
|
|
1573
1587
|
}
|
|
1588
|
+
if (qopts.limitClause) {
|
|
1589
|
+
inst.setLimit(qopts.limitClause.value);
|
|
1590
|
+
}
|
|
1591
|
+
if (qopts.offsetClause) {
|
|
1592
|
+
inst.setOffset(qopts.offsetClause.value);
|
|
1593
|
+
}
|
|
1574
1594
|
}
|
|
1575
1595
|
|
|
1576
1596
|
async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
@@ -1624,7 +1644,7 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1624
1644
|
}
|
|
1625
1645
|
const res: Resolver = await getResolverForPath(entryName, moduleName, env);
|
|
1626
1646
|
let r: Instance | undefined;
|
|
1627
|
-
await computeExprAttributes(inst,
|
|
1647
|
+
await computeExprAttributes(inst, crud.body?.attributes, inst.attributes, env);
|
|
1628
1648
|
await setMetaAttributes(inst.attributes, env);
|
|
1629
1649
|
if (env.isInUpsertMode()) {
|
|
1630
1650
|
await runPreUpdateEvents(inst, env);
|
|
@@ -1913,24 +1933,98 @@ async function computeExprAttributes(
|
|
|
1913
1933
|
updatedAttrs?.forEach((v: any, k: string) => {
|
|
1914
1934
|
if (v !== undefined) newEnv.bind(k, v);
|
|
1915
1935
|
});
|
|
1936
|
+
// Bind related instances from between-relationships so that @expr references
|
|
1937
|
+
// like DeptEmployee.Department.BudgetMultiplier can be resolved via followReference.
|
|
1938
|
+
const entityFqName = inst.getFqName();
|
|
1939
|
+
const fqParts = splitFqName(entityFqName);
|
|
1940
|
+
const rels = getAllBetweenRelationshipsForEntity(fqParts[0], fqParts[1]);
|
|
1941
|
+
for (const rel of rels) {
|
|
1942
|
+
const isFirst = rel.isFirstNodeName(entityFqName);
|
|
1943
|
+
// Only bind if this entity is on a valid side for single-entity resolution
|
|
1944
|
+
if (rel.isManyToMany()) continue;
|
|
1945
|
+
if (rel.isOneToMany() && isFirst) continue;
|
|
1946
|
+
// Determine the target entity on the other side
|
|
1947
|
+
const targetNode = isFirst ? rel.node2 : rel.node1;
|
|
1948
|
+
const targetAlias = targetNode.alias;
|
|
1949
|
+
let connectedInst: Instance | undefined;
|
|
1950
|
+
// Fast path: check if the environment carries between-rel info for this relationship
|
|
1951
|
+
const betRelInfo = env.getBetweenRelInfo();
|
|
1952
|
+
if (betRelInfo && betRelInfo.relationship.name === rel.name) {
|
|
1953
|
+
connectedInst = betRelInfo.connectedInstance;
|
|
1954
|
+
} else if (inst.lookup(PathAttributeName)) {
|
|
1955
|
+
// Slow path: query the connected instance through the resolver.
|
|
1956
|
+
// Only possible if the current instance has been persisted (has a __path__).
|
|
1957
|
+
try {
|
|
1958
|
+
const targetFqName = targetNode.path.asFqName();
|
|
1959
|
+
const targetParts = splitFqName(targetFqName);
|
|
1960
|
+
const res: Resolver = await getResolverForPath(targetParts[1], targetParts[0], env);
|
|
1961
|
+
const queryInst = Instance.EmptyInstance(targetParts[1], targetParts[0]);
|
|
1962
|
+
const connected: Instance[] = await res.queryConnectedInstances(rel, inst, queryInst);
|
|
1963
|
+
if (connected && connected.length > 0) {
|
|
1964
|
+
connectedInst = connected[0];
|
|
1965
|
+
}
|
|
1966
|
+
} catch (reason: any) {
|
|
1967
|
+
logger.debug(
|
|
1968
|
+
`Relationship query failed (e.g. not yet linked) - skip binding - ${reason}`
|
|
1969
|
+
);
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
if (connectedInst) {
|
|
1973
|
+
const relMap = new Map<string, Instance>();
|
|
1974
|
+
relMap.set(targetAlias, connectedInst);
|
|
1975
|
+
newEnv.bind(rel.name, relMap);
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
// Build a map of user-provided values for @expr attributes so that
|
|
1979
|
+
// overrides are applied inline during expression evaluation, allowing
|
|
1980
|
+
// dependent expressions to see the user's value immediately.
|
|
1981
|
+
let userExprOverrides: Map<string, Expr> | undefined;
|
|
1982
|
+
if (exprAttrs && origAttrs) {
|
|
1983
|
+
for (let i = 0; i < origAttrs.length; ++i) {
|
|
1984
|
+
const a: SetAttribute = origAttrs[i];
|
|
1985
|
+
const n = a.name;
|
|
1986
|
+
if (exprAttrs.has(n) && !n.endsWith(QuerySuffix) && a.value !== undefined) {
|
|
1987
|
+
if (userExprOverrides === undefined) {
|
|
1988
|
+
userExprOverrides = new Map();
|
|
1989
|
+
}
|
|
1990
|
+
userExprOverrides.set(n, a.value);
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1916
1994
|
if (exprAttrs) {
|
|
1917
1995
|
const ks = [...exprAttrs.keys()];
|
|
1918
1996
|
for (let i = 0; i < ks.length; ++i) {
|
|
1919
1997
|
const n = ks[i];
|
|
1920
|
-
const
|
|
1921
|
-
if (
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1998
|
+
const userValue = userExprOverrides?.get(n);
|
|
1999
|
+
if (userValue !== undefined) {
|
|
2000
|
+
// User explicitly provided a value for this @expr attribute - use it
|
|
2001
|
+
await evaluateExpression(userValue, newEnv);
|
|
2002
|
+
} else {
|
|
2003
|
+
// No user override - evaluate the @expr expression
|
|
2004
|
+
const expr: Expr | undefined = exprAttrs.get(n);
|
|
2005
|
+
if (expr) {
|
|
2006
|
+
await evaluateExpression(expr, newEnv);
|
|
2007
|
+
} else {
|
|
2008
|
+
continue;
|
|
2009
|
+
}
|
|
1927
2010
|
}
|
|
2011
|
+
const v: Result = newEnv.getLastResult();
|
|
2012
|
+
newEnv.bind(n, v);
|
|
2013
|
+
inst.attributes.set(n, v);
|
|
2014
|
+
updatedAttrs?.set(n, v);
|
|
1928
2015
|
}
|
|
1929
2016
|
}
|
|
1930
|
-
|
|
2017
|
+
// Re-evaluate non-@expr attribute expressions from origAttrs in the context
|
|
2018
|
+
// of the queried instance. This handles workflow update expressions like
|
|
2019
|
+
// `balance balance + (balance * interestRate) + makeDeposit.amount` where
|
|
2020
|
+
// the local attribute references must resolve from the existing instance.
|
|
2021
|
+
// Only runs on the update path (where updatedAttrs is a separate map from
|
|
2022
|
+
// inst.attributes) to avoid double-evaluating expressions on create.
|
|
2023
|
+
if (origAttrs && updatedAttrs && updatedAttrs !== inst.attributes) {
|
|
1931
2024
|
for (let i = 0; i < origAttrs.length; ++i) {
|
|
1932
2025
|
const a: SetAttribute = origAttrs[i];
|
|
1933
2026
|
const n = a.name;
|
|
2027
|
+
if (exprAttrs?.has(n)) continue;
|
|
1934
2028
|
if (!n.endsWith(QuerySuffix) && updatedAttrs.has(n) && a.value !== undefined) {
|
|
1935
2029
|
await evaluateExpression(a.value, newEnv);
|
|
1936
2030
|
const v: Result = newEnv.getLastResult();
|
|
@@ -2085,6 +2179,8 @@ async function agentInvoke(agent: AgentInstance, msg: string, env: Environment):
|
|
|
2085
2179
|
console.debug(invokeDebugMsg);
|
|
2086
2180
|
//
|
|
2087
2181
|
|
|
2182
|
+
const agentChatId = env.getAgentChatId() || env.getActiveChatId() || '';
|
|
2183
|
+
await clearCancellation(agentChatId);
|
|
2088
2184
|
const monitoringEnabled = isMonitoringEnabled();
|
|
2089
2185
|
|
|
2090
2186
|
await agent.invoke(msg, env);
|
|
@@ -2101,6 +2197,7 @@ async function agentInvoke(agent: AgentInstance, msg: string, env: Environment):
|
|
|
2101
2197
|
}
|
|
2102
2198
|
let retries = 0;
|
|
2103
2199
|
while (true) {
|
|
2200
|
+
await checkCancelled(agentChatId);
|
|
2104
2201
|
try {
|
|
2105
2202
|
let rs: string = result ? normalizeGeneratedCode(result) : '';
|
|
2106
2203
|
if (agent.tools) {
|
|
@@ -2162,6 +2259,7 @@ async function agentInvoke(agent: AgentInstance, msg: string, env: Environment):
|
|
|
2162
2259
|
} else {
|
|
2163
2260
|
let retries = 0;
|
|
2164
2261
|
while (true) {
|
|
2262
|
+
await checkCancelled(agentChatId);
|
|
2165
2263
|
try {
|
|
2166
2264
|
result = normalizeGeneratedCode(result);
|
|
2167
2265
|
const obj = agent.maybeValidateJsonResponse(result);
|
|
@@ -2287,9 +2385,11 @@ async function iterateOnFlow(
|
|
|
2287
2385
|
rootAgent.disableSession();
|
|
2288
2386
|
const chatId = env.getActiveEventInstance()?.lookup('chatId');
|
|
2289
2387
|
const iterId = chatId || crypto.randomUUID();
|
|
2388
|
+
await clearCancellation(iterId);
|
|
2290
2389
|
let step = '';
|
|
2291
2390
|
let fullFlowRetries = 0;
|
|
2292
2391
|
while (true) {
|
|
2392
|
+
await checkCancelled(iterId);
|
|
2293
2393
|
try {
|
|
2294
2394
|
const initContext = msg;
|
|
2295
2395
|
const s = `Now consider the following flowchart and return the next step:\n${flow}\n
|
|
@@ -2312,6 +2412,7 @@ async function iterateOnFlow(
|
|
|
2312
2412
|
env.flagMonitorEntryAsFlow().incrementMonitor();
|
|
2313
2413
|
}
|
|
2314
2414
|
while (step != 'DONE' && !executedSteps.has(step)) {
|
|
2415
|
+
await checkCancelled(iterId);
|
|
2315
2416
|
if (stepc > MaxFlowSteps) {
|
|
2316
2417
|
throw new Error(`Flow execution exceeded maximum steps limit`);
|
|
2317
2418
|
}
|
|
@@ -2366,6 +2467,9 @@ async function iterateOnFlow(
|
|
|
2366
2467
|
needAgentProcessing = preprocResult.needAgentProcessing;
|
|
2367
2468
|
}
|
|
2368
2469
|
} catch (reason: any) {
|
|
2470
|
+
if (reason instanceof AgentCancelledException) {
|
|
2471
|
+
throw reason;
|
|
2472
|
+
}
|
|
2369
2473
|
if (fullFlowRetries < MaxFlowRetries) {
|
|
2370
2474
|
msg = `The previous attempt failed at step ${step} with the error ${reason}. Restart the flow the appropriate step
|
|
2371
2475
|
(maybe even from the first step) and try to fix the issue.`;
|
|
@@ -2598,6 +2702,32 @@ export async function evaluateExpression(expr: Expr, env: Environment): Promise<
|
|
|
2598
2702
|
env.setLastResult(result);
|
|
2599
2703
|
}
|
|
2600
2704
|
|
|
2705
|
+
export function extractRefsFromExpr(expr: Expr): string[] {
|
|
2706
|
+
const refs: string[] = [];
|
|
2707
|
+
function walk(e: Expr) {
|
|
2708
|
+
if (isBinExpr(e)) {
|
|
2709
|
+
walk(e.e1);
|
|
2710
|
+
walk(e.e2);
|
|
2711
|
+
} else if (isLiteral(e)) {
|
|
2712
|
+
if (e.ref) refs.push(e.ref);
|
|
2713
|
+
if (e.fnCall) {
|
|
2714
|
+
for (const arg of e.fnCall.args) walk(arg);
|
|
2715
|
+
}
|
|
2716
|
+
if (e.asyncFnCall) {
|
|
2717
|
+
for (const arg of e.asyncFnCall.fnCall.args) walk(arg);
|
|
2718
|
+
}
|
|
2719
|
+
} else if (isGroup(e)) {
|
|
2720
|
+
walk(e.ge);
|
|
2721
|
+
} else if (isNegExpr(e)) {
|
|
2722
|
+
walk(e.ne);
|
|
2723
|
+
} else if (isNotExpr(e)) {
|
|
2724
|
+
walk(e.ne);
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
walk(expr);
|
|
2728
|
+
return refs;
|
|
2729
|
+
}
|
|
2730
|
+
|
|
2601
2731
|
async function getRef(r: string, src: any, env: Environment): Promise<Result> {
|
|
2602
2732
|
if (Instance.IsInstance(src)) return src.lookup(r);
|
|
2603
2733
|
else if (src instanceof Map) return src.get(r);
|