-
Couldn't load subscription status.
- Fork 79
Enable Native Dapr Workflows with Message Router Decorators #233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: cyb3rward0g/llm-agent-activities
Are you sure you want to change the base?
Enable Native Dapr Workflows with Message Router Decorators #233
Conversation
Signed-off-by: Roberto Rodriguez <[email protected]>
Signed-off-by: Roberto Rodriguez <[email protected]>
Signed-off-by: Roberto Rodriguez <[email protected]>
Signed-off-by: Roberto Rodriguez <[email protected]>
Signed-off-by: Roberto Rodriguez <[email protected]>
Signed-off-by: Roberto Rodriguez <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a great addition to simplify things and support a more python-native decorator approach to handle pubsub messages and trigger workflows!
| _MESSAGE_ROUTER_DEPRECATION_MESSAGE = ( | ||
| "@message_router (legacy version from dapr_agents.workflow.decorators.messaging) " | ||
| "is deprecated and will be removed in a future release. " | ||
| "Please migrate to the updated decorator in " | ||
| "`dapr_agents.workflow.decorators.routers`, which supports " | ||
| "Union types, forward references, and explicit Dapr workflow integration." | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i vote we just remove since we are not v1.0 and beyond, we can make breaking changes and remove the message_router as long as we let folks know in the next release announcement :)
| └─ message_client.py # publishes a test message to the topic | ||
| ``` | ||
|
|
||
| ## Files |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think it might be nice moving forward for us to not put the code in the readmes and just reference/link the files/components. Thoughts?
| func: Optional[Callable[..., Any]] = None, | ||
| *, | ||
| pubsub: Optional[str] = None, | ||
| topic: Optional[str] = None, | ||
| dead_letter_topic: Optional[str] = None, | ||
| broadcast: bool = False, | ||
| ) -> Callable[[Callable[..., Any]], Callable[..., Any]]: | ||
| """ | ||
| Decorate a message handler with routing metadata. | ||
| The handler must accept a parameter named `message`. Its type hint defines the | ||
| expected payload model(s), e.g.: | ||
| @message_router(pubsub="pubsub", topic="orders") | ||
| def on_order(message: OrderCreated): ... | ||
| @message_router(pubsub="pubsub", topic="events") | ||
| def on_event(message: Union[Foo, Bar]): ... | ||
| Args: | ||
| func: (optional) bare-decorator form support. | ||
| pubsub: Name of the Dapr pub/sub component (required when used with args). | ||
| topic: Topic name to subscribe to (required when used with args). | ||
| dead_letter_topic: Optional dead-letter topic (defaults to f"{topic}_DEAD"). | ||
| broadcast: Optional flag you can use downstream for fan-out semantics. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some of these say required in the docs string but the code shows optional. Are func, pubsub, topic the ones that we require?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
IMO, In addition to declarative, programatic, and streaming subscriptions, the Message Router is another (4th) type of subscribing to a topic. It is probably the most pythonic version among all.
-
Is there anything specific to DaprAgents or can message router be even at python sdk?
-
I love this feature, just not sure where it fits best (DA or Python SDK) and what to call it? There is already the concept of subscription, and @app.route in python sdk
|
Isn't this the way to create a streaming consumer?
There is no extra time requirement, but we have to make sure:
|
that is not enough subscription = client.subscribe(
pubsub_name='pubsub', topic='orders', dead_letter_topic='orders_dead'
)We need to map it to a handler which can be done with close_fn = client.subscribe_with_handler(
pubsub_name='pubsub', topic='orders', handler_fn=process_message,
dead_letter_topic='orders_dead'
)But once again, that is not enough, the "handler_fun" in our project would point to a Dapr Workflow script which would need to be run using a dapr workflow client. Therefore, we need to create that abstraction so that we can use it on our DurableAgent or Orchestrator class which rely on a |
This PR Depends on #232
Overview
This PR introduces a new
@message_routerdecorator that enables native Dapr workflow orchestration triggered directly from Pub/Sub messages without relying on legacy Dapr Agents abstractions. Developers now have full control over the Dapr Workflow runtime and Pub/Sub client, allowing workflows and LLM/Agent activities to be registered, composed, and executed using the official Dapr APIs.This update modernizes the message routing layer to align with Dapr’s workflow primitives, improving transparency, flexibility, and maintainability.
Key Changes
decorators/routers.py@message_routerdecorator for schema-aware message routingWorkflowRuntimeand DaprClient lifecycleutils/routers.py: message extraction, validation, and CloudEvent parsing helpersutils/registration.py:register_message_handlers()for runtime subscription via the active DaprClientdecorators/messaging.pyMessage Router WorkflowQuickstartmessage_client.pypublisher and updated README with full configurationMessage Router Workflowalongside LLM- and Agent-based patterns