diff --git a/src/gateway/memory_maintenance.rs b/src/gateway/memory_maintenance.rs index 5f0c8af..203542a 100644 --- a/src/gateway/memory_maintenance.rs +++ b/src/gateway/memory_maintenance.rs @@ -151,12 +151,11 @@ impl MemoryMaintenanceService { ), ], temperature: Some(0.0), - max_tokens: Some(1200), + max_tokens: Some(4000), tools: None, }; let mut last_error = None; - let mut response = None; for (attempt, delay_ms) in MEMORY_MAINTENANCE_RETRY_DELAYS_MS .iter() @@ -165,11 +164,8 @@ impl MemoryMaintenanceService { .chain(std::iter::once(None)) .enumerate() { - match provider.chat(request.clone()).await { - Ok(success) => { - response = Some(success); - break; - } + let response = match provider.chat(request.clone()).await { + Ok(success) => success, Err(err) => { let error_text = err.to_string(); let should_retry = @@ -194,34 +190,56 @@ impl MemoryMaintenanceService { error_text ))); } + }; + + let raw_content = strip_json_code_fence(&response.content); + let json_candidate = extract_json_object(raw_content).unwrap_or(raw_content); + + match serde_json::from_str::(json_candidate) { + Ok(parsed) => return Ok(parsed), + Err(err) => { + let error_msg = err.to_string(); + let is_truncated = error_msg.contains("EOF while parsing") + || error_msg.contains("expected"); + + let should_retry = delay_ms.is_some() && is_truncated; + last_error = Some(error_msg.clone()); + + if should_retry { + tracing::warn!( + scope_key = %scope_key, + attempt = attempt + 1, + retry_in_ms = delay_ms.unwrap_or_default(), + error = %error_msg, + raw_len = raw_content.len(), + "Memory organization JSON parse failed (possibly truncated), retrying" + ); + tokio::time::sleep(Duration::from_millis(delay_ms.unwrap_or_default())) + .await; + continue; + } + + tracing::error!( + scope_key = %scope_key, + error = %err, + raw_len = raw_content.len(), + raw_preview = %preview_text(raw_content, 400), + json_candidate_len = json_candidate.len(), + json_candidate_preview = %preview_text(json_candidate, 400), + "Memory maintenance JSON decode failed" + ); + return Err(AgentError::Other(format!( + "memory maintenance JSON decode error: {}", + err + ))); + } } } - let response = response.ok_or_else(|| { - AgentError::Other(format!( - "memory organization model error: {}", - last_error.unwrap_or_else(|| "unknown provider error".to_string()) - )) - })?; - - let raw_content = strip_json_code_fence(&response.content); - let json_candidate = extract_json_object(raw_content).unwrap_or(raw_content); - - let output: MemoryOrganizationOutput = - serde_json::from_str(json_candidate).map_err(|err| { - tracing::error!( - scope_key = %scope_key, - error = %err, - raw_len = raw_content.len(), - raw_preview = %preview_text(raw_content, 400), - json_candidate_len = json_candidate.len(), - json_candidate_preview = %preview_text(json_candidate, 400), - "Memory maintenance JSON decode failed" - ); - AgentError::Other(format!("memory maintenance JSON decode error: {}", err)) - })?; - - Ok(output) + Err(AgentError::Other(format!( + "memory organization failed after retries: {}", + last_error.unwrap_or_else(|| "unknown error".to_string()) + ))) } #[cfg_attr(not(test), allow(dead_code))]