-
Notifications
You must be signed in to change notification settings - Fork 4
feat: add AgentRunner, AgentGraphRunner ABCs and result types (PR-4) #103
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
Merged
Merged
Changes from 1 commit
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| """Runner ABCs and result types for LaunchDarkly AI SDK.""" | ||
|
|
||
| from ldai.runners.agent_graph_runner import AgentGraphRunner | ||
| from ldai.runners.agent_runner import AgentRunner | ||
| from ldai.runners.types import AgentGraphResult, AgentResult, ToolRegistry | ||
|
|
||
| __all__ = [ | ||
| 'AgentRunner', | ||
| 'AgentGraphRunner', | ||
| 'AgentResult', | ||
| 'AgentGraphResult', | ||
| 'ToolRegistry', | ||
| ] |
26 changes: 26 additions & 0 deletions
26
packages/sdk/server-ai/src/ldai/runners/agent_graph_runner.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| """Abstract base class for agent graph runners.""" | ||
|
|
||
| from abc import ABC, abstractmethod | ||
| from typing import Any | ||
|
|
||
| from ldai.runners.types import AgentGraphResult | ||
|
|
||
|
|
||
| class AgentGraphRunner(ABC): | ||
| """ | ||
| Abstract base class for agent graph runners. | ||
|
|
||
| An AgentGraphRunner encapsulates multi-agent graph execution. | ||
| Provider-specific implementations (e.g. OpenAIAgentGraphRunner) are | ||
| returned by RunnerFactory.create_agent_graph() and hold all provider | ||
| wiring internally. | ||
| """ | ||
|
|
||
| @abstractmethod | ||
| async def run(self, input: Any) -> AgentGraphResult: | ||
| """ | ||
| Run the agent graph with the given input. | ||
|
|
||
| :param input: The input to the agent graph (string prompt or structured input) | ||
| :return: AgentGraphResult containing the output, raw response, and metrics | ||
| """ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| """Abstract base class for agent runners.""" | ||
|
|
||
| from abc import ABC, abstractmethod | ||
| from typing import Any | ||
|
|
||
| from ldai.runners.types import AgentResult | ||
|
|
||
|
|
||
| class AgentRunner(ABC): | ||
| """ | ||
| Abstract base class for single-agent runners. | ||
|
|
||
| An AgentRunner encapsulates the execution of a single AI agent. | ||
| Provider-specific implementations (e.g. OpenAIAgentRunner) are returned | ||
| by RunnerFactory.create_agent() and hold all provider wiring internally. | ||
| """ | ||
|
|
||
| @abstractmethod | ||
| async def run(self, input: Any) -> AgentResult: | ||
| """ | ||
| Run the agent with the given input. | ||
|
|
||
| :param input: The input to the agent (string prompt or structured input) | ||
| :return: AgentResult containing the output, raw response, and metrics | ||
| """ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| """Result types and type aliases for agent and agent graph runners.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from dataclasses import dataclass | ||
| from typing import Any, Callable, Dict | ||
|
|
||
| from ldai.providers.types import LDAIMetrics | ||
|
|
||
| # Type alias for a registry of tools available to an agent. | ||
| # Keys are tool names; values are the callable implementations. | ||
| ToolRegistry = Dict[str, Callable] | ||
|
|
||
|
|
||
| @dataclass | ||
| class AgentResult: | ||
| """ | ||
| Result from a single-agent run. | ||
| """ | ||
| output: str | ||
| raw: Any | ||
| metrics: LDAIMetrics | ||
|
|
||
|
|
||
| @dataclass | ||
| class AgentGraphResult: | ||
| """ | ||
| Result from an agent graph run. | ||
| """ | ||
| output: str | ||
| raw: Any | ||
| metrics: LDAIMetrics | ||
|
jsonbailey marked this conversation as resolved.
Outdated
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| import pytest | ||
|
|
||
| from ldai.providers.types import LDAIMetrics | ||
| from ldai.runners.agent_graph_runner import AgentGraphRunner | ||
| from ldai.runners.agent_runner import AgentRunner | ||
| from ldai.runners.types import AgentGraphResult, AgentResult, ToolRegistry | ||
|
|
||
|
|
||
| # --- Concrete test doubles --- | ||
|
|
||
| class ConcreteAgentRunner(AgentRunner): | ||
| async def run(self, input): | ||
| return AgentResult( | ||
| output=f"agent response to: {input}", | ||
| raw={"raw": input}, | ||
| metrics=LDAIMetrics(success=True), | ||
| ) | ||
|
|
||
|
|
||
| class ConcreteAgentGraphRunner(AgentGraphRunner): | ||
| async def run(self, input): | ||
| return AgentGraphResult( | ||
| output=f"graph response to: {input}", | ||
| raw={"raw": input}, | ||
| metrics=LDAIMetrics(success=True), | ||
| ) | ||
|
|
||
|
|
||
| # --- AgentRunner --- | ||
|
|
||
| def test_agent_runner_is_abstract(): | ||
| with pytest.raises(TypeError): | ||
| AgentRunner() # type: ignore[abstract] | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_agent_runner_run_returns_agent_result(): | ||
| runner = ConcreteAgentRunner() | ||
| result = await runner.run("hello") | ||
| assert isinstance(result, AgentResult) | ||
| assert result.output == "agent response to: hello" | ||
| assert result.raw == {"raw": "hello"} | ||
| assert result.metrics.success is True | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_agent_result_fields(): | ||
| metrics = LDAIMetrics(success=True) | ||
| result = AgentResult(output="done", raw={"key": "val"}, metrics=metrics) | ||
| assert result.output == "done" | ||
| assert result.raw == {"key": "val"} | ||
| assert result.metrics is metrics | ||
|
|
||
|
|
||
| # --- AgentGraphRunner --- | ||
|
|
||
| def test_agent_graph_runner_is_abstract(): | ||
| with pytest.raises(TypeError): | ||
| AgentGraphRunner() # type: ignore[abstract] | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_agent_graph_runner_run_returns_agent_graph_result(): | ||
| runner = ConcreteAgentGraphRunner() | ||
| result = await runner.run("hello graph") | ||
| assert isinstance(result, AgentGraphResult) | ||
| assert result.output == "graph response to: hello graph" | ||
| assert result.raw == {"raw": "hello graph"} | ||
| assert result.metrics.success is True | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_agent_graph_result_fields(): | ||
| metrics = LDAIMetrics(success=False) | ||
| result = AgentGraphResult(output="", raw=None, metrics=metrics) | ||
| assert result.output == "" | ||
| assert result.raw is None | ||
| assert result.metrics.success is False | ||
|
|
||
|
|
||
| # --- ToolRegistry --- | ||
|
|
||
| def test_tool_registry_is_dict_of_callables(): | ||
| tools: ToolRegistry = { | ||
| "search": lambda q: f"results for {q}", | ||
| "calculator": lambda x: x * 2, | ||
| } | ||
| assert tools["search"]("python") == "results for python" | ||
| assert tools["calculator"](21) == 42 | ||
|
|
||
|
|
||
| # --- Top-level exports --- | ||
|
|
||
| def test_top_level_exports(): | ||
| import ldai | ||
| assert hasattr(ldai, 'AgentRunner') | ||
| assert hasattr(ldai, 'AgentGraphRunner') | ||
| assert hasattr(ldai, 'AgentResult') | ||
| assert hasattr(ldai, 'AgentGraphResult') | ||
| assert hasattr(ldai, 'ToolRegistry') |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.