|
14 | 14 | from src.contexts.service import ServiceContext |
15 | 15 | from src.schemas.entities import LLMInput |
16 | 16 | from src.constants import APP_LOG_LEVEL |
17 | | -from src.agents import construct_agent, resolve_sandbox_backend, prepare_memory_files |
| 17 | +from src.agents import ( |
| 18 | + construct_agent, |
| 19 | + resolve_sandbox_backend, |
| 20 | + prepare_memory_files, |
| 21 | + is_daytona_error, |
| 22 | + _create_state_backend, |
| 23 | +) |
18 | 24 | from src.services.db import get_checkpoint_db |
19 | 25 | from src.utils.messages import from_message_to_dict |
20 | 26 | from langchain_core.messages import ( |
@@ -223,7 +229,7 @@ async def stream_generator( |
223 | 229 | stream_writer=lambda _: None, |
224 | 230 | config=config, |
225 | 231 | ) |
226 | | - backend, _sandbox = resolve_sandbox_backend(runtime, sandbox_type=sandbox_type) |
| 232 | + backend, _sandbox, effective_type = resolve_sandbox_backend(runtime, sandbox_type=sandbox_type) |
227 | 233 | agent = await construct_agent( |
228 | 234 | instructions=instructions, |
229 | 235 | system_prompt=system_prompt, |
@@ -281,16 +287,62 @@ async def stream_generator( |
281 | 287 | except PIIDetectionError as e: |
282 | 288 | # Yield error as SSE if streaming fails |
283 | 289 | logger.warning(f"Sensitive data detected in the query: {e}") |
284 | | - # raise HTTPException(status_code=500, detail=str(e)) |
285 | 290 | error_msg = ujson.dumps(("error", str(e))) |
286 | 291 | yield f"data: {error_msg}\n\n" |
287 | 292 |
|
288 | 293 | except Exception as e: |
289 | | - # Yield error as SSE if streaming fails |
290 | | - logger.exception("Error in stream_generator: %s", e) |
291 | | - # raise HTTPException(status_code=500, detail=str(e)) |
292 | | - error_msg = ujson.dumps(("error", str(e))) |
293 | | - yield f"data: {error_msg}\n\n" |
| 294 | + if is_daytona_error(e): |
| 295 | + if sandbox_type == "daytona": |
| 296 | + # Explicit daytona mode: surface the detailed error |
| 297 | + logger.error(f"Daytona sandbox error (daytona mode): {e}") |
| 298 | + error_msg = ujson.dumps(("error", f"Daytona sandbox error: {e}")) |
| 299 | + yield f"data: {error_msg}\n\n" |
| 300 | + elif sandbox_type in (None, "auto") and effective_type == "daytona": |
| 301 | + # Auto mode: fallback to local StateBackend and retry |
| 302 | + logger.warning(f"Daytona sandbox error in auto mode, falling back to local: {e}") |
| 303 | + try: |
| 304 | + fallback_backend, _ = _create_state_backend(runtime) |
| 305 | + agent = await construct_agent( |
| 306 | + instructions=instructions, |
| 307 | + system_prompt=system_prompt, |
| 308 | + model=model, |
| 309 | + tools=tools, |
| 310 | + subagents=subagents, |
| 311 | + checkpointer=checkpointer, |
| 312 | + backend=fallback_backend, |
| 313 | + service_context=service_context, |
| 314 | + api_key=api_key, |
| 315 | + memory=memory_sources, |
| 316 | + ) |
| 317 | + async for chunk in agent.astream( |
| 318 | + input, |
| 319 | + **astream_kwargs, |
| 320 | + ): |
| 321 | + stream_chunk = handle_multi_mode(chunk) |
| 322 | + if stream_chunk: |
| 323 | + stream_type = stream_chunk[0] |
| 324 | + chunk_data = stream_chunk[1] |
| 325 | + if stream_type == "values" and "files" in chunk_data: |
| 326 | + files_map = {**files_map, **chunk_data["files"]} |
| 327 | + if stream_type == "values" and "todos" in chunk_data: |
| 328 | + todos_list = chunk_data["todos"] |
| 329 | + data = ujson.dumps(stream_chunk) |
| 330 | + log_to_file(str(data), agent.model) and APP_LOG_LEVEL == "DEBUG" |
| 331 | + logger.debug(f"data: {str(data)}") |
| 332 | + yield f"data: {data}\n\n" |
| 333 | + except Exception as fallback_err: |
| 334 | + logger.exception("Fallback also failed in stream_generator: %s", fallback_err) |
| 335 | + error_msg = ujson.dumps(("error", str(fallback_err))) |
| 336 | + yield f"data: {error_msg}\n\n" |
| 337 | + else: |
| 338 | + logger.exception("Error in stream_generator: %s", e) |
| 339 | + error_msg = ujson.dumps(("error", str(e))) |
| 340 | + yield f"data: {error_msg}\n\n" |
| 341 | + else: |
| 342 | + # Non-Daytona error: original behavior |
| 343 | + logger.exception("Error in stream_generator: %s", e) |
| 344 | + error_msg = ujson.dumps(("error", str(e))) |
| 345 | + yield f"data: {error_msg}\n\n" |
294 | 346 | finally: |
295 | 347 | try: |
296 | 348 | if service_context.user_id and checkpointer and agent: |
|
0 commit comments