from __future__ import annotations
import json
import os
import re
import subprocess
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[2]
ANSI_ESCAPE_RE = re.compile(r"\x1b\[[0-9;?]*[ -/]*[@-~]")
def _msagent_command() -> list[str]:
source_command = [sys.executable, str(PROJECT_ROOT / "run.py")]
script_dir = Path(sys.executable).parent
candidates = [
script_dir / "msagent",
script_dir / "msagent.exe",
script_dir / "msagent.cmd",
script_dir / "msagent.bat",
]
if os.environ.get("MSAGENT_E2E_USE_INSTALLED", "").strip().lower() not in {"1", "true", "yes"}:
return source_command
for candidate in candidates:
if candidate.exists():
return [str(candidate)]
return source_command
def _run_msagent(*args: str, cwd: Path, env: dict[str, str] | None = None) -> subprocess.CompletedProcess[str]:
merged_env = os.environ.copy()
merged_env["PYTHONIOENCODING"] = "utf-8"
if env:
merged_env.update(env)
return subprocess.run(
[*_msagent_command(), *args],
cwd=str(cwd),
env=merged_env,
capture_output=True,
text=True,
encoding="utf-8",
errors="replace",
timeout=60,
check=False,
)
def _normalize_terminal_output(content: str) -> str:
return ANSI_ESCAPE_RE.sub("", content).replace("\r", "")
def _read_jsonl(path: Path) -> list[dict]:
return [json.loads(line) for line in path.read_text(encoding="utf-8").splitlines() if line.strip()]
def test_entrypoint_version_and_config_show(tmp_path: Path) -> None:
version = _run_msagent("--version", cwd=PROJECT_ROOT)
assert version.returncode == 0
assert "msAgent" in version.stdout
config = _run_msagent("config", "--show", "-w", str(tmp_path), cwd=PROJECT_ROOT)
assert config.returncode == 0
assert "Current Configuration" in config.stdout
assert "LLM Provider" in config.stdout
def test_entrypoint_one_shot_tool_call_and_todo_render(tmp_path: Path) -> None:
env = {"MSAGENT_FAKE_BACKEND": "1"}
tool = _run_msagent(
"-w",
str(tmp_path),
"please run one tool call",
cwd=PROJECT_ROOT,
env=env,
)
assert tool.returncode == 0
tool_stdout = _normalize_terminal_output(tool.stdout)
assert "Use tool run_command" in tool_stdout
assert "fake-tool-output" in tool_stdout
todo = _run_msagent(
"-w",
str(tmp_path),
"please update todo list",
cwd=PROJECT_ROOT,
env=env,
)
assert todo.returncode == 0
todo_stdout = _normalize_terminal_output(todo.stdout)
assert "TODOs" in todo_stdout
assert "Review profile bottleneck" in todo_stdout
def test_entrypoint_trace_jsonl_records_tools_tokens_and_time(tmp_path: Path) -> None:
trace_path = tmp_path / "msagent.events.jsonl"
result = _run_msagent(
"--no-stream",
"--trace-jsonl",
str(trace_path),
"-w",
str(tmp_path),
"please run one tool call",
cwd=PROJECT_ROOT,
env={"MSAGENT_FAKE_BACKEND": "1"},
)
assert result.returncode == 0
events = _read_jsonl(trace_path)
assert [event["type"] for event in events][:2] == ["session_started", "token_usage"]
tool_call = next(event for event in events if event["type"] == "tool_call")
assert tool_call["tool"] == "run_command"
assert tool_call["input"] == {"command": "echo fake-tool-output"}
tool_result = next(event for event in events if event["type"] == "tool_result")
assert tool_result["tool"] == "run_command"
assert tool_result["item_id"] == "call-tool-1"
assert tool_result["duration_ms"] == 500
finished = events[-1]
assert finished["type"] == "session_finished"
assert finished["duration_ms"] >= 0
assert finished["token_usage"] == {
"available": True,
"source": "msagent-cli-jsonl",
"input_tokens": 105,
"output_tokens": 14,
"total_tokens": 119,
}