agentlang 0.10.9 → 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/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +26 -25
- package/out/runtime/interpreter.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 +1 -0
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +1 -0
- 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 +35 -12
- 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/interpreter.ts +70 -27
- package/src/runtime/logger.ts +27 -0
- package/src/runtime/module.ts +45 -13
- package/src/runtime/modules/ai.ts +1 -0
- package/src/runtime/modules/auth.ts +35 -12
- 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
|
+
}
|
|
@@ -128,6 +128,7 @@ import { detailedDiff } from 'deep-object-diff';
|
|
|
128
128
|
import { callMcpTool, mcpClientNameFromToolEvent } from './mcpclient.js';
|
|
129
129
|
import { isNodeEnv } from '../utils/runtime.js';
|
|
130
130
|
import Handlebars from 'handlebars';
|
|
131
|
+
import { createCodedError } from './errors/coded-error.js';
|
|
131
132
|
|
|
132
133
|
export type Result = any;
|
|
133
134
|
|
|
@@ -446,7 +447,11 @@ export class Environment extends Instance {
|
|
|
446
447
|
|
|
447
448
|
setActiveEvent(eventInst: Instance | undefined): Environment {
|
|
448
449
|
if (eventInst) {
|
|
449
|
-
if (!isEventInstance(eventInst))
|
|
450
|
+
if (!isEventInstance(eventInst))
|
|
451
|
+
throw createCodedError(
|
|
452
|
+
`Not an event instance - ${eventInst.name}`,
|
|
453
|
+
'AL_INT_NOT_EVENT_INSTANCE'
|
|
454
|
+
);
|
|
450
455
|
this.bindInstance(eventInst);
|
|
451
456
|
this.activeModule = eventInst.moduleName;
|
|
452
457
|
this.activeEventInstance = eventInst;
|
|
@@ -532,7 +537,7 @@ export class Environment extends Instance {
|
|
|
532
537
|
if (this.suspensionId) {
|
|
533
538
|
return this.suspensionId;
|
|
534
539
|
} else {
|
|
535
|
-
throw
|
|
540
|
+
throw createCodedError('SuspensionId is not set', 'AL_INT_SUSPENSION_ID_NOT_SET');
|
|
536
541
|
}
|
|
537
542
|
}
|
|
538
543
|
|
|
@@ -682,7 +687,7 @@ export class Environment extends Instance {
|
|
|
682
687
|
this.activeTransactions.set(n, txnId);
|
|
683
688
|
return txnId;
|
|
684
689
|
} else {
|
|
685
|
-
throw
|
|
690
|
+
throw createCodedError(`Failed to start transaction for ${n}`, 'AL_INT_TXN_START_FAILED');
|
|
686
691
|
}
|
|
687
692
|
}
|
|
688
693
|
}
|
|
@@ -774,7 +779,7 @@ export class Environment extends Instance {
|
|
|
774
779
|
popHandlers(): CatchHandlers {
|
|
775
780
|
const r = this.activeCatchHandlers.pop();
|
|
776
781
|
if (r === undefined) {
|
|
777
|
-
throw
|
|
782
|
+
throw createCodedError(`No more handlers to pop`, 'AL_INT_NO_HANDLERS_TO_POP');
|
|
778
783
|
}
|
|
779
784
|
return r;
|
|
780
785
|
}
|
|
@@ -1000,7 +1005,7 @@ export let evaluate = async function (
|
|
|
1000
1005
|
return null;
|
|
1001
1006
|
}
|
|
1002
1007
|
} else {
|
|
1003
|
-
throw
|
|
1008
|
+
throw createCodedError('Not an event - ' + eventInstance.name, 'AL_INT_NOT_AN_EVENT');
|
|
1004
1009
|
}
|
|
1005
1010
|
} catch (err) {
|
|
1006
1011
|
if (env && env.hasHandlers()) {
|
|
@@ -1097,7 +1102,10 @@ async function evaluateAsyncPattern(
|
|
|
1097
1102
|
if (s.$cstNode) {
|
|
1098
1103
|
return s.$cstNode.text;
|
|
1099
1104
|
} else {
|
|
1100
|
-
throw
|
|
1105
|
+
throw createCodedError(
|
|
1106
|
+
'failed to extract code for suspension statement',
|
|
1107
|
+
'AL_INT_SUSPENSION_CODE_EXTRACT'
|
|
1108
|
+
);
|
|
1101
1109
|
}
|
|
1102
1110
|
}),
|
|
1103
1111
|
env
|
|
@@ -1387,7 +1395,7 @@ export async function evaluatePattern(
|
|
|
1387
1395
|
|
|
1388
1396
|
async function evaluateThrowError(throwErr: ThrowError, env: Environment) {
|
|
1389
1397
|
await evaluateExpression(throwErr.reason, env);
|
|
1390
|
-
throw
|
|
1398
|
+
throw createCodedError(String(env.getLastResult()), 'AL_INT_USER_THROW');
|
|
1391
1399
|
}
|
|
1392
1400
|
|
|
1393
1401
|
async function evaluateFullTextSearch(fts: FullTextSearch, env: Environment): Promise<void> {
|
|
@@ -1397,7 +1405,10 @@ async function evaluateFullTextSearch(fts: FullTextSearch, env: Environment): Pr
|
|
|
1397
1405
|
if (inst) {
|
|
1398
1406
|
n = makeFqName(inst.moduleName, n);
|
|
1399
1407
|
} else {
|
|
1400
|
-
throw
|
|
1408
|
+
throw createCodedError(
|
|
1409
|
+
`Fully qualified name required for full-text-search in ${n}`,
|
|
1410
|
+
'AL_INT_FTS_FQN_REQUIRED'
|
|
1411
|
+
);
|
|
1401
1412
|
}
|
|
1402
1413
|
}
|
|
1403
1414
|
const path = nameToPath(n);
|
|
@@ -1407,7 +1418,10 @@ async function evaluateFullTextSearch(fts: FullTextSearch, env: Environment): Pr
|
|
|
1407
1418
|
await evaluateLiteral(fts.query, env);
|
|
1408
1419
|
const q = env.getLastResult();
|
|
1409
1420
|
if (!isString(q)) {
|
|
1410
|
-
throw
|
|
1421
|
+
throw createCodedError(
|
|
1422
|
+
`Full text search query must be a string - ${q}`,
|
|
1423
|
+
'AL_INT_FTS_QUERY_STRING'
|
|
1424
|
+
);
|
|
1411
1425
|
}
|
|
1412
1426
|
let options: Map<string, any> | undefined;
|
|
1413
1427
|
if (fts.options) {
|
|
@@ -1527,7 +1541,10 @@ async function patternToInstance(
|
|
|
1527
1541
|
let aname: string = a.name;
|
|
1528
1542
|
if (aname.endsWith(QuerySuffix)) {
|
|
1529
1543
|
if (isQueryAll) {
|
|
1530
|
-
throw
|
|
1544
|
+
throw createCodedError(
|
|
1545
|
+
`Cannot specifiy query attribute ${aname} here`,
|
|
1546
|
+
'AL_INT_QUERY_ATTR_FORBIDDEN'
|
|
1547
|
+
);
|
|
1531
1548
|
}
|
|
1532
1549
|
if (qattrs === undefined) qattrs = newInstanceAttributes();
|
|
1533
1550
|
if (qattrVals === undefined) qattrVals = newInstanceAttributes();
|
|
@@ -1570,11 +1587,15 @@ async function instanceFromSource(crud: CrudMap, env: Environment): Promise<Inst
|
|
|
1570
1587
|
const m = nparts.hasModule() ? nparts.getModuleName() : env.getActiveModuleName();
|
|
1571
1588
|
return makeInstance(m, n, attrs);
|
|
1572
1589
|
} else {
|
|
1573
|
-
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
|
+
);
|
|
1574
1594
|
}
|
|
1575
1595
|
} else {
|
|
1576
|
-
throw
|
|
1577
|
-
`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'
|
|
1578
1599
|
);
|
|
1579
1600
|
}
|
|
1580
1601
|
}
|
|
@@ -1589,7 +1610,7 @@ async function maybeValidateOneOfRefs(inst: Instance, env: Environment) {
|
|
|
1589
1610
|
const attrSpec = inst.record.schema.get(n);
|
|
1590
1611
|
if (!attrSpec) continue;
|
|
1591
1612
|
const r = getOneOfRef(attrSpec);
|
|
1592
|
-
if (!r) throw
|
|
1613
|
+
if (!r) throw createCodedError(`Failed to fetch one-of-ref for ${n}`, 'AL_INT_ONEOF_REF_FETCH');
|
|
1593
1614
|
if (r) {
|
|
1594
1615
|
const parts = r.split('.');
|
|
1595
1616
|
const insts = await lookupOneOfVals(parts[0], env);
|
|
@@ -1602,7 +1623,7 @@ async function maybeValidateOneOfRefs(inst: Instance, env: Environment) {
|
|
|
1602
1623
|
return i.lookup(parts[1]) == v;
|
|
1603
1624
|
})
|
|
1604
1625
|
) {
|
|
1605
|
-
throw
|
|
1626
|
+
throw createCodedError(`Invalid enum-value ${v} for ${n}`, 'AL_INT_INVALID_ENUM');
|
|
1606
1627
|
}
|
|
1607
1628
|
}
|
|
1608
1629
|
}
|
|
@@ -1656,12 +1677,16 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1656
1677
|
}
|
|
1657
1678
|
if (qopts.into) {
|
|
1658
1679
|
if (attrs.size > 0) {
|
|
1659
|
-
throw
|
|
1660
|
-
`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'
|
|
1661
1683
|
);
|
|
1662
1684
|
}
|
|
1663
1685
|
if (qattrs === undefined && !isQueryAll) {
|
|
1664
|
-
throw
|
|
1686
|
+
throw createCodedError(
|
|
1687
|
+
`Pattern for ${entryName} with 'into' clause must be a query`,
|
|
1688
|
+
'AL_INT_INTO_MUST_BE_QUERY'
|
|
1689
|
+
);
|
|
1665
1690
|
}
|
|
1666
1691
|
if (qopts.joins && qopts.joins.length > 0) {
|
|
1667
1692
|
await evaluateJoinQuery(qopts.joins, qopts.into, qopts.where, inst, distinct, env);
|
|
@@ -1914,7 +1939,10 @@ async function handleDocEvent(inst: Instance, env: Environment): Promise<void> {
|
|
|
1914
1939
|
const url = inst.lookup('url');
|
|
1915
1940
|
if (typeof url === 'string' && url.startsWith('s3://')) {
|
|
1916
1941
|
if (!isNodeEnv) {
|
|
1917
|
-
throw
|
|
1942
|
+
throw createCodedError(
|
|
1943
|
+
'Document fetching is only available in Node.js environment',
|
|
1944
|
+
'AL_INT_DOC_FETCH_NODE_ONLY'
|
|
1945
|
+
);
|
|
1918
1946
|
}
|
|
1919
1947
|
const title = inst.lookup('title');
|
|
1920
1948
|
const retrievalConfig = inst.lookup('retrievalConfig');
|
|
@@ -2213,7 +2241,10 @@ async function walkJoinQueryPattern(
|
|
|
2213
2241
|
});
|
|
2214
2242
|
return joinsSpec;
|
|
2215
2243
|
} else {
|
|
2216
|
-
throw
|
|
2244
|
+
throw createCodedError(
|
|
2245
|
+
`Expected a query for relationship ${rp.name}`,
|
|
2246
|
+
'AL_INT_RELATIONSHIP_QUERY_EXPECTED'
|
|
2247
|
+
);
|
|
2217
2248
|
}
|
|
2218
2249
|
}
|
|
2219
2250
|
|
|
@@ -2338,10 +2369,13 @@ async function agentInvoke(agent: AgentInstance, msg: string, env: Environment):
|
|
|
2338
2369
|
}
|
|
2339
2370
|
}
|
|
2340
2371
|
} else {
|
|
2341
|
-
throw
|
|
2372
|
+
throw createCodedError(
|
|
2373
|
+
`Agent ${agent.name} failed to generate a response`,
|
|
2374
|
+
'AL_INT_AGENT_NO_RESPONSE'
|
|
2375
|
+
);
|
|
2342
2376
|
}
|
|
2343
2377
|
if (agentInternalError !== undefined) {
|
|
2344
|
-
throw
|
|
2378
|
+
throw createCodedError(agentInternalError, 'AL_INT_AGENT_INTERNAL');
|
|
2345
2379
|
}
|
|
2346
2380
|
}
|
|
2347
2381
|
|
|
@@ -2469,7 +2503,10 @@ async function iterateOnFlow(
|
|
|
2469
2503
|
while (step != 'DONE' && !executedSteps.has(step)) {
|
|
2470
2504
|
await checkCancelled(iterId);
|
|
2471
2505
|
if (stepc > MaxFlowSteps) {
|
|
2472
|
-
throw
|
|
2506
|
+
throw createCodedError(
|
|
2507
|
+
`Flow execution exceeded maximum steps limit`,
|
|
2508
|
+
'AL_INT_FLOW_MAX_STEPS'
|
|
2509
|
+
);
|
|
2473
2510
|
}
|
|
2474
2511
|
executedSteps.add(step);
|
|
2475
2512
|
++stepc;
|
|
@@ -2531,7 +2568,10 @@ async function iterateOnFlow(
|
|
|
2531
2568
|
++fullFlowRetries;
|
|
2532
2569
|
continue;
|
|
2533
2570
|
} else {
|
|
2534
|
-
throw
|
|
2571
|
+
throw createCodedError(
|
|
2572
|
+
typeof reason === 'string' ? reason : String(reason),
|
|
2573
|
+
'AL_INT_FLOW_FATAL'
|
|
2574
|
+
);
|
|
2535
2575
|
}
|
|
2536
2576
|
} finally {
|
|
2537
2577
|
env.decrementMonitor().revokeLastResult().setMonitorFlowResult();
|
|
@@ -2739,7 +2779,7 @@ export async function evaluateExpression(expr: Expr, env: Environment): Promise<
|
|
|
2739
2779
|
});
|
|
2740
2780
|
break;
|
|
2741
2781
|
default:
|
|
2742
|
-
throw
|
|
2782
|
+
throw createCodedError(`Unrecognized binary operator: ${expr.op}`, 'AL_INT_BAD_BINARY_OP');
|
|
2743
2783
|
}
|
|
2744
2784
|
} else if (isNegExpr(expr)) {
|
|
2745
2785
|
await evaluateExpression(expr.ne, env);
|
|
@@ -2817,7 +2857,10 @@ async function followReference(env: Environment, s: string): Promise<Result> {
|
|
|
2817
2857
|
async function dereferencePath(path: string, env: Environment): Promise<Result> {
|
|
2818
2858
|
const fqName = fqNameFromPath(path);
|
|
2819
2859
|
if (fqName === undefined) {
|
|
2820
|
-
throw
|
|
2860
|
+
throw createCodedError(
|
|
2861
|
+
`Failed to deduce entry-name from path - ${path}`,
|
|
2862
|
+
'AL_INT_DEDUCE_ENTRY_NAME'
|
|
2863
|
+
);
|
|
2821
2864
|
}
|
|
2822
2865
|
const newEnv = new Environment('path-deref', env);
|
|
2823
2866
|
await parseAndEvaluateStatement(
|
|
@@ -2925,7 +2968,7 @@ async function runPrePostEvents(
|
|
|
2925
2968
|
if (env.hasHandlers()) {
|
|
2926
2969
|
throw reason;
|
|
2927
2970
|
} else {
|
|
2928
|
-
throw
|
|
2971
|
+
throw createCodedError(`${prefix}: ${reason}`, 'AL_INT_PREPOST_EVENT_FAILED');
|
|
2929
2972
|
}
|
|
2930
2973
|
};
|
|
2931
2974
|
if (trigInfo.async) {
|
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
|
|
package/src/runtime/module.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import { createCodedError } from './errors/coded-error.js';
|
|
2
3
|
import {
|
|
3
4
|
AttributeDefinition,
|
|
4
5
|
Expr,
|
|
@@ -2631,7 +2632,11 @@ export class Module {
|
|
|
2631
2632
|
|
|
2632
2633
|
getEntry(entryName: string): ModuleEntry {
|
|
2633
2634
|
const idx: number = this.getEntryIndex(entryName);
|
|
2634
|
-
if (idx < 0)
|
|
2635
|
+
if (idx < 0)
|
|
2636
|
+
throw createCodedError(
|
|
2637
|
+
`Entry ${entryName} not found in module ${this.name}`,
|
|
2638
|
+
'AL_MOD_ENTRY_NOT_FOUND'
|
|
2639
|
+
);
|
|
2635
2640
|
return this.entries[idx];
|
|
2636
2641
|
}
|
|
2637
2642
|
|
|
@@ -2646,7 +2651,10 @@ export class Module {
|
|
|
2646
2651
|
if (e instanceof Record) {
|
|
2647
2652
|
return e as Record;
|
|
2648
2653
|
}
|
|
2649
|
-
throw
|
|
2654
|
+
throw createCodedError(
|
|
2655
|
+
`${recordName} is not a record in module ${this.name}`,
|
|
2656
|
+
'AL_MOD_NOT_A_RECORD'
|
|
2657
|
+
);
|
|
2650
2658
|
}
|
|
2651
2659
|
|
|
2652
2660
|
removeEntry(entryName: string): boolean {
|
|
@@ -2942,7 +2950,7 @@ export function isModule(name: string): boolean {
|
|
|
2942
2950
|
export function fetchModule(moduleName: string): Module {
|
|
2943
2951
|
const module: Module | undefined = getModuleDb().get(moduleName);
|
|
2944
2952
|
if (module === undefined) {
|
|
2945
|
-
throw
|
|
2953
|
+
throw createCodedError(`Module not found - ${moduleName}`, 'AL_MOD_MODULE_NOT_FOUND');
|
|
2946
2954
|
}
|
|
2947
2955
|
return module;
|
|
2948
2956
|
}
|
|
@@ -3481,7 +3489,7 @@ export function getEntity(name: string, moduleName: string): Entity | undefined
|
|
|
3481
3489
|
export function fetchEntity(path: Path): Entity {
|
|
3482
3490
|
const e = getEntity(path.getEntryName(), path.getModuleName());
|
|
3483
3491
|
if (e === undefined) {
|
|
3484
|
-
throw
|
|
3492
|
+
throw createCodedError(`Entity not found - ${path.asFqName()}`, 'AL_MOD_ENTITY_NOT_FOUND');
|
|
3485
3493
|
}
|
|
3486
3494
|
return e;
|
|
3487
3495
|
}
|
|
@@ -3513,7 +3521,10 @@ export function getEvent(name: string, moduleName: string): Event {
|
|
|
3513
3521
|
if (fr.module.isEvent(fr.entryName)) {
|
|
3514
3522
|
return fr.module.getEntry(fr.entryName) as Event;
|
|
3515
3523
|
}
|
|
3516
|
-
throw
|
|
3524
|
+
throw createCodedError(
|
|
3525
|
+
`Event ${fr.entryName} not found in module ${fr.moduleName}`,
|
|
3526
|
+
'AL_MOD_EVENT_NOT_FOUND'
|
|
3527
|
+
);
|
|
3517
3528
|
}
|
|
3518
3529
|
|
|
3519
3530
|
export function maybeGetEvent(name: string, moduleName: string): Event | undefined {
|
|
@@ -3529,7 +3540,10 @@ export function getRecord(name: string, moduleName: string): Record {
|
|
|
3529
3540
|
if (fr.module.isRecord(fr.entryName)) {
|
|
3530
3541
|
return fr.module.getEntry(fr.entryName) as Record;
|
|
3531
3542
|
}
|
|
3532
|
-
throw
|
|
3543
|
+
throw createCodedError(
|
|
3544
|
+
`Record ${fr.entryName} not found in module ${fr.moduleName}`,
|
|
3545
|
+
'AL_MOD_RECORD_NOT_FOUND'
|
|
3546
|
+
);
|
|
3533
3547
|
}
|
|
3534
3548
|
|
|
3535
3549
|
export function getRelationship(name: string, moduleName: string): Relationship {
|
|
@@ -3537,7 +3551,10 @@ export function getRelationship(name: string, moduleName: string): Relationship
|
|
|
3537
3551
|
if (fr.module.isRelationship(fr.entryName)) {
|
|
3538
3552
|
return fr.module.getEntry(fr.entryName) as Relationship;
|
|
3539
3553
|
}
|
|
3540
|
-
throw
|
|
3554
|
+
throw createCodedError(
|
|
3555
|
+
`Relationship ${fr.entryName} not found in module ${fr.moduleName}`,
|
|
3556
|
+
'AL_MOD_RELATIONSHIP_NOT_FOUND'
|
|
3557
|
+
);
|
|
3541
3558
|
}
|
|
3542
3559
|
|
|
3543
3560
|
export function getAllBetweenRelationships(): Relationship[] {
|
|
@@ -3707,7 +3724,10 @@ function checkOneOfValue(attrSpec: AttributeSpec, attrName: string, attrValue: a
|
|
|
3707
3724
|
const vals: Set<string> | undefined = getEnumValues(attrSpec);
|
|
3708
3725
|
if (vals) {
|
|
3709
3726
|
if (!vals.has(attrValue as string)) {
|
|
3710
|
-
throw
|
|
3727
|
+
throw createCodedError(
|
|
3728
|
+
`Value of ${attrName} must be one of [${[...vals]}]`,
|
|
3729
|
+
'AL_MOD_TYPE_MISMATCH'
|
|
3730
|
+
);
|
|
3711
3731
|
}
|
|
3712
3732
|
return true;
|
|
3713
3733
|
}
|
|
@@ -3725,7 +3745,10 @@ function getCheckPredicate(attrSpec: AttributeSpec): any {
|
|
|
3725
3745
|
function validateType(attrName: string, attrValue: any, attrSpec: AttributeSpec) {
|
|
3726
3746
|
if (attrSpec.type == 'Path') {
|
|
3727
3747
|
if (!isPath(attrValue, getRefSpec(attrSpec))) {
|
|
3728
|
-
throw
|
|
3748
|
+
throw createCodedError(
|
|
3749
|
+
`Failed to validate Path ${attrValue} passed to ${attrName}`,
|
|
3750
|
+
'AL_MOD_TYPE_MISMATCH'
|
|
3751
|
+
);
|
|
3729
3752
|
}
|
|
3730
3753
|
}
|
|
3731
3754
|
let predic = getCheckPredicate(attrSpec);
|
|
@@ -3733,16 +3756,22 @@ function validateType(attrName: string, attrValue: any, attrSpec: AttributeSpec)
|
|
|
3733
3756
|
if (predic !== undefined) {
|
|
3734
3757
|
if (isArrayAttribute(attrSpec)) {
|
|
3735
3758
|
if (!(attrValue instanceof Array)) {
|
|
3736
|
-
throw
|
|
3759
|
+
throw createCodedError(`${attrName} expects an array of values`, 'AL_MOD_TYPE_MISMATCH');
|
|
3737
3760
|
} else {
|
|
3738
3761
|
if (!attrValue.every(predic)) {
|
|
3739
|
-
throw
|
|
3762
|
+
throw createCodedError(
|
|
3763
|
+
`Invalid value in the array passed to ${attrName}`,
|
|
3764
|
+
'AL_MOD_TYPE_MISMATCH'
|
|
3765
|
+
);
|
|
3740
3766
|
}
|
|
3741
3767
|
}
|
|
3742
3768
|
} else {
|
|
3743
3769
|
if (!checkOneOfValue(attrSpec, attrName, attrValue)) {
|
|
3744
3770
|
if (!predic(attrValue)) {
|
|
3745
|
-
throw
|
|
3771
|
+
throw createCodedError(
|
|
3772
|
+
`Invalid value ${attrValue} specified for ${attrName}`,
|
|
3773
|
+
'AL_MOD_TYPE_MISMATCH'
|
|
3774
|
+
);
|
|
3746
3775
|
}
|
|
3747
3776
|
}
|
|
3748
3777
|
}
|
|
@@ -4307,7 +4336,10 @@ export function makeInstance(
|
|
|
4307
4336
|
if (schema.size > 0) {
|
|
4308
4337
|
attributes.forEach((value: any, key: string) => {
|
|
4309
4338
|
if (!schema.has(key)) {
|
|
4310
|
-
throw
|
|
4339
|
+
throw createCodedError(
|
|
4340
|
+
`Invalid attribute '${key}' specified for ${moduleName}/${entryName}`,
|
|
4341
|
+
'AL_MOD_INVALID_ATTR'
|
|
4342
|
+
);
|
|
4311
4343
|
}
|
|
4312
4344
|
const spec: AttributeSpec = getAttributeSpec(schema, key);
|
|
4313
4345
|
if (value !== null && value !== undefined) validateType(key, value, spec);
|
|
@@ -85,6 +85,7 @@ const AgentEvalType = 'eval';
|
|
|
85
85
|
// --- Agent cancellation infrastructure ---
|
|
86
86
|
|
|
87
87
|
export class AgentCancelledException extends Error {
|
|
88
|
+
readonly agentlangCode = 'AL_AGENT_CANCELLED';
|
|
88
89
|
constructor(chatId: string) {
|
|
89
90
|
super(`Agent cancelled for chatId: ${chatId}`);
|
|
90
91
|
this.name = 'AgentCancelledException';
|