mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-14 10:34:06 +02:00
# Description of Changes Adds storage in the database for full document content alongside the RAG content (and changes the service to `DocumentService` instead of `RagService`). Then adds a generic capability that should be usable by any agent (currently just used by the Question Agent) which allows the agent to pull out the full contents of the doc, chunks it into various sections that will fit in the context window, and then processes them in parallel to create an intermediate result, and then processes the intermediate result into a final answer. It will re-chunk as many times as necessary to get the content small enough for the actual answer to be analysed (I've tested on PDFs ~3500 pages long, which is well above the context limit and requires maybe 3 rounds of compression to get an answer). The new full doc analysis stuff is heavier than the RAG lookup so both remain. The agents should use RAG for targeted info and the chunked reasoner for info that requires reading the full doc.
108 lines
3.2 KiB
Python
108 lines
3.2 KiB
Python
from stirling.config import AppSettings
|
|
from stirling.contracts import (
|
|
AgentExecutionRequest,
|
|
AgentSpec,
|
|
AgentSpecStep,
|
|
AiFile,
|
|
EditPlanResponse,
|
|
ExecutionContext,
|
|
ExtractedFileText,
|
|
ExtractedTextArtifact,
|
|
OrchestratorRequest,
|
|
PdfQuestionAnswerResponse,
|
|
PdfTextSelection,
|
|
ToolOperationStep,
|
|
)
|
|
from stirling.models import FileId
|
|
from stirling.models.tool_models import Angle, RotatePdfParams, ToolEndpoint
|
|
|
|
|
|
def test_orchestrator_request_accepts_user_message() -> None:
|
|
request = OrchestratorRequest(
|
|
user_message="Rotate the PDF",
|
|
files=[AiFile(id=FileId("test-id"), name="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:
|
|
from pathlib import Path
|
|
|
|
from stirling.config import RagBackend
|
|
|
|
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,
|
|
rag_backend=RagBackend.SQLITE,
|
|
rag_embedding_model="voyageai:voyage-4",
|
|
rag_store_path=Path(":memory:"),
|
|
rag_pgvector_dsn="",
|
|
rag_chunk_size=512,
|
|
rag_chunk_overlap=64,
|
|
rag_default_top_k=5,
|
|
rag_max_searches=5,
|
|
chunked_reasoner_chars_per_slice=16_000,
|
|
chunked_reasoner_concurrency=10,
|
|
chunked_reasoner_worker_timeout_seconds=60.0,
|
|
chunked_reasoner_notes_char_budget=250_000,
|
|
max_pages=200,
|
|
max_characters=200_000,
|
|
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
|