@ai-sdk/harness-claude-code 1.0.170 → 1.0.172

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,27 @@
1
1
  # @ai-sdk/harness-claude-code
2
2
 
3
+ ## 1.0.172
4
+
5
+ ### Patch Changes
6
+
7
+ - 4ab93bb: feat(harness-claude-code): add `toolHints` to mark host tools read-only or always-loaded
8
+ - ede06e3: carry out an approval answered after a resume instead of asking again
9
+ - 0808bf4: fix(harness-claude-code): preserve host tool numeric bounds, string lengths, array item counts, and defaults in Zod schemas
10
+ - Updated dependencies [033f8d9]
11
+ - Updated dependencies [e7a8988]
12
+ - Updated dependencies [2c12e25]
13
+ - Updated dependencies [61a315e]
14
+ - Updated dependencies [6eab0f7]
15
+ - @ai-sdk/harness@1.0.168
16
+ - @ai-sdk/provider-utils@5.0.71
17
+
18
+ ## 1.0.171
19
+
20
+ ### Patch Changes
21
+
22
+ - 726a1cc: fix(harness): copy bridge lockfile as `pnpm-lockfile.yaml` in `dist/` so `pnpm pack` includes it in published tarballs
23
+ - @ai-sdk/harness@1.0.167
24
+
3
25
  ## 1.0.170
4
26
 
5
27
  ### Patch Changes
