Skip to content

Latest commit

 

History

History

oracle

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Agent Framework Oracle vector store

An alpha connector for storing and searching native VECTOR columns in Oracle AI Database 26ai. OracleCollection implements async batch CRUD and vector search; OracleStore shares a client across collections; OracleSettings describes the connection and pool settings resolved through Agent Framework.

Installation and setup

pip install agent-framework-oracle --pre

Requires Python 3.10+, Oracle AI Database 26ai with COMPATIBLE set to 23.4.0 or higher, python-oracledb 2.2.x or 3.x, and permission to create/drop tables in the connected user's schema. The connector uses the driver's async Thin-mode API; it does not initialize the Thick client or provision a database. It does not create or alter schemas, vector indexes, or existing tables.

For username/password authentication, set ORACLE_DSN (for example localhost:1521/FREEPDB1), ORACLE_USER, and ORACLE_PASSWORD, or pass dsn, user, and password to either constructor. Typed driver settings can also be supplied with the pool_parameters mapping. Settings are resolved in order: named dsn/user/password argument > pool_parameters > selected .env file > process environment > connector pool defaults. A .env file is read only when env_file_path is specified; the selected file must exist, and env_file_encoding overrides UTF-8. password accepts str or Agent Framework SecretString and is unwrapped only when opening a connection.

Named connection values must be nonempty when supplied, but their presence is not required by the connector. Authentication and connection-descriptor completeness are validated by python-oracledb, allowing alternatives such as access_token, externalauth, or host with service_name/sid.

Explicit pool_parameters keys are forwarded when they are accepted by the installed python-oracledb version, including newly added driver options not yet declared by the open OracleSettings typed dictionary. This preserves editor discovery for known options while allowing forward-compatible keys. Unsupported names and typos raise an error; unrecognized ORACLE_ environment variables remain ignored.

Recognized scalar oracledb.create_pool_async() options can also be supplied as ORACLE_ settings. The prefix is removed, the remainder is converted to the driver's lowercase keyword name, and boolean, integer, and floating-point values are converted before the pool is created. Password-like values remain masked until they are passed to the driver. For example:

ORACLE_DSN=localhost:1521/FREEPDB1
ORACLE_USER=example
ORACLE_PASSWORD=database-password
ORACLE_WALLET_LOCATION=/path/to/wallet
ORACLE_WALLET_PASSWORD=wallet-password
ORACLE_MIN=1
ORACLE_MAX=8
ORACLE_HOMOGENEOUS=false

The connector uses min=0 and max=4 when those options are not configured. Unrecognized ORACLE_ variables are ignored. Options that require callbacks, classes, collections, or SSL context objects are not loaded from text settings; pass them through pool_parameters or use a configured client.

Alternatively, pass a configured oracledb.AsyncConnection or oracledb.AsyncConnectionPool as client for advanced authentication. A supplied client cannot be combined with connection settings and remains caller-owned. A connector-created pool opens on first use and closes on close() or async context exit. A collection obtained from a store borrows its client; closing that collection does not close the store. The store must remain open while its collections are used.

Writes on pooled connections (both connector-owned and caller-supplied pools) are committed on success and rolled back on failure. Writes to a supplied AsyncConnection are left in the caller's transaction; the caller must commit or roll back. Oracle DDL commits independently of the surrounding transaction. Batch upserts on a borrowed connection may leave partial pending work on failure, so roll it back before reuse.

ensure_collection_exists() leaves an existing table unchanged and does not validate its schema; use a matching definition or create a new table. It never migrates data or changes existing indexes.

Usage

import asyncio
from dataclasses import dataclass
from typing import Annotated

from agent_framework import Filter, VectorStoreField, vectorstoremodel
from agent_framework_oracle import OracleStore


@vectorstoremodel(collection_name="articles")
@dataclass
class Article:
    id: Annotated[str, VectorStoreField("key")]
    text: Annotated[str, VectorStoreField("data")]
    embedding: Annotated[list[float] | None, VectorStoreField("vector", dimensions=3)] = None


async def main() -> None:
    async with OracleStore() as store:
        collection = store.get_collection(Article)
        await collection.ensure_collection_exists()
        await collection.upsert([Article("one", "Oracle vector search", [1, 0, 0])], generate_vectors=False)
        results = await collection.search(
            vector=[1, 0, 0], filter=Filter("text", "contains_text", "Oracle"), top=3
        )
        async for result in results:
            print(result["record"].text, result["score"])


asyncio.run(main())

Pass generate_vectors=False for precomputed vectors, or configure an embedding_generator for local generation. get() excludes vector columns by default; pass include_vectors=True to restore them. get(keys) preserves requested key order and duplicates, omitting missing keys; filtered retrieval supports top, skip, and order_by. Both get() and search() execute portable filters and paging in Oracle. The runnable sample creates and deletes a unique test table.

Capabilities and limits

  • A collection is one table in the current user's schema. Keys are application-provided strings (up to 512 UTF-8 bytes), signed 64-bit integers, or UUIDs; automatically generated keys are not supported.
  • Multiple nullable native vector columns are supported. Vector fields may declare float/float32 (Oracle FLOAT32), float64 (FLOAT64), or int8 (INT8); omitted element types use FLOAT32. Dimensions must be 1–65535. Supplied vectors must be dense finite numeric sequences with the declared dimensions. Binary and sparse vectors are not supported.
  • Scalar data fields support str (up to 4000 UTF-8 bytes), int (signed 64-bit), float (BINARY_DOUBLE), and bool (stored as NUMBER(1,0)). Oracle converts empty strings to NULL, so this connector rejects empty string values rather than changing their meaning. JSON fields, nested paths, provider annotations, data/full-text/vector indexes, and schema migration are not supported.
  • Search uses Oracle VECTOR_DISTANCE with an explicit metric. The default is COSINE distance; cosine_similarity, Euclidean distance, dot product, negative dot product, squared Euclidean distance, and Manhattan distance are also available. Scores are native metric values, not probabilities. For distances a score_threshold is a maximum; for similarities/dot product it is a minimum. The cutoff is applied in SQL before paging. No ANN indexes are created or managed; Oracle may use an existing index if the table already has one. There is no exact/approximate toggle, server-side embedding generation, or keyword-hybrid search. Index-selected approximate searches may return fewer than the requested number of results.
  • Portable filters support scalar equality (including NULL and boolean distinctions), in/not_in, numeric ranges, is_null, is_not_null, exists, literal text contains_text/starts_with/ends_with, and AND/OR/NOT. Finite Decimal values are supported for exact numeric equality and membership; malformed UUID filter values compare as unequal. Collection membership and nested filters are rejected. Ordered filters on integer fields reject non-integral float operands; ordered Decimal operands are not supported. String comparison follows the configured Oracle collation. Input values are bound; identifiers are checked and quoted as individual names.

Opt-in database tests

The unit tests require no Oracle server. To run the live integration test, provide all three ORACLE_TEST_DSN, ORACLE_TEST_USER, and ORACLE_TEST_PASSWORD for an explicitly designated disposable Oracle AI Database 26ai schema where the user can create and drop tables:

cd python
uv run --package agent-framework-oracle pytest packages/oracle/tests \
  -m integration

Without those variables, the integration test skips; it never falls back to ordinary application credentials. The fixture creates a unique table and deletes only that table.

Documentation