@ai-sdk/harness-opencode 1.0.37 → 1.0.39
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 +19 -0
- package/dist/bridge/index.mjs +141 -120
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/bridge/package.json +2 -2
- package/dist/bridge/pnpm-lock.yaml +59 -59
- package/dist/index.js +1 -1
- package/package.json +4 -4
- package/src/bridge/index.ts +5 -142
- package/src/bridge/opencode-events.ts +182 -0
- package/src/bridge/package.json +2 -2
- package/src/bridge/pnpm-lock.yaml +59 -59
package/dist/bridge/package.json
CHANGED
|
@@ -12,11 +12,11 @@ importers:
|
|
|
12
12
|
specifier: 1.29.0
|
|
13
13
|
version: 1.29.0(zod@3.25.76)
|
|
14
14
|
'@opencode-ai/sdk':
|
|
15
|
-
specifier: 1.
|
|
16
|
-
version: 1.
|
|
15
|
+
specifier: 1.18.3
|
|
16
|
+
version: 1.18.3
|
|
17
17
|
opencode-ai:
|
|
18
|
-
specifier: 1.
|
|
19
|
-
version: 1.
|
|
18
|
+
specifier: 1.18.3
|
|
19
|
+
version: 1.18.3
|
|
20
20
|
ws:
|
|
21
21
|
specifier: 8.21.0
|
|
22
22
|
version: 8.21.0
|
|
@@ -42,8 +42,8 @@ packages:
|
|
|
42
42
|
'@cfworker/json-schema':
|
|
43
43
|
optional: true
|
|
44
44
|
|
|
45
|
-
'@opencode-ai/sdk@1.
|
|
46
|
-
resolution: {integrity: sha512-
|
|
45
|
+
'@opencode-ai/sdk@1.18.3':
|
|
46
|
+
resolution: {integrity: sha512-Mevo4e6kQwbvto9E+42KSIVMhp+JBu+SwQhC5AomAvrV6Xkio3U249T+xDILDCXhl5Z/Hi/DlAuVLzpGnuh0gg==}
|
|
47
47
|
|
|
48
48
|
accepts@2.0.0:
|
|
49
49
|
resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
|
|
@@ -286,72 +286,72 @@ packages:
|
|
|
286
286
|
once@1.4.0:
|
|
287
287
|
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
|
288
288
|
|
|
289
|
-
opencode-ai@1.
|
|
290
|
-
resolution: {integrity: sha512-
|
|
289
|
+
opencode-ai@1.18.3:
|
|
290
|
+
resolution: {integrity: sha512-HnItl/+uhSpj7JV9x6ITiE0XFq4b/PKF5OM03TIyiFoFiLw3MQoJOAXZFTEzC7IOgAIYcysRQBBmCmlXILkxww==}
|
|
291
291
|
cpu: [arm64, x64]
|
|
292
292
|
os: [darwin, linux, win32]
|
|
293
293
|
hasBin: true
|
|
294
294
|
|
|
295
|
-
opencode-darwin-arm64@1.
|
|
296
|
-
resolution: {integrity: sha512-
|
|
295
|
+
opencode-darwin-arm64@1.18.3:
|
|
296
|
+
resolution: {integrity: sha512-BkfJf4E502OVwpDXgaVz8eqTDOy2B9xXPefYebT+xv8TXYvEo1wtby4eu4MoN51o4o1qpzcvCCXDqUDXu1pBGQ==}
|
|
297
297
|
cpu: [arm64]
|
|
298
298
|
os: [darwin]
|
|
299
299
|
|
|
300
|
-
opencode-darwin-x64-baseline@1.
|
|
301
|
-
resolution: {integrity: sha512-
|
|
300
|
+
opencode-darwin-x64-baseline@1.18.3:
|
|
301
|
+
resolution: {integrity: sha512-8qQ9Ig7Zp7LEKaKGRL+OIlDb/uTLYkeAq6SGsN0fLHR2rHZRHyb61KrpkS5TgUlGwSWPtb5uCeVtTA9rGbEAKw==}
|
|
302
302
|
cpu: [x64]
|
|
303
303
|
os: [darwin]
|
|
304
304
|
|
|
305
|
-
opencode-darwin-x64@1.
|
|
306
|
-
resolution: {integrity: sha512-
|
|
305
|
+
opencode-darwin-x64@1.18.3:
|
|
306
|
+
resolution: {integrity: sha512-ujy61O3WUEHjPqk+qXMBl97zR9q3crOzHbm2VLmXLHUWbqB5ZtN1HToODbuI1SBMKVR8GyZwPygRQVMfON4DHg==}
|
|
307
307
|
cpu: [x64]
|
|
308
308
|
os: [darwin]
|
|
309
309
|
|
|
310
|
-
opencode-linux-arm64-musl@1.
|
|
311
|
-
resolution: {integrity: sha512-
|
|
310
|
+
opencode-linux-arm64-musl@1.18.3:
|
|
311
|
+
resolution: {integrity: sha512-s1vNP8dpIH3vFs8aoMzgHViBNVz6xtR7n24gGg0WOw4uSZVM+sRUmZKc3Hj56XjHQSsVBg5AkwR2Xm0nFSfIUQ==}
|
|
312
312
|
cpu: [arm64]
|
|
313
313
|
os: [linux]
|
|
314
314
|
libc: [musl]
|
|
315
315
|
|
|
316
|
-
opencode-linux-arm64@1.
|
|
317
|
-
resolution: {integrity: sha512-
|
|
316
|
+
opencode-linux-arm64@1.18.3:
|
|
317
|
+
resolution: {integrity: sha512-K+1SPkfrYFUufPUYpbSurlB2ogpjv5in2usA1FwOM7HCOpNxR3ap7K+X4uQXnOV8AtsON+Vr9W5uYXQJA1yKlA==}
|
|
318
318
|
cpu: [arm64]
|
|
319
319
|
os: [linux]
|
|
320
320
|
|
|
321
|
-
opencode-linux-x64-baseline-musl@1.
|
|
322
|
-
resolution: {integrity: sha512-
|
|
321
|
+
opencode-linux-x64-baseline-musl@1.18.3:
|
|
322
|
+
resolution: {integrity: sha512-F2nNPqYPdTCydLvNH1rvSXdlX3pfmOmOOfsFl+pqi3W0iE3Alyxmv28AjrIGUw4/6EfWhMKYcyxKjNIKLFyaZQ==}
|
|
323
323
|
cpu: [x64]
|
|
324
324
|
os: [linux]
|
|
325
325
|
libc: [musl]
|
|
326
326
|
|
|
327
|
-
opencode-linux-x64-baseline@1.
|
|
328
|
-
resolution: {integrity: sha512-
|
|
327
|
+
opencode-linux-x64-baseline@1.18.3:
|
|
328
|
+
resolution: {integrity: sha512-DDfspGSQ123yhsFhAlbpF+tsvje5kHOS2/PYUpWJroTlvgtqRLGmET51Anrxd5BrAFrqB6PXYA2kGh5QStPU/g==}
|
|
329
329
|
cpu: [x64]
|
|
330
330
|
os: [linux]
|
|
331
331
|
|
|
332
|
-
opencode-linux-x64-musl@1.
|
|
333
|
-
resolution: {integrity: sha512-
|
|
332
|
+
opencode-linux-x64-musl@1.18.3:
|
|
333
|
+
resolution: {integrity: sha512-SSp2zSpAM4dntcPZw8ISl3CmXYrWPftLc8u0HuAIeNWJOo6G4xAHPoXhNnXI3tQYqqGcppArf/3EMPnF9WnyFw==}
|
|
334
334
|
cpu: [x64]
|
|
335
335
|
os: [linux]
|
|
336
336
|
libc: [musl]
|
|
337
337
|
|
|
338
|
-
opencode-linux-x64@1.
|
|
339
|
-
resolution: {integrity: sha512-
|
|
338
|
+
opencode-linux-x64@1.18.3:
|
|
339
|
+
resolution: {integrity: sha512-p+19dSTf3pWL3+Rh/Ym94DvS9mNxNG94HJnR5oMCDhQvgimdT5tSdoK4ETtk4XOoCKz3OcTQDPHTdYKcJg32KQ==}
|
|
340
340
|
cpu: [x64]
|
|
341
341
|
os: [linux]
|
|
342
342
|
|
|
343
|
-
opencode-windows-arm64@1.
|
|
344
|
-
resolution: {integrity: sha512-
|
|
343
|
+
opencode-windows-arm64@1.18.3:
|
|
344
|
+
resolution: {integrity: sha512-qkz9/r6kUhhgLycQv71MoSQ2m5UI2QnZZx8SeZgyYD7oB8pDH6DIGbDWcs6BJ02ND1Y5hmgYWlP+rOrMkGlMJw==}
|
|
345
345
|
cpu: [arm64]
|
|
346
346
|
os: [win32]
|
|
347
347
|
|
|
348
|
-
opencode-windows-x64-baseline@1.
|
|
349
|
-
resolution: {integrity: sha512
|
|
348
|
+
opencode-windows-x64-baseline@1.18.3:
|
|
349
|
+
resolution: {integrity: sha512-+tyoxwSfY7msfZNY1IoA0ZWRL9XfdqY+ash6U3ldfE+GfF2WNAdhewmmYiUsC4lHjkdSmLt2brdWgoebQK9HAg==}
|
|
350
350
|
cpu: [x64]
|
|
351
351
|
os: [win32]
|
|
352
352
|
|
|
353
|
-
opencode-windows-x64@1.
|
|
354
|
-
resolution: {integrity: sha512-
|
|
353
|
+
opencode-windows-x64@1.18.3:
|
|
354
|
+
resolution: {integrity: sha512-V/Q4VkyZ7TkotLbpTCX/s5wP8MoFj5UnRqBHFJ8WGptb/+oYw36kamUUt1P1wN8iRjmw+8vwYhuYdAe+3xbgpQ==}
|
|
355
355
|
cpu: [x64]
|
|
356
356
|
os: [win32]
|
|
357
357
|
|
|
@@ -508,7 +508,7 @@ snapshots:
|
|
|
508
508
|
transitivePeerDependencies:
|
|
509
509
|
- supports-color
|
|
510
510
|
|
|
511
|
-
'@opencode-ai/sdk@1.
|
|
511
|
+
'@opencode-ai/sdk@1.18.3':
|
|
512
512
|
dependencies:
|
|
513
513
|
cross-spawn: 7.0.6
|
|
514
514
|
|
|
@@ -752,55 +752,55 @@ snapshots:
|
|
|
752
752
|
dependencies:
|
|
753
753
|
wrappy: 1.0.2
|
|
754
754
|
|
|
755
|
-
opencode-ai@1.
|
|
755
|
+
opencode-ai@1.18.3:
|
|
756
756
|
optionalDependencies:
|
|
757
|
-
opencode-darwin-arm64: 1.
|
|
758
|
-
opencode-darwin-x64: 1.
|
|
759
|
-
opencode-darwin-x64-baseline: 1.
|
|
760
|
-
opencode-linux-arm64: 1.
|
|
761
|
-
opencode-linux-arm64-musl: 1.
|
|
762
|
-
opencode-linux-x64: 1.
|
|
763
|
-
opencode-linux-x64-baseline: 1.
|
|
764
|
-
opencode-linux-x64-baseline-musl: 1.
|
|
765
|
-
opencode-linux-x64-musl: 1.
|
|
766
|
-
opencode-windows-arm64: 1.
|
|
767
|
-
opencode-windows-x64: 1.
|
|
768
|
-
opencode-windows-x64-baseline: 1.
|
|
769
|
-
|
|
770
|
-
opencode-darwin-arm64@1.
|
|
757
|
+
opencode-darwin-arm64: 1.18.3
|
|
758
|
+
opencode-darwin-x64: 1.18.3
|
|
759
|
+
opencode-darwin-x64-baseline: 1.18.3
|
|
760
|
+
opencode-linux-arm64: 1.18.3
|
|
761
|
+
opencode-linux-arm64-musl: 1.18.3
|
|
762
|
+
opencode-linux-x64: 1.18.3
|
|
763
|
+
opencode-linux-x64-baseline: 1.18.3
|
|
764
|
+
opencode-linux-x64-baseline-musl: 1.18.3
|
|
765
|
+
opencode-linux-x64-musl: 1.18.3
|
|
766
|
+
opencode-windows-arm64: 1.18.3
|
|
767
|
+
opencode-windows-x64: 1.18.3
|
|
768
|
+
opencode-windows-x64-baseline: 1.18.3
|
|
769
|
+
|
|
770
|
+
opencode-darwin-arm64@1.18.3:
|
|
771
771
|
optional: true
|
|
772
772
|
|
|
773
|
-
opencode-darwin-x64-baseline@1.
|
|
773
|
+
opencode-darwin-x64-baseline@1.18.3:
|
|
774
774
|
optional: true
|
|
775
775
|
|
|
776
|
-
opencode-darwin-x64@1.
|
|
776
|
+
opencode-darwin-x64@1.18.3:
|
|
777
777
|
optional: true
|
|
778
778
|
|
|
779
|
-
opencode-linux-arm64-musl@1.
|
|
779
|
+
opencode-linux-arm64-musl@1.18.3:
|
|
780
780
|
optional: true
|
|
781
781
|
|
|
782
|
-
opencode-linux-arm64@1.
|
|
782
|
+
opencode-linux-arm64@1.18.3:
|
|
783
783
|
optional: true
|
|
784
784
|
|
|
785
|
-
opencode-linux-x64-baseline-musl@1.
|
|
785
|
+
opencode-linux-x64-baseline-musl@1.18.3:
|
|
786
786
|
optional: true
|
|
787
787
|
|
|
788
|
-
opencode-linux-x64-baseline@1.
|
|
788
|
+
opencode-linux-x64-baseline@1.18.3:
|
|
789
789
|
optional: true
|
|
790
790
|
|
|
791
|
-
opencode-linux-x64-musl@1.
|
|
791
|
+
opencode-linux-x64-musl@1.18.3:
|
|
792
792
|
optional: true
|
|
793
793
|
|
|
794
|
-
opencode-linux-x64@1.
|
|
794
|
+
opencode-linux-x64@1.18.3:
|
|
795
795
|
optional: true
|
|
796
796
|
|
|
797
|
-
opencode-windows-arm64@1.
|
|
797
|
+
opencode-windows-arm64@1.18.3:
|
|
798
798
|
optional: true
|
|
799
799
|
|
|
800
|
-
opencode-windows-x64-baseline@1.
|
|
800
|
+
opencode-windows-x64-baseline@1.18.3:
|
|
801
801
|
optional: true
|
|
802
802
|
|
|
803
|
-
opencode-windows-x64@1.
|
|
803
|
+
opencode-windows-x64@1.18.3:
|
|
804
804
|
optional: true
|
|
805
805
|
|
|
806
806
|
parseurl@1.3.3: {}
|
package/dist/index.js
CHANGED
|
@@ -168,7 +168,7 @@ var inboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
168
168
|
]);
|
|
169
169
|
|
|
170
170
|
// src/version.ts
|
|
171
|
-
var VERSION = true ? "1.0.
|
|
171
|
+
var VERSION = true ? "1.0.39" : "0.0.0-test";
|
|
172
172
|
|
|
173
173
|
// src/opencode-harness.ts
|
|
174
174
|
var OPENCODE_CLIENT_APP = `ai-sdk/harness-opencode/${VERSION}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/harness-opencode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.39",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"ws": "8.21.0",
|
|
30
|
-
"@ai-sdk/
|
|
31
|
-
"@ai-sdk/
|
|
30
|
+
"@ai-sdk/provider-utils": "5.0.12",
|
|
31
|
+
"@ai-sdk/harness": "1.0.38"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"zod": "^3.25.76 || ^4.1.8"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
38
|
-
"@opencode-ai/sdk": "1.
|
|
38
|
+
"@opencode-ai/sdk": "1.18.3",
|
|
39
39
|
"@types/node": "22.19.19",
|
|
40
40
|
"@types/ws": "^8.5.13",
|
|
41
41
|
"tsup": "^8.5.1",
|
package/src/bridge/index.ts
CHANGED
|
@@ -14,10 +14,14 @@ import {
|
|
|
14
14
|
createOpencodeServer,
|
|
15
15
|
} from '@opencode-ai/sdk/v2';
|
|
16
16
|
import {
|
|
17
|
+
createTranslationState,
|
|
18
|
+
emitLegacyPartDelta,
|
|
19
|
+
emitLegacyTextPartUpdate,
|
|
17
20
|
emitMissingFinalDelta,
|
|
18
21
|
getOpenCodeEventSessionId,
|
|
19
22
|
isStepSettlementEvent,
|
|
20
23
|
type OpenCodeEvent,
|
|
24
|
+
type TranslationState,
|
|
21
25
|
unwrapOpenCodeEvent,
|
|
22
26
|
} from './opencode-events';
|
|
23
27
|
import {
|
|
@@ -798,40 +802,6 @@ async function consumeEvents({
|
|
|
798
802
|
}
|
|
799
803
|
}
|
|
800
804
|
|
|
801
|
-
type TranslationState = {
|
|
802
|
-
textDeltas: Map<string, string>;
|
|
803
|
-
reasoningDeltas: Map<string, string>;
|
|
804
|
-
toolInputs: Map<string, string>;
|
|
805
|
-
toolNames: Map<string, { rawToolName: string; toolName: string }>;
|
|
806
|
-
toolCallsEmitted: Set<string>;
|
|
807
|
-
toolResultsEmitted: Set<string>;
|
|
808
|
-
hostToolCallsAuthorized: Set<string>;
|
|
809
|
-
shellCommands: Map<string, string>;
|
|
810
|
-
messageRoles: Map<string, string>;
|
|
811
|
-
turnUsage: Record<string, unknown> | undefined;
|
|
812
|
-
legacyTextPartIds: Set<string>;
|
|
813
|
-
legacyReasoningPartIds: Set<string>;
|
|
814
|
-
legacyStepFinishPartIds: Set<string>;
|
|
815
|
-
};
|
|
816
|
-
|
|
817
|
-
function createTranslationState(): TranslationState {
|
|
818
|
-
return {
|
|
819
|
-
textDeltas: new Map(),
|
|
820
|
-
reasoningDeltas: new Map(),
|
|
821
|
-
toolInputs: new Map(),
|
|
822
|
-
toolNames: new Map(),
|
|
823
|
-
toolCallsEmitted: new Set(),
|
|
824
|
-
toolResultsEmitted: new Set(),
|
|
825
|
-
hostToolCallsAuthorized: new Set(),
|
|
826
|
-
shellCommands: new Map(),
|
|
827
|
-
messageRoles: new Map(),
|
|
828
|
-
turnUsage: undefined,
|
|
829
|
-
legacyTextPartIds: new Set(),
|
|
830
|
-
legacyReasoningPartIds: new Set(),
|
|
831
|
-
legacyStepFinishPartIds: new Set(),
|
|
832
|
-
};
|
|
833
|
-
}
|
|
834
|
-
|
|
835
805
|
async function translateAndEmit({
|
|
836
806
|
event,
|
|
837
807
|
state,
|
|
@@ -865,32 +835,7 @@ async function translateAndEmit({
|
|
|
865
835
|
}
|
|
866
836
|
|
|
867
837
|
if (type === 'message.part.delta') {
|
|
868
|
-
|
|
869
|
-
const delta = String(props.delta ?? '');
|
|
870
|
-
if (!delta) return;
|
|
871
|
-
const messageID = stringValue(props.messageID);
|
|
872
|
-
if (messageID && state.messageRoles.get(messageID) === 'user') return;
|
|
873
|
-
if (field === 'text') {
|
|
874
|
-
const id = legacyPartId({ value: props, fallback: 'legacy-text' });
|
|
875
|
-
startLegacyPart({ ids: state.legacyTextPartIds, id, emit, type: 'text' });
|
|
876
|
-
state.textDeltas.set(id, `${state.textDeltas.get(id) ?? ''}${delta}`);
|
|
877
|
-
emit({ type: 'text-delta', id, delta });
|
|
878
|
-
return;
|
|
879
|
-
}
|
|
880
|
-
if (field === 'reasoning') {
|
|
881
|
-
const id = legacyPartId({ value: props, fallback: 'legacy-reasoning' });
|
|
882
|
-
startLegacyPart({
|
|
883
|
-
ids: state.legacyReasoningPartIds,
|
|
884
|
-
id,
|
|
885
|
-
emit,
|
|
886
|
-
type: 'reasoning',
|
|
887
|
-
});
|
|
888
|
-
state.reasoningDeltas.set(
|
|
889
|
-
id,
|
|
890
|
-
`${state.reasoningDeltas.get(id) ?? ''}${delta}`,
|
|
891
|
-
);
|
|
892
|
-
emit({ type: 'reasoning-delta', id, delta });
|
|
893
|
-
}
|
|
838
|
+
emitLegacyPartDelta({ props, state, emit });
|
|
894
839
|
return;
|
|
895
840
|
}
|
|
896
841
|
|
|
@@ -1142,88 +1087,6 @@ async function translateAndEmit({
|
|
|
1142
1087
|
}
|
|
1143
1088
|
}
|
|
1144
1089
|
|
|
1145
|
-
function legacyPartId({
|
|
1146
|
-
value,
|
|
1147
|
-
fallback,
|
|
1148
|
-
}: {
|
|
1149
|
-
value: Record<string, unknown>;
|
|
1150
|
-
fallback: string;
|
|
1151
|
-
}): string {
|
|
1152
|
-
return stringValue(value.partID) ?? stringValue(value.id) ?? fallback;
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
function startLegacyPart({
|
|
1156
|
-
ids,
|
|
1157
|
-
id,
|
|
1158
|
-
emit,
|
|
1159
|
-
type,
|
|
1160
|
-
}: {
|
|
1161
|
-
ids: Set<string>;
|
|
1162
|
-
id: string;
|
|
1163
|
-
emit: Emit;
|
|
1164
|
-
type: 'text' | 'reasoning';
|
|
1165
|
-
}): void {
|
|
1166
|
-
if (ids.has(id)) return;
|
|
1167
|
-
ids.add(id);
|
|
1168
|
-
emit({ type: `${type}-start`, id });
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
function emitLegacyTextPartUpdate({
|
|
1172
|
-
part,
|
|
1173
|
-
state,
|
|
1174
|
-
emit,
|
|
1175
|
-
}: {
|
|
1176
|
-
part: unknown;
|
|
1177
|
-
state: TranslationState;
|
|
1178
|
-
emit: Emit;
|
|
1179
|
-
}): boolean {
|
|
1180
|
-
if (!isRecord(part)) return false;
|
|
1181
|
-
if (part.type !== 'text' && part.type !== 'reasoning') return false;
|
|
1182
|
-
const id = stringValue(part.id);
|
|
1183
|
-
if (!id) return true;
|
|
1184
|
-
|
|
1185
|
-
const messageID = stringValue(part.messageID);
|
|
1186
|
-
if (messageID && state.messageRoles.get(messageID) === 'user') return true;
|
|
1187
|
-
|
|
1188
|
-
const isReasoning = part.type === 'reasoning';
|
|
1189
|
-
const ids = isReasoning
|
|
1190
|
-
? state.legacyReasoningPartIds
|
|
1191
|
-
: state.legacyTextPartIds;
|
|
1192
|
-
const deltaMap = isReasoning ? state.reasoningDeltas : state.textDeltas;
|
|
1193
|
-
const deltaType = isReasoning ? 'reasoning-delta' : 'text-delta';
|
|
1194
|
-
const text = typeof part.text === 'string' ? part.text : undefined;
|
|
1195
|
-
|
|
1196
|
-
startLegacyPart({
|
|
1197
|
-
ids,
|
|
1198
|
-
id,
|
|
1199
|
-
emit,
|
|
1200
|
-
type: isReasoning ? 'reasoning' : 'text',
|
|
1201
|
-
});
|
|
1202
|
-
|
|
1203
|
-
if (text !== undefined) {
|
|
1204
|
-
emitMissingFinalDelta({
|
|
1205
|
-
id,
|
|
1206
|
-
fullText: text,
|
|
1207
|
-
emittedText: deltaMap.get(id) ?? '',
|
|
1208
|
-
emit,
|
|
1209
|
-
type: deltaType,
|
|
1210
|
-
});
|
|
1211
|
-
deltaMap.set(id, text);
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
if (legacyPartEnded(part)) {
|
|
1215
|
-
ids.delete(id);
|
|
1216
|
-
deltaMap.delete(id);
|
|
1217
|
-
emit({ type: isReasoning ? 'reasoning-end' : 'text-end', id });
|
|
1218
|
-
}
|
|
1219
|
-
|
|
1220
|
-
return true;
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
function legacyPartEnded(part: Record<string, unknown>): boolean {
|
|
1224
|
-
return isRecord(part.time) && part.time.end != null;
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
1090
|
function closeLegacyOpenParts({
|
|
1228
1091
|
state,
|
|
1229
1092
|
emit,
|
|
@@ -4,6 +4,42 @@ export type OpenCodeEvent = {
|
|
|
4
4
|
properties?: Record<string, any>;
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
+
type Emit = (msg: Record<string, unknown>) => void;
|
|
8
|
+
|
|
9
|
+
export type TranslationState = {
|
|
10
|
+
textDeltas: Map<string, string>;
|
|
11
|
+
reasoningDeltas: Map<string, string>;
|
|
12
|
+
toolInputs: Map<string, string>;
|
|
13
|
+
toolNames: Map<string, { rawToolName: string; toolName: string }>;
|
|
14
|
+
toolCallsEmitted: Set<string>;
|
|
15
|
+
toolResultsEmitted: Set<string>;
|
|
16
|
+
hostToolCallsAuthorized: Set<string>;
|
|
17
|
+
shellCommands: Map<string, string>;
|
|
18
|
+
messageRoles: Map<string, string>;
|
|
19
|
+
turnUsage: Record<string, unknown> | undefined;
|
|
20
|
+
legacyTextPartIds: Set<string>;
|
|
21
|
+
legacyReasoningPartIds: Set<string>;
|
|
22
|
+
legacyStepFinishPartIds: Set<string>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function createTranslationState(): TranslationState {
|
|
26
|
+
return {
|
|
27
|
+
textDeltas: new Map(),
|
|
28
|
+
reasoningDeltas: new Map(),
|
|
29
|
+
toolInputs: new Map(),
|
|
30
|
+
toolNames: new Map(),
|
|
31
|
+
toolCallsEmitted: new Set(),
|
|
32
|
+
toolResultsEmitted: new Set(),
|
|
33
|
+
hostToolCallsAuthorized: new Set(),
|
|
34
|
+
shellCommands: new Map(),
|
|
35
|
+
messageRoles: new Map(),
|
|
36
|
+
turnUsage: undefined,
|
|
37
|
+
legacyTextPartIds: new Set(),
|
|
38
|
+
legacyReasoningPartIds: new Set(),
|
|
39
|
+
legacyStepFinishPartIds: new Set(),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
7
43
|
export function unwrapOpenCodeEvent(
|
|
8
44
|
rawEvent: unknown,
|
|
9
45
|
): OpenCodeEvent | undefined {
|
|
@@ -77,6 +113,114 @@ export function emitMissingFinalDelta({
|
|
|
77
113
|
emit({ type, id, delta: fullText.slice(emittedText.length) });
|
|
78
114
|
}
|
|
79
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Translates an OpenCode `message.part.delta` event (a streaming text or
|
|
118
|
+
* reasoning delta) into legacy stream parts.
|
|
119
|
+
*/
|
|
120
|
+
export function emitLegacyPartDelta({
|
|
121
|
+
props,
|
|
122
|
+
state,
|
|
123
|
+
emit,
|
|
124
|
+
}: {
|
|
125
|
+
props: Record<string, unknown>;
|
|
126
|
+
state: TranslationState;
|
|
127
|
+
emit: Emit;
|
|
128
|
+
}): void {
|
|
129
|
+
const field = String(props.field ?? '');
|
|
130
|
+
const delta = String(props.delta ?? '');
|
|
131
|
+
if (!delta) return;
|
|
132
|
+
const messageID = stringValue(props.messageID);
|
|
133
|
+
if (messageID && state.messageRoles.get(messageID) === 'user') return;
|
|
134
|
+
if (field === 'text') {
|
|
135
|
+
const id = legacyPartId({ value: props, fallback: 'legacy-text' });
|
|
136
|
+
// OpenCode publishes reasoning deltas with field:"text". If this id was
|
|
137
|
+
// already announced as a reasoning part, route it to reasoning so it is not
|
|
138
|
+
// duplicated as a text part.
|
|
139
|
+
if (state.legacyReasoningPartIds.has(id)) {
|
|
140
|
+
state.reasoningDeltas.set(
|
|
141
|
+
id,
|
|
142
|
+
`${state.reasoningDeltas.get(id) ?? ''}${delta}`,
|
|
143
|
+
);
|
|
144
|
+
emit({ type: 'reasoning-delta', id, delta });
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
startLegacyPart({ ids: state.legacyTextPartIds, id, emit, type: 'text' });
|
|
148
|
+
state.textDeltas.set(id, `${state.textDeltas.get(id) ?? ''}${delta}`);
|
|
149
|
+
emit({ type: 'text-delta', id, delta });
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (field === 'reasoning') {
|
|
153
|
+
const id = legacyPartId({ value: props, fallback: 'legacy-reasoning' });
|
|
154
|
+
startLegacyPart({
|
|
155
|
+
ids: state.legacyReasoningPartIds,
|
|
156
|
+
id,
|
|
157
|
+
emit,
|
|
158
|
+
type: 'reasoning',
|
|
159
|
+
});
|
|
160
|
+
state.reasoningDeltas.set(
|
|
161
|
+
id,
|
|
162
|
+
`${state.reasoningDeltas.get(id) ?? ''}${delta}`,
|
|
163
|
+
);
|
|
164
|
+
emit({ type: 'reasoning-delta', id, delta });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Translates an OpenCode `message.part.updated` event for a text or reasoning
|
|
170
|
+
* part. Returns `true` when it handled the part.
|
|
171
|
+
*/
|
|
172
|
+
export function emitLegacyTextPartUpdate({
|
|
173
|
+
part,
|
|
174
|
+
state,
|
|
175
|
+
emit,
|
|
176
|
+
}: {
|
|
177
|
+
part: unknown;
|
|
178
|
+
state: TranslationState;
|
|
179
|
+
emit: Emit;
|
|
180
|
+
}): boolean {
|
|
181
|
+
if (!isRecord(part)) return false;
|
|
182
|
+
if (part.type !== 'text' && part.type !== 'reasoning') return false;
|
|
183
|
+
const id = stringValue(part.id);
|
|
184
|
+
if (!id) return true;
|
|
185
|
+
|
|
186
|
+
const messageID = stringValue(part.messageID);
|
|
187
|
+
if (messageID && state.messageRoles.get(messageID) === 'user') return true;
|
|
188
|
+
|
|
189
|
+
const isReasoning = part.type === 'reasoning';
|
|
190
|
+
const ids = isReasoning
|
|
191
|
+
? state.legacyReasoningPartIds
|
|
192
|
+
: state.legacyTextPartIds;
|
|
193
|
+
const deltaMap = isReasoning ? state.reasoningDeltas : state.textDeltas;
|
|
194
|
+
const deltaType = isReasoning ? 'reasoning-delta' : 'text-delta';
|
|
195
|
+
const text = typeof part.text === 'string' ? part.text : undefined;
|
|
196
|
+
|
|
197
|
+
startLegacyPart({
|
|
198
|
+
ids,
|
|
199
|
+
id,
|
|
200
|
+
emit,
|
|
201
|
+
type: isReasoning ? 'reasoning' : 'text',
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
if (text !== undefined) {
|
|
205
|
+
emitMissingFinalDelta({
|
|
206
|
+
id,
|
|
207
|
+
fullText: text,
|
|
208
|
+
emittedText: deltaMap.get(id) ?? '',
|
|
209
|
+
emit,
|
|
210
|
+
type: deltaType,
|
|
211
|
+
});
|
|
212
|
+
deltaMap.set(id, text);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (legacyPartEnded(part)) {
|
|
216
|
+
ids.delete(id);
|
|
217
|
+
deltaMap.delete(id);
|
|
218
|
+
emit({ type: isReasoning ? 'reasoning-end' : 'text-end', id });
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
|
|
80
224
|
function stripSyncVersion(type: string): string {
|
|
81
225
|
return type.replace(/\.\d+$/, '');
|
|
82
226
|
}
|
|
@@ -86,3 +230,41 @@ function asRecord(value: unknown): Record<string, any> | undefined {
|
|
|
86
230
|
return undefined;
|
|
87
231
|
return value as Record<string, any>;
|
|
88
232
|
}
|
|
233
|
+
|
|
234
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
235
|
+
return Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function stringValue(value: unknown): string | undefined {
|
|
239
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function legacyPartId({
|
|
243
|
+
value,
|
|
244
|
+
fallback,
|
|
245
|
+
}: {
|
|
246
|
+
value: Record<string, unknown>;
|
|
247
|
+
fallback: string;
|
|
248
|
+
}): string {
|
|
249
|
+
return stringValue(value.partID) ?? stringValue(value.id) ?? fallback;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function startLegacyPart({
|
|
253
|
+
ids,
|
|
254
|
+
id,
|
|
255
|
+
emit,
|
|
256
|
+
type,
|
|
257
|
+
}: {
|
|
258
|
+
ids: Set<string>;
|
|
259
|
+
id: string;
|
|
260
|
+
emit: Emit;
|
|
261
|
+
type: 'text' | 'reasoning';
|
|
262
|
+
}): void {
|
|
263
|
+
if (ids.has(id)) return;
|
|
264
|
+
ids.add(id);
|
|
265
|
+
emit({ type: `${type}-start`, id });
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function legacyPartEnded(part: Record<string, unknown>): boolean {
|
|
269
|
+
return isRecord(part.time) && part.time.end != null;
|
|
270
|
+
}
|
package/src/bridge/package.json
CHANGED