@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 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
@@ -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: legacyToolPartInput(toolPart)
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 = { toolNames: /* @__PURE__ */ new Set() };
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
- config.mcp = {
1583
- "harness-tools": {
1584
- type: "local",
1585
- enabled: true,
1586
- command: ["node", `${bootstrapDir}/host-tool-mcp.mjs`],
1587
- environment: {
1588
- TOOL_SCHEMAS: JSON.stringify(
1589
- start.tools.map((t) => ({
1590
- name: t.name,
1591
- description: t.description,
1592
- inputSchema: t.inputSchema
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,