@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.
- package/LICENSE +21 -0
- package/README.md +70 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/json-schema/_index.json +3794 -0
- package/dist/json-schema/connect.hello.json +117 -0
- package/dist/json-schema/discovery.changed.json +190 -0
- package/dist/json-schema/discovery.get.json +183 -0
- package/dist/json-schema/discovery.list.json +182 -0
- package/dist/json-schema/document.prepare_upload.json +96 -0
- package/dist/json-schema/document.send.json +165 -0
- package/dist/json-schema/hook.fired.json +100 -0
- package/dist/json-schema/hook.resolve.json +96 -0
- package/dist/json-schema/interaction.cancel.json +48 -0
- package/dist/json-schema/interaction.request.json +376 -0
- package/dist/json-schema/interaction.response.json +68 -0
- package/dist/json-schema/project.create.json +89 -0
- package/dist/json-schema/project.get.json +76 -0
- package/dist/json-schema/project.git.deleteBranch.json +64 -0
- package/dist/json-schema/project.list.json +72 -0
- package/dist/json-schema/project.remove.json +69 -0
- package/dist/json-schema/project.worktree.create.json +88 -0
- package/dist/json-schema/project.worktree.list.json +77 -0
- package/dist/json-schema/project.worktree.remove.json +61 -0
- package/dist/json-schema/session.compress.json +72 -0
- package/dist/json-schema/session.create.json +128 -0
- package/dist/json-schema/session.inject.json +72 -0
- package/dist/json-schema/session.interrupt.json +58 -0
- package/dist/json-schema/session.list.json +127 -0
- package/dist/json-schema/session.send.json +132 -0
- package/dist/json-schema/session.status.json +94 -0
- package/dist/json-schema/session.switchModel.json +73 -0
- package/dist/json-schema/session.terminate.json +54 -0
- package/dist/json-schema/skill.install.json +171 -0
- package/dist/json-schema/skill.list.json +101 -0
- package/dist/json-schema/skill.uninstall.json +76 -0
- package/dist/json-schema/stream.ack.json +36 -0
- package/dist/json-schema/stream.event.json +381 -0
- package/dist/schemas/capabilities.d.ts +90 -0
- package/dist/schemas/capabilities.d.ts.map +1 -0
- package/dist/schemas/capabilities.js +59 -0
- package/dist/schemas/capabilities.js.map +1 -0
- package/dist/schemas/common.d.ts +66 -0
- package/dist/schemas/common.d.ts.map +1 -0
- package/dist/schemas/common.js +97 -0
- package/dist/schemas/common.js.map +1 -0
- package/dist/schemas/connect.d.ts +111 -0
- package/dist/schemas/connect.d.ts.map +1 -0
- package/dist/schemas/connect.js +46 -0
- package/dist/schemas/connect.js.map +1 -0
- package/dist/schemas/device.d.ts +221 -0
- package/dist/schemas/device.d.ts.map +1 -0
- package/dist/schemas/device.js +59 -0
- package/dist/schemas/device.js.map +1 -0
- package/dist/schemas/discovery.d.ts +892 -0
- package/dist/schemas/discovery.d.ts.map +1 -0
- package/dist/schemas/discovery.js +66 -0
- package/dist/schemas/discovery.js.map +1 -0
- package/dist/schemas/document.d.ts +351 -0
- package/dist/schemas/document.d.ts.map +1 -0
- package/dist/schemas/document.js +103 -0
- package/dist/schemas/document.js.map +1 -0
- package/dist/schemas/env.d.ts +265 -0
- package/dist/schemas/env.d.ts.map +1 -0
- package/dist/schemas/env.js +44 -0
- package/dist/schemas/env.js.map +1 -0
- package/dist/schemas/file.d.ts +274 -0
- package/dist/schemas/file.d.ts.map +1 -0
- package/dist/schemas/file.js +72 -0
- package/dist/schemas/file.js.map +1 -0
- package/dist/schemas/hook.d.ts +132 -0
- package/dist/schemas/hook.d.ts.map +1 -0
- package/dist/schemas/hook.js +58 -0
- package/dist/schemas/hook.js.map +1 -0
- package/dist/schemas/interaction.d.ts +1583 -0
- package/dist/schemas/interaction.d.ts.map +1 -0
- package/dist/schemas/interaction.js +112 -0
- package/dist/schemas/interaction.js.map +1 -0
- package/dist/schemas/jsonrpc.d.ts +314 -0
- package/dist/schemas/jsonrpc.d.ts.map +1 -0
- package/dist/schemas/jsonrpc.js +64 -0
- package/dist/schemas/jsonrpc.js.map +1 -0
- package/dist/schemas/methods.d.ts +3826 -0
- package/dist/schemas/methods.d.ts.map +1 -0
- package/dist/schemas/methods.js +311 -0
- package/dist/schemas/methods.js.map +1 -0
- package/dist/schemas/policy.d.ts +81 -0
- package/dist/schemas/policy.d.ts.map +1 -0
- package/dist/schemas/policy.js +66 -0
- package/dist/schemas/policy.js.map +1 -0
- package/dist/schemas/project.d.ts +506 -0
- package/dist/schemas/project.d.ts.map +1 -0
- package/dist/schemas/project.js +148 -0
- package/dist/schemas/project.js.map +1 -0
- package/dist/schemas/session.d.ts +730 -0
- package/dist/schemas/session.d.ts.map +1 -0
- package/dist/schemas/session.js +287 -0
- package/dist/schemas/session.js.map +1 -0
- package/dist/schemas/skill.d.ts +465 -0
- package/dist/schemas/skill.d.ts.map +1 -0
- package/dist/schemas/skill.js +103 -0
- package/dist/schemas/skill.js.map +1 -0
- package/dist/schemas/stream.d.ts +688 -0
- package/dist/schemas/stream.d.ts.map +1 -0
- package/dist/schemas/stream.js +133 -0
- package/dist/schemas/stream.js.map +1 -0
- package/package.json +52 -0
- package/src/index.ts +24 -0
- package/src/schemas/capabilities.ts +62 -0
- package/src/schemas/common.ts +119 -0
- package/src/schemas/connect.ts +50 -0
- package/src/schemas/device.ts +67 -0
- package/src/schemas/discovery.ts +80 -0
- package/src/schemas/document.ts +121 -0
- package/src/schemas/env.ts +60 -0
- package/src/schemas/file.ts +97 -0
- package/src/schemas/hook.ts +66 -0
- package/src/schemas/interaction.ts +135 -0
- package/src/schemas/jsonrpc.ts +80 -0
- package/src/schemas/methods.ts +414 -0
- package/src/schemas/policy.ts +71 -0
- package/src/schemas/project.ts +185 -0
- package/src/schemas/session.ts +336 -0
- package/src/schemas/skill.ts +121 -0
- package/src/schemas/stream.ts +149 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AgentId, ProjectId, SessionId, Timestamp, Verbosity } from "./common.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* L1 Session 协议原语(design §4)。
|
|
6
|
+
*
|
|
7
|
+
* 铁律:session 必须绑定 agent(D15)。每条 session 天生属于某个 agent + model,
|
|
8
|
+
* 这是 session 的一等身份,不是可选配置。发任务 = 在 session 里对话。
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** session 状态。 */
|
|
12
|
+
/**
|
|
13
|
+
* session 状态(design D19)。
|
|
14
|
+
* - idle : 活着、空闲、就绪可接 send(create 后初始态;turn 结束/interrupt 后回到这)
|
|
15
|
+
* - running : agent 正在执行一个 turn
|
|
16
|
+
* - paused : 挂起(重启后从 DB 恢复、原生 ref 尚未 re-attach;或被显式暂停),需恢复才能用
|
|
17
|
+
* - terminated : 已结束销毁
|
|
18
|
+
*/
|
|
19
|
+
export const SessionStatus = z.enum(["idle", "running", "paused", "terminated"]);
|
|
20
|
+
export type SessionStatus = z.infer<typeof SessionStatus>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 上下文条目 —— 用于 initialContext / inject。
|
|
24
|
+
* 设计成「角色 + 文本」的最小通用形态,具体 adapter 自行翻译成原生格式。
|
|
25
|
+
*/
|
|
26
|
+
export const ContextItem = z.object({
|
|
27
|
+
role: z.enum(["system", "user", "assistant"]),
|
|
28
|
+
content: z.string(),
|
|
29
|
+
});
|
|
30
|
+
export type ContextItem = z.infer<typeof ContextItem>;
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// session.create
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
export const SessionCreateParams = z.object({
|
|
36
|
+
/** 可选:幂等键(P0-3,断线重发去重)。 */
|
|
37
|
+
clientRequestId: z.string().optional(),
|
|
38
|
+
/** 必填:绑定的项目(所有 session 必须有项目目录,D23)。 */
|
|
39
|
+
project: ProjectId,
|
|
40
|
+
/** 可选:跑在哪个 worktree(缺省用项目主工作区,D25)。 */
|
|
41
|
+
worktreeId: z.string().optional(),
|
|
42
|
+
/** 必填:绑定的 agent(来自 discovery 的 agentId)。 */
|
|
43
|
+
agent: AgentId,
|
|
44
|
+
/** 必填:绑定的模型(必须在该 agent 的可用模型列表内)。 */
|
|
45
|
+
model: z.string().min(1),
|
|
46
|
+
/** 透传给 adapter 的 agent 私有配置(cwd、工具白名单、thinking 等)。 */
|
|
47
|
+
agentConfig: z.record(z.unknown()).optional(),
|
|
48
|
+
/** 初始上下文设置(system prompt / 预置对话)。 */
|
|
49
|
+
initialContext: z.array(ContextItem).optional(),
|
|
50
|
+
/** 默认返回详细度,send 可覆盖。默认 messages。 */
|
|
51
|
+
verbosity: Verbosity.default("messages"),
|
|
52
|
+
/** 可选:调用方自带的标签,便于服务端侧对账(phonon 原样回显)。 */
|
|
53
|
+
clientTag: z.string().optional(),
|
|
54
|
+
});
|
|
55
|
+
export type SessionCreateParams = z.infer<typeof SessionCreateParams>;
|
|
56
|
+
|
|
57
|
+
export const SessionCreateResult = z.object({
|
|
58
|
+
sessionId: SessionId,
|
|
59
|
+
/** 回显绑定身份,方便调用方确认。 */
|
|
60
|
+
project: ProjectId,
|
|
61
|
+
agent: AgentId,
|
|
62
|
+
model: z.string(),
|
|
63
|
+
status: SessionStatus,
|
|
64
|
+
createdAt: Timestamp,
|
|
65
|
+
});
|
|
66
|
+
export type SessionCreateResult = z.infer<typeof SessionCreateResult>;
|
|
67
|
+
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// session.send —— 发任务 = 对话;结果以流式 events 异步返回(见 stream.ts)
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 忙碌处理模式(D18)—— 新消息进来时上一轮还没结束怎么办:
|
|
74
|
+
* - queue :等待,上一轮结束后自动发送积压消息(默认,最安全)。
|
|
75
|
+
* - interrupt:中断当前 turn(session 存活),再发新消息;需 capability.interrupt。
|
|
76
|
+
* - inject :不中断,在下一次 tool call 边界插入输入让 agent 接着处理;
|
|
77
|
+
* 需 capability.injectMidTurn(agent 原生接口或通过 hook 实现)。
|
|
78
|
+
* 不论哪种模式,**消息不丢**:要么按序送达、要么明确拒绝并告知原因。
|
|
79
|
+
*/
|
|
80
|
+
export const WhenBusy = z.enum(["queue", "interrupt", "inject"]);
|
|
81
|
+
export type WhenBusy = z.infer<typeof WhenBusy>;
|
|
82
|
+
|
|
83
|
+
export const SessionSendParams = z.object({
|
|
84
|
+
sessionId: SessionId,
|
|
85
|
+
/** 用户输入 / 任务内容。 */
|
|
86
|
+
input: z.string(),
|
|
87
|
+
/**
|
|
88
|
+
* 可选:幂等键(P0-3)。服务端断线重发同一 send 时带相同值,
|
|
89
|
+
* phonon 去重,避免 agent 收两遍同样消息;重复回 `errDuplicateRequest` 或原 turnId。
|
|
90
|
+
*/
|
|
91
|
+
clientRequestId: z.string().optional(),
|
|
92
|
+
/**
|
|
93
|
+
* 可选:本轮指定要用的 skill(D26)。每项可是简单名字(string),
|
|
94
|
+
* 或结构体 {name,version?,scope?,force?}(P2-12,消除同名 global/project 歧义)。
|
|
95
|
+
* phonon 保证:(1) skill 在 agent 能访问到的位置;(2) 上下文注入强制加载指令。
|
|
96
|
+
* 优先级:send 指定 > project skill > global skill。
|
|
97
|
+
*/
|
|
98
|
+
skills: z
|
|
99
|
+
.array(
|
|
100
|
+
z.union([
|
|
101
|
+
z.string(),
|
|
102
|
+
z.object({
|
|
103
|
+
name: z.string().min(1),
|
|
104
|
+
version: z.string().optional(),
|
|
105
|
+
scope: z.enum(["global", "project"]).optional(),
|
|
106
|
+
force: z.boolean().optional(),
|
|
107
|
+
}),
|
|
108
|
+
]),
|
|
109
|
+
)
|
|
110
|
+
.optional(),
|
|
111
|
+
/** 可选:覆盖本轮详细度。 */
|
|
112
|
+
verbosity: Verbosity.optional(),
|
|
113
|
+
/**
|
|
114
|
+
* 忙碌时的处理模式(D18)。缺省 queue。
|
|
115
|
+
* 若选的模式该 agent 不支持(看 capability)且未设 fallback → errCapabilityUnsupported。
|
|
116
|
+
*/
|
|
117
|
+
whenBusy: WhenBusy.default("queue"),
|
|
118
|
+
/**
|
|
119
|
+
* 可选:降级模式(P1-11)。当 whenBusy 该 agent 不支持时,不报错而自动降级为它,
|
|
120
|
+
* 保证自动化编排连贯。如 whenBusy="inject", fallback="queue"。
|
|
121
|
+
*/
|
|
122
|
+
fallback: WhenBusy.optional(),
|
|
123
|
+
/**
|
|
124
|
+
* 可选:本轮关联 id。phonon 会把该轮所有 stream.event 标上同一 turnId,
|
|
125
|
+
* 调用方据此聚合流式输出。缺省由 phonon 生成并在 ack 中返回。
|
|
126
|
+
*/
|
|
127
|
+
turnId: z.string().optional(),
|
|
128
|
+
});
|
|
129
|
+
export type SessionSendParams = z.infer<typeof SessionSendParams>;
|
|
130
|
+
|
|
131
|
+
/** send 的同步 ack(真正的内容走 stream.event 异步推)。 */
|
|
132
|
+
export const SessionSendAck = z.object({
|
|
133
|
+
sessionId: SessionId,
|
|
134
|
+
turnId: z.string(),
|
|
135
|
+
accepted: z.literal(true),
|
|
136
|
+
/**
|
|
137
|
+
* 本次 send 的实际处由:
|
|
138
|
+
* - started :立即开始执行(session 空闲)
|
|
139
|
+
* - queued :已排队(whenBusy=queue 且正忙)
|
|
140
|
+
* - interrupted:已中断上一轮并开始本轮(whenBusy=interrupt)
|
|
141
|
+
* - injected :将在下一 tool call 边界插入(whenBusy=inject)
|
|
142
|
+
*/
|
|
143
|
+
disposition: z.enum(["started", "queued", "interrupted", "injected"]),
|
|
144
|
+
/** queued 时的队列位置(从 1 起)。 */
|
|
145
|
+
queuePosition: z.number().int().positive().optional(),
|
|
146
|
+
});
|
|
147
|
+
export type SessionSendAck = z.infer<typeof SessionSendAck>;
|
|
148
|
+
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
// session.interrupt —— 打断当前正在进行的 turn(session 存活,D18)
|
|
151
|
+
// 区别于 session.terminate(销毁整个 session)。
|
|
152
|
+
// P0-2:interrupt 后 phonon 必须为被打断的 turn 发一条终态 stream.event
|
|
153
|
+
// { type:"result", final:true, status:"interrupted" },服务端状态机才不悬空。
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
export const SessionInterruptParams = z.object({
|
|
156
|
+
sessionId: SessionId,
|
|
157
|
+
/** 可选:中断原因(传给 agent / 记录)。 */
|
|
158
|
+
reason: z.string().optional(),
|
|
159
|
+
});
|
|
160
|
+
export type SessionInterruptParams = z.infer<typeof SessionInterruptParams>;
|
|
161
|
+
|
|
162
|
+
export const SessionInterruptResult = z.object({
|
|
163
|
+
sessionId: SessionId,
|
|
164
|
+
/** 被中断的 turn(若当时有在跑的)。 */
|
|
165
|
+
interruptedTurnId: z.string().optional(),
|
|
166
|
+
/** 中断后 session 状态(通常回到 active 空闲)。 */
|
|
167
|
+
status: SessionStatus,
|
|
168
|
+
});
|
|
169
|
+
export type SessionInterruptResult = z.infer<typeof SessionInterruptResult>;
|
|
170
|
+
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
// session.inject —— 上下文注入
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
export const SessionInjectParams = z.object({
|
|
175
|
+
sessionId: SessionId,
|
|
176
|
+
context: z.array(ContextItem),
|
|
177
|
+
});
|
|
178
|
+
export type SessionInjectParams = z.infer<typeof SessionInjectParams>;
|
|
179
|
+
|
|
180
|
+
export const SessionInjectResult = z.object({
|
|
181
|
+
sessionId: SessionId,
|
|
182
|
+
injected: z.number().int().nonnegative(),
|
|
183
|
+
});
|
|
184
|
+
export type SessionInjectResult = z.infer<typeof SessionInjectResult>;
|
|
185
|
+
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
// session.compress —— 压缩双模(design §4 / D7)
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
export const CompressMode = z.enum(["native", "custom"]);
|
|
190
|
+
export type CompressMode = z.infer<typeof CompressMode>;
|
|
191
|
+
|
|
192
|
+
export const SessionCompressParams = z.object({
|
|
193
|
+
sessionId: SessionId,
|
|
194
|
+
/** native = 透传 agent 原生压缩;custom = phonon 自有压缩引擎。 */
|
|
195
|
+
mode: CompressMode,
|
|
196
|
+
/**
|
|
197
|
+
* custom 模式下的策略名(P2-15)。**server-private:phonon 不做协议层枚举校验**,
|
|
198
|
+
* 透传给 adapter/压缩引擎自行解释(如 summary / truncate_keep_recent)。
|
|
199
|
+
*/
|
|
200
|
+
strategy: z.string().optional(),
|
|
201
|
+
/** dropToolIO 策略:保留最近 N 个 tool call 及其 result,默认 3。 */
|
|
202
|
+
keepRecentToolCalls: z.number().int().nonnegative().optional(),
|
|
203
|
+
});
|
|
204
|
+
export type SessionCompressParams = z.infer<typeof SessionCompressParams>;
|
|
205
|
+
|
|
206
|
+
export const SessionCompressResult = z.object({
|
|
207
|
+
sessionId: SessionId,
|
|
208
|
+
mode: CompressMode,
|
|
209
|
+
/** 压缩前后的 token 估算(若可得)。 */
|
|
210
|
+
tokensBefore: z.number().int().nonnegative().optional(),
|
|
211
|
+
tokensAfter: z.number().int().nonnegative().optional(),
|
|
212
|
+
/** 简短摘要/说明。 */
|
|
213
|
+
summary: z.string().optional(),
|
|
214
|
+
});
|
|
215
|
+
export type SessionCompressResult = z.infer<typeof SessionCompressResult>;
|
|
216
|
+
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
// session.terminate
|
|
219
|
+
// ---------------------------------------------------------------------------
|
|
220
|
+
export const SessionTerminateParams = z.object({
|
|
221
|
+
sessionId: SessionId,
|
|
222
|
+
/**
|
|
223
|
+
* 可选:销毁会话时顺手清理其专用 worktree(P1-10)。
|
|
224
|
+
* 仅当该 session 跑在一个专为它建的 worktree 上才生效;主工作区不清。
|
|
225
|
+
*/
|
|
226
|
+
cleanWorktree: z.boolean().default(false),
|
|
227
|
+
});
|
|
228
|
+
export type SessionTerminateParams = z.infer<typeof SessionTerminateParams>;
|
|
229
|
+
|
|
230
|
+
export const SessionTerminateResult = z.object({
|
|
231
|
+
sessionId: SessionId,
|
|
232
|
+
status: z.literal("terminated"),
|
|
233
|
+
/** 若 cleanWorktree 且确实清了,返回被清理的 worktreeId。 */
|
|
234
|
+
cleanedWorktreeId: z.string().optional(),
|
|
235
|
+
});
|
|
236
|
+
export type SessionTerminateResult = z.infer<typeof SessionTerminateResult>;
|
|
237
|
+
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
239
|
+
// session.switchModel —— 同会话中途切换模型(design D16)
|
|
240
|
+
// agent 绑定不可变,但 model 可换:某模型不行了就换另一个。
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
export const SessionSwitchModelParams = z.object({
|
|
243
|
+
sessionId: SessionId,
|
|
244
|
+
/** 新模型,必须在该 session 绑定 agent 的可用模型列表内。 */
|
|
245
|
+
model: z.string().min(1),
|
|
246
|
+
/**
|
|
247
|
+
* running 时的策略(P1-8):
|
|
248
|
+
* - reject(默认) :running 时拒绝切换,避免 adapter 状态不一致
|
|
249
|
+
* - afterCurrentTurn:等当前 turn 结束后再切
|
|
250
|
+
* - interrupt :打断当前 turn 立即切
|
|
251
|
+
* idle 时忽略此参数,直接切。
|
|
252
|
+
*/
|
|
253
|
+
whenRunning: z.enum(["reject", "afterCurrentTurn", "interrupt"]).default("reject"),
|
|
254
|
+
});
|
|
255
|
+
export type SessionSwitchModelParams = z.infer<typeof SessionSwitchModelParams>;
|
|
256
|
+
|
|
257
|
+
export const SessionSwitchModelResult = z.object({
|
|
258
|
+
sessionId: SessionId,
|
|
259
|
+
/** 切换前的模型(便于调用方记录/回滚)。 */
|
|
260
|
+
previousModel: z.string(),
|
|
261
|
+
model: z.string(),
|
|
262
|
+
/**
|
|
263
|
+
* 可选警告(P1-8 / Minimax):adapter 发现潜在不兼容(系统提示格式/tool schema 变化)
|
|
264
|
+
* 时填入,server 据此决定是否继续。
|
|
265
|
+
*/
|
|
266
|
+
warnings: z.array(z.string()).optional(),
|
|
267
|
+
/** 若 whenRunning=afterCurrentTurn 且当时 running,表示已排期未立即生效。 */
|
|
268
|
+
deferred: z.boolean().optional(),
|
|
269
|
+
});
|
|
270
|
+
export type SessionSwitchModelResult = z.infer<typeof SessionSwitchModelResult>;
|
|
271
|
+
|
|
272
|
+
// ---------------------------------------------------------------------------
|
|
273
|
+
// session.status / session.list —— 始终携带 agent 身份
|
|
274
|
+
// ---------------------------------------------------------------------------
|
|
275
|
+
export const SessionMeta = z.object({
|
|
276
|
+
sessionId: SessionId,
|
|
277
|
+
/** 绑定的项目(一等身份,D23)。 */
|
|
278
|
+
project: ProjectId,
|
|
279
|
+
/** 绑定的 agent 身份,全程携带。 */
|
|
280
|
+
agent: AgentId,
|
|
281
|
+
model: z.string(),
|
|
282
|
+
status: SessionStatus,
|
|
283
|
+
/** 当 status=running 时,正在执行的 turnId(服务端据此知道「在跑哪一轮」)。 */
|
|
284
|
+
currentTurnId: z.string().optional(),
|
|
285
|
+
/** 队列中等待的 send 数(whenBusy=queue 积压,D18)。 */
|
|
286
|
+
queuedCount: z.number().int().nonnegative().optional(),
|
|
287
|
+
/**
|
|
288
|
+
* 上下文信息(D33)——adapter 能提供时填,便于 server 监控上下文压力。
|
|
289
|
+
*/
|
|
290
|
+
context: z
|
|
291
|
+
.object({
|
|
292
|
+
/** 上下文窗口总容量(token)。 */
|
|
293
|
+
contextWindow: z.number().int().nonnegative().optional(),
|
|
294
|
+
/** 已用上下文(token,若可估)。 */
|
|
295
|
+
usedTokens: z.number().int().nonnegative().optional(),
|
|
296
|
+
/** 已用上下文占比 0-100。 */
|
|
297
|
+
usagePercent: z.number().min(0).max(100).optional(),
|
|
298
|
+
/** 已发生的压缩次数。 */
|
|
299
|
+
compactions: z.number().int().nonnegative().optional(),
|
|
300
|
+
})
|
|
301
|
+
.optional(),
|
|
302
|
+
verbosity: Verbosity,
|
|
303
|
+
clientTag: z.string().optional(),
|
|
304
|
+
createdAt: Timestamp,
|
|
305
|
+
lastActiveAt: Timestamp.optional(),
|
|
306
|
+
});
|
|
307
|
+
export type SessionMeta = z.infer<typeof SessionMeta>;
|
|
308
|
+
|
|
309
|
+
export const SessionStatusParams = z.object({
|
|
310
|
+
sessionId: SessionId,
|
|
311
|
+
});
|
|
312
|
+
export type SessionStatusParams = z.infer<typeof SessionStatusParams>;
|
|
313
|
+
|
|
314
|
+
export const SessionStatusResult = SessionMeta;
|
|
315
|
+
export type SessionStatusResult = z.infer<typeof SessionStatusResult>;
|
|
316
|
+
|
|
317
|
+
export const SessionListParams = z.object({
|
|
318
|
+
/** 可选:按项目过滤。 */
|
|
319
|
+
project: ProjectId.optional(),
|
|
320
|
+
/** 可选:按 agent 过滤。 */
|
|
321
|
+
agent: AgentId.optional(),
|
|
322
|
+
/** 可选:按状态过滤。 */
|
|
323
|
+
status: SessionStatus.optional(),
|
|
324
|
+
/** 可选:分页上限(P2-14)。 */
|
|
325
|
+
limit: z.number().int().positive().max(500).optional(),
|
|
326
|
+
/** 可选:分页游标(上一页返回的 nextCursor)。 */
|
|
327
|
+
cursor: z.string().optional(),
|
|
328
|
+
});
|
|
329
|
+
export type SessionListParams = z.infer<typeof SessionListParams>;
|
|
330
|
+
|
|
331
|
+
export const SessionListResult = z.object({
|
|
332
|
+
sessions: z.array(SessionMeta),
|
|
333
|
+
/** 下一页游标;缺省/null 表示已到末尾。 */
|
|
334
|
+
nextCursor: z.string().optional(),
|
|
335
|
+
});
|
|
336
|
+
export type SessionListResult = z.infer<typeof SessionListResult>;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AgentId, ProjectId, Timestamp } from "./common.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Skill 管理协议(design D24)。
|
|
6
|
+
*
|
|
7
|
+
* 给指定 agent 安装/卸载 skill,支持两级 scope:
|
|
8
|
+
* - global : agent 全局,对该 agent 所有项目可见
|
|
9
|
+
* - project : 项目级,仅对某 projectId 可见(需 projectId)
|
|
10
|
+
*
|
|
11
|
+
* 每个 agent 靠 capability `skillManagement` 声明是否支持;不支持 → errCapabilityUnsupported。
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export const SkillScope = z.enum(["global", "project"]);
|
|
15
|
+
export type SkillScope = z.infer<typeof SkillScope>;
|
|
16
|
+
|
|
17
|
+
/** skill 来源:内联内容、本地路径、或远端引用。 */
|
|
18
|
+
export const SkillSource = z.union([
|
|
19
|
+
z.object({ kind: z.literal("inline"), files: z.record(z.string()) }), // path → content
|
|
20
|
+
z.object({
|
|
21
|
+
kind: z.literal("archive"),
|
|
22
|
+
/** v0 先支持 tar.gz;zip/archiveUrl 后续再加,避免安全边界没收稳。 */
|
|
23
|
+
format: z.literal("tar.gz"),
|
|
24
|
+
contentBase64: z.string().min(1),
|
|
25
|
+
/** 强烈建议传;phonon 会校验内容 hash,防传输/供应链篡改。 */
|
|
26
|
+
sha256: z.string().optional(),
|
|
27
|
+
/** 可选大小提示,便于 policy/日志;实际大小以 decode 后为准。 */
|
|
28
|
+
sizeBytes: z.number().int().positive().optional(),
|
|
29
|
+
}),
|
|
30
|
+
z.object({ kind: z.literal("localPath"), path: z.string().min(1) }),
|
|
31
|
+
z.object({
|
|
32
|
+
kind: z.literal("url"),
|
|
33
|
+
url: z.string().min(1),
|
|
34
|
+
/** 可选:内容校验和(P2-12 / 供应链可信度)。url 装需 policy allowUrlSkillInstall。 */
|
|
35
|
+
sha256: z.string().optional(),
|
|
36
|
+
}),
|
|
37
|
+
]);
|
|
38
|
+
export type SkillSource = z.infer<typeof SkillSource>;
|
|
39
|
+
|
|
40
|
+
/** 已安装 skill 的描述。 */
|
|
41
|
+
export const SkillDescriptor = z.object({
|
|
42
|
+
/** skill 名/key。 */
|
|
43
|
+
name: z.string().min(1),
|
|
44
|
+
/** 归属哪个 agent。 */
|
|
45
|
+
agent: AgentId,
|
|
46
|
+
scope: SkillScope,
|
|
47
|
+
/** scope=project 时所属项目。 */
|
|
48
|
+
projectId: ProjectId.optional(),
|
|
49
|
+
/** 版本(P2-12,同名冲突可辨)。 */
|
|
50
|
+
version: z.string().optional(),
|
|
51
|
+
/** 内容 hash(P2-12,可复现/防篡改)。 */
|
|
52
|
+
hash: z.string().optional(),
|
|
53
|
+
/** 适配的 agent(某些 skill 只适 OpenClaw 不适 Codex)。 */
|
|
54
|
+
compatibleAgents: z.array(AgentId).optional(),
|
|
55
|
+
/** 来源是否可信(本地/内联=可信,url=需校验)。 */
|
|
56
|
+
sourceTrusted: z.boolean().optional(),
|
|
57
|
+
/** 安装落地路径(设备本地)。 */
|
|
58
|
+
installedPath: z.string().optional(),
|
|
59
|
+
installedAt: Timestamp.optional(),
|
|
60
|
+
});
|
|
61
|
+
export type SkillDescriptor = z.infer<typeof SkillDescriptor>;
|
|
62
|
+
|
|
63
|
+
// --- skill.install ---
|
|
64
|
+
export const SkillInstallParams = z
|
|
65
|
+
.object({
|
|
66
|
+
/** 目标 agent。 */
|
|
67
|
+
agent: AgentId,
|
|
68
|
+
name: z.string().min(1),
|
|
69
|
+
scope: SkillScope,
|
|
70
|
+
/** scope=project 时必填。 */
|
|
71
|
+
projectId: ProjectId.optional(),
|
|
72
|
+
source: SkillSource,
|
|
73
|
+
})
|
|
74
|
+
.refine((v) => v.scope !== "project" || !!v.projectId, {
|
|
75
|
+
message: "scope=project requires projectId",
|
|
76
|
+
path: ["projectId"],
|
|
77
|
+
});
|
|
78
|
+
export type SkillInstallParams = z.infer<typeof SkillInstallParams>;
|
|
79
|
+
|
|
80
|
+
export const SkillInstallResult = z.object({
|
|
81
|
+
skill: SkillDescriptor,
|
|
82
|
+
});
|
|
83
|
+
export type SkillInstallResult = z.infer<typeof SkillInstallResult>;
|
|
84
|
+
|
|
85
|
+
// --- skill.uninstall ---
|
|
86
|
+
export const SkillUninstallParams = z
|
|
87
|
+
.object({
|
|
88
|
+
agent: AgentId,
|
|
89
|
+
name: z.string().min(1),
|
|
90
|
+
scope: SkillScope,
|
|
91
|
+
projectId: ProjectId.optional(),
|
|
92
|
+
})
|
|
93
|
+
.refine((v) => v.scope !== "project" || !!v.projectId, {
|
|
94
|
+
message: "scope=project requires projectId",
|
|
95
|
+
path: ["projectId"],
|
|
96
|
+
});
|
|
97
|
+
export type SkillUninstallParams = z.infer<typeof SkillUninstallParams>;
|
|
98
|
+
|
|
99
|
+
export const SkillUninstallResult = z.object({
|
|
100
|
+
agent: AgentId,
|
|
101
|
+
name: z.string(),
|
|
102
|
+
scope: SkillScope,
|
|
103
|
+
uninstalled: z.literal(true),
|
|
104
|
+
});
|
|
105
|
+
export type SkillUninstallResult = z.infer<typeof SkillUninstallResult>;
|
|
106
|
+
|
|
107
|
+
// --- skill.list ---
|
|
108
|
+
export const SkillListParams = z.object({
|
|
109
|
+
/** 可选:按 agent 过滤。 */
|
|
110
|
+
agent: AgentId.optional(),
|
|
111
|
+
/** 可选:按 scope 过滤。 */
|
|
112
|
+
scope: SkillScope.optional(),
|
|
113
|
+
/** 可选:按项目过滤(看某项目可见的 skill)。 */
|
|
114
|
+
projectId: ProjectId.optional(),
|
|
115
|
+
});
|
|
116
|
+
export type SkillListParams = z.infer<typeof SkillListParams>;
|
|
117
|
+
|
|
118
|
+
export const SkillListResult = z.object({
|
|
119
|
+
skills: z.array(SkillDescriptor),
|
|
120
|
+
});
|
|
121
|
+
export type SkillListResult = z.infer<typeof SkillListResult>;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { SessionId, Timestamp } from "./common.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 流式事件(design §4 / §6 / 订阅模型)——phonon → server 异步推送。
|
|
6
|
+
*
|
|
7
|
+
* 关键:session 不只是「请求-响应」,还是一条**可订阅的持续输出流**。
|
|
8
|
+
* 输出分两种来源(origin):
|
|
9
|
+
* - solicited :某次 session.send 触发的响应(用 send 返回的 turnId)。
|
|
10
|
+
* - unsolicited:agent 自发输出(OpenClaw 的 cron/定时/心跳),无 send 触发;
|
|
11
|
+
* turnId 由 phonon 生成,source 标明冲泡来源。
|
|
12
|
+
*
|
|
13
|
+
* “create 即订阅”:server 拥有的 session 的**所有** stream.event(含自发)都自动
|
|
14
|
+
* 推给该 tenant 连接,无需显式 subscribe。Codex 一次性 session 流到 result final 就停;
|
|
15
|
+
* OpenClaw 持久 session 即使不 send 也会持续往上冒。
|
|
16
|
+
*
|
|
17
|
+
* 不同事件对应不同 verbosity 档位:
|
|
18
|
+
* final → 只会收到 result
|
|
19
|
+
* messages → message + result
|
|
20
|
+
* tools → message + tool_call + tool_result + result
|
|
21
|
+
* trace → 以上 + thinking + token delta
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/** 输出来源:请求触发 vs agent 自发。 */
|
|
25
|
+
export const StreamOrigin = z.enum(["solicited", "unsolicited"]);
|
|
26
|
+
export type StreamOrigin = z.infer<typeof StreamOrigin>;
|
|
27
|
+
|
|
28
|
+
/** 事件种类。 */
|
|
29
|
+
export const StreamEventType = z.enum([
|
|
30
|
+
"message", // 一条完整/增量消息文本
|
|
31
|
+
"thinking", // 思考过程(trace 档)
|
|
32
|
+
"tool_call", // agent 发起工具调用
|
|
33
|
+
"tool_result", // 工具返回
|
|
34
|
+
"token", // 增量 token(流式打字机,trace/可选)
|
|
35
|
+
"result", // 本轮最终结果(终止事件)
|
|
36
|
+
"error", // 本轮出错(终止事件)
|
|
37
|
+
]);
|
|
38
|
+
export type StreamEventType = z.infer<typeof StreamEventType>;
|
|
39
|
+
|
|
40
|
+
const StreamEventBase = z.object({
|
|
41
|
+
sessionId: SessionId,
|
|
42
|
+
/**
|
|
43
|
+
* 本轮关联 id。solicited 事件用 send 返回的 turnId;
|
|
44
|
+
* unsolicited(自发)事件由 phonon 生成,server 从事件中首次见到。
|
|
45
|
+
*/
|
|
46
|
+
turnId: z.string(),
|
|
47
|
+
/** 输出来源:默认 solicited;agent 自发为 unsolicited。 */
|
|
48
|
+
origin: StreamOrigin.default("solicited"),
|
|
49
|
+
/** unsolicited 时的冲泡来源标签,如 "cron" / "scheduled" / "heartbeat"。 */
|
|
50
|
+
source: z.string().optional(),
|
|
51
|
+
/** 单调递增序号(按 session),保证调用方可排序/去重。 */
|
|
52
|
+
seq: z.number().int().nonnegative(),
|
|
53
|
+
at: Timestamp,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export const StreamMessageEvent = StreamEventBase.extend({
|
|
57
|
+
type: z.literal("message"),
|
|
58
|
+
role: z.enum(["assistant", "user", "system"]).default("assistant"),
|
|
59
|
+
text: z.string(),
|
|
60
|
+
/** 是否为增量分片(true 表示需要与同 turn 的后续 message 拼接)。 */
|
|
61
|
+
delta: z.boolean().default(false),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export const StreamThinkingEvent = StreamEventBase.extend({
|
|
65
|
+
type: z.literal("thinking"),
|
|
66
|
+
text: z.string(),
|
|
67
|
+
delta: z.boolean().default(false),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
export const StreamToolCallEvent = StreamEventBase.extend({
|
|
71
|
+
type: z.literal("tool_call"),
|
|
72
|
+
toolName: z.string(),
|
|
73
|
+
/** 工具入参(原样透传,结构由 agent/工具决定)。 */
|
|
74
|
+
args: z.unknown().optional(),
|
|
75
|
+
/** 工具调用 id,用于和 tool_result 配对。 */
|
|
76
|
+
toolCallId: z.string().optional(),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export const StreamToolResultEvent = StreamEventBase.extend({
|
|
80
|
+
type: z.literal("tool_result"),
|
|
81
|
+
toolName: z.string(),
|
|
82
|
+
toolCallId: z.string().optional(),
|
|
83
|
+
ok: z.boolean(),
|
|
84
|
+
/** 工具输出(可能被截断,取决于 verbosity/大小限制)。 */
|
|
85
|
+
output: z.unknown().optional(),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
export const StreamTokenEvent = StreamEventBase.extend({
|
|
89
|
+
type: z.literal("token"),
|
|
90
|
+
text: z.string(),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
export const StreamResultEvent = StreamEventBase.extend({
|
|
94
|
+
type: z.literal("result"),
|
|
95
|
+
/** 本轮最终文本结果。 */
|
|
96
|
+
text: z.string(),
|
|
97
|
+
/** 可选 usage 统计。 */
|
|
98
|
+
usage: z
|
|
99
|
+
.object({
|
|
100
|
+
inputTokens: z.number().int().nonnegative().optional(),
|
|
101
|
+
outputTokens: z.number().int().nonnegative().optional(),
|
|
102
|
+
})
|
|
103
|
+
.optional(),
|
|
104
|
+
/**
|
|
105
|
+
* 本轮终态(P0-2)——每个 turn 必须有明确终态,服务端状态机才不会悬空:
|
|
106
|
+
* completed 正常完成
|
|
107
|
+
* interrupted 被 session.interrupt 打断
|
|
108
|
+
* aborted 被 hook abort / 主动中止
|
|
109
|
+
* failed 出错终止(详情另见 error 事件)
|
|
110
|
+
* timeout 超时
|
|
111
|
+
*/
|
|
112
|
+
status: z.enum(["completed", "interrupted", "aborted", "failed", "timeout"]).default("completed"),
|
|
113
|
+
/** 标记本轮结束。 */
|
|
114
|
+
final: z.literal(true),
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
export const StreamErrorEvent = StreamEventBase.extend({
|
|
118
|
+
type: z.literal("error"),
|
|
119
|
+
message: z.string(),
|
|
120
|
+
/** 可选应用错误码(与 common.PhononErrorCode 对齐)。 */
|
|
121
|
+
appCode: z.string().optional(),
|
|
122
|
+
/** 终态(与 result.status 对齐,错误场景通常 failed/aborted/timeout)。 */
|
|
123
|
+
status: z.enum(["failed", "aborted", "timeout", "interrupted"]).default("failed"),
|
|
124
|
+
final: z.literal(true),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// stream.ack —— server → phonon,确认已收到 seq <= lastSeq(P0-4)
|
|
129
|
+
// 让 phonon 能清理 outbox / 控制背压;可按 session 粒度或全局。
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
export const StreamAckParams = z.object({
|
|
132
|
+
/** 按 session 确认;缺省表示该连接全局。 */
|
|
133
|
+
sessionId: SessionId.optional(),
|
|
134
|
+
/** 已收到的最大连续 seq(含);phonon 可清理 <= 此值的 outbox。 */
|
|
135
|
+
lastSeq: z.number().int().nonnegative(),
|
|
136
|
+
});
|
|
137
|
+
export type StreamAckParams = z.infer<typeof StreamAckParams>;
|
|
138
|
+
|
|
139
|
+
/** 流式事件联合体(phonon → server,方法名 stream.event)。 */
|
|
140
|
+
export const StreamEvent = z.discriminatedUnion("type", [
|
|
141
|
+
StreamMessageEvent,
|
|
142
|
+
StreamThinkingEvent,
|
|
143
|
+
StreamToolCallEvent,
|
|
144
|
+
StreamToolResultEvent,
|
|
145
|
+
StreamTokenEvent,
|
|
146
|
+
StreamResultEvent,
|
|
147
|
+
StreamErrorEvent,
|
|
148
|
+
]);
|
|
149
|
+
export type StreamEvent = z.infer<typeof StreamEvent>;
|