@stackfactor/agent-utils 1.1.5 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,7 @@ declare const _default: {
8
8
  };
9
9
  ERROR: {
10
10
  UNABLE_TO_GENERATE_CONTENT: string;
11
+ MISSING_INFORMATION: string;
11
12
  UNEXPECTED_ERROR: string;
12
13
  UNSUPPORTED_MODEL: string;
13
14
  QUOTA_EXHAUSTED: string;
@@ -1 +1 @@
1
- {"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../src/const.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,wBAgBE"}
1
+ {"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../src/const.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wBAiBE"}
package/dist/cjs/const.js CHANGED
@@ -10,6 +10,7 @@ exports.default = {
10
10
  },
11
11
  ERROR: {
12
12
  UNABLE_TO_GENERATE_CONTENT: "Unable to generate content",
13
+ MISSING_INFORMATION: "Required information is missing or invalid",
13
14
  UNEXPECTED_ERROR: "An unexpected error occured. If the issue persists please contact the StackFactor support team at support@stackfactor.ai",
14
15
  UNSUPPORTED_MODEL: "The specified model is not supported",
15
16
  QUOTA_EXHAUSTED: "Agent session quota exhausted: no remaining budget for additional LLM calls.",
@@ -1,3 +1,74 @@
1
+ /** Winston log levels accepted by the shared {@link logger}. */
2
+ type LogLevel = "error" | "warn" | "info" | "http" | "verbose" | "debug" | "silly";
3
+ /**
4
+ * The normalised shape every error is reduced to: a numeric code, a human-readable
5
+ * message, optional structured `details`, and the failing `integration` name when
6
+ * the error originated from an external service call.
7
+ */
8
+ export interface ParsedError {
9
+ code?: number;
10
+ message?: string;
11
+ details?: any;
12
+ integration?: string;
13
+ }
14
+ /**
15
+ * A structured, throwable error that normalises any caught value, logs itself
16
+ * through the shared {@link logger}, and serialises to the `ErrorInfo` wire frame
17
+ * (`{ code, message }`) that {@link serve} sends and unwraps across the gRPC
18
+ * boundary.
19
+ *
20
+ * @example
21
+ * try {
22
+ * await doWork();
23
+ * } catch (err) {
24
+ * throw AppError.from(err).log(request).toWireError();
25
+ * }
26
+ */
27
+ export declare class AppError extends Error {
28
+ /** Numeric HTTP/application status code; defaults to 500 when unknown. */
29
+ readonly code: number;
30
+ /** Optional structured supplementary information (e.g. validation details). */
31
+ readonly details?: any;
32
+ /** Name of the external integration that failed, when applicable. */
33
+ readonly integration?: string;
34
+ constructor(parsed?: ParsedError);
35
+ /**
36
+ * Normalise any thrown value into an {@link AppError}. Idempotent — an existing
37
+ * `AppError` is returned unchanged.
38
+ */
39
+ static from(error: unknown): AppError;
40
+ /**
41
+ * Inspect any value and return its {@link ParsedError} shape without
42
+ * constructing an error instance.
43
+ */
44
+ static parse(error: unknown): ParsedError;
45
+ /**
46
+ * The serialisable payload: code + message, plus details/integration when
47
+ * present. The extra fields are dropped by proto-loader on the `ErrorInfo`
48
+ * frame and preserved everywhere else (logs, JSON responses).
49
+ */
50
+ toFrame(): ParsedError & {
51
+ code: number;
52
+ message: string;
53
+ };
54
+ toJSON(): ParsedError;
55
+ /**
56
+ * Encode this error for rethrow across the agent boundary. {@link serve}'s
57
+ * handler unwraps `error.message` as JSON, so the structured payload lives
58
+ * there.
59
+ */
60
+ toWireError(): Error;
61
+ /**
62
+ * Log this error through the shared {@link logger} and return `this` for
63
+ * chaining (`AppError.from(err).log(request).toWireError()`).
64
+ *
65
+ * @param request - HTTP/agent request used by the logger to prefix the user's
66
+ * email; may be `null`.
67
+ * @param level - Log level; defaults to `"error"`.
68
+ * @param options - Extra structured fields merged into the log record.
69
+ */
70
+ log(request?: any, level?: LogLevel, options?: any): this;
71
+ }
1
72
  declare const _default: {
2
73
  /**
3
74
  * Creates a structured error object with a code, message, and optional details.
@@ -15,6 +86,16 @@ declare const _default: {
15
86
  details: any;
16
87
  stack: string;
17
88
  };
89
+ /** {@link AppError.parse} — normalise any value to a {@link ParsedError}. */
90
+ parse: (error: any) => ParsedError;
91
+ /** {@link AppError.from} — normalise any value to an {@link AppError}. */
92
+ from: typeof AppError.from;
93
+ /** Normalise + log a caught value in one call; returns the {@link AppError}. */
94
+ handle: (error: unknown, request?: any, options?: any) => AppError;
95
+ /** Test whether a value is a valid HTTP status code. */
96
+ isHttpCode: (code: any) => code is number;
97
+ /** The {@link AppError} class. */
98
+ AppError: typeof AppError;
18
99
  };
19
100
  export default _default;
20
101
  //# sourceMappingURL=errorHandling.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errorHandling.d.ts","sourceRoot":"","sources":["../../src/errorHandling.ts"],"names":[],"mappings":";IACE;;;;;;;;;OASG;wBACiB,MAAM,gBAAgB,MAAM,YAAW,GAAG;;;;;;;AAXhE,wBAoBE"}
1
+ {"version":3,"file":"errorHandling.d.ts","sourceRoot":"","sources":["../../src/errorHandling.ts"],"names":[],"mappings":"AAGA,gEAAgE;AAChE,KAAK,QAAQ,GACT,OAAO,GACP,MAAM,GACN,MAAM,GACN,MAAM,GACN,SAAS,GACT,OAAO,GACP,OAAO,CAAC;AAEZ;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA8GD;;;;;;;;;;;;GAYG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC;IACvB,qEAAqE;IACrE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;gBAElB,MAAM,GAAE,WAAgB;IAUpC;;;OAGG;IACH,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ;IAKrC;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW;IAIzC;;;;OAIG;IACH,OAAO,IAAI,WAAW,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAS1D,MAAM,IAAI,WAAW;IAIrB;;;;OAIG;IACH,WAAW,IAAI,KAAK;IAIpB;;;;;;;;OAQG;IACH,GAAG,CAAC,OAAO,GAAE,GAAU,EAAE,KAAK,GAAE,QAAkB,EAAE,OAAO,GAAE,GAAQ,GAAG,IAAI;CAU7E;;IAkBC;;;;;;;;;OASG;wBACiB,MAAM,gBAAgB,MAAM,YAAW,GAAG;;;;;;IAU9D,6EAA6E;mBApOpD,GAAG,KAAG,WAAW;IAsO1C,0EAA0E;;IAE1E,gFAAgF;oBA9BzE,OAAO,YACL,GAAG,YACH,GAAG,KACX,QAAQ;IA6BT,wDAAwD;uBArPhC,GAAG,KAAG,IAAI,IAAI,MAAM;IAuP5C,kCAAkC;;;AA7BpC,wBA+BE"}
@@ -1,5 +1,211 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AppError = void 0;
7
+ const const_js_1 = __importDefault(require("./const.js"));
8
+ const logger_js_1 = __importDefault(require("./logger.js"));
9
+ /** True when `code` is a syntactically valid HTTP status (100–599). */
10
+ const isHttpCode = (code) => typeof code === "number" && Number.isInteger(code) && code >= 100 && code <= 599;
11
+ /**
12
+ * Reduce any thrown value — Error, axios failure, validation error, structured
13
+ * payload from {@link create}, JSON-encoded rethrow, or bare string — into a
14
+ * consistent {@link ParsedError}. Never throws; falls back to a generic 500.
15
+ *
16
+ * @param error - Anything that was caught or thrown.
17
+ * @returns The normalised error shape.
18
+ */
19
+ const parseError = (error) => {
20
+ try {
21
+ if (typeof error === "object" && error !== null) {
22
+ // Integration calls tag the failing integration's name.
23
+ const integration = error.integrationName;
24
+ // express-validator style validation error (e.g. runSocketValidators).
25
+ if (error.message === "VALIDATION_ERROR" && Array.isArray(error.details)) {
26
+ return {
27
+ code: const_js_1.default.HTTP_CODES.BAD_REQUEST,
28
+ message: const_js_1.default.ERROR.MISSING_INFORMATION,
29
+ details: error.details,
30
+ integration,
31
+ };
32
+ }
33
+ // Structured error produced by create().
34
+ if (error.code && error.message && isHttpCode(error.code)) {
35
+ return {
36
+ code: error.code,
37
+ message: error.message,
38
+ details: error.details,
39
+ integration,
40
+ };
41
+ }
42
+ // axios error format.
43
+ if (error.isAxiosError && error.response) {
44
+ return {
45
+ code: error.response.status,
46
+ message: error.response.data?.message || error.response.statusText,
47
+ integration,
48
+ };
49
+ }
50
+ // Any other error carrying an HTTP-style response.
51
+ if (error.response) {
52
+ return {
53
+ code: error.response.status,
54
+ message: error.response.data?.message || error.response.statusText,
55
+ integration,
56
+ };
57
+ }
58
+ // Standard Error objects or objects with a message.
59
+ if (typeof error.message === "string") {
60
+ // The message may itself be a JSON-encoded error — agents rethrow across
61
+ // the gRPC boundary as `new Error(JSON.stringify({ code, message }))`.
62
+ try {
63
+ const parsed = JSON.parse(error.message);
64
+ if (parsed && (parsed.code || parsed.message)) {
65
+ return {
66
+ code: isHttpCode(parsed.code) ? parsed.code : undefined,
67
+ message: parsed.message,
68
+ details: parsed.details,
69
+ integration: parsed.integration ?? integration,
70
+ };
71
+ }
72
+ }
73
+ catch {
74
+ // Not JSON — use the message as-is.
75
+ }
76
+ return {
77
+ code: error.message.includes("validation failed")
78
+ ? const_js_1.default.HTTP_CODES.BAD_REQUEST
79
+ : undefined,
80
+ message: error.message,
81
+ integration,
82
+ };
83
+ }
84
+ return { message: const_js_1.default.ERROR.UNEXPECTED_ERROR, integration };
85
+ }
86
+ if (typeof error === "string") {
87
+ // A JSON-encoded error string, or just a plain message.
88
+ try {
89
+ const parsed = JSON.parse(error);
90
+ return {
91
+ code: isHttpCode(parsed.code) ? parsed.code : undefined,
92
+ message: parsed.message,
93
+ integration: parsed.integration,
94
+ };
95
+ }
96
+ catch {
97
+ return { message: error };
98
+ }
99
+ }
100
+ }
101
+ catch {
102
+ // Fall through to the generic fallback below.
103
+ }
104
+ return {
105
+ code: const_js_1.default.HTTP_CODES.INTERNAL_SERVER_ERROR,
106
+ message: const_js_1.default.ERROR.UNEXPECTED_ERROR,
107
+ };
108
+ };
109
+ /**
110
+ * A structured, throwable error that normalises any caught value, logs itself
111
+ * through the shared {@link logger}, and serialises to the `ErrorInfo` wire frame
112
+ * (`{ code, message }`) that {@link serve} sends and unwraps across the gRPC
113
+ * boundary.
114
+ *
115
+ * @example
116
+ * try {
117
+ * await doWork();
118
+ * } catch (err) {
119
+ * throw AppError.from(err).log(request).toWireError();
120
+ * }
121
+ */
122
+ class AppError extends Error {
123
+ /** Numeric HTTP/application status code; defaults to 500 when unknown. */
124
+ code;
125
+ /** Optional structured supplementary information (e.g. validation details). */
126
+ details;
127
+ /** Name of the external integration that failed, when applicable. */
128
+ integration;
129
+ constructor(parsed = {}) {
130
+ super(parsed.message ?? const_js_1.default.ERROR.UNEXPECTED_ERROR);
131
+ this.name = "AppError";
132
+ this.code = parsed.code ?? const_js_1.default.HTTP_CODES.INTERNAL_SERVER_ERROR;
133
+ this.details = parsed.details;
134
+ this.integration = parsed.integration;
135
+ // Restore the prototype chain (TS targeting ES2022 extending built-ins).
136
+ Object.setPrototypeOf(this, AppError.prototype);
137
+ }
138
+ /**
139
+ * Normalise any thrown value into an {@link AppError}. Idempotent — an existing
140
+ * `AppError` is returned unchanged.
141
+ */
142
+ static from(error) {
143
+ if (error instanceof AppError)
144
+ return error;
145
+ return new AppError(parseError(error));
146
+ }
147
+ /**
148
+ * Inspect any value and return its {@link ParsedError} shape without
149
+ * constructing an error instance.
150
+ */
151
+ static parse(error) {
152
+ return parseError(error);
153
+ }
154
+ /**
155
+ * The serialisable payload: code + message, plus details/integration when
156
+ * present. The extra fields are dropped by proto-loader on the `ErrorInfo`
157
+ * frame and preserved everywhere else (logs, JSON responses).
158
+ */
159
+ toFrame() {
160
+ return {
161
+ code: this.code,
162
+ message: this.message,
163
+ ...(this.details !== undefined ? { details: this.details } : {}),
164
+ ...(this.integration ? { integration: this.integration } : {}),
165
+ };
166
+ }
167
+ toJSON() {
168
+ return this.toFrame();
169
+ }
170
+ /**
171
+ * Encode this error for rethrow across the agent boundary. {@link serve}'s
172
+ * handler unwraps `error.message` as JSON, so the structured payload lives
173
+ * there.
174
+ */
175
+ toWireError() {
176
+ return new Error(JSON.stringify(this.toFrame()));
177
+ }
178
+ /**
179
+ * Log this error through the shared {@link logger} and return `this` for
180
+ * chaining (`AppError.from(err).log(request).toWireError()`).
181
+ *
182
+ * @param request - HTTP/agent request used by the logger to prefix the user's
183
+ * email; may be `null`.
184
+ * @param level - Log level; defaults to `"error"`.
185
+ * @param options - Extra structured fields merged into the log record.
186
+ */
187
+ log(request = null, level = "error", options = {}) {
188
+ logger_js_1.default.log(request, level, this.message, {
189
+ code: this.code,
190
+ ...(this.details !== undefined ? { details: this.details } : {}),
191
+ ...(this.integration ? { integration: this.integration } : {}),
192
+ stack: this.stack,
193
+ ...options,
194
+ });
195
+ return this;
196
+ }
197
+ }
198
+ exports.AppError = AppError;
199
+ /**
200
+ * One-shot handler for a caught value: normalise it to an {@link AppError}, log
201
+ * it, and return it so the caller can serialise (`.toFrame()` / `.toWireError()`)
202
+ * or rethrow.
203
+ *
204
+ * @param error - The caught value.
205
+ * @param request - Request passed to the logger for the email prefix; may be `null`.
206
+ * @param options - Extra structured fields merged into the log record.
207
+ */
208
+ const handle = (error, request = null, options = {}) => AppError.from(error).log(request, "error", options);
3
209
  exports.default = {
4
210
  /**
5
211
  * Creates a structured error object with a code, message, and optional details.
@@ -20,4 +226,14 @@ exports.default = {
20
226
  stack: error.stack,
21
227
  };
22
228
  },
229
+ /** {@link AppError.parse} — normalise any value to a {@link ParsedError}. */
230
+ parse: parseError,
231
+ /** {@link AppError.from} — normalise any value to an {@link AppError}. */
232
+ from: AppError.from,
233
+ /** Normalise + log a caught value in one call; returns the {@link AppError}. */
234
+ handle,
235
+ /** Test whether a value is a valid HTTP status code. */
236
+ isHttpCode,
237
+ /** The {@link AppError} class. */
238
+ AppError,
23
239
  };
@@ -1,12 +1,13 @@
1
1
  import constants from "./const.js";
2
- import errorHandling from "./errorHandling.js";
2
+ import errorHandling, { AppError } from "./errorHandling.js";
3
3
  import langChain from "./langChain.js";
4
4
  import logger from "./logger.js";
5
5
  import { serve } from "./serve.js";
6
6
  import { callAgent, checkAgent } from "./client.js";
7
7
  import * as runtimeContext from "./runtimeContext.js";
8
8
  export { constants };
9
- export { errorHandling };
9
+ export { errorHandling, AppError };
10
+ export type { ParsedError } from "./errorHandling.js";
10
11
  export { langChain };
11
12
  export { logger };
12
13
  export { serve };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAC/C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,OAAO,EAAE,KAAK,EAAE,CAAC;AAEjB,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,EAAE,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;AAEnC,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,OAAO,EAAE,KAAK,EAAE,CAAC;AAEjB,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,cAAc,EAAE,CAAC"}
package/dist/cjs/index.js CHANGED
@@ -36,11 +36,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.runtimeContext = exports.checkAgent = exports.callAgent = exports.serve = exports.logger = exports.langChain = exports.errorHandling = exports.constants = void 0;
39
+ exports.runtimeContext = exports.checkAgent = exports.callAgent = exports.serve = exports.logger = exports.langChain = exports.AppError = exports.errorHandling = exports.constants = void 0;
40
40
  const const_js_1 = __importDefault(require("./const.js"));
41
41
  exports.constants = const_js_1.default;
42
- const errorHandling_js_1 = __importDefault(require("./errorHandling.js"));
42
+ const errorHandling_js_1 = __importStar(require("./errorHandling.js"));
43
43
  exports.errorHandling = errorHandling_js_1.default;
44
+ Object.defineProperty(exports, "AppError", { enumerable: true, get: function () { return errorHandling_js_1.AppError; } });
44
45
  const langChain_js_1 = __importDefault(require("./langChain.js"));
45
46
  exports.langChain = langChain_js_1.default;
46
47
  const logger_js_1 = __importDefault(require("./logger.js"));
@@ -8,6 +8,7 @@ declare const _default: {
8
8
  };
9
9
  ERROR: {
10
10
  UNABLE_TO_GENERATE_CONTENT: string;
11
+ MISSING_INFORMATION: string;
11
12
  UNEXPECTED_ERROR: string;
12
13
  UNSUPPORTED_MODEL: string;
13
14
  QUOTA_EXHAUSTED: string;
@@ -1 +1 @@
1
- {"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../src/const.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,wBAgBE"}
1
+ {"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../src/const.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wBAiBE"}
package/dist/esm/const.js CHANGED
@@ -8,6 +8,7 @@ export default {
8
8
  },
9
9
  ERROR: {
10
10
  UNABLE_TO_GENERATE_CONTENT: "Unable to generate content",
11
+ MISSING_INFORMATION: "Required information is missing or invalid",
11
12
  UNEXPECTED_ERROR: "An unexpected error occured. If the issue persists please contact the StackFactor support team at support@stackfactor.ai",
12
13
  UNSUPPORTED_MODEL: "The specified model is not supported",
13
14
  QUOTA_EXHAUSTED: "Agent session quota exhausted: no remaining budget for additional LLM calls.",
@@ -1,3 +1,74 @@
1
+ /** Winston log levels accepted by the shared {@link logger}. */
2
+ type LogLevel = "error" | "warn" | "info" | "http" | "verbose" | "debug" | "silly";
3
+ /**
4
+ * The normalised shape every error is reduced to: a numeric code, a human-readable
5
+ * message, optional structured `details`, and the failing `integration` name when
6
+ * the error originated from an external service call.
7
+ */
8
+ export interface ParsedError {
9
+ code?: number;
10
+ message?: string;
11
+ details?: any;
12
+ integration?: string;
13
+ }
14
+ /**
15
+ * A structured, throwable error that normalises any caught value, logs itself
16
+ * through the shared {@link logger}, and serialises to the `ErrorInfo` wire frame
17
+ * (`{ code, message }`) that {@link serve} sends and unwraps across the gRPC
18
+ * boundary.
19
+ *
20
+ * @example
21
+ * try {
22
+ * await doWork();
23
+ * } catch (err) {
24
+ * throw AppError.from(err).log(request).toWireError();
25
+ * }
26
+ */
27
+ export declare class AppError extends Error {
28
+ /** Numeric HTTP/application status code; defaults to 500 when unknown. */
29
+ readonly code: number;
30
+ /** Optional structured supplementary information (e.g. validation details). */
31
+ readonly details?: any;
32
+ /** Name of the external integration that failed, when applicable. */
33
+ readonly integration?: string;
34
+ constructor(parsed?: ParsedError);
35
+ /**
36
+ * Normalise any thrown value into an {@link AppError}. Idempotent — an existing
37
+ * `AppError` is returned unchanged.
38
+ */
39
+ static from(error: unknown): AppError;
40
+ /**
41
+ * Inspect any value and return its {@link ParsedError} shape without
42
+ * constructing an error instance.
43
+ */
44
+ static parse(error: unknown): ParsedError;
45
+ /**
46
+ * The serialisable payload: code + message, plus details/integration when
47
+ * present. The extra fields are dropped by proto-loader on the `ErrorInfo`
48
+ * frame and preserved everywhere else (logs, JSON responses).
49
+ */
50
+ toFrame(): ParsedError & {
51
+ code: number;
52
+ message: string;
53
+ };
54
+ toJSON(): ParsedError;
55
+ /**
56
+ * Encode this error for rethrow across the agent boundary. {@link serve}'s
57
+ * handler unwraps `error.message` as JSON, so the structured payload lives
58
+ * there.
59
+ */
60
+ toWireError(): Error;
61
+ /**
62
+ * Log this error through the shared {@link logger} and return `this` for
63
+ * chaining (`AppError.from(err).log(request).toWireError()`).
64
+ *
65
+ * @param request - HTTP/agent request used by the logger to prefix the user's
66
+ * email; may be `null`.
67
+ * @param level - Log level; defaults to `"error"`.
68
+ * @param options - Extra structured fields merged into the log record.
69
+ */
70
+ log(request?: any, level?: LogLevel, options?: any): this;
71
+ }
1
72
  declare const _default: {
2
73
  /**
3
74
  * Creates a structured error object with a code, message, and optional details.
@@ -15,6 +86,16 @@ declare const _default: {
15
86
  details: any;
16
87
  stack: string;
17
88
  };
89
+ /** {@link AppError.parse} — normalise any value to a {@link ParsedError}. */
90
+ parse: (error: any) => ParsedError;
91
+ /** {@link AppError.from} — normalise any value to an {@link AppError}. */
92
+ from: typeof AppError.from;
93
+ /** Normalise + log a caught value in one call; returns the {@link AppError}. */
94
+ handle: (error: unknown, request?: any, options?: any) => AppError;
95
+ /** Test whether a value is a valid HTTP status code. */
96
+ isHttpCode: (code: any) => code is number;
97
+ /** The {@link AppError} class. */
98
+ AppError: typeof AppError;
18
99
  };
19
100
  export default _default;
20
101
  //# sourceMappingURL=errorHandling.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errorHandling.d.ts","sourceRoot":"","sources":["../../src/errorHandling.ts"],"names":[],"mappings":";IACE;;;;;;;;;OASG;wBACiB,MAAM,gBAAgB,MAAM,YAAW,GAAG;;;;;;;AAXhE,wBAoBE"}
1
+ {"version":3,"file":"errorHandling.d.ts","sourceRoot":"","sources":["../../src/errorHandling.ts"],"names":[],"mappings":"AAGA,gEAAgE;AAChE,KAAK,QAAQ,GACT,OAAO,GACP,MAAM,GACN,MAAM,GACN,MAAM,GACN,SAAS,GACT,OAAO,GACP,OAAO,CAAC;AAEZ;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA8GD;;;;;;;;;;;;GAYG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC;IACvB,qEAAqE;IACrE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;gBAElB,MAAM,GAAE,WAAgB;IAUpC;;;OAGG;IACH,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ;IAKrC;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW;IAIzC;;;;OAIG;IACH,OAAO,IAAI,WAAW,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAS1D,MAAM,IAAI,WAAW;IAIrB;;;;OAIG;IACH,WAAW,IAAI,KAAK;IAIpB;;;;;;;;OAQG;IACH,GAAG,CAAC,OAAO,GAAE,GAAU,EAAE,KAAK,GAAE,QAAkB,EAAE,OAAO,GAAE,GAAQ,GAAG,IAAI;CAU7E;;IAkBC;;;;;;;;;OASG;wBACiB,MAAM,gBAAgB,MAAM,YAAW,GAAG;;;;;;IAU9D,6EAA6E;mBApOpD,GAAG,KAAG,WAAW;IAsO1C,0EAA0E;;IAE1E,gFAAgF;oBA9BzE,OAAO,YACL,GAAG,YACH,GAAG,KACX,QAAQ;IA6BT,wDAAwD;uBArPhC,GAAG,KAAG,IAAI,IAAI,MAAM;IAuP5C,kCAAkC;;;AA7BpC,wBA+BE"}
@@ -1,3 +1,204 @@
1
+ import constants from "./const.js";
2
+ import logger from "./logger.js";
3
+ /** True when `code` is a syntactically valid HTTP status (100–599). */
4
+ const isHttpCode = (code) => typeof code === "number" && Number.isInteger(code) && code >= 100 && code <= 599;
5
+ /**
6
+ * Reduce any thrown value — Error, axios failure, validation error, structured
7
+ * payload from {@link create}, JSON-encoded rethrow, or bare string — into a
8
+ * consistent {@link ParsedError}. Never throws; falls back to a generic 500.
9
+ *
10
+ * @param error - Anything that was caught or thrown.
11
+ * @returns The normalised error shape.
12
+ */
13
+ const parseError = (error) => {
14
+ try {
15
+ if (typeof error === "object" && error !== null) {
16
+ // Integration calls tag the failing integration's name.
17
+ const integration = error.integrationName;
18
+ // express-validator style validation error (e.g. runSocketValidators).
19
+ if (error.message === "VALIDATION_ERROR" && Array.isArray(error.details)) {
20
+ return {
21
+ code: constants.HTTP_CODES.BAD_REQUEST,
22
+ message: constants.ERROR.MISSING_INFORMATION,
23
+ details: error.details,
24
+ integration,
25
+ };
26
+ }
27
+ // Structured error produced by create().
28
+ if (error.code && error.message && isHttpCode(error.code)) {
29
+ return {
30
+ code: error.code,
31
+ message: error.message,
32
+ details: error.details,
33
+ integration,
34
+ };
35
+ }
36
+ // axios error format.
37
+ if (error.isAxiosError && error.response) {
38
+ return {
39
+ code: error.response.status,
40
+ message: error.response.data?.message || error.response.statusText,
41
+ integration,
42
+ };
43
+ }
44
+ // Any other error carrying an HTTP-style response.
45
+ if (error.response) {
46
+ return {
47
+ code: error.response.status,
48
+ message: error.response.data?.message || error.response.statusText,
49
+ integration,
50
+ };
51
+ }
52
+ // Standard Error objects or objects with a message.
53
+ if (typeof error.message === "string") {
54
+ // The message may itself be a JSON-encoded error — agents rethrow across
55
+ // the gRPC boundary as `new Error(JSON.stringify({ code, message }))`.
56
+ try {
57
+ const parsed = JSON.parse(error.message);
58
+ if (parsed && (parsed.code || parsed.message)) {
59
+ return {
60
+ code: isHttpCode(parsed.code) ? parsed.code : undefined,
61
+ message: parsed.message,
62
+ details: parsed.details,
63
+ integration: parsed.integration ?? integration,
64
+ };
65
+ }
66
+ }
67
+ catch {
68
+ // Not JSON — use the message as-is.
69
+ }
70
+ return {
71
+ code: error.message.includes("validation failed")
72
+ ? constants.HTTP_CODES.BAD_REQUEST
73
+ : undefined,
74
+ message: error.message,
75
+ integration,
76
+ };
77
+ }
78
+ return { message: constants.ERROR.UNEXPECTED_ERROR, integration };
79
+ }
80
+ if (typeof error === "string") {
81
+ // A JSON-encoded error string, or just a plain message.
82
+ try {
83
+ const parsed = JSON.parse(error);
84
+ return {
85
+ code: isHttpCode(parsed.code) ? parsed.code : undefined,
86
+ message: parsed.message,
87
+ integration: parsed.integration,
88
+ };
89
+ }
90
+ catch {
91
+ return { message: error };
92
+ }
93
+ }
94
+ }
95
+ catch {
96
+ // Fall through to the generic fallback below.
97
+ }
98
+ return {
99
+ code: constants.HTTP_CODES.INTERNAL_SERVER_ERROR,
100
+ message: constants.ERROR.UNEXPECTED_ERROR,
101
+ };
102
+ };
103
+ /**
104
+ * A structured, throwable error that normalises any caught value, logs itself
105
+ * through the shared {@link logger}, and serialises to the `ErrorInfo` wire frame
106
+ * (`{ code, message }`) that {@link serve} sends and unwraps across the gRPC
107
+ * boundary.
108
+ *
109
+ * @example
110
+ * try {
111
+ * await doWork();
112
+ * } catch (err) {
113
+ * throw AppError.from(err).log(request).toWireError();
114
+ * }
115
+ */
116
+ export class AppError extends Error {
117
+ /** Numeric HTTP/application status code; defaults to 500 when unknown. */
118
+ code;
119
+ /** Optional structured supplementary information (e.g. validation details). */
120
+ details;
121
+ /** Name of the external integration that failed, when applicable. */
122
+ integration;
123
+ constructor(parsed = {}) {
124
+ super(parsed.message ?? constants.ERROR.UNEXPECTED_ERROR);
125
+ this.name = "AppError";
126
+ this.code = parsed.code ?? constants.HTTP_CODES.INTERNAL_SERVER_ERROR;
127
+ this.details = parsed.details;
128
+ this.integration = parsed.integration;
129
+ // Restore the prototype chain (TS targeting ES2022 extending built-ins).
130
+ Object.setPrototypeOf(this, AppError.prototype);
131
+ }
132
+ /**
133
+ * Normalise any thrown value into an {@link AppError}. Idempotent — an existing
134
+ * `AppError` is returned unchanged.
135
+ */
136
+ static from(error) {
137
+ if (error instanceof AppError)
138
+ return error;
139
+ return new AppError(parseError(error));
140
+ }
141
+ /**
142
+ * Inspect any value and return its {@link ParsedError} shape without
143
+ * constructing an error instance.
144
+ */
145
+ static parse(error) {
146
+ return parseError(error);
147
+ }
148
+ /**
149
+ * The serialisable payload: code + message, plus details/integration when
150
+ * present. The extra fields are dropped by proto-loader on the `ErrorInfo`
151
+ * frame and preserved everywhere else (logs, JSON responses).
152
+ */
153
+ toFrame() {
154
+ return {
155
+ code: this.code,
156
+ message: this.message,
157
+ ...(this.details !== undefined ? { details: this.details } : {}),
158
+ ...(this.integration ? { integration: this.integration } : {}),
159
+ };
160
+ }
161
+ toJSON() {
162
+ return this.toFrame();
163
+ }
164
+ /**
165
+ * Encode this error for rethrow across the agent boundary. {@link serve}'s
166
+ * handler unwraps `error.message` as JSON, so the structured payload lives
167
+ * there.
168
+ */
169
+ toWireError() {
170
+ return new Error(JSON.stringify(this.toFrame()));
171
+ }
172
+ /**
173
+ * Log this error through the shared {@link logger} and return `this` for
174
+ * chaining (`AppError.from(err).log(request).toWireError()`).
175
+ *
176
+ * @param request - HTTP/agent request used by the logger to prefix the user's
177
+ * email; may be `null`.
178
+ * @param level - Log level; defaults to `"error"`.
179
+ * @param options - Extra structured fields merged into the log record.
180
+ */
181
+ log(request = null, level = "error", options = {}) {
182
+ logger.log(request, level, this.message, {
183
+ code: this.code,
184
+ ...(this.details !== undefined ? { details: this.details } : {}),
185
+ ...(this.integration ? { integration: this.integration } : {}),
186
+ stack: this.stack,
187
+ ...options,
188
+ });
189
+ return this;
190
+ }
191
+ }
192
+ /**
193
+ * One-shot handler for a caught value: normalise it to an {@link AppError}, log
194
+ * it, and return it so the caller can serialise (`.toFrame()` / `.toWireError()`)
195
+ * or rethrow.
196
+ *
197
+ * @param error - The caught value.
198
+ * @param request - Request passed to the logger for the email prefix; may be `null`.
199
+ * @param options - Extra structured fields merged into the log record.
200
+ */
201
+ const handle = (error, request = null, options = {}) => AppError.from(error).log(request, "error", options);
1
202
  export default {
2
203
  /**
3
204
  * Creates a structured error object with a code, message, and optional details.
@@ -18,4 +219,14 @@ export default {
18
219
  stack: error.stack,
19
220
  };
20
221
  },
222
+ /** {@link AppError.parse} — normalise any value to a {@link ParsedError}. */
223
+ parse: parseError,
224
+ /** {@link AppError.from} — normalise any value to an {@link AppError}. */
225
+ from: AppError.from,
226
+ /** Normalise + log a caught value in one call; returns the {@link AppError}. */
227
+ handle,
228
+ /** Test whether a value is a valid HTTP status code. */
229
+ isHttpCode,
230
+ /** The {@link AppError} class. */
231
+ AppError,
21
232
  };
@@ -1,12 +1,13 @@
1
1
  import constants from "./const.js";
2
- import errorHandling from "./errorHandling.js";
2
+ import errorHandling, { AppError } from "./errorHandling.js";
3
3
  import langChain from "./langChain.js";
4
4
  import logger from "./logger.js";
5
5
  import { serve } from "./serve.js";
6
6
  import { callAgent, checkAgent } from "./client.js";
7
7
  import * as runtimeContext from "./runtimeContext.js";
8
8
  export { constants };
9
- export { errorHandling };
9
+ export { errorHandling, AppError };
10
+ export type { ParsedError } from "./errorHandling.js";
10
11
  export { langChain };
11
12
  export { logger };
12
13
  export { serve };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAC/C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,OAAO,EAAE,KAAK,EAAE,CAAC;AAEjB,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,EAAE,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;AAEnC,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,OAAO,EAAE,KAAK,EAAE,CAAC;AAEjB,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,cAAc,EAAE,CAAC"}
package/dist/esm/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import constants from "./const.js";
2
- import errorHandling from "./errorHandling.js";
2
+ import errorHandling, { AppError } from "./errorHandling.js";
3
3
  import langChain from "./langChain.js";
4
4
  import logger from "./logger.js";
5
5
  import { serve } from "./serve.js";
6
6
  import { callAgent, checkAgent } from "./client.js";
7
7
  import * as runtimeContext from "./runtimeContext.js";
8
8
  export { constants };
9
- export { errorHandling };
9
+ export { errorHandling, AppError };
10
10
  export { langChain };
11
11
  export { logger };
12
12
  export { serve };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.1.5",
6
+ "version": "1.1.7",
7
7
  "description": "",
8
8
  "main": "dist/cjs/index.js",
9
9
  "module": "dist/esm/index.js",