diff --git a/.env.example b/.env.example index 687281a..430dc0d 100644 --- a/.env.example +++ b/.env.example @@ -19,7 +19,7 @@ OPENAI_API_KEY=your-openai-api-key PARSER_MODEL=gpt-4.1-mini PURCHASE_PARSER_MODEL=gpt-5-mini ASSISTANT_MODEL=gpt-5-mini -ASSISTANT_TIMEOUT_MS=15000 +ASSISTANT_TIMEOUT_MS=20000 ASSISTANT_MEMORY_MAX_TURNS=12 ASSISTANT_RATE_LIMIT_BURST=5 ASSISTANT_RATE_LIMIT_BURST_WINDOW_MS=60000 diff --git a/apps/bot/src/config.ts b/apps/bot/src/config.ts index 0f7dc03..eb2c51a 100644 --- a/apps/bot/src/config.ts +++ b/apps/bot/src/config.ts @@ -133,7 +133,7 @@ export function getBotRuntimeConfig(env: NodeJS.ProcessEnv = process.env): BotRu assistantModel: env.ASSISTANT_MODEL?.trim() || 'gpt-5-mini', assistantTimeoutMs: parsePositiveInteger( env.ASSISTANT_TIMEOUT_MS, - 15_000, + 20_000, 'ASSISTANT_TIMEOUT_MS' ), assistantMemoryMaxTurns: parsePositiveInteger( diff --git a/apps/bot/src/dm-assistant.ts b/apps/bot/src/dm-assistant.ts index d367787..e9223dd 100644 --- a/apps/bot/src/dm-assistant.ts +++ b/apps/bot/src/dm-assistant.ts @@ -73,6 +73,26 @@ interface PaymentProposalPayload { currency: 'GEL' | 'USD' } +function describeError(error: unknown): { + errorMessage?: string + errorName?: string +} { + if (error instanceof Error) { + return { + errorMessage: error.message, + errorName: error.name + } + } + + if (typeof error === 'string') { + return { + errorMessage: error + } + } + + return {} +} + function isPrivateChat(ctx: Context): boolean { return ctx.chat?.type === 'private' } @@ -749,8 +769,13 @@ export function registerDmAssistant(options: { const memory = options.memoryStore.get(telegramUserId) const typingIndicator = startTypingIndicator(ctx) let pendingReply: PendingAssistantReply | null = null + const assistantStartedAt = Date.now() + let stage: 'household_context' | 'assistant_response' = 'household_context' + let contextBuildMs: number | null = null + let assistantResponseMs: number | null = null try { + const contextStartedAt = Date.now() const householdContext = await buildHouseholdContext({ householdId: member.householdId, memberId: member.id, @@ -759,7 +784,10 @@ export function registerDmAssistant(options: { householdConfigurationRepository: options.householdConfigurationRepository, financeService }) + contextBuildMs = Date.now() - contextStartedAt pendingReply = await sendAssistantProcessingReply(ctx, t.processing) + stage = 'assistant_response' + const assistantResponseStartedAt = Date.now() const reply = await options.assistant.respond({ locale, householdContext, @@ -767,6 +795,7 @@ export function registerDmAssistant(options: { recentTurns: memory.turns, userMessage: ctx.msg.text }) + assistantResponseMs = Date.now() - assistantResponseStartedAt options.usageTracker.record({ householdId: member.householdId, @@ -788,6 +817,12 @@ export function registerDmAssistant(options: { event: 'assistant.reply', householdId: member.householdId, telegramUserId, + contextBuildMs, + assistantResponseMs, + totalDurationMs: Date.now() - assistantStartedAt, + householdContextChars: householdContext.length, + recentTurnsCount: memory.turns.length, + memorySummaryChars: memory.summary?.length ?? 0, inputTokens: reply.usage.inputTokens, outputTokens: reply.usage.outputTokens, totalTokens: reply.usage.totalTokens @@ -802,6 +837,11 @@ export function registerDmAssistant(options: { event: 'assistant.reply_failed', householdId: member.householdId, telegramUserId, + stage, + contextBuildMs, + assistantResponseMs, + totalDurationMs: Date.now() - assistantStartedAt, + ...describeError(error), error }, 'DM assistant reply failed' diff --git a/infra/terraform/terraform.tfvars.example b/infra/terraform/terraform.tfvars.example index 645f7e4..83246f0 100644 --- a/infra/terraform/terraform.tfvars.example +++ b/infra/terraform/terraform.tfvars.example @@ -14,7 +14,7 @@ openai_api_key_secret_id = "openai-api-key" bot_parser_model = "gpt-4.1-mini" bot_purchase_parser_model = "gpt-5-mini" bot_assistant_model = "gpt-5-mini" -bot_assistant_timeout_ms = 15000 +bot_assistant_timeout_ms = 20000 bot_assistant_memory_max_turns = 12 bot_assistant_rate_limit_burst = 5 bot_assistant_rate_limit_burst_window_ms = 60000 diff --git a/packages/config/src/env.ts b/packages/config/src/env.ts index 1cc4631..e2a2ecb 100644 --- a/packages/config/src/env.ts +++ b/packages/config/src/env.ts @@ -34,7 +34,7 @@ const server = { PARSER_MODEL: z.string().min(1).default('gpt-4.1-mini'), PURCHASE_PARSER_MODEL: z.string().min(1).default('gpt-5-mini'), ASSISTANT_MODEL: z.string().min(1).default('gpt-5-mini'), - ASSISTANT_TIMEOUT_MS: z.coerce.number().int().positive().default(15000), + ASSISTANT_TIMEOUT_MS: z.coerce.number().int().positive().default(20000), ASSISTANT_MEMORY_MAX_TURNS: z.coerce.number().int().positive().default(12), ASSISTANT_RATE_LIMIT_BURST: z.coerce.number().int().positive().default(5), ASSISTANT_RATE_LIMIT_BURST_WINDOW_MS: z.coerce.number().int().positive().default(60000),