-
Notifications
You must be signed in to change notification settings - Fork 2
Terminal API Reference
AceGuru-mjh edited this page Oct 1, 2026
·
4 revisions
📑 本页目录
终端对外暴露一套**冻结于 P60(API Version 1.0)**的公共 API。来源
docs/terminal-api.md。 冻结规则:允许 ADD(可选字段/新能力),谨慎改语义,禁止删除 API / 改参数含义 / 向 Agent 暴露 PID、PTY、Process。
Agent → Terminal(root)→ TerminalSession → JobHandle / Observation / Input
Agent 永不接触 PTY、PID、ProcessHandle、TerminalCore、ObservationEngine、
SessionManager、JobManager、RecoveryCoordinator。
flowchart LR
A["terminal.createSession(SessionRequest)"] --> B["TerminalSession"]
B --> C["session.execute(ExecutionRequest) → JobHandle"]
C --> D["session.observe(ObservationRequest) → ObservationResult"]
D --> E["session.sendInput(TerminalInput)"]
E --> F["job.await() → JobResult"]
F --> G["session.close()(幂等)"]
| 方法 | 返回 | 说明 |
|---|---|---|
createSession(SessionRequest) |
Result<TerminalSession> |
创建 workspace 与会话 |
getSession(SessionId) |
TerminalSession? |
取回会话 |
listSessions() |
List<SessionSummary> |
全部活跃会话 |
shutdown() |
Result<Unit> |
关闭全部 |
capabilities() |
TerminalCapabilities |
后端能力 |
apiVersion() |
String |
恒为 "1.0"
|
| 方法 | 返回 | 说明 |
|---|---|---|
execute(ExecutionRequest) |
Result<JobHandle> |
非阻塞 |
sendInput(TerminalInput) |
Result<Unit> |
写入 PTY |
observe(ObservationRequest) |
Result<ObservationResult> |
增量观察 |
snapshot() |
SessionSnapshot |
全量状态 |
resize(TerminalSize) |
Result<Unit> |
PTY + VT + Screen 同步 |
stop() |
Result<Unit> |
停 job,会话仍存活 |
close() |
Result<Unit> |
幂等,完整清理 |
| 方法 | 说明 |
|---|---|
cancel() |
请求停止(CANCELLING → CANCELLED) |
snapshot() |
不可变 JobSnapshot
|
await() |
阻塞至终止。取消 await ≠ 取消 Job |
统一 TerminalError(code, message, retryable) —— Agent 按 code 匹配,不要匹配 message。
| code | 可重试 | 含义 |
|---|---|---|
SESSION_NOT_FOUND |
❌ | 会话不存在 |
SESSION_NOT_RUNNING |
❌ | 会话非运行态 |
SESSION_ALREADY_CLOSED |
❌ | 已关闭(幂等 close 返回成功) |
JOB_NOT_FOUND |
❌ | job 不存在 |
TIMEOUT |
✅ | 超时 |
CANCELLED |
❌ | 已取消 |
BACKEND_UNAVAILABLE |
✅ | 后端不可用 |
CURSOR_EXPIRED |
✅ | 观察游标过旧 → 调 snapshot() 重新同步 |
INVALID_CURSOR |
❌ | 游标来自别的 session |
UNSUPPORTED |
❌ | 后端无此能力 |
| 调用 | 返回 |
|---|---|
observe(cursor = null) |
ObservationResult.Snapshot(全量) |
observe(cursor = "abc") |
ObservationResult.Delta(增量) |
observe(cursor = "expired") |
ObservationResult.CursorExpired(需重新同步) |
Caution
游标是不透明字符串:Agent 禁止解析、禁止跨 session 使用。
-
Terminal/TerminalSession/JobHandle线程安全(任意线程/协程); -
TerminalSnapshot及所有公开模型不可变,可安全共享; - 回调在独立 dispatcher 派发,绝不在持锁时执行;
- 顺序固定:状态变更 → 事件入队 → 释放锁 → 派发回调。
| 后端 | id | 实现 |
|---|---|---|
LocalShellBackend |
"local" |
forkpty + execv("/system/bin/sh", "-i")
|
LinuxPRootBackend |
"linux-ubuntu" |
forkpty + execv(libproot.so … /bin/bash -i)
|
- 默认
backendId = "local"; - Agent 通过
terminal.backends()发现后端(可用性READY/NEEDS_ROOTFS/FAILED), 通过terminal.ubuntu.install(幂等、可续传)供应 rootfs; - Agent 不需要知道当前是哪个后端 —— 换后端 = Agent 代码零改动;
- 会话元数据(
backendId/rootfsId/workspaceId/guestCwd/ binds)随会话持久化 (SessionRecordschema v3),崩溃恢复才能区分 local 与 Ubuntu 会话。
| 挂载 | 宿主路径 | guest 路径 |
|---|---|---|
| workspace | <filesDir>/linux/workspaces/<id>/ |
/workspace |
| user home | <filesDir>/linux/home/ |
/root |
规则:
- workspace id 正则
^[a-z0-9][a-z0-9_-]{0,63}$;未知但合法者自动创建(workspace-per-task 零摩擦); -
delete在有会话挂载时拒绝(需先 close); - guest
/root是宿主 bind,不在 rootfs 内 → 用户文件在 rootfs 换版后仍存活;首次使用从/etc/skel播种(或最小.bashrc兜底); - guest 环境携带
HOME=/rootUSER=rootLOGNAME=root; -
LOCAL 会话拒绝
workspaceId(InvalidInput,显式优于静默)。
s = terminal.createSession(SessionRequest(workingDirectory = "/sdcard"))
job = s.execute(ExecutionRequest(command = "echo hello"))
result = job.await()
assert result.exitInfo?.exitCode == 0
s.close() # 幂等
- 终端运行时 · SDK 边界 · Termux 能力矩阵
- Ubuntu 生命周期 · 终端性能
-
MCP 生态总览
新 - (沙箱 MCP · 官方 Hub · 逆向 Host · 门控语义)
- 终端运行时
- 终端 API 契约
- SDK 边界
- Termux 能力矩阵
- Ubuntu rootfs 供给
- Ubuntu 生命周期
- PRoot 二进制溯源
- VT100/ANSI 模拟器
- 终端性能
- 终端迁移
- 原生层 C++/JNI