wormclaude 1.0.79 → 1.0.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +40 -2
- package/dist/theme.js +1 -1
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -120,6 +120,30 @@ export async function* streamChat(messages, tools, config, signal) {
|
|
|
120
120
|
};
|
|
121
121
|
if (tools && tools.length)
|
|
122
122
|
body.tools = tools;
|
|
123
|
+
// ── Zaman aşımı koruması ──────────────────────────────────────────────────
|
|
124
|
+
// Node fetch (undici) varsayılan olarak header ve chunk'lar için SONSUZA kadar
|
|
125
|
+
// bekler. Bayat keep-alive soketi / ağ takılmasında akış ebediyen asılı kalır
|
|
126
|
+
// ("mesaj gönderdim, yanıt gelmiyor"). Header ve chunk'lar-arası (idle) zaman
|
|
127
|
+
// aşımı ekliyoruz; kullanıcının abort sinyaliyle BİRLEŞİR.
|
|
128
|
+
const HEADERS_MS = Number(process.env.WORMCLAUDE_HEADERS_TIMEOUT_MS) || 45_000;
|
|
129
|
+
const IDLE_MS = Number(process.env.WORMCLAUDE_IDLE_TIMEOUT_MS) || 60_000;
|
|
130
|
+
const ac = new AbortController();
|
|
131
|
+
let timedOut = false;
|
|
132
|
+
const onUserAbort = () => ac.abort();
|
|
133
|
+
if (signal) {
|
|
134
|
+
if (signal.aborted)
|
|
135
|
+
ac.abort();
|
|
136
|
+
else
|
|
137
|
+
signal.addEventListener('abort', onUserAbort, { once: true });
|
|
138
|
+
}
|
|
139
|
+
let timer = setTimeout(() => { timedOut = true; ac.abort(); }, HEADERS_MS);
|
|
140
|
+
const armIdle = () => { if (timer)
|
|
141
|
+
clearTimeout(timer); timer = setTimeout(() => { timedOut = true; ac.abort(); }, IDLE_MS); };
|
|
142
|
+
const clearTimer = () => { if (timer) {
|
|
143
|
+
clearTimeout(timer);
|
|
144
|
+
timer = null;
|
|
145
|
+
} if (signal)
|
|
146
|
+
signal.removeEventListener('abort', onUserAbort); };
|
|
123
147
|
let res;
|
|
124
148
|
try {
|
|
125
149
|
res = await fetchWithRetry(`${config.baseUrl}/chat/completions`, {
|
|
@@ -130,10 +154,15 @@ export async function* streamChat(messages, tools, config, signal) {
|
|
|
130
154
|
...(getTrace() ? { 'X-WC-Trace': getTrace(), 'X-WC-Session': getSession() } : {}),
|
|
131
155
|
},
|
|
132
156
|
body: JSON.stringify(body),
|
|
133
|
-
signal,
|
|
157
|
+
signal: ac.signal,
|
|
134
158
|
});
|
|
135
159
|
}
|
|
136
160
|
catch (e) {
|
|
161
|
+
clearTimer();
|
|
162
|
+
if (timedOut) {
|
|
163
|
+
yield { type: 'error', error: `Yanıt zaman aşımı — ${Math.round(HEADERS_MS / 1000)}sn içinde sunucudan yanıt gelmedi. Tekrar dene.` };
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
137
166
|
if (signal?.aborted || e?.name === 'AbortError') {
|
|
138
167
|
yield { type: 'done', toolCalls: [] };
|
|
139
168
|
return;
|
|
@@ -142,6 +171,7 @@ export async function* streamChat(messages, tools, config, signal) {
|
|
|
142
171
|
return;
|
|
143
172
|
}
|
|
144
173
|
if (!res.ok || !res.body) {
|
|
174
|
+
clearTimer();
|
|
145
175
|
let detail = '';
|
|
146
176
|
try {
|
|
147
177
|
detail = await res.text();
|
|
@@ -150,13 +180,14 @@ export async function* streamChat(messages, tools, config, signal) {
|
|
|
150
180
|
yield { type: 'error', error: `HTTP ${res.status}: ${detail.slice(0, 300)}` };
|
|
151
181
|
return;
|
|
152
182
|
}
|
|
183
|
+
armIdle(); // header geldi → chunk'lar-arası idle zaman aşımına geç
|
|
153
184
|
const reader = res.body.getReader();
|
|
154
185
|
const decoder = new TextDecoder();
|
|
155
186
|
let buf = '';
|
|
156
187
|
const toolParser = new StreamingToolCallParser();
|
|
157
188
|
let usage;
|
|
158
189
|
while (true) {
|
|
159
|
-
if (signal
|
|
190
|
+
if (ac.signal.aborted && !timedOut) {
|
|
160
191
|
try {
|
|
161
192
|
await reader.cancel();
|
|
162
193
|
}
|
|
@@ -168,10 +199,16 @@ export async function* streamChat(messages, tools, config, signal) {
|
|
|
168
199
|
chunk = await reader.read();
|
|
169
200
|
}
|
|
170
201
|
catch (e) {
|
|
202
|
+
clearTimer();
|
|
203
|
+
if (timedOut) {
|
|
204
|
+
yield { type: 'error', error: `Bağlantı durdu — ${Math.round(IDLE_MS / 1000)}sn yeni veri gelmedi. Tekrar dene.` };
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
171
207
|
if (signal?.aborted || e?.name === 'AbortError')
|
|
172
208
|
break;
|
|
173
209
|
throw e;
|
|
174
210
|
}
|
|
211
|
+
armIdle(); // her chunk → idle sayacını sıfırla
|
|
175
212
|
const { done, value } = chunk;
|
|
176
213
|
if (done)
|
|
177
214
|
break;
|
|
@@ -212,6 +249,7 @@ export async function* streamChat(messages, tools, config, signal) {
|
|
|
212
249
|
}
|
|
213
250
|
}
|
|
214
251
|
}
|
|
252
|
+
clearTimer(); // akış normal bitti → zamanlayıcı + dinleyici temizle
|
|
215
253
|
// Tamamlanan çağrıları sağlam biçimde topla; args'ı GEÇERLİ JSON string olarak emit et
|
|
216
254
|
// (tools.ts tarafındaki JSON.parse artık asla patlamaz — onarım burada yapıldı).
|
|
217
255
|
const toolCalls = toolParser.getCompleted().map((c) => ({
|
package/dist/theme.js
CHANGED