You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Python: Allow for factory callbacks in the process framework (microsoft#10451)
### Motivation and Context
In the current Python process framework, in runtimes like Dapr, there is
no easy way to pass complex (unserializable) dependencies to a step --
this includes things like a ChatCompletion service or an agent of type
ChatCompletionAgent.
Similar to how the kernel dependency was propagated to the step_actor or
process_actor, we're introducing the ability to specify a factory
callback that will be called as the step is instantiated. The factory is
created, if specified via the optional kwarg when adding a step to the
process builder like:
```python
myBStep = process.add_step(step_type=BStep, factory_function=bstep_factory)
```
The `bstep_factory` looks like (along with its corresponding step)
```python
async def bstep_factory():
"""Creates a BStep instance with ephemeral references like ChatCompletionAgent."""
kernel = Kernel()
kernel.add_service(AzureChatCompletion())
agent = ChatCompletionAgent(kernel=kernel, name="echo", instructions="repeat the input back")
step_instance = BStep()
step_instance.agent = agent
return step_instance
class BStep(KernelProcessStep):
"""A sample BStep that optionally holds a ChatCompletionAgent.
By design, the agent is ephemeral (not stored in state).
"""
# Ephemeral references won't be persisted to Dapr
# because we do not place them in a step state model.
# We'll set this in the factory function:
agent: ChatCompletionAgent | None = None
@kernel_function(name="do_it")
async def do_it(self, context: KernelProcessStepContext):
print("##### BStep ran (do_it).")
await asyncio.sleep(2)
if self.agent:
history = ChatHistory()
history.add_user_message("Hello from BStep!")
async for msg in self.agent.invoke(history):
print(f"BStep got agent response: {msg.content}")
await context.emit_event(process_event="BStepDone", data="I did B")
```
Although this isn't explicitly necessary with the local runtime, the
factory callback will also work, if desired.
<!-- Thank you for your contribution to the semantic-kernel repo!
Please help reviewers and future users, providing the following
information:
1. Why is this change required?
2. What problem does it solve?
3. What scenario does it contribute to?
4. If it fixes an open issue, please link to the issue here.
-->
### Description
Adds the ability to specify a factory callback for a step in the process
framework.
- Adjusts the Dapr FastAPI demo sample to show how one can include a
dependency like a `ChatCompletionAgent` and use the factory callback for
`BStep`. Although the output from the agent isn't needed, it
demonstrates the capability to handle these types of dependencies while
running Dapr.
- Adds unit tests
- Closesmicrosoft#10409
<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->
### Contribution Checklist
<!-- Before submitting this PR, please make sure: -->
- [X] The code builds clean without any errors or warnings
- [X] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [X] All unit tests pass, and I have added new tests where possible
- [X] I didn't break anyone 😄
0 commit comments