@1agents/dreammate-network 0.1.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/README.md +58 -0
- package/dist/typescript/types.d.ts +210 -0
- package/dist/typescript/types.js +11 -0
- package/docs/protocol.md +221 -0
- package/package.json +51 -0
- package/schemas/execution.schema.json +107 -0
- package/schemas/node.schema.json +81 -0
- package/schemas/service.schema.json +119 -0
- package/schemas/session-ref.schema.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# dreammate-network
|
|
2
|
+
|
|
3
|
+
> DreamMate Network 的 **L0 协议包**:schema + types,零依赖,**不含业务逻辑**。
|
|
4
|
+
> 版本 0.1.0 | 状态:草案
|
|
5
|
+
|
|
6
|
+
判断改动该不该进这个包,只看一条:
|
|
7
|
+
|
|
8
|
+
> 它是所有 repo 都要共用的**词汇**,还是某一方的**行为**?
|
|
9
|
+
> 是词汇 → 进来。是行为 → 出去。
|
|
10
|
+
|
|
11
|
+
## 内容
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
dreammate-network/
|
|
15
|
+
├── schemas/ JSON Schema (draft 2020-12),唯一事实源
|
|
16
|
+
│ ├── node.schema.json
|
|
17
|
+
│ ├── service.schema.json
|
|
18
|
+
│ ├── execution.schema.json
|
|
19
|
+
│ └── session-ref.schema.json
|
|
20
|
+
├── typescript/types.ts 上述 schema 的 TS 投影,纯类型
|
|
21
|
+
├── docs/protocol.md 协议正文
|
|
22
|
+
└── package.json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 用
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import type { NodeManifest, Execution, SessionURI } from "dreammate-network";
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Go / Swift 侧读同一份 `schemas/*.json`。详见 [`docs/protocol.md` §9](docs/protocol.md)。
|
|
32
|
+
|
|
33
|
+
## 三条不能破的规则
|
|
34
|
+
|
|
35
|
+
| 规则 | 破了会怎样 |
|
|
36
|
+
|------|-----------|
|
|
37
|
+
| **Node ≠ Agent** | 无 Agent 的录音硬件就进不了网络 |
|
|
38
|
+
| **Capability ≠ Resource** | 调度侧与检索侧路径缠在一起 |
|
|
39
|
+
| **Execution 不含 `task_id`** | 体外循环(想到了直接干)变成非法状态 |
|
|
40
|
+
|
|
41
|
+
## 依赖规则
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
L4 ──→ L3 ──→ L2 / L1 ──→ L0
|
|
45
|
+
|
|
46
|
+
✅ 任何层都可以 import L0
|
|
47
|
+
❌ L0 不 import 任何人
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
一条实操检查:**如果 A 需要 `go.mod replace` 或 `file:../` 才能用 B,说明 A 和 B 没解耦。**
|
|
51
|
+
|
|
52
|
+
## 出处
|
|
53
|
+
|
|
54
|
+
设计册是 1agents 工作区里的 `docs/architecture/dreammate-network/`(10 篇,不随本包发布)。
|
|
55
|
+
本包对应其中迁移步骤 **S1**(09-仓库拆分与依赖边界 §8)。
|
|
56
|
+
|
|
57
|
+
下一步是 **S2**(`modules/*` 上移)与 **S3**(session-reader 加 `1session serve` + `/manifest`)——
|
|
58
|
+
S1–S3 就足够跑出 M1 + M2,不需要等全部拆完。
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DreamMate Network — L0 协议类型
|
|
3
|
+
*
|
|
4
|
+
* 这是所有 repo 共享的「公共语言」,零依赖、不含任何业务逻辑。
|
|
5
|
+
* 每一个类型都与 ../schemas/*.json 一一对应,改动必须同步两边。
|
|
6
|
+
*
|
|
7
|
+
* 依赖规则(强制单向):任何层都可以 import 本包,本包不 import 任何人。
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
export declare const PROTOCOL_VERSION = "0.1.0";
|
|
12
|
+
/** `session://<node>/<runtime>/<session_id>` */
|
|
13
|
+
export type SessionURI = `session://${string}/${string}/${string}`;
|
|
14
|
+
/** 资源寻址,如 `recording://tingqi-01/abc`、`speaker://tingqi-001/speaker-23` */
|
|
15
|
+
export type ResourceURI = `${string}://${string}`;
|
|
16
|
+
/**
|
|
17
|
+
* 点分命名的能力标识,如 `sessions.read`、`reminders.create`、`recordings.list`。
|
|
18
|
+
*
|
|
19
|
+
* 第一版刻意就是一个字符串——不带 provider / permission / availability 等元数据。
|
|
20
|
+
* 那些留到真的要做 capability 调度时再说。
|
|
21
|
+
*/
|
|
22
|
+
export type Capability = string;
|
|
23
|
+
/** Service 拥有的资源类别(声明 scheme,而不是逐条枚举资源)。 */
|
|
24
|
+
export interface ResourceDescriptor {
|
|
25
|
+
scheme: string;
|
|
26
|
+
description?: string | null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* `mcp` / `cli` / `http` 面向 Capability 与 Resource;
|
|
30
|
+
* `acp` 面向 Agent Runtime 的 Session 控制,与前三者不是一回事。
|
|
31
|
+
*/
|
|
32
|
+
export type Protocol = "mcp" | "http" | "cli" | "acp";
|
|
33
|
+
/**
|
|
34
|
+
* 同一组能力可以同时有多种 access,调用方不必关心底层是谁。
|
|
35
|
+
* 包装优先级 MCP > CLI > HTTP,但第一版不做自动 fallback 编排,手工声明即可。
|
|
36
|
+
*/
|
|
37
|
+
export interface AccessDescriptor {
|
|
38
|
+
protocol: Protocol;
|
|
39
|
+
/** protocol=http:服务基址,如 `http://scott-mac:7777/v1` */
|
|
40
|
+
base_url?: string;
|
|
41
|
+
/** protocol=http:单个 capability 的相对路由,如 `GET /transcripts/:id` */
|
|
42
|
+
endpoint?: string;
|
|
43
|
+
/** protocol=mcp:对应的 tool 名 */
|
|
44
|
+
tool?: string;
|
|
45
|
+
/** protocol=mcp:MCP server 标识 */
|
|
46
|
+
server?: string;
|
|
47
|
+
/** protocol=cli:命令,如 `tingqi transcript get` */
|
|
48
|
+
command?: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 非 generic 的几种在传输层保留原生协议,不强行塞进
|
|
52
|
+
* `POST /capabilities/:name/invoke`。
|
|
53
|
+
*/
|
|
54
|
+
export type ServiceKind = "generic" | "agent_runtime" | "session_registry" | "resource_provider" | "mcp";
|
|
55
|
+
/**
|
|
56
|
+
* Node 上的一组能力聚合。
|
|
57
|
+
*
|
|
58
|
+
* 三层结构是 Node → Service → Capability / Resource,
|
|
59
|
+
* 不要把 Capability 扁平铺到 Node 上。
|
|
60
|
+
*/
|
|
61
|
+
export interface Service {
|
|
62
|
+
id: string;
|
|
63
|
+
name?: string | null;
|
|
64
|
+
/** 省略等同于 `"generic"` */
|
|
65
|
+
kind?: ServiceKind;
|
|
66
|
+
/** 可以为空数组(纯 Resource Provider) */
|
|
67
|
+
capabilities: Capability[];
|
|
68
|
+
resources?: ResourceDescriptor[];
|
|
69
|
+
access?: AccessDescriptor[];
|
|
70
|
+
metadata?: Record<string, unknown>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 节点形态。故意保留 `(string & {})` 开放口——任何硬件都应该能进入同一张网络。
|
|
74
|
+
*/
|
|
75
|
+
export type NodeType = "macos" | "ios" | "linux" | "windows" | "recorder" | "gpu" | (string & {});
|
|
76
|
+
/**
|
|
77
|
+
* 由节点侧 `GET /manifest` 返回,并通过 `POST /nodes/register` 上报给 Control Plane。
|
|
78
|
+
*
|
|
79
|
+
* **Node ≠ Agent。** Node = 一个可以在网络中被发现、声明资源和能力、
|
|
80
|
+
* 接受读取或操作请求的实体。Agent Runtime 只是它可以承载的一种 Service。
|
|
81
|
+
*/
|
|
82
|
+
export interface NodeManifest {
|
|
83
|
+
node_id: string;
|
|
84
|
+
name: string;
|
|
85
|
+
type: NodeType;
|
|
86
|
+
/** tailnet 内的寻址名。第一版所有节点通过 Tailscale 统一寻址。 */
|
|
87
|
+
tailscale_name?: string | null;
|
|
88
|
+
/** 由 Control Plane 依据 heartbeat 维护;节点自报时可省略。 */
|
|
89
|
+
online?: boolean;
|
|
90
|
+
/** 可以为空数组——还没声明任何能力的节点仍然是合法节点。 */
|
|
91
|
+
services: Service[];
|
|
92
|
+
metadata?: Record<string, unknown>;
|
|
93
|
+
}
|
|
94
|
+
/** 不是只有 Agent 才产生 Execution。 */
|
|
95
|
+
export type ExecutionType =
|
|
96
|
+
/** 有 Node / Runtime / Session */
|
|
97
|
+
"agent_execution"
|
|
98
|
+
/** 有 Node / Service / Capability,无 Session */
|
|
99
|
+
| "capability_invocation"
|
|
100
|
+
/** 设备侧任务 */
|
|
101
|
+
| "device_job"
|
|
102
|
+
/** 读取远端资源,无 Agent */
|
|
103
|
+
| "resource_access"
|
|
104
|
+
/** 人在现实中的动作 */
|
|
105
|
+
| "human_action";
|
|
106
|
+
/**
|
|
107
|
+
* `waiting_for_user` 是接入手机后必须新增的一类状态:请求用户在现实世界
|
|
108
|
+
* 做某个动作(确认日程、选联系人、授权 iOS 权限)。有了它,总管才能直接
|
|
109
|
+
* 回答「3 个任务正在执行,1 个等待你确认」。
|
|
110
|
+
*/
|
|
111
|
+
export type ExecutionStatus = "queued" | "running" | "waiting_for_user" | "completed" | "failed";
|
|
112
|
+
/**
|
|
113
|
+
* 现实中实际发生的一次工作行为。
|
|
114
|
+
*
|
|
115
|
+
* 两条硬规则:
|
|
116
|
+
*
|
|
117
|
+
* 1. **这里没有 `task_id`。** Task 关联是独立的 many-to-many link
|
|
118
|
+
* (见 {@link TaskExecutionLink}),绝不允许 `executions.task_id NOT NULL`。
|
|
119
|
+
* 2. **大量字段可空是刻意的**,一个 `capability_invocation` 既没有 session
|
|
120
|
+
* 也没有 runtime。
|
|
121
|
+
*
|
|
122
|
+
* 粒度边界:跨系统 / 跨调度边界才升级为 Execution;Session 内的低层 tool call
|
|
123
|
+
* (`cat README`、`npm test`)记为 Session Event。否则一个 338 次 tool call 的
|
|
124
|
+
* Codex Session 会生成 338 个 Execution,Work Graph 立刻失去意义。
|
|
125
|
+
*/
|
|
126
|
+
export interface Execution {
|
|
127
|
+
id: string;
|
|
128
|
+
type: ExecutionType;
|
|
129
|
+
created_at: string;
|
|
130
|
+
started_at?: string | null;
|
|
131
|
+
finished_at?: string | null;
|
|
132
|
+
status: ExecutionStatus;
|
|
133
|
+
/** status=waiting_for_user 时向用户描述需要他做什么。 */
|
|
134
|
+
requires_user_action?: string | null;
|
|
135
|
+
/** 发起方 Session(通常是总管)。写入时产生 Session --initiates--> Execution。 */
|
|
136
|
+
initiated_by_session_id?: string | null;
|
|
137
|
+
/** 在哪里执行 */
|
|
138
|
+
node_id?: string | null;
|
|
139
|
+
/** 用了该 Node 上的哪个 Service */
|
|
140
|
+
service_id?: string | null;
|
|
141
|
+
/** 调用了哪个 Capability */
|
|
142
|
+
capability?: Capability | null;
|
|
143
|
+
/** 用什么 Agent harness 执行 */
|
|
144
|
+
agent_runtime?: string | null;
|
|
145
|
+
/** 这次推理用谁 */
|
|
146
|
+
model?: string | null;
|
|
147
|
+
/** 仅 agent_execution 才有。写入时产生 Execution --opens--> Session。 */
|
|
148
|
+
session_id?: string | SessionURI | null;
|
|
149
|
+
/** type=resource_access 时访问的资源。写入时产生 Execution --accesses--> Resource。 */
|
|
150
|
+
resource_uri?: ResourceURI | null;
|
|
151
|
+
/** 子 Agent 派生时写入,形成 Execution --delegates--> Execution。 */
|
|
152
|
+
parent_execution_id?: string | null;
|
|
153
|
+
metadata?: Record<string, unknown>;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* 所有边由调用事件实时写入(B 调用 `sessions.read(A)` 时就写
|
|
157
|
+
* `B --references--> A`),不靠后台扫库猜 DAG。
|
|
158
|
+
*
|
|
159
|
+
* 注意整体 Work Graph **不是** DAG:Session 之间完全可以成环,
|
|
160
|
+
* DAG 只是它的某些投影视图(任务分解树、委派树、Agent spawn 树)。
|
|
161
|
+
*/
|
|
162
|
+
export type EdgeRelation = "references" | "opens" | "initiates" | "delegates" | "produces" | "accesses";
|
|
163
|
+
/**
|
|
164
|
+
* 跨节点引用一个 Session。设备类型不影响 Session Graph——
|
|
165
|
+
* `session://iphone/yima/abc123` 与 `session://mac/codex/01a0907c`
|
|
166
|
+
* 是同等级实体,引用关系完全对称。
|
|
167
|
+
*/
|
|
168
|
+
export interface SessionRef {
|
|
169
|
+
uri: SessionURI;
|
|
170
|
+
/** 冗余字段,便于消费方免解析。 */
|
|
171
|
+
node?: string;
|
|
172
|
+
runtime?: string;
|
|
173
|
+
session_id?: string;
|
|
174
|
+
relation?: EdgeRelation;
|
|
175
|
+
/** 这条边被观察到的时刻。底层只保存事实,不提前做价值判断。 */
|
|
176
|
+
observed_at?: string | null;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Task 与 Execution 的关系是 `0..N ←→ 0..N`:
|
|
180
|
+
*
|
|
181
|
+
* - Task 可以没有 Execution:计划了还没做
|
|
182
|
+
* - Execution 可以没有 Task:直接干了没计划(体外循环,一等公民)
|
|
183
|
+
* - 一个 Task 多个 Execution:Codex 第一轮 → Claude 接力 → Codex review
|
|
184
|
+
* - 一个 Execution 同时推进多个 Task
|
|
185
|
+
*
|
|
186
|
+
* 所以必须是独立关联表,**绝不要**把 task_id 塞进 executions。
|
|
187
|
+
*/
|
|
188
|
+
export interface TaskExecutionLink {
|
|
189
|
+
task_id: string;
|
|
190
|
+
execution_id: string;
|
|
191
|
+
linked_at: string;
|
|
192
|
+
relation?: string;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* 计划状态**不存字段**,由四个时间事实推导:
|
|
196
|
+
* `task_created_at` / `execution_started_at` / `execution_finished_at` /
|
|
197
|
+
* `task_execution_link_created_at`。
|
|
198
|
+
*
|
|
199
|
+
* 这里只给分类命名,协议本身不存储它,也不在 L0 实现推导逻辑——
|
|
200
|
+
* 底层只保存事实,不提前做价值判断。
|
|
201
|
+
*/
|
|
202
|
+
export type PlanningClass =
|
|
203
|
+
/** 计划后执行:link 在 execution 开始前 */
|
|
204
|
+
"planned"
|
|
205
|
+
/** 执行中纳入:link 在 start 与 finish 之间 */
|
|
206
|
+
| "in_flight_captured"
|
|
207
|
+
/** 事后归档:link 在 finish 之后 */
|
|
208
|
+
| "retrospective"
|
|
209
|
+
/** 完全体外:没有任何 task edge */
|
|
210
|
+
| "out_of_plan";
|
package/docs/protocol.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# DreamMate Network Protocol v0.1.0
|
|
2
|
+
|
|
3
|
+
> L0 协议层。**零依赖,不含业务逻辑。**
|
|
4
|
+
> 设计依据:1agents 工作区的 `docs/architecture/dreammate-network/`(10 篇设计册,不随本包发布)
|
|
5
|
+
> 本文件只写「协议是什么」,不写「为什么这么设计」——后者在设计册里。
|
|
6
|
+
|
|
7
|
+
## 1. 定位
|
|
8
|
+
|
|
9
|
+
**DreamMate Network 不是 Agent Network,是 Capability Network。**
|
|
10
|
+
|
|
11
|
+
- **Agent** 负责思考与编排
|
|
12
|
+
- **设备 / 节点** 负责提供能力与数据
|
|
13
|
+
- **Session** 负责留下认知轨迹
|
|
14
|
+
- **Execution** 负责记录现实中到底发生了什么
|
|
15
|
+
- **Task** 负责表达我们原本想做什么(可选,不是执行的前提)
|
|
16
|
+
|
|
17
|
+
本包是四层架构里的 L0,所有其他层都可以 import 它,它不 import 任何人:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
L4 节点宿主 desktop / phone / mini / server
|
|
21
|
+
L3 控制面 control-plane
|
|
22
|
+
L2 服务 session-reader / data-service / tingqi-adapter
|
|
23
|
+
L1 运行时 1acp / HarnessKit / cc-connect / happy-cli
|
|
24
|
+
L0 协议 dreammate-network ← 本包
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 2. 六个核心对象
|
|
28
|
+
|
|
29
|
+
第一版只定义这六个,**Task 是可选关联对象,不是执行链的前置条件**:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
Node 在哪里执行
|
|
33
|
+
Service 节点上的一组能力聚合
|
|
34
|
+
Capability 能做什么
|
|
35
|
+
Resource 拥有什么
|
|
36
|
+
Execution 某一次具体发生的工作行为
|
|
37
|
+
Session 这一次的工作上下文
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
关系:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
Node
|
|
44
|
+
├─ Services
|
|
45
|
+
│ ├─ Capabilities
|
|
46
|
+
│ └─ Resources
|
|
47
|
+
│
|
|
48
|
+
└─ Agent Runtime? (Service 的一种特殊 kind)
|
|
49
|
+
└─ Sessions
|
|
50
|
+
|
|
51
|
+
Execution
|
|
52
|
+
├─ node?
|
|
53
|
+
├─ service?
|
|
54
|
+
├─ session?
|
|
55
|
+
└─ task? ← 可空,且是独立关联表
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
三条不能破的规则:
|
|
59
|
+
|
|
60
|
+
| 规则 | 破了会怎样 |
|
|
61
|
+
|------|-----------|
|
|
62
|
+
| **Node ≠ Agent** | 无 Agent 的录音硬件就进不了网络 |
|
|
63
|
+
| **Capability ≠ Resource** | 调度侧与检索侧路径缠在一起 |
|
|
64
|
+
| **Execution 不含 task_id** | 体外循环(想到了直接干)变成非法状态 |
|
|
65
|
+
|
|
66
|
+
## 3. 四个 Schema
|
|
67
|
+
|
|
68
|
+
| 文件 | 对应类型 | 用在哪 |
|
|
69
|
+
|------|----------|--------|
|
|
70
|
+
| [`schemas/node.schema.json`](../schemas/node.schema.json) | `NodeManifest` | `GET /manifest`、`POST /nodes/register` |
|
|
71
|
+
| [`schemas/service.schema.json`](../schemas/service.schema.json) | `Service`、`AccessDescriptor` | 嵌在 Node Manifest 内 |
|
|
72
|
+
| [`schemas/execution.schema.json`](../schemas/execution.schema.json) | `Execution` | `POST /executions`、`PATCH /executions/:id` |
|
|
73
|
+
| [`schemas/session-ref.schema.json`](../schemas/session-ref.schema.json) | `SessionRef` | 跨机 Session 引用与图的边 |
|
|
74
|
+
|
|
75
|
+
Schema 与 [`typescript/types.ts`](../typescript/types.ts) 一一对应,**改动必须同步两边**。
|
|
76
|
+
|
|
77
|
+
`TaskExecutionLink` 与 `PlanningClass` 只在 types.ts 里,没有对应 schema——
|
|
78
|
+
前者是 Control Plane 侧的存储关系(不在节点间传输),后者是从时间事实推导出的
|
|
79
|
+
分类命名(协议不存储它,也不在 L0 实现推导)。
|
|
80
|
+
|
|
81
|
+
## 4. URI 方案
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
session://<node>/<runtime>/<session_id>
|
|
85
|
+
|
|
86
|
+
session://mac/codex/01a0907c
|
|
87
|
+
session://iphone/yima/abc123
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
资源同理:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
recording://tingqi-01/abc
|
|
94
|
+
transcript://tingqi-01/abc
|
|
95
|
+
speaker://tingqi-001/speaker-23
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`session://iphone/yima/abc123` 与 `session://mac/codex/01a0907c` 是**同等级实体**,
|
|
99
|
+
引用关系完全对称。设备类型不影响 Session Graph。
|
|
100
|
+
|
|
101
|
+
## 5. 节点侧必须实现的接口
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
GET /manifest 返回 NodeManifest
|
|
105
|
+
GET /health
|
|
106
|
+
POST /capabilities/:name/invoke
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
外加向 Control Plane 的三个动作:`register` / `heartbeat` / `update manifest`。
|
|
110
|
+
|
|
111
|
+
**不要为了统一而把一切硬塞进 `/invoke`。** 特殊 Service 保留原生协议:
|
|
112
|
+
|
|
113
|
+
| Service kind | 协议 |
|
|
114
|
+
|--------------|------|
|
|
115
|
+
| `session_registry` | session-reader HTTP(`1session serve`) |
|
|
116
|
+
| `agent_runtime` | ACP |
|
|
117
|
+
| `mcp` | MCP |
|
|
118
|
+
|
|
119
|
+
Capability Manifest 只负责告诉调用方:**我有什么,以及应该怎么访问。**
|
|
120
|
+
|
|
121
|
+
## 6. 传输只出现在 `access` 里
|
|
122
|
+
|
|
123
|
+
数据模型里**不存在** MCP Capability / CLI Capability / HTTP Capability。
|
|
124
|
+
一个 Capability 可以有多种 access,调用方不关心底层是谁:
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"id": "transcripts",
|
|
129
|
+
"capabilities": ["transcript.read"],
|
|
130
|
+
"access": [
|
|
131
|
+
{ "protocol": "mcp", "tool": "transcript_read" },
|
|
132
|
+
{ "protocol": "http", "endpoint": "GET /transcripts/:id" },
|
|
133
|
+
{ "protocol": "cli", "command": "tingqi transcript get" }
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
包装优先级 `MCP > CLI > HTTP`,但**第一版不做自动 fallback 编排**,手工声明即可。
|
|
139
|
+
|
|
140
|
+
`acp` 与前三者不是一回事:MCP/CLI/HTTP 面向 Capability 与 Resource,
|
|
141
|
+
ACP 面向 Agent Runtime 的 Session 控制(`agent.session.new` / `prompt` / `cancel` /
|
|
142
|
+
`status` / `resume`)。
|
|
143
|
+
|
|
144
|
+
## 7. 图的边由事件实时写入
|
|
145
|
+
|
|
146
|
+
不跑后台扫库猜 DAG。调用发生时就写边:
|
|
147
|
+
|
|
148
|
+
| 边 | 何时写 |
|
|
149
|
+
|----|--------|
|
|
150
|
+
| `Session B --references--> Session A` | B 调用 `sessions.read(A)` 时 |
|
|
151
|
+
| `Session O --initiates--> Execution E` | 总管创建执行时 |
|
|
152
|
+
| `Execution E --opens--> Session S` | Agent Session 建立时 |
|
|
153
|
+
| `Execution E1 --delegates--> Execution E2` | 子 Agent 派生时 |
|
|
154
|
+
| `Session A --produces--> Artifact` | 产出时 |
|
|
155
|
+
| `Execution E --accesses--> Resource R` | 访问时 |
|
|
156
|
+
|
|
157
|
+
整体 Work Graph **不是** DAG(Session 之间可以成环);DAG 只是它的投影视图。
|
|
158
|
+
|
|
159
|
+
## 8. Execution 的粒度边界
|
|
160
|
+
|
|
161
|
+
| 层级 | 记录为 |
|
|
162
|
+
|------|--------|
|
|
163
|
+
| Session 内的低层行为(`cat README`、`grep foo`、`npm test`) | Session Event / Tool Call |
|
|
164
|
+
| 跨系统边界、跨调度边界 | **Execution** |
|
|
165
|
+
|
|
166
|
+
否则一个 338 次 tool call 的 Codex Session 会生成 338 个 Execution,
|
|
167
|
+
Work Graph 立刻失去意义。
|
|
168
|
+
|
|
169
|
+
## 9. 怎么消费本包
|
|
170
|
+
|
|
171
|
+
**TypeScript**(工作区内直接引源码,不引入构建链,从而保持真正零依赖):
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import type { NodeManifest, Execution, SessionURI } from "dreammate-network";
|
|
175
|
+
|
|
176
|
+
const manifest: NodeManifest = {
|
|
177
|
+
node_id: "iphone_xxx",
|
|
178
|
+
name: "Scott-iPhone",
|
|
179
|
+
type: "ios",
|
|
180
|
+
services: [
|
|
181
|
+
{ id: "reminders", capabilities: ["reminders.read", "reminders.create"] },
|
|
182
|
+
],
|
|
183
|
+
};
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
pnpm workspace 里加 `"dreammate-network": "workspace:*"`;其他情况用
|
|
187
|
+
`file:` / git 依赖。`exports` 的入口指向 `.ts` 源码,由消费方的 bundler
|
|
188
|
+
(vite / esbuild / tsx / webpack)处理;需要独立 JS 产物时再加 build,第一版不加。
|
|
189
|
+
|
|
190
|
+
**Go / Swift / 其他语言**:读同一份 `schemas/*.json`,手写或代码生成对应结构体。
|
|
191
|
+
schema 是唯一事实源,types.ts 只是它的 TS 投影。
|
|
192
|
+
|
|
193
|
+
**校验**(任意 JSON Schema draft 2020-12 校验器):
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# Node Manifest(-r 带上被 $ref 的 service schema)
|
|
197
|
+
npx -p ajv-cli@5 -p ajv-formats@2 ajv validate --spec=draft2020 -c ajv-formats \
|
|
198
|
+
-s schemas/node.schema.json -r schemas/service.schema.json -d your-manifest.json
|
|
199
|
+
|
|
200
|
+
# Execution / SessionRef 用到 format: date-time,必须带 -c ajv-formats,
|
|
201
|
+
# 否则 ajv 会报 unknown format "date-time"。
|
|
202
|
+
npx -p ajv-cli@5 -p ajv-formats@2 ajv validate --spec=draft2020 -c ajv-formats \
|
|
203
|
+
-s schemas/execution.schema.json -d your-execution.json
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
每个 schema 自带 `examples`,可以直接抽出来当冒烟用例跑。
|
|
207
|
+
|
|
208
|
+
## 10. 第一版明确不做
|
|
209
|
+
|
|
210
|
+
- ❌ 不写任何业务逻辑(本包只是公共语言)
|
|
211
|
+
- ❌ Capability 不带 provider / permission / availability 元数据
|
|
212
|
+
- ❌ 不做自动服务发现(节点手工配 `control_plane`)
|
|
213
|
+
- ❌ 不做 MCP→CLI→HTTP 自动 fallback 编排
|
|
214
|
+
- ❌ 不做 Capability 调度评分
|
|
215
|
+
- ❌ 不要求所有能力统一成 MCP
|
|
216
|
+
- ❌ 不存 `planned = true/false`(由时间事实推导)
|
|
217
|
+
|
|
218
|
+
## 11. 版本
|
|
219
|
+
|
|
220
|
+
`PROTOCOL_VERSION = "0.1.0"`。v0.x 期间 schema 可能破坏性变更,
|
|
221
|
+
以设计册 06-实施路线图的 M1–M5 验收结果为准收敛。
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@1agents/dreammate-network",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "DreamMate Network L0 协议包:schema + types,零运行时依赖,不含业务逻辑。",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dreammate",
|
|
7
|
+
"capability-network",
|
|
8
|
+
"node-manifest",
|
|
9
|
+
"json-schema",
|
|
10
|
+
"protocol"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/scottzx/dreammate-network.git"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "./dist/typescript/types.js",
|
|
19
|
+
"types": "./dist/typescript/types.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/typescript/types.d.ts",
|
|
23
|
+
"import": "./dist/typescript/types.js"
|
|
24
|
+
},
|
|
25
|
+
"./schemas/*.json": "./schemas/*.json",
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"schemas",
|
|
31
|
+
"docs",
|
|
32
|
+
"README.md"
|
|
33
|
+
],
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc -p tsconfig.json",
|
|
37
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
38
|
+
"test": "node --test test/schemas.test.js",
|
|
39
|
+
"prepack": "npm run build"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=22.5"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"typescript": "^5.7.2"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public",
|
|
49
|
+
"registry": "https://registry.npmjs.org"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://dreammate.work/schemas/execution.schema.json",
|
|
4
|
+
"title": "DreamMate Execution",
|
|
5
|
+
"description": "现实中实际发生的一次工作行为。不是只有 Agent 才产生 Execution。注意两条硬规则:(1) 这里没有 task_id——Task 关联是独立的 many-to-many link,绝不允许 executions.task_id NOT NULL;(2) 大量字段可空是刻意的,一个 capability_invocation 既没有 session 也没有 runtime。粒度边界:跨系统/跨调度边界才升级为 Execution,Session 内的低层 tool call 记为 Session Event,否则一个 338 次 tool call 的 Codex Session 会生成 338 个 Execution,Work Graph 立刻失去意义。",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["id", "type", "created_at", "status"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"id": { "type": "string", "minLength": 1 },
|
|
10
|
+
"type": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"enum": [
|
|
13
|
+
"agent_execution",
|
|
14
|
+
"capability_invocation",
|
|
15
|
+
"device_job",
|
|
16
|
+
"resource_access",
|
|
17
|
+
"human_action"
|
|
18
|
+
],
|
|
19
|
+
"description": "agent_execution 有 Node/Runtime/Session;capability_invocation 有 Node/Service/Capability 但无 Session;resource_access 读远端资源;human_action 是人在现实中的动作。"
|
|
20
|
+
},
|
|
21
|
+
"created_at": { "type": "string", "format": "date-time" },
|
|
22
|
+
"started_at": { "type": ["string", "null"], "format": "date-time" },
|
|
23
|
+
"finished_at": { "type": ["string", "null"], "format": "date-time" },
|
|
24
|
+
"status": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"enum": ["queued", "running", "waiting_for_user", "completed", "failed"],
|
|
27
|
+
"description": "waiting_for_user 是手机接入后必须新增的一类状态:请求用户在现实世界做某个动作(确认日程、选联系人、授权 iOS 权限)。有了它,总管才能直接回答『3 个任务正在执行,1 个等待你确认』。"
|
|
28
|
+
},
|
|
29
|
+
"requires_user_action": {
|
|
30
|
+
"type": ["string", "null"],
|
|
31
|
+
"description": "status=waiting_for_user 时向用户描述需要他做什么。",
|
|
32
|
+
"examples": ["请选择要添加到日历的地点"]
|
|
33
|
+
},
|
|
34
|
+
"initiated_by_session_id": {
|
|
35
|
+
"type": ["string", "null"],
|
|
36
|
+
"description": "发起这次执行的 Session(通常是总管 Session)。写入时同时产生一条 Session --initiates--> Execution 的边。"
|
|
37
|
+
},
|
|
38
|
+
"node_id": { "type": ["string", "null"], "description": "在哪里执行。" },
|
|
39
|
+
"service_id": { "type": ["string", "null"], "description": "用了该 Node 上的哪个 Service。" },
|
|
40
|
+
"capability": { "type": ["string", "null"], "description": "调用了哪个 Capability。" },
|
|
41
|
+
"agent_runtime": {
|
|
42
|
+
"type": ["string", "null"],
|
|
43
|
+
"description": "用什么 Agent harness 执行。与 node / model / session 正交——同一个 runtime 换模型换节点仍是同一个 runtime。",
|
|
44
|
+
"examples": ["codex", "claude", "yima"]
|
|
45
|
+
},
|
|
46
|
+
"model": {
|
|
47
|
+
"type": ["string", "null"],
|
|
48
|
+
"description": "这次推理用谁。",
|
|
49
|
+
"examples": ["deepseek-chat"]
|
|
50
|
+
},
|
|
51
|
+
"session_id": {
|
|
52
|
+
"type": ["string", "null"],
|
|
53
|
+
"description": "该 Execution 打开的 Session,仅 agent_execution 才有。可以是本地 id 或 session:// URI。写入时产生 Execution --opens--> Session 的边。"
|
|
54
|
+
},
|
|
55
|
+
"resource_uri": {
|
|
56
|
+
"type": ["string", "null"],
|
|
57
|
+
"description": "type=resource_access 时访问的资源。写入时产生 Execution --accesses--> Resource 的边。",
|
|
58
|
+
"examples": ["recording://tingqi-01/abc", "transcript://tingqi-01/abc"]
|
|
59
|
+
},
|
|
60
|
+
"parent_execution_id": {
|
|
61
|
+
"type": ["string", "null"],
|
|
62
|
+
"description": "父执行。子 Agent 派生时写入,形成 Execution --delegates--> Execution 的边。"
|
|
63
|
+
},
|
|
64
|
+
"metadata": { "type": "object", "additionalProperties": true }
|
|
65
|
+
},
|
|
66
|
+
"examples": [
|
|
67
|
+
{
|
|
68
|
+
"id": "E27",
|
|
69
|
+
"type": "capability_invocation",
|
|
70
|
+
"created_at": "2026-09-14T10:00:00Z",
|
|
71
|
+
"status": "completed",
|
|
72
|
+
"node_id": "iphone_xxx",
|
|
73
|
+
"service_id": "reminders",
|
|
74
|
+
"capability": "reminders.create"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "E28",
|
|
78
|
+
"type": "resource_access",
|
|
79
|
+
"created_at": "2026-09-14T10:01:00Z",
|
|
80
|
+
"status": "completed",
|
|
81
|
+
"node_id": "recorder_xxx",
|
|
82
|
+
"service_id": "recordings",
|
|
83
|
+
"capability": "recordings.list",
|
|
84
|
+
"resource_uri": "recording://tingqi-01/abc"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"id": "E29",
|
|
88
|
+
"type": "agent_execution",
|
|
89
|
+
"created_at": "2026-09-14T10:02:00Z",
|
|
90
|
+
"status": "running",
|
|
91
|
+
"node_id": "node_yyy",
|
|
92
|
+
"agent_runtime": "codex",
|
|
93
|
+
"model": "deepseek-chat",
|
|
94
|
+
"session_id": "session://mac/codex/01a0907c"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"id": "E5",
|
|
98
|
+
"type": "capability_invocation",
|
|
99
|
+
"created_at": "2026-09-14T10:03:00Z",
|
|
100
|
+
"status": "waiting_for_user",
|
|
101
|
+
"requires_user_action": "请选择要添加到日历的地点",
|
|
102
|
+
"node_id": "iphone_xxx",
|
|
103
|
+
"service_id": "calendar",
|
|
104
|
+
"capability": "calendar.create"
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://dreammate.work/schemas/node.schema.json",
|
|
4
|
+
"title": "DreamMate Node Manifest",
|
|
5
|
+
"description": "一个 Node 对外声明自己的身份、在线状态与所提供的 Services。Node ≠ Agent:Agent Runtime 只是 Node 可以承载的一种 Service,不是 Node 存在的必要条件。由节点侧 GET /manifest 返回,并通过 POST /nodes/register 上报给 Control Plane。",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["node_id", "name", "type", "services"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"node_id": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "网络内全局唯一且稳定的节点标识,重启不变。",
|
|
12
|
+
"minLength": 1,
|
|
13
|
+
"examples": ["node_yyy", "iphone_xxx", "recorder_xxx"]
|
|
14
|
+
},
|
|
15
|
+
"name": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "人类可读名称。",
|
|
18
|
+
"minLength": 1,
|
|
19
|
+
"examples": ["scott-mac", "Scott-iPhone", "听器-01", "dgx-spark"]
|
|
20
|
+
},
|
|
21
|
+
"type": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "节点形态。故意不用 enum 封死——任何硬件都应该能进入同一张网络。已知取值:macos / ios / linux / windows / recorder / gpu。",
|
|
24
|
+
"minLength": 1,
|
|
25
|
+
"examples": ["macos", "ios", "recorder", "gpu"]
|
|
26
|
+
},
|
|
27
|
+
"tailscale_name": {
|
|
28
|
+
"type": ["string", "null"],
|
|
29
|
+
"description": "tailnet 内的寻址名。第一版所有节点通过 Tailscale 统一寻址。"
|
|
30
|
+
},
|
|
31
|
+
"online": {
|
|
32
|
+
"type": "boolean",
|
|
33
|
+
"description": "由 Control Plane 依据 heartbeat 维护;节点自报时可省略。"
|
|
34
|
+
},
|
|
35
|
+
"services": {
|
|
36
|
+
"type": "array",
|
|
37
|
+
"description": "该节点上的 Service 列表。可以为空数组——一个还没声明任何能力的节点仍然是合法节点。",
|
|
38
|
+
"items": { "$ref": "service.schema.json" }
|
|
39
|
+
},
|
|
40
|
+
"metadata": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"description": "节点级自由扩展字段(如 GPU 显存、架构、固件版本)。协议不解释其内容。",
|
|
43
|
+
"additionalProperties": true
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"examples": [
|
|
47
|
+
{
|
|
48
|
+
"node_id": "node_yyy",
|
|
49
|
+
"name": "scott-mac",
|
|
50
|
+
"type": "macos",
|
|
51
|
+
"tailscale_name": "scott-mac",
|
|
52
|
+
"online": true,
|
|
53
|
+
"services": [
|
|
54
|
+
{
|
|
55
|
+
"id": "session-registry",
|
|
56
|
+
"kind": "session_registry",
|
|
57
|
+
"capabilities": ["sessions.list", "sessions.search", "sessions.read", "sessions.graph"],
|
|
58
|
+
"access": [{ "protocol": "http", "base_url": "http://scott-mac:7777/v1" }]
|
|
59
|
+
},
|
|
60
|
+
{ "id": "shell", "capabilities": ["shell.exec"] }
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"node_id": "iphone_xxx",
|
|
65
|
+
"name": "Scott-iPhone",
|
|
66
|
+
"type": "ios",
|
|
67
|
+
"services": [
|
|
68
|
+
{ "id": "calendar", "capabilities": ["calendar.read", "calendar.create"] },
|
|
69
|
+
{ "id": "reminders", "capabilities": ["reminders.read", "reminders.create"] }
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"node_id": "recorder_xxx",
|
|
74
|
+
"name": "听器-01",
|
|
75
|
+
"type": "recorder",
|
|
76
|
+
"services": [
|
|
77
|
+
{ "id": "recordings", "capabilities": ["recordings.list", "recordings.read"] }
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://dreammate.work/schemas/service.schema.json",
|
|
4
|
+
"title": "DreamMate Service",
|
|
5
|
+
"description": "Node 上的一组能力聚合。三层结构是 Node → Service → Capability / Resource,不要把 Capability 扁平铺到 Node 上。Agent Runtime 是 Service 的一种特殊 kind。",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["id", "capabilities"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"id": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Service 在所属 Node 内唯一。",
|
|
12
|
+
"minLength": 1,
|
|
13
|
+
"examples": ["session-registry", "reminders", "recordings", "agent-runtime"]
|
|
14
|
+
},
|
|
15
|
+
"name": {
|
|
16
|
+
"type": ["string", "null"],
|
|
17
|
+
"description": "人类可读名称,可省略。"
|
|
18
|
+
},
|
|
19
|
+
"kind": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"description": "Service 类型。generic 之外的几种在传输层保留原生协议(见 protocol.md §5),不强行塞进 /capabilities/:name/invoke。",
|
|
22
|
+
"enum": ["generic", "agent_runtime", "session_registry", "resource_provider", "mcp"],
|
|
23
|
+
"default": "generic"
|
|
24
|
+
},
|
|
25
|
+
"capabilities": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"description": "该 Service 能做什么。第一版就是点分命名的字符串,不带权限/可用性等元数据。可以为空数组(纯 Resource Provider)。",
|
|
28
|
+
"items": { "type": "string", "minLength": 1 },
|
|
29
|
+
"examples": [["sessions.list", "sessions.read"], ["reminders.create"], ["recordings.list", "recording.read"]]
|
|
30
|
+
},
|
|
31
|
+
"resources": {
|
|
32
|
+
"type": "array",
|
|
33
|
+
"description": "该 Service 拥有什么(可选,声明资源 URI 的 scheme 而非逐条枚举)。Capability=能做什么,Resource=拥有什么,两者不要混:检索侧走 resource.search/read,调度侧走 capability.invoke。",
|
|
34
|
+
"items": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"required": ["scheme"],
|
|
37
|
+
"properties": {
|
|
38
|
+
"scheme": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"description": "资源 URI 的 scheme。",
|
|
41
|
+
"examples": ["recording", "transcript", "speaker", "session"]
|
|
42
|
+
},
|
|
43
|
+
"description": { "type": ["string", "null"] }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"access": {
|
|
48
|
+
"type": "array",
|
|
49
|
+
"description": "怎么访问这个 Service。传输方式只出现在这里,绝不进数据模型——不存在所谓 MCP Capability / CLI Capability。同一组能力可以同时有多种 access,调用方不必关心底层是谁。包装优先级 MCP > CLI > HTTP,但第一版不做自动 fallback 编排,手工声明即可。",
|
|
50
|
+
"items": { "$ref": "#/$defs/access" }
|
|
51
|
+
},
|
|
52
|
+
"metadata": {
|
|
53
|
+
"type": "object",
|
|
54
|
+
"description": "Service 级自由扩展字段。协议不解释其内容。",
|
|
55
|
+
"additionalProperties": true
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"$defs": {
|
|
59
|
+
"access": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"title": "Access Descriptor",
|
|
62
|
+
"required": ["protocol"],
|
|
63
|
+
"properties": {
|
|
64
|
+
"protocol": {
|
|
65
|
+
"type": "string",
|
|
66
|
+
"enum": ["mcp", "http", "cli", "acp"],
|
|
67
|
+
"description": "acp 只用于 kind=agent_runtime 的 Session 控制,与前三者不是一回事:MCP/CLI/HTTP 面向 Capability / Resource,ACP 面向 Agent Runtime / Session Control。"
|
|
68
|
+
},
|
|
69
|
+
"base_url": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"description": "protocol=http 时的服务基址。",
|
|
72
|
+
"examples": ["http://scott-mac:7777/v1"]
|
|
73
|
+
},
|
|
74
|
+
"endpoint": {
|
|
75
|
+
"type": "string",
|
|
76
|
+
"description": "protocol=http 时单个 capability 的相对路由。",
|
|
77
|
+
"examples": ["GET /transcripts/:id"]
|
|
78
|
+
},
|
|
79
|
+
"tool": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"description": "protocol=mcp 时对应的 tool 名。",
|
|
82
|
+
"examples": ["transcript_read"]
|
|
83
|
+
},
|
|
84
|
+
"server": {
|
|
85
|
+
"type": "string",
|
|
86
|
+
"description": "protocol=mcp 时的 MCP server 标识。"
|
|
87
|
+
},
|
|
88
|
+
"command": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"description": "protocol=cli 时的命令。",
|
|
91
|
+
"examples": ["tingqi transcript get", "1session overview"]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"examples": [
|
|
97
|
+
{
|
|
98
|
+
"id": "transcripts",
|
|
99
|
+
"capabilities": ["transcript.read"],
|
|
100
|
+
"access": [
|
|
101
|
+
{ "protocol": "mcp", "tool": "transcript_read" },
|
|
102
|
+
{ "protocol": "http", "endpoint": "GET /transcripts/:id" },
|
|
103
|
+
{ "protocol": "cli", "command": "tingqi transcript get" }
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"id": "agent-runtime",
|
|
108
|
+
"kind": "agent_runtime",
|
|
109
|
+
"capabilities": [
|
|
110
|
+
"agent.session.new",
|
|
111
|
+
"agent.session.prompt",
|
|
112
|
+
"agent.session.cancel",
|
|
113
|
+
"agent.session.status",
|
|
114
|
+
"agent.session.resume"
|
|
115
|
+
],
|
|
116
|
+
"access": [{ "protocol": "acp" }]
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://dreammate.work/schemas/session-ref.schema.json",
|
|
4
|
+
"title": "DreamMate Session Reference",
|
|
5
|
+
"description": "跨节点引用一个 Session 的方式:session://<node>/<runtime>/<session_id>。设备类型不影响 Session Graph——session://iphone/yima/abc123 与 session://mac/codex/01a0907c 是同等级实体,引用关系完全对称。",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["uri"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"uri": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"pattern": "^session://[^/]+/[^/]+/.+$",
|
|
12
|
+
"description": "规范形式 session://<node>/<runtime>/<session_id>。",
|
|
13
|
+
"examples": ["session://mac/codex/01a0907c", "session://iphone/yima/abc123"]
|
|
14
|
+
},
|
|
15
|
+
"node": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "URI 第一段,与 node manifest 的 name 或 node_id 对应。冗余字段,便于消费方免解析。"
|
|
18
|
+
},
|
|
19
|
+
"runtime": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"description": "URI 第二段。",
|
|
22
|
+
"examples": ["codex", "claude", "antigravity", "yima"]
|
|
23
|
+
},
|
|
24
|
+
"session_id": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"description": "URI 第三段,节点本地的 session id。"
|
|
27
|
+
},
|
|
28
|
+
"relation": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"enum": ["references", "opens", "initiates", "delegates", "produces", "accesses"],
|
|
31
|
+
"description": "这条引用代表哪种边。所有边由调用事件实时写入(B 调用 sessions.read(A) 时就写 B --references--> A),不靠后台扫库猜 DAG。注意整体 Work Graph 不是 DAG:Session 之间完全可以成环,DAG 只是某些投影视图。"
|
|
32
|
+
},
|
|
33
|
+
"observed_at": {
|
|
34
|
+
"type": ["string", "null"],
|
|
35
|
+
"format": "date-time",
|
|
36
|
+
"description": "这条边被观察到的时刻。底层只保存事实,不提前做价值判断。"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"examples": [
|
|
40
|
+
{
|
|
41
|
+
"uri": "session://mac/codex/01a0907c",
|
|
42
|
+
"node": "mac",
|
|
43
|
+
"runtime": "codex",
|
|
44
|
+
"session_id": "01a0907c"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"uri": "session://iphone/yima/abc123",
|
|
48
|
+
"node": "iphone",
|
|
49
|
+
"runtime": "yima",
|
|
50
|
+
"session_id": "abc123",
|
|
51
|
+
"relation": "references",
|
|
52
|
+
"observed_at": "2026-09-14T10:05:00Z"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|