agent-framework-postgres 0.0.0a1__tar.gz → 1.0.0a261002__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,170 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-framework-postgres
3
+ Version: 1.0.0a261002
4
+ Summary: PostgreSQL and pgvector integration for Microsoft Agent Framework.
5
+ Author-email: Microsoft <af-support@microsoft.com>
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Typing :: Typed
18
+ License-File: LICENSE
19
+ Requires-Dist: agent-framework-core>=1.18.0,<2
20
+ Requires-Dist: psycopg[binary, pool]>=3.3.5,<4 ; python_version < '3.15'
21
+ Requires-Dist: psycopg[pool]>=3.3.5,<4 ; python_version >= '3.15'
22
+ Requires-Dist: pgvector>=0.5.0,<0.6
23
+ Project-URL: homepage, https://aka.ms/agent-framework
24
+ Project-URL: issues, https://github.com/microsoft/agent-framework/issues
25
+ Project-URL: source, https://github.com/microsoft/agent-framework/tree/main/python
26
+
27
+ # Agent Framework PostgreSQL / pgvector
28
+
29
+ Store and search vector records in PostgreSQL with this alpha integration for
30
+ [Microsoft Agent Framework](https://learn.microsoft.com/agent-framework/).
31
+ The package uses Psycopg 3 and the official pgvector Python adapter.
32
+
33
+ - **`PostgresCollection`** provides batch upsert, retrieval, deletion, and vector similarity search.
34
+ - **`PostgresStore`** creates collection clients that share a connection pool.
35
+ - **`PostgresSettings`** describes connection settings resolved by Agent Framework.
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ pip install agent-framework-postgres --pre
41
+ ```
42
+
43
+ Requires Python 3.10+, PostgreSQL 13+, and pgvector 0.8.0+.
44
+ Import the connector directly from `agent_framework_postgres`.
45
+ Python 3.10 through 3.14 install Psycopg's binary distribution. Python 3.15+
46
+ uses the pure-Python implementation because binary wheels are not yet
47
+ published, so a system `libpq` installation is required.
48
+
49
+ ## Connection setup
50
+
51
+ Have your database administrator install and enable the `vector` extension and
52
+ provide an existing schema. The extension must be visible through the connection's
53
+ `search_path`. The connector never creates schemas, enables extensions, or changes
54
+ server-wide configuration. `ensure_collection_exists()` explicitly creates the
55
+ table and requested indexes; it requires the corresponding permissions and does
56
+ not migrate existing tables.
57
+
58
+ Set `POSTGRES_CONNECTION_STRING` to a PostgreSQL URI or Psycopg conninfo string,
59
+ or pass `connection_string` to either constructor. Both accept a string or AF
60
+ `SecretString`. Settings precedence is **explicit argument > selected `.env`
61
+ file > environment**. Select a file with `env_file_path` and optional
62
+ `env_file_encoding`; missing or empty connection strings are rejected.
63
+ The `schema` argument defaults to `public`.
64
+
65
+ A connector-created pool is closed by `close()` or an async context manager.
66
+ Alternatively, inject an open Psycopg `AsyncConnection` or `AsyncConnectionPool`
67
+ using `client`; it remains caller-owned and bypasses settings loading.
68
+ Injected clients cannot be combined with connection-string or `.env` options.
69
+ Collections created by a store borrow its pool, so keep the store open while
70
+ using them.
71
+
72
+ ## Example
73
+
74
+ With `POSTGRES_CONNECTION_STRING` configured, create a typed collection and
75
+ search using precomputed embeddings:
76
+
77
+ ```python
78
+ import asyncio
79
+ from dataclasses import dataclass
80
+ from typing import Annotated
81
+
82
+ from agent_framework import Filter, VectorStoreField, vectorstoremodel
83
+ from agent_framework_postgres import PostgresStore
84
+
85
+
86
+ @vectorstoremodel(collection_name="articles")
87
+ @dataclass
88
+ class Article:
89
+ id: Annotated[str, VectorStoreField("key")]
90
+ text: Annotated[str, VectorStoreField("data")]
91
+ embedding: Annotated[list[float] | None, VectorStoreField("vector", dimensions=3)] = None
92
+
93
+
94
+ async def main() -> None:
95
+ async with PostgresStore() as store:
96
+ collection = store.get_collection(Article)
97
+ await collection.ensure_collection_exists()
98
+ await collection.upsert(
99
+ [
100
+ Article("1", "PostgreSQL supports vectors", [1, 0, 0]),
101
+ Article("2", "A travel journal", [0, 1, 0]),
102
+ ],
103
+ generate_vectors=False,
104
+ )
105
+ results = await collection.search(
106
+ vector=[1, 0, 0],
107
+ filter=Filter("text", "contains_text", "PostgreSQL"),
108
+ score_threshold=0.25,
109
+ top=3,
110
+ )
111
+ async for result in results:
112
+ print(result["record"].text, result["score"])
113
+
114
+
115
+ if __name__ == "__main__":
116
+ asyncio.run(main())
117
+ ```
118
+
119
+ Pass `generate_vectors=False` to preserve supplied embeddings. To generate them
120
+ locally, configure an `embedding_generator`. Retrieval excludes embeddings by
121
+ default; use `include_vectors=True` to return them.
122
+
123
+ ## Capabilities and limits
124
+
125
+ The connector supports typed models, string/integer/UUID keys (including generated
126
+ keys), multiple nullable vector columns, storage aliases, and database-side
127
+ filters and paging. Batch writes are transactional; an existing transaction on
128
+ an injected connection remains under the caller's commit control.
129
+
130
+ Vector fields support `float`, `float32`, and `float16` declarations. PostgreSQL
131
+ `vector` storage uses 32-bit floats; `float16` defaults to 16-bit `halfvec`.
132
+ The `postgres.vector_type` provider annotation explicitly selects either storage
133
+ type. Ordinary Python floats and integer-valued elements are accepted and rounded
134
+ to the selected precision; declared `int` and `float64` vector fields are rejected.
135
+
136
+ Storage precision does not determine the model's Python scalar type. The default
137
+ decoder returns ordinary Python floats: use `list[float]` annotations even with
138
+ explicit `float16` or `float32` field metadata. Models annotated with
139
+ `list[numpy.float16]` or `list[numpy.float32]` require a custom `decoder` passed to
140
+ `vectorstoremodel` or `register_vectorstoremodel`. That decoder must reconstruct
141
+ each component with the declared NumPy scalar type and handle omitted vector
142
+ fields when `include_vectors=False`. NumPy is not a connector runtime dependency.
143
+
144
+ Exact search is the default. HNSW and IVFFlat are optional approximate indexes;
145
+ selective filters can reduce their recall. Use
146
+ `operation_options={"exact": True}` when complete recall is required.
147
+ `exact=False` requires an HNSW or IVFFlat field. Result metadata's `approximate`
148
+ flag identifies ANN-permitted query mode, not proof that PostgreSQL used an ANN
149
+ index.
150
+ IVFFlat needs data before index creation: first call
151
+ `ensure_collection_exists(operation_options={"create_indexes": False})`, load
152
+ records, then call `ensure_collection_exists()` again.
153
+ Storage supports up to 16,000 dimensions; ANN indexes support up to 2,000 for
154
+ `vector` and 4,000 for `halfvec`.
155
+
156
+ Scores use the selected metric's units, not probabilities. The default is cosine
157
+ distance, where lower is better and `score_threshold` is a maximum. Cosine
158
+ similarity and dot product use minimum thresholds; negative dot product, L2, and
159
+ L1 distances use maximum thresholds. IVFFlat does not support L1.
160
+
161
+ Keyword/hybrid/full-text search, sparse/binary vectors, nested filter paths,
162
+ schema migration, and server-side embedding generation are not supported.
163
+
164
+ ## Documentation
165
+
166
+ - [Microsoft Agent Framework documentation](https://learn.microsoft.com/agent-framework/)
167
+ - [PostgreSQL documentation](https://www.postgresql.org/docs/current/)
168
+ - [pgvector setup, indexes, and distance functions](https://github.com/pgvector/pgvector)
169
+ - [Psycopg connection pools](https://www.psycopg.org/psycopg3/docs/advanced/pool.html)
170
+
@@ -0,0 +1,143 @@
1
+ # Agent Framework PostgreSQL / pgvector
2
+
3
+ Store and search vector records in PostgreSQL with this alpha integration for
4
+ [Microsoft Agent Framework](https://learn.microsoft.com/agent-framework/).
5
+ The package uses Psycopg 3 and the official pgvector Python adapter.
6
+
7
+ - **`PostgresCollection`** provides batch upsert, retrieval, deletion, and vector similarity search.
8
+ - **`PostgresStore`** creates collection clients that share a connection pool.
9
+ - **`PostgresSettings`** describes connection settings resolved by Agent Framework.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pip install agent-framework-postgres --pre
15
+ ```
16
+
17
+ Requires Python 3.10+, PostgreSQL 13+, and pgvector 0.8.0+.
18
+ Import the connector directly from `agent_framework_postgres`.
19
+ Python 3.10 through 3.14 install Psycopg's binary distribution. Python 3.15+
20
+ uses the pure-Python implementation because binary wheels are not yet
21
+ published, so a system `libpq` installation is required.
22
+
23
+ ## Connection setup
24
+
25
+ Have your database administrator install and enable the `vector` extension and
26
+ provide an existing schema. The extension must be visible through the connection's
27
+ `search_path`. The connector never creates schemas, enables extensions, or changes
28
+ server-wide configuration. `ensure_collection_exists()` explicitly creates the
29
+ table and requested indexes; it requires the corresponding permissions and does
30
+ not migrate existing tables.
31
+
32
+ Set `POSTGRES_CONNECTION_STRING` to a PostgreSQL URI or Psycopg conninfo string,
33
+ or pass `connection_string` to either constructor. Both accept a string or AF
34
+ `SecretString`. Settings precedence is **explicit argument > selected `.env`
35
+ file > environment**. Select a file with `env_file_path` and optional
36
+ `env_file_encoding`; missing or empty connection strings are rejected.
37
+ The `schema` argument defaults to `public`.
38
+
39
+ A connector-created pool is closed by `close()` or an async context manager.
40
+ Alternatively, inject an open Psycopg `AsyncConnection` or `AsyncConnectionPool`
41
+ using `client`; it remains caller-owned and bypasses settings loading.
42
+ Injected clients cannot be combined with connection-string or `.env` options.
43
+ Collections created by a store borrow its pool, so keep the store open while
44
+ using them.
45
+
46
+ ## Example
47
+
48
+ With `POSTGRES_CONNECTION_STRING` configured, create a typed collection and
49
+ search using precomputed embeddings:
50
+
51
+ ```python
52
+ import asyncio
53
+ from dataclasses import dataclass
54
+ from typing import Annotated
55
+
56
+ from agent_framework import Filter, VectorStoreField, vectorstoremodel
57
+ from agent_framework_postgres import PostgresStore
58
+
59
+
60
+ @vectorstoremodel(collection_name="articles")
61
+ @dataclass
62
+ class Article:
63
+ id: Annotated[str, VectorStoreField("key")]
64
+ text: Annotated[str, VectorStoreField("data")]
65
+ embedding: Annotated[list[float] | None, VectorStoreField("vector", dimensions=3)] = None
66
+
67
+
68
+ async def main() -> None:
69
+ async with PostgresStore() as store:
70
+ collection = store.get_collection(Article)
71
+ await collection.ensure_collection_exists()
72
+ await collection.upsert(
73
+ [
74
+ Article("1", "PostgreSQL supports vectors", [1, 0, 0]),
75
+ Article("2", "A travel journal", [0, 1, 0]),
76
+ ],
77
+ generate_vectors=False,
78
+ )
79
+ results = await collection.search(
80
+ vector=[1, 0, 0],
81
+ filter=Filter("text", "contains_text", "PostgreSQL"),
82
+ score_threshold=0.25,
83
+ top=3,
84
+ )
85
+ async for result in results:
86
+ print(result["record"].text, result["score"])
87
+
88
+
89
+ if __name__ == "__main__":
90
+ asyncio.run(main())
91
+ ```
92
+
93
+ Pass `generate_vectors=False` to preserve supplied embeddings. To generate them
94
+ locally, configure an `embedding_generator`. Retrieval excludes embeddings by
95
+ default; use `include_vectors=True` to return them.
96
+
97
+ ## Capabilities and limits
98
+
99
+ The connector supports typed models, string/integer/UUID keys (including generated
100
+ keys), multiple nullable vector columns, storage aliases, and database-side
101
+ filters and paging. Batch writes are transactional; an existing transaction on
102
+ an injected connection remains under the caller's commit control.
103
+
104
+ Vector fields support `float`, `float32`, and `float16` declarations. PostgreSQL
105
+ `vector` storage uses 32-bit floats; `float16` defaults to 16-bit `halfvec`.
106
+ The `postgres.vector_type` provider annotation explicitly selects either storage
107
+ type. Ordinary Python floats and integer-valued elements are accepted and rounded
108
+ to the selected precision; declared `int` and `float64` vector fields are rejected.
109
+
110
+ Storage precision does not determine the model's Python scalar type. The default
111
+ decoder returns ordinary Python floats: use `list[float]` annotations even with
112
+ explicit `float16` or `float32` field metadata. Models annotated with
113
+ `list[numpy.float16]` or `list[numpy.float32]` require a custom `decoder` passed to
114
+ `vectorstoremodel` or `register_vectorstoremodel`. That decoder must reconstruct
115
+ each component with the declared NumPy scalar type and handle omitted vector
116
+ fields when `include_vectors=False`. NumPy is not a connector runtime dependency.
117
+
118
+ Exact search is the default. HNSW and IVFFlat are optional approximate indexes;
119
+ selective filters can reduce their recall. Use
120
+ `operation_options={"exact": True}` when complete recall is required.
121
+ `exact=False` requires an HNSW or IVFFlat field. Result metadata's `approximate`
122
+ flag identifies ANN-permitted query mode, not proof that PostgreSQL used an ANN
123
+ index.
124
+ IVFFlat needs data before index creation: first call
125
+ `ensure_collection_exists(operation_options={"create_indexes": False})`, load
126
+ records, then call `ensure_collection_exists()` again.
127
+ Storage supports up to 16,000 dimensions; ANN indexes support up to 2,000 for
128
+ `vector` and 4,000 for `halfvec`.
129
+
130
+ Scores use the selected metric's units, not probabilities. The default is cosine
131
+ distance, where lower is better and `score_threshold` is a maximum. Cosine
132
+ similarity and dot product use minimum thresholds; negative dot product, L2, and
133
+ L1 distances use maximum thresholds. IVFFlat does not support L1.
134
+
135
+ Keyword/hybrid/full-text search, sparse/binary vectors, nested filter paths,
136
+ schema migration, and server-side embedding generation are not supported.
137
+
138
+ ## Documentation
139
+
140
+ - [Microsoft Agent Framework documentation](https://learn.microsoft.com/agent-framework/)
141
+ - [PostgreSQL documentation](https://www.postgresql.org/docs/current/)
142
+ - [pgvector setup, indexes, and distance functions](https://github.com/pgvector/pgvector)
143
+ - [Psycopg connection pools](https://www.psycopg.org/psycopg3/docs/advanced/pool.html)
@@ -0,0 +1,16 @@
1
+ # Copyright (c) Microsoft. All rights reserved.
2
+
3
+ """Async PostgreSQL/pgvector vector collections and stores."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import importlib.metadata
8
+
9
+ from ._vector_store import PostgresCollection, PostgresSettings, PostgresStore
10
+
11
+ try:
12
+ __version__ = importlib.metadata.version(__name__)
13
+ except importlib.metadata.PackageNotFoundError:
14
+ __version__ = "0.0.0"
15
+
16
+ __all__ = ["PostgresCollection", "PostgresSettings", "PostgresStore", "__version__"]