agent-devkit 0.1.5 → 0.1.6
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.
- package/README.md +2 -2
- package/package.json +1 -1
- package/runtime/README.md +74 -5
- package/runtime/agents/README.md +8 -0
- package/runtime/agents/execution-reviewer/AGENTS.md +8 -0
- package/runtime/agents/execution-reviewer/README.md +13 -0
- package/runtime/agents/execution-reviewer/agent.yaml +25 -0
- package/runtime/agents/execution-reviewer/capabilities/review-agent-result/capability.yaml +15 -0
- package/runtime/agents/execution-reviewer/capabilities/review-agent-result/decision-rules.md +6 -0
- package/runtime/agents/execution-reviewer/capabilities/review-agent-result/workflow.md +7 -0
- package/runtime/agents/execution-reviewer/capabilities/review-final-output/capability.yaml +15 -0
- package/runtime/agents/execution-reviewer/capabilities/review-final-output/decision-rules.md +6 -0
- package/runtime/agents/execution-reviewer/capabilities/review-final-output/workflow.md +7 -0
- package/runtime/agents/execution-reviewer/capabilities/review-plan/capability.yaml +15 -0
- package/runtime/agents/execution-reviewer/capabilities/review-plan/decision-rules.md +6 -0
- package/runtime/agents/execution-reviewer/capabilities/review-plan/workflow.md +7 -0
- package/runtime/agents/execution-reviewer/infra/README.md +4 -0
- package/runtime/agents/execution-reviewer/knowledge/context.md +6 -0
- package/runtime/agents/execution-reviewer/knowledge/system.md +18 -0
- package/runtime/agents/execution-reviewer/templates/README.md +4 -0
- package/runtime/agents/local-llm-operator/AGENTS.md +8 -0
- package/runtime/agents/local-llm-operator/README.md +12 -0
- package/runtime/agents/local-llm-operator/agent.yaml +26 -0
- package/runtime/agents/local-llm-operator/capabilities/delegate-operational-task/capability.yaml +15 -0
- package/runtime/agents/local-llm-operator/capabilities/delegate-operational-task/decision-rules.md +6 -0
- package/runtime/agents/local-llm-operator/capabilities/delegate-operational-task/workflow.md +7 -0
- package/runtime/agents/local-llm-operator/capabilities/inspect-local-models/capability.yaml +15 -0
- package/runtime/agents/local-llm-operator/capabilities/inspect-local-models/decision-rules.md +5 -0
- package/runtime/agents/local-llm-operator/capabilities/inspect-local-models/workflow.md +6 -0
- package/runtime/agents/local-llm-operator/capabilities/select-local-worker/capability.yaml +15 -0
- package/runtime/agents/local-llm-operator/capabilities/select-local-worker/decision-rules.md +6 -0
- package/runtime/agents/local-llm-operator/capabilities/select-local-worker/workflow.md +7 -0
- package/runtime/agents/local-llm-operator/infra/README.md +4 -0
- package/runtime/agents/local-llm-operator/knowledge/context.md +6 -0
- package/runtime/agents/local-llm-operator/knowledge/system.md +18 -0
- package/runtime/agents/local-llm-operator/templates/README.md +4 -0
- package/runtime/agents/provider-configurator/AGENTS.md +8 -0
- package/runtime/agents/provider-configurator/README.md +5 -0
- package/runtime/agents/provider-configurator/agent.yaml +25 -0
- package/runtime/agents/provider-configurator/capabilities/collect-provider-credentials/capability.yaml +15 -0
- package/runtime/agents/provider-configurator/capabilities/collect-provider-credentials/decision-rules.md +6 -0
- package/runtime/agents/provider-configurator/capabilities/collect-provider-credentials/workflow.md +7 -0
- package/runtime/agents/provider-configurator/capabilities/configure-provider-source/capability.yaml +15 -0
- package/runtime/agents/provider-configurator/capabilities/configure-provider-source/decision-rules.md +6 -0
- package/runtime/agents/provider-configurator/capabilities/configure-provider-source/workflow.md +8 -0
- package/runtime/agents/provider-configurator/capabilities/validate-provider-readiness/capability.yaml +15 -0
- package/runtime/agents/provider-configurator/capabilities/validate-provider-readiness/decision-rules.md +6 -0
- package/runtime/agents/provider-configurator/capabilities/validate-provider-readiness/workflow.md +7 -0
- package/runtime/agents/provider-configurator/infra/README.md +5 -0
- package/runtime/agents/provider-configurator/knowledge/context.md +8 -0
- package/runtime/agents/provider-configurator/knowledge/system.md +19 -0
- package/runtime/agents/provider-configurator/templates/README.md +4 -0
- package/runtime/agents/task-orchestrator/AGENTS.md +8 -0
- package/runtime/agents/task-orchestrator/README.md +7 -0
- package/runtime/agents/task-orchestrator/agent.yaml +31 -0
- package/runtime/agents/task-orchestrator/capabilities/coordinate-execution/capability.yaml +15 -0
- package/runtime/agents/task-orchestrator/capabilities/coordinate-execution/decision-rules.md +6 -0
- package/runtime/agents/task-orchestrator/capabilities/coordinate-execution/workflow.md +7 -0
- package/runtime/agents/task-orchestrator/capabilities/plan-task/capability.yaml +15 -0
- package/runtime/agents/task-orchestrator/capabilities/plan-task/decision-rules.md +6 -0
- package/runtime/agents/task-orchestrator/capabilities/plan-task/workflow.md +8 -0
- package/runtime/agents/task-orchestrator/capabilities/select-specialists/capability.yaml +15 -0
- package/runtime/agents/task-orchestrator/capabilities/select-specialists/decision-rules.md +6 -0
- package/runtime/agents/task-orchestrator/capabilities/select-specialists/workflow.md +7 -0
- package/runtime/agents/task-orchestrator/infra/README.md +5 -0
- package/runtime/agents/task-orchestrator/knowledge/context.md +9 -0
- package/runtime/agents/task-orchestrator/knowledge/system.md +20 -0
- package/runtime/agents/task-orchestrator/templates/README.md +4 -0
- package/runtime/cli/README.md +76 -11
- package/runtime/cli/aikit/__init__.py +1 -1
- package/runtime/cli/aikit/agent_executor.py +66 -0
- package/runtime/cli/aikit/agent_registry.py +80 -0
- package/runtime/cli/aikit/app_home.py +87 -2
- package/runtime/cli/aikit/audit.py +44 -0
- package/runtime/cli/aikit/control_router.py +298 -0
- package/runtime/cli/aikit/decision_store.py +17 -0
- package/runtime/cli/aikit/diagnostics.py +2 -1
- package/runtime/cli/aikit/execution_reviewer.py +174 -0
- package/runtime/cli/aikit/install.py +4 -3
- package/runtime/cli/aikit/local_llm_operator.py +112 -0
- package/runtime/cli/aikit/lock.py +4 -1
- package/runtime/cli/aikit/main.py +355 -80
- package/runtime/cli/aikit/model_router.py +13 -4
- package/runtime/cli/aikit/orchestrator.py +535 -0
- package/runtime/cli/aikit/sessions.py +37 -0
- package/runtime/cli/aikit/sources.py +6 -2
- package/runtime/cli/aikit/wizard_state.py +503 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""Runtime execution for the execution-reviewer agent."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from cli.aikit.llm import BACKENDS, candidate_backend_ids, doctor_backend, invoke_agent_prompt, load_config
|
|
8
|
+
from cli.aikit.review_gate import mark_reviewed
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
PREFERRED_REVIEW_BACKENDS = ("claude-code", "codex-cli")
|
|
12
|
+
REVIEW_OK_MARKER = "REVIEW OK"
|
|
13
|
+
REVIEW_BLOCKED_MARKER = "REVIEW BLOCKED"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def enforce_execution_review(
|
|
17
|
+
*,
|
|
18
|
+
prompt: str,
|
|
19
|
+
result: dict[str, Any],
|
|
20
|
+
review_gate: dict[str, Any],
|
|
21
|
+
execution_plan: dict[str, Any] | None = None,
|
|
22
|
+
producer_backend: str | None = None,
|
|
23
|
+
) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any]]:
|
|
24
|
+
"""Run a second concrete review when required and apply the gate outcome."""
|
|
25
|
+
if not review_gate.get("required"):
|
|
26
|
+
review_result = {
|
|
27
|
+
"kind": "execution-review",
|
|
28
|
+
"agent_id": "execution-reviewer",
|
|
29
|
+
"capability_id": "review-final-output",
|
|
30
|
+
"status": "not-required",
|
|
31
|
+
"ok": True,
|
|
32
|
+
}
|
|
33
|
+
return result, review_gate, review_result
|
|
34
|
+
|
|
35
|
+
response = str(result.get("response") or result.get("message") or "")
|
|
36
|
+
review_backend = select_review_backend(producer_backend=producer_backend, preferred=review_gate.get("preferred_reviewers") or [])
|
|
37
|
+
if not review_backend:
|
|
38
|
+
review_result = needs_review("No configured independent reviewer backend is available.", producer_backend=producer_backend)
|
|
39
|
+
return block_for_review(result, review_gate, review_result)
|
|
40
|
+
|
|
41
|
+
review_prompt = build_review_prompt(prompt=prompt, response=response, review_gate=review_gate, execution_plan=execution_plan)
|
|
42
|
+
invoked = invoke_agent_prompt(
|
|
43
|
+
review_prompt,
|
|
44
|
+
review_backend,
|
|
45
|
+
public_name="Execution Reviewer",
|
|
46
|
+
allow_fallback=False,
|
|
47
|
+
)
|
|
48
|
+
decision = parse_review_decision(str(invoked.get("response") or ""))
|
|
49
|
+
review_result = {
|
|
50
|
+
"kind": "execution-review",
|
|
51
|
+
"agent_id": "execution-reviewer",
|
|
52
|
+
"capability_id": "review-final-output",
|
|
53
|
+
"capability": "execution-reviewer.review-final-output",
|
|
54
|
+
"status": review_status(invoked=invoked, decision=decision),
|
|
55
|
+
"ok": bool(invoked.get("ok")) and decision == "approved",
|
|
56
|
+
"llm_backend": invoked.get("llm_backend"),
|
|
57
|
+
"producer_backend": producer_backend,
|
|
58
|
+
"decision": decision,
|
|
59
|
+
"response": invoked.get("response"),
|
|
60
|
+
"message": invoked.get("message"),
|
|
61
|
+
"attempts": invoked.get("llm_backend_attempts"),
|
|
62
|
+
}
|
|
63
|
+
if not invoked.get("ok"):
|
|
64
|
+
return block_for_review(result, review_gate, review_result)
|
|
65
|
+
if decision == "blocked":
|
|
66
|
+
review_result["message"] = "Execution reviewer blocked the proposed final output."
|
|
67
|
+
return block_for_review(result, review_gate, review_result)
|
|
68
|
+
if decision != "approved":
|
|
69
|
+
review_result["message"] = "Execution reviewer did not return REVIEW OK."
|
|
70
|
+
return block_for_review(result, review_gate, review_result)
|
|
71
|
+
reviewed_gate = mark_reviewed(review_gate, reviewer=str(invoked.get("llm_backend") or review_backend), notes=str(invoked.get("response") or "Reviewed."))
|
|
72
|
+
return result, reviewed_gate, review_result
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def select_review_backend(*, producer_backend: str | None, preferred: list[str]) -> str | None:
|
|
76
|
+
config = load_config()
|
|
77
|
+
candidates = candidate_backend_ids(config=config, allow_fallback=True)
|
|
78
|
+
preferred_order = [item for item in list(preferred or []) + list(PREFERRED_REVIEW_BACKENDS) if item in BACKENDS]
|
|
79
|
+
ordered = [item for item in preferred_order if item in candidates]
|
|
80
|
+
ordered.extend(item for item in candidates if item not in ordered and item != "ollama")
|
|
81
|
+
for backend_id in ordered:
|
|
82
|
+
if backend_id == producer_backend:
|
|
83
|
+
continue
|
|
84
|
+
backend = doctor_backend(BACKENDS[backend_id], config)
|
|
85
|
+
if backend.get("status") == "ok":
|
|
86
|
+
return backend_id
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def build_review_prompt(
|
|
91
|
+
*,
|
|
92
|
+
prompt: str,
|
|
93
|
+
response: str,
|
|
94
|
+
review_gate: dict[str, Any],
|
|
95
|
+
execution_plan: dict[str, Any] | None,
|
|
96
|
+
) -> str:
|
|
97
|
+
plan_summary = {}
|
|
98
|
+
if isinstance(execution_plan, dict):
|
|
99
|
+
plan_summary = {
|
|
100
|
+
"status": execution_plan.get("status"),
|
|
101
|
+
"coordinator": (execution_plan.get("coordinator_agent") or {}).get("id") if isinstance(execution_plan.get("coordinator_agent"), dict) else None,
|
|
102
|
+
"specialist_tasks": [
|
|
103
|
+
{
|
|
104
|
+
"agent_id": task.get("agent_id"),
|
|
105
|
+
"capability_id": task.get("capability_id"),
|
|
106
|
+
"status": task.get("status"),
|
|
107
|
+
}
|
|
108
|
+
for task in execution_plan.get("specialist_tasks") or []
|
|
109
|
+
if isinstance(task, dict)
|
|
110
|
+
],
|
|
111
|
+
}
|
|
112
|
+
return "\n".join(
|
|
113
|
+
[
|
|
114
|
+
"Revise a entrega final do Agent DevKit antes da conclusao.",
|
|
115
|
+
"Verifique aderencia ao pedido, riscos, lacunas, evidencias, uso indevido de credenciais e necessidade de bloquear.",
|
|
116
|
+
"Responda com uma decisao objetiva: REVIEW OK ou REVIEW BLOCKED, seguida de justificativa curta.",
|
|
117
|
+
"",
|
|
118
|
+
f"Motivo do review gate: {review_gate.get('reason')}",
|
|
119
|
+
f"Prompt original: {prompt}",
|
|
120
|
+
f"Resumo do plano: {plan_summary}",
|
|
121
|
+
"",
|
|
122
|
+
"Resposta final proposta:",
|
|
123
|
+
response,
|
|
124
|
+
]
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def parse_review_decision(response: str) -> str:
|
|
129
|
+
upper = response.upper()
|
|
130
|
+
if REVIEW_BLOCKED_MARKER in upper:
|
|
131
|
+
return "blocked"
|
|
132
|
+
if REVIEW_OK_MARKER in upper:
|
|
133
|
+
return "approved"
|
|
134
|
+
return "unstructured"
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def review_status(*, invoked: dict[str, Any], decision: str) -> str:
|
|
138
|
+
if not invoked.get("ok"):
|
|
139
|
+
return str(invoked.get("status", "failed"))
|
|
140
|
+
if decision == "blocked":
|
|
141
|
+
return "blocked"
|
|
142
|
+
if decision != "approved":
|
|
143
|
+
return "needs-review"
|
|
144
|
+
return "ok"
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def needs_review(message: str, *, producer_backend: str | None) -> dict[str, Any]:
|
|
148
|
+
return {
|
|
149
|
+
"kind": "execution-review",
|
|
150
|
+
"agent_id": "execution-reviewer",
|
|
151
|
+
"capability_id": "review-final-output",
|
|
152
|
+
"capability": "execution-reviewer.review-final-output",
|
|
153
|
+
"status": "needs-review",
|
|
154
|
+
"ok": False,
|
|
155
|
+
"producer_backend": producer_backend,
|
|
156
|
+
"message": message,
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def block_for_review(
|
|
161
|
+
result: dict[str, Any],
|
|
162
|
+
review_gate: dict[str, Any],
|
|
163
|
+
review_result: dict[str, Any],
|
|
164
|
+
) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any]]:
|
|
165
|
+
blocked = dict(result)
|
|
166
|
+
blocked["status"] = "needs-review"
|
|
167
|
+
blocked["ok"] = False
|
|
168
|
+
blocked["exit_code"] = 2
|
|
169
|
+
blocked["message"] = review_result.get("message") or "Execution requires review before completion."
|
|
170
|
+
gate = dict(review_gate)
|
|
171
|
+
gate["status"] = "needs-review"
|
|
172
|
+
gate["reviewer"] = None
|
|
173
|
+
gate["notes"] = review_result.get("message")
|
|
174
|
+
return blocked, gate, review_result
|
|
@@ -9,7 +9,7 @@ from pathlib import Path
|
|
|
9
9
|
from typing import Any
|
|
10
10
|
|
|
11
11
|
from cli.aikit import __version__
|
|
12
|
-
from cli.aikit.lock import lock_path, write_lock
|
|
12
|
+
from cli.aikit.lock import GLOBAL_RUNTIME_DIR, PROJECT_RUNTIME_DIR, lock_path, write_lock
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
HOST_ALIASES = {
|
|
@@ -46,7 +46,7 @@ def install_runtime(
|
|
|
46
46
|
hosts = resolve_hosts(host)
|
|
47
47
|
root = root.resolve()
|
|
48
48
|
base = resolve_base(scope, target=target, home=home)
|
|
49
|
-
runtime_dir = base / "
|
|
49
|
+
runtime_dir = base / (GLOBAL_RUNTIME_DIR if scope == "global" else PROJECT_RUNTIME_DIR)
|
|
50
50
|
bin_dir = runtime_dir / "bin"
|
|
51
51
|
config_path = runtime_dir / "config.yaml"
|
|
52
52
|
runtime_lock_path = lock_path(base, scope)
|
|
@@ -256,7 +256,8 @@ def write_runtime_config(path: Path, root: Path, scope: str, hosts: tuple[str, .
|
|
|
256
256
|
|
|
257
257
|
|
|
258
258
|
def next_steps(scope: str, hosts: tuple[str, ...]) -> list[str]:
|
|
259
|
-
|
|
259
|
+
runtime_dir_name = GLOBAL_RUNTIME_DIR if scope == "global" else PROJECT_RUNTIME_DIR
|
|
260
|
+
steps = [f"Add `{runtime_dir_name}/bin` to PATH when you want to call the installed `agent` directly."]
|
|
260
261
|
steps.append("Run `agent doctor --json` to validate the local runtime.")
|
|
261
262
|
if "codex" in hosts:
|
|
262
263
|
steps.append("Restart or reload Codex so it can discover the AI DevKit plugin/skill.")
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Runtime execution for the local-llm-operator agent."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from cli.aikit.llm import invoke_agent_prompt
|
|
8
|
+
from cli.aikit.memory import redact_secrets
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
FORBIDDEN_DELEGATION_MARKERS = (
|
|
12
|
+
"aprove",
|
|
13
|
+
"aprovar",
|
|
14
|
+
"reprove",
|
|
15
|
+
"reprovar",
|
|
16
|
+
"deploy",
|
|
17
|
+
"delete",
|
|
18
|
+
"excluir",
|
|
19
|
+
"execute escrita",
|
|
20
|
+
"permissao",
|
|
21
|
+
"permissão",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def maybe_delegate_local_llm(prompt: str, model_plan: dict[str, Any]) -> dict[str, Any]:
|
|
26
|
+
"""Execute a bounded operational task with Ollama when the model plan selected it."""
|
|
27
|
+
delegation = model_plan.get("delegation") if isinstance(model_plan.get("delegation"), dict) else {}
|
|
28
|
+
if not model_plan.get("local_llm_selected") or not delegation.get("selected"):
|
|
29
|
+
return skipped("not-selected", "Local LLM delegation was not selected for this prompt.", model_plan=model_plan)
|
|
30
|
+
lowered = prompt.lower()
|
|
31
|
+
if any(marker in lowered for marker in FORBIDDEN_DELEGATION_MARKERS):
|
|
32
|
+
return skipped("forbidden", "Prompt contains an action that local LLM workers cannot execute.", model_plan=model_plan)
|
|
33
|
+
delegated_prompt = build_delegated_prompt(prompt, model_plan)
|
|
34
|
+
result = invoke_agent_prompt(
|
|
35
|
+
delegated_prompt,
|
|
36
|
+
"ollama",
|
|
37
|
+
public_name="Local LLM Operator",
|
|
38
|
+
allow_fallback=False,
|
|
39
|
+
)
|
|
40
|
+
payload = {
|
|
41
|
+
"kind": "local-llm-execution",
|
|
42
|
+
"agent_id": "local-llm-operator",
|
|
43
|
+
"capability_id": "delegate-operational-task",
|
|
44
|
+
"capability": "local-llm-operator.delegate-operational-task",
|
|
45
|
+
"status": "ok" if result.get("ok") else result.get("status", "failed"),
|
|
46
|
+
"ok": bool(result.get("ok")),
|
|
47
|
+
"llm_backend": result.get("llm_backend"),
|
|
48
|
+
"model_provider": "ollama",
|
|
49
|
+
"delegated_prompt": redact_secrets(delegated_prompt),
|
|
50
|
+
"response": result.get("response"),
|
|
51
|
+
"result": sanitize_llm_result(result),
|
|
52
|
+
"requires_review": True,
|
|
53
|
+
}
|
|
54
|
+
if not result.get("ok"):
|
|
55
|
+
payload["message"] = result.get("message") or "Local LLM delegation failed."
|
|
56
|
+
return payload
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def build_delegated_prompt(prompt: str, model_plan: dict[str, Any]) -> str:
|
|
60
|
+
forbidden = ", ".join((model_plan.get("delegation") or {}).get("forbidden_actions") or [])
|
|
61
|
+
return "\n".join(
|
|
62
|
+
[
|
|
63
|
+
"Execute apenas a parte operacional da tarefa abaixo.",
|
|
64
|
+
"Nao tome decisao final, nao aprove, nao escreva externamente e nao revise a entrega final.",
|
|
65
|
+
f"Acoes proibidas: {forbidden}.",
|
|
66
|
+
"Retorne um resumo estruturado, evidencias extraidas, lacunas e confianca.",
|
|
67
|
+
"",
|
|
68
|
+
"Tarefa original:",
|
|
69
|
+
redact_secrets(prompt),
|
|
70
|
+
]
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def enrich_prompt_with_local_result(prompt: str, local_execution: dict[str, Any]) -> str:
|
|
75
|
+
if not local_execution.get("ok") or not local_execution.get("response"):
|
|
76
|
+
return prompt
|
|
77
|
+
return "\n".join(
|
|
78
|
+
[
|
|
79
|
+
prompt,
|
|
80
|
+
"",
|
|
81
|
+
"Contexto operacional produzido pelo local-llm-operator/Ollama:",
|
|
82
|
+
str(local_execution["response"]),
|
|
83
|
+
"",
|
|
84
|
+
"Use esse contexto apenas como apoio. A decisao, resposta final e revisao continuam sob responsabilidade do coordenador.",
|
|
85
|
+
]
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def skipped(reason: str, message: str, *, model_plan: dict[str, Any]) -> dict[str, Any]:
|
|
90
|
+
return {
|
|
91
|
+
"kind": "local-llm-execution",
|
|
92
|
+
"agent_id": "local-llm-operator",
|
|
93
|
+
"capability_id": "delegate-operational-task",
|
|
94
|
+
"capability": "local-llm-operator.delegate-operational-task",
|
|
95
|
+
"status": "skipped",
|
|
96
|
+
"ok": False,
|
|
97
|
+
"reason": reason,
|
|
98
|
+
"message": message,
|
|
99
|
+
"model_provider": model_plan.get("local_llm_provider") or "ollama",
|
|
100
|
+
"requires_review": bool(model_plan.get("local_llm_recommended") or model_plan.get("local_llm_selected")),
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def sanitize_llm_result(result: dict[str, Any]) -> dict[str, Any]:
|
|
105
|
+
return {
|
|
106
|
+
"status": result.get("status"),
|
|
107
|
+
"ok": result.get("ok"),
|
|
108
|
+
"llm_backend": result.get("llm_backend"),
|
|
109
|
+
"llm_backend_attempts": result.get("llm_backend_attempts"),
|
|
110
|
+
"message": result.get("message"),
|
|
111
|
+
"exit_code": result.get("exit_code"),
|
|
112
|
+
}
|
|
@@ -14,11 +14,14 @@ from cli.aikit import __version__
|
|
|
14
14
|
|
|
15
15
|
PROJECT_LOCK_NAME = "ai-devkit.lock"
|
|
16
16
|
GLOBAL_LOCK_NAME = "runtime.lock"
|
|
17
|
+
PROJECT_RUNTIME_DIR = ".ai-devkit"
|
|
18
|
+
GLOBAL_RUNTIME_DIR = ".agent-devkit"
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
def lock_path(base: Path, scope: str) -> Path:
|
|
20
22
|
name = GLOBAL_LOCK_NAME if scope == "global" else PROJECT_LOCK_NAME
|
|
21
|
-
|
|
23
|
+
runtime_dir = GLOBAL_RUNTIME_DIR if scope == "global" else PROJECT_RUNTIME_DIR
|
|
24
|
+
return base / runtime_dir / name
|
|
22
25
|
|
|
23
26
|
|
|
24
27
|
def write_lock(
|