feat(danisman): profil onayı kredi harcamaz; yapay zekâ sağlayıcı adresi .env'den (AI_BASE_URL/AI_API_KEY)

- Bilal kararı (26 Eyl 2026): 'kaydedeyim mi?' sorusuna kısa evet/hayır
  cevabı bedelsiz. Sunucu son danışman mesajında onay ibaresini arar,
  mesaj ≤40 karakter ve evet/hayır kalıbıyla başlıyorsa kredi düşmez,
  ledger'a yazılmaz, iade yolu atlanır; X-Kredi-Dusuldu başlığıyla istemci
  bakiyeyi buna göre günceller. Gerçek soru içeren 'evet ama …' bedava geçmez.
- Bilal kararı: model Türkiye'de barındırılacak. client.ts baseURL ve
  anahtar AI_BASE_URL/AI_API_KEY'den okunur (OPENROUTER_* geriye uyumlu);
  sağlayıcı değişince kod değil .env değişir, /gizlilik aynı commit'te.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-09-25 10:44:44 +03:00
parent 5a04db7e4b
commit 70423853f3
4 changed files with 108 additions and 30 deletions

View File

@@ -137,6 +137,33 @@ export async function spendCreditForMessage(opts: {
}
}
/**
* Kredi DÜŞMEDEN kullanıcı mesajı kaydeder — yalnız profil onayı ("kaydedeyim
* mi?" → "evet") için (Bilal kararı, 26 Eyl 2026: onay ücretsiz). Ledger'a
* satır yazılmaz; clientMessageId çakışırsa DUPLICATE.
*/
export async function bedelsizMesajKaydet(opts: {
userId: string;
content: string;
clientMessageId: string;
}): Promise<SpendResult & { messageId?: string }> {
const messageId = newId();
try {
await appDb.insert(chatMessages).values({
id: messageId,
userId: opts.userId,
role: "user",
content: opts.content,
clientMessageId: opts.clientMessageId,
createdAt: new Date(),
});
return { ok: true, messageId };
} catch (err) {
if (uniqueIhlaliMi(err)) return { ok: false, error: "DUPLICATE" };
throw err;
}
}
/** `paketTekil` ile çağrılan tanımlamada kullanıcı zaten paketliyse fırlatılır. */
class ZatenPaketli extends Error {}