perf: memo GridCard, fuse save fns, fix slash tab active color
Some checks failed
CI / Lint, Unit Tests & Build (push) Failing after 1m32s
CI / Deploy production (on server) (push) Has been skipped

This commit is contained in:
Antigravity
2026-06-14 14:06:05 +00:00
parent a8785ed4f1
commit a623454347
120 changed files with 12301 additions and 785 deletions

View File

@@ -9,6 +9,7 @@ import { hasUserAiConsent } from '@/lib/consent/server-consent'
import { loadTranslations, getTranslationValue, SupportedLanguage } from '@/lib/i18n'
import { toolRegistry } from '@/lib/ai/tools'
import { checkEntitlementOrThrow, QuotaExceededError, incrementUsageAsync } from '@/lib/entitlements'
import { ByokUnavailableError } from '@/lib/byok'
import { trackFeatureUsage } from '@/lib/usage-tracker'
import { readFile } from 'fs/promises'
import path from 'path'
@@ -70,6 +71,12 @@ export async function POST(req: Request) {
if (err instanceof QuotaExceededError) {
return Response.json(err.toJSON(), { status: 402 })
}
if (err instanceof ByokUnavailableError) {
return Response.json(
{ error: 'byok_unavailable', message: 'Votre clé API BYOK est configurée mais n\'a pas pu être chargée. Vérifiez vos paramètres BYOK.' },
{ status: 503 }
)
}
console.error('[chat] Quota check error (fail-open):', err)
}
@@ -410,40 +417,49 @@ Focus ONLY on this note unless asked otherwise.`
]
const wantsChart = chartKeywords.some(k => lastMessage.includes(k))
const { result, usedByok } = await runLaneWithBillingUser(
'chat',
sysConfig,
userId,
async (provider) =>
streamText({
model: provider.getModel(),
system: systemPrompt,
messages: incomingMessages,
tools: chatTools,
toolChoice: wantsChart && chatTools.insert_chart ? { type: 'tool', toolName: 'insert_chart' } : undefined,
stopWhen: stepCountIs(5),
onFinish: async (final) => {
const userContent = incomingMessages[incomingMessages.length - 1].content
await prisma.chatMessage.create({
data: { conversationId: conversation.id, role: 'user', content: userContent },
})
await prisma.chatMessage.create({
data: { conversationId: conversation.id, role: 'assistant', content: final.text },
})
if (!usedByok) {
trackFeatureUsage(userId, 'chat', final.usage?.totalTokens ?? 0)
incrementUsageAsync(userId, 'chat')
}
logAuditEvent({
userId,
action: 'AI_REQUEST',
resource: 'chat',
metadata: { tokens: final.usage?.totalTokens, byok: usedByok },
ip: getClientIp(req),
})
},
}),
)
return result.toUIMessageStreamResponse()
try {
const { result, usedByok } = await runLaneWithBillingUser(
'chat',
sysConfig,
userId,
async (provider) =>
streamText({
model: provider.getModel(),
system: systemPrompt,
messages: incomingMessages,
tools: chatTools,
toolChoice: wantsChart && chatTools.insert_chart ? { type: 'tool', toolName: 'insert_chart' } : undefined,
stopWhen: stepCountIs(5),
onFinish: async (final) => {
const userContent = incomingMessages[incomingMessages.length - 1].content
await prisma.chatMessage.create({
data: { conversationId: conversation.id, role: 'user', content: userContent },
})
await prisma.chatMessage.create({
data: { conversationId: conversation.id, role: 'assistant', content: final.text },
})
if (!usedByok) {
trackFeatureUsage(userId, 'chat', final.usage?.totalTokens ?? 0)
incrementUsageAsync(userId, 'chat')
}
logAuditEvent({
userId,
action: 'AI_REQUEST',
resource: 'chat',
metadata: { tokens: final.usage?.totalTokens, byok: usedByok },
ip: getClientIp(req),
})
},
}),
)
return result.toUIMessageStreamResponse()
} catch (err) {
if (err instanceof ByokUnavailableError) {
return Response.json(
{ error: 'byok_unavailable', message: 'Votre clé API BYOK est configurée mais n\'a pas pu être chargée. Vérifiez vos paramètres dans Réglages > Clés API.' },
{ status: 503 }
)
}
throw err
}
}