Metadata-Version: 2.4
Name: ahr
Version: 0.1.0
Summary: Agent Harness Runtime — standalone Agent runtime with TUI, MCP, and streaming support
Author: Jiang Yingjin
License-Expression: MIT
Project-URL: Homepage, https://github.com/JiangYingjin/ahr
Project-URL: Repository, https://github.com/JiangYingjin/ahr
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: httpx
Requires-Dist: mcp
Requires-Dist: rich
Requires-Dist: tqdm
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-asyncio; extra == "dev"
Requires-Dist: ruff; extra == "dev"

# Agent Harness Runtime

轻量级 Agent 引擎。一条命令或两行代码即可启动 LLM Agent。

```
ahr run "查一下 SKHY 最新股价"
```

```python
from ahr import Agent
print(Agent().run("查一下 SKHY 最新股价").output)
```

## 快速开始

```bash
pip install ahr
ahr run "你好"
```

或配置 API key 后：

```bash
# 方式一：环境变量
export OPENAI_API_KEY=sk-...
export OPENAI_API_BASE=https://your-api.com/v1
export MODEL_NAME=your-model
ahr run "1+2=?"

# 方式二：配置文件 ~/.config/ahr/config.json
cat > ~/.config/ahr/config.json <<'EOF'
{"OPENAI_API_KEY": "sk-...", "OPENAI_API_BASE": "https://...", "MODEL_NAME": "your-model"}
EOF

# 方式三：.env 文件（优先级：shell env > .env > config.json）
```

## 外部引用 — 最简用法

```python
from ahr import Agent, tool

# 一行
result = Agent().run("1+2=?")
print(result.output)

# 多轮对话
agent = Agent()
agent.run("我的名字是张三")
agent.run("我叫什么名字？")      # 记得
agent.close()

# 并行任务
results = Agent().batch(["task1", "task2", "task3"], workers=3)

# 持久化到文件
agent = Agent(journal=True)
agent.run("重要任务")             # 自动写入 events.jsonl + meta.json
agent.close()

# 自定义工具
@tool
def get_weather(city: str) -> str:
    """查城市天气。

    Args:
        city: 城市名
    """
    return f"{city}: 25°C"

with Agent(tools=[get_weather]) as a:
    print(a.run("北京天气").output)
```

## 三层架构

| 类 | 位置 | 职责 | 隐喻 |
|---|------|------|------|
| `Agent` | `ahr.Agent` | public sync 入口 | 方向盘 |
| `Runtime` | `runtime.Runtime` | async 生命周期管理 | 驾驶座 |
| `Engine` | `runtime.core.agent.Engine` | 内部 ReAct 循环 | 发动机 |

## CLI

```bash
ahr run "task"                 # 执行任务（自动持久化 events.jsonl）
ahr tui                        # 交互式 REPL
ahr ps                         # 列出所有运行
ahr show <run_id>              # 查看运行详情
ahr debug config               # 检查配置
```

## 测试

```bash
pytest                           # 108 确定性测试
pytest --smoke=only              # 真实 LLM 端到端测试
pytest tests/unit/               # 纯逻辑测试
pytest tests/integration/        # Engine + MockLLMClient
```

## 项目结构

```
ahr/                              CLI + Public API
├── __init__.py                   Agent, AgentResult, run, tool, 内建工具
├── api.py                        Agent sync 包装器
├── cli.py                        argparse 入口
├── cmd_run.py                    run / resume / fork
├── cmd_ps.py                     ps
├── cmd_show.py                   show
├── cmd_approval.py               approve / reject
├── cmd_stop.py                   stop
├── cmd_debug.py                  debug
└── tui.py                       交互式 REPL（rich）

runtime/                          Agent 引擎（零 ahr 反向依赖）
├── runtime.py                    Runtime async facade
├── factory.py                    build_runtime / build_agent 构建器
├── settings.py                   Settings 数据类（零 import-time 副作用）
├── context.py                    ContextManager + SlidingWindow
├── toolkit.py                    ToolExecutor + HookPipeline
├── skills.py                     技能发现
├── guardrails.py                 输入/输出护栏
├── core/
│   ├── agent.py                  Engine — 核心 ReAct 循环
│   ├── consumer.py               EventConsumer + Printer Protocol（UI 输出解耦）
│   ├── llm.py                    LLMClient（stream/invoke）
│   └── types.py                  消息类型 + @tool 装饰器 + AgentResult
├── events/
│   ├── schema.py                 5 种事件 dataclass
│   ├── protocol.py               EventSink 协议
│   ├── recorder.py               EventRecorder + reconstruct_state
│   ├── store.py                  运行目录 / meta / 用量聚合
│   └── runs.py                   run / resume / fork 会话生命周期
└── tools/
    ├── __init__.py               default_tools()（file + shell + web_search + MCP）
    ├── builtin/                  file_ops, code_exec, web_search, task
    └── mcp/                      MCP 客户端（JSON-RPC 2.0 over stdio/HTTP）

tests/
├── unit/                         纯逻辑（~51 测试）
├── integration/                  Engine + MockLLMClient（~65 测试）
└── smoke/                        真实 LLM（1 测试）
```
