Stores and Schema
This page presents the core store abstractions and schema controls used by the Oracle Agent Memory SDK.
Store API
class oracleagentmemory.core.OracleMemoryStore
Bases: IMemoryStore
Common store interface used by OracleAgentMemory.
A store implementation is responsible for persisting text records and performing similarity search over them. Both synchronous and asynchronous entry points are defined so higher-level APIs can expose matching sync/async surfaces without duplicating store-specific logic.
method search (abstract)
Search records by similarity.
- Parameters:
- query
str | None– Natural language query. Must be provided whenquery_vectoris omitted. - query_vector
list[float] | None– Optional precomputed query embedding. Exactly one ofqueryandquery_vectormust be provided. - k
int– Maximum number of results to return. Explicit values must be at least1. - thread_id
str | None– Optional thread scope. - user_id
str | None– Optional user and agent scope filters. - agent_id
str | None– Optional user and agent scope filters. - exact_user_match
bool– Whether each provided scope identifier must be matched exactly. - exact_agent_match
bool– Whether each provided scope identifier must be matched exactly. - exact_thread_match
bool– Whether each provided scope identifier must be matched exactly. - record_types
set[str] | None– Optional set of record types to include. - metadata_filter
dict[str, Any] | None– Optional partial metadata mapping. A record matches only when its stored metadata contains all requested keys and values. Nested dictionaries are matched recursively. List values are matched by exact equality rather than recursive subset matching, so list order and length must also match.
- query
- Returns:
(record, distance)pairs sorted by increasing distance. - Return type: list[tuple[Record, float]]
- Raises:
ValueError – If
kis less than1.
Examples
store.add(
["Searchable abstract memory"],
record_type="memory",
record_ids="mem-search-abstract-docs",
)
['mem-search-abstract-docs']
store.search("Searchable", 1, record_types={"memory"})[0][0].id
'mem-search-abstract-docs'
Filter on a scalar metadata value:
store.add(
["pizza release"],
record_type="memory",
record_ids="mem-search-meta-source-docs",
metadata={"source": "slack"},
)
['mem-search-meta-source-docs']
any(
record.id == "mem-search-meta-source-docs"
for record, _ in store.search(
"pizza",
k=3,
metadata_filter={"source": "slack"},
)
)
True
Filter on nested metadata:
store.add(
["pizza review"],
record_type="memory",
record_ids="mem-search-meta-review-docs",
metadata={"review": {"status": "open"}},
)
['mem-search-meta-review-docs']
any(
record.id == "mem-search-meta-review-docs"
for record, _ in store.search(
"pizza",
k=3,
metadata_filter={"review": {"status": "open"}},
)
)
True
Match a list value exactly, including order:
store.add(
["pizza tags"],
record_type="memory",
record_ids="mem-search-meta-tags-docs",
metadata={"tags": ["prod", "urgent"]},
)
['mem-search-meta-tags-docs']
any(
record.id == "mem-search-meta-tags-docs"
for record, _ in store.search(
"pizza",
k=3,
metadata_filter={"tags": ["prod", "urgent"]},
)
)
True
Oracle DB Store
class oracleagentmemory.core.OracleDBMemoryStore
Bases: OracleMemoryStore
Database-backed persistence for messages, memories, and actor profiles.
Create an Oracle DB store.
- Parameters:
- embedder
IEmbedder | None– Embedder used for vectorized record types. May beNonewhen callers always provide precomputed vectors inadd,update, andsearch. - pool
Any– Oracle DB connection or pool. Passing a raw connection enables single-session mode for this store instance: concurrent store calls are serialized locally to preserve the row-lock and transaction assumptions used by write operations. Use a connection pool for concurrent requests. - schema_policy
SchemaPolicy | str– Schema setup mode. Defaults to requiring an existing, up-to-date managed schema and performing no DDL changes. UseSchemaPolicy.CREATE_IF_NECESSARYto fill missing objects, orSchemaPolicy.RECREATEto drop and recreate managed objects. - vector_dim
int– Embedding dimension for schema creation when VECTOR columns are created. - table_name_prefix
str– Optional prefix added to managed table/index names.
- embedder
method add_agent
Add an agent profile record.
- Parameters:
- agent_id
str– Agent identifier. - information
str– Free-form information about the agent. This text is stored as the profile content and used to build the profile embedding row inRECORD_CHUNKS.
- agent_id
- Returns: Identifier of the inserted agent profile record.
- Return type: str
Notes
Agent profile records are unscoped. The inserted public record
identifier is the same value passed as agent_id.
Examples
store.add_agent("a-docs-agent", "Support assistant")
'a-docs-agent'
method add_user
Add a user profile record.
- Parameters:
- user_id
str– User identifier. - information
str– Free-form information about the user. This text is stored as the profile content and used to build the profile embedding row inRECORD_CHUNKS.
- user_id
- Returns: Identifier of the inserted user profile record.
- Return type: str
Notes
User profile records are unscoped. The inserted public record
identifier is the same value passed as user_id.
Examples
store.add_user("u-docs-profile", "Prefers concise answers.")
'u-docs-profile'
method delete
Delete one managed row and its chunk rows by identifier.
- Parameters:
- record_type
str– Record type label to delete. Supported types include"thread","message","memory","guideline","fact","preference","user_profile", and"agent_profile". - record_id
str– Identifier to delete. - cascade
bool– WhenTrue, expand supported top-level targets such as actor profiles to their scoped child rows inside the same transaction. For a user-profile or agent-profile target, this deletes the owned thread rows first, which removes their thread-scoped message and memory-table rows, then deletes any remaining directly actor-scoped messages and memory-like rows (memory,guideline,fact,preference). This scoped cleanup still runs when the matching profile row is already absent.
- record_type
- Returns:
Number of requested top-level targets removed, typically
0or1. Cascaded child rows are not counted separately, so this may still be0when a missing actor profile triggers scoped cleanup. - Return type: int
Notes
The operation runs inside one transaction. When cascade is enabled
for a supported top-level target, the profile delete and all scoped
child deletes are committed or rolled back together.
Examples
store.add(["Delete me"], record_type="memory", record_ids="mem-delete-docs")
['mem-delete-docs']
store.delete("memory", "mem-delete-docs")
1
method delete_thread
Delete a thread and its associated stored rows.
- Parameters:
thread_id
str– Thread identifier whose rows should be removed, including the thread row, dependent child rows, and explicit chunk-row cleanup. - Returns:
Number of deleted thread rows (
0or1). - Return type: int
Notes
Use this operation when you need thread-scoped cascading cleanup. In
the DB-backed store, deleting the thread removes the managed thread
row together with associated message and memory rows, plus the
record-chunk rows maintained for retrieval. This is broader than a
message-level delete, which removes only the raw message row. Thread
deletion removes the dependent message and memory rows referenced from
THREAD together with the matching RECORD_CHUNKS rows in the
same transaction.
Examples
store.delete_thread("c1")
0
method get
Retrieve a stored record by identifier.
- Parameters:
- record_type
str– Record type label resolving to a managed row, such as"message","memory","guideline","fact","preference","user_profile", or"agent_profile". - record_id
str– Identifier to look up.
- record_type
- Returns:
Populated record with decoded metadata when found, otherwise
None. - Return type: Record | None
Examples
store.add(["Remember this"], record_type="memory", record_ids="mem-get-docs")
['mem-get-docs']
store.get("memory", "mem-get-docs").id
'mem-get-docs'
method list
Enumerate persisted records for a record type.
- Parameters:
- record_type
str– Record type label (e.g."message","memory","guideline","fact","preference","user_profile", or"agent_profile"). - limit
int | None– Optional maximum number of records to return. When omitted, the store uses its default listing cap. PassNoneto disable that cap and return every matching record. - thread_id
str | None– Exact thread-scope filter. When omitted, no filtering is applied. When set toNone, only rows whosethread_idis SQLNULLare returned. Unscoped record types ignore this filter. - user_id
str | None– Exact user-scope filter. When omitted, no filtering is applied. When set toNone, only rows whoseuser_idis SQLNULLare returned. Unscoped record types ignore this filter. - agent_id
str | None– Exact agent-scope filter. When omitted, no filtering is applied. When set toNone, only rows whoseagent_idis SQLNULLare returned. Unscoped record types ignore this filter. - metadata_filter
dict[str, Any] | None– Metadata filter. When omitted, no filtering is applied. When set toNone, only records with no stored metadata are returned. When set to a dict, stored metadata must contain all requested keys and values. Nested dictionaries are matched recursively. List values are matched by exact equality rather than recursive subset matching, so list order and length must also match.
- record_type
- Returns: Records ordered by insertion order.
- Return type: list[Record]
Notes
"user_profile" and "agent_profile" are unscoped record types.
For those record types, thread_id, user_id, and agent_id
are ignored and actor identity remains in record.id.
Examples
store.add(
["First listed", "Second listed"],
record_type="memory",
record_ids=["mem-list-docs-1", "mem-list-docs-2"],
)
['mem-list-docs-1', 'mem-list-docs-2']
[record.id for record in store.list("memory", limit=2)]
['mem-list-docs-1', 'mem-list-docs-2']
store.add_user("u-list-docs", "Prefers concise answers.")
'u-list-docs'
any(
record.id == "u-list-docs"
for record in store.list("user_profile", user_id=None, limit=10)
)
True
method list_thread_messages
Return persisted messages for a thread.
- Parameters:
- thread_id
str– Thread identifier whose messages should be returned. - last_n
int | None– Optional number of most-recent messages to return.
- thread_id
- Returns: Message records ordered by insertion order.
- Return type: list[MessageRecord]
Examples
store.list_thread_messages("c1")
[]
method search
Search records by similarity.
- Parameters:
- query
str | None– Natural language query. Must be provided whenquery_vectoris omitted. - query_vector
list[float] | None– Optional precomputed query embedding. Exactly one ofqueryandquery_vectormust be provided. - k
int– Maximum number of results to return. Explicit values must be at least1. - thread_id
str | None– Optional thread-scope identifier.exact_thread_match=Falseleaves the thread dimension unconstrained.exact_thread_match=Truematches the providedthread_idexactly. Ifthread_id=None, it matches only records unscoped on the thread dimension. - user_id
str | None– Optional user and agent scope identifiers. The correspondingexact_*_match=Falseflag leaves that dimension unconstrained.exact_*_match=Truematches the provided ID exactly. If the ID isNone, it matches only records unscoped on that dimension. - agent_id
str | None– Optional user and agent scope identifiers. The correspondingexact_*_match=Falseflag leaves that dimension unconstrained.exact_*_match=Truematches the provided ID exactly. If the ID isNone, it matches only records unscoped on that dimension. - exact_user_match
bool– Whether each scope identifier must be matched exactly.Falseleaves that dimension unconstrained.Truematches the provided value exactly. If that value isNone, it matches only unscoped records on that dimension. - exact_agent_match
bool– Whether each scope identifier must be matched exactly.Falseleaves that dimension unconstrained.Truematches the provided value exactly. If that value isNone, it matches only unscoped records on that dimension. - exact_thread_match
bool– Whether each scope identifier must be matched exactly.Falseleaves that dimension unconstrained.Truematches the provided value exactly. If that value isNone, it matches only unscoped records on that dimension. - record_types
set[str] | None– Optional set of searchable record types to include. When omitted, the DB search covers messages, memory-table rows, and actor profiles. Actor profiles contribute theirinformationpayload, while message and memory rows contribute theircontentpayload. During search, profile record types use their actor identifier for the applicable scope dimension while the remaining scope dimensions behave asNone. - metadata_filter
dict[str, Any] | None– Optional partial metadata mapping. A record matches only when its stored metadata contains all requested keys and values. Nested dictionaries are matched recursively. List values are matched by exact equality rather than recursive subset matching, so list order and length must also match.
- query
- Returns:
(record, distance)pairs sorted by increasing distance. - Return type: list[tuple[Record, float]]
- Raises:
ValueError – If
kis less than1.
Examples
store.add(
["pizza preference"],
record_type="memory",
record_ids="mem-search-docs",
thread_ids="c-search-docs",
)
['mem-search-docs']
results = store.search(
"pizza",
1,
thread_id="c-search-docs",
exact_thread_match=True,
record_types={"memory"},
)
results[0][0].id
'mem-search-docs'
Filter on a scalar metadata value:
store.add(
["pizza release"],
record_type="memory",
record_ids="mem-search-meta-source-docs",
metadata={"source": "slack"},
)
['mem-search-meta-source-docs']
any(
record.id == "mem-search-meta-source-docs"
for record, _ in store.search(
"pizza",
k=3,
metadata_filter={"source": "slack"},
)
)
True
Filter on nested metadata:
store.add(
["pizza review"],
record_type="memory",
record_ids="mem-search-meta-review-docs",
metadata={"review": {"status": "open"}},
)
['mem-search-meta-review-docs']
any(
record.id == "mem-search-meta-review-docs"
for record, _ in store.search(
"pizza",
k=3,
metadata_filter={"review": {"status": "open"}},
)
)
True
Match a list value exactly, including order:
store.add(
["pizza tags"],
record_type="memory",
record_ids="mem-search-meta-tags-docs",
metadata={"tags": ["prod", "urgent"]},
)
['mem-search-meta-tags-docs']
any(
record.id == "mem-search-meta-tags-docs"
for record, _ in store.search(
"pizza",
k=3,
metadata_filter={"tags": ["prod", "urgent"]},
)
)
True
method update
Update stored record content, chunk embeddings, and metadata values.
- Parameters:
- record_type
str– Record type label of the row being modified (for example"message","memory","guideline","fact","preference","user_profile", or"agent_profile") - record_id
str– Identifier of the stored row to update. - text
str | None– Optional replacement text persisted in thecontentcolumn. PassNoneto clear the stored text and clear the stored embedding. Pass onlyNoneor omitted semantic arguments in the same call. Pass""to preserve explicit empty content while clearing any chunk embedding for that record. When omitted, the existing content is left unchanged. - index_text
str | None– Optional embedding-only payload. When omitted,textis embedded. - embedding
list[float] | ndarray | None– Optional precomputed embedding vector. When provided, this is used directly and no embedder call is made. PassNoneto clear the stored embedding. - metadata
dict[str, Any] | None– Optional metadata mapping serialized to JSON and stored inmetadata.
- record_type
- Returns:
Number of updated rows (
0or1). Returns0when no logical record matchesrecord_typeandrecord_id. - Return type: int
- Raises:
ValueError – If
record_typeis unsupported, if no update payload is provided, or if the semantic update arguments are incompatible.
Examples
store.add(["Original note"], record_type="memory", record_ids="mem-update-docs")
['mem-update-docs']
store.update("memory", "mem-update-docs", text="Updated note")
1
store.get("memory", "mem-update-docs").content
'Updated note'
Schema Policy
class oracleagentmemory.core.SchemaPolicy
Bases: str, Enum
Schema creation policy for Oracle DB stores.
REQUIRE_EXISTING
Validate that the full managed schema already exists and is up-to-date. Do not create or modify DB objects.
CREATE_IF_EMPTY
If no managed objects exist, bootstrap schema. If objects already exist, require a complete and up-to-date managed schema.
CREATE_IF_NECESSARY
Create only missing managed objects, including metadata.
RECREATE
Drop and recreate all managed schema objects. This is destructive.