agent-runtime-core 0.6.0__tar.gz → 0.7.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/PKG-INFO +202 -1
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/README.md +195 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/__init__.py +118 -2
- agent_runtime_core-0.7.1/agent_runtime_core/agentic_loop.py +254 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/config.py +54 -4
- agent_runtime_core-0.7.1/agent_runtime_core/config_schema.py +307 -0
- agent_runtime_core-0.7.1/agent_runtime_core/contexts.py +348 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/interfaces.py +106 -0
- agent_runtime_core-0.7.1/agent_runtime_core/json_runtime.py +509 -0
- agent_runtime_core-0.7.1/agent_runtime_core/llm/__init__.py +156 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/llm/anthropic.py +133 -12
- agent_runtime_core-0.7.1/agent_runtime_core/llm/models_config.py +180 -0
- agent_runtime_core-0.7.1/agent_runtime_core/memory/__init__.py +70 -0
- agent_runtime_core-0.7.1/agent_runtime_core/memory/manager.py +554 -0
- agent_runtime_core-0.7.1/agent_runtime_core/memory/mixin.py +294 -0
- agent_runtime_core-0.7.1/agent_runtime_core/multi_agent.py +569 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/persistence/__init__.py +2 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/persistence/file.py +277 -0
- agent_runtime_core-0.7.1/agent_runtime_core/rag/__init__.py +65 -0
- agent_runtime_core-0.7.1/agent_runtime_core/rag/chunking.py +224 -0
- agent_runtime_core-0.7.1/agent_runtime_core/rag/indexer.py +253 -0
- agent_runtime_core-0.7.1/agent_runtime_core/rag/retriever.py +261 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/runner.py +193 -15
- agent_runtime_core-0.7.1/agent_runtime_core/tool_calling_agent.py +214 -0
- agent_runtime_core-0.7.1/agent_runtime_core/tools.py +179 -0
- agent_runtime_core-0.7.1/agent_runtime_core/vectorstore/__init__.py +193 -0
- agent_runtime_core-0.7.1/agent_runtime_core/vectorstore/base.py +138 -0
- agent_runtime_core-0.7.1/agent_runtime_core/vectorstore/embeddings.py +242 -0
- agent_runtime_core-0.7.1/agent_runtime_core/vectorstore/sqlite_vec.py +328 -0
- agent_runtime_core-0.7.1/agent_runtime_core/vectorstore/vertex.py +295 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/pyproject.toml +6 -1
- agent_runtime_core-0.7.1/tests/test_contexts.py +263 -0
- agent_runtime_core-0.7.1/tests/test_memory.py +503 -0
- agent_runtime_core-0.7.1/tests/test_multi_agent.py +465 -0
- agent_runtime_core-0.7.1/tests/test_rag.py +235 -0
- agent_runtime_core-0.7.1/tests/test_tools.py +275 -0
- agent_runtime_core-0.7.1/tests/test_vectorstore.py +242 -0
- agent_runtime_core-0.6.0/agent_runtime_core/llm/__init__.py +0 -83
- agent_runtime_core-0.6.0/agent_runtime_core/tool_calling_agent.py +0 -256
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/.gitignore +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/LICENSE +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/events/__init__.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/events/base.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/events/memory.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/events/redis.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/events/sqlite.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/llm/litellm_client.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/llm/openai.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/persistence/base.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/persistence/manager.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/queue/__init__.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/queue/base.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/queue/memory.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/queue/redis.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/queue/sqlite.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/registry.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/state/__init__.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/state/base.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/state/memory.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/state/redis.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/state/sqlite.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/steps.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/testing.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/tracing/__init__.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/tracing/langfuse.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/agent_runtime_core/tracing/noop.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/tests/__init__.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/tests/test_events.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/tests/test_imports.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/tests/test_persistence.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/tests/test_queue.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/tests/test_state.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/tests/test_steps.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/tests/test_testing.py +0 -0
- {agent_runtime_core-0.6.0 → agent_runtime_core-0.7.1}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-runtime-core
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Summary: Framework-agnostic Python library for executing AI agents with consistent patterns
|
|
5
5
|
Project-URL: Homepage, https://github.com/makemore/agent-runtime-core
|
|
6
6
|
Project-URL: Repository, https://github.com/makemore/agent-runtime-core
|
|
@@ -19,10 +19,12 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
19
19
|
Requires-Python: >=3.11
|
|
20
20
|
Provides-Extra: all
|
|
21
21
|
Requires-Dist: anthropic>=0.18.0; extra == 'all'
|
|
22
|
+
Requires-Dist: google-cloud-aiplatform>=1.38.0; extra == 'all'
|
|
22
23
|
Requires-Dist: langfuse>=2.0.0; extra == 'all'
|
|
23
24
|
Requires-Dist: litellm>=1.0.0; extra == 'all'
|
|
24
25
|
Requires-Dist: openai>=1.0.0; extra == 'all'
|
|
25
26
|
Requires-Dist: redis>=5.0.0; extra == 'all'
|
|
27
|
+
Requires-Dist: sqlite-vec>=0.1.0; extra == 'all'
|
|
26
28
|
Provides-Extra: anthropic
|
|
27
29
|
Requires-Dist: anthropic>=0.18.0; extra == 'anthropic'
|
|
28
30
|
Provides-Extra: dev
|
|
@@ -39,6 +41,10 @@ Provides-Extra: openai
|
|
|
39
41
|
Requires-Dist: openai>=1.0.0; extra == 'openai'
|
|
40
42
|
Provides-Extra: redis
|
|
41
43
|
Requires-Dist: redis>=5.0.0; extra == 'redis'
|
|
44
|
+
Provides-Extra: sqlite-vec
|
|
45
|
+
Requires-Dist: sqlite-vec>=0.1.0; extra == 'sqlite-vec'
|
|
46
|
+
Provides-Extra: vertex
|
|
47
|
+
Requires-Dist: google-cloud-aiplatform>=1.38.0; extra == 'vertex'
|
|
42
48
|
Description-Content-Type: text/markdown
|
|
43
49
|
|
|
44
50
|
# agent-runtime-core
|
|
@@ -53,6 +59,7 @@ A lightweight, framework-agnostic Python library for building AI agent systems.
|
|
|
53
59
|
|
|
54
60
|
| Version | Date | Changes |
|
|
55
61
|
|---------|------|---------|
|
|
62
|
+
| **0.7.1** | 2026-01-24 | RAG module, vector stores (sqlite-vec, Vertex AI), memory system, multi-agent support, agentic loop, JSON runtime |
|
|
56
63
|
| **0.6.0** | 2025-01-23 | Enhanced registry with factory functions and class registration |
|
|
57
64
|
| **0.5.2** | 2025-01-14 | Add ToolCallingAgent base class, execute_with_events helper |
|
|
58
65
|
| **0.5.1** | 2025-01-13 | Bug fixes and improvements |
|
|
@@ -820,6 +827,200 @@ The executor emits events for observability:
|
|
|
820
827
|
- `EventType.STEP_SKIPPED` - Step skipped (already completed)
|
|
821
828
|
- `EventType.PROGRESS_UPDATE` - Progress percentage update
|
|
822
829
|
|
|
830
|
+
## Multi-Agent Systems
|
|
831
|
+
|
|
832
|
+
The `multi_agent` module provides the "agent-as-tool" pattern, allowing agents to invoke other agents as tools. This enables router/dispatcher patterns, hierarchical agent systems, and specialist delegation.
|
|
833
|
+
|
|
834
|
+
### Core Concepts
|
|
835
|
+
|
|
836
|
+
**Invocation Modes:**
|
|
837
|
+
- `DELEGATE`: Sub-agent runs and returns result to parent (parent continues). Good for "get me an answer".
|
|
838
|
+
- `HANDOFF`: Control transfers completely to sub-agent (parent exits). Good for "transfer this customer to billing".
|
|
839
|
+
|
|
840
|
+
**Context Modes:**
|
|
841
|
+
- `FULL`: Complete conversation history passed to sub-agent (default)
|
|
842
|
+
- `SUMMARY`: Summarized context + current message (more efficient)
|
|
843
|
+
- `MESSAGE_ONLY`: Only the invocation message (clean isolation)
|
|
844
|
+
|
|
845
|
+
### Creating Agent Tools
|
|
846
|
+
|
|
847
|
+
Wrap any agent as a tool that can be called by other agents:
|
|
848
|
+
|
|
849
|
+
```python
|
|
850
|
+
from agent_runtime_core.multi_agent import (
|
|
851
|
+
AgentTool,
|
|
852
|
+
InvocationMode,
|
|
853
|
+
ContextMode,
|
|
854
|
+
invoke_agent,
|
|
855
|
+
register_agent_tools,
|
|
856
|
+
)
|
|
857
|
+
|
|
858
|
+
# Define specialist agents
|
|
859
|
+
class BillingAgent(AgentRuntime):
|
|
860
|
+
@property
|
|
861
|
+
def key(self) -> str:
|
|
862
|
+
return "billing-specialist"
|
|
863
|
+
|
|
864
|
+
async def run(self, ctx: RunContext) -> RunResult:
|
|
865
|
+
# Handle billing questions, refunds, payments
|
|
866
|
+
...
|
|
867
|
+
|
|
868
|
+
class TechSupportAgent(AgentRuntime):
|
|
869
|
+
@property
|
|
870
|
+
def key(self) -> str:
|
|
871
|
+
return "tech-support"
|
|
872
|
+
|
|
873
|
+
async def run(self, ctx: RunContext) -> RunResult:
|
|
874
|
+
# Handle technical issues
|
|
875
|
+
...
|
|
876
|
+
|
|
877
|
+
# Wrap agents as tools
|
|
878
|
+
billing_tool = AgentTool(
|
|
879
|
+
agent=BillingAgent(),
|
|
880
|
+
name="billing_specialist",
|
|
881
|
+
description="Handles billing questions, refunds, and payment issues. Use when customer has billing-related questions.",
|
|
882
|
+
invocation_mode=InvocationMode.DELEGATE,
|
|
883
|
+
context_mode=ContextMode.FULL,
|
|
884
|
+
)
|
|
885
|
+
|
|
886
|
+
tech_support_tool = AgentTool(
|
|
887
|
+
agent=TechSupportAgent(),
|
|
888
|
+
name="tech_support",
|
|
889
|
+
description="Handles technical issues and troubleshooting. Use for technical problems.",
|
|
890
|
+
invocation_mode=InvocationMode.HANDOFF, # Transfer control completely
|
|
891
|
+
)
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
### Router Agent Pattern
|
|
895
|
+
|
|
896
|
+
Create a router agent that delegates to specialists:
|
|
897
|
+
|
|
898
|
+
```python
|
|
899
|
+
class RouterAgent(AgentRuntime):
|
|
900
|
+
"""Routes customer requests to appropriate specialist agents."""
|
|
901
|
+
|
|
902
|
+
def __init__(self):
|
|
903
|
+
self.agent_tools = [billing_tool, tech_support_tool]
|
|
904
|
+
|
|
905
|
+
@property
|
|
906
|
+
def key(self) -> str:
|
|
907
|
+
return "customer-router"
|
|
908
|
+
|
|
909
|
+
async def run(self, ctx: RunContext) -> RunResult:
|
|
910
|
+
from agent_runtime_core.llm import get_llm_client
|
|
911
|
+
llm = get_llm_client()
|
|
912
|
+
|
|
913
|
+
# Create tool registry with agent-tools
|
|
914
|
+
tools = ToolRegistry()
|
|
915
|
+
messages = list(ctx.input_messages)
|
|
916
|
+
|
|
917
|
+
# Register agent-tools as callable tools
|
|
918
|
+
register_agent_tools(
|
|
919
|
+
registry=tools,
|
|
920
|
+
agent_tools=self.agent_tools,
|
|
921
|
+
get_conversation_history=lambda: messages,
|
|
922
|
+
parent_ctx=ctx,
|
|
923
|
+
)
|
|
924
|
+
|
|
925
|
+
# Add system prompt for routing
|
|
926
|
+
system_message = {
|
|
927
|
+
"role": "system",
|
|
928
|
+
"content": """You are a customer service router. Analyze the customer's
|
|
929
|
+
request and delegate to the appropriate specialist:
|
|
930
|
+
- billing_specialist: For billing, payments, refunds
|
|
931
|
+
- tech_support: For technical issues (this will transfer the customer)
|
|
932
|
+
|
|
933
|
+
If you can answer directly, do so. Otherwise, use the appropriate tool."""
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
while True:
|
|
937
|
+
response = await llm.generate(
|
|
938
|
+
[system_message] + messages,
|
|
939
|
+
tools=tools.to_openai_format(),
|
|
940
|
+
)
|
|
941
|
+
|
|
942
|
+
messages.append(response.message)
|
|
943
|
+
|
|
944
|
+
if not response.tool_calls:
|
|
945
|
+
# No tool call - respond directly
|
|
946
|
+
await ctx.emit(EventType.ASSISTANT_MESSAGE, {
|
|
947
|
+
"content": response.content,
|
|
948
|
+
})
|
|
949
|
+
break
|
|
950
|
+
|
|
951
|
+
# Execute tool calls (which may invoke sub-agents)
|
|
952
|
+
for tool_call in response.tool_calls:
|
|
953
|
+
result = await tools.execute_with_events(tool_call, ctx)
|
|
954
|
+
|
|
955
|
+
# Check for handoff
|
|
956
|
+
if isinstance(result, dict) and result.get("handoff"):
|
|
957
|
+
# Sub-agent took over - we're done
|
|
958
|
+
return RunResult(
|
|
959
|
+
final_output=result.get("final_output", {}),
|
|
960
|
+
final_messages=messages,
|
|
961
|
+
)
|
|
962
|
+
|
|
963
|
+
# Add result to conversation
|
|
964
|
+
messages.append({
|
|
965
|
+
"role": "tool",
|
|
966
|
+
"tool_call_id": tool_call.id,
|
|
967
|
+
"content": str(result.get("response", result)),
|
|
968
|
+
})
|
|
969
|
+
|
|
970
|
+
return RunResult(
|
|
971
|
+
final_output={"response": response.content},
|
|
972
|
+
final_messages=messages,
|
|
973
|
+
)
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
### Direct Invocation
|
|
977
|
+
|
|
978
|
+
You can also invoke agents directly without the tool pattern:
|
|
979
|
+
|
|
980
|
+
```python
|
|
981
|
+
from agent_runtime_core.multi_agent import invoke_agent
|
|
982
|
+
|
|
983
|
+
# Invoke a sub-agent directly
|
|
984
|
+
result = await invoke_agent(
|
|
985
|
+
agent_tool=billing_tool,
|
|
986
|
+
message="Customer wants a refund for order #123",
|
|
987
|
+
parent_ctx=ctx,
|
|
988
|
+
conversation_history=messages,
|
|
989
|
+
additional_context="Customer has been waiting 2 weeks",
|
|
990
|
+
)
|
|
991
|
+
|
|
992
|
+
if result.handoff:
|
|
993
|
+
# Sub-agent took over
|
|
994
|
+
return RunResult(final_output=result.run_result.final_output)
|
|
995
|
+
else:
|
|
996
|
+
# Use the response
|
|
997
|
+
print(result.response)
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
### Events
|
|
1001
|
+
|
|
1002
|
+
Multi-agent invocations emit events for observability:
|
|
1003
|
+
|
|
1004
|
+
- `sub_agent.start` - Sub-agent invocation started
|
|
1005
|
+
- `sub_agent.end` - Sub-agent invocation completed
|
|
1006
|
+
- `tool.call` with `is_agent_tool: true` - Agent-tool was called
|
|
1007
|
+
- `tool.result` with `is_agent_tool: true` - Agent-tool returned
|
|
1008
|
+
|
|
1009
|
+
### AgentTool Options
|
|
1010
|
+
|
|
1011
|
+
```python
|
|
1012
|
+
AgentTool(
|
|
1013
|
+
agent=my_agent, # Required: The agent to wrap
|
|
1014
|
+
name="specialist", # Required: Tool name
|
|
1015
|
+
description="When to use this agent", # Required: Shown to parent LLM
|
|
1016
|
+
invocation_mode=InvocationMode.DELEGATE, # DELEGATE or HANDOFF
|
|
1017
|
+
context_mode=ContextMode.FULL, # FULL, SUMMARY, or MESSAGE_ONLY
|
|
1018
|
+
max_turns=10, # Optional: Limit sub-agent turns
|
|
1019
|
+
input_schema={...}, # Optional: Custom input schema
|
|
1020
|
+
metadata={"category": "billing"}, # Optional: Additional metadata
|
|
1021
|
+
)
|
|
1022
|
+
```
|
|
1023
|
+
|
|
823
1024
|
## API Reference
|
|
824
1025
|
|
|
825
1026
|
### Configuration
|
|
@@ -10,6 +10,7 @@ A lightweight, framework-agnostic Python library for building AI agent systems.
|
|
|
10
10
|
|
|
11
11
|
| Version | Date | Changes |
|
|
12
12
|
|---------|------|---------|
|
|
13
|
+
| **0.7.1** | 2026-01-24 | RAG module, vector stores (sqlite-vec, Vertex AI), memory system, multi-agent support, agentic loop, JSON runtime |
|
|
13
14
|
| **0.6.0** | 2025-01-23 | Enhanced registry with factory functions and class registration |
|
|
14
15
|
| **0.5.2** | 2025-01-14 | Add ToolCallingAgent base class, execute_with_events helper |
|
|
15
16
|
| **0.5.1** | 2025-01-13 | Bug fixes and improvements |
|
|
@@ -777,6 +778,200 @@ The executor emits events for observability:
|
|
|
777
778
|
- `EventType.STEP_SKIPPED` - Step skipped (already completed)
|
|
778
779
|
- `EventType.PROGRESS_UPDATE` - Progress percentage update
|
|
779
780
|
|
|
781
|
+
## Multi-Agent Systems
|
|
782
|
+
|
|
783
|
+
The `multi_agent` module provides the "agent-as-tool" pattern, allowing agents to invoke other agents as tools. This enables router/dispatcher patterns, hierarchical agent systems, and specialist delegation.
|
|
784
|
+
|
|
785
|
+
### Core Concepts
|
|
786
|
+
|
|
787
|
+
**Invocation Modes:**
|
|
788
|
+
- `DELEGATE`: Sub-agent runs and returns result to parent (parent continues). Good for "get me an answer".
|
|
789
|
+
- `HANDOFF`: Control transfers completely to sub-agent (parent exits). Good for "transfer this customer to billing".
|
|
790
|
+
|
|
791
|
+
**Context Modes:**
|
|
792
|
+
- `FULL`: Complete conversation history passed to sub-agent (default)
|
|
793
|
+
- `SUMMARY`: Summarized context + current message (more efficient)
|
|
794
|
+
- `MESSAGE_ONLY`: Only the invocation message (clean isolation)
|
|
795
|
+
|
|
796
|
+
### Creating Agent Tools
|
|
797
|
+
|
|
798
|
+
Wrap any agent as a tool that can be called by other agents:
|
|
799
|
+
|
|
800
|
+
```python
|
|
801
|
+
from agent_runtime_core.multi_agent import (
|
|
802
|
+
AgentTool,
|
|
803
|
+
InvocationMode,
|
|
804
|
+
ContextMode,
|
|
805
|
+
invoke_agent,
|
|
806
|
+
register_agent_tools,
|
|
807
|
+
)
|
|
808
|
+
|
|
809
|
+
# Define specialist agents
|
|
810
|
+
class BillingAgent(AgentRuntime):
|
|
811
|
+
@property
|
|
812
|
+
def key(self) -> str:
|
|
813
|
+
return "billing-specialist"
|
|
814
|
+
|
|
815
|
+
async def run(self, ctx: RunContext) -> RunResult:
|
|
816
|
+
# Handle billing questions, refunds, payments
|
|
817
|
+
...
|
|
818
|
+
|
|
819
|
+
class TechSupportAgent(AgentRuntime):
|
|
820
|
+
@property
|
|
821
|
+
def key(self) -> str:
|
|
822
|
+
return "tech-support"
|
|
823
|
+
|
|
824
|
+
async def run(self, ctx: RunContext) -> RunResult:
|
|
825
|
+
# Handle technical issues
|
|
826
|
+
...
|
|
827
|
+
|
|
828
|
+
# Wrap agents as tools
|
|
829
|
+
billing_tool = AgentTool(
|
|
830
|
+
agent=BillingAgent(),
|
|
831
|
+
name="billing_specialist",
|
|
832
|
+
description="Handles billing questions, refunds, and payment issues. Use when customer has billing-related questions.",
|
|
833
|
+
invocation_mode=InvocationMode.DELEGATE,
|
|
834
|
+
context_mode=ContextMode.FULL,
|
|
835
|
+
)
|
|
836
|
+
|
|
837
|
+
tech_support_tool = AgentTool(
|
|
838
|
+
agent=TechSupportAgent(),
|
|
839
|
+
name="tech_support",
|
|
840
|
+
description="Handles technical issues and troubleshooting. Use for technical problems.",
|
|
841
|
+
invocation_mode=InvocationMode.HANDOFF, # Transfer control completely
|
|
842
|
+
)
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
### Router Agent Pattern
|
|
846
|
+
|
|
847
|
+
Create a router agent that delegates to specialists:
|
|
848
|
+
|
|
849
|
+
```python
|
|
850
|
+
class RouterAgent(AgentRuntime):
|
|
851
|
+
"""Routes customer requests to appropriate specialist agents."""
|
|
852
|
+
|
|
853
|
+
def __init__(self):
|
|
854
|
+
self.agent_tools = [billing_tool, tech_support_tool]
|
|
855
|
+
|
|
856
|
+
@property
|
|
857
|
+
def key(self) -> str:
|
|
858
|
+
return "customer-router"
|
|
859
|
+
|
|
860
|
+
async def run(self, ctx: RunContext) -> RunResult:
|
|
861
|
+
from agent_runtime_core.llm import get_llm_client
|
|
862
|
+
llm = get_llm_client()
|
|
863
|
+
|
|
864
|
+
# Create tool registry with agent-tools
|
|
865
|
+
tools = ToolRegistry()
|
|
866
|
+
messages = list(ctx.input_messages)
|
|
867
|
+
|
|
868
|
+
# Register agent-tools as callable tools
|
|
869
|
+
register_agent_tools(
|
|
870
|
+
registry=tools,
|
|
871
|
+
agent_tools=self.agent_tools,
|
|
872
|
+
get_conversation_history=lambda: messages,
|
|
873
|
+
parent_ctx=ctx,
|
|
874
|
+
)
|
|
875
|
+
|
|
876
|
+
# Add system prompt for routing
|
|
877
|
+
system_message = {
|
|
878
|
+
"role": "system",
|
|
879
|
+
"content": """You are a customer service router. Analyze the customer's
|
|
880
|
+
request and delegate to the appropriate specialist:
|
|
881
|
+
- billing_specialist: For billing, payments, refunds
|
|
882
|
+
- tech_support: For technical issues (this will transfer the customer)
|
|
883
|
+
|
|
884
|
+
If you can answer directly, do so. Otherwise, use the appropriate tool."""
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
while True:
|
|
888
|
+
response = await llm.generate(
|
|
889
|
+
[system_message] + messages,
|
|
890
|
+
tools=tools.to_openai_format(),
|
|
891
|
+
)
|
|
892
|
+
|
|
893
|
+
messages.append(response.message)
|
|
894
|
+
|
|
895
|
+
if not response.tool_calls:
|
|
896
|
+
# No tool call - respond directly
|
|
897
|
+
await ctx.emit(EventType.ASSISTANT_MESSAGE, {
|
|
898
|
+
"content": response.content,
|
|
899
|
+
})
|
|
900
|
+
break
|
|
901
|
+
|
|
902
|
+
# Execute tool calls (which may invoke sub-agents)
|
|
903
|
+
for tool_call in response.tool_calls:
|
|
904
|
+
result = await tools.execute_with_events(tool_call, ctx)
|
|
905
|
+
|
|
906
|
+
# Check for handoff
|
|
907
|
+
if isinstance(result, dict) and result.get("handoff"):
|
|
908
|
+
# Sub-agent took over - we're done
|
|
909
|
+
return RunResult(
|
|
910
|
+
final_output=result.get("final_output", {}),
|
|
911
|
+
final_messages=messages,
|
|
912
|
+
)
|
|
913
|
+
|
|
914
|
+
# Add result to conversation
|
|
915
|
+
messages.append({
|
|
916
|
+
"role": "tool",
|
|
917
|
+
"tool_call_id": tool_call.id,
|
|
918
|
+
"content": str(result.get("response", result)),
|
|
919
|
+
})
|
|
920
|
+
|
|
921
|
+
return RunResult(
|
|
922
|
+
final_output={"response": response.content},
|
|
923
|
+
final_messages=messages,
|
|
924
|
+
)
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
### Direct Invocation
|
|
928
|
+
|
|
929
|
+
You can also invoke agents directly without the tool pattern:
|
|
930
|
+
|
|
931
|
+
```python
|
|
932
|
+
from agent_runtime_core.multi_agent import invoke_agent
|
|
933
|
+
|
|
934
|
+
# Invoke a sub-agent directly
|
|
935
|
+
result = await invoke_agent(
|
|
936
|
+
agent_tool=billing_tool,
|
|
937
|
+
message="Customer wants a refund for order #123",
|
|
938
|
+
parent_ctx=ctx,
|
|
939
|
+
conversation_history=messages,
|
|
940
|
+
additional_context="Customer has been waiting 2 weeks",
|
|
941
|
+
)
|
|
942
|
+
|
|
943
|
+
if result.handoff:
|
|
944
|
+
# Sub-agent took over
|
|
945
|
+
return RunResult(final_output=result.run_result.final_output)
|
|
946
|
+
else:
|
|
947
|
+
# Use the response
|
|
948
|
+
print(result.response)
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
### Events
|
|
952
|
+
|
|
953
|
+
Multi-agent invocations emit events for observability:
|
|
954
|
+
|
|
955
|
+
- `sub_agent.start` - Sub-agent invocation started
|
|
956
|
+
- `sub_agent.end` - Sub-agent invocation completed
|
|
957
|
+
- `tool.call` with `is_agent_tool: true` - Agent-tool was called
|
|
958
|
+
- `tool.result` with `is_agent_tool: true` - Agent-tool returned
|
|
959
|
+
|
|
960
|
+
### AgentTool Options
|
|
961
|
+
|
|
962
|
+
```python
|
|
963
|
+
AgentTool(
|
|
964
|
+
agent=my_agent, # Required: The agent to wrap
|
|
965
|
+
name="specialist", # Required: Tool name
|
|
966
|
+
description="When to use this agent", # Required: Shown to parent LLM
|
|
967
|
+
invocation_mode=InvocationMode.DELEGATE, # DELEGATE or HANDOFF
|
|
968
|
+
context_mode=ContextMode.FULL, # FULL, SUMMARY, or MESSAGE_ONLY
|
|
969
|
+
max_turns=10, # Optional: Limit sub-agent turns
|
|
970
|
+
input_schema={...}, # Optional: Custom input schema
|
|
971
|
+
metadata={"category": "billing"}, # Optional: Additional metadata
|
|
972
|
+
)
|
|
973
|
+
```
|
|
974
|
+
|
|
780
975
|
## API Reference
|
|
781
976
|
|
|
782
977
|
### Configuration
|
|
@@ -34,16 +34,18 @@ Example usage:
|
|
|
34
34
|
return RunResult(final_output={"message": "Hello!"})
|
|
35
35
|
"""
|
|
36
36
|
|
|
37
|
-
__version__ = "0.
|
|
37
|
+
__version__ = "0.7.0"
|
|
38
38
|
|
|
39
39
|
# Core interfaces
|
|
40
40
|
from agent_runtime_core.interfaces import (
|
|
41
41
|
AgentRuntime,
|
|
42
42
|
EventType,
|
|
43
|
+
EventVisibility,
|
|
43
44
|
ErrorInfo,
|
|
44
45
|
LLMClient,
|
|
45
46
|
LLMResponse,
|
|
46
47
|
LLMStreamChunk,
|
|
48
|
+
LLMToolCall,
|
|
47
49
|
Message,
|
|
48
50
|
RunContext,
|
|
49
51
|
RunResult,
|
|
@@ -57,6 +59,12 @@ from agent_runtime_core.interfaces import (
|
|
|
57
59
|
# Tool Calling Agent base class
|
|
58
60
|
from agent_runtime_core.tool_calling_agent import ToolCallingAgent
|
|
59
61
|
|
|
62
|
+
# Agentic loop helper
|
|
63
|
+
from agent_runtime_core.agentic_loop import (
|
|
64
|
+
run_agentic_loop,
|
|
65
|
+
AgenticLoopResult,
|
|
66
|
+
)
|
|
67
|
+
|
|
60
68
|
# Configuration
|
|
61
69
|
from agent_runtime_core.config import (
|
|
62
70
|
RuntimeConfig,
|
|
@@ -91,6 +99,12 @@ from agent_runtime_core.steps import (
|
|
|
91
99
|
StepCancelledError,
|
|
92
100
|
)
|
|
93
101
|
|
|
102
|
+
# Concrete RunContext implementations for different use cases
|
|
103
|
+
from agent_runtime_core.contexts import (
|
|
104
|
+
InMemoryRunContext,
|
|
105
|
+
FileRunContext,
|
|
106
|
+
)
|
|
107
|
+
|
|
94
108
|
# Testing utilities
|
|
95
109
|
from agent_runtime_core.testing import (
|
|
96
110
|
MockRunContext,
|
|
@@ -122,6 +136,7 @@ from agent_runtime_core.persistence import (
|
|
|
122
136
|
FileConversationStore,
|
|
123
137
|
FileTaskStore,
|
|
124
138
|
FilePreferencesStore,
|
|
139
|
+
FileKnowledgeStore,
|
|
125
140
|
# Manager
|
|
126
141
|
PersistenceManager,
|
|
127
142
|
PersistenceConfig,
|
|
@@ -129,6 +144,69 @@ from agent_runtime_core.persistence import (
|
|
|
129
144
|
configure_persistence,
|
|
130
145
|
)
|
|
131
146
|
|
|
147
|
+
# Agent configuration schema (portable JSON format)
|
|
148
|
+
from agent_runtime_core.config_schema import (
|
|
149
|
+
AgentConfig,
|
|
150
|
+
ToolConfig,
|
|
151
|
+
KnowledgeConfig,
|
|
152
|
+
SubAgentToolConfig,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
# JSON-based runtime (loads from AgentConfig)
|
|
156
|
+
from agent_runtime_core.json_runtime import (
|
|
157
|
+
JsonAgentRuntime,
|
|
158
|
+
ConfiguredTool,
|
|
159
|
+
SubAgentTool,
|
|
160
|
+
resolve_function,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# Vector store (optional - requires additional dependencies)
|
|
164
|
+
# Import these directly from agent_runtime_core.vectorstore when needed:
|
|
165
|
+
# from agent_runtime_core.vectorstore import (
|
|
166
|
+
# VectorStore, VectorRecord, VectorSearchResult,
|
|
167
|
+
# EmbeddingClient, OpenAIEmbeddings, VertexAIEmbeddings,
|
|
168
|
+
# get_vector_store, get_embedding_client,
|
|
169
|
+
# )
|
|
170
|
+
|
|
171
|
+
# RAG (Retrieval Augmented Generation)
|
|
172
|
+
from agent_runtime_core.rag import (
|
|
173
|
+
chunk_text,
|
|
174
|
+
ChunkingConfig,
|
|
175
|
+
TextChunk,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# RAG services are imported lazily to avoid circular dependencies
|
|
179
|
+
# Import directly when needed:
|
|
180
|
+
# from agent_runtime_core.rag import KnowledgeIndexer, KnowledgeRetriever
|
|
181
|
+
|
|
182
|
+
# Tool schema builder utilities
|
|
183
|
+
from agent_runtime_core.tools import (
|
|
184
|
+
ToolSchema,
|
|
185
|
+
ToolSchemaBuilder,
|
|
186
|
+
ToolParameter,
|
|
187
|
+
schemas_to_openai_format,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Multi-agent support (agent-as-tool pattern)
|
|
191
|
+
from agent_runtime_core.multi_agent import (
|
|
192
|
+
AgentTool,
|
|
193
|
+
AgentInvocationResult,
|
|
194
|
+
InvocationMode,
|
|
195
|
+
ContextMode,
|
|
196
|
+
SubAgentContext,
|
|
197
|
+
invoke_agent,
|
|
198
|
+
create_agent_tool_handler,
|
|
199
|
+
register_agent_tools,
|
|
200
|
+
build_sub_agent_messages,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# Cross-conversation memory
|
|
204
|
+
# Import directly when needed for full functionality:
|
|
205
|
+
# from agent_runtime_core.memory import (
|
|
206
|
+
# MemoryManager, MemoryConfig, MemoryEnabledAgent,
|
|
207
|
+
# ExtractedMemory, RecalledMemory, with_memory,
|
|
208
|
+
# )
|
|
209
|
+
|
|
132
210
|
__all__ = [
|
|
133
211
|
# Version
|
|
134
212
|
"__version__",
|
|
@@ -137,6 +215,7 @@ __all__ = [
|
|
|
137
215
|
"LLMClient",
|
|
138
216
|
"LLMResponse",
|
|
139
217
|
"LLMStreamChunk",
|
|
218
|
+
"LLMToolCall",
|
|
140
219
|
"Message",
|
|
141
220
|
"RunContext",
|
|
142
221
|
"RunResult",
|
|
@@ -145,8 +224,12 @@ __all__ = [
|
|
|
145
224
|
"ToolDefinition",
|
|
146
225
|
"TraceSink",
|
|
147
226
|
"EventType",
|
|
227
|
+
"EventVisibility",
|
|
148
228
|
"ErrorInfo",
|
|
149
|
-
|
|
229
|
+
# Tool calling
|
|
230
|
+
"ToolCallingAgent",
|
|
231
|
+
"run_agentic_loop",
|
|
232
|
+
"AgenticLoopResult",
|
|
150
233
|
# Configuration
|
|
151
234
|
"RuntimeConfig",
|
|
152
235
|
"configure",
|
|
@@ -169,6 +252,9 @@ __all__ = [
|
|
|
169
252
|
"ExecutionState",
|
|
170
253
|
"StepExecutionError",
|
|
171
254
|
"StepCancelledError",
|
|
255
|
+
# Concrete RunContext implementations
|
|
256
|
+
"InMemoryRunContext",
|
|
257
|
+
"FileRunContext",
|
|
172
258
|
# Testing
|
|
173
259
|
"MockRunContext",
|
|
174
260
|
"MockLLMClient",
|
|
@@ -195,9 +281,39 @@ __all__ = [
|
|
|
195
281
|
"FileConversationStore",
|
|
196
282
|
"FileTaskStore",
|
|
197
283
|
"FilePreferencesStore",
|
|
284
|
+
"FileKnowledgeStore",
|
|
198
285
|
# Persistence - Manager
|
|
199
286
|
"PersistenceManager",
|
|
200
287
|
"PersistenceConfig",
|
|
201
288
|
"get_persistence_manager",
|
|
202
289
|
"configure_persistence",
|
|
290
|
+
# Agent configuration schema
|
|
291
|
+
"AgentConfig",
|
|
292
|
+
"ToolConfig",
|
|
293
|
+
"KnowledgeConfig",
|
|
294
|
+
"SubAgentToolConfig",
|
|
295
|
+
# JSON-based runtime
|
|
296
|
+
"JsonAgentRuntime",
|
|
297
|
+
"ConfiguredTool",
|
|
298
|
+
"SubAgentTool",
|
|
299
|
+
"resolve_function",
|
|
300
|
+
# RAG (Retrieval Augmented Generation)
|
|
301
|
+
"chunk_text",
|
|
302
|
+
"ChunkingConfig",
|
|
303
|
+
"TextChunk",
|
|
304
|
+
# Tool schema builder
|
|
305
|
+
"ToolSchema",
|
|
306
|
+
"ToolSchemaBuilder",
|
|
307
|
+
"ToolParameter",
|
|
308
|
+
"schemas_to_openai_format",
|
|
309
|
+
# Multi-agent support
|
|
310
|
+
"AgentTool",
|
|
311
|
+
"AgentInvocationResult",
|
|
312
|
+
"InvocationMode",
|
|
313
|
+
"ContextMode",
|
|
314
|
+
"SubAgentContext",
|
|
315
|
+
"invoke_agent",
|
|
316
|
+
"create_agent_tool_handler",
|
|
317
|
+
"register_agent_tools",
|
|
318
|
+
"build_sub_agent_messages",
|
|
203
319
|
]
|