devops-bot-sdk 1.4.117__tar.gz → 1.4.119__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 (90) hide show
  1. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/PKG-INFO +1 -1
  2. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
  3. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/devops_bot_sdk.egg-info/SOURCES.txt +1 -1
  4. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/pyproject.toml +4 -1
  5. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/__init__.py +3 -3
  6. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agentd.py +6 -7
  7. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/prompt_studio.py +104 -0
  8. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/cli.py +25 -263
  9. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/client.py +81 -91
  10. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/config.py +68 -0
  11. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ipc/handlers.py +8 -8
  12. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/api.py +141 -222
  13. devops_bot_sdk-1.4.119/sdk/ui/ip_allowlist.py +110 -0
  14. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/security.py +9 -2
  15. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/server.py +16 -3
  16. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/static/app.js +17 -35
  17. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/static/custom-agents.html +7 -8
  18. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/static/default-agents.html +3 -3
  19. devops_bot_sdk-1.4.117/sdk/ui/static/prompt-studio.html +0 -92
  20. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/README.md +0 -0
  21. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
  22. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
  23. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/devops_bot_sdk.egg-info/requires.txt +0 -0
  24. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/devops_bot_sdk.egg-info/top_level.txt +0 -0
  25. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/__init__.py +0 -0
  26. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/builder.py +0 -0
  27. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/chat.py +0 -0
  28. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/connectors.py +0 -0
  29. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/engines/__init__.py +0 -0
  30. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/engines/claude_code.py +0 -0
  31. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/engines/http.py +0 -0
  32. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/engines/mcp.py +0 -0
  33. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/engines/n8n.py +0 -0
  34. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/engines/shell.py +0 -0
  35. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/integrations.py +0 -0
  36. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/inventory.py +0 -0
  37. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/library/__init__.py +0 -0
  38. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/manifest.py +0 -0
  39. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/prompt_template.py +0 -0
  40. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/prompt_vars.py +0 -0
  41. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/run_log.py +0 -0
  42. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/secrets.py +0 -0
  43. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/usage.py +0 -0
  44. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/agents/varstore.py +0 -0
  45. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/collectors/__init__.py +0 -0
  46. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/collectors/files.py +0 -0
  47. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/collectors/process.py +0 -0
  48. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/collectors/screenshot.py +0 -0
  49. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/crucial.py +0 -0
  50. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/design_verify/__init__.py +0 -0
  51. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/design_verify/assets.py +0 -0
  52. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/design_verify/bootstrap.py +0 -0
  53. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/design_verify/browser.py +0 -0
  54. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/design_verify/compare.py +0 -0
  55. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/design_verify/loop.py +0 -0
  56. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/exceptions.py +0 -0
  57. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/git_ops.py +0 -0
  58. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/graphify.py +0 -0
  59. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/hooks/__init__.py +0 -0
  60. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/hooks/crucial_guard.py +0 -0
  61. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ipc/__init__.py +0 -0
  62. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ipc/electron_bridge.py +0 -0
  63. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/local_exec.py +0 -0
  64. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/models/__init__.py +0 -0
  65. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/models/envelope.py +0 -0
  66. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/models/requests.py +0 -0
  67. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/models/responses.py +0 -0
  68. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/models/snapshots.py +0 -0
  69. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/platform_compat.py +0 -0
  70. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/py.typed +0 -0
  71. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/run_auto.py +0 -0
  72. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/sse.py +0 -0
  73. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/test.py +0 -0
  74. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/test_pipeline.py +0 -0
  75. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/__init__.py +0 -0
  76. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/dashboard.py +0 -0
  77. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/jobs.py +0 -0
  78. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/runner.py +0 -0
  79. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/service.py +0 -0
  80. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/setup_manager.py +0 -0
  81. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/static/agents.html +0 -0
  82. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/static/index.html +0 -0
  83. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/static/runs.html +0 -0
  84. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/static/setup.html +0 -0
  85. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/static/styles.css +0 -0
  86. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/ui/static/tickets.html +0 -0
  87. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/sdk/updater.py +0 -0
  88. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/setup.cfg +0 -0
  89. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/tests/test_agent_chat_features.py +0 -0
  90. {devops_bot_sdk-1.4.117 → devops_bot_sdk-1.4.119}/tests/test_agents_connectors_builder.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devops-bot-sdk
