minder-cli 0.5.2__tar.gz → 0.5.3__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 (160) hide show
  1. {minder_cli-0.5.2 → minder_cli-0.5.3}/PKG-INFO +1 -1
  2. {minder_cli-0.5.2 → minder_cli-0.5.3}/pyproject.toml +1 -1
  3. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/application/admin/dto.py +24 -0
  4. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/application/admin/use_cases.py +137 -0
  5. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/http/admin/api.py +99 -0
  6. {minder_cli-0.5.2 → minder_cli-0.5.3}/.gitignore +0 -0
  7. {minder_cli-0.5.2 → minder_cli-0.5.3}/LICENSE +0 -0
  8. {minder_cli-0.5.2 → minder_cli-0.5.3}/README-pypi.md +0 -0
  9. {minder_cli-0.5.2 → minder_cli-0.5.3}/README.md +0 -0
  10. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/__init__.py +0 -0
  11. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/api/routers/prompts.py +0 -0
  12. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/application/__init__.py +0 -0
  13. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/application/admin/__init__.py +0 -0
  14. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/application/admin/jobs.py +0 -0
  15. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/auth/__init__.py +0 -0
  16. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/auth/context.py +0 -0
  17. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/auth/middleware.py +0 -0
  18. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/auth/principal.py +0 -0
  19. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/auth/rate_limiter.py +0 -0
  20. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/auth/rbac.py +0 -0
  21. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/auth/service.py +0 -0
  22. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/bootstrap/__init__.py +0 -0
  23. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/bootstrap/agent_seeder.py +0 -0
  24. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/bootstrap/providers.py +0 -0
  25. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/bootstrap/transport.py +0 -0
  26. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/cache/__init__.py +0 -0
  27. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/cache/providers.py +0 -0
  28. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/chunking/__init__.py +0 -0
  29. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/chunking/code_splitter.py +0 -0
  30. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/chunking/splitter.py +0 -0
  31. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/cli.py +0 -0
  32. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/config.py +0 -0
  33. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/context_compactor.py +0 -0
  34. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/continuity.py +0 -0
  35. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/dev.py +0 -0
  36. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/embedding/__init__.py +0 -0
  37. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/embedding/base.py +0 -0
  38. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/embedding/local.py +0 -0
  39. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/embedding/openai.py +0 -0
  40. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/__init__.py +0 -0
  41. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/edges.py +0 -0
  42. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/executor.py +0 -0
  43. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/graph.py +0 -0
  44. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/nodes/__init__.py +0 -0
  45. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/nodes/clarification.py +0 -0
  46. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/nodes/evaluator.py +0 -0
  47. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/nodes/guard.py +0 -0
  48. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/nodes/llm.py +0 -0
  49. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/nodes/planning.py +0 -0
  50. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/nodes/reasoning.py +0 -0
  51. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/nodes/reflection.py +0 -0
  52. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/nodes/reranker.py +0 -0
  53. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/nodes/retriever.py +0 -0
  54. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/nodes/verification.py +0 -0
  55. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/nodes/workflow_planner.py +0 -0
  56. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/runtime.py +0 -0
  57. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/graph/state.py +0 -0
  58. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/learning/__init__.py +0 -0
  59. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/learning/error_learner.py +0 -0
  60. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/learning/pattern_extractor.py +0 -0
  61. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/learning/quality_optimizer.py +0 -0
  62. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/learning/skill_synthesizer.py +0 -0
  63. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/llm/__init__.py +0 -0
  64. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/llm/base.py +0 -0
  65. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/llm/factory.py +0 -0
  66. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/llm/llama_cpp_llm.py +0 -0
  67. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/llm/openai.py +0 -0
  68. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/__init__.py +0 -0
  69. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/agent.py +0 -0
  70. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/base.py +0 -0
  71. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/client.py +0 -0
  72. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/document.py +0 -0
  73. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/error.py +0 -0
  74. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/graph.py +0 -0
  75. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/history.py +0 -0
  76. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/job.py +0 -0
  77. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/prompt.py +0 -0
  78. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/repository.py +0 -0
  79. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/rule.py +0 -0
  80. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/session.py +0 -0
  81. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/skill.py +0 -0
  82. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/user.py +0 -0
  83. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/models/workflow.py +0 -0
  84. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/observability/__init__.py +0 -0
  85. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/observability/audit.py +0 -0
  86. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/observability/logging.py +0 -0
  87. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/observability/metrics.py +0 -0
  88. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/observability/tracing.py +0 -0
  89. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/__init__.py +0 -0
  90. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/cli/__init__.py +0 -0
  91. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/cli/commands/agent.py +0 -0
  92. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/cli/commands/auth.py +0 -0
  93. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/cli/commands/ide.py +0 -0
  94. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/cli/commands/mcp.py +0 -0
  95. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/cli/commands/sync.py +0 -0
  96. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/cli/commands/update.py +0 -0
  97. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/cli/main.py +0 -0
  98. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/cli/utils/common.py +0 -0
  99. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/cli/utils/config.py +0 -0
  100. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/cli/utils/git.py +0 -0
  101. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/cli/utils/version.py +0 -0
  102. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/http/__init__.py +0 -0
  103. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/http/admin/__init__.py +0 -0
  104. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/http/admin/agents.py +0 -0
  105. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/http/admin/context.py +0 -0
  106. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/http/admin/dashboard.py +0 -0
  107. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/http/admin/jobs.py +0 -0
  108. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/http/admin/memories.py +0 -0
  109. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/http/admin/prompts.py +0 -0
  110. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/http/admin/routes.py +0 -0
  111. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/http/admin/runtime.py +0 -0
  112. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/http/admin/search.py +0 -0
  113. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/presentation/http/admin/skills.py +0 -0
  114. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/prompts/__init__.py +0 -0
  115. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/prompts/formatter.py +0 -0
  116. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/resources/__init__.py +0 -0
  117. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/retrieval/__init__.py +0 -0
  118. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/retrieval/hybrid.py +0 -0
  119. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/retrieval/mmr.py +0 -0
  120. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/retrieval/multi_hop.py +0 -0
  121. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/runtime.py +0 -0
  122. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/server.py +0 -0
  123. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/__init__.py +0 -0
  124. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/document.py +0 -0
  125. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/error.py +0 -0
  126. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/feedback.py +0 -0
  127. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/graph.py +0 -0
  128. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/history.py +0 -0
  129. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/interfaces.py +0 -0
  130. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/milvus/__init__.py +0 -0
  131. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/milvus/client.py +0 -0
  132. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/milvus/collections.py +0 -0
  133. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/milvus/vector_store.py +0 -0
  134. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/mongodb/__init__.py +0 -0
  135. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/mongodb/client.py +0 -0
  136. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/mongodb/graph_store.py +0 -0
  137. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/mongodb/indexes.py +0 -0
  138. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/mongodb/operational_store.py +0 -0
  139. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/relational.py +0 -0
  140. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/repo_state.py +0 -0
  141. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/rule.py +0 -0
  142. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/store/vector.py +0 -0
  143. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/__init__.py +0 -0
  144. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/agents.py +0 -0
  145. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/auth.py +0 -0
  146. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/graph.py +0 -0
  147. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/ingest.py +0 -0
  148. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/memory.py +0 -0
  149. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/query.py +0 -0
  150. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/registry.py +0 -0
  151. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/repo_scanner.py +0 -0
  152. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/seeds/__init__.py +0 -0
  153. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/seeds/default_agents.py +0 -0
  154. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/session.py +0 -0
  155. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/skills.py +0 -0
  156. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/tools/workflow.py +0 -0
  157. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/transport/__init__.py +0 -0
  158. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/transport/base.py +0 -0
  159. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/transport/sse.py +0 -0
  160. {minder_cli-0.5.2 → minder_cli-0.5.3}/src/minder/transport/stdio.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: minder-cli
