@agent-phonon/protocol 0.2.0

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.
Files changed (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +70 -0
  3. package/dist/index.d.ts +24 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +24 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/json-schema/_index.json +3794 -0
  8. package/dist/json-schema/connect.hello.json +117 -0
  9. package/dist/json-schema/discovery.changed.json +190 -0
  10. package/dist/json-schema/discovery.get.json +183 -0
  11. package/dist/json-schema/discovery.list.json +182 -0
  12. package/dist/json-schema/document.prepare_upload.json +96 -0
  13. package/dist/json-schema/document.send.json +165 -0
  14. package/dist/json-schema/hook.fired.json +100 -0
  15. package/dist/json-schema/hook.resolve.json +96 -0
  16. package/dist/json-schema/interaction.cancel.json +48 -0
  17. package/dist/json-schema/interaction.request.json +376 -0
  18. package/dist/json-schema/interaction.response.json +68 -0
  19. package/dist/json-schema/project.create.json +89 -0
  20. package/dist/json-schema/project.get.json +76 -0
  21. package/dist/json-schema/project.git.deleteBranch.json +64 -0
  22. package/dist/json-schema/project.list.json +72 -0
  23. package/dist/json-schema/project.remove.json +69 -0
  24. package/dist/json-schema/project.worktree.create.json +88 -0
  25. package/dist/json-schema/project.worktree.list.json +77 -0
  26. package/dist/json-schema/project.worktree.remove.json +61 -0
  27. package/dist/json-schema/session.compress.json +72 -0
  28. package/dist/json-schema/session.create.json +128 -0
  29. package/dist/json-schema/session.inject.json +72 -0
  30. package/dist/json-schema/session.interrupt.json +58 -0
  31. package/dist/json-schema/session.list.json +127 -0
  32. package/dist/json-schema/session.send.json +132 -0
  33. package/dist/json-schema/session.status.json +94 -0
  34. package/dist/json-schema/session.switchModel.json +73 -0
  35. package/dist/json-schema/session.terminate.json +54 -0
  36. package/dist/json-schema/skill.install.json +171 -0
  37. package/dist/json-schema/skill.list.json +101 -0
  38. package/dist/json-schema/skill.uninstall.json +76 -0
  39. package/dist/json-schema/stream.ack.json +36 -0
  40. package/dist/json-schema/stream.event.json +381 -0
  41. package/dist/schemas/capabilities.d.ts +90 -0
  42. package/dist/schemas/capabilities.d.ts.map +1 -0
  43. package/dist/schemas/capabilities.js +59 -0
  44. package/dist/schemas/capabilities.js.map +1 -0
  45. package/dist/schemas/common.d.ts +66 -0
  46. package/dist/schemas/common.d.ts.map +1 -0
  47. package/dist/schemas/common.js +97 -0
  48. package/dist/schemas/common.js.map +1 -0
  49. package/dist/schemas/connect.d.ts +111 -0
  50. package/dist/schemas/connect.d.ts.map +1 -0
  51. package/dist/schemas/connect.js +46 -0
  52. package/dist/schemas/connect.js.map +1 -0
  53. package/dist/schemas/device.d.ts +221 -0
  54. package/dist/schemas/device.d.ts.map +1 -0
  55. package/dist/schemas/device.js +59 -0
  56. package/dist/schemas/device.js.map +1 -0
  57. package/dist/schemas/discovery.d.ts +892 -0
  58. package/dist/schemas/discovery.d.ts.map +1 -0
  59. package/dist/schemas/discovery.js +66 -0
  60. package/dist/schemas/discovery.js.map +1 -0
  61. package/dist/schemas/document.d.ts +351 -0
  62. package/dist/schemas/document.d.ts.map +1 -0
  63. package/dist/schemas/document.js +103 -0
  64. package/dist/schemas/document.js.map +1 -0
  65. package/dist/schemas/env.d.ts +265 -0
  66. package/dist/schemas/env.d.ts.map +1 -0
  67. package/dist/schemas/env.js +44 -0
  68. package/dist/schemas/env.js.map +1 -0
  69. package/dist/schemas/file.d.ts +274 -0
  70. package/dist/schemas/file.d.ts.map +1 -0
  71. package/dist/schemas/file.js +72 -0
  72. package/dist/schemas/file.js.map +1 -0
  73. package/dist/schemas/hook.d.ts +132 -0
  74. package/dist/schemas/hook.d.ts.map +1 -0
  75. package/dist/schemas/hook.js +58 -0
  76. package/dist/schemas/hook.js.map +1 -0
  77. package/dist/schemas/interaction.d.ts +1583 -0
  78. package/dist/schemas/interaction.d.ts.map +1 -0
  79. package/dist/schemas/interaction.js +112 -0
  80. package/dist/schemas/interaction.js.map +1 -0
  81. package/dist/schemas/jsonrpc.d.ts +314 -0
  82. package/dist/schemas/jsonrpc.d.ts.map +1 -0
  83. package/dist/schemas/jsonrpc.js +64 -0
  84. package/dist/schemas/jsonrpc.js.map +1 -0
  85. package/dist/schemas/methods.d.ts +3826 -0
  86. package/dist/schemas/methods.d.ts.map +1 -0
  87. package/dist/schemas/methods.js +311 -0
  88. package/dist/schemas/methods.js.map +1 -0
  89. package/dist/schemas/policy.d.ts +81 -0
  90. package/dist/schemas/policy.d.ts.map +1 -0
  91. package/dist/schemas/policy.js +66 -0
  92. package/dist/schemas/policy.js.map +1 -0
  93. package/dist/schemas/project.d.ts +506 -0
  94. package/dist/schemas/project.d.ts.map +1 -0
  95. package/dist/schemas/project.js +148 -0
  96. package/dist/schemas/project.js.map +1 -0
  97. package/dist/schemas/session.d.ts +730 -0
  98. package/dist/schemas/session.d.ts.map +1 -0
  99. package/dist/schemas/session.js +287 -0
  100. package/dist/schemas/session.js.map +1 -0
  101. package/dist/schemas/skill.d.ts +465 -0
  102. package/dist/schemas/skill.d.ts.map +1 -0
  103. package/dist/schemas/skill.js +103 -0
  104. package/dist/schemas/skill.js.map +1 -0
  105. package/dist/schemas/stream.d.ts +688 -0
  106. package/dist/schemas/stream.d.ts.map +1 -0
  107. package/dist/schemas/stream.js +133 -0
  108. package/dist/schemas/stream.js.map +1 -0
  109. package/package.json +52 -0
  110. package/src/index.ts +24 -0
  111. package/src/schemas/capabilities.ts +62 -0
  112. package/src/schemas/common.ts +119 -0
  113. package/src/schemas/connect.ts +50 -0
  114. package/src/schemas/device.ts +67 -0
  115. package/src/schemas/discovery.ts +80 -0
  116. package/src/schemas/document.ts +121 -0
  117. package/src/schemas/env.ts +60 -0
  118. package/src/schemas/file.ts +97 -0
  119. package/src/schemas/hook.ts +66 -0
  120. package/src/schemas/interaction.ts +135 -0
  121. package/src/schemas/jsonrpc.ts +80 -0
  122. package/src/schemas/methods.ts +414 -0
  123. package/src/schemas/policy.ts +71 -0
  124. package/src/schemas/project.ts +185 -0
  125. package/src/schemas/session.ts +336 -0
  126. package/src/schemas/skill.ts +121 -0
  127. package/src/schemas/stream.ts +149 -0
@@ -0,0 +1,133 @@
1
+ import { z } from "zod";
2
+ import { SessionId, Timestamp } from "./common.js";
3
+ /**
4
+ * 流式事件(design §4 / §6 / 订阅模型)——phonon → server 异步推送。
5
+ *
6
+ * 关键:session 不只是「请求-响应」,还是一条**可订阅的持续输出流**。
7
+ * 输出分两种来源(origin):
8
+ * - solicited :某次 session.send 触发的响应(用 send 返回的 turnId)。
9
+ * - unsolicited:agent 自发输出(OpenClaw 的 cron/定时/心跳),无 send 触发;
10
+ * turnId 由 phonon 生成,source 标明冲泡来源。
11
+ *
12
+ * “create 即订阅”:server 拥有的 session 的**所有** stream.event(含自发)都自动
13
+ * 推给该 tenant 连接,无需显式 subscribe。Codex 一次性 session 流到 result final 就停;
14
+ * OpenClaw 持久 session 即使不 send 也会持续往上冒。
15
+ *
16
+ * 不同事件对应不同 verbosity 档位:
17
+ * final → 只会收到 result
18
+ * messages → message + result
19
+ * tools → message + tool_call + tool_result + result
20
+ * trace → 以上 + thinking + token delta
21
+ */
22
+ /** 输出来源:请求触发 vs agent 自发。 */
23
+ export const StreamOrigin = z.enum(["solicited", "unsolicited"]);
24
+ /** 事件种类。 */
25
+ export const StreamEventType = z.enum([
26
+ "message", // 一条完整/增量消息文本
27
+ "thinking", // 思考过程(trace 档)
28
+ "tool_call", // agent 发起工具调用
29
+ "tool_result", // 工具返回
30
+ "token", // 增量 token(流式打字机,trace/可选)
31
+ "result", // 本轮最终结果(终止事件)
32
+ "error", // 本轮出错(终止事件)
33
+ ]);
34
+ const StreamEventBase = z.object({
35
+ sessionId: SessionId,
36
+ /**
37
+ * 本轮关联 id。solicited 事件用 send 返回的 turnId;
38
+ * unsolicited(自发)事件由 phonon 生成,server 从事件中首次见到。
39
+ */
40
+ turnId: z.string(),
41
+ /** 输出来源:默认 solicited;agent 自发为 unsolicited。 */
42
+ origin: StreamOrigin.default("solicited"),
43
+ /** unsolicited 时的冲泡来源标签,如 "cron" / "scheduled" / "heartbeat"。 */
44
+ source: z.string().optional(),
45
+ /** 单调递增序号(按 session),保证调用方可排序/去重。 */
46
+ seq: z.number().int().nonnegative(),
47
+ at: Timestamp,
48
+ });
49
+ export const StreamMessageEvent = StreamEventBase.extend({
50
+ type: z.literal("message"),
51
+ role: z.enum(["assistant", "user", "system"]).default("assistant"),
52
+ text: z.string(),
53
+ /** 是否为增量分片(true 表示需要与同 turn 的后续 message 拼接)。 */
54
+ delta: z.boolean().default(false),
55
+ });
56
+ export const StreamThinkingEvent = StreamEventBase.extend({
57
+ type: z.literal("thinking"),
58
+ text: z.string(),
59
+ delta: z.boolean().default(false),
60
+ });
61
+ export const StreamToolCallEvent = StreamEventBase.extend({
62
+ type: z.literal("tool_call"),
63
+ toolName: z.string(),
64
+ /** 工具入参(原样透传,结构由 agent/工具决定)。 */
65
+ args: z.unknown().optional(),
66
+ /** 工具调用 id,用于和 tool_result 配对。 */
67
+ toolCallId: z.string().optional(),
68
+ });
69
+ export const StreamToolResultEvent = StreamEventBase.extend({
70
+ type: z.literal("tool_result"),
71
+ toolName: z.string(),
72
+ toolCallId: z.string().optional(),
73
+ ok: z.boolean(),
74
+ /** 工具输出(可能被截断,取决于 verbosity/大小限制)。 */
75
+ output: z.unknown().optional(),
76
+ });
77
+ export const StreamTokenEvent = StreamEventBase.extend({
78
+ type: z.literal("token"),
79
+ text: z.string(),
80
+ });
81
+ export const StreamResultEvent = StreamEventBase.extend({
82
+ type: z.literal("result"),
83
+ /** 本轮最终文本结果。 */
84
+ text: z.string(),
85
+ /** 可选 usage 统计。 */
86
+ usage: z
87
+ .object({
88
+ inputTokens: z.number().int().nonnegative().optional(),
89
+ outputTokens: z.number().int().nonnegative().optional(),
90
+ })
91
+ .optional(),
92
+ /**
93
+ * 本轮终态(P0-2)——每个 turn 必须有明确终态,服务端状态机才不会悬空:
94
+ * completed 正常完成
95
+ * interrupted 被 session.interrupt 打断
96
+ * aborted 被 hook abort / 主动中止
97
+ * failed 出错终止(详情另见 error 事件)
98
+ * timeout 超时
99
+ */
100
+ status: z.enum(["completed", "interrupted", "aborted", "failed", "timeout"]).default("completed"),
101
+ /** 标记本轮结束。 */
102
+ final: z.literal(true),
103
+ });
104
+ export const StreamErrorEvent = StreamEventBase.extend({
105
+ type: z.literal("error"),
106
+ message: z.string(),
107
+ /** 可选应用错误码(与 common.PhononErrorCode 对齐)。 */
108
+ appCode: z.string().optional(),
109
+ /** 终态(与 result.status 对齐,错误场景通常 failed/aborted/timeout)。 */
110
+ status: z.enum(["failed", "aborted", "timeout", "interrupted"]).default("failed"),
111
+ final: z.literal(true),
112
+ });
113
+ // ---------------------------------------------------------------------------
114
+ // stream.ack —— server → phonon,确认已收到 seq <= lastSeq(P0-4)
115
+ // 让 phonon 能清理 outbox / 控制背压;可按 session 粒度或全局。
116
+ // ---------------------------------------------------------------------------
117
+ export const StreamAckParams = z.object({
118
+ /** 按 session 确认;缺省表示该连接全局。 */
119
+ sessionId: SessionId.optional(),
120
+ /** 已收到的最大连续 seq(含);phonon 可清理 <= 此值的 outbox。 */
121
+ lastSeq: z.number().int().nonnegative(),
122
+ });
123
+ /** 流式事件联合体(phonon → server,方法名 stream.event)。 */
124
+ export const StreamEvent = z.discriminatedUnion("type", [
125
+ StreamMessageEvent,
126
+ StreamThinkingEvent,
127
+ StreamToolCallEvent,
128
+ StreamToolResultEvent,
129
+ StreamTokenEvent,
130
+ StreamResultEvent,
131
+ StreamErrorEvent,
132
+ ]);
133
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/schemas/stream.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@agent-phonon/protocol",
3
+ "version": "0.2.0",
4
+ "description": "Wire protocol (zod schemas + types) for agent-phonon — the single source of truth contract between phonon devices and servers.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "src",
19
+ "!dist/__tests__/**",
20
+ "!src/__tests__/**",
21
+ "!**/*.test.ts",
22
+ "!**/*.test.js",
23
+ "!**/*.test.d.ts"
24
+ ],
25
+ "dependencies": {
26
+ "zod": "^3.23.8"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "22",
30
+ "typescript": "^5.6.3",
31
+ "zod-to-json-schema": "^3.23.5"
32
+ },
33
+ "author": "agent-phonon contributors",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/hackerphysics/agent-phonon.git",
37
+ "directory": "packages/protocol"
38
+ },
39
+ "homepage": "https://github.com/hackerphysics/agent-phonon#readme",
40
+ "bugs": {
41
+ "url": "https://github.com/hackerphysics/agent-phonon/issues"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "scripts": {
47
+ "build": "tsc -p tsconfig.json",
48
+ "typecheck": "tsc -p tsconfig.json --noEmit",
49
+ "test": "pnpm build && node --test dist/__tests__/*.test.js",
50
+ "json-schema": "pnpm build && node scripts/gen-json-schema.mjs"
51
+ }
52
+ }
package/src/index.ts ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @agent-phonon/protocol
3
+ *
4
+ * agent-phonon 的线协议——phonon 设备与服务端之间的唯一契约。
5
+ * zod schema + 类型 + 方法注册表的单一事实来源(design docs/design.md)。
6
+ */
7
+
8
+ export * from "./schemas/common.js";
9
+ export * from "./schemas/capabilities.js";
10
+ export * from "./schemas/discovery.js";
11
+ export * from "./schemas/session.js";
12
+ export * from "./schemas/stream.js";
13
+ export * from "./schemas/hook.js";
14
+ export * from "./schemas/document.js";
15
+ export * from "./schemas/interaction.js";
16
+ export * from "./schemas/project.js";
17
+ export * from "./schemas/skill.js";
18
+ export * from "./schemas/policy.js";
19
+ export * from "./schemas/connect.js";
20
+ export * from "./schemas/device.js";
21
+ export * from "./schemas/file.js";
22
+ export * from "./schemas/env.js";
23
+ export * from "./schemas/jsonrpc.js";
24
+ export * from "./schemas/methods.js";
@@ -0,0 +1,62 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * Hook 类型 — 归一化的拦截点(design §8)。
5
+ * adapter 负责把各家原生 hook 点(Codex hooks / Claude Code PreToolUse /
6
+ * OpenClaw 审批…)映射成这些归一化类型。
7
+ */
8
+ export const HookType = z.enum([
9
+ "pre_tool", // 工具调用前
10
+ "post_tool", // 工具调用后
11
+ "pre_command", // 执行 shell/命令前(rm/git push 等危险操作)
12
+ "pre_file_write", // 写文件前
13
+ "pre_network", // 发起网络/外部请求前
14
+ "session_start", // 会话开始
15
+ "session_end", // 会话结束
16
+ "notification", // agent 主动通知(无需裁决,纯告知)
17
+ ]);
18
+ export type HookType = z.infer<typeof HookType>;
19
+
20
+ /**
21
+ * Adapter 能力声明(design §7)。
22
+ * adapter 不假装统一,而是声明自己原生支持什么,phonon core 据此补齐缺口。
23
+ * 这份能力随 discovery 一起暴露给服务端,服务端先知能力再决定怎么用。
24
+ */
25
+ export const AgentCapabilities = z.object({
26
+ /** 原生 session / resume(无则由 core 用注册表模拟)。 */
27
+ nativeSession: z.boolean(),
28
+ /** 原生上下文压缩(决定 session.compress mode=native 是否可用)。 */
29
+ nativeCompression: z.boolean(),
30
+ /** 原生上下文注入。 */
31
+ contextInjection: z.boolean(),
32
+ /**
33
+ * 是否会**主动/非请求触发地输出**(design 订阅模型)。
34
+ * OpenClaw 这类有 cron/心跳/定时任务,同一 session 内会不定期自发冲泡 → true;
35
+ * Codex 这类一次性,流到结果就结束 → false。
36
+ * server 据此判断哪些 session 需要长期保持监听。
37
+ */
38
+ proactiveOutput: z.boolean(),
39
+ /** 是否支持同会话中途切换模型(design D16)。 */
40
+ modelSwitch: z.boolean(),
41
+ /** 是否支持打断正在进行的 turn(session.interrupt / whenBusy=interrupt,D18)。 */
42
+ interrupt: z.boolean(),
43
+ /** 是否支持中途插入输入(下一次 tool call 边界,whenBusy=inject,D18)。 */
44
+ injectMidTurn: z.boolean(),
45
+ /** 是否支持给该 agent 安装/卸载 skill(skill.* 接口,D24)。 */
46
+ skillManagement: z.boolean(),
47
+ /** 原生支持的 hook 点(其余由 core 尽力补齐或不支持)。 */
48
+ hooks: z.array(HookType),
49
+ /** 是否支持流式输出。 */
50
+ streaming: z.boolean(),
51
+ /**
52
+ * 可选调度限制(P2-13):server 据此做调度/背压。
53
+ */
54
+ limits: z
55
+ .object({
56
+ maxConcurrentSessions: z.number().int().positive().optional(),
57
+ maxContextTokens: z.number().int().positive().optional(),
58
+ maxMessageBytes: z.number().int().positive().optional(),
59
+ })
60
+ .optional(),
61
+ });
62
+ export type AgentCapabilities = z.infer<typeof AgentCapabilities>;
@@ -0,0 +1,119 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * agent-phonon wire protocol — shared primitives.
5
+ *
6
+ * 设计参考 docs/design.md。本文件定义全协议复用的基础类型:
7
+ * 协议版本、各类 ID、verbosity、错误码。
8
+ */
9
+
10
+ /** 协议语义版本。device 与 server 握手时比对(见 connect.hello)。 */
11
+ export const PROTOCOL_VERSION = "0.1.0" as const;
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // ID 原语(全部是不透明字符串,调用方不应解析其结构)
15
+ // ---------------------------------------------------------------------------
16
+
17
+ /** phonon 侧全局唯一的 session id(归属某一 tenant)。 */
18
+ export const SessionId = z.string().min(1).brand<"SessionId">();
19
+ export type SessionId = z.infer<typeof SessionId>;
20
+
21
+ /** discovery 返回的 agent 标识,也是 session.create 的 `agent` 入参。 */
22
+ export const AgentId = z.string().min(1).brand<"AgentId">();
23
+ export type AgentId = z.infer<typeof AgentId>;
24
+
25
+ /** 项目标识(项目 = 目录 + Git)。所有 session 必须绑定一个项目。 */
26
+ export const ProjectId = z.string().min(1).brand<"ProjectId">();
27
+ export type ProjectId = z.infer<typeof ProjectId>;
28
+
29
+ /** 本地配置赋予的稳定租户 id(= 一条服务端连接,见 design D13)。 */
30
+ export const TenantId = z.string().min(1).brand<"TenantId">();
31
+ export type TenantId = z.infer<typeof TenantId>;
32
+
33
+ /** 设备自身标识(一台设备一个,用于服务端区分多设备,但 phonon 不感知其他设备)。 */
34
+ export const DeviceId = z.string().min(1).brand<"DeviceId">();
35
+ export type DeviceId = z.infer<typeof DeviceId>;
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // Verbosity — 控制 session 返回内容的多少(design §4)
39
+ // ---------------------------------------------------------------------------
40
+
41
+ /**
42
+ * 4 档详细度,create 时设定、send 可覆盖:
43
+ * - final : 仅最终结果
44
+ * - messages : 每轮消息
45
+ * - tools : 含工具调用
46
+ * - trace : 全量(含思考)
47
+ */
48
+ export const Verbosity = z.enum(["final", "messages", "tools", "trace"]);
49
+ export type Verbosity = z.infer<typeof Verbosity>;
50
+
51
+ // ---------------------------------------------------------------------------
52
+ // 错误码 — JSON-RPC error.data.code 用(design 中提到的归一化错误)
53
+ // ---------------------------------------------------------------------------
54
+
55
+ /**
56
+ * 应用级错误码(区别于 JSON-RPC 传输级 code)。
57
+ * 放在 JSON-RPC error 对象的 `data.appCode` 字段,便于调用方稳定判别。
58
+ */
59
+ export const PhononErrorCode = z.enum([
60
+ // 协议/握手
61
+ "errProtocolMismatch", // device 与 server 协议版本不兼容
62
+ "errUnauthorized", // device key 无效(注:终端用户鉴权在 server,不在此)
63
+ // 租户隔离(design §6 / D13)
64
+ "errSessionNotInTenant", // 跨租户访问 session
65
+ "errTenantQuotaExceeded", // 触达 per-tenant 配额
66
+ "errDeviceQuotaExceeded", // 触达全局配额
67
+ // 发现 / agent 绑定(design §5 / D14 / D15)
68
+ "errAgentUnavailable", // 目标 agent 不存在或不可用
69
+ "errModelUnavailable", // 模型不在该 agent 的可用列表内
70
+ // session 生命周期
71
+ "errSessionNotFound",
72
+ "errSessionTerminated", // 操作了已结束的 session
73
+ "errSessionBusy", // session 正忙(如上一轮未结束)
74
+ // 能力
75
+ "errCapabilityUnsupported", // adapter 不支持该操作(如 native 压缩缺失)
76
+ // hook / HITL
77
+ "errHookResolveInvalid", // hook.resolve 的裁决非法
78
+ "errHookTimeout", // 等待服务端裁决超时
79
+ // 项目 / skill(D23-D26)
80
+ "errProjectNotFound",
81
+ "errProjectExists", // 同名/同路径项目已存在
82
+ "errProjectHasActiveSessions", // 项目下还有 active session(remove 拦)
83
+ "errSkillNotFound",
84
+ "errSkillScopeInvalid", // scope=project 但缺 projectId 等
85
+ "errSkillInstallFailed",
86
+ // git / worktree(D25)
87
+ "errWorktreeNotFound",
88
+ "errWorktreeHasChanges", // 未提交变更,非 force 不清
89
+ "errWorktreeInUse", // worktree 还有 active session
90
+ "errBranchNotMerged", // 分支未合并,非 force 不删
91
+ "errBranchInUse", // 分支仍被某 worktree 检出
92
+ // 文档 / 上传(D20)
93
+ "errDocumentTooLarge", // 超 maxUploadBytes
94
+ "errDocumentPathDenied", // 路径不在项目范围 / 命中 deny
95
+ // 本地 policy(D27)
96
+ "errPolicyDenied", // 被设备本地安全策略拦截
97
+ // 幂等
98
+ "errDuplicateRequest", // clientRequestId 重复(已处理过)
99
+ // 通用
100
+ "errInvalidParams",
101
+ "errInternal",
102
+ ]);
103
+ export type PhononErrorCode = z.infer<typeof PhononErrorCode>;
104
+
105
+ /** 统一附在 JSON-RPC error.data 上的结构。 */
106
+ export const PhononErrorData = z.object({
107
+ appCode: PhononErrorCode,
108
+ /** 可选的人类可读补充(不用于程序判别)。 */
109
+ detail: z.string().optional(),
110
+ /** 可选:相关 session/agent/tenant,便于服务端定位。 */
111
+ sessionId: SessionId.optional(),
112
+ agentId: AgentId.optional(),
113
+ tenantId: TenantId.optional(),
114
+ });
115
+ export type PhononErrorData = z.infer<typeof PhononErrorData>;
116
+
117
+ /** ISO-8601 时间戳字符串(统一用字符串,避免时区/精度歧义)。 */
118
+ export const Timestamp = z.string().datetime({ offset: true });
119
+ export type Timestamp = z.infer<typeof Timestamp>;
@@ -0,0 +1,50 @@
1
+ import { z } from "zod";
2
+ import { DeviceId, TenantId, Timestamp } from "./common.js";
3
+
4
+ /**
5
+ * 连接握手(design §6)。
6
+ *
7
+ * phonon 拨出连接后,首先发 connect.hello 表明:协议版本、设备身份。
8
+ * device key 的鉴权由传输层/服务端处理(如 WS header / 首帧),不在业务 params 里明文带。
9
+ * server 回 connect.welcome 确认,并可下发 tenant 绑定与服务端能力。
10
+ */
11
+
12
+ export const ConnectHelloParams = z.object({
13
+ /** 本端协议版本(= PROTOCOL_VERSION)。 */
14
+ protocolVersion: z.string(),
15
+ /** 设备标识(服务端用于区分多设备)。 */
16
+ deviceId: DeviceId,
17
+ /** phonon 实现版本(软件版本,便于服务端兼容处理)。 */
18
+ phononVersion: z.string().optional(),
19
+ /** 本端声明支持的可选特性开关,便于前向兼容。 */
20
+ features: z.array(z.string()).default([]),
21
+ /** 设备鉴权(可选):server 据此验证设备身份。也可走传输层 header。 */
22
+ auth: z.object({ deviceKey: z.string() }).optional(),
23
+ /**
24
+ * 重连时携带(P0-4):phonon 本地 outbox 中每个 session 尚未被 ack 的起始 seq,
25
+ * 让 server 知道哪些要补发 / 从哪重放。首次连接可省略。
26
+ */
27
+ resumeFrom: z
28
+ .array(z.object({ sessionId: z.string(), fromSeq: z.number().int().nonnegative() }))
29
+ .optional(),
30
+ at: Timestamp,
31
+ });
32
+ export type ConnectHelloParams = z.infer<typeof ConnectHelloParams>;
33
+
34
+ export const ConnectWelcomeResult = z.object({
35
+ /** 服务端协议版本。 */
36
+ protocolVersion: z.string(),
37
+ /** 服务端为本连接分配/确认的租户身份(= 一条服务端连接,design D13)。 */
38
+ tenantId: TenantId,
39
+ /** 服务端声明支持的可选特性。 */
40
+ features: z.array(z.string()).default([]),
41
+ /**
42
+ * 重连时服务端告知「我各 session 最后收到的 seq」(P0-4),
43
+ * phonon 据此从 outbox 精确补发(> lastSeq 的),避免重复/遗漏。
44
+ */
45
+ ackedSeqs: z
46
+ .array(z.object({ sessionId: z.string(), lastSeq: z.number().int().nonnegative() }))
47
+ .optional(),
48
+ at: Timestamp,
49
+ });
50
+ export type ConnectWelcomeResult = z.infer<typeof ConnectWelcomeResult>;
@@ -0,0 +1,67 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * 设备级信息与可观测协议。
5
+ *
6
+ * device.info:相对静态的 OS/机器信息,用于服务端按需调度。
7
+ * device.resources:运行时资源快照,用于 debug,不做资源调度或限制。
8
+ */
9
+
10
+ export const DeviceInfoParams = z.object({}).default({});
11
+ export type DeviceInfoParams = z.infer<typeof DeviceInfoParams>;
12
+
13
+ export const DeviceInfoResult = z.object({
14
+ at: z.string().datetime({ offset: true }),
15
+ hostname: z.string(),
16
+ os: z.object({
17
+ platform: z.enum(["aix", "darwin", "freebsd", "linux", "openbsd", "sunos", "win32", "cygwin", "netbsd"]).or(z.string()),
18
+ type: z.string(),
19
+ release: z.string(),
20
+ arch: z.string(),
21
+ }),
22
+ runtime: z.object({
23
+ node: z.string().optional(),
24
+ }).optional(),
25
+ /** 便于 server 做粗粒度任务路由:ios-development/windows-desktop-development/nvidia-gpu 等。 */
26
+ capabilities: z.array(z.string()).default([]),
27
+ });
28
+ export type DeviceInfoResult = z.infer<typeof DeviceInfoResult>;
29
+
30
+ export const DeviceResourcesParams = z.object({}).default({});
31
+ export type DeviceResourcesParams = z.infer<typeof DeviceResourcesParams>;
32
+
33
+ export const DeviceResourcesResult = z.object({
34
+ at: z.string().datetime({ offset: true }),
35
+ cpu: z.object({
36
+ loadavg: z.array(z.number()).length(3).optional(),
37
+ cores: z.number().int().positive().optional(),
38
+ usagePercent: z.number().min(0).max(100).optional(),
39
+ }).optional(),
40
+ memory: z.object({
41
+ totalBytes: z.number().nonnegative(),
42
+ freeBytes: z.number().nonnegative(),
43
+ usedBytes: z.number().nonnegative(),
44
+ usagePercent: z.number().min(0).max(100).optional(),
45
+ }),
46
+ disk: z.object({
47
+ path: z.string(),
48
+ totalBytes: z.number().nonnegative().optional(),
49
+ freeBytes: z.number().nonnegative().optional(),
50
+ usedBytes: z.number().nonnegative().optional(),
51
+ usagePercent: z.number().min(0).max(100).optional(),
52
+ }).optional(),
53
+ gpu: z.array(z.object({
54
+ name: z.string().optional(),
55
+ memoryTotalBytes: z.number().nonnegative().optional(),
56
+ memoryUsedBytes: z.number().nonnegative().optional(),
57
+ utilizationPercent: z.number().min(0).max(100).optional(),
58
+ })).optional(),
59
+ process: z.object({
60
+ pid: z.number().int().positive(),
61
+ uptimeSeconds: z.number().nonnegative(),
62
+ rssBytes: z.number().nonnegative().optional(),
63
+ heapUsedBytes: z.number().nonnegative().optional(),
64
+ heapTotalBytes: z.number().nonnegative().optional(),
65
+ }).optional(),
66
+ });
67
+ export type DeviceResourcesResult = z.infer<typeof DeviceResourcesResult>;
@@ -0,0 +1,80 @@
1
+ import { z } from "zod";
2
+ import { AgentId, Timestamp } from "./common.js";
3
+ import { AgentCapabilities } from "./capabilities.js";
4
+
5
+ /**
6
+ * Agent / 模型发现(design §5 / D14)。
7
+ *
8
+ * 发现 = 内部扫描机制(非协议)+ 对外暴露接口(属协议)。本文件只定义
9
+ * **对外接口**的数据形状:服务端借此感知「这台设备上哪些 agent 可用、
10
+ * 各自哪些模型可用」。
11
+ */
12
+
13
+ /** 单个模型的可用性描述。 */
14
+ export const ModelInfo = z.object({
15
+ /** 模型 id,session.create 的 `model` 入参取自这里。 */
16
+ id: z.string().min(1),
17
+ /** 展示名(可选)。 */
18
+ displayName: z.string().optional(),
19
+ /** 上下文窗口(token,若已知)。注意:以 phonon 实测/配置为准,不盲信后端返回。 */
20
+ contextWindow: z.number().int().positive().optional(),
21
+ /** 该模型当前是否可用(如鉴权过期会变 false)。 */
22
+ available: z.boolean().default(true),
23
+ });
24
+ export type ModelInfo = z.infer<typeof ModelInfo>;
25
+
26
+ /** 单个 agent 的发现条目。 */
27
+ export const AgentDescriptor = z.object({
28
+ agentId: AgentId,
29
+ /** 展示名,如 "Claude Code" / "OpenClaw"。 */
30
+ displayName: z.string().min(1),
31
+ /** 适配器内部名,如 "openclaw" / "claude-code"。 */
32
+ adapter: z.string().min(1),
33
+ /** 整体是否可用(已安装 + 可执行 + 凭证就绪)。 */
34
+ available: z.boolean(),
35
+ /** 不可用时的原因(如 "not_installed" / "not_logged_in" / "no_credentials")。 */
36
+ unavailableReason: z.string().optional(),
37
+ /** agent 自身版本(若可探测)。 */
38
+ version: z.string().optional(),
39
+ /** 可用模型列表。 */
40
+ models: z.array(ModelInfo),
41
+ /** 能力声明(随 discovery 暴露,见 §7)。 */
42
+ capabilities: AgentCapabilities,
43
+ /** 最近一次扫描时间。 */
44
+ scannedAt: Timestamp.optional(),
45
+ });
46
+ export type AgentDescriptor = z.infer<typeof AgentDescriptor>;
47
+
48
+ // --- discovery.list ---
49
+ export const DiscoveryListParams = z.object({
50
+ /** 可选:只看可用的。 */
51
+ availableOnly: z.boolean().optional(),
52
+ });
53
+ export type DiscoveryListParams = z.infer<typeof DiscoveryListParams>;
54
+
55
+ export const DiscoveryListResult = z.object({
56
+ agents: z.array(AgentDescriptor),
57
+ });
58
+ export type DiscoveryListResult = z.infer<typeof DiscoveryListResult>;
59
+
60
+ // --- discovery.get ---
61
+ export const DiscoveryGetParams = z.object({
62
+ agentId: AgentId,
63
+ });
64
+ export type DiscoveryGetParams = z.infer<typeof DiscoveryGetParams>;
65
+
66
+ export const DiscoveryGetResult = z.object({
67
+ agent: AgentDescriptor,
68
+ });
69
+ export type DiscoveryGetResult = z.infer<typeof DiscoveryGetResult>;
70
+
71
+ // --- discovery.changed (phonon -> server 主动推送,notification) ---
72
+ export const DiscoveryChangedParams = z.object({
73
+ /** 变更类型:agent 上/下线、模型增减、能力变化。 */
74
+ kind: z.enum(["agent_added", "agent_removed", "agent_updated", "models_changed"]),
75
+ agentId: AgentId,
76
+ /** 变更后的完整快照(可选,便于服务端直接更新缓存)。 */
77
+ snapshot: AgentDescriptor.optional(),
78
+ at: Timestamp,
79
+ });
80
+ export type DiscoveryChangedParams = z.infer<typeof DiscoveryChangedParams>;