bloby-bot 0.47.3 → 0.47.4
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/package.json
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* Endpoint: POST {baseUrl}/models/{modelId}:streamGenerateContent?alt=sse&key={apiKey}
|
|
9
9
|
* Stream: SSE — each `data: {...}` is one candidate update.
|
|
10
10
|
*/
|
|
11
|
+
import { log } from '../../../../shared/logger.js';
|
|
11
12
|
import type {
|
|
12
13
|
PiStreamRequest,
|
|
13
14
|
PiStreamEvent,
|
|
@@ -149,9 +150,18 @@ export async function* streamGoogle(req: PiStreamRequest): AsyncIterable<PiStrea
|
|
|
149
150
|
let lastFinish: string | undefined;
|
|
150
151
|
let promptBlockReason: string | undefined;
|
|
151
152
|
let usage: { inputTokens?: number; outputTokens?: number } | undefined;
|
|
153
|
+
// Debug counters — drop once this stabilises.
|
|
154
|
+
let chunkCount = 0;
|
|
155
|
+
let thoughtPartCount = 0;
|
|
156
|
+
let emptyTextPartCount = 0;
|
|
157
|
+
let firstChunkSummary = '';
|
|
152
158
|
|
|
153
159
|
try {
|
|
154
160
|
for await (const chunk of parseSse(res)) {
|
|
161
|
+
chunkCount++;
|
|
162
|
+
if (chunkCount === 1) {
|
|
163
|
+
try { firstChunkSummary = JSON.stringify(chunk).slice(0, 600); } catch {}
|
|
164
|
+
}
|
|
155
165
|
// The whole prompt can be rejected before we even get a candidate.
|
|
156
166
|
if (chunk?.promptFeedback?.blockReason) {
|
|
157
167
|
promptBlockReason = chunk.promptFeedback.blockReason;
|
|
@@ -161,10 +171,12 @@ export async function* streamGoogle(req: PiStreamRequest): AsyncIterable<PiStrea
|
|
|
161
171
|
for (const part of parts) {
|
|
162
172
|
// Thinking models emit reasoning parts with `thought: true`. They
|
|
163
173
|
// shouldn't be shown to the user as part of the visible answer.
|
|
164
|
-
if (part?.thought) continue;
|
|
174
|
+
if (part?.thought) { thoughtPartCount++; continue; }
|
|
165
175
|
if (typeof part?.text === 'string' && part.text.length > 0) {
|
|
166
176
|
accumulated += part.text;
|
|
167
177
|
yield { type: 'text_delta', delta: part.text };
|
|
178
|
+
} else {
|
|
179
|
+
emptyTextPartCount++;
|
|
168
180
|
}
|
|
169
181
|
}
|
|
170
182
|
if (candidate?.finishReason) lastFinish = candidate.finishReason;
|
|
@@ -185,6 +197,18 @@ export async function* streamGoogle(req: PiStreamRequest): AsyncIterable<PiStrea
|
|
|
185
197
|
return;
|
|
186
198
|
}
|
|
187
199
|
|
|
200
|
+
log.info(
|
|
201
|
+
`[pi/google] stream done — chunks=${chunkCount} text=${accumulated.length} ` +
|
|
202
|
+
`thoughtParts=${thoughtPartCount} emptyTextParts=${emptyTextPartCount} ` +
|
|
203
|
+
`finishReason=${lastFinish || 'none'} ` +
|
|
204
|
+
`promptTok=${usage?.inputTokens ?? '?'} outTok=${usage?.outputTokens ?? '?'}`,
|
|
205
|
+
);
|
|
206
|
+
if (chunkCount > 0 && !accumulated) {
|
|
207
|
+
log.info(`[pi/google] first chunk (truncated): ${firstChunkSummary}`);
|
|
208
|
+
} else if (chunkCount === 0) {
|
|
209
|
+
log.warn(`[pi/google] SSE stream parsed zero chunks — check response shape (status=${res.status} content-type=${res.headers.get('content-type') || ''})`);
|
|
210
|
+
}
|
|
211
|
+
|
|
188
212
|
// Prompt-level block: nothing came back at all.
|
|
189
213
|
if (promptBlockReason) {
|
|
190
214
|
yield { type: 'error', error: `Gemini blocked the prompt (${promptBlockReason}).` };
|
|
@@ -199,7 +223,10 @@ export async function* streamGoogle(req: PiStreamRequest): AsyncIterable<PiStrea
|
|
|
199
223
|
const reason = lastFinish && lastFinish !== 'STOP' && lastFinish !== 'FINISH_REASON_STOP'
|
|
200
224
|
? lastFinish
|
|
201
225
|
: undefined;
|
|
202
|
-
|
|
226
|
+
const hint = thoughtPartCount > 0 && !lastFinish
|
|
227
|
+
? ' (model emitted thinking but never the final answer — try a non-thinking model like gemini-2.5-flash, or raise maxOutputTokens)'
|
|
228
|
+
: '';
|
|
229
|
+
yield { type: 'error', error: finishReasonMessage(reason) + hint };
|
|
203
230
|
yield { type: 'done', stopReason: mapStopReason(lastFinish), usage };
|
|
204
231
|
return;
|
|
205
232
|
}
|