Make list_documents return structured output and give feedback about total count and pages

This commit is contained in:
Yiorgis Gozadinos 2026-01-27 17:00:39 +02:00
parent cca03dbe61
commit 626f5cdd0e
No known key found for this signature in database
7 changed files with 78 additions and 18 deletions

View file

@ -4,8 +4,9 @@
### Added
- **Chat Agent Document Awareness Tools**: Two new tools for browsing and understanding the knowledge base
- `list_documents` — Browse available documents with title, URI, and creation date; respects session document filter
- `list_documents` — Browse available documents with title, URI, and creation date; respects session document filter; paginated with total count
- `summarize_document` — Generate LLM-powered summaries of specific documents
- **Document Count API**: New `count_documents(filter)` method on `HaikuRAG` client for efficient document counting
- **Read-Only Initial Context**: Initial context is now locked after the first message, providing consistent session context
- Chat TUI: `--initial-context` CLI option sets background context for the session
- Context can be edited via command palette before the first message is sent

View file

@ -151,6 +151,15 @@ docs = await client.list_documents(
)
```
Count documents:
```python
# Count all documents
total = await client.count_documents()
# Count with filter
pdf_count = await client.count_documents(filter="uri LIKE '%.pdf'")
```
### Updating Documents
```python

View file

@ -8,6 +8,8 @@ from haiku.rag.agents.chat.state import (
AGUI_STATE_KEY,
ChatDeps,
ChatSessionState,
DocumentInfo,
DocumentListResponse,
QAResponse,
SearchDeps,
SessionContext,
@ -20,6 +22,8 @@ __all__ = [
"SearchAgent",
"ChatDeps",
"ChatSessionState",
"DocumentInfo",
"DocumentListResponse",
"QAResponse",
"SearchDeps",
"SessionContext",

View file

@ -14,6 +14,8 @@ from haiku.rag.agents.chat.state import (
MAX_QA_HISTORY,
ChatDeps,
ChatSessionState,
DocumentInfo,
DocumentListResponse,
QAResponse,
build_document_filter,
build_multi_document_filter,
@ -373,17 +375,18 @@ def create_chat_agent(config: AppConfig) -> Agent[ChatDeps, str]:
@agent.tool
async def list_documents(
ctx: RunContext[ChatDeps],
limit: int | None = None,
offset: int | None = None,
) -> str:
page: int = 1,
) -> DocumentListResponse:
"""List available documents in the knowledge base.
Use this when the user wants to browse or see what documents are available.
Args:
limit: Maximum number of documents to return
offset: Number of documents to skip (for pagination)
page: Page number (default: 1, 50 documents per page)
"""
page_size = 50
offset = (page - 1) * page_size
# Build session filter from document_filter
doc_filter = None
if ctx.deps.session_state and ctx.deps.session_state.document_filter:
@ -392,20 +395,24 @@ def create_chat_agent(config: AppConfig) -> Agent[ChatDeps, str]:
)
docs = await ctx.deps.client.list_documents(
limit=limit, offset=offset, filter=doc_filter
limit=page_size, offset=offset, filter=doc_filter
)
total = await ctx.deps.client.count_documents(filter=doc_filter)
total_pages = (total + page_size - 1) // page_size if total > 0 else 1
if not docs:
return "No documents found in the knowledge base."
lines = [f"Found {len(docs)} document(s):\n"]
for doc in docs:
title = doc.title or "Untitled"
uri = doc.uri or "N/A"
created = doc.created_at.strftime("%Y-%m-%d")
lines.append(f"- **{title}** (URI: {uri}, Created: {created})")
return "\n".join(lines)
return DocumentListResponse(
documents=[
DocumentInfo(
title=doc.title or "Untitled",
uri=doc.uri or "",
created=doc.created_at.strftime("%Y-%m-%d"),
)
for doc in docs
],
page=page,
total_pages=total_pages,
total_documents=total,
)
async def _find_document(client: HaikuRAG, query: str):
"""Find a document by exact URI, partial URI, or partial title match."""

View file

@ -42,6 +42,23 @@ class QAResponse(BaseModel):
)
class DocumentInfo(BaseModel):
"""Document info for list_documents response."""
title: str
uri: str
created: str
class DocumentListResponse(BaseModel):
"""Response from list_documents tool."""
documents: list[DocumentInfo]
page: int
total_pages: int
total_documents: int
class SessionContext(BaseModel):
"""Compressed summary of conversation history for research graph."""

View file

@ -854,6 +854,17 @@ class HaikuRAG:
limit=limit, offset=offset, filter=filter
)
async def count_documents(self, filter: str | None = None) -> int:
"""Count documents with optional filtering.
Args:
filter: Optional SQL WHERE clause to filter documents.
Returns:
Number of documents matching the criteria.
"""
return await self.document_repository.count(filter=filter)
async def search(
self,
query: str,

View file

@ -167,6 +167,17 @@ class DocumentRepository:
results = list(query.to_pydantic(DocumentRecord))
return [self._record_to_document(doc) for doc in results]
async def count(self, filter: str | None = None) -> int:
"""Count documents with optional filtering.
Args:
filter: Optional SQL WHERE clause to filter documents.
Returns:
Number of documents matching the criteria.
"""
return self.store.documents_table.count_rows(filter=filter)
async def get_by_uri(self, uri: str) -> Document | None:
"""Get a document by its URI."""
escaped_uri = _escape_sql_string(uri)