mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Define Workflow and Executor APIs (#272)
* Workflow init commit * Add samples and clean up * ExecutionContext -> WorkflowContext * Address comments 1 * Fix mypy * flatting folder structure, and rename contexts * Remove add_loop * Add map reduce sample, remove Activation conditions * Add AgentExecutor and allow multiple handlers per executor * Minor improvement * Add RequestInfoExecutor * Add unit tests part 1 * Address comments 2 * Pre-commit update * Add run method and more unit tests * Add xml docs * run_stream -> run_streaming * message_handler -> handler --------- Co-authored-by: Chris <66376200+crickman@users.noreply.github.com> Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
0d4d7abde1
commit
c8694a8c76
@@ -0,0 +1,102 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import pytest
|
||||
from agent_framework.workflow import Executor, WorkflowContext, handler
|
||||
|
||||
|
||||
def test_executor_without_handlers():
|
||||
"""Test that an executor without handlers raises an error when trying to run."""
|
||||
|
||||
class MockExecutorWithoutHandlers(Executor):
|
||||
"""A mock executor that does not implement any handlers."""
|
||||
|
||||
pass
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
MockExecutorWithoutHandlers()
|
||||
|
||||
|
||||
def test_executor_handler_without_annotations():
|
||||
"""Test that an executor with one handler without annotations raises an error when trying to run."""
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
|
||||
class MockExecutorWithOneHandlerWithoutAnnotations(Executor): # type: ignore
|
||||
"""A mock executor with one handler that does not implement any annotations."""
|
||||
|
||||
@handler
|
||||
async def handle(self, message, ctx) -> None: # type: ignore
|
||||
"""A mock handler that does not implement any annotations."""
|
||||
pass
|
||||
|
||||
|
||||
def test_executor_invalid_handler_signature():
|
||||
"""Test that an executor with an invalid handler signature raises an error when trying to run."""
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
|
||||
class MockExecutorWithInvalidHandlerSignature(Executor): # type: ignore
|
||||
"""A mock executor with an invalid handler signature."""
|
||||
|
||||
@handler # type: ignore
|
||||
async def handle(self, message, other, ctx) -> None: # type: ignore
|
||||
"""A mock handler with an invalid signature."""
|
||||
pass
|
||||
|
||||
|
||||
def test_executor_with_valid_handlers():
|
||||
"""Test that an executor with valid handlers can be instantiated and run."""
|
||||
|
||||
class MockExecutorWithValidHandlers(Executor): # type: ignore
|
||||
"""A mock executor with valid handlers."""
|
||||
|
||||
@handler
|
||||
async def handle_text(self, text: str, ctx: WorkflowContext) -> None: # type: ignore
|
||||
"""A mock handler with a valid signature."""
|
||||
pass
|
||||
|
||||
@handler
|
||||
async def handle_number(self, number: int, ctx: WorkflowContext) -> None: # type: ignore
|
||||
"""Another mock handler with a valid signature."""
|
||||
pass
|
||||
|
||||
executor = MockExecutorWithValidHandlers()
|
||||
assert executor.id is not None
|
||||
assert len(executor._handlers) == 2 # type: ignore
|
||||
assert executor.can_handle("text") is True
|
||||
assert executor.can_handle(42) is True
|
||||
assert executor.can_handle(3.14) is False
|
||||
|
||||
|
||||
def test_executor_handlers_with_output_types():
|
||||
"""Test that an executor with handlers that specify output types can be instantiated and run."""
|
||||
|
||||
class MockExecutorWithOutputTypes(Executor): # type: ignore
|
||||
"""A mock executor with handlers that specify output types."""
|
||||
|
||||
@handler(output_types=[str])
|
||||
async def handle_string(self, text: str, ctx: WorkflowContext) -> None: # type: ignore
|
||||
"""A mock handler that outputs a string."""
|
||||
pass
|
||||
|
||||
@handler(output_types=[int])
|
||||
async def handle_integer(self, number: int, ctx: WorkflowContext) -> None: # type: ignore
|
||||
"""A mock handler that outputs an integer."""
|
||||
pass
|
||||
|
||||
executor = MockExecutorWithOutputTypes()
|
||||
assert len(executor._handlers) == 2 # type: ignore
|
||||
|
||||
string_handler = executor._handlers[str] # type: ignore
|
||||
assert string_handler is not None
|
||||
assert string_handler._handler_spec is not None # type: ignore
|
||||
assert string_handler._handler_spec["name"] == "handle_string" # type: ignore
|
||||
assert string_handler._handler_spec["message_type"] is str # type: ignore
|
||||
assert string_handler._handler_spec["output_types"] == [str] # type: ignore
|
||||
|
||||
int_handler = executor._handlers[int] # type: ignore
|
||||
assert int_handler is not None
|
||||
assert int_handler._handler_spec is not None # type: ignore
|
||||
assert int_handler._handler_spec["name"] == "handle_integer" # type: ignore
|
||||
assert int_handler._handler_spec["message_type"] is int # type: ignore
|
||||
assert int_handler._handler_spec["output_types"] == [int] # type: ignore
|
||||
Reference in New Issue
Block a user