Releases: ravendb/ravendb-python-client
7.1.5 🔥
7.1.5 brings a major overhaul of the Vector Search API with cleaner and more functional methods, adds Embeddings Generation Tasks for automatic vector embedding creation, and introduces new AI agent capabilities.
If you're new to AI in RavenDB, start here for an in-depth introduction.
PyPi link: https://pypi.org/project/ravendb/7.1.5/
Highlights
Embeddings Generation Tasks
New Embeddings Generation Tasks let you automatically generate vector embeddings from document content. Define which document properties to embed, configure chunking strategies, and RavenDB handles the rest - calling the AI provider, caching embeddings, and keeping them in sync as documents change.
Generated embeddings are stored in dedicated collections (@embeddings) and cached (@embeddings-cache) to avoid redundant provider calls. The task processes documents continuously as they change. You can learn more about embedding generation tasks here.
from ravendb.documents.operations.ai import (
EmbeddingsGenerationConfiguration,
EmbeddingPathConfiguration,
ChunkingOptions,
ChunkingMethod,
AddEmbeddingsGenerationOperation,
)
# Configure chunking - how text is split before sending to the AI provider
chunking = ChunkingOptions(
chunking_method=ChunkingMethod.PLAIN_TEXT_SPLIT_LINES,
max_tokens_per_chunk=2048,
)
# Configure the Embeddings Generation task
config = EmbeddingsGenerationConfiguration(
name="PostEmbeddings",
identifier="post-embeddings",
collection="Posts",
connection_string_name="openai-embeddings",
embeddings_path_configurations=[
EmbeddingPathConfiguration(path="Content", chunking_options=chunking),
EmbeddingPathConfiguration(path="Title", chunking_options=chunking),
],
chunking_options_for_querying=chunking, # Used when embedding search terms
)
# Deploy the task
result = store.maintenance.send(AddEmbeddingsGenerationOperation(config))
print(f"Task created with ID: {result.task_id}")Vector Search API Rework
The Vector Search API has been improved with cleaner, more intuitive method families. There are no breaking changes. The new API provides dedicated methods for each embedding type and use case:
Core methods by embedding type:
# Float32 embeddings (default)
session.query(Product).vector_search("Embedding", vector)
# Int8 quantized embeddings
session.query(Product).vector_search_i8("Embedding", int8_vector)
# Binary (int1) quantized embeddings
session.query(Product).vector_search_i1("Embedding", binary_vector)
# Text-based search (uses embeddings generation task)
session.query(Product).vector_search_text(
"Embedding",
"semantic search query",
embedding_generation_task_identifier="my-embeddings-task"
)Index field methods for querying pre-indexed embeddings:
# Query against index embedding fields
session.query_index("ProductIndex").vector_search_with_field("EmbeddingField", vector)
session.query_index("ProductIndex").vector_search_with_i8_field("EmbeddingField", int8_vector)
session.query_index("ProductIndex").vector_search_with_i1_field("EmbeddingField", binary_vector)
session.query_index("ProductIndex").vector_search_with_text_field("EmbeddingField", "search text")Document-based similarity search:
# Find similar documents based on another document's embeddings
session.query(Product).vector_search_text_for_document(
"Embedding",
document_id="products/123-A",
embedding_generation_task_identifier="my-embeddings-task"
)Base64-encoded vector support:
# For base64-encoded vectors stored in documents
session.query(Product).vector_search_with_base64("Embedding", base64_or_float_vector)
session.query(Product).vector_search_with_base64_i8("Embedding", base64_or_int8_vector)
session.query(Product).vector_search_with_base64_i1("Embedding", base64_or_binary_vector)All methods support optional parameters: minimum_similarity, number_of_candidates, is_exact, and where applicable, target_quantization.
Deprecated methods: The old vector_search_f32_i8, vector_search_f32_i1, vector_search_text_using_task, and similar methods are now deprecated. Use the new unified methods with appropriate parameters instead.
AI Agent Query Tool Options
Query tools now support additional options for controlling LLM access and initial context:
from ravendb.documents.operations.ai.agents import (
AiAgentConfiguration,
AiAgentToolQuery,
AiAgentToolQueryOptions,
)
config = AiAgentConfiguration(
identifier="my-agent",
name="Support Agent",
system_prompt="You help customers with their orders.",
query_tools=[
AiAgentToolQuery(
name="GetRecentOrders",
description="Retrieves recent orders for a customer",
query="from Orders where CustomerId = $customerId order by OrderDate desc limit 5",
options=AiAgentToolQueryOptions(
add_to_initial_context=True, # Run query at conversation start
allow_model_queries=False, # Prevent LLM from invoking directly
),
),
],
)Artificial Actions for AI Agent Conversations
You can now inject artificial tool call responses into AI agent conversations. This is useful for providing context from external systems, simulating tool responses during testing, or pre-populating conversation context:
from ravendb.documents.ai import AiAgentArtificialActionResponse
# Inject an artificial action with its response into the conversation
chat.add_artificial_action_with_response(
AiAgentArtificialActionResponse(
tool_id="weather_lookup_123",
content='{"temperature": 72, "conditions": "sunny"}'
)
)
# The model will see this as if a tool was called and responded
result = chat.run("response")Additional Improvements
- Agent disable support: Agents can now be disabled without deletion via
disabled=TrueinAiAgentConfiguration - VectorQuantizer fix:
to_int8()andto_int1()now returnlist[int]instead ofbytesfor proper JSON serialization - AI connection settings: Added
embeddings_max_concurrent_batchesparameter to all AI provider settings for controlling batch parallelism - GenAI Configuration: Added
enable_tracingfor debugging AI interactions andexpiration_in_secfor cache control - UpdateGenAiOperation: Now supports a
resetparameter to reprocess all documents from scratch - Session improvements: Revisions loaded into session now have
ignore_changes=Trueto prevent accidental change tracking;SessionInfoexposesdatabase_nameproperty - ChunkingOptions validation: Added validation for overlap tokens - only supported with paragraph-based chunking methods
- Python 3.13/3.14 compatibility: Fixed compatibility issues with newer Python versions
- JSONL stream parsing: Added
max_empty_lines_in_jsonl_streamconvention for handling empty lines in streaming responses
PRs
- RDBC-999 VectorQuantizer should return list[int] instead of bytes for proper serialization by @poissoncorp in #262
- RDBC-1012 Implement AiAgentToolQueryOptions by @poissoncorp in #263
- RDBC-1013 Rework Python VectorSearch API by @poissoncorp in #264
- RDBC-978 Python 7.1.4->7.1.5 Sync by @poissoncorp in #265
Full Changelog: 7.1.4...7.1.5
7.1.4 🎉
7.1.4 continues the AI integration story: it adds GenAI Tasks (document-level AI processing), introduces structured prompts with ContentPart, and brings enhanced agent parameters with visibility control. This release syncs the Python client with RavenDB 7.1.4.
If you're new to AI in RavenDB, start here:
- AI Agents Docs: https://docs.ravendb.net/ai-integration/ai-agents/ai-agents_start
- GenAI Tasks Docs: https://docs.ravendb.net/ai-integration/gen-ai-integration/gen-ai_start
PyPi link: https://pypi.org/project/ravendb/7.1.4/
Highlights
GenAI Tasks
New GenAI Tasks let you automatically process documents with AI. Define a prompt, point it at a collection, and RavenDB handles the rest - calling the model, updating documents, and tracking progress.
from ravendb.documents.operations.ai import (
GenAiConfiguration,
GenAiTransformation,
AddGenAiOperation,
)
from ravendb.documents.starting_point_change_vector import StartingPointChangeVector
# Configure the GenAI task
config = GenAiConfiguration(
name="DocumentSummarizer",
identifier="doc-summarizer",
collection="Articles",
connection_string_name="openai-connection",
prompt="Summarize the following article",
gen_ai_transformation=GenAiTransformation(script="ai.genContext({text: this.Content});"),
update_script="this.Summary = $output.Summary;",
sample_object='{"Summary": "A brief summary of the article"}',
max_concurrency=4,
)
# Add the task and start processing documents
result = store.maintenance.send(AddGenAiOperation(config))
print(f"Task created with ID: {result.task_id}")
# Start from the beginning
result = store.maintenance.send(
AddGenAiOperation(config, StartingPointChangeVector.BEGINNING_OF_TIME)
)Full CRUD operations are available:
from ravendb.documents.operations.ongoing_tasks import (
GetOngoingTaskInfoOperation,
DeleteOngoingTaskOperation,
OngoingTaskType,
)
from ravendb.documents.operations.ai import UpdateGenAiOperation
# Get task info
task = store.maintenance.send(
GetOngoingTaskInfoOperation(result.task_id, OngoingTaskType.GEN_AI)
)
# Update task (with optional reset to reprocess documents)
config.prompt = "Updated prompt: Provide a detailed summary"
config.task_id = result.task_id
store.maintenance.send(UpdateGenAiOperation(result.task_id, config, reset=True))
# Delete task
store.maintenance.send(
DeleteOngoingTaskOperation(result.task_id, OngoingTaskType.GEN_AI)
)Structured Prompts with ContentPart
Prompts now support structured content parts for richer interactions:
from ravendb.documents.ai import TextPart, ContentPart
chat.add_user_prompt("Analyze this document") # New method
chat.set_user_prompt("Analyze this document") # Still works as before
# The prompt is internally converted to:
# [TextPart("Analyze this document")]Enhanced Agent Parameters
Agent parameters now support descriptions and visibility control:
from ravendb.documents.operations.ai.agents import AiAgentConfiguration, AiAgentParameter
config = AiAgentConfiguration(
identifier="my-agent",
name="Customer Support Agent",
system_prompt="You are helping {{user}}. Their account type is {{account_type}}.",
parameters=[
# Simple string (backward compatible)
"user",
# Full parameter with description and visibility
AiAgentParameter(
name="account_type",
description="The customer's subscription tier",
send_to_model=False,
),
],
)When send_to_model=False, the parameter value is substituted into the prompt but not exposed in echo messages or other model interactions, which is useful for sensitive data.
Reasoning Tokens & Usage Tracking
AiUsage now tracks reasoning tokens (for models that use chain-of-thought):
result = chat.run("response")
print(f"Reasoning tokens: {result.usage.reasoning_tokens}")
print(f"Total tokens: {result.usage.total_tokens}")
# Calculate usage difference between turns
diff = AiUsage.get_usage_difference(current_usage, previous_usage)PR
(yeah, singular)
- RDBC-967 Python 7.1.3->7.1.4 Sync + GenAI Tasks Operations by @poissoncorp in #260
- RDBC-982 Release 7.1.4 Python Client by @poissoncorp in #261
Full Changelog: 7.1.3...7.1.4
7.1.3 🎉
Starting with 7.1.2, the Python client gained full AI Agents support.
7.1.3 takes that further: it syncs the API with RavenDB 7.1.3, smooths out the Agent experience (streaming, action handling, metrics), and adds connection string operations (including Vertex AI) plus a bunch of reliability fixes.
If you’re new to Agents, start here:
- AI Agents Docs: https://docs.ravendb.net/ai-integration/ai-agents/ai-agents_start
- AI Agents Feature Announcement: ravendb/ravendb#21249
PyPi link: https://pypi.org/project/ravendb/7.1.3/
Highlights
AI Agents
- New
stream(...)method lets you push Agent responses to your UI as they arrive, ChatGPT-style. - You can register actions via conventient API and decide what happens when the model calls something you didn’t wire up, using
handle(...),receive(...)andon_unhandled_action. - AI conversation
run()returns rich stats (token usage, elapsed time, etc.) insideAiAnswer.
ai_agent_result = store.ai.add_or_update_agent(ai_agent_configuration)
ai_agent = store.ai.get_agents(ai_agent_result.identifier)
chat = store.ai.conversation(
ai_agent.ai_agents[0].identifier,
"chats/",
AiConversationCreationOptions(expiration_in_sec=3600).add_parameter("user", "users/15-A")
)
chat.on_unhandled_action = lambda args: print(f"Unhandled action: {args.action.name}")
# Handle SendNotification action tool request
chat.handle(
"SendNotification",
lambda args: f"Notification sent to {args['recipients']}", # mock sending notification
AiHandleErrorStrategy.SEND_ERRORS_TO_MODEL,
)
while True:
chat.set_user_prompt(input())
def _on_chunk(answer: str):
print(answer, end="")
result = chat.stream("response", _on_chunk)
print(result.usage)
print(result.elapsed)Vertex AI connection strings
You can now configure Vertex AI as an AI connection string, side-by-side with OpenAI and others:
cs_name = "vertex-demo"
vertex = VertexSettings(
model="gemini-1.5-pro",
google_credentials_json='{"project_id":"demo-vertex-project"}',
location="us-central1",
ai_version=VertexAIVersion.V1,
)
ai_cs = AiConnectionString(
name=cs_name,
identifier=cs_name,
vertex_settings=vertex,
model_type=AiModelType.CHAT,
)
store.maintenance.send(PutConnectionStringOperation(ai_cs))Later you can point your AI Agent configuration at connection_string_name="vertex-demo" and talk to Vertex via the same Agents API.
Connection String CRUD (including AI)
New operations let you Add / Update / Get / Delete all connection string types (including AI ones), plus a dedicated RemoveConnectionStringByNameOperation that matches other SDKs.
Minimal CRUD example:
# Put
store.maintenance.send(PutConnectionStringOperation(ai_cs))
# Get single AI connection string
get_result = store.maintenance.send(
GetConnectionStringsOperation(cs_name, ConnectionStringType.AI)
)
ai_map = get_result.ai_connection_strings
ai_cs_loaded = ai_map[cs_name]
# Remove by name
store.maintenance.send(
RemoveConnectionStringByNameOperation(ConnectionStringType.AI, cs_name)
)Fixes
- Fix: zstd-compression module prevented storing the data by yh-0 #254
- Topology & network error handling by @redknightlois #249
PRs
- README.md should use order_by_descending() by @Scooletz in #246
- RDBC-935 Add Connection String Operations by @yh-0 in #247
- RDBC-949: Refactors is_read_request to a method by @redknightlois in #250
- RDBC-948: Ensure topology handling matches C# Client. by @redknightlois in #249
- RDBC-940 v7.1 Zstd-compression data prevents simple store. by @yh-0 in #251
- RDBC-964 Fix SSLError in https test by @yh-0 in #256
- RDBC-954 Python client: fix Connection String R/W Bugs (OLAP + AI) by @yh-0 in #255
- RDBC-934 Sync to 7.1.3 by @poissoncorp in #258
- RDBC-934 7.1.3 C# API parity by @poissoncorp in #259
7.1.2 - RavenDB AI Agents in Python 🎉
Starting v7.1.2, the RavenDB Python client ships with the AI Agents API. This way you can spin up safe, tool-driven agents right from your Python app.
If you haven’t seen what our Agents are or why we built them, grab 2 minutes and read the feature announcement (it’s genuinely good):
👉 AI Agents Feature Announcement: ravendb/ravendb#21249
👉 AI Agents Documentation: https://docs.ravendb.net/ai-integration/ai-agents/ai-agents-api
Usage example (create → chat → handle actions)
from ravendb import DocumentStore, AiAgentConfiguration, AiAgentToolAction
# 1) Connect
store = DocumentStore(["http://localhost:8080"], "AwesomeDatabase")
store.initialize()
# 2) Define an agent (connection string configured in RavenDB Studio)
agent = AiAgentConfiguration(
name="orders-manager-test",
connection_string_name="OpenAI",
system_prompt="You help users with their orders and can email results."
)
agent.sample_object = '{"answer":"text"}'
# Optional: let the agent request supervised actions
send_email = AiAgentToolAction(
name="SendEmail",
description="Send an email with provided content to the given address."
)
send_email.parameters_sample_object = '{"Address":"user@example.com","EmailContent":"text"}'
agent.actions.append(send_email)
agent_id = store.ai.add_or_update_agent(agent).identifier
# 3) Run a conversation
with store.ai.conversation(agent_id) as chat:
chat.set_user_prompt("Send message 'Raven on Python has agents now lmao' to josh@example.com.")
result = chat.run()
# 4) If the agent requested an action, handle it and reply with the result
if result.action_requests:
for action in result.action_requests:
if action.name == "SendEmail":
# ...your app actually sends the email here...
chat.add_action_response(action.tool_id, "email sent ✅")
# Continue the conversation after fulfilling actions
result = chat.run()
print("Agent says:", result.response)Which results in:
Agent says: {'answer': 'The message has been sent to josh@example.com!'}
That’s the core loop. The API also supports parameters, query tools, persistence, and chat-trimming see the README examples:
https://github.com/ravendb/ravendb-python-client/blob/v7.1/AI_AGENT_README.md
Enjoy, happy coding! 🤖💙
7.0.2
Python Client 7.0.2 is out 🐍🚀
It delivers powerful streaming capabilities, AI Integration query API, plus a fix for handling emojis
- New: Document and Query Streaming API – stream large result sets efficiently 🔄📄
- New: AI Integration's
using_tasksupport in vector search – vector queries using AI Embedding Generation Tasks 🤖🧠 - Fix: Better error parsing in
RequestExecutorfor smoother debugging 🛠️ - Fix: 🐛 UTF-8 encoding added to document data – your emojis are safe now 💾📦
New Contributors
- 👏 @yh-0 implemented streaming support (#238)
- 👏 @MohKamal improved emoji handling with UTF-8 encoding (#239)
Feel free to join our Discord Community & discuss the release here: https://discord.gg/ravendb 💬🧑💻
💡 Highlight: AI Integration using_task
Perform semantic search using AI Embeddings Generation:
q = session.query(object_type=Dto).vector_search_text_using_task("EmbeddingField", "fishing", "my-ai-task")Also supports variants:
vector_search_text_i1_using_task(...)vector_search_text_i8_using_task(...)- All with optional
is_exact=True
RavenDB Embeddings Generation docs here.
🚿 Streaming API: Lightweight Queries at Scale
Stream documents, queries, raw queries, and even query statistics without loading all results into memory:
✅ Stream a normal query
query = session.query(object_type=Color)
stream = session.advanced.stream(query)
for result in stream:
print(result.document.name)✅ Stream a raw RQL query
raw_query = session.advanced.raw_query("from Colors where is_primary = true", object_type=Color)
stream = session.advanced.stream(raw_query)
for result in stream:
print(result.document.name)✅ Stream with statistics
def stats_callback(stats):
print(f"Total results: {stats.total_results}")
query = session.query(object_type=Color).where_equals("is_primary", True)
stream = session.advanced.stream_with_statistics(query, stats_callback)
for result in stream:
print(result.document.name)✅ Stream documents by ID prefix
stream = session.advanced.stream_starting_with("colors/", object_type=Color)
for result in stream:
print(result.document.name)PRs
- RDBC-893 Fix parsing of errors inside
RequestExecutor._handle_unsuccessful_responseby @poissoncorp (#236) - RDBC-900 Add
usingTaskto Python Vector Search API by @poissoncorp (#237) - RDBC-670 Streaming by @yh-0 (#238)
- Add UTF-8 encoding to document data by @MohKamal (#239)
Full Changelog: 7.0.0...7.0.2
7.0.0
Python Client 7.0 is here 🐍⚡
- Added Vector Search API, for AI & ML integrations 🦾🤖 (PR)
- Added
SearchEngineTypeto IndexDefinition - allows creating Corax static indexes 🐦⬛📊 - Bugfixes, operations, more helper methods
Merged PRs worth mentioning
- RDBC-822 Fix FacetOptions serialization by @poissoncorp in #214
- RDBC-817 Implement query.projection() by @poissoncorp in #215
- RDBC-843 Add GetDetailedCollectionStatisticsOperation by @poissoncorp in #217
- RDBC-845 Implement AddDatabaseNodeOperation by @poissoncorp in #218
- RDBC-851 Attachments bulk insert doesn't drop concurrency lock after store by @poissoncorp in #219
- RDBC-844 Implement database settings operations by @poissoncorp in #222
- RDBC-847 Implement documentStore.Maintenance.Server.ForNode by @poissoncorp in #223
- RDBC-848 Implement session.Advanced.SessionInfo.SetContext by @poissoncorp in #224
- RDBC-837/838 Move has_changes and ignore_changes_for to session.advanced by @poissoncorp in #225
- RDBC-839 Use find_identity_property - implement get identity property by @poissoncorp in #226
- RDBC-833 Implement session.advanced.get_current_session_node by @poissoncorp in #227
Full Changelog: 5.2.6...7.0.0
5.2.6 ⚡
Breaking changes 🔥
Session methods - lazily.load() and include().load() - #210
- set
object_typeargument as optional - inverted the
object_typeandkeyarguments order lazily.load()now takes a list ofstrdocument IDs, not*ids
'Id' property won't be stored at the server anymore - #211
- Document id is still available as a value of the Id property, but the value is set after serialization
- Documents loaded as dict objects won't contain the Id key (still available via
session.advanced.get_metadata_for(...)["@id"]orsession.advanced.get_document_id()) - Custom from_json methods that have been setting the Id property should skip that step, as the Id property will be set to a valid value after the serialization
What's new 🌬️
- Added include time series API to subscription includes builder
- Storing a
dict-document while providing document id collection prefix (e.g.session.store({"Name":"Graziano"}, "Users/"}) stores the document under valid collection (e.g. Users), not"dicts" - Made
object_typeargument inget_compare_exchange_values()optional - Fixed
load_starting_with_into_stream()and made it returnbytesstream, instead of passing it as an argument to be modified within the method itself - Marked
object_typeargument as optional in many methods across the API - Fixed a bug that caused an error when disposing uninitialized
RequestExecutor - Improved
session.time_series_for()error messages
5.2.5
What's New
- Ensured full compatibility with RavenDB 6.0.x ⚡
- Time Series
- Creation of a document with server-generated GUID (#199)
- Revisions (#201)
- Configuration
- Crud
- Force revision creation
- Bulk insert (#202)
- Counters bulk insert
- Time series bulk insert
- HTTPS
- Secured changes API (#204)
- Multiple new useful operations & commands (#200, #203)
- ResetIndexOperation
- GetStatisticsOperation
- DeleteIndexErrorsOperation
- CreateSampleDataOperation
- ConfigureExpirationOperation
- ReorderDatabaseMembersOperation
- PromoteDatabaseNodeOperation
- NextIdentityForOperation
- SeedIdentityForOperation
- CompactDatabaseOperation
- ExplainQueryCommand
- GetIdentitiesOperation
- ToggleDatabasesStateOperation
- PutSortersOperation
- DeleteSorterOperation
- PutServerWideAnalyzersOperation
- DeleteServerWideAnalyzerOperation
- PutServerWideBackupConfigurationOperation
- GetServerWideBackupConfigurationsOperation
- GetServerWideBackupConfigurationOperation
- DeleteServerWideTaskOperation
- UpdateDocumentsCompressionConfigurationOperation
- GetLogsConfigurationOperation
- SetLogsConfigurationOperation
- SetDatabasesLockOperation
- PutServerWideSortersOperation
- DeleteServerWideSorterOperation
Breaking changes 💔
- Changed method name in spatial options - GeographySpatialOptionsFactory.quad_prefix_tree_level to quad_prefix_tree_index - 243b292
- Removed duplicated
FacetTermSortMode- here - aggregate_by_facets now takes a list of Facets - 02346f5
Improved typehints for:
LoaderWithInclude.load()attachments.store()session.advanced.attachments.get()
Minor fixes for:
- Facets queries
- Spatial queries
The client is now being tested using Embedded RavenDB Server as a package!
https://github.com/ravendb/ravendb-python-embedded
It's a great tool for so many scenarios!
Full Changelog: 5.2.4...5.2.5
5.2.4
- Bulk insert dependencies bugfix
Available here https://pypi.org/project/ravendb/5.2.4/
5.2.3
- New feature - Counters
- Counters indexes
Available here https://pypi.org/project/ravendb/5.2.3/