Skip to content

Commit f62a97b

Browse files
committed
refactor: extract extractChunkDeltaText helper to deduplicate advisor chunk parsing
The text-delta and reasoning-delta cases in onAdvisorChunk both cast the chunk to the same shape and probe three field names for a string value, differing only in priority order. Extract a shared helper that takes the chunk and an ordered list of field names, returning the first string found. Behavior is preserved — field lookup order is unchanged.
1 parent dff38d1 commit f62a97b

1 file changed

Lines changed: 29 additions & 26 deletions

File tree

src/node/services/aiService.ts

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,25 @@ interface ToolExecutionContext {
193193
abortSignal?: AbortSignal;
194194
}
195195

196+
/**
197+
* Extract the first string-typed value from a chunk object by trying field names
198+
* in priority order. Different AI SDK chunk types (`text-delta`, `reasoning-delta`)
199+
* surface the delta text under varying field names; this avoids duplicating the
200+
* probe logic for each case.
201+
*/
202+
function extractChunkDeltaText(
203+
chunk: Record<string, unknown>,
204+
fieldPriority: readonly string[]
205+
): string {
206+
for (const field of fieldPriority) {
207+
const value = chunk[field];
208+
if (typeof value === "string") {
209+
return value;
210+
}
211+
}
212+
return "";
213+
}
214+
196215
function isToolExecutionContext(value: unknown): value is ToolExecutionContext {
197216
if (typeof value !== "object" || value == null || Array.isArray(value)) {
198217
return false;
@@ -1307,40 +1326,24 @@ export class AIService extends EventEmitter {
13071326
const onAdvisorChunk: StreamTextOnChunk = ({ chunk }) => {
13081327
switch (chunk.type) {
13091328
case "text-delta": {
1310-
const textDeltaChunk = chunk as {
1311-
text?: unknown;
1312-
delta?: unknown;
1313-
textDelta?: unknown;
1314-
};
13151329
// Providers/SDKs can stream advisor text deltas under different field names.
1316-
const chunkText =
1317-
typeof textDeltaChunk.textDelta === "string"
1318-
? textDeltaChunk.textDelta
1319-
: typeof textDeltaChunk.delta === "string"
1320-
? textDeltaChunk.delta
1321-
: typeof textDeltaChunk.text === "string"
1322-
? textDeltaChunk.text
1323-
: "";
1330+
const chunkText = extractChunkDeltaText(chunk as Record<string, unknown>, [
1331+
"textDelta",
1332+
"delta",
1333+
"text",
1334+
]);
13241335
if (chunkText.length > 0) {
13251336
advisorStepCaptureRef.currentStepText += chunkText;
13261337
}
13271338
return;
13281339
}
13291340
case "reasoning-delta": {
1330-
const reasoningChunk = chunk as {
1331-
text?: unknown;
1332-
textDelta?: unknown;
1333-
delta?: unknown;
1334-
};
13351341
// Anthropic signature updates can arrive as reasoning deltas without text.
1336-
const chunkText =
1337-
typeof reasoningChunk.text === "string"
1338-
? reasoningChunk.text
1339-
: typeof reasoningChunk.textDelta === "string"
1340-
? reasoningChunk.textDelta
1341-
: typeof reasoningChunk.delta === "string"
1342-
? reasoningChunk.delta
1343-
: "";
1342+
const chunkText = extractChunkDeltaText(chunk as Record<string, unknown>, [
1343+
"text",
1344+
"textDelta",
1345+
"delta",
1346+
]);
13441347
if (chunkText.length > 0) {
13451348
advisorStepCaptureRef.currentStepReasoning += chunkText;
13461349
}

0 commit comments

Comments
 (0)