fix: Detect streaming state in reasoning content blocks (#21549)
This commit is contained in:
parent
d1f82e382d
commit
ecce0087da
File diff suppressed because one or more lines are too long
|
|
@ -18,7 +18,7 @@
|
||||||
<div style="display: contents">
|
<div style="display: contents">
|
||||||
<script>
|
<script>
|
||||||
{
|
{
|
||||||
__sveltekit_1y361v9 = {
|
__sveltekit_1wqaxod = {
|
||||||
base: new URL('.', location).pathname.slice(0, -1)
|
base: new URL('.', location).pathname.slice(0, -1)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
const showToolCallInProgress = $derived(config().showToolCallInProgress as boolean);
|
const showToolCallInProgress = $derived(config().showToolCallInProgress as boolean);
|
||||||
const showThoughtInProgress = $derived(config().showThoughtInProgress as boolean);
|
const showThoughtInProgress = $derived(config().showThoughtInProgress as boolean);
|
||||||
|
|
||||||
const sections = $derived(deriveAgenticSections(message, toolMessages, []));
|
const sections = $derived(deriveAgenticSections(message, toolMessages, [], isStreaming));
|
||||||
|
|
||||||
// Parse tool results with images
|
// Parse tool results with images
|
||||||
const sectionsParsed = $derived(
|
const sectionsParsed = $derived(
|
||||||
|
|
|
||||||
|
|
@ -38,14 +38,19 @@ export type ToolResultLine = {
|
||||||
function deriveSingleTurnSections(
|
function deriveSingleTurnSections(
|
||||||
message: DatabaseMessage,
|
message: DatabaseMessage,
|
||||||
toolMessages: DatabaseMessage[] = [],
|
toolMessages: DatabaseMessage[] = [],
|
||||||
streamingToolCalls: ApiChatCompletionToolCall[] = []
|
streamingToolCalls: ApiChatCompletionToolCall[] = [],
|
||||||
|
isStreaming: boolean = false
|
||||||
): AgenticSection[] {
|
): AgenticSection[] {
|
||||||
const sections: AgenticSection[] = [];
|
const sections: AgenticSection[] = [];
|
||||||
|
|
||||||
// 1. Reasoning content (from dedicated field)
|
// 1. Reasoning content (from dedicated field)
|
||||||
if (message.reasoningContent) {
|
if (message.reasoningContent) {
|
||||||
|
const toolCalls = parseToolCalls(message.toolCalls);
|
||||||
|
const hasContentAfterReasoning =
|
||||||
|
!!message.content?.trim() || toolCalls.length > 0 || streamingToolCalls.length > 0;
|
||||||
|
const isPending = isStreaming && !hasContentAfterReasoning;
|
||||||
sections.push({
|
sections.push({
|
||||||
type: AgenticSectionType.REASONING,
|
type: isPending ? AgenticSectionType.REASONING_PENDING : AgenticSectionType.REASONING,
|
||||||
content: message.reasoningContent
|
content: message.reasoningContent
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -104,12 +109,13 @@ function deriveSingleTurnSections(
|
||||||
export function deriveAgenticSections(
|
export function deriveAgenticSections(
|
||||||
message: DatabaseMessage,
|
message: DatabaseMessage,
|
||||||
toolMessages: DatabaseMessage[] = [],
|
toolMessages: DatabaseMessage[] = [],
|
||||||
streamingToolCalls: ApiChatCompletionToolCall[] = []
|
streamingToolCalls: ApiChatCompletionToolCall[] = [],
|
||||||
|
isStreaming: boolean = false
|
||||||
): AgenticSection[] {
|
): AgenticSection[] {
|
||||||
const hasAssistantContinuations = toolMessages.some((m) => m.role === MessageRole.ASSISTANT);
|
const hasAssistantContinuations = toolMessages.some((m) => m.role === MessageRole.ASSISTANT);
|
||||||
|
|
||||||
if (!hasAssistantContinuations) {
|
if (!hasAssistantContinuations) {
|
||||||
return deriveSingleTurnSections(message, toolMessages, streamingToolCalls);
|
return deriveSingleTurnSections(message, toolMessages, streamingToolCalls, isStreaming);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sections: AgenticSection[] = [];
|
const sections: AgenticSection[] = [];
|
||||||
|
|
@ -127,7 +133,12 @@ export function deriveAgenticSections(
|
||||||
const isLastTurn = i + 1 + turnToolMsgs.length >= toolMessages.length;
|
const isLastTurn = i + 1 + turnToolMsgs.length >= toolMessages.length;
|
||||||
|
|
||||||
sections.push(
|
sections.push(
|
||||||
...deriveSingleTurnSections(msg, turnToolMsgs, isLastTurn ? streamingToolCalls : [])
|
...deriveSingleTurnSections(
|
||||||
|
msg,
|
||||||
|
turnToolMsgs,
|
||||||
|
isLastTurn ? streamingToolCalls : [],
|
||||||
|
isLastTurn && isStreaming
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
i += 1 + turnToolMsgs.length;
|
i += 1 + turnToolMsgs.length;
|
||||||
|
|
|
||||||
|
|
@ -162,6 +162,36 @@ describe('deriveAgenticSections', () => {
|
||||||
expect(sections[4].content).toBe('Here is the analysis.');
|
expect(sections[4].content).toBe('Here is the analysis.');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns REASONING_PENDING when streaming with only reasoning content', () => {
|
||||||
|
const msg = makeAssistant({
|
||||||
|
reasoningContent: 'Let me think about this...'
|
||||||
|
});
|
||||||
|
const sections = deriveAgenticSections(msg, [], [], true);
|
||||||
|
expect(sections).toHaveLength(1);
|
||||||
|
expect(sections[0].type).toBe(AgenticSectionType.REASONING_PENDING);
|
||||||
|
expect(sections[0].content).toBe('Let me think about this...');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns REASONING (not pending) when streaming but text content has appeared', () => {
|
||||||
|
const msg = makeAssistant({
|
||||||
|
content: 'The answer is',
|
||||||
|
reasoningContent: 'Let me think...'
|
||||||
|
});
|
||||||
|
const sections = deriveAgenticSections(msg, [], [], true);
|
||||||
|
expect(sections).toHaveLength(2);
|
||||||
|
expect(sections[0].type).toBe(AgenticSectionType.REASONING);
|
||||||
|
expect(sections[1].type).toBe(AgenticSectionType.TEXT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns REASONING (not pending) when not streaming', () => {
|
||||||
|
const msg = makeAssistant({
|
||||||
|
reasoningContent: 'Let me think...'
|
||||||
|
});
|
||||||
|
const sections = deriveAgenticSections(msg, [], [], false);
|
||||||
|
expect(sections).toHaveLength(1);
|
||||||
|
expect(sections[0].type).toBe(AgenticSectionType.REASONING);
|
||||||
|
});
|
||||||
|
|
||||||
it('multi-turn: streaming tool calls on last turn', () => {
|
it('multi-turn: streaming tool calls on last turn', () => {
|
||||||
const assistant1 = makeAssistant({
|
const assistant1 = makeAssistant({
|
||||||
toolCalls: JSON.stringify([
|
toolCalls: JSON.stringify([
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue