(namespace, path): the same path can
exist in two bags, and a write in one bag does not see the other.
Here tone.md exists twice. ("support-bot", "tone.md") and
("sales-bot", "tone.md") are two different files.
Bags are visible to the API key, across every user_id that key acts for. Two
clients built with the same key and different user_id values share the same
memory files. client.memory does not send user_id. Chat and threads still
use the client’s user_id.
There is no create_namespace call. The first successful create() against a
new name brings that bag into existence. list_namespaces() then includes the
name. get and delete on a path that is not in that bag raise
NotFoundError. They do not create the bag.
For the HTTP contract, see Memory on the platform.
For every signature, see client.memory.
Create, list, and read
namespace is required on create, get, update, and delete. Omitting it
is a TypeError. list() with no filter returns every file visible to this
API key. Pass namespace= to keep one bag.
purpose is why the file exists. The agent reads it. content is the body,
and "" is allowed. version on the returned file is an opaque token for the
next write.
list() returns the most recently updated files first. Without a filter, the
same path can appear several times, once per namespace, so always key a file
by (namespace, path). list_namespaces() has no guaranteed order. There is
no pagination or sort argument.
Size limits
These limits still apply and are enforced by the API, not by the SDK:purposeis trimmed, then must be 1 to 100 characters.contentis at most 1 MiB.- A file named
User.mdhas a shorter content limit than other files. pathhas at most one folder segment (see Rules the SDK checks locally).
Update and delete
update is partial. Omitted fields stay as they are. Pass at least one of
content or purpose. Pass the version from your last read unchanged.
content=None or purpose=None raises InvalidParams before any request.
The API would ignore a JSON null and still return 200. Omit the argument to
keep a field. There is no way to clear a field once it is set.
delete returns None on success (HTTP 204). It is not idempotent: deleting
a path that is already gone raises NotFoundError.
list_namespaces() once it no longer has a file.
Attach a thread to a bag
chat.start accepts an optional memory_namespace. The value is frozen at
start. chat.send does not accept it. Passing it to send is a TypeError.
options, next to agent_id
and user_id. When you omit it, options has no memory_namespace key. It
is not sent as null. options.user_id still scopes the thread, not the bag.
Thread, ThreadSummary, and Message do not expose the thread’s namespace.
Keep the name you passed to start.
You cannot force “no memory” on an agent that already has a namespace.
Omitting
memory_namespace uses the agent’s default. When you pass a value to
start, it wins over the agent’s. The SDK does not read or write the agent’s
own namespace. That setting lives on the platform.memory_namespace on
every start where you expect memory.
Isolate your users
A namespace is shared by everyone in the organization who uses it, and the client’suser_id is not part of the scope. To keep end users apart, put an
identifier in the name yourself:
Rules the SDK checks locally
These fail withInvalidParams before any HTTP request:
namespaceis astrof at most 128 characters. Length 128 is accepted. Length 129 is rejected. The string is not trimmed.pathmay contain at most one/."tone.md"and"preferences/tone.md"are accepted."a/b/tone.md"is rejected. The API would answer 422"Maximum folder depth is 1". The SDK fails first.updatewith neithercontentnorpurpose, or with an explicitNone, is rejected.
version raises ConflictError (409). A malformed
version is not detected locally. The API answers 422 and the SDK raises
APIError, not ConflictError and not InvalidParams.
Migrate from per-user memory
Memory used to be scoped to the client’suser_id. It is now scoped to a
namespace you choose. client.user_id is still required, and it is still
applied to chat and threads.
MemoryFileOut and MemoryFileSummaryOut each include namespace. Use the
value the API returns. Do not assume a bag named default.
Files written before namespaces existed are kept. On the platform they sit in
a namespace named {user_id}::default, one per former user. Pass that exact
string as namespace to read them, or copy them to a namespace you choose.
Threads that were already running keep reading that same bag when you continue
them. A new thread has no memory until you pass memory_namespace.
Memory requests no longer send user_id. POST /memory sends namespace in
the body. The other memory calls send namespace as a query parameter (list
only when you passed one).