agencode 0.1.0__py3-none-any.whl
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.
- agencli/__init__.py +5 -0
- agencli/__main__.py +9 -0
- agencli/agents/__init__.py +1 -0
- agencli/agents/editor.py +110 -0
- agencli/agents/factory.py +335 -0
- agencli/agents/management_tools.py +277 -0
- agencli/agents/prebuilt/__init__.py +1 -0
- agencli/agents/prebuilt/catalog.py +66 -0
- agencli/agents/registry.py +50 -0
- agencli/agents/runtime.py +266 -0
- agencli/agents/supervisor.py +67 -0
- agencli/cli.py +561 -0
- agencli/core/__init__.py +1 -0
- agencli/core/config.py +179 -0
- agencli/core/keystore.py +14 -0
- agencli/core/logger.py +17 -0
- agencli/core/paths.py +37 -0
- agencli/core/session.py +513 -0
- agencli/mcp/__init__.py +1 -0
- agencli/mcp/client.py +33 -0
- agencli/mcp/config.py +99 -0
- agencli/providers/__init__.py +1 -0
- agencli/providers/model.py +180 -0
- agencli/skills/__init__.py +37 -0
- agencli/skills/cli_backend.py +446 -0
- agencli/skills/loader.py +77 -0
- agencli/skills/manager.py +153 -0
- agencli/tools/__init__.py +1 -0
- agencli/tools/mcp.py +106 -0
- agencli/tui/__init__.py +1 -0
- agencli/tui/app.py +4274 -0
- agencli/tui/commands.py +86 -0
- agencli/tui/screens.py +939 -0
- agencli/tui/trace.py +334 -0
- agencli/tui/voice.py +77 -0
- agencode-0.1.0.dist-info/METADATA +44 -0
- agencode-0.1.0.dist-info/RECORD +39 -0
- agencode-0.1.0.dist-info/WHEEL +4 -0
- agencode-0.1.0.dist-info/entry_points.txt +3 -0
agencli/core/config.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import asdict, dataclass, field
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import tomllib
|
|
6
|
+
|
|
7
|
+
import tomli_w
|
|
8
|
+
|
|
9
|
+
from agencli.core.keystore import OPENAI_COMPATIBLE_API_KEY, get_secret, set_secret
|
|
10
|
+
from agencli.core.paths import AgenCLIPaths, default_paths, ensure_dirs
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(slots=True)
|
|
14
|
+
class OpenAICompatibleConfig:
|
|
15
|
+
provider_name: str = "openai-compatible"
|
|
16
|
+
base_url: str = ""
|
|
17
|
+
model: str = ""
|
|
18
|
+
model_kind: str = "chat"
|
|
19
|
+
api_key_env: str = "OPENAI_API_KEY"
|
|
20
|
+
api_key_name: str = OPENAI_COMPATIBLE_API_KEY
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _infer_api_key_env(provider_name: str, base_url: str, configured_env: str | None = None) -> str:
|
|
24
|
+
if configured_env:
|
|
25
|
+
return configured_env
|
|
26
|
+
|
|
27
|
+
lowered_provider = provider_name.lower()
|
|
28
|
+
lowered_base_url = base_url.lower()
|
|
29
|
+
if "deepseek" in lowered_provider or "deepseek" in lowered_base_url:
|
|
30
|
+
return "DEEPSEEK_API_KEY"
|
|
31
|
+
return "OPENAI_API_KEY"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(slots=True)
|
|
35
|
+
class AgenCLIConfig:
|
|
36
|
+
default_model: str = "openai:gpt-4.1"
|
|
37
|
+
log_level: str = "INFO"
|
|
38
|
+
workspace_dir: str = ""
|
|
39
|
+
sessions_dir: str = ""
|
|
40
|
+
agents_dir: str = ""
|
|
41
|
+
skills_dir: str = ""
|
|
42
|
+
mcp_config_path: str = ""
|
|
43
|
+
shell_personality: str = "concise"
|
|
44
|
+
approval_mode: str = "confirm"
|
|
45
|
+
plan_mode: bool = False
|
|
46
|
+
skills_last_query: str = ""
|
|
47
|
+
skills_install_scope: str = "global"
|
|
48
|
+
openai_compatible: OpenAICompatibleConfig = field(default_factory=OpenAICompatibleConfig)
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def from_paths(cls, paths: AgenCLIPaths) -> "AgenCLIConfig":
|
|
52
|
+
return cls(
|
|
53
|
+
workspace_dir=str(paths.workspace_dir),
|
|
54
|
+
sessions_dir=str(paths.sessions_dir),
|
|
55
|
+
agents_dir=str(paths.agents_dir),
|
|
56
|
+
skills_dir=str(paths.skills_dir),
|
|
57
|
+
mcp_config_path=str(paths.mcp_file),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _from_legacy_config(raw: dict, paths: AgenCLIPaths) -> AgenCLIConfig:
|
|
62
|
+
core = raw.get("core", {})
|
|
63
|
+
providers = raw.get("providers", {})
|
|
64
|
+
default_provider = core.get("default_provider", "openai")
|
|
65
|
+
provider_model = providers.get(default_provider, {}).get("model", "")
|
|
66
|
+
selected_provider = providers.get(default_provider, {})
|
|
67
|
+
return AgenCLIConfig(
|
|
68
|
+
default_model=core.get("default_model", provider_model or "openai:gpt-4.1"),
|
|
69
|
+
log_level=core.get("log_level", "INFO"),
|
|
70
|
+
workspace_dir=core.get("workspace_dir", str(paths.workspace_dir)),
|
|
71
|
+
sessions_dir=core.get("session_dir", str(paths.sessions_dir)),
|
|
72
|
+
agents_dir=raw.get("agents_dir", str(paths.agents_dir)),
|
|
73
|
+
skills_dir=raw.get("skills_dir", str(paths.skills_dir)),
|
|
74
|
+
mcp_config_path=raw.get("mcp_config_path", str(paths.mcp_file)),
|
|
75
|
+
skills_last_query=raw.get("skills_last_query", ""),
|
|
76
|
+
skills_install_scope=raw.get("skills_install_scope", "global"),
|
|
77
|
+
openai_compatible=OpenAICompatibleConfig(
|
|
78
|
+
provider_name=default_provider,
|
|
79
|
+
base_url=selected_provider.get("base_url", ""),
|
|
80
|
+
model=provider_model or core.get("default_model", ""),
|
|
81
|
+
model_kind=selected_provider.get("model_kind", "chat"),
|
|
82
|
+
api_key_env=_infer_api_key_env(
|
|
83
|
+
default_provider,
|
|
84
|
+
selected_provider.get("base_url", ""),
|
|
85
|
+
selected_provider.get("api_key_env"),
|
|
86
|
+
),
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _from_modern_config(raw: dict) -> AgenCLIConfig:
|
|
92
|
+
openai_compatible_raw = raw.get("openai_compatible", {})
|
|
93
|
+
return AgenCLIConfig(
|
|
94
|
+
default_model=raw.get("default_model", "openai:gpt-4.1"),
|
|
95
|
+
log_level=raw.get("log_level", "INFO"),
|
|
96
|
+
workspace_dir=raw.get("workspace_dir", ""),
|
|
97
|
+
sessions_dir=raw.get("sessions_dir", ""),
|
|
98
|
+
agents_dir=raw.get("agents_dir", ""),
|
|
99
|
+
skills_dir=raw.get("skills_dir", ""),
|
|
100
|
+
mcp_config_path=raw.get("mcp_config_path", ""),
|
|
101
|
+
skills_last_query=raw.get("skills_last_query", ""),
|
|
102
|
+
skills_install_scope=raw.get("skills_install_scope", "global"),
|
|
103
|
+
openai_compatible=OpenAICompatibleConfig(**openai_compatible_raw),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def ensure_config(root: Path | None = None, overwrite: bool = False) -> Path:
|
|
108
|
+
paths = ensure_dirs(default_paths(root))
|
|
109
|
+
if paths.config_file.exists() and not overwrite:
|
|
110
|
+
return paths.config_file
|
|
111
|
+
|
|
112
|
+
config = AgenCLIConfig.from_paths(paths)
|
|
113
|
+
paths.config_file.write_text(tomli_w.dumps(asdict(config)), encoding="utf-8")
|
|
114
|
+
return paths.config_file
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def load_config(config_path: Path | None = None) -> AgenCLIConfig:
|
|
118
|
+
if config_path is None:
|
|
119
|
+
config_path = ensure_config()
|
|
120
|
+
|
|
121
|
+
with config_path.open("rb") as handle:
|
|
122
|
+
raw = tomllib.load(handle)
|
|
123
|
+
|
|
124
|
+
root = config_path.parent
|
|
125
|
+
paths = ensure_dirs(default_paths(root))
|
|
126
|
+
|
|
127
|
+
if "core" in raw or "providers" in raw:
|
|
128
|
+
config = _from_legacy_config(raw, paths)
|
|
129
|
+
else:
|
|
130
|
+
config = _from_modern_config(raw)
|
|
131
|
+
|
|
132
|
+
defaults = AgenCLIConfig.from_paths(paths)
|
|
133
|
+
for field in ("workspace_dir", "sessions_dir", "agents_dir", "skills_dir", "mcp_config_path"):
|
|
134
|
+
if not getattr(config, field):
|
|
135
|
+
setattr(config, field, getattr(defaults, field))
|
|
136
|
+
|
|
137
|
+
return config
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def save_config(config: AgenCLIConfig, config_path: Path | None = None) -> Path:
|
|
141
|
+
if config_path is None:
|
|
142
|
+
config_path = ensure_config()
|
|
143
|
+
config_path.write_text(tomli_w.dumps(asdict(config)), encoding="utf-8")
|
|
144
|
+
return config_path
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def set_openai_compatible_provider(
|
|
148
|
+
*,
|
|
149
|
+
config_path: Path | None = None,
|
|
150
|
+
provider_name: str | None = None,
|
|
151
|
+
base_url: str | None = None,
|
|
152
|
+
model: str | None = None,
|
|
153
|
+
model_kind: str | None = None,
|
|
154
|
+
api_key: str | None = None,
|
|
155
|
+
api_key_env: str | None = None,
|
|
156
|
+
set_as_default: bool = True,
|
|
157
|
+
) -> AgenCLIConfig:
|
|
158
|
+
config = load_config(config_path)
|
|
159
|
+
provider = config.openai_compatible
|
|
160
|
+
if provider_name is not None:
|
|
161
|
+
provider.provider_name = provider_name
|
|
162
|
+
if base_url is not None:
|
|
163
|
+
provider.base_url = base_url
|
|
164
|
+
if model is not None:
|
|
165
|
+
provider.model = model
|
|
166
|
+
if model_kind is not None:
|
|
167
|
+
provider.model_kind = model_kind
|
|
168
|
+
if api_key_env is not None:
|
|
169
|
+
provider.api_key_env = api_key_env
|
|
170
|
+
if set_as_default and provider.model:
|
|
171
|
+
config.default_model = provider.model
|
|
172
|
+
save_config(config, config_path)
|
|
173
|
+
if api_key is not None:
|
|
174
|
+
set_secret(provider.api_key_name, api_key)
|
|
175
|
+
return config
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def get_openai_compatible_api_key(config: AgenCLIConfig) -> str | None:
|
|
179
|
+
return get_secret(config.openai_compatible.api_key_name)
|
agencli/core/keystore.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import keyring
|
|
4
|
+
|
|
5
|
+
SERVICE_NAME = "agencli"
|
|
6
|
+
OPENAI_COMPATIBLE_API_KEY = "openai_compatible_api_key"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def set_secret(name: str, value: str) -> None:
|
|
10
|
+
keyring.set_password(SERVICE_NAME, name, value)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_secret(name: str) -> str | None:
|
|
14
|
+
return keyring.get_password(SERVICE_NAME, name)
|
agencli/core/logger.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def configure_logging(level: str = "INFO") -> None:
|
|
7
|
+
logging.basicConfig(
|
|
8
|
+
level=getattr(logging, level.upper(), logging.INFO),
|
|
9
|
+
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
|
|
10
|
+
)
|
|
11
|
+
for noisy_logger in (
|
|
12
|
+
"httpx",
|
|
13
|
+
"httpcore",
|
|
14
|
+
"openai",
|
|
15
|
+
"langchain_openai",
|
|
16
|
+
):
|
|
17
|
+
logging.getLogger(noisy_logger).setLevel(logging.WARNING)
|
agencli/core/paths.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class AgenCLIPaths:
|
|
9
|
+
root: Path
|
|
10
|
+
config_file: Path
|
|
11
|
+
mcp_file: Path
|
|
12
|
+
agents_dir: Path
|
|
13
|
+
skills_dir: Path
|
|
14
|
+
sessions_dir: Path
|
|
15
|
+
workspace_dir: Path
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def default_paths(root: Path | None = None) -> AgenCLIPaths:
|
|
19
|
+
base = (root or (Path.home() / ".agencli")).expanduser()
|
|
20
|
+
return AgenCLIPaths(
|
|
21
|
+
root=base,
|
|
22
|
+
config_file=base / "config.toml",
|
|
23
|
+
mcp_file=base / "mcp.json",
|
|
24
|
+
agents_dir=base / "agents",
|
|
25
|
+
skills_dir=base / "skills",
|
|
26
|
+
sessions_dir=base / "sessions",
|
|
27
|
+
workspace_dir=base / "workspace",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def ensure_dirs(paths: AgenCLIPaths) -> AgenCLIPaths:
|
|
32
|
+
paths.root.mkdir(parents=True, exist_ok=True)
|
|
33
|
+
paths.agents_dir.mkdir(parents=True, exist_ok=True)
|
|
34
|
+
paths.skills_dir.mkdir(parents=True, exist_ok=True)
|
|
35
|
+
paths.sessions_dir.mkdir(parents=True, exist_ok=True)
|
|
36
|
+
paths.workspace_dir.mkdir(parents=True, exist_ok=True)
|
|
37
|
+
return paths
|