Skip to content
Compresr docs

Guides

Web search

Add Tavily, Brave, or Amazon Bedrock AgentCore web search to your agent loop with automatic compression.

Use WebSearchTool to add web search to your agent loop with automatic compression. It returns a real LangChain BaseTool. Pass it to any of the agent client interfaces and CompresrToolMiddleware compresses search results before they re-enter the model context. No extra wiring.

Three backends ship out of the box:

ProviderStrengthsBring your own key
Tavily (default)LLM-tuned results, strong on recency and citations, allowed_domains / blocked_domains filtering, max_results forwarded verbatimTAVILY_API_KEY
BraveGeneralist web index, independent crawler, native domain filtering uses Goggles (out of scope for v1)BRAVE_SEARCH_API_KEY (fallback: BRAVE_API_KEY)
AgentCoreAmazon Bedrock web search over MCP + Cognito OAuth, max_results clamped 1..25Cognito client credentials (see AgentCore below)

Provider-native server search tools (Anthropic's web_search_20250305, OpenAI's web_search_preview, Gemini's google_search) run server-side and return opaque or encrypted content that Compresr cannot read or compress. The model sees the search content but the SDK doesn't, so there is nothing to intercept.

WebSearchTool calls the search API client-side instead. Plaintext results reach the SDK first, pass through CompresrToolMiddleware, and arrive at the model compressed. This is the only path where Compresr's compression actually fires for web search results.

Quick start: Tavily

python

The model decides when to call tavily_search (or brave_search / agentcore_web_search). The SDK calls the underlying API, and the middleware compresses the result before it re-enters the model context. Mechanics: How compression interacts below.

Construction options

All three backends take a small, deliberately narrow option set. Anything provider-specific (e.g. Tavily search_depth) goes through the extra / **extra escape hatch.

Tavily

python

Brave

python

No native domain filtering on Brave

Brave doesn't expose native allowed_domains / blocked_domains. Its filtering flows through Goggles, which is out of scope for v1. Python emits a UserWarning and proceeds; TypeScript silently ignores the kwargs. Use Tavily if you need real domain filtering.

TypeScript Brave + Claude tool_use

WebSearchTool.brave in TypeScript returns the upstream BraveSearch directly, which ships without an args_schema. Anthropic (Claude) tool_use calls can then fail with missing 1 required positional argument: 'query'. Workaround: wrap it in your own tool() factory that declares a query: z.string() schema, or use Tavily or AgentCore. Python wraps Brave with an explicit schema, so this is a TypeScript-only pitfall.

AgentCore

AgentCore is Amazon Bedrock web search over an MCP streamable-HTTP session, authenticated with a Cognito OAuth client-credentials handshake. Runtime deps are optional. Install the extra: pip install compresr[agentcore] (Python) or npm install @modelcontextprotocol/sdk (TypeScript).

python

Each config field resolves from the explicit argument first, then two env vars in order:

FieldPrimary env varFallback env var
gateway_url / gatewayUrlAGENTCORE_GATEWAY_MCP_URLGATEWAY_MCP_URL
cognito_token_url / cognitoTokenUrlAGENTCORE_COGNITO_TOKEN_URLCOGNITO_TOKEN_URL
client_id / clientIdAGENTCORE_COGNITO_CLIENT_IDCOGNITO_CLIENT_ID
client_secret / clientSecretAGENTCORE_COGNITO_CLIENT_SECRETCOGNITO_CLIENT_SECRET
scopeAGENTCORE_COGNITO_SCOPECOGNITO_SCOPE

Runtime behaviour:

  • HTTPS-only URLs (TypeScript). gatewayUrl and cognitoTokenUrl must start with https://. A plaintext URL throws CompresrError('invalid_config') before any credential leaves the process.
  • max_results clamp. TypeScript enforces 1..25 at build time. Python passes the value through to the underlying client, which applies the same bound.
  • Bearer-token cache. The Cognito token is minted once and cached on the shared client. A 401 from the gateway triggers exactly one automatic re-mint before the call is retried.
  • Timeouts and response cap. Cognito requests time out at 30s, tool calls at 30s, and responses are hard-capped at 1 MB.

Constructor form

Use the classmethod factories above when you can. The constructor form is equivalent and useful when the provider is a runtime variable:

python

CompresrToolMiddleware runs on every tool return inside the agent loop:

  1. The model emits a tool call (e.g. tavily_search({ query: "..." })).
  2. The SDK invokes the provider and normalises the response via _flatten_search_results / flattenSearchResults. The raw JSON becomes blank-line-separated plain-text blocks of title\nurl\ncontent. This is the shape latte_v1 can actually compress; JSON input is a no-op for compression.
  3. The middleware checks the serialized string length. At or below compression.min_tokens (default 200), it's forwarded untouched. Above that, the middleware calls client.compress(...) with the result body as context and the user's last message as query.
  4. The compressed body replaces the original in the agent state. The model never sees the uncompressed search results.

Two consequences:

  • Tune compression.min_tokens to your search backend. Tavily returns long content per hit and easily exceeds 200 tokens. Brave returns shorter snippets, so you may want to lower min_tokens to e.g. 100 to catch them.
  • Compression uses the user's intent as the query, not the model's tool-call query string. So compression stays aimed at what the user actually asked, even when the model rewords the search.

Errors & failure modes

ScenarioBehaviourMitigation
Missing peer dep (langchain-tavily / langchain-community / @modelcontextprotocol/sdk)Python raises ImportError naming the extra. TypeScript raises CompresrError code missing_peer_dependency.Install the extra: pip install compresr[agents-tavily\</td> <td>agents-brave\</td> <td>agentcore] or npm install @langchain/tavily @langchain/community @modelcontextprotocol/sdk.
Missing API key or configPython raises ValueError naming the arg and env-var fallback. TypeScript raises CompresrError with code missing_api_key (Brave), missing_config (AgentCore), or invalid_config (AgentCore non-HTTPS URL), plus invalid_provider for the constructor form.Pass the arg or set the env var.
Search-provider 401 / 403 / rate limit at call timePython: the provider's exception propagates inside the agent loop. TypeScript: raised as CompresrError — for AgentCore specifically, codes agentcore_auth_error, agentcore_no_tool, agentcore_bad_response, agentcore_tool_error.Rotate the key or back off / lower max_results.
Compresr backend down while the middleware firesReturns the original (uncompressed) search result by default (on_error="passthrough" on the policy).Set compression=&#123;"on_error": "raise"&#125; if you want to fail loudly instead.
No tools fired (model answered without searching)No compression call. The middleware only runs on tool returns.Encourage the model to search via the user prompt or a system instruction.

Research facade: client.research

Use client.research when you want web search, snippet compression, and citation extraction in one call, instead of wiring WebSearchTool into an agent loop by hand. It requires a client constructed with llm=; accessing it otherwise raises CompresrError. client.research.run(question) runs the full search-and-synthesize loop, up to max_steps. client.research.search(question) is the same loop capped at 2 steps for quick lookups.

python

Options (Python names; TypeScript uses camelCase):

OptionDefaultEffect
search"tavily""tavily" or "brave" (env-var key fallbacks apply), or a preconstructed WebSearchTool, which is the only way to use AgentCore here.
max_steps10Upper bound on search / synthesize iterations. .search() overrides this to 2.
modelclient llmOverride the client-level model for this call.
compress_snippetstrueRoute each search snippet through the compression API before it enters the LLM context.
compression_model"latte_v1"Which model compresses the snippets.
min_compress_tokens100Skip compression for snippets shorter than this.
max_context_tokens120,000Hard ceiling on total tokens across all compressed snippets before synthesis.
system_promptbuilt-inOverride the research system prompt.

ResearchResult fields: answer, explanation, confidence, text, citations (each with url, title, snippet), trajectory, usage (input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, calls, search_calls), raw.

Next steps

  • Agent client: the full client surface (Anthropic shape, OpenAI shape, native).
  • LangChain integration: lower-level CompresrToolMiddleware, wrap_tool_with_compression, and CompresrExtractor for custom retrieval pipelines.
  • LangGraph integration: drop-in compression node for StateGraph-style agents.