agents 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-routing-QDcchcQP.d.ts → agent-routing-CDbpVjYq.d.ts} +18 -8
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-DHL2XI7u.d.ts → agent-tools-C8DH8Yii.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/{ai-ahruGw7e.d.ts → ai-iXw0uOGj.d.ts} +3 -3
- package/dist/{ai-sdk-Bdsf6mSA.js → ai-sdk-DRPh2rRa.js} +218 -132
- package/dist/ai-sdk-DRPh2rRa.js.map +1 -0
- package/dist/browser/ai.d.ts +1 -1
- package/dist/browser/ai.js +2 -2
- package/dist/browser/index.d.ts +8 -8
- package/dist/browser/index.js +3 -3
- package/dist/browser/tools/ai-sdk.d.ts +2 -2
- package/dist/browser/tools/ai-sdk.js +1 -1
- package/dist/browser/tools/pi.d.ts +1 -1
- package/dist/browser/tools/pi.js +3 -3
- package/dist/browser/tools/pi.js.map +1 -1
- package/dist/browser/tools/tanstack-ai.d.ts +2 -2
- package/dist/browser/tools/tanstack-ai.js +1 -1
- package/dist/{browser-CEdNlsaD.js → browser-DccPw_wW.js} +130 -79
- package/dist/browser-DccPw_wW.js.map +1 -0
- package/dist/{browser-D30VlpcA.d.ts → browser-DlXhSAdf.d.ts} +41 -37
- package/dist/{browser-tool-4iomavs_.js → browser-tool-B1mhifin.js} +3 -3
- package/dist/{browser-tool-4iomavs_.js.map → browser-tool-B1mhifin.js.map} +1 -1
- package/dist/{browser-tool-vtrPOV8e.d.ts → browser-tool-Cxjk5sgG.d.ts} +2 -2
- package/dist/chat/index.d.ts +143 -71
- package/dist/chat/index.js +269 -110
- package/dist/chat/index.js.map +1 -1
- package/dist/chat-sdk/index.d.ts +1 -1
- package/dist/chat-sdk/index.js +1 -1
- package/dist/cli.js +33 -33
- package/dist/{client-BGIQKJhX.d.ts → client-C27CtRZr.d.ts} +2 -2
- package/dist/client.d.ts +1 -1
- package/dist/{connector-DEXzVoaY.d.ts → connector-20DJ6p4k.d.ts} +2 -2
- package/dist/{connector-CtZylXdk.js → connector-DAXBOIIi.js} +2 -2
- package/dist/{connector-CtZylXdk.js.map → connector-DAXBOIIi.js.map} +1 -1
- package/dist/experimental/channels/web/index.js +1 -1
- package/dist/{handler-stateless-VvrWSAVA.js → handler-stateless-Bly_nSH3.js} +12 -3
- package/dist/handler-stateless-Bly_nSH3.js.map +1 -0
- package/dist/harness/container/index.js +1 -1
- package/dist/harness/container/index.js.map +1 -1
- package/dist/harness/opencode/index.d.ts +182 -6
- package/dist/harness/opencode/index.js +354 -23
- package/dist/harness/opencode/index.js.map +1 -1
- package/dist/harness/pi/index.d.ts +13 -5
- package/dist/harness/pi/index.js +8 -214
- package/dist/harness/pi/index.js.map +1 -1
- package/dist/{images-Ce9SCu3X.js → images-xaDv2Fqe.js} +662 -152
- package/dist/images-xaDv2Fqe.js.map +1 -0
- package/dist/index-DCxk3OSJ.d.ts +378 -0
- package/dist/{index-kbSUIer3.d.ts → index-iv9FTXX9.d.ts} +80 -112
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{input-schema-D2QAtHZH.js → input-schema-B0Etuo-o.js} +2 -2
- package/dist/{input-schema-D2QAtHZH.js.map → input-schema-B0Etuo-o.js.map} +1 -1
- package/dist/lifecycle/index.js +1 -1
- package/dist/{lifecycle-DGorpAmA.js → lifecycle-ClT4DmF2.js} +11 -3
- package/dist/lifecycle-ClT4DmF2.js.map +1 -0
- package/dist/mcp/client/index.d.ts +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +17 -3
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server/index.js +1 -1
- package/dist/models/ai-sdk/index.d.ts +31 -326
- package/dist/models/ai-sdk/index.js +1 -1
- package/dist/models/opencode/index.d.ts +25 -13
- package/dist/models/opencode/index.js +16 -11
- package/dist/models/opencode/index.js.map +1 -1
- package/dist/models/pi-ai/index.d.ts +17 -13
- package/dist/models/pi-ai/index.js +89 -36
- package/dist/models/pi-ai/index.js.map +1 -1
- package/dist/react.d.ts +2 -2
- package/dist/routing/index.d.ts +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/{session-store-DoPY12xM.d.ts → session-store-_IK6dV-w.d.ts} +14 -2
- package/dist/{session-store-Do4xkDcf.js → session-store-yvwq1f9x.js} +55 -2
- package/dist/session-store-yvwq1f9x.js.map +1 -0
- package/dist/{settings-C45hDliX.js → settings-Dk2il2Hf.js} +10 -4
- package/dist/settings-Dk2il2Hf.js.map +1 -0
- package/dist/skills/index.d.ts +22 -28
- package/dist/skills/index.js +183 -143
- package/dist/skills/index.js.map +1 -1
- package/dist/{src-CQxJFv4l.js → src-6lr7MtM_.js} +3 -3
- package/dist/src-6lr7MtM_.js.map +1 -0
- package/dist/sub-routing.d.ts +1 -1
- package/dist/{tool-cQRkwSZZ.js → tool-DkT_DJBm.js} +2 -2
- package/dist/tool-DkT_DJBm.js.map +1 -0
- package/dist/transport-CPh7YGiw.d.ts +623 -0
- package/dist/voice/index.d.ts +1 -1
- package/dist/web/fetch/tools/pi.js +2 -2
- package/dist/web/fetch/tools/pi.js.map +1 -1
- package/dist/web/search/index.js +1 -1
- package/dist/web/search/tools/ai-sdk.js +2 -2
- package/dist/web/search/tools/pi.js +3 -3
- package/dist/web/search/tools/pi.js.map +1 -1
- package/dist/web/search/tools/tanstack-ai.js +2 -2
- package/dist/websockets/index.js +1 -1
- package/dist/{websockets-C3zy8YR0.js → websockets-CqxnntmE.js} +2 -2
- package/dist/{websockets-C3zy8YR0.js.map → websockets-CqxnntmE.js.map} +1 -1
- package/dist/workflow-types.d.ts +1 -1
- package/dist/workflows.d.ts +1 -1
- package/dist/workflows.js +1 -1
- package/docs/browse-the-web.md +1 -1
- package/docs/chat-agents.md +19 -18
- package/docs/harnesses/pi.md +47 -18
- package/docs/mcp-client.md +1 -1
- package/docs/mcp-servers.md +1 -1
- package/docs/models-pi-ai.md +70 -17
- package/docs/models.md +219 -152
- package/package.json +14 -14
- package/dist/ai-sdk-Bdsf6mSA.js.map +0 -1
- package/dist/browser-CEdNlsaD.js.map +0 -1
- package/dist/handler-stateless-VvrWSAVA.js.map +0 -1
- package/dist/images-Ce9SCu3X.js.map +0 -1
- package/dist/lifecycle-DGorpAmA.js.map +0 -1
- package/dist/session-store-Do4xkDcf.js.map +0 -1
- package/dist/settings-C45hDliX.js.map +0 -1
- package/dist/settings-NgGwF7Qt.d.ts +0 -331
- package/dist/src-CQxJFv4l.js.map +0 -1
- package/dist/tool-cQRkwSZZ.js.map +0 -1
- package/dist/transport-k2mFrtL8.d.ts +0 -200
|
@@ -30,7 +30,10 @@ type OpenCodeInput =
|
|
|
30
30
|
type OpenCodeMessage = Awaited<
|
|
31
31
|
ReturnType<OpenCode["sessions"]["context"]>
|
|
32
32
|
>[number];
|
|
33
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* One of OpenCode's own events: durable transcript events and live deltas.
|
|
35
|
+
* `session.events()` translates these into `OpenCodeSessionEvent`s.
|
|
36
|
+
*/
|
|
34
37
|
type OpenCodeEvent =
|
|
35
38
|
ReturnType<OpenCode["events"]["subscribe"]> extends AsyncIterable<infer E>
|
|
36
39
|
? E
|
|
@@ -101,6 +104,173 @@ type OpenCodeSessionInfo = {
|
|
|
101
104
|
readonly title?: string /** Running, input waiting, or a turn a restart cut off, about to resume. */;
|
|
102
105
|
readonly busy: boolean;
|
|
103
106
|
};
|
|
107
|
+
/** A permission OpenCode asked for, waiting on a reply. */
|
|
108
|
+
type OpenCodePermission = {
|
|
109
|
+
readonly id: string;
|
|
110
|
+
readonly session: OpenCodeSessionId /** What OpenCode wants to do, such as `edit` or `webfetch`. */;
|
|
111
|
+
readonly action: string /** What the action applies to, such as paths or URLs. */;
|
|
112
|
+
readonly resources: readonly string[];
|
|
113
|
+
readonly message?: string;
|
|
114
|
+
};
|
|
115
|
+
/** How an assistant message's step ended, as OpenCode reports it. */
|
|
116
|
+
type OpenCodeFinish =
|
|
117
|
+
| "stop"
|
|
118
|
+
| "length"
|
|
119
|
+
| "tool-calls"
|
|
120
|
+
| "content-filter"
|
|
121
|
+
| "error"
|
|
122
|
+
| "unknown";
|
|
123
|
+
/**
|
|
124
|
+
* One event on a session's stream, translated from OpenCode's events into
|
|
125
|
+
* the same kinds of event `PiHarness` and `ContainerHarness` report.
|
|
126
|
+
* `messageId` is OpenCode's assistant message id. Text and reasoning are
|
|
127
|
+
* addressed by `ordinal`, their position among the message's parts of the
|
|
128
|
+
* same kind.
|
|
129
|
+
*/
|
|
130
|
+
type OpenCodeSessionEvent =
|
|
131
|
+
/**
|
|
132
|
+
* An input is in OpenCode's inbox. Every input goes through it, so this
|
|
133
|
+
* comes before `operation_start` even when the session is idle.
|
|
134
|
+
*/
|
|
135
|
+
| {
|
|
136
|
+
readonly type: "operation_queued";
|
|
137
|
+
readonly operationId: string;
|
|
138
|
+
} /** A queued input was withdrawn before it ran. */
|
|
139
|
+
| {
|
|
140
|
+
readonly type: "operation_withdrawn";
|
|
141
|
+
readonly operationId: string;
|
|
142
|
+
} /** An input joined the transcript; the next assistant message answers it. */
|
|
143
|
+
| {
|
|
144
|
+
readonly type: "operation_start";
|
|
145
|
+
readonly operationId: string;
|
|
146
|
+
} /** An input has its answer: the same result `wait()` returns. */
|
|
147
|
+
| {
|
|
148
|
+
readonly type: "operation_end";
|
|
149
|
+
readonly result: OpenCodeOperationResult;
|
|
150
|
+
} /** OpenCode started a run. One run answers every input it drains. */
|
|
151
|
+
| {
|
|
152
|
+
readonly type: "run_start";
|
|
153
|
+
}
|
|
154
|
+
| {
|
|
155
|
+
readonly type: "run_end";
|
|
156
|
+
readonly outcome: "succeeded" | "failed" | "interrupted";
|
|
157
|
+
readonly error?: string;
|
|
158
|
+
}
|
|
159
|
+
| {
|
|
160
|
+
readonly type: "message_start";
|
|
161
|
+
readonly messageId: string;
|
|
162
|
+
readonly agent: string;
|
|
163
|
+
readonly model: {
|
|
164
|
+
readonly providerID: string;
|
|
165
|
+
readonly id: string;
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
| {
|
|
169
|
+
readonly type: "text_delta";
|
|
170
|
+
readonly messageId: string;
|
|
171
|
+
readonly ordinal: number;
|
|
172
|
+
readonly delta: string;
|
|
173
|
+
} /** A text part is complete; `text` is the whole part. */
|
|
174
|
+
| {
|
|
175
|
+
readonly type: "text_end";
|
|
176
|
+
readonly messageId: string;
|
|
177
|
+
readonly ordinal: number;
|
|
178
|
+
readonly text: string;
|
|
179
|
+
}
|
|
180
|
+
| {
|
|
181
|
+
readonly type: "reasoning_delta";
|
|
182
|
+
readonly messageId: string;
|
|
183
|
+
readonly ordinal: number;
|
|
184
|
+
readonly delta: string;
|
|
185
|
+
}
|
|
186
|
+
| {
|
|
187
|
+
readonly type: "reasoning_end";
|
|
188
|
+
readonly messageId: string;
|
|
189
|
+
readonly ordinal: number;
|
|
190
|
+
readonly text: string;
|
|
191
|
+
} /** The model called a tool and OpenCode has its whole input. */
|
|
192
|
+
| {
|
|
193
|
+
readonly type: "tool_start";
|
|
194
|
+
readonly messageId: string;
|
|
195
|
+
readonly toolCallId: string;
|
|
196
|
+
readonly name: string;
|
|
197
|
+
readonly input: Readonly<Record<string, unknown>>;
|
|
198
|
+
}
|
|
199
|
+
| {
|
|
200
|
+
readonly type: "tool_end";
|
|
201
|
+
readonly messageId: string;
|
|
202
|
+
readonly toolCallId: string;
|
|
203
|
+
readonly name: string;
|
|
204
|
+
readonly error: boolean /** The tool's text output, or its error message. */;
|
|
205
|
+
readonly output: string;
|
|
206
|
+
}
|
|
207
|
+
| {
|
|
208
|
+
readonly type: "message_end";
|
|
209
|
+
readonly messageId: string;
|
|
210
|
+
readonly finish: OpenCodeFinish;
|
|
211
|
+
readonly error?: string;
|
|
212
|
+
} /** A model call failed and OpenCode will try again at `at`. */
|
|
213
|
+
| {
|
|
214
|
+
readonly type: "retry_scheduled";
|
|
215
|
+
readonly messageId: string;
|
|
216
|
+
readonly attempt: number;
|
|
217
|
+
readonly at: number;
|
|
218
|
+
readonly error: string;
|
|
219
|
+
}
|
|
220
|
+
| {
|
|
221
|
+
readonly type: "compaction_start";
|
|
222
|
+
readonly reason: "auto" | "manual";
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* OpenCode compacted the session: `messages()` is now shorter, and
|
|
226
|
+
* `history()` has a compaction message. Read the transcript again.
|
|
227
|
+
*/
|
|
228
|
+
| {
|
|
229
|
+
readonly type: "transcript_reset";
|
|
230
|
+
readonly reason: "compaction";
|
|
231
|
+
}
|
|
232
|
+
| {
|
|
233
|
+
readonly type: "permission_asked";
|
|
234
|
+
readonly permission: OpenCodePermission;
|
|
235
|
+
}
|
|
236
|
+
| {
|
|
237
|
+
readonly type: "permission_replied";
|
|
238
|
+
readonly permissionId: string;
|
|
239
|
+
readonly reply: "once" | "always" | "reject";
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Something went wrong outside a model step: `compaction_failed`, or
|
|
243
|
+
* `events_failed` when OpenCode's event stream ended with an error. No
|
|
244
|
+
* more events follow `events_failed`; open a new stream.
|
|
245
|
+
*/
|
|
246
|
+
| {
|
|
247
|
+
readonly type: "fault";
|
|
248
|
+
readonly code: "compaction_failed" | "events_failed";
|
|
249
|
+
readonly message: string;
|
|
250
|
+
};
|
|
251
|
+
/** A session's state when its event stream opens. */
|
|
252
|
+
type OpenCodeSessionSnapshot = {
|
|
253
|
+
readonly session: OpenCodeSessionId /** The whole transcript, compacted messages included: `history()`. */;
|
|
254
|
+
readonly messages: readonly OpenCodeMessage[];
|
|
255
|
+
readonly pending: readonly OpenCodePendingOperation[];
|
|
256
|
+
readonly busy: boolean /** Permissions OpenCode is waiting on. */;
|
|
257
|
+
readonly permissions: readonly OpenCodePermission[];
|
|
258
|
+
};
|
|
259
|
+
/**
|
|
260
|
+
* A session's events: the snapshot taken when the stream opened, then every
|
|
261
|
+
* event after it, in batches, including any that arrived before `start()`.
|
|
262
|
+
* An event may repeat what the snapshot already shows; messages are keyed
|
|
263
|
+
* by id. Live: events reach listeners in the isolate that runs the harness,
|
|
264
|
+
* and the stream holds OpenCode open until `stop()`. Call `stop()` when
|
|
265
|
+
* done, started or not.
|
|
266
|
+
*/
|
|
267
|
+
type OpenCodeEventStream = {
|
|
268
|
+
readonly snapshot: OpenCodeSessionSnapshot /** Start delivering events. Call once. */;
|
|
269
|
+
start(
|
|
270
|
+
listener: (events: readonly OpenCodeSessionEvent[]) => void
|
|
271
|
+
): void /** Stop delivering events and release OpenCode. */;
|
|
272
|
+
stop(): Promise<void>;
|
|
273
|
+
};
|
|
104
274
|
//#endregion
|
|
105
275
|
//#region src/harness/opencode/harness.d.ts
|
|
106
276
|
/** The root session's id. OpenCode session ids start with `ses`. */
|
|
@@ -304,12 +474,13 @@ declare class OpenCodeSession {
|
|
|
304
474
|
*/
|
|
305
475
|
history(): Promise<OpenCodeMessage[]>;
|
|
306
476
|
/**
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
* durable
|
|
477
|
+
* The session's state now, then everything that happens to it after, as
|
|
478
|
+
* `OpenCodeSessionEvent`s: the same kinds of event `PiHarness` reports,
|
|
479
|
+
* live text deltas included. The stream holds OpenCode open until
|
|
480
|
+
* `stop()`. For OpenCode's own events, durable and resumable by sequence
|
|
481
|
+
* number, use `log()`.
|
|
311
482
|
*/
|
|
312
|
-
events(
|
|
483
|
+
events(): Promise<OpenCodeEventStream>;
|
|
313
484
|
/**
|
|
314
485
|
* The session's durable events after sequence number `after` (from the
|
|
315
486
|
* start by default), then, with `follow`, new ones as they are committed,
|
|
@@ -344,6 +515,8 @@ declare class OpenCodeSessions {
|
|
|
344
515
|
export {
|
|
345
516
|
type OpenCode,
|
|
346
517
|
type OpenCodeEvent,
|
|
518
|
+
type OpenCodeEventStream,
|
|
519
|
+
type OpenCodeFinish,
|
|
347
520
|
OpenCodeHarness,
|
|
348
521
|
type OpenCodeHarnessContext,
|
|
349
522
|
type OpenCodeHarnessFactory,
|
|
@@ -354,13 +527,16 @@ export {
|
|
|
354
527
|
type OpenCodeModel,
|
|
355
528
|
type OpenCodeOperationResult,
|
|
356
529
|
type OpenCodePendingOperation,
|
|
530
|
+
type OpenCodePermission,
|
|
357
531
|
type OpenCodePromptResponse,
|
|
358
532
|
type OpenCodeReceipt,
|
|
359
533
|
OpenCodeSession,
|
|
360
534
|
type OpenCodeSessionDefaults,
|
|
535
|
+
type OpenCodeSessionEvent,
|
|
361
536
|
type OpenCodeSessionId,
|
|
362
537
|
type OpenCodeSessionInfo,
|
|
363
538
|
type OpenCodeSessionOptions,
|
|
539
|
+
type OpenCodeSessionSnapshot,
|
|
364
540
|
OpenCodeSessions,
|
|
365
541
|
type OpenCodeSubmitOptions,
|
|
366
542
|
type OpenCodeWhenBusy,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "../../classPrivateFieldGet2-DZBYAB34.js";
|
|
2
2
|
import { t as _classPrivateMethodInitSpec } from "../../classPrivateMethodInitSpec-qMjJ6sHQ.js";
|
|
3
3
|
import { t as LifecycleCapability } from "../../capability-DBAKc6UZ.js";
|
|
4
|
-
import "../../lifecycle-
|
|
4
|
+
import "../../lifecycle-ClT4DmF2.js";
|
|
5
5
|
//#region src/harness/table-prefix.ts
|
|
6
6
|
/**
|
|
7
7
|
* A view of `storage` whose SQL is rewritten into `prefix`'s namespace.
|
|
@@ -284,6 +284,268 @@ function closing(sql, start, close) {
|
|
|
284
284
|
return sql.length;
|
|
285
285
|
}
|
|
286
286
|
//#endregion
|
|
287
|
+
//#region src/harness/opencode/operation-id.ts
|
|
288
|
+
const OPERATION_ID = /^[A-Za-z0-9._~-]+$/;
|
|
289
|
+
/** OpenCode's id for the user message an operation submits. */
|
|
290
|
+
function messageIdOf(operationId) {
|
|
291
|
+
if (!OPERATION_ID.test(operationId)) throw new TypeError(`Invalid operation id ${JSON.stringify(operationId)}: use letters, digits, ".", "_", "~" and "-"`);
|
|
292
|
+
return `msg_${operationId}`;
|
|
293
|
+
}
|
|
294
|
+
/** The operation id of a message or inbox item, the inverse of `messageIdOf`. */
|
|
295
|
+
function operationIdOf(messageId) {
|
|
296
|
+
return messageId.startsWith("msg_") ? messageId.slice(4) : messageId;
|
|
297
|
+
}
|
|
298
|
+
//#endregion
|
|
299
|
+
//#region src/harness/opencode/events.ts
|
|
300
|
+
/** The text parts of a tool's result, joined. */
|
|
301
|
+
function toolText(content) {
|
|
302
|
+
return (content ?? []).map((part) => "text" in part ? part.text : "").join("\n");
|
|
303
|
+
}
|
|
304
|
+
/** The session an OpenCode event belongs to, if it belongs to one. */
|
|
305
|
+
function sessionIdOf(event) {
|
|
306
|
+
const data = event.data;
|
|
307
|
+
return typeof data === "object" && data !== null && "sessionID" in data && typeof data.sessionID === "string" ? data.sessionID : void 0;
|
|
308
|
+
}
|
|
309
|
+
function answerOf(message) {
|
|
310
|
+
if (message.type !== "assistant") return void 0;
|
|
311
|
+
const text = /* @__PURE__ */ new Map();
|
|
312
|
+
for (const part of message.content) if (part.type === "text") text.set(text.size, part.text);
|
|
313
|
+
return {
|
|
314
|
+
id: message.id,
|
|
315
|
+
text,
|
|
316
|
+
error: message.error?.message
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
var _session = /* @__PURE__ */ new WeakMap();
|
|
320
|
+
var _toolNames = /* @__PURE__ */ new WeakMap();
|
|
321
|
+
var _answering = /* @__PURE__ */ new WeakMap();
|
|
322
|
+
var _ended = /* @__PURE__ */ new WeakMap();
|
|
323
|
+
var _answered = /* @__PURE__ */ new WeakMap();
|
|
324
|
+
var _answer = /* @__PURE__ */ new WeakMap();
|
|
325
|
+
var _SessionEventProjector_brand = /* @__PURE__ */ new WeakSet();
|
|
326
|
+
/**
|
|
327
|
+
* Translates one session's OpenCode events into `OpenCodeSessionEvent`s.
|
|
328
|
+
*
|
|
329
|
+
* OpenCode's events leave out some of what the translated ones carry, so
|
|
330
|
+
* the projector keeps it: tool names (`session.tool.called` has only the
|
|
331
|
+
* call id), and which inputs the current answer is for, so it can report
|
|
332
|
+
* `operation_end`. It starts from the stream's snapshot, so a stream opened
|
|
333
|
+
* mid-run knows the run's inputs and tools.
|
|
334
|
+
*
|
|
335
|
+
* `operation_end` follows the rule `wait()` uses on the transcript: an
|
|
336
|
+
* input's answer ends at the next input that joins after an assistant
|
|
337
|
+
* message, or at the end of the run.
|
|
338
|
+
*
|
|
339
|
+
* Events that arrive while the snapshot is read are projected after it, so
|
|
340
|
+
* some repeat what the snapshot shows. Projection is idempotent for those:
|
|
341
|
+
* an input the projector already knows is not started or ended again.
|
|
342
|
+
*/
|
|
343
|
+
var SessionEventProjector = class {
|
|
344
|
+
constructor(snapshot) {
|
|
345
|
+
_classPrivateMethodInitSpec(this, _SessionEventProjector_brand);
|
|
346
|
+
_classPrivateFieldInitSpec(this, _session, void 0);
|
|
347
|
+
_classPrivateFieldInitSpec(this, _toolNames, /* @__PURE__ */ new Map());
|
|
348
|
+
_classPrivateFieldInitSpec(this, _answering, []);
|
|
349
|
+
_classPrivateFieldInitSpec(this, _ended, /* @__PURE__ */ new Set());
|
|
350
|
+
_classPrivateFieldInitSpec(this, _answered, false);
|
|
351
|
+
_classPrivateFieldInitSpec(this, _answer, void 0);
|
|
352
|
+
_classPrivateFieldSet2(_session, this, snapshot.session);
|
|
353
|
+
for (const message of snapshot.messages) {
|
|
354
|
+
if (message.type !== "assistant") continue;
|
|
355
|
+
for (const part of message.content) if (part.type === "tool") _classPrivateFieldGet2(_toolNames, this).set(part.id, part.name);
|
|
356
|
+
}
|
|
357
|
+
_classPrivateFieldSet2(_answering, this, snapshot.pending.filter((operation) => operation.status === "running").map((operation) => operation.operationId));
|
|
358
|
+
if (_classPrivateFieldGet2(_answering, this).length > 0) {
|
|
359
|
+
const last = snapshot.messages.at(-1);
|
|
360
|
+
_classPrivateFieldSet2(_answer, this, last === void 0 ? void 0 : answerOf(last));
|
|
361
|
+
_classPrivateFieldSet2(_answered, this, _classPrivateFieldGet2(_answer, this) !== void 0);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/** The translated events for one OpenCode event; often none. */
|
|
365
|
+
project(event) {
|
|
366
|
+
switch (event.type) {
|
|
367
|
+
case "session.inbox.enqueued": return event.data.item.type === "user" ? [{
|
|
368
|
+
type: "operation_queued",
|
|
369
|
+
operationId: operationIdOf(event.data.inboxID)
|
|
370
|
+
}] : [];
|
|
371
|
+
case "session.inbox.cancelled": return [{
|
|
372
|
+
type: "operation_withdrawn",
|
|
373
|
+
operationId: operationIdOf(event.data.inboxID)
|
|
374
|
+
}];
|
|
375
|
+
case "session.inbox.delivered": {
|
|
376
|
+
const operationId = operationIdOf(event.data.inboxID);
|
|
377
|
+
if (_classPrivateFieldGet2(_answering, this).includes(operationId) || _classPrivateFieldGet2(_ended, this).has(operationId)) return [];
|
|
378
|
+
const ended = _classPrivateFieldGet2(_answered, this) ? _assertClassBrand(_SessionEventProjector_brand, this, _settle).call(this, "succeeded") : [];
|
|
379
|
+
_classPrivateFieldGet2(_answering, this).push(operationId);
|
|
380
|
+
return [...ended, {
|
|
381
|
+
type: "operation_start",
|
|
382
|
+
operationId
|
|
383
|
+
}];
|
|
384
|
+
}
|
|
385
|
+
case "session.execution.started":
|
|
386
|
+
if (_classPrivateFieldGet2(_answering, this).length === 0) {
|
|
387
|
+
_classPrivateFieldSet2(_answer, this, void 0);
|
|
388
|
+
_classPrivateFieldSet2(_answered, this, false);
|
|
389
|
+
}
|
|
390
|
+
return [{ type: "run_start" }];
|
|
391
|
+
case "session.execution.succeeded": return [..._assertClassBrand(_SessionEventProjector_brand, this, _settle).call(this, "succeeded"), runEnd("succeeded")];
|
|
392
|
+
case "session.execution.failed": return [..._assertClassBrand(_SessionEventProjector_brand, this, _settle).call(this, "failed", event.data.error.message), runEnd("failed", event.data.error.message)];
|
|
393
|
+
case "session.execution.interrupted": return [..._assertClassBrand(_SessionEventProjector_brand, this, _settle).call(this, "interrupted"), runEnd("interrupted")];
|
|
394
|
+
case "session.step.started":
|
|
395
|
+
_classPrivateFieldSet2(_answered, this, true);
|
|
396
|
+
_classPrivateFieldSet2(_answer, this, {
|
|
397
|
+
id: event.data.assistantMessageID,
|
|
398
|
+
text: /* @__PURE__ */ new Map(),
|
|
399
|
+
error: void 0
|
|
400
|
+
});
|
|
401
|
+
return [{
|
|
402
|
+
type: "message_start",
|
|
403
|
+
messageId: event.data.assistantMessageID,
|
|
404
|
+
agent: event.data.agent,
|
|
405
|
+
model: {
|
|
406
|
+
providerID: event.data.model.providerID,
|
|
407
|
+
id: event.data.model.id
|
|
408
|
+
}
|
|
409
|
+
}];
|
|
410
|
+
case "session.step.ended": return [{
|
|
411
|
+
type: "message_end",
|
|
412
|
+
messageId: event.data.assistantMessageID,
|
|
413
|
+
finish: event.data.finish
|
|
414
|
+
}];
|
|
415
|
+
case "session.step.failed":
|
|
416
|
+
if (_classPrivateFieldGet2(_answer, this)?.id === event.data.assistantMessageID) _classPrivateFieldGet2(_answer, this).error = event.data.error.message;
|
|
417
|
+
return [{
|
|
418
|
+
type: "message_end",
|
|
419
|
+
messageId: event.data.assistantMessageID,
|
|
420
|
+
finish: "error",
|
|
421
|
+
error: event.data.error.message
|
|
422
|
+
}];
|
|
423
|
+
case "session.text.delta":
|
|
424
|
+
case "session.reasoning.delta": return [{
|
|
425
|
+
type: event.type === "session.text.delta" ? "text_delta" : "reasoning_delta",
|
|
426
|
+
messageId: event.data.assistantMessageID,
|
|
427
|
+
ordinal: event.data.ordinal,
|
|
428
|
+
delta: event.data.delta
|
|
429
|
+
}];
|
|
430
|
+
case "session.text.ended":
|
|
431
|
+
if (_classPrivateFieldGet2(_answer, this)?.id === event.data.assistantMessageID) _classPrivateFieldGet2(_answer, this).text.set(event.data.ordinal, event.data.text);
|
|
432
|
+
return [{
|
|
433
|
+
type: "text_end",
|
|
434
|
+
messageId: event.data.assistantMessageID,
|
|
435
|
+
ordinal: event.data.ordinal,
|
|
436
|
+
text: event.data.text
|
|
437
|
+
}];
|
|
438
|
+
case "session.reasoning.ended": return [{
|
|
439
|
+
type: "reasoning_end",
|
|
440
|
+
messageId: event.data.assistantMessageID,
|
|
441
|
+
ordinal: event.data.ordinal,
|
|
442
|
+
text: event.data.text
|
|
443
|
+
}];
|
|
444
|
+
case "session.tool.input.started":
|
|
445
|
+
_classPrivateFieldGet2(_toolNames, this).set(event.data.id, event.data.name);
|
|
446
|
+
return [];
|
|
447
|
+
case "session.tool.called": return [{
|
|
448
|
+
type: "tool_start",
|
|
449
|
+
messageId: event.data.assistantMessageID,
|
|
450
|
+
toolCallId: event.data.id,
|
|
451
|
+
name: _classPrivateFieldGet2(_toolNames, this).get(event.data.id) ?? "",
|
|
452
|
+
input: event.data.input
|
|
453
|
+
}];
|
|
454
|
+
case "session.tool.success": return [{
|
|
455
|
+
type: "tool_end",
|
|
456
|
+
messageId: event.data.assistantMessageID,
|
|
457
|
+
toolCallId: event.data.id,
|
|
458
|
+
name: _classPrivateFieldGet2(_toolNames, this).get(event.data.id) ?? "",
|
|
459
|
+
error: false,
|
|
460
|
+
output: toolText(event.data.content)
|
|
461
|
+
}];
|
|
462
|
+
case "session.tool.failed": return [{
|
|
463
|
+
type: "tool_end",
|
|
464
|
+
messageId: event.data.assistantMessageID,
|
|
465
|
+
toolCallId: event.data.id,
|
|
466
|
+
name: _classPrivateFieldGet2(_toolNames, this).get(event.data.id) ?? "",
|
|
467
|
+
error: true,
|
|
468
|
+
output: event.data.error.message
|
|
469
|
+
}];
|
|
470
|
+
case "session.retry.scheduled": return [{
|
|
471
|
+
type: "retry_scheduled",
|
|
472
|
+
messageId: event.data.assistantMessageID,
|
|
473
|
+
attempt: event.data.attempt,
|
|
474
|
+
at: event.data.at,
|
|
475
|
+
error: event.data.error.message
|
|
476
|
+
}];
|
|
477
|
+
case "session.compaction.started": return [{
|
|
478
|
+
type: "compaction_start",
|
|
479
|
+
reason: event.data.reason
|
|
480
|
+
}];
|
|
481
|
+
case "session.compaction.ended": return [{
|
|
482
|
+
type: "transcript_reset",
|
|
483
|
+
reason: "compaction"
|
|
484
|
+
}];
|
|
485
|
+
case "session.compaction.failed": return [{
|
|
486
|
+
type: "fault",
|
|
487
|
+
code: "compaction_failed",
|
|
488
|
+
message: event.data.error.message
|
|
489
|
+
}];
|
|
490
|
+
case "permission.asked": return [{
|
|
491
|
+
type: "permission_asked",
|
|
492
|
+
permission: {
|
|
493
|
+
id: event.data.id,
|
|
494
|
+
session: event.data.sessionID,
|
|
495
|
+
action: event.data.action,
|
|
496
|
+
resources: event.data.resources,
|
|
497
|
+
...event.data.message === void 0 ? {} : { message: event.data.message }
|
|
498
|
+
}
|
|
499
|
+
}];
|
|
500
|
+
case "permission.replied": return [{
|
|
501
|
+
type: "permission_replied",
|
|
502
|
+
permissionId: event.data.requestID,
|
|
503
|
+
reply: event.data.reply
|
|
504
|
+
}];
|
|
505
|
+
default: return [];
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
/** End every input the latest answer was for. */
|
|
510
|
+
function _settle(outcome, runError) {
|
|
511
|
+
const answer = _classPrivateFieldGet2(_answer, this);
|
|
512
|
+
const text = [...(answer?.text ?? /* @__PURE__ */ new Map()).entries()].sort(([a], [b]) => a - b).map(([, part]) => part).join("");
|
|
513
|
+
const error = answer?.error ?? runError;
|
|
514
|
+
const ended = _classPrivateFieldGet2(_answering, this).map((operationId) => {
|
|
515
|
+
_classPrivateFieldGet2(_ended, this).add(operationId);
|
|
516
|
+
return {
|
|
517
|
+
type: "operation_end",
|
|
518
|
+
result: resultOf(_classPrivateFieldGet2(_session, this), operationId, outcome, text, error)
|
|
519
|
+
};
|
|
520
|
+
});
|
|
521
|
+
_classPrivateFieldSet2(_answering, this, []);
|
|
522
|
+
_classPrivateFieldSet2(_answered, this, false);
|
|
523
|
+
_classPrivateFieldSet2(_answer, this, void 0);
|
|
524
|
+
return ended;
|
|
525
|
+
}
|
|
526
|
+
function runEnd(outcome, error) {
|
|
527
|
+
return {
|
|
528
|
+
type: "run_end",
|
|
529
|
+
outcome,
|
|
530
|
+
...error === void 0 ? {} : { error }
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
/** The result `wait()` would return for the same ending. */
|
|
534
|
+
function resultOf(session, operationId, outcome, text, error) {
|
|
535
|
+
if (outcome === "succeeded" && error === void 0) return {
|
|
536
|
+
operationId,
|
|
537
|
+
session,
|
|
538
|
+
status: "done",
|
|
539
|
+
text
|
|
540
|
+
};
|
|
541
|
+
return {
|
|
542
|
+
operationId,
|
|
543
|
+
session,
|
|
544
|
+
status: "unanswered",
|
|
545
|
+
reason: outcome === "interrupted" ? "interrupted" : error ?? "failed"
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
//#endregion
|
|
287
549
|
//#region src/harness/opencode/harness.ts
|
|
288
550
|
/** The root session's id. OpenCode session ids start with `ses`. */
|
|
289
551
|
const ROOT_SESSION = "ses_root";
|
|
@@ -319,16 +581,6 @@ function wakeJobId(session) {
|
|
|
319
581
|
function sessionOfJob(payload) {
|
|
320
582
|
return typeof payload === "object" && payload !== null && "session" in payload && typeof payload.session === "string" ? payload.session : void 0;
|
|
321
583
|
}
|
|
322
|
-
const OPERATION_ID = /^[A-Za-z0-9._~-]+$/;
|
|
323
|
-
/** OpenCode's id for the user message an operation submits. */
|
|
324
|
-
function messageIdOf(operationId) {
|
|
325
|
-
if (!OPERATION_ID.test(operationId)) throw new TypeError(`Invalid operation id ${JSON.stringify(operationId)}: use letters, digits, ".", "_", "~" and "-"`);
|
|
326
|
-
return `msg_${operationId}`;
|
|
327
|
-
}
|
|
328
|
-
/** The operation id of a message or inbox item, the inverse of `messageIdOf`. */
|
|
329
|
-
function operationIdOf(messageId) {
|
|
330
|
-
return messageId.startsWith("msg_") ? messageId.slice(4) : messageId;
|
|
331
|
-
}
|
|
332
584
|
/** Whether an OpenCode client error is the tagged error `tag`. */
|
|
333
585
|
function isTagged(error, tag) {
|
|
334
586
|
return typeof error === "object" && error !== null && "_tag" in error && error._tag === tag;
|
|
@@ -343,11 +595,6 @@ function textOf(message) {
|
|
|
343
595
|
if (message?.type !== "assistant") return "";
|
|
344
596
|
return message.content.map((part) => part.type === "text" ? part.text : "").join("");
|
|
345
597
|
}
|
|
346
|
-
function sessionIdOf(event) {
|
|
347
|
-
if (!("data" in event)) return void 0;
|
|
348
|
-
const data = event.data;
|
|
349
|
-
return typeof data === "object" && data !== null && "sessionID" in data && typeof data.sessionID === "string" ? data.sessionID : void 0;
|
|
350
|
-
}
|
|
351
598
|
var _options = /* @__PURE__ */ new WeakMap();
|
|
352
599
|
var _waits = /* @__PURE__ */ new WeakMap();
|
|
353
600
|
var _admitting = /* @__PURE__ */ new WeakMap();
|
|
@@ -910,6 +1157,7 @@ function delay(ms, signal) {
|
|
|
910
1157
|
});
|
|
911
1158
|
}
|
|
912
1159
|
var _harness = /* @__PURE__ */ new WeakMap();
|
|
1160
|
+
var _OpenCodeSession_brand = /* @__PURE__ */ new WeakSet();
|
|
913
1161
|
/** One OpenCode session, addressed through the harness. */
|
|
914
1162
|
var OpenCodeSession = class {
|
|
915
1163
|
/**
|
|
@@ -917,6 +1165,7 @@ var OpenCodeSession = class {
|
|
|
917
1165
|
* @param id - The session's id.
|
|
918
1166
|
*/
|
|
919
1167
|
constructor(harness, id) {
|
|
1168
|
+
_classPrivateMethodInitSpec(this, _OpenCodeSession_brand);
|
|
920
1169
|
_classPrivateFieldInitSpec(this, _harness, void 0);
|
|
921
1170
|
_classPrivateFieldSet2(_harness, this, harness);
|
|
922
1171
|
this.id = id;
|
|
@@ -1001,18 +1250,79 @@ var OpenCodeSession = class {
|
|
|
1001
1250
|
});
|
|
1002
1251
|
}
|
|
1003
1252
|
/**
|
|
1004
|
-
*
|
|
1005
|
-
*
|
|
1006
|
-
*
|
|
1007
|
-
* durable
|
|
1253
|
+
* The session's state now, then everything that happens to it after, as
|
|
1254
|
+
* `OpenCodeSessionEvent`s: the same kinds of event `PiHarness` reports,
|
|
1255
|
+
* live text deltas included. The stream holds OpenCode open until
|
|
1256
|
+
* `stop()`. For OpenCode's own events, durable and resumable by sequence
|
|
1257
|
+
* number, use `log()`.
|
|
1008
1258
|
*/
|
|
1009
|
-
async
|
|
1259
|
+
async events() {
|
|
1010
1260
|
const release = _classPrivateFieldGet2(_harness, this).lease();
|
|
1261
|
+
const controller = new AbortController();
|
|
1262
|
+
const early = [];
|
|
1263
|
+
const pending = [];
|
|
1264
|
+
let projector;
|
|
1265
|
+
let listener;
|
|
1266
|
+
let stopped = false;
|
|
1267
|
+
const deliver = (events) => {
|
|
1268
|
+
if (events.length === 0 || stopped) return;
|
|
1269
|
+
if (listener === void 0) pending.push(...events);
|
|
1270
|
+
else listener(events);
|
|
1271
|
+
};
|
|
1272
|
+
let attached;
|
|
1273
|
+
const subscribed = new Promise((resolve) => {
|
|
1274
|
+
attached = resolve;
|
|
1275
|
+
});
|
|
1276
|
+
let pump = Promise.resolve();
|
|
1011
1277
|
try {
|
|
1012
1278
|
const opencode = await _classPrivateFieldGet2(_harness, this).opencode();
|
|
1013
|
-
|
|
1014
|
-
|
|
1279
|
+
pump = (async () => {
|
|
1280
|
+
try {
|
|
1281
|
+
for await (const event of opencode.events.subscribe({ signal: controller.signal })) {
|
|
1282
|
+
if (event.type === "server.connected") attached();
|
|
1283
|
+
if (sessionIdOf(event) !== this.id) continue;
|
|
1284
|
+
if (projector === void 0) early.push(event);
|
|
1285
|
+
else deliver(projector.project(event));
|
|
1286
|
+
}
|
|
1287
|
+
} catch (error) {
|
|
1288
|
+
if (!controller.signal.aborted) deliver([{
|
|
1289
|
+
type: "fault",
|
|
1290
|
+
code: "events_failed",
|
|
1291
|
+
message: describe(error)
|
|
1292
|
+
}]);
|
|
1293
|
+
} finally {
|
|
1294
|
+
attached();
|
|
1295
|
+
}
|
|
1296
|
+
})();
|
|
1297
|
+
await subscribed;
|
|
1298
|
+
const snapshot = await _assertClassBrand(_OpenCodeSession_brand, this, _snapshot).call(this, opencode);
|
|
1299
|
+
projector = new SessionEventProjector(snapshot);
|
|
1300
|
+
for (const event of early.splice(0)) deliver(projector.project(event));
|
|
1301
|
+
let stopping;
|
|
1302
|
+
return {
|
|
1303
|
+
snapshot,
|
|
1304
|
+
start: (next) => {
|
|
1305
|
+
if (listener !== void 0) throw new Error("OpenCodeEventStream.start() was already called");
|
|
1306
|
+
if (stopping !== void 0) return;
|
|
1307
|
+
listener = next;
|
|
1308
|
+
deliver(pending.splice(0));
|
|
1309
|
+
},
|
|
1310
|
+
stop: () => {
|
|
1311
|
+
stopping ??= (async () => {
|
|
1312
|
+
stopped = true;
|
|
1313
|
+
pending.length = 0;
|
|
1314
|
+
controller.abort();
|
|
1315
|
+
await pump;
|
|
1316
|
+
await release();
|
|
1317
|
+
})();
|
|
1318
|
+
return stopping;
|
|
1319
|
+
}
|
|
1320
|
+
};
|
|
1321
|
+
} catch (error) {
|
|
1322
|
+
controller.abort();
|
|
1323
|
+
await pump;
|
|
1015
1324
|
await release();
|
|
1325
|
+
throw error;
|
|
1016
1326
|
}
|
|
1017
1327
|
}
|
|
1018
1328
|
/**
|
|
@@ -1040,6 +1350,27 @@ var OpenCodeSession = class {
|
|
|
1040
1350
|
return _classPrivateFieldGet2(_harness, this).use(async (opencode) => sessionBusy(opencode, this.id, await opencode.sessions.active()));
|
|
1041
1351
|
}
|
|
1042
1352
|
};
|
|
1353
|
+
async function _snapshot(opencode) {
|
|
1354
|
+
const [messages, busy, pending, permissions] = await Promise.all([
|
|
1355
|
+
this.history(),
|
|
1356
|
+
this.busy(),
|
|
1357
|
+
_classPrivateFieldGet2(_harness, this).pending({ session: this.id }),
|
|
1358
|
+
opencode.permission.list({ sessionID: this.id })
|
|
1359
|
+
]);
|
|
1360
|
+
return {
|
|
1361
|
+
session: this.id,
|
|
1362
|
+
messages,
|
|
1363
|
+
busy,
|
|
1364
|
+
pending,
|
|
1365
|
+
permissions: permissions.map((request) => ({
|
|
1366
|
+
id: request.id,
|
|
1367
|
+
session: request.sessionID,
|
|
1368
|
+
action: request.action,
|
|
1369
|
+
resources: request.resources,
|
|
1370
|
+
...request.message === void 0 ? {} : { message: request.message }
|
|
1371
|
+
}))
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1043
1374
|
var _harness2 = /* @__PURE__ */ new WeakMap();
|
|
1044
1375
|
/** Every OpenCode session in this object. */
|
|
1045
1376
|
var OpenCodeSessions = class {
|