Skip to main content

3tears-search

Provider-agnostic web and media search for the 3tears family.

The authority for everything in this package is docs/search-spec.md (decisions D1-D28), with requirement IDs (SR-*, G*, P*) defined in docs/search-requirements.md.

Layout

threetears/search/
  contracts/        # the leaf within the leaf -- types, protocols, errors, keys
  adapters/
    searxng.py      # one provider's API, over the injected transport
  call.py           # a query → one candidate set, bounded and negotiated
  bind.py           # prose for a model + the metadata projection
  standalone.py     # bare-httpx transport   [standalone] -- the sanctioned path (D19)
  testing/          # the shared provider-conformance suite + declared doubles

Layer names (Adapter, Call, Bind, …) are module vocabulary and never type names, so a later re-cut of the layers stays cheap.

contracts/ is the lingua franca every layer and every consumer speaks:

  • SearchRequest and the open criteria vocabulary (typed constructors for well-known criteria, namespaced keys for everything else), with per-criterion dispositions (pushdown | local | unsatisfied | ignored-unknown).
  • Candidate -- the carrier-neutral result core: identity, locators, provenance, named provenanced scores (never a single score field, D1), fidelity available/achieved, an optional content slot, and additive facets keyed by the media-contracts vocabulary.
  • Spend -- every resource a call consumed: money (Decimal), wall-clock, call count, weighted provider units, bytes.
  • The typed error taxonomy (SR-J1), every error carrying Spend (SR-E3). Zero results is a success value, not an error (SR-J2).
  • SearchTransport -- the injected transport seam (SR-N1, P9). A thin host-side adapter over threetears.core.http_client.TracedHttpClient satisfies it structurally; this package never imports core.
  • SEARCH_RESULTS_METADATA_KEY and the versioned metadata projection (D13, D22).
  • ProviderCapabilities -- what a provider can express, declared and queryable so a consumer branches before sending rather than after failing (SR-B4), following the 3tears-models capability-metadata pattern.
  • SearchProvider -- the provider seam Call depends on and the conformance suite parametrizes over.
  • Canonical serialization of request/parameter types -- one canonical form consumed by both the D26 replay key and eval run identity (SR-F1).

Using it

import asyncio

from threetears.search.adapters.searxng import SearxngAdapter
from threetears.search.bind import bind_search
from threetears.search.contracts import Criterion, SearchRequest
from threetears.search.standalone import StandaloneTransport   # or your own


async def main() -> None:
    adapter = SearxngAdapter(
        base_url="https://searx.internal.example",   # deployment config, never env
        transport=StandaloneTransport(allow_private_addresses=True),
        provider_instance="searxng-main",
    )
    rendered = await bind_search(
        SearchRequest(query="capybara habitat range", criteria=(Criterion.max_results(5),)),
        provider=adapter,
    )
    print(rendered.content)                                  # prose for a model
    print(rendered.metadata["search_results"]["candidates"])  # structure for a program


asyncio.run(main())

bind_search never raises: a typed failure arrives as a failed RenderedSearch carrying its spend under the same metadata key (D10). Callers that want the exception go through threetears.search.call.search instead.

Budgets and pacing pass through the same entry point: hand bind_search (or search) a budget= implementing BudgetPort, a limiter= such as threetears.search.limiter.InProcessRateLimiter -- construct one per process and share it, or pacing paces nothing -- and the egress= name your transport actually exits by (D8, D20). A budget refusal or pacing denial renders as a failed result like any other typed failure; omitting the ports means no budget is consulted and no pacing applies.

Hosts that already have threetears.core should inject a thin adapter over TracedHttpClient rather than take the [standalone] extra -- it brings timeouts, retry, circuit-breaking and spans for free.

Provider conformance

threetears.search.testing ships the suite every adapter passes -- contract shape, spend on failure, error taxonomy, disposition honesty, zero-results-is-success (SR-O5). It imports no test framework, so a consumer can run it against its own wiring:

from threetears.search.testing import ProviderConformanceCase, ProviderConformanceSuite


class TestMyProviderConformance(ProviderConformanceSuite):
    case = ProviderConformanceCase(...)

Not here yet

aggregate.py, extract.py, select.py, limiter.py and replay.py are later phases of docs/search-spec.md §7. Budget-port consultation and pacing are marked seams inside call.py: the port types are Phase 1 PR 2, and a placeholder protocol would only be a second vocabulary to migrate off.

Import-cleanliness

Importing threetears.search.contracts pulls nothing beyond stdlib, pydantic, and 3tears-media-contracts. Nothing in this package imports threetears.core, threetears.agent.*, langchain, or NATS. Nothing reads environment variables -- the host passes base URLs, secret references, and transport (SR-K1).

standalone.py is the only module that imports httpx, and nothing in the package imports standalone at module level: the extra stays opt-in, and a host that injects its own transport never installs it. Both facts are pinned by tests/test_package_boundaries.py, and the module's path is the D19 widening of the no-bespoke-client norm in tests/enforcement/test_no_bespoke_reuse.py -- a sanctioned transport, with no exemption filed.

Release files for 3tears-search 0.41.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for 3tears-search 0.41.1
File Size Uploaded
3tears_search-0.41.1.tar.gz 224.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for 3tears-search 0.41.1
File Interpreter ABI Platform
3tears_search-0.41.1-py3-none-any.whl Python 3 none any Details

Total release size: 386.0 kB

Release files / 3tears_search-0.41.1.tar.gz

Download URL 3tears_search-0.41.1.tar.gz
Size 224.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f842f29679f7c5d11f4cd1dbbf8436e1548e99b8770cf70bc1b9b37bccb54b80
BLAKE2b-256 checksum
How to use checksums
c20e66480dbc22634a88eaf81383c72dc338406e9fdd239aa2d557a6d184c183
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.

Transparency log

Release files / 3tears_search-0.41.1-py3-none-any.whl

Download URL 3tears_search-0.41.1-py3-none-any.whl
Size 161.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
eb7b38a4f4989ba7adc54599309fedbb3d1c8c1979064a09a403a7693cb5c637
BLAKE2b-256 checksum
How to use checksums
c3c7a86ef157146a48529a545f752224638ff0990ef619e080c565967bf94072
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.

Transparency log

Release history Release notifications | RSS feed

0.52.1

2 release files

0.52.0

2 release files

0.51.1

2 release files

0.51.0

2 release files

0.50.0

2 release files

0.49.0

2 release files

0.48.0

2 release files

0.47.1

2 release files

0.47.0

2 release files

0.46.1

2 release files

0.46.0

2 release files

0.45.1

2 release files

0.45.0

2 release files

0.44.0

2 release files

0.43.0

2 release files

0.42.0

2 release files

0.41.4

2 release files

0.41.3

2 release files

0.41.2

2 release files

This release

0.41.1 This release

2 release files

0.41.0

2 release files

0.40.0

2 release files

0.39.0

2 release files

0.38.0

2 release files

0.37.0

2 release files

0.30.0

2 release files

0.29.0

2 release files

0.28.0

2 release files

0.27.0

2 release files

0.26.1

2 release files

0.26.0

2 release files

0.25.0

2 release files

0.24.7

2 release files

0.24.6

2 release files

0.24.5

2 release files

0.24.4

2 release files

0.24.3

2 release files

0.24.2

2 release files

0.24.1

2 release files

0.24.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page