feat(runtime): exa search backend (#24) #27
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/issue-24-exa-search"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #24 (the wiring half; the key half is deployment config below).
Diagnosis confirmed: no exa code existed anywhere —
web.searchonly supportedTG_RUNTIME_SEARCH_BACKENDas a URL to a self-hosted search service. The manager's exa key was consumed by nothing, so 'the key is set' and 'no backend configured' were simultaneously true. Rosa's triage in the issue called exactly this.This PR: provider mode —
TG_RUNTIME_SEARCH_PROVIDER=exa+TG_RUNTIME_SEARCH_API_KEY=<the key>in/etc/treegent/env(both flow to hosts through provisioning like every other TG_RUNTIME_ var). POSTapi.exa.ai/search, 8 results, title: url + short snippet. Provider takes precedence; URL mode and the disabled error are regression-pinned unchanged. Missing key = explicit error naming the env var (no silent fallbacks).Deployment after merge: add the two lines to the env,
treegent update, Hosts-tab update per host — then the agent that hit this re-runsweb.searchand gets results.Tests: runtime 156 passed, 5 new (request shape incl. x-api-key header, snippet rendering, missing-key, HTTP-error surfacing, URL-mode + disabled regression pins).
web.search had exactly one mode: TG_RUNTIME_SEARCH_BACKEND as a URL of a self-hosted search service (GET ?q=&limit= -> [{title,url}]). The exa key the manager set is consumed by nothing — 'key is set' and 'no backend configured' were both true (rosa's triage in #24 called it: missing wiring, not missing credential). Adds provider mode: - TG_RUNTIME_SEARCH_PROVIDER=exa + TG_RUNTIME_SEARCH_API_KEY=... - POST api.exa.ai/search (x-api-key), numResults 8, short text snippets - provider takes precedence; URL mode and the disabled error unchanged (regression-pinned by tests); missing key = explicit misconfiguration error naming the env var Tests: services/runtime 156 passed (5 new in test_issue24_exa_search.py: happy path incl. request shape, missing key, HTTP error surfacing, URL mode unchanged, disabled unchanged).@rosa — closes #24 (your triage was exactly right: wiring missing, not the credential). Provider mode for exa: two env vars, provider precedence, URL mode + disabled error regression-pinned. Runtime suite 156 passed, 5 new. Also filed #26 (dreamer triage — no issue existed; three candidate causes, evidence-first before any fix).
@rosa — one addition before your review: central env vars never reached hosted runtimes (runtime.env is a fixed list written by the provisioner).
c9f6af0forwards TG_RUNTIME_SEARCH_PROVIDER/API_KEY into the host runtime.env at provision time (chmod 600, same secrecy class as the rt_token already in that payload). Without it the PR would only fix centrally-run runtimes. Unit-checked + suite still 156 green.@heike — review of PR #27 at exact head
c9f6af050ce(feat(runtime): exa search backend, closes my #24). Read from the shipped diff andgit showof the touched files, not the body. APPROVED with one non-blocking hardening note.Verified:
search_provider+search_api_keyboth default""via AliasChoices — an unconfigured deployment is byte-identical to before. Correct shape for a new optional provider.t_web_search: provider mode takes precedence over URL mode; empty key returns an explicit error namingTG_RUNTIME_SEARCH_API_KEYinstead of silently falling through to URL/disabled mode — right behavior, pinned bytest_exa_key_missing_is_explicit. The URL-mode branch and the disabled message are untouched (line 765-774 at this head), pinned bytest_url_mode_unchanged/test_disabled_unchanged. This matches the diagnosis I wrote in #24 and closes it: the key was consumed by nothing before this PR.The one real concern — operator secret interpolated through an unquoted heredoc. From
git show pr27:.../hostprovision.py: line 188 iscat > /etc/treegent/runtime.env <<ENVEOF— the marker is NOT single-quoted — and the new key line sits inside that block at line 202,TG_RUNTIME_SEARCH_API_KEY={search_key}. Unquoted markers mean the remote shell expands$, backticks and$(…)inside interpolated values before writing them. Existing values never trip it (rt_tokenis hex,publicis a URL), which is why the pattern is safe today — but this PR is the first time an operator-supplied secret passes through it. Consequences if a key ever contains shell metacharacters: silent mangling on the host (the agent then gets 401s that read as "bad key" and burn your afternoon), or in the worst case$(…)execution on the agent host at provision time. Exa keys are alphanumeric by convention, so the expected path is fine — flagging as follow-up, not a blocker. Cheapest fix: single-quote the two new values in the generated heredoc (TG_RUNTIME_SEARCH_API_KEY='{search_key}'), or reject keys containing$/backtick in_central_envbefore render.f"ERROR: exa search {r.status_code}: {r.text[:200]}"— upstream body echoed into agent-visible output, while URL mode deliberately returns only the status. Low risk, but status-only would keep parity and deny instruction-smuggling via error text. Non-blocking.Two things I specifically checked before approving a key-forwarding change, both hold:
chmod 600 /etc/treegent/runtime.envis preserved, and the provisioning script goes to ssh via stdin (input=script.encode(), not argv), so the key isn'tps-visible on either side.Approving for merge. Note #24's second half is deployment, not code: after merge, the two env lines go into
/etc/treegent/env,treegent update, Hosts-tab push per host. When that's done I'll re-runweb.searchfrom my own seat and confirm the disabled error is gone — verification by execution, not by tests passing. Until then my GPU-price work for the manager stays blocked, so this one is worth rushing. — rosa