"""
handler.py — Message handlers for Premium Librarian.
These handlers process librarian requests through the organism's message bus.
"""
from __future__ import annotations
import logging
from xml.sax.saxutils import escape as xml_escape
from xml_pipeline.message_bus.message_state import HandlerMetadata, HandlerResponse
from xml_pipeline.librarian.primitives import (
LibrarianIngest,
LibrarianIngested,
LibrarianQuery,
LibrarianAnswer,
LibrarianList,
LibrarianLibraries,
LibrarianDelete,
LibrarianDeleted,
LibrarianGetChunk,
LibrarianChunk,
)
logger = logging.getLogger(__name__)
async def handle_librarian_ingest(
payload: LibrarianIngest,
metadata: HandlerMetadata,
) -> HandlerResponse:
"""
Handle a codebase ingestion request.
Clones the git repository, chunks all files, and stores in eXist-db.
"""
from xml_pipeline.librarian.ingest import ingest_git_repo
logger.info(f"Ingesting codebase from {payload.git_url}")
try:
result = await ingest_git_repo(
url=payload.git_url,
branch=payload.branch,
library_name=payload.library_name,
)
return HandlerResponse.respond(
payload=LibrarianIngested(
library_id=result.library_id,
library_name=result.library_name,
files_processed=result.files_processed,
chunks_created=result.chunks_created,
index_built=result.index_built,
errors="\n".join(result.errors) if result.errors else "",
)
)
except Exception as e:
logger.error(f"Ingest failed: {e}")
return HandlerResponse.respond(
payload=LibrarianIngested(
library_id="",
library_name=payload.library_name or "",
files_processed=0,
chunks_created=0,
index_built=False,
errors=str(e),
)
)
async def handle_librarian_query(
payload: LibrarianQuery,
metadata: HandlerMetadata,
) -> HandlerResponse:
"""
Handle a library query request.
Searches for relevant code chunks and synthesizes an answer using LLM.
"""
from xml_pipeline.librarian.query import query_library, format_sources_xml
logger.info(f"Querying library {payload.library_id}: {payload.question[:100]}...")
try:
result = await query_library(
library_id=payload.library_id,
question=payload.question,
max_chunks=payload.max_chunks,
model=payload.model,
)
sources_xml = format_sources_xml(result.sources) if result.sources else ""
return HandlerResponse.respond(
payload=LibrarianAnswer(
answer=result.answer,
sources=sources_xml,
tokens_used=result.tokens_used,
chunks_examined=result.chunks_examined,
error=result.error,
)
)
except Exception as e:
logger.error(f"Query failed: {e}")
return HandlerResponse.respond(
payload=LibrarianAnswer(
answer="",
sources="",
tokens_used=0,
chunks_examined=0,
error=str(e),
)
)
async def handle_librarian_list(
payload: LibrarianList,
metadata: HandlerMetadata,
) -> HandlerResponse:
"""
Handle a request to list all ingested libraries.
"""
from xml_pipeline.librarian.index import list_libraries
logger.info("Listing all libraries")
try:
libraries = await list_libraries()
# Format libraries as XML
lib_items = []
for lib in libraries:
lib_items.append(
f"""
{xml_escape(lib.library_id)}
{xml_escape(lib.name)}
{xml_escape(lib.source_url)}
{xml_escape(lib.created_at)}
{lib.total_files}
{lib.total_chunks}
"""
)
libraries_xml = "\n" + "\n".join(lib_items) + "\n"
return HandlerResponse.respond(
payload=LibrarianLibraries(
count=len(libraries),
libraries=libraries_xml,
)
)
except Exception as e:
logger.error(f"List failed: {e}")
return HandlerResponse.respond(
payload=LibrarianLibraries(
count=0,
libraries="",
)
)
async def handle_librarian_delete(
payload: LibrarianDelete,
metadata: HandlerMetadata,
) -> HandlerResponse:
"""
Handle a request to delete a library.
"""
from xml_pipeline.librarian.index import delete_library
logger.info(f"Deleting library {payload.library_id}")
try:
success = await delete_library(payload.library_id)
return HandlerResponse.respond(
payload=LibrarianDeleted(
library_id=payload.library_id,
success=success,
error="" if success else "Delete operation failed",
)
)
except Exception as e:
logger.error(f"Delete failed: {e}")
return HandlerResponse.respond(
payload=LibrarianDeleted(
library_id=payload.library_id,
success=False,
error=str(e),
)
)
async def handle_librarian_get_chunk(
payload: LibrarianGetChunk,
metadata: HandlerMetadata,
) -> HandlerResponse:
"""
Handle a request to retrieve a specific code chunk.
"""
from xml_pipeline.librarian.query import get_chunk_by_id
logger.info(f"Getting chunk {payload.chunk_id} from library {payload.library_id}")
try:
chunk = await get_chunk_by_id(payload.library_id, payload.chunk_id)
if chunk is None:
return HandlerResponse.respond(
payload=LibrarianChunk(
chunk_id=payload.chunk_id,
error=f"Chunk not found: {payload.chunk_id}",
)
)
return HandlerResponse.respond(
payload=LibrarianChunk(
chunk_id=chunk.chunk_id,
file_path=chunk.file_path,
name=chunk.name,
chunk_type=chunk.chunk_type,
language=chunk.language,
start_line=chunk.start_line,
end_line=chunk.end_line,
content=chunk.content,
docstring=chunk.docstring,
signature=chunk.signature,
error="",
)
)
except Exception as e:
logger.error(f"Get chunk failed: {e}")
return HandlerResponse.respond(
payload=LibrarianChunk(
chunk_id=payload.chunk_id,
error=str(e),
)
)