@ai-sdk/harness-opencode 1.0.91 → 1.0.92
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 +7 -0
- package/dist/bridge/index.mjs +61 -3
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/src/bridge/create-emit-stream-event.ts +21 -0
- package/src/bridge/index.ts +61 -3
- package/src/bridge/opencode-events.ts +10 -0
- package/src/bridge/opencode-types.ts +1 -0
package/dist/index.js
CHANGED
|
@@ -364,7 +364,7 @@ var inboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
364
364
|
]);
|
|
365
365
|
|
|
366
366
|
// src/version.ts
|
|
367
|
-
var VERSION = true ? "1.0.
|
|
367
|
+
var VERSION = true ? "1.0.92" : "0.0.0-test";
|
|
368
368
|
|
|
369
369
|
// src/opencode-harness.ts
|
|
370
370
|
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.92",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@ai-sdk/harness": "1.0.
|
|
29
|
+
"@ai-sdk/harness": "1.0.91",
|
|
30
30
|
"@ai-sdk/provider-utils": "5.0.32",
|
|
31
31
|
"ws": "8.21.0"
|
|
32
32
|
},
|
|
@@ -19,6 +19,11 @@ import {
|
|
|
19
19
|
|
|
20
20
|
type Emit = (message: Record<string, unknown>) => void;
|
|
21
21
|
|
|
22
|
+
type SubagentSession = {
|
|
23
|
+
parentSessionId: string;
|
|
24
|
+
sessionId: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
22
27
|
export function createEmitStreamEvent({
|
|
23
28
|
state,
|
|
24
29
|
emit,
|
|
@@ -28,6 +33,7 @@ export function createEmitStreamEvent({
|
|
|
28
33
|
nativeNameField,
|
|
29
34
|
getHostToolName,
|
|
30
35
|
authorizeHostToolCall,
|
|
36
|
+
onSubagentSession,
|
|
31
37
|
isMcpToolName,
|
|
32
38
|
stripWorkDir,
|
|
33
39
|
formatError,
|
|
@@ -49,6 +55,7 @@ export function createEmitStreamEvent({
|
|
|
49
55
|
toolName: string;
|
|
50
56
|
input: unknown;
|
|
51
57
|
}) => void;
|
|
58
|
+
onSubagentSession?: (session: SubagentSession) => void;
|
|
52
59
|
isMcpToolName: (toolName: string) => boolean;
|
|
53
60
|
stripWorkDir: (file: string) => string;
|
|
54
61
|
formatError: (error: unknown) => string;
|
|
@@ -83,6 +90,7 @@ export function createEmitStreamEvent({
|
|
|
83
90
|
nativeNameField,
|
|
84
91
|
getHostToolName,
|
|
85
92
|
authorizeHostToolCall,
|
|
93
|
+
onSubagentSession,
|
|
86
94
|
isMcpToolName,
|
|
87
95
|
});
|
|
88
96
|
return;
|
|
@@ -359,6 +367,7 @@ function emitLegacyToolPart({
|
|
|
359
367
|
nativeNameField,
|
|
360
368
|
getHostToolName,
|
|
361
369
|
authorizeHostToolCall,
|
|
370
|
+
onSubagentSession,
|
|
362
371
|
isMcpToolName,
|
|
363
372
|
}: {
|
|
364
373
|
part: unknown;
|
|
@@ -377,6 +386,7 @@ function emitLegacyToolPart({
|
|
|
377
386
|
toolName: string;
|
|
378
387
|
input: unknown;
|
|
379
388
|
}) => void;
|
|
389
|
+
onSubagentSession?: (session: SubagentSession) => void;
|
|
380
390
|
isMcpToolName: (toolName: string) => boolean;
|
|
381
391
|
}): void {
|
|
382
392
|
const toolPart = legacyToolPartFromValue(part);
|
|
@@ -389,6 +399,17 @@ function emitLegacyToolPart({
|
|
|
389
399
|
const rawToolName = toolPart.tool;
|
|
390
400
|
if (rawToolName === 'StructuredOutput') return;
|
|
391
401
|
const toolName = toWireToolName(rawToolName);
|
|
402
|
+
if (toolName === 'agent') {
|
|
403
|
+
const metadata = {
|
|
404
|
+
...(toolPart.metadata ?? {}),
|
|
405
|
+
...(toolPart.state?.metadata ?? {}),
|
|
406
|
+
};
|
|
407
|
+
const parentSessionId = stringValue(metadata.parentSessionId);
|
|
408
|
+
const sessionId = stringValue(metadata.sessionId);
|
|
409
|
+
if (parentSessionId && sessionId) {
|
|
410
|
+
onSubagentSession?.({ parentSessionId, sessionId });
|
|
411
|
+
}
|
|
412
|
+
}
|
|
392
413
|
state.toolNames.set(callID, { rawToolName, toolName });
|
|
393
414
|
const hostToolName = getHostToolName(toolName, rawToolName);
|
|
394
415
|
if (hostToolName) {
|
package/src/bridge/index.ts
CHANGED
|
@@ -878,6 +878,22 @@ async function consumeEvents({
|
|
|
878
878
|
const stream = await subscribeLegacyEvents({ client, signal });
|
|
879
879
|
onSubscribed?.();
|
|
880
880
|
if (!stream) return;
|
|
881
|
+
const taskSessionIds = new Set([sessionId]);
|
|
882
|
+
const registerSubagentSession = (sourceSessionId: string) =>
|
|
883
|
+
function register({
|
|
884
|
+
parentSessionId,
|
|
885
|
+
sessionId: subagentSessionId,
|
|
886
|
+
}: {
|
|
887
|
+
parentSessionId: string;
|
|
888
|
+
sessionId: string;
|
|
889
|
+
}) {
|
|
890
|
+
if (
|
|
891
|
+
parentSessionId === sourceSessionId &&
|
|
892
|
+
taskSessionIds.has(sourceSessionId)
|
|
893
|
+
) {
|
|
894
|
+
taskSessionIds.add(subagentSessionId);
|
|
895
|
+
}
|
|
896
|
+
};
|
|
881
897
|
const emitStreamEvent = createEmitStreamEvent({
|
|
882
898
|
state,
|
|
883
899
|
emit,
|
|
@@ -887,20 +903,59 @@ async function consumeEvents({
|
|
|
887
903
|
nativeNameField,
|
|
888
904
|
getHostToolName,
|
|
889
905
|
authorizeHostToolCall: input => authorizeHostToolCall({ ...input, state }),
|
|
906
|
+
onSubagentSession: registerSubagentSession(sessionId),
|
|
890
907
|
isMcpToolName: toolName =>
|
|
891
908
|
[...runtime.mcpToolPrefixes].some(prefix => toolName.startsWith(prefix)),
|
|
892
909
|
stripWorkDir,
|
|
893
910
|
formatError,
|
|
894
911
|
});
|
|
912
|
+
const descendantEventProcessors = new Map<
|
|
913
|
+
string,
|
|
914
|
+
(event: OpenCodeEvent) => void
|
|
915
|
+
>();
|
|
916
|
+
const processDescendantEvent = (
|
|
917
|
+
descendantSessionId: string,
|
|
918
|
+
event: OpenCodeEvent,
|
|
919
|
+
) => {
|
|
920
|
+
let processEvent = descendantEventProcessors.get(descendantSessionId);
|
|
921
|
+
if (!processEvent) {
|
|
922
|
+
const descendantState = createTranslationState();
|
|
923
|
+
processEvent = createEmitStreamEvent({
|
|
924
|
+
state: descendantState,
|
|
925
|
+
emit: () => undefined,
|
|
926
|
+
emitWarning: () => undefined,
|
|
927
|
+
emitError: () => undefined,
|
|
928
|
+
toWireToolName,
|
|
929
|
+
nativeNameField,
|
|
930
|
+
getHostToolName,
|
|
931
|
+
authorizeHostToolCall: input =>
|
|
932
|
+
authorizeHostToolCall({ ...input, state: descendantState }),
|
|
933
|
+
onSubagentSession: registerSubagentSession(descendantSessionId),
|
|
934
|
+
isMcpToolName: () => false,
|
|
935
|
+
stripWorkDir,
|
|
936
|
+
formatError,
|
|
937
|
+
});
|
|
938
|
+
descendantEventProcessors.set(descendantSessionId, processEvent);
|
|
939
|
+
}
|
|
940
|
+
processEvent(event);
|
|
941
|
+
};
|
|
895
942
|
for await (const rawEvent of stream) {
|
|
896
943
|
if (signal.aborted || turn.abortSignal.aborted) break;
|
|
897
944
|
const event = unwrapOpenCodeEvent(rawEvent);
|
|
898
945
|
const eventSessionId = event ? getOpenCodeEventSessionId(event) : undefined;
|
|
899
|
-
if (!event
|
|
946
|
+
if (!event) continue;
|
|
947
|
+
const scopedSessionId =
|
|
948
|
+
!eventSessionId || eventSessionId === sessionId
|
|
949
|
+
? sessionId
|
|
950
|
+
: taskSessionIds.has(eventSessionId)
|
|
951
|
+
? eventSessionId
|
|
952
|
+
: undefined;
|
|
953
|
+
if (!scopedSessionId) continue;
|
|
954
|
+
const isDescendant = scopedSessionId !== sessionId;
|
|
900
955
|
if (event.type === 'permission.v2.asked') {
|
|
901
956
|
await handlePermissionV2({
|
|
902
957
|
client,
|
|
903
|
-
sessionId,
|
|
958
|
+
sessionId: scopedSessionId,
|
|
904
959
|
permissionMode,
|
|
905
960
|
builtinToolFiltering,
|
|
906
961
|
turn,
|
|
@@ -910,16 +965,19 @@ async function consumeEvents({
|
|
|
910
965
|
} else if (event.type === 'permission.asked') {
|
|
911
966
|
await handlePermission({
|
|
912
967
|
client,
|
|
913
|
-
sessionId,
|
|
968
|
+
sessionId: scopedSessionId,
|
|
914
969
|
permissionMode,
|
|
915
970
|
builtinToolFiltering,
|
|
916
971
|
turn,
|
|
917
972
|
emit,
|
|
918
973
|
event,
|
|
919
974
|
});
|
|
975
|
+
} else if (isDescendant) {
|
|
976
|
+
processDescendantEvent(scopedSessionId, event);
|
|
920
977
|
} else {
|
|
921
978
|
emitStreamEvent(event);
|
|
922
979
|
}
|
|
980
|
+
if (isDescendant) continue;
|
|
923
981
|
if (onEvent?.(event)) break;
|
|
924
982
|
}
|
|
925
983
|
}
|
|
@@ -101,6 +101,16 @@ export function getOpenCodeEventSessionId(
|
|
|
101
101
|
if (event.type?.startsWith('session.') && typeof props.id === 'string') {
|
|
102
102
|
return props.id;
|
|
103
103
|
}
|
|
104
|
+
const info = asOpenCodeObject(props.info);
|
|
105
|
+
if (typeof info?.sessionID === 'string') return info.sessionID;
|
|
106
|
+
if (
|
|
107
|
+
(event.type === 'session.created' ||
|
|
108
|
+
event.type === 'session.updated' ||
|
|
109
|
+
event.type === 'session.deleted') &&
|
|
110
|
+
typeof info?.id === 'string'
|
|
111
|
+
) {
|
|
112
|
+
return info.id;
|
|
113
|
+
}
|
|
104
114
|
const part = props.part;
|
|
105
115
|
const partObject = asOpenCodeObject(part);
|
|
106
116
|
if (typeof partObject?.sessionID === 'string') return partObject.sessionID;
|