3
- Version: 1.4.117
3
+ Version: 1.4.119
4
4
  Summary: DevOps Bot Desktop SDK — thin client for the AgentOS Electron desktop app
5
5
  Author: noumanaziz2128
6
6
  License-Expression: LicenseRef-Proprietary
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devops-bot-sdk
3
- Version: 1.4.117
3
+ Version: 1.4.119
4
4
  Summary: DevOps Bot Desktop SDK — thin client for the AgentOS Electron desktop app
5
5
  Author: noumanaziz2128
6
6
  License-Expression: LicenseRef-Proprietary
@@ -67,6 +67,7 @@ sdk/models/snapshots.py
67
67
  sdk/ui/__init__.py
68
68
  sdk/ui/api.py
69
69
  sdk/ui/dashboard.py
70
+ sdk/ui/ip_allowlist.py
70
71
  sdk/ui/jobs.py
71
72
  sdk/ui/runner.py
72
73
  sdk/ui/security.py
@@ -78,7 +79,6 @@ sdk/ui/static/app.js
78
79
  sdk/ui/static/custom-agents.html
79
80
  sdk/ui/static/default-agents.html
80
81
  sdk/ui/static/index.html
81
- sdk/ui/static/prompt-studio.html
82
82
  sdk/ui/static/runs.html
83
83
  sdk/ui/static/setup.html
84
84
  sdk/ui/static/styles.css
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "devops-bot-sdk"
7
- version = "1.4.117"
7
+ dynamic = ["version"] # single source of truth: sdk/__init__.py __version__
8
8
  description = "DevOps Bot Desktop SDK — thin client for the AgentOS Electron desktop app"
9
9
  readme = "README.md"
10
10
  license = "LicenseRef-Proprietary"
@@ -49,6 +49,9 @@ agentos-ui = "sdk.ui.server:main" # local web control panel (needs the
49
49
  Homepage = "https://agentos.io"
50
50
  Repository = "https://github.com/consultancy-outfit/DevOpsBot-SDK"
51
51
 
52
+ [tool.setuptools.dynamic]
53
+ version = { attr = "sdk.__version__" } # bump sdk/__init__.py → wheel + client + server all follow
54
+
52
55
  [tool.setuptools.packages.find]
53
56
  where = ["."]
54
57
  include = ["sdk*"]
@@ -1,6 +1,6 @@
1
1
  """AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
2
2
 
3
- Version: 1.4.117
3
+ Version: 1.4.119
4
4
 
5
5
  Public surface:
6
6
  BackendClient.from_config() — create client from ~/.agentos/config.toml
@@ -30,8 +30,8 @@ Rules:
30
30
  - All data egress through submit_webhook only
31
31
  """
32
32
 
33
- __version__ = "1.4.117"
34
- __author__ = "AgentOS"
33
+ __version__ = "1.4.119" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
34
+ __author__ = "AgentOS" # sdk.client.SDK_VERSION and the UI server version all read this.
35
35
 
36
36
  from sdk.client import BackendClient
