@ai-sdk/harness-opencode 1.0.73 → 1.0.75
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 +15 -0
- package/dist/bridge/index.mjs +52 -27
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/bridge/create-emit-stream-event.ts +3 -0
- package/src/bridge/index.ts +44 -7
- package/src/opencode-harness.ts +26 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @ai-sdk/harness-opencode
|
|
2
2
|
|
|
3
|
+
## 1.0.75
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @ai-sdk/harness@1.0.74
|
|
8
|
+
|
|
9
|
+
## 1.0.74
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 62a9c2a: feat(harness): add support for structured output to `HarnessAgent` via `output` property
|
|
14
|
+
- Updated dependencies [62a9c2a]
|
|
15
|
+
- Updated dependencies [d25cae2]
|
|
16
|
+
- @ai-sdk/harness@1.0.73
|
|
17
|
+
|
|
3
18
|
## 1.0.73
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/dist/bridge/index.mjs
CHANGED
|
@@ -53,7 +53,6 @@ async function runBridge(options) {
|
|
|
53
53
|
let currentBoundPort = 0;
|
|
54
54
|
let currentTurnState = "init";
|
|
55
55
|
let activeSocket;
|
|
56
|
-
let activeSocketReadyForLiveEvents = false;
|
|
57
56
|
let isFirstTurn = true;
|
|
58
57
|
let turnAbort;
|
|
59
58
|
let currentUserMessages;
|
|
@@ -137,14 +136,6 @@ async function runBridge(options) {
|
|
|
137
136
|
} catch {
|
|
138
137
|
}
|
|
139
138
|
};
|
|
140
|
-
const sendControl = (msg) => {
|
|
141
|
-
if (activeSocket?.readyState === WS_OPEN) {
|
|
142
|
-
try {
|
|
143
|
-
activeSocket.send(JSON.stringify(msg));
|
|
144
|
-
} catch {
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
139
|
const emit = (event) => {
|
|
149
140
|
const seq = ++seqCounter;
|
|
150
141
|
const line = JSON.stringify({ ...event, seq });
|
|
@@ -152,7 +143,7 @@ async function runBridge(options) {
|
|
|
152
143
|
diskBuffer += `${line}
|
|
153
144
|
`;
|
|
154
145
|
scheduleEventFlush();
|
|
155
|
-
if (
|
|
146
|
+
if (activeSocket?.readyState === WS_OPEN) {
|
|
156
147
|
try {
|
|
157
148
|
activeSocket.send(line);
|
|
158
149
|
} catch {
|
|
@@ -255,8 +246,7 @@ async function runBridge(options) {
|
|
|
255
246
|
const handleInbound = async (msg, ws) => {
|
|
256
247
|
switch (msg.type) {
|
|
257
248
|
case "start": {
|
|
258
|
-
|
|
259
|
-
activeSocketReadyForLiveEvents = true;
|
|
249
|
+
activeSocket = ws;
|
|
260
250
|
const firstTurn = isFirstTurn;
|
|
261
251
|
isFirstTurn = false;
|
|
262
252
|
eventLog = [];
|
|
@@ -336,9 +326,8 @@ async function runBridge(options) {
|
|
|
336
326
|
turnAbort?.abort();
|
|
337
327
|
return;
|
|
338
328
|
case "resume":
|
|
339
|
-
|
|
329
|
+
activeSocket = ws;
|
|
340
330
|
replay(ws, msg.lastSeenEventId);
|
|
341
|
-
activeSocketReadyForLiveEvents = true;
|
|
342
331
|
return;
|
|
343
332
|
case "destroy":
|
|
344
333
|
currentTurnState = "done";
|
|
@@ -350,7 +339,7 @@ async function runBridge(options) {
|
|
|
350
339
|
currentTurnState = "done";
|
|
351
340
|
void writeBridgeMeta("done");
|
|
352
341
|
const data = await onStop?.() ?? {};
|
|
353
|
-
sendControl({ type: "bridge-stop", data });
|
|
342
|
+
sendControl(ws, { type: "bridge-stop", data });
|
|
354
343
|
drainThenExit(ws, 1e3, "stop");
|
|
355
344
|
return;
|
|
356
345
|
}
|
|
@@ -403,9 +392,7 @@ async function runBridge(options) {
|
|
|
403
392
|
ws.close(1008, "unauthorized");
|
|
404
393
|
return;
|
|
405
394
|
}
|
|
406
|
-
|
|
407
|
-
activeSocketReadyForLiveEvents = false;
|
|
408
|
-
sendControl({
|
|
395
|
+
sendControl(ws, {
|
|
409
396
|
type: "bridge-hello",
|
|
410
397
|
state: currentTurnState,
|
|
411
398
|
lastSeq: seqCounter
|
|
@@ -416,7 +403,7 @@ async function runBridge(options) {
|
|
|
416
403
|
const text = typeof raw === "string" ? raw : Buffer.from(raw).toString("utf8");
|
|
417
404
|
parsed = JSON.parse(text);
|
|
418
405
|
} catch (err) {
|
|
419
|
-
sendControl({
|
|
406
|
+
sendControl(ws, {
|
|
420
407
|
type: "error",
|
|
421
408
|
error: `protocol parse error: ${err.message}`
|
|
422
409
|
});
|
|
@@ -427,7 +414,6 @@ async function runBridge(options) {
|
|
|
427
414
|
ws.on("close", () => {
|
|
428
415
|
if (activeSocket === ws) {
|
|
429
416
|
activeSocket = void 0;
|
|
430
|
-
activeSocketReadyForLiveEvents = false;
|
|
431
417
|
}
|
|
432
418
|
});
|
|
433
419
|
ws.on("error", () => {
|
|
@@ -454,6 +440,14 @@ async function runBridge(options) {
|
|
|
454
440
|
})
|
|
455
441
|
};
|
|
456
442
|
}
|
|
443
|
+
function sendControl(socket, message) {
|
|
444
|
+
if (socket?.readyState === WS_OPEN) {
|
|
445
|
+
try {
|
|
446
|
+
socket.send(JSON.stringify(message));
|
|
447
|
+
} catch {
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
457
451
|
function serialiseError(err) {
|
|
458
452
|
if (err instanceof Error) {
|
|
459
453
|
return { name: err.name, message: err.message, stack: err.stack };
|
|
@@ -972,6 +966,7 @@ function createEmitStreamEvent({
|
|
|
972
966
|
if (type === "session.next.tool.called") {
|
|
973
967
|
const callID = String(props.callID ?? event.id);
|
|
974
968
|
const rawToolName = String(props.tool ?? "unknown");
|
|
969
|
+
if (rawToolName === "StructuredOutput") return;
|
|
975
970
|
const toolName = toWireToolName2(rawToolName);
|
|
976
971
|
state.toolNames.set(callID, { rawToolName, toolName });
|
|
977
972
|
const hostToolName = getHostToolName2(toolName, props.tool);
|
|
@@ -1000,6 +995,7 @@ function createEmitStreamEvent({
|
|
|
1000
995
|
const callID = String(props.callID ?? event.id);
|
|
1001
996
|
const cachedTool = state.toolNames.get(callID);
|
|
1002
997
|
const rawToolName = cachedTool?.rawToolName ?? String(props.tool ?? "");
|
|
998
|
+
if (rawToolName === "StructuredOutput") return;
|
|
1003
999
|
const toolName = cachedTool?.toolName ?? toWireToolName2(rawToolName || "unknown");
|
|
1004
1000
|
if (getHostToolName2(toolName, rawToolName)) return;
|
|
1005
1001
|
emit({
|
|
@@ -1118,6 +1114,7 @@ function emitLegacyToolPart({
|
|
|
1118
1114
|
}
|
|
1119
1115
|
const callID = toolPart.callID;
|
|
1120
1116
|
const rawToolName = toolPart.tool;
|
|
1117
|
+
if (rawToolName === "StructuredOutput") return;
|
|
1121
1118
|
const toolName = toWireToolName2(rawToolName);
|
|
1122
1119
|
state.toolNames.set(callID, { rawToolName, toolName });
|
|
1123
1120
|
const hostToolName = getHostToolName2(toolName, rawToolName);
|
|
@@ -1736,6 +1733,12 @@ async function legacySessionPrompt({
|
|
|
1736
1733
|
sessionID: sessionId,
|
|
1737
1734
|
...start.instructions ? { system: start.instructions } : {},
|
|
1738
1735
|
...start.variant ? { variant: start.variant } : {},
|
|
1736
|
+
...start.responseFormat?.type === "json" && start.responseFormat.schema != null ? {
|
|
1737
|
+
format: {
|
|
1738
|
+
type: "json_schema",
|
|
1739
|
+
schema: start.responseFormat.schema
|
|
1740
|
+
}
|
|
1741
|
+
} : {},
|
|
1739
1742
|
parts: [{ type: "text", text: start.prompt }]
|
|
1740
1743
|
});
|
|
1741
1744
|
}
|
|
@@ -1875,11 +1878,36 @@ async function runPrompt({
|
|
|
1875
1878
|
state,
|
|
1876
1879
|
emit
|
|
1877
1880
|
});
|
|
1881
|
+
const info = asOpenCodeObject(event.properties?.info);
|
|
1882
|
+
if (start.responseFormat?.type === "json" && info?.structured !== void 0) {
|
|
1883
|
+
const id = String(info.id ?? randomUUID());
|
|
1884
|
+
emit({ type: "text-start", id });
|
|
1885
|
+
emit({
|
|
1886
|
+
type: "text-delta",
|
|
1887
|
+
id,
|
|
1888
|
+
delta: JSON.stringify(info.structured)
|
|
1889
|
+
});
|
|
1890
|
+
emit({ type: "text-end", id });
|
|
1891
|
+
emit({
|
|
1892
|
+
type: "finish-step",
|
|
1893
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
1894
|
+
usage: defaultUsage()
|
|
1895
|
+
});
|
|
1896
|
+
sawFinishStep = true;
|
|
1897
|
+
turnSettled.resolve();
|
|
1898
|
+
return true;
|
|
1899
|
+
}
|
|
1878
1900
|
}
|
|
1879
1901
|
if (event.type === "session.updated") {
|
|
1880
1902
|
latestSessionTokens = extractSessionTokens(event.properties) ?? latestSessionTokens;
|
|
1881
1903
|
}
|
|
1882
1904
|
if (isStepSettlementEvent(event)) {
|
|
1905
|
+
if (event.type === "session.error") {
|
|
1906
|
+
terminalError = formatError(event.properties?.error ?? event);
|
|
1907
|
+
}
|
|
1908
|
+
if (start.responseFormat?.type === "json" && event.type === "session.next.step.ended") {
|
|
1909
|
+
return;
|
|
1910
|
+
}
|
|
1883
1911
|
turnSettled.resolve();
|
|
1884
1912
|
return true;
|
|
1885
1913
|
}
|
|
@@ -1890,13 +1918,10 @@ async function runPrompt({
|
|
|
1890
1918
|
sawBusy = true;
|
|
1891
1919
|
turn.emitWarning({ message: legacyRetryStatusMessage(event) });
|
|
1892
1920
|
} else if (sawBusy && status === "idle") {
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
terminalError = formatError(event.properties?.error ?? event);
|
|
1898
|
-
turnSettled.resolve();
|
|
1899
|
-
return true;
|
|
1921
|
+
if (start.responseFormat?.type !== "json") {
|
|
1922
|
+
turnSettled.resolve();
|
|
1923
|
+
return true;
|
|
1924
|
+
}
|
|
1900
1925
|
}
|
|
1901
1926
|
}
|
|
1902
1927
|
}).finally(() => {
|