agent-devkit 0.2.0 → 0.3.1
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 +66 -13
- package/bin/agent.mjs +133 -7
- package/package.json +1 -1
- package/runtime/README.md +205 -13
- 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 +47 -8
- 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 +2 -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 +146 -8
- package/runtime/cli/aikit/contribution.py +132 -2
- package/runtime/cli/aikit/doctor_runtime.py +85 -0
- package/runtime/cli/aikit/embedded_mini_brain.py +351 -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 +146 -0
- package/runtime/cli/aikit/knowledge_base.py +1067 -0
- package/runtime/cli/aikit/llm.py +40 -6
- package/runtime/cli/aikit/local_artifacts.py +444 -0
- package/runtime/cli/aikit/local_llm.py +176 -0
- package/runtime/cli/aikit/local_llm_operator.py +15 -5
- 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 +56 -25
- package/runtime/cli/aikit/model_router.py +42 -9
- package/runtime/cli/aikit/natural_prompt_runtime.py +194 -2
- 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/review_gate.py +14 -2
- 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/models/qwen2.5-0.5b-instruct/manifest.json +30 -0
- 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
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import re
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
|
+
from cli.aikit.embedded_mini_brain import EMBEDDED_BACKEND_ID
|
|
8
9
|
from cli.aikit.llm import BACKENDS, doctor_backend, llm_preference, load_config
|
|
9
10
|
from cli.aikit.mini_brain import mini_brain_contract
|
|
10
11
|
from cli.aikit.ollama import ollama_status
|
|
@@ -14,6 +15,9 @@ from cli.aikit.write_policy import normalize_write_policy, write_policy_public_f
|
|
|
14
15
|
OPERATIONAL_PATTERN = re.compile(
|
|
15
16
|
r"(?i)\b(resum\w*|sumari\w*|classifi\w*|extra(?:i|ir|ia|cao|ção)\w*|normaliz\w*|compar\w*|logs?|rascunho|agrupe|agrupar)\b"
|
|
16
17
|
)
|
|
18
|
+
SIMPLE_CHAT_SETUP_PATTERN = re.compile(
|
|
19
|
+
r"(?i)\b(ol[aá]|oi|bom dia|boa tarde|boa noite|ajuda|help|comec(?:ar|o)|começ(?:ar|o)|setup|onboard|configur|instal|usar)\b"
|
|
20
|
+
)
|
|
17
21
|
HIGH_LEVEL_PATTERN = re.compile(
|
|
18
22
|
r"(?i)\b(arquitet|decid|aprovar|reprovar|especifica|requisit|implemente|codigo|c[oó]digo|documento|automac|deploy|seguran)\b"
|
|
19
23
|
)
|
|
@@ -48,7 +52,9 @@ def build_model_plan(
|
|
|
48
52
|
mini_brain = mini_brain_contract(config=config, ollama_payload=ollama, ollama_backend=ollama_backend)
|
|
49
53
|
local_available = mini_brain.get("available") is True
|
|
50
54
|
operational = bool(OPERATIONAL_PATTERN.search(prompt))
|
|
55
|
+
simple_chat_setup = bool(SIMPLE_CHAT_SETUP_PATTERN.search(prompt))
|
|
51
56
|
high_level = bool(HIGH_LEVEL_PATTERN.search(prompt))
|
|
57
|
+
local_provider = select_local_provider(ollama_payload=ollama, ollama_backend=ollama_backend, mini_brain=mini_brain)
|
|
52
58
|
policy = choose_model_strategy(
|
|
53
59
|
prompt,
|
|
54
60
|
route=route,
|
|
@@ -56,10 +62,12 @@ def build_model_plan(
|
|
|
56
62
|
specialist_tasks=specialist_tasks or [],
|
|
57
63
|
configuration_tasks=configuration_tasks or [],
|
|
58
64
|
operational=operational,
|
|
65
|
+
simple_chat_setup=simple_chat_setup,
|
|
59
66
|
high_level=high_level,
|
|
60
67
|
local_available=local_available,
|
|
61
68
|
)
|
|
62
69
|
use_local = policy["strategy"] == "mini-brain" and local_available
|
|
70
|
+
delegate_local = use_local and operational
|
|
63
71
|
return {
|
|
64
72
|
"kind": "model-plan",
|
|
65
73
|
"status": "planned",
|
|
@@ -73,22 +81,30 @@ def build_model_plan(
|
|
|
73
81
|
"max_llm_calls": policy["max_llm_calls"],
|
|
74
82
|
"intent": route.get("intent") if route else "llm",
|
|
75
83
|
"primary_coordinators": coordinator_order(preference),
|
|
76
|
-
"local_llm_role": "operational-worker",
|
|
84
|
+
"local_llm_role": "operational-worker" if operational else "bootstrap-coordinator",
|
|
77
85
|
"local_llm_available": local_available,
|
|
78
|
-
"local_llm_provider":
|
|
79
|
-
"local_llm_backend_configured": ollama_backend.get("
|
|
86
|
+
"local_llm_provider": local_provider,
|
|
87
|
+
"local_llm_backend_configured": ollama_backend.get("configured") is True if local_provider == "ollama" else True,
|
|
80
88
|
"local_llm_runtime": {
|
|
81
|
-
"
|
|
89
|
+
"provider": local_provider,
|
|
90
|
+
"binary_status": ollama.get("status") if local_provider == "ollama" else "embedded",
|
|
82
91
|
"backend_status": ollama_backend.get("status"),
|
|
83
|
-
"model": mini_brain.get("ollama_model") or ollama_backend.get("model"),
|
|
84
|
-
"base_url": ollama_backend.get("base_url"),
|
|
92
|
+
"model": (mini_brain.get("ollama_model") or ollama_backend.get("model")) if local_provider == "ollama" else mini_brain.get("hf_model"),
|
|
93
|
+
"base_url": ollama_backend.get("base_url") if local_provider == "ollama" else None,
|
|
94
|
+
},
|
|
95
|
+
"optional_local_providers": {
|
|
96
|
+
"ollama": {
|
|
97
|
+
"status": ollama.get("status"),
|
|
98
|
+
"backend_status": ollama_backend.get("status"),
|
|
99
|
+
"model_count": ollama.get("model_count"),
|
|
100
|
+
}
|
|
85
101
|
},
|
|
86
102
|
"mini_brain": mini_brain,
|
|
87
103
|
"local_llm_recommended": operational,
|
|
88
104
|
"local_llm_selected": use_local,
|
|
89
105
|
"delegation": {
|
|
90
|
-
"allowed": policy["strategy"] == "mini-brain",
|
|
91
|
-
"selected":
|
|
106
|
+
"allowed": policy["strategy"] == "mini-brain" and operational,
|
|
107
|
+
"selected": delegate_local,
|
|
92
108
|
"reason": local_reason(
|
|
93
109
|
operational=operational,
|
|
94
110
|
local_available=local_available,
|
|
@@ -110,6 +126,7 @@ def choose_model_strategy(
|
|
|
110
126
|
specialist_tasks: list[dict[str, Any]],
|
|
111
127
|
configuration_tasks: list[dict[str, Any]],
|
|
112
128
|
operational: bool,
|
|
129
|
+
simple_chat_setup: bool,
|
|
113
130
|
high_level: bool,
|
|
114
131
|
local_available: bool,
|
|
115
132
|
) -> dict[str, Any]:
|
|
@@ -154,7 +171,7 @@ def choose_model_strategy(
|
|
|
154
171
|
max_llm_calls=0,
|
|
155
172
|
matrix="Conhecida + estruturada + baixo risco -> automacao",
|
|
156
173
|
)
|
|
157
|
-
if operational and not high_level:
|
|
174
|
+
if (operational or simple_chat_setup) and not high_level:
|
|
158
175
|
return policy(
|
|
159
176
|
"mini-brain" if local_available else "external-llm",
|
|
160
177
|
"The prompt is operational and low-risk; local mini-brain is preferred when available.",
|
|
@@ -241,3 +258,19 @@ def local_reason(*, operational: bool, local_available: bool, high_level: bool,
|
|
|
241
258
|
if operational and not local_available:
|
|
242
259
|
return "Task is operational, but the local mini-brain is not enabled or available; coordinator/API fallback should execute."
|
|
243
260
|
return "Task requires coordinator-level reasoning or review."
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def select_local_provider(
|
|
264
|
+
*,
|
|
265
|
+
ollama_payload: dict[str, Any],
|
|
266
|
+
ollama_backend: dict[str, Any],
|
|
267
|
+
mini_brain: dict[str, Any],
|
|
268
|
+
) -> str:
|
|
269
|
+
ollama_ready = (
|
|
270
|
+
ollama_payload.get("status") == "ok"
|
|
271
|
+
and ollama_backend.get("status") == "ok"
|
|
272
|
+
and (ollama_backend.get("configured") is True or int(ollama_payload.get("model_count") or 0) > 0)
|
|
273
|
+
)
|
|
274
|
+
if ollama_ready:
|
|
275
|
+
return "ollama"
|
|
276
|
+
return str(mini_brain.get("provider") or EMBEDDED_BACKEND_ID)
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import argparse
|
|
6
|
+
import re
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from typing import Any
|
|
8
9
|
|
|
10
|
+
from cli.aikit.agent_registry import load_agent_registry
|
|
9
11
|
from cli.aikit.agent_executor import execute_plan_tasks
|
|
10
12
|
from cli.aikit.capability_runtime import load_agent, run_capability
|
|
11
13
|
from cli.aikit.calendar import calendar_summary, calendar_today, calendar_tomorrow
|
|
@@ -22,7 +24,7 @@ from cli.aikit.memory import napkin_context, record_usage
|
|
|
22
24
|
from cli.aikit.model_router import build_model_plan
|
|
23
25
|
from cli.aikit.module_controller import run_module_controller
|
|
24
26
|
from cli.aikit.orchestrator import attach_source_to_primary_task, build_execution_plan, mark_plan_after_execution, mark_review_task
|
|
25
|
-
from cli.aikit.personality import load_personality
|
|
27
|
+
from cli.aikit.personality import load_personality, update_personality
|
|
26
28
|
from cli.aikit.provider_wizard import missing_source_wizard
|
|
27
29
|
from cli.aikit.review_gate import build_review_gate
|
|
28
30
|
from cli.aikit.router import route_prompt
|
|
@@ -36,6 +38,142 @@ def effective_dry_run(args: argparse.Namespace) -> bool:
|
|
|
36
38
|
return bool(getattr(args, "dry_run", False) or getattr(args, "global_dry_run", False))
|
|
37
39
|
|
|
38
40
|
|
|
41
|
+
def parse_rename_prompt(prompt: str) -> str | None:
|
|
42
|
+
text = " ".join(prompt.strip().split())
|
|
43
|
+
patterns = [
|
|
44
|
+
r"(?i)\b(?:mude|troque|altere|renomeie)\s+(?:o\s+)?seu\s+nome\s+para\s+(.+)$",
|
|
45
|
+
r"(?i)\b(?:seu\s+nome\s+agora\s+e|seu\s+nome\s+agora\s+é)\s+(.+)$",
|
|
46
|
+
r"(?i)\b(?:teu\s+nome\s+agora\s+e|teu\s+nome\s+agora\s+é)\s+(.+)$",
|
|
47
|
+
]
|
|
48
|
+
for pattern in patterns:
|
|
49
|
+
match = re.search(pattern, text)
|
|
50
|
+
if not match:
|
|
51
|
+
continue
|
|
52
|
+
value = clean_requested_name(match.group(1))
|
|
53
|
+
if value:
|
|
54
|
+
return value
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def clean_requested_name(value: str) -> str | None:
|
|
59
|
+
cleaned = " ".join(value.strip().strip("\"'`.,;:!").split())
|
|
60
|
+
if not cleaned:
|
|
61
|
+
return None
|
|
62
|
+
return cleaned[:80]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def is_capabilities_help_prompt(prompt: str) -> bool:
|
|
66
|
+
normalized = normalize_text(prompt)
|
|
67
|
+
if normalized in {"ajuda", "help", "o que voce faz", "o que voce consegue fazer"}:
|
|
68
|
+
return True
|
|
69
|
+
capability_markers = (
|
|
70
|
+
"o que voce consegue fazer",
|
|
71
|
+
"o que voce pode fazer",
|
|
72
|
+
"como voce pode ajudar",
|
|
73
|
+
"como usar o agent",
|
|
74
|
+
"como usar voce",
|
|
75
|
+
"quais suas capacidades",
|
|
76
|
+
"quais sao suas capacidades",
|
|
77
|
+
"quais agentes voce tem",
|
|
78
|
+
"que agentes voce tem",
|
|
79
|
+
)
|
|
80
|
+
return any(marker in normalized for marker in capability_markers)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def normalize_text(value: str) -> str:
|
|
84
|
+
replacements = str.maketrans(
|
|
85
|
+
{
|
|
86
|
+
"á": "a",
|
|
87
|
+
"à": "a",
|
|
88
|
+
"ã": "a",
|
|
89
|
+
"â": "a",
|
|
90
|
+
"é": "e",
|
|
91
|
+
"ê": "e",
|
|
92
|
+
"í": "i",
|
|
93
|
+
"ó": "o",
|
|
94
|
+
"õ": "o",
|
|
95
|
+
"ô": "o",
|
|
96
|
+
"ú": "u",
|
|
97
|
+
"ç": "c",
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
text = value.lower().translate(replacements)
|
|
101
|
+
return " ".join(re.sub(r"[^a-z0-9._:-]+", " ", text).split())
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def local_capabilities_help_response(prompt: str, *, name: str) -> dict[str, Any]:
|
|
105
|
+
registry = load_agent_registry(ROOT)
|
|
106
|
+
agents = registry.get("agents") if isinstance(registry.get("agents"), dict) else {}
|
|
107
|
+
capabilities = registry.get("capabilities") if isinstance(registry.get("capabilities"), dict) else {}
|
|
108
|
+
examples = [
|
|
109
|
+
'agent "analise o card 7914 do projeto sustentacao no azure"',
|
|
110
|
+
'agent "mude seu nome para Ianota"',
|
|
111
|
+
"agent onboard minimal",
|
|
112
|
+
"agent catalog search pr",
|
|
113
|
+
"agent mcp tools",
|
|
114
|
+
"agent memory show",
|
|
115
|
+
]
|
|
116
|
+
response = (
|
|
117
|
+
f"Eu sou {name}. Posso operar como harness/agente local do Agent DevKit: "
|
|
118
|
+
"validar onboarding, lembrar preferencias locais, rotear pedidos para agentes especialistas, "
|
|
119
|
+
"criar wizards de configuracao quando faltar provider/source, executar capabilities deterministicas, "
|
|
120
|
+
"expor ferramentas via MCP, preparar automacoes locais e usar LLMs configuradas quando a tarefa exigir raciocinio aberto. "
|
|
121
|
+
f"Neste runtime encontrei {len(agents)} agentes e {len(capabilities)} capabilities."
|
|
122
|
+
)
|
|
123
|
+
return {
|
|
124
|
+
"kind": "agent",
|
|
125
|
+
"status": "ok",
|
|
126
|
+
"ok": True,
|
|
127
|
+
"requires_llm": False,
|
|
128
|
+
"prompt_received": True,
|
|
129
|
+
"prompt_length": len(prompt),
|
|
130
|
+
"mode": "local-capabilities-help",
|
|
131
|
+
"identity": {"name": name, "source": "local"},
|
|
132
|
+
"response": response,
|
|
133
|
+
"catalog": {
|
|
134
|
+
"agents": len(agents),
|
|
135
|
+
"capabilities": len(capabilities),
|
|
136
|
+
},
|
|
137
|
+
"next_steps": examples,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def embedded_mini_brain_install_response(prompt: str, *, name: str, model_plan: dict[str, Any]) -> dict[str, Any]:
|
|
142
|
+
embedded = (
|
|
143
|
+
((model_plan.get("mini_brain") or {}).get("embedded") or {})
|
|
144
|
+
if isinstance(model_plan.get("mini_brain"), dict)
|
|
145
|
+
else {}
|
|
146
|
+
)
|
|
147
|
+
status = embedded.get("status") or "not-installed"
|
|
148
|
+
response = (
|
|
149
|
+
f"Eu sou {name}. Consigo orientar o setup inicial localmente, mas o mini-cerebro local ainda nao esta instalado "
|
|
150
|
+
f"(status: {status}). Para habilitar conversa local sem Claude, Codex, Ollama ou API externa, execute "
|
|
151
|
+
"`agent setup mini-brain --yes`. Sem esse download, posso continuar com onboarding, memoria, wizards e "
|
|
152
|
+
"capabilities deterministicas."
|
|
153
|
+
)
|
|
154
|
+
return {
|
|
155
|
+
"kind": "agent",
|
|
156
|
+
"status": "needs-setup",
|
|
157
|
+
"ok": False,
|
|
158
|
+
"requires_llm": False,
|
|
159
|
+
"prompt_received": True,
|
|
160
|
+
"prompt_length": len(prompt),
|
|
161
|
+
"mode": "embedded-mini-brain-not-installed",
|
|
162
|
+
"identity": {"name": name, "source": "local"},
|
|
163
|
+
"llm_backend": "embedded-mini-brain",
|
|
164
|
+
"mini_brain": model_plan.get("mini_brain"),
|
|
165
|
+
"response": response,
|
|
166
|
+
"message": "Embedded mini-brain is not installed yet.",
|
|
167
|
+
"next_steps": [
|
|
168
|
+
"agent setup mini-brain --dry-run",
|
|
169
|
+
"agent setup mini-brain --yes",
|
|
170
|
+
"agent llm configure claude-code --set-default",
|
|
171
|
+
"agent llm configure codex-cli --set-default",
|
|
172
|
+
],
|
|
173
|
+
"exit_code": 2,
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
39
177
|
def agent_requires_llm(args: argparse.Namespace) -> dict[str, Any]:
|
|
40
178
|
prompt = " ".join(args.prompt).strip()
|
|
41
179
|
return run_agent_prompt_request(
|
|
@@ -70,6 +208,21 @@ def run_agent_prompt_request(request: AgentPromptRequest) -> dict[str, Any]:
|
|
|
70
208
|
raise DevKitError(str(exc)) from exc
|
|
71
209
|
personality = load_personality()
|
|
72
210
|
name = public_name(personality=personality, invoked_as=request.prog_name)
|
|
211
|
+
rename = parse_rename_prompt(prompt)
|
|
212
|
+
if rename:
|
|
213
|
+
updated = update_personality(agent_name=rename)
|
|
214
|
+
result = {
|
|
215
|
+
"kind": "agent",
|
|
216
|
+
"status": "ok",
|
|
217
|
+
"ok": True,
|
|
218
|
+
"requires_llm": False,
|
|
219
|
+
"prompt_received": True,
|
|
220
|
+
"prompt_length": len(prompt),
|
|
221
|
+
"identity": {"name": updated.get("agent_name"), "source": "local"},
|
|
222
|
+
"action": "rename",
|
|
223
|
+
"response": f"Pronto. Meu nome local agora e {updated.get('agent_name')}.",
|
|
224
|
+
}
|
|
225
|
+
return finalize_agent_session(result, session, prompt, backend=request.llm)
|
|
73
226
|
if is_identity_question(prompt):
|
|
74
227
|
result = {
|
|
75
228
|
"kind": "agent",
|
|
@@ -82,6 +235,13 @@ def run_agent_prompt_request(request: AgentPromptRequest) -> dict[str, Any]:
|
|
|
82
235
|
"response": local_identity_response(prompt, name=name),
|
|
83
236
|
}
|
|
84
237
|
return finalize_agent_session(result, session, prompt, backend=request.llm)
|
|
238
|
+
if is_capabilities_help_prompt(prompt):
|
|
239
|
+
return finalize_agent_session(
|
|
240
|
+
local_capabilities_help_response(prompt, name=name),
|
|
241
|
+
session,
|
|
242
|
+
prompt,
|
|
243
|
+
backend=request.llm,
|
|
244
|
+
)
|
|
85
245
|
natural_result = dispatch_natural_operational_prompt(prompt)
|
|
86
246
|
if natural_result:
|
|
87
247
|
return finalize_agent_session(natural_result, session, prompt, backend=request.llm)
|
|
@@ -113,9 +273,15 @@ def run_agent_prompt_request(request: AgentPromptRequest) -> dict[str, Any]:
|
|
|
113
273
|
)
|
|
114
274
|
local_llm_execution = maybe_delegate_local_llm(prompt, model_plan)
|
|
115
275
|
coordinator_prompt = enrich_prompt_with_local_result(contextual_prompt, local_llm_execution)
|
|
276
|
+
requested_backend = request.llm
|
|
277
|
+
if should_prompt_for_embedded_install(model_plan, requested_backend=request.llm):
|
|
278
|
+
result = embedded_mini_brain_install_response(prompt, name=name, model_plan=model_plan)
|
|
279
|
+
return finalize_agent_session(result, session, prompt, backend="embedded-mini-brain")
|
|
280
|
+
if should_use_embedded_coordinator(model_plan, requested_backend=request.llm):
|
|
281
|
+
requested_backend = "embedded-mini-brain"
|
|
116
282
|
result = invoke_agent_prompt(
|
|
117
283
|
coordinator_prompt,
|
|
118
|
-
|
|
284
|
+
requested_backend,
|
|
119
285
|
public_name=name,
|
|
120
286
|
allow_fallback=not request.no_llm_fallback,
|
|
121
287
|
)
|
|
@@ -154,6 +320,32 @@ def run_agent_prompt_request(request: AgentPromptRequest) -> dict[str, Any]:
|
|
|
154
320
|
return finalize_agent_session(result, session, prompt, backend=result.get("llm_backend") or request.llm)
|
|
155
321
|
|
|
156
322
|
|
|
323
|
+
def should_use_embedded_coordinator(model_plan: dict[str, Any], *, requested_backend: str | None) -> bool:
|
|
324
|
+
if requested_backend:
|
|
325
|
+
return False
|
|
326
|
+
return (
|
|
327
|
+
model_plan.get("strategy") == "mini-brain"
|
|
328
|
+
and model_plan.get("local_llm_provider") == "embedded-mini-brain"
|
|
329
|
+
and model_plan.get("risk") == "low"
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def should_prompt_for_embedded_install(model_plan: dict[str, Any], *, requested_backend: str | None) -> bool:
|
|
334
|
+
if requested_backend:
|
|
335
|
+
return False
|
|
336
|
+
embedded = (
|
|
337
|
+
((model_plan.get("mini_brain") or {}).get("embedded") or {})
|
|
338
|
+
if isinstance(model_plan.get("mini_brain"), dict)
|
|
339
|
+
else {}
|
|
340
|
+
)
|
|
341
|
+
return (
|
|
342
|
+
model_plan.get("strategy") in {"mini-brain", "external-llm"}
|
|
343
|
+
and model_plan.get("local_llm_provider") == "embedded-mini-brain"
|
|
344
|
+
and embedded.get("available") is not True
|
|
345
|
+
and model_plan.get("fallback") == "configure-local-mini-brain-or-use-external-llm"
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
|
|
157
349
|
def mark_review_task_needs_review(execution_plan: dict[str, Any], review_result: dict[str, Any]) -> dict[str, Any]:
|
|
158
350
|
task = dict(execution_plan.get("review_task") or {})
|
|
159
351
|
if task:
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
|
+
import os
|
|
6
7
|
import platform
|
|
7
8
|
import shutil
|
|
8
9
|
import subprocess
|
|
@@ -10,17 +11,31 @@ import urllib.error
|
|
|
10
11
|
import urllib.request
|
|
11
12
|
from typing import Any
|
|
12
13
|
|
|
14
|
+
from cli.aikit.app_home import config_path
|
|
15
|
+
|
|
13
16
|
|
|
14
17
|
OLLAMA_TIMEOUT_SECONDS = 120
|
|
15
18
|
DEFAULT_BASE_URL = "http://localhost:11434"
|
|
19
|
+
DEFAULT_RECOMMENDED_MODELS = [
|
|
20
|
+
{"name": "qwen3:0.6b", "family": "mini-brain", "recommended_for": "setup help, short summaries and lightweight intent classification"},
|
|
21
|
+
{"name": "qwen2.5-coder", "family": "coding", "recommended_for": "operational code reading and generation"},
|
|
22
|
+
{"name": "deepseek-coder", "family": "coding", "recommended_for": "code analysis and mechanical refactors"},
|
|
23
|
+
{"name": "deepseek-r1", "family": "reasoning", "recommended_for": "local reasoning drafts with mandatory review"},
|
|
24
|
+
{"name": "llama3.2", "family": "general", "recommended_for": "general local summaries and classification"},
|
|
25
|
+
{"name": "mistral", "family": "general", "recommended_for": "lightweight operational summaries"},
|
|
26
|
+
{"name": "gemma", "family": "classification", "recommended_for": "small extraction and classification tasks"},
|
|
27
|
+
]
|
|
16
28
|
|
|
17
29
|
|
|
18
30
|
def ollama_status(*, base_url: str = DEFAULT_BASE_URL) -> dict[str, Any]:
|
|
31
|
+
base_url = os.environ.get("OLLAMA_BASE_URL") or base_url
|
|
19
32
|
binary = shutil.which("ollama")
|
|
20
33
|
version = command_output(["ollama", "--version"]) if binary else None
|
|
21
34
|
daemon = daemon_status(base_url) if binary else {"status": "unknown", "message": "Ollama binary is not installed."}
|
|
22
35
|
models = list_local_models(binary_available=bool(binary))
|
|
23
|
-
status = "
|
|
36
|
+
status = "missing"
|
|
37
|
+
if binary:
|
|
38
|
+
status = "ok" if daemon.get("status") == "ok" else "partial"
|
|
24
39
|
return {
|
|
25
40
|
"kind": "ollama-status",
|
|
26
41
|
"status": status,
|
|
@@ -52,10 +67,12 @@ def ollama_pull(model: str | None, *, yes: bool = False, dry_run: bool = False)
|
|
|
52
67
|
binary = shutil.which("ollama")
|
|
53
68
|
command = ["ollama", "pull", model]
|
|
54
69
|
if dry_run or not yes:
|
|
70
|
+
needs_confirmation = not dry_run and not yes
|
|
55
71
|
return {
|
|
56
72
|
"kind": "ollama-pull",
|
|
57
73
|
"status": "planned" if dry_run else "needs-confirmation",
|
|
58
74
|
"ok": bool(dry_run),
|
|
75
|
+
"exit_code": 2 if needs_confirmation else 0,
|
|
59
76
|
"model": model,
|
|
60
77
|
"binary": binary,
|
|
61
78
|
"command": command,
|
|
@@ -91,10 +108,12 @@ def ollama_pull(model: str | None, *, yes: bool = False, dry_run: bool = False)
|
|
|
91
108
|
def ollama_update(*, yes: bool = False, dry_run: bool = False) -> dict[str, Any]:
|
|
92
109
|
command = update_command()
|
|
93
110
|
if dry_run or not yes:
|
|
111
|
+
needs_confirmation = not dry_run and not yes
|
|
94
112
|
return {
|
|
95
113
|
"kind": "ollama-update",
|
|
96
114
|
"status": "planned" if dry_run else "needs-confirmation",
|
|
97
115
|
"ok": bool(dry_run),
|
|
116
|
+
"exit_code": 2 if needs_confirmation else 0,
|
|
98
117
|
"command": command,
|
|
99
118
|
"dry_run": dry_run,
|
|
100
119
|
"yes": yes,
|
|
@@ -142,26 +161,56 @@ def parse_ollama_list(output: str) -> list[dict[str, Any]]:
|
|
|
142
161
|
|
|
143
162
|
|
|
144
163
|
def recommended_models(*, installed: set[str]) -> list[dict[str, Any]]:
|
|
145
|
-
catalog =
|
|
146
|
-
("qwen3:0.6b", "mini-brain", "setup help, short summaries and lightweight intent classification"),
|
|
147
|
-
("qwen2.5-coder", "coding", "operational code reading and generation"),
|
|
148
|
-
("deepseek-coder", "coding", "code analysis and mechanical refactors"),
|
|
149
|
-
("deepseek-r1", "reasoning", "local reasoning drafts with mandatory review"),
|
|
150
|
-
("llama3.2", "general", "general local summaries and classification"),
|
|
151
|
-
("mistral", "general", "lightweight operational summaries"),
|
|
152
|
-
("gemma", "classification", "small extraction and classification tasks"),
|
|
153
|
-
]
|
|
164
|
+
catalog = model_catalog()
|
|
154
165
|
return [
|
|
155
166
|
{
|
|
156
|
-
"name": name,
|
|
157
|
-
"family": family,
|
|
158
|
-
"recommended_for": recommended_for,
|
|
159
|
-
"installed": any(
|
|
167
|
+
"name": item["name"],
|
|
168
|
+
"family": item["family"],
|
|
169
|
+
"recommended_for": item["recommended_for"],
|
|
170
|
+
"installed": any(model == item["name"] or model.startswith(f"{item['name']}:") for model in installed),
|
|
171
|
+
"source": item["source"],
|
|
160
172
|
}
|
|
161
|
-
for
|
|
173
|
+
for item in catalog
|
|
162
174
|
]
|
|
163
175
|
|
|
164
176
|
|
|
177
|
+
def model_catalog() -> list[dict[str, str]]:
|
|
178
|
+
items = {item["name"]: {**item, "source": "default"} for item in DEFAULT_RECOMMENDED_MODELS}
|
|
179
|
+
for item in configured_model_catalog():
|
|
180
|
+
name = str(item.get("name") or "").strip()
|
|
181
|
+
if not name:
|
|
182
|
+
continue
|
|
183
|
+
items[name] = {
|
|
184
|
+
"name": name,
|
|
185
|
+
"family": str(item.get("family") or "custom").strip() or "custom",
|
|
186
|
+
"recommended_for": str(item.get("recommended_for") or item.get("purpose") or "configured local model").strip(),
|
|
187
|
+
"source": "config",
|
|
188
|
+
}
|
|
189
|
+
return list(items.values())
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def configured_model_catalog() -> list[dict[str, Any]]:
|
|
193
|
+
path = config_path()
|
|
194
|
+
if not path.exists():
|
|
195
|
+
return []
|
|
196
|
+
try:
|
|
197
|
+
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
198
|
+
except (OSError, json.JSONDecodeError):
|
|
199
|
+
return []
|
|
200
|
+
if not isinstance(payload, dict):
|
|
201
|
+
return []
|
|
202
|
+
local_llm = payload.get("local_llm") if isinstance(payload.get("local_llm"), dict) else {}
|
|
203
|
+
mini_brain = payload.get("mini_brain") if isinstance(payload.get("mini_brain"), dict) else {}
|
|
204
|
+
for value in (
|
|
205
|
+
local_llm.get("recommended_models"),
|
|
206
|
+
local_llm.get("models"),
|
|
207
|
+
mini_brain.get("recommended_models"),
|
|
208
|
+
):
|
|
209
|
+
if isinstance(value, list):
|
|
210
|
+
return [item for item in value if isinstance(item, dict)]
|
|
211
|
+
return []
|
|
212
|
+
|
|
213
|
+
|
|
165
214
|
def daemon_status(base_url: str) -> dict[str, Any]:
|
|
166
215
|
url = base_url.rstrip("/") + "/api/tags"
|
|
167
216
|
try:
|