@@ -1224,7 +1224,8 @@ function defaultUsage() {
1224
1224
  //#endregion
1225
1225
  //#region src/bridge/json-schema-to-zod.ts
1226
1226
  function jsonSchemaToZodObject(input) {
1227
- return toZodObject(isJsonSchemaObject(input) ? input : {});
1227
+ const schema = isJsonSchemaObject(input) ? input : {};
1228
+ return withJsonSchemaMetadata(toZodObject(schema), schema);
1228
1229
  }
1229
1230
  function toZodObject(schema) {
1230
1231
  const object = z.object(toZodShape(schema));
@@ -1248,7 +1249,22 @@ function toZodType(schema) {
1248
1249
  let zType = zodForConst(schema) ?? zodForEnum(schema) ?? zodForUnion(schema) ?? zodForType(schema);
1249
1250
  if (isNullable(schema)) zType = zType.nullable();
1250
1251
  if (schema.description) zType = zType.describe(schema.description);
1251
- return zType;
1252
+ return withJsonSchemaMetadata(zType, schema);
1253
+ }
1254
+ function withJsonSchemaMetadata(zType, schema) {
1255
+ const metadata = {};
1256
+ for (const key of [
1257
+ "minimum",
1258
+ "maximum",
1259
+ "exclusiveMinimum",
1260
+ "exclusiveMaximum",
1261
+ "minLength",
1262
+ "maxLength",
1263
+ "minItems",
1264
+ "maxItems",
1265
+ "default"
1266
+ ]) if (schema[key] !== void 0) metadata[key] = schema[key];
1267
+ return zType.meta(metadata);
1252
1268
  }
1253
1269
  function zodForType(schema) {
1254
1270
  const types = getNonNullTypes(schema);
@@ -1487,18 +1503,23 @@ function createPermissionOptions(input) {
1487
1503
  return {
1488
1504
  ...baseOptions,
1489
1505
  canUseTool: async (toolName, toolInput, options) => {
1490
- if (toolName.startsWith("mcp__harness-tools__")) return {
1491
- behavior: "allow",
1492
- updatedInput: toolInput
1493
- };
1494
- if (!inactiveNativeTools.has(toolName) && !nativeToolRequiresApproval({
1495
- nativeName: toolName,
1496
- permissionMode
1506
+ if (!needsHostApproval({
1507
+ toolName,
1508
+ permissionMode,
1509
+ inactiveNativeTools
1497
1510
  })) return {
1498
1511
  behavior: "allow",
1499
1512
  updatedInput: toolInput
1500
1513
  };
1501
1514
  const approvalId = options.toolUseID;
1515
+ if (input.approvalDecisions.get(approvalId)?.approved === true) {
1516
+ input.approvalDecisions.delete(approvalId);
1517
+ return {
1518
+ behavior: "allow",
1519
+ updatedInput: toolInput,
1520
+ toolUseID: approvalId
1521
+ };
1522
+ }
1502
1523
  input.approvalRequestedToolUseIds.add(approvalId);
1503
1524
  input.nativeToolCallNames.set(approvalId, toolName);
1504
1525
  if (!input.emittedToolCallIds.has(approvalId)) {
@@ -1582,6 +1603,41 @@ function createPermissionSettings(input) {
1582
1603
  sandbox: { autoAllowBashIfSandboxed: false }
1583
1604
  };
1584
1605
  }
1606
+ function needsHostApproval(input) {
1607
+ if (input.toolName.startsWith("mcp__harness-tools__")) return false;
1608
+ return input.inactiveNativeTools.has(input.toolName) || nativeToolRequiresApproval({
1609
+ nativeName: input.toolName,
1610
+ permissionMode: input.permissionMode
1611
+ });
1612
+ }
1613
+ function createApprovalPreToolUseHook(input) {
1614
+ return async (hookInput, toolUseID) => {
1615
+ const toolName = hookInput.tool_name;
1616
+ if (toolUseID == null || typeof toolName !== "string" || toolName === "AskUserQuestion") return {};
1617
+ const decision = input.decisions.get(toolUseID);
1618
+ if (decision != null) {
1619
+ input.nativeToolCallNames.set(toolUseID, toolName);
1620
+ if (!decision.approved) input.decisions.delete(toolUseID);
1621
+ return { hookSpecificOutput: {
1622
+ hookEventName: "PreToolUse",
1623
+ ...decision.approved ? { permissionDecision: "allow" } : {
1624
+ permissionDecision: "deny",
1625
+ permissionDecisionReason: decision.reason ?? "Denied"
1626
+ }
1627
+ } };
1628
+ }
1629
+ if (!needsHostApproval({
1630
+ toolName,
1631
+ permissionMode: input.permissionMode,
1632
+ inactiveNativeTools: input.inactiveNativeTools
1633
+ })) return {};
1634
+ input.deferredToolUseIds.add(toolUseID);
1635
+ return { hookSpecificOutput: {
1636
+ hookEventName: "PreToolUse",
1637
+ permissionDecision: "defer"
1638
+ } };
1639
+ };
1640
+ }
1585
1641
  function nativeToolRequiresApproval(input) {
1586
1642
  if (input.permissionMode === "allow-all") return false;
1587
1643
  const kind = NATIVE_TOOL_KINDS[input.nativeName] ?? "edit";
@@ -1606,70 +1662,75 @@ async function runTurn(start, turn) {
1606
1662
  name: "harness-tools",
1607
1663
  version: "1.0.0"
1608
1664
  });
1609
- for (const tool of start.tools) server.registerTool(tool.name, {
1610
- description: tool.description ?? "",
1611
- inputSchema: jsonSchemaToZodObject(tool.inputSchema)
1612
- }, async (...handlerArgs) => {
1613
- const [input, extra] = handlerArgs;
1614
- const metadataToolCallId = extra._meta?.["claudecode/toolUseId"];
1615
- const toolCallId = resolveMcpHandlerToolUseId({
1616
- state: streamEventState,
1617
- metadataToolUseId: typeof metadataToolCallId === "string" ? metadataToolCallId : void 0,
1618
- toolName: tool.name,
1619
- input
1620
- }) ?? randomUUID();
1621
- streamEventState.mcpHandlerCalls.set(toolCallId, {
1622
- toolName: tool.name,
1623
- input
1624
- });
1625
- if (!streamEventState.emittedToolCallIds.has(toolCallId)) {
1626
- streamEventState.emittedToolCallIds.add(toolCallId);
1627
- emit({
1628
- type: "tool-call",
1629
- toolCallId,
1665
+ for (const tool of start.tools) {
1666
+ const hints = start.toolHints?.[tool.name];
1667
+ server.registerTool(tool.name, {
1668
+ description: tool.description ?? "",
1669
+ inputSchema: jsonSchemaToZodObject(tool.inputSchema),
1670
+ ...hints?.readOnly == null ? {} : { annotations: { readOnlyHint: hints.readOnly } },
1671
+ ...hints?.alwaysLoad == null ? {} : { _meta: { "anthropic/alwaysLoad": hints.alwaysLoad } }
1672
+ }, async (...handlerArgs) => {
1673
+ const [input, extra] = handlerArgs;
1674
+ const metadataToolCallId = extra._meta?.["claudecode/toolUseId"];
1675
+ const toolCallId = resolveMcpHandlerToolUseId({
1676
+ state: streamEventState,
1677
+ metadataToolUseId: typeof metadataToolCallId === "string" ? metadataToolCallId : void 0,
1678
+ toolName: tool.name,
1679
+ input
1680
+ }) ?? randomUUID();
1681
+ streamEventState.mcpHandlerCalls.set(toolCallId, {
1630
1682
  toolName: tool.name,
1631
- input: JSON.stringify(input),
1632
- providerExecuted: false
1683
+ input
1633
1684
  });
1634
- markWaitingOnHostInput({
1635
- state: streamEventState,
1636
- emit,
1637
- toolUseId: toolCallId
1685
+ if (!streamEventState.emittedToolCallIds.has(toolCallId)) {
1686
+ streamEventState.emittedToolCallIds.add(toolCallId);
1687
+ emit({
1688
+ type: "tool-call",
1689
+ toolCallId,
1690
+ toolName: tool.name,
1691
+ input: JSON.stringify(input),
1692
+ providerExecuted: false
1693
+ });
1694
+ markWaitingOnHostInput({
1695
+ state: streamEventState,
1696
+ emit,
1697
+ toolUseId: toolCallId
1698
+ });
1699
+ }
1700
+ const { output, isError, toolResult } = await turn.requestToolResult(toolCallId).finally(() => {
1701
+ clearWaitingOnHostInput({
1702
+ state: streamEventState,
1703
+ toolUseId: toolCallId
1704
+ });
1705
+ if (!streamEventState.mcpToolCalls.has(toolCallId)) streamEventState.pendingStepToolUseIds.delete(toolCallId);
1638
1706
  });
1639
- }
1640
- const { output, isError, toolResult } = await turn.requestToolResult(toolCallId).finally(() => {
1641
- clearWaitingOnHostInput({
1642
- state: streamEventState,
1643
- toolUseId: toolCallId
1707
+ emit({
1708
+ type: "tool-result",
1709
+ toolCallId,
1710
+ toolName: tool.name,
1711
+ result: output ?? null,
1712
+ isError: !!isError
1644
1713
  });
1645
- if (!streamEventState.mcpToolCalls.has(toolCallId)) streamEventState.pendingStepToolUseIds.delete(toolCallId);
1646
- });
1647
- emit({
1648
- type: "tool-result",
1649
- toolCallId,
1650
- toolName: tool.name,
1651
- result: output ?? null,
1652
- isError: !!isError
1653
- });
1654
- if (toolResult != null) {
1655
- const converted = convertHarnessToolModelOutput({ output: toolResult.output });
1714
+ if (toolResult != null) {
1715
+ const converted = convertHarnessToolModelOutput({ output: toolResult.output });
1716
+ return {
1717
+ content: converted.content.map((part) => part.type === "text" ? part : {
1718
+ type: "image",
1719
+ data: part.data,
1720
+ mimeType: part.mediaType
1721
+ }),
1722
+ isError: isError === true || converted.isError
1723
+ };
1724
+ }
1656
1725
  return {
1657
- content: converted.content.map((part) => part.type === "text" ? part : {
1658
- type: "image",
1659
- data: part.data,
1660
- mimeType: part.mediaType
1661
- }),
1662
- isError: isError === true || converted.isError
1726
+ content: [{
1727
+ type: "text",
1728
+ text: JSON.stringify(output ?? null)
1729
+ }],
1730
+ isError
1663
1731
  };
1664
- }
1665
- return {
1666
- content: [{
1667
- type: "text",
1668
- text: JSON.stringify(output ?? null)
1669
- }],
1670
- isError
1671
- };
1672
- });
1732
+ });
1733
+ }
1673
1734
  mcpServers["harness-tools"] = {
1674
1735
  type: "sdk",
1675
1736
  name: "harness-tools",
@@ -1693,7 +1754,10 @@ async function runTurn(start, turn) {
1693
1754
  const skillsOption = toClaudeSkillsOption(start.skills);
1694
1755
  const nativeTools = resolveNativeTools(start.builtinToolFiltering);
1695
1756
  const inactiveNativeTools = resolveInactiveNativeTools(start.builtinToolFiltering);
1757
+ const permissionMode = start.permissionMode ?? "allow-all";
1758
+ const approvalDecisions = /* @__PURE__ */ new Map();
1696
1759
  const permissionOptions = createPermissionOptions({
1760
+ approvalDecisions,
1697
1761
  start,
1698
1762
  inactiveNativeTools,
1699
1763
  turn,
@@ -1711,6 +1775,14 @@ async function runTurn(start, turn) {
1711
1775
  approvalRequestedToolUseIds: streamEventState.approvalRequestedToolUseIds,
1712
1776
  emittedToolCallIds: streamEventState.emittedToolCallIds
1713
1777
  });
1778
+ const deferredToolUseIds = /* @__PURE__ */ new Set();
1779
+ const approvalPreToolUseHook = createApprovalPreToolUseHook({
1780
+ permissionMode,
1781
+ inactiveNativeTools: new Set(inactiveNativeTools),
1782
+ decisions: approvalDecisions,
1783
+ deferredToolUseIds,
1784
+ nativeToolCallNames: streamEventState.nativeToolCallNames
1785
+ });
1714
1786
  const questionPreToolUseHook = createQuestionPreToolUseHook({
1715
1787
  turn,
1716
1788
  emit,
@@ -1725,7 +1797,7 @@ async function runTurn(start, turn) {
1725
1797
  toolUseId
1726
1798
  })
1727
1799
  });
1728
- const q = claudeSdk.query({
1800
+ const queryArgs = {
1729
1801
  prompt: queryInput.input,
1730
1802
  options: {
1731
1803
  ...start.model ? { model: start.model } : {},
@@ -1750,7 +1822,7 @@ async function runTurn(start, turn) {
1750
1822
  } } : {},
1751
1823
  includePartialMessages: true,
1752
1824
  hooks: {
1753
- PreToolUse: [{
1825
+ PreToolUse: [...permissionMode === "allow-all" ? [] : [{ hooks: [approvalPreToolUseHook] }], {
1754
1826
  matcher: "AskUserQuestion",
1755
1827
  hooks: [questionPreToolUseHook],
1756
1828
  ...start.questionTimeoutMs !== void 0 ? { timeout: Math.ceil(start.questionTimeoutMs / 1e3) } : {}
@@ -1766,14 +1838,62 @@ async function runTurn(start, turn) {
1766
1838
  cwd: workdir,
1767
1839
  abortSignal: abortCtl.signal
1768
1840
  }
1841
+ };
1842
+ let deferredToolUseId = start.deferredToolUseId;
1843
+ let resumingDeferredCall = false;
1844
+ let q = deferredToolUseId == null ? claudeSdk.query(queryArgs) : void 0;
1845
+ const hostAborted = new Promise((resolve) => {
1846
+ if (abortCtl.signal.aborted) resolve(void 0);
1847
+ abortCtl.signal.addEventListener("abort", () => resolve(void 0), { once: true });
1769
1848
  });
1770
1849
  gracefulAbort = () => {
1771
1850
  hardAbortTimer = setTimeout(() => abortCtl.abort(), 5e3);
1772
1851
  hardAbortTimer.unref?.();
1773
- Promise.resolve().then(() => q.interrupt()).catch(() => abortCtl.abort());
1852
+ Promise.resolve().then(() => q?.interrupt()).catch(() => abortCtl.abort());
1774
1853
  };
1775
1854
  let turnUsage;
1776
1855
  let totalCostUsd;
1856
+ let deferredDecision;
1857
+ const requestDeferredApproval = (call) => {
1858
+ for (const droppedToolUseId of deferredToolUseIds) {
1859
+ if (droppedToolUseId === call.toolUseId) continue;
1860
+ const nativeName = streamEventState.nativeToolCallNames.get(droppedToolUseId) ?? "unknown";
1861
+ emit({
1862
+ type: "tool-result",
1863
+ toolCallId: droppedToolUseId,
1864
+ toolName: toCommonName(nativeName),
1865
+ result: "Claude Code can wait for only one approval at a time, so this call did not run.",
1866
+ isError: true
1867
+ });
1868
+ streamEventState.pendingStepToolUseIds.delete(droppedToolUseId);
1869
+ }
1870
+ deferredToolUseIds.clear();
1871
+ streamEventState.approvalRequestedToolUseIds.add(call.toolUseId);
1872
+ streamEventState.nativeToolCallNames.set(call.toolUseId, call.toolName);
1873
+ if (!streamEventState.emittedToolCallIds.has(call.toolUseId)) {
1874
+ streamEventState.emittedToolCallIds.add(call.toolUseId);
1875
+ emit({
1876
+ type: "tool-call",
1877
+ toolCallId: call.toolUseId,
1878
+ toolName: toCommonName(call.toolName),
1879
+ nativeName: call.toolName,
1880
+ input: JSON.stringify(call.toolInput ?? {}),
1881
+ providerExecuted: true,
1882
+ ...isExternalMcpTool(call.toolName) ? { dynamic: true } : {}
1883
+ });
1884
+ }
1885
+ deferredDecision = turn.requestToolApproval(call.toolUseId);
1886
+ emit({
1887
+ type: "tool-approval-request",
1888
+ approvalId: call.toolUseId,
1889
+ toolCallId: call.toolUseId
1890
+ });
1891
+ markWaitingOnHostInput({
1892
+ state: streamEventState,
1893
+ emit,
1894
+ toolUseId: call.toolUseId
1895
+ });
1896
+ };
1777
1897
  let emittedTerminalError = false;
1778
1898
  let emittedTerminalFinish = false;
1779
1899
  const emitTerminalError = (message) => {
@@ -1796,14 +1916,59 @@ async function runTurn(start, turn) {
1796
1916
  onCompactionBoundary: (boundary) => compaction.onBoundary(boundary),
1797
1917
  toCommonName
1798
1918
  });
1919
+ async function* messages() {
1920
+ for (;;) {
1921
+ if (deferredToolUseId != null) {
1922
+ const toolUseId = deferredToolUseId;
1923
+ const decision = await Promise.race([deferredDecision ?? turn.requestToolApproval(toolUseId), hostAborted]).finally(() => clearWaitingOnHostInput({
1924
+ state: streamEventState,
1925
+ toolUseId
1926
+ }));
1927
+ deferredDecision = void 0;
1928
+ if (decision == null || abortCtl.signal.aborted) return;
1929
+ approvalDecisions.set(toolUseId, decision);
1930
+ deferredToolUseId = void 0;
1931
+ resumingDeferredCall = true;
1932
+ q = claudeSdk.query({
1933
+ prompt: withoutInitialMessage(queryInput.input),
1934
+ options: {
1935
+ ...queryArgs.options,
1936
+ ...lastClaudeSessionId != null ? {
1937
+ continue: void 0,
1938
+ resume: lastClaudeSessionId
1939
+ } : {}
1940
+ }
1941
+ });
1942
+ }
1943
+ for await (const msg of q) {
1944
+ yield msg;
1945
+ if (deferredToolUseId != null) break;
1946
+ }
1947
+ if (deferredToolUseId == null || abortCtl.signal.aborted) return;
1948
+ queryInput.retire();
1949
+ await disposeQuery(q);
1950
+ }
1951
+ }
1799
1952
  try {
1800
- for await (const msg of q) {
1953
+ for await (const msg of messages()) {
1801
1954
  if (abortCtl.signal.aborted) break;
1802
1955
  const type = msg.type;
1803
1956
  if (type === "command_lifecycle") queryInput.handleLifecycle(msg);
1804
1957
  const sessionId = msg.session_id;
1805
1958
  if (typeof sessionId === "string" && sessionId.length > 0) lastClaudeSessionId = sessionId;
1806
1959
  emitStreamEvent(msg);
1960
+ if (type === "result" && msg.terminal_reason === "tool_deferred" && msg.deferred_tool_use?.id != null) {
1961
+ const harnessUsage = mapUsage(msg.usage ?? msg.message?.usage);
1962
+ if (harnessUsage) turnUsage = addUsage(turnUsage, harnessUsage);
1963
+ if (typeof msg.total_cost_usd === "number") totalCostUsd = msg.total_cost_usd;
1964
+ deferredToolUseId = msg.deferred_tool_use.id;
1965
+ requestDeferredApproval({
1966
+ toolUseId: msg.deferred_tool_use.id,
1967
+ toolName: msg.deferred_tool_use.name,
1968
+ toolInput: msg.deferred_tool_use.input
1969
+ });
1970
+ continue;
1971
+ }
1807
1972
  if (type === "result") {
1808
1973
  if (msg.subtype === "success") {
1809
1974
  if (msg.is_error) {
@@ -1839,7 +2004,7 @@ async function runTurn(start, turn) {
1839
2004
  emit,
1840
2005
  usage: streamEventState.pendingStepUsage ?? harnessUsage
1841
2006
  });
1842
- if (!queryInput.answersSentMessage(msg)) continue;
2007
+ if (!resumingDeferredCall && !queryInput.answersSentMessage(msg)) continue;
1843
2008
  queryInput.observeResult();
1844
2009
  if (!queryInput.hasActiveUserMessages()) {
1845
2010
  queryInput.close();
@@ -1864,9 +2029,7 @@ async function runTurn(start, turn) {
1864
2029
  if (hardAbortTimer != null) clearTimeout(hardAbortTimer);
1865
2030
  turn.abortSignal.removeEventListener("abort", onHostAbort);
1866
2031
  queryInput.close();
1867
- try {
1868
- await q.return?.(void 0);
1869
- } catch {}
2032
+ await disposeQuery(q);
1870
2033
  }
1871
2034
  if (emittedTerminalError) return;
1872
2035
  emittedTerminalFinish = true;
@@ -1923,6 +2086,24 @@ function createQueryInput({ initialUserMessage, userMessages, abortSignal }) {
1923
2086
  ...options.priority == null ? {} : { priority: options.priority }
1924
2087
  });
1925
2088
  const messageIterator = userMessages[Symbol.asyncIterator]();
2089
+ let liveInputId = 0;
2090
+ let bufferedMessage;
2091
+ let pulling;
2092
+ const takeMessage = async (inputId) => {
2093
+ for (;;) {
2094
+ if (inputId !== liveInputId) return void 0;
2095
+ if (bufferedMessage != null) {
2096
+ const message = bufferedMessage;
2097
+ bufferedMessage = void 0;
2098
+ return message;
2099
+ }
2100
+ pulling ??= messageIterator.next().then((result) => {
2101
+ bufferedMessage = result;
2102
+ pulling = void 0;
2103
+ });
2104
+ await pulling;
2105
+ }
2106
+ };
1926
2107
  return {
1927
2108
  close,
1928
2109
  handleLifecycle: (message) => {
@@ -1947,10 +2128,14 @@ function createQueryInput({ initialUserMessage, userMessages, abortSignal }) {
1947
2128
  observeResult: () => {
1948
2129
  observedResult = true;
1949
2130
  },
2131
+ retire: () => {
2132
+ liveInputId++;
2133
+ },
1950
2134
  get hasObservedResult() {
1951
2135
  return observedResult;
1952
2136
  },
1953
2137
  input: { [Symbol.asyncIterator]() {
2138
+ const inputId = ++liveInputId;
1954
2139
  let sentInitial = false;
1955
2140
  return { async next() {
1956
2141
  if (closed || abortSignal.aborted) return {
@@ -1967,8 +2152,8 @@ function createQueryInput({ initialUserMessage, userMessages, abortSignal }) {
1967
2152
  done: false
1968
2153
  };
1969
2154
  }
1970
- const nextMessage = await messageIterator.next();
1971
- if (nextMessage.done) return {
2155
+ const nextMessage = await takeMessage(inputId);
2156
+ if (nextMessage == null || nextMessage.done) return {
1972
2157
  value: void 0,
1973
2158
  done: true
1974
2159
  };
@@ -1986,6 +2171,24 @@ function createQueryInput({ initialUserMessage, userMessages, abortSignal }) {
1986
2171
  } }
1987
2172
  };
1988
2173
  }
2174
+ function withoutInitialMessage(input) {
2175
+ return { [Symbol.asyncIterator]() {
2176
+ const iterator = input[Symbol.asyncIterator]();
2177
+ let skipped = false;
2178
+ return { async next() {
2179
+ if (!skipped) {
2180
+ skipped = true;
2181
+ await iterator.next();
2182
+ }
2183
+ return iterator.next();
2184
+ } };
2185
+ } };
2186
+ }
2187
+ async function disposeQuery(query) {
2188
+ try {
2189
+ await query?.return?.(void 0);
2190
+ } catch {}
2191
+ }
1989
2192
  function addUsage(total, usage) {
1990
2193
  if (total == null) return usage;
1991
2194
  const result = { ...total };