mirror of
https://github.com/HeyPuter/puter.git
synced 2026-05-04 00:20:45 +00:00
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
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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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`,
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user