agencode 0.1.0__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.
Files changed (46) hide show
  1. agencode-0.1.0/.gitignore +29 -0
  2. agencode-0.1.0/PKG-INFO +44 -0
  3. agencode-0.1.0/README.md +25 -0
  4. agencode-0.1.0/agencli/__init__.py +5 -0
  5. agencode-0.1.0/agencli/__main__.py +9 -0
  6. agencode-0.1.0/agencli/agents/__init__.py +1 -0
  7. agencode-0.1.0/agencli/agents/editor.py +110 -0
  8. agencode-0.1.0/agencli/agents/factory.py +335 -0
  9. agencode-0.1.0/agencli/agents/management_tools.py +277 -0
  10. agencode-0.1.0/agencli/agents/prebuilt/__init__.py +1 -0
  11. agencode-0.1.0/agencli/agents/prebuilt/catalog.py +66 -0
  12. agencode-0.1.0/agencli/agents/registry.py +50 -0
  13. agencode-0.1.0/agencli/agents/runtime.py +266 -0
  14. agencode-0.1.0/agencli/agents/supervisor.py +67 -0
  15. agencode-0.1.0/agencli/cli.py +561 -0
  16. agencode-0.1.0/agencli/core/__init__.py +1 -0
  17. agencode-0.1.0/agencli/core/config.py +179 -0
  18. agencode-0.1.0/agencli/core/keystore.py +14 -0
  19. agencode-0.1.0/agencli/core/logger.py +17 -0
  20. agencode-0.1.0/agencli/core/paths.py +37 -0
  21. agencode-0.1.0/agencli/core/session.py +513 -0
  22. agencode-0.1.0/agencli/mcp/__init__.py +1 -0
  23. agencode-0.1.0/agencli/mcp/client.py +33 -0
  24. agencode-0.1.0/agencli/mcp/config.py +99 -0
  25. agencode-0.1.0/agencli/providers/__init__.py +1 -0
  26. agencode-0.1.0/agencli/providers/model.py +180 -0
  27. agencode-0.1.0/agencli/skills/__init__.py +37 -0
  28. agencode-0.1.0/agencli/skills/cli_backend.py +446 -0
  29. agencode-0.1.0/agencli/skills/loader.py +77 -0
  30. agencode-0.1.0/agencli/skills/manager.py +153 -0
  31. agencode-0.1.0/agencli/tools/__init__.py +1 -0
  32. agencode-0.1.0/agencli/tools/mcp.py +106 -0
  33. agencode-0.1.0/agencli/tui/__init__.py +1 -0
  34. agencode-0.1.0/agencli/tui/app.py +4274 -0
  35. agencode-0.1.0/agencli/tui/commands.py +86 -0
  36. agencode-0.1.0/agencli/tui/screens.py +939 -0
  37. agencode-0.1.0/agencli/tui/trace.py +334 -0
  38. agencode-0.1.0/agencli/tui/voice.py +77 -0
  39. agencode-0.1.0/pyproject.toml +40 -0
  40. agencode-0.1.0/tests/test_agent_editor.py +105 -0
  41. agencode-0.1.0/tests/test_cli.py +63 -0
  42. agencode-0.1.0/tests/test_mcp_tools.py +62 -0
  43. agencode-0.1.0/tests/test_runtime.py +738 -0
  44. agencode-0.1.0/tests/test_skills.py +219 -0
  45. agencode-0.1.0/tests/test_tui_app.py +1107 -0
  46. agencode-0.1.0/tests/test_tui_commands.py +53 -0
@@ -0,0 +1,29 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Local project state
13
+ .agencode/
14
+
15
+ # Test and tool caches
16
+ .pytest_cache/
17
+ .coverage
18
+ htmlcov/
19
+ .mypy_cache/
20
+ .ruff_cache/
21
+
22
+ # Local notes and scratch docs
23
+ agencli-progress.md
24
+ agencli-deepagents-plan.md
25
+ Reference/
26
+
27
+ # Editor and OS noise
28
+ .DS_Store
29
+ *.swp
@@ -0,0 +1,44 @@
1
+ Metadata-Version: 2.4
2
+ Name: agencode
3
+ Version: 0.1.0
4
+ Summary: AgenCLI: a multi-agent terminal workspace built in Python.
5
+ Requires-Python: >=3.12
6
+ Requires-Dist: deepagents
7
+ Requires-Dist: httpx>=0.28.1
8
+ Requires-Dist: keyring>=25.6.0
9
+ Requires-Dist: langchain
10
+ Requires-Dist: langchain-mcp-adapters
11
+ Requires-Dist: langchain-openai
12
+ Requires-Dist: langgraph
13
+ Requires-Dist: langgraph-checkpoint-sqlite
14
+ Requires-Dist: rich>=14.1.0
15
+ Requires-Dist: textual>=6.2.1
16
+ Requires-Dist: tomli-w>=1.2.0
17
+ Requires-Dist: typer>=0.19.2
18
+ Description-Content-Type: text/markdown
19
+
20
+ # AgenCLI
21
+
22
+ AgenCLI is the Python reboot of the original agent CLI concept: a multi-agent terminal workspace with a Textual UI and a DeepAgents/LangGraph runtime.
23
+
24
+ This repo is now scaffolded as a proper `uv` project with:
25
+
26
+ - a package entrypoint at `agencode`
27
+ - `agencode tui` uses the current directory as the workspace by default
28
+ - a Typer CLI
29
+ - a minimal Textual app
30
+ - config and session directory bootstrapping
31
+ - basic agent registry and runtime stubs for the later DeepAgents integration
32
+ - CLI support for OpenAI-compatible `base_url`, `api_key`, `model`, and `model_kind`
33
+
34
+ ## Run
35
+
36
+ ```bash
37
+ uv sync
38
+ uv run agencode doctor
39
+ uv run agencode config-openai --base-url https://api.deepseek.com --model deepseek-chat --model-kind chat
40
+ uv run agencode tui
41
+
42
+ # Open a specific workspace explicitly
43
+ uv run agencode tui --workspace /path/to/project
44
+ ```
@@ -0,0 +1,25 @@
1
+ # AgenCLI
2
+
3
+ AgenCLI is the Python reboot of the original agent CLI concept: a multi-agent terminal workspace with a Textual UI and a DeepAgents/LangGraph runtime.
4
+
5
+ This repo is now scaffolded as a proper `uv` project with:
6
+
7
+ - a package entrypoint at `agencode`
8
+ - `agencode tui` uses the current directory as the workspace by default
9
+ - a Typer CLI
10
+ - a minimal Textual app
11
+ - config and session directory bootstrapping
12
+ - basic agent registry and runtime stubs for the later DeepAgents integration
13
+ - CLI support for OpenAI-compatible `base_url`, `api_key`, `model`, and `model_kind`
14
+
15
+ ## Run
16
+
17
+ ```bash
18
+ uv sync
19
+ uv run agencode doctor
20
+ uv run agencode config-openai --base-url https://api.deepseek.com --model deepseek-chat --model-kind chat
21
+ uv run agencode tui
22
+
23
+ # Open a specific workspace explicitly
24
+ uv run agencode tui --workspace /path/to/project
25
+ ```
@@ -0,0 +1,5 @@
1
+ """AgenCLI package."""
2
+
3
+ __all__ = ["__version__"]
4
+
5
+ __version__ = "0.1.0"
@@ -0,0 +1,9 @@
1
+ from agencli.cli import app
2
+
3
+
4
+ def main() -> None:
5
+ app()
6
+
7
+
8
+ if __name__ == "__main__":
9
+ main()
@@ -0,0 +1 @@
1
+ """Agent construction and registration helpers."""
@@ -0,0 +1,110 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Collection, Iterable, Sequence
4
+
5
+ from agencli.agents.factory import AgentSpec
6
+
7
+
8
+ def parse_token_list(raw: str) -> list[str]:
9
+ tokens = [token.strip() for chunk in raw.replace("\n", ",").split(",") for token in [chunk.strip()]]
10
+ return _dedupe([token for token in tokens if token])
11
+
12
+
13
+ def format_token_list(values: Sequence[str]) -> str:
14
+ return ", ".join(value for value in values if value)
15
+
16
+
17
+ def partition_skill_tokens(
18
+ skill_tokens: Sequence[str],
19
+ installed_skill_names: Collection[str],
20
+ ) -> tuple[list[str], list[str]]:
21
+ installed_names = set(installed_skill_names)
22
+ managed: list[str] = []
23
+ extra: list[str] = []
24
+ for token in skill_tokens:
25
+ if token == "installed" or token in installed_names:
26
+ managed.append(token)
27
+ else:
28
+ extra.append(token)
29
+ return _dedupe(managed), _dedupe(extra)
30
+
31
+
32
+ def suggest_custom_agent_name(base_name: str, existing_names: Collection[str]) -> str:
33
+ existing = set(existing_names)
34
+ normalized_base = base_name.strip() or "custom-agent"
35
+ candidate = normalized_base if normalized_base not in existing else f"{normalized_base}-custom"
36
+ if candidate not in existing:
37
+ return candidate
38
+
39
+ index = 2
40
+ while f"{candidate}-{index}" in existing:
41
+ index += 1
42
+ return f"{candidate}-{index}"
43
+
44
+
45
+ def copy_agent_spec_for_customization(
46
+ spec: AgentSpec | None,
47
+ *,
48
+ existing_names: Collection[str],
49
+ default_model: str,
50
+ ) -> AgentSpec:
51
+ if spec is None:
52
+ return AgentSpec(
53
+ name=suggest_custom_agent_name("custom-agent", existing_names),
54
+ model=default_model,
55
+ system_prompt="You are a helpful AI agent. Work carefully and explain your reasoning clearly.",
56
+ )
57
+
58
+ copied = AgentSpec.from_dict(spec.serializable_dict())
59
+ copied.name = suggest_custom_agent_name(spec.name, existing_names)
60
+ if not copied.model:
61
+ copied.model = default_model
62
+ return copied
63
+
64
+
65
+ def build_agent_spec_from_editor(
66
+ *,
67
+ base_spec: AgentSpec | None,
68
+ name: str,
69
+ model: str,
70
+ description: str,
71
+ system_prompt: str,
72
+ workspace_dir: str,
73
+ mcp_servers_raw: str,
74
+ selected_skill_tokens: Iterable[str],
75
+ extra_skill_tokens_raw: str,
76
+ ) -> AgentSpec:
77
+ normalized_name = name.strip()
78
+ normalized_model = model.strip()
79
+ normalized_prompt = system_prompt.strip()
80
+ if not normalized_name:
81
+ raise ValueError("Agent name is required.")
82
+ if not normalized_model:
83
+ raise ValueError("Agent model is required.")
84
+ if not normalized_prompt:
85
+ raise ValueError("System prompt is required.")
86
+
87
+ seeded = AgentSpec.from_dict(base_spec.serializable_dict()) if base_spec is not None else AgentSpec(
88
+ name=normalized_name,
89
+ model=normalized_model,
90
+ system_prompt=normalized_prompt,
91
+ )
92
+ seeded.name = normalized_name
93
+ seeded.model = normalized_model
94
+ seeded.description = description.strip()
95
+ seeded.system_prompt = normalized_prompt
96
+ seeded.workspace_dir = workspace_dir.strip() or None
97
+ seeded.mcp_servers = parse_token_list(mcp_servers_raw)
98
+ seeded.skills = _dedupe([*selected_skill_tokens, *parse_token_list(extra_skill_tokens_raw)])
99
+ return seeded
100
+
101
+
102
+ def _dedupe(values: Iterable[str]) -> list[str]:
103
+ seen: set[str] = set()
104
+ deduped: list[str] = []
105
+ for value in values:
106
+ if value in seen:
107
+ continue
108
+ seen.add(value)
109
+ deduped.append(value)
110
+ return deduped
@@ -0,0 +1,335 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Any
5
+
6
+ from agencli.core.config import AgenCLIConfig
7
+ from agencli.core.session import ensure_langgraph_checkpointer, ensure_langgraph_checkpointer_async
8
+ from agencli.providers.model import init_model
9
+ from agencli.skills.loader import resolve_skill_sources
10
+ from agencli.tools.mcp import load_mcp_tools, load_mcp_tools_async
11
+
12
+
13
+ @dataclass(slots=True)
14
+ class SubAgentSpec:
15
+ name: str
16
+ description: str
17
+ system_prompt: str
18
+ model: str | None = None
19
+ skills: list[str] = field(default_factory=list)
20
+ mcp_servers: list[str] = field(default_factory=list)
21
+ workspace_dir: str | None = None
22
+
23
+ def serializable_dict(self) -> dict[str, Any]:
24
+ return {
25
+ "name": self.name,
26
+ "description": self.description,
27
+ "system_prompt": self.system_prompt,
28
+ "model": self.model,
29
+ "skills": self.skills,
30
+ "mcp_servers": self.mcp_servers,
31
+ "workspace_dir": self.workspace_dir,
32
+ }
33
+
34
+ @classmethod
35
+ def from_dict(cls, raw: dict[str, Any]) -> "SubAgentSpec":
36
+ return cls(
37
+ name=raw["name"],
38
+ description=raw["description"],
39
+ system_prompt=raw["system_prompt"],
40
+ model=raw.get("model"),
41
+ skills=list(raw.get("skills", [])),
42
+ mcp_servers=list(raw.get("mcp_servers", [])),
43
+ workspace_dir=raw.get("workspace_dir"),
44
+ )
45
+
46
+
47
+ @dataclass(slots=True)
48
+ class AgentSpec:
49
+ name: str
50
+ model: str
51
+ system_prompt: str
52
+ description: str = ""
53
+ tools: list[Any] = field(default_factory=list)
54
+ subagents: list[SubAgentSpec | dict[str, Any]] = field(default_factory=list)
55
+ skills: list[str] = field(default_factory=list)
56
+ mcp_servers: list[str] = field(default_factory=list)
57
+ workspace_dir: str | None = None
58
+
59
+ def serializable_dict(self) -> dict[str, Any]:
60
+ return {
61
+ "name": self.name,
62
+ "model": self.model,
63
+ "system_prompt": self.system_prompt,
64
+ "description": self.description,
65
+ "subagents": [_serialize_subagent(subagent) for subagent in self.subagents],
66
+ "skills": self.skills,
67
+ "mcp_servers": self.mcp_servers,
68
+ "workspace_dir": self.workspace_dir,
69
+ }
70
+
71
+ @classmethod
72
+ def from_dict(cls, raw: dict[str, Any]) -> "AgentSpec":
73
+ return cls(
74
+ name=raw["name"],
75
+ model=raw["model"],
76
+ system_prompt=raw["system_prompt"],
77
+ description=raw.get("description", ""),
78
+ subagents=[_deserialize_subagent(subagent) for subagent in raw.get("subagents", [])],
79
+ skills=list(raw.get("skills", [])),
80
+ mcp_servers=list(raw.get("mcp_servers", [])),
81
+ workspace_dir=raw.get("workspace_dir"),
82
+ )
83
+
84
+
85
+ def build_agent(
86
+ spec: AgentSpec,
87
+ config: AgenCLIConfig | None = None,
88
+ *,
89
+ session_name: str = "default",
90
+ checkpointer: Any | None = None,
91
+ diagnostics: list[str] | None = None,
92
+ ) -> Any:
93
+ """Build a DeepAgent graph lazily once the runtime dependencies are installed."""
94
+ try:
95
+ from deepagents import create_deep_agent
96
+ from deepagents.backends import FilesystemBackend, LocalShellBackend
97
+ except ImportError as exc:
98
+ raise RuntimeError(
99
+ "Deep agent runtime dependencies are not installed yet. Run `uv sync` after dependencies are added."
100
+ ) from exc
101
+
102
+ resolved_tools = list(spec.tools)
103
+ if config is None:
104
+ try:
105
+ from langchain.chat_models import init_chat_model
106
+ except ImportError as exc:
107
+ raise RuntimeError(
108
+ "langchain is not installed yet. Run `uv sync` after dependencies are added."
109
+ ) from exc
110
+ model = init_chat_model(spec.model)
111
+ workspace_dir = spec.workspace_dir
112
+ resolved_subagents = _resolve_subagents(spec.subagents, model_name=spec.model)
113
+ resolved_skills = list(spec.skills)
114
+ else:
115
+ model = init_model(config, model_name=spec.model)
116
+ workspace_dir = spec.workspace_dir or config.workspace_dir
117
+ if checkpointer is None:
118
+ checkpointer = ensure_langgraph_checkpointer(config.sessions_dir, session_name=session_name)
119
+ if spec.name == "supervisor-agent":
120
+ from agencli.agents.management_tools import build_supervisor_management_tools
121
+
122
+ resolved_tools.extend(build_supervisor_management_tools(config))
123
+ if spec.mcp_servers:
124
+ resolved_tools.extend(
125
+ load_mcp_tools(
126
+ config.mcp_config_path,
127
+ server_names=spec.mcp_servers,
128
+ diagnostics=diagnostics,
129
+ )
130
+ )
131
+ resolved_subagents = _resolve_subagents(
132
+ spec.subagents,
133
+ config=config,
134
+ model_name=spec.model,
135
+ diagnostics=diagnostics,
136
+ )
137
+ resolved_skills = resolve_skill_sources(spec.skills, config.skills_dir)
138
+
139
+ backend = _build_backend(spec.name, workspace_dir, FilesystemBackend, LocalShellBackend)
140
+ return create_deep_agent(
141
+ model=model,
142
+ tools=resolved_tools,
143
+ system_prompt=spec.system_prompt,
144
+ subagents=resolved_subagents,
145
+ skills=resolved_skills or None,
146
+ backend=backend,
147
+ checkpointer=checkpointer,
148
+ name=spec.name,
149
+ )
150
+
151
+
152
+ async def build_agent_async(
153
+ spec: AgentSpec,
154
+ config: AgenCLIConfig | None = None,
155
+ *,
156
+ session_name: str = "default",
157
+ checkpointer: Any | None = None,
158
+ diagnostics: list[str] | None = None,
159
+ ) -> Any:
160
+ try:
161
+ from deepagents import create_deep_agent
162
+ from deepagents.backends import FilesystemBackend, LocalShellBackend
163
+ except ImportError as exc:
164
+ raise RuntimeError(
165
+ "Deep agent runtime dependencies are not installed yet. Run `uv sync` after dependencies are added."
166
+ ) from exc
167
+
168
+ resolved_tools = list(spec.tools)
169
+ if config is None:
170
+ return build_agent(
171
+ spec,
172
+ config=None,
173
+ session_name=session_name,
174
+ checkpointer=checkpointer,
175
+ diagnostics=diagnostics,
176
+ )
177
+
178
+ model = init_model(config, model_name=spec.model)
179
+ workspace_dir = spec.workspace_dir or config.workspace_dir
180
+ if checkpointer is None:
181
+ checkpointer = await ensure_langgraph_checkpointer_async(config.sessions_dir, session_name=session_name)
182
+ if spec.name == "supervisor-agent":
183
+ from agencli.agents.management_tools import build_supervisor_management_tools
184
+
185
+ resolved_tools.extend(build_supervisor_management_tools(config))
186
+ if spec.mcp_servers:
187
+ resolved_tools.extend(
188
+ await load_mcp_tools_async(
189
+ config.mcp_config_path,
190
+ server_names=spec.mcp_servers,
191
+ diagnostics=diagnostics,
192
+ )
193
+ )
194
+ resolved_subagents = await _resolve_subagents_async(
195
+ spec.subagents,
196
+ config=config,
197
+ model_name=spec.model,
198
+ diagnostics=diagnostics,
199
+ )
200
+ resolved_skills = resolve_skill_sources(spec.skills, config.skills_dir)
201
+
202
+ backend = _build_backend(spec.name, workspace_dir, FilesystemBackend, LocalShellBackend)
203
+ return create_deep_agent(
204
+ model=model,
205
+ tools=resolved_tools,
206
+ system_prompt=spec.system_prompt,
207
+ subagents=resolved_subagents,
208
+ skills=resolved_skills or None,
209
+ backend=backend,
210
+ checkpointer=checkpointer,
211
+ name=spec.name,
212
+ )
213
+
214
+
215
+ def _serialize_subagent(subagent: SubAgentSpec | dict[str, Any]) -> dict[str, Any]:
216
+ if isinstance(subagent, SubAgentSpec):
217
+ return {"kind": "spec", **subagent.serializable_dict()}
218
+ if isinstance(subagent, dict) and "runnable" in subagent:
219
+ raise ValueError("Compiled subagents cannot be serialized into agent registry JSON.")
220
+ if isinstance(subagent, dict):
221
+ return dict(subagent)
222
+ raise TypeError(f"Unsupported subagent type: {type(subagent)!r}")
223
+
224
+
225
+ def _deserialize_subagent(raw: dict[str, Any]) -> SubAgentSpec | dict[str, Any]:
226
+ if raw.get("kind") == "spec":
227
+ payload = dict(raw)
228
+ payload.pop("kind", None)
229
+ return SubAgentSpec.from_dict(payload)
230
+ if {"name", "description", "system_prompt"}.issubset(raw):
231
+ return SubAgentSpec.from_dict(raw)
232
+ return raw
233
+
234
+
235
+ def _build_backend(
236
+ agent_name: str,
237
+ workspace_dir: str | None,
238
+ filesystem_backend_cls: Any,
239
+ local_shell_backend_cls: Any,
240
+ ):
241
+ shell_enabled_agents = {"shell-agent", "coding-agent", "supervisor-agent"}
242
+ backend_cls = local_shell_backend_cls if agent_name in shell_enabled_agents else filesystem_backend_cls
243
+ if workspace_dir:
244
+ return backend_cls(root_dir=workspace_dir)
245
+ return backend_cls()
246
+
247
+
248
+ def _resolve_subagents(
249
+ subagents: list[SubAgentSpec | dict[str, Any]],
250
+ *,
251
+ config: AgenCLIConfig | None = None,
252
+ model_name: str,
253
+ diagnostics: list[str] | None = None,
254
+ ) -> list[dict[str, Any]]:
255
+ resolved: list[dict[str, Any]] = []
256
+ for subagent in subagents:
257
+ if isinstance(subagent, SubAgentSpec):
258
+ tools: list[Any] = []
259
+ if config is not None and subagent.mcp_servers:
260
+ tools.extend(
261
+ load_mcp_tools(
262
+ config.mcp_config_path,
263
+ server_names=subagent.mcp_servers,
264
+ diagnostics=diagnostics,
265
+ )
266
+ )
267
+ elif subagent.mcp_servers:
268
+ raise RuntimeError("Subagents with MCP servers require a resolved AgenCLI config.")
269
+ payload: dict[str, Any] = {
270
+ "name": subagent.name,
271
+ "description": subagent.description,
272
+ "system_prompt": subagent.system_prompt,
273
+ "tools": tools,
274
+ }
275
+ if subagent.model:
276
+ payload["model"] = init_model(config, model_name=subagent.model) if config is not None else subagent.model
277
+ elif config is not None:
278
+ payload["model"] = init_model(config, model_name=model_name)
279
+ else:
280
+ payload["model"] = model_name
281
+ if subagent.skills:
282
+ payload["skills"] = (
283
+ resolve_skill_sources(subagent.skills, config.skills_dir)
284
+ if config is not None
285
+ else list(subagent.skills)
286
+ )
287
+ resolved.append(payload)
288
+ else:
289
+ resolved.append(dict(subagent))
290
+ return resolved
291
+
292
+
293
+ async def _resolve_subagents_async(
294
+ subagents: list[SubAgentSpec | dict[str, Any]],
295
+ *,
296
+ config: AgenCLIConfig | None = None,
297
+ model_name: str,
298
+ diagnostics: list[str] | None = None,
299
+ ) -> list[dict[str, Any]]:
300
+ resolved: list[dict[str, Any]] = []
301
+ for subagent in subagents:
302
+ if isinstance(subagent, SubAgentSpec):
303
+ tools: list[Any] = []
304
+ if config is not None and subagent.mcp_servers:
305
+ tools.extend(
306
+ await load_mcp_tools_async(
307
+ config.mcp_config_path,
308
+ server_names=subagent.mcp_servers,
309
+ diagnostics=diagnostics,
310
+ )
311
+ )
312
+ elif subagent.mcp_servers:
313
+ raise RuntimeError("Subagents with MCP servers require a resolved AgenCLI config.")
314
+ payload: dict[str, Any] = {
315
+ "name": subagent.name,
316
+ "description": subagent.description,
317
+ "system_prompt": subagent.system_prompt,
318
+ "tools": tools,
319
+ }
320
+ if subagent.model:
321
+ payload["model"] = init_model(config, model_name=subagent.model) if config is not None else subagent.model
322
+ elif config is not None:
323
+ payload["model"] = init_model(config, model_name=model_name)
324
+ else:
325
+ payload["model"] = model_name
326
+ if subagent.skills:
327
+ payload["skills"] = (
328
+ resolve_skill_sources(subagent.skills, config.skills_dir)
329
+ if config is not None
330
+ else list(subagent.skills)
331
+ )
332
+ resolved.append(payload)
333
+ else:
334
+ resolved.append(dict(subagent))
335
+ return resolved