37
37
  from sdk.exceptions import (
@@ -15,9 +15,9 @@ See docs/GUIDE_2_Development_Plan_Custom_Agents.md:
15
15
  ``sdk/run_auto.py`` (which only ever drives the Jira To-Do queue) into a
16
16
  general-purpose daemon with five components:
17
17
  1. manifest loader — ``sdk.agents.manifest.load_agents()``
18
- 2. registration push every loaded PERSONAL manifest to the
19
- backend (``BackendClient.register_custom_agent``)
20
- so dashboards/routing stay in sync
18
+ 2. (removed) registration the daemon no longer pushes local manifests to
19
+ the backend; agents are authored in the web app
20
+ and the SDK is consume-only (local trigger/run).
21
21
  3. department pull — fetch this user's DEPARTMENT default agents
22
22
  (``BackendClient.list_department_agents()``)
23
23
  and materialize them alongside personal
@@ -451,12 +451,11 @@ class AgentDaemon:
451
451
  department = await self._load_department_agents()
452
452
  self._manifests = personal + department
453
453
 
454
+ # Consume-only: the daemon no longer registers/pushes local manifests to
455
+ # the backend — agents are authored in the web app and written to the
456
+ # `agents` table. The daemon just schedules + runs them LOCALLY on trigger.
454
457
  for m in personal:
455
458
  self._schedule_if_cron(m, job_id=m.name)
456
- try:
457
- await self.client.register_custom_agent(m.model_dump(mode="json"))
458
- except Exception as exc: # noqa: BLE001 — registration is best-effort
459
- logger.warning("agentd.register_failed agent=%s err=%s", m.name, exc)
460
459
 
461
460
  for m in department:
462
461
  # "dept:" job-id prefix avoids colliding with a personal agent
@@ -92,6 +92,110 @@ def build_comments_prompt(system_prompt: str) -> str:
92
92
  return COMMENTS_INSTRUCTION.replace("__SYSTEM_PROMPT__", system_prompt.strip())
93
93
 
94
94
 
95
+ # ── Generate: name + type + job → a full system prompt with {{variables}} ────
96
+ # This is the claude_code engine's authoring instruction. It runs LOCALLY in the
97
+ # SDK (run_claude_local); the AI backend calls this SDK endpoint on the VPS.
98
+
99
+ GENERATE_INSTRUCTION = (
100
+ "You are an expert prompt engineer. Write the SYSTEM PROMPT for a reusable AI "
101
+ "agent, given its NAME, TYPE, and main JOB. Produce a single, self-contained "
102
+ "prompt that follows EXACTLY this structure and Markdown headings:\n"
103
+ "# Role\nYou are <NAME>, <one-line identity from the type and job>.\n"
104
+ "## Objective\n<one paragraph: the single outcome this agent must produce>\n"
105
+ "## Rules\n- <hard constraints and guardrails>\n"
106
+ "- Never embed secrets; reference credentials as ${ENV_VAR} placeholders.\n"
107
+ "## Workflow\n1. <ordered steps to do the job>\n"
108
+ "## Output\n<exactly what the agent returns and in what format>\n\n"
109
+ "VARIABLE RULE (critical): any value the user must supply AT RUN TIME must "
110
+ "appear in the prompt text as {{variable_name}} (double curly braces, "
111
+ "snake_case). Only create a variable when the job genuinely needs a per-run "
112
+ "input; a self-contained agent may have NONE. Do not invent placeholders for "
113
+ "things the agent can work out itself.\n"
114
+ "Return ONLY a single minified JSON object, no prose, of the exact shape:\n"
115
+ '{"system_prompt":"<full prompt text with \\n line breaks and {{vars}} inline>",'
116
+ '"variables":[{"name":"","label":"","description":"","type":"string"}]}\n'
117
+ "Every {{variable}} in system_prompt MUST have a matching entry in variables, "
118
+ "and vice-versa. If there are none, return \"variables\": [].\n\n"
119
+ "AGENT NAME: __NAME__\nAGENT TYPE: __TYPE__\nMAIN JOB: __JOB____CONTEXT__"
120
+ )
121
+
122
+ REGENERATE_INSTRUCTION = (
123
+ "You are an expert prompt engineer. REGENERATE and improve the EXISTING system "
124
+ "prompt below. The same rules as a fresh prompt apply: keep the exact structure "
125
+ "(# Role / ## Objective / ## Rules / ## Workflow / ## Output), keep "
126
+ "{{variable_name}} placeholders for every per-run input, and keep every "
127
+ "{{variable}} and the variables list in sync. Preserve the original intent and "
128
+ "any working variables; fix structure, clarity, missing sections, weak rules, "
129
+ "and vague output specs. Apply the FEEDBACK if given.\n"
130
+ "Return ONLY a single minified JSON object of the exact shape:\n"
131
+ '{"system_prompt":"...","variables":[{"name":"","label":"","description":"","type":"string"}]}\n\n'
132
+ "__META__FEEDBACK: __FEEDBACK__\n\nEXISTING SYSTEM PROMPT:\n```\n__PROMPT__\n```"
133
+ )
134
+
135
+
136
+ def build_generate_prompt(agent_name: str, agent_type: str, job: str,
137
+ context: str = "") -> str:
138
+ ctx = f"\nADDITIONAL CONTEXT: {context.strip()}" if context and context.strip() else ""
139
+ return (
140
+ GENERATE_INSTRUCTION
141
+ .replace("__NAME__", (agent_name or "").strip())
142
+ .replace("__TYPE__", (agent_type or "").strip())
143
+ .replace("__JOB__", (job or "").strip())
144
+ .replace("__CONTEXT__", ctx)
145
+ )
146
+
147
+
148
+ def build_regenerate_prompt(system_prompt: str, feedback: str = "",
149
+ agent_name: str = "", agent_type: str = "",
150
+ job: str = "") -> str:
151
+ meta_bits = []
152
+ if (agent_name or "").strip():
153
+ meta_bits.append(f"AGENT NAME: {agent_name.strip()}")
154
+ if (agent_type or "").strip():
155
+ meta_bits.append(f"AGENT TYPE: {agent_type.strip()}")
156
+ if (job or "").strip():
157
+ meta_bits.append(f"MAIN JOB: {job.strip()}")
158
+ meta = ("\n".join(meta_bits) + "\n") if meta_bits else ""
159
+ return (
160
+ REGENERATE_INSTRUCTION
161
+ .replace("__META__", meta)
162
+ .replace("__FEEDBACK__", (feedback or "").strip() or "(none — just improve quality)")
163
+ .replace("__PROMPT__", (system_prompt or "").strip())
164
+ )
165
+
166
+
167
+ def parse_generation(model_output: str) -> dict:
168
+ """Parse a generate/regenerate model reply into ``{system_prompt, variables}``.
169
+
170
+ Placeholders present in the produced prompt are authoritative for the variable
171
+ LIST (so prompt ↔ schema can't drift); the model's ``variables`` array only
172
+ supplies each one's label/description/type. Tolerant of fences/prose.
173
+ """
174
+ from sdk.agents.prompt_vars import extract_variables
175
+
176
+ data = _extract_json(model_output)
177
+ system_prompt = str(data.get("system_prompt", "")).strip() if isinstance(data, dict) else ""
178
+
179
+ meta: dict[str, dict] = {}
180
+ for v in (data.get("variables", []) if isinstance(data, dict) else []):
181
+ if isinstance(v, dict) and str(v.get("name", "")).strip():
182
+ meta[str(v["name"]).strip()] = v
183
+ elif isinstance(v, str) and v.strip():
184
+ meta[v.strip()] = {"name": v.strip()}
185
+
186
+ variables = []
187
+ for name in extract_variables(system_prompt):
188
+ m = meta.get(name, {})
189
+ vtype = str(m.get("type", "string")).strip() or "string"
190
+ variables.append({
191
+ "name": name,
192
+ "label": str(m.get("label") or name.replace("_", " ").title()).strip(),
193
+ "description": str(m.get("description", "")).strip(),
194
+ "type": vtype,
195
+ })
196
+ return {"system_prompt": system_prompt, "variables": variables}
197
+
198
+
95
199
  def _extract_json(model_output: str) -> dict:
96
200
  text = (model_output or "").strip()
97
201
  if "```" in text:
@@ -104,10 +104,10 @@ def _print_usage() -> None:
104
104
  print("usage: agentos <configure|agent|integration|default-agents|agentd> ...")
105
105
  print()
106
106
  print(" agentos configure [--rotate]")
107
- print(" agentos agent <new|add PATH|list|run NAME|chat NAME MSG|logs NAME|enable NAME|disable NAME|rm NAME>")
107
+ print(" agentos agent <list|run NAME|chat NAME MSG|logs NAME|enable NAME|disable NAME|rm NAME>")
108
108
  print(" agentos agent <set-key NAME KEY[=VALUE]…|keys NAME|rm-key NAME KEY…> # persistent API keys (custom agents)")
109
109
  print(" agentos integration <add PATH|test NAME|list|rm NAME>")
110
- print(" agentos default-agents <list|activate NAME|seed PATH|seed-library [SLUG]|enable NAME|disable NAME|rm NAME> [--department-id UUID]")
110
+ print(" agentos default-agents list [--department-id UUID] # read-only; agents are created in the web app")
111
111
  print(" agentos agentd <start [--foreground]|status>")
112
112
 
113
113
 
@@ -117,11 +117,13 @@ def _agent_command(args: list[str]) -> None:
117
117
  verb = args[0] if args else None
118
118
  rest = args[1:]
119
119
 
120
- if verb == "new":
121
- _agent_new()
122
- return
123
- if verb == "add" and rest:
124
- _agent_add(rest[0])
120
+ # Agent CREATION (`new` / `add`) is not owned by the SDK anymore — agents are
121
+ # authored in the web app and written to the backend `agents` table. The CLI is
122
+ # consume-only: list / run / chat / logs / enable / disable / rm / keys.
123
+ if verb in ("new", "add"):
124
+ print("`agentos agent new/add` has been removed — agents are created in the "
125
+ "web app now. Use `agentos agent list` to see yours and `agentos agent "
126
+ "run <name>` to run one.")
125
127
  return
126
128
  if verb == "list":
127
129
  _agent_list()
@@ -132,10 +134,6 @@ def _agent_command(args: list[str]) -> None:
132
134
  if verb == "chat" and len(rest) >= 2:
133
135
  _agent_chat(rest[0], " ".join(rest[1:]))
134
136
  return
135
- if verb == "template":
136
- from sdk.agents.prompt_template import render_system_prompt
137
- print(render_system_prompt(name=(rest[0] if rest else "my-agent")))
138
- return
139
137
  if verb == "logs" and rest:
140
138
  _agent_logs(rest[0])
141
139
  return
@@ -183,80 +181,6 @@ def _agent_chat(name: str, message: str) -> None:
183
181
  sys.exit(1)
184
182
 
185
183
 
186
- def _register_agent(manifest) -> None:
187
- """Register a validated manifest with the backend — shared by `new` and `add`."""
188
- from sdk.client import BackendClient
189
-
190
- resp = asyncio.run(
191
- BackendClient.from_config().register_custom_agent(manifest.model_dump(mode="json"))
192
- )
193
- resp = resp or {}
194
- agent_id = resp.get("id") or resp.get("agent_id")
195
- status = resp.get("status")
196
- print(f"registered '{manifest.name}' with backend — id={agent_id} status={status}")
197
-
198
-
199
- def _agent_new() -> None:
200
- from sdk.agents.manifest import AGENTS_DIR, AgentManifest, TriggerSpec
201
-
202
- print("AgentOS — New Agent")
203
- print("=" * 40)
204
- name = input("Name: ").strip()
205
- description = input("Description: ").strip()
206
- engine = input("Engine [claude_code]: ").strip() or "claude_code"
207
- trigger_type = input("Trigger type (schedule/ticket_label/manual/webhook): ").strip()
208
-
209
- trigger_kwargs: dict = {"type": trigger_type}
210
- if trigger_type == "schedule":
211
- trigger_kwargs["cron"] = input("Cron string: ").strip()
212
- elif trigger_type == "ticket_label":
213
- trigger_kwargs["ticket_label"] = input("Ticket label: ").strip()
214
- # manual / webhook need no extra prompt
215
-
216
- prompt_text = input("Prompt: ").strip()
217
-
218
- try:
219
- trigger = TriggerSpec(**trigger_kwargs)
220
- manifest = AgentManifest(
221
- name=name,
222
- description=description,
223
- engine=engine,
224
- trigger=trigger,
225
- prompt=prompt_text,
226
- )
227
- except Exception as exc: # noqa: BLE001 — surface pydantic's validation message plainly
228
- print(f"error: invalid agent — {exc}")
229
- sys.exit(1)
230
-
231
- AGENTS_DIR.mkdir(parents=True, exist_ok=True)
232
- dest = AGENTS_DIR / f"{manifest.name}.yaml"
233
- dest.write_text(yaml.safe_dump(manifest.model_dump(mode="json"), sort_keys=False))
234
- print(f"saved manifest to {dest}")
235
-
236
- _register_agent(manifest)
237
-
238
-
239
- def _agent_add(path: str) -> None:
240
- from sdk.agents.manifest import AGENTS_DIR, AgentManifest
241
-
242
- src = Path(path).expanduser()
243
- try:
244
- raw_text = src.read_text()
245
- data = yaml.safe_load(raw_text) or {}
246
- manifest = AgentManifest(**data)
247
- except Exception as exc: # noqa: BLE001 — surface a clear validation/IO error
248
- print(f"error: invalid agent manifest '{path}' — {exc}")
249
- sys.exit(1)
250
-
251
- AGENTS_DIR.mkdir(parents=True, exist_ok=True)
252
- dest = AGENTS_DIR / f"{manifest.name}.yaml"
253
- if dest.resolve() != src.resolve():
254
- dest.write_text(raw_text)
255
- print(f"copied manifest to {dest}")
256
-
257
- _register_agent(manifest)
258
-
259
-
260
184
  def _agent_list() -> None:
261
185
  from sdk.agents.manifest import load_agents
262
186
  from sdk.client import BackendClient
@@ -543,201 +467,39 @@ def _default_agents_command(args: list[str]) -> None:
543
467
  if verb == "list":
544
468
  _default_agents_list(_resolve_department_id(dept_id))
545
469
  return
546
- if verb == "activate" and tail:
547
- _default_agents_activate(_resolve_department_id(dept_id), tail[0])
548
- return
549
- # ── manager verbs (team_lead+ of the department) ──
550
- # Gated client-side by role (employees are refused); the backend also enforces.
551
- if verb == "seed" and tail:
552
- _require_department_manager(verb)
553
- _default_agents_seed(_resolve_department_id(dept_id), tail)
554
- return
555
- if verb == "seed-library":
556
- _require_department_manager(verb)
557
- _default_agents_seed_library(_resolve_department_id(dept_id), tail)
558
- return
559
- if verb in ("enable", "disable") and tail:
560
- _require_department_manager(verb)
561
- _default_agents_set_status(
562
- _resolve_department_id(dept_id), tail[0],
563
- "active" if verb == "enable" else "disabled",
564
- )
565
- return
566
- if verb == "rm" and tail:
567
- _require_department_manager(verb)
568
- _default_agents_rm(_resolve_department_id(dept_id), tail[0])
470
+
471
+ # Seeding / activating / managing department defaults is not owned by the SDK
472
+ # anymore — agents are authored in the web app and written to the backend
473
+ # `agents` table. The CLI is consume-only.
474
+ if verb in ("seed", "seed-library", "activate", "enable", "disable", "rm"):
475
+ print(f"`agentos default-agents {verb}` has been removed — department default "
476
+ "agents are managed in the web app now. Use `agentos default-agents list`.")
569
477
  return
570
478
 
571
- print(
572
- "usage: agentos default-agents "
573
- "<list|activate NAME|seed PATH|seed-library [SLUG]|enable NAME|disable NAME|rm NAME> "
574
- "[--department-id UUID]"
575
- )
576
- print(" (seed/enable/disable/rm require department-manager rights)")
479
+ print("usage: agentos default-agents list [--department-id UUID]")
577
480
  sys.exit(1)
578
481
 
579
482
 
580
- def _default_agents_seed(department_id: str, tail: list[str]) -> None:
581
- """Create/update ONE department default from a manifest YAML (manager only).
582
-
583
- Flags: --min-role-tier TIER, --sort-order N, --system.
584
- """
585
- import yaml
586
-
587
- path = tail[0]
588
- min_tier, sort_order, is_system = "employee", 0, False
589
- i = 1
590
- while i < len(tail):
591
- if tail[i] == "--min-role-tier" and i + 1 < len(tail):
592
- min_tier = tail[i + 1]; i += 2; continue
593
- if tail[i] == "--sort-order" and i + 1 < len(tail):
594
- sort_order = int(tail[i + 1]); i += 2; continue
595
- if tail[i] == "--system":
596
- is_system = True; i += 1; continue
597
- i += 1
598
-
599
- from sdk.agents.manifest import AgentManifest
600
- from sdk.client import BackendClient
601
-
602
- try:
603
- raw = yaml.safe_load(Path(path).expanduser().read_text()) or {}
604
- AgentManifest(**raw) # validate before sending
605
- except Exception as exc: # noqa: BLE001
606
- print(f"error: invalid manifest '{path}' — {exc}")
607
- sys.exit(1)
608
-
609
- payload = {
610
- "manifest": raw,
611
- "min_role_tier": min_tier,
612
- "is_system_default": is_system,
613
- "sort_order": sort_order,
614
- }
615
- try:
616
- result = asyncio.run(
617
- BackendClient.from_config().seed_department_default_agent(department_id, payload)
618
- )
619
- except Exception as exc: # noqa: BLE001 — surface 403 (not a manager) clearly
620
- print(f"error: {exc}")
621
- sys.exit(1)
622
- print(f"seeded default agent '{raw.get('name')}' into department {department_id} "
623
- f"(id={result.get('agent_id')})")
624
-
625
-
626
- def _default_agents_seed_library(department_id: str, tail: list[str]) -> None:
627
- """Seed a whole department's bundled library (manager only). SLUG defaults to 'developers'."""
628
- from sdk.agents.library import load_department
629
- from sdk.client import BackendClient
630
-
631
- slug = tail[0] if tail else "developers"
632
- try:
633
- templates = load_department(slug)
634
- except KeyError:
635
- print(f"error: no library department '{slug}'")
636
- sys.exit(1)
637
-
638
- client = BackendClient.from_config()
639
- ok = 0
640
- for t in templates:
641
- payload = {
642
- "manifest": t.manifest.model_dump(mode="json"),
643
- "min_role_tier": t.min_role_tier,
644
- "is_system_default": t.is_system_default,
645
- "sort_order": t.sort_order,
646
- }
647
- try:
648
- asyncio.run(client.seed_department_default_agent(department_id, payload))
649
- print(f" seeded {t.manifest.name}")
650
- ok += 1
651
- except Exception as exc: # noqa: BLE001
652
- print(f" FAILED {t.manifest.name}: {exc}", file=sys.stderr)
653
- print(f"seeded {ok}/{len(templates)} '{slug}' agents into department {department_id}")
654
-
655
-
656
- def _default_agents_set_status(department_id: str, name: str, status: str) -> None:
657
- from sdk.client import BackendClient
658
- try:
659
- asyncio.run(
660
- BackendClient.from_config().update_department_default_agent(
661
- department_id, name, status
662
- )
663
- )
664
- except Exception as exc: # noqa: BLE001
665
- print(f"error: {exc}")
666
- sys.exit(1)
667
- print(f"default agent '{name}' set to {status}")
668
-
669
-
670
- def _default_agents_rm(department_id: str, name: str) -> None:
671
- from sdk.client import BackendClient
672
- try:
673
- asyncio.run(
674
- BackendClient.from_config().delete_department_default_agent(department_id, name)
675
- )
676
- except Exception as exc: # noqa: BLE001
677
- print(f"error: {exc}")
678
- sys.exit(1)
679
- print(f"deleted default agent '{name}' from department {department_id}")
680
-
681
-
682
483
  def _default_agents_list(department_id: str) -> None:
484
+ """List the caller's department default agents (read-only, new prompt schema)."""
683
485
  from sdk.client import BackendClient
684
486
  from sdk.exceptions import BackendFeatureMissing
685
487
 
686
488
  try:
687
- agents = asyncio.run(
688
- BackendClient.from_config().list_department_default_agents(department_id)
689
- )
489
+ agents = asyncio.run(BackendClient.from_config().list_department_agents())
690
490
  except BackendFeatureMissing as exc:
691
- # A 404 here means the endpoint isn't deployed — NOT that the department
692
- # has no defaults. Say so, so this isn't mistaken for an empty list.
693
491
  print(f"error: {exc}")
694
492
  sys.exit(1)
695
493
  if not agents:
696
- print(f"no default agents seeded for department {department_id} "
697
- f"(a manager can add them with `agentos default-agents seed …`).")
494
+ print(f"no department default agents visible for department {department_id}.")
698
495
  return
699
496
 
700
- print(f"{'NAME':<26}{'ENGINE':<13}{'TRIGGER':<14}{'MIN TIER':<11}{'STATUS'}")
497
+ print(f"{'NAME':<28}{'STATUS':<10}{'SKILLS':<8}SUMMARY")
701
498
  for a in agents:
702
- print(
703
- f"{a.get('name',''):<26}{a.get('engine',''):<13}"
704
- f"{a.get('trigger_type',''):<14}{a.get('min_role_tier',''):<11}{a.get('status','')}"
705
- )
706
-
707
-
708
- def _default_agents_activate(department_id: str, name: str) -> None:
709
- """Clone a department default into the caller's custom agents + install locally."""
710
- import yaml as _yaml
711
-
712
- from sdk.agents.library import find_template
713
- from sdk.agents.manifest import AGENTS_DIR, SKILLS_DIR
714
- from sdk.client import BackendClient
715
-
716
- result = asyncio.run(
717
- BackendClient.from_config().activate_department_default_agent(department_id, name)
718
- )
719
- manifest = result.get("manifest") or {}
720
-
721
- # Install the manifest locally so agentd / `agent run` can execute it.
722
- if manifest:
723
- AGENTS_DIR.mkdir(parents=True, exist_ok=True)
724
- (AGENTS_DIR / f"{name}.yaml").write_text(
725
- _yaml.safe_dump(manifest, sort_keys=False)
726
- )
727
-
728
- # Copy any skills the template bundles into ~/.agentos/skills.
729
- template = find_template(name)
730
- copied_skills: list[str] = []
731
- if template and template.skills:
732
- SKILLS_DIR.mkdir(parents=True, exist_ok=True)
733
- for skill_name, path in template.skills.items():
734
- (SKILLS_DIR / f"{skill_name}.md").write_text(path.read_text(encoding="utf-8"))
735
- copied_skills.append(skill_name)
736
-
737
- print(f"activated '{name}' — cloned to your custom agents (id={result.get('custom_agent_id')})")
738
- print(f" installed manifest to {AGENTS_DIR / (name + '.yaml')}")
739
- if copied_skills:
740
- print(f" installed skills: {', '.join(copied_skills)}")
499
+ prompt = a.get("prompt") or {}
500
+ summary = (prompt.get("system_prompt") if isinstance(prompt, dict) else "") or ""
501
+ print(f"{a.get('name',''):<28}{a.get('status',''):<10}"
502
+ f"{len(a.get('skills') or []):<8}{summary.strip()[:60]}")
741
503
 
742
504
 
743
505
  # ── agentd ───────────────────────────────────────────────────────────────