agent-devkit 0.2.0 → 0.3.0
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 +48 -6
- package/bin/agent.mjs +133 -7
- package/package.json +1 -1
- package/runtime/README.md +187 -5
- package/runtime/agent +31 -5
- package/runtime/agents/README.md +18 -0
- package/runtime/agents/contribution-reviewer/AGENTS.md +8 -0
- package/runtime/agents/contribution-reviewer/README.md +8 -0
- package/runtime/agents/contribution-reviewer/agent.yaml +40 -0
- package/runtime/agents/contribution-reviewer/capabilities/plan-contribution-pr/capability.yaml +27 -0
- package/runtime/agents/contribution-reviewer/capabilities/plan-contribution-pr/decision-rules.md +5 -0
- package/runtime/agents/contribution-reviewer/capabilities/plan-contribution-pr/workflow.md +6 -0
- package/runtime/agents/contribution-reviewer/capabilities/review-contribution/capability.yaml +25 -0
- package/runtime/agents/contribution-reviewer/capabilities/review-contribution/decision-rules.md +5 -0
- package/runtime/agents/contribution-reviewer/capabilities/review-contribution/workflow.md +5 -0
- package/runtime/agents/contribution-reviewer/capabilities/validate-local-contribution/capability.yaml +26 -0
- package/runtime/agents/contribution-reviewer/capabilities/validate-local-contribution/decision-rules.md +5 -0
- package/runtime/agents/contribution-reviewer/capabilities/validate-local-contribution/workflow.md +6 -0
- package/runtime/agents/contribution-reviewer/infra/README.md +6 -0
- package/runtime/agents/contribution-reviewer/knowledge/context.md +8 -0
- package/runtime/agents/contribution-reviewer/knowledge/system.md +8 -0
- package/runtime/agents/contribution-reviewer/templates/README.md +3 -0
- package/runtime/agents/knowledge-author/AGENTS.md +7 -0
- package/runtime/agents/knowledge-author/README.md +7 -0
- package/runtime/agents/knowledge-author/agent.yaml +37 -0
- package/runtime/agents/knowledge-author/capabilities/create-knowledge-snapshot/capability.yaml +30 -0
- package/runtime/agents/knowledge-author/capabilities/create-knowledge-snapshot/decision-rules.md +6 -0
- package/runtime/agents/knowledge-author/capabilities/create-knowledge-snapshot/workflow.md +7 -0
- package/runtime/agents/knowledge-author/infra/.gitkeep +1 -0
- package/runtime/agents/knowledge-author/knowledge/context.md +4 -0
- package/runtime/agents/knowledge-author/knowledge/system.md +4 -0
- package/runtime/agents/knowledge-author/templates/.gitkeep +1 -0
- package/runtime/agents/knowledge-curator/AGENTS.md +7 -0
- package/runtime/agents/knowledge-curator/README.md +6 -0
- package/runtime/agents/knowledge-curator/agent.yaml +37 -0
- package/runtime/agents/knowledge-curator/capabilities/curate-knowledge-base/capability.yaml +29 -0
- package/runtime/agents/knowledge-curator/capabilities/curate-knowledge-base/decision-rules.md +6 -0
- package/runtime/agents/knowledge-curator/capabilities/curate-knowledge-base/workflow.md +7 -0
- package/runtime/agents/knowledge-curator/infra/.gitkeep +1 -0
- package/runtime/agents/knowledge-curator/knowledge/context.md +4 -0
- package/runtime/agents/knowledge-curator/knowledge/system.md +4 -0
- package/runtime/agents/knowledge-curator/templates/.gitkeep +1 -0
- package/runtime/agents/knowledge-infra-builder/AGENTS.md +8 -0
- package/runtime/agents/knowledge-infra-builder/README.md +8 -0
- package/runtime/agents/knowledge-infra-builder/agent.yaml +38 -0
- package/runtime/agents/knowledge-infra-builder/capabilities/create-knowledge-base/capability.yaml +30 -0
- package/runtime/agents/knowledge-infra-builder/capabilities/create-knowledge-base/decision-rules.md +6 -0
- package/runtime/agents/knowledge-infra-builder/capabilities/create-knowledge-base/workflow.md +7 -0
- package/runtime/agents/knowledge-infra-builder/infra/.gitkeep +1 -0
- package/runtime/agents/knowledge-infra-builder/knowledge/context.md +4 -0
- package/runtime/agents/knowledge-infra-builder/knowledge/system.md +4 -0
- package/runtime/agents/knowledge-infra-builder/templates/.gitkeep +1 -0
- package/runtime/agents/knowledge-owner/AGENTS.md +7 -0
- package/runtime/agents/knowledge-owner/README.md +6 -0
- package/runtime/agents/knowledge-owner/agent.yaml +37 -0
- package/runtime/agents/knowledge-owner/capabilities/publish-knowledge-snapshot/capability.yaml +28 -0
- package/runtime/agents/knowledge-owner/capabilities/publish-knowledge-snapshot/decision-rules.md +6 -0
- package/runtime/agents/knowledge-owner/capabilities/publish-knowledge-snapshot/workflow.md +7 -0
- package/runtime/agents/knowledge-owner/infra/.gitkeep +1 -0
- package/runtime/agents/knowledge-owner/knowledge/context.md +4 -0
- package/runtime/agents/knowledge-owner/knowledge/system.md +4 -0
- package/runtime/agents/knowledge-owner/templates/.gitkeep +1 -0
- package/runtime/agents/knowledge-reviewer/AGENTS.md +7 -0
- package/runtime/agents/knowledge-reviewer/README.md +7 -0
- package/runtime/agents/knowledge-reviewer/agent.yaml +36 -0
- package/runtime/agents/knowledge-reviewer/capabilities/review-knowledge-snapshot/capability.yaml +26 -0
- package/runtime/agents/knowledge-reviewer/capabilities/review-knowledge-snapshot/decision-rules.md +6 -0
- package/runtime/agents/knowledge-reviewer/capabilities/review-knowledge-snapshot/workflow.md +7 -0
- package/runtime/agents/knowledge-reviewer/infra/.gitkeep +1 -0
- package/runtime/agents/knowledge-reviewer/knowledge/context.md +4 -0
- package/runtime/agents/knowledge-reviewer/knowledge/system.md +4 -0
- package/runtime/agents/knowledge-reviewer/templates/.gitkeep +1 -0
- package/runtime/agents/local-memory-manager/AGENTS.md +5 -0
- package/runtime/agents/local-memory-manager/README.md +7 -0
- package/runtime/agents/local-memory-manager/agent.yaml +38 -0
- package/runtime/agents/local-memory-manager/capabilities/curate-local-memory/capability.yaml +19 -0
- package/runtime/agents/local-memory-manager/capabilities/curate-local-memory/decision-rules.md +5 -0
- package/runtime/agents/local-memory-manager/capabilities/curate-local-memory/workflow.md +6 -0
- package/runtime/agents/local-memory-manager/capabilities/inspect-local-memory/capability.yaml +19 -0
- package/runtime/agents/local-memory-manager/capabilities/inspect-local-memory/decision-rules.md +5 -0
- package/runtime/agents/local-memory-manager/capabilities/inspect-local-memory/workflow.md +5 -0
- package/runtime/agents/local-memory-manager/infra/.gitkeep +1 -0
- package/runtime/agents/local-memory-manager/knowledge/context.md +4 -0
- package/runtime/agents/local-memory-manager/knowledge/system.md +4 -0
- package/runtime/agents/local-memory-manager/templates/.gitkeep +1 -0
- package/runtime/agents/memory-sync-manager/AGENTS.md +7 -0
- package/runtime/agents/memory-sync-manager/README.md +7 -0
- package/runtime/agents/memory-sync-manager/agent.yaml +37 -0
- package/runtime/agents/memory-sync-manager/capabilities/plan-memory-backup/capability.yaml +29 -0
- package/runtime/agents/memory-sync-manager/capabilities/plan-memory-backup/decision-rules.md +6 -0
- package/runtime/agents/memory-sync-manager/capabilities/plan-memory-backup/workflow.md +7 -0
- package/runtime/agents/memory-sync-manager/infra/.gitkeep +1 -0
- package/runtime/agents/memory-sync-manager/knowledge/context.md +4 -0
- package/runtime/agents/memory-sync-manager/knowledge/system.md +4 -0
- package/runtime/agents/memory-sync-manager/templates/.gitkeep +1 -0
- package/runtime/agents/shared-memory-curator/AGENTS.md +5 -0
- package/runtime/agents/shared-memory-curator/README.md +6 -0
- package/runtime/agents/shared-memory-curator/agent.yaml +38 -0
- package/runtime/agents/shared-memory-curator/capabilities/create-shared-memory/capability.yaml +19 -0
- package/runtime/agents/shared-memory-curator/capabilities/create-shared-memory/decision-rules.md +5 -0
- package/runtime/agents/shared-memory-curator/capabilities/create-shared-memory/workflow.md +5 -0
- package/runtime/agents/shared-memory-curator/capabilities/publish-shared-submission/capability.yaml +19 -0
- package/runtime/agents/shared-memory-curator/capabilities/publish-shared-submission/decision-rules.md +5 -0
- package/runtime/agents/shared-memory-curator/capabilities/publish-shared-submission/workflow.md +5 -0
- package/runtime/agents/shared-memory-curator/capabilities/review-shared-submission/capability.yaml +19 -0
- package/runtime/agents/shared-memory-curator/capabilities/review-shared-submission/decision-rules.md +5 -0
- package/runtime/agents/shared-memory-curator/capabilities/review-shared-submission/workflow.md +5 -0
- package/runtime/agents/shared-memory-curator/infra/.gitkeep +1 -0
- package/runtime/agents/shared-memory-curator/knowledge/context.md +5 -0
- package/runtime/agents/shared-memory-curator/knowledge/system.md +4 -0
- package/runtime/agents/shared-memory-curator/templates/.gitkeep +1 -0
- package/runtime/cli/README.md +35 -4
- package/runtime/cli/aikit/__init__.py +1 -1
- package/runtime/cli/aikit/agent_registry.py +4 -2
- package/runtime/cli/aikit/agentic_commands.py +158 -0
- package/runtime/cli/aikit/app_home.py +1 -0
- package/runtime/cli/aikit/audit.py +16 -6
- package/runtime/cli/aikit/catalog.py +278 -8
- package/runtime/cli/aikit/cli_dispatch.py +489 -13
- package/runtime/cli/aikit/cli_parser.py +145 -7
- package/runtime/cli/aikit/contribution.py +132 -2
- package/runtime/cli/aikit/doctor_runtime.py +85 -0
- package/runtime/cli/aikit/eval.py +356 -10
- package/runtime/cli/aikit/human_output.py +310 -4
- package/runtime/cli/aikit/interactive_wizard.py +148 -0
- package/runtime/cli/aikit/knowledge_base.py +1067 -0
- package/runtime/cli/aikit/llm.py +12 -4
- package/runtime/cli/aikit/local_artifacts.py +444 -0
- package/runtime/cli/aikit/local_llm.py +161 -0
- package/runtime/cli/aikit/main.py +15 -0
- package/runtime/cli/aikit/mcp_manifest.py +798 -0
- package/runtime/cli/aikit/mcp_tools.py +643 -5
- package/runtime/cli/aikit/memory.py +405 -0
- package/runtime/cli/aikit/mini_brain.py +20 -1
- package/runtime/cli/aikit/natural_prompt_runtime.py +125 -1
- package/runtime/cli/aikit/ollama.py +64 -15
- package/runtime/cli/aikit/onboarding.py +551 -0
- package/runtime/cli/aikit/output.py +67 -0
- package/runtime/cli/aikit/prompt_injection.py +12 -1
- package/runtime/cli/aikit/roadmap_cli.py +1 -1
- package/runtime/cli/aikit/secrets.py +3 -2
- package/runtime/cli/aikit/setup_wizard_payload.py +3 -0
- package/runtime/cli/aikit/shared_memory.py +415 -0
- package/runtime/cli/aikit/specialist_readiness.py +152 -0
- package/runtime/cli/aikit/tasks.py +104 -1
- package/runtime/cli/aikit/team.py +380 -0
- package/runtime/cli/aikit/toolchain.py +7 -2
- package/runtime/cli/aikit/workflows.py +115 -14
- package/runtime/providers/knowledge-github.yaml +40 -0
- package/runtime/providers/knowledge-google-drive.yaml +32 -0
- package/runtime/providers/knowledge-local.yaml +26 -0
- package/runtime/providers/knowledge-notion.yaml +32 -0
- package/runtime/providers/knowledge-obsidian.yaml +24 -0
- package/runtime/providers/knowledge-onedrive.yaml +36 -0
- package/runtime/providers/knowledge-s3.yaml +45 -0
- package/runtime/providers/knowledge-sharepoint.yaml +39 -0
- package/runtime/providers/knowledge-supabase.yaml +43 -0
- package/runtime/providers/knowledge-vector.yaml +39 -0
- package/runtime/requirements.txt +6 -0
- package/runtime/scripts/docker-cli-qa.sh +453 -0
- package/runtime/scripts/release-catalog-snapshot.json +55 -4
- package/runtime/scripts/release-gate.py +54 -13
- package/runtime/tooling/toolchain.yaml +92 -0
- package/runtime/vendor/skills/napkin/napkin.md +21 -7
- package/runtime/workflows/azure-card-analysis/README.md +3 -0
- package/runtime/workflows/azure-card-analysis/workflow.yaml +30 -0
- package/runtime/workflows/daily-pr-review/README.md +3 -0
- package/runtime/workflows/daily-pr-review/workflow.yaml +31 -0
- package/runtime/workflows/incident-analysis/README.md +3 -0
- package/runtime/workflows/incident-analysis/workflow.yaml +33 -0
- package/runtime/workflows/release-prep/README.md +3 -0
- package/runtime/workflows/release-prep/workflow.yaml +30 -0
package/runtime/cli/README.md
CHANGED
|
@@ -199,6 +199,37 @@ O comando retorna erro apenas para problemas estruturais do runtime, como raiz
|
|
|
199
199
|
inexistente. Provider opcional ausente, LLM sem chave ou CLI de host nao
|
|
200
200
|
instalada aparecem no bloco de diagnostico e podem ser resolvidos sob demanda.
|
|
201
201
|
|
|
202
|
+
## Onboarding
|
|
203
|
+
|
|
204
|
+
Executar apenas `agent` inicia o status/wizard local. Para planejar setup sem
|
|
205
|
+
executar instalacoes externas:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
agent onboard minimal
|
|
209
|
+
agent onboard complete
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
`minimal` cobre identidade, coordenador LLM, mini-cerebro Qwen3-0.6B via
|
|
213
|
+
Ollama e memoria local. `complete` inclui tambem toolchain, providers/sources,
|
|
214
|
+
catalogo de agentes, automacoes locais, tarefas, notificacoes, knowledge e
|
|
215
|
+
memoria compartilhada. Instalacoes externas continuam exigindo opt-in.
|
|
216
|
+
|
|
217
|
+
Backups locais de memoria e personalidade sao gerenciados por:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
agent memory backup create --title "Antes da migracao"
|
|
221
|
+
export AGENT_DEVKIT_BACKUP_PASSPHRASE="frase longa"
|
|
222
|
+
agent memory backup create --title "Antes da migracao" --encrypted --passphrase-env AGENT_DEVKIT_BACKUP_PASSPHRASE
|
|
223
|
+
agent memory backup list
|
|
224
|
+
agent memory backup restore <backup-id> --yes
|
|
225
|
+
agent memory backup restore --file ./backup.adkmb --passphrase-env AGENT_DEVKIT_BACKUP_PASSPHRASE --yes
|
|
226
|
+
agent memory backup delete <backup-id> --yes
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
O backup criptografado gera um pacote portatil `.adkmb` e remove a copia local
|
|
230
|
+
em claro dentro da pasta do backup. Esse fluxo nao executa upload remoto. Sync
|
|
231
|
+
remoto continua exigindo provider, criptografia e opt-in explicito.
|
|
232
|
+
|
|
202
233
|
## Backends LLM
|
|
203
234
|
|
|
204
235
|
O modo `agent "<prompt>"` exige um backend LLM. O Agent DevKit suporta tres
|
|
@@ -292,10 +323,10 @@ agent llm doctor openrouter
|
|
|
292
323
|
```bash
|
|
293
324
|
agent ollama status
|
|
294
325
|
agent ollama models
|
|
295
|
-
agent ollama pull
|
|
296
|
-
agent ollama pull
|
|
326
|
+
agent ollama pull qwen3:0.6b --dry-run
|
|
327
|
+
agent ollama pull qwen3:0.6b --yes
|
|
297
328
|
ollama serve
|
|
298
|
-
agent llm configure ollama --base-url http://localhost:11434/v1 --model
|
|
329
|
+
agent llm configure ollama --base-url http://localhost:11434/v1 --model qwen3:0.6b --set-default
|
|
299
330
|
agent llm doctor ollama
|
|
300
331
|
```
|
|
301
332
|
|
|
@@ -319,7 +350,7 @@ agent llm list
|
|
|
319
350
|
agent llm configure openai --api-key-env OPENAI_API_KEY --set-default
|
|
320
351
|
agent llm configure anthropic --api-key-env ANTHROPIC_API_KEY --set-default
|
|
321
352
|
agent llm configure openrouter --api-key-env OPENROUTER_API_KEY --set-default
|
|
322
|
-
agent llm configure ollama --base-url http://localhost:11434/v1 --model
|
|
353
|
+
agent llm configure ollama --base-url http://localhost:11434/v1 --model qwen3:0.6b --set-default
|
|
323
354
|
agent llm configure codex-cli --set-default
|
|
324
355
|
agent llm configure claude-code --set-default
|
|
325
356
|
agent llm set-default codex-cli
|
|
@@ -5,8 +5,6 @@ from __future__ import annotations
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
|
-
import yaml
|
|
9
|
-
|
|
10
8
|
from cli.aikit.write_policy import normalize_write_policy, write_policy_public_fields
|
|
11
9
|
|
|
12
10
|
|
|
@@ -96,6 +94,10 @@ def find_capability(registry: dict[str, Any], agent_id: str, capability_id: str)
|
|
|
96
94
|
|
|
97
95
|
|
|
98
96
|
def read_yaml(path: Path) -> dict[str, Any]:
|
|
97
|
+
try:
|
|
98
|
+
import yaml # type: ignore
|
|
99
|
+
except ImportError as exc:
|
|
100
|
+
raise RuntimeError("PyYAML is required to read Agent DevKit manifests. Install requirements.txt.") from exc
|
|
99
101
|
data = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
|
|
100
102
|
return data if isinstance(data, dict) else {}
|
|
101
103
|
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""Explicit agentic planning and orchestration CLI commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from cli.aikit.core.requests import AgentPromptRequest
|
|
9
|
+
from cli.aikit.errors import DevKitError
|
|
10
|
+
from cli.aikit.natural_prompt_runtime import run_agent_prompt_request
|
|
11
|
+
from cli.aikit.orchestrator import build_execution_plan
|
|
12
|
+
from cli.aikit.runtime_paths import ROOT
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def agentic_plan(root: Path, prompt_parts: list[str] | tuple[str, ...] | None) -> dict[str, Any]:
|
|
16
|
+
prompt = normalize_prompt(prompt_parts, command="plan")
|
|
17
|
+
plan = build_execution_plan(root, prompt, dry_run=True)
|
|
18
|
+
return {
|
|
19
|
+
"kind": "agentic-plan",
|
|
20
|
+
"status": plan.get("status") or "planned",
|
|
21
|
+
"ok": True,
|
|
22
|
+
"dry_run": True,
|
|
23
|
+
"prompt_received": True,
|
|
24
|
+
"prompt_length": len(prompt),
|
|
25
|
+
"summary": plan_summary(plan),
|
|
26
|
+
"execution_plan": plan,
|
|
27
|
+
"orchestration_trace": plan.get("trace", []),
|
|
28
|
+
"response": "Plano agentico gerado sem executar LLM, automacoes ou escritas externas.",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def agentic_execute(
|
|
33
|
+
prompt_parts: list[str] | tuple[str, ...] | None,
|
|
34
|
+
*,
|
|
35
|
+
llm: str | None = None,
|
|
36
|
+
dry_run: bool = False,
|
|
37
|
+
session_id: str | None = None,
|
|
38
|
+
new_session: bool = False,
|
|
39
|
+
no_llm_fallback: bool = False,
|
|
40
|
+
prog_name: str = "agent",
|
|
41
|
+
project: str | None = None,
|
|
42
|
+
mode: str = "execute",
|
|
43
|
+
) -> dict[str, Any]:
|
|
44
|
+
prompt = normalize_prompt(prompt_parts, command=mode)
|
|
45
|
+
if dry_run:
|
|
46
|
+
payload = agentic_plan(ROOT, [prompt])
|
|
47
|
+
payload["command_mode"] = mode
|
|
48
|
+
return payload
|
|
49
|
+
result = run_agent_prompt_request(
|
|
50
|
+
AgentPromptRequest(
|
|
51
|
+
prompt=prompt,
|
|
52
|
+
llm=llm,
|
|
53
|
+
dry_run=False,
|
|
54
|
+
session_id=session_id,
|
|
55
|
+
new_session=new_session,
|
|
56
|
+
no_llm_fallback=no_llm_fallback,
|
|
57
|
+
prog_name=prog_name,
|
|
58
|
+
project=project,
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
return attach_agentic_metadata(result, prompt=prompt, mode=mode)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def normalize_prompt(prompt_parts: list[str] | tuple[str, ...] | None, *, command: str) -> str:
|
|
65
|
+
prompt = " ".join(str(part) for part in (prompt_parts or [])).strip()
|
|
66
|
+
if not prompt:
|
|
67
|
+
raise DevKitError(f"agent {command} requires a natural-language prompt")
|
|
68
|
+
return prompt
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def plan_summary(plan: dict[str, Any]) -> dict[str, Any]:
|
|
72
|
+
specialist_tasks = [task for task in plan.get("specialist_tasks") or [] if isinstance(task, dict)]
|
|
73
|
+
configuration_tasks = [task for task in plan.get("configuration_tasks") or [] if isinstance(task, dict)]
|
|
74
|
+
review_task = plan.get("review_task") if isinstance(plan.get("review_task"), dict) else {}
|
|
75
|
+
model_plan = plan.get("model_plan") if isinstance(plan.get("model_plan"), dict) else {}
|
|
76
|
+
routing_decision = plan.get("routing_decision") if isinstance(plan.get("routing_decision"), dict) else {}
|
|
77
|
+
autonomy = plan.get("autonomy_contract") if isinstance(plan.get("autonomy_contract"), dict) else {}
|
|
78
|
+
needs_input = (
|
|
79
|
+
plan.get("status") == "needs-input"
|
|
80
|
+
or bool(configuration_tasks)
|
|
81
|
+
or model_plan.get("strategy") == "human"
|
|
82
|
+
or autonomy.get("requires_human") is True
|
|
83
|
+
or autonomy.get("status") == "needs-input"
|
|
84
|
+
)
|
|
85
|
+
return {
|
|
86
|
+
"routing_status": routing_decision.get("status"),
|
|
87
|
+
"selected_agent_id": routing_decision.get("selected_agent_id"),
|
|
88
|
+
"selected_capability_id": routing_decision.get("selected_capability_id"),
|
|
89
|
+
"model_strategy": model_plan.get("strategy"),
|
|
90
|
+
"local_llm_selected": model_plan.get("local_llm_selected"),
|
|
91
|
+
"specialist_tasks": len(specialist_tasks),
|
|
92
|
+
"configuration_tasks": len(configuration_tasks),
|
|
93
|
+
"review_required": bool(review_task.get("required") or review_task.get("status") in {"pending", "required"}),
|
|
94
|
+
"collaboration_enabled": bool(plan.get("collaboration_enabled")),
|
|
95
|
+
"controller_enabled": bool(plan.get("controller_enabled")),
|
|
96
|
+
"needs_input": needs_input,
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def attach_agentic_metadata(result: dict[str, Any], *, prompt: str, mode: str) -> dict[str, Any]:
|
|
101
|
+
plan = result.get("execution_plan") if isinstance(result.get("execution_plan"), dict) else None
|
|
102
|
+
if plan is None:
|
|
103
|
+
plan = local_shortcut_execution_plan(prompt=prompt, result=result, mode=mode)
|
|
104
|
+
result["execution_plan"] = plan
|
|
105
|
+
result.setdefault("orchestration_trace", plan.get("trace", []))
|
|
106
|
+
result["agentic_summary"] = plan_summary(plan)
|
|
107
|
+
result["command_mode"] = mode
|
|
108
|
+
result["agentic_command"] = mode
|
|
109
|
+
return result
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def local_shortcut_execution_plan(*, prompt: str, result: dict[str, Any], mode: str) -> dict[str, Any]:
|
|
113
|
+
status = str(result.get("status") or "ok")
|
|
114
|
+
local_mode = str(result.get("mode") or result.get("action") or "local-shortcut")
|
|
115
|
+
ok = result.get("ok") is not False and status not in {"blocked", "failed", "needs-input", "needs-review"}
|
|
116
|
+
return {
|
|
117
|
+
"schema_version": "ai-devkit.agentic-plan/v1",
|
|
118
|
+
"status": "completed" if ok else status,
|
|
119
|
+
"prompt": prompt,
|
|
120
|
+
"dry_run": False,
|
|
121
|
+
"command_mode": mode,
|
|
122
|
+
"routing_decision": {
|
|
123
|
+
"status": "selected",
|
|
124
|
+
"selected_agent_id": "agent-devkit",
|
|
125
|
+
"selected_capability_id": local_mode,
|
|
126
|
+
"method": "local-shortcut",
|
|
127
|
+
"confidence": 1.0,
|
|
128
|
+
},
|
|
129
|
+
"model_plan": {
|
|
130
|
+
"strategy": "deterministic-local",
|
|
131
|
+
"local_llm_selected": False,
|
|
132
|
+
"local_llm_recommended": False,
|
|
133
|
+
"fallback": None,
|
|
134
|
+
},
|
|
135
|
+
"specialist_tasks": [],
|
|
136
|
+
"configuration_tasks": [],
|
|
137
|
+
"review_task": {
|
|
138
|
+
"agent_id": "execution-reviewer",
|
|
139
|
+
"capability_id": "review-final-output",
|
|
140
|
+
"status": "not-required",
|
|
141
|
+
"required": False,
|
|
142
|
+
},
|
|
143
|
+
"review_gate": {
|
|
144
|
+
"required": False,
|
|
145
|
+
"status": "not-required",
|
|
146
|
+
"reason": "local deterministic shortcut",
|
|
147
|
+
},
|
|
148
|
+
"collaboration_enabled": False,
|
|
149
|
+
"controller_enabled": False,
|
|
150
|
+
"trace": [
|
|
151
|
+
{
|
|
152
|
+
"agent_id": "task-orchestrator",
|
|
153
|
+
"action": "local-shortcut",
|
|
154
|
+
"mode": local_mode,
|
|
155
|
+
"status": status,
|
|
156
|
+
}
|
|
157
|
+
],
|
|
158
|
+
}
|
|
@@ -58,7 +58,7 @@ def record_audit(
|
|
|
58
58
|
execution_id = f"exec_{now_utc().strftime('%Y%m%d%H%M%S')}_{uuid.uuid4().hex[:8]}"
|
|
59
59
|
prompt = extract_prompt(args)
|
|
60
60
|
try:
|
|
61
|
-
safe_result = redact_value(result or {})
|
|
61
|
+
safe_result = redact_value(result or {}, redact_access_keys=True)
|
|
62
62
|
safe_prompt = redact_secrets(prompt) if prompt else None
|
|
63
63
|
safe_error = redact_secrets(error) if error else None
|
|
64
64
|
except Exception as exc: # noqa: BLE001 - never write an unredacted audit fallback.
|
|
@@ -227,25 +227,35 @@ def find_audit_json(execution_id: str) -> Path:
|
|
|
227
227
|
return matches[0]
|
|
228
228
|
|
|
229
229
|
|
|
230
|
-
def redact_value(value: Any) -> Any:
|
|
230
|
+
def redact_value(value: Any, *, redact_access_keys: bool = False, parent_key: str | None = None) -> Any:
|
|
231
231
|
if isinstance(value, str):
|
|
232
232
|
return redact_secrets(value)
|
|
233
233
|
if isinstance(value, list):
|
|
234
|
-
return [redact_value(item) for item in value]
|
|
234
|
+
return [redact_value(item, redact_access_keys=redact_access_keys, parent_key=parent_key) for item in value]
|
|
235
235
|
if isinstance(value, tuple):
|
|
236
|
-
return [redact_value(item) for item in value]
|
|
236
|
+
return [redact_value(item, redact_access_keys=redact_access_keys, parent_key=parent_key) for item in value]
|
|
237
237
|
if isinstance(value, dict):
|
|
238
238
|
redacted: dict[str, Any] = {}
|
|
239
239
|
for key, item in value.items():
|
|
240
240
|
key_text = str(key)
|
|
241
|
-
if secret_key(key_text):
|
|
241
|
+
if secret_key(key_text) or access_key(key_text, parent_key=parent_key, enabled=redact_access_keys):
|
|
242
242
|
redacted[key_text] = "[REDACTED_SECRET]"
|
|
243
243
|
else:
|
|
244
|
-
redacted[key_text] = redact_value(item)
|
|
244
|
+
redacted[key_text] = redact_value(item, redact_access_keys=redact_access_keys, parent_key=key_text)
|
|
245
245
|
return redacted
|
|
246
246
|
return value
|
|
247
247
|
|
|
248
248
|
|
|
249
|
+
def access_key(key: str, *, parent_key: str | None, enabled: bool) -> bool:
|
|
250
|
+
if not enabled:
|
|
251
|
+
return False
|
|
252
|
+
normalized = key.lower().replace("-", "_")
|
|
253
|
+
if normalized in {"owner_key", "contributor_key", "shared_key"}:
|
|
254
|
+
return True
|
|
255
|
+
parent = (parent_key or "").lower().replace("-", "_")
|
|
256
|
+
return normalized == "key" and parent in {"owner_access", "contributor_access", "shared_access"}
|
|
257
|
+
|
|
258
|
+
|
|
249
259
|
def secret_key(key: str) -> bool:
|
|
250
260
|
normalized = key.lower().replace("-", "_")
|
|
251
261
|
if normalized in {"token_estimate", "tokens", "prompt_tokens", "completion_tokens", "total_tokens"}:
|
|
@@ -2,24 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import json
|
|
5
6
|
import re
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from typing import Any
|
|
8
9
|
|
|
10
|
+
from cli.aikit.app_home import cache_home
|
|
9
11
|
from cli.aikit.agent_registry import load_agent_registry
|
|
10
12
|
from cli.aikit.errors import DevKitError
|
|
13
|
+
from cli.aikit.extensions import local_extensions_list
|
|
14
|
+
from cli.aikit.local_artifacts import local_agent_list, local_automation_list, script_list, skill_list
|
|
11
15
|
from cli.aikit.providers import ProviderRegistryError, list_providers
|
|
12
16
|
from cli.aikit.runtime_paths import ROOT
|
|
17
|
+
from cli.aikit.toolchain import list_toolchain
|
|
18
|
+
from cli.aikit.workflows import workflow_list
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
CATALOG_SCHEMA_VERSION = "agent-devkit.catalog/v1"
|
|
16
22
|
|
|
17
23
|
|
|
18
|
-
def catalog_list(root: Path | None = None, *, item_type: str | None = None) -> dict[str, Any]:
|
|
24
|
+
def catalog_list(root: Path | None = None, *, item_type: str | None = None, filters: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
19
25
|
root = root or ROOT
|
|
20
|
-
items =
|
|
21
|
-
if item_type:
|
|
22
|
-
items = [item for item in items if item["type"] == item_type]
|
|
26
|
+
items = filtered_catalog_items(root, item_type=item_type, filters=filters)
|
|
23
27
|
return {
|
|
24
28
|
"kind": "catalog",
|
|
25
29
|
"schema_version": CATALOG_SCHEMA_VERSION,
|
|
@@ -28,20 +32,19 @@ def catalog_list(root: Path | None = None, *, item_type: str | None = None) -> d
|
|
|
28
32
|
"query": None,
|
|
29
33
|
"type": item_type,
|
|
30
34
|
"count": len(items),
|
|
35
|
+
"filters": public_filters(item_type=item_type, filters=filters),
|
|
31
36
|
"items": items,
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
|
|
35
|
-
def catalog_search(query: str, root: Path | None = None, *, item_type: str | None = None) -> dict[str, Any]:
|
|
40
|
+
def catalog_search(query: str, root: Path | None = None, *, item_type: str | None = None, filters: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
36
41
|
root = root or ROOT
|
|
37
42
|
query = (query or "").strip()
|
|
38
43
|
if not query:
|
|
39
44
|
raise DevKitError("catalog search requires a query")
|
|
40
45
|
tokens = tokenize(query)
|
|
41
46
|
scored: list[tuple[int, dict[str, Any]]] = []
|
|
42
|
-
for item in
|
|
43
|
-
if item_type and item["type"] != item_type:
|
|
44
|
-
continue
|
|
47
|
+
for item in filtered_catalog_items(root, item_type=item_type, filters=filters):
|
|
45
48
|
score = match_score(item, tokens)
|
|
46
49
|
if score > 0:
|
|
47
50
|
enriched = dict(item)
|
|
@@ -56,6 +59,7 @@ def catalog_search(query: str, root: Path | None = None, *, item_type: str | Non
|
|
|
56
59
|
"query": query,
|
|
57
60
|
"type": item_type,
|
|
58
61
|
"count": len(scored),
|
|
62
|
+
"filters": public_filters(item_type=item_type, filters=filters),
|
|
59
63
|
"items": [item for _score, item in scored],
|
|
60
64
|
}
|
|
61
65
|
|
|
@@ -80,6 +84,25 @@ def catalog_show(item_id: str, root: Path | None = None, *, item_type: str | Non
|
|
|
80
84
|
raise DevKitError(f"catalog item not found{suffix}: {item_id}")
|
|
81
85
|
|
|
82
86
|
|
|
87
|
+
def catalog_rebuild_index(root: Path | None = None) -> dict[str, Any]:
|
|
88
|
+
root = root or ROOT
|
|
89
|
+
items = catalog_items(root)
|
|
90
|
+
path = catalog_index_path()
|
|
91
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
92
|
+
payload = {
|
|
93
|
+
"schema_version": CATALOG_SCHEMA_VERSION,
|
|
94
|
+
"items": items,
|
|
95
|
+
}
|
|
96
|
+
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
|
97
|
+
return {
|
|
98
|
+
"kind": "catalog-index",
|
|
99
|
+
"schema_version": CATALOG_SCHEMA_VERSION,
|
|
100
|
+
"status": "rebuilt",
|
|
101
|
+
"path": str(path),
|
|
102
|
+
"count": len(items),
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
83
106
|
def catalog_items(root: Path) -> list[dict[str, Any]]:
|
|
84
107
|
registry = load_agent_registry(root)
|
|
85
108
|
items: list[dict[str, Any]] = []
|
|
@@ -90,6 +113,33 @@ def catalog_items(root: Path) -> list[dict[str, Any]]:
|
|
|
90
113
|
if isinstance(capability, dict):
|
|
91
114
|
items.append(capability_item(capability))
|
|
92
115
|
items.extend(provider_items(root))
|
|
116
|
+
items.extend(workflow_items())
|
|
117
|
+
items.extend(tool_items(root))
|
|
118
|
+
items.extend(skill_items(root))
|
|
119
|
+
items.extend(plugin_items(root))
|
|
120
|
+
items.extend(extension_items())
|
|
121
|
+
items.extend(local_artifact_items())
|
|
122
|
+
return items
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def filtered_catalog_items(root: Path, *, item_type: str | None = None, filters: dict[str, Any] | None = None) -> list[dict[str, Any]]:
|
|
126
|
+
filters = {key: value for key, value in (filters or {}).items() if value not in {None, ""}}
|
|
127
|
+
items = catalog_items(root)
|
|
128
|
+
if item_type:
|
|
129
|
+
items = [
|
|
130
|
+
item
|
|
131
|
+
for item in items
|
|
132
|
+
if item["type"] == item_type or item.get("local_kind") == item_type
|
|
133
|
+
]
|
|
134
|
+
for key, value in filters.items():
|
|
135
|
+
if key == "provider":
|
|
136
|
+
items = [item for item in items if value in (item.get("providers_required") or []) or item.get("provider") == value]
|
|
137
|
+
elif key == "status":
|
|
138
|
+
items = [item for item in items if item.get("status") == value]
|
|
139
|
+
elif key == "write_policy":
|
|
140
|
+
items = [item for item in items if item.get("write_policy") == value]
|
|
141
|
+
elif key == "readiness":
|
|
142
|
+
items = [item for item in items if (item.get("readiness") or {}).get("status") == value]
|
|
93
143
|
return items
|
|
94
144
|
|
|
95
145
|
|
|
@@ -105,6 +155,7 @@ def agent_item(agent: dict[str, Any]) -> dict[str, Any]:
|
|
|
105
155
|
"write_policy": agent.get("write_policy"),
|
|
106
156
|
"write_policy_metadata": agent.get("write_policy_metadata"),
|
|
107
157
|
"source_contract": None,
|
|
158
|
+
"provider": None,
|
|
108
159
|
"providers_required": [],
|
|
109
160
|
"runner": None,
|
|
110
161
|
"agent_mode": agent.get("agent_mode") or {},
|
|
@@ -142,6 +193,7 @@ def capability_item(capability: dict[str, Any]) -> dict[str, Any]:
|
|
|
142
193
|
"write_policy": capability.get("write_policy"),
|
|
143
194
|
"write_policy_metadata": capability.get("write_policy_metadata"),
|
|
144
195
|
"source_contract": capability.get("source_contract") or capability.get("source"),
|
|
196
|
+
"provider": provider,
|
|
145
197
|
"providers_required": providers_required,
|
|
146
198
|
"runner": capability.get("runner") or (capability.get("runtime") or {}).get("runner"),
|
|
147
199
|
"agent_mode": None,
|
|
@@ -174,6 +226,7 @@ def provider_items(root: Path) -> list[dict[str, Any]]:
|
|
|
174
226
|
"path": provider.get("path"),
|
|
175
227
|
"write_policy": "read_only",
|
|
176
228
|
"source_contract": None,
|
|
229
|
+
"provider": provider.get("id"),
|
|
177
230
|
"providers_required": [],
|
|
178
231
|
"runner": None,
|
|
179
232
|
"agent_mode": None,
|
|
@@ -185,6 +238,223 @@ def provider_items(root: Path) -> list[dict[str, Any]]:
|
|
|
185
238
|
return items
|
|
186
239
|
|
|
187
240
|
|
|
241
|
+
def workflow_items() -> list[dict[str, Any]]:
|
|
242
|
+
try:
|
|
243
|
+
payload = workflow_list()
|
|
244
|
+
except Exception:
|
|
245
|
+
return []
|
|
246
|
+
return [
|
|
247
|
+
{
|
|
248
|
+
"id": str(workflow.get("id") or ""),
|
|
249
|
+
"type": "workflow",
|
|
250
|
+
"description": workflow.get("description") or workflow.get("title") or "",
|
|
251
|
+
"status": "ok",
|
|
252
|
+
"version": None,
|
|
253
|
+
"path": workflow.get("path"),
|
|
254
|
+
"write_policy": workflow.get("write_policy"),
|
|
255
|
+
"source_contract": None,
|
|
256
|
+
"provider": None,
|
|
257
|
+
"providers_required": workflow.get("providers_required") or [],
|
|
258
|
+
"runner": "workflow",
|
|
259
|
+
"agent_mode": None,
|
|
260
|
+
"routing": {},
|
|
261
|
+
"prompt_examples": workflow.get("examples") or [],
|
|
262
|
+
"readiness": {"status": "ready"},
|
|
263
|
+
"next_step": f"agent workflow show {workflow.get('id')}",
|
|
264
|
+
}
|
|
265
|
+
for workflow in payload.get("items") or []
|
|
266
|
+
if isinstance(workflow, dict)
|
|
267
|
+
]
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def tool_items(root: Path) -> list[dict[str, Any]]:
|
|
271
|
+
try:
|
|
272
|
+
payload = list_toolchain(root)
|
|
273
|
+
except Exception:
|
|
274
|
+
return []
|
|
275
|
+
return [
|
|
276
|
+
{
|
|
277
|
+
"id": str(tool.get("id") or ""),
|
|
278
|
+
"type": "tool",
|
|
279
|
+
"description": tool.get("notes") or tool.get("label") or "",
|
|
280
|
+
"status": "required" if tool.get("required") else "optional",
|
|
281
|
+
"version": None,
|
|
282
|
+
"path": None,
|
|
283
|
+
"write_policy": "confirm",
|
|
284
|
+
"source_contract": None,
|
|
285
|
+
"provider": None,
|
|
286
|
+
"providers_required": [],
|
|
287
|
+
"runner": tool.get("command"),
|
|
288
|
+
"agent_mode": None,
|
|
289
|
+
"routing": {},
|
|
290
|
+
"prompt_examples": [],
|
|
291
|
+
"readiness": {"status": "requires-install-check", "command": tool.get("command")},
|
|
292
|
+
"next_step": f"agent toolchain doctor {tool.get('id')}",
|
|
293
|
+
}
|
|
294
|
+
for tool in payload.get("items") or []
|
|
295
|
+
if isinstance(tool, dict)
|
|
296
|
+
]
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def skill_items(root: Path) -> list[dict[str, Any]]:
|
|
300
|
+
catalog = parse_markdown_catalog(root / "vendor" / "skills" / "CATALOG.md", item_type="skill")
|
|
301
|
+
if catalog:
|
|
302
|
+
return catalog
|
|
303
|
+
return filesystem_items(root / "vendor" / "skills", item_type="skill", marker="SKILL.md")
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def plugin_items(root: Path) -> list[dict[str, Any]]:
|
|
307
|
+
catalog = parse_markdown_catalog(root / "vendor" / "plugins" / "CATALOG.md", item_type="plugin")
|
|
308
|
+
if catalog:
|
|
309
|
+
return catalog
|
|
310
|
+
return filesystem_items(root / "vendor" / "plugins", item_type="plugin", marker="README.md")
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def extension_items() -> list[dict[str, Any]]:
|
|
314
|
+
try:
|
|
315
|
+
payload = local_extensions_list()
|
|
316
|
+
except Exception:
|
|
317
|
+
return []
|
|
318
|
+
return [
|
|
319
|
+
{
|
|
320
|
+
"id": str(item.get("id") or ""),
|
|
321
|
+
"type": "extension",
|
|
322
|
+
"description": f"Local extension at {item.get('path')}",
|
|
323
|
+
"status": "enabled" if item.get("enabled") else "disabled",
|
|
324
|
+
"version": None,
|
|
325
|
+
"path": item.get("path"),
|
|
326
|
+
"write_policy": "local_config_write",
|
|
327
|
+
"source_contract": None,
|
|
328
|
+
"provider": None,
|
|
329
|
+
"providers_required": [],
|
|
330
|
+
"runner": None,
|
|
331
|
+
"agent_mode": None,
|
|
332
|
+
"routing": {},
|
|
333
|
+
"prompt_examples": [],
|
|
334
|
+
"readiness": {"status": "ready" if item.get("enabled") else "disabled"},
|
|
335
|
+
"next_step": f"agent local validate {item.get('id')}",
|
|
336
|
+
}
|
|
337
|
+
for item in payload.get("items") or []
|
|
338
|
+
if isinstance(item, dict)
|
|
339
|
+
]
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def local_artifact_items() -> list[dict[str, Any]]:
|
|
343
|
+
payloads = []
|
|
344
|
+
for factory, item_type, command in (
|
|
345
|
+
(skill_list, "skill", "agent skill show"),
|
|
346
|
+
(script_list, "script", "agent script run"),
|
|
347
|
+
(local_agent_list, "agent", "agent agents validate"),
|
|
348
|
+
(local_automation_list, "automation", "agent local automation show"),
|
|
349
|
+
):
|
|
350
|
+
try:
|
|
351
|
+
payload = factory()
|
|
352
|
+
except Exception:
|
|
353
|
+
continue
|
|
354
|
+
for item in payload.get("items") or []:
|
|
355
|
+
if not isinstance(item, dict):
|
|
356
|
+
continue
|
|
357
|
+
payloads.append(
|
|
358
|
+
{
|
|
359
|
+
"id": str(item.get("id") or ""),
|
|
360
|
+
"type": item_type,
|
|
361
|
+
"local_kind": item.get("kind"),
|
|
362
|
+
"origin": "local",
|
|
363
|
+
"description": f"Local {item_type} at {item.get('path')}",
|
|
364
|
+
"status": "enabled" if item.get("enabled") else "disabled",
|
|
365
|
+
"version": None,
|
|
366
|
+
"path": item.get("path"),
|
|
367
|
+
"write_policy": "local_config_write",
|
|
368
|
+
"source_contract": None,
|
|
369
|
+
"provider": None,
|
|
370
|
+
"providers_required": [],
|
|
371
|
+
"runner": None,
|
|
372
|
+
"agent_mode": None,
|
|
373
|
+
"routing": {},
|
|
374
|
+
"prompt_examples": [],
|
|
375
|
+
"readiness": {"status": "ready" if item.get("enabled") else "disabled"},
|
|
376
|
+
"next_step": f"{command} {item.get('id')}",
|
|
377
|
+
}
|
|
378
|
+
)
|
|
379
|
+
return payloads
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def parse_markdown_catalog(path: Path, *, item_type: str) -> list[dict[str, Any]]:
|
|
383
|
+
if not path.exists():
|
|
384
|
+
return []
|
|
385
|
+
items: list[dict[str, Any]] = []
|
|
386
|
+
for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
|
|
387
|
+
stripped = line.strip()
|
|
388
|
+
if not stripped.startswith("| `"):
|
|
389
|
+
continue
|
|
390
|
+
cells = [cell.strip() for cell in stripped.strip("|").split("|")]
|
|
391
|
+
if len(cells) < 3:
|
|
392
|
+
continue
|
|
393
|
+
item_id = cells[0].strip("` ")
|
|
394
|
+
description = cells[1]
|
|
395
|
+
path_cell = cells[-1].strip("` ")
|
|
396
|
+
items.append(
|
|
397
|
+
{
|
|
398
|
+
"id": item_id,
|
|
399
|
+
"type": item_type,
|
|
400
|
+
"description": description,
|
|
401
|
+
"status": "available",
|
|
402
|
+
"version": None,
|
|
403
|
+
"path": path_cell,
|
|
404
|
+
"write_policy": "read_only",
|
|
405
|
+
"source_contract": None,
|
|
406
|
+
"provider": None,
|
|
407
|
+
"providers_required": [],
|
|
408
|
+
"runner": None,
|
|
409
|
+
"agent_mode": None,
|
|
410
|
+
"routing": {},
|
|
411
|
+
"prompt_examples": [],
|
|
412
|
+
"readiness": {"status": "available"},
|
|
413
|
+
"next_step": f"Use {item_type} {item_id} when relevant.",
|
|
414
|
+
}
|
|
415
|
+
)
|
|
416
|
+
return items
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
def filesystem_items(root: Path, *, item_type: str, marker: str) -> list[dict[str, Any]]:
|
|
420
|
+
if not root.exists():
|
|
421
|
+
return []
|
|
422
|
+
items = []
|
|
423
|
+
for marker_path in sorted(root.glob(f"**/{marker}")):
|
|
424
|
+
item_root = marker_path.parent
|
|
425
|
+
items.append(
|
|
426
|
+
{
|
|
427
|
+
"id": item_root.name,
|
|
428
|
+
"type": item_type,
|
|
429
|
+
"description": "",
|
|
430
|
+
"status": "available",
|
|
431
|
+
"version": None,
|
|
432
|
+
"path": str(item_root.relative_to(ROOT)) if item_root.is_relative_to(ROOT) else str(item_root),
|
|
433
|
+
"write_policy": "read_only",
|
|
434
|
+
"source_contract": None,
|
|
435
|
+
"provider": None,
|
|
436
|
+
"providers_required": [],
|
|
437
|
+
"runner": None,
|
|
438
|
+
"agent_mode": None,
|
|
439
|
+
"routing": {},
|
|
440
|
+
"prompt_examples": [],
|
|
441
|
+
"readiness": {"status": "available"},
|
|
442
|
+
}
|
|
443
|
+
)
|
|
444
|
+
return items
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def catalog_index_path() -> Path:
|
|
448
|
+
return cache_home() / "catalog-index.json"
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def public_filters(*, item_type: str | None, filters: dict[str, Any] | None) -> dict[str, Any]:
|
|
452
|
+
payload = {key: value for key, value in (filters or {}).items() if value not in {None, ""}}
|
|
453
|
+
if item_type:
|
|
454
|
+
payload["type"] = item_type
|
|
455
|
+
return payload
|
|
456
|
+
|
|
457
|
+
|
|
188
458
|
def tokenize(value: str) -> set[str]:
|
|
189
459
|
tokens = {token for token in re.findall(r"[a-z0-9]+", value.lower()) if token}
|
|
190
460
|
return expand_query_tokens(tokens)
|