Exa App walkthrough
Exa is the smaller real integration. It demonstrates two public research Tools, exact credential-safe HTTP policy, Action-owned provider mapping, bounded local search history and a fixed View that never receives provider transport.
Product boundary
Data searches table: bounded local history consumed by the View
Actions search + fetch
View recent search status/results history
Public Tools
research.search
research.fetchManifest and native policy
Exa declares data.sqlite and net.http. Its HTTP policy permits POST to exactly https://api.exa.ai/search and /contents, allows only accept and content-type request headers, and binds native credential id exa.api-key tox-api-key.
The manifest's Tool schemas describe search mode, categories, domain/date filters, result bounds and content freshness. The Agent receives those product-facing choices; it never receives the credential or a generic HTTP Tool.
Search Action
- Validate and normalize the query/options.
- POST a bounded JSON request with the remaining Action deadline.
- Return the full live Exa response to the Agent.
- Persist only query, time, status, result count, top title or error for the fixed history View.
- Delete history older than seven days inside the same transaction.
This is an important App rule: SQLite is the fixed View/product projection, not a generic cache of every provider payload. Fetched document text is returned to the Agent but is not duplicated into local history because the current View does not consume it.
Failure is also useful product state
If the provider call fails, the Action commits a bounded error history row and then rethrows. The Agent receives an error Tool result while the fixed View can explain that the latest search failed. The App does not turn failure into an empty success.
View and pagination
The View initially projects eleven rows to show ten and detect hasMore. It increases a bounded limit in pages up to 50 total history rows, renders six at a time and uses a ScrollRail rather than materializing an unbounded list. A manual binding.refresh() supports pagination; App revisions handle new search commits.
Simulator behavior
The simulator's native App service returns deterministic Exa-shaped fixtures. The exactactions.js, SQLite transaction and view.js run unchanged, but no real Exa credential or network result is proven there.
What to copy into a new App
- exact endpoint/header policy rather than a broad network proxy;
- one Action that returns live provider value and persists only View-owned product state;
- explicit request body and response-size bounds;
- retention cleanup in the same durable transaction;
- bounded Projection pagination and visible-row rendering.
Read the source: app.json ↗, schema.sql ↗, actions.js ↗, view.js ↗.