diff --git a/src/lib/ai/sohbet-akisi.ts b/src/lib/ai/sohbet-akisi.ts index b391315..b6cbb92 100644 --- a/src/lib/ai/sohbet-akisi.ts +++ b/src/lib/ai/sohbet-akisi.ts @@ -34,6 +34,8 @@ export function danismanAkisi(opts: { onTamam: (metin: string) => Promise; /** Cevap tamamlanamadı; `metin` o ana kadar üretilen kısım (boş olabilir). */ onYarim: (metin: string) => Promise; + /** Sağlayıcı bu sürede bitirmezse cevap yarım sayılır (varsayılan 120 sn). */ + zamanAsimiMs?: number; }): ReadableStream { return createUIMessageStream({ execute: async ({ writer }) => { @@ -41,6 +43,9 @@ export function danismanAkisi(opts: { let metin = ""; // Model/sağlayıcı hatası akışa "error" parçası olarak düşer let akisHatasi: string | null = null; + // Sağlayıcı takılırsa SDK akışı "abort" parçasıyla sessizce bitirir + // (hata fırlatmaz); döngüden sonra sinyale ayrıca bakılır. + const zamanAsimi = AbortSignal.timeout(opts.zamanAsimiMs ?? 120_000); try { const result = streamText({ model: sohbetDilModeli(), @@ -53,7 +58,7 @@ export function danismanAkisi(opts: { prepareStep: ({ stepNumber }) => stepNumber >= ARAC_TUR_SINIRI - 1 ? { toolChoice: "none" } : undefined, maxOutputTokens: 1024, - abortSignal: AbortSignal.timeout(120_000), + abortSignal: zamanAsimi, providerOptions: { openaiCompatible: { reasoningEffort: "none" } }, onError: ({ error }) => { // Hata nesnesinin tamamı istek gövdesini ve cevap başlıklarını @@ -71,6 +76,8 @@ export function danismanAkisi(opts: { for (;;) { const { done, value: parca } = await okuyucu.read(); if (done) break; + // Kesilme istemciye "abort" değil hata olarak gider (aşağıda fırlatılır) + if (parca.type === "abort") continue; if (parca.type === "text-start" && metin && !metin.endsWith("\n")) { // Araç turundan sonra yeni metin parçası: kayıtta yapışmasın metin += "\n\n"; @@ -82,6 +89,8 @@ export function danismanAkisi(opts: { writer.write(parca); } if (akisHatasi != null) throw new Error(akisHatasi); + // Yarım metin "tamamlandı" diye kaydedilmesin: onYarim krediyi iade eder + if (zamanAsimi.aborted) throw new Error("Zaman aşımı: sağlayıcı cevabı bitirmedi"); if (!metin.trim()) throw new Error("Boş cevap"); // Çıktı denetimi (jev.ts): cevap garanti/olasılık dili içeriyorsa