3
- Version: 0.5.2
3
+ Version: 0.5.3
4
4
  Summary: Minder CLI is the command-line interface for the Minder self-hosted MCP platform.
5
5
  Project-URL: Homepage, https://github.com/hiimtrung/minder
6
6
  Project-URL: Repository, https://github.com/hiimtrung/minder
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "minder-cli"
7
- version = "0.5.2"
7
+ version = "0.5.3"
8
8
  description = "Minder CLI is the command-line interface for the Minder self-hosted MCP platform."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.14"
@@ -479,3 +479,27 @@ class RepositoryLandscapePayload(TypedDict):
479
479
  nodes: list[RepositoryLandscapeNodePayload]
480
480
  edges: list[RepositoryLandscapeEdgePayload]
481
481
  summary: dict[str, int]
482
+
483
+
484
+
485
+ class AgentPayload(TypedDict):
486
+ id: str
487
+ name: str
488
+ title: str
489
+ description: str
490
+ system_prompt: str
491
+ tools: list[str]
492
+ workflow_steps: list[str]
493
+ artifact_types: list[str]
494
+ tags: list[str]
495
+ is_default: bool
496
+ created_at: str | None
497
+ updated_at: str | None
498
+
499
+
500
+ class AgentListPayload(TypedDict):
501
+ agents: list[AgentPayload]
502
+
503
+
504
+ class AgentDetailPayload(TypedDict):
505
+ agent: AgentPayload
@@ -13,6 +13,9 @@ from minder.application.admin.dto import (
13
13
  ActivityEventPayload,
14
14
  AdminLoginPayload,
15
15
  AdminSessionPayload,
16
+ AgentDetailPayload,
17
+ AgentListPayload,
18
+ AgentPayload,
16
19
  AuditEventPayload,
17
20
  AuditListPayload,
18
21
  ClientConnectionTestPayload,
@@ -651,6 +654,116 @@ class AdminConsoleUseCases:
651
654
  ),
