Observed since 20 Oct, 15:38 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Provider-agnostic web and media search for the 3tears family: contracts, adapters, and the staged pipeline
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.
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.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.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.
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(...)
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.
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.
pypistats · 70 observations shown. Missing days are unknown. Source category: overall: without mirrors.
| Date / source period | Value | Observed at |
|---|---|---|
| 2026-10-19 – 2026-10-19 | 67 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-18 – 2026-10-18 | 311 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-17 – 2026-10-17 | 179 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-16 – 2026-10-16 | 259 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-15 – 2026-10-15 | 180 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-14 – 2026-10-14 | 294 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-13 – 2026-10-13 | 270 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-12 – 2026-10-12 | 62 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-11 – 2026-10-11 | 68 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-10 – 2026-10-10 | 139 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-09 – 2026-10-09 | 224 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-08 – 2026-10-08 | 196 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-07 – 2026-10-07 | 53 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-06 – 2026-10-06 | 21 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-05 – 2026-10-05 | 413 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-04 – 2026-10-04 | 587 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-03 – 2026-10-03 | 331 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-02 – 2026-10-02 | 126 | 2026-10-20T15:51:50.2735848Z |
| 2026-10-01 – 2026-10-01 | 62 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-30 – 2026-09-30 | 169 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-29 – 2026-09-29 | 306 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-28 – 2026-09-28 | 370 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-27 – 2026-09-27 | 271 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-26 – 2026-09-26 | 350 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-25 – 2026-09-25 | 385 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-24 – 2026-09-24 | 345 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-23 – 2026-09-23 | 335 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-22 – 2026-09-22 | 183 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-21 – 2026-09-21 | 340 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-20 – 2026-09-20 | 217 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-19 – 2026-09-19 | 90 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-18 – 2026-09-18 | 187 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-17 – 2026-09-17 | 445 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-16 – 2026-09-16 | 364 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-15 – 2026-09-15 | 340 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-14 – 2026-09-14 | 468 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-13 – 2026-09-13 | 288 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-12 – 2026-09-12 | 120 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-11 – 2026-09-11 | 132 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-10 – 2026-09-10 | 191 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-09 – 2026-09-09 | 390 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-08 – 2026-09-08 | 66 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-07 – 2026-09-07 | 245 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-06 – 2026-09-06 | 40 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-05 – 2026-09-05 | 120 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-04 – 2026-09-04 | 44 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-03 – 2026-09-03 | 175 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-02 – 2026-09-02 | 118 | 2026-10-20T15:51:50.2735848Z |
| 2026-09-01 – 2026-09-01 | 183 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-31 – 2026-08-31 | 149 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-30 – 2026-08-30 | 20 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-29 – 2026-08-29 | 179 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-28 – 2026-08-28 | 36 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-27 – 2026-08-27 | 4 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-26 – 2026-08-26 | 78 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-25 – 2026-08-25 | 176 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-24 – 2026-08-24 | 111 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-23 – 2026-08-23 | 179 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-22 – 2026-08-22 | 19 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-21 – 2026-08-21 | 26 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-20 – 2026-08-20 | 14 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-19 – 2026-08-19 | 94 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-18 – 2026-08-18 | 506 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-17 – 2026-08-17 | 117 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-16 – 2026-08-16 | 66 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-15 – 2026-08-15 | 134 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-14 – 2026-08-14 | 142 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-13 – 2026-08-13 | 174 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-12 – 2026-08-12 | 196 | 2026-10-20T15:51:50.2735848Z |
| 2026-08-11 – 2026-08-11 | 109 | 2026-10-20T15:51:50.2735848Z |
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.72.0 | 20 Oct 2026 | 5 |
This describes our collected data; it is not a security assessment.
Shared repository data · GitHub
Public sponsor counts have not been collected. These signals belong to the repository owner.
github · 1 observations shown. Missing days are unknown.
| Date / source period | Value | Observed at |
|---|---|---|
| 2026-10-20 | 0 | 2026-10-20T17:18:19.8928356Z |
Observed since 20 Oct, 15:38 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:0b630cb69dd7345dca6bace5a33618e0e420696410ddf94deab71e064d76a83c