@ai-sdk/harness-opencode 1.0.114 → 1.0.115

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,17 @@
1
1
  # @ai-sdk/harness-opencode
2
2
 
3
+ ## 1.0.115
4
+
5
+ ### Patch Changes
6
+
7
+ - 0185c4d: fix(harness-opencode): refresh warm runtimes when native configuration changes
8
+ - b3c82fd: fix(harness-opencode): preserve native compaction events without leaking internal summary text
9
+ - Updated dependencies [91c2128]
10
+ - Updated dependencies [2cd80b3]
11
+ - Updated dependencies [2fa5e0e]
12
+ - @ai-sdk/provider-utils@5.0.42
13
+ - @ai-sdk/harness@1.0.113
14
+
3
15
  ## 1.0.114
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -27,4 +27,15 @@ Adapter-managed settings take precedence when the same key is present in
27
27
  `openCodeConfig`. Agent-local `permission` and deprecated `tools` settings are
28
28
  ignored so they cannot bypass harness permissions or built-in tool filtering.
29
29
 
30
+ ## Compaction events
31
+
32
+ Native automatic and manual compaction emit a `compaction` stream part on
33
+ completion. Internal summary text is available on that part, rather than
34
+ streamed as assistant answer text. Summary model usage is preserved.
35
+
36
+ With `includeRawChunks` enabled, `opencode.compaction` raw events expose
37
+ `messageId` and `status` (`started` or `failed`). Successful completion uses
38
+ the normalized `compaction` part, whose `harnessMetadata.opencode.messageId`
39
+ identifies the same operation.
40
+
30
41
  See the AI SDK documentation for usage.
@@ -648,6 +648,7 @@ function serialiseError(err) {
648
648
  import { randomUUID as randomUUID2 } from "crypto";
649
649
  import path2 from "path";
650
650
  import { argv, env as procEnv2 } from "process";
651
+ import { isDeepStrictEqual } from "util";
651
652
  import {
652
653
  createOpencodeClient,
653
654
  createOpencodeServer
@@ -1036,6 +1037,30 @@ function createEmitStreamEvent({
1036
1037
  stripWorkDir: stripWorkDir2,
1037
1038
  formatError: formatError2
1038
1039
  }) {
1040
+ const compactionMessages = /* @__PURE__ */ new Set();
1041
+ let compactionTrigger = "auto";
1042
+ let compaction;
1043
+ const finishCompaction = (failed = false) => {
1044
+ if (!compaction) return;
1045
+ if (failed) {
1046
+ emit({
1047
+ type: "raw",
1048
+ rawValue: {
1049
+ type: "opencode.compaction",
1050
+ messageId: compaction.id,
1051
+ status: "failed"
1052
+ }
1053
+ });
1054
+ } else {
1055
+ emit({
1056
+ type: "compaction",
1057
+ trigger: compaction.trigger,
1058
+ summary: [...compaction.text.values()].join(""),
1059
+ harnessMetadata: { opencode: { messageId: compaction.id } }
1060
+ });
1061
+ }
1062
+ compaction = void 0;
1063
+ };
1039
1064
  return (event) => {
1040
1065
  const type = event.type;
1041
1066
  const props = event.properties ?? {};
@@ -1045,9 +1070,56 @@ function createEmitStreamEvent({
1045
1070
  const id = stringValue2(info.id);
1046
1071
  const role = stringValue2(info.role);
1047
1072
  if (id && role) state.messageRoles.set(id, role);
1073
+ if (id && info.summary === true) {
1074
+ if (!compactionMessages.has(id)) {
1075
+ compactionMessages.add(id);
1076
+ compaction = { id, trigger: compactionTrigger, text: /* @__PURE__ */ new Map() };
1077
+ emitOpenCodeStreamStart({ info, state, emit });
1078
+ emit({
1079
+ type: "raw",
1080
+ rawValue: {
1081
+ type: "opencode.compaction",
1082
+ messageId: id,
1083
+ status: "started"
1084
+ }
1085
+ });
1086
+ }
1087
+ if (info.error && compaction?.id === id) finishCompaction(true);
1088
+ }
1048
1089
  }
1049
1090
  return;
1050
1091
  }
1092
+ if (type === "session.compacted") {
1093
+ finishCompaction();
1094
+ return;
1095
+ }
1096
+ if (type === "message.part.updated" || type === "message.part.delta") {
1097
+ const part = asOpenCodeObject(props.part);
1098
+ if (type === "message.part.updated" && part?.type === "compaction") {
1099
+ compactionTrigger = part.auto === false ? "manual" : "auto";
1100
+ return;
1101
+ }
1102
+ const messageId = stringValue2(
1103
+ type === "message.part.updated" ? part?.messageID : props.messageID
1104
+ );
1105
+ if (messageId && compactionMessages.has(messageId)) {
1106
+ if (type === "message.part.updated") {
1107
+ if (messageId === compaction?.id && part?.type === "text") {
1108
+ const id = stringValue2(part.id);
1109
+ if (id && typeof part.text === "string") {
1110
+ compaction.text.set(id, part.text);
1111
+ }
1112
+ }
1113
+ emitLegacyStepFinishPart({ part: props.part, state, emit });
1114
+ } else if (messageId === compaction?.id && props.field === "text") {
1115
+ const id = stringValue2(props.partID);
1116
+ if (id && compaction.text.has(id) && typeof props.delta === "string") {
1117
+ compaction.text.set(id, compaction.text.get(id) + props.delta);
1118
+ }
1119
+ }
1120
+ return;
1121
+ }
1122
+ }
1051
1123
  if (type === "message.part.delta") {
1052
1124
  emitLegacyPartDelta({ props, state, emit });
1053
1125
  return;
@@ -1268,6 +1340,7 @@ function createEmitStreamEvent({
1268
1340
  return;
1269
1341
  }
1270
1342
  if (type === "session.error" || type === "session.next.step.failed") {
1343
+ finishCompaction(true);
1271
1344
  const error = props.error ?? event;
1272
1345
  emitError({
1273
1346
  error,
@@ -1835,38 +1908,57 @@ async function ensureRuntime({
1835
1908
  turn,
1836
1909
  emit
1837
1910
  }) {
1838
- if (runtime.client) return;
1839
- if (start.tools && start.tools.length > 0) {
1840
- runtime.toolNames = new Set(start.tools.map((tool) => tool.name));
1841
- runtime.relay = await startToolRelay({
1842
- tools: start.tools,
1843
- emit,
1844
- requestToolResult: turn.requestToolResult
1845
- });
1911
+ if (runtime.client && isDeepStrictEqual(runtime.openCodeConfig, start.openCodeConfig)) {
1912
+ return;
1846
1913
  }
1847
- const serverAuthHeaders = configureOpenCodeServerAuth({ env: procEnv2 });
1848
- const server = await createOpencodeServer({
1849
- hostname: "127.0.0.1",
1850
- port: 0,
1851
- timeout: 3e4,
1852
- config: buildOpenCodeConfig({
1853
- start,
1854
- relayPort: runtime.relay?.port
1855
- })
1856
- });
1857
- runtime.server = server;
1858
- runtime.client = createOpencodeClient({
1859
- baseUrl: server.url,
1860
- directory: workdir,
1861
- headers: serverAuthHeaders
1862
- });
1863
- const mcpStatus = await runtime.client.mcp.status();
1864
- const mcpServers = asOpenCodeObject(mcpStatus.data) ?? {};
1865
- runtime.mcpToolPrefixes = new Set(
1866
- Object.entries(mcpServers).filter(
1867
- ([serverName, status]) => serverName !== "harness-tools" && asOpenCodeObject(status)?.status === "connected"
1868
- ).map(([serverName]) => `${sanitizeMcpToolName(serverName)}_`)
1869
- );
1914
+ closeRuntime();
1915
+ try {
1916
+ if (start.tools && start.tools.length > 0) {
1917
+ runtime.toolNames = new Set(start.tools.map((tool) => tool.name));
1918
+ runtime.relay = await startToolRelay({
1919
+ tools: start.tools,
1920
+ emit,
1921
+ requestToolResult: turn.requestToolResult
1922
+ });
1923
+ }
1924
+ const serverAuthHeaders = configureOpenCodeServerAuth({ env: procEnv2 });
1925
+ const server = await createOpencodeServer({
1926
+ hostname: "127.0.0.1",
1927
+ port: 0,
1928
+ timeout: 3e4,
1929
+ config: buildOpenCodeConfig({
1930
+ start,
1931
+ relayPort: runtime.relay?.port
1932
+ })
1933
+ });
1934
+ runtime.server = server;
1935
+ runtime.client = createOpencodeClient({
1936
+ baseUrl: server.url,
1937
+ directory: workdir,
1938
+ headers: serverAuthHeaders
1939
+ });
1940
+ const mcpStatus = await runtime.client.mcp.status();
1941
+ const mcpServers = asOpenCodeObject(mcpStatus.data) ?? {};
1942
+ runtime.mcpToolPrefixes = new Set(
1943
+ Object.entries(mcpServers).filter(
1944
+ ([serverName, status]) => serverName !== "harness-tools" && asOpenCodeObject(status)?.status === "connected"
1945
+ ).map(([serverName]) => `${sanitizeMcpToolName(serverName)}_`)
1946
+ );
1947
+ runtime.openCodeConfig = structuredClone(start.openCodeConfig);
1948
+ } catch (error) {
1949
+ closeRuntime();
1950
+ throw error;
1951
+ }
1952
+ }
1953
+ function closeRuntime() {
1954
+ runtime.relay?.close();
1955
+ runtime.server?.close();
1956
+ runtime.server = void 0;
1957
+ runtime.client = void 0;
1958
+ runtime.relay = void 0;
1959
+ runtime.openCodeConfig = void 0;
1960
+ runtime.toolNames = /* @__PURE__ */ new Set();
1961
+ runtime.mcpToolPrefixes = /* @__PURE__ */ new Set();
1870
1962
  }
1871
1963
  function buildOpenCodeConfig({
1872
1964
  start,