devops-bot-sdk 1.4.120__tar.gz → 1.4.125__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.
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/inventory.py +45 -33
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/api.py +72 -52
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/static/app.js +39 -8
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/static/custom-agents.html +6 -3
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/README.md +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/devops_bot_sdk.egg-info/SOURCES.txt +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/devops_bot_sdk.egg-info/requires.txt +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/pyproject.toml +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agentd.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/__init__.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/builder.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/chat.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/connectors.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/engines/__init__.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/engines/claude_code.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/engines/http.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/engines/mcp.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/engines/n8n.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/engines/shell.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/integrations.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/library/__init__.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/manifest.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/prompt_studio.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/prompt_template.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/prompt_vars.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/run_log.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/secrets.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/usage.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/agents/varstore.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/cli.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/client.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/config.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/design_verify/__init__.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/design_verify/assets.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/design_verify/bootstrap.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/design_verify/browser.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/design_verify/compare.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/design_verify/loop.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/git_ops.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/graphify.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ipc/handlers.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/local_exec.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/platform_compat.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/run_auto.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/test.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/__init__.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/dashboard.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/ip_allowlist.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/jobs.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/runner.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/security.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/server.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/service.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/setup_manager.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/static/agents.html +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/static/default-agents.html +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/static/index.html +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/static/runs.html +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/static/setup.html +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/static/styles.css +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/ui/static/tickets.html +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/sdk/updater.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/setup.cfg +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/tests/test_agent_chat_features.py +0 -0
- {devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/tests/test_agents_connectors_builder.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
|
|
2
2
|
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.125
|
|
4
4
|
|
|
5
5
|
Public surface:
|
|
6
6
|
BackendClient.from_config() — create client from ~/.agentos/config.toml
|
|
@@ -30,7 +30,7 @@ Rules:
|
|
|
30
30
|
- All data egress through submit_webhook only
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
|
-
__version__ = "1.4.
|
|
33
|
+
__version__ = "1.4.125" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
|
|
34
34
|
__author__ = "AgentOS" # sdk.client.SDK_VERSION and the UI server version all read this.
|
|
35
35
|
|
|
36
36
|
from sdk.client import BackendClient
|
|
@@ -16,22 +16,39 @@ import subprocess
|
|
|
16
16
|
from pathlib import Path
|
|
17
17
|
|
|
18
18
|
from sdk.agents import usage as usage_mod
|
|
19
|
-
from sdk.agents.manifest import
|
|
20
|
-
from sdk.agents.prompt_vars import extract_variables
|
|
19
|
+
from sdk.agents.manifest import load_skills
|
|
21
20
|
|
|
22
21
|
logger = logging.getLogger("sdk.agents.inventory")
|
|
23
22
|
|
|
24
23
|
|
|
25
|
-
def
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
def _map_backend_agent(row: dict, source: str) -> dict:
|
|
25
|
+
"""Project a backend prompt-based ``agents`` row into the inventory shape."""
|
|
26
|
+
prompt = row.get("prompt") or {}
|
|
27
|
+
sys_prompt = prompt.get("system_prompt", "") if isinstance(prompt, dict) else ""
|
|
28
|
+
pvars = prompt.get("variables", []) if isinstance(prompt, dict) else []
|
|
29
|
+
return {
|
|
30
|
+
"name": row.get("name"),
|
|
31
|
+
"description": sys_prompt[:200],
|
|
32
|
+
"variables": [v.get("name") for v in pvars if isinstance(v, dict) and v.get("name")],
|
|
33
|
+
"skills": row.get("skills", []),
|
|
34
|
+
"status": row.get("status", "active"),
|
|
35
|
+
"source": source,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
async def _custom_agents() -> list[dict]:
|
|
40
|
+
"""The caller's custom agents (``relation_type=person``) from the backend.
|
|
41
|
+
|
|
42
|
+
Backend is the source of truth — agents are authored in the web app and read
|
|
43
|
+
via GET /api/v1/agents. Best-effort: degrades to empty on any error.
|
|
44
|
+
"""
|
|
45
|
+
try:
|
|
46
|
+
from sdk.client import BackendClient
|
|
47
|
+
rows = await BackendClient.from_config().list_custom_agents()
|
|
48
|
+
return [_map_backend_agent(r, "custom") for r in rows]
|
|
49
|
+
except Exception as exc: # noqa: BLE001
|
|
50
|
+
logger.debug("custom-agent inventory failed: %s", exc)
|
|
51
|
+
return []
|
|
35
52
|
|
|
36
53
|
|
|
37
54
|
def _skills() -> list[dict]:
|
|
@@ -101,31 +118,26 @@ def _claude_subagents() -> list[dict]:
|
|
|
101
118
|
|
|
102
119
|
|
|
103
120
|
async def _default_agents() -> list[dict]:
|
|
104
|
-
"""Department default agents
|
|
121
|
+
"""Department default agents (``relation_type=department`` + org-wide common)
|
|
122
|
+
from the backend (best-effort).
|
|
105
123
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
department's templates locally — no AI-backend ``/departments/{id}/
|
|
109
|
-
default-agents`` call.
|
|
124
|
+
Reads the live rows via GET /api/v1/department-agents — the source of truth —
|
|
125
|
+
rather than the bundled SDK library. Degrades to empty on any error.
|
|
110
126
|
"""
|
|
111
127
|
try:
|
|
112
128
|
from sdk.client import BackendClient
|
|
113
|
-
from sdk.agents.library import (
|
|
114
|
-
load_common_templates, load_department, resolve_department_slug,
|
|
115
|
-
)
|
|
116
|
-
|
|
117
129
|
client = BackendClient.from_config()
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
130
|
+
try:
|
|
131
|
+
title = (await client.profile()).department_title or ""
|
|
132
|
+
except Exception: # noqa: BLE001 — department label is cosmetic
|
|
133
|
+
title = ""
|
|
134
|
+
rows = await client.list_department_agents()
|
|
135
|
+
out = []
|
|
136
|
+
for r in rows:
|
|
137
|
+
entry = _map_backend_agent(r, "default")
|
|
138
|
+
entry["department"] = title
|
|
139
|
+
out.append(entry)
|
|
140
|
+
return out
|
|
129
141
|
except Exception as exc: # noqa: BLE001
|
|
130
142
|
logger.debug("default-agent inventory failed: %s", exc)
|
|
131
143
|
return []
|
|
@@ -133,7 +145,7 @@ async def _default_agents() -> list[dict]:
|
|
|
133
145
|
|
|
134
146
|
async def build_inventory() -> dict:
|
|
135
147
|
"""The full snapshot: agents, subagents, tools, plugins + per-agent usage."""
|
|
136
|
-
customs = _custom_agents()
|
|
148
|
+
customs = await _custom_agents()
|
|
137
149
|
usage = usage_mod.summary()
|
|
138
150
|
# Attach utilisation to each custom agent.
|
|
139
151
|
for a in customs:
|
|
@@ -265,75 +265,95 @@ async def connectors() -> dict:
|
|
|
265
265
|
|
|
266
266
|
@router.get("/agents", dependencies=[_auth])
|
|
267
267
|
async def agents() -> dict:
|
|
268
|
-
"""
|
|
269
|
-
from sdk.agents.manifest import load_agents
|
|
270
|
-
from sdk.agents.prompt_vars import extract_variables
|
|
268
|
+
"""The caller's custom agents (``relation_type=person``) from the backend.
|
|
271
269
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
270
|
+
Backend is the source of truth — agents are authored in the web app and read
|
|
271
|
+
here via GET /api/v1/agents (prompt-based shape: prompt = {system_prompt,
|
|
272
|
+
variables:[…]}; skills = [{name,…}]). Best-effort: on backend error the list
|
|
273
|
+
is empty with an ``error`` string the UI can surface.
|
|
274
|
+
"""
|
|
275
|
+
from sdk.client import BackendClient
|
|
276
|
+
from sdk.exceptions import BackendFeatureMissing
|
|
277
|
+
|
|
278
|
+
try:
|
|
279
|
+
rows = await BackendClient.from_config().list_custom_agents()
|
|
280
|
+
except BackendFeatureMissing:
|
|
281
|
+
return {"agents": [], "error": ("Custom agents aren't available on this "
|
|
282
|
+
"backend — it may be running an older version.")}
|
|
283
|
+
except Exception as exc: # noqa: BLE001 — degrade to empty, surface the reason
|
|
284
|
+
return {"agents": [], "error": str(exc)}
|
|
285
|
+
return {"agents": rows, "error": ""}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _flat_agent(row: dict, source: str, *, chattable: bool, department_id: str = "") -> dict:
|
|
289
|
+
"""Flatten a backend prompt-based ``agents`` row into the picker shape the UI
|
|
290
|
+
expects (``name``/``description``/``variables``/``skills``/``source``)."""
|
|
291
|
+
prompt = row.get("prompt") or {}
|
|
292
|
+
sys_prompt = prompt.get("system_prompt", "") if isinstance(prompt, dict) else ""
|
|
293
|
+
pvars = prompt.get("variables", []) if isinstance(prompt, dict) else []
|
|
294
|
+
entry = {
|
|
295
|
+
"name": row.get("name"),
|
|
296
|
+
"description": sys_prompt[:200],
|
|
297
|
+
"variables": [v.get("name") for v in pvars if isinstance(v, dict) and v.get("name")],
|
|
298
|
+
"skills": row.get("skills", []),
|
|
299
|
+
"status": row.get("status", "active"),
|
|
300
|
+
"source": source,
|
|
301
|
+
"chattable": chattable,
|
|
279
302
|
}
|
|
303
|
+
if department_id:
|
|
304
|
+
entry["department_id"] = department_id
|
|
305
|
+
return entry
|
|
280
306
|
|
|
281
307
|
|
|
282
308
|
@router.get("/agents/all", dependencies=[_auth])
|
|
283
309
|
async def agents_all(department_id: str = Query("")) -> dict:
|
|
284
|
-
"""Every agent a person can pick to chat:
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
310
|
+
"""Every agent a person can pick to chat: their custom agents + department
|
|
311
|
+
defaults, both read from the backend (source of truth).
|
|
312
|
+
|
|
313
|
+
Custom agents (``relation_type=person``) come from GET /api/v1/agents; defaults
|
|
314
|
+
(``relation_type=department`` + org-wide common) from GET /api/v1/department-agents.
|
|
315
|
+
Custom wins on a name collision. Each entry carries its detected variables so
|
|
316
|
+
the UI can render input fields. Both are best-effort — an unreachable backend
|
|
317
|
+
yields an empty list plus an error string rather than a hard failure.
|
|
290
318
|
"""
|
|
291
|
-
from sdk.
|
|
292
|
-
from sdk.
|
|
293
|
-
|
|
294
|
-
locals_ = load_agents()
|
|
295
|
-
local_names = {m.name for m in locals_}
|
|
296
|
-
out = [
|
|
297
|
-
{"name": m.name, "engine": m.engine, "description": m.description,
|
|
298
|
-
"variables": extract_variables(m.prompt), "source": "custom",
|
|
299
|
-
"chattable": True}
|
|
300
|
-
for m in locals_
|
|
301
|
-
]
|
|
319
|
+
from sdk.client import BackendClient
|
|
320
|
+
from sdk.exceptions import BackendFeatureMissing
|
|
302
321
|
|
|
322
|
+
out: list[dict] = []
|
|
323
|
+
seen: set[str] = set()
|
|
303
324
|
dept = department_id
|
|
304
325
|
defaults_error = ""
|
|
326
|
+
|
|
305
327
|
try:
|
|
306
|
-
from sdk.client import BackendClient
|
|
307
|
-
from sdk.exceptions import BackendFeatureMissing
|
|
308
328
|
client = BackendClient.from_config()
|
|
309
329
|
if not dept:
|
|
310
330
|
profile = await client.bootstrap()
|
|
311
331
|
dept = getattr(profile, "department_id", None) or ""
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
332
|
+
|
|
333
|
+
# Custom agents first so they win any name collision with a default.
|
|
334
|
+
try:
|
|
335
|
+
for r in await client.list_custom_agents():
|
|
336
|
+
nm = r.get("name")
|
|
337
|
+
if not nm or nm in seen:
|
|
338
|
+
continue
|
|
339
|
+
seen.add(nm)
|
|
340
|
+
out.append(_flat_agent(r, "custom", chattable=True))
|
|
341
|
+
except BackendFeatureMissing:
|
|
342
|
+
defaults_error = ("Custom agents aren't available on this backend — "
|
|
343
|
+
"it may be running an older version.")
|
|
344
|
+
|
|
345
|
+
# Department defaults (a default must be activated/cloned before it runs).
|
|
346
|
+
try:
|
|
347
|
+
for r in await client.list_department_agents():
|
|
323
348
|
nm = r.get("name")
|
|
324
|
-
if not nm or nm in
|
|
349
|
+
if not nm or nm in seen:
|
|
325
350
|
continue
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
"variables": [v.get("name") for v in pvars if isinstance(v, dict) and v.get("name")],
|
|
333
|
-
"skills": r.get("skills", []),
|
|
334
|
-
"source": "default", "department_id": dept, "chattable": False,
|
|
335
|
-
})
|
|
336
|
-
except Exception: # noqa: BLE001 — defaults are best-effort
|
|
351
|
+
seen.add(nm)
|
|
352
|
+
out.append(_flat_agent(r, "default", chattable=False, department_id=dept))
|
|
353
|
+
except BackendFeatureMissing:
|
|
354
|
+
defaults_error = ("Department default agents aren't available on this "
|
|
355
|
+
"backend — it may be running an older version.")
|
|
356
|
+
except Exception: # noqa: BLE001 — best-effort; return whatever we gathered
|
|
337
357
|
pass
|
|
338
358
|
|
|
339
359
|
return {"agents": out, "department_id": dept, "defaults_error": defaults_error}
|
|
@@ -650,26 +650,40 @@
|
|
|
650
650
|
try {
|
|
651
651
|
const d = await api("/api/ui/agents");
|
|
652
652
|
const rows = d.agents || [];
|
|
653
|
+
if (!rows.length && d.error) {
|
|
654
|
+
$("local-agents").innerHTML = `<div class="empty">${esc(d.error)}</div>`;
|
|
655
|
+
const kaSel0 = $("key-agent");
|
|
656
|
+
if (kaSel0) { kaSel0.innerHTML = `<option value="">(no agents yet)</option>`; onAgentSelect(); }
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
653
659
|
caMeta = {}; rows.forEach(a => { caMeta[a.name] = a; });
|
|
654
660
|
const kaSel = $("key-agent");
|
|
655
661
|
if (kaSel) {
|
|
656
662
|
kaSel.innerHTML = rows.length
|
|
657
|
-
? rows.map(a => `<option value="${esc(a.name)}">${esc(a.name)}
|
|
663
|
+
? rows.map(a => `<option value="${esc(a.name)}">${esc(a.name)}</option>`).join("")
|
|
658
664
|
: `<option value="">(no agents yet)</option>`;
|
|
659
665
|
onAgentSelect();
|
|
660
666
|
}
|
|
661
|
-
$("local-agents").innerHTML = rows.length ? rows.map(a =>
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
667
|
+
$("local-agents").innerHTML = rows.length ? rows.map(a => {
|
|
668
|
+
const prompt = a.prompt || {};
|
|
669
|
+
const summary = (prompt.system_prompt || "").trim().slice(0, 200);
|
|
670
|
+
const nvars = (prompt.variables || []).length;
|
|
671
|
+
const nskills = (a.skills || []).length;
|
|
672
|
+
return `<div class="agent-card">
|
|
673
|
+
<div class="agent-head">
|
|
674
|
+
<span class="agent-name">${esc(a.name)}</span>
|
|
675
|
+
<span class="pill ${a.status === "disabled" ? "off" : "on"}">${esc(a.status || "active")}</span>
|
|
676
|
+
</div>
|
|
677
|
+
<div class="agent-meta">${nvars} variable(s) · ${nskills} skill(s)</div>
|
|
678
|
+
<div class="agent-desc">${esc(summary)}</div>
|
|
666
679
|
<div class="agent-actions">
|
|
667
680
|
<a class="btn primary" href="/agents.html?agent=${encodeURIComponent(a.name)}">Run</a>
|
|
668
681
|
<button class="btn" data-enable="${esc(a.name)}">Enable</button>
|
|
669
682
|
<button class="btn" data-disable="${esc(a.name)}">Disable</button>
|
|
670
683
|
<button class="btn danger" data-del="${esc(a.name)}">Delete</button>
|
|
671
684
|
</div>
|
|
672
|
-
</div
|
|
685
|
+
</div>`;
|
|
686
|
+
}).join("")
|
|
673
687
|
: "<div class='empty'>No custom agents assigned to you yet. Agents are created in the web app.</div>";
|
|
674
688
|
|
|
675
689
|
$("local-agents").querySelectorAll("[data-enable]").forEach(b => b.onclick = () => setStatus(b.dataset.enable, "active"));
|
|
@@ -734,11 +748,20 @@
|
|
|
734
748
|
return out;
|
|
735
749
|
}
|
|
736
750
|
|
|
751
|
+
function collapseKeyAdd() {
|
|
752
|
+
const box = $("key-add"); if (!box) return;
|
|
753
|
+
box.style.display = "none";
|
|
754
|
+
if ($("key-name")) $("key-name").value = "";
|
|
755
|
+
if ($("key-value")) $("key-value").value = "";
|
|
756
|
+
if ($("key-add-toggle")) $("key-add-toggle").textContent = "+ Add API key";
|
|
757
|
+
}
|
|
758
|
+
|
|
737
759
|
function onAgentSelect() {
|
|
738
760
|
const m = caMeta[$("key-agent") && $("key-agent").value];
|
|
739
761
|
if ($("ca-about")) $("ca-about").textContent = m ? (m.description || "No description provided.") : "Pick an agent.";
|
|
740
762
|
if ($("ca-output")) $("ca-output").style.display = "none";
|
|
741
763
|
if ($("ca-run-status")) $("ca-run-status").textContent = "";
|
|
764
|
+
collapseKeyAdd();
|
|
742
765
|
loadVars();
|
|
743
766
|
loadKeys();
|
|
744
767
|
}
|
|
@@ -772,6 +795,14 @@
|
|
|
772
795
|
}
|
|
773
796
|
}
|
|
774
797
|
|
|
798
|
+
if ($("key-add-toggle")) $("key-add-toggle").onclick = () => {
|
|
799
|
+
const box = $("key-add"); if (!box) return;
|
|
800
|
+
const show = box.style.display === "none";
|
|
801
|
+
box.style.display = show ? "" : "none";
|
|
802
|
+
$("key-add-toggle").textContent = show ? "Cancel" : "+ Add API key";
|
|
803
|
+
if (show && $("key-name")) $("key-name").focus();
|
|
804
|
+
};
|
|
805
|
+
|
|
775
806
|
if ($("key-agent")) $("key-agent").addEventListener("change", onAgentSelect);
|
|
776
807
|
if ($("ca-run")) $("ca-run").onclick = caRun;
|
|
777
808
|
if ($("ca-stop")) $("ca-stop").onclick = () => { if (caRunJob) { cancelJob(caRunJob); toast("Stopping…"); } };
|
|
@@ -782,7 +813,7 @@
|
|
|
782
813
|
if (!v) { toast("Enter a value", "err"); return; }
|
|
783
814
|
try {
|
|
784
815
|
await api("/api/ui/agents/keys", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name, keys: { [k]: v } }) });
|
|
785
|
-
|
|
816
|
+
collapseKeyAdd();
|
|
786
817
|
toast("Saved " + k + " for " + name, "ok"); loadKeys();
|
|
787
818
|
} catch (e) { toast("Save failed: " + (e.message || ""), "err"); }
|
|
788
819
|
};
|
|
@@ -52,9 +52,12 @@
|
|
|
52
52
|
Leave blank to keep the current one; enter a value to change it.
|
|
53
53
|
</p>
|
|
54
54
|
<div id="key-list" class="vars"><div class="muted">Pick an agent to see its stored keys.</div></div>
|
|
55
|
-
<
|
|
56
|
-
<div
|
|
57
|
-
|
|
55
|
+
<button class="btn sm" id="key-add-toggle" style="margin-top:.4em">+ Add API key</button>
|
|
56
|
+
<div id="key-add" style="display:none;margin-top:.5em">
|
|
57
|
+
<div class="field"><label>Key name (e.g. OPENAI_API_KEY)</label><input id="key-name" placeholder="ENV_VAR_NAME" autocomplete="off" /></div>
|
|
58
|
+
<div class="field"><label>Value</label><input id="key-value" type="password" placeholder="paste the secret (hidden)" autocomplete="off" /></div>
|
|
59
|
+
<button class="btn" id="key-save">Save key</button>
|
|
60
|
+
</div>
|
|
58
61
|
</div>
|
|
59
62
|
</div>
|
|
60
63
|
</div>
|
|
File without changes
|
|
File without changes
|
{devops_bot_sdk-1.4.120 → devops_bot_sdk-1.4.125}/devops_bot_sdk.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|