fix(chat-ui): fix MCPEvent layering, batch localStorage writes, module-level test imports

- Move MCPEvent interface definition into chat/types.ts (single source of truth)
- MCPEventsDisplay.tsx now imports MCPEvent from types.ts instead of defining it locally
- Batch MCP event localStorage writes: accumulate during stream, persist once in finally
- Move test imports to module level per PEP 8 convention
This commit is contained in:
Ishaan Jaffer 2026-03-10 17:12:43 -07:00
parent 90b7e32332
commit 712c15ee68
4 changed files with 39 additions and 46 deletions

View file

@ -6,11 +6,15 @@ Verifies that:
2. Absence of previous_response_id does not break the call
3. The aresponses function signature exposes the expected parameters
"""
import inspect
import json
import os
import sys
import unittest.mock as mock
sys.path.insert(0, os.path.abspath("../.."))
import httpx
import pytest
import litellm
@ -21,8 +25,6 @@ class TestResponsesSessionChaining:
def test_responses_api_signature_accepts_previous_response_id(self):
"""aresponses must accept previous_response_id and onResponseId-like params."""
import inspect
sig = inspect.signature(litellm.aresponses)
assert "previous_response_id" in sig.parameters, (
"aresponses must accept previous_response_id for multi-turn session chaining"
@ -33,13 +35,9 @@ class TestResponsesSessionChaining:
@pytest.mark.asyncio
async def test_previous_response_id_included_in_request_body(self):
"""previous_response_id must appear in the outgoing HTTP request body."""
import httpx
captured_body: dict = {}
async def mock_send(self_transport, request: httpx.Request, **kwargs):
import json
try:
captured_body.update(json.loads(request.content))
except Exception:
@ -68,8 +66,6 @@ class TestResponsesSessionChaining:
request=request,
)
import unittest.mock as mock
with mock.patch("httpx.AsyncClient.send", mock_send):
try:
await litellm.aresponses(
@ -88,13 +84,9 @@ class TestResponsesSessionChaining:
@pytest.mark.asyncio
async def test_no_previous_response_id_omitted_from_request(self):
"""When previous_response_id is None, it must not appear in the request body."""
import httpx
captured_body: dict = {}
async def mock_send(self_transport, request: httpx.Request, **kwargs):
import json
try:
captured_body.update(json.loads(request.content))
except Exception:
@ -118,8 +110,6 @@ class TestResponsesSessionChaining:
}
return httpx.Response(200, json=response_json, request=request)
import unittest.mock as mock
with mock.patch("httpx.AsyncClient.send", mock_send):
try:
await litellm.aresponses(

View file

@ -304,10 +304,9 @@ const ChatPage: React.FC<ChatPageProps> = ({ accessToken, userRole, userId, user
previousResponseId,
(id: string) => setResponsesSessionId(id),
(event: MCPEvent) => {
// Accumulate locally only — persisted once in finally to avoid
// one full localStorage write per MCP event during streaming.
accumulatedMCPEvents.push(event);
// Persist a snapshot to the assistant message so events survive
// across turns instead of disappearing when the next send starts.
updateLastAssistantMessage(convId!, { mcpEvents: [...accumulatedMCPEvents] });
},
);
} catch (err: unknown) {
@ -321,6 +320,10 @@ const ChatPage: React.FC<ChatPageProps> = ({ accessToken, userRole, userId, user
});
}
} finally {
// Persist MCP events once after the turn ends (single localStorage write).
if (accumulatedMCPEvents.length > 0) {
updateLastAssistantMessage(convId!, { mcpEvents: accumulatedMCPEvents });
}
setIsStreaming(false);
abortControllerRef.current = null;
}

View file

@ -1,6 +1,29 @@
import type { MCPEvent } from "../playground/chat_ui/MCPEventsDisplay";
export type { MCPEvent };
/** Represents a single MCP tool event emitted during an assistant turn. */
export interface MCPEvent {
type: string;
sequence_number?: number;
output_index?: number;
item_id?: string;
item?: {
id?: string;
type?: string;
server_label?: string;
tools?: Array<{
name: string;
description: string;
annotations?: {
read_only?: boolean;
};
input_schema?: unknown;
}>;
name?: string;
arguments?: string;
output?: string;
};
delta?: string;
arguments?: string;
timestamp?: number;
}
export interface ChatMessage {
id: string;

View file

@ -1,35 +1,12 @@
import React from "react";
import { Typography, Collapse } from "antd";
import type { MCPEvent } from "../../chat/types";
export type { MCPEvent };
const { Text } = Typography;
const { Panel } = Collapse;
export interface MCPEvent {
type: string;
sequence_number?: number;
output_index?: number;
item_id?: string;
item?: {
id?: string;
type?: string;
server_label?: string;
tools?: Array<{
name: string;
description: string;
annotations?: {
read_only?: boolean;
};
input_schema?: any;
}>;
name?: string;
arguments?: string;
output?: string;
};
delta?: string;
arguments?: string;
timestamp?: number;
}
interface MCPEventsDisplayProps {
events: MCPEvent[];
className?: string;