|
7 | 7 | from datetime import timedelta
|
8 | 8 | from inspect import iscoroutinefunction
|
9 | 9 | from types import ModuleType, SimpleNamespace
|
10 |
| -from typing import ClassVar, Generic, cast, overload |
| 10 | +from typing import ClassVar, Generic, TypeVar, cast, overload |
11 | 11 |
|
12 | 12 | from pydantic import BaseModel, Field
|
13 | 13 | from typing_extensions import Self
|
@@ -82,11 +82,70 @@ class AgentOptions(Options, Generic[LLMClientOptionsT]):
|
82 | 82 | or None, agent will run forever"""
|
83 | 83 |
|
84 | 84 |
|
85 |
| -class AgentRunContext(BaseModel): |
| 85 | +DepsT = TypeVar("DepsT") |
| 86 | + |
| 87 | + |
| 88 | +class AgentDependencies(BaseModel, Generic[DepsT]): |
86 | 89 | """
|
87 |
| - Context for the agent run. |
| 90 | + Container for agent runtime dependencies. |
| 91 | +
|
| 92 | + Becomes immutable after first attribute access. |
88 | 93 | """
|
89 | 94 |
|
| 95 | + model_config = {"arbitrary_types_allowed": True} |
| 96 | + |
| 97 | + _frozen: bool |
| 98 | + _value: DepsT | None |
| 99 | + |
| 100 | + def __init__(self, value: DepsT | None = None) -> None: |
| 101 | + super().__init__() |
| 102 | + self._value = value |
| 103 | + self._frozen = False |
| 104 | + |
| 105 | + def __setattr__(self, name: str, value: object) -> None: |
| 106 | + is_frozen = False |
| 107 | + if name != "_frozen": |
| 108 | + try: |
| 109 | + is_frozen = object.__getattribute__(self, "_frozen") |
| 110 | + except AttributeError: |
| 111 | + is_frozen = False |
| 112 | + |
| 113 | + if is_frozen and name not in {"_frozen"}: |
| 114 | + raise RuntimeError("Dependencies are immutable after first access") |
| 115 | + |
| 116 | + super().__setattr__(name, value) |
| 117 | + |
| 118 | + @property |
| 119 | + def value(self) -> DepsT | None: |
| 120 | + return self._value |
| 121 | + |
| 122 | + @value.setter |
| 123 | + def value(self, value: DepsT) -> None: |
| 124 | + if self._frozen: |
| 125 | + raise RuntimeError("Dependencies are immutable after first access") |
| 126 | + self._value = value |
| 127 | + |
| 128 | + def _freeze(self) -> None: |
| 129 | + if not self._frozen: |
| 130 | + self._frozen = True |
| 131 | + |
| 132 | + def __getattr__(self, name: str) -> object: |
| 133 | + value = object.__getattribute__(self, "_value") |
| 134 | + if value is None: |
| 135 | + raise AttributeError(name) |
| 136 | + self._freeze() |
| 137 | + return getattr(value, name) |
| 138 | + |
| 139 | + def __contains__(self, key: str) -> bool: |
| 140 | + value = object.__getattribute__(self, "_value") |
| 141 | + return hasattr(value, key) if value is not None else False |
| 142 | + |
| 143 | + |
| 144 | +class AgentRunContext(BaseModel, Generic[DepsT]): |
| 145 | + """Context for the agent run.""" |
| 146 | + |
| 147 | + deps: AgentDependencies[DepsT] = Field(default_factory=lambda: AgentDependencies()) |
| 148 | + """Container for external dependencies.""" |
90 | 149 | usage: Usage = Field(default_factory=Usage)
|
91 | 150 | """The usage of the agent."""
|
92 | 151 |
|
|
0 commit comments