@qvac/harness 0.4.0 → 0.5.0

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.
Files changed (299) hide show
  1. package/CHANGELOG.md +689 -141
  2. package/README.md +29 -7
  3. package/dist/harness.bundle +71 -50
  4. package/dist-lib/index.d.ts +36 -39
  5. package/dist-lib/index.js +279 -114
  6. package/dist-lib/lib/audio-transcode-bare.d.ts +2 -2
  7. package/dist-lib/lib/audio-transcode-bare.js +28 -18
  8. package/dist-lib/lib/audio-transcode-node.d.ts +2 -2
  9. package/dist-lib/lib/capabilities/audio-resample.d.ts +7 -6
  10. package/dist-lib/lib/capabilities/audio-resample.js +30 -18
  11. package/dist-lib/lib/capabilities/completion.d.ts +20 -19
  12. package/dist-lib/lib/capabilities/completion.js +193 -132
  13. package/dist-lib/lib/capabilities/download.d.ts +6 -6
  14. package/dist-lib/lib/capabilities/download.js +15 -8
  15. package/dist-lib/lib/capabilities/embed.js +2 -1
  16. package/dist-lib/lib/capabilities/enhance.d.ts +6 -1
  17. package/dist-lib/lib/capabilities/enhance.js +7 -4
  18. package/dist-lib/lib/capabilities/invoke.js +7 -4
  19. package/dist-lib/lib/capabilities/kv-cache.js +2 -1
  20. package/dist-lib/lib/capabilities/preview-model-source.d.ts +9 -7
  21. package/dist-lib/lib/capabilities/preview-model-source.js +80 -28
  22. package/dist-lib/lib/capabilities/speech-text.js +5 -4
  23. package/dist-lib/lib/capabilities/tool-selection.js +10 -9
  24. package/dist-lib/lib/capabilities/tool-turns.js +30 -16
  25. package/dist-lib/lib/capabilities/usage-breakdown.js +2 -1
  26. package/dist-lib/lib/capabilities/voice.d.ts +5 -1
  27. package/dist-lib/lib/capabilities/voice.js +22 -12
  28. package/dist-lib/lib/connect.d.ts +11 -32
  29. package/dist-lib/lib/connect.js +152 -112
  30. package/dist-lib/lib/context-window.js +25 -21
  31. package/dist-lib/lib/contract-types.d.ts +22 -15
  32. package/dist-lib/lib/diagram-repair.d.ts +4 -4
  33. package/dist-lib/lib/diagram-repair.js +6 -3
  34. package/dist-lib/lib/docx/index.d.ts +3 -2
  35. package/dist-lib/lib/{error-fields.d.ts → guards.d.ts} +1 -0
  36. package/dist-lib/lib/{error-fields.js → guards.js} +3 -0
  37. package/dist-lib/lib/hardware/capability-probe.js +20 -10
  38. package/dist-lib/lib/hardware/gpu-classify.js +6 -3
  39. package/dist-lib/lib/hardware/gpu-probe-addon.js +8 -4
  40. package/dist-lib/lib/hardware/gpu-probe.js +4 -2
  41. package/dist-lib/lib/hardware/gpu-stats.native.cjs +8 -9
  42. package/dist-lib/lib/hardware/parsers.js +8 -4
  43. package/dist-lib/lib/helpers/buffer-burst.js +4 -2
  44. package/dist-lib/lib/helpers/control-tokens.js +4 -2
  45. package/dist-lib/lib/helpers/join-guard.d.ts +2 -2
  46. package/dist-lib/lib/helpers/join-guard.js +4 -2
  47. package/dist-lib/lib/helpers/load-stall.js +4 -2
  48. package/dist-lib/lib/helpers/markup-stream-filter.d.ts +2 -2
  49. package/dist-lib/lib/helpers/markup-stream-filter.js +6 -3
  50. package/dist-lib/lib/helpers/race-abort.js +2 -1
  51. package/dist-lib/lib/helpers/race-timeout.d.ts +5 -0
  52. package/dist-lib/lib/helpers/race-timeout.js +14 -0
  53. package/dist-lib/lib/helpers/run-outcome.d.ts +6 -8
  54. package/dist-lib/lib/helpers/run-outcome.js +36 -20
  55. package/dist-lib/lib/helpers/spawn-path.js +6 -3
  56. package/dist-lib/lib/helpers/text-coalescer.js +6 -3
  57. package/dist-lib/lib/helpers/thinking.js +38 -45
  58. package/dist-lib/lib/helpers/tool-call-markup.d.ts +9 -7
  59. package/dist-lib/lib/helpers/tool-call-markup.js +36 -20
  60. package/dist-lib/lib/helpers/tool-intent.d.ts +3 -2
  61. package/dist-lib/lib/helpers/tool-intent.js +4 -2
  62. package/dist-lib/lib/helpers/tool-label.js +18 -9
  63. package/dist-lib/lib/hooks/built-in/arg-repair.js +23 -13
  64. package/dist-lib/lib/hooks/built-in/egress.js +2 -1
  65. package/dist-lib/lib/hooks/built-in/skill-catalog.js +2 -1
  66. package/dist-lib/lib/hooks/pipeline.d.ts +5 -4
  67. package/dist-lib/lib/hooks/pipeline.js +6 -3
  68. package/dist-lib/lib/hooks/run.js +12 -8
  69. package/dist-lib/lib/model-download-progress.js +10 -8
  70. package/dist-lib/lib/models/context.d.ts +1 -1
  71. package/dist-lib/lib/models/context.js +5 -1
  72. package/dist-lib/lib/models/custom-model-cache.d.ts +10 -1
  73. package/dist-lib/lib/models/custom-model-cache.js +43 -15
  74. package/dist-lib/lib/models/gguf-header.d.ts +3 -2
  75. package/dist-lib/lib/models/gguf-header.js +44 -22
  76. package/dist-lib/lib/models/idle-unload.d.ts +14 -0
  77. package/dist-lib/lib/models/idle-unload.js +51 -0
  78. package/dist-lib/lib/models/kv-cache.d.ts +3 -2
  79. package/dist-lib/lib/models/kv-cache.js +4 -3
  80. package/dist-lib/lib/models/llm-presets.d.ts +2 -2
  81. package/dist-lib/lib/models/llm-presets.js +4 -2
  82. package/dist-lib/lib/models/model-catalog-constants.js +3 -2
  83. package/dist-lib/lib/models/model-catalog.d.ts +13 -20
  84. package/dist-lib/lib/models/model-catalog.js +59 -31
  85. package/dist-lib/lib/models/model-delete.js +18 -8
  86. package/dist-lib/lib/models/model-handle.js +2 -1
  87. package/dist-lib/lib/models/model-list.d.ts +8 -3
  88. package/dist-lib/lib/models/model-list.js +11 -6
  89. package/dist-lib/lib/models/model-pool.d.ts +44 -10
  90. package/dist-lib/lib/models/model-pool.js +47 -42
  91. package/dist-lib/lib/models/model-source.js +10 -5
  92. package/dist-lib/lib/models/music-catalog.d.ts +2 -2
  93. package/dist-lib/lib/models/nmt-catalog.d.ts +4 -3
  94. package/dist-lib/lib/models/nmt-catalog.js +10 -5
  95. package/dist-lib/lib/models/opencl-cache.d.ts +6 -1
  96. package/dist-lib/lib/models/opencl-cache.js +5 -3
  97. package/dist-lib/lib/models/sdk-faults.d.ts +11 -8
  98. package/dist-lib/lib/models/sdk-faults.js +9 -6
  99. package/dist-lib/lib/models/shards.d.ts +11 -0
  100. package/dist-lib/lib/models/shards.js +15 -0
  101. package/dist-lib/lib/models/tool-dialect.js +10 -5
  102. package/dist-lib/lib/no-redirect-fetch-bare.d.ts +3 -3
  103. package/dist-lib/lib/no-redirect-fetch-bare.js +1 -1
  104. package/dist-lib/lib/no-redirect-fetch-impl.js +6 -3
  105. package/dist-lib/lib/no-redirect-fetch-node.d.ts +1 -1
  106. package/dist-lib/lib/no-redirect-fetch-node.js +9 -9
  107. package/dist-lib/lib/office/index.d.ts +3 -2
  108. package/dist-lib/lib/office/python.d.ts +3 -2
  109. package/dist-lib/lib/office/python.js +2 -1
  110. package/dist-lib/lib/prompt.d.ts +5 -4
  111. package/dist-lib/lib/prompt.js +8 -4
  112. package/dist-lib/lib/queue.js +10 -5
  113. package/dist-lib/lib/resolution-detector.js +21 -11
  114. package/dist-lib/lib/rpc-session.js +2 -1
  115. package/dist-lib/lib/sdk-loader.js +2 -1
  116. package/dist-lib/lib/sdk-storage.js +4 -2
  117. package/dist-lib/lib/serve.js +110 -66
  118. package/dist-lib/lib/spawn.js +7 -4
  119. package/dist-lib/lib/tmp-path.d.ts +7 -6
  120. package/dist-lib/lib/tool-call-display.d.ts +2 -2
  121. package/dist-lib/lib/tools/create-documents.js +18 -10
  122. package/dist-lib/lib/tools/edit-documents.js +23 -13
  123. package/dist-lib/lib/tools/edit-image.d.ts +2 -2
  124. package/dist-lib/lib/tools/edit-image.js +60 -36
  125. package/dist-lib/lib/tools/exec/adapters/adapter.d.ts +10 -10
  126. package/dist-lib/lib/tools/exec/adapters/python/attachments.d.ts +17 -11
  127. package/dist-lib/lib/tools/exec/adapters/python/attachments.js +53 -40
  128. package/dist-lib/lib/tools/exec/adapters/python/create-effect.d.ts +2 -2
  129. package/dist-lib/lib/tools/exec/adapters/python/create-effect.js +60 -32
  130. package/dist-lib/lib/tools/exec/adapters/python/guarded-fetch.d.ts +33 -22
  131. package/dist-lib/lib/tools/exec/adapters/python/guarded-fetch.js +58 -29
  132. package/dist-lib/lib/tools/exec/adapters/python/interrupt-timer.d.ts +2 -2
  133. package/dist-lib/lib/tools/exec/adapters/python/loader.js +23 -12
  134. package/dist-lib/lib/tools/exec/adapters/python/memfs.d.ts +13 -11
  135. package/dist-lib/lib/tools/exec/adapters/python/memfs.js +10 -5
  136. package/dist-lib/lib/tools/exec/adapters/python/net-shim.js +3 -1
  137. package/dist-lib/lib/tools/exec/adapters/python/output-policy.d.ts +6 -4
  138. package/dist-lib/lib/tools/exec/adapters/python/output-policy.js +20 -10
  139. package/dist-lib/lib/tools/exec/adapters/python/pyodide.d.ts +2 -2
  140. package/dist-lib/lib/tools/exec/adapters/python/pyodide.js +14 -7
  141. package/dist-lib/lib/tools/exec/adapters/python/python-adapter.d.ts +41 -34
  142. package/dist-lib/lib/tools/exec/adapters/python/python-adapter.js +316 -166
  143. package/dist-lib/lib/tools/exec/adapters/python/run-session.d.ts +9 -8
  144. package/dist-lib/lib/tools/exec/adapters/python/run-session.js +56 -28
  145. package/dist-lib/lib/tools/exec/adapters/python/wheels.d.ts +8 -10
  146. package/dist-lib/lib/tools/exec/adapters/python/wheels.js +22 -11
  147. package/dist-lib/lib/tools/exec/adapters/python/worker/client.d.ts +3 -2
  148. package/dist-lib/lib/tools/exec/adapters/python/worker/client.js +41 -26
  149. package/dist-lib/lib/tools/exec/adapters/python/worker/entry.js +27 -18
  150. package/dist-lib/lib/tools/exec/adapters/python/worker/protocol.d.ts +2 -2
  151. package/dist-lib/lib/tools/exec/adapters/python/worker/protocol.js +14 -13
  152. package/dist-lib/lib/tools/exec/adapters/python/worker/spawn-node.d.ts +4 -4
  153. package/dist-lib/lib/tools/exec/adapters/python/worker/spawn-node.js +10 -5
  154. package/dist-lib/lib/tools/exec/adapters/shell/shell-adapter.d.ts +4 -4
  155. package/dist-lib/lib/tools/exec/adapters/shell/shell-adapter.js +2 -1
  156. package/dist-lib/lib/tools/exec/obsidian/cli-process.d.ts +6 -1
  157. package/dist-lib/lib/tools/exec/obsidian/cli-process.js +8 -5
  158. package/dist-lib/lib/tools/exec/obsidian/cli.d.ts +6 -6
  159. package/dist-lib/lib/tools/exec/obsidian/cli.js +4 -4
  160. package/dist-lib/lib/tools/exec/obsidian/command.d.ts +3 -2
  161. package/dist-lib/lib/tools/exec/obsidian/command.js +6 -3
  162. package/dist-lib/lib/tools/exec/obsidian/output.js +2 -1
  163. package/dist-lib/lib/tools/exec/obsidian/route.d.ts +4 -6
  164. package/dist-lib/lib/tools/exec/obsidian/route.js +17 -11
  165. package/dist-lib/lib/tools/exec/obsidian/safe-path.js +2 -1
  166. package/dist-lib/lib/tools/exec/obsidian/vault-create.js +15 -7
  167. package/dist-lib/lib/tools/exec/obsidian/vault-paths.d.ts +2 -2
  168. package/dist-lib/lib/tools/exec/obsidian/vault-paths.js +20 -10
  169. package/dist-lib/lib/tools/exec/obsidian/vault-read.js +20 -13
  170. package/dist-lib/lib/tools/exec/obsidian/vault-write.js +24 -12
  171. package/dist-lib/lib/tools/exec/runner.d.ts +14 -14
  172. package/dist-lib/lib/tools/exec/runner.js +5 -3
  173. package/dist-lib/lib/tools/exec/scope.js +52 -28
  174. package/dist-lib/lib/tools/exec/shell-argv.js +31 -18
  175. package/dist-lib/lib/tools/exec/shell-guidance.d.ts +6 -1
  176. package/dist-lib/lib/tools/exec/shell-guidance.js +35 -20
  177. package/dist-lib/lib/tools/exec/video-tools.js +2 -2
  178. package/dist-lib/lib/tools/exec.d.ts +6 -8
  179. package/dist-lib/lib/tools/exec.js +113 -54
  180. package/dist-lib/lib/tools/file-glob.d.ts +4 -5
  181. package/dist-lib/lib/tools/file-glob.js +16 -11
  182. package/dist-lib/lib/tools/fs/glob.js +13 -18
  183. package/dist-lib/lib/tools/fs/remote-protocol.d.ts +10 -10
  184. package/dist-lib/lib/tools/fs/remote.d.ts +3 -2
  185. package/dist-lib/lib/tools/fs/remote.js +13 -7
  186. package/dist-lib/lib/tools/fs/scope.d.ts +8 -3
  187. package/dist-lib/lib/tools/fs/scope.js +20 -12
  188. package/dist-lib/lib/tools/fs/walk.js +6 -3
  189. package/dist-lib/lib/tools/fs/write.d.ts +3 -2
  190. package/dist-lib/lib/tools/generate-image.d.ts +11 -9
  191. package/dist-lib/lib/tools/generate-image.js +73 -37
  192. package/dist-lib/lib/tools/generate-music.d.ts +22 -11
  193. package/dist-lib/lib/tools/generate-music.js +79 -48
  194. package/dist-lib/lib/tools/grep.js +66 -41
  195. package/dist-lib/lib/tools/http-request/encode-fields.js +18 -9
  196. package/dist-lib/lib/tools/http-request/{utils.js → request.js} +20 -11
  197. package/dist-lib/lib/tools/http-request/truncate-response.js +57 -46
  198. package/dist-lib/lib/tools/http-request.d.ts +1 -1
  199. package/dist-lib/lib/tools/http-request.js +33 -18
  200. package/dist-lib/lib/tools/mcp/protocol.d.ts +53 -0
  201. package/dist-lib/lib/tools/mcp/{utils.js → protocol.js} +45 -23
  202. package/dist-lib/lib/tools/mcp-call.d.ts +1 -1
  203. package/dist-lib/lib/tools/mcp-call.js +37 -16
  204. package/dist-lib/lib/tools/operations/builders.js +10 -6
  205. package/dist-lib/lib/tools/operations/compile.js +20 -10
  206. package/dist-lib/lib/tools/operations/decoders.js +12 -6
  207. package/dist-lib/lib/tools/operations/gmail-message.js +3 -2
  208. package/dist-lib/lib/tools/outbound-guard.d.ts +4 -3
  209. package/dist-lib/lib/tools/outbound-guard.js +14 -8
  210. package/dist-lib/lib/tools/private-ip.js +8 -7
  211. package/dist-lib/lib/tools/rag-search.js +14 -7
  212. package/dist-lib/lib/tools/read-files.js +23 -20
  213. package/dist-lib/lib/tools/skill.js +19 -10
  214. package/dist-lib/lib/tools/skills/auth-resolver.d.ts +11 -18
  215. package/dist-lib/lib/tools/skills/auth-resolver.js +30 -18
  216. package/dist-lib/lib/tools/skills/bin-check.d.ts +3 -2
  217. package/dist-lib/lib/tools/skills/bin-check.js +10 -3
  218. package/dist-lib/lib/tools/skills/bundled-dir.js +20 -10
  219. package/dist-lib/lib/tools/skills/bundled-hash.d.ts +3 -2
  220. package/dist-lib/lib/tools/skills/bundled-hash.js +6 -1
  221. package/dist-lib/lib/tools/skills/catalog.d.ts +3 -2
  222. package/dist-lib/lib/tools/skills/catalog.js +33 -28
  223. package/dist-lib/lib/tools/skills/cli-argv.d.ts +3 -2
  224. package/dist-lib/lib/tools/skills/cli-argv.js +55 -52
  225. package/dist-lib/lib/tools/skills/cli-schema-check.js +21 -10
  226. package/dist-lib/lib/tools/skills/cli-schema-load.js +28 -20
  227. package/dist-lib/lib/tools/skills/cli-schema-types.d.ts +6 -6
  228. package/dist-lib/lib/tools/skills/cli-schema.js +2 -1
  229. package/dist-lib/lib/tools/skills/credential-check.d.ts +6 -3
  230. package/dist-lib/lib/tools/skills/credential-check.js +24 -12
  231. package/dist-lib/lib/tools/skills/credential-grants.js +1 -6
  232. package/dist-lib/lib/tools/skills/credential-health.d.ts +5 -1
  233. package/dist-lib/lib/tools/skills/credential-health.js +5 -3
  234. package/dist-lib/lib/tools/skills/frontmatter-parser.js +10 -5
  235. package/dist-lib/lib/tools/skills/manifest-parse.js +84 -64
  236. package/dist-lib/lib/tools/skills/mention.js +7 -6
  237. package/dist-lib/lib/tools/skills/obsidian-readiness.d.ts +2 -2
  238. package/dist-lib/lib/tools/skills/obsidian-readiness.js +11 -3
  239. package/dist-lib/lib/tools/skills/overlay-crud.d.ts +6 -4
  240. package/dist-lib/lib/tools/skills/overlay-crud.js +12 -6
  241. package/dist-lib/lib/tools/skills/overlay-dir.js +4 -2
  242. package/dist-lib/lib/tools/skills/overlay-watch.d.ts +3 -2
  243. package/dist-lib/lib/tools/skills/overlay-watch.js +8 -4
  244. package/dist-lib/lib/tools/skills/setup-routes.js +1 -3
  245. package/dist-lib/lib/tools/skills/skill-settings.js +4 -1
  246. package/dist-lib/lib/tools/skills/skill-state.d.ts +6 -11
  247. package/dist-lib/lib/tools/skills/skill-state.js +48 -29
  248. package/dist-lib/lib/tools/skills/tool-grants.js +6 -3
  249. package/dist-lib/lib/tools/toolsets.js +2 -1
  250. package/dist-lib/lib/tools/translate.d.ts +4 -5
  251. package/dist-lib/lib/tools/translate.js +31 -14
  252. package/dist-lib/lib/tools/url-guard.js +2 -1
  253. package/dist-lib/lib/tools/weather-lookup/place.js +8 -4
  254. package/dist-lib/lib/tools/weather-lookup/report.d.ts +7 -1
  255. package/dist-lib/lib/tools/weather-lookup/report.js +46 -9
  256. package/dist-lib/lib/tools/weather-lookup.js +18 -12
  257. package/dist-lib/lib/tools/web-fetch.js +47 -24
  258. package/dist-lib/lib/tools/web-search.js +8 -3
  259. package/dist-lib/lib/validating-lookup.d.ts +4 -4
  260. package/dist-lib/lib/wav-encode.d.ts +1 -1
  261. package/dist-lib/lib/wav-encode.js +11 -10
  262. package/dist-lib/lib/web-fetch/embedded-state.js +24 -12
  263. package/dist-lib/lib/web-fetch/extract.js +4 -2
  264. package/dist-lib/lib/web-fetch/images.js +8 -4
  265. package/dist-lib/lib/web-fetch/video.d.ts +2 -2
  266. package/dist-lib/lib/web-fetch/video.js +8 -4
  267. package/dist-lib/lib/web-search/engine-registry.d.ts +2 -2
  268. package/dist-lib/lib/web-search/engines/aol.js +1 -1
  269. package/dist-lib/lib/web-search/engines/bing.js +1 -1
  270. package/dist-lib/lib/web-search/engines/brave.js +4 -1
  271. package/dist-lib/lib/web-search/engines/duckduckgo.js +3 -2
  272. package/dist-lib/lib/web-search/engines/google.js +7 -3
  273. package/dist-lib/lib/web-search/engines/wikipedia.js +5 -4
  274. package/dist-lib/lib/web-search/engines/yahoo.js +1 -1
  275. package/dist-lib/lib/web-search/fetch-html.d.ts +5 -4
  276. package/dist-lib/lib/web-search/fetch-html.js +13 -7
  277. package/dist-lib/lib/web-search/orchestrator.d.ts +9 -5
  278. package/dist-lib/lib/web-search/orchestrator.js +3 -3
  279. package/dist-lib/lib/wire.d.ts +3 -2
  280. package/dist-lib/lib/wire.js +23 -15
  281. package/dist-lib/schema/baseline.js +10 -5
  282. package/dist-lib/schema/build.js +2 -1
  283. package/dist-lib/schema/harness.d.ts +15 -2
  284. package/dist-lib/schema/harness.js +14 -2
  285. package/dist-lib/schema/release-tags.d.ts +3 -2
  286. package/dist-lib/schema/release-tags.js +6 -3
  287. package/dist-lib/spec/bind.js +3 -0
  288. package/dist-lib/spec/calls.js +1 -0
  289. package/dist-lib/spec/hrpc/hrpc.json +13 -0
  290. package/dist-lib/spec/hrpc/index.js +15 -3
  291. package/dist-lib/spec/hrpc/messages.js +39 -8
  292. package/dist-lib/spec/hyperschema/index.js +39 -8
  293. package/dist-lib/spec/hyperschema/schema.json +30 -1
  294. package/dist-lib/spec/hyperschema/types.d.ts +9 -1
  295. package/package.json +13 -14
  296. package/worker/harness-sidecar.mjs +15 -22
  297. package/worker/stow-entry.mjs +7 -4
  298. package/dist-lib/lib/tools/mcp/utils.d.ts +0 -47
  299. /package/dist-lib/lib/tools/http-request/{utils.d.ts → request.d.ts} +0 -0
@@ -1,4 +1,5 @@
1
1
  import { TOOL_CONTINUATION_NUDGE } from '../capabilities/tool-turns.js';
2
+ import { isRecord } from '../guards.js';
2
3
  export const DEGENERATE_ANSWER_FALLBACK = "I couldn't complete that step and don't have a useful result to share.";
3
4
  export const ROUND_CAP_ANSWER = "I ran out of steps before I could finish that. Ask me to continue and I'll pick up where I left off.";
4
5
  export const SEARCH_CAPPED_ANSWER = "I searched the web but couldn't find the answer in the results I got.";
@@ -26,8 +27,9 @@ export function createRunOutcomeTracker() {
26
27
  record(result, outcome) {
27
28
  hasRoundResult = true;
28
29
  const failure = failureFromToolExecution(result, outcome);
29
- if (failure)
30
+ if (failure) {
30
31
  roundFailure = failure;
32
+ }
31
33
  },
32
34
  finishRound() {
33
35
  if (!hasRoundResult)
@@ -36,8 +38,9 @@ export function createRunOutcomeTracker() {
36
38
  },
37
39
  confirmWrite(result) {
38
40
  const write = writeResult(result);
39
- if (write)
41
+ if (write) {
40
42
  confirmedWrites.push(write);
43
+ }
41
44
  },
42
45
  facts() {
43
46
  return { latestFailure, confirmedWrites };
@@ -62,13 +65,15 @@ export function failureFromToolExecution(result, outcome) {
62
65
  export function degenerateAnswer(outcome, history, facts) {
63
66
  const rest = (facts ? facts.latestFailure : lastFailedToolAnswer(history)) ?? cappedAnswer(outcome, history);
64
67
  const written = writeReport(facts?.confirmedWrites ?? []);
65
- if (written)
68
+ if (written) {
66
69
  return rest ? `${written}\n\n${rest}` : written;
70
+ }
67
71
  return rest ?? DEGENERATE_ANSWER_FALLBACK;
68
72
  }
69
73
  function cappedAnswer(outcome, history) {
70
- if (outcome === 'search-capped')
74
+ if (outcome === 'search-capped') {
71
75
  return searchCappedAnswer(history);
76
+ }
72
77
  if (outcome === 'time-capped')
73
78
  return TIME_CAPPED_ANSWER;
74
79
  return outcome === 'exhausted' ? ROUND_CAP_ANSWER : null;
@@ -90,33 +95,40 @@ function searchCappedAnswer(history) {
90
95
  continue;
91
96
  seen.add(url);
92
97
  lines.push(`- ${title.trim()}: ${url}`);
93
- if (lines.length === MAX_CAPPED_SOURCES)
98
+ if (lines.length === MAX_CAPPED_SOURCES) {
94
99
  break;
100
+ }
95
101
  }
96
102
  }
97
- if (!lines.length)
103
+ if (!lines.length) {
98
104
  return SEARCH_CAPPED_ANSWER;
105
+ }
99
106
  return `${SEARCH_CAPPED_ANSWER} These pages looked most relevant:\n${lines.join('\n')}`;
100
107
  }
101
108
  export function lastFailedToolAnswer(history) {
102
109
  for (let i = history.length - 1; i >= 0; i--) {
103
110
  const turn = history[i];
104
- if (turn?.role === 'user' && turn.content === TOOL_CONTINUATION_NUDGE)
111
+ if (turn?.role === 'user' && turn.content === TOOL_CONTINUATION_NUDGE) {
105
112
  continue;
106
- if (turn?.role !== 'tool')
113
+ }
114
+ if (turn?.role !== 'tool') {
107
115
  return null;
116
+ }
108
117
  const failure = failureText(turn.content.replace(TOOL_RESULT_HEADER_RE, ''));
109
- if (failure)
118
+ if (failure) {
110
119
  return failure;
120
+ }
111
121
  }
112
122
  return null;
113
123
  }
114
124
  export function writeResult(output) {
115
125
  const result = asRecord(output);
116
- if (!result || typeof result.status !== 'number')
126
+ if (!result || typeof result.status !== 'number') {
117
127
  return null;
118
- if (result.status >= 400 || nonEmpty(result.error))
128
+ }
129
+ if (result.status >= 400 || nonEmpty(result.error)) {
119
130
  return null;
131
+ }
120
132
  return nonEmpty(result.body);
121
133
  }
122
134
  export function unnamedWrites(answer, landed) {
@@ -139,8 +151,9 @@ export function writeReport(landed) {
139
151
  const share = Math.floor(MAX_SUCCESS_CHARS / listed.length);
140
152
  const lines = listed.map((write) => bound(write, share));
141
153
  const dropped = landed.length - listed.length;
142
- if (dropped)
154
+ if (dropped) {
143
155
  lines.push(`(+${dropped} more)`);
156
+ }
144
157
  return `${WRITE_RESULT_LEAD}\n${lines.join('\n')}`;
145
158
  }
146
159
  function failureText(payload) {
@@ -149,17 +162,21 @@ function failureText(payload) {
149
162
  }
150
163
  function resultFailure(value) {
151
164
  const result = typeof value === 'string' ? parsed(value) : asRecord(value);
152
- if (!result)
165
+ if (!result) {
153
166
  return null;
154
- if (result.denied === true || result.guidance === true)
167
+ }
168
+ if (result.denied === true || result.guidance === true) {
155
169
  return null;
170
+ }
156
171
  const status = typeof result.status === 'number' ? result.status : null;
157
172
  const httpSuffix = status !== null && status >= 400 ? ` (HTTP ${status.toString()})` : '';
158
173
  const error = nonEmpty(result.error);
159
- if (error)
174
+ if (error) {
160
175
  return `${bound(error, MAX_FAILURE_CHARS)}${httpSuffix}`;
161
- if (status !== null && status >= 400)
176
+ }
177
+ if (status !== null && status >= 400) {
162
178
  return httpFailure(status, result.body);
179
+ }
163
180
  if (typeof result.exitCode === 'number' && result.exitCode !== 0) {
164
181
  const output = nonEmpty(result.stderr) ?? nonEmpty(result.stdout);
165
182
  return output ? bound(output, MAX_FAILURE_CHARS) : null;
@@ -174,8 +191,9 @@ function httpFailure(status, body) {
174
191
  }
175
192
  function apiMessage(body) {
176
193
  const value = typeof body === 'string' ? parsed(body) : asRecord(body);
177
- if (!value)
194
+ if (!value) {
178
195
  return null;
196
+ }
179
197
  const error = value.error;
180
198
  const fromError = typeof error === 'string' ? nonEmpty(error) : nonEmpty(asRecord(error)?.['message']);
181
199
  return fromError ?? nonEmpty(value.message);
@@ -189,9 +207,7 @@ function parsed(payload) {
189
207
  }
190
208
  }
191
209
  function asRecord(value) {
192
- return value && typeof value === 'object' && !Array.isArray(value)
193
- ? value
194
- : null;
210
+ return isRecord(value) && !Array.isArray(value) ? value : null;
195
211
  }
196
212
  function nonEmpty(value) {
197
213
  if (typeof value !== 'string')
@@ -5,8 +5,9 @@ export function withHomebrewPath(path, platformName) {
5
5
  const dirs = (path ?? '').split(':').filter(Boolean);
6
6
  const seen = new Set(dirs);
7
7
  const missing = HOMEBREW_BIN_DIRS.filter((dir) => !seen.has(dir));
8
- if (missing.length === 0)
8
+ if (missing.length === 0) {
9
9
  return path;
10
+ }
10
11
  return [...dirs, ...missing].join(':');
11
12
  }
12
13
  export const EXEC_ENV_ALLOWLIST = [
@@ -44,12 +45,14 @@ export function execEnv(env, platformName) {
44
45
  const keys = [...EXEC_ENV_ALLOWLIST, ...(PLATFORM_EXEC_ENV_ALLOWLIST[platformName] ?? [])];
45
46
  for (const key of keys) {
46
47
  const value = env[key];
47
- if (value !== undefined)
48
+ if (value !== undefined) {
48
49
  out[key] = value;
50
+ }
49
51
  }
50
52
  const path = withHomebrewPath(out.PATH ?? env.Path, platformName);
51
- if (path !== undefined)
53
+ if (path !== undefined) {
52
54
  out.PATH = path;
55
+ }
53
56
  return out;
54
57
  }
55
58
  export function spawnEnv(env, platformName, overrides) {
@@ -10,23 +10,26 @@ export class TextCoalescer {
10
10
  this._holdMs = holdMs;
11
11
  }
12
12
  async add(type, text) {
13
- if (this._buffered && this._buffered.type !== type)
13
+ if (this._buffered && this._buffered.type !== type) {
14
14
  await this.flush();
15
+ }
15
16
  if (!this._buffered) {
16
17
  this._buffered = { type, text: '' };
17
18
  this._hold = setTimeout(() => void this.flush(), this._holdMs);
18
19
  }
19
20
  this._buffered.text += text;
20
- if (this._buffered.text.length >= this._cap)
21
+ if (this._buffered.text.length >= this._cap) {
21
22
  await this.flush();
23
+ }
22
24
  }
23
25
  flush() {
24
26
  if (this._hold) {
25
27
  clearTimeout(this._hold);
26
28
  this._hold = null;
27
29
  }
28
- if (!this._buffered)
30
+ if (!this._buffered) {
29
31
  return Promise.resolve();
32
+ }
30
33
  const { type, text } = this._buffered;
31
34
  this._buffered = null;
32
35
  return this._write(type, text);
@@ -10,6 +10,20 @@ function findEarliest(buffer, tags) {
10
10
  const found = firstMarker(buffer, tags);
11
11
  return found === null ? null : { idx: found.index, len: found.marker.length };
12
12
  }
13
+ function nextTag(buffer, inThink) {
14
+ const open = findEarliest(buffer, OPEN_TAGS);
15
+ const close = findEarliest(buffer, CLOSE_TAGS);
16
+ if (inThink) {
17
+ if (open && (!close || open.idx < close.idx)) {
18
+ return { ...open, inThink: true };
19
+ }
20
+ return close && { ...close, inThink: false };
21
+ }
22
+ if (close && (!open || close.idx < open.idx)) {
23
+ return { ...close, inThink: false };
24
+ }
25
+ return open && { ...open, inThink: true };
26
+ }
13
27
  export async function* splitThinking(tokens, opts) {
14
28
  let buffer = '';
15
29
  let inThink = opts?.startInThink === true;
@@ -20,75 +34,54 @@ export async function* splitThinking(tokens, opts) {
20
34
  };
21
35
  const emit = (type, text) => {
22
36
  const shown = guards[type].push(text);
23
- if (!shown)
37
+ if (!shown) {
24
38
  return null;
25
- if (type === 'thinking' && unproven !== null)
39
+ }
40
+ if (type === 'thinking' && unproven !== null) {
26
41
  unproven += shown;
42
+ }
27
43
  return { type, text: shown };
28
44
  };
29
45
  for await (const token of tokens) {
30
46
  buffer += token;
31
47
  while (true) {
32
- if (inThink) {
33
- const open = findEarliest(buffer, OPEN_TAGS);
34
- const close = findEarliest(buffer, CLOSE_TAGS);
35
- if (open && (!close || open.idx < close.idx)) {
36
- const event = emit('thinking', buffer.slice(0, open.idx));
37
- if (event)
38
- yield event;
39
- guards.thinking.cut();
40
- buffer = buffer.slice(open.idx + open.len);
41
- continue;
42
- }
43
- if (!close)
44
- break;
45
- const event = emit('thinking', buffer.slice(0, close.idx));
46
- if (event)
47
- yield event;
48
- guards.thinking.cut();
49
- buffer = buffer.slice(close.idx + close.len);
50
- inThink = false;
51
- unproven = null;
52
- continue;
48
+ const tag = nextTag(buffer, inThink);
49
+ if (!tag) {
50
+ break;
53
51
  }
54
- const open = findEarliest(buffer, OPEN_TAGS);
55
- const close = findEarliest(buffer, CLOSE_TAGS);
56
- if (close && (!open || close.idx < open.idx)) {
57
- const event = emit('content', buffer.slice(0, close.idx));
58
- if (event)
59
- yield event;
60
- guards.content.cut();
61
- buffer = buffer.slice(close.idx + close.len);
62
- continue;
52
+ const type = inThink ? 'thinking' : 'content';
53
+ const event = emit(type, buffer.slice(0, tag.idx));
54
+ if (event) {
55
+ yield event;
63
56
  }
64
- if (open) {
65
- const event = emit('content', buffer.slice(0, open.idx));
66
- if (event)
67
- yield event;
68
- guards.content.cut();
69
- buffer = buffer.slice(open.idx + open.len);
70
- inThink = true;
71
- continue;
57
+ guards[type].cut();
58
+ buffer = buffer.slice(tag.idx + tag.len);
59
+ if (inThink && !tag.inThink) {
60
+ unproven = null;
72
61
  }
73
- break;
62
+ inThink = tag.inThink;
74
63
  }
75
64
  const held = holdback(buffer, inThink ? CLOSE_TAGS : ALL_TAGS);
76
65
  if (buffer.length > held) {
77
66
  const event = emit(inThink ? 'thinking' : 'content', buffer.slice(0, buffer.length - held));
78
- if (event)
67
+ if (event) {
79
68
  yield event;
69
+ }
80
70
  buffer = buffer.slice(buffer.length - held);
81
71
  }
82
72
  }
83
73
  const last = emit(inThink ? 'thinking' : 'content', buffer);
84
- if (last)
74
+ if (last) {
85
75
  yield last;
76
+ }
86
77
  for (const type of ['thinking', 'content']) {
87
78
  const rest = guards[type].flush();
88
- if (!rest)
79
+ if (!rest) {
89
80
  continue;
90
- if (type === 'thinking' && unproven !== null)
81
+ }
82
+ if (type === 'thinking' && unproven !== null) {
91
83
  unproven += rest;
84
+ }
92
85
  yield { type, text: rest };
93
86
  }
94
87
  return unproven;
@@ -6,15 +6,17 @@ export interface RecoveredToolCall {
6
6
  }
7
7
  export declare const MAX_RAW_CALL_CHARS = 4096;
8
8
  export declare function clipRawCall(raw: string): string;
9
- export declare function recoverMarkupToolCalls(text: string, knownTools: ReadonlyArray<{
10
- name: string;
11
- }>): RecoveredToolCall[];
9
+ export interface KnownTool {
10
+ readonly name: string;
11
+ }
12
+ export declare function recoverMarkupToolCalls(text: string, knownTools: ReadonlyArray<KnownTool>): RecoveredToolCall[];
12
13
  export declare function stripToolCallMarkup(text: string): string;
13
14
  export declare function stripToolResponseBlocks(text: string): string;
14
- export declare function toolCallMarkup(calls: ReadonlyArray<{
15
- name: string;
16
- arguments?: Record<string, unknown>;
17
- }>): string;
15
+ export interface MarkupToolCall {
16
+ readonly name: string;
17
+ readonly arguments?: Record<string, unknown>;
18
+ }
19
+ export declare function toolCallMarkup(calls: ReadonlyArray<MarkupToolCall>): string;
18
20
  export declare function normalizeToolArgs(args: Record<string, unknown>, declaredKeys: ReadonlyArray<string>): Record<string, unknown>;
19
21
  export declare function recoverSkillNamedCall(text: string, skillNames: ReadonlyArray<string>, skillToolName: string): RecoveredToolCall[];
20
22
  export declare function recoverPrintedSkillLoad(text: string, skillToolName: string): RecoveredToolCall[];
@@ -1,3 +1,4 @@
1
+ import { isRecord } from '../guards.js';
1
2
  const FUNCTION_OPEN = '<function=';
2
3
  const FUNCTION_CLOSE = '</function>';
3
4
  const TOOL_RESPONSE = { open: '<tool_response>', close: '</tool_response>' };
@@ -9,17 +10,20 @@ function* markupBlocks(text, open, close) {
9
10
  let cursor = 0;
10
11
  for (;;) {
11
12
  const start = text.indexOf(open, cursor);
12
- if (start === -1)
13
+ if (start === -1) {
13
14
  return;
15
+ }
14
16
  const nameStart = start + open.length;
15
17
  cursor = nameStart;
16
18
  const name = nameOf(text, nameStart);
17
- if (name === null)
19
+ if (name === null) {
18
20
  continue;
21
+ }
19
22
  const bodyStart = nameStart + name.length + 1;
20
23
  const bodyEnd = text.indexOf(close, bodyStart);
21
- if (bodyEnd === -1)
24
+ if (bodyEnd === -1) {
22
25
  return;
26
+ }
23
27
  yield {
24
28
  name: name.trim(),
25
29
  body: text.slice(bodyStart, bodyEnd),
@@ -32,8 +36,9 @@ function* markupBlocks(text, open, close) {
32
36
  function nameOf(text, nameStart) {
33
37
  const window = text.slice(nameStart, nameStart + MAX_NAME_LENGTH + 1);
34
38
  const nameEnd = window.indexOf('>');
35
- if (nameEnd === -1)
39
+ if (nameEnd === -1) {
36
40
  return null;
41
+ }
37
42
  const name = window.slice(0, nameEnd);
38
43
  return name.includes('\n') ? null : name;
39
44
  }
@@ -78,12 +83,14 @@ function stripSpans(text, span) {
78
83
  let cursor = 0;
79
84
  for (;;) {
80
85
  const start = hay.indexOf(span.open, cursor);
81
- if (start === -1)
86
+ if (start === -1) {
82
87
  break;
88
+ }
83
89
  out += text.slice(cursor, start);
84
90
  const end = hay.indexOf(span.close, start + span.open.length);
85
- if (end === -1)
91
+ if (end === -1) {
86
92
  return out;
93
+ }
87
94
  cursor = end + span.close.length;
88
95
  }
89
96
  return out + text.slice(cursor);
@@ -98,11 +105,13 @@ function danglingIndex(text) {
98
105
  let cursor = 0;
99
106
  for (;;) {
100
107
  const start = text.indexOf(FUNCTION_OPEN, cursor);
101
- if (start === -1)
108
+ if (start === -1) {
102
109
  return -1;
110
+ }
103
111
  const nameStart = start + FUNCTION_OPEN.length;
104
- if (nameOf(text, nameStart) !== null)
112
+ if (nameOf(text, nameStart) !== null) {
105
113
  return start;
114
+ }
106
115
  cursor = nameStart;
107
116
  }
108
117
  }
@@ -119,24 +128,27 @@ function encodeMarkupValue(value) {
119
128
  return JSON.stringify(value ?? null).replace(/</g, '\\u003c');
120
129
  }
121
130
  const ARG_WRAPPER_KEYS = new Set(['parameters', 'arguments', 'args', 'input', 'params']);
122
- function isRecord(value) {
123
- return value !== null && typeof value === 'object' && !Array.isArray(value);
131
+ function isPlainObject(value) {
132
+ return isRecord(value) && !Array.isArray(value);
124
133
  }
125
134
  export function normalizeToolArgs(args, declaredKeys) {
126
- const keys = Object.keys(args);
127
- if (keys.length !== 1)
135
+ const [only, ...rest] = Object.keys(args);
136
+ if (only === undefined || rest.length) {
128
137
  return args;
129
- const only = keys[0];
130
- if (!ARG_WRAPPER_KEYS.has(only) || declaredKeys.includes(only))
138
+ }
139
+ if (!ARG_WRAPPER_KEYS.has(only) || declaredKeys.includes(only)) {
131
140
  return args;
141
+ }
132
142
  const inner = args[only];
133
- if (isRecord(inner))
143
+ if (isPlainObject(inner)) {
134
144
  return inner;
145
+ }
135
146
  if (typeof inner === 'string') {
136
147
  try {
137
148
  const parsed = JSON.parse(inner);
138
- if (isRecord(parsed))
149
+ if (isPlainObject(parsed)) {
139
150
  return parsed;
151
+ }
140
152
  }
141
153
  catch {
142
154
  return args;
@@ -185,17 +197,21 @@ export function recoverPrintedSkillLoad(text, skillToolName) {
185
197
  catch {
186
198
  continue;
187
199
  }
188
- if (!isRecord(candidate))
200
+ if (!isPlainObject(candidate)) {
189
201
  continue;
202
+ }
190
203
  const keys = Object.keys(candidate);
191
- if (keys.length === 0 || !keys.every((key) => SKILL_LOAD_KEYS.has(key)))
204
+ if (keys.length === 0 || !keys.every((key) => SKILL_LOAD_KEYS.has(key))) {
192
205
  continue;
206
+ }
193
207
  const name = candidate.name ?? candidate.skill ?? candidate.skill_name;
194
208
  const file = candidate.file ?? candidate.path ?? candidate.filename;
195
- if (typeof name !== 'string' || typeof file !== 'string')
209
+ if (typeof name !== 'string' || typeof file !== 'string') {
196
210
  continue;
197
- if (!/\.(md|py)\s*$/i.test(file.replaceAll('"', '').trim()))
211
+ }
212
+ if (!/\.(md|py)\s*$/i.test(file.replaceAll('"', '').trim())) {
198
213
  continue;
214
+ }
199
215
  return [
200
216
  {
201
217
  id: 'recovered-printed-skill-load',
@@ -1,7 +1,8 @@
1
1
  export declare const INTENT_PARAM = "intent";
2
2
  export declare const INTENT_PARAM_DESCRIPTION: string;
3
3
  export declare function sanitizeToolIntent(value: unknown): string | undefined;
4
- export declare function takeToolIntent(args: Record<string, unknown>): {
4
+ export interface TakenToolIntent {
5
5
  args: Record<string, unknown>;
6
6
  intent?: string;
7
- };
7
+ }
8
+ export declare function takeToolIntent(args: Record<string, unknown>): TakenToolIntent;
@@ -8,13 +8,15 @@ export function sanitizeToolIntent(value) {
8
8
  if (typeof value !== 'string')
9
9
  return undefined;
10
10
  const collapsed = stripControlTokens(value).replace(/\s+/g, ' ').trim();
11
- if (!collapsed)
11
+ if (!collapsed) {
12
12
  return undefined;
13
+ }
13
14
  return collapsed.length > MAX_INTENT_LENGTH ? collapsed.slice(0, MAX_INTENT_LENGTH) : collapsed;
14
15
  }
15
16
  export function takeToolIntent(args) {
16
- if (!(INTENT_PARAM in args))
17
+ if (!(INTENT_PARAM in args)) {
17
18
  return { args };
19
+ }
18
20
  const { [INTENT_PARAM]: raw, ...rest } = args;
19
21
  const intent = sanitizeToolIntent(raw);
20
22
  return intent === undefined ? { args: rest } : { args: rest, intent };
@@ -33,29 +33,33 @@ function normalizeModelLabel(raw) {
33
33
  .split(/\r?\n/)
34
34
  .map((line) => line.trim())
35
35
  .find(Boolean);
36
- if (!firstLine)
36
+ if (!firstLine) {
37
37
  return null;
38
+ }
38
39
  const unlabeled = firstLine.replace(/^label\s*[:\-–]\s*/i, '');
39
40
  const unquoted = unwrap(unlabeled)
40
41
  .replace(/^["'`]+|["'`]+$/g, '')
41
42
  .trim();
42
43
  const words = unquoted.split(/\s+/).filter(Boolean).slice(0, MAX_LABEL_WORDS);
43
- if (words.length === 0)
44
+ if (words.length === 0) {
44
45
  return null;
46
+ }
45
47
  const label = words
46
48
  .join(' ')
47
49
  .replace(/[.,;:!?]+$/, '')
48
50
  .trim()
49
51
  .slice(0, MAX_LABEL_LENGTH)
50
52
  .trim();
51
- if (!label || ECHOED_INSTRUCTION.test(label))
53
+ if (!label || ECHOED_INSTRUCTION.test(label)) {
52
54
  return null;
55
+ }
53
56
  return label;
54
57
  }
55
58
  export function skillCallLabel(args) {
56
59
  const name = stringArg(args, 'name') || stringArg(args, 'skill_name') || stringArg(args, 'skill');
57
- if (!name)
60
+ if (!name) {
58
61
  return 'Load skill instructions';
62
+ }
59
63
  const title = titleSkillName(name);
60
64
  const file = stringArg(args, 'file');
61
65
  return file ? `Read ${title}/${fileName(file)}` : `Load ${title}`;
@@ -65,8 +69,9 @@ export function isSkillTool(name) {
65
69
  }
66
70
  function stringArg(args, key) {
67
71
  const value = args[key];
68
- if (typeof value !== 'string')
72
+ if (typeof value !== 'string') {
69
73
  return '';
74
+ }
70
75
  return unquoteArg(value).trim();
71
76
  }
72
77
  function fileName(path) {
@@ -82,8 +87,9 @@ function titleSkillName(name) {
82
87
  }
83
88
  function normalizeModelDescription(raw) {
84
89
  const text = stripControlTokens(raw).replace(/\s+/g, ' ').trim();
85
- if (!text || ECHOED_INSTRUCTION.test(text))
90
+ if (!text || ECHOED_INSTRUCTION.test(text)) {
86
91
  return undefined;
92
+ }
87
93
  return text.length > MAX_DESCRIPTION_LENGTH
88
94
  ? `${text.slice(0, MAX_DESCRIPTION_LENGTH).trimEnd()}…`
89
95
  : text;
@@ -94,8 +100,9 @@ export function parseToolLabelResponse(raw) {
94
100
  try {
95
101
  const parsed = JSON.parse(trimmed);
96
102
  const label = typeof parsed.label === 'string' ? normalizeModelLabel(parsed.label) : null;
97
- if (!label)
103
+ if (!label) {
98
104
  return null;
105
+ }
99
106
  const description = typeof parsed.description === 'string'
100
107
  ? normalizeModelDescription(parsed.description)
101
108
  : undefined;
@@ -108,11 +115,13 @@ export function parseToolLabelResponse(raw) {
108
115
  return label ? { label } : null;
109
116
  }
110
117
  export function fallbackToolLabel(name, args = {}) {
111
- if (isSkillTool(name))
118
+ if (isSkillTool(name)) {
112
119
  return skillCallLabel(args);
120
+ }
113
121
  const query = stringArg(args, 'query');
114
- if (query)
122
+ if (query) {
115
123
  return `Search ${query}`.slice(0, MAX_LABEL_LENGTH).trim();
124
+ }
116
125
  const url = stringArg(args, 'url');
117
126
  if (url) {
118
127
  const method = stringArg(args, 'method').toUpperCase();