fix(danisman): H2 (2) — zaman aşımında yarım cevap tamam sayılmasın, kredi iade edilsin

SDK akış ortası abort'u hata fırlatmadan "abort" parçasıyla bitiriyordu;
döngü bunu tamamlanma sayıp yarım metni kaydediyor, krediyi iade etmiyordu.
Döngüden sonra sinyale bakılır: kesildiyse onYarim (iade + yarım kayıt) çalışır,
istemciye hata parçası gider. Süre zamanAsimiMs ile verilebilir (varsayılan 120 sn).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-10-05 01:06:34 +03:00
parent 3f1e770013
commit 90a9994e5f

View File

@@ -34,6 +34,8 @@ export function danismanAkisi(opts: {
onTamam: (metin: string) => Promise<void>;
/** Cevap tamamlanamadı; `metin` o ana kadar üretilen kısım (boş olabilir). */
onYarim: (metin: string) => Promise<void>;
/** Sağlayıcı bu sürede bitirmezse cevap yarım sayılır (varsayılan 120 sn). */
zamanAsimiMs?: number;
}): ReadableStream<UIMessageChunk> {
return createUIMessageStream<UIMessage>({
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