Repository navigation
feat: add Responses file_search protocol and execution - #486
Conversation
## Summary Add typed file, vector-store, and search contracts; pluggable `FileSearchRepository` and `FileBlobStore` interfaces; portable SQL metadata and bounded exact retrieval; and local blob storage. Store listing batches current attachment counts and usage. Durable, token-fenced cleanup intents cover uploads and deletions; expired leases cannot let a publisher expose missing content. Recovery retains abandoned-upload tombstones for later sweeps when a delayed write finishes after an initial cleanup pass. Local staging is addressable by file ID, and cancellation drains publication before cleanup. This is the independently compilable foundation of the file-search stack; HTTP routes and periodic cleanup are in #485. CI uses the macOS 15 Apple Silicon runner because GitHub is retiring macOS 14 and its scheduled brownout canceled wheel validation. Review order: #483 → #484 → #485 → #486 → #34. PostgreSQL vector indexing remains in follow-up #278. ## Test Plan - `cargo test --offline -p agentic-server-core --test file_search_service`: 31 passed, 1 PostgreSQL test ignored locally. Includes two-service upload/recovery interleavings, restart recovery after metadata rejection plus failed blob removal, delayed-staging cancellation, and a late-write/failed-rollback regression. - `cargo test --offline -p agentic-server-core --lib storage::local_files::tests`: 5 passed, including absent-directory and deterministic staging cleanup. - `cargo test --offline -p agentic-server-core --lib storage::schema::tests`: 6 passed, 4 PostgreSQL tests ignored locally; PostgreSQL CI exercises the final schema. - `cargo clippy --offline --all-targets -- -D warnings`, `cargo fmt -- --check`, and repository pre-commit hooks: passed. - The official OpenAI Python SDK HTTP integration test is in #485 and passed locally against the rebuilt final stack. --------- Signed-off-by: Francisco Javier Arceo <4163062+franciscojavierarceo@users.noreply.github.com>
21d7916 to
25ebb03
Compare
5e2b78b to
2e628a1
Compare
7d19fb3 to
8def410
Compare
e7c0c83 to
1984b9f
Compare
8def410 to
3cc360b
Compare
1984b9f to
0e2e73e
Compare
f95dbe1 to
7af4b65
Compare
0e2e73e to
8183d07
Compare
7af4b65 to
9fc840a
Compare
8183d07 to
9e919b4
Compare
9fc840a to
b644c3f
Compare
9e919b4 to
1420da9
Compare
b644c3f to
8e09904
Compare
1420da9 to
f0478c3
Compare
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
4 open issues
ActiveItem::is_donetreatsfile_search_callas terminal only forCompleted | Failed. If… · NewAllowedToolis a public struct that can be constructed in an invalid state (e.g., `type_ ==… · Newvector_store_idsis anOptionbut currently lacksskip_serializing_if = \"Option::is_none\",… · New OpenAPI components now registerFileSearchCallResult(in addition toFileSearchCalland… · New
What changed in this PR
Adds typed file_search request/response and citation models, wires them through strict event/stream lifecycle handling, and exposes the new shapes in OpenAPI.
Changes:
- Introduces typed
file_searchtool params plus typed output items (file_search_call) andfile_citationannotations. - Extends streaming/event validation, accumulator lifecycle, and response budgeting to preserve and account for file-search items.
- Updates OpenAPI schemas and tests to validate the new public wire shapes.
| File | Description |
|---|---|
| crates/agentic-server/src/openapi.rs | Registers file-search schemas and updates OpenAPI validation tests. |
| crates/agentic-server-core/tests/support/mod.rs | Updates test helpers to handle FileSearchCall output items. |
| crates/agentic-server-core/tests/relayed_stream_validation_test.rs | Adds regression test ensuring file citations survive JSON + SSE relay decoding. |
| crates/agentic-server-core/src/types/tools/params/file_search.rs | New typed file-search tool parameter struct + OpenAPI schema helper. |
| crates/agentic-server-core/src/types/tools/params.rs | Moves FileSearchToolParam into its own module; adds strict schema handling and tests. |
| crates/agentic-server-core/src/types/io/tools.rs | Adds file_search tool choice/selector normalization + OpenAPI schema updates. |
| crates/agentic-server-core/src/types/io/output/history.rs | Extracts history-related logic for output items; includes file-search handling. |
| crates/agentic-server-core/src/types/io/output/file_search.rs | New public types for file_search_call results + file_citation annotation. |
| crates/agentic-server-core/src/types/io/output.rs | Adds file_search_call output item variant + schema and lifecycle integrations. |
| crates/agentic-server-core/src/types/io/mod.rs | Re-exports new file-search output/citation types. |
| crates/agentic-server-core/src/types/io/item/item_id.rs | Adds id/prefix handling for FileSearchCall. |
| crates/agentic-server-core/src/types/io/input/file_text.rs | Tweaks error message to clarify Responses input limitations. |
| crates/agentic-server-core/src/executor/translate/context.rs | Ensures async-call marking logic includes file-search output items. |
| crates/agentic-server-core/src/executor/response_budget/file_search.rs | Adds retained-size accounting for file-search output items/results. |
| crates/agentic-server-core/src/executor/response_budget.rs | Wires file-search retained-size accounting into overall budgeting. |
| crates/agentic-server-core/src/executor/item_lifecycle.rs | Includes FileSearchCall in lifecycle classification. |
| crates/agentic-server-core/src/executor/gateway/lifecycle.rs | Emits synthetic file-search start/completion events for gateway streaming. |
| crates/agentic-server-core/src/executor/gateway/admission.rs | Adds refusal behavior for file-search output items. |
| crates/agentic-server-core/src/executor/accumulator/tests.rs | Adds strict/lenient lifecycle tests for file-search streaming. |
| crates/agentic-server-core/src/executor/accumulator/slot.rs | Includes FileSearchCall in slot-map handling. |
| crates/agentic-server-core/src/executor/accumulator/active/size.rs | Extracts retained-size logic for active streaming items; includes file-search. |
| crates/agentic-server-core/src/executor/accumulator/active.rs | Adds FileSearchCall as an active streaming item variant. |
| crates/agentic-server-core/src/events/validate.rs | Validates file-search event types map to the correct item type. |
| crates/agentic-server-core/src/events/types/item.rs | Adds file_search_call SSE item type. |
| crates/agentic-server-core/src/events/types.rs | Adds response.file_search_call.in_progress event type + mappings and tests. |
| crates/agentic-server-core/src/events/normalize.rs | Ensures file-search events route to the right payload normalization. |
| crates/agentic-llm-d/tests/split_execution_integration.rs | Adjusts integration test stream to use a future/unknown tool call item type. |
Review effort: Lite
b4485be to
5179091
Compare
## Summary Add a `FileSearchRepository` backed by sqlite-vec for semantic cosine retrieval on a file-backed SQLite database. It keeps portable SQL metadata and published-chunk visibility, normalizes embeddings before indexing, and records a provider identity so stores cannot silently switch indexes. Keyword and hybrid search continue through the bounded exact ranker. SQLite metadata and vector rows now publish in one transaction, so concurrent replicas cannot remove a winning attachment. Orphan cleanup rechecks rows under a writer lock and immediately reclaims stale rows and per-store tables; search skips empty stores and unpublished rows, and uses bounded exact ranking when sqlite-vec's 4,096-candidate limit is exceeded. The loadable extension path is deployment-controlled; #485 wires its configuration. BEIR-sized corpus testing exposed the old 64 MiB serialized-corpus limit and top-k edge cases with duplicate chunks and near ties. This branch keeps the default exact-search limit at 64 MiB and gives sqlite-vec a 256 MiB limit, validates vector-index coverage, and adaptively fetches candidates to preserve the requested document count. Review order: #483 → #484 → #485 → #486 → #34. PostgreSQL vector indexing remains in #278. ## Test Plan - Review follow-up: the portable vector map is migration-owned; extension-specific index SQL lives in `storage/file_search/sqlite_vec_index.rs`, publication has one implementation, and writes use `BEGIN IMMEDIATE` without a process-wide mutex. Focused storage and schema tests passed; the original 3 sqlite-vec integration tests passed, including immediate orphan-row and orphan-table recovery. - `SQLITE_VEC_EXTENSION_PATH=/tmp/vec0.so cargo test -p agentic-server-core --test sqlite_vec_repository -- --ignored`: 4 passed in CI with sqlite-vec 0.1.9, covering publication, extreme finite embeddings, restart, filtered and duplicate-chunk search, deletion, concurrent attachment conflicts, unpublished rows, empty stores, and searches beyond the 4,096-candidate limit. - `cargo test -p agentic-server-core --lib`: 1,370 passed, 6 ignored. `cargo clippy -p agentic-server-core --all-targets -- -D warnings`, `cargo fmt -- --check`, and pre-commit hooks passed. - Maral's capacity regression: a new sqlite-vec integration test publishes a serialized store above 64 MiB, then exercises keyword, hybrid, and filtered semantic searches against it. The Rust CI run passed this test and the full ignored sqlite-vec integration suite. - CI downloads the pinned Linux sqlite-vec release asset, verifies its SHA-256, and runs the ignored integration tests. ### BEIR retrieval evidence (2026-11-03, benchmark commit `fd6b574`) Compared the provider's semantic search with [OGX's published vector-mode results](https://ogx-ai.github.io/docs/building_applications/rag_benchmarks). Used the official BEIR **test** corpora, queries, and relevance judgments, title + body text, `cl100k_base` 512-token chunks with 128-token overlap, `nomic-ai/nomic-embed-text-v1.5` embeddings, and top-10 document scoring with `pytrec_eval`. The 512/128 setting comes from [OGX's documented benchmark config](https://ogx-ai.github.io/docs/building_applications/rag_benchmarks), but this was a local preparation, not [OGX's full API ingestion path](https://github.com/ogx-ai/ogx/tree/12a51077cdd4f89b16df5eb6de12a88b0bfcf7df/benchmarking/rag). A local harness loaded the prepared chunks into the actual `SqliteVecRepository` and called its `search` method for every judged query. sqlite-vec 0.1.9 ran on CPU. | Dataset | Documents / chunks / queries | nDCG@10 OGX vector → ours | Recall@10 OGX vector → ours | MAP@10 OGX vector → ours | | --- | ---: | ---: | ---: | ---: | | NFCorpus | 3,633 / 4,921 / 323 | 0.3106 → **0.3101** | 0.1482 → 0.1462 | 0.1153 → 0.1137 | | SciFact | 5,183 / 6,604 / 300 | 0.6943 → **0.6968** | 0.8369 → 0.8296 | 0.6442 → 0.6496 | | ArguAna | 8,674 / 9,278 / 1,406 | 0.3765 → **0.3928** | 0.7610 → 0.8037 | 0.2542 → 0.2624 | All 2,029 searches succeeded. An independent exhaustive NumPy cosine calculation on the same embeddings gave identical aggregate nDCG@10 for SciFact and ArguAna; NFCorpus differed by 0.000084. This validates sqlite-vec against an exact-cosine oracle on our prepared vectors. The proximity to OGX's published vector scores is indicative, not exact parity: OGX's current batch ingestion path applies whitespace cleaning and appears to use 800/400-token file-processor defaults for automatic chunking, despite the benchmark config documenting 512/128. The published run does not include materialized chunk/embedding or per-query result fixtures, so its exact input and rankings cannot yet be compared. **Scope and limit:** This is a repository-level semantic retrieval test with prepared embeddings; it does not exercise the Files/Vector Stores HTTP APIs, automatic ingestion, hybrid reranking, Responses `file_search`, or end-to-end answer generation. OGX's fourth BEIR dataset, FiQA, produces 63,129 chunks and exceeds this branch's 10,000-chunk corpus bound, so full four-dataset parity remains unvalidated. --------- Signed-off-by: Francisco Javier Arceo <4163062+franciscojavierarceo@users.noreply.github.com>
98a0d45 to
7a4ecee
Compare
fa49123 to
a222dd5
Compare
01c5d4f to
f687cce
Compare
4ef8354 to
09843d7
Compare
d41177b to
bba92ca
Compare
09843d7 to
04a5a1e
Compare
## Summary Expose the Files and vector-store upload, lifecycle, attachment, and search routes over the pluggable core service. Add server configuration for local file bytes, embeddings, and an optional trusted sqlite-vec extension path. Wire the routes into authentication and OpenAPI, with deployment documentation. Reconcile abandoned blob cleanup intents at startup and periodically while the gateway runs. Local routes enforce the configured API key and request-body ceiling; deletion tolerates a cleanup marker already removed by reconciliation, and startup logs provider setup diagnostics. This layer does not register the Responses `file_search` built-in tool. Review order: #485 → #486 → #34. #483 and #484 are merged. PostgreSQL vector indexing remains in #278. ## Test Plan - `cargo test -p agentic-server --test file_search_http_test`: 6 passed, including missing, incorrect, and valid API-key cases and configured multipart/JSON body limits. - `cargo test -p agentic-server-core --test file_search_service`: 32 passed, 1 ignored, including the deletion cleanup-marker race regression. - Full workspace `cargo test --offline` passed on the restacked #34 head containing these fixes. - `cargo test -p agentic-server --lib openapi`: 19 passed. - `cargo test -p agentic-server --bin agentic-server config_file::tests`: 37 passed. - `cargo build --offline -p agentic-server --bin agentic-server` and `cargo clippy --offline -p agentic-server -p agentic-server-core --all-targets -- -D warnings`: passed. - `openai==3.8.0` client E2E: upload, list/retrieve/content, vector-store attachment, filtered search, detach, and deletion passed against the rebuilt local gateway. The Rust CI job runs this script. - Formatting and repository pre-commit hooks passed on signed-off commits. CI also runs PostgreSQL file-search persistence, sqlite-vec, and bounded PDF ingestion checks. - OpenAI reference cassette parity for Files and vector-store routes remains unverified: this environment has no OpenAI API credential. The focused local gateway HTTP suite and OpenAI SDK client E2E cover the route lifecycle; no reference cassette was hand-authored. Signed-off-by: Francisco Javier Arceo <4163062+franciscojavierarceo@users.noreply.github.com>
Signed-off-by: Francisco Javier Arceo <4163062+franciscojavierarceo@users.noreply.github.com>
Signed-off-by: Francisco Javier Arceo <4163062+franciscojavierarceo@users.noreply.github.com>
Signed-off-by: Francisco Javier Arceo <4163062+franciscojavierarceo@users.noreply.github.com>
b1825cc to
8957cc3
Compare
Signed-off-by: Francisco Javier Arceo <4163062+franciscojavierarceo@users.noreply.github.com>
8957cc3 to
3d90f65
Compare
|
@copilot review |
Review findings: [P2] [P2] [P2] Coverage: reviewed the full PR diff against |
## Summary Register and execute the Responses `file_search` built-in tool through the existing typed gateway tool loop. The handler searches the configured file-search service, keeps retrieved passages private for model continuation, exposes `file_search_call.results` only when requested, and restores typed file citations in completed and streamed output. This is the top layer of a smaller stack; the Files and vector-store APIs, provider contracts, SQLite-vec adapter, and protocol types are reviewed below it. Review order: #483 (storage contracts and portable SQL/local providers) → #484 (SQLite-vec) → #485 (Files and vector-store HTTP APIs and provider configuration) → #486 (Responses protocol and stream lifecycle) → this PR. The existing PostgreSQL/pgvector follow-up is #278; later retrieval and lifecycle work remains stacked above it. The storage service accepts injected `FileSearchRepository` and `FileBlobStore` implementations. The lower layers configure SQLite-vec for semantic retrieval; Milvus and remote blob stores remain adapter extension points. ## Test Plan - `cargo test -p agentic-server-core --test file_search_tool_test`: 6 passed, covering blocking and streaming calls, citations, opt-in results, mixed client tools, failures, and selector validation. - `cargo test -p agentic-server-core --lib`: 1,385 passed, 6 ignored on the corrected, restacked file tree. Full workspace `cargo test --offline` also passed on that tree. - Changed-crate all-target Clippy with warnings denied, formatting, and all-file pre-commit hooks passed on the corrected, restacked file tree. - The failing Rust CI check at `33b20ba` came from an output-item test fixture missing the typed `logprobs: []` field. The corrected citation projection test passes locally; CI is running on the cleanly restacked head. - SQLite-vec review fixes from #484 are carried through the stack: atomic publication, safe orphan cleanup, empty/unpublished row handling, and exact fallback above sqlite-vec's candidate limit. Signed-off-by: Francisco Javier Arceo <arceofrancisco@gmail.com>
Signed-off-by: Francisco Javier Arceo <4163062+franciscojavierarceo@users.noreply.github.com>
|
fixed the first two findings in the recorder-generated file-search cassette is still outstanding. this environment has no live provider credential, and the cassette workflow requires recording a real response rather than writing YAML by hand. the existing gateway execution integration tests use a mocked upstream and cover blocking/streaming search, citations, opt-in results, and continuation; i’m not treating those as a recorded OpenAI wire capture. |



Summary
Add typed Responses
file_searchdeclarations, output items, optional result fields, and file citation annotations, with strict event and streaming lifecycle validation. Register the built-in tool in the gateway tool loop so it searches the configured file-search service, keeps retrieved passages private for model continuation, exposesfile_search_call.resultsonly when requested, and preserves citations in completed and streamed responses. Persist the model-facing search call and result forprevious_response_idcontinuation.This PR includes the execution layer merged from #34. #483 (pluggable storage), #484 (sqlite-vec), and #485 (Files/vector-store HTTP APIs) are merged. PostgreSQL/pgvector indexing remains in draft #278.
Test Plan
45c729f: Rust Clippy and tests, the OpenAI Python client file API integration test, SQLite vector provider test, CLI end-to-end test, Python, pre-commit, DCO, PostgreSQL, Kubernetes, embedded interpreter, container smoke test, and Linux/macOS wheel builds.file_search_call.resultsdeserialization regression, typed citation JSON/SSE relay regression, and generated OpenAPI schema assertions.