From 0fbd7dce1a4472d256b3fe351fc272b249b0cf9d Mon Sep 17 00:00:00 2001 From: Barabashka Date: Tue, 21 Apr 2026 17:37:36 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20FastAPI=20endpoint=20=D0=B7=D0=B0=D0=BF=D1=83=D1=81?= =?UTF-8?q?=D0=BA=D0=B0=20=D1=81=D1=86=D0=B5=D0=BD=D0=B0=D1=80=D0=B8=D1=8F?= =?UTF-8?q?=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20AgentOS=20base=5Fapp.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Подключен верхний HTTP-слой с POST /api/runs и обновлены схемы/README, чтобы запуск сценариев шел через единый API-контракт поверх Agno workflow. --- README.md | 35 ++++++++++++++++++++++++++++++++++- src/agent_os.py | 14 +++++++++++++- src/api_routes.py | 17 +++++++++++++++++ src/schemas.py | 10 +++++++++- 4 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 src/api_routes.py diff --git a/README.md b/README.md index 5e24e2a..09b8e53 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ## Требования -- Python 3.11+ +- Python 3.10+ - Запущенный Ollama endpoint (по умолчанию: `http://localhost:11435`) - Доступная модель в Ollama (по умолчанию: `gemma4:31b`) @@ -23,11 +23,13 @@ prisma_platform/ │ └── v1.json └── src/ ├── __init__.py + ├── api_routes.py ├── agent_os.py ├── agent_runner.py ├── main.py ├── observability.py ├── scenario_store.py + ├── schemas.py ├── stub_tools.py └── workflow_runner.py ``` @@ -76,6 +78,37 @@ python -m src.agent_os - `http://127.0.0.1:7777/docs` - `http://127.0.0.1:7777/redoc` +Верхний слой сервиса реализован как кастомные FastAPI роуты (`src/api_routes.py`), подключенные через `AgentOS(base_app=...)`. + +### Запуск сценария через HTTP + +- `POST http://127.0.0.1:7777/api/runs` +- Тело запроса (JSON): + +```json +{ + "scenario_id": "news_source_discovery_v1", + "input": { + "url": "https://example.com/news" + } +} +``` + +Пример запроса: + +```bash +curl -X POST "http://127.0.0.1:7777/api/runs" \ + -H "Content-Type: application/json" \ + -d '{ + "scenario_id": "news_source_discovery_v1", + "input": { + "url": "https://example.com/news" + } + }' +``` + +Endpoint возвращает структурированный ответ со статусом `success` или `failed`. + Проверка, что сервер поднят: ```bash diff --git a/src/agent_os.py b/src/agent_os.py index 39a2505..7e5f648 100644 --- a/src/agent_os.py +++ b/src/agent_os.py @@ -1,9 +1,11 @@ import os from dotenv import load_dotenv +from fastapi import FastAPI from agno.os import AgentOS +from src.api_routes import router as api_router from src.agent_runner import get_agent from src.observability import init_phoenix_tracing from src.scenario_store import load_scenario_definition @@ -16,7 +18,17 @@ _agent = get_agent() _default_scenario_id = "news_source_discovery_v1" _scenario = load_scenario_definition(_default_scenario_id) _workflow = get_workflow_for_scenario(_default_scenario_id, _scenario) -_agent_os = AgentOS(agents=[_agent], workflows=[_workflow], tracing=_tracing_enabled) +_base_app = FastAPI( + title="Prisma Platform API", + version="0.1.0", +) +_base_app.include_router(api_router) +_agent_os = AgentOS( + agents=[_agent], + workflows=[_workflow], + tracing=_tracing_enabled, + base_app=_base_app, +) app = _agent_os.get_app() diff --git a/src/api_routes.py b/src/api_routes.py new file mode 100644 index 0000000..8b183bb --- /dev/null +++ b/src/api_routes.py @@ -0,0 +1,17 @@ +from fastapi import APIRouter +from pydantic import TypeAdapter + +from src.schemas import ScenarioRunRequest, ScenarioRunResponse +from src.workflow_runner import run_scenario_workflow + +router = APIRouter(prefix="/api", tags=["workflow"]) +_run_response_adapter = TypeAdapter(ScenarioRunResponse) + + +@router.post("/runs", response_model=ScenarioRunResponse) +async def run_scenario(request: ScenarioRunRequest) -> ScenarioRunResponse: + result = await run_scenario_workflow( + input_data=request.input, + scenario_id=request.scenario_id, + ) + return _run_response_adapter.validate_python(result) diff --git a/src/schemas.py b/src/schemas.py index fe7708f..9a4f95d 100644 --- a/src/schemas.py +++ b/src/schemas.py @@ -2,7 +2,7 @@ from __future__ import annotations from typing import Any, Literal -from pydantic import BaseModel +from pydantic import BaseModel, Field class RunError(BaseModel): @@ -10,6 +10,11 @@ class RunError(BaseModel): message: str +class ScenarioRunRequest(BaseModel): + scenario_id: str = "news_source_discovery_v1" + input: dict[str, Any] = Field(default_factory=dict) + + class ScenarioRunBase(BaseModel): scenario_id: str status: Literal["success", "failed"] @@ -29,3 +34,6 @@ class ScenarioRunSuccess(ScenarioRunBase): result: dict[str, Any] run_id: str | None = None session_id: str | None = None + + +ScenarioRunResponse = ScenarioRunSuccess | ScenarioRunFailed