alvin-bot 4.18.4 → 4.18.5
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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Alvin Bot are documented here.
|
|
4
4
|
|
|
5
|
+
## [4.18.5] — 2026-04-23
|
|
6
|
+
|
|
7
|
+
### 🐛 Fix: auto-reset stale SDK sessionId on empty-stream detection
|
|
8
|
+
|
|
9
|
+
**Problem:** After a round of failed queries (common trigger: token rotation, quota exhaustion mid-turn, Claude backend dropping the session silently), the stored `session.sessionId` references a conversation that the Claude backend has already discarded. Every subsequent query passes `resume: session.sessionId` into the SDK, the backend can't find the session, and the stream terminates with zero text chunks. The v4.18.3 empty-stream detector only invalidated the availability cache — the sessionId stayed stale, so the next retry resumed the same dead session. A burn-credits loop that required a manual `/new` to escape.
|
|
10
|
+
|
|
11
|
+
**Fix:** the provider now sets a new `sessionResetRequested: true` flag on the empty-stream text chunk. Both message handlers (`handlers/message.ts` and `handlers/platform-message.ts`) listen for it and clear `session.sessionId` + `session.lastSdkHistoryIndex` immediately, so the very next user message starts a fresh SDK session instead of resuming the dead one.
|
|
12
|
+
|
|
13
|
+
**Net effect:** after a single empty-stream, the bot self-heals. One resend from the user is enough; no manual `/new`, no bot restart.
|
|
14
|
+
|
|
5
15
|
## [4.18.4] — 2026-04-23
|
|
6
16
|
|
|
7
17
|
### 🐛 Critical fix: detect Anthropic quota-exhausted responses
|
package/dist/handlers/message.js
CHANGED
|
@@ -446,6 +446,16 @@ export async function handleMessage(ctx) {
|
|
|
446
446
|
// Clear any tool-use status line — real content is flowing now.
|
|
447
447
|
streamer.setStatus(null);
|
|
448
448
|
await streamer.update(finalText);
|
|
449
|
+
// v4.18.5 — Provider requested a session reset (empty-stream / stale
|
|
450
|
+
// sessionId recovery). Clear the session's sessionId + SDK anchor so
|
|
451
|
+
// the next query starts a fresh Claude session instead of resuming
|
|
452
|
+
// the broken one. Without this, the bot would loop empty-stream
|
|
453
|
+
// replies and burn credits until the user manually runs /new.
|
|
454
|
+
if (chunk.sessionResetRequested) {
|
|
455
|
+
console.warn(`[session] provider requested reset for ${sessionKey} — clearing sessionId + SDK anchor`);
|
|
456
|
+
session.sessionId = null;
|
|
457
|
+
session.lastSdkHistoryIndex = -1;
|
|
458
|
+
}
|
|
449
459
|
// Emit the new delta for observers — accumulated text minus what
|
|
450
460
|
// we already broadcast.
|
|
451
461
|
if (finalText.length > lastBroadcastLen) {
|
|
@@ -194,6 +194,13 @@ export async function handlePlatformMessage(msg, adapter) {
|
|
|
194
194
|
switch (chunk.type) {
|
|
195
195
|
case "text":
|
|
196
196
|
finalText = chunk.text || "";
|
|
197
|
+
// v4.18.5 — Provider-requested session reset on empty-stream detection.
|
|
198
|
+
// Mirror of the same handling in handlers/message.ts.
|
|
199
|
+
if (chunk.sessionResetRequested) {
|
|
200
|
+
console.warn(`[session] provider requested reset for ${sessionKey} — clearing sessionId + SDK anchor`);
|
|
201
|
+
session.sessionId = null;
|
|
202
|
+
session.lastSdkHistoryIndex = -1;
|
|
203
|
+
}
|
|
197
204
|
break;
|
|
198
205
|
case "done":
|
|
199
206
|
if (chunk.sessionId)
|
|
@@ -377,13 +377,19 @@ export class ClaudeSDKProvider {
|
|
|
377
377
|
// and knows to resend — without tripping the failover.
|
|
378
378
|
if (accumulatedText === "" && outputTok === 0) {
|
|
379
379
|
this.invalidateAvailabilityCache();
|
|
380
|
-
const hint = "⚠️ Claude antwortete mit leerem Stream
|
|
381
|
-
"
|
|
380
|
+
const hint = "⚠️ Claude antwortete mit leerem Stream. " +
|
|
381
|
+
"Meist Folge einer stale SDK-Session nach /extra-usage, /login oder Token-Refresh. " +
|
|
382
|
+
"Ich starte die Session automatisch neu — bitte schick die Nachricht einfach nochmal.";
|
|
382
383
|
yield {
|
|
383
384
|
type: "text",
|
|
384
385
|
text: hint,
|
|
385
386
|
delta: hint,
|
|
386
387
|
sessionId: resultMsg.session_id || capturedSessionId,
|
|
388
|
+
// v4.18.5 — Signal to the message handler that it should clear
|
|
389
|
+
// session.sessionId now. Without this the next query resumes
|
|
390
|
+
// the same stale sessionId and produces another empty stream
|
|
391
|
+
// in a loop that burns credits until the user manually /new's.
|
|
392
|
+
sessionResetRequested: true,
|
|
387
393
|
};
|
|
388
394
|
}
|
|
389
395
|
yield {
|