Files
Stirling-PDF/engine/tests/test_stirling_contracts.py
T
e5767ed58b Change AI engine to execute tools in Java instead of on frontend (#6116)
# Description of Changes
Redesign AI engine so that it autogenerates the `tool_models.py` file
from the OpenAPI spec so the Python has access to the Java API
parameters and the full list of Java tools that it can run. CI ensures
that whenever someone modifies a tool endpoint that the AI enigne tool
models get updated as well (the dev gets told to run `task
engine:tool-models`).

There's loads of advantages to having the Java be the one that actually
executes the tools, rather than the frontend as it was previously set up
to theoretically use:
- The AI gets much better descriptions of the params from the API docs
- It'll be usable headless in the future so a Java daemon could run to
execute ops on files in a folder without the need for the UI to run
- The Java already has all the logic it needs to execute the tools 
- We don't need to parse the TypeScript to find the API (which is hard
because the TS wasn't designed to be computer-read to extract the API)

I've also hooked up the prototype frontend to ensure it's working
properly, and have built it in a way that all the tool names can be
translated properly, which was always an issue with previous prototypes
of this.

---------

Co-authored-by: Anthony Stirling <[email protected]>
Co-authored-by: EthanHealy01 <[email protected]>
2026-04-20 15:57:11 +01:00

88 lines
2.6 KiB
Python

from stirling.config import AppSettings
from stirling.contracts import (
AgentExecutionRequest,
AgentSpec,
AgentSpecStep,
EditPlanResponse,
ExecutionContext,
ExtractedFileText,
ExtractedTextArtifact,
OrchestratorRequest,
PdfQuestionAnswerResponse,
PdfTextSelection,
ToolOperationStep,
)
from stirling.models.tool_models import Angle, RotatePdfParams, ToolEndpoint
def test_orchestrator_request_accepts_user_message() -> None:
request = OrchestratorRequest(
user_message="Rotate the PDF",
file_names=["test.pdf"],
artifacts=[
ExtractedTextArtifact(
files=[
ExtractedFileText(
file_name="test.pdf",
pages=[PdfTextSelection(page_number=1, text="Hello")],
)
]
)
],
)
assert request.user_message == "Rotate the PDF"
assert len(request.artifacts) == 1
def test_agent_execution_request_uses_typed_agent_spec() -> None:
steps: list[AgentSpecStep] = [
ToolOperationStep(
tool=ToolEndpoint.ROTATE_PDF,
parameters=RotatePdfParams(angle=Angle(90)),
)
]
request = AgentExecutionRequest(
agent_spec=AgentSpec(
name="Invoice cleanup",
description="Normalise inbound invoices",
objective="Prepare uploads for accounting review",
steps=steps,
),
current_step_index=0,
execution_context=ExecutionContext(input_files=["invoice.pdf"]),
)
assert request.agent_spec.steps[0].kind == "tool"
def test_edit_plan_response_has_typed_steps() -> None:
steps = [ToolOperationStep(tool=ToolEndpoint.ROTATE_PDF, parameters=RotatePdfParams(angle=Angle(90)))]
response = EditPlanResponse(
summary="Rotate the input PDF by 90 degrees.",
steps=steps,
)
assert response.steps[0].tool == ToolEndpoint.ROTATE_PDF
def test_pdf_question_answer_defaults_evidence_list() -> None:
response = PdfQuestionAnswerResponse(answer="The invoice total is 120.00")
assert response.evidence == []
def test_app_settings_accepts_model_configuration() -> None:
settings = AppSettings(
smart_model_name="claude-sonnet-4-5-20250929",
fast_model_name="claude-haiku-4-5-20251001",
smart_model_max_tokens=8192,
fast_model_max_tokens=2048,
posthog_enabled=False,
posthog_api_key="",
posthog_host="https://eu.i.posthog.com",
)
assert settings.smart_model_name
assert settings.fast_model_max_tokens == 2048