Skip to content

Commit c0c5616

Browse files
fix(beeai): handle removal of experimental features
Adds TYPE_CHECKING guards and try/except ImportError handling to gracefully handle beeai-framework versions that removed experimental.agent and experimental.requirements modules. This follows the existing pattern in beeai's ProcessorLocator which uses contextlib.suppress(ImportError) to handle optional framework components. Unlike ProcessorLocator's optional registration pattern, these processors require fallback values (None) when experimental features are unavailable, making try/except more appropriate than contextlib.suppress. Fixes mypy attr-defined errors in py311-ci-beeai and py311-ci-beeai-latest. Signed-off-by: Adrian Cole <[email protected]>
1 parent 047f716 commit c0c5616

File tree

3 files changed

+90
-42
lines changed

3 files changed

+90
-42
lines changed

python/instrumentation/openinference-instrumentation-beeai/src/openinference/instrumentation/beeai/processors/agents/requirement_agent.py

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
1-
from typing import Any
1+
from typing import TYPE_CHECKING, Any
2+
3+
if TYPE_CHECKING:
4+
from beeai_framework.agents.experimental.events import ( # type: ignore[attr-defined]
5+
RequirementAgentStartEvent,
6+
RequirementAgentSuccessEvent,
7+
)
8+
from beeai_framework.agents.experimental.types import ( # type: ignore[attr-defined]
9+
RequirementAgentRunStateStep,
10+
)
11+
from beeai_framework.context import RunContextStartEvent
12+
from beeai_framework.emitter import EventMeta
13+
else:
14+
try:
15+
from beeai_framework.agents.experimental.events import (
16+
RequirementAgentStartEvent,
17+
RequirementAgentSuccessEvent,
18+
)
19+
from beeai_framework.agents.experimental.types import RequirementAgentRunStateStep
20+
except ImportError:
21+
# beeai-framework removed experimental features
22+
RequirementAgentStartEvent = None # type: ignore
23+
RequirementAgentSuccessEvent = None # type: ignore
24+
RequirementAgentRunStateStep = None # type: ignore
25+
from beeai_framework.context import RunContextStartEvent
26+
from beeai_framework.emitter import EventMeta
227

3-
from beeai_framework.agents.experimental.events import (
4-
RequirementAgentStartEvent,
5-
RequirementAgentSuccessEvent,
6-
)
7-
from beeai_framework.agents.experimental.types import RequirementAgentRunStateStep
8-
from beeai_framework.context import RunContextStartEvent
9-
from beeai_framework.emitter import EventMeta
1028
from typing_extensions import override
1129

1230
from openinference.instrumentation.beeai._utils import _unpack_object
@@ -28,27 +46,26 @@ async def update(
2846
await super().update(event, meta)
2947
self.span.add_event(f"{meta.name} ({meta.path})", timestamp=meta.created_at)
3048

31-
match event:
32-
case RequirementAgentStartEvent():
33-
self._sync_steps(event.state.steps)
34-
case RequirementAgentSuccessEvent():
35-
self._sync_steps(event.state.steps)
49+
if RequirementAgentStartEvent is not None and isinstance(event, RequirementAgentStartEvent):
50+
self._sync_steps(event.state.steps)
51+
elif RequirementAgentSuccessEvent is not None and isinstance(
52+
event, RequirementAgentSuccessEvent
53+
):
54+
self._sync_steps(event.state.steps)
3655

37-
if event.state.answer is not None:
38-
self.span.set_attributes(
39-
{
40-
SpanAttributes.OUTPUT_VALUE: event.state.answer.text,
41-
SpanAttributes.OUTPUT_MIME_TYPE: OpenInferenceMimeTypeValues.TEXT.value,
42-
}
43-
)
44-
if event.state.result is not None:
45-
self.span.set_attributes(
46-
_unpack_object(
47-
event.state.result, prefix=f"{SpanAttributes.METADATA}.result"
48-
)
49-
)
50-
case _:
51-
self.span.child(meta.name, event=(event, meta))
56+
if event.state.answer is not None:
57+
self.span.set_attributes(
58+
{
59+
SpanAttributes.OUTPUT_VALUE: event.state.answer.text,
60+
SpanAttributes.OUTPUT_MIME_TYPE: OpenInferenceMimeTypeValues.TEXT.value,
61+
}
62+
)
63+
if event.state.result is not None:
64+
self.span.set_attributes(
65+
_unpack_object(event.state.result, prefix=f"{SpanAttributes.METADATA}.result")
66+
)
67+
else:
68+
self.span.child(meta.name, event=(event, meta))
5269

5370
def _sync_steps(self, steps: list["RequirementAgentRunStateStep"]) -> None:
5471
new_items = steps[len(self._steps) :]

python/instrumentation/openinference-instrumentation-beeai/src/openinference/instrumentation/beeai/processors/locator.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,18 @@ def _load() -> None:
4747
ProcessorLocator.entries[ToolCallingAgent] = ToolCallingAgentProcessor
4848

4949
with contextlib.suppress(ImportError):
50-
from beeai_framework.agents.experimental.agent import RequirementAgent
50+
from beeai_framework.agents.experimental.agent import ( # type: ignore[attr-defined]
51+
RequirementAgent,
52+
)
5153

5254
from .agents.requirement_agent import RequirementAgentProcessor
5355

5456
ProcessorLocator.entries[RequirementAgent] = RequirementAgentProcessor
5557

5658
with contextlib.suppress(ImportError):
57-
from beeai_framework.agents.experimental.requirements.requirement import Requirement
59+
from beeai_framework.agents.experimental.requirements.requirement import ( # type: ignore[attr-defined]
60+
Requirement,
61+
)
5862

5963
from openinference.instrumentation.beeai.processors.requirement import (
6064
RequirementProcessor,

python/instrumentation/openinference-instrumentation-beeai/src/openinference/instrumentation/beeai/processors/requirement.py

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,39 @@
1-
from typing import Any, ClassVar
1+
from typing import TYPE_CHECKING, Any, ClassVar
2+
3+
if TYPE_CHECKING:
4+
from beeai_framework.agents.experimental.requirements.ask_permission import ( # type: ignore[attr-defined]
5+
AskPermissionRequirement,
6+
)
7+
from beeai_framework.agents.experimental.requirements.conditional import ( # type: ignore[attr-defined]
8+
ConditionalRequirement,
9+
)
10+
from beeai_framework.agents.experimental.requirements.events import ( # type: ignore[attr-defined]
11+
RequirementInitEvent,
12+
)
13+
from beeai_framework.agents.experimental.requirements.requirement import ( # type: ignore[attr-defined]
14+
Requirement,
15+
)
16+
from beeai_framework.context import RunContext, RunContextStartEvent
17+
from beeai_framework.emitter import EventMeta
18+
else:
19+
try:
20+
from beeai_framework.agents.experimental.requirements.ask_permission import (
21+
AskPermissionRequirement,
22+
)
23+
from beeai_framework.agents.experimental.requirements.conditional import (
24+
ConditionalRequirement,
25+
)
26+
from beeai_framework.agents.experimental.requirements.events import RequirementInitEvent
27+
from beeai_framework.agents.experimental.requirements.requirement import Requirement
28+
except ImportError:
29+
# beeai-framework removed experimental features
30+
AskPermissionRequirement = None # type: ignore
31+
ConditionalRequirement = None # type: ignore
32+
RequirementInitEvent = None # type: ignore
33+
Requirement = None # type: ignore
34+
from beeai_framework.context import RunContext, RunContextStartEvent
35+
from beeai_framework.emitter import EventMeta
236

3-
from beeai_framework.agents.experimental.requirements.ask_permission import AskPermissionRequirement
4-
from beeai_framework.agents.experimental.requirements.conditional import ConditionalRequirement
5-
from beeai_framework.agents.experimental.requirements.events import RequirementInitEvent
6-
from beeai_framework.agents.experimental.requirements.requirement import Requirement
7-
from beeai_framework.context import RunContext, RunContextStartEvent
8-
from beeai_framework.emitter import EventMeta
937
from typing_extensions import override
1038

1139
from openinference.instrumentation.beeai._utils import _unpack_object
@@ -60,8 +88,7 @@ async def update(
6088

6189
self.span.add_event(f"{meta.name} ({meta.path})", timestamp=meta.created_at)
6290

63-
match event:
64-
case RequirementInitEvent():
65-
pass
66-
case _:
67-
self.span.child(meta.name, event=(event, meta))
91+
if RequirementInitEvent is not None and isinstance(event, RequirementInitEvent):
92+
pass
93+
else:
94+
self.span.child(meta.name, event=(event, meta))

0 commit comments

Comments
 (0)