@hestia-earth/api 0.27.4 → 0.27.6
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/errors.d.ts +40 -0
- package/errors.js +87 -0
- package/esm/errors.js +77 -0
- package/esm/files/model/llm-preset.js +61 -0
- package/esm/logger.js +31 -0
- package/esm/models.js +1 -0
- package/esm/settings/model/model.js +1 -0
- package/files/model/llm-preset.d.ts +37 -0
- package/files/model/llm-preset.js +66 -0
- package/logger.d.ts +4 -0
- package/logger.js +34 -0
- package/models.d.ts +1 -0
- package/models.js +1 -0
- package/package.json +1 -1
- package/reconciliations/model/validations.d.ts +1 -1
- package/settings/model/model.d.ts +2 -1
- package/settings/model/model.js +1 -0
package/errors.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Express, Request, Response, NextFunction } from 'express';
|
|
2
|
+
import { NextHandleFunction } from 'connect';
|
|
3
|
+
export declare enum Errors {
|
|
4
|
+
UnderMaintenance = "under-maintenance",
|
|
5
|
+
ReadOnly = "read-only",
|
|
6
|
+
InvalidQueryParam = "invalid-param-query",
|
|
7
|
+
MissingQueryParam = "missing-param-query",
|
|
8
|
+
InvalidBodyParam = "invalid-param-body",
|
|
9
|
+
MissingBodyParam = "missing-param-body",
|
|
10
|
+
MissingHeaderParam = "missing-param-header",
|
|
11
|
+
SchemaInvalid = "invalid-schema",
|
|
12
|
+
NotFound = "not-found",
|
|
13
|
+
Unauthorized = "Unauthorized",
|
|
14
|
+
BadRequest = "bad-request",
|
|
15
|
+
FilesLocked = "files-locked"
|
|
16
|
+
}
|
|
17
|
+
export declare enum StatusCodes {
|
|
18
|
+
BadRequest = 400,
|
|
19
|
+
Unauthorized = 401,
|
|
20
|
+
Forbidden = 403,
|
|
21
|
+
NotFound = 404,
|
|
22
|
+
MethodNotAllowed = 405,
|
|
23
|
+
Conflict = 409,
|
|
24
|
+
RateLimit = 429,
|
|
25
|
+
ServiceUnavailable = 503,
|
|
26
|
+
InternalServerError = 500
|
|
27
|
+
}
|
|
28
|
+
export declare class HestiaError extends Error {
|
|
29
|
+
details: {};
|
|
30
|
+
statusCode?: StatusCodes;
|
|
31
|
+
constructor(message: string, details?: {}, statusCode?: StatusCodes);
|
|
32
|
+
}
|
|
33
|
+
export declare const throwError: (message: string, details?: any, statusCode?: StatusCodes) => never;
|
|
34
|
+
export declare const isRecalculationError: (e: any) => boolean;
|
|
35
|
+
export declare const shouldHandleError: (error: Error) => boolean;
|
|
36
|
+
export declare const errorMessage: (error?: Error) => string;
|
|
37
|
+
export declare const errorHandler: (err: any, _r: Request, res: Response, _n?: NextFunction) => Response<any, Record<string, any>>;
|
|
38
|
+
export declare const handleSyntaxError: (middleware: NextHandleFunction) => (req: Request, res: Response, next: NextFunction) => void;
|
|
39
|
+
declare const _default: (app: Express) => void;
|
|
40
|
+
export default _default;
|
package/errors.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleSyntaxError = exports.errorHandler = exports.errorMessage = exports.shouldHandleError = exports.isRecalculationError = exports.throwError = exports.HestiaError = exports.StatusCodes = exports.Errors = void 0;
|
|
4
|
+
const Sentry = require("@sentry/node");
|
|
5
|
+
const pick = require('lodash.pick');
|
|
6
|
+
const logger_1 = require("./logger");
|
|
7
|
+
var Errors;
|
|
8
|
+
(function (Errors) {
|
|
9
|
+
Errors["UnderMaintenance"] = "under-maintenance";
|
|
10
|
+
Errors["ReadOnly"] = "read-only";
|
|
11
|
+
Errors["InvalidQueryParam"] = "invalid-param-query";
|
|
12
|
+
Errors["MissingQueryParam"] = "missing-param-query";
|
|
13
|
+
Errors["InvalidBodyParam"] = "invalid-param-body";
|
|
14
|
+
Errors["MissingBodyParam"] = "missing-param-body";
|
|
15
|
+
Errors["MissingHeaderParam"] = "missing-param-header";
|
|
16
|
+
Errors["SchemaInvalid"] = "invalid-schema";
|
|
17
|
+
Errors["NotFound"] = "not-found";
|
|
18
|
+
Errors["Unauthorized"] = "Unauthorized";
|
|
19
|
+
Errors["BadRequest"] = "bad-request";
|
|
20
|
+
Errors["FilesLocked"] = "files-locked";
|
|
21
|
+
})(Errors || (exports.Errors = Errors = {}));
|
|
22
|
+
var StatusCodes;
|
|
23
|
+
(function (StatusCodes) {
|
|
24
|
+
StatusCodes[StatusCodes["BadRequest"] = 400] = "BadRequest";
|
|
25
|
+
StatusCodes[StatusCodes["Unauthorized"] = 401] = "Unauthorized";
|
|
26
|
+
StatusCodes[StatusCodes["Forbidden"] = 403] = "Forbidden";
|
|
27
|
+
StatusCodes[StatusCodes["NotFound"] = 404] = "NotFound";
|
|
28
|
+
StatusCodes[StatusCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed";
|
|
29
|
+
StatusCodes[StatusCodes["Conflict"] = 409] = "Conflict";
|
|
30
|
+
StatusCodes[StatusCodes["RateLimit"] = 429] = "RateLimit";
|
|
31
|
+
StatusCodes[StatusCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable";
|
|
32
|
+
StatusCodes[StatusCodes["InternalServerError"] = 500] = "InternalServerError";
|
|
33
|
+
})(StatusCodes || (exports.StatusCodes = StatusCodes = {}));
|
|
34
|
+
class HestiaError extends Error {
|
|
35
|
+
details;
|
|
36
|
+
statusCode;
|
|
37
|
+
constructor(message, details = {}, statusCode) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.details = details;
|
|
40
|
+
this.statusCode = statusCode;
|
|
41
|
+
this.name = 'HestiaError';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.HestiaError = HestiaError;
|
|
45
|
+
const throwError = (message, details, statusCode) => {
|
|
46
|
+
throw new HestiaError(message, details, statusCode);
|
|
47
|
+
};
|
|
48
|
+
exports.throwError = throwError;
|
|
49
|
+
const isHestiaError = (error) => error.name === 'HestiaError';
|
|
50
|
+
const isRecalculationError = e => ['recalculation-error', 'invalid-nodes'].includes(e.message);
|
|
51
|
+
exports.isRecalculationError = isRecalculationError;
|
|
52
|
+
const shouldHandleError = (error) => !isHestiaError(error);
|
|
53
|
+
exports.shouldHandleError = shouldHandleError;
|
|
54
|
+
const statusCode = (error) => error.statusCode ||
|
|
55
|
+
((0, exports.errorMessage)(error).includes(Errors.NotFound)
|
|
56
|
+
? StatusCodes.NotFound
|
|
57
|
+
: error.message === Errors.Unauthorized
|
|
58
|
+
? StatusCodes.Unauthorized
|
|
59
|
+
: isHestiaError(error)
|
|
60
|
+
? StatusCodes.BadRequest
|
|
61
|
+
: StatusCodes.InternalServerError);
|
|
62
|
+
const errorMessage = (error) => error?.message || 'There was an error processing your request.';
|
|
63
|
+
exports.errorMessage = errorMessage;
|
|
64
|
+
const errorHandler = (err, _r, res, _n) => {
|
|
65
|
+
const unexpectedError = (0, exports.shouldHandleError)(err);
|
|
66
|
+
unexpectedError && logger_1.logger.error(err.stack ? err.stack : err);
|
|
67
|
+
const message = (0, exports.errorMessage)(err);
|
|
68
|
+
res.statusCode = statusCode(err);
|
|
69
|
+
return res.json({
|
|
70
|
+
message,
|
|
71
|
+
...pick(err, ['details', 'oauthError'])
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
exports.errorHandler = errorHandler;
|
|
75
|
+
const handleSyntaxError = (middleware) => (req, res, next) => middleware(req, res, err => {
|
|
76
|
+
if (err instanceof SyntaxError) {
|
|
77
|
+
const message = (0, exports.errorMessage)(err);
|
|
78
|
+
res.statusCode = 400;
|
|
79
|
+
return res.json({ message });
|
|
80
|
+
}
|
|
81
|
+
next();
|
|
82
|
+
});
|
|
83
|
+
exports.handleSyntaxError = handleSyntaxError;
|
|
84
|
+
exports.default = (app) => {
|
|
85
|
+
app.use(Sentry.Handlers.errorHandler({ shouldHandleError: exports.shouldHandleError }));
|
|
86
|
+
app.use(exports.errorHandler);
|
|
87
|
+
};
|
package/esm/errors.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as Sentry from '@sentry/node';
|
|
2
|
+
const pick = require('lodash.pick');
|
|
3
|
+
import { logger } from './logger.js';
|
|
4
|
+
export var Errors;
|
|
5
|
+
(function (Errors) {
|
|
6
|
+
Errors["UnderMaintenance"] = "under-maintenance";
|
|
7
|
+
Errors["ReadOnly"] = "read-only";
|
|
8
|
+
Errors["InvalidQueryParam"] = "invalid-param-query";
|
|
9
|
+
Errors["MissingQueryParam"] = "missing-param-query";
|
|
10
|
+
Errors["InvalidBodyParam"] = "invalid-param-body";
|
|
11
|
+
Errors["MissingBodyParam"] = "missing-param-body";
|
|
12
|
+
Errors["MissingHeaderParam"] = "missing-param-header";
|
|
13
|
+
Errors["SchemaInvalid"] = "invalid-schema";
|
|
14
|
+
Errors["NotFound"] = "not-found";
|
|
15
|
+
Errors["Unauthorized"] = "Unauthorized";
|
|
16
|
+
Errors["BadRequest"] = "bad-request";
|
|
17
|
+
Errors["FilesLocked"] = "files-locked";
|
|
18
|
+
})(Errors || (Errors = {}));
|
|
19
|
+
export var StatusCodes;
|
|
20
|
+
(function (StatusCodes) {
|
|
21
|
+
StatusCodes[StatusCodes["BadRequest"] = 400] = "BadRequest";
|
|
22
|
+
StatusCodes[StatusCodes["Unauthorized"] = 401] = "Unauthorized";
|
|
23
|
+
StatusCodes[StatusCodes["Forbidden"] = 403] = "Forbidden";
|
|
24
|
+
StatusCodes[StatusCodes["NotFound"] = 404] = "NotFound";
|
|
25
|
+
StatusCodes[StatusCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed";
|
|
26
|
+
StatusCodes[StatusCodes["Conflict"] = 409] = "Conflict";
|
|
27
|
+
StatusCodes[StatusCodes["RateLimit"] = 429] = "RateLimit";
|
|
28
|
+
StatusCodes[StatusCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable";
|
|
29
|
+
StatusCodes[StatusCodes["InternalServerError"] = 500] = "InternalServerError";
|
|
30
|
+
})(StatusCodes || (StatusCodes = {}));
|
|
31
|
+
export class HestiaError extends Error {
|
|
32
|
+
details;
|
|
33
|
+
statusCode;
|
|
34
|
+
constructor(message, details = {}, statusCode) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.details = details;
|
|
37
|
+
this.statusCode = statusCode;
|
|
38
|
+
this.name = 'HestiaError';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export const throwError = (message, details, statusCode) => {
|
|
42
|
+
throw new HestiaError(message, details, statusCode);
|
|
43
|
+
};
|
|
44
|
+
const isHestiaError = (error) => error.name === 'HestiaError';
|
|
45
|
+
export const isRecalculationError = e => ['recalculation-error', 'invalid-nodes'].includes(e.message);
|
|
46
|
+
export const shouldHandleError = (error) => !isHestiaError(error);
|
|
47
|
+
const statusCode = (error) => error.statusCode ||
|
|
48
|
+
(errorMessage(error).includes(Errors.NotFound)
|
|
49
|
+
? StatusCodes.NotFound
|
|
50
|
+
: error.message === Errors.Unauthorized
|
|
51
|
+
? StatusCodes.Unauthorized
|
|
52
|
+
: isHestiaError(error)
|
|
53
|
+
? StatusCodes.BadRequest
|
|
54
|
+
: StatusCodes.InternalServerError);
|
|
55
|
+
export const errorMessage = (error) => error?.message || 'There was an error processing your request.';
|
|
56
|
+
export const errorHandler = (err, _r, res, _n) => {
|
|
57
|
+
const unexpectedError = shouldHandleError(err);
|
|
58
|
+
unexpectedError && logger.error(err.stack ? err.stack : err);
|
|
59
|
+
const message = errorMessage(err);
|
|
60
|
+
res.statusCode = statusCode(err);
|
|
61
|
+
return res.json({
|
|
62
|
+
message,
|
|
63
|
+
...pick(err, ['details', 'oauthError'])
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
export const handleSyntaxError = (middleware) => (req, res, next) => middleware(req, res, err => {
|
|
67
|
+
if (err instanceof SyntaxError) {
|
|
68
|
+
const message = errorMessage(err);
|
|
69
|
+
res.statusCode = 400;
|
|
70
|
+
return res.json({ message });
|
|
71
|
+
}
|
|
72
|
+
next();
|
|
73
|
+
});
|
|
74
|
+
export default (app) => {
|
|
75
|
+
app.use(Sentry.Handlers.errorHandler({ shouldHandleError }));
|
|
76
|
+
app.use(errorHandler);
|
|
77
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { throwError } from '../../errors.js';
|
|
2
|
+
export var LlmEngine;
|
|
3
|
+
(function (LlmEngine) {
|
|
4
|
+
LlmEngine["claude"] = "claude";
|
|
5
|
+
LlmEngine["gemini"] = "gemini";
|
|
6
|
+
LlmEngine["openrouter"] = "openrouter";
|
|
7
|
+
LlmEngine["zai"] = "zai";
|
|
8
|
+
LlmEngine["hf"] = "hf";
|
|
9
|
+
LlmEngine["nvidia"] = "nvidia";
|
|
10
|
+
LlmEngine["deepseek"] = "deepseek";
|
|
11
|
+
LlmEngine["openai"] = "openai";
|
|
12
|
+
})(LlmEngine || (LlmEngine = {}));
|
|
13
|
+
export var LlmApiKey;
|
|
14
|
+
(function (LlmApiKey) {
|
|
15
|
+
LlmApiKey["OPENROUTER_KEY"] = "OPENROUTER_KEY";
|
|
16
|
+
LlmApiKey["Z_AI_KEY"] = "Z_AI_KEY";
|
|
17
|
+
LlmApiKey["HF_TOKEN"] = "HF_TOKEN";
|
|
18
|
+
LlmApiKey["NVIDIA_API_KEY"] = "NVIDIA_API_KEY";
|
|
19
|
+
LlmApiKey["DEEP_SEEK_API_KEY"] = "DEEP_SEEK_API_KEY";
|
|
20
|
+
LlmApiKey["ANTHROPIC_API_KEY"] = "ANTHROPIC_API_KEY";
|
|
21
|
+
LlmApiKey["OPENAI_API_KEY"] = "OPENAI_API_KEY";
|
|
22
|
+
})(LlmApiKey || (LlmApiKey = {}));
|
|
23
|
+
export const llmApiKeys = Object.values(LlmApiKey);
|
|
24
|
+
export const stripPresetSecrets = (presets = []) => presets.map(({ config, ...preset }) => {
|
|
25
|
+
const { apiKeys, ...rest } = config || {};
|
|
26
|
+
return { ...preset, config: rest };
|
|
27
|
+
});
|
|
28
|
+
const engines = Object.values(LlmEngine);
|
|
29
|
+
const isEngine = (value) => engines.includes(value);
|
|
30
|
+
const isReviewer = (value) => typeof value === 'string' && value.length > 0 && isEngine(value.split(':')[0]);
|
|
31
|
+
const isStringRecord = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
|
|
32
|
+
const invalid = (reason) => throwError('invalid-llm-presets', { reason });
|
|
33
|
+
const validateEngine = (field, value) => (value === undefined || isEngine(value)) || invalid(`invalid ${field} "${value}"`);
|
|
34
|
+
const validateOptionalString = (field, value) => (value === undefined || typeof value === 'string') || invalid(`${field} must be a string`);
|
|
35
|
+
const validateOptionalBoolean = (field, value) => (value === undefined || typeof value === 'boolean') || invalid(`${field} must be a boolean`);
|
|
36
|
+
const validateReviewers = (reviewers) => (reviewers === undefined || (Array.isArray(reviewers) && reviewers.every(isReviewer))) ||
|
|
37
|
+
invalid('reviewers must be a list of "engine" or "engine:model"');
|
|
38
|
+
const validateApiKeys = (apiKeys) => (apiKeys === undefined ||
|
|
39
|
+
(isStringRecord(apiKeys) &&
|
|
40
|
+
Object.entries(apiKeys).every(([key, value]) => llmApiKeys.includes(key) && typeof value === 'string'))) || invalid('apiKeys contains an unknown key or non-string value');
|
|
41
|
+
const validateConfig = (config) => {
|
|
42
|
+
isStringRecord(config) || invalid('config must be an object');
|
|
43
|
+
validateEngine('engine', config.engine);
|
|
44
|
+
validateEngine('fixEngine', config.fixEngine);
|
|
45
|
+
validateOptionalString('model', config.model);
|
|
46
|
+
validateOptionalString('fixModel', config.fixModel);
|
|
47
|
+
validateReviewers(config.reviewers);
|
|
48
|
+
validateApiKeys(config.apiKeys);
|
|
49
|
+
};
|
|
50
|
+
const validatePreset = (preset) => {
|
|
51
|
+
(isStringRecord(preset) && typeof preset.name === 'string' && preset.name.length > 0) ||
|
|
52
|
+
invalid('each preset requires a non-empty name');
|
|
53
|
+
validateOptionalString('description', preset.description);
|
|
54
|
+
validateOptionalBoolean('default', preset.default);
|
|
55
|
+
validateConfig(preset.config);
|
|
56
|
+
};
|
|
57
|
+
export const validateLlmPresets = (value) => {
|
|
58
|
+
Array.isArray(value) || invalid('presets must be a list');
|
|
59
|
+
value.forEach(validatePreset);
|
|
60
|
+
return value;
|
|
61
|
+
};
|
package/esm/logger.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createLogger, format, transports } from 'winston';
|
|
2
|
+
const { combine, timestamp, json } = format;
|
|
3
|
+
const logFilename = process.env.LOG_FILENAME;
|
|
4
|
+
const handleExceptions = process.env.NODE_ENV !== 'test';
|
|
5
|
+
const options = {
|
|
6
|
+
file: {
|
|
7
|
+
level: (process.env.LOG_LEVEL || 'info').toLowerCase(),
|
|
8
|
+
filename: logFilename,
|
|
9
|
+
handleExceptions,
|
|
10
|
+
json: true,
|
|
11
|
+
maxsize: 5242880,
|
|
12
|
+
maxFiles: 5,
|
|
13
|
+
colorize: false
|
|
14
|
+
},
|
|
15
|
+
console: {
|
|
16
|
+
level: 'debug',
|
|
17
|
+
handleExceptions,
|
|
18
|
+
json: false,
|
|
19
|
+
colorize: true
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export const logger = createLogger({
|
|
23
|
+
format: combine(timestamp(), json()),
|
|
24
|
+
transports: [...(logFilename ? [new transports.File(options.file)] : []), new transports.Console(options.console)],
|
|
25
|
+
exitOnError: false
|
|
26
|
+
});
|
|
27
|
+
export const stream = {
|
|
28
|
+
write: message => {
|
|
29
|
+
logger.info(message);
|
|
30
|
+
}
|
|
31
|
+
};
|
package/esm/models.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from './analyses/model/model.js';
|
|
|
4
4
|
export * from './cycles/model/model.js';
|
|
5
5
|
export * from './drafts/model/model.js';
|
|
6
6
|
export * from './earth-engine/model/model.js';
|
|
7
|
+
export * from './files/model/llm-preset.js';
|
|
7
8
|
export * from './files/model/model.js';
|
|
8
9
|
export * from './glossary/model/model.js';
|
|
9
10
|
export * from './migrations/model/model.js';
|
|
@@ -10,6 +10,7 @@ export var SettingKey;
|
|
|
10
10
|
SettingKey["calculationEngine"] = "calculationEngine";
|
|
11
11
|
SettingKey["users"] = "users";
|
|
12
12
|
SettingKey["dataReleases"] = "dataReleases";
|
|
13
|
+
SettingKey["llmPresets"] = "llmPresets";
|
|
13
14
|
})(SettingKey || (SettingKey = {}));
|
|
14
15
|
export class Setting extends BaseModel {
|
|
15
16
|
key;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export declare enum LlmEngine {
|
|
2
|
+
claude = "claude",
|
|
3
|
+
gemini = "gemini",
|
|
4
|
+
openrouter = "openrouter",
|
|
5
|
+
zai = "zai",
|
|
6
|
+
hf = "hf",
|
|
7
|
+
nvidia = "nvidia",
|
|
8
|
+
deepseek = "deepseek",
|
|
9
|
+
openai = "openai"
|
|
10
|
+
}
|
|
11
|
+
export declare enum LlmApiKey {
|
|
12
|
+
OPENROUTER_KEY = "OPENROUTER_KEY",
|
|
13
|
+
Z_AI_KEY = "Z_AI_KEY",
|
|
14
|
+
HF_TOKEN = "HF_TOKEN",
|
|
15
|
+
NVIDIA_API_KEY = "NVIDIA_API_KEY",
|
|
16
|
+
DEEP_SEEK_API_KEY = "DEEP_SEEK_API_KEY",
|
|
17
|
+
ANTHROPIC_API_KEY = "ANTHROPIC_API_KEY",
|
|
18
|
+
OPENAI_API_KEY = "OPENAI_API_KEY"
|
|
19
|
+
}
|
|
20
|
+
export declare const llmApiKeys: LlmApiKey[];
|
|
21
|
+
export type LlmReviewer = LlmEngine | `${LlmEngine}:${string}`;
|
|
22
|
+
export interface LlmPresetConfig {
|
|
23
|
+
engine?: LlmEngine;
|
|
24
|
+
model?: string;
|
|
25
|
+
reviewers?: LlmReviewer[];
|
|
26
|
+
fixEngine?: LlmEngine;
|
|
27
|
+
fixModel?: string;
|
|
28
|
+
apiKeys?: Partial<Record<LlmApiKey, string>>;
|
|
29
|
+
}
|
|
30
|
+
export interface LlmPreset {
|
|
31
|
+
name: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
default?: boolean;
|
|
34
|
+
config: LlmPresetConfig;
|
|
35
|
+
}
|
|
36
|
+
export declare const stripPresetSecrets: (presets?: LlmPreset[]) => LlmPreset[];
|
|
37
|
+
export declare const validateLlmPresets: (value: any) => LlmPreset[];
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateLlmPresets = exports.stripPresetSecrets = exports.llmApiKeys = exports.LlmApiKey = exports.LlmEngine = void 0;
|
|
4
|
+
const errors_1 = require("../../errors");
|
|
5
|
+
var LlmEngine;
|
|
6
|
+
(function (LlmEngine) {
|
|
7
|
+
LlmEngine["claude"] = "claude";
|
|
8
|
+
LlmEngine["gemini"] = "gemini";
|
|
9
|
+
LlmEngine["openrouter"] = "openrouter";
|
|
10
|
+
LlmEngine["zai"] = "zai";
|
|
11
|
+
LlmEngine["hf"] = "hf";
|
|
12
|
+
LlmEngine["nvidia"] = "nvidia";
|
|
13
|
+
LlmEngine["deepseek"] = "deepseek";
|
|
14
|
+
LlmEngine["openai"] = "openai";
|
|
15
|
+
})(LlmEngine || (exports.LlmEngine = LlmEngine = {}));
|
|
16
|
+
var LlmApiKey;
|
|
17
|
+
(function (LlmApiKey) {
|
|
18
|
+
LlmApiKey["OPENROUTER_KEY"] = "OPENROUTER_KEY";
|
|
19
|
+
LlmApiKey["Z_AI_KEY"] = "Z_AI_KEY";
|
|
20
|
+
LlmApiKey["HF_TOKEN"] = "HF_TOKEN";
|
|
21
|
+
LlmApiKey["NVIDIA_API_KEY"] = "NVIDIA_API_KEY";
|
|
22
|
+
LlmApiKey["DEEP_SEEK_API_KEY"] = "DEEP_SEEK_API_KEY";
|
|
23
|
+
LlmApiKey["ANTHROPIC_API_KEY"] = "ANTHROPIC_API_KEY";
|
|
24
|
+
LlmApiKey["OPENAI_API_KEY"] = "OPENAI_API_KEY";
|
|
25
|
+
})(LlmApiKey || (exports.LlmApiKey = LlmApiKey = {}));
|
|
26
|
+
exports.llmApiKeys = Object.values(LlmApiKey);
|
|
27
|
+
const stripPresetSecrets = (presets = []) => presets.map(({ config, ...preset }) => {
|
|
28
|
+
const { apiKeys, ...rest } = config || {};
|
|
29
|
+
return { ...preset, config: rest };
|
|
30
|
+
});
|
|
31
|
+
exports.stripPresetSecrets = stripPresetSecrets;
|
|
32
|
+
const engines = Object.values(LlmEngine);
|
|
33
|
+
const isEngine = (value) => engines.includes(value);
|
|
34
|
+
const isReviewer = (value) => typeof value === 'string' && value.length > 0 && isEngine(value.split(':')[0]);
|
|
35
|
+
const isStringRecord = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
|
|
36
|
+
const invalid = (reason) => (0, errors_1.throwError)('invalid-llm-presets', { reason });
|
|
37
|
+
const validateEngine = (field, value) => (value === undefined || isEngine(value)) || invalid(`invalid ${field} "${value}"`);
|
|
38
|
+
const validateOptionalString = (field, value) => (value === undefined || typeof value === 'string') || invalid(`${field} must be a string`);
|
|
39
|
+
const validateOptionalBoolean = (field, value) => (value === undefined || typeof value === 'boolean') || invalid(`${field} must be a boolean`);
|
|
40
|
+
const validateReviewers = (reviewers) => (reviewers === undefined || (Array.isArray(reviewers) && reviewers.every(isReviewer))) ||
|
|
41
|
+
invalid('reviewers must be a list of "engine" or "engine:model"');
|
|
42
|
+
const validateApiKeys = (apiKeys) => (apiKeys === undefined ||
|
|
43
|
+
(isStringRecord(apiKeys) &&
|
|
44
|
+
Object.entries(apiKeys).every(([key, value]) => exports.llmApiKeys.includes(key) && typeof value === 'string'))) || invalid('apiKeys contains an unknown key or non-string value');
|
|
45
|
+
const validateConfig = (config) => {
|
|
46
|
+
isStringRecord(config) || invalid('config must be an object');
|
|
47
|
+
validateEngine('engine', config.engine);
|
|
48
|
+
validateEngine('fixEngine', config.fixEngine);
|
|
49
|
+
validateOptionalString('model', config.model);
|
|
50
|
+
validateOptionalString('fixModel', config.fixModel);
|
|
51
|
+
validateReviewers(config.reviewers);
|
|
52
|
+
validateApiKeys(config.apiKeys);
|
|
53
|
+
};
|
|
54
|
+
const validatePreset = (preset) => {
|
|
55
|
+
(isStringRecord(preset) && typeof preset.name === 'string' && preset.name.length > 0) ||
|
|
56
|
+
invalid('each preset requires a non-empty name');
|
|
57
|
+
validateOptionalString('description', preset.description);
|
|
58
|
+
validateOptionalBoolean('default', preset.default);
|
|
59
|
+
validateConfig(preset.config);
|
|
60
|
+
};
|
|
61
|
+
const validateLlmPresets = (value) => {
|
|
62
|
+
Array.isArray(value) || invalid('presets must be a list');
|
|
63
|
+
value.forEach(validatePreset);
|
|
64
|
+
return value;
|
|
65
|
+
};
|
|
66
|
+
exports.validateLlmPresets = validateLlmPresets;
|
package/logger.d.ts
ADDED
package/logger.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stream = exports.logger = void 0;
|
|
4
|
+
const winston_1 = require("winston");
|
|
5
|
+
const { combine, timestamp, json } = winston_1.format;
|
|
6
|
+
const logFilename = process.env.LOG_FILENAME;
|
|
7
|
+
const handleExceptions = process.env.NODE_ENV !== 'test';
|
|
8
|
+
const options = {
|
|
9
|
+
file: {
|
|
10
|
+
level: (process.env.LOG_LEVEL || 'info').toLowerCase(),
|
|
11
|
+
filename: logFilename,
|
|
12
|
+
handleExceptions,
|
|
13
|
+
json: true,
|
|
14
|
+
maxsize: 5242880,
|
|
15
|
+
maxFiles: 5,
|
|
16
|
+
colorize: false
|
|
17
|
+
},
|
|
18
|
+
console: {
|
|
19
|
+
level: 'debug',
|
|
20
|
+
handleExceptions,
|
|
21
|
+
json: false,
|
|
22
|
+
colorize: true
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
exports.logger = (0, winston_1.createLogger)({
|
|
26
|
+
format: combine(timestamp(), json()),
|
|
27
|
+
transports: [...(logFilename ? [new winston_1.transports.File(options.file)] : []), new winston_1.transports.Console(options.console)],
|
|
28
|
+
exitOnError: false
|
|
29
|
+
});
|
|
30
|
+
exports.stream = {
|
|
31
|
+
write: message => {
|
|
32
|
+
exports.logger.info(message);
|
|
33
|
+
}
|
|
34
|
+
};
|
package/models.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './analyses/model/model';
|
|
|
4
4
|
export * from './cycles/model/model';
|
|
5
5
|
export * from './drafts/model/model';
|
|
6
6
|
export * from './earth-engine/model/model';
|
|
7
|
+
export * from './files/model/llm-preset';
|
|
7
8
|
export * from './files/model/model';
|
|
8
9
|
export * from './glossary/model/model';
|
|
9
10
|
export * from './migrations/model/model';
|
package/models.js
CHANGED
|
@@ -20,6 +20,7 @@ __exportStar(require("./analyses/model/model"), exports);
|
|
|
20
20
|
__exportStar(require("./cycles/model/model"), exports);
|
|
21
21
|
__exportStar(require("./drafts/model/model"), exports);
|
|
22
22
|
__exportStar(require("./earth-engine/model/model"), exports);
|
|
23
|
+
__exportStar(require("./files/model/llm-preset"), exports);
|
|
23
24
|
__exportStar(require("./files/model/model"), exports);
|
|
24
25
|
__exportStar(require("./glossary/model/model"), exports);
|
|
25
26
|
__exportStar(require("./migrations/model/model"), exports);
|
package/package.json
CHANGED
|
@@ -9,4 +9,4 @@ export declare const validateExpectedNodes: (nodes: Node[]) => string[];
|
|
|
9
9
|
export declare const validateImpactAssessmentLinks: (nodes: Node[]) => string[];
|
|
10
10
|
export declare const validatePrivate: (cycle: ICycleJSONLD) => string[];
|
|
11
11
|
export declare const validateProductCorrespondence: (expectedProducts: (ITermJSONLD | Term)[], recalculatedProducts: (ITermJSONLD | Term)[], idRecalculated: string) => string[];
|
|
12
|
-
export declare const getMainErrorMessage: (errors: any) => "
|
|
12
|
+
export declare const getMainErrorMessage: (errors: any) => "recalculation-error" | "invalid-nodes" | "expected-not-private";
|
|
@@ -8,7 +8,8 @@ export declare enum SettingKey {
|
|
|
8
8
|
aggregationEngine = "aggregationEngine",
|
|
9
9
|
calculationEngine = "calculationEngine",
|
|
10
10
|
users = "users",
|
|
11
|
-
dataReleases = "dataReleases"
|
|
11
|
+
dataReleases = "dataReleases",
|
|
12
|
+
llmPresets = "llmPresets"
|
|
12
13
|
}
|
|
13
14
|
export interface IReleaseData {
|
|
14
15
|
name?: string;
|
package/settings/model/model.js
CHANGED
|
@@ -13,6 +13,7 @@ var SettingKey;
|
|
|
13
13
|
SettingKey["calculationEngine"] = "calculationEngine";
|
|
14
14
|
SettingKey["users"] = "users";
|
|
15
15
|
SettingKey["dataReleases"] = "dataReleases";
|
|
16
|
+
SettingKey["llmPresets"] = "llmPresets";
|
|
16
17
|
})(SettingKey || (exports.SettingKey = SettingKey = {}));
|
|
17
18
|
class Setting extends model_base_1.BaseModel {
|
|
18
19
|
key;
|