Skip to content

Feat/matcher#23

Closed
JohnRichard4096 wants to merge 8 commits intomainfrom
feat/matcher
Closed

Feat/matcher#23
JohnRichard4096 wants to merge 8 commits intomainfrom
feat/matcher

Conversation

@JohnRichard4096
Copy link
Copy Markdown
Member

@JohnRichard4096 JohnRichard4096 commented Feb 26, 2026

close #22

Summary by Sourcery

Introduce a new, priority-aware matcher and dependency injection system for event handling, add preset fallback events and Anthropic adapter support, and extend chat and configuration flows to support CoT filtering and robust LLM fallback behavior.

New Features:

  • Add AnthropicAdapter to support Anthropic/Claude protocol alongside OpenAI, including streaming and non-streaming responses.
  • Introduce a Depends/DependsFactory-based dependency injection system for matchers with concurrent resolution and runtime injection support.
  • Add FallbackContext events and on_preset_fallback hook to enable configurable preset-based LLM fallback handling in chat flows.
  • Support chain-of-thought style models via a cot_model option that strips blocks from streamed responses.

Bug Fixes:

  • Ensure matcher cancellation semantics use CancelException for stopping processing and make ChatException alias the generic MatcherException.
  • Fix type signatures and generic annotations across utilities, queues, and protocol interfaces to be more precise and safe.

Enhancements:

  • Refactor EventRegistry and MatcherManager into a priority-bucketed MatcherFactory with richer error handling, dependency resolution, and deprecation-safe APIs.
  • Improve UniResponseUsage and split_list generics to be more flexible and type-safe, and clean up unused time formatting helpers.
  • Extend libchat streaming to hide model thinking segments while still accumulating final content.
  • Improve logging and error propagation in matcher execution, including handling of ignored exceptions via ExceptionGroup.

Build:

  • Add anthropic and deprecated libraries as project dependencies and bump project version to 0.5.0.

Documentation:

  • Document FallbackContext, Depends, and DependsFactory in both English and Chinese API references and link them from the sidebar.
  • Expand event concept guides (EN/ZH) with preset fallback events, updated hook lists, DI examples, and dynamic preset mutation examples.

Tests:

  • Add comprehensive matcher and dependency injection tests covering registration, dependency resolution, runtime deps, error handling, and concurrency behavior.

@JohnRichard4096
Copy link
Copy Markdown
Member Author

@sourcery-ai dismiss

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Feb 26, 2026

Reviewer's Guide

Introduces a more powerful matcher/DI system with Depends/DependsFactory, event priority handling and fallback preset events, adds Anthropic adapter and CoT-think tag filtering, and wires these into ChatObject with preset fallback retries, while updating docs, config, protocol, and tests.

Class diagram for matcher, dependency injection, and fallback events

