feat:
- added retry logic with exponential backoff - per request base_url setting - configurable key_dir - protocol downgrade protection - public secure memory API
This commit is contained in:
parent
3b1792e613
commit
76b2a284d5
5 changed files with 220 additions and 37 deletions
|
|
@ -10,6 +10,8 @@ import { ChatCompletionRequest, ChatCompletionResponse } from '../types/api';
|
|||
export class SecureChatCompletion {
|
||||
private client: SecureCompletionClient;
|
||||
private apiKey?: string;
|
||||
/** Stored config used to spin up a temporary per-request instance when base_url is overridden */
|
||||
private readonly _config: ChatCompletionConfig;
|
||||
|
||||
constructor(config: ChatCompletionConfig = {}) {
|
||||
const {
|
||||
|
|
@ -22,8 +24,11 @@ export class SecureChatCompletion {
|
|||
keyRotationInterval,
|
||||
keyRotationDir,
|
||||
keyRotationPassword,
|
||||
maxRetries,
|
||||
keyDir,
|
||||
} = config;
|
||||
|
||||
this._config = config;
|
||||
this.apiKey = apiKey;
|
||||
this.client = new SecureCompletionClient({
|
||||
routerUrl: baseUrl,
|
||||
|
|
@ -34,6 +39,8 @@ export class SecureChatCompletion {
|
|||
...(keyRotationInterval !== undefined && { keyRotationInterval }),
|
||||
...(keyRotationDir !== undefined && { keyRotationDir }),
|
||||
...(keyRotationPassword !== undefined && { keyRotationPassword }),
|
||||
...(maxRetries !== undefined && { maxRetries }),
|
||||
...(keyDir !== undefined && { keyDir }),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -43,18 +50,19 @@ export class SecureChatCompletion {
|
|||
* Supports additional NOMYO-specific fields:
|
||||
* - `security_tier`: "standard" | "high" | "maximum" — controls hardware routing
|
||||
* - `api_key`: per-request API key override (takes precedence over constructor key)
|
||||
* - `base_url`: per-request router URL override (creates a temporary client for
|
||||
* this single call, matching the Python SDK's `create(base_url=...)` behaviour)
|
||||
*/
|
||||
async create(request: ChatCompletionRequest): Promise<ChatCompletionResponse> {
|
||||
const payloadId = generateUUID();
|
||||
|
||||
// Extract NOMYO-specific fields that must not go into the encrypted payload
|
||||
const { security_tier, api_key, ...payload } = request as ChatCompletionRequest & {
|
||||
const { security_tier, api_key, base_url, ...payload } = request as ChatCompletionRequest & {
|
||||
security_tier?: string;
|
||||
api_key?: string;
|
||||
base_url?: string;
|
||||
};
|
||||
|
||||
const apiKey = api_key ?? this.apiKey;
|
||||
|
||||
if (!payload.model) {
|
||||
throw new Error('Missing required field: model');
|
||||
}
|
||||
|
|
@ -62,6 +70,29 @@ export class SecureChatCompletion {
|
|||
throw new Error('Missing or invalid required field: messages');
|
||||
}
|
||||
|
||||
const apiKey = api_key ?? this.apiKey;
|
||||
|
||||
// Per-request base_url: spin up a temporary client for this one call,
|
||||
// inheriting all other config from the current instance.
|
||||
if (base_url !== undefined) {
|
||||
const tempInstance = new SecureChatCompletion({
|
||||
...this._config,
|
||||
baseUrl: base_url,
|
||||
apiKey: this.apiKey,
|
||||
});
|
||||
try {
|
||||
const response = await tempInstance.client.sendSecureRequest(
|
||||
payload,
|
||||
payloadId,
|
||||
apiKey,
|
||||
security_tier
|
||||
);
|
||||
return response as unknown as ChatCompletionResponse;
|
||||
} finally {
|
||||
tempInstance.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
const response = await this.client.sendSecureRequest(
|
||||
payload,
|
||||
payloadId,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue