-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathagent_dsl_json.py
More file actions
152 lines (129 loc) · 5.7 KB
/
agent_dsl_json.py
File metadata and controls
152 lines (129 loc) · 5.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
"""Agent DSL JSON example — Load multi-agent config from JSON and run subagent delegation.
This example demonstrates:
- Loading agent specifications from a JSON file using Agent DSL
- Compiler auto-wiring: ToolRegistryComponent, SubagentSessionTableComponent, SubagentSystem
- Manager agent delegates a research task via the 'subagent' tool
- SystemPromptRenderSystem resolving ${_installed_subagents} placeholder
- OwnerComponent parent-child relationship between manager and spawned sub-agent
Requires LLM_API_KEY to be set. Optionally set LLM_BASE_URL and LLM_MODEL.
"""
import asyncio
import os
from pathlib import Path
from ecs_agent.components import ConversationComponent, OwnerComponent
from ecs_agent.core import Runner, World
from ecs_agent.dsl import compile_agent_specs, load_json_agents, resolve_agent_specs
from ecs_agent.logging import configure_logging
from ecs_agent.providers import Model
from ecs_agent.providers.config import ApiFormat
from ecs_agent.providers.protocol import LLMModel
from ecs_agent.systems.error_handling import ErrorHandlingSystem
from ecs_agent.systems.memory import MemorySystem
from ecs_agent.systems.reasoning import ReasoningSystem
from ecs_agent.systems.tool_execution import ToolExecutionSystem
from ecs_agent.types import EntityId, Message
def create_model(model: str, system_prompt: str) -> LLMModel:
"""Create a model from environment variables.
Args:
model: Model identifier (e.g., "qwen3.5-flash")
system_prompt: System prompt for the model (unused at construction time)
Returns:
LLMModel configured from environment.
"""
api_key = os.environ.get("LLM_API_KEY", "")
base_url = os.environ.get(
"LLM_BASE_URL", "https://dashscope.aliyuncs.com/compatible-mode/v1"
)
if not api_key:
print("Error: LLM_API_KEY is not set.")
print(
"Set LLM_API_KEY (and optionally LLM_BASE_URL, LLM_MODEL) to run this example."
)
raise SystemExit(1)
return Model(model, base_url=base_url, api_key=api_key, api_format=ApiFormat.OPENAI_CHAT_COMPLETIONS)
def _print_conversation(label: str, entity_id: EntityId, world: World) -> None:
"""Pretty-print an entity's conversation."""
print(f"\n--- {label} (entity {entity_id}) ---")
conv = world.get_component(entity_id, ConversationComponent)
if conv is None:
print(" (no conversation)")
return
for msg in conv.messages:
role = msg.role.upper()
if msg.tool_calls:
print(f" [{role}] {msg.content or '(no content)'}")
for tool_call in msg.tool_calls:
print(f" → Tool Call: {tool_call.name}({tool_call.arguments})")
elif msg.role == "tool":
print(f" [{role}] (tool_call_id={msg.tool_call_id})")
lines = (msg.content or "").split("\n")
first, rest = lines[0], lines[1:]
print(f" {first}")
for line in rest:
print(f" {line}")
else:
lines = (msg.content or "").split("\n")
first, rest = lines[0], lines[1:]
print(f" [{role}] {first}")
for line in rest:
print(f" {line}")
async def main() -> None:
"""Run Agent DSL JSON subagent delegation example."""
configure_logging(json_output=False)
model = os.environ.get("LLM_MODEL", "qwen3.5-flash")
print(f"Using model: {model}")
# Load agent specifications from JSON file
config_path = Path(__file__).parent / "agents_config.json"
print(f"Loading agent configuration from: {config_path}")
spec_list = load_json_agents(config_path)
specs = resolve_agent_specs(spec_list)
print(f"Loaded {len(specs)} agent specification(s):")
for name, spec in specs.items():
print(f" - {name}: mode={spec.mode}, model={spec.model}")
# Compile specs into ECS World
# compile_agent_specs auto-wires:
# - SystemPromptRenderSystem (priority=-20)
# - UserPromptNormalizationSystem (priority=-10)
# - ToolRegistryComponent (always)
# - SubagentSystem + SubagentSessionTableComponent (when subagents present)
print("\nCompiling agent specs into ECS World...")
primary_entity, world = compile_agent_specs(specs, model_factory=create_model)
print(f"Created primary entity: {primary_entity}")
# Add conversation with user's research question
world.add_component(
primary_entity,
ConversationComponent(
messages=[
Message(
role="user",
content=(
"What are the most promising near-term applications "
"of quantum computing?"
),
)
]
),
)
# Register runtime systems (prompt/subagent systems registered by compiler)
world.register_system(ReasoningSystem(priority=0), priority=0)
world.register_system(ToolExecutionSystem(priority=5), priority=5)
world.register_system(MemorySystem(), priority=10)
world.register_system(ErrorHandlingSystem(priority=99), priority=99)
# Run the agent
print("\nRunning agent...")
runner = Runner()
await runner.run(world, max_ticks=10)
# Print results
print("\n" + "=" * 60)
print("Manager Conversation (Agent DSL JSON)")
print("=" * 60)
_print_conversation("Manager", primary_entity, world)
# Show parent-child relationship from subagent delegation
for entity_id, components in world.query(OwnerComponent):
(owner_comp,) = components
print(
f"\n[OwnerComponent] Sub-agent (entity {entity_id}) "
f"→ Manager (entity {owner_comp.owner_id})"
)
if __name__ == "__main__":
asyncio.run(main())