MCPcopy Create free account
hub / github.com/AI45Lab/Code / generate_streaming

Function generate_streaming

core/src/llm/structured.rs:194–290  ·  view source on GitHub ↗

Generate a structured JSON object with streaming partial updates. Calls `on_partial` with progressively more complete partial objects as tokens arrive. Returns the final validated object. In streaming mode, `max_repair_attempts` defaults to 0 because a repair would reset the partial object stream (confusing for consumers).

(
    client: &dyn LlmClient,
    req: &StructuredRequest,
    on_partial: PartialObjectCallback,
)

Source from the content-addressed store, hash-verified

192/// In streaming mode, `max_repair_attempts` defaults to 0 because a repair
193/// would reset the partial object stream (confusing for consumers).
194pub async fn generate_streaming(
195 client: &dyn LlmClient,
196 req: &StructuredRequest,
197 on_partial: PartialObjectCallback,
198) -> Result<StructuredResult> {
199 let mode = resolve_mode(req.mode, client.native_structured_support());
200 let messages = build_initial_messages(req, mode);
201 let system = build_system_prompt(req, mode);
202 let tools = build_tools(req, mode);
203 let directive = build_directive(req, mode);
204
205 let cancel_token = CancellationToken::new();
206 let mut rx = client
207 .complete_streaming_structured(&messages, Some(&system), &tools, &directive, cancel_token)
208 .await
209 .context("LLM streaming call failed during structured generation")?;
210
211 let mut json_buffer = String::new();
212 let mut last_valid_partial: Option<Value> = None;
213 let mut final_response: Option<super::LlmResponse> = None;
214 let mut last_parse_len: usize = 0;
215 // Minimum bytes of new data before attempting a partial parse (reduces CPU)
216 const PARSE_THRESHOLD: usize = 8;
217
218 while let Some(event) = rx.recv().await {
219 match event {
220 StreamEvent::ToolUseInputDelta(delta) if mode == StructuredMode::Tool => {
221 if final_response.is_some() {
222 continue;
223 }
224 json_buffer.push_str(&delta);
225 if json_buffer.len() - last_parse_len >= PARSE_THRESHOLD {
226 if let Some(partial) = try_parse_partial_json(&json_buffer) {
227 if last_valid_partial.as_ref() != Some(&partial) {
228 on_partial(&partial);
229 last_valid_partial = Some(partial);
230 }
231 }
232 last_parse_len = json_buffer.len();
233 }
234 }
235 StreamEvent::TextDelta(delta) if mode != StructuredMode::Tool => {
236 if final_response.is_some() {
237 continue;
238 }
239 json_buffer.push_str(&delta);
240 if json_buffer.len() - last_parse_len >= PARSE_THRESHOLD {
241 if let Some(json_start) = find_json_start(&json_buffer) {
242 let candidate = &json_buffer[json_start..];
243 if let Some(partial) = try_parse_partial_json(candidate) {
244 if last_valid_partial.as_ref() != Some(&partial) {
245 on_partial(&partial);
246 last_valid_partial = Some(partial);
247 }
248 }
249 }
250 last_parse_len = json_buffer.len();
251 }

Calls 13

resolve_modeFunction · 0.85
build_initial_messagesFunction · 0.85
build_system_promptFunction · 0.85
build_toolsFunction · 0.85
build_directiveFunction · 0.85
try_parse_partial_jsonFunction · 0.85
find_json_startFunction · 0.85
extract_raw_candidatesFunction · 0.85
resolve_structuredFunction · 0.85
contextMethod · 0.80