Core operations
Search memories
Find the stored memories closest in meaning to a question, best match first, in one call.
search() takes a question or a few keywords. Each hit (one memory in the results) carries a
score (how close it is) and a snippet
(the start of the stored text).
For your agent's prompt, start with get_context.
It returns a ready-to-use block of the most relevant
facts and memories. Use search when you want the stored memories
themselves, ranked and scored.
Quick start
You need Python 3.9 or later, pip install korely-memory, and
an API key (kor_live_...).
Get a free API key (Quickstart).
For Node.js 18 or later, run npm install korely-memory; the
Node example is under Reference. The examples are
checked with version 0.1.28 for Python and 0.1.17 for Node.js.
The code writes one memory for the end user customer-4812, then searches that end user's memories with a question.
from korely_memory import Korelykorely = Korely(api_key="kor_live_...")korely.add("Northwind Hosting costs 50 euro per month since the June upgrade.", user_id="customer-4812")for hit in korely.search("How much does Northwind Hosting cost per month?", user_id="customer-4812", limit=5): print(hit.score, hit.snippet)
You see one line: a score around 0.7, then the sentence you wrote. The
Python SDK returns the list of hits directly; the REST API returns
{"results": [...]}.
A memory is searchable right after add(), even while Korely
is still running extraction on it
(status processing). If you add the same text twice, for example by running this code
again, you get two hits with the same score.
If you see nothing, check that user_id is spelled exactly the
same in both calls (case counts) and that both calls use the same key: a
key reads only the memories of its project.
Terms
The Glossary defines the words used across the docs. These are the ones specific to this page.
min_score: an optional floor from 0 to 1; hits below it are dropped.
Reference
Parameters, response, errors and limits, for when you build your integration.
How it works
flowchart LR
Q([query]) --> EMB[Turn query<br/>into an embedding]
EMB --> VEC[Compare with each<br/>memory's embedding]
VEC --> R([closest memories first]) Search compares meanings and returns the closest memories. It does not match exact words and it does not return facts. No chat model reads or writes anything at search time: Korely turns the query into an embedding (see the Glossary) with a small model on its own server.
Request
Endpoint: POST /v1/memories/search. SDK: korely.search(query, *, user_id=None, agent_id=None, run_id=None, metadata=None, limit=None, min_score=None, exclude_sessions=False).
| Parameter | Type | Notes |
|---|---|---|
query | string | Required, 1 to 2,000 characters: a short phrase or a full question. Blank or whitespace only returns 422. |
user_id | string | Optional, 1 to 255 characters. Limits the search to one end user. Without it, the search covers every end user the key can read; a confined key covers only the end users it is confined to. An empty string returns 422: leave the field out instead. |
agent_id | string | Optional, max 255 characters. Only memories written by that agent. Without it, all agents. |
run_id | string | Optional, max 255 characters. Only memories of that run or session. |
metadata | object | Optional. Only memories whose stored metadata matches every key you pass. Values are compared as text, so 5 and "5" are the same. Example: a memory saved with {"source": "slack", "tier": 5} matches {"tier": "5"}, not {"source": "email"}. Use plain values (text, numbers, true, false, null); an object, array or NaN returns 422. At most 32 keys and about 8 KB of JSON (8,192 bytes). |
limit | integer | Hits to return, 1 to 50. Default 15. |
min_score | number | 0 to 1. Drops hits scoring below it. Absent: no floor. See A floor on the score. |
exclude_sessions | boolean | true hides memories of kind session, the work logs a coding assistant saves. Default false. |
Any other field, such as top_k or filters, returns 422 invalid_request.
Filters
Filters add up: each one narrows the search. Here only memories of
customer-4812, written by infra-bot, with
source set to slack, come back.
results = korely.search( "northwind pricing", user_id="customer-4812", agent_id="infra-bot", metadata={"source": "slack"},)
The Quick start memory has no agent_id and no metadata: to see
a hit here, first add a memory with those values.
Pass user_id in customer-facing agents.
Without it, one customer's chat can surface another customer's memories.
Example
from korely_memory import Korely
korely = Korely(api_key="kor_live_...")
results = korely.search( "northwind pricing", user_id="customer-4812", limit=5,)
for hit in results: print(hit.id, hit.score, hit.snippet) # mem_8f2c1a4d9b3e47a6b05e2c7d1f3a9e84 0.573 Northwind Hosting costs 50 euro per month since the June upgrade. # mem_3c77d94e1a7b4f2c8d05b9a63e1f7c20 0.1579 I just upgraded to the Advanced plan.Response
{ "results": [ { "id": "mem_8f2c1a4d9b3e47a6b05e2c7d1f3a9e84", "score": 0.573, "snippet": "Northwind Hosting costs 50 euro per month since the June upgrade.", "user_id": "customer-4812", "agent_id": "infra-bot", "metadata": { "source": "slack" } }, { "id": "mem_3c77d94e1a7b4f2c8d05b9a63e1f7c20", "score": 0.1579, "snippet": "I just upgraded to the Advanced plan.", "user_id": "customer-4812", "agent_id": null, "metadata": {} } ]}
The ids are illustrative. Two keywords such as "northwind pricing" score
lower than a full question: 0.573 here, about 0.7 in the Quick start. With
no match the reply is {"results": []}; there is no
total field.
Response fields
| Field | Type | Description |
|---|---|---|
results | array | The hits, best score first. |
results[].id | string | Memory ID. korely.get(id) returns the full text and the facts that are true now. |
results[].score | float | How close the memory is to the query, rounded to 4 decimals. At most 1; higher is closer; it can dip slightly below 0. |
results[].snippet | string | Up to the first 280 characters of the memory, ready for a prompt or a UI. |
results[].user_id | string or null | The end user the memory belongs to. |
results[].agent_id | string or null | The agent that wrote the memory, or null. |
results[].metadata | object | The metadata stored with the memory; an empty object if none. |
A floor on the score
Search always returns the closest memories, even when none of them
answers the question. Pass min_score to drop weak hits:
{ "query": "what is the customer's dog called?", "user_id": "customer-4812", "min_score": 0.3}
If no memory reaches 0.3, the reply is
{"results": []}. With memories about hosting and plans only,
the best hit for this question scores about 0.24, so the list is empty. With
0.2, that unrelated memory would pass. A min_score of
0 drops the negative scores. Read your own scores
before you choose a floor.
Fetching full content
The snippet stops at 280 characters. For a close hit, fetch the whole memory.
results = korely.search("northwind pricing", user_id="customer-4812", limit=3)
# Pull full content for the top hit; pick the threshold from your own scoresif results and results[0].score > 0.5: memory = korely.get(results[0].id) print(memory.content) # Northwind Hosting costs 50 euro per month since the June upgrade.Errors
Every error body carries code (stable: branch on it),
message (for a person) and detail (extra data,
such as the wrong fields of a 422 or resets_at of
a quota 429). The SDKs raise an APIError
(from korely_memory import APIError in Python,
import { APIError } from "korely-memory" in Node.js).
Catch it and read err.status and err.code: they
match the table.
| Status | Code string | When it occurs |
|---|---|---|
401 | invalid_key | The Authorization header is missing or malformed, or the key is unknown, revoked or expired. The message starts with "Invalid or missing API key" and says why. |
403 | forbidden | The key lacks the memories:read permission (a normal key has it), or it is a confined key and the user_id is not one of its end users. |
413 | payload_too_large | The request body is larger than the size limit. |
422 | invalid_request | Validation failed: query missing, blank or too long; user_id empty; limit outside 1 to 50; min_score outside 0 to 1; a bad metadata value; an unknown field. The message names the field that failed, e.g. "query: Field required". |
429 | quota_exceeded | Your monthly queries are used up: wait for the date in resets_at (00:00 UTC on the 1st), or upgrade. resets_at is in detail, with limit and used; there is no Retry-After header. |
429 | rate_limit_exceeded | Too many requests in a short time (a minute, hour or day): wait the number of seconds in the Retry-After header. |
500 | internal_error | The request failed on our side. Retry. |
503 | search_unavailable | The search could not run right now: the service that computes embeddings is busy or did not answer. Under a burst from one account a search first waits its turn, up to 20 seconds. Retry after the seconds in the Retry-After header. It does not mean there are no memories. |
503 | service_paused | Korely itself has paused the service for a while; this is not about your account. Retry after the seconds in the Retry-After header (one hour): retrying sooner changes nothing. |
503 | unavailable | The database did not answer in time. Retry later. |
Quota
Two counters apply, both shown per plan on the Pricing page.
- Monthly queries: each accepted search is one read, which counts one query (writes are counted apart). A search refused with
403or422, or ended in503 search_unavailable, does not count. - Rate limit (requests per minute, hour and day): counts every request, refused ones included.
Details
- Languages and length. A question in Italian finds memories written in English; a memory's embedding uses at most its first 8,000 characters, so text past them does not change its score.
- Several wrong fields. A
422message names the first and adds "(and N more)";detaillists them all. - Ties. Equal scores come back in id order, not newest first; identical memories are not merged.
Related
- Add a memory: store the memories you search.
- Delete a memory: a deleted memory no longer appears in search.
- List memories: all of a user's memories, newest first.
- API reference for every
/v1endpoint.