Fix markdown streaming duplication by splitting newlines first

- Added string-width library for proper terminal column width calculation
- Fixed wrapLine() to split by newlines before wrapping (like Text component)
- Fixed Loader interval leak by stopping before container removal
- Changed loader message from 'Loading...' to 'Working...'
This commit is contained in:
Mario Zechner 2025-11-11 19:27:58 +01:00
parent 985f955ea0
commit c5083bb7cb
16 changed files with 429 additions and 372 deletions

View file

@ -167,29 +167,26 @@ async function stateUpdates(model: Model<any>) {
}),
});
const stateSnapshots: Array<{ isStreaming: boolean; messageCount: number; hasStreamMessage: boolean }> = [];
const events: Array<string> = [];
agent.subscribe((event) => {
if (event.type === "state-update") {
stateSnapshots.push({
isStreaming: event.state.isStreaming,
messageCount: event.state.messages.length,
hasStreamMessage: event.state.streamMessage !== null,
});
}
events.push(event.type);
});
await agent.prompt("Count from 1 to 5.");
const streamingStates = stateSnapshots.filter((s) => s.isStreaming);
const nonStreamingStates = stateSnapshots.filter((s) => !s.isStreaming);
// Should have received lifecycle events
expect(events).toContain("agent_start");
expect(events).toContain("agent_end");
expect(events).toContain("message_start");
expect(events).toContain("message_end");
// May have message_update events during streaming
const hasMessageUpdates = events.some((e) => e === "message_update");
expect(hasMessageUpdates).toBe(true);
expect(streamingStates.length).toBeGreaterThan(0);
expect(nonStreamingStates.length).toBeGreaterThan(0);
const finalState = stateSnapshots[stateSnapshots.length - 1];
expect(finalState.isStreaming).toBe(false);
expect(finalState.messageCount).toBe(2);
// Check final state
expect(agent.state.isStreaming).toBe(false);
expect(agent.state.messages.length).toBe(2); // User message + assistant response
}
async function multiTurnConversation(model: Model<any>) {