classDiagram
    class EventTypeEnum {
        <<enum>>
        PRECOMPLETION
        COMPLETION
        Nil
        BEFORE_COMPLETION
        PRESET_FALLBACK
    }

    class BaseEvent {
        <<abstract>>
        +event_type EventTypeEnum
        +get_event_type() EventTypeEnum
    }

    class FallbackContext {
        +preset ModelPreset
        +exc_info BaseException
        +config AmritaConfig
        +context SendMessageWrap
        +term int
        +fail(reason Any) Never
        +get_event_type() EventTypeEnum
    }

    class FunctionData {
        +function Callable
        +signature inspect.Signature
        +frame FrameType
        +priority int
        +matcher Matcher
    }

    class EventRegistry {
        -_event_handlers defaultdict~str,defaultdict~int,list~FunctionData~~~~
        +register_handler(event_type str, data FunctionData) void
        +get_handlers(event_type str) defaultdict~int,list~FunctionData~~
        +get_all() defaultdict~str,defaultdict~int,list~FunctionData~~~~
    }

    class Matcher {
        +event_type str
        +priority int
        +block bool
        +append_handler(func Callable[...,Awaitable~Any~]]) void
        +set_block(block bool) void
        +stop_process() void
        +cancel_matcher() void
        +pass_event() void
    }

    class DependsFactory~T~ {
        -_depency_func Callable[...,T|Awaitable~T~]
        +resolve(*args, **kwargs) T|None
    }

    class MatcherFactory {
        +trigger_event(event BaseEvent, config AmritaConfig, *args, **kwargs) void
        +_resolve_dependencies(signature inspect.Signature, session_args Iterable~Any~, session_kwargs dict~str,Any~) (bool,tuple,dict~str,Any~,dict~str,DependsFactory~Any~~)
        +_do_runtime_resolve(runtime_args dict~int,DependsFactory~Any~~, runtime_kwargs dict~str,DependsFactory~Any~~, args2update list~Any~, kwargs2update dict~str,Any~, session_args list~Any~, session_kwargs dict~str,Any~, exception_ignored tuple~type~BaseException~~) bool
        +_simple_run(matcher_list list~FunctionData~, event BaseEvent, config AmritaConfig, exception_ignored tuple~type~BaseException~~, extra_args tuple, extra_kwargs dict~str,Any~) bool
    }

    class MatcherManager {
    }

    class AmritaConfig {
    }

    class ModelPreset {
        +name str
        +model str
        +api_key str
        +base_url str
        +config ModelConfig
    }

    class ModelConfig {
        +stream bool
        +top_p float
        +temperature float
        +cot_model bool
    }

    class LLMConfig {
        +auto_retry bool
        +max_retries int
        +max_fallbacks int
    }

    class ChatObject {
        +preset ModelPreset
        +config AmritaConfig
        +context_wrap SendMessageWrap
        +_response_queue asyncio.Queue~RESPONSE_TYPE~
        +_overflow_queue asyncio.Queue~RESPONSE_TYPE~
        +_process_chat() None
    }

    class FallbackFailed {
        <<exception>>
    }

    class MatcherException {
        <<exception>>
    }

    class CancelException {
        <<exception>>
    }

    class BlockException {
        <<exception>>
    }

    class PassException {
        <<exception>>
    }

    class ChatException {
        <<typealias>>
    }

    BaseEvent <|-- FallbackContext
    FallbackContext ..> ModelPreset
    FallbackContext ..> AmritaConfig
    FallbackContext ..> SendMessageWrap
    FallbackContext ..> FallbackFailed

    MatcherException <|-- CancelException
    MatcherException <|-- BlockException
    MatcherException <|-- PassException

    ChatException <.. MatcherException

    Matcher "1" o-- "*" FunctionData : owns
    FunctionData --> Matcher : matcher
    EventRegistry "1" --> "*" FunctionData : stores

    MatcherFactory ..> EventRegistry
    MatcherFactory ..> DependsFactory
    MatcherFactory ..> FunctionData
    MatcherFactory ..> BaseEvent
    MatcherFactory ..> AmritaConfig

    MatcherManager <|-- MatcherFactory

    ChatObject ..> MatcherManager : trigger_event
    ChatObject ..> FallbackContext
    ChatObject ..> LLMConfig

    EventTypeEnum <.. BaseEvent
    EventTypeEnum <.. FallbackContext

    FallbackFailed <|-- RuntimeError
Loading

File-Level Changes

Change Details Files
Refactor matcher/event system to support typed dependency injection, priority buckets, new event types, and matcher factory APIs.
  • Replace flat event handler list with nested defaultdict keyed by event type and priority, and expose new get_handlers/get_all APIs in EventRegistry with a deprecated _all alias.
  • Redefine ChatException to wrap MatcherException and adjust Matcher API (remove block from FunctionData, add set_block, change stop_process semantics, deprecate cancel_matcher with warning).
  • Introduce DependsFactory and Depends helper with signature-based dependency resolution, plus MatcherFactory with _resolve_dependencies, concurrent _do_runtime_resolve, _simple_run, and an overloaded trigger_event that runs handlers by priority and supports exception_ignored and runtime DI.
  • Update MatcherManager alias to point to MatcherFactory and adjust on_preset_fallback/on_event helpers to use new EventTypeEnum.PRESET_FALLBACK and matcher behavior.
src/amrita_core/hook/matcher.py
src/amrita_core/hook/on.py
src/amrita_core/hook/event.py
src/amrita_core/hook/exception.py
tests/test_matcher.py
Add preset fallback handling and FallbackContext events into the chat flow with configurable limits.
  • Introduce FallbackContext event type and PRESET_FALLBACK enum variant with fail() API that raises FallbackFailed, and wire a new on_preset_fallback decorator.
  • In ChatObject._process_chat, wrap LLM call in a loop with max_fallbacks, emit FallbackContext via MatcherManager.trigger_event on failure, allow handlers to swap presets, and raise FallbackFailed when exhausted.
  • Extend LLMConfig with max_fallbacks to control the maximum number of preset fallbacks.
src/amrita_core/hook/event.py
src/amrita_core/hook/on.py
src/amrita_core/hook/exception.py
src/amrita_core/chatmanager.py
src/amrita_core/config.py
Extend model adapters and protocol to support Anthropic, improve OpenAI streaming, and add CoT tag filtering.
  • Add AnthropicAdapter implementing ModelAdapter.call_api using anthropic.AsyncAnthropic with streaming/non-streaming branches and token usage mapping, and register its protocol names.
  • Adjust OpenAIAdapter.call_api to accept *args/**kwargs and yield UniResponse directly, and expose a shared model_dump helper for BaseModel/dict messages.
  • Update ModelAdapter.call_api protocol to accept **kwargs, and modify libchat.call_completion to filter out ... segments when preset.config.cot_model is true.
  • Allow UniResponseUsage fields to be optional (default None) and add a cot_model flag to ModelConfig to control CoT filtering behavior.
src/amrita_core/builtins/adapter.py
src/amrita_core/protocol.py
src/amrita_core/libchat.py
src/amrita_core/types.py
Clean up and generalize utilities and type hints used across chat and utils.
  • Remove unused datetime formatting helper from chatmanager and related test, tighten ChatObject queue typing to RESPONSE_TYPE, and switch split_list to be generically typed returning list[list[T]].
  • Drop format_datetime_timestamp from utils and its tests, and adjust imports to use TypeVar instead of Any where appropriate.
src/amrita_core/chatmanager.py
src/amrita_core/utils.py
tests/test_utils.py
Enhance documentation and site navigation for events, dependency injection, and new types in both English and Chinese guides.
  • Document FallbackContext events, on_preset_fallback hook, and preset mutation examples in the event concept guides; add a full section describing the Depends-based DI system including runtime Depends usage and concurrency semantics.
  • Add API reference pages for Depends, DependsFactory, and FallbackContext in both languages and link them from the API index and navigation configuration.
  • Clarify and renumber event guide sections, mention removal of @on_tools, and update examples to reflect new behavior and parameter descriptions.
docs/guide/concepts/event.md
docs/zh/guide/concepts/event.md
docs/guide/api-reference/index.md
docs/zh/guide/api-reference/index.md
docs/guide/api-reference/classes/Depends.md
docs/zh/guide/api-reference/classes/Depends.md
docs/guide/api-reference/classes/DependsFactory.md
docs/zh/guide/api-reference/classes/DependsFactory.md
docs/guide/api-reference/classes/FallbackContext.md
docs/zh/guide/api-reference/classes/FallbackContext.md
docs/.vitepress/config.mts
Update project metadata and dependencies for new matcher, anthropic support, and deprecation helpers.
  • Bump project version to 0.5.0 and add anthropic and deprecated to runtime dependencies.
  • Introduce uv.lock for dependency locking (content not detailed in diff).
pyproject.toml
uv.lock

Assessment against linked issues

Issue Objective Addressed Explanation
#22 Add a new model-fallback hook decorator and context type (on_model_fallback / FallbackContext) following the existing event-driven matcher pattern, with a context object that exposes session/model-call information needed for custom fallback logic. The PR introduces a new event type and decorator named on_preset_fallback (not on_model_fallback) and a FallbackContext class. However, FallbackContext does not expose all the fields requested in the issue (e.g., there is no session_id or direct chat_object reference, and the error field is named exc_info). The documented usage is oriented toward preset switching rather than the broader async-generator fallback pattern described in the issue. So the hook exists but does not fully match the specified interface and semantics.
#22 Integrate the fallback hook into the model calling pipeline so that when model calls fail, fallback handlers are triggered and can influence subsequent behavior (e.g., retrying with alternative presets/models) while preserving the async response pattern.
#22 Document the new fallback hook/context and how to use it within the framework’s event system so users can configure fallback behavior.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 5 issues, and left some high level feedback:

  • In builtins/adapter.py, the helper model_dump reuses the name obj for both the iterable and the loop variable (for obj in obj), which will fail at runtime; rename the loop variable (e.g. for item in obj) and use item.model_dump() accordingly.
  • In MatcherFactory._simple_run, the check isinstance(e, CancelException | BlockException) will never match because CancelException | BlockException is a types.UnionType; use a tuple instead, e.g. isinstance(e, (CancelException, BlockException)), so cancel/block behavior works as intended.
  • In ChatObject._process_chat, the fallback warning message logs ({i}/{self.config.llm.max_retries}) while the loop is controlled by max_fallbacks, which is misleading; update the message to reflect max_fallbacks or the actual controlling value.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `builtins/adapter.py`, the helper `model_dump` reuses the name `obj` for both the iterable and the loop variable (`for obj in obj`), which will fail at runtime; rename the loop variable (e.g. `for item in obj`) and use `item.model_dump()` accordingly.
- In `MatcherFactory._simple_run`, the check `isinstance(e, CancelException | BlockException)` will never match because `CancelException | BlockException` is a `types.UnionType`; use a tuple instead, e.g. `isinstance(e, (CancelException, BlockException))`, so cancel/block behavior works as intended.
- In `ChatObject._process_chat`, the fallback warning message logs `({i}/{self.config.llm.max_retries})` while the loop is controlled by `max_fallbacks`, which is misleading; update the message to reflect `max_fallbacks` or the actual controlling value.

## Individual Comments

### Comment 1
<location path="src/amrita_core/chatmanager.py" line_range="840-841" />
<code_context>
+                logger.warning(
+                    f"Because of `{e!s}`, LLM request failed, retrying ({i}/{self.config.llm.max_retries})..."
+                )
+                ctx = FallbackContext(self.preset, e, self.config, self.context_wrap, i)
+                await MatcherManager.trigger_event(ctx, ctx.config, (FallbackFailed,))
+                if ctx.preset is self.preset:
+                    ctx.fail("No preset fallback available, exiting!")
</code_context>
<issue_to_address>
**issue (bug_risk):** The `FallbackFailed` exception type is not actually passed to `exception_ignored` in `trigger_event`.

Here `(FallbackFailed,)` is passed as a positional arg and is treated as an extra DI parameter, so `exception_ignored` remains its default `()`. That means `FallbackFailed` from a fallback matcher is caught and logged instead of re-raised. To ensure it’s ignored by `_simple_run`, call:

```python
await MatcherManager.trigger_event(
    ctx,
    ctx.config,
    exception_ignored=(FallbackFailed,),
)
```
</issue_to_address>

### Comment 2
<location path="src/amrita_core/hook/matcher.py" line_range="180-189" />
<code_context>
+        return rs
+
+
+def Depends(dependency: Callable[..., T | Awaitable[T]]) -> Any:
+    """
+    Dependency injection decorator.
+
+    Args:
+        dependency: The dependency function to inject
+
+    Returns:
+        DependsFactory: A factory for dependency injection
+
+    Example:
+        ```python
+        async def get_example_dependency(...) -> Any | None:
+            ...
+
+        @on_precompletion()
+        async def a_function_with_dependencies(
+            event: PreCompletionEvent,
+            dep: ExampleDependency = Depends(get_example_dependency),
+        ):
+            ...
+        ```
+
+        If DependendsFactory's return is None, this function won't be called.
+    """
+    return DependsFactory[T](dependency)
+
+
</code_context>
<issue_to_address>
**suggestion:** The `Depends` helper returns `Any` and the generic argument is unused, which weakens typing for dependency injection.

Because the function returns `Any`, callers lose the information that `DependsFactory` is parameterized by `T`, so type checkers can’t infer the injected dependency type. Returning the concrete generic instead would preserve typing, e.g.:

```python
def Depends(dependency: Callable[..., T | Awaitable[T]]) -> DependsFactory[T]:
    return DependsFactory(dependency)
```

That way, handler parameters like `dep: Example = Depends(get_example)` will have the correct inferred type.

Suggested implementation:

```python
def Depends(dependency: Callable[..., T | Awaitable[T]]) -> DependsFactory[T]:

```

```python
    return DependsFactory(dependency)

```

If `Any` was only used as the return type of `Depends`, you should also:
1. Remove `Any` from the `from typing import ...` list in this file to avoid an unused import.
</issue_to_address>

### Comment 3
<location path="tests/test_matcher.py" line_range="307" />
<code_context>
+        assert result is False
+        assert kwargs2update == {}  # Should not be updated
+
+    @pytest.mark.asyncio
+    async def test_do_runtime_resolve_exception(self):
+        """Test _do_runtime_resolve with exception in dependency."""
+
</code_context>
<issue_to_address>
**suggestion (testing):** Consider adding a test for `_do_runtime_resolve` where an exception type listed in `exception_ignored` is raised, to verify the special handling path.

You can mirror `test_do_runtime_resolve_exception` but use a custom exception passed in `exception_ignored` and assert it is raised directly, e.g.:

```python
@pytest.mark.asyncio
async def test_do_runtime_resolve_exception_ignored(self):
    class CustomError(Exception):
        pass

    async def error_dep() -> str:
        raise CustomError("ignored")

    factory = DependsFactory(error_dep)

    with pytest.raises(CustomError):
        await MatcherFactory._do_runtime_resolve(
            {},  # runtime_args
            {"key": factory},  # runtime_kwargs
            [],  # args2update
            {},  # kwargs2update
            [],  # session_args
            {},  # session_kwargs
            (CustomError,),  # exception_ignored
        )
```

This verifies that ignored exceptions are re-raised instead of being collected into the `ExceptionGroup`.

```suggestion
        """Test _do_runtime_resolve with exception in dependency."""

    @pytest.mark.asyncio
    async def test_do_runtime_resolve_exception_ignored(self):
        class CustomError(Exception):
            pass

        async def error_dep() -> str:
            raise CustomError("ignored")

        factory = DependsFactory(error_dep)

        with pytest.raises(CustomError):
            await MatcherFactory._do_runtime_resolve(
                {},  # runtime_args
                {"key": factory},  # runtime_kwargs
                [],  # args2update
                {},  # kwargs2update
                [],  # session_args
                {},  # session_kwargs
                (CustomError,),  # exception_ignored
            )
```
</issue_to_address>

### Comment 4
<location path="docs/guide/api-reference/classes/DependsFactory.md" line_range="8" />
<code_context>
+## Constructor
+
+```python
+def __init__(self, depency: Callable[..., T | Awaitable[T]])
+```
+
</code_context>
<issue_to_address>
**issue (typo):** Parameter name `depency` looks like a typo and should likely be `dependency`.

Since this appears in user-facing API docs, updating the parameter name there as well will prevent confusion and keep terminology consistent with the rest of the text.

Suggested implementation:

```
def __init__(self, dependency: Callable[..., T | Awaitable[T]])

```

```
- `dependency`: The dependency function to wrap, which can return any type `T` or an awaitable object `Awaitable[T]`

```
</issue_to_address>

### Comment 5
<location path="docs/zh/guide/api-reference/classes/DependsFactory.md" line_range="8" />
<code_context>
+## Constructor
+
+```python
+def __init__(self, depency: Callable[..., T | Awaitable[T]])
+```
+
</code_context>
<issue_to_address>
**issue (typo):** Constructor parameter `depency` appears to be a misspelling of `dependency`.

建议在文档和代码中统一改为 `dependency`,以避免歧义并保持一致性。
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +840 to +841
ctx = FallbackContext(self.preset, e, self.config, self.context_wrap, i)
await MatcherManager.trigger_event(ctx, ctx.config, (FallbackFailed,))
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.

issue (bug_risk): The FallbackFailed exception type is not actually passed to exception_ignored in trigger_event.

Here (FallbackFailed,) is passed as a positional arg and is treated as an extra DI parameter, so exception_ignored remains its default (). That means FallbackFailed from a fallback matcher is caught and logged instead of re-raised. To ensure it’s ignored by _simple_run, call:

await MatcherManager.trigger_event(
    ctx,
    ctx.config,
    exception_ignored=(FallbackFailed,),
)

Comment on lines +180 to +189
def Depends(dependency: Callable[..., T | Awaitable[T]]) -> Any:
"""
Dependency injection decorator.

Args:
dependency: The dependency function to inject

Returns:
DependsFactory: A factory for dependency injection

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.

suggestion: The Depends helper returns Any and the generic argument is unused, which weakens typing for dependency injection.

Because the function returns Any, callers lose the information that DependsFactory is parameterized by T, so type checkers can’t infer the injected dependency type. Returning the concrete generic instead would preserve typing, e.g.:

def Depends(dependency: Callable[..., T | Awaitable[T]]) -> DependsFactory[T]:
    return DependsFactory(dependency)

That way, handler parameters like dep: Example = Depends(get_example) will have the correct inferred type.

Suggested implementation:

def Depends(dependency: Callable[..., T | Awaitable[T]]) -> DependsFactory[T]:
    return DependsFactory(dependency)

If Any was only used as the return type of Depends, you should also:

  1. Remove Any from the from typing import ... list in this file to avoid an unused import.

Comment thread tests/test_matcher.py

@pytest.mark.asyncio
async def test_do_runtime_resolve_exception(self):
"""Test _do_runtime_resolve with exception in dependency."""
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.

suggestion (testing): Consider adding a test for _do_runtime_resolve where an exception type listed in exception_ignored is raised, to verify the special handling path.

You can mirror test_do_runtime_resolve_exception but use a custom exception passed in exception_ignored and assert it is raised directly, e.g.:

@pytest.mark.asyncio
async def test_do_runtime_resolve_exception_ignored(self):
    class CustomError(Exception):
        pass

    async def error_dep() -> str:
        raise CustomError("ignored")

    factory = DependsFactory(error_dep)

    with pytest.raises(CustomError):
        await MatcherFactory._do_runtime_resolve(
            {},  # runtime_args
            {"key": factory},  # runtime_kwargs
            [],  # args2update
            {},  # kwargs2update
            [],  # session_args
            {},  # session_kwargs
            (CustomError,),  # exception_ignored
        )

This verifies that ignored exceptions are re-raised instead of being collected into the ExceptionGroup.

Suggested change
"""Test _do_runtime_resolve with exception in dependency."""
"""Test _do_runtime_resolve with exception in dependency."""
@pytest.mark.asyncio
async def test_do_runtime_resolve_exception_ignored(self):
class CustomError(Exception):
pass
async def error_dep() -> str:
raise CustomError("ignored")
factory = DependsFactory(error_dep)
with pytest.raises(CustomError):
await MatcherFactory._do_runtime_resolve(
{}, # runtime_args
{"key": factory}, # runtime_kwargs
[], # args2update
{}, # kwargs2update
[], # session_args
{}, # session_kwargs
(CustomError,), # exception_ignored
)

## Constructor

```python
def __init__(self, depency: Callable[..., T | Awaitable[T]])
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.

issue (typo): Parameter name depency looks like a typo and should likely be dependency.

Since this appears in user-facing API docs, updating the parameter name there as well will prevent confusion and keep terminology consistent with the rest of the text.

Suggested implementation:

def __init__(self, dependency: Callable[..., T | Awaitable[T]])

- `dependency`: The dependency function to wrap, which can return any type `T` or an awaitable object `Awaitable[T]`

## Constructor

```python
def __init__(self, depency: Callable[..., T | Awaitable[T]])
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.

issue (typo): Constructor parameter depency appears to be a misspelling of dependency.

建议在文档和代码中统一改为 dependency,以避免歧义并保持一致性。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[New Feature] Add on_model_fallback or similiar hook.

1 participant