Spaces:
Running
Running
sync: 190 file da Baida98/AI@fe52a247 (2026-08-26 16:35 UTC) [deploy-all]
#121
by Baida07 - opened
- api/agent.py +49 -0
api/agent.py
CHANGED
|
@@ -1404,6 +1404,55 @@ async def stream_agent_task(task_id: str, request: Request, resume: int = 0, rol
|
|
| 1404 |
allow_tools=not bool(task.get('forbid_tools', False)),
|
| 1405 |
allow_local_csv_conversion=bool(task.get('allow_local_csv_conversion', False)),
|
| 1406 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1407 |
_agent_tasks[task_id]['status'] = 'SUCCESS'
|
| 1408 |
asyncio.create_task(sb_update_status(task_id, 'SUCCESS')).add_done_callback(_log_task_exc)
|
| 1409 |
# ARCH-K2.2: pubblica lifecycle event via Kernel
|
|
|
|
| 1404 |
allow_tools=not bool(task.get('forbid_tools', False)),
|
| 1405 |
allow_local_csv_conversion=bool(task.get('allow_local_csv_conversion', False)),
|
| 1406 |
)
|
| 1407 |
+
|
| 1408 |
+
# ARTIFACT-CONTRACT-FALLBACK: alcuni provider restituiscono codice HTML
|
| 1409 |
+
# nella risposta finale dopo aver narrato una scrittura, senza produrre
|
| 1410 |
+
# il tool event `file_written`. Non committiamo mai una falsa positività:
|
| 1411 |
+
# se il goal è UI, proviamo solo a materializzare un documento HTML
|
| 1412 |
+
# completo già presente nell'output, usando l'executor VFS autenticato.
|
| 1413 |
+
# Se non troviamo un documento completo o la scrittura fallisce, il task
|
| 1414 |
+
# resta senza artifact e il frontend non riceve alcun sync inventato.
|
| 1415 |
+
if _artifact_goal and not _vfs_written_paths and getattr(loop, 'executor', None):
|
| 1416 |
+
_artifact_output = str(result.get('output', result) if isinstance(result, dict) else result)
|
| 1417 |
+
_html_match = re.search(r'(?is)(<!doctype\s+html\b.*?</html>)', _artifact_output)
|
| 1418 |
+
if not _html_match:
|
| 1419 |
+
_html_match = re.search(r'(?is)(<html(?:\s[^>]*)?>.*?</html>)', _artifact_output)
|
| 1420 |
+
if _html_match:
|
| 1421 |
+
_artifact_content = _html_match.group(1).strip()
|
| 1422 |
+
_artifact_path = 'index.html'
|
| 1423 |
+
_path_match = re.search(r'(?i)(?:/|\b)([\w.-]+\.html)\b', _artifact_output)
|
| 1424 |
+
if _path_match:
|
| 1425 |
+
_artifact_path = _path_match.group(1)
|
| 1426 |
+
try:
|
| 1427 |
+
_write_result = await asyncio.wait_for(
|
| 1428 |
+
loop.executor.run_tool('write_file', {
|
| 1429 |
+
'path': _artifact_path,
|
| 1430 |
+
'content': _artifact_content,
|
| 1431 |
+
}),
|
| 1432 |
+
timeout=25.0,
|
| 1433 |
+
)
|
| 1434 |
+
_write_ok = not (isinstance(_write_result, dict) and _write_result.get('error'))
|
| 1435 |
+
if _write_ok:
|
| 1436 |
+
_vfs_written_paths.add(_artifact_path)
|
| 1437 |
+
await step_cb({
|
| 1438 |
+
'action': 'file_written', 'status': 'done',
|
| 1439 |
+
'path': _artifact_path, 'content': _artifact_content,
|
| 1440 |
+
'result': f'Artifact materializzato: {_artifact_path}',
|
| 1441 |
+
})
|
| 1442 |
+
_read_result = await asyncio.wait_for(
|
| 1443 |
+
loop.executor.run_tool('read_file', {'path': _artifact_path}),
|
| 1444 |
+
timeout=15.0,
|
| 1445 |
+
)
|
| 1446 |
+
_read_ok = not (isinstance(_read_result, dict) and _read_result.get('error'))
|
| 1447 |
+
await step_cb({
|
| 1448 |
+
'action': 'read_file',
|
| 1449 |
+
'status': 'done' if _read_ok else 'error',
|
| 1450 |
+
'path': _artifact_path,
|
| 1451 |
+
'result': f'Verifica artifact: {_artifact_path}' if _read_ok else str(_read_result)[:300],
|
| 1452 |
+
})
|
| 1453 |
+
except Exception as _artifact_exc:
|
| 1454 |
+
_logger.warning('[agent] artifact fallback failed: %s', type(_artifact_exc).__name__)
|
| 1455 |
+
|
| 1456 |
_agent_tasks[task_id]['status'] = 'SUCCESS'
|
| 1457 |
asyncio.create_task(sb_update_status(task_id, 'SUCCESS')).add_done_callback(_log_task_exc)
|
| 1458 |
# ARCH-K2.2: pubblica lifecycle event via Kernel
|