@huynle/hub 0.11.0 → 0.11.1
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/CHANGELOG.md +26 -0
- package/README.md +19 -5
- package/package.json +1 -1
- package/packages/claude-code/package.json +1 -1
- package/packages/claude-code/src/sessions.ts +4 -1
- package/packages/cli/dist/hub-cli.js +240 -83
- package/packages/cli/package.json +1 -1
- package/packages/cli/src/cli.ts +12 -7
- package/packages/cli/src/decisions.ts +52 -4
- package/packages/cli/src/format.ts +9 -0
- package/packages/cli/src/mcp.ts +20 -4
- package/packages/cli/src/team-intake-mcp.ts +2 -1
- package/packages/cli/src/teams-mcp.ts +7 -3
- package/packages/codex/package.json +1 -1
- package/packages/codex/src/sessions.ts +14 -3
- package/packages/node/package.json +1 -1
- package/packages/preset/package.json +1 -1
- package/packages/protocol/package.json +1 -1
- package/packages/protocol/schema/api/v1/_root.json +119 -0
- package/packages/protocol/schema/api/v1/account.json +419 -0
- package/packages/protocol/schema/api/v1/decisions.json +635 -0
- package/packages/protocol/schema/api/v1/discovery.json +110 -0
- package/packages/protocol/schema/api/v1/events.json +679 -0
- package/packages/protocol/schema/api/v1/session-actions.json +660 -0
- package/packages/protocol/schema/api/v1/sessions.json +2055 -0
- package/packages/protocol/schema/api/v1/speech.json +492 -0
- package/packages/protocol/schema/api/v1/unspecified.json +282 -0
- package/packages/protocol/schema/app-delivery/v1.schema.json +67 -5
- package/packages/protocol/schema/app-front/v1.schema.json +7 -3
- package/packages/protocol/src/api-v1.ts +8 -0
- package/packages/protocol/src/index.ts +2 -0
- package/packages/protocol/src/teams.ts +13 -1
- package/packages/runtime-openshell/package.json +1 -1
- package/packages/runtime-sdk/package.json +1 -1
- package/packages/sdk/package.json +1 -1
- package/packages/sdk/src/app-front.ts +2 -2
- package/packages/sdk/src/ask-fields.ts +76 -0
- package/packages/sdk/src/client.ts +11 -2
- package/packages/sdk/src/envelope.ts +3 -2
- package/packages/sdk/src/index.ts +1 -0
- package/packages/sdk/src/team-intake.ts +6 -0
- package/packages/sdk/src/teams.ts +2 -0
- package/packages/sdk/src/types.ts +36 -4
- package/packages/sdk/src/wake.ts +9 -4
- package/packages/spoke-sdk/package.json +1 -1
- package/src/central/agent/agent-limits.ts +185 -0
- package/src/central/agent/app-decisions.ts +6 -5
- package/src/central/agent/decisions.ts +130 -9
- package/src/central/agent/delivery.ts +134 -22
- package/src/central/agent/errors.ts +2 -1
- package/src/central/agent/events.ts +20 -2
- package/src/central/agent/launch-engine.ts +6 -3
- package/src/central/agent/message-limits.ts +5 -2
- package/src/central/agent/message-routes.ts +33 -6
- package/src/central/agent/messages.ts +7 -0
- package/src/central/agent/placement.ts +4 -2
- package/src/central/agent/read-routes.ts +5 -0
- package/src/central/agent/routes.ts +2 -0
- package/src/central/agent/subscriptions.ts +13 -4
- package/src/central/api-v1.ts +115 -0
- package/src/central/artifacts/store.ts +4 -2
- package/src/central/concierge/board-results.ts +2 -1
- package/src/central/concierge/notifier.ts +4 -2
- package/src/central/config.ts +20 -6
- package/src/central/health/classify.ts +209 -0
- package/src/central/http.ts +285 -23
- package/src/central/recording/index.ts +2 -1
- package/src/central/recording/schema.ts +2 -1
- package/src/central/registry.ts +34 -3
- package/src/central/teams/budgets.ts +144 -0
- package/src/central/teams/hop-stalls.ts +14 -6
- package/src/central/teams/intake.ts +38 -6
- package/src/central/teams/involvement.ts +95 -0
- package/src/central/teams/item-decisions.ts +60 -0
- package/src/central/teams/item-eligibility.ts +35 -0
- package/src/central/teams/item-stalls.ts +87 -0
- package/src/central/teams/loops.ts +40 -0
- package/src/central/teams/progress.ts +154 -0
- package/src/central/teams/routes.ts +2 -2
- package/src/central/teams/store.ts +21 -5
- package/src/central/teams/validation.ts +17 -6
- package/src/central/workspaces/coordinator.ts +3 -1
- package/src/spoke/hub-tool.ts +26 -11
- package/web/dist/assets/{ArtifactPage-C5MMqXLN.js → ArtifactPage-TbFJi59n.js} +1 -1
- package/web/dist/assets/{ArtifactPane-CXSCmhyJ.js → ArtifactPane-7D-M-Ich.js} +1 -1
- package/web/dist/assets/{ArtifactWorkbench-S0RxNGWy.js → ArtifactWorkbench-DlCLEjut.js} +1 -1
- package/web/dist/assets/{Diagram-BGmyRb-R.js → Diagram-PvOPetOI.js} +1 -1
- package/web/dist/assets/{Library-CFmMbXEa.js → Library-Cdi83pOV.js} +2 -2
- package/web/dist/assets/{ProfilesDestination-7jpOc2HM.js → ProfilesDestination-cryC7P6j.js} +1 -1
- package/web/dist/assets/TeamsPage-B4xrlGhp.js +1 -0
- package/web/dist/assets/Watchtower-60B1JX_J.js +2 -0
- package/web/dist/assets/index-DA0gKIzv.js +33 -0
- package/web/dist/assets/live-B2IfKm37.js +5 -0
- package/web/dist/assets/{live-BUofsQpz.css → live-De-kd3eW.css} +1 -1
- package/web/dist/assets/{renderer2d-B2Nh39UN.js → renderer2d-CsZnF3_o.js} +1 -1
- package/web/dist/assets/{renderer3d-CTYbljHH.js → renderer3d-BIMA0wFn.js} +2 -2
- package/web/dist/assets/{safe-area-CkhEclGo.js → safe-area-dtrnw9NF.js} +1 -1
- package/web/dist/index.html +1 -1
- package/web/dist/assets/TeamsPage-C1NGrUR-.js +0 -1
- package/web/dist/assets/Watchtower-DnvlJaU0.js +0 -2
- package/web/dist/assets/index-Da8SKXMw.js +0 -33
- package/web/dist/assets/live-BmqLASSo.js +0 -5
|
@@ -0,0 +1,2055 @@
|
|
|
1
|
+
{
|
|
2
|
+
"paths": {
|
|
3
|
+
"/api/v1/machines": {
|
|
4
|
+
"get": {
|
|
5
|
+
"operationId": "listMachines",
|
|
6
|
+
"tags": ["sessions"],
|
|
7
|
+
"x-hub-access": "user",
|
|
8
|
+
"summary": "The catalog: the user's machines, their processes and sessions",
|
|
9
|
+
"description": "What the session list is built from. The live stream (GET /api/v1/events) sends the same list again as a catalog message whenever it changes.",
|
|
10
|
+
"responses": {
|
|
11
|
+
"200": {
|
|
12
|
+
"description": "Every machine of the user, online or not, with the processes connected now and the sessions they report.",
|
|
13
|
+
"content": {
|
|
14
|
+
"application/json": {
|
|
15
|
+
"schema": {
|
|
16
|
+
"$ref": "#/components/schemas/MachineCatalog"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"default": {
|
|
22
|
+
"$ref": "#/components/responses/Error"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"/api/v1/sessions/{session}": {
|
|
28
|
+
"get": {
|
|
29
|
+
"operationId": "getSession",
|
|
30
|
+
"tags": ["sessions"],
|
|
31
|
+
"x-hub-access": "session",
|
|
32
|
+
"summary": "One session: its status tree, blockers and activity",
|
|
33
|
+
"description": "A subagent session no process lists is answered from its root's status tree. Fails with 404 not_found for a session nobody reports (an offline one too) or another user's.",
|
|
34
|
+
"parameters": [
|
|
35
|
+
{
|
|
36
|
+
"name": "session",
|
|
37
|
+
"in": "path",
|
|
38
|
+
"required": true,
|
|
39
|
+
"description": "The session's ID.",
|
|
40
|
+
"schema": {
|
|
41
|
+
"type": "string"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"responses": {
|
|
46
|
+
"200": {
|
|
47
|
+
"description": "The session as the processes that report it see it, with its live state.",
|
|
48
|
+
"content": {
|
|
49
|
+
"application/json": {
|
|
50
|
+
"schema": {
|
|
51
|
+
"$ref": "#/components/schemas/SessionView"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"default": {
|
|
57
|
+
"$ref": "#/components/responses/Error"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"/api/v1/sessions/{session}/timeline": {
|
|
63
|
+
"get": {
|
|
64
|
+
"operationId": "getTimeline",
|
|
65
|
+
"tags": ["sessions"],
|
|
66
|
+
"x-hub-access": "session",
|
|
67
|
+
"summary": "A page of the session's transcript",
|
|
68
|
+
"description": "Two ways to page. Forward: no `order` (or asc), `cursor` from the previous page; the oldest rows come first and `cursor` names the next newer page. Newest first: `order=desc` for the newest rows, then `before=<older>` for the page before them; the rows of a page are still in chronological order. Both cursors are opaque. Read from the session's machine: fails with 409 conflict when no process of the session is connected, 400 invalid for a bad query or a cursor whose row is gone (history reverted or compacted: start over), 404 not_found for an unknown or another user's session.",
|
|
69
|
+
"parameters": [
|
|
70
|
+
{
|
|
71
|
+
"name": "session",
|
|
72
|
+
"in": "path",
|
|
73
|
+
"required": true,
|
|
74
|
+
"description": "The session's ID.",
|
|
75
|
+
"schema": {
|
|
76
|
+
"type": "string"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"name": "limit",
|
|
81
|
+
"in": "query",
|
|
82
|
+
"description": "Rows per page, 1 to 200 (the spoke's default: 50).",
|
|
83
|
+
"schema": {
|
|
84
|
+
"type": "integer",
|
|
85
|
+
"format": "int32",
|
|
86
|
+
"minimum": 1,
|
|
87
|
+
"maximum": 200
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"name": "order",
|
|
92
|
+
"in": "query",
|
|
93
|
+
"description": "desc: the newest page first (newest-first paging).",
|
|
94
|
+
"schema": {
|
|
95
|
+
"type": "string",
|
|
96
|
+
"enum": ["asc", "desc"]
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"name": "before",
|
|
101
|
+
"in": "query",
|
|
102
|
+
"description": "Newest-first paging: the `older` of the page after this one.",
|
|
103
|
+
"schema": {
|
|
104
|
+
"type": "string",
|
|
105
|
+
"maxLength": 4096
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"name": "cursor",
|
|
110
|
+
"in": "query",
|
|
111
|
+
"description": "Forward paging: the `cursor` of the previous page. Not with `before` or order=desc.",
|
|
112
|
+
"schema": {
|
|
113
|
+
"type": "string",
|
|
114
|
+
"maxLength": 4096
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
"responses": {
|
|
119
|
+
"200": {
|
|
120
|
+
"description": "A page of rows, in chronological order.",
|
|
121
|
+
"content": {
|
|
122
|
+
"application/json": {
|
|
123
|
+
"schema": {
|
|
124
|
+
"$ref": "#/components/schemas/TimelinePage"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"default": {
|
|
130
|
+
"$ref": "#/components/responses/Error"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"/api/v1/sessions/{session}/messages": {
|
|
136
|
+
"get": {
|
|
137
|
+
"operationId": "listSessionMessages",
|
|
138
|
+
"tags": ["sessions"],
|
|
139
|
+
"x-hub-access": "session",
|
|
140
|
+
"summary": "The agent messages the session sent or received",
|
|
141
|
+
"description": "Hub messages between sessions, the user and apps (the messaging area). Also answers for an offline session the user's directory knows. Messages of a history a committed revert removed are left out. Fails with 400 invalid for a bad limit.",
|
|
142
|
+
"parameters": [
|
|
143
|
+
{
|
|
144
|
+
"name": "session",
|
|
145
|
+
"in": "path",
|
|
146
|
+
"required": true,
|
|
147
|
+
"description": "The session's ID.",
|
|
148
|
+
"schema": {
|
|
149
|
+
"type": "string"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"name": "limit",
|
|
154
|
+
"in": "query",
|
|
155
|
+
"description": "At most this many, 1 to 200 (default: every message the session keeps, up to 200).",
|
|
156
|
+
"schema": {
|
|
157
|
+
"type": "integer",
|
|
158
|
+
"format": "int32",
|
|
159
|
+
"minimum": 1,
|
|
160
|
+
"maximum": 200
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
"responses": {
|
|
165
|
+
"200": {
|
|
166
|
+
"description": "Newest first. A client merges them into the timeline by `at`.",
|
|
167
|
+
"content": {
|
|
168
|
+
"application/json": {
|
|
169
|
+
"schema": {
|
|
170
|
+
"$ref": "#/components/schemas/SessionMessageList"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
"default": {
|
|
176
|
+
"$ref": "#/components/responses/Error"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"/api/v1/sessions/{session}/timeline/messages/{message}/parts/{part}": {
|
|
182
|
+
"get": {
|
|
183
|
+
"operationId": "getTimelinePart",
|
|
184
|
+
"tags": ["sessions"],
|
|
185
|
+
"x-hub-access": "session",
|
|
186
|
+
"summary": "The full detail of a tool row",
|
|
187
|
+
"description": "What a timeline row leaves out of a tool call: its whole input, output and state. Embedded images are replaced by small placeholders. Read from the session's machine (409 conflict when none is connected); a detail too large to display fails.",
|
|
188
|
+
"parameters": [
|
|
189
|
+
{
|
|
190
|
+
"name": "session",
|
|
191
|
+
"in": "path",
|
|
192
|
+
"required": true,
|
|
193
|
+
"description": "The session's ID.",
|
|
194
|
+
"schema": {
|
|
195
|
+
"type": "string"
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"name": "message",
|
|
200
|
+
"in": "path",
|
|
201
|
+
"required": true,
|
|
202
|
+
"description": "The timeline row's messageID.",
|
|
203
|
+
"schema": {
|
|
204
|
+
"type": "string"
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"name": "part",
|
|
209
|
+
"in": "path",
|
|
210
|
+
"required": true,
|
|
211
|
+
"description": "The tool row's partID.",
|
|
212
|
+
"schema": {
|
|
213
|
+
"type": "string"
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
],
|
|
217
|
+
"responses": {
|
|
218
|
+
"200": {
|
|
219
|
+
"description": "The tool call's detail.",
|
|
220
|
+
"content": {
|
|
221
|
+
"application/json": {
|
|
222
|
+
"schema": {
|
|
223
|
+
"$ref": "#/components/schemas/TimelinePart"
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
"default": {
|
|
229
|
+
"$ref": "#/components/responses/Error"
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
"/api/v1/sessions/{session}/timeline/messages/{message}/files/{index}": {
|
|
235
|
+
"get": {
|
|
236
|
+
"operationId": "getTimelineFile",
|
|
237
|
+
"tags": ["sessions"],
|
|
238
|
+
"x-hub-access": "session",
|
|
239
|
+
"summary": "An image attached to a user message, by position",
|
|
240
|
+
"description": "The same image as media/f<index>, which it is on a spoke with the timelineMedia feature (ETag, 304, ?download=1). An older spoke answers in one piece, without an ETag, and serves PNG, JPEG, WebP and GIF only. Fails with 400 invalid for an index outside 0–999, 404 not_found for no such image, 413 too_large for an image too large to show.",
|
|
241
|
+
"parameters": [
|
|
242
|
+
{
|
|
243
|
+
"name": "session",
|
|
244
|
+
"in": "path",
|
|
245
|
+
"required": true,
|
|
246
|
+
"description": "The session's ID.",
|
|
247
|
+
"schema": {
|
|
248
|
+
"type": "string"
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"name": "message",
|
|
253
|
+
"in": "path",
|
|
254
|
+
"required": true,
|
|
255
|
+
"description": "The timeline row's messageID.",
|
|
256
|
+
"schema": {
|
|
257
|
+
"type": "string"
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"name": "index",
|
|
262
|
+
"in": "path",
|
|
263
|
+
"required": true,
|
|
264
|
+
"description": "The attachment's position: a user row's files[].index (0–999).",
|
|
265
|
+
"schema": {
|
|
266
|
+
"type": "string"
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"name": "download",
|
|
271
|
+
"in": "query",
|
|
272
|
+
"description": "1: answer as an attachment (Content-Disposition), for saving the image.",
|
|
273
|
+
"schema": {
|
|
274
|
+
"type": "string",
|
|
275
|
+
"enum": ["1"]
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"name": "If-None-Match",
|
|
280
|
+
"in": "header",
|
|
281
|
+
"description": "The ETag of a copy the client holds: the answer is then 304 when it is still current.",
|
|
282
|
+
"schema": {
|
|
283
|
+
"type": "string"
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
],
|
|
287
|
+
"responses": {
|
|
288
|
+
"200": {
|
|
289
|
+
"description": "The image's bytes. Only image types are served.",
|
|
290
|
+
"headers": {
|
|
291
|
+
"ETag": {
|
|
292
|
+
"description": "The image's SHA-256 as a strong validator (\"sha256-<hex>\"); send it back as If-None-Match. Absent on an older spoke's answer (files/:index without timelineMedia).",
|
|
293
|
+
"schema": {
|
|
294
|
+
"type": "string"
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
"Content-Disposition": {
|
|
298
|
+
"description": "inline, or attachment with ?download=1 and for SVG, with a file name. Absent on an older spoke's answer.",
|
|
299
|
+
"schema": {
|
|
300
|
+
"type": "string"
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
"content": {
|
|
305
|
+
"image/png": {
|
|
306
|
+
"schema": {
|
|
307
|
+
"type": "string",
|
|
308
|
+
"format": "binary"
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
"image/jpeg": {
|
|
312
|
+
"schema": {
|
|
313
|
+
"type": "string",
|
|
314
|
+
"format": "binary"
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
"image/webp": {
|
|
318
|
+
"schema": {
|
|
319
|
+
"type": "string",
|
|
320
|
+
"format": "binary"
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
"image/gif": {
|
|
324
|
+
"schema": {
|
|
325
|
+
"type": "string",
|
|
326
|
+
"format": "binary"
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
"image/svg+xml": {
|
|
330
|
+
"schema": {
|
|
331
|
+
"type": "string",
|
|
332
|
+
"format": "binary"
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
"304": {
|
|
338
|
+
"description": "Not modified: If-None-Match named the image's current ETag. No body."
|
|
339
|
+
},
|
|
340
|
+
"default": {
|
|
341
|
+
"$ref": "#/components/responses/Error"
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
"/api/v1/sessions/{session}/timeline/messages/{message}/media/{ref}": {
|
|
347
|
+
"get": {
|
|
348
|
+
"operationId": "getTimelineMedia",
|
|
349
|
+
"tags": ["sessions"],
|
|
350
|
+
"x-hub-access": "session",
|
|
351
|
+
"summary": "An image of a timeline row, by ref",
|
|
352
|
+
"description": "A user row's attachment, a tool row's image or an image path in an assistant text, pulled from the session's machine in chunks and cached by the hub. Needs the spoke's timelineMedia feature: else 422 unsupported (with feature and harness). Other failures: 400 invalid (a malformed ref or message ID), 404 (not_found, path: not in the session's files, hidden: hidden by a revert), 413 (too_large, dimensions), 415 type (not an image the hub shows), 429 rate_limited (at most 4 images at once per user, 2 per machine; Retry-After), 502 (bad_answer, integrity: the machine sent a broken image), 504 timeout, 409 conflict (no process of the session connected).",
|
|
353
|
+
"parameters": [
|
|
354
|
+
{
|
|
355
|
+
"name": "session",
|
|
356
|
+
"in": "path",
|
|
357
|
+
"required": true,
|
|
358
|
+
"description": "The session's ID.",
|
|
359
|
+
"schema": {
|
|
360
|
+
"type": "string"
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
"name": "message",
|
|
365
|
+
"in": "path",
|
|
366
|
+
"required": true,
|
|
367
|
+
"description": "The timeline row's messageID.",
|
|
368
|
+
"schema": {
|
|
369
|
+
"type": "string"
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
"name": "ref",
|
|
374
|
+
"in": "path",
|
|
375
|
+
"required": true,
|
|
376
|
+
"description": "A media ref, from a row's files[].ref or media[].ref: f<n>, t<part>.<item> or p:<path>. URL-encode it.",
|
|
377
|
+
"schema": {
|
|
378
|
+
"type": "string"
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
"name": "download",
|
|
383
|
+
"in": "query",
|
|
384
|
+
"description": "1: answer as an attachment (Content-Disposition), for saving the image.",
|
|
385
|
+
"schema": {
|
|
386
|
+
"type": "string",
|
|
387
|
+
"enum": ["1"]
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
"name": "If-None-Match",
|
|
392
|
+
"in": "header",
|
|
393
|
+
"description": "The ETag of a copy the client holds: the answer is then 304 when it is still current.",
|
|
394
|
+
"schema": {
|
|
395
|
+
"type": "string"
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
],
|
|
399
|
+
"responses": {
|
|
400
|
+
"200": {
|
|
401
|
+
"description": "The image's bytes, whole and verified (length and SHA-256), sniffed to be the type it claims. SVG is always an attachment.",
|
|
402
|
+
"headers": {
|
|
403
|
+
"ETag": {
|
|
404
|
+
"description": "The image's SHA-256 as a strong validator (\"sha256-<hex>\"); send it back as If-None-Match. Absent on an older spoke's answer (files/:index without timelineMedia).",
|
|
405
|
+
"schema": {
|
|
406
|
+
"type": "string"
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
"Content-Disposition": {
|
|
410
|
+
"description": "inline, or attachment with ?download=1 and for SVG, with a file name. Absent on an older spoke's answer.",
|
|
411
|
+
"schema": {
|
|
412
|
+
"type": "string"
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
"content": {
|
|
417
|
+
"image/png": {
|
|
418
|
+
"schema": {
|
|
419
|
+
"type": "string",
|
|
420
|
+
"format": "binary"
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
"image/jpeg": {
|
|
424
|
+
"schema": {
|
|
425
|
+
"type": "string",
|
|
426
|
+
"format": "binary"
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
"image/webp": {
|
|
430
|
+
"schema": {
|
|
431
|
+
"type": "string",
|
|
432
|
+
"format": "binary"
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
"image/gif": {
|
|
436
|
+
"schema": {
|
|
437
|
+
"type": "string",
|
|
438
|
+
"format": "binary"
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
"image/svg+xml": {
|
|
442
|
+
"schema": {
|
|
443
|
+
"type": "string",
|
|
444
|
+
"format": "binary"
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
"304": {
|
|
450
|
+
"description": "Not modified: If-None-Match named the image's current ETag. No body."
|
|
451
|
+
},
|
|
452
|
+
"default": {
|
|
453
|
+
"$ref": "#/components/responses/Error"
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
"/api/v1/reads": {
|
|
459
|
+
"get": {
|
|
460
|
+
"operationId": "getReads",
|
|
461
|
+
"tags": ["sessions"],
|
|
462
|
+
"x-hub-access": "user",
|
|
463
|
+
"summary": "When the user last read each session",
|
|
464
|
+
"description": "A session is unread while it changed after its mark. The live stream sends the marks again as a reads message when another device changes them.",
|
|
465
|
+
"responses": {
|
|
466
|
+
"200": {
|
|
467
|
+
"description": "The user's read marks, shared by all their devices.",
|
|
468
|
+
"content": {
|
|
469
|
+
"application/json": {
|
|
470
|
+
"schema": {
|
|
471
|
+
"$ref": "#/components/schemas/ReadMarks"
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
"default": {
|
|
477
|
+
"$ref": "#/components/responses/Error"
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
"/api/v1/sessions/{session}/read": {
|
|
483
|
+
"post": {
|
|
484
|
+
"operationId": "markSessionRead",
|
|
485
|
+
"tags": ["sessions"],
|
|
486
|
+
"x-hub-access": "session",
|
|
487
|
+
"summary": "Mark a session read now",
|
|
488
|
+
"description": "A mark never moves back. The user's other devices get the marks on the live stream. The body is optional.",
|
|
489
|
+
"parameters": [
|
|
490
|
+
{
|
|
491
|
+
"name": "session",
|
|
492
|
+
"in": "path",
|
|
493
|
+
"required": true,
|
|
494
|
+
"description": "The session's ID.",
|
|
495
|
+
"schema": {
|
|
496
|
+
"type": "string"
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
],
|
|
500
|
+
"requestBody": {
|
|
501
|
+
"required": false,
|
|
502
|
+
"content": {
|
|
503
|
+
"application/json": {
|
|
504
|
+
"schema": {
|
|
505
|
+
"$ref": "#/components/schemas/MarkReadRequest"
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
},
|
|
510
|
+
"responses": {
|
|
511
|
+
"200": {
|
|
512
|
+
"description": "Every read mark of the user, this one included.",
|
|
513
|
+
"content": {
|
|
514
|
+
"application/json": {
|
|
515
|
+
"schema": {
|
|
516
|
+
"$ref": "#/components/schemas/ReadMarks"
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
"default": {
|
|
522
|
+
"$ref": "#/components/responses/Error"
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
"/api/v1/prefs/view": {
|
|
528
|
+
"get": {
|
|
529
|
+
"operationId": "getViewPrefs",
|
|
530
|
+
"tags": ["sessions"],
|
|
531
|
+
"x-hub-access": "user",
|
|
532
|
+
"summary": "The user's session list preferences",
|
|
533
|
+
"responses": {
|
|
534
|
+
"200": {
|
|
535
|
+
"description": "The hidden (archived) and pinned sessions and workspaces.",
|
|
536
|
+
"content": {
|
|
537
|
+
"application/json": {
|
|
538
|
+
"schema": {
|
|
539
|
+
"$ref": "#/components/schemas/ViewPrefsState"
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
},
|
|
544
|
+
"default": {
|
|
545
|
+
"$ref": "#/components/responses/Error"
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
},
|
|
549
|
+
"put": {
|
|
550
|
+
"operationId": "setViewPrefs",
|
|
551
|
+
"tags": ["sessions"],
|
|
552
|
+
"x-hub-access": "user",
|
|
553
|
+
"summary": "Change the user's session list preferences",
|
|
554
|
+
"description": "Each list given replaces the stored one (duplicates dropped); the others stay. The user's other devices get the change on the live stream. Fails with 400 invalid for an empty body, an unknown key or a list over its limit.",
|
|
555
|
+
"requestBody": {
|
|
556
|
+
"required": true,
|
|
557
|
+
"content": {
|
|
558
|
+
"application/json": {
|
|
559
|
+
"schema": {
|
|
560
|
+
"$ref": "#/components/schemas/ViewPrefsChange"
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
},
|
|
565
|
+
"responses": {
|
|
566
|
+
"200": {
|
|
567
|
+
"description": "The preferences after the change.",
|
|
568
|
+
"content": {
|
|
569
|
+
"application/json": {
|
|
570
|
+
"schema": {
|
|
571
|
+
"$ref": "#/components/schemas/ViewPrefsState"
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
},
|
|
576
|
+
"default": {
|
|
577
|
+
"$ref": "#/components/responses/Error"
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
"components": {
|
|
584
|
+
"schemas": {
|
|
585
|
+
"MachineCatalog": {
|
|
586
|
+
"type": "object",
|
|
587
|
+
"required": ["machines"],
|
|
588
|
+
"properties": {
|
|
589
|
+
"machines": {
|
|
590
|
+
"type": "array",
|
|
591
|
+
"items": {
|
|
592
|
+
"$ref": "#/components/schemas/CatalogMachine"
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
},
|
|
597
|
+
"CatalogMachine": {
|
|
598
|
+
"type": "object",
|
|
599
|
+
"description": "A machine of the user (a computer running the Hub plugin or a harness).",
|
|
600
|
+
"required": ["id", "name", "created", "lastSeen", "online", "processes"],
|
|
601
|
+
"properties": {
|
|
602
|
+
"id": {
|
|
603
|
+
"type": "string"
|
|
604
|
+
},
|
|
605
|
+
"name": {
|
|
606
|
+
"type": "string"
|
|
607
|
+
},
|
|
608
|
+
"created": {
|
|
609
|
+
"type": "integer",
|
|
610
|
+
"format": "int64",
|
|
611
|
+
"description": "When the machine was enrolled, in epoch milliseconds."
|
|
612
|
+
},
|
|
613
|
+
"lastSeen": {
|
|
614
|
+
"type": "integer",
|
|
615
|
+
"format": "int64",
|
|
616
|
+
"description": "When the hub last heard from it, in epoch milliseconds."
|
|
617
|
+
},
|
|
618
|
+
"online": {
|
|
619
|
+
"type": "boolean",
|
|
620
|
+
"description": "A process of the machine is connected now."
|
|
621
|
+
},
|
|
622
|
+
"processes": {
|
|
623
|
+
"type": "array",
|
|
624
|
+
"items": {
|
|
625
|
+
"$ref": "#/components/schemas/CatalogProcess"
|
|
626
|
+
},
|
|
627
|
+
"description": "Its connected processes, oldest connection first; empty when offline."
|
|
628
|
+
},
|
|
629
|
+
"terminals": {
|
|
630
|
+
"$ref": "#/components/schemas/MachineTerminals"
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
},
|
|
634
|
+
"MachineTerminals": {
|
|
635
|
+
"type": "object",
|
|
636
|
+
"description": "The machine's terminal context, as one of its processes reported it. May be empty.",
|
|
637
|
+
"properties": {
|
|
638
|
+
"herdr": {
|
|
639
|
+
"$ref": "#/components/schemas/HerdrTerminals"
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
},
|
|
643
|
+
"HerdrTerminals": {
|
|
644
|
+
"type": "object",
|
|
645
|
+
"required": ["workspaces"],
|
|
646
|
+
"properties": {
|
|
647
|
+
"workspaces": {
|
|
648
|
+
"type": "array",
|
|
649
|
+
"items": {
|
|
650
|
+
"$ref": "#/components/schemas/HerdrWorkspace"
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
},
|
|
655
|
+
"HerdrWorkspace": {
|
|
656
|
+
"type": "object",
|
|
657
|
+
"description": "A Herdr workspace on the machine: a place to open new sessions.",
|
|
658
|
+
"required": ["id", "label", "directories"],
|
|
659
|
+
"properties": {
|
|
660
|
+
"id": {
|
|
661
|
+
"type": "string"
|
|
662
|
+
},
|
|
663
|
+
"label": {
|
|
664
|
+
"type": "string",
|
|
665
|
+
"description": "e.g. \"research\"."
|
|
666
|
+
},
|
|
667
|
+
"directories": {
|
|
668
|
+
"type": "array",
|
|
669
|
+
"items": {
|
|
670
|
+
"type": "string"
|
|
671
|
+
},
|
|
672
|
+
"description": "Folders of the workspace's panes, most used first."
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
},
|
|
676
|
+
"CatalogProcess": {
|
|
677
|
+
"type": "object",
|
|
678
|
+
"description": "A connected process of a machine (a spoke) and the sessions it reports.",
|
|
679
|
+
"required": [
|
|
680
|
+
"id",
|
|
681
|
+
"kind",
|
|
682
|
+
"directory",
|
|
683
|
+
"pid",
|
|
684
|
+
"mode",
|
|
685
|
+
"opencodeVersion",
|
|
686
|
+
"pluginVersion",
|
|
687
|
+
"harness",
|
|
688
|
+
"harnessVersion",
|
|
689
|
+
"evidence",
|
|
690
|
+
"features",
|
|
691
|
+
"connected",
|
|
692
|
+
"lastSeen",
|
|
693
|
+
"sessions"
|
|
694
|
+
],
|
|
695
|
+
"properties": {
|
|
696
|
+
"id": {
|
|
697
|
+
"type": "string",
|
|
698
|
+
"description": "The process ID the spoke chose."
|
|
699
|
+
},
|
|
700
|
+
"kind": {
|
|
701
|
+
"type": "string",
|
|
702
|
+
"x-hub-known": ["service", "standalone"],
|
|
703
|
+
"description": "service: the machine's background service; standalone: a process of its own (an OpenCode TUI)."
|
|
704
|
+
},
|
|
705
|
+
"directory": {
|
|
706
|
+
"type": "string"
|
|
707
|
+
},
|
|
708
|
+
"pid": {
|
|
709
|
+
"type": "integer",
|
|
710
|
+
"format": "int64",
|
|
711
|
+
"description": "The operating system's process ID."
|
|
712
|
+
},
|
|
713
|
+
"mode": {
|
|
714
|
+
"type": "string",
|
|
715
|
+
"x-hub-known": ["always", "session"],
|
|
716
|
+
"description": "always: every session has Voice; session: Voice is enabled per session."
|
|
717
|
+
},
|
|
718
|
+
"opencodeVersion": {
|
|
719
|
+
"type": "string",
|
|
720
|
+
"description": "OpenCode's version, as the process said (empty for other harnesses; see harnessVersion)."
|
|
721
|
+
},
|
|
722
|
+
"pluginVersion": {
|
|
723
|
+
"type": "string"
|
|
724
|
+
},
|
|
725
|
+
"harness": {
|
|
726
|
+
"type": "string",
|
|
727
|
+
"x-hub-known": ["opencode", "claude-code", "codex"],
|
|
728
|
+
"description": "The harness: opencode, claude-code, codex, …"
|
|
729
|
+
},
|
|
730
|
+
"harnessVersion": {
|
|
731
|
+
"type": "string"
|
|
732
|
+
},
|
|
733
|
+
"evidence": {
|
|
734
|
+
"type": "string",
|
|
735
|
+
"x-hub-known": ["native", "hooks", "rpc", "screen", "unknown"],
|
|
736
|
+
"description": "How the process observes a session's activity; a session with unknown evidence never counts as idle."
|
|
737
|
+
},
|
|
738
|
+
"features": {
|
|
739
|
+
"type": "array",
|
|
740
|
+
"items": {
|
|
741
|
+
"type": "string"
|
|
742
|
+
},
|
|
743
|
+
"description": "What the process serves (its core operations and optional features), sorted. Clients show a control only when its feature is here."
|
|
744
|
+
},
|
|
745
|
+
"connected": {
|
|
746
|
+
"type": "integer",
|
|
747
|
+
"format": "int64",
|
|
748
|
+
"description": "When it connected, in epoch milliseconds."
|
|
749
|
+
},
|
|
750
|
+
"lastSeen": {
|
|
751
|
+
"type": "integer",
|
|
752
|
+
"format": "int64",
|
|
753
|
+
"description": "When the hub last heard from it, in epoch milliseconds."
|
|
754
|
+
},
|
|
755
|
+
"sessions": {
|
|
756
|
+
"type": "array",
|
|
757
|
+
"items": {
|
|
758
|
+
"$ref": "#/components/schemas/CatalogSession"
|
|
759
|
+
}
|
|
760
|
+
},
|
|
761
|
+
"sessionsPending": {
|
|
762
|
+
"type": "boolean",
|
|
763
|
+
"description": "True while the process has not reported its sessions yet: an empty `sessions` says nothing then."
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
},
|
|
767
|
+
"CatalogSession": {
|
|
768
|
+
"type": "object",
|
|
769
|
+
"description": "A session as one process reports it. A session reported by several processes appears under each.",
|
|
770
|
+
"required": ["id", "title", "directory", "updated", "owned", "exposed", "state", "blockers", "processID", "machineID", "status", "busy", "conversation"],
|
|
771
|
+
"properties": {
|
|
772
|
+
"id": {
|
|
773
|
+
"type": "string"
|
|
774
|
+
},
|
|
775
|
+
"title": {
|
|
776
|
+
"type": "string"
|
|
777
|
+
},
|
|
778
|
+
"directory": {
|
|
779
|
+
"type": "string",
|
|
780
|
+
"description": "The working directory."
|
|
781
|
+
},
|
|
782
|
+
"parentID": {
|
|
783
|
+
"type": "string",
|
|
784
|
+
"description": "Set on a subagent session: its parent."
|
|
785
|
+
},
|
|
786
|
+
"project": {
|
|
787
|
+
"type": "string",
|
|
788
|
+
"description": "The workspace (project) root the session belongs to; differs from directory in worktrees and subfolders."
|
|
789
|
+
},
|
|
790
|
+
"projectName": {
|
|
791
|
+
"type": "string"
|
|
792
|
+
},
|
|
793
|
+
"updated": {
|
|
794
|
+
"type": "integer",
|
|
795
|
+
"format": "int64",
|
|
796
|
+
"description": "When the session last changed, in epoch milliseconds."
|
|
797
|
+
},
|
|
798
|
+
"open": {
|
|
799
|
+
"type": "boolean",
|
|
800
|
+
"description": "True while the session is open in a terminal (a Herdr pane or an OpenCode TUI)."
|
|
801
|
+
},
|
|
802
|
+
"terminal": {
|
|
803
|
+
"$ref": "#/components/schemas/TerminalInfo"
|
|
804
|
+
},
|
|
805
|
+
"revert": {
|
|
806
|
+
"$ref": "#/components/schemas/SessionRevert"
|
|
807
|
+
},
|
|
808
|
+
"revertCommitted": {
|
|
809
|
+
"$ref": "#/components/schemas/RevertCommitted"
|
|
810
|
+
},
|
|
811
|
+
"agent": {
|
|
812
|
+
"type": "string",
|
|
813
|
+
"description": "A locked (Concierge) session: the agent it last ran on."
|
|
814
|
+
},
|
|
815
|
+
"contextRevision": {
|
|
816
|
+
"type": "integer",
|
|
817
|
+
"format": "int64",
|
|
818
|
+
"description": "A locked (Concierge) session: the context revision its machine holds."
|
|
819
|
+
},
|
|
820
|
+
"owned": {
|
|
821
|
+
"type": "boolean",
|
|
822
|
+
"description": "This process owns the session: it viewed or ran it most recently."
|
|
823
|
+
},
|
|
824
|
+
"archived": {
|
|
825
|
+
"type": "boolean",
|
|
826
|
+
"description": "Archived in the harness."
|
|
827
|
+
},
|
|
828
|
+
"locked": {
|
|
829
|
+
"type": "boolean",
|
|
830
|
+
"description": "True for a session locked as a Concierge session."
|
|
831
|
+
},
|
|
832
|
+
"exposed": {
|
|
833
|
+
"type": "boolean",
|
|
834
|
+
"description": "Voice is enabled for the session. Reading and typed control do not depend on it; speech does."
|
|
835
|
+
},
|
|
836
|
+
"state": {
|
|
837
|
+
"type": "string",
|
|
838
|
+
"x-hub-known": ["idle", "working", "blocked", "error"],
|
|
839
|
+
"description": "blocked when anything in the session or below it waits for the user; else error (the session itself failed), working (anything below runs) or idle."
|
|
840
|
+
},
|
|
841
|
+
"blockers": {
|
|
842
|
+
"type": "array",
|
|
843
|
+
"items": {
|
|
844
|
+
"$ref": "#/components/schemas/Blocker"
|
|
845
|
+
},
|
|
846
|
+
"description": "What waits for the user in the session and below it, each with sessionID and sessionTitle."
|
|
847
|
+
},
|
|
848
|
+
"now": {
|
|
849
|
+
"$ref": "#/components/schemas/NowActivity"
|
|
850
|
+
},
|
|
851
|
+
"processID": {
|
|
852
|
+
"type": "string",
|
|
853
|
+
"description": "The process that reports it."
|
|
854
|
+
},
|
|
855
|
+
"machineID": {
|
|
856
|
+
"type": "string"
|
|
857
|
+
},
|
|
858
|
+
"status": {
|
|
859
|
+
"type": "array",
|
|
860
|
+
"items": {
|
|
861
|
+
"$ref": "#/components/schemas/SessionStatus"
|
|
862
|
+
},
|
|
863
|
+
"description": "The status tree of the session's root: the root first, then its subagent sessions."
|
|
864
|
+
},
|
|
865
|
+
"busy": {
|
|
866
|
+
"type": "boolean",
|
|
867
|
+
"description": "A turn the hub started runs in the session."
|
|
868
|
+
},
|
|
869
|
+
"conversation": {
|
|
870
|
+
"type": "boolean",
|
|
871
|
+
"description": "Conversation mode is on: the assistant's text is spoken."
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
},
|
|
875
|
+
"SessionView": {
|
|
876
|
+
"type": "object",
|
|
877
|
+
"description": "One session as the session screen shows it, merged from every process that reports it (the most recent report wins).",
|
|
878
|
+
"required": ["id", "title", "directory", "updated", "exposed", "state", "blockers", "busy", "conversation", "status", "activity"],
|
|
879
|
+
"properties": {
|
|
880
|
+
"id": {
|
|
881
|
+
"type": "string"
|
|
882
|
+
},
|
|
883
|
+
"title": {
|
|
884
|
+
"type": "string"
|
|
885
|
+
},
|
|
886
|
+
"directory": {
|
|
887
|
+
"type": "string",
|
|
888
|
+
"description": "The working directory."
|
|
889
|
+
},
|
|
890
|
+
"parentID": {
|
|
891
|
+
"type": "string",
|
|
892
|
+
"description": "Set on a subagent session: its parent."
|
|
893
|
+
},
|
|
894
|
+
"project": {
|
|
895
|
+
"type": "string",
|
|
896
|
+
"description": "The workspace (project) root the session belongs to; differs from directory in worktrees and subfolders."
|
|
897
|
+
},
|
|
898
|
+
"projectName": {
|
|
899
|
+
"type": "string"
|
|
900
|
+
},
|
|
901
|
+
"updated": {
|
|
902
|
+
"type": "integer",
|
|
903
|
+
"format": "int64",
|
|
904
|
+
"description": "When the session last changed, in epoch milliseconds."
|
|
905
|
+
},
|
|
906
|
+
"open": {
|
|
907
|
+
"type": "boolean",
|
|
908
|
+
"description": "True while the session is open in a terminal (a Herdr pane or an OpenCode TUI)."
|
|
909
|
+
},
|
|
910
|
+
"terminal": {
|
|
911
|
+
"$ref": "#/components/schemas/TerminalInfo"
|
|
912
|
+
},
|
|
913
|
+
"revert": {
|
|
914
|
+
"$ref": "#/components/schemas/SessionRevert"
|
|
915
|
+
},
|
|
916
|
+
"revertCommitted": {
|
|
917
|
+
"$ref": "#/components/schemas/RevertCommitted"
|
|
918
|
+
},
|
|
919
|
+
"agent": {
|
|
920
|
+
"type": "string",
|
|
921
|
+
"description": "A locked (Concierge) session: the agent it last ran on."
|
|
922
|
+
},
|
|
923
|
+
"contextRevision": {
|
|
924
|
+
"type": "integer",
|
|
925
|
+
"format": "int64",
|
|
926
|
+
"description": "A locked (Concierge) session: the context revision its machine holds."
|
|
927
|
+
},
|
|
928
|
+
"exposed": {
|
|
929
|
+
"type": "boolean",
|
|
930
|
+
"description": "Voice is enabled for the session. Reading and typed control do not depend on it; speech does."
|
|
931
|
+
},
|
|
932
|
+
"state": {
|
|
933
|
+
"type": "string",
|
|
934
|
+
"x-hub-known": ["idle", "working", "blocked", "error"],
|
|
935
|
+
"description": "blocked when anything in the session or below it waits for the user; else error (the session itself failed), working (anything below runs) or idle."
|
|
936
|
+
},
|
|
937
|
+
"blockers": {
|
|
938
|
+
"type": "array",
|
|
939
|
+
"items": {
|
|
940
|
+
"$ref": "#/components/schemas/Blocker"
|
|
941
|
+
},
|
|
942
|
+
"description": "What waits for the user in the session and below it, each with sessionID and sessionTitle."
|
|
943
|
+
},
|
|
944
|
+
"now": {
|
|
945
|
+
"$ref": "#/components/schemas/NowActivity"
|
|
946
|
+
},
|
|
947
|
+
"busy": {
|
|
948
|
+
"type": "boolean",
|
|
949
|
+
"description": "A turn the hub started runs in the session."
|
|
950
|
+
},
|
|
951
|
+
"conversation": {
|
|
952
|
+
"type": "boolean",
|
|
953
|
+
"description": "Conversation mode is on: the assistant's text is spoken."
|
|
954
|
+
},
|
|
955
|
+
"status": {
|
|
956
|
+
"type": "array",
|
|
957
|
+
"items": {
|
|
958
|
+
"$ref": "#/components/schemas/SessionStatus"
|
|
959
|
+
},
|
|
960
|
+
"description": "The status tree of the root session that contains this one: the root first, then its subagent sessions."
|
|
961
|
+
},
|
|
962
|
+
"activity": {
|
|
963
|
+
"type": "array",
|
|
964
|
+
"items": {
|
|
965
|
+
"$ref": "#/components/schemas/ActivityItem"
|
|
966
|
+
},
|
|
967
|
+
"description": "Recent activity of the root session and its subagent sessions (at most 30), newest last."
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
},
|
|
971
|
+
"TerminalInfo": {
|
|
972
|
+
"type": "object",
|
|
973
|
+
"description": "Where a session is open in a terminal.",
|
|
974
|
+
"required": ["source"],
|
|
975
|
+
"properties": {
|
|
976
|
+
"source": {
|
|
977
|
+
"type": "string",
|
|
978
|
+
"x-hub-known": ["herdr", "tui"],
|
|
979
|
+
"description": "Where it is open."
|
|
980
|
+
},
|
|
981
|
+
"workspaceID": {
|
|
982
|
+
"type": "string",
|
|
983
|
+
"description": "The Herdr workspace."
|
|
984
|
+
},
|
|
985
|
+
"workspace": {
|
|
986
|
+
"type": "string",
|
|
987
|
+
"description": "The Herdr workspace's label."
|
|
988
|
+
},
|
|
989
|
+
"title": {
|
|
990
|
+
"type": "string",
|
|
991
|
+
"description": "The pane's title, e.g. \"OC | Fix the login redirect\"."
|
|
992
|
+
},
|
|
993
|
+
"status": {
|
|
994
|
+
"type": "string",
|
|
995
|
+
"x-hub-known": ["idle", "working", "blocked", "done", "unknown"],
|
|
996
|
+
"description": "Herdr's agent status of the pane."
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
},
|
|
1000
|
+
"SessionRevert": {
|
|
1001
|
+
"type": "object",
|
|
1002
|
+
"description": "A staged revert: restored with POST …/revert/restore, committed by the next prompt.",
|
|
1003
|
+
"required": ["messageID", "hidden", "files", "filesTotal"],
|
|
1004
|
+
"properties": {
|
|
1005
|
+
"messageID": {
|
|
1006
|
+
"type": "string",
|
|
1007
|
+
"description": "The reverted user message: it and everything after it are hidden."
|
|
1008
|
+
},
|
|
1009
|
+
"hidden": {
|
|
1010
|
+
"type": "integer",
|
|
1011
|
+
"format": "int32",
|
|
1012
|
+
"description": "User messages hidden."
|
|
1013
|
+
},
|
|
1014
|
+
"at": {
|
|
1015
|
+
"type": "integer",
|
|
1016
|
+
"format": "int64",
|
|
1017
|
+
"description": "When the reverted message was created, in epoch milliseconds."
|
|
1018
|
+
},
|
|
1019
|
+
"files": {
|
|
1020
|
+
"type": "array",
|
|
1021
|
+
"items": {
|
|
1022
|
+
"$ref": "#/components/schemas/RevertFile"
|
|
1023
|
+
},
|
|
1024
|
+
"description": "Files restored (at most 50)."
|
|
1025
|
+
},
|
|
1026
|
+
"filesTotal": {
|
|
1027
|
+
"type": "integer",
|
|
1028
|
+
"format": "int32",
|
|
1029
|
+
"description": "Files restored in all."
|
|
1030
|
+
},
|
|
1031
|
+
"stagedAt": {
|
|
1032
|
+
"type": "integer",
|
|
1033
|
+
"format": "int64",
|
|
1034
|
+
"description": "When it was staged, in epoch milliseconds."
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
},
|
|
1038
|
+
"RevertFile": {
|
|
1039
|
+
"type": "object",
|
|
1040
|
+
"description": "A file a revert restores.",
|
|
1041
|
+
"required": ["file"],
|
|
1042
|
+
"properties": {
|
|
1043
|
+
"file": {
|
|
1044
|
+
"type": "string",
|
|
1045
|
+
"description": "Its path in the session's directory."
|
|
1046
|
+
},
|
|
1047
|
+
"status": {
|
|
1048
|
+
"type": "string",
|
|
1049
|
+
"x-hub-known": ["added", "deleted", "modified"]
|
|
1050
|
+
},
|
|
1051
|
+
"additions": {
|
|
1052
|
+
"type": "integer",
|
|
1053
|
+
"format": "int32"
|
|
1054
|
+
},
|
|
1055
|
+
"deletions": {
|
|
1056
|
+
"type": "integer",
|
|
1057
|
+
"format": "int32"
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
},
|
|
1061
|
+
"RevertCommitted": {
|
|
1062
|
+
"type": "object",
|
|
1063
|
+
"description": "The latest committed revert's removed window.",
|
|
1064
|
+
"required": ["messageID", "until", "at"],
|
|
1065
|
+
"properties": {
|
|
1066
|
+
"messageID": {
|
|
1067
|
+
"type": "string",
|
|
1068
|
+
"description": "The reverted message: it and everything after it were removed."
|
|
1069
|
+
},
|
|
1070
|
+
"from": {
|
|
1071
|
+
"type": "integer",
|
|
1072
|
+
"format": "int64",
|
|
1073
|
+
"description": "The reverted message's time, in epoch milliseconds."
|
|
1074
|
+
},
|
|
1075
|
+
"until": {
|
|
1076
|
+
"type": "integer",
|
|
1077
|
+
"format": "int64",
|
|
1078
|
+
"description": "When the revert was staged, in epoch milliseconds. Hub messages between from and until belonged to the removed history."
|
|
1079
|
+
},
|
|
1080
|
+
"at": {
|
|
1081
|
+
"type": "integer",
|
|
1082
|
+
"format": "int64",
|
|
1083
|
+
"description": "When it was committed, in epoch milliseconds."
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
},
|
|
1087
|
+
"NowActivity": {
|
|
1088
|
+
"type": "object",
|
|
1089
|
+
"description": "What the session (or a subagent below it) is doing now: its latest running activity.",
|
|
1090
|
+
"required": ["kind"],
|
|
1091
|
+
"properties": {
|
|
1092
|
+
"kind": {
|
|
1093
|
+
"type": "string",
|
|
1094
|
+
"x-hub-known": ["tool", "thinking"]
|
|
1095
|
+
},
|
|
1096
|
+
"tool": {
|
|
1097
|
+
"type": "string",
|
|
1098
|
+
"description": "The tool's name."
|
|
1099
|
+
},
|
|
1100
|
+
"summary": {
|
|
1101
|
+
"type": "string",
|
|
1102
|
+
"description": "A short summary of the tool's input: a command, a path."
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
"SessionStatus": {
|
|
1107
|
+
"type": "object",
|
|
1108
|
+
"description": "One entry of a status tree: a session's own state.",
|
|
1109
|
+
"required": ["id", "title", "state", "blockers"],
|
|
1110
|
+
"properties": {
|
|
1111
|
+
"id": {
|
|
1112
|
+
"type": "string"
|
|
1113
|
+
},
|
|
1114
|
+
"parentID": {
|
|
1115
|
+
"type": "string",
|
|
1116
|
+
"description": "A subagent session's parent."
|
|
1117
|
+
},
|
|
1118
|
+
"title": {
|
|
1119
|
+
"type": "string"
|
|
1120
|
+
},
|
|
1121
|
+
"state": {
|
|
1122
|
+
"type": "string",
|
|
1123
|
+
"x-hub-known": ["idle", "working", "blocked", "error"],
|
|
1124
|
+
"description": "blocked: waits for the user (a blocker); error: the last run failed; working; idle."
|
|
1125
|
+
},
|
|
1126
|
+
"detail": {
|
|
1127
|
+
"type": "string",
|
|
1128
|
+
"description": "state error: the error; while retrying: \"Retrying: <why>\"."
|
|
1129
|
+
},
|
|
1130
|
+
"blockers": {
|
|
1131
|
+
"type": "array",
|
|
1132
|
+
"items": {
|
|
1133
|
+
"$ref": "#/components/schemas/Blocker"
|
|
1134
|
+
},
|
|
1135
|
+
"description": "What waits for the user in this session (without sessionID and sessionTitle)."
|
|
1136
|
+
},
|
|
1137
|
+
"retry": {
|
|
1138
|
+
"$ref": "#/components/schemas/RetryInfo"
|
|
1139
|
+
},
|
|
1140
|
+
"errorType": {
|
|
1141
|
+
"type": "string",
|
|
1142
|
+
"description": "state error: the error's type (\"provider.quota\", \"tool.execution\", …), when known."
|
|
1143
|
+
},
|
|
1144
|
+
"errorStatus": {
|
|
1145
|
+
"type": "integer",
|
|
1146
|
+
"format": "int32",
|
|
1147
|
+
"description": "state error: the error's HTTP status, when known."
|
|
1148
|
+
},
|
|
1149
|
+
"jobs": {
|
|
1150
|
+
"type": "array",
|
|
1151
|
+
"items": {
|
|
1152
|
+
"$ref": "#/components/schemas/JobInfo"
|
|
1153
|
+
},
|
|
1154
|
+
"description": "Shells and terminals of the session: running ones, then the last few that ended."
|
|
1155
|
+
},
|
|
1156
|
+
"since": {
|
|
1157
|
+
"type": "integer",
|
|
1158
|
+
"format": "int64",
|
|
1159
|
+
"description": "state working: when the current run started, in epoch milliseconds."
|
|
1160
|
+
},
|
|
1161
|
+
"blockedSince": {
|
|
1162
|
+
"type": "integer",
|
|
1163
|
+
"format": "int64",
|
|
1164
|
+
"description": "state blocked: when the oldest open blocker was first seen, in epoch milliseconds."
|
|
1165
|
+
},
|
|
1166
|
+
"health": {
|
|
1167
|
+
"$ref": "#/components/schemas/SessionHealth"
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
},
|
|
1171
|
+
"SessionHealth": {
|
|
1172
|
+
"type": "object",
|
|
1173
|
+
"description": "(SS-1) Why the session is not making progress, next to its state (a session retrying a provider request stays \"working\"). Absent: ok. A kind the client does not know should be shown as-is.",
|
|
1174
|
+
"required": ["kind"],
|
|
1175
|
+
"properties": {
|
|
1176
|
+
"kind": {
|
|
1177
|
+
"type": "string",
|
|
1178
|
+
"x-hub-known": ["ok", "retrying", "stalled", "quota", "auth", "model_unavailable", "context_overflow", "network", "failed"],
|
|
1179
|
+
"description": "retrying: the provider request is being retried; stalled: still retrying after 3 attempts or 5 minutes; quota, auth, model_unavailable, context_overflow: retrying will not fix it; network: a connection failure; failed: any other failed run."
|
|
1180
|
+
},
|
|
1181
|
+
"since": {
|
|
1182
|
+
"type": "integer",
|
|
1183
|
+
"format": "int64",
|
|
1184
|
+
"description": "When this kind was first seen, in epoch milliseconds."
|
|
1185
|
+
},
|
|
1186
|
+
"resetAt": {
|
|
1187
|
+
"type": "integer",
|
|
1188
|
+
"format": "int64",
|
|
1189
|
+
"description": "quota: when the provider says the limit resets, in epoch milliseconds (when its message says)."
|
|
1190
|
+
},
|
|
1191
|
+
"attempt": {
|
|
1192
|
+
"type": "integer",
|
|
1193
|
+
"format": "int32",
|
|
1194
|
+
"description": "While retrying: the provider retry's attempt number."
|
|
1195
|
+
},
|
|
1196
|
+
"detail": {
|
|
1197
|
+
"type": "string",
|
|
1198
|
+
"maxLength": 200,
|
|
1199
|
+
"description": "The provider's message: one line, secrets redacted, at most 200 characters (untrusted text)."
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
},
|
|
1203
|
+
"RetryInfo": {
|
|
1204
|
+
"type": "object",
|
|
1205
|
+
"description": "The model request is being retried (the state stays working).",
|
|
1206
|
+
"properties": {
|
|
1207
|
+
"attempt": {
|
|
1208
|
+
"type": "integer",
|
|
1209
|
+
"format": "int32"
|
|
1210
|
+
},
|
|
1211
|
+
"message": {
|
|
1212
|
+
"type": "string",
|
|
1213
|
+
"description": "Why it retries."
|
|
1214
|
+
},
|
|
1215
|
+
"next": {
|
|
1216
|
+
"type": "integer",
|
|
1217
|
+
"format": "int64",
|
|
1218
|
+
"description": "When the next attempt runs, in epoch milliseconds."
|
|
1219
|
+
},
|
|
1220
|
+
"errorType": {
|
|
1221
|
+
"type": "string",
|
|
1222
|
+
"description": "e.g. \"provider.rate-limit\"."
|
|
1223
|
+
},
|
|
1224
|
+
"errorStatus": {
|
|
1225
|
+
"type": "integer",
|
|
1226
|
+
"format": "int32",
|
|
1227
|
+
"description": "The error's HTTP status."
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
},
|
|
1231
|
+
"JobInfo": {
|
|
1232
|
+
"type": "object",
|
|
1233
|
+
"description": "A shell or terminal of a session.",
|
|
1234
|
+
"required": ["id", "kind", "status"],
|
|
1235
|
+
"properties": {
|
|
1236
|
+
"id": {
|
|
1237
|
+
"type": "string"
|
|
1238
|
+
},
|
|
1239
|
+
"kind": {
|
|
1240
|
+
"type": "string",
|
|
1241
|
+
"x-hub-known": ["shell", "pty"]
|
|
1242
|
+
},
|
|
1243
|
+
"command": {
|
|
1244
|
+
"type": "string"
|
|
1245
|
+
},
|
|
1246
|
+
"status": {
|
|
1247
|
+
"type": "string",
|
|
1248
|
+
"x-hub-known": ["running", "exited", "timeout", "killed"]
|
|
1249
|
+
},
|
|
1250
|
+
"exit": {
|
|
1251
|
+
"type": "integer",
|
|
1252
|
+
"format": "int32",
|
|
1253
|
+
"description": "The exit code, once it ended."
|
|
1254
|
+
},
|
|
1255
|
+
"background": {
|
|
1256
|
+
"type": "boolean"
|
|
1257
|
+
},
|
|
1258
|
+
"started": {
|
|
1259
|
+
"type": "integer",
|
|
1260
|
+
"format": "int64",
|
|
1261
|
+
"description": "In epoch milliseconds."
|
|
1262
|
+
},
|
|
1263
|
+
"ended": {
|
|
1264
|
+
"type": "integer",
|
|
1265
|
+
"format": "int64",
|
|
1266
|
+
"description": "In epoch milliseconds."
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
},
|
|
1270
|
+
"Blocker": {
|
|
1271
|
+
"description": "Something a session waits for the user to answer: a permission request (answered with POST /api/v1/sessions/{session}/permission) or a form, which includes the agent's questions (POST …/form). In a session's `blockers` (the catalog, the session view) each carries the session it was asked in (sessionID, sessionTitle); in a status entry's it does not.",
|
|
1272
|
+
"oneOf": [
|
|
1273
|
+
{
|
|
1274
|
+
"$ref": "#/components/schemas/PermissionBlocker"
|
|
1275
|
+
},
|
|
1276
|
+
{
|
|
1277
|
+
"$ref": "#/components/schemas/FormBlocker"
|
|
1278
|
+
}
|
|
1279
|
+
],
|
|
1280
|
+
"discriminator": {
|
|
1281
|
+
"propertyName": "kind",
|
|
1282
|
+
"mapping": {
|
|
1283
|
+
"permission": "#/components/schemas/PermissionBlocker",
|
|
1284
|
+
"form": "#/components/schemas/FormBlocker"
|
|
1285
|
+
}
|
|
1286
|
+
},
|
|
1287
|
+
"x-hub-union": true
|
|
1288
|
+
},
|
|
1289
|
+
"PermissionBlocker": {
|
|
1290
|
+
"type": "object",
|
|
1291
|
+
"description": "A permission request.",
|
|
1292
|
+
"required": ["kind", "id", "summary"],
|
|
1293
|
+
"properties": {
|
|
1294
|
+
"kind": {
|
|
1295
|
+
"type": "string",
|
|
1296
|
+
"enum": ["permission"]
|
|
1297
|
+
},
|
|
1298
|
+
"id": {
|
|
1299
|
+
"type": "string",
|
|
1300
|
+
"description": "The request's ID."
|
|
1301
|
+
},
|
|
1302
|
+
"summary": {
|
|
1303
|
+
"type": "string",
|
|
1304
|
+
"description": "What it asks, as one line: \"<action>: <resources>\"."
|
|
1305
|
+
},
|
|
1306
|
+
"action": {
|
|
1307
|
+
"type": "string",
|
|
1308
|
+
"description": "What the agent asks to do: \"bash\", \"edit\", \"read\", an MCP tool, …"
|
|
1309
|
+
},
|
|
1310
|
+
"resources": {
|
|
1311
|
+
"type": "array",
|
|
1312
|
+
"items": {
|
|
1313
|
+
"type": "string"
|
|
1314
|
+
},
|
|
1315
|
+
"description": "What it applies to (commands, paths): at most 10, each shortened."
|
|
1316
|
+
},
|
|
1317
|
+
"recommendation": {
|
|
1318
|
+
"$ref": "#/components/schemas/BlockerRecommendation"
|
|
1319
|
+
},
|
|
1320
|
+
"sessionID": {
|
|
1321
|
+
"type": "string",
|
|
1322
|
+
"description": "The session it was asked in."
|
|
1323
|
+
},
|
|
1324
|
+
"sessionTitle": {
|
|
1325
|
+
"type": "string",
|
|
1326
|
+
"description": "That session's title."
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
},
|
|
1330
|
+
"FormBlocker": {
|
|
1331
|
+
"type": "object",
|
|
1332
|
+
"description": "A form, or a question of the agent.",
|
|
1333
|
+
"required": ["kind", "id", "summary"],
|
|
1334
|
+
"properties": {
|
|
1335
|
+
"kind": {
|
|
1336
|
+
"type": "string",
|
|
1337
|
+
"enum": ["form"]
|
|
1338
|
+
},
|
|
1339
|
+
"id": {
|
|
1340
|
+
"type": "string",
|
|
1341
|
+
"description": "The form's ID."
|
|
1342
|
+
},
|
|
1343
|
+
"summary": {
|
|
1344
|
+
"type": "string",
|
|
1345
|
+
"description": "The form's title (\"question\" when it has none)."
|
|
1346
|
+
},
|
|
1347
|
+
"question": {
|
|
1348
|
+
"type": "boolean",
|
|
1349
|
+
"description": "True when the agent's question tool asked it."
|
|
1350
|
+
},
|
|
1351
|
+
"fields": {
|
|
1352
|
+
"type": "array",
|
|
1353
|
+
"items": {
|
|
1354
|
+
"$ref": "#/components/schemas/FormField"
|
|
1355
|
+
},
|
|
1356
|
+
"description": "The fields a client can render (at most 20). Absent when the form was too large to carry: it is answered in the terminal then."
|
|
1357
|
+
},
|
|
1358
|
+
"sessionID": {
|
|
1359
|
+
"type": "string",
|
|
1360
|
+
"description": "The session it was asked in."
|
|
1361
|
+
},
|
|
1362
|
+
"sessionTitle": {
|
|
1363
|
+
"type": "string",
|
|
1364
|
+
"description": "That session's title."
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
},
|
|
1368
|
+
"BlockerRecommendation": {
|
|
1369
|
+
"type": "object",
|
|
1370
|
+
"description": "An agent escalated the permission request (it was outside its grant) and recommends an answer.",
|
|
1371
|
+
"required": ["by"],
|
|
1372
|
+
"properties": {
|
|
1373
|
+
"by": {
|
|
1374
|
+
"type": "string",
|
|
1375
|
+
"description": "The agent that recommends, as the hub names it."
|
|
1376
|
+
},
|
|
1377
|
+
"recommends": {
|
|
1378
|
+
"type": "string",
|
|
1379
|
+
"x-hub-known": ["approve"],
|
|
1380
|
+
"description": "Absent: it recommends nothing and only links its Decision."
|
|
1381
|
+
},
|
|
1382
|
+
"why": {
|
|
1383
|
+
"type": "string"
|
|
1384
|
+
},
|
|
1385
|
+
"decisionID": {
|
|
1386
|
+
"type": "string",
|
|
1387
|
+
"description": "The Decision the user answers it in."
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
},
|
|
1391
|
+
"FormField": {
|
|
1392
|
+
"type": "object",
|
|
1393
|
+
"description": "A field of a form, with what a client needs to render and check it.",
|
|
1394
|
+
"required": ["key", "type"],
|
|
1395
|
+
"properties": {
|
|
1396
|
+
"key": {
|
|
1397
|
+
"type": "string"
|
|
1398
|
+
},
|
|
1399
|
+
"type": {
|
|
1400
|
+
"type": "string",
|
|
1401
|
+
"x-hub-known": ["string", "number", "integer", "boolean", "multiselect", "external"],
|
|
1402
|
+
"description": "A field of a type the client does not know cannot be answered there."
|
|
1403
|
+
},
|
|
1404
|
+
"title": {
|
|
1405
|
+
"type": "string"
|
|
1406
|
+
},
|
|
1407
|
+
"description": {
|
|
1408
|
+
"type": "string"
|
|
1409
|
+
},
|
|
1410
|
+
"required": {
|
|
1411
|
+
"type": "boolean"
|
|
1412
|
+
},
|
|
1413
|
+
"options": {
|
|
1414
|
+
"type": "array",
|
|
1415
|
+
"items": {
|
|
1416
|
+
"$ref": "#/components/schemas/FormOption"
|
|
1417
|
+
},
|
|
1418
|
+
"description": "string and multiselect: the choices."
|
|
1419
|
+
},
|
|
1420
|
+
"custom": {
|
|
1421
|
+
"type": "boolean",
|
|
1422
|
+
"description": "With options: free text is allowed besides them."
|
|
1423
|
+
},
|
|
1424
|
+
"placeholder": {
|
|
1425
|
+
"type": "string"
|
|
1426
|
+
},
|
|
1427
|
+
"default": {
|
|
1428
|
+
"$ref": "#/components/schemas/JsonValue",
|
|
1429
|
+
"description": "The default: a string, a number, a boolean or a list of strings (multiselect)."
|
|
1430
|
+
},
|
|
1431
|
+
"minimum": {
|
|
1432
|
+
"type": "number"
|
|
1433
|
+
},
|
|
1434
|
+
"maximum": {
|
|
1435
|
+
"type": "number"
|
|
1436
|
+
},
|
|
1437
|
+
"minLength": {
|
|
1438
|
+
"type": "number"
|
|
1439
|
+
},
|
|
1440
|
+
"maxLength": {
|
|
1441
|
+
"type": "number"
|
|
1442
|
+
},
|
|
1443
|
+
"minItems": {
|
|
1444
|
+
"type": "number"
|
|
1445
|
+
},
|
|
1446
|
+
"maxItems": {
|
|
1447
|
+
"type": "number"
|
|
1448
|
+
},
|
|
1449
|
+
"format": {
|
|
1450
|
+
"type": "string"
|
|
1451
|
+
},
|
|
1452
|
+
"pattern": {
|
|
1453
|
+
"type": "string"
|
|
1454
|
+
},
|
|
1455
|
+
"url": {
|
|
1456
|
+
"type": "string",
|
|
1457
|
+
"description": "external: the link the user follows."
|
|
1458
|
+
},
|
|
1459
|
+
"when": {
|
|
1460
|
+
"type": "array",
|
|
1461
|
+
"items": {
|
|
1462
|
+
"$ref": "#/components/schemas/FormCondition"
|
|
1463
|
+
},
|
|
1464
|
+
"description": "Shown only when all of these hold."
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
},
|
|
1468
|
+
"FormOption": {
|
|
1469
|
+
"type": "object",
|
|
1470
|
+
"required": ["value", "label"],
|
|
1471
|
+
"properties": {
|
|
1472
|
+
"value": {
|
|
1473
|
+
"type": "string"
|
|
1474
|
+
},
|
|
1475
|
+
"label": {
|
|
1476
|
+
"type": "string"
|
|
1477
|
+
},
|
|
1478
|
+
"description": {
|
|
1479
|
+
"type": "string"
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
},
|
|
1483
|
+
"FormCondition": {
|
|
1484
|
+
"type": "object",
|
|
1485
|
+
"description": "A condition on another field's value.",
|
|
1486
|
+
"required": ["key", "op", "value"],
|
|
1487
|
+
"properties": {
|
|
1488
|
+
"key": {
|
|
1489
|
+
"type": "string",
|
|
1490
|
+
"description": "Another field's key."
|
|
1491
|
+
},
|
|
1492
|
+
"op": {
|
|
1493
|
+
"type": "string",
|
|
1494
|
+
"x-hub-known": ["eq", "neq"]
|
|
1495
|
+
},
|
|
1496
|
+
"value": {
|
|
1497
|
+
"$ref": "#/components/schemas/JsonValue",
|
|
1498
|
+
"description": "A string, a number or a boolean."
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
},
|
|
1502
|
+
"ActivityItem": {
|
|
1503
|
+
"type": "object",
|
|
1504
|
+
"description": "A tool call or a stretch of reasoning in a root session or below it.",
|
|
1505
|
+
"required": ["id", "sessionID", "kind", "state", "at"],
|
|
1506
|
+
"properties": {
|
|
1507
|
+
"id": {
|
|
1508
|
+
"type": "string",
|
|
1509
|
+
"description": "The tool call's ID, or thinking:<assistant message ID>."
|
|
1510
|
+
},
|
|
1511
|
+
"sessionID": {
|
|
1512
|
+
"type": "string",
|
|
1513
|
+
"description": "Where it happened: the root or a subagent session."
|
|
1514
|
+
},
|
|
1515
|
+
"kind": {
|
|
1516
|
+
"type": "string",
|
|
1517
|
+
"x-hub-known": ["tool", "thinking"]
|
|
1518
|
+
},
|
|
1519
|
+
"tool": {
|
|
1520
|
+
"type": "string"
|
|
1521
|
+
},
|
|
1522
|
+
"summary": {
|
|
1523
|
+
"type": "string",
|
|
1524
|
+
"description": "A short summary of the tool's input."
|
|
1525
|
+
},
|
|
1526
|
+
"background": {
|
|
1527
|
+
"type": "boolean",
|
|
1528
|
+
"description": "The tool was started in the background."
|
|
1529
|
+
},
|
|
1530
|
+
"childSessionID": {
|
|
1531
|
+
"type": "string",
|
|
1532
|
+
"description": "A subagent tool: the session it runs."
|
|
1533
|
+
},
|
|
1534
|
+
"state": {
|
|
1535
|
+
"type": "string",
|
|
1536
|
+
"x-hub-known": ["running", "done", "failed"]
|
|
1537
|
+
},
|
|
1538
|
+
"error": {
|
|
1539
|
+
"type": "string"
|
|
1540
|
+
},
|
|
1541
|
+
"at": {
|
|
1542
|
+
"type": "integer",
|
|
1543
|
+
"format": "int64",
|
|
1544
|
+
"description": "When it was created, then when its state last changed, in epoch milliseconds."
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
},
|
|
1548
|
+
"TimelinePage": {
|
|
1549
|
+
"type": "object",
|
|
1550
|
+
"description": "A page of a session's transcript.",
|
|
1551
|
+
"required": ["items"],
|
|
1552
|
+
"properties": {
|
|
1553
|
+
"items": {
|
|
1554
|
+
"type": "array",
|
|
1555
|
+
"items": {
|
|
1556
|
+
"$ref": "#/components/schemas/TimelineItem"
|
|
1557
|
+
},
|
|
1558
|
+
"description": "Rows in chronological order (sorted by pos where present)."
|
|
1559
|
+
},
|
|
1560
|
+
"cursor": {
|
|
1561
|
+
"type": "string",
|
|
1562
|
+
"description": "Forward paging: pass as `cursor` for the next newer page; absent at the end."
|
|
1563
|
+
},
|
|
1564
|
+
"older": {
|
|
1565
|
+
"type": "string",
|
|
1566
|
+
"description": "Newest-first paging: pass as `before` for the page before this one; absent at the beginning."
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
},
|
|
1570
|
+
"TimelineItem": {
|
|
1571
|
+
"type": "object",
|
|
1572
|
+
"description": "One row of the transcript. Which fields a row has depends on its kind.",
|
|
1573
|
+
"required": ["key", "messageID", "sessionID", "kind"],
|
|
1574
|
+
"properties": {
|
|
1575
|
+
"key": {
|
|
1576
|
+
"type": "string",
|
|
1577
|
+
"description": "Unique and stable in the session."
|
|
1578
|
+
},
|
|
1579
|
+
"messageID": {
|
|
1580
|
+
"type": "string",
|
|
1581
|
+
"description": "The harness's message (a message row: the hub message's ID)."
|
|
1582
|
+
},
|
|
1583
|
+
"partID": {
|
|
1584
|
+
"type": "string",
|
|
1585
|
+
"description": "The part of the message (assistant, reasoning and tool rows): the part of …/parts/{part}."
|
|
1586
|
+
},
|
|
1587
|
+
"sessionID": {
|
|
1588
|
+
"type": "string"
|
|
1589
|
+
},
|
|
1590
|
+
"kind": {
|
|
1591
|
+
"type": "string",
|
|
1592
|
+
"x-hub-known": ["user", "assistant", "reasoning", "tool", "message", "error", "retry"],
|
|
1593
|
+
"description": "user: the user's prompt; assistant: text of the agent; reasoning; tool: a tool call; message: a hub message delivered to the session; error: the turn failed; retry: the model request is being retried. A row of a kind the client does not know can be skipped."
|
|
1594
|
+
},
|
|
1595
|
+
"text": {
|
|
1596
|
+
"type": "string",
|
|
1597
|
+
"description": "user, assistant, reasoning, message: the text; error, retry: the error's message."
|
|
1598
|
+
},
|
|
1599
|
+
"name": {
|
|
1600
|
+
"type": "string",
|
|
1601
|
+
"description": "tool: the tool's name."
|
|
1602
|
+
},
|
|
1603
|
+
"state": {
|
|
1604
|
+
"type": "string",
|
|
1605
|
+
"x-hub-known": ["running", "done", "failed"],
|
|
1606
|
+
"description": "reasoning and tool rows."
|
|
1607
|
+
},
|
|
1608
|
+
"at": {
|
|
1609
|
+
"type": "integer",
|
|
1610
|
+
"format": "int64",
|
|
1611
|
+
"description": "When it was created, in epoch milliseconds (never used to order rows: see pos)."
|
|
1612
|
+
},
|
|
1613
|
+
"completed": {
|
|
1614
|
+
"type": "integer",
|
|
1615
|
+
"format": "int64",
|
|
1616
|
+
"description": "reasoning and tool rows: when they ended, in epoch milliseconds."
|
|
1617
|
+
},
|
|
1618
|
+
"files": {
|
|
1619
|
+
"type": "array",
|
|
1620
|
+
"items": {
|
|
1621
|
+
"$ref": "#/components/schemas/TimelineFile"
|
|
1622
|
+
},
|
|
1623
|
+
"description": "user: the message's attachments (metadata only; the bytes through …/files/{index} or …/media/{ref})."
|
|
1624
|
+
},
|
|
1625
|
+
"media": {
|
|
1626
|
+
"type": "array",
|
|
1627
|
+
"items": {
|
|
1628
|
+
"$ref": "#/components/schemas/TimelineFile"
|
|
1629
|
+
},
|
|
1630
|
+
"description": "tool: its image results; assistant: local image paths in the text."
|
|
1631
|
+
},
|
|
1632
|
+
"pos": {
|
|
1633
|
+
"type": "integer",
|
|
1634
|
+
"format": "int64",
|
|
1635
|
+
"description": "The ordering position: rows sort by it. Stable while history pages or the context window move."
|
|
1636
|
+
},
|
|
1637
|
+
"callID": {
|
|
1638
|
+
"type": "string",
|
|
1639
|
+
"description": "tool: the tool call's ID (live activity items use it)."
|
|
1640
|
+
},
|
|
1641
|
+
"childSessionID": {
|
|
1642
|
+
"type": "string",
|
|
1643
|
+
"description": "A subagent tool: the session it runs in."
|
|
1644
|
+
},
|
|
1645
|
+
"summary": {
|
|
1646
|
+
"type": "string",
|
|
1647
|
+
"description": "tool: a short summary of its input."
|
|
1648
|
+
},
|
|
1649
|
+
"title": {
|
|
1650
|
+
"type": "string",
|
|
1651
|
+
"description": "A subagent tool: the task's short description."
|
|
1652
|
+
},
|
|
1653
|
+
"ordinal": {
|
|
1654
|
+
"type": "integer",
|
|
1655
|
+
"format": "int32",
|
|
1656
|
+
"description": "assistant: which text part of the message this is (0, 1, …), as in live text deltas."
|
|
1657
|
+
},
|
|
1658
|
+
"direction": {
|
|
1659
|
+
"type": "string",
|
|
1660
|
+
"x-hub-known": ["in", "out"],
|
|
1661
|
+
"description": "message: in (delivered to the session) or out (sent by it)."
|
|
1662
|
+
},
|
|
1663
|
+
"message": {
|
|
1664
|
+
"$ref": "#/components/schemas/TimelineMessageMeta"
|
|
1665
|
+
},
|
|
1666
|
+
"errorType": {
|
|
1667
|
+
"type": "string",
|
|
1668
|
+
"description": "error and retry: the error's type."
|
|
1669
|
+
},
|
|
1670
|
+
"errorStatus": {
|
|
1671
|
+
"type": "integer",
|
|
1672
|
+
"format": "int32",
|
|
1673
|
+
"description": "error and retry: the error's HTTP status."
|
|
1674
|
+
},
|
|
1675
|
+
"declined": {
|
|
1676
|
+
"type": "boolean",
|
|
1677
|
+
"description": "error: a denied permission stopped the turn."
|
|
1678
|
+
},
|
|
1679
|
+
"attempt": {
|
|
1680
|
+
"type": "integer",
|
|
1681
|
+
"format": "int32",
|
|
1682
|
+
"description": "retry: the attempt."
|
|
1683
|
+
},
|
|
1684
|
+
"next": {
|
|
1685
|
+
"type": "integer",
|
|
1686
|
+
"format": "int64",
|
|
1687
|
+
"description": "retry: when the next attempt starts, in epoch milliseconds."
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
},
|
|
1691
|
+
"TimelineMessageMeta": {
|
|
1692
|
+
"type": "object",
|
|
1693
|
+
"description": "A message row's envelope.",
|
|
1694
|
+
"required": ["kind", "from", "to"],
|
|
1695
|
+
"properties": {
|
|
1696
|
+
"kind": {
|
|
1697
|
+
"type": "string",
|
|
1698
|
+
"x-hub-known": ["msg", "ask", "reply", "decline", "primer", "decision", "prompt"]
|
|
1699
|
+
},
|
|
1700
|
+
"from": {
|
|
1701
|
+
"type": "string",
|
|
1702
|
+
"description": "The sender's address, e.g. \"@api-refactor\"."
|
|
1703
|
+
},
|
|
1704
|
+
"to": {
|
|
1705
|
+
"type": "string",
|
|
1706
|
+
"description": "The address the sender wrote, e.g. \"@@reviewer\"."
|
|
1707
|
+
},
|
|
1708
|
+
"replyTo": {
|
|
1709
|
+
"type": "string",
|
|
1710
|
+
"description": "What a reply or decline answers."
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
},
|
|
1714
|
+
"TimelineFile": {
|
|
1715
|
+
"type": "object",
|
|
1716
|
+
"description": "An image of a row.",
|
|
1717
|
+
"required": ["index", "ref", "mime"],
|
|
1718
|
+
"properties": {
|
|
1719
|
+
"index": {
|
|
1720
|
+
"type": "integer",
|
|
1721
|
+
"format": "int32",
|
|
1722
|
+
"description": "Its position: in the user message's files, the tool's content, or among the text's images."
|
|
1723
|
+
},
|
|
1724
|
+
"ref": {
|
|
1725
|
+
"type": "string",
|
|
1726
|
+
"description": "Names it for …/media/{ref}: f<n>, t<part>.<item> or p:<path>."
|
|
1727
|
+
},
|
|
1728
|
+
"mime": {
|
|
1729
|
+
"type": "string"
|
|
1730
|
+
},
|
|
1731
|
+
"name": {
|
|
1732
|
+
"type": "string",
|
|
1733
|
+
"description": "A file name, or the image path as written."
|
|
1734
|
+
},
|
|
1735
|
+
"bytes": {
|
|
1736
|
+
"type": "integer",
|
|
1737
|
+
"format": "int64",
|
|
1738
|
+
"description": "Its size, when the machine knows it without reading the file."
|
|
1739
|
+
},
|
|
1740
|
+
"width": {
|
|
1741
|
+
"type": "integer",
|
|
1742
|
+
"format": "int32"
|
|
1743
|
+
},
|
|
1744
|
+
"height": {
|
|
1745
|
+
"type": "integer",
|
|
1746
|
+
"format": "int32"
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
},
|
|
1750
|
+
"TimelinePart": {
|
|
1751
|
+
"type": "object",
|
|
1752
|
+
"required": ["detail"],
|
|
1753
|
+
"properties": {
|
|
1754
|
+
"detail": {
|
|
1755
|
+
"$ref": "#/components/schemas/JsonValue",
|
|
1756
|
+
"description": "The harness's tool call: name, state (input, output, error, metadata) and time."
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
},
|
|
1760
|
+
"SessionMessageList": {
|
|
1761
|
+
"type": "object",
|
|
1762
|
+
"required": ["messages"],
|
|
1763
|
+
"properties": {
|
|
1764
|
+
"messages": {
|
|
1765
|
+
"type": "array",
|
|
1766
|
+
"items": {
|
|
1767
|
+
"$ref": "#/components/schemas/AgentMessage"
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
},
|
|
1772
|
+
"AgentMessage": {
|
|
1773
|
+
"type": "object",
|
|
1774
|
+
"description": "A hub message between sessions, the user and apps.",
|
|
1775
|
+
"required": ["id", "kind", "from", "to", "recipient", "text", "state", "at", "hop"],
|
|
1776
|
+
"properties": {
|
|
1777
|
+
"id": {
|
|
1778
|
+
"type": "string"
|
|
1779
|
+
},
|
|
1780
|
+
"kind": {
|
|
1781
|
+
"type": "string",
|
|
1782
|
+
"x-hub-known": ["msg", "ask", "reply", "decline"],
|
|
1783
|
+
"description": "msg: a message; ask: a question awaiting a reply; reply and decline: the answer to an ask."
|
|
1784
|
+
},
|
|
1785
|
+
"from": {
|
|
1786
|
+
"$ref": "#/components/schemas/Party"
|
|
1787
|
+
},
|
|
1788
|
+
"to": {
|
|
1789
|
+
"type": "string",
|
|
1790
|
+
"description": "The address as the sender wrote it, e.g. \"@@reviewer\"."
|
|
1791
|
+
},
|
|
1792
|
+
"recipient": {
|
|
1793
|
+
"$ref": "#/components/schemas/Party"
|
|
1794
|
+
},
|
|
1795
|
+
"generation": {
|
|
1796
|
+
"type": "integer",
|
|
1797
|
+
"format": "int64",
|
|
1798
|
+
"description": "A role address: the role holder generation it reached."
|
|
1799
|
+
},
|
|
1800
|
+
"text": {
|
|
1801
|
+
"type": "string"
|
|
1802
|
+
},
|
|
1803
|
+
"replyTo": {
|
|
1804
|
+
"type": "string",
|
|
1805
|
+
"description": "What a reply or decline answers."
|
|
1806
|
+
},
|
|
1807
|
+
"state": {
|
|
1808
|
+
"type": "string",
|
|
1809
|
+
"x-hub-known": ["sent", "open", "answered", "declined", "expired"],
|
|
1810
|
+
"description": "sent for msg, reply and decline; an ask is open until answered, declined or expired."
|
|
1811
|
+
},
|
|
1812
|
+
"at": {
|
|
1813
|
+
"type": "integer",
|
|
1814
|
+
"format": "int64",
|
|
1815
|
+
"description": "When it was sent, in epoch milliseconds."
|
|
1816
|
+
},
|
|
1817
|
+
"hop": {
|
|
1818
|
+
"type": "integer",
|
|
1819
|
+
"format": "int32",
|
|
1820
|
+
"description": "Hops since a human turn (loop protection)."
|
|
1821
|
+
},
|
|
1822
|
+
"expiresAt": {
|
|
1823
|
+
"type": "integer",
|
|
1824
|
+
"format": "int64",
|
|
1825
|
+
"description": "An ask: when it expires, in epoch milliseconds."
|
|
1826
|
+
},
|
|
1827
|
+
"notAfter": {
|
|
1828
|
+
"type": "integer",
|
|
1829
|
+
"format": "int64",
|
|
1830
|
+
"description": "Not delivered after this, in epoch milliseconds."
|
|
1831
|
+
},
|
|
1832
|
+
"delivery": {
|
|
1833
|
+
"type": "string",
|
|
1834
|
+
"x-hub-known": ["steer", "turn", "queued", "retained", "pending", "dropped", "expired"],
|
|
1835
|
+
"description": "How it reached its recipient."
|
|
1836
|
+
},
|
|
1837
|
+
"expiredReason": {
|
|
1838
|
+
"type": "string",
|
|
1839
|
+
"x-hub-known": ["not_after", "pending_timeout"],
|
|
1840
|
+
"description": "delivery expired: why."
|
|
1841
|
+
},
|
|
1842
|
+
"deliveredAt": {
|
|
1843
|
+
"type": "integer",
|
|
1844
|
+
"format": "int64",
|
|
1845
|
+
"description": "When it was first delivered, in epoch milliseconds."
|
|
1846
|
+
},
|
|
1847
|
+
"answer": {
|
|
1848
|
+
"$ref": "#/components/schemas/MessageAnswerRef"
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
},
|
|
1852
|
+
"MessageAnswerRef": {
|
|
1853
|
+
"type": "object",
|
|
1854
|
+
"description": "What closed an ask.",
|
|
1855
|
+
"required": ["id", "at"],
|
|
1856
|
+
"properties": {
|
|
1857
|
+
"id": {
|
|
1858
|
+
"type": "string",
|
|
1859
|
+
"description": "The reply or decline."
|
|
1860
|
+
},
|
|
1861
|
+
"at": {
|
|
1862
|
+
"type": "integer",
|
|
1863
|
+
"format": "int64",
|
|
1864
|
+
"description": "In epoch milliseconds."
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
},
|
|
1868
|
+
"Party": {
|
|
1869
|
+
"description": "Who sends or receives a message: a session, the user (@me) or an app.",
|
|
1870
|
+
"oneOf": [
|
|
1871
|
+
{
|
|
1872
|
+
"$ref": "#/components/schemas/SessionParty"
|
|
1873
|
+
},
|
|
1874
|
+
{
|
|
1875
|
+
"$ref": "#/components/schemas/UserParty"
|
|
1876
|
+
},
|
|
1877
|
+
{
|
|
1878
|
+
"$ref": "#/components/schemas/AppParty"
|
|
1879
|
+
}
|
|
1880
|
+
],
|
|
1881
|
+
"discriminator": {
|
|
1882
|
+
"propertyName": "kind",
|
|
1883
|
+
"mapping": {
|
|
1884
|
+
"session": "#/components/schemas/SessionParty",
|
|
1885
|
+
"user": "#/components/schemas/UserParty",
|
|
1886
|
+
"app": "#/components/schemas/AppParty"
|
|
1887
|
+
}
|
|
1888
|
+
},
|
|
1889
|
+
"x-hub-union": true
|
|
1890
|
+
},
|
|
1891
|
+
"SessionParty": {
|
|
1892
|
+
"type": "object",
|
|
1893
|
+
"required": ["kind", "sessionID"],
|
|
1894
|
+
"properties": {
|
|
1895
|
+
"kind": {
|
|
1896
|
+
"type": "string",
|
|
1897
|
+
"enum": ["session"]
|
|
1898
|
+
},
|
|
1899
|
+
"sessionID": {
|
|
1900
|
+
"type": "string"
|
|
1901
|
+
},
|
|
1902
|
+
"name": {
|
|
1903
|
+
"type": "string",
|
|
1904
|
+
"description": "Its name in the directory, when known."
|
|
1905
|
+
},
|
|
1906
|
+
"harness": {
|
|
1907
|
+
"type": "string"
|
|
1908
|
+
},
|
|
1909
|
+
"machine": {
|
|
1910
|
+
"type": "string",
|
|
1911
|
+
"description": "Its machine's name."
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
},
|
|
1915
|
+
"UserParty": {
|
|
1916
|
+
"type": "object",
|
|
1917
|
+
"description": "The user (@me).",
|
|
1918
|
+
"required": ["kind"],
|
|
1919
|
+
"properties": {
|
|
1920
|
+
"kind": {
|
|
1921
|
+
"type": "string",
|
|
1922
|
+
"enum": ["user"]
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
},
|
|
1926
|
+
"AppParty": {
|
|
1927
|
+
"type": "object",
|
|
1928
|
+
"required": ["kind", "tokenID"],
|
|
1929
|
+
"properties": {
|
|
1930
|
+
"kind": {
|
|
1931
|
+
"type": "string",
|
|
1932
|
+
"enum": ["app"]
|
|
1933
|
+
},
|
|
1934
|
+
"tokenID": {
|
|
1935
|
+
"type": "string",
|
|
1936
|
+
"description": "The app token's ID."
|
|
1937
|
+
},
|
|
1938
|
+
"label": {
|
|
1939
|
+
"type": "string"
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
},
|
|
1943
|
+
"ReadMarks": {
|
|
1944
|
+
"type": "object",
|
|
1945
|
+
"required": ["reads"],
|
|
1946
|
+
"properties": {
|
|
1947
|
+
"reads": {
|
|
1948
|
+
"type": "object",
|
|
1949
|
+
"additionalProperties": {
|
|
1950
|
+
"type": "integer",
|
|
1951
|
+
"format": "int64",
|
|
1952
|
+
"description": "When it was read, in epoch milliseconds."
|
|
1953
|
+
},
|
|
1954
|
+
"description": "Session ID → when the user last read it."
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
},
|
|
1958
|
+
"MarkReadRequest": {
|
|
1959
|
+
"type": "object",
|
|
1960
|
+
"properties": {
|
|
1961
|
+
"open": {
|
|
1962
|
+
"type": "boolean",
|
|
1963
|
+
"description": "True when the user opened the session (navigated to it, or showed it again), not when a visible pane marks itself read: only an open counts as the user's activity."
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
},
|
|
1967
|
+
"ViewPrefs": {
|
|
1968
|
+
"type": "object",
|
|
1969
|
+
"description": "The session list's hidden and pinned sessions and workspaces. A workspace key is herdr:<workspaceID> or a folder path.",
|
|
1970
|
+
"required": ["hiddenSessions", "hiddenWorkspaces", "pinnedSessions", "pinnedWorkspaces"],
|
|
1971
|
+
"properties": {
|
|
1972
|
+
"hiddenSessions": {
|
|
1973
|
+
"type": "array",
|
|
1974
|
+
"items": {
|
|
1975
|
+
"type": "string"
|
|
1976
|
+
},
|
|
1977
|
+
"description": "Archived sessions."
|
|
1978
|
+
},
|
|
1979
|
+
"hiddenWorkspaces": {
|
|
1980
|
+
"type": "array",
|
|
1981
|
+
"items": {
|
|
1982
|
+
"type": "string"
|
|
1983
|
+
},
|
|
1984
|
+
"description": "Hidden workspaces: herdr:<workspaceID> or a folder path."
|
|
1985
|
+
},
|
|
1986
|
+
"pinnedSessions": {
|
|
1987
|
+
"type": "array",
|
|
1988
|
+
"items": {
|
|
1989
|
+
"type": "string"
|
|
1990
|
+
}
|
|
1991
|
+
},
|
|
1992
|
+
"pinnedWorkspaces": {
|
|
1993
|
+
"type": "array",
|
|
1994
|
+
"items": {
|
|
1995
|
+
"type": "string"
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
},
|
|
2000
|
+
"ViewPrefsState": {
|
|
2001
|
+
"type": "object",
|
|
2002
|
+
"required": ["prefs"],
|
|
2003
|
+
"properties": {
|
|
2004
|
+
"prefs": {
|
|
2005
|
+
"$ref": "#/components/schemas/ViewPrefs"
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
},
|
|
2009
|
+
"ViewPrefsChange": {
|
|
2010
|
+
"type": "object",
|
|
2011
|
+
"description": "At least one list; each replaces the stored one. No other keys.",
|
|
2012
|
+
"properties": {
|
|
2013
|
+
"hiddenSessions": {
|
|
2014
|
+
"type": "array",
|
|
2015
|
+
"items": {
|
|
2016
|
+
"type": "string",
|
|
2017
|
+
"minLength": 1,
|
|
2018
|
+
"maxLength": 4096
|
|
2019
|
+
},
|
|
2020
|
+
"maxItems": 5000,
|
|
2021
|
+
"description": "Replaces the archived sessions."
|
|
2022
|
+
},
|
|
2023
|
+
"hiddenWorkspaces": {
|
|
2024
|
+
"type": "array",
|
|
2025
|
+
"items": {
|
|
2026
|
+
"type": "string",
|
|
2027
|
+
"minLength": 1,
|
|
2028
|
+
"maxLength": 4096
|
|
2029
|
+
},
|
|
2030
|
+
"maxItems": 500
|
|
2031
|
+
},
|
|
2032
|
+
"pinnedSessions": {
|
|
2033
|
+
"type": "array",
|
|
2034
|
+
"items": {
|
|
2035
|
+
"type": "string",
|
|
2036
|
+
"minLength": 1,
|
|
2037
|
+
"maxLength": 4096
|
|
2038
|
+
},
|
|
2039
|
+
"maxItems": 500
|
|
2040
|
+
},
|
|
2041
|
+
"pinnedWorkspaces": {
|
|
2042
|
+
"type": "array",
|
|
2043
|
+
"items": {
|
|
2044
|
+
"type": "string",
|
|
2045
|
+
"minLength": 1,
|
|
2046
|
+
"maxLength": 4096
|
|
2047
|
+
},
|
|
2048
|
+
"maxItems": 500
|
|
2049
|
+
}
|
|
2050
|
+
},
|
|
2051
|
+
"minProperties": 1
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
}
|