A Unix-style CLI tool for interacting with LLMs. Supports provider/model configuration, session history, streaming output, and a single built-in tool (bash_exec) for local shell access. LLM can use this tool to discover commands and operate local resources.
- 单一内置工具:PAI 仅直接支持一个内置工具
bash_exec。LLM 通过这个工具发现命令/操作本地资源,保持工具链简洁。 - 双输出模式:同时提供人类可读输出(默认)和机器可解析输出(
--json/--stream --json)。--json实际只影响 stderr 的输出格式,stdout 始终是模型输出。 - Session 文件为 JSONL:会话历史以 JSONL 格式存储,每行一个消息对象,支持多模态内容。并发写入需保证"原子追加或失败"。
- 配置优先级明确:CLI 参数 > 环境变量 > 配置文件 > Provider 默认值。凭证来源同理。
- 日志按需生成:仅在指定
--log_file时写日志文件,格式固定为 Markdown,内容必须脱敏。
- LLM Interaction: Submit chat requests with support for multi-turn tool calls.
- Provider Management: Configure and manage multiple LLM providers and model aliases.
- Session Management: Maintain conversation history via JSONL session files.
- Tool Execution: Built-in
bash_exectool for local shell access.
- TypeScript + ESM (Node 20+)
- 构建: tsup (ESM, shebang banner)
- 测试: vitest (unit, pbt, fixtures)
- CLI 解析: commander
~/.config/pai/
└── default.json # Default config file (JSON, must contain schema_version)
- 可通过
--config <path>或PAI_CONFIG环境变量覆盖。 - 在多环境(dev/staging/prod)场景,推荐每个环境独立配置文件并通过
PAI_CONFIG选择。
- 配置文件格式为 JSON,必须包含
schema_version字段。 - provider 配置至少包含:
name、provider、认证信息引用(不要求明文)。
- CLI explicit args (
--config,--model,--system_instruction_text) - Environment variables (
PAI_CONFIG,PAI_LANG) - Default config file
- Provider defaults
- CLI args (
--set apiKey=...) - Environment variables
- Config file
TODO: 当前凭证以明文存储在配置文件中。未来考虑集成 OS keyring、1Password CLI 等统一 secret management 方案。
Manage providers and model aliases.
- 默认仅列出已配置 providers。
--all列出所有支持 providers(包含未配置项)。--json输出稳定数组结构。
JSON output: [{ "name": string, "provider": string, "configured": boolean, "models": string[] }]
--add同时支持新增或替换同名配置。- 参数校验:
--name非空;--provider必须在支持列表中;--set必须满足key=value格式。
- 删除指定名称配置;指定项不存在时返回可解析错误。
Submit a chat request (may contain multiple tool-call rounds). Supports stdin/pipe, session files, and streaming.
pai chat [prompt] [--model <name>] [flags...]
Core Args:
--model <name>— optional; falls back to provider'sdefaultModel, then first inmodelslist, then error--model_params '<json-string>'or--model_params_file <path>--system_instruction_text <text>or--system_instruction_file <path>(mutually exclusive)--user_input_text <text>(i.e. positional[prompt]) or--user_input_file <path>(mutually exclusive)--session_file <path>--no-append— disable writing results back to session--stream--json--log_file <path>— optional; write this turn's log to file (.md format)
Model params priority: --model_params > --model_params_file > provider default
stdin behavior (must be consistent):
- No stdin: use CLI args or session file only.
- stdin +
prompt: stdin as additional context. - stdin + no
prompt: stdin as user input.
当 --session_file 存在时:
- 若 session 第一条为
system:- 未提供系统指令参数:沿用该条;
- 提供系统指令参数:覆盖该条。
- 若 session 不含首条
system:采用 CLI/文件输入。
- 若 session 最后一条为
user:- 未提供 user 输入参数:沿用该条;
- 提供 user 输入参数:覆盖该条。
- 若 session 不含末条
user:采用 CLI/文件/stdin 输入。
覆盖语义统一定义为"替换目标消息内容,不保留旧内容"。
stdout: Final result text or streamable result increments.stderr: Progress, debug, meta-events, warnings.- 用户若要获得完整回答,必须读取
stdout全量内容。 - 敏感信息(API key、token、secret 原文)不得输出到 stdout/stderr。
- Without
--json: human-readable output. - With
--json: machine-parseable output.
对于 stdout: 输出总是模型的输出,和 --json 参数无关。
因此 --json 参数实际只影响 stderr 的输出格式:
- 有
--json时,stderr 输出为 NDJSON 行的事件流。 - 无
--json时,stderr 输出为人类可读的文本行事件流。
--stream 参数主要影响:
- 内部调用 LLM 时是否使用流式 API;
- stderr 进度事件是否实时输出。
stdout 始终以流式方式写出(process.stdout.write)。当 LLM 以流式返回时,stdout 为真流式;当 LLM 以非流式返回时,stdout 为"假流式"(一次性写出完整内容)。这不影响调用者行为,因为调用者总是需要读取到 EOF。
- 文件格式:JSONL(每行一个 JSON 对象)。
Message object required fields:
role:"system" | "user" | "assistant" | "tool"content:string | object | array
Optional fields: timestamp (ISO 8601), id
Content formats:
- Simple text: string, or
{ "type": "text", "text": "..." } - Multimodal:
{ "type": "image_url", "image_url": { "url": "https://..." } }
Write & concurrency:
- 指定
--session_file时,默认在调用成功后追加本轮assistant/tool消息。 - 可通过
--no-append禁用追加。 - 并发写入要求:实现需保证"原子追加或失败";锁竞争失败返回 IO 错误(退出码 4)。
Examples (single JSONL lines):
{"role":"system","content":"...","timestamp":"2026-03-11T12:00:00Z"}
{"role":"user","content":[{"type":"text","text":"what is in this image"},{"type":"image_url","image_url":{"url":"https://example.com/image.png"}}]}
JSON Schema (simplified):
{
"type": "object",
"required": ["role", "content"],
"properties": {
"role": { "type": "string", "enum": ["system", "user", "assistant", "tool"] },
"content": {},
"timestamp": { "type": "string", "format": "date-time" },
"id": { "type": "string" }
}
}| Code | Meaning |
|---|---|
0 |
Success |
1 |
Argument or usage error |
2 |
Local runtime error |
3 |
External API / provider error |
4 |
IO / file read-write error (including session append failure) |
- Default (no
--json): human-readable error tostderr. --json: error event tostderr(same NDJSON shape as other events), no success body onstdout.
Error event structure (unified with all stderr events):
{ "type": "error", "message": string, "context": object|null, "timestamp": number }
Args: --log_file <path> — enable per-turn log file.
Requirements:
- 仅在指定
--log_file时写日志文件。 - 日志文件格式固定为 Markdown(
.md)。 - 记录内容为本轮调用日志(请求参数摘要、关键事件、错误信息、结果摘要)。
- 日志内容必须脱敏,不得包含明文凭证。
| Variable | Description | Default |
|---|---|---|
PAI_CONFIG |
Config file path | ~/.config/pai/default.json |
PAI_LANG |
Output language preference | (system default) |