Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions cadence/contrib/openai/cadence_handoff.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from dataclasses import dataclass
from typing import Any

from agents import Handoff
from agents.run_context import RunContextWrapper


@dataclass
class CadenceHandoff:
"""Serializable representation of a Handoff for crossing the Cadence activity boundary.
Only the fields needed by the model (tool schema) are kept; callable/runtime
fields are reconstructed with no-op stubs on the activity side."""

tool_name: str
tool_description: str
input_json_schema: dict[str, Any]
agent_name: str
strict_json_schema: bool = True


def to_cadence_handoff(handoff: Handoff[Any, Any]) -> CadenceHandoff:
return CadenceHandoff(
tool_name=handoff.tool_name,
tool_description=handoff.tool_description,
input_json_schema=handoff.input_json_schema,
agent_name=handoff.agent_name,
strict_json_schema=handoff.strict_json_schema,
)


def from_cadence_handoff(ch: CadenceHandoff) -> Handoff[Any, Any]:
async def noop_invoke(_ctx: RunContextWrapper[Any], _json: str):
raise RuntimeError("Handoff invocation is handled by the runner, not the model")

return Handoff(
tool_name=ch.tool_name,
tool_description=ch.tool_description,
input_json_schema=ch.input_json_schema,
on_invoke_handoff=noop_invoke,
agent_name=ch.agent_name,
strict_json_schema=ch.strict_json_schema,
)
30 changes: 14 additions & 16 deletions cadence/contrib/openai/cadence_model.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import AsyncIterator, cast
from typing import AsyncIterator
from agents import (
Model,
ModelSettings,
Expand All @@ -13,6 +13,7 @@
from openai.types.responses import ResponsePromptParam

from cadence.contrib.openai.cadence_tool import to_cadence_tool
from cadence.contrib.openai.cadence_handoff import to_cadence_handoff
from cadence.contrib.openai.openai_activities import OpenAIActivities


Expand All @@ -39,21 +40,18 @@ async def get_response(
run model inside cadence activity
"""
# cast needed: mypy can't infer R through ParamSpec with complex OpenAI union types
return cast(
ModelResponse,
await self._openai_activities.invoke_model(
model_name=self._model_name,
system_instructions=system_instructions,
input=input,
model_settings=model_settings,
tools=[to_cadence_tool(tool) for tool in tools],
output_schema=output_schema,
handoffs=handoffs,
tracing=tracing,
previous_response_id=previous_response_id,
conversation_id=conversation_id,
prompt=prompt,
),
return await self._openai_activities.invoke_model(
model_name=self._model_name,
system_instructions=system_instructions,
input=input,
model_settings=model_settings,
tools=[to_cadence_tool(tool) for tool in tools],
output_schema=output_schema,
handoffs=[to_cadence_handoff(h) for h in handoffs],
tracing=tracing,
previous_response_id=previous_response_id,
conversation_id=conversation_id,
prompt=prompt,
)

def stream_response(
Expand Down
6 changes: 6 additions & 0 deletions cadence/contrib/openai/cadence_registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import cadence
from cadence.contrib.openai import OpenAIActivities


cadence_registry = cadence.Registry()
cadence_registry.register_activities(OpenAIActivities())
Comment on lines +5 to +6
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Quality: Module-level side effect in cadence_registry.py

cadence_registry.py instantiates OpenAIActivities() and registers it at import time. This means merely importing the module triggers side effects (object creation, registration). Consider using a factory function or lazy initialization pattern so consumers have explicit control over when registration happens.

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

expected

6 changes: 3 additions & 3 deletions cadence/contrib/openai/openai_activities.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
TResponseInputItem,
ModelSettings,
AgentOutputSchemaBase,
Handoff,
ModelTracing,
ModelResponse,
)

from cadence.contrib.openai.cadence_tool import CadenceTool, from_cadence_tool
from cadence.contrib.openai.cadence_handoff import CadenceHandoff, from_cadence_handoff


class OpenAIActivities:
Expand All @@ -29,7 +29,7 @@ async def invoke_model(
model_settings: ModelSettings,
tools: list[CadenceTool],
output_schema: AgentOutputSchemaBase | None,
handoffs: list[Handoff],
handoffs: list[CadenceHandoff],
tracing: ModelTracing,
previous_response_id: str | None,
conversation_id: str | None,
Expand All @@ -43,7 +43,7 @@ async def invoke_model(
model_settings=model_settings,
tools=[from_cadence_tool(tool) for tool in tools],
output_schema=output_schema,
handoffs=handoffs,
handoffs=[from_cadence_handoff(h) for h in handoffs],
tracing=tracing,
previous_response_id=previous_response_id,
conversation_id=conversation_id,
Expand Down
Loading