Docs⌘ K  Search
Docs/Search & chat/Chat completions
Chat API

Chat Completions

OpenAI-compatible chat endpoint with automatic memory injection. Drop-in replacement that gives your AI persistent memory.

1
Receive Message
User sends a message to your AI
2
Search Memories
Hebbrix finds relevant context
3
Respond with Context
AI responds with full memory context

Outcome advice for tool calls

Non-streaming requests can opt into tool_advice with explicit function-name bindings to configured policy/action/context identities. Each binding names the target argument; every other argument must exactly match fixed_arguments. Use the same collection and end-user scope as the policy. Agent/run and all-scope requests are rejected for this feature.

Explicit tool mapping
"tool_advice": {
  "mode": "hold",
  "bindings": {
    "inspect_service": {
      "policy_key": "sandbox.inspect", "action_key": "logs",
      "context": {"issue":"slow"}, "target_argument": "service",
      "fixed_arguments": {"operation":"read_logs"}
    }
  }
}

The proxy checks actual returned arguments, qualified outcomes and independent rules. memory_context.tool_advice.calls contains ACT / ASK / BLOCK and evidence. Unknown calls, argument mismatches or advice errors remain ASK. Default hold mode removes all executable calls from the completion, including ACT, and retains them in held receipts for independent approval. Annotate mode preserves proposals with advisory verdicts, except calls that violate the caller's selection contract or report incomplete/filtered generation: those are withheld even in annotate mode. No tool is executed and no authorization is granted. Streaming is rejected when tool advice is enabled so partial arguments cannot bypass assessment.

Tool-advice requests require uniquely named supplied function tools, bindings to those tools, and tool_choice of auto, none, required or an exact supplied function name. Invalid contracts fail with 422 before generation. Read per-choice selection_contract, completion_contract and provider_finish_reason. Auto permits no call; required requests a model choice among tools, not a named choice. Missing termination metadata remains unverified, and absence of a length/filter flag does not prove argument completeness. Fallback adapters must not silently drop unsupported caller requirements.

Memory context also includes separate exact-query relevance feedback counts alongside scoped logged outcomes. Repeated thumbs-down is described as relevance feedback, never fabricated execution failure. This informs the model but does not guarantee it will never repeat an error.

How It Works

Round10 contract corrections

features.memory: false disables memory, profile and personalization injection together, while preserving your system instructions and conversation. Round10 removes canned greeting replies, defaults deep analytics to opt-in, and adds retrieval_trace with considered, prompt-used and dropped IDs/reasons. Prompt use is not proof that the model used or verified a fact. Requested and served model identities appear in model_resolution; opt-in strict_model: true rejects an alias substitution before generation. Check the live release and canonical schema for the deployed contract. New SDK convenience fields remain source-only unless your installed package explicitly includes them; the HTTP options do not require republishing an SDK.

When you send a chat request, Hebbrix automatically searches for relevant memories and injects them into the system prompt. Your AI gets context from past conversations without any extra code.

Endpoint

Code Examples

Drop-in Replacement for OpenAI

Python (OpenAI SDK)
import os
from uuid import uuid4
from openai import OpenAI

# Just change the base URL and API key
client = OpenAI(
    api_key="mem_sk_your_hebbrix_key",
    base_url="https://api.hebbrix.com/v1",
    timeout=100.0,
    max_retries=0,
)

# Use exactly like OpenAI
response = client.chat.completions.create(
    model="gpt-5-nano",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "What did we discuss last time?"}
    ],
    extra_body={"collection_id": os.environ["HEBBRIX_COLLECTION_ID"],
                "user_id": "user-123", "features": {"learning": False}},
    extra_headers={"Idempotency-Key": str(uuid4()),
                   "X-Hebbrix-Require-Collection": "true"},
)

print(response.choices[0].message.content)
# The response will include context from previous conversations!

With Hebbrix SDK

Python (direct API)
import os
import time
import requests
from uuid import uuid4

BASE = "https://api.hebbrix.com/v1"
H = {"Authorization": f"Bearer {os.environ['HEBBRIX_API_KEY']}"}
SCOPE = {"collection_id": os.environ["HEBBRIX_COLLECTION_ID"], "user_id": "user-123"}
learn_request_id = str(uuid4())  # Keep this value if retrying this exact request.

# First turn: the backend extracts and stores the fact automatically
# when the `features.memory` and `features.learning` flags are enabled.
r = requests.post(
    f"{BASE}/chat/completions",
    headers={**H, "Idempotency-Key": learn_request_id},
    json={
        **SCOPE,
        "model": "gpt-5-nano",
        "messages": [
            {"role": "user", "content": "Remember that my favorite color is blue"},
        ],
        "session_id": "user_123_session",
        "features": {
            "memory": True,
            "user_profile": True,
            "learning": True,
        },
    }, timeout=100,
)
r.raise_for_status()
receipt = r.json()["memory_context"]["memory_learning"]
if receipt["status"] == "queued":
    for _ in range(60):
        job_response = requests.get("https://api.hebbrix.com" + receipt["poll_url"], headers=H, timeout=10)
        job_response.raise_for_status()
        job = job_response.json()
        if job["status"] == "completed":
            break
        if job["status"] in ("failed", "cancelled"):
            raise RuntimeError("Learning did not complete")
        time.sleep(1)
    else:
        raise TimeoutError("Learning is still pending; keep the receipt")

# Later conversation: the backend injects prior memories as context
recall_request_id = str(uuid4())
r = requests.post(
    f"{BASE}/chat/completions",
    headers={**H, "Idempotency-Key": recall_request_id},
    json={
        **SCOPE,
        "model": "gpt-5-nano",
        "messages": [
            {"role": "user", "content": "What's my favorite color?"},
        ],
        "session_id": "user_123_session",
        "features": {"learning": False},
    }, timeout=100,
)
print(r.json()["choices"][0]["message"]["content"])
# → "Your favorite color is blue!"

Streaming Response

Python (Streaming)
import os
from openai import OpenAI

# Drop-in OpenAI client: point base_url at Hebbrix
client = OpenAI(
    api_key="mem_sk_your_hebbrix_key",
    base_url="https://api.hebbrix.com/v1",
    timeout=100.0,
    max_retries=0,
)

# Enable streaming for real-time responses
stream = client.chat.completions.create(
    model="gpt-5-nano",
    messages=[{"role": "user", "content": "Tell me a story"}],
    stream=True,
    extra_body={"collection_id": os.environ["HEBBRIX_COLLECTION_ID"],
                "user_id": "user-123", "features": {"learning": False}},
)

for chunk in stream:
    delta = chunk.choices[0].delta.content if chunk.choices else None
    if delta:
        print(delta, end="")

cURL Example

POST/v1/chat/completions
curl -X POST "https://api.hebbrix.com/v1/chat/completions" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "model": "gpt-5-nano",
  "collection_id": "YOUR_COLLECTION_ID",
  "user_id": "user-123",
  "messages": [
    {
      "role": "user",
      "content": "What are my preferences?"
    }
  ],
  "features": {
    "memory": true,
    "learning": false
  }
}'

Consent, learning and retries

Memory learning requires both features.memory and features.learning. Opt-out returns memory_learning.status: disabled. Chat history has a separate retention policy; this switch is not a no-storage promise for conversation history.

When queued, poll memory_context.memory_learning.poll_url, canonically/v1/memory-jobs/{job_id}, until completed or failed. Completion includes learned memory IDs. The authenticated /v1/memories/jobs/{job_id} path is a compatibility alias. Do not assume a returned answer means extraction is already searchable.

Within an account, collection, end-user and agent scope, learning jobs wait for earlier non-terminal jobs. Session and run IDs are provenance, not separate current-truth owners. Deferred profile writes reject retired source memories and older conflicting source events. Poll both jobs before checking a rapid update; a queued update does not change the current answer immediately, and a failed job is not a successful correction.

Use a stable Idempotency-Key for retries of the same request. A timeout may have occurred after side effects; do not create a new key to retry blindly. Non-streaming completed responses may be replayed; streams are not replayable and a duplicate key returns 409. Server deadlines return 504 before response headers, or an error event after a stream has started.

Grounding modes follow search evidence semantics. Profile facts are separate prompt context and can support a response when memories_used is zero. Neither soft nor off permits superseded or cross-tenant evidence.

Default personal recall with no supplied memory, profile or user statement can return an explicit missing-information answer before model generation. Prior assistant claims, greetings and questions are not personal evidence. Introductions remain answerable from the supplied message. This finite guard is not a general semantic verifier; tool and structured-output contracts keep their caller-owned generation path. Inspect each requested fact separately, especially when only part of a question has evidence.

Memory Context in Response

Each response includes a memory_context object showing which memories were used. relevance_score is a retrieval ranking signal, not a truth probability. Scores may be low even for useful paraphrases; they are not universally calibrated. Inspect the retrieval grounding receipt separately, and do not treat a low score as evidence that a stored safety constraint does not exist. For multi-part questions, the top-level grounding.facets receipt distinguishes evidence for each part from the wider candidate context. A name fact cannot establish allergy coverage. grounding_status is not_verified because this endpoint does not independently verify its generated answer. profile_facts lists the selected facts actually injected:

Response memory_context
{
  "memory_context": {
    "memories_used": 1,
    "profile_injected": false,
    "profile_facts": [],
    "grounding_status": "not_verified",
    "grounding_score": null,
    "memory_learning": {"status": "disabled"},
    "relevance_score": 0.89,
    "processing_time_ms": 45,
    "memories": [
      {
        "id": "mem_abc123",
        "content": "User prefers dark mode",
        "score": 0.95
      }
    ]
  }
}
Ask the docs
reading · this page

Hi! I'm the Hebbrix docs assistant. Ask me anything about this page: setup, code examples, endpoints, pricing, or integrations.