Unified Search
Search across all entity types in a single call.
search
Search across all entity types (profiles, agent_playbooks, user_playbooks) in a single call. The server prepares the query, then retrieves the requested entity types.
Async applications can call await client.search_async(...) with the same
request fields and response model. It uses native async HTTP, applies the
client's total timeout, and preserves task cancellation.
The server applies a five-second deadline to POST /api/search, including
authentication, billing checks, retrieval and response preparation. If that
budget expires before the complete response is accepted, it returns HTTP 504 with detail: "Request timeout",
reason: "search_deadline" and a correlation_id; no partial results are returned.
If the five-second deadline is disabled, the server's existing HTTP backstop
still applies and reports reason: "backstop_timeout". Slow or oversized request
bodies are bounded before authentication/search worker admission.
Once a complete successful response is accepted, the server finishes durable
exposure recording before releasing it. The finalizer must start and accept the
response within the original budget; queue expiry returns 504 without served-state
changes. Accepted finalization has one additional five-second commit budget and
waits for actual cleanup instead of returning a timeout after a durable write.
Total latency can therefore reach ten seconds plus cleanup. With the search
deadline disabled, finalization uses the remaining HTTP backstop. Session deduplication, applied-learning metering, and
completion observers run only for accepted responses. A disconnect prevents
callbacks that have not claimed execution; already active callbacks may finish.
This preserves durable work and does not guarantee that the client received the response.
Client-to-server network time is additional. Under sustained stalled work,
the server can return HTTP 503 rather than admit more searches. Total storage
failure also returns 503. Usable partial results remain 200, with degradation
metadata; an empty successful result is distinct from unavailable storage.
Self-hosted operators can disable deadline enforcement with
REFLEXIO_SEARCH_DEADLINE_ENABLED=false; timing and connection recovery remain
active. Direct embedded Python calls do not acquire this HTTP deadline.
When an agent playbook is returned, user_playbooks omits source user playbooks already represented by that agent playbook. The server does not refill suppressed user playbooks, so user_playbooks may contain fewer than top_k items.
response = client.search(
query="user preferences",
user_id="user_123",
session_id="session_001",
source="api",
top_k=5,
threshold=0.45,
tags=["preferences", "support"],
)curl -X POST "${REFLEXIO_URL:-https://www.reflexio.ai}/api/search" \
-H "User-Agent: my-agent-reflexio" \
-H "Authorization: Bearer $REFLEXIO_API_KEY" \
-H "Content-Type: application/json" \
--data @- <<'JSON'
{
"query": "user preferences",
"user_id": "user_123",
"session_id": "session_001",
"source": "api",
"top_k": 5,
"threshold": 0.45,
"tags": ["preferences", "support"]
}
JSON| Prop | Type | Default | Description |
|---|---|---|---|
query | str | — | Search query text |
top_k? | int | 5 | Maximum results per entity type, from 1 through 100. |
threshold? | float | model-specific | Similarity threshold for the vector arm. Omit it to use the embedding model's default. |
agent_version? | str | — | Filter by agent version (agent_playbooks, user_playbooks) |
playbook_name? | str | — | Filter by playbook name (agent_playbooks, user_playbooks) |
user_id? | str | — | Filter by user ID (profiles, user_playbooks) and identify the user for retrieval-experiment assignment. Required for agent traffic while an experiment is active. At most 255 characters. |
source? | str | — | Filter every selected entity type by exact source. Agent playbooks match when at least one linked source user playbook has that source. Omit, pass null, or pass an empty string to disable source filtering. |
request_id? | str | — | Optional caller correlation ID for the search turn. At most 255 characters. Published exposure evidence binds to the actual publish request; search does not persist exposure records. |
session_id? | str | — | Optional caller session ID for the search turn. At most 255 characters. Enables session-scoped result deduplication and binds a returned exposure receipt to this session; publish that receipt in the same session. |
interaction_id? | int | — | Optional positive integer (minimum 1) used to attribute served results to the caller interaction. |
tags? | list[str] | — | Match entities having any requested tag (OR semantics). Omit or pass an empty list to disable tag filtering. |
entity_types? | list[str] | — | Entity types to search. Valid values: "profiles", "user_playbooks", "agent_playbooks". When unset, all are searched. |
agent_playbook_status_filter? | list[PlaybookStatus | str] | — | Agent-playbook approval statuses to include |
enable_reformulation? | bool | false | Enable query reformulation for improved search results |
enable_agent_answer? | bool | false | Enable agentic answer synthesis when the configured search backend supports it |
conversation_history? | list[ConversationTurn] | — | Prior conversation turns for context-aware query reformulation |
search_mode? | SearchMode | str | — | Search mode: "vector", "fts", or "hybrid". Accepts SearchMode enum or string. When unset, the server uses its configured default ("hybrid"). |
Example:
# Basic unified search
response = client.search(query="response quality issues", session_id="session_001")
print(f"Profiles: {len(response.profiles)}")
print(f"Agent Playbooks: {len(response.agent_playbooks)}")
print(f"User Playbooks: {len(response.user_playbooks)}")
if response.reformulated_query:
print(f"Reformulated query: {response.reformulated_query}")
for profile in response.profiles:
print(f" Profile: {profile.content[:80]}...")
for playbook in response.agent_playbooks:
print(f" Playbook: {playbook.content[:80]}...")
# Search with filters
response = client.search(
query="handling edge cases",
session_id="session_002",
agent_version="v2.1.0",
tags=["reliability", "support"],
top_k=10,
threshold=0.4
)
# Search filtered by user
response = client.search(
query="product preferences",
user_id="user_123",
session_id="session_003",
top_k=5
)curl -X POST "${REFLEXIO_URL:-https://www.reflexio.ai}/api/search" \
-H "User-Agent: my-agent-reflexio" \
-H "Authorization: Bearer $REFLEXIO_API_KEY" \
-H "Content-Type: application/json" \
--data @- <<'JSON'
{
"query": "response quality issues",
"session_id": "session_001"
}
JSON
curl -X POST "${REFLEXIO_URL:-https://www.reflexio.ai}/api/search" \
-H "User-Agent: my-agent-reflexio" \
-H "Authorization: Bearer $REFLEXIO_API_KEY" \
-H "Content-Type: application/json" \
--data @- <<'JSON'
{
"query": "handling edge cases",
"session_id": "session_002",
"agent_version": "v2.1.0",
"tags": ["reliability", "support"],
"top_k": 10,
"threshold": 0.4
}
JSON
curl -X POST "${REFLEXIO_URL:-https://www.reflexio.ai}/api/search" \
-H "User-Agent: my-agent-reflexio" \
-H "Authorization: Bearer $REFLEXIO_API_KEY" \
-H "Content-Type: application/json" \
--data @- <<'JSON'
{
"query": "product preferences",
"user_id": "user_123",
"session_id": "session_003",
"top_k": 5
}
JSONPublished exposure receipts
Enterprise user-playbook search results may include an opaque exposure_receipt.
Preserve it with the matching user-playbook ID in the Assistant interaction’s
retrieved_learnings when publishing. The server records exposure atomically with
that interaction, using the version served by search. Search itself writes no
exposure ledger row. Claude-smart and OpenClaw preserve receipts automatically.
Missing or rejected receipts remain incomplete published evidence; they do not recover served-version fingerprints from the current playbook. Receipts describe client-declared published injections, not proof of actual causal use.