Skip to content

feat(tools): add Keenable backend to web_search - #1722

Merged
PattaraS merged 2 commits into
omnigent-ai:mainfrom
ilya-bogin-keenable:feat/keenable-web-search
Jul 3, 2026
Merged

feat(tools): add Keenable backend to web_search#1722
PattaraS merged 2 commits into
omnigent-ai:mainfrom
ilya-bogin-keenable:feat/keenable-web-search

Conversation

@ilya-bogin-keenable

@ilya-bogin-keenable ilya-bogin-keenable commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a Keenable search backend to the web_search built-in tool, alongside
the existing google / perplexity / nimble / tavily backends, giving non-OpenAI
models another grounded-search option.

Unlike the other backends, Keenable is keyless by default: with no api_key
it calls the public endpoint (/v1/search/public), so it works out of the box.
Supplying an api_key switches to the authenticated endpoint (/v1/search,
X-API-Key header) and lifts rate limits.

  • New web_search_keenable.py, mirroring the Tavily/Nimble backends: optional
    api_key, max_results clamped 1–20, X-Keenable-Title: Omnigent attribution
    header, error-as-string contract, and the OMNIGENT_KEENABLE_BASE_URL test
    override.
  • web_search.py gains a _run_keenable dispatch branch (no required key —
    this is the only keyless backend) plus updated help text and module/_search
    docstrings.

Test Plan

  • uv run pytest tests/tools/builtins/test_web_search.py → 45 passed (8 new
    Keenable cases: keyed path, keyless-by-default, X-API-Key/endpoint switch,
    X-Keenable-Title header, HTTP error, empty results, max_results slice + clamp).
  • uv run ruff check . && uv run ruff format --check . → clean on the touched files.
  • Manually smoke-tested against the live Keenable API and an offline stub via
    OMNIGENT_KEENABLE_BASE_URL; request shape and result formatting confirmed.

Demo

This is a core-tool backend with no UI surface, so the user-visible behaviour is
the tool's returned text. Live run through the unified web_search tool with
search_provider: keenable and no API key (keyless public endpoint):

$ web_search(query="what is retrieval augmented generation")   # search_provider: keenable, max_results: 3

1. Retrieval-Augmented Generation (RAG)
   https://link.springer.com/article/10.1007/s12599-025-00945-3
   Business & Information Systems Engineering -

2. Retrieval-augmented generation
   https://en.wikipedia.org/wiki/Retrieval-augmented_generation

3. What Is Retrieval-Augmented Generation (RAG)? [2026]
   https://atlan.com/know/what-is-retrieval-augmented-generation
   Atlan is the context layer for enterprise AI. It continuously reads your
   warehouses, databases, pipelines, BI tools, and business systems ...

Same call with an api_key in the spec transparently switches to the
authenticated endpoint (/v1/search, X-API-Key) and returns the same shape.

Type of change

  • Bug fix
  • Feature
  • Refactor / chore
  • Docs
  • Test / CI
  • Breaking change

Test coverage

  • Unit tests added / updated
  • Integration tests added / updated
  • E2E tests added / updated
  • Manual verification completed
  • Existing tests cover this change
  • Not applicable

@github-actions github-actions Bot added the size/L Pull request size: L label Jun 30, 2026
@github-actions
github-actions Bot requested a review from PattaraS June 30, 2026 16:28
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

@ilya-bogin-keenable This PR is a Bug fix, Feature, or UI / frontend change but the Demo section is missing or only contains a placeholder.

These change types require a screenshot or screen recording so reviewers can see the new behaviour without checking out the branch. Please update the Demo section with:

  • A screenshot or screen recording of the change, or
  • A link to a hosted video or GIF showing the new behaviour.

Use N/A only when the change has no user-visible effect whatsoever (e.g. a pure refactor or test-only change). If that's the case, uncheck the relevant type box and check Refactor / chore or Test / CI instead.

@github-actions github-actions Bot added the needs-demo PR needs a demo screenshot or recording label Jul 1, 2026
Adds a Keenable search backend to the web_search built-in tool, alongside
the existing google / perplexity / nimble / tavily backends, giving
non-OpenAI models another grounded-search option.

Unlike the other backends, Keenable is keyless by default: with no api_key
it calls the public endpoint (/v1/search/public), so it works out of the
box. Supplying an api_key switches to the authenticated endpoint
(/v1/search, X-API-Key header) and lifts rate limits.

- New web_search_keenable.py, mirroring the Tavily/Nimble backends:
  optional api_key, max_results clamped 1-20, X-Keenable-Title: Omnigent
  attribution header, error-as-string contract, OMNIGENT_KEENABLE_BASE_URL
  test override.
- web_search.py gains a _run_keenable dispatch branch (no required key)
  plus updated help text and module/_search docstrings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@PattaraS
PattaraS force-pushed the feat/keenable-web-search branch from 39548a0 to f16c7e4 Compare July 3, 2026 10:24
@PattaraS

PattaraS commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Thanks Ilya! Rebased this onto main for you and resolved the conflict with the newly-landed duckduckgo backend (both keyless options now coexist in the dispatch and the help text). All 45 web_search tests pass, ruff clean.

Verified the integration end to end: hit the keyless /v1/search/public endpoint live and it returns real ranked results with no credentials, and the keyed path correctly switches to /v1/search with the X-API-Key header. Clean isolation in its own backend module, good test coverage across keyless/keyed/error/clamping. Nice touch making it keyless by default.

PattaraS
PattaraS previously approved these changes Jul 3, 2026
@omnigent-ci

omnigent-ci Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Polly AI Review

Blocking issues

None. The Keenable backend faithfully mirrors the existing Tavily/Nimble pattern: error-as-string contract, max_results clamped 1–20, test-only base-URL override, and a clean dispatch branch in _search. The keyless-by-default behavior is intentional and correctly gated (no api_key/v1/search/public with no auth header; with a key → /v1/search + X-API-Key). Help text and docstrings are updated consistently, and the test suite covers the meaningful paths (keyed/keyless endpoint switch, attribution header, HTTP error, empty results, slice + clamp).

Security vulnerabilities

None. The base URL is a fixed constant; OMNIGENT_KEENABLE_BASE_URL only overrides it for tests, and the query is sent as a JSON body field, so there's no SSRF or injection surface introduced. No secrets are logged. The api_key travels only in the X-API-Key header. No lockfile or dependency changes.

Non-blocking notes

  • Narrow exception coverage. _search_keenable catches HTTPStatusError, ConnectError, and TimeoutException, but other httpx transport errors (e.g. ReadError, RemoteProtocolError) and a malformed/non-JSON body (resp.json() raising) would propagate as an unhandled exception rather than the error-string contract. This matches the existing Tavily/Nimble backends, so it's consistent, but catching httpx.HTTPError (and guarding the .json() decode) would make the "error-as-string" contract fully robust.
  • Result numbering can gap. _format_results enumerates the sliced list but continues past non-dict items, so a stray non-dict entry leaves a gap in the displayed 1. / 2. / … numbering. Cosmetic and unlikely given the API shape.
  • Keyless default sends live external traffic out of the box. Selecting search_provider: keenable with no key silently calls the public Keenable endpoint. This is the documented design intent and clearly stated in the help text; just noting it as a behavioral distinction from every other backend, which all fail loudly without a key.

Summary

A clean, well-tested feature addition that closely follows the established backend conventions. No correctness, contract, or security problems in the diff. It's a purely backend tool change with no user-visible UI, so no visual demonstration is needed. The only items worth considering are hardening the exception/JSON-decode handling and the minor numbering edge case — all non-blocking. Ready to merge once those are weighed.


Automated review by Polly · workflow run

The selectable search_provider engines were hardcoded in ~5 places
(module + class + _search docstrings, the if/elif dispatch, and two error
strings), so adding a backend meant editing prose in each spot and the
lists had already drifted. Add a `_BACKENDS` registry as the single source
of truth: the dispatch and the error hint both derive from it, and adding
an engine is now a `_run_*` plus one row.
@PattaraS

PattaraS commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Added a small follow-up commit on top (not a force-push, so the history is preserved): the selectable search_provider engines were hardcoded in ~5 places (module/class/_search docstrings, the if-chain dispatch, and two error strings), which had already drifted. Pulled them into a single _BACKENDS registry so the dispatch and the error hint both derive from one source. Adding a backend is now a _run_* plus one row in the map, nothing else.

All 45 web_search tests still pass, ruff + format clean. No behavior change.

@PattaraS

PattaraS commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Mering this. Thanks again, @ilya-bogin-keenable!

@PattaraS
PattaraS enabled auto-merge (squash) July 3, 2026 14:15
@PattaraS
PattaraS merged commit b26f1cb into omnigent-ai:main Jul 3, 2026
48 of 49 checks passed
@github-actions github-actions Bot added the needs-doc-update Merged PR needs a user-facing docs update label Jul 3, 2026
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🏷️ Doc impact: needs-doc-update

Adds a new keyless "keenable" backend to the web_search tool's selectable search_provider options, a user-configurable integration surface that the web_search docs should list.

Drafting a docs PR to omnigent-ai/omnigent-site (staged on 0.5-docs until release)…

Auto-classified on merge. Set the label manually before merging to override. · run

PattaraS pushed a commit to omnigent-ai/omnigent-site that referenced this pull request Jul 4, 2026
Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>
dhruv0811 added a commit to omnigent-ai/omnigent-site that referenced this pull request Jul 10, 2026
* docs: document omnigent-ai/omnigent#1722 (#261)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#2018 (#265)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#1386 (#272)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#2156 (#278)

* docs: document omnigent-ai/omnigent#2156

* Apply suggestion from @serena-ruan

* Apply suggestions from code review

Co-authored-by: Serena Ruan <82044803+serena-ruan@users.noreply.github.com>

---------

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>
Co-authored-by: Serena Ruan <82044803+serena-ruan@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#2022 (#268)

* docs: document omnigent-ai/omnigent#2022

* docs: add steering gif and simplify message queue section

Co-authored-by: Isaac

---------

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>
Co-authored-by: Serena Ruan <serena.rxy@gmail.com>

* chore(api): sync openapi.json from omnigent@3c7a558 (#274)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#526 (#279)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: rename hindsight extra to memory (omnigent[memory]) (#282)

The memory tools ship under the `memory` extra (omnigent[memory]), not
`hindsight`. Update the install instruction and extra name to match.
The Hindsight product name and the hindsight_* tool names are unchanged.

* docs: document default base branch for new worktrees (#284)

* docs: document default base branch for new worktrees

* docs: condense worktree branches section and add setting demo gif

Co-authored-by: Isaac

---------

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>
Co-authored-by: Serena Ruan <serena.rxy@gmail.com>

* chore(api): sync openapi.json from omnigent@7fb779f (#281)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* chore(api): sync openapi.json from omnigent@60e775a (#288)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#2152 (#280)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#1859 (#277)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#2135 (#276)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

---------

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>
Co-authored-by: Serena Ruan <82044803+serena-ruan@users.noreply.github.com>
Co-authored-by: Serena Ruan <serena.rxy@gmail.com>
Co-authored-by: Pat Sukprasert <pattara.sk127@gmail.com>
Co-authored-by: Dhruv Gupta <dhruv.gupta@databricks.com>
daniellok-db added a commit to omnigent-ai/omnigent-site that referenced this pull request Jul 17, 2026
* docs: document omnigent-ai/omnigent#1722 (#261)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#2018 (#265)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#1386 (#272)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#2156 (#278)

* docs: document omnigent-ai/omnigent#2156

* Apply suggestion from @serena-ruan

* Apply suggestions from code review

Co-authored-by: Serena Ruan <82044803+serena-ruan@users.noreply.github.com>

---------

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>
Co-authored-by: Serena Ruan <82044803+serena-ruan@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#2022 (#268)

* docs: document omnigent-ai/omnigent#2022

* docs: add steering gif and simplify message queue section

Co-authored-by: Isaac

---------

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>
Co-authored-by: Serena Ruan <serena.rxy@gmail.com>

* chore(api): sync openapi.json from omnigent@3c7a558 (#274)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#526 (#279)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: rename hindsight extra to memory (omnigent[memory]) (#282)

The memory tools ship under the `memory` extra (omnigent[memory]), not
`hindsight`. Update the install instruction and extra name to match.
The Hindsight product name and the hindsight_* tool names are unchanged.

* docs: document default base branch for new worktrees (#284)

* docs: document default base branch for new worktrees

* docs: condense worktree branches section and add setting demo gif

Co-authored-by: Isaac

---------

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>
Co-authored-by: Serena Ruan <serena.rxy@gmail.com>

* chore(api): sync openapi.json from omnigent@7fb779f (#281)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* chore(api): sync openapi.json from omnigent@60e775a (#288)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#2152 (#280)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#1859 (#277)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document omnigent-ai/omnigent#2135 (#276)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

* docs: document official kubernetes server image variant (#285)

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>

---------

Co-authored-by: omnigent-ci[bot] <294685417+omnigent-ci[bot]@users.noreply.github.com>
Co-authored-by: Serena Ruan <82044803+serena-ruan@users.noreply.github.com>
Co-authored-by: Serena Ruan <serena.rxy@gmail.com>
Co-authored-by: Pat Sukprasert <pattara.sk127@gmail.com>
Co-authored-by: Dhruv Gupta <dhruv.gupta@databricks.com>
Co-authored-by: Daniel Lok <daniel.lok@databricks.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-demo PR needs a demo screenshot or recording needs-doc-update Merged PR needs a user-facing docs update size/L Pull request size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants