mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-04-22 23:08:53 +02:00
Redesign Python AI engine (#5991)
# Description of Changes Redesign the Python AI engine to be properly agentic and make use of `pydantic-ai` instead of `langchain` for correctness and ergonomics. This should be a good foundation for us to build our AI engine on going forwards.
This commit is contained in:
191
engine/tests/test_stirling_api.py
Normal file
191
engine/tests/test_stirling_api.py
Normal file
@@ -0,0 +1,191 @@
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from stirling.api import app
|
||||
from stirling.api.dependencies import (
|
||||
get_execution_planning_agent,
|
||||
get_orchestrator_agent,
|
||||
get_pdf_edit_agent,
|
||||
get_pdf_question_agent,
|
||||
get_user_spec_agent,
|
||||
)
|
||||
from stirling.config import AppSettings, load_settings
|
||||
from stirling.contracts import (
|
||||
AgentDraft,
|
||||
AgentDraftRequest,
|
||||
AgentDraftResponse,
|
||||
AgentExecutionRequest,
|
||||
AgentRevisionRequest,
|
||||
AgentRevisionResponse,
|
||||
CannotContinueExecutionAction,
|
||||
EditCannotDoResponse,
|
||||
OrchestratorRequest,
|
||||
PdfEditRequest,
|
||||
PdfQuestionNotFoundResponse,
|
||||
PdfQuestionRequest,
|
||||
UnsupportedCapabilityResponse,
|
||||
)
|
||||
from stirling.models.tool_models import RotateParams
|
||||
|
||||
|
||||
class StubSettingsProvider:
|
||||
def __call__(self) -> AppSettings:
|
||||
return AppSettings(
|
||||
smart_model_name="test",
|
||||
fast_model_name="test",
|
||||
smart_model_max_tokens=8192,
|
||||
fast_model_max_tokens=2048,
|
||||
)
|
||||
|
||||
|
||||
class StubOrchestratorAgent:
|
||||
async def handle(self, request: OrchestratorRequest) -> UnsupportedCapabilityResponse:
|
||||
return UnsupportedCapabilityResponse(capability="pdf_edit", message=request.user_message)
|
||||
|
||||
|
||||
class StubPdfEditAgent:
|
||||
async def handle(self, request: PdfEditRequest) -> EditCannotDoResponse:
|
||||
return EditCannotDoResponse(reason=request.user_message)
|
||||
|
||||
|
||||
class StubPdfQuestionAgent:
|
||||
async def handle(self, request: PdfQuestionRequest) -> PdfQuestionNotFoundResponse:
|
||||
return PdfQuestionNotFoundResponse(reason=request.question)
|
||||
|
||||
|
||||
class StubUserSpecAgent:
|
||||
async def draft(self, request: AgentDraftRequest) -> AgentDraftResponse:
|
||||
return AgentDraftResponse(
|
||||
draft=AgentDraft(
|
||||
name="Drafted",
|
||||
description="Route wiring test",
|
||||
objective=request.user_message,
|
||||
steps=[],
|
||||
)
|
||||
)
|
||||
|
||||
async def revise(self, request: AgentRevisionRequest) -> AgentRevisionResponse:
|
||||
return AgentRevisionResponse(draft=request.current_draft)
|
||||
|
||||
|
||||
class StubExecutionPlanningAgent:
|
||||
async def next_action(self, request: AgentExecutionRequest) -> CannotContinueExecutionAction:
|
||||
return CannotContinueExecutionAction(reason=str(request.current_step_index))
|
||||
|
||||
|
||||
client: TestClient = TestClient(app)
|
||||
|
||||
|
||||
def override_settings() -> AppSettings:
|
||||
return StubSettingsProvider()()
|
||||
|
||||
|
||||
def override_orchestrator_agent() -> StubOrchestratorAgent:
|
||||
return StubOrchestratorAgent()
|
||||
|
||||
|
||||
def override_pdf_edit_agent() -> StubPdfEditAgent:
|
||||
return StubPdfEditAgent()
|
||||
|
||||
|
||||
def override_pdf_question_agent() -> StubPdfQuestionAgent:
|
||||
return StubPdfQuestionAgent()
|
||||
|
||||
|
||||
def override_user_spec_agent() -> StubUserSpecAgent:
|
||||
return StubUserSpecAgent()
|
||||
|
||||
|
||||
def override_execution_agent() -> StubExecutionPlanningAgent:
|
||||
return StubExecutionPlanningAgent()
|
||||
|
||||
|
||||
app.dependency_overrides[load_settings] = override_settings
|
||||
app.dependency_overrides[get_orchestrator_agent] = override_orchestrator_agent
|
||||
app.dependency_overrides[get_pdf_edit_agent] = override_pdf_edit_agent
|
||||
app.dependency_overrides[get_pdf_question_agent] = override_pdf_question_agent
|
||||
app.dependency_overrides[get_user_spec_agent] = override_user_spec_agent
|
||||
app.dependency_overrides[get_execution_planning_agent] = override_execution_agent
|
||||
|
||||
|
||||
def test_health_route() -> None:
|
||||
response = client.get("/health")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["status"] == "ok"
|
||||
|
||||
|
||||
def test_orchestrator_route() -> None:
|
||||
response = client.post("/api/v1/orchestrator", json={"userMessage": "route this"})
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["outcome"] == "unsupported_capability"
|
||||
|
||||
|
||||
def test_pdf_edit_route() -> None:
|
||||
response = client.post("/api/v1/pdf/edit", json={"userMessage": "rotate this"})
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["outcome"] == "cannot_do"
|
||||
|
||||
|
||||
def test_pdf_questions_route() -> None:
|
||||
response = client.post("/api/v1/pdf/questions", json={"question": "what is this?"})
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["outcome"] == "not_found"
|
||||
|
||||
|
||||
def test_agent_draft_route() -> None:
|
||||
response = client.post("/api/v1/agents/draft", json={"userMessage": "build me an agent"})
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["outcome"] == "draft"
|
||||
|
||||
|
||||
def test_agent_revise_route() -> None:
|
||||
response = client.post(
|
||||
"/api/v1/agents/revise",
|
||||
json={
|
||||
"userMessage": "revise it",
|
||||
"currentDraft": {
|
||||
"name": "Drafted",
|
||||
"description": "Route wiring test",
|
||||
"objective": "build me an agent",
|
||||
"steps": [
|
||||
{
|
||||
"kind": "tool",
|
||||
"tool": "rotate",
|
||||
"parameters": RotateParams(angle=90).model_dump(by_alias=True),
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["outcome"] == "draft"
|
||||
|
||||
|
||||
def test_next_action_route() -> None:
|
||||
response = client.post(
|
||||
"/api/v1/agents/next-action",
|
||||
json={
|
||||
"agentSpec": {
|
||||
"name": "Drafted",
|
||||
"description": "Route wiring test",
|
||||
"objective": "build me an agent",
|
||||
"steps": [
|
||||
{
|
||||
"kind": "tool",
|
||||
"tool": "rotate",
|
||||
"parameters": RotateParams(angle=90).model_dump(by_alias=True),
|
||||
}
|
||||
],
|
||||
},
|
||||
"currentStepIndex": 0,
|
||||
"executionContext": {"inputFiles": ["input.pdf"], "metadata": {}},
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["outcome"] == "cannot_continue"
|
||||
Reference in New Issue
Block a user