Skip to content

Python: fix(redis): prefer an injected history client over connection settings - #9977

Merged
Eduard van Valkenburg (eavanvalkenburg) merged 3 commits into
microsoft:mainfrom
he-yufeng:fix/redis-history-prefer-injected-client
Nov 3, 2026
Merged

Eduard van Valkenburg (eavanvalkenburg) merged 3 commits into
microsoft:mainfrom
he-yufeng:fix/redis-history-prefer-injected-client

Conversation

@he-yufeng

@he-yufeng Yufeng He (he-yufeng) commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Motivation & Context

RedisHistoryProvider treats redis_client, redis_url and credential_provider as mutually exclusive, so a working caller-owned client cannot be passed alongside any other connection source without construction raising redis_client, redis_url, and credential_provider are mutually exclusive. A caller that already has a configured client has to know to strip the settings it also passes everywhere else, and a config layer that always forwards a URL breaks the moment a test or a deployment injects a client.

Those settings describe how to build a client. When one is supplied there is nothing to build and nothing to validate, so supplying them is redundant rather than conflicting. The Redis vector stores already behave this way: _create_client bypasses URL and .env settings entirely once a redis_client is injected, and only runs the checks that describe the client itself. The history provider is the odd one out in the same package.

Fixes #9966, which is labelled ready-for-implementation and lists focused acceptance tests. No other PR is open for it.

Description & Review Guide

What are the major changes?

An injected redis_client takes precedence over redis_url, credential_provider, host, port, ssl and username. Those are ignored rather than treated as a conflict, and they are validated only in the branch that builds a client. A borrowed client must still be a standalone redis.asyncio.Redis with decode_responses=True; those checks describe the client rather than its construction, so they still run in both modes. aclose still leaves a borrowed client open, which was already true and is now pinned alongside the redundant settings.

self.redis_url now reports the source the provider actually used. When a client was injected it is None, because a URL passed alongside it was never opened and advertising it would claim a connection that was not made. This mirrors test_credential_provider_with_host, which already asserts redis_url is None when the credential path builds the client.

The package guide now documents the same precedence. Constructor coverage includes a credential provider without a host and URL plus credential provider alongside a borrowed client, proving that neither owned-client validation remains active. All four precedence cases fail against the current upstream base and pass with this change.

What is the impact of these changes?

Beta construction stops raising for redundant connection sources and matches the vector-store behaviour in the same package. Owned-client construction is unchanged: the errors for no source at all, for redis_url alongside credential_provider, and for a credential provider without a host all still fire exactly as before. Provider-level storage settings, meaning key_prefix, key_format, the scoped identifiers and max_messages, are untouched and keep working in both modes.

What do you want reviewers to focus on?

Whether ignoring the connection settings outright is the behaviour you want, versus validating them for consistency and then discarding. I went with ignore, since validating settings that cannot be used turns a redundant argument into a source of spurious failures, and the issue asks for them to be checked only when a client is created. The self.redis_url is None choice is the same reasoning and is the one place where a caller could observe a difference beyond construction not raising.

Related Issue

Fixes #9966

AI Assistance

  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details: implementation, tests and this description. The change was written, run and checked locally before submission.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • New and existing unit tests pass locally (pytest packages/redis/tests, 335 passed, 58 skipped)
  • ruff check and ruff format --check are clean on both touched Python files
  • pyright reports 0 errors on the changed module
  • Documentation updated: the constructor docstring and package guide describe injected-client precedence.

… settings

RedisHistoryProvider treated redis_client, redis_url and credential_provider as mutually exclusive, so a working caller-owned client could not be passed alongside any other connection source without construction raising. Those settings describe how to build a client. When one is supplied there is nothing to build and nothing to validate.

An injected client now takes precedence. redis_url, credential_provider, host, port, ssl and username are ignored rather than treated as a conflict, and they are only validated when the provider creates a client itself. The checks that describe the client rather than its construction still run, so a borrowed client must still be a standalone redis.asyncio.Redis with decode_responses=True, and its lifetime stays with the caller: aclose leaves it open.

This is the precedence the Redis vector stores already apply in _create_client, which bypasses URL and env settings entirely once a client is injected. Provider-level storage settings are untouched, so key scope, key_format and retention behave exactly as before in both modes.

self.redis_url now reports the source the provider actually used, so it is None when a client was injected rather than advertising a URL that was never opened. Owned-client construction is unchanged, including the existing errors for a missing source, for redis_url alongside credential_provider, and for a credential provider without a host.

Fixes microsoft#9966

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The package guide still documents the removed restriction, and tests omit borrowed-client cases that would catch lingering owned-client validation.

2 open issues
What changed in this PR

This PR addresses #9966 by making RedisHistoryProvider prefer an injected Redis client over redundant connection settings, aligning it with the package’s vector stores.

Changes:

  • Limits connection-source validation to provider-created clients while retaining injected-client compatibility checks and caller ownership.
  • Sets redis_url to None when an injected client is used and documents the precedence behavior.
  • Adds regression tests for client precedence, compatibility checks, and provider scoping and retention settings.
File Description
python/​packages/​redis/​tests/​test_providers.py Adds coverage for injected-client precedence and preserved provider settings.
python/​packages/​redis/​agent_framework_redis/​_history_provider.py Updates connection validation, URL reporting, and constructor documentation.

Review effort: Balanced

@agent-framework-automation agent-framework-automation Bot added the documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs label Nov 3, 2026
Merged via the queue into microsoft:main with commit f4bdd1d Nov 3, 2026
54 checks passed

This branch was previously deployed

1 inactive deployment
github-app-auth — c79a5e1e Deployed Nov 3, 2026 by he-yufeng via add_label #26902
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: RedisHistoryProvider rejects connection settings instead of preferring an injected client

3 participants