MCPcopy Create free account
hub / github.com/IBM/mcp-cli / ToolCallAccumulator

Class ToolCallAccumulator

src/mcp_cli/chat/streaming_handler.py:86–219  ·  view source on GitHub ↗

Manages accumulation of tool calls across streaming chunks. Uses Pydantic models for type-safe state management. Handles fragmented JSON and validates tool call structure.

Source from the content-addressed store, hash-verified

84
85
86class ToolCallAccumulator:
87 """Manages accumulation of tool calls across streaming chunks.
88
89 Uses Pydantic models for type-safe state management.
90 Handles fragmented JSON and validates tool call structure.
91 """
92
93 def __init__(self) -> None:
94 self._accumulated: list[ToolCallData] = []
95
96 def process_chunk_tool_calls(self, chunk_tool_calls: list[dict[str, Any]]) -> None:
97 """Process tool calls from a chunk and accumulate them.
98
99 Args:
100 chunk_tool_calls: Tool calls extracted from current chunk
101 """
102 for tc_dict in chunk_tool_calls:
103 # Convert dict to Pydantic model
104 tc = ToolCallData.from_dict(tc_dict)
105
106 # Find or create accumulator for this tool call
107 existing = self._find_accumulated_call(tc.id, tc.index)
108
109 if existing:
110 # Merge chunk data using intelligent JSON merging
111 self._merge_tool_call(existing, tc)
112 else:
113 # New tool call - add to accumulated list
114 self._accumulated.append(tc)
115
116 def _find_accumulated_call(self, tc_id: str, tc_index: int) -> ToolCallData | None:
117 """Find existing accumulated tool call by ID or index."""
118 for tc in self._accumulated:
119 if tc.id == tc_id or tc.index == tc_index:
120 return tc
121 return None
122
123 def _merge_tool_call(self, existing: ToolCallData, new: ToolCallData) -> None:
124 """Merge new tool call data into existing accumulator."""
125 # Update function name if provided
126 if new.function.name:
127 existing.function.name = new.function.name
128
129 # Accumulate arguments using intelligent JSON merging
130 if new.function.arguments:
131 merged_args = self._merge_json_strings(
132 existing.function.arguments, new.function.arguments
133 )
134 existing.function.arguments = merged_args
135
136 def _merge_json_strings(self, current: str, new: str) -> str:
137 """Merge two JSON strings intelligently.
138
139 Tries multiple strategies:
140 1. Parse both and merge dicts
141 2. Concatenate and validate
142 3. Fix common issues
143 """

Calls

no outgoing calls