@opencode/protocol 2.0.2 → 2.0.4
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/dist/api.d.ts +4 -6
- package/dist/api.js +4 -8
- package/dist/client.d.ts +0 -2
- package/dist/client.js +0 -2
- package/dist/errors.d.ts +20 -0
- package/dist/errors.js +17 -0
- package/dist/groups/agent.d.ts +6 -5
- package/dist/groups/agent.js +2 -2
- package/dist/groups/command.d.ts +3 -3
- package/dist/groups/command.js +1 -1
- package/dist/groups/config.d.ts +5 -13
- package/dist/groups/config.js +11 -18
- package/dist/groups/credential.d.ts +3 -18
- package/dist/groups/credential.js +3 -10
- package/dist/groups/debug.d.ts +0 -8
- package/dist/groups/debug.js +3 -3
- package/dist/groups/event.d.ts +99 -74
- package/dist/groups/event.js +3 -3
- package/dist/groups/form.d.ts +6 -654
- package/dist/groups/form.js +6 -83
- package/dist/groups/fs.d.ts +6 -6
- package/dist/groups/fs.js +3 -3
- package/dist/groups/generate.d.ts +1 -1
- package/dist/groups/generate.js +2 -2
- package/dist/groups/integration.d.ts +27 -27
- package/dist/groups/integration.js +19 -16
- package/dist/groups/location.d.ts +10 -4
- package/dist/groups/location.js +2 -3
- package/dist/groups/mcp.d.ts +11 -13
- package/dist/groups/mcp.js +10 -10
- package/dist/groups/message.d.ts +710 -41
- package/dist/groups/message.js +26 -3
- package/dist/groups/migration.js +1 -1
- package/dist/groups/model.d.ts +12 -9
- package/dist/groups/model.js +2 -2
- package/dist/groups/permission.d.ts +9 -16
- package/dist/groups/permission.js +8 -20
- package/dist/groups/persistent-pty.js +1 -1
- package/dist/groups/plugin.d.ts +7 -12
- package/dist/groups/plugin.js +3 -13
- package/dist/groups/project.d.ts +1 -14
- package/dist/groups/project.js +2 -13
- package/dist/groups/provider.d.ts +8 -7
- package/dist/groups/provider.js +2 -2
- package/dist/groups/pty.d.ts +15 -12
- package/dist/groups/pty.js +8 -8
- package/dist/groups/reference.d.ts +8 -12
- package/dist/groups/reference.js +16 -3
- package/dist/groups/rpc.d.ts +0 -1
- package/dist/groups/rpc.js +1 -1
- package/dist/groups/server.d.ts +9 -1
- package/dist/groups/server.js +11 -5
- package/dist/groups/session.d.ts +1146 -787
- package/dist/groups/session.js +192 -93
- package/dist/groups/shell.d.ts +13 -43
- package/dist/groups/shell.js +6 -24
- package/dist/groups/skill.d.ts +4 -5
- package/dist/groups/skill.js +1 -1
- package/dist/groups/vcs.d.ts +17 -12
- package/dist/groups/vcs.js +6 -6
- package/dist/groups/websearch.d.ts +6 -5
- package/dist/groups/websearch.js +2 -2
- package/dist/groups/worktree.d.ts +17 -23
- package/dist/groups/worktree.js +21 -30
- package/package.json +2 -2
- package/dist/groups/health.d.ts +0 -15
- package/dist/groups/health.js +0 -20
- package/dist/groups/workspace.d.ts +0 -22
- package/dist/groups/workspace.js +0 -27
package/dist/groups/session.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { SessionMessage } from "@opencode/schema/session-message";
|
|
2
|
-
import { SessionTransfer } from "@opencode/schema/session-transfer";
|
|
3
2
|
import { SessionInbox } from "@opencode/schema/session-inbox";
|
|
4
3
|
import { PromptInput } from "@opencode/schema/prompt-input";
|
|
5
4
|
import { Session } from "@opencode/schema/session";
|
|
6
5
|
import { SessionStats } from "@opencode/schema/session-stats";
|
|
7
6
|
import { InstructionEntry } from "@opencode/schema/instruction-entry";
|
|
8
7
|
import { Project } from "@opencode/schema/project";
|
|
9
|
-
import { AbsolutePath, NonNegativeInt, PositiveInt, RelativePath, statics } from "@opencode/schema/schema";
|
|
8
|
+
import { AbsolutePath, DateTimeUtcFromMillis, NonNegativeInt, PositiveInt, RelativePath, statics, } from "@opencode/schema/schema";
|
|
10
9
|
import { Event } from "@opencode/schema/event";
|
|
11
|
-
import { Workspace } from "@opencode/schema/workspace";
|
|
12
10
|
import { Context, Effect, Encoding, Result, Schema, SchemaGetter, Struct } from "effect";
|
|
13
11
|
import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, OpenApi } from "effect/unstable/httpapi";
|
|
14
|
-
import { ConflictError, CommandExecutionError, CommandNotFoundError, InvalidCursorError, InvalidRequestError, MessageNotFoundError, ServiceUnavailableError, SessionBusyError, SessionNotFoundError, SkillNotFoundError, UnknownError, } from "../errors.js";
|
|
12
|
+
import { ConflictError, CommandExecutionError, CommandNotFoundError, FormAlreadySettledError, FormInvalidAnswerError, FormNotFoundError, InvalidCursorError, InvalidRequestError, MessageNotFoundError, ServiceUnavailableError, SessionBusyError, SessionNotFoundError, SkillNotFoundError, UnknownError, } from "../errors.js";
|
|
15
13
|
import { Agent } from "@opencode/schema/agent";
|
|
16
14
|
import { Skill } from "@opencode/schema/skill";
|
|
17
15
|
import { Model } from "@opencode/schema/model";
|
|
@@ -19,6 +17,9 @@ import { Permission } from "@opencode/schema/permission";
|
|
|
19
17
|
import { Location } from "@opencode/schema/location";
|
|
20
18
|
import { SessionEvent } from "@opencode/schema/session-event";
|
|
21
19
|
import { EventLog } from "@opencode/schema/event-log";
|
|
20
|
+
import { FileDiff } from "@opencode/schema/file-diff";
|
|
21
|
+
import { Form } from "@opencode/schema/form";
|
|
22
|
+
import { PublicSessionMessage } from "./message.js";
|
|
22
23
|
const ParentIDFilter = Schema.Union([
|
|
23
24
|
Session.ID,
|
|
24
25
|
Schema.Null.pipe(Schema.encodeTo(Schema.Literal("null"), {
|
|
@@ -29,7 +30,6 @@ const ParentIDFilter = Schema.Union([
|
|
|
29
30
|
description: "Filter by parent session. Use null to return only root sessions.",
|
|
30
31
|
});
|
|
31
32
|
const SessionsQueryFields = {
|
|
32
|
-
workspace: Workspace.ID.pipe(Schema.optional),
|
|
33
33
|
limit: Schema.NumberFromString.pipe(Schema.decodeTo(PositiveInt), Schema.optional).annotate({
|
|
34
34
|
description: "Maximum number of sessions to return. Defaults to the newest 50 sessions.",
|
|
35
35
|
}),
|
|
@@ -77,6 +77,34 @@ export const SessionsCursor = Schema.String.pipe(Schema.brand("SessionsCursor"),
|
|
|
77
77
|
const SessionActive = Schema.Struct({
|
|
78
78
|
type: Schema.Literal("running"),
|
|
79
79
|
}).annotate({ identifier: "SessionActive" });
|
|
80
|
+
const PublicSessionInfo = Schema.Struct({
|
|
81
|
+
...Struct.omit(Session.Info.fields, ["location"]),
|
|
82
|
+
location: Location.PublicRef,
|
|
83
|
+
}).annotate({ identifier: "Session.Info" });
|
|
84
|
+
const PublicSessionTransfer = Schema.Struct({
|
|
85
|
+
info: PublicSessionInfo,
|
|
86
|
+
messages: Schema.Array(PublicSessionMessage),
|
|
87
|
+
}).annotate({ identifier: "SessionTransfer.Data" });
|
|
88
|
+
const PublicMovePayload = Schema.Struct({
|
|
89
|
+
...Struct.omit(SessionInbox.MovePayload.fields, ["location"]),
|
|
90
|
+
location: Location.PublicRef,
|
|
91
|
+
}).annotate({ identifier: "Session.Inbox.MovePayload" });
|
|
92
|
+
const PublicMove = Schema.Struct({
|
|
93
|
+
...Struct.omit(SessionInbox.Move.fields, ["payload"]),
|
|
94
|
+
payload: PublicMovePayload,
|
|
95
|
+
}).annotate({ identifier: "Session.Inbox.Move" });
|
|
96
|
+
const PublicInboxInfo = Schema.Union([
|
|
97
|
+
SessionInbox.User,
|
|
98
|
+
SessionInbox.Synthetic,
|
|
99
|
+
SessionInbox.Compaction,
|
|
100
|
+
PublicMove,
|
|
101
|
+
]).annotate({ identifier: "Session.Inbox.Info" });
|
|
102
|
+
const FormCreatePayload = Schema.Struct({
|
|
103
|
+
id: Form.ID.pipe(Schema.optional),
|
|
104
|
+
title: Form.Info.fields.title,
|
|
105
|
+
metadata: Form.Info.fields.metadata,
|
|
106
|
+
fields: Form.Info.fields.fields,
|
|
107
|
+
}).annotate({ identifier: "Form.CreatePayload" });
|
|
80
108
|
const BooleanFromString = Schema.Literals(["true", "false"]).pipe(Schema.decodeTo(Schema.Boolean, {
|
|
81
109
|
decode: SchemaGetter.transform((value) => value === "true"),
|
|
82
110
|
encode: SchemaGetter.transform((value) => (value ? "true" : "false")),
|
|
@@ -91,11 +119,11 @@ export const SessionsQuery = Schema.Struct({
|
|
|
91
119
|
subpath: RelativePath.pipe(Schema.optional),
|
|
92
120
|
cursor: SessionsQueryCursor.pipe(Schema.optional),
|
|
93
121
|
}).annotate({ identifier: "SessionsQuery" });
|
|
94
|
-
export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make("server.session")
|
|
122
|
+
export const makeSessionGroup = (sessionLocationMiddleware, formLocationMiddleware) => HttpApiGroup.make("server.session")
|
|
95
123
|
.add(HttpApiEndpoint.get("session.list", "/api/session", {
|
|
96
124
|
query: SessionsQuery,
|
|
97
125
|
success: Schema.Struct({
|
|
98
|
-
data: Schema.Array(
|
|
126
|
+
data: Schema.Array(PublicSessionInfo),
|
|
99
127
|
cursor: Schema.Struct({
|
|
100
128
|
previous: SessionsCursor.pipe(Schema.optional),
|
|
101
129
|
next: SessionsCursor.pipe(Schema.optional),
|
|
@@ -103,11 +131,11 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
103
131
|
}).annotate({ identifier: "SessionsResponse" }),
|
|
104
132
|
error: [InvalidCursorError, InvalidRequestError],
|
|
105
133
|
}).annotateMerge(OpenApi.annotations({
|
|
106
|
-
identifier: "
|
|
134
|
+
identifier: "session.list",
|
|
107
135
|
summary: "List sessions",
|
|
108
136
|
description: "Retrieve sessions in the requested order. Items keep that order across pages; use cursor.next or cursor.previous to move through the ordered list.",
|
|
109
137
|
})))
|
|
110
|
-
.add(HttpApiEndpoint.get("session.stats", "/api/session/stats", {
|
|
138
|
+
.add(HttpApiEndpoint.get("session.stats", "/api/experimental/session/stats", {
|
|
111
139
|
query: Schema.Struct({
|
|
112
140
|
from: Schema.NumberFromString.pipe(Schema.optional),
|
|
113
141
|
to: Schema.NumberFromString.pipe(Schema.optional),
|
|
@@ -118,7 +146,7 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
118
146
|
success: Schema.Struct({ data: SessionStats.Info }),
|
|
119
147
|
error: InvalidRequestError,
|
|
120
148
|
}).annotateMerge(OpenApi.annotations({
|
|
121
|
-
identifier: "
|
|
149
|
+
identifier: "experimental.session.stats",
|
|
122
150
|
summary: "Get session statistics",
|
|
123
151
|
description: "Aggregate local session activity, usage, and tool reliability for a time range.",
|
|
124
152
|
})))
|
|
@@ -128,51 +156,51 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
128
156
|
title: Schema.String.pipe(Schema.optional),
|
|
129
157
|
agent: Agent.ID.pipe(Schema.optional),
|
|
130
158
|
model: Model.Ref.pipe(Schema.optional),
|
|
131
|
-
location: Location.
|
|
159
|
+
location: Location.PublicRef.pipe(Schema.optional),
|
|
132
160
|
metadata: Session.Metadata.pipe(Schema.optional),
|
|
133
161
|
permissions: Permission.Ruleset.pipe(Schema.optional),
|
|
134
162
|
}),
|
|
135
|
-
success: Schema.Struct({ data:
|
|
163
|
+
success: Schema.Struct({ data: PublicSessionInfo }),
|
|
136
164
|
}).annotateMerge(OpenApi.annotations({
|
|
137
|
-
identifier: "
|
|
165
|
+
identifier: "session.create",
|
|
138
166
|
summary: "Create session",
|
|
139
167
|
description: "Create a session at the requested location.",
|
|
140
168
|
})))
|
|
141
|
-
.add(HttpApiEndpoint.post("session.import", "/api/session/import", {
|
|
169
|
+
.add(HttpApiEndpoint.post("session.import", "/api/experimental/session/import", {
|
|
142
170
|
payload: Schema.Struct({
|
|
143
|
-
...
|
|
144
|
-
location: Location.
|
|
171
|
+
...PublicSessionTransfer.fields,
|
|
172
|
+
location: Location.PublicRef.pipe(Schema.optional),
|
|
145
173
|
}),
|
|
146
|
-
success: Schema.Struct({ data:
|
|
174
|
+
success: Schema.Struct({ data: PublicSessionInfo }),
|
|
147
175
|
error: [ConflictError, SessionNotFoundError],
|
|
148
176
|
}).annotateMerge(OpenApi.annotations({
|
|
149
|
-
identifier: "
|
|
177
|
+
identifier: "experimental.session.import",
|
|
150
178
|
summary: "Import session",
|
|
151
179
|
description: "Import a projected session transcript at the requested location. If parentID is supplied, the parent session must already exist; import parents before children.",
|
|
152
180
|
})))
|
|
153
|
-
.add(HttpApiEndpoint.get("session.export", "/api/session/:sessionID/export", {
|
|
181
|
+
.add(HttpApiEndpoint.get("session.export", "/api/experimental/session/:sessionID/export", {
|
|
154
182
|
params: { sessionID: Session.ID },
|
|
155
183
|
query: Schema.Struct({ sanitize: BooleanFromString.pipe(Schema.optional) }),
|
|
156
|
-
success: Schema.Struct({ data:
|
|
184
|
+
success: Schema.Struct({ data: PublicSessionTransfer }),
|
|
157
185
|
error: [SessionNotFoundError, UnknownError],
|
|
158
186
|
}).annotateMerge(OpenApi.annotations({
|
|
159
|
-
identifier: "
|
|
187
|
+
identifier: "experimental.session.export",
|
|
160
188
|
summary: "Export session",
|
|
161
189
|
description: "Export a complete projected session transcript.",
|
|
162
190
|
})))
|
|
163
191
|
.add(HttpApiEndpoint.get("session.active", "/api/session/active", {
|
|
164
192
|
success: Schema.Struct({ data: Schema.Record(Session.ID, SessionActive) }),
|
|
165
193
|
}).annotateMerge(OpenApi.annotations({
|
|
166
|
-
identifier: "
|
|
194
|
+
identifier: "session.active",
|
|
167
195
|
summary: "List active sessions",
|
|
168
196
|
description: "Retrieve foreground Session drains currently owned by this OpenCode process. Sessions absent from the result are inactive.",
|
|
169
197
|
})))
|
|
170
198
|
.add(HttpApiEndpoint.get("session.get", "/api/session/:sessionID", {
|
|
171
199
|
params: { sessionID: Session.ID },
|
|
172
|
-
success: Schema.Struct({ data:
|
|
200
|
+
success: Schema.Struct({ data: PublicSessionInfo }),
|
|
173
201
|
error: SessionNotFoundError,
|
|
174
202
|
}).annotateMerge(OpenApi.annotations({
|
|
175
|
-
identifier: "
|
|
203
|
+
identifier: "session.get",
|
|
176
204
|
summary: "Get session",
|
|
177
205
|
description: "Retrieve a session by ID.",
|
|
178
206
|
})))
|
|
@@ -181,21 +209,21 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
181
209
|
success: HttpApiSchema.NoContent,
|
|
182
210
|
error: SessionNotFoundError,
|
|
183
211
|
}).annotateMerge(OpenApi.annotations({
|
|
184
|
-
identifier: "
|
|
212
|
+
identifier: "session.remove",
|
|
185
213
|
summary: "Delete session",
|
|
186
214
|
description: "Delete a session and its child sessions.",
|
|
187
215
|
})))
|
|
188
216
|
.add(HttpApiEndpoint.post("session.fork", "/api/session/:sessionID/fork", {
|
|
189
217
|
params: { sessionID: Session.ID },
|
|
190
|
-
payload: Schema.Struct({
|
|
191
|
-
success: Schema.Struct({ data:
|
|
218
|
+
payload: Schema.Struct({ before: SessionMessage.ID.pipe(Schema.optional) }),
|
|
219
|
+
success: Schema.Struct({ data: PublicSessionInfo }),
|
|
192
220
|
error: [SessionNotFoundError, MessageNotFoundError, InvalidRequestError],
|
|
193
221
|
})
|
|
194
222
|
.middleware(sessionLocationMiddleware)
|
|
195
223
|
.annotateMerge(OpenApi.annotations({
|
|
196
|
-
identifier: "
|
|
224
|
+
identifier: "session.fork",
|
|
197
225
|
summary: "Fork session",
|
|
198
|
-
description: "Create a child session by copying projected history
|
|
226
|
+
description: "Create a child session by copying projected history before a message. Omit before to copy the full history.",
|
|
199
227
|
})))
|
|
200
228
|
.add(HttpApiEndpoint.post("session.switchAgent", "/api/session/:sessionID/agent", {
|
|
201
229
|
params: { sessionID: Session.ID },
|
|
@@ -205,7 +233,7 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
205
233
|
})
|
|
206
234
|
.middleware(sessionLocationMiddleware)
|
|
207
235
|
.annotateMerge(OpenApi.annotations({
|
|
208
|
-
identifier: "
|
|
236
|
+
identifier: "session.switchAgent",
|
|
209
237
|
summary: "Switch session agent",
|
|
210
238
|
description: "Switch the agent used by subsequent provider turns.",
|
|
211
239
|
})))
|
|
@@ -217,31 +245,34 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
217
245
|
})
|
|
218
246
|
.middleware(sessionLocationMiddleware)
|
|
219
247
|
.annotateMerge(OpenApi.annotations({
|
|
220
|
-
identifier: "
|
|
248
|
+
identifier: "session.switchModel",
|
|
221
249
|
summary: "Switch session model",
|
|
222
250
|
description: "Switch the model used by subsequent provider turns.",
|
|
223
251
|
})))
|
|
224
|
-
.add(HttpApiEndpoint.
|
|
252
|
+
.add(HttpApiEndpoint.patch("session.update", "/api/session/:sessionID", {
|
|
225
253
|
params: { sessionID: Session.ID },
|
|
226
|
-
payload: Schema.Struct({
|
|
254
|
+
payload: Schema.Struct({
|
|
255
|
+
title: Schema.String.pipe(Schema.optional),
|
|
256
|
+
permissions: Permission.Ruleset.pipe(Schema.optional),
|
|
257
|
+
}),
|
|
227
258
|
success: HttpApiSchema.NoContent,
|
|
228
259
|
error: SessionNotFoundError,
|
|
229
260
|
})
|
|
230
261
|
.middleware(sessionLocationMiddleware)
|
|
231
262
|
.annotateMerge(OpenApi.annotations({
|
|
232
|
-
identifier: "
|
|
233
|
-
summary: "
|
|
234
|
-
description: "Update
|
|
263
|
+
identifier: "session.update",
|
|
264
|
+
summary: "Update session",
|
|
265
|
+
description: "Update mutable session properties.",
|
|
235
266
|
})))
|
|
236
267
|
.add(HttpApiEndpoint.post("session.move", "/api/session/:sessionID/move", {
|
|
237
268
|
params: { sessionID: Session.ID },
|
|
238
|
-
payload: Schema.Struct({ ...Location.
|
|
269
|
+
payload: Schema.Struct({ ...Location.PublicRef.fields, delivery: SessionInbox.Delivery.pipe(Schema.optional) }),
|
|
239
270
|
success: HttpApiSchema.NoContent,
|
|
240
271
|
error: [SessionNotFoundError, InvalidRequestError],
|
|
241
272
|
}).annotateMerge(OpenApi.annotations({
|
|
242
|
-
identifier: "
|
|
273
|
+
identifier: "session.move",
|
|
243
274
|
summary: "Move session",
|
|
244
|
-
description: "Move a session to another project directory
|
|
275
|
+
description: "Move a session to another project directory at the requested delivery boundary.",
|
|
245
276
|
})))
|
|
246
277
|
.add(HttpApiEndpoint.post("session.prompt", "/api/session/:sessionID/prompt", {
|
|
247
278
|
params: { sessionID: Session.ID },
|
|
@@ -257,14 +288,14 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
257
288
|
})
|
|
258
289
|
.middleware(sessionLocationMiddleware)
|
|
259
290
|
.annotateMerge(OpenApi.annotations({
|
|
260
|
-
identifier: "
|
|
291
|
+
identifier: "session.prompt",
|
|
261
292
|
summary: "Send message",
|
|
262
293
|
description: "Durably admit one session input and schedule agent-loop execution unless resume is false.",
|
|
263
294
|
})))
|
|
264
295
|
.add(HttpApiEndpoint.post("session.command", "/api/session/:sessionID/command", {
|
|
265
296
|
params: { sessionID: Session.ID },
|
|
266
297
|
payload: Schema.Struct({
|
|
267
|
-
|
|
298
|
+
name: Schema.String,
|
|
268
299
|
...PromptInput.Prompt.fields,
|
|
269
300
|
delivery: SessionInbox.Delivery.pipe(Schema.optional),
|
|
270
301
|
}),
|
|
@@ -273,15 +304,14 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
273
304
|
})
|
|
274
305
|
.middleware(sessionLocationMiddleware)
|
|
275
306
|
.annotateMerge(OpenApi.annotations({
|
|
276
|
-
identifier: "
|
|
307
|
+
identifier: "session.command",
|
|
277
308
|
summary: "Run command",
|
|
278
309
|
description: "Execute a slash command callback immediately.",
|
|
279
310
|
})))
|
|
280
|
-
.add(HttpApiEndpoint.post("session.skill", "/api/session/:sessionID/skill", {
|
|
311
|
+
.add(HttpApiEndpoint.post("session.skill", "/api/experimental/session/:sessionID/skill", {
|
|
281
312
|
params: { sessionID: Session.ID },
|
|
282
313
|
payload: Schema.Struct({
|
|
283
|
-
id:
|
|
284
|
-
skill: Skill.ID,
|
|
314
|
+
id: Skill.ID,
|
|
285
315
|
resume: Schema.Boolean.pipe(Schema.optional),
|
|
286
316
|
}),
|
|
287
317
|
success: HttpApiSchema.NoContent,
|
|
@@ -289,7 +319,7 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
289
319
|
})
|
|
290
320
|
.middleware(sessionLocationMiddleware)
|
|
291
321
|
.annotateMerge(OpenApi.annotations({
|
|
292
|
-
identifier: "
|
|
322
|
+
identifier: "experimental.session.skill",
|
|
293
323
|
summary: "Activate skill",
|
|
294
324
|
description: "Activate a skill for a session by appending a skill message and resuming execution.",
|
|
295
325
|
})))
|
|
@@ -308,14 +338,14 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
308
338
|
})
|
|
309
339
|
.middleware(sessionLocationMiddleware)
|
|
310
340
|
.annotateMerge(OpenApi.annotations({
|
|
311
|
-
identifier: "
|
|
341
|
+
identifier: "session.synthetic",
|
|
312
342
|
summary: "Add synthetic message",
|
|
313
343
|
description: "Durably admit synthetic session input and schedule execution unless resume is false.",
|
|
314
344
|
})))
|
|
315
345
|
.add(HttpApiEndpoint.post("session.shell", "/api/session/:sessionID/shell", {
|
|
316
346
|
params: { sessionID: Session.ID },
|
|
317
347
|
payload: Schema.Struct({
|
|
318
|
-
id:
|
|
348
|
+
id: SessionMessage.ID.pipe(Schema.optional),
|
|
319
349
|
command: Schema.String,
|
|
320
350
|
}),
|
|
321
351
|
success: HttpApiSchema.NoContent,
|
|
@@ -323,7 +353,7 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
323
353
|
})
|
|
324
354
|
.middleware(sessionLocationMiddleware)
|
|
325
355
|
.annotateMerge(OpenApi.annotations({
|
|
326
|
-
identifier: "
|
|
356
|
+
identifier: "session.shell",
|
|
327
357
|
summary: "Run shell command",
|
|
328
358
|
description: "Execute one shell command in the session's working directory. Emits a shell.started event before execution and a shell.ended event with the merged output after.",
|
|
329
359
|
})))
|
|
@@ -338,18 +368,18 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
338
368
|
})
|
|
339
369
|
.middleware(sessionLocationMiddleware)
|
|
340
370
|
.annotateMerge(OpenApi.annotations({
|
|
341
|
-
identifier: "
|
|
371
|
+
identifier: "session.compact",
|
|
342
372
|
summary: "Compact session",
|
|
343
373
|
description: "Durably admit a session compaction request. Steers by default: it runs at the next step boundary instead of waiting behind queued prompts.",
|
|
344
374
|
})))
|
|
345
|
-
.add(HttpApiEndpoint.post("session.wait", "/api/session/:sessionID/wait", {
|
|
375
|
+
.add(HttpApiEndpoint.post("session.wait", "/api/experimental/session/:sessionID/wait", {
|
|
346
376
|
params: { sessionID: Session.ID },
|
|
347
377
|
success: HttpApiSchema.NoContent,
|
|
348
378
|
error: [SessionNotFoundError, ServiceUnavailableError],
|
|
349
379
|
})
|
|
350
380
|
.middleware(sessionLocationMiddleware)
|
|
351
381
|
.annotateMerge(OpenApi.annotations({
|
|
352
|
-
identifier: "
|
|
382
|
+
identifier: "experimental.session.wait",
|
|
353
383
|
summary: "Wait for session",
|
|
354
384
|
description: "Wait for a session agent loop to become idle.",
|
|
355
385
|
})))
|
|
@@ -361,81 +391,93 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
361
391
|
})
|
|
362
392
|
.middleware(sessionLocationMiddleware)
|
|
363
393
|
.annotateMerge(OpenApi.annotations({
|
|
364
|
-
identifier: "
|
|
394
|
+
identifier: "session.revert.stage",
|
|
365
395
|
summary: "Stage session revert",
|
|
366
396
|
description: "Stage or move a reversible session boundary and optionally apply its file changes.",
|
|
367
397
|
})))
|
|
368
|
-
.add(HttpApiEndpoint.
|
|
398
|
+
.add(HttpApiEndpoint.delete("session.revert.clear", "/api/session/:sessionID/revert", {
|
|
369
399
|
params: { sessionID: Session.ID },
|
|
370
400
|
success: HttpApiSchema.NoContent,
|
|
371
401
|
error: [SessionNotFoundError, SessionBusyError, UnknownError],
|
|
372
402
|
})
|
|
373
403
|
.middleware(sessionLocationMiddleware)
|
|
374
|
-
.annotateMerge(OpenApi.annotations({ identifier: "
|
|
404
|
+
.annotateMerge(OpenApi.annotations({ identifier: "session.revert.clear", summary: "Clear staged revert" })))
|
|
375
405
|
.add(HttpApiEndpoint.post("session.revert.commit", "/api/session/:sessionID/revert/commit", {
|
|
376
406
|
params: { sessionID: Session.ID },
|
|
377
407
|
success: HttpApiSchema.NoContent,
|
|
378
408
|
error: [SessionNotFoundError, SessionBusyError],
|
|
379
409
|
})
|
|
380
410
|
.middleware(sessionLocationMiddleware)
|
|
381
|
-
.annotateMerge(OpenApi.annotations({ identifier: "
|
|
411
|
+
.annotateMerge(OpenApi.annotations({ identifier: "session.revert.commit", summary: "Commit staged revert" })))
|
|
382
412
|
.add(HttpApiEndpoint.get("session.context", "/api/session/:sessionID/context", {
|
|
383
413
|
params: { sessionID: Session.ID },
|
|
384
|
-
success: Schema.Struct({ data: Schema.Array(
|
|
414
|
+
success: Schema.Struct({ data: Schema.Array(PublicSessionMessage) }),
|
|
385
415
|
error: [SessionNotFoundError, UnknownError],
|
|
386
416
|
}).annotateMerge(OpenApi.annotations({
|
|
387
|
-
identifier: "
|
|
417
|
+
identifier: "session.context",
|
|
388
418
|
summary: "Get session context",
|
|
389
419
|
description: "Retrieve the active context messages for a session (all messages after the last compaction).",
|
|
420
|
+
})))
|
|
421
|
+
.add(HttpApiEndpoint.get("session.diff", "/api/session/:sessionID/diff", {
|
|
422
|
+
params: { sessionID: Session.ID },
|
|
423
|
+
query: Schema.Struct({
|
|
424
|
+
from: Schema.optional(SessionMessage.ID).annotate({
|
|
425
|
+
description: "User message whose turn to diff. Defaults to the turn of the newest user message.",
|
|
426
|
+
}),
|
|
427
|
+
to: Schema.optional(SessionMessage.ID).annotate({
|
|
428
|
+
description: "Later user message whose turn ends the range. Defaults to the turn of `from` alone.",
|
|
429
|
+
}),
|
|
430
|
+
context: Schema.NumberFromString.pipe(Schema.decodeTo(NonNegativeInt), Schema.optional).annotate({
|
|
431
|
+
description: "Unchanged lines around each hunk. Omit for full-file patches.",
|
|
432
|
+
}),
|
|
433
|
+
}),
|
|
434
|
+
success: Schema.Struct({ data: Schema.Array(FileDiff.Info) }),
|
|
435
|
+
error: [InvalidRequestError, MessageNotFoundError, SessionNotFoundError, UnknownError],
|
|
436
|
+
}).annotateMerge(OpenApi.annotations({
|
|
437
|
+
identifier: "session.diff",
|
|
438
|
+
summary: "Diff session turns",
|
|
439
|
+
description: "Structured per-file diffs of the files a turn changed. A turn runs from the first prompt after the session was last idle until its next idle marker, so prompts steered in while it was busy belong to the same turn; `to` extends the range through a later turn. Compares the range's first recorded snapshot with its last; a step still running in the active session compares against the working copy. Ranges that span a location change are rejected. In sessions without any idle marker, a prompt's turn spans until the next user message.",
|
|
390
440
|
})))
|
|
391
441
|
.add(HttpApiEndpoint.get("session.inbox.list", "/api/session/:sessionID/inbox", {
|
|
392
442
|
params: { sessionID: Session.ID },
|
|
393
|
-
success: Schema.Struct({ data: Schema.Array(
|
|
443
|
+
success: Schema.Struct({ data: Schema.Array(PublicInboxInfo) }),
|
|
394
444
|
error: SessionNotFoundError,
|
|
395
445
|
}).annotateMerge(OpenApi.annotations({
|
|
396
|
-
identifier: "
|
|
446
|
+
identifier: "session.inbox.list",
|
|
397
447
|
summary: "List session inbox",
|
|
398
448
|
description: "List durable enqueued session work not yet delivered, ordered by enqueue sequence. Includes user, synthetic, compaction, and move items.",
|
|
399
449
|
})))
|
|
400
450
|
.add(HttpApiEndpoint.delete("session.inbox.cancel", "/api/session/:sessionID/inbox/:inboxID", {
|
|
401
451
|
params: { sessionID: Session.ID, inboxID: SessionMessage.ID },
|
|
402
452
|
success: HttpApiSchema.NoContent,
|
|
403
|
-
error:
|
|
453
|
+
error: SessionNotFoundError,
|
|
404
454
|
}).annotateMerge(OpenApi.annotations({
|
|
405
|
-
identifier: "
|
|
455
|
+
identifier: "session.inbox.cancel",
|
|
406
456
|
summary: "Cancel inbox input",
|
|
407
|
-
description: "Cancel an inbox item that has not yet been delivered.",
|
|
408
|
-
})))
|
|
409
|
-
.add(HttpApiEndpoint.post("session.inbox.steer", "/api/session/:sessionID/inbox/:inboxID/steer", {
|
|
410
|
-
params: { sessionID: Session.ID, inboxID: SessionMessage.ID },
|
|
411
|
-
success: HttpApiSchema.NoContent,
|
|
412
|
-
error: [ConflictError, SessionNotFoundError],
|
|
413
|
-
}).annotateMerge(OpenApi.annotations({
|
|
414
|
-
identifier: "v2.session.inbox.steer",
|
|
415
|
-
summary: "Steer queued item",
|
|
416
|
-
description: "Change a queued inbox item to steer delivery and wake session execution.",
|
|
457
|
+
description: "Cancel an inbox item that has not yet been delivered. Unavailable items are a no-op.",
|
|
417
458
|
})))
|
|
418
|
-
.add(HttpApiEndpoint.
|
|
459
|
+
.add(HttpApiEndpoint.patch("session.inbox.update", "/api/session/:sessionID/inbox/:inboxID", {
|
|
419
460
|
params: { sessionID: Session.ID, inboxID: SessionMessage.ID },
|
|
461
|
+
payload: Schema.Struct({ delivery: SessionInbox.Delivery }),
|
|
420
462
|
success: HttpApiSchema.NoContent,
|
|
421
463
|
error: [ConflictError, SessionNotFoundError],
|
|
422
464
|
}).annotateMerge(OpenApi.annotations({
|
|
423
|
-
identifier: "
|
|
424
|
-
summary: "
|
|
425
|
-
description: "Change a
|
|
465
|
+
identifier: "session.inbox.update",
|
|
466
|
+
summary: "Update inbox item",
|
|
467
|
+
description: "Change a pending inbox item's delivery mode. Steering wakes session execution.",
|
|
426
468
|
})))
|
|
427
|
-
.add(HttpApiEndpoint.get("session.instructions.entry.list", "/api/session/:sessionID/instructions/entries", {
|
|
469
|
+
.add(HttpApiEndpoint.get("session.instructions.entry.list", "/api/experimental/session/:sessionID/instructions/entries", {
|
|
428
470
|
params: { sessionID: Session.ID },
|
|
429
471
|
success: Schema.Struct({ data: Schema.Array(InstructionEntry.Info) }),
|
|
430
472
|
error: SessionNotFoundError,
|
|
431
473
|
})
|
|
432
474
|
.middleware(sessionLocationMiddleware)
|
|
433
475
|
.annotateMerge(OpenApi.annotations({
|
|
434
|
-
identifier: "
|
|
476
|
+
identifier: "experimental.session.instructions.entry.list",
|
|
435
477
|
summary: "List instruction entries",
|
|
436
478
|
description: "List API-managed instruction entries attached to the session.",
|
|
437
479
|
})))
|
|
438
|
-
.add(HttpApiEndpoint.put("session.instructions.entry.put", "/api/session/:sessionID/instructions/entries/:key", {
|
|
480
|
+
.add(HttpApiEndpoint.put("session.instructions.entry.put", "/api/experimental/session/:sessionID/instructions/entries/:key", {
|
|
439
481
|
params: { sessionID: Session.ID, key: InstructionEntry.Key },
|
|
440
482
|
payload: Schema.Struct({ value: Schema.Json }),
|
|
441
483
|
success: HttpApiSchema.NoContent,
|
|
@@ -443,18 +485,18 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
443
485
|
})
|
|
444
486
|
.middleware(sessionLocationMiddleware)
|
|
445
487
|
.annotateMerge(OpenApi.annotations({
|
|
446
|
-
identifier: "
|
|
488
|
+
identifier: "experimental.session.instructions.entry.put",
|
|
447
489
|
summary: "Put instruction entry",
|
|
448
490
|
description: "Attach or replace one durable instruction entry. Changes announce as updates at the next step boundary.",
|
|
449
491
|
})))
|
|
450
|
-
.add(HttpApiEndpoint.delete("session.instructions.entry.remove", "/api/session/:sessionID/instructions/entries/:key", {
|
|
492
|
+
.add(HttpApiEndpoint.delete("session.instructions.entry.remove", "/api/experimental/session/:sessionID/instructions/entries/:key", {
|
|
451
493
|
params: { sessionID: Session.ID, key: InstructionEntry.Key },
|
|
452
494
|
success: HttpApiSchema.NoContent,
|
|
453
495
|
error: SessionNotFoundError,
|
|
454
496
|
})
|
|
455
497
|
.middleware(sessionLocationMiddleware)
|
|
456
498
|
.annotateMerge(OpenApi.annotations({
|
|
457
|
-
identifier: "
|
|
499
|
+
identifier: "experimental.session.instructions.entry.remove",
|
|
458
500
|
summary: "Remove instruction entry",
|
|
459
501
|
description: "Remove one instruction entry; the removal is announced to the model at the next step boundary.",
|
|
460
502
|
})))
|
|
@@ -468,7 +510,7 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
468
510
|
})
|
|
469
511
|
.middleware(sessionLocationMiddleware)
|
|
470
512
|
.annotateMerge(OpenApi.annotations({
|
|
471
|
-
identifier: "
|
|
513
|
+
identifier: "session.generate",
|
|
472
514
|
summary: "Generate text from session context",
|
|
473
515
|
description: "Generate transient text from the current session context without mutating session history.",
|
|
474
516
|
})))
|
|
@@ -483,13 +525,13 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
483
525
|
}),
|
|
484
526
|
error: SessionNotFoundError,
|
|
485
527
|
}).annotateMerge(OpenApi.annotations({
|
|
486
|
-
identifier: "
|
|
528
|
+
identifier: "session.log",
|
|
487
529
|
summary: "Read the session log",
|
|
488
530
|
description: "Experimental durable session event log. Reads events after an exclusive aggregate sequence and continues with live events when follow=true.",
|
|
489
531
|
})))
|
|
490
532
|
.add(HttpApiEndpoint.post("session.interrupt", "/api/session/:sessionID/interrupt", {
|
|
491
533
|
params: { sessionID: Session.ID },
|
|
492
|
-
query: {
|
|
534
|
+
query: { resume: BooleanFromString.pipe(Schema.optional) },
|
|
493
535
|
success: Schema.Struct({
|
|
494
536
|
interrupted: Schema.Boolean.annotate({
|
|
495
537
|
description: "Whether an active execution owned by this OpenCode process was interrupted.",
|
|
@@ -499,9 +541,9 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
499
541
|
})
|
|
500
542
|
.middleware(sessionLocationMiddleware)
|
|
501
543
|
.annotateMerge(OpenApi.annotations({
|
|
502
|
-
identifier: "
|
|
544
|
+
identifier: "session.interrupt",
|
|
503
545
|
summary: "Interrupt session execution",
|
|
504
|
-
description: "Interrupt active execution owned by this OpenCode process. Returns interrupted=true when an active execution was interrupted and false for the idle no-op. When
|
|
546
|
+
description: "Interrupt active execution owned by this OpenCode process. Returns interrupted=true when an active execution was interrupted and false for the idle no-op. When resume=true, execution resumes pending steering input and next-in-line control items (manual compaction, moves) while queued prompts remain parked.",
|
|
505
547
|
})))
|
|
506
548
|
.add(HttpApiEndpoint.post("session.background", "/api/session/:sessionID/background", {
|
|
507
549
|
params: { sessionID: Session.ID },
|
|
@@ -510,18 +552,75 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
510
552
|
})
|
|
511
553
|
.middleware(sessionLocationMiddleware)
|
|
512
554
|
.annotateMerge(OpenApi.annotations({
|
|
513
|
-
identifier: "
|
|
555
|
+
identifier: "session.background",
|
|
514
556
|
summary: "Background blocking session tools",
|
|
515
557
|
description: "Move active foreground backgroundable tools for this session into background observation. Idle requests are a no-op.",
|
|
516
558
|
})))
|
|
517
559
|
.add(HttpApiEndpoint.get("session.message", "/api/session/:sessionID/message/:messageID", {
|
|
518
560
|
params: { sessionID: Session.ID, messageID: SessionMessage.ID },
|
|
519
|
-
success: Schema.Struct({ data:
|
|
561
|
+
success: Schema.Struct({ data: PublicSessionMessage }),
|
|
520
562
|
error: [SessionNotFoundError, MessageNotFoundError],
|
|
521
563
|
}).annotateMerge(OpenApi.annotations({
|
|
522
|
-
identifier: "
|
|
564
|
+
identifier: "session.message.get",
|
|
523
565
|
summary: "Get session message",
|
|
524
566
|
description: "Retrieve one projected message owned by the Session.",
|
|
567
|
+
})))
|
|
568
|
+
.add(HttpApiEndpoint.get("session.form.list", "/api/session/:sessionID/form", {
|
|
569
|
+
params: { sessionID: Schema.String },
|
|
570
|
+
success: Schema.Struct({ data: Schema.Array(Form.Info) }),
|
|
571
|
+
error: SessionNotFoundError,
|
|
572
|
+
})
|
|
573
|
+
.middleware(formLocationMiddleware)
|
|
574
|
+
.annotateMerge(OpenApi.annotations({
|
|
575
|
+
identifier: "session.form.list",
|
|
576
|
+
summary: "List session forms",
|
|
577
|
+
description: "Retrieve pending forms for a session.",
|
|
578
|
+
})))
|
|
579
|
+
.add(HttpApiEndpoint.post("session.form.create", "/api/session/:sessionID/form", {
|
|
580
|
+
params: { sessionID: Schema.String },
|
|
581
|
+
payload: FormCreatePayload,
|
|
582
|
+
success: Schema.Struct({ data: Form.Info }),
|
|
583
|
+
error: [SessionNotFoundError, ConflictError, InvalidRequestError],
|
|
584
|
+
})
|
|
585
|
+
.middleware(formLocationMiddleware)
|
|
586
|
+
.annotateMerge(OpenApi.annotations({
|
|
587
|
+
identifier: "session.form.create",
|
|
588
|
+
summary: "Create session form",
|
|
589
|
+
description: "Create a form for a session.",
|
|
590
|
+
})))
|
|
591
|
+
.add(HttpApiEndpoint.get("session.form.get", "/api/session/:sessionID/form/:formID", {
|
|
592
|
+
params: { sessionID: Schema.String, formID: Form.ID },
|
|
593
|
+
success: Schema.Struct({ data: Form.Detail }),
|
|
594
|
+
error: [SessionNotFoundError, FormNotFoundError],
|
|
595
|
+
})
|
|
596
|
+
.middleware(formLocationMiddleware)
|
|
597
|
+
.annotateMerge(OpenApi.annotations({
|
|
598
|
+
identifier: "session.form.get",
|
|
599
|
+
summary: "Get session form",
|
|
600
|
+
description: "Retrieve a form and its current state for a session.",
|
|
601
|
+
})))
|
|
602
|
+
.add(HttpApiEndpoint.post("session.form.reply", "/api/session/:sessionID/form/:formID/reply", {
|
|
603
|
+
params: { sessionID: Schema.String, formID: Form.ID },
|
|
604
|
+
payload: Form.Reply,
|
|
605
|
+
success: HttpApiSchema.NoContent,
|
|
606
|
+
error: [SessionNotFoundError, FormAlreadySettledError, FormInvalidAnswerError, FormNotFoundError],
|
|
607
|
+
})
|
|
608
|
+
.middleware(formLocationMiddleware)
|
|
609
|
+
.annotateMerge(OpenApi.annotations({
|
|
610
|
+
identifier: "session.form.reply",
|
|
611
|
+
summary: "Reply to form",
|
|
612
|
+
description: "Submit an answer to a pending form.",
|
|
613
|
+
})))
|
|
614
|
+
.add(HttpApiEndpoint.delete("session.form.cancel", "/api/session/:sessionID/form/:formID", {
|
|
615
|
+
params: { sessionID: Schema.String, formID: Form.ID },
|
|
616
|
+
success: HttpApiSchema.NoContent,
|
|
617
|
+
error: [SessionNotFoundError, FormAlreadySettledError, FormNotFoundError],
|
|
618
|
+
})
|
|
619
|
+
.middleware(formLocationMiddleware)
|
|
620
|
+
.annotateMerge(OpenApi.annotations({
|
|
621
|
+
identifier: "session.form.cancel",
|
|
622
|
+
summary: "Cancel form",
|
|
623
|
+
description: "Cancel a pending form.",
|
|
525
624
|
})))
|
|
526
625
|
.add(HttpApiEndpoint.put("session.environment", "/api/session/:sessionID/environment", {
|
|
527
626
|
params: { sessionID: Session.ID },
|
|
@@ -529,17 +628,17 @@ export const makeSessionGroup = (sessionLocationMiddleware) => HttpApiGroup.make
|
|
|
529
628
|
success: HttpApiSchema.NoContent,
|
|
530
629
|
error: SessionNotFoundError,
|
|
531
630
|
}).annotateMerge(OpenApi.annotations({
|
|
532
|
-
identifier: "
|
|
631
|
+
identifier: "session.environment",
|
|
533
632
|
summary: "Set session environment",
|
|
534
633
|
description: "Replace the process environment used by local shell commands for this session.",
|
|
535
634
|
})))
|
|
536
635
|
.add(HttpApiEndpoint.post("session.view", "/api/session/:sessionID/view", {
|
|
537
636
|
params: { sessionID: Session.ID },
|
|
538
|
-
payload: Schema.Struct({ idle:
|
|
637
|
+
payload: Schema.Struct({ idle: DateTimeUtcFromMillis }),
|
|
539
638
|
success: HttpApiSchema.NoContent,
|
|
540
639
|
error: SessionNotFoundError,
|
|
541
640
|
}).annotateMerge(OpenApi.annotations({
|
|
542
|
-
identifier: "
|
|
641
|
+
identifier: "session.view",
|
|
543
642
|
summary: "View session",
|
|
544
643
|
description: "Mark the idle transition observed by the viewer as viewed.",
|
|
545
644
|
})))
|