aizen-ai-cli 2.2.2__tar.gz → 2.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aizen_ai_cli-2.2.2/aizen_ai_cli.egg-info → aizen_ai_cli-2.2.3}/PKG-INFO +1 -1
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen/config.py +16 -16
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen/main.py +30 -37
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3/aizen_ai_cli.egg-info}/PKG-INFO +1 -1
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/pyproject.toml +1 -1
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/setup.py +1 -1
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/MANIFEST.in +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/README.md +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen/__init__.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen/commands.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen/context.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen/exceptions.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen/logging_config.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen/mcp.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen/plugins.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen/retry.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen/session.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen/tools.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen/utils.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen_ai_cli.egg-info/SOURCES.txt +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen_ai_cli.egg-info/dependency_links.txt +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen_ai_cli.egg-info/entry_points.txt +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen_ai_cli.egg-info/requires.txt +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/aizen_ai_cli.egg-info/top_level.txt +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/requirements.txt +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/setup.cfg +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/tests/test_commands.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/tests/test_config.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/tests/test_context.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/tests/test_main.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/tests/test_mcp.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/tests/test_session.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/tests/test_tools.py +0 -0
- {aizen_ai_cli-2.2.2 → aizen_ai_cli-2.2.3}/tests/test_utils.py +0 -0
|
@@ -3,12 +3,12 @@ import json
|
|
|
3
3
|
import logging
|
|
4
4
|
import os
|
|
5
5
|
import shutil
|
|
6
|
+
import ssl
|
|
6
7
|
import sys
|
|
7
8
|
import threading
|
|
8
9
|
import time
|
|
9
|
-
import urllib.request
|
|
10
10
|
import urllib.error
|
|
11
|
-
import
|
|
11
|
+
import urllib.request
|
|
12
12
|
from importlib.metadata import PackageNotFoundError
|
|
13
13
|
from importlib.metadata import version as _pkg_version
|
|
14
14
|
|
|
@@ -21,7 +21,7 @@ logger = logging.getLogger("aizen")
|
|
|
21
21
|
|
|
22
22
|
# Read version from installed package metadata (stays in sync with pyproject.toml).
|
|
23
23
|
# Falls back to a hardcoded value only when running from source without installing.
|
|
24
|
-
_FALLBACK_VERSION = "2.2.
|
|
24
|
+
_FALLBACK_VERSION = "2.2.3"
|
|
25
25
|
try:
|
|
26
26
|
VERSION = _pkg_version("aizen-ai-cli")
|
|
27
27
|
except PackageNotFoundError:
|
|
@@ -29,16 +29,16 @@ except PackageNotFoundError:
|
|
|
29
29
|
CONFIG_PATH = os.path.expanduser("~/.aizen_config.json")
|
|
30
30
|
SESSIONS_DIR = os.path.expanduser("~/.aizen_sessions")
|
|
31
31
|
BACKUPS_DIR = os.path.expanduser("~/.aizen_backups")
|
|
32
|
-
DEFAULT_MODEL = "
|
|
33
|
-
|
|
34
|
-
AIZEN_ASCII = r"""[bold
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
DEFAULT_MODEL = "openrouter/free"
|
|
33
|
+
|
|
34
|
+
AIZEN_ASCII = r"""[bold #ffabf3]
|
|
35
|
+
█████╗ ██╗███████╗███████╗███╗ ██╗
|
|
36
|
+
██╔══██╗██║╚══███╔╝██╔════╝████╗ ██║
|
|
37
|
+
███████║██║ ███╔╝ █████╗ ██╔██╗ ██║
|
|
38
|
+
██╔══██║██║ ███╔╝ ██╔══╝ ██║╚██╗██║
|
|
39
|
+
██║ ██║██║███████╗███████╗██║ ╚████║
|
|
40
|
+
╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚═╝ ╚═══╝
|
|
41
|
+
[/bold #ffabf3]
|
|
42
42
|
"""
|
|
43
43
|
|
|
44
44
|
# Safe commands that auto-execute without confirmation
|
|
@@ -134,7 +134,7 @@ def build_system_prompt(config: dict | None = None) -> str:
|
|
|
134
134
|
f"The following rules are defined by the project maintainers "
|
|
135
135
|
f"(from {rules_file}):\n\n{project_rules}"
|
|
136
136
|
)
|
|
137
|
-
console.print(f"
|
|
137
|
+
console.print(f"[bold #ffabf3][SYSTEM][/bold #ffabf3] Project rules loaded from [#d3fbff]{rules_file}[/#d3fbff]")
|
|
138
138
|
break # Only use the first rules file found
|
|
139
139
|
except Exception as e:
|
|
140
140
|
logger.debug("Failed to load project rules from %s: %s", rules_file, e)
|
|
@@ -258,7 +258,7 @@ def _do_update_check(config: dict):
|
|
|
258
258
|
ctx.load_verify_locations(cafile=certifi.where())
|
|
259
259
|
except ImportError:
|
|
260
260
|
ctx = ssl._create_unverified_context()
|
|
261
|
-
|
|
261
|
+
|
|
262
262
|
url = "https://pypi.org/pypi/aizen-ai-cli/json"
|
|
263
263
|
req = urllib.request.Request(url, headers={"User-Agent": "aizen-ai-cli"})
|
|
264
264
|
with urllib.request.urlopen(req, timeout=3, context=ctx) as response:
|
|
@@ -329,7 +329,7 @@ def _do_fetch_models():
|
|
|
329
329
|
ctx.load_verify_locations(cafile=certifi.where())
|
|
330
330
|
except ImportError:
|
|
331
331
|
ctx = ssl._create_unverified_context()
|
|
332
|
-
|
|
332
|
+
|
|
333
333
|
req = urllib.request.Request("https://openrouter.ai/api/v1/models")
|
|
334
334
|
with urllib.request.urlopen(req, timeout=5, context=ctx) as response:
|
|
335
335
|
data = json.loads(response.read().decode())
|
|
@@ -14,15 +14,15 @@ import sys
|
|
|
14
14
|
from typing import Any
|
|
15
15
|
|
|
16
16
|
from openai import APIConnectionError as OpenAIConnectionError
|
|
17
|
-
from openai import APITimeoutError, AsyncOpenAI, AuthenticationError
|
|
17
|
+
from openai import APITimeoutError, AsyncOpenAI, AuthenticationError, BadRequestError
|
|
18
18
|
from openai import RateLimitError as OpenAIRateLimitError
|
|
19
19
|
from prompt_toolkit import PromptSession
|
|
20
20
|
from prompt_toolkit.filters import completion_is_selected, has_completions
|
|
21
|
-
from prompt_toolkit.formatted_text import
|
|
21
|
+
from prompt_toolkit.formatted_text import FormattedText
|
|
22
22
|
from prompt_toolkit.key_binding import KeyBindings
|
|
23
23
|
from rich.live import Live
|
|
24
24
|
from rich.markdown import Markdown
|
|
25
|
-
from rich.
|
|
25
|
+
from rich.spinner import Spinner
|
|
26
26
|
from rich.text import Text
|
|
27
27
|
|
|
28
28
|
from .commands import AizenCompleter, handle_slash_command
|
|
@@ -212,16 +212,12 @@ async def main_loop():
|
|
|
212
212
|
|
|
213
213
|
# ── Header ──
|
|
214
214
|
console.print(AIZEN_ASCII)
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
header.append(" │ ", style="dim")
|
|
218
|
-
header.append(get_active_model(), style="cyan")
|
|
215
|
+
console.print(f"[bold #ffabf3][SYSTEM][/bold #ffabf3] Initializing Aizen AI v{VERSION}...")
|
|
216
|
+
console.print(f"[bold #ffabf3][SYSTEM][/bold #ffabf3] Model: {get_active_model()}")
|
|
219
217
|
if auto_approve:
|
|
220
|
-
|
|
221
|
-
header.append("YOLO MODE", style="bold red")
|
|
222
|
-
console.print(header)
|
|
218
|
+
console.print("[bold #ffabf3][SYSTEM][/bold #ffabf3] Mode: YOLO")
|
|
223
219
|
console.print(
|
|
224
|
-
"[dim]Type /help for commands • @file to attach • exit to quit[/dim]\n"
|
|
220
|
+
"\n[dim]Type /help for commands • @file to attach • exit to quit[/dim]\n"
|
|
225
221
|
)
|
|
226
222
|
|
|
227
223
|
# ── Keybindings ──
|
|
@@ -239,10 +235,12 @@ async def main_loop():
|
|
|
239
235
|
try:
|
|
240
236
|
# ── Multi-line Input ──
|
|
241
237
|
lines = []
|
|
242
|
-
prompt_html =
|
|
243
|
-
"
|
|
244
|
-
"
|
|
245
|
-
|
|
238
|
+
prompt_html = FormattedText([
|
|
239
|
+
("fg:#ffabf3", "➜"),
|
|
240
|
+
("", " "),
|
|
241
|
+
("fg:#d3fbff", "~"),
|
|
242
|
+
("", " ")
|
|
243
|
+
])
|
|
246
244
|
first_line = await session.prompt_async(prompt_html)
|
|
247
245
|
lines.append(first_line)
|
|
248
246
|
|
|
@@ -250,7 +248,7 @@ async def main_loop():
|
|
|
250
248
|
while lines[-1].rstrip().endswith("\\"):
|
|
251
249
|
lines[-1] = lines[-1].rstrip()[:-1] # Remove trailing backslash
|
|
252
250
|
continuation = await session.prompt_async(
|
|
253
|
-
|
|
251
|
+
FormattedText([("", " ")])
|
|
254
252
|
)
|
|
255
253
|
lines.append(continuation)
|
|
256
254
|
|
|
@@ -346,9 +344,7 @@ async def main_loop():
|
|
|
346
344
|
"Exploring...",
|
|
347
345
|
]
|
|
348
346
|
)
|
|
349
|
-
spinner_display = Text()
|
|
350
|
-
spinner_display.append(" ✦ ", style="bold magenta")
|
|
351
|
-
spinner_display.append(spinner_label, style="dim italic")
|
|
347
|
+
spinner_display = Spinner("dots", text=Text(spinner_label, style="#8e8e93 italic"), style="#ffabf3 bold")
|
|
352
348
|
|
|
353
349
|
try:
|
|
354
350
|
with Live(
|
|
@@ -378,23 +374,14 @@ async def main_loop():
|
|
|
378
374
|
full_content += delta.content
|
|
379
375
|
# Live-render Markdown in a panel
|
|
380
376
|
try:
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
border_style="magenta",
|
|
385
|
-
padding=(1, 2),
|
|
386
|
-
)
|
|
377
|
+
# Prepend AIZEN: styling before the markdown
|
|
378
|
+
display_content = f"**AIZEN:** {full_content}"
|
|
379
|
+
rendered = Markdown(display_content)
|
|
387
380
|
live.update(rendered)
|
|
388
381
|
except Exception:
|
|
389
382
|
# Fallback for incomplete markdown
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
Text(full_content),
|
|
393
|
-
title="[bold magenta]✦ Aizen[/bold magenta]",
|
|
394
|
-
border_style="magenta",
|
|
395
|
-
padding=(1, 2),
|
|
396
|
-
)
|
|
397
|
-
)
|
|
383
|
+
display_text = Text.from_markup(f"[bold #ffabf3]AIZEN:[/bold #ffabf3] {full_content}")
|
|
384
|
+
live.update(display_text)
|
|
398
385
|
|
|
399
386
|
# ── Tool call tokens ──
|
|
400
387
|
if delta.tool_calls:
|
|
@@ -427,10 +414,9 @@ async def main_loop():
|
|
|
427
414
|
]
|
|
428
415
|
if names and not full_content:
|
|
429
416
|
tool_text = Text()
|
|
430
|
-
tool_text.append("
|
|
417
|
+
tool_text.append("AIZEN: ", style="bold #ffabf3")
|
|
431
418
|
tool_text.append(
|
|
432
|
-
f"
|
|
433
|
-
style="dim italic",
|
|
419
|
+
f"Invoking [#d3fbff]{', '.join(names)}[/#d3fbff]...",
|
|
434
420
|
)
|
|
435
421
|
live.update(tool_text)
|
|
436
422
|
|
|
@@ -470,8 +456,15 @@ async def main_loop():
|
|
|
470
456
|
"[dim]Hint: Check your internet connection or API base URL.[/dim]"
|
|
471
457
|
)
|
|
472
458
|
break
|
|
459
|
+
except BadRequestError as e:
|
|
460
|
+
logger.error("Bad request to API: %s", e)
|
|
461
|
+
console.print(f"\n[bold red]Bad Request Error:[/bold red] {e}")
|
|
462
|
+
console.print(
|
|
463
|
+
"[dim]Hint: This usually means the model ID is invalid or the context length was exceeded.[/dim]"
|
|
464
|
+
)
|
|
465
|
+
break
|
|
473
466
|
except Exception as e:
|
|
474
|
-
logger.
|
|
467
|
+
logger.error("Unexpected API error: %s", e)
|
|
475
468
|
console.print(f"\n[bold red]API Error:[/bold red] {e}")
|
|
476
469
|
error_str = str(e).lower()
|
|
477
470
|
if "401" in error_str or "unauthorized" in error_str:
|
|
@@ -8,7 +8,7 @@ def parse_requirements(filename):
|
|
|
8
8
|
|
|
9
9
|
setup(
|
|
10
10
|
name="aizen-ai-cli",
|
|
11
|
-
version="2.2.
|
|
11
|
+
version="2.2.3",
|
|
12
12
|
description="Aizen AI Agent — A professional-grade AI coding assistant for your terminal.",
|
|
13
13
|
packages=["aizen"],
|
|
14
14
|
install_requires=parse_requirements("requirements.txt"),
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|