652
655
  }
653
656
 
657
+ # ------------------------------------------------------------------
658
+ # SubAgent management
659
+ # ------------------------------------------------------------------
660
+
661
+ async def list_agents(self) -> AgentListPayload:
662
+ agents = await self._store.list_agents()
663
+ return {"agents": [self.serialize_agent(a) for a in agents]}
664
+
665
+ async def get_agent_detail(self, agent_id: uuid.UUID) -> AgentDetailPayload:
666
+ agent = await self._store.get_agent_by_id(agent_id)
667
+ if agent is None:
668
+ raise LookupError(f"Agent {agent_id} not found")
669
+ return {"agent": self.serialize_agent(agent)}
670
+
671
+ async def create_agent(
672
+ self,
673
+ *,
674
+ name: str,
675
+ title: str = "",
676
+ description: str = "",
677
+ system_prompt: str = "",
678
+ tools: list[str] | None = None,
679
+ workflow_steps: list[str] | None = None,
680
+ artifact_types: list[str] | None = None,
681
+ tags: list[str] | None = None,
682
+ is_default: bool = False,
683
+ ) -> AgentDetailPayload:
684
+ agent = await self._store.create_agent(
685
+ name=name,
686
+ title=title,
687
+ description=description,
688
+ system_prompt=system_prompt,
689
+ tools=tools or [],
690
+ workflow_steps=workflow_steps or [],
691
+ artifact_types=artifact_types or [],
692
+ tags=tags or [],
693
+ is_default=is_default,
694
+ )
695
+ return {"agent": self.serialize_agent(agent)}
696
+
697
+ async def update_agent(
698
+ self,
699
+ agent_id: uuid.UUID,
700
+ *,
701
+ name: str | None = None,
702
+ title: str | None = None,
703
+ description: str | None = None,
704
+ system_prompt: str | None = None,
705
+ tools: list[str] | None = None,
706
+ workflow_steps: list[str] | None = None,
707
+ artifact_types: list[str] | None = None,
708
+ tags: list[str] | None = None,
709
+ is_default: bool | None = None,
710
+ ) -> AgentDetailPayload:
711
+ kwargs: dict[str, Any] = {}
712
+ if name is not None:
713
+ kwargs["name"] = name
714
+ if title is not None:
715
+ kwargs["title"] = title
716
+ if description is not None:
717
+ kwargs["description"] = description
718
+ if system_prompt is not None:
719
+ kwargs["system_prompt"] = system_prompt
720
+ if tools is not None:
721
+ kwargs["tools"] = tools
722
+ if workflow_steps is not None:
723
+ kwargs["workflow_steps"] = workflow_steps
724
+ if artifact_types is not None:
725
+ kwargs["artifact_types"] = artifact_types
726
+ if tags is not None:
727
+ kwargs["tags"] = tags
728
+ if is_default is not None:
729
+ kwargs["is_default"] = is_default
730
+ updated = await self._store.update_agent(agent_id, **kwargs)
731
+ if updated is None:
732
+ raise LookupError(f"Agent {agent_id} not found")
733
+ return {"agent": self.serialize_agent(updated)}
734
+
735
+ async def delete_agent(self, agent_id: uuid.UUID) -> dict[str, bool]:
736
+ existing = await self._store.get_agent_by_id(agent_id)
737
+ if existing is None:
738
+ raise LookupError(f"Agent {agent_id} not found")
739
+ await self._store.delete_agent(agent_id)
740
+ return {"deleted": True}
741
+
742
+ @staticmethod
743
+ def serialize_agent(agent: Any) -> AgentPayload:
744
+ return {
745
+ "id": str(agent.id),
746
+ "name": getattr(agent, "name", ""),
747
+ "title": getattr(agent, "title", ""),
748
+ "description": getattr(agent, "description", ""),
749
+ "system_prompt": getattr(agent, "system_prompt", ""),
750
+ "tools": list(getattr(agent, "tools", []) or []),
751
+ "workflow_steps": list(getattr(agent, "workflow_steps", []) or []),
752
+ "artifact_types": list(getattr(agent, "artifact_types", []) or []),
753
+ "tags": list(getattr(agent, "tags", []) or []),
754
+ "is_default": bool(getattr(agent, "is_default", False)),
755
+ "created_at": (
756
+ agent.created_at.isoformat()
757
+ if getattr(agent, "created_at", None)
758
+ else None
759
+ ),
760
+ "updated_at": (
761
+ agent.updated_at.isoformat()
762
+ if getattr(agent, "updated_at", None)
763
+ else None
764
+ ),
765
+ }
766
+
654
767
  # ------------------------------------------------------------------
655
768
  # Session management
656
769
  # ------------------------------------------------------------------
@@ -788,19 +901,43 @@ class AdminConsoleUseCases:
788
901
  if not normalized_path:
789
902
  raise ValueError("Repository path is required")
790
903
  updates["state_path"] = normalized_path
904
+ new_workflow_id: uuid.UUID | None = _UNSET # type: ignore[assignment]
791
905
  if workflow_id is not _UNSET:
792
906
  if workflow_id is None or str(workflow_id).strip() == "":
793
907
  updates["workflow_id"] = None
908
+ new_workflow_id = None
794
909
  else:
795
910
  wf_id = uuid.UUID(str(workflow_id))
796
911
  workflow = await self._store.get_workflow_by_id(wf_id)
797
912
  if workflow is None:
798
913
  raise LookupError(f"Workflow {wf_id} not found")
799
914
  updates["workflow_id"] = str(wf_id)
915
+ new_workflow_id = wf_id
800
916
 
801
917
  updated = await self._store.update_repository(repo_id, **updates)
802
918
  if updated is None:
803
919
  raise LookupError("Repository not found")
920
+
921
+ # Create workflow_state when a workflow is first assigned to a repo
922
+ if new_workflow_id is not _UNSET and new_workflow_id is not None: # type: ignore[comparison-overlap]
923
+ existing_state = await self._store.get_workflow_state_by_repo(repo_id)
924
+ if existing_state is None:
925
+ workflow_obj = await self._store.get_workflow_by_id(new_workflow_id)
926
+ steps = list(getattr(workflow_obj, "steps", []) or []) if workflow_obj else []
927
+ step_names = [
928
+ s["name"] for s in steps if isinstance(s, dict) and "name" in s
929
+ ]
930
+ first_step = step_names[0] if step_names else ""
931
+ second_step = step_names[1] if len(step_names) > 1 else None
932
+ await self._store.create_workflow_state(
933
+ repo_id=repo_id,
934
+ current_step=first_step,
935
+ completed_steps=[],
936
+ blocked_by=[],
937
+ artifacts={},
938
+ next_step=second_step,
939
+ )
940
+
804
941
  return await self.get_repository_detail(repo_id)
805
942
 
806
943
  async def delete_repository(self, repo_id: uuid.UUID) -> DeleteRepositoryPayload:
@@ -520,6 +520,98 @@ def build_admin_api_routes(context: AdminRouteContext) -> list[BaseRoute]:
520
520
 
521
521
  return JSONResponse({"error": "Method not allowed"}, status_code=405)
522
522
 
523
+ # ------------------------------------------------------------------
524
+ # SubAgent management
525
+ # ------------------------------------------------------------------
526
+
527
+ async def admin_agents(request):
528
+ try:
529
+ await context.admin_user_from_request(request)
530
+ except PermissionError:
531
+ return JSONResponse({"error": "Admin role required"}, status_code=403)
532
+ except Exception as exc:
533
+ return JSONResponse({"error": str(exc)}, status_code=401)
534
+
535
+ if request.method == "GET":
536
+ return JSONResponse(await context.use_cases.list_agents())
537
+
538
+ if request.method == "POST":
539
+ try:
540
+ payload = await request.json()
541
+ except Exception:
542
+ return JSONResponse({"error": "Invalid JSON"}, status_code=400)
543
+ name = str(payload.get("name", "")).strip()
544
+ if not name:
545
+ return JSONResponse({"error": "name is required"}, status_code=400)
546
+ try:
547
+ return JSONResponse(
548
+ await context.use_cases.create_agent(
549
+ name=name,
550
+ title=str(payload.get("title", "")),
551
+ description=str(payload.get("description", "")),
552
+ system_prompt=str(payload.get("system_prompt", "")),
553
+ tools=payload.get("tools") or [],
554
+ workflow_steps=payload.get("workflow_steps") or [],
555
+ artifact_types=payload.get("artifact_types") or [],
556
+ tags=payload.get("tags") or [],
557
+ is_default=bool(payload.get("is_default", False)),
558
+ ),
559
+ status_code=201,
560
+ )
561
+ except Exception as exc:
562
+ return JSONResponse({"error": str(exc)}, status_code=400)
563
+
564
+ return JSONResponse({"error": "Method not allowed"}, status_code=405)
565
+
566
+ async def agent_detail(request):
567
+ try:
568
+ await context.admin_user_from_request(request)
569
+ except PermissionError:
570
+ return JSONResponse({"error": "Admin role required"}, status_code=403)
571
+ except Exception as exc:
572
+ return JSONResponse({"error": str(exc)}, status_code=401)
573
+
574
+ agent_id = uuid.UUID(str(request.path_params["agent_id"]))
575
+
576
+ if request.method == "GET":
577
+ try:
578
+ return JSONResponse(await context.use_cases.get_agent_detail(agent_id))
579
+ except LookupError:
580
+ return JSONResponse({"error": "Agent not found"}, status_code=404)
581
+
582
+ if request.method == "PATCH":
583
+ try:
584
+ payload = await request.json()
585
+ except Exception:
586
+ return JSONResponse({"error": "Invalid JSON"}, status_code=400)
587
+ try:
588
+ return JSONResponse(
589
+ await context.use_cases.update_agent(
590
+ agent_id,
591
+ name=payload.get("name"),
592
+ title=payload.get("title"),
593
+ description=payload.get("description"),
594
+ system_prompt=payload.get("system_prompt"),
595
+ tools=payload.get("tools"),
596
+ workflow_steps=payload.get("workflow_steps"),
597
+ artifact_types=payload.get("artifact_types"),
598
+ tags=payload.get("tags"),
599
+ is_default=payload.get("is_default"),
600
+ )
601
+ )
602
+ except LookupError:
603
+ return JSONResponse({"error": "Agent not found"}, status_code=404)
604
+ except Exception as exc:
605
+ return JSONResponse({"error": str(exc)}, status_code=400)
606
+
607
+ if request.method == "DELETE":
608
+ try:
609
+ return JSONResponse(await context.use_cases.delete_agent(agent_id))
610
+ except LookupError:
611
+ return JSONResponse({"error": "Agent not found"}, status_code=404)
612
+
613
+ return JSONResponse({"error": "Method not allowed"}, status_code=405)
614
+
523
615
  # ------------------------------------------------------------------
524
616
  # Workflow management
525
617
  # ------------------------------------------------------------------
@@ -1331,6 +1423,13 @@ def build_admin_api_routes(context: AdminRouteContext) -> list[BaseRoute]:
1331
1423
  user_detail,
1332
1424
  methods=["GET", "PATCH", "DELETE"],
1333
1425
  ),
1426
+ # SubAgent management
1427
+ Route("/v1/admin/agents", admin_agents, methods=["GET", "POST"]),
1428
+ Route(
1429
+ "/v1/admin/agents/{agent_id:uuid}",
1430
+ agent_detail,
1431
+ methods=["GET", "PATCH", "DELETE"],
1432
+ ),
1334
1433
  # Workflow management
1335
1434
  Route("/v1/admin/workflows", admin_workflows, methods=["GET", "POST"]),
1336
1435
  Route(
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes