Commit graph

57 commits

Author SHA1 Message Date
Yiorgis Gozadinos
afdef92b5b
Finish the comment pass, and escape document fields everywhere Rich renders
`_rich_print_document` escapes uri, title and metadata, the sibling of
the escaped search-result renderer. The remaining comments and
docstrings that narrated rejected alternatives, consequences or history
now state the current invariant. The Sandbox class docstring names the
held connection close() releases, and wrapped docs paragraphs join to
one line.
2026-08-28 15:34:47 +03:00
Yiorgis Gozadinos
590719fca7
Read a document, chunk or picture from the database that names it
`resolve_document` and `find_document` selected a document through a listing,
then dropped its source and looked the id up across the set. Ids repeat between
copies of a database, so a title that matched in one could be answered by
another's document.

`get_document_by_id` and `get_chunk_by_id` join `get_picture_bytes` in taking an
optional `source`, and all three route it through `clients_covering`, so a name
the client does not cover raises `UnknownDatabaseError` rather than being
answered by the database it does cover. Without a source the reads are as they
were, answering from the first database in configured order that holds the id.
2026-08-28 13:30:05 +03:00
Yiorgis Gozadinos
fa319596cc
Name the collection on a retrieved image, not only in the text
Search results and capsule entries name the collection they came from; the
images attached beside them carried only the chunk id and reference. Two
collections can return the same picture of the same document, so the two
labels were identical and the model could place neither.

The decision is the one already made for the text: `covers_multiple` at the
generic search tool, and the flag `search_corpus` computed for the capability
tools, which it now returns.
2026-08-28 12:02:16 +03:00
Yiorgis Gozadinos
225a37ca73
Tell one collection's pictures from another's
Three places identified a picture by document and reference alone, and one
identified a citation's images by chunk id alone. Both repeat between copies of
a database, so a search returning a figure from two collections sent one, a
capsule retained one, and a citation rendered the other collection's figures.

Keyed on the source as well: `(source, document_id, self_ref)` for search
pictures, the capability and source for retained ones, and `qualified_id` for
the chat's citation images.
2026-08-28 10:35:46 +03:00
Yiorgis Gozadinos
0d7810c78a
Render collection identity only for multi-collection searches
`format_for_agent` named the database whenever one was named, so a search over
a single named database carried a line with nothing to distinguish. It now takes
`include_collection` from the caller, which decides from the search selection
rather than from the hits: a search that could have drawn on two collections
names them even when everything came back from one.

`Collection:` at the model boundary, database in configuration and
administration. `source` on results, documents, citations and analysis
dictionaries is unchanged.
2026-08-27 12:41:05 +03:00
Yiorgis Gozadinos
2000098e16
Say which commands cover a set, and what a shared id does
Three groups, not two: `search`, `ask`, `analyze` and `chat` cover the set,
`settings`, `init-config` and `download-models` open no database, and every
other command works on one — or on a configured set of one, which is
unambiguous and keeps its name. A database named in `lancedb.databases` keeps
that name whether or not it is the only one covered; only `lancedb.uri` places
one without naming it.

Document ids repeat between copies of a database, where the sandbox refuses a
duplicate but the chat filter's `id IN (...)` matches the document in every
copy. `build_document_id_filter` claimed ids never widen a selection.

Document the facade: `covers_multiple`, `source_names`, `source`,
`reader_for`, `clients_for`, the lifetime of a borrowed client, and
`sources=None` against `sources=[]`.

Drop the vision callout from the README, which the features list already
covers.
2026-08-26 13:03:58 +03:00
Yiorgis Gozadinos
307e250f29
Select documents to filter by id, not by displayed name
A title repeats within a corpus and across databases, so a substring
match on the displayed name widened the filter to documents the user did
not pick. The label names the database.
2026-08-24 15:27:59 +03:00
Yiorgis Gozadinos
2cd568847e
Move the wire rewrite into the compaction capability
`_compact_old_tool_returns`, `PRIOR_TURN_NOTICE` and `turn_start` leave
`RAGCapabilityBase`, along with its `wrap_model_request` hook. The evidence
capabilities now retrieve and validate, and nothing else. Registering the compaction
capability is what rewrites a request; leaving it out sends the transcript untouched,
which was never a choice a host could make before.

The boundary is the recorded question identity rather than message shape, so a
resumption compacts what lies below the question in progress instead of switching
compaction off for the whole run. The newest earlier evidence return carries the
capsule and every other becomes a receipt, so one capsule exists by construction and
every return stays paired with its call.

Pictures of cited evidence are fetched through the capability that retrieved them and
re-attached beside the capsule with fresh labels. Ownership of a picture on the wire
requires the machine tag we write and an image directly after it, since neither
position nor prose is proof: several tools' results can arrive in one request, and a
user quoting our wording above their own picture had it removed. A picture that cannot
be fetched or decoded is emitted with neither its image nor its label.

The chat TUI and the example backend register the compactor, being multi-turn.
`client.ask`, `client.analyze` and the MCP tools do not: a single-shot question has
nothing earlier to compact.
2026-08-13 13:00:02 +03:00
Yiorgis Gozadinos
46f7ab8d97
Name the search result each page image belongs to
ToolReturn.content reaches the model as a user-role message and the pictures
arrive bare, so nothing connects a figure to the chunk it came from:
BinaryContent.identifier does not survive serialization to the vision API, and
the captions in the result text correlate only by position.

Precede each picture with its position, source chunk id and self_ref.
build_binary_parts_from_results becomes build_image_content_from_results and
returns the labels interleaved with the pictures, so both attachment sites emit
them the same way.

This does not stop a model narrating retrieved pictures as user-supplied.
Measured on gemma4-26b with a single note ahead of the batch, and again with
per-image labels: it quotes the label and still says the user provided them.
The message role wins over its text.
2026-08-13 13:00:01 +03:00
Yiorgis Gozadinos
f13a3fb677
Report tool failures with ToolFailed 2026-07-27 18:26:42 +03:00
Yiorgis Gozadinos
a6e5664c78
Verify picture bytes before attaching to multimodal tool returns 2026-05-13 16:01:39 +03:00
Yiorgis Gozadinos
c96894a0f0
fix cross-document picture dedup in agent and skill search tools 2026-05-05 15:56:10 +03:00
Yiorgis Gozadinos
ee41bc676f
remove defensive code 2026-05-04 15:12:27 +03:00
Yiorgis Gozadinos
21f12cd770
add vision: bool flag on ModelConfig (default False). Gate the agent search tool's BinaryContent attachment on qa.model.vision so picture bytes are only sent to vision-capable QA models. 2026-05-04 10:47:21 +03:00
Yiorgis Gozadinos
b01c649684
surface picture image bytes in SearchResult and emit multimodal ToolReturn from the agent search tool 2026-04-30 12:43:05 +03:00
Yiorgis Gozadinos
eb4e1721ce
remove dead code, add tool descriptions in frontend, update changelog 2026-04-20 15:38:17 +03:00
Yiorgis Gozadinos
aa4ce07dc9
remove filter parameter from analyze skill tool and clean up unused filter helpers 2026-04-17 18:35:16 +03:00
Yiorgis Gozadinos
499a843a43
remove unused create_analysis_toolset and AnalysisResult 2026-04-17 18:32:01 +03:00
Yiorgis Gozadinos
bf8eec68e3
Use dict-keyed counter for concurrent-safe search cap 2026-03-11 12:19:19 +02:00
Yiorgis Gozadinos
e2749ad2a6
Cap QA agent search iterations to reduce response time 2026-03-11 12:13:43 +02:00
Yiorgis Gozadinos
70273ecf5b
Remove filter from the search tool 2026-03-02 17:15:38 +02:00
Yiorgis Gozadinos
d3c6322481
Simplify sandbox with run_monty_async, replace manual ThreadPoolExecutor start/resume loop 2026-02-24 11:35:39 +02:00
Yiorgis Gozadinos
c61ded1271
Replace Docker sandbox with pydantic-monty 2026-02-24 09:55:40 +02:00
Yiorgis Gozadinos
492f5cf1e4
Avoid mutable defaults 2026-02-20 17:59:35 +02:00
Yiorgis Gozadinos
ed89ff0fc9
Simplify tools/ — remove AG-UI state machinery, keep core toolsets 2026-02-20 16:36:48 +02:00
Yiorgis Gozadinos
524647c501
Add unified RAG skill with session context and reuse existing tools; 2026-02-20 16:36:47 +02:00
Yiorgis Gozadinos
a870052ee9
Fix coverage 2026-02-17 13:22:23 +02:00
Yiorgis Gozadinos
f4735667df
emit StateDeltaEvent with client-aware baseline 2026-02-17 12:24:09 +02:00
Yiorgis Gozadinos
8c76897af2
Update tui and app to use the toolkit 2026-02-16 12:54:44 +02:00
Yiorgis Gozadinos
7ff2123806
Introduce toolkit to reduce toolset creation ceremony 2026-02-16 11:51:02 +02:00
Yiorgis Gozadinos
969c64d106
Add citations_history to SessionState for unified citation rendering between search and ask 2026-02-13 16:21:50 +02:00
Yiorgis Gozadinos
c0ed93da2d
Expand tests 2026-02-13 14:34:24 +02:00
Yiorgis Gozadinos
f5c562db9b
Fix double summarization, cleanup 2026-02-13 12:16:23 +02:00
Yiorgis Gozadinos
d9acdfba9d
prompt builder 2026-02-13 11:21:09 +02:00
Yiorgis Gozadinos
5f6d9e9812
handle state_key duplication between deps and ToolContext 2026-02-13 10:23:12 +02:00
Yiorgis Gozadinos
a5b8e3be7e
Add AgentDeps and prepare_context for custom agent DX 2026-02-12 17:37:37 +02:00
Yiorgis Gozadinos
8f180f707b
Decouple QA toolset from chat agent, add ToolContext state methods 2026-02-12 17:27:47 +02:00
Yiorgis Gozadinos
0c6d73409d
Move SessionContext from agents/chat/state.py to tools/session.py, change QASessionState.session_context to use it 2026-02-12 17:13:01 +02:00
Yiorgis Gozadinos
05ebd781d4
Move client and tool_context from toolset factories to RunContext.deps 2026-02-12 15:50:46 +02:00
Yiorgis Gozadinos
51f1d9cf13
Issue a full state snapshot from ask() tool to preserve server side background context 2026-02-11 17:49:09 +02:00
Yiorgis Gozadinos
58c2bd49ea
Clean up server vs client session setting priorities 2026-02-11 16:54:00 +02:00
Yiorgis Gozadinos
9e63ff1ff7
Remove session_id from state layer, remove module-level caches 2026-02-11 14:55:53 +02:00
Yiorgis Gozadinos
d88f2f003a
Remove incoming_* fields, simplify delta computation 2026-02-11 14:31:37 +02:00
Yiorgis Gozadinos
d67df09cce
Introduce ToolContextCache 2026-02-11 14:18:26 +02:00
Yiorgis Gozadinos
c916356a42
Clean up toolset exports, simplify update_session_context(), fix health check 2026-02-11 12:46:50 +02:00
Yiorgis Gozadinos
87bcb7a5dc
Extract run_qa_core() from ask closure in QA toolset. Remove redundant tests and cassettes for OpenAI and Anthropic QA tools, as they are now tested in the core function tests. 2026-02-11 11:38:34 +02:00
Yiorgis Gozadinos
f85aaefed7
Extract shared snapshot helpers 2026-02-10 17:34:30 +02:00
Yiorgis Gozadinos
a592a04031
Removed unused accumulator states 2026-02-10 16:15:30 +02:00
Yiorgis Gozadinos
da47e3e345
Unify get_typed() into get() with optional type parameter
Fix find_document regression
2026-02-10 14:38:14 +02:00
Yiorgis Gozadinos
dd7162e72e
Fix get_or_create type annotation, export compute_combined_state_delta 2026-02-10 14:38:13 +02:00