diff --git a/src/backend/drivers/ai-chat/ChatCompletionDriver.ts b/src/backend/drivers/ai-chat/ChatCompletionDriver.ts index b848d63f2..90ce3840c 100644 --- a/src/backend/drivers/ai-chat/ChatCompletionDriver.ts +++ b/src/backend/drivers/ai-chat/ChatCompletionDriver.ts @@ -1209,14 +1209,6 @@ export class ChatCompletionDriver extends PuterDriver { ); } - const togetherKey = readKey(providers['together-ai']); - if (togetherKey) { - this.#providers['together-ai'] = new TogetherAIProvider( - { apiKey: togetherKey }, - metering, - ); - } - // Ollama — auto-discover local instance unless `enabled: false`. const ollama = providers['ollama']; if (ollama?.enabled !== false) { @@ -1228,6 +1220,18 @@ export class ChatCompletionDriver extends PuterDriver { ); } + const infron = providers['infron']; + const infronKey = readKey(infron); + if (infronKey) { + this.#providers['infron'] = new InfronProvider( + { + apiKey: infronKey, + apiBaseUrl: infron?.apiBaseUrl as string | undefined, + }, + metering, + ); + } + const openrouter = providers['openrouter']; const openrouterKey = readKey(openrouter); if (openrouterKey) { @@ -1240,14 +1244,10 @@ export class ChatCompletionDriver extends PuterDriver { ); } - const infron = providers['infron']; - const infronKey = readKey(infron); - if (infronKey) { - this.#providers['infron'] = new InfronProvider( - { - apiKey: infronKey, - apiBaseUrl: infron?.apiBaseUrl as string | undefined, - }, + const togetherKey = readKey(providers['together-ai']); + if (togetherKey) { + this.#providers['together-ai'] = new TogetherAIProvider( + { apiKey: togetherKey }, metering, ); } diff --git a/src/backend/drivers/ai-chat/providers/azure/AzureChatProvider.ts b/src/backend/drivers/ai-chat/providers/azure/AzureChatProvider.ts index bec9db009..e25e5d212 100644 --- a/src/backend/drivers/ai-chat/providers/azure/AzureChatProvider.ts +++ b/src/backend/drivers/ai-chat/providers/azure/AzureChatProvider.ts @@ -81,7 +81,7 @@ export class AzureChatProvider implements IChatProvider { baseURL: config.apiURL, }); } - checkModeration(_text: string): { flagged: boolean; categories: string[] } { + checkModeration(_text: string) { throw new Error('Method not implemented.'); } @@ -180,7 +180,7 @@ export class AzureChatProvider implements IChatProvider { // }) const userIdentifier = - actor.user?.id + actor.app?.uid ? `:${actor?.app?.uid}` : ''; + `${actor.user?.id}` + actor.app?.uid ? `:${actor?.app?.uid}` : ''; // Resolve any `puter_path` content parts into inline base64 data URLs. // Chat Completions doesn't support file uploads, so this is the only diff --git a/src/backend/drivers/ai-chat/providers/openai/OpenAiChatResponsesProvider.ts b/src/backend/drivers/ai-chat/providers/openai/OpenAiChatResponsesProvider.ts index f31973e26..a353b36f7 100644 --- a/src/backend/drivers/ai-chat/providers/openai/OpenAiChatResponsesProvider.ts +++ b/src/backend/drivers/ai-chat/providers/openai/OpenAiChatResponsesProvider.ts @@ -146,7 +146,7 @@ export class OpenAiResponsesChatProvider implements IChatProvider { // }) const userIdentifier = - actor?.user.id + actor?.app?.uid ? `:${actor?.app?.uid}` : ''; + `${actor?.user.id}` + actor?.app?.uid ? `:${actor?.app?.uid}` : ''; // Resolve any `puter_path` content parts into inline base64 data URLs // before the Responses API sees them. @@ -260,7 +260,7 @@ export class OpenAiResponsesChatProvider implements IChatProvider { this.#meteringService.utilRecordUsageObject( trackedUsage, - actor, + actor!, `openai:${modelUsed?.id}`, costsOverrideFromModel, ); diff --git a/src/backend/drivers/ai-chat/types.ts b/src/backend/drivers/ai-chat/types.ts index eb4f3a195..a5bd4aa42 100644 --- a/src/backend/drivers/ai-chat/types.ts +++ b/src/backend/drivers/ai-chat/types.ts @@ -146,5 +146,7 @@ export interface IChatProvider { list(): string[] | Promise; getDefaultModel(): string; complete(arg: ICompleteArguments): Promise; - checkModeration(text: string): { flagged: boolean; categories: string[] }; + checkModeration( + text: string, + ): Promise<{ flagged: boolean; categories?: string[] }> | void; } diff --git a/src/backend/drivers/ai-chat/utils/OpenAIUtil.js b/src/backend/drivers/ai-chat/utils/OpenAIUtil.js index 26acf35dd..430832b85 100644 --- a/src/backend/drivers/ai-chat/utils/OpenAIUtil.js +++ b/src/backend/drivers/ai-chat/utils/OpenAIUtil.js @@ -564,7 +564,7 @@ export const handle_completion_output = async ( * @param {(args: { * usage: import('openai/resources/completions.mjs').CompletionUsage; * }) => unknown} params.usage_calculator - * @returns + * @returns {ReturnType} */ export const handle_completion_output_responses_api = async ({ deviations, diff --git a/src/backend/services/share/ShareNotificationService.ts b/src/backend/services/share/ShareNotificationService.ts index b8e55d79a..b80368d5c 100644 --- a/src/backend/services/share/ShareNotificationService.ts +++ b/src/backend/services/share/ShareNotificationService.ts @@ -56,11 +56,11 @@ export const SHARE_NOTIFY_RECIPIENT_DAILY_LIMIT = 50; * span goes as a single message. Email can't be rewritten the way the in-app * notification can, so it gets the grouped wording by waiting instead. */ -export const SHARE_EMAIL_BATCH_SECONDS = 90; +export const SHARE_EMAIL_BATCH_SECONDS = 30; // Long enough to list, claim and send; short enough that a crashed flusher // doesn't strand the digest. -const DIGEST_LOCK_SECONDS = 30; +const DIGEST_LOCK_SECONDS = 20; // Ceiling on how long an entry may sit unflushed: a node dying with the only // timer leaves entries behind, and mail this stale is noise rather than news.