import json from smolagents import MultiStepAgent from smolagents.memory import ActionStep, FinalAnswerStep, PlanningStep def _format_arguments(arguments) -> str: if arguments is None: return "{}" if isinstance(arguments, str): return arguments try: return json.dumps(arguments, ensure_ascii=False, indent=2) except TypeError: return str(arguments) def _truncate(text: str, limit: int = 600) -> str: if not text: return "(пусто)" text = str(text).strip() if len(text) <= limit: return text return text[:limit] + f"\n… (ещё {len(text) - limit} символов)" class StreamingAgentRunner: def __init__(self, agent: MultiStepAgent): self.agent = agent def _format_action_step(self, step: ActionStep) -> list[str]: lines = [f"### Шаг {step.step_number}"] if step.model_output: output = step.model_output if isinstance(output, list): output = json.dumps(output, ensure_ascii=False) lines.append("**Модель:**") lines.append(f"```\n{_truncate(output, 400)}\n```") if step.tool_calls: for i, tc in enumerate(step.tool_calls, start=1): prefix = f"[{step.step_number}.{i}]" if len(step.tool_calls) > 1 else f"[{step.step_number}]" lines.append(f"**{prefix} → `{tc.name}`**") lines.append(f"```json\n{_format_arguments(tc.arguments)}\n```") if step.observations: lines.append("**← результат:**") lines.append(f"```\n{_truncate(step.observations)}\n```") if step.error: lines.append(f"**⚠ ошибка:** {step.error}") return lines def run(self, query: str): """Генератор прогресса агента и финального ответа.""" parts = ["Агент думает...\n"] yield parts[0], 0 try: for step in self.agent.run(query, stream=True, reset=True): if isinstance(step, PlanningStep): parts.append(f"**План:** {step.plan.strip()}") elif isinstance(step, ActionStep): parts.extend(self._format_action_step(step)) elif isinstance(step, FinalAnswerStep): parts.append(f"## Ответ\n\n{step.output}") progress = min(len(parts) / (self.agent.max_steps + 1), 0.95) yield "\n\n".join(parts), progress yield "\n\n".join(parts), 1.0 except Exception as e: yield f"Ошибка: {e}", 1.0