based-models-agentloop-tools
based-models-agentloop-tools provides typed, validated tools for
based-models-agentloop agents. Its first tool family makes provider-hosted web search easy
to configure, limits where searches may go, and extracts the sources and citations behind an
answer.
The package is installed as based-models-agentloop-tools and imported as
agentloop_tools. It requires Python 3.12 or newer.
Why use agentloop-tools?
- Add native Anthropic or OpenAI web search to an
Agentwith one tool factory. - Validate domain filters, location data, search limits, and provider options before a request is sent.
- Apply one allowlist or blocklist both to the provider request and to a post-response audit.
- Recover deduplicated search sources and ordered answer citations from a transcript.
- Detect disallowed domains in search results, citations, URLs, Markdown links, and blocked host names written in an answer.
- Keep configuration and credentials in the application; this package never reads the environment.
- Stay provider-light: the package depends only on
based-models-agentloopand imports only its public API.
Installation
Install this package together with the extra for the provider your agent uses.
For Anthropic:
pip install based-models-agentloop-tools "based-models-agentloop[anthropic]"
For OpenAI:
pip install based-models-agentloop-tools "based-models-agentloop[openai-compat]"
Native web search works with Anthropic Messages and the OpenAI Responses API. OpenAI uses
Responses by default; it will not work when OPENAI_API=completions is selected. OpenRouter,
Modal/vLLM, and other Chat Completions-compatible providers do not offer this hosted tool.
Quick start
Create a hosted search tool, pass it to Agent, and use a Transcript when you want to
inspect the evidence:
import os
from agentloop import Agent, Transcript, final_text
from agentloop_tools.web import citations, native_web_search, sources
search = native_web_search(
allowed_domains=["europa.eu"],
user_location={"country": "BE"},
)
transcript = Transcript()
transcript.add_user_message(
"What does the EU AI Act say about general-purpose models?"
)
with Agent.from_env(
os.environ,
tools=[search],
system="Use web search and cite your sources.",
) as agent:
agent.converse(transcript)
print(final_text(transcript))
for source in sources(transcript):
print("searched:", source.url)
for citation in citations(transcript):
print("cited:", citation.url)
The provider performs the search. agentloop records the search activity, sources,
citations, and provider replay data in the transcript; this package provides the validated
configuration and evidence readers.
Native web search options
from agentloop_tools.web import native_web_search
search = native_web_search(
allowed_domains=["europa.eu", "oecd.org/ai"],
max_uses=3,
user_location={
"city": "Brussels",
"country": "BE",
"timezone": "Europe/Brussels",
},
search_context_size="high",
)
| Option | Meaning | Anthropic | OpenAI Responses |
|---|---|---|---|
allowed_domains |
Search only these domains and paths | Yes | Yes |
blocked_domains |
Exclude these domains and paths | Yes | Yes |
user_location |
Approximate city, region, country, or timezone | Yes | Yes |
max_uses |
Maximum searches per request | Yes | Ignored with a warning |
dynamic_filtering |
Filter results with provider-side code | Yes | Ignored with a warning |
search_context_size |
Amount of search content supplied to the model | Ignored with a warning | Yes |
Unknown options are rejected. Unsupported domain restrictions are never silently dropped; unsupported tuning options are logged and ignored by the adapter.
Domain validation
Domain filters use bare ASCII domains without a URL scheme:
native_web_search(allowed_domains=["europa.eu", "example.com/reports"])
- Pass either
allowed_domainsorblocked_domains, never both. - A rule includes the named host and its subdomains.
- An optional path restricts the rule to that path prefix.
*is allowed within a path, but not in a hostname.- Schemes such as
https://are rejected. - Non-ASCII domains are rejected to prevent look-alike Unicode domains from bypassing a filter.
Sources and citations
The two evidence readers serve different purposes:
from agentloop_tools.web import citations, sources
searched_pages = sources(transcript)
cited_claims = citations(transcript)
sources(transcript)returns every page a hosted search consulted, deduplicated by URL in first-appearance order.citations(transcript)returns every citation attached to assistant text, in transcript order.
A source shows what the provider searched. A citation ties part of the generated answer to a page. They are related but not interchangeable: a provider may search a page without citing it, and not every search mode produces citations.
Anthropic dynamic filtering
dynamic_filtering=False is the default because Anthropic's basic search preserves
citations. When enabled, Anthropic runs provider-side code to filter search results before
they reach the model. This can help search-heavy requests, but it has important tradeoffs:
sources()still returns the pages consulted.citations()may be empty because the model reads the filtering program's output rather than citation-bearing search-result blocks.- The mode is not eligible for Zero Data Retention.
OpenAI ignores dynamic_filtering with a warning.
Domain policy: prevent, then audit
DomainPolicy keeps one allowlist or blocklist as the source of truth for both request-time
filtering and response-time auditing.
import os
from agentloop import Agent, Transcript, final_text
from agentloop_tools.web import DomainPolicy
policy = DomainPolicy.allow(["europa.eu", "oecd.org"])
search = policy.native_web_search(search_context_size="high")
transcript = Transcript()
before = len(transcript.messages)
transcript.add_user_message("Summarize recent AI-policy guidance.")
with Agent.from_env(os.environ, tools=[search]) as agent:
agent.converse(transcript)
violations = policy.audit(transcript, since=before)
if violations:
for violation in violations:
print(violation.where, violation.url, violation.rule)
else:
print(final_text(transcript))
Construct policies with one of:
allowed = DomainPolicy.allow(["europa.eu", "oecd.org"])
blocked = DomainPolicy.block(["example.com", "example.org/private"])
policy.native_web_search() sends the policy's domains to the provider. policy.audit()
then inspects completed assistant messages for:
- Sources returned by hosted search
- Citations attached to assistant text
- Full URLs, including Markdown link targets, written in the answer
- Bare mentions of blocked hosts in block mode
Each Violation reports the URL or mention, where it appeared, the transcript message index,
and the matching block rule when applicable. Auditing does not modify the transcript, raise
an exception, retry the request, or choose an enforcement response; the application decides
whether to log, reject, re-ask, or warn the user.
Policy limits
Native search runs inside the provider's response. A domain filter asks the provider not to
return a domain, but downstream code cannot prevent the model from reading a page that the
provider did return. DomainPolicy therefore follows a deliberate two-stage model:
- Prevent what the provider can prevent with its native domain filter.
- Report disallowed domains that still appear in sources, citations, or answer text.
In allow mode, the audit checks full URLs but does not treat every host-like word as a domain;
doing so would create false positives for text such as config.py. In block mode, it can
also look specifically for bare mentions of the configured blocked hosts.
API overview
Import web tools explicitly from agentloop_tools.web:
from agentloop_tools.web import (
DomainPolicy,
Violation,
citations,
native_web_search,
sources,
)
native_web_search(...)builds a validatedHostedToolfor provider-run search.sources(transcript)extracts unique consulted pages.citations(transcript)extracts citations attached to assistant text.DomainPolicy.allow(...)andDomainPolicy.block(...)create domain policies.policy.native_web_search(...)builds a search tool using the policy's domain list.policy.match(...)identifies the matching rule for a URL or hostname.policy.permits(...)checks whether a URL or hostname is allowed.policy.audit(...)returns policy violations without mutating the transcript.
Tool families are intentionally imported explicitly rather than re-exported from the package
root. The package uses only agentloop's public API and never reads configuration, API keys,
or environment variables.
This release provides provider-hosted web search. Client-side search—where your own Python tool calls a search API and controls results before the model sees them—is a separate feature and is not included yet.
Documentation
Full documentation and additional examples are coming soon.
Stability and license
based-models-agentloop-tools is currently beta software. While the version is 0.x, a
minor release may change the public API.
Licensed under the Apache License 2.0.
Metadata
Release files for based-models-agentloop-tools 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| based_models_agentloop_tools-0.1.0.tar.gz | 13.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| based_models_agentloop_tools-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 27.6 kB
Release files / based_models_agentloop_tools-0.1.0.tar.gz
| Download URL | based_models_agentloop_tools-0.1.0.tar.gz |
|---|---|
| Size | 13.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6262962ac1f556bf8fcc9c00d0a011cf3ff61c232fef6ca82dff3cc708357d49
|
|
BLAKE2b-256 checksum How to use checksums |
55502413fbfeb3f0955691f39c44b87049b5f3466842861292b58738634f7c70
|
| 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 Oct 1, 2026.
Transparency logRelease files / based_models_agentloop_tools-0.1.0-py3-none-any.whl
| Download URL | based_models_agentloop_tools-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7a57896c1450094228543fee4eeefe2ce110a879dee79ec975538de2acd171f5
|
|
BLAKE2b-256 checksum How to use checksums |
b932587ebcfaaa59d70bdc40e4a9bad7c8ab6be9f70ef23adc13f508a924d7e6
|
| 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 Oct 1, 2026.
Transparency log