clean: misc cleanups
Docker Image CI / build-and-push-image (push) Waiting to run
Maintain Release Merge PR / update-release-pr (push) Waiting to run
release-please / release-please (push) Waiting to run
test / test (18.x) (push) Waiting to run
test / test (20.x) (push) Waiting to run
test / test (22.x) (push) Waiting to run

This commit is contained in:
KernelDeimos
2024-12-10 15:58:22 -05:00
parent ff62d9009e
commit cd7755da6b
8 changed files with 24 additions and 220 deletions
-12
View File
@@ -475,18 +475,6 @@ module.exports = class APIError {
status: 400,
message: 'Incorrect or missing anti-CSRF token.',
},
// Chat
// TODO: specifying these errors here might be a violation
// of separation of concerns. Services could register their
// own errors with an error registry.
'max_tokens_exceeded': {
status: 400,
message: ({ input_tokens, max_tokens }) =>
`Input exceeds maximum token count. ` +
`Input has ${input_tokens} tokens, ` +
`but the maximum is ${max_tokens}.`,
},
};
/**
@@ -17,9 +17,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
module.exports = class UserParam {
constructor () {
//
}
consolidate ({ req }) {
return req.user;
}
+4 -4
View File
@@ -140,15 +140,15 @@ if ( config.os.refined ) {
module.exports = config;
// NEW_CONFIG_LOADING
const maybe_port = config =>
config.pub_port !== 80 && config.pub_port !== 443 ? ':' + config.pub_port : '';
const computed_defaults = {
pub_port: config => config.http_port,
origin: config => config.protocol + '://' + config.domain +
(config.pub_port !== 80 && config.pub_port !== 443 ? ':' + config.pub_port : ''),
origin: config => config.protocol + '://' + config.domain + maybe_port(config),
api_base_url: config => config.experimental_no_subdomain
? config.origin
: config.protocol + '://api.' + config.domain +
(config.pub_port !== 80 && config.pub_port !== 443 ? ':' + config.pub_port : ''),
: config.protocol + '://api.' + config.domain + maybe_port(config),
social_card: config => `${config.origin}/assets/img/screenshot.png`,
};
-190
View File
@@ -1,190 +0,0 @@
/*
* Copyright (C) 2024 Puter Technologies Inc.
*
* This file is part of Puter.
*
* Puter is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("@heyputer/putility");
const { Context } = require('../util/context')
const APIError = require("../api/APIError");
const { AppUnderUserActorType, UserActorType } = require("../services/auth/Actor");
const { BaseOperation } = require("../services/OperationTraceService");
const { CodeUtil } = require("../codex/CodeUtil");
/**
* Base class for all driver implementations.
*
* @deprecated - we use traits on services now. This class is kept for compatibility
* with EntityStoreImplementation and DBKVStore which still use this.
*/
class Driver extends AdvancedBase {
constructor (...a) {
super(...a);
const methods = this._get_merged_static_object('METHODS');
// Turn each method into an operation
for ( const k in methods ) {
methods[k] = CodeUtil.mrwrap(methods[k], BaseOperation, {
name: `${this.constructor.ID}:${k}`,
});
};
this.methods = methods;
this.sla = this._get_merged_static_object('SLA');
}
async call (method, args) {
if ( ! this.methods[method] ) {
throw new Error(`method not found: ${method}`);
}
const pseudo_this = Object.assign({}, this);
const context = Context.get();
pseudo_this.context = context;
pseudo_this.services = context.get('services');
const services = context.get('services');
pseudo_this.log = services.get('log-service').create(this.constructor.name);
await this._sla_enforcement(method);
return await this.methods[method].call(pseudo_this, args);
}
async _sla_enforcement (method) {
const context = Context.get();
const services = context.get('services');
const method_key = `${this.constructor.ID}:${method}`;
const svc_sla = services.get('sla');
// System SLA enforcement
{
const sla_key = `driver:impl:${method_key}`;
const sla = await svc_sla.get('system', sla_key);
const sys_method_key = `system:${method_key}`;
// short-term rate limiting
if ( sla?.rate_limit ) {
const svc_rateLimit = services.get('rate-limit');
let eventual_success = false;
for ( let i = 0 ; i < 60 ; i++ ) {
try {
await svc_rateLimit.check_and_increment(sys_method_key, sla.rate_limit.max, sla.rate_limit.period);
eventual_success = true;
break;
} catch ( e ) {
if (
! ( e instanceof APIError ) ||
e.fields.code !== 'rate_limit_exceeded'
) throw e;
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
if ( ! eventual_success ) {
throw APIError.create('server_rate_exceeded');
}
}
}
// test_mode is checked to prevent rate limiting when it is enabled
const test_mode = context.get('test_mode');
// User SLA enforcement
{
const actor = context.get('actor').get_related_actor(UserActorType);
const user_is_verified = !! actor.type.user.email_confirmed;
const sla_key = `driver:impl:${method_key}`;
const sla = await svc_sla.get(
user_is_verified ? 'user_verified' : 'user_unverified',
sla_key
);
// short-term rate limiting
if ( sla?.rate_limit ) {
const svc_rateLimit = services.get('rate-limit');
await svc_rateLimit.check_and_increment(method_key, sla.rate_limit.max, sla.rate_limit.period);
}
// long-term rate limiting
if ( sla?.monthly_limit && ! test_mode ) {
const svc_monthlyUsage = services.get('monthly-usage');
const count = await svc_monthlyUsage.check(
actor, {
'driver.interface': this.constructor.INTERFACE,
'driver.implementation': this.constructor.ID,
'driver.method': method,
});
if ( count >= sla.monthly_limit ) {
throw APIError.create('monthly_limit_exceeded', null, {
method_key,
limit: sla.monthly_limit,
});
}
}
}
// App SLA enforcement
await (async () => {
const actor = context.get('actor');
if ( ! ( actor.type instanceof AppUnderUserActorType ) ) return;
const sla_key = `driver:impl:${method_key}`;
const sla = await svc_sla.get('app_default', sla_key);
// long-term rate limiting
if ( sla?.monthly_limit && ! test_mode ) {
const svc_monthlyUsage = services.get('monthly-usage');
const count = await svc_monthlyUsage.check(
actor, {
'driver.interface': this.constructor.INTERFACE,
'driver.implementation': this.constructor.ID,
'driver.method': method,
});
if ( count >= sla.monthly_limit ) {
throw APIError.create('monthly_limit_exceeded', null, {
method_key,
limit: sla.monthly_limit,
});
}
}
})();
// Record monthly usage
if ( ! test_mode ) {
const actor = context.get('actor');
const svc_monthlyUsage = services.get('monthly-usage');
const extra = {
'driver.interface': this.constructor.INTERFACE,
'driver.implementation': this.constructor.ID,
'driver.method': method,
...(this.get_usage_extra ? this.get_usage_extra() : {}),
};
await svc_monthlyUsage.increment(actor, method_key, extra);
}
}
async get_response_meta () {
return {
driver: this.constructor.ID,
driver_version: this.constructor.VERSION,
driver_interface: this.constructor.INTERFACE,
};
}
}
module.exports = {
Driver,
};
+7 -7
View File
@@ -50,7 +50,7 @@ const error_help_details = [
apply (more) {
more.references = [
...reused.runtime_env_references,
]
];
}
},
{
@@ -68,10 +68,10 @@ const error_help_details = [
{
title: 'Set CONFIG_PATH or RUNTIME_PATH environment variable',
},
],
];
more.references = [
...reused.runtime_env_references,
]
];
}
},
{
@@ -83,7 +83,7 @@ const error_help_details = [
{
title: 'Create a valid config file',
},
]
];
}
},
{
@@ -112,7 +112,7 @@ const error_help_details = [
use: 'describes why this error occurs',
url: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_const_assignment'
},
]
];
}
},
{
@@ -122,7 +122,7 @@ const error_help_details = [
apply (more) {
more.notes = [
'It looks like this might be our fault.',
]
];
more.solutions = [
{
title: `Check for an issue on ` +
@@ -135,7 +135,7 @@ const error_help_details = [
'create one'
) + '.'
}
]
];
}
},
{
@@ -92,6 +92,17 @@ class AIChatService extends BaseService {
await this.db.insert('ai_usage', values);
});
const svc_apiErrpr = this.services.get('api-error');
svc_apiErrpr.register({
max_tokens_exceeded: {
status: 400,
message: ({ input_tokens, max_tokens }) =>
`Input exceeds maximum token count. ` +
`Input has ${input_tokens} tokens, ` +
`but the maximum is ${max_tokens}.`,
},
});
}
@@ -341,8 +341,9 @@ class OpenAICompletionService extends BaseService {
const max_tokens = 4096 - token_count;
console.log('MAX TOKENS ???', max_tokens);
const svc_apiErrpr = this.services.get('api-error');
if ( max_tokens <= 8 ) {
throw APIError.create('max_tokens_exceeded', null, {
throw svc_apiErrpr.create('max_tokens_exceeded', {
input_tokens: token_count,
max_tokens: 4096 - 8,
});
@@ -26,9 +26,6 @@ const APIError = require('../../../api/APIError.js');
* Since Express 5 is not yet released, this function is used by
* eggspress() to handle errors instead of as a middleware.
*
* @todo remove this function and use express error handling
* when Express 5 is released
*
* @param {*} err
* @param {*} req
* @param {*} res