@ai-sdk/harness-opencode 1.0.64 → 1.0.66
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 +20 -0
- package/dist/bridge/index.mjs +46 -22
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +16 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/bridge/create-emit-stream-event.ts +12 -1
- package/src/bridge/index.ts +37 -16
- package/src/bridge/opencode-events.ts +2 -0
- package/src/opencode-bridge-protocol.ts +1 -0
- package/src/opencode-harness.ts +31 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @ai-sdk/harness-opencode
|
|
2
2
|
|
|
3
|
+
## 1.0.66
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- ecd9169: fix(harness-opencode): authorize legacy host tool relay calls using raw tool input
|
|
8
|
+
- a03ff6c: feat(harness): add support for per-harness MCP servers
|
|
9
|
+
- fc3baaf: feat(harness): add optional `mintBridgeToken(sandboxId)` to harness settings to control the bridge token value
|
|
10
|
+
- Updated dependencies [401a4ba]
|
|
11
|
+
- Updated dependencies [a03ff6c]
|
|
12
|
+
- @ai-sdk/provider-utils@5.0.26
|
|
13
|
+
- @ai-sdk/harness@1.0.65
|
|
14
|
+
|
|
15
|
+
## 1.0.65
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Updated dependencies [81cd026]
|
|
20
|
+
- @ai-sdk/provider-utils@5.0.25
|
|
21
|
+
- @ai-sdk/harness@1.0.64
|
|
22
|
+
|
|
3
23
|
## 1.0.64
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/dist/bridge/index.mjs
CHANGED
|
@@ -492,7 +492,8 @@ function createTranslationState() {
|
|
|
492
492
|
turnUsage: void 0,
|
|
493
493
|
legacyTextPartIds: /* @__PURE__ */ new Set(),
|
|
494
494
|
legacyReasoningPartIds: /* @__PURE__ */ new Set(),
|
|
495
|
-
legacyStepFinishPartIds: /* @__PURE__ */ new Set()
|
|
495
|
+
legacyStepFinishPartIds: /* @__PURE__ */ new Set(),
|
|
496
|
+
dynamicToolCallIds: /* @__PURE__ */ new Set()
|
|
496
497
|
};
|
|
497
498
|
}
|
|
498
499
|
function emitOpenCodeStreamStart({
|
|
@@ -830,6 +831,7 @@ function createEmitStreamEvent({
|
|
|
830
831
|
nativeNameField: nativeNameField2,
|
|
831
832
|
getHostToolName: getHostToolName2,
|
|
832
833
|
authorizeHostToolCall: authorizeHostToolCall2,
|
|
834
|
+
isMcpToolName,
|
|
833
835
|
stripWorkDir: stripWorkDir2,
|
|
834
836
|
formatError: formatError2
|
|
835
837
|
}) {
|
|
@@ -859,7 +861,8 @@ function createEmitStreamEvent({
|
|
|
859
861
|
toWireToolName: toWireToolName2,
|
|
860
862
|
nativeNameField: nativeNameField2,
|
|
861
863
|
getHostToolName: getHostToolName2,
|
|
862
|
-
authorizeHostToolCall: authorizeHostToolCall2
|
|
864
|
+
authorizeHostToolCall: authorizeHostToolCall2,
|
|
865
|
+
isMcpToolName
|
|
863
866
|
});
|
|
864
867
|
return;
|
|
865
868
|
}
|
|
@@ -987,8 +990,10 @@ function createEmitStreamEvent({
|
|
|
987
990
|
...nativeNameField2({ nativeName: rawToolName, toolName }),
|
|
988
991
|
input: JSON.stringify(props.input ?? parseToolInput(state, props)),
|
|
989
992
|
providerExecuted: true,
|
|
993
|
+
...isMcpToolName(rawToolName) ? { dynamic: true } : {},
|
|
990
994
|
...props.provider?.metadata ? { providerMetadata: props.provider.metadata } : {}
|
|
991
995
|
});
|
|
996
|
+
if (isMcpToolName(rawToolName)) state.dynamicToolCallIds.add(callID);
|
|
992
997
|
return;
|
|
993
998
|
}
|
|
994
999
|
if (type === "session.next.tool.success" || type === "session.next.tool.failed") {
|
|
@@ -1002,7 +1007,8 @@ function createEmitStreamEvent({
|
|
|
1002
1007
|
toolCallId: callID,
|
|
1003
1008
|
toolName,
|
|
1004
1009
|
result: props.result ?? props.structured ?? ("content" in props ? props.content : null) ?? null,
|
|
1005
|
-
...type === "session.next.tool.failed" ? { isError: true } : {}
|
|
1010
|
+
...type === "session.next.tool.failed" ? { isError: true } : {},
|
|
1011
|
+
...state.dynamicToolCallIds.delete(callID) ? { dynamic: true } : {}
|
|
1006
1012
|
});
|
|
1007
1013
|
return;
|
|
1008
1014
|
}
|
|
@@ -1101,7 +1107,8 @@ function emitLegacyToolPart({
|
|
|
1101
1107
|
toWireToolName: toWireToolName2,
|
|
1102
1108
|
nativeNameField: nativeNameField2,
|
|
1103
1109
|
getHostToolName: getHostToolName2,
|
|
1104
|
-
authorizeHostToolCall: authorizeHostToolCall2
|
|
1110
|
+
authorizeHostToolCall: authorizeHostToolCall2,
|
|
1111
|
+
isMcpToolName
|
|
1105
1112
|
}) {
|
|
1106
1113
|
const toolPart = legacyToolPartFromValue(part);
|
|
1107
1114
|
if (!toolPart) return;
|
|
@@ -1119,7 +1126,7 @@ function emitLegacyToolPart({
|
|
|
1119
1126
|
authorizeHostToolCall2({
|
|
1120
1127
|
callID,
|
|
1121
1128
|
toolName: hostToolName,
|
|
1122
|
-
input:
|
|
1129
|
+
input: toolPart.state?.input ?? {}
|
|
1123
1130
|
});
|
|
1124
1131
|
}
|
|
1125
1132
|
return;
|
|
@@ -1133,8 +1140,10 @@ function emitLegacyToolPart({
|
|
|
1133
1140
|
...nativeNameField2({ nativeName: rawToolName, toolName }),
|
|
1134
1141
|
input: JSON.stringify(legacyToolPartInput(toolPart)),
|
|
1135
1142
|
providerExecuted: true,
|
|
1143
|
+
...isMcpToolName(rawToolName) ? { dynamic: true } : {},
|
|
1136
1144
|
...toolPart.providerMetadata ? { providerMetadata: toolPart.providerMetadata } : {}
|
|
1137
1145
|
});
|
|
1146
|
+
if (isMcpToolName(rawToolName)) state.dynamicToolCallIds.add(callID);
|
|
1138
1147
|
}
|
|
1139
1148
|
if ((status === "completed" || status === "error") && !state.toolResultsEmitted.has(callID)) {
|
|
1140
1149
|
state.toolResultsEmitted.add(callID);
|
|
@@ -1143,7 +1152,8 @@ function emitLegacyToolPart({
|
|
|
1143
1152
|
toolCallId: callID,
|
|
1144
1153
|
toolName,
|
|
1145
1154
|
result: legacyToolPartOutput(toolPart),
|
|
1146
|
-
...status === "error" ? { isError: true } : {}
|
|
1155
|
+
...status === "error" ? { isError: true } : {},
|
|
1156
|
+
...state.dynamicToolCallIds.delete(callID) ? { dynamic: true } : {}
|
|
1147
1157
|
});
|
|
1148
1158
|
}
|
|
1149
1159
|
}
|
|
@@ -1482,7 +1492,10 @@ var workdir = args.workdir ?? emitFatal("Missing --workdir argument.");
|
|
|
1482
1492
|
var bridgeStateDir = args.bridgeStateDir ?? emitFatal("Missing --bridge-state-dir argument.");
|
|
1483
1493
|
var bootstrapDir = args.bootstrapDir ?? workdir;
|
|
1484
1494
|
var skillsDir = args.skillsDir;
|
|
1485
|
-
var runtime = {
|
|
1495
|
+
var runtime = {
|
|
1496
|
+
toolNames: /* @__PURE__ */ new Set(),
|
|
1497
|
+
mcpToolPrefixes: /* @__PURE__ */ new Set()
|
|
1498
|
+
};
|
|
1486
1499
|
prependOpenCodeBinToPath({ bootstrapDir, env: procEnv2 });
|
|
1487
1500
|
mkdirSync(process.env.HOME ?? "/tmp/opencode-home", { recursive: true });
|
|
1488
1501
|
await runBridge({
|
|
@@ -1541,6 +1554,13 @@ async function ensureRuntime({
|
|
|
1541
1554
|
baseUrl: server.url,
|
|
1542
1555
|
directory: workdir
|
|
1543
1556
|
});
|
|
1557
|
+
const mcpStatus = await runtime.client.mcp.status();
|
|
1558
|
+
const mcpServers = asOpenCodeObject(mcpStatus.data) ?? {};
|
|
1559
|
+
runtime.mcpToolPrefixes = new Set(
|
|
1560
|
+
Object.entries(mcpServers).filter(
|
|
1561
|
+
([serverName, status]) => serverName !== "harness-tools" && asOpenCodeObject(status)?.status === "connected"
|
|
1562
|
+
).map(([serverName]) => `${sanitizeMcpToolName(serverName)}_`)
|
|
1563
|
+
);
|
|
1544
1564
|
}
|
|
1545
1565
|
function buildOpenCodeConfig({
|
|
1546
1566
|
start,
|
|
@@ -1578,25 +1598,25 @@ function buildOpenCodeConfig({
|
|
|
1578
1598
|
}
|
|
1579
1599
|
const provider = buildProviderConfig(start);
|
|
1580
1600
|
if (provider) config.provider = provider;
|
|
1601
|
+
const mcp = { ...start.mcpServers ?? {} };
|
|
1581
1602
|
if (relayPort && start.tools && start.tools.length > 0) {
|
|
1582
|
-
|
|
1583
|
-
"
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
TOOL_RELAY_URL: `http://127.0.0.1:${relayPort}`
|
|
1596
|
-
}
|
|
1603
|
+
mcp["harness-tools"] = {
|
|
1604
|
+
type: "local",
|
|
1605
|
+
enabled: true,
|
|
1606
|
+
command: ["node", `${bootstrapDir}/host-tool-mcp.mjs`],
|
|
1607
|
+
environment: {
|
|
1608
|
+
TOOL_SCHEMAS: JSON.stringify(
|
|
1609
|
+
start.tools.map((t) => ({
|
|
1610
|
+
name: t.name,
|
|
1611
|
+
description: t.description,
|
|
1612
|
+
inputSchema: t.inputSchema
|
|
1613
|
+
}))
|
|
1614
|
+
),
|
|
1615
|
+
TOOL_RELAY_URL: `http://127.0.0.1:${relayPort}`
|
|
1597
1616
|
}
|
|
1598
1617
|
};
|
|
1599
1618
|
}
|
|
1619
|
+
if (Object.keys(mcp).length > 0) config.mcp = mcp;
|
|
1600
1620
|
return config;
|
|
1601
1621
|
}
|
|
1602
1622
|
function buildProviderConfig(start) {
|
|
@@ -2018,6 +2038,7 @@ async function consumeEvents({
|
|
|
2018
2038
|
nativeNameField,
|
|
2019
2039
|
getHostToolName,
|
|
2020
2040
|
authorizeHostToolCall: (input) => authorizeHostToolCall({ ...input, state }),
|
|
2041
|
+
isMcpToolName: (toolName) => [...runtime.mcpToolPrefixes].some((prefix) => toolName.startsWith(prefix)),
|
|
2021
2042
|
stripWorkDir,
|
|
2022
2043
|
formatError
|
|
2023
2044
|
});
|
|
@@ -2052,6 +2073,9 @@ async function consumeEvents({
|
|
|
2052
2073
|
if (onEvent?.(event)) break;
|
|
2053
2074
|
}
|
|
2054
2075
|
}
|
|
2076
|
+
function sanitizeMcpToolName(value) {
|
|
2077
|
+
return value.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2078
|
+
}
|
|
2055
2079
|
async function handlePermissionV2({
|
|
2056
2080
|
client,
|
|
2057
2081
|
sessionId,
|