@ai-sdk/harness-opencode 1.0.118 → 1.0.120

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/index.d.ts CHANGED
@@ -3,6 +3,7 @@ import { HarnessV1Authentication, HarnessV1CredentialForwarding, HarnessV1PortEn
3
3
  import * as _ai_sdk_provider from '@ai-sdk/provider';
4
4
  import * as _ai_sdk_provider_utils from '@ai-sdk/provider-utils';
5
5
  import { Experimental_SandboxSession } from '@ai-sdk/provider-utils';
6
+ import { SandboxChannelReconnectOptions } from '@ai-sdk/harness/utils';
6
7
 
7
8
  type OpenCodeAuthenticationMode = HarnessV1Authentication<'anthropic' | 'openai'>;
8
9
 
@@ -39,6 +40,13 @@ type OpenCodeHarnessSettings = {
39
40
  */
40
41
  readonly portEndpoint?: HarnessV1PortEndpoint;
41
42
  readonly startupTimeoutMs?: number;
43
+ /**
44
+ * Configures reconnection attempts after an established bridge connection
45
+ * drops. The reconnect window includes connection establishment and
46
+ * backoff delays. Defaults to 30 seconds with exponential backoff from 50
47
+ * milliseconds up to 2 seconds.
48
+ */
49
+ readonly reconnect?: SandboxChannelReconnectOptions;
42
50
  /**
43
51
  * Creates the authentication token used by the sandbox bridge. Defaults to
44
52
  * a random 32-byte hexadecimal token.
package/dist/index.js CHANGED
@@ -909,7 +909,7 @@ var inboundMessageSchema = z.discriminatedUnion("type", [
909
909
  ]);
910
910
 
911
911
  // src/version.ts
912
- var VERSION = true ? "1.0.118" : "0.0.0-test";
912
+ var VERSION = true ? "1.0.120" : "0.0.0-test";
913
913
 
914
914
  // src/opencode-harness.ts
915
915
  var OPENCODE_CLIENT_APP = `ai-sdk/harness-opencode/${VERSION}`;
@@ -1166,9 +1166,10 @@ function createOpenCode(settings = {}) {
1166
1166
  });
1167
1167
  let supportsUserMessageResponses2 = false;
1168
1168
  const attachChannel = new SandboxChannel({
1169
- connect: () => openWebSocket({
1169
+ connect: ({ abortSignal }) => openWebSocket({
1170
1170
  endpoint: attachEndpoint,
1171
1171
  helloTimeoutMs: Math.min(timeoutMs, 5e3),
1172
+ abortSignal,
1172
1173
  onHello: (supported) => {
1173
1174
  supportsUserMessageResponses2 = supported;
1174
1175
  }
@@ -1176,7 +1177,8 @@ function createOpenCode(settings = {}) {
1176
1177
  outboundSchema: outboundMessageSchema,
1177
1178
  initialLastSeenEventId: coords.lastSeenEventId,
1178
1179
  onDiagnostic,
1179
- onBridgeError
1180
+ onBridgeError,
1181
+ reconnect: settings.reconnect
1180
1182
  });
1181
1183
  await attachChannel.open(isContinue ? { resume: true } : void 0);
1182
1184
  return createSession({
@@ -1310,9 +1312,10 @@ function createOpenCode(settings = {}) {
1310
1312
  const bridgeEndpoint = withBridgeToken({ endpoint, token });
1311
1313
  let supportsUserMessageResponses = false;
1312
1314
  const channel = new SandboxChannel({
1313
- connect: () => openWebSocket({
1315
+ connect: ({ abortSignal }) => openWebSocket({
1314
1316
  endpoint: bridgeEndpoint,
1315
1317
  helloTimeoutMs: Math.min(timeoutMs, 5e3),
1318
+ abortSignal,
1316
1319
  onHello: (supported) => {
1317
1320
  supportsUserMessageResponses = supported;
1318
1321
  }
@@ -1320,6 +1323,7 @@ function createOpenCode(settings = {}) {
1320
1323
  outboundSchema: outboundMessageSchema,
1321
1324
  onDiagnostic,
1322
1325
  onBridgeError,
1326
+ reconnect: settings.reconnect,
1323
1327
  ...respawnStrategy === "replay" ? { initialLastSeenEventId: coords?.lastSeenEventId ?? 0 } : {}
1324
1328
  });
1325
1329
  await channel.open(
@@ -1402,21 +1406,32 @@ async function resolveBridgeEndpoint({
1402
1406
  function openWebSocket({
1403
1407
  endpoint,
1404
1408
  helloTimeoutMs,
1409
+ abortSignal,
1405
1410
  onHello
1406
1411
  }) {
1407
1412
  return new Promise((resolve, reject) => {
1413
+ const abortReason = () => abortSignal.reason ?? new Error("WebSocket connection aborted");
1414
+ if (abortSignal.aborted) {
1415
+ reject(abortReason());
1416
+ return;
1417
+ }
1408
1418
  const ws = new WebSocket(endpoint.url, {
1409
1419
  headers: endpoint.headers == null ? void 0 : { ...endpoint.headers }
1410
1420
  });
1411
1421
  let opened = false;
1412
1422
  let receivedHello = false;
1413
1423
  let settled = false;
1424
+ let helloTimer;
1425
+ let onAbort;
1414
1426
  const cleanup = () => {
1415
1427
  clearTimeout(helloTimer);
1416
1428
  ws.off("open", onOpen);
1417
1429
  ws.off("message", onMessage);
1418
1430
  ws.off("close", onClose);
1419
1431
  ws.off("error", onError);
1432
+ if (onAbort != null) {
1433
+ abortSignal.removeEventListener("abort", onAbort);
1434
+ }
1420
1435
  };
1421
1436
  const settle = (error) => {
1422
1437
  if (settled) return;
@@ -1425,6 +1440,18 @@ function openWebSocket({
1425
1440
  if (error == null) {
1426
1441
  resolve(ws);
1427
1442
  } else {
1443
+ const suppressError = () => {
1444
+ };
1445
+ const socketWithOnce = ws;
1446
+ socketWithOnce.once?.("error", suppressError);
1447
+ try {
1448
+ ws.terminate();
1449
+ } catch {
1450
+ try {
1451
+ ws.close();
1452
+ } catch {
1453
+ }
1454
+ }
1428
1455
  reject(error);
1429
1456
  }
1430
1457
  };
@@ -1455,11 +1482,17 @@ function openWebSocket({
1455
1482
  const onError = (err) => {
1456
1483
  settle(err);
1457
1484
  };
1485
+ onAbort = () => settle(abortReason());
1458
1486
  ws.on("open", onOpen);
1459
1487
  ws.on("message", onMessage);
1460
1488
  ws.on("close", onClose);
1461
1489
  ws.on("error", onError);
1462
- const helloTimer = setTimeout(
1490
+ abortSignal.addEventListener("abort", onAbort, { once: true });
1491
+ if (abortSignal.aborted) {
1492
+ onAbort();
1493
+ return;
1494
+ }
1495
+ helloTimer = setTimeout(
1463
1496
  () => settle(
1464
1497
  new Error(
1465
1498
  `OpenCode bridge did not send bridge-hello within ${helloTimeoutMs}ms.`