agentlang 0.10.8 → 0.11.0
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 +60 -0
- package/out/api/http.d.ts.map +1 -1
- package/out/api/http.js +64 -39
- package/out/api/http.js.map +1 -1
- package/out/cli/main.d.ts +1 -1
- package/out/cli/main.d.ts.map +1 -1
- package/out/cli/main.js +7 -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/main.cjs +504 -504
- package/out/language/main.cjs.map +3 -3
- package/out/runtime/auth/cognito.d.ts.map +1 -1
- package/out/runtime/auth/cognito.js +129 -64
- package/out/runtime/auth/cognito.js.map +1 -1
- package/out/runtime/defs.d.ts +22 -9
- package/out/runtime/defs.d.ts.map +1 -1
- package/out/runtime/defs.js +44 -9
- 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/errors/coded-error.d.ts +8 -0
- package/out/runtime/errors/coded-error.d.ts.map +1 -0
- package/out/runtime/errors/coded-error.js +13 -0
- package/out/runtime/errors/coded-error.js.map +1 -0
- package/out/runtime/errors/http-error.d.ts +25 -0
- package/out/runtime/errors/http-error.d.ts.map +1 -0
- package/out/runtime/errors/http-error.js +169 -0
- package/out/runtime/errors/http-error.js.map +1 -0
- package/out/runtime/excel-resolver.d.ts +4 -0
- package/out/runtime/excel-resolver.d.ts.map +1 -0
- package/out/runtime/excel-resolver.js +96 -0
- package/out/runtime/excel-resolver.js.map +1 -0
- package/out/runtime/excel.d.ts +25 -0
- package/out/runtime/excel.d.ts.map +1 -0
- package/out/runtime/excel.js +127 -0
- package/out/runtime/excel.js.map +1 -0
- package/out/runtime/exec-graph-cache.d.ts +5 -0
- package/out/runtime/exec-graph-cache.d.ts.map +1 -0
- package/out/runtime/exec-graph-cache.js +9 -0
- package/out/runtime/exec-graph-cache.js.map +1 -0
- package/out/runtime/exec-graph.d.ts.map +1 -1
- package/out/runtime/exec-graph.js +2 -1
- package/out/runtime/exec-graph.js.map +1 -1
- package/out/runtime/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +30 -27
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/loader.d.ts.map +1 -1
- package/out/runtime/loader.js +5 -1
- package/out/runtime/loader.js.map +1 -1
- package/out/runtime/logger.d.ts +6 -0
- package/out/runtime/logger.d.ts.map +1 -1
- package/out/runtime/logger.js +21 -0
- package/out/runtime/logger.js.map +1 -1
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +14 -13
- package/out/runtime/module.js.map +1 -1
- package/out/runtime/modules/ai.d.ts +2 -1
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +7 -2
- package/out/runtime/modules/ai.js.map +1 -1
- package/out/runtime/modules/auth.d.ts.map +1 -1
- package/out/runtime/modules/auth.js +44 -16
- package/out/runtime/modules/auth.js.map +1 -1
- package/out/runtime/modules/core.d.ts +6 -0
- package/out/runtime/modules/core.d.ts.map +1 -1
- package/out/runtime/modules/core.js +20 -0
- package/out/runtime/modules/core.js.map +1 -1
- package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/database.js +76 -39
- package/out/runtime/resolvers/sqldb/database.js.map +1 -1
- package/out/runtime/resolvers/sqldb/db-errors.d.ts +6 -0
- package/out/runtime/resolvers/sqldb/db-errors.d.ts.map +1 -0
- package/out/runtime/resolvers/sqldb/db-errors.js +100 -0
- package/out/runtime/resolvers/sqldb/db-errors.js.map +1 -0
- 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/state.d.ts +3 -0
- package/out/runtime/state.d.ts.map +1 -1
- package/out/runtime/state.js +7 -0
- package/out/runtime/state.js.map +1 -1
- package/out/setupClassic.d.ts +98 -0
- package/out/setupClassic.d.ts.map +1 -0
- package/out/setupClassic.js +38 -0
- package/out/setupClassic.js.map +1 -0
- package/out/setupCommon.d.ts +2 -0
- package/out/setupCommon.d.ts.map +1 -0
- package/out/setupCommon.js +33 -0
- package/out/setupCommon.js.map +1 -0
- package/out/setupExtended.d.ts +40 -0
- package/out/setupExtended.d.ts.map +1 -0
- package/out/setupExtended.js +67 -0
- package/out/setupExtended.js.map +1 -0
- package/package.json +19 -18
- package/src/api/http.ts +71 -37
- package/src/cli/main.ts +12 -4
- package/src/runtime/auth/cognito.ts +187 -65
- package/src/runtime/defs.ts +51 -18
- package/src/runtime/errors/coded-error.ts +18 -0
- package/src/runtime/errors/http-error.ts +197 -0
- package/src/runtime/exec-graph-cache.ts +12 -0
- package/src/runtime/exec-graph.ts +2 -2
- package/src/runtime/interpreter.ts +73 -28
- package/src/runtime/loader.ts +5 -0
- package/src/runtime/logger.ts +27 -0
- package/src/runtime/module.ts +45 -13
- package/src/runtime/modules/ai.ts +11 -2
- package/src/runtime/modules/auth.ts +45 -18
- package/src/runtime/modules/core.ts +26 -0
- package/src/runtime/resolvers/sqldb/database.ts +88 -37
- package/src/runtime/resolvers/sqldb/db-errors.ts +113 -0
- package/src/runtime/state.ts +7 -0
- package/src/xlsx.d.ts +17 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Stable bucket for errors without an explicit code. */
|
|
2
|
+
export const AL_RUNTIME_UNHANDLED = 'AL_RUNTIME_UNHANDLED';
|
|
3
|
+
|
|
4
|
+
export type CodedError = Error & { agentlangCode: string };
|
|
5
|
+
|
|
6
|
+
export function createCodedError(message: string, code: string): CodedError {
|
|
7
|
+
const e = new Error(message) as CodedError;
|
|
8
|
+
e.agentlangCode = code;
|
|
9
|
+
return e;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function isCodedError(err: unknown): err is CodedError {
|
|
13
|
+
return (
|
|
14
|
+
err instanceof Error &&
|
|
15
|
+
typeof (err as CodedError).agentlangCode === 'string' &&
|
|
16
|
+
(err as CodedError).agentlangCode.length > 0
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { AgentCancelledException } from '../modules/ai.js';
|
|
2
|
+
import { lookupCustomErrorMessage } from '../modules/core.js';
|
|
3
|
+
import {
|
|
4
|
+
BadRequestError,
|
|
5
|
+
CodeMismatchError,
|
|
6
|
+
ExpiredCodeError,
|
|
7
|
+
InvalidParameterError,
|
|
8
|
+
PasswordResetRequiredError,
|
|
9
|
+
TooManyRequestsError,
|
|
10
|
+
UnauthorisedError,
|
|
11
|
+
UserNotConfirmedError,
|
|
12
|
+
UserNotFoundError,
|
|
13
|
+
} from '../defs.js';
|
|
14
|
+
import { errorFileLogger, logger } from '../logger.js';
|
|
15
|
+
import { AppConfig } from '../state.js';
|
|
16
|
+
import { AL_RUNTIME_UNHANDLED, isCodedError } from './coded-error.js';
|
|
17
|
+
|
|
18
|
+
/** Registry of Tier-1 HTTP-facing error codes (documentation / consistency). */
|
|
19
|
+
export const AgentlangErrorCodes = {
|
|
20
|
+
AL_RUNTIME_UNHANDLED,
|
|
21
|
+
AL_HTTP_AUTH_REQUIRED: 'AL_HTTP_AUTH_REQUIRED',
|
|
22
|
+
AL_HTTP_HANDLER_EXCEPTION: 'AL_HTTP_HANDLER_EXCEPTION',
|
|
23
|
+
} as const;
|
|
24
|
+
|
|
25
|
+
/** `target` value of an override that applies to any entity for a given code. */
|
|
26
|
+
const UNIVERSAL_TARGET = '*';
|
|
27
|
+
|
|
28
|
+
/** Replace `{{code}}` and `{{message}}` with runtime values (iterates until stable). */
|
|
29
|
+
export function applyErrorMessageTemplate(
|
|
30
|
+
template: string,
|
|
31
|
+
code: string,
|
|
32
|
+
originalMessage: string
|
|
33
|
+
): string {
|
|
34
|
+
let out = template;
|
|
35
|
+
const maxPasses = 10;
|
|
36
|
+
for (let i = 0; i < maxPasses; i++) {
|
|
37
|
+
const next = out.replace(/\{\{code\}\}/g, code).replace(/\{\{message\}\}/g, originalMessage);
|
|
38
|
+
if (next === out) break;
|
|
39
|
+
out = next;
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function customMessagesEnabled(): boolean {
|
|
45
|
+
return AppConfig?.customErrorMessages?.enabled === true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* When custom error messages are enabled, append the error to a dedicated
|
|
50
|
+
* `logs/errors-<DATE>.log` file as a single line: timestamp (added by the logger),
|
|
51
|
+
* error code, and error message. No-op when custom messages are disabled.
|
|
52
|
+
*/
|
|
53
|
+
export function recordCustomError(code: string, message: string): void {
|
|
54
|
+
if (!customMessagesEnabled()) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
errorFileLogger?.error(`${code} ${message}`);
|
|
59
|
+
} catch (e) {
|
|
60
|
+
logger.warn(`Failed to write error to errors log file: ${e}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function getErrorCode(err: unknown): string {
|
|
65
|
+
if (isCodedError(err)) {
|
|
66
|
+
return err.agentlangCode;
|
|
67
|
+
}
|
|
68
|
+
if (err instanceof UnauthorisedError) {
|
|
69
|
+
return err.agentlangCode;
|
|
70
|
+
}
|
|
71
|
+
if (err instanceof BadRequestError) {
|
|
72
|
+
return err.agentlangCode;
|
|
73
|
+
}
|
|
74
|
+
if (err instanceof UserNotFoundError) {
|
|
75
|
+
return err.agentlangCode;
|
|
76
|
+
}
|
|
77
|
+
if (err instanceof UserNotConfirmedError) {
|
|
78
|
+
return err.agentlangCode;
|
|
79
|
+
}
|
|
80
|
+
if (err instanceof PasswordResetRequiredError) {
|
|
81
|
+
return err.agentlangCode;
|
|
82
|
+
}
|
|
83
|
+
if (err instanceof TooManyRequestsError) {
|
|
84
|
+
return err.agentlangCode;
|
|
85
|
+
}
|
|
86
|
+
if (err instanceof InvalidParameterError) {
|
|
87
|
+
return err.agentlangCode;
|
|
88
|
+
}
|
|
89
|
+
if (err instanceof ExpiredCodeError) {
|
|
90
|
+
return err.agentlangCode;
|
|
91
|
+
}
|
|
92
|
+
if (err instanceof CodeMismatchError) {
|
|
93
|
+
return err.agentlangCode;
|
|
94
|
+
}
|
|
95
|
+
if (err instanceof AgentCancelledException) {
|
|
96
|
+
return err.agentlangCode;
|
|
97
|
+
}
|
|
98
|
+
return AL_RUNTIME_UNHANDLED;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Resolve the message for an entity-route error from the `agentlang/errorMessage`
|
|
103
|
+
* system entity. An entity-specific override (`module/Entry`) wins over a universal
|
|
104
|
+
* (`*`) one for the same code; falls back to `defaultMessage` when neither exists or
|
|
105
|
+
* when custom messages are disabled.
|
|
106
|
+
*/
|
|
107
|
+
export async function resolveEntityErrorMessage(
|
|
108
|
+
moduleName: string,
|
|
109
|
+
entryName: string,
|
|
110
|
+
code: string,
|
|
111
|
+
defaultMessage: string
|
|
112
|
+
): Promise<string> {
|
|
113
|
+
if (!customMessagesEnabled()) {
|
|
114
|
+
return defaultMessage;
|
|
115
|
+
}
|
|
116
|
+
let template: string | undefined;
|
|
117
|
+
try {
|
|
118
|
+
const entityKey = `${moduleName}/${entryName}`;
|
|
119
|
+
template =
|
|
120
|
+
(await lookupCustomErrorMessage(entityKey, code)) ??
|
|
121
|
+
(await lookupCustomErrorMessage(UNIVERSAL_TARGET, code));
|
|
122
|
+
} catch (e) {
|
|
123
|
+
logger.warn(`Failed to resolve custom error message for code ${code}: ${e}`);
|
|
124
|
+
return defaultMessage;
|
|
125
|
+
}
|
|
126
|
+
if (template === undefined) {
|
|
127
|
+
return defaultMessage;
|
|
128
|
+
}
|
|
129
|
+
return applyErrorMessageTemplate(template, code, defaultMessage);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function httpStatusFromError(err: unknown): number {
|
|
133
|
+
const ec = getErrorCode(err);
|
|
134
|
+
if (ec === 'AL_DB_UNIQUE_VIOLATION') {
|
|
135
|
+
return 409;
|
|
136
|
+
}
|
|
137
|
+
if (
|
|
138
|
+
ec === 'AL_DB_FOREIGN_KEY_VIOLATION' ||
|
|
139
|
+
ec === 'AL_DB_NOT_NULL_VIOLATION' ||
|
|
140
|
+
ec === 'AL_DB_CHECK_VIOLATION' ||
|
|
141
|
+
ec === 'AL_DB_INVALID_TYPE' ||
|
|
142
|
+
ec === 'AL_MOD_TYPE_MISMATCH' ||
|
|
143
|
+
ec === 'AL_MOD_INVALID_ATTR'
|
|
144
|
+
) {
|
|
145
|
+
return 400;
|
|
146
|
+
}
|
|
147
|
+
if (
|
|
148
|
+
ec === 'AL_DB_DEADLOCK' ||
|
|
149
|
+
ec === 'AL_DB_LOCK_WAIT_TIMEOUT' ||
|
|
150
|
+
ec === 'AL_DB_SERIALIZATION_FAILURE'
|
|
151
|
+
) {
|
|
152
|
+
return 503;
|
|
153
|
+
}
|
|
154
|
+
if (ec === 'AL_DB_SYNTAX_ERROR' || ec === 'AL_DB_QUERY_FAILED') {
|
|
155
|
+
return 500;
|
|
156
|
+
}
|
|
157
|
+
if (err instanceof UserNotFoundError) {
|
|
158
|
+
return 404;
|
|
159
|
+
}
|
|
160
|
+
if (err instanceof UnauthorisedError) {
|
|
161
|
+
return 401;
|
|
162
|
+
}
|
|
163
|
+
if (err instanceof TooManyRequestsError) {
|
|
164
|
+
return 429;
|
|
165
|
+
}
|
|
166
|
+
if (err instanceof BadRequestError || err instanceof InvalidParameterError) {
|
|
167
|
+
return 400;
|
|
168
|
+
}
|
|
169
|
+
if (err instanceof ExpiredCodeError || err instanceof CodeMismatchError) {
|
|
170
|
+
return 400;
|
|
171
|
+
}
|
|
172
|
+
if (err instanceof UserNotConfirmedError || err instanceof PasswordResetRequiredError) {
|
|
173
|
+
return 403;
|
|
174
|
+
}
|
|
175
|
+
if (err instanceof Error && err.message) {
|
|
176
|
+
if (
|
|
177
|
+
err.message.includes('temporarily unavailable') ||
|
|
178
|
+
err.message.includes('service error') ||
|
|
179
|
+
err.message.includes('configuration error')
|
|
180
|
+
) {
|
|
181
|
+
return 503;
|
|
182
|
+
}
|
|
183
|
+
if (err.message.includes('contact support')) {
|
|
184
|
+
return 500;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return 500;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function logEntityRouteError(reason: unknown, agentlangCode: string): void {
|
|
191
|
+
if (reason instanceof Error) {
|
|
192
|
+
const stack = reason.stack ? `\n${reason.stack}` : '';
|
|
193
|
+
logger.error(`[${agentlangCode}] ${reason.name}: ${reason.message}${stack}`);
|
|
194
|
+
} else {
|
|
195
|
+
logger.error(`[${agentlangCode}] ${String(reason)}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ExecGraph } from './defs.js';
|
|
2
|
+
|
|
3
|
+
const graphCache = new Map<string, ExecGraph>();
|
|
4
|
+
|
|
5
|
+
/** Drop cached graphs so workflow/agent structure changes after module reload are picked up. */
|
|
6
|
+
export function clearExecutionGraphCache(): void {
|
|
7
|
+
graphCache.clear();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getExecutionGraphCache(): Map<string, ExecGraph> {
|
|
11
|
+
return graphCache;
|
|
12
|
+
}
|
|
@@ -56,10 +56,10 @@ import {
|
|
|
56
56
|
makeFqName,
|
|
57
57
|
nameToPath,
|
|
58
58
|
} from './util.js';
|
|
59
|
-
|
|
60
|
-
const GraphCache = new Map<string, ExecGraph>();
|
|
59
|
+
import { getExecutionGraphCache } from './exec-graph-cache.js';
|
|
61
60
|
|
|
62
61
|
export async function generateExecutionGraph(eventName: string): Promise<ExecGraph | undefined> {
|
|
62
|
+
const GraphCache = getExecutionGraphCache();
|
|
63
63
|
const cg = GraphCache.get(eventName);
|
|
64
64
|
if (cg) return cg;
|
|
65
65
|
const wf = getWorkflowForEvent(eventName);
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
import {
|
|
35
35
|
Agent,
|
|
36
36
|
defineAgentEvent,
|
|
37
|
+
eventAgentName,
|
|
37
38
|
Event,
|
|
38
39
|
getOneOfRef,
|
|
39
40
|
getRelationship,
|
|
@@ -127,6 +128,7 @@ import { detailedDiff } from 'deep-object-diff';
|
|
|
127
128
|
import { callMcpTool, mcpClientNameFromToolEvent } from './mcpclient.js';
|
|
128
129
|
import { isNodeEnv } from '../utils/runtime.js';
|
|
129
130
|
import Handlebars from 'handlebars';
|
|
131
|
+
import { createCodedError } from './errors/coded-error.js';
|
|
130
132
|
|
|
131
133
|
export type Result = any;
|
|
132
134
|
|
|
@@ -445,7 +447,11 @@ export class Environment extends Instance {
|
|
|
445
447
|
|
|
446
448
|
setActiveEvent(eventInst: Instance | undefined): Environment {
|
|
447
449
|
if (eventInst) {
|
|
448
|
-
if (!isEventInstance(eventInst))
|
|
450
|
+
if (!isEventInstance(eventInst))
|
|
451
|
+
throw createCodedError(
|
|
452
|
+
`Not an event instance - ${eventInst.name}`,
|
|
453
|
+
'AL_INT_NOT_EVENT_INSTANCE'
|
|
454
|
+
);
|
|
449
455
|
this.bindInstance(eventInst);
|
|
450
456
|
this.activeModule = eventInst.moduleName;
|
|
451
457
|
this.activeEventInstance = eventInst;
|
|
@@ -531,7 +537,7 @@ export class Environment extends Instance {
|
|
|
531
537
|
if (this.suspensionId) {
|
|
532
538
|
return this.suspensionId;
|
|
533
539
|
} else {
|
|
534
|
-
throw
|
|
540
|
+
throw createCodedError('SuspensionId is not set', 'AL_INT_SUSPENSION_ID_NOT_SET');
|
|
535
541
|
}
|
|
536
542
|
}
|
|
537
543
|
|
|
@@ -681,7 +687,7 @@ export class Environment extends Instance {
|
|
|
681
687
|
this.activeTransactions.set(n, txnId);
|
|
682
688
|
return txnId;
|
|
683
689
|
} else {
|
|
684
|
-
throw
|
|
690
|
+
throw createCodedError(`Failed to start transaction for ${n}`, 'AL_INT_TXN_START_FAILED');
|
|
685
691
|
}
|
|
686
692
|
}
|
|
687
693
|
}
|
|
@@ -773,7 +779,7 @@ export class Environment extends Instance {
|
|
|
773
779
|
popHandlers(): CatchHandlers {
|
|
774
780
|
const r = this.activeCatchHandlers.pop();
|
|
775
781
|
if (r === undefined) {
|
|
776
|
-
throw
|
|
782
|
+
throw createCodedError(`No more handlers to pop`, 'AL_INT_NO_HANDLERS_TO_POP');
|
|
777
783
|
}
|
|
778
784
|
return r;
|
|
779
785
|
}
|
|
@@ -999,7 +1005,7 @@ export let evaluate = async function (
|
|
|
999
1005
|
return null;
|
|
1000
1006
|
}
|
|
1001
1007
|
} else {
|
|
1002
|
-
throw
|
|
1008
|
+
throw createCodedError('Not an event - ' + eventInstance.name, 'AL_INT_NOT_AN_EVENT');
|
|
1003
1009
|
}
|
|
1004
1010
|
} catch (err) {
|
|
1005
1011
|
if (env && env.hasHandlers()) {
|
|
@@ -1096,7 +1102,10 @@ async function evaluateAsyncPattern(
|
|
|
1096
1102
|
if (s.$cstNode) {
|
|
1097
1103
|
return s.$cstNode.text;
|
|
1098
1104
|
} else {
|
|
1099
|
-
throw
|
|
1105
|
+
throw createCodedError(
|
|
1106
|
+
'failed to extract code for suspension statement',
|
|
1107
|
+
'AL_INT_SUSPENSION_CODE_EXTRACT'
|
|
1108
|
+
);
|
|
1100
1109
|
}
|
|
1101
1110
|
}),
|
|
1102
1111
|
env
|
|
@@ -1386,7 +1395,7 @@ export async function evaluatePattern(
|
|
|
1386
1395
|
|
|
1387
1396
|
async function evaluateThrowError(throwErr: ThrowError, env: Environment) {
|
|
1388
1397
|
await evaluateExpression(throwErr.reason, env);
|
|
1389
|
-
throw
|
|
1398
|
+
throw createCodedError(String(env.getLastResult()), 'AL_INT_USER_THROW');
|
|
1390
1399
|
}
|
|
1391
1400
|
|
|
1392
1401
|
async function evaluateFullTextSearch(fts: FullTextSearch, env: Environment): Promise<void> {
|
|
@@ -1396,7 +1405,10 @@ async function evaluateFullTextSearch(fts: FullTextSearch, env: Environment): Pr
|
|
|
1396
1405
|
if (inst) {
|
|
1397
1406
|
n = makeFqName(inst.moduleName, n);
|
|
1398
1407
|
} else {
|
|
1399
|
-
throw
|
|
1408
|
+
throw createCodedError(
|
|
1409
|
+
`Fully qualified name required for full-text-search in ${n}`,
|
|
1410
|
+
'AL_INT_FTS_FQN_REQUIRED'
|
|
1411
|
+
);
|
|
1400
1412
|
}
|
|
1401
1413
|
}
|
|
1402
1414
|
const path = nameToPath(n);
|
|
@@ -1406,7 +1418,10 @@ async function evaluateFullTextSearch(fts: FullTextSearch, env: Environment): Pr
|
|
|
1406
1418
|
await evaluateLiteral(fts.query, env);
|
|
1407
1419
|
const q = env.getLastResult();
|
|
1408
1420
|
if (!isString(q)) {
|
|
1409
|
-
throw
|
|
1421
|
+
throw createCodedError(
|
|
1422
|
+
`Full text search query must be a string - ${q}`,
|
|
1423
|
+
'AL_INT_FTS_QUERY_STRING'
|
|
1424
|
+
);
|
|
1410
1425
|
}
|
|
1411
1426
|
let options: Map<string, any> | undefined;
|
|
1412
1427
|
if (fts.options) {
|
|
@@ -1526,7 +1541,10 @@ async function patternToInstance(
|
|
|
1526
1541
|
let aname: string = a.name;
|
|
1527
1542
|
if (aname.endsWith(QuerySuffix)) {
|
|
1528
1543
|
if (isQueryAll) {
|
|
1529
|
-
throw
|
|
1544
|
+
throw createCodedError(
|
|
1545
|
+
`Cannot specifiy query attribute ${aname} here`,
|
|
1546
|
+
'AL_INT_QUERY_ATTR_FORBIDDEN'
|
|
1547
|
+
);
|
|
1530
1548
|
}
|
|
1531
1549
|
if (qattrs === undefined) qattrs = newInstanceAttributes();
|
|
1532
1550
|
if (qattrVals === undefined) qattrVals = newInstanceAttributes();
|
|
@@ -1569,11 +1587,15 @@ async function instanceFromSource(crud: CrudMap, env: Environment): Promise<Inst
|
|
|
1569
1587
|
const m = nparts.hasModule() ? nparts.getModuleName() : env.getActiveModuleName();
|
|
1570
1588
|
return makeInstance(m, n, attrs);
|
|
1571
1589
|
} else {
|
|
1572
|
-
throw
|
|
1590
|
+
throw createCodedError(
|
|
1591
|
+
`Failed to initialize instance of ${crud.name}, expected a map after @from.`,
|
|
1592
|
+
'AL_INT_CRUD_INIT_MAP_EXPECTED'
|
|
1593
|
+
);
|
|
1573
1594
|
}
|
|
1574
1595
|
} else {
|
|
1575
|
-
throw
|
|
1576
|
-
`Cannot create instance of ${crud.name}, CRUD pattern does not specify a source map
|
|
1596
|
+
throw createCodedError(
|
|
1597
|
+
`Cannot create instance of ${crud.name}, CRUD pattern does not specify a source map.`,
|
|
1598
|
+
'AL_INT_CRUD_NO_SOURCE_MAP'
|
|
1577
1599
|
);
|
|
1578
1600
|
}
|
|
1579
1601
|
}
|
|
@@ -1588,7 +1610,7 @@ async function maybeValidateOneOfRefs(inst: Instance, env: Environment) {
|
|
|
1588
1610
|
const attrSpec = inst.record.schema.get(n);
|
|
1589
1611
|
if (!attrSpec) continue;
|
|
1590
1612
|
const r = getOneOfRef(attrSpec);
|
|
1591
|
-
if (!r) throw
|
|
1613
|
+
if (!r) throw createCodedError(`Failed to fetch one-of-ref for ${n}`, 'AL_INT_ONEOF_REF_FETCH');
|
|
1592
1614
|
if (r) {
|
|
1593
1615
|
const parts = r.split('.');
|
|
1594
1616
|
const insts = await lookupOneOfVals(parts[0], env);
|
|
@@ -1601,7 +1623,7 @@ async function maybeValidateOneOfRefs(inst: Instance, env: Environment) {
|
|
|
1601
1623
|
return i.lookup(parts[1]) == v;
|
|
1602
1624
|
})
|
|
1603
1625
|
) {
|
|
1604
|
-
throw
|
|
1626
|
+
throw createCodedError(`Invalid enum-value ${v} for ${n}`, 'AL_INT_INVALID_ENUM');
|
|
1605
1627
|
}
|
|
1606
1628
|
}
|
|
1607
1629
|
}
|
|
@@ -1655,12 +1677,16 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1655
1677
|
}
|
|
1656
1678
|
if (qopts.into) {
|
|
1657
1679
|
if (attrs.size > 0) {
|
|
1658
|
-
throw
|
|
1659
|
-
`Query pattern for ${entryName} with 'into' clause cannot be used to update attributes
|
|
1680
|
+
throw createCodedError(
|
|
1681
|
+
`Query pattern for ${entryName} with 'into' clause cannot be used to update attributes`,
|
|
1682
|
+
'AL_INT_INTO_WITH_ATTRS'
|
|
1660
1683
|
);
|
|
1661
1684
|
}
|
|
1662
1685
|
if (qattrs === undefined && !isQueryAll) {
|
|
1663
|
-
throw
|
|
1686
|
+
throw createCodedError(
|
|
1687
|
+
`Pattern for ${entryName} with 'into' clause must be a query`,
|
|
1688
|
+
'AL_INT_INTO_MUST_BE_QUERY'
|
|
1689
|
+
);
|
|
1664
1690
|
}
|
|
1665
1691
|
if (qopts.joins && qopts.joins.length > 0) {
|
|
1666
1692
|
await evaluateJoinQuery(qopts.joins, qopts.into, qopts.where, inst, distinct, env);
|
|
@@ -1913,7 +1939,10 @@ async function handleDocEvent(inst: Instance, env: Environment): Promise<void> {
|
|
|
1913
1939
|
const url = inst.lookup('url');
|
|
1914
1940
|
if (typeof url === 'string' && url.startsWith('s3://')) {
|
|
1915
1941
|
if (!isNodeEnv) {
|
|
1916
|
-
throw
|
|
1942
|
+
throw createCodedError(
|
|
1943
|
+
'Document fetching is only available in Node.js environment',
|
|
1944
|
+
'AL_INT_DOC_FETCH_NODE_ONLY'
|
|
1945
|
+
);
|
|
1917
1946
|
}
|
|
1918
1947
|
const title = inst.lookup('title');
|
|
1919
1948
|
const retrievalConfig = inst.lookup('retrievalConfig');
|
|
@@ -2212,7 +2241,10 @@ async function walkJoinQueryPattern(
|
|
|
2212
2241
|
});
|
|
2213
2242
|
return joinsSpec;
|
|
2214
2243
|
} else {
|
|
2215
|
-
throw
|
|
2244
|
+
throw createCodedError(
|
|
2245
|
+
`Expected a query for relationship ${rp.name}`,
|
|
2246
|
+
'AL_INT_RELATIONSHIP_QUERY_EXPECTED'
|
|
2247
|
+
);
|
|
2216
2248
|
}
|
|
2217
2249
|
}
|
|
2218
2250
|
|
|
@@ -2337,10 +2369,13 @@ async function agentInvoke(agent: AgentInstance, msg: string, env: Environment):
|
|
|
2337
2369
|
}
|
|
2338
2370
|
}
|
|
2339
2371
|
} else {
|
|
2340
|
-
throw
|
|
2372
|
+
throw createCodedError(
|
|
2373
|
+
`Agent ${agent.name} failed to generate a response`,
|
|
2374
|
+
'AL_INT_AGENT_NO_RESPONSE'
|
|
2375
|
+
);
|
|
2341
2376
|
}
|
|
2342
2377
|
if (agentInternalError !== undefined) {
|
|
2343
|
-
throw
|
|
2378
|
+
throw createCodedError(agentInternalError, 'AL_INT_AGENT_INTERNAL');
|
|
2344
2379
|
}
|
|
2345
2380
|
}
|
|
2346
2381
|
|
|
@@ -2348,7 +2383,8 @@ export async function handleAgentInvocation(
|
|
|
2348
2383
|
agentEventInst: Instance,
|
|
2349
2384
|
env: Environment
|
|
2350
2385
|
): Promise<void> {
|
|
2351
|
-
const
|
|
2386
|
+
const agentLookupName = eventAgentName(agentEventInst) ?? agentEventInst.name;
|
|
2387
|
+
const agent: AgentInstance = await findAgentByName(agentLookupName, env);
|
|
2352
2388
|
if (agent.role) {
|
|
2353
2389
|
env.setAssumedRole(agent.role);
|
|
2354
2390
|
}
|
|
@@ -2467,7 +2503,10 @@ async function iterateOnFlow(
|
|
|
2467
2503
|
while (step != 'DONE' && !executedSteps.has(step)) {
|
|
2468
2504
|
await checkCancelled(iterId);
|
|
2469
2505
|
if (stepc > MaxFlowSteps) {
|
|
2470
|
-
throw
|
|
2506
|
+
throw createCodedError(
|
|
2507
|
+
`Flow execution exceeded maximum steps limit`,
|
|
2508
|
+
'AL_INT_FLOW_MAX_STEPS'
|
|
2509
|
+
);
|
|
2471
2510
|
}
|
|
2472
2511
|
executedSteps.add(step);
|
|
2473
2512
|
++stepc;
|
|
@@ -2529,7 +2568,10 @@ async function iterateOnFlow(
|
|
|
2529
2568
|
++fullFlowRetries;
|
|
2530
2569
|
continue;
|
|
2531
2570
|
} else {
|
|
2532
|
-
throw
|
|
2571
|
+
throw createCodedError(
|
|
2572
|
+
typeof reason === 'string' ? reason : String(reason),
|
|
2573
|
+
'AL_INT_FLOW_FATAL'
|
|
2574
|
+
);
|
|
2533
2575
|
}
|
|
2534
2576
|
} finally {
|
|
2535
2577
|
env.decrementMonitor().revokeLastResult().setMonitorFlowResult();
|
|
@@ -2737,7 +2779,7 @@ export async function evaluateExpression(expr: Expr, env: Environment): Promise<
|
|
|
2737
2779
|
});
|
|
2738
2780
|
break;
|
|
2739
2781
|
default:
|
|
2740
|
-
throw
|
|
2782
|
+
throw createCodedError(`Unrecognized binary operator: ${expr.op}`, 'AL_INT_BAD_BINARY_OP');
|
|
2741
2783
|
}
|
|
2742
2784
|
} else if (isNegExpr(expr)) {
|
|
2743
2785
|
await evaluateExpression(expr.ne, env);
|
|
@@ -2815,7 +2857,10 @@ async function followReference(env: Environment, s: string): Promise<Result> {
|
|
|
2815
2857
|
async function dereferencePath(path: string, env: Environment): Promise<Result> {
|
|
2816
2858
|
const fqName = fqNameFromPath(path);
|
|
2817
2859
|
if (fqName === undefined) {
|
|
2818
|
-
throw
|
|
2860
|
+
throw createCodedError(
|
|
2861
|
+
`Failed to deduce entry-name from path - ${path}`,
|
|
2862
|
+
'AL_INT_DEDUCE_ENTRY_NAME'
|
|
2863
|
+
);
|
|
2819
2864
|
}
|
|
2820
2865
|
const newEnv = new Environment('path-deref', env);
|
|
2821
2866
|
await parseAndEvaluateStatement(
|
|
@@ -2923,7 +2968,7 @@ async function runPrePostEvents(
|
|
|
2923
2968
|
if (env.hasHandlers()) {
|
|
2924
2969
|
throw reason;
|
|
2925
2970
|
} else {
|
|
2926
|
-
throw
|
|
2971
|
+
throw createCodedError(`${prefix}: ${reason}`, 'AL_INT_PREPOST_EVENT_FAILED');
|
|
2927
2972
|
}
|
|
2928
2973
|
};
|
|
2929
2974
|
if (trigInfo.async) {
|
package/src/runtime/loader.ts
CHANGED
|
@@ -80,6 +80,7 @@ import {
|
|
|
80
80
|
asStringLiteralsMap,
|
|
81
81
|
escapeSpecialChars,
|
|
82
82
|
findRbacSchema,
|
|
83
|
+
isCoreModule,
|
|
83
84
|
isFqName,
|
|
84
85
|
makeFqName,
|
|
85
86
|
maybeExtends,
|
|
@@ -105,6 +106,7 @@ import {
|
|
|
105
106
|
parseStatement,
|
|
106
107
|
parseWorkflow,
|
|
107
108
|
} from '../language/parser.js';
|
|
109
|
+
import { clearExecutionGraphCache } from './exec-graph-cache.js';
|
|
108
110
|
import { logger } from './logger.js';
|
|
109
111
|
import {
|
|
110
112
|
Environment,
|
|
@@ -1305,6 +1307,9 @@ export async function internModule(
|
|
|
1305
1307
|
moduleFileName?: string
|
|
1306
1308
|
): Promise<Module> {
|
|
1307
1309
|
const mn = module.name;
|
|
1310
|
+
if (!isCoreModule(mn)) {
|
|
1311
|
+
clearExecutionGraphCache();
|
|
1312
|
+
}
|
|
1308
1313
|
const r = addModule(mn);
|
|
1309
1314
|
// Process imports sequentially to ensure all JS modules are loaded before definitions
|
|
1310
1315
|
for (const imp of module.imports as Import[]) {
|
package/src/runtime/logger.ts
CHANGED
|
@@ -17,6 +17,13 @@ if (isNodeEnv) {
|
|
|
17
17
|
|
|
18
18
|
export let logger: any;
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Dedicated logger that records each error to `logs/errors-<DATE>.log`, one line
|
|
22
|
+
* per error. Used when custom error messages are enabled (see `recordCustomError`
|
|
23
|
+
* in errors/http-error.ts).
|
|
24
|
+
*/
|
|
25
|
+
export let errorFileLogger: any;
|
|
26
|
+
|
|
20
27
|
function getLogLevel(): string {
|
|
21
28
|
if (isNodeEnv && process.env && process.env.DEBUG) {
|
|
22
29
|
return 'debug';
|
|
@@ -46,6 +53,25 @@ export function initializeLogger() {
|
|
|
46
53
|
),
|
|
47
54
|
transports: [fileTransport],
|
|
48
55
|
});
|
|
56
|
+
|
|
57
|
+
const errorFileTransport = new DailyRotateFile({
|
|
58
|
+
level: 'error',
|
|
59
|
+
filename: 'logs/errors-%DATE%.log',
|
|
60
|
+
datePattern: 'YYYY-MM-DD',
|
|
61
|
+
maxSize: '20m',
|
|
62
|
+
maxFiles: '30d',
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
errorFileLogger = winston.createLogger({
|
|
66
|
+
level: 'error',
|
|
67
|
+
format: winston.format.combine(
|
|
68
|
+
winston.format.timestamp(),
|
|
69
|
+
winston.format.printf(({ timestamp, message }: any) => {
|
|
70
|
+
return `[${timestamp}] ${message}`;
|
|
71
|
+
})
|
|
72
|
+
),
|
|
73
|
+
transports: [errorFileTransport],
|
|
74
|
+
});
|
|
49
75
|
} else {
|
|
50
76
|
function mkLogger(tag: string): Function {
|
|
51
77
|
return (msg: string) => {
|
|
@@ -58,6 +84,7 @@ export function initializeLogger() {
|
|
|
58
84
|
warn: mkLogger('WARN'),
|
|
59
85
|
error: mkLogger('ERROR'),
|
|
60
86
|
};
|
|
87
|
+
errorFileLogger = { error: mkLogger('ERROR') };
|
|
61
88
|
}
|
|
62
89
|
}
|
|
63
90
|
|