@qvac/harness 0.4.0 → 0.6.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 +740 -141
  2. package/README.md +75 -7
  3. package/dist/harness.bundle +72 -50
  4. package/dist-lib/index.d.ts +49 -39
  5. package/dist-lib/index.js +448 -161
  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 +13 -32
  29. package/dist-lib/lib/connect.js +170 -112
  30. package/dist-lib/lib/context-window.js +25 -21
  31. package/dist-lib/lib/contract-types.d.ts +35 -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 +15 -20
  84. package/dist-lib/lib/models/model-catalog.js +66 -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 +48 -10
  90. package/dist-lib/lib/models/model-pool.js +106 -45
  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 +122 -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 +39 -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 +9 -0
  288. package/dist-lib/spec/calls.js +3 -0
  289. package/dist-lib/spec/hrpc/hrpc.json +39 -0
  290. package/dist-lib/spec/hrpc/index.js +39 -3
  291. package/dist-lib/spec/hrpc/messages.js +105 -8
  292. package/dist-lib/spec/hyperschema/index.js +105 -8
  293. package/dist-lib/spec/hyperschema/schema.json +77 -1
  294. package/dist-lib/spec/hyperschema/types.d.ts +25 -1
  295. package/package.json +14 -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
@@ -4,12 +4,12 @@ import { type DiffusionRuntime } from './generate-image.ts';
4
4
  interface Rgba {
5
5
  width: number;
6
6
  height: number;
7
- data: Buffer;
7
+ data: Uint8Array;
8
8
  frames?: Rgba[];
9
9
  }
10
10
  interface Media {
11
11
  image: {
12
- decode(input: Buffer, opts?: {
12
+ decode(input: Uint8Array, opts?: {
13
13
  maxFrames?: number;
14
14
  }): Promise<Rgba>;
15
15
  encode(rgba: Rgba, opts: {
@@ -1,3 +1,4 @@
1
+ import b4a from 'b4a';
1
2
  import fs from 'fs';
2
3
  import path from 'path';
3
4
  import { AbortedError } from '../helpers/race-abort.js';
@@ -11,13 +12,14 @@ async function turnSources(turnImages) {
11
12
  const sources = [];
12
13
  for (const image of turnImages) {
13
14
  const bytes = await fs.promises.readFile(image.path).catch(toNull);
14
- if (!bytes)
15
+ if (!bytes) {
15
16
  return { error: `could not read attached image ${path.basename(image.path)}` };
17
+ }
16
18
  sources.push({ bytes, fileName: path.basename(image.path) });
17
19
  }
18
20
  return sources;
19
21
  }
20
- async function resolveSources(fetchAttachment, ids, turnImages, signal) {
22
+ async function resolveSources(fetchAttachment, { ids, turnImages, signal }) {
21
23
  if (!ids.length) {
22
24
  if (turnImages.length) {
23
25
  const sources = await turnSources(turnImages);
@@ -33,13 +35,16 @@ async function resolveSources(fetchAttachment, ids, turnImages, signal) {
33
35
  const missing = [];
34
36
  for (const id of ids) {
35
37
  const found = await fetchAttachment({ attachmentId: id, signal });
36
- if (found && 'bytes' in found && found.bytes)
38
+ if (found && 'bytes' in found && found.bytes) {
37
39
  sources.push(found);
38
- else
40
+ }
41
+ else {
39
42
  missing.push(id);
43
+ }
40
44
  }
41
- if (!missing.length)
45
+ if (!missing.length) {
42
46
  return { sources };
47
+ }
43
48
  if (sources.length) {
44
49
  return {
45
50
  sources,
@@ -48,8 +53,9 @@ async function resolveSources(fetchAttachment, ids, turnImages, signal) {
48
53
  }
49
54
  if (turnImages.length) {
50
55
  const fallback = await turnSources(turnImages);
51
- if ('error' in fallback)
56
+ if ('error' in fallback) {
52
57
  return fallback;
58
+ }
53
59
  return {
54
60
  sources: fallback,
55
61
  note: `ignored unknown attachment id(s) ${missing.join(', ')} — edited the image(s) from the user's latest message`
@@ -62,7 +68,7 @@ async function resolveSources(fetchAttachment, ids, turnImages, signal) {
62
68
  }
63
69
  async function defaultLoadMedia() {
64
70
  try {
65
- return (await import('bare-media'));
71
+ return await import('bare-media');
66
72
  }
67
73
  catch {
68
74
  return null;
@@ -129,8 +135,9 @@ export function createEditImageTool(runtime, { loadMedia = defaultLoadMedia, res
129
135
  }),
130
136
  execute: async (args, ctx) => {
131
137
  const common = parseCommonArgs(args, cap.maxSteps);
132
- if ('error' in common)
138
+ if ('error' in common) {
133
139
  return common;
140
+ }
134
141
  let strength = DEFAULT_STRENGTH;
135
142
  if (args.strength !== undefined && args.strength !== null) {
136
143
  strength = Number(args.strength);
@@ -144,15 +151,17 @@ export function createEditImageTool(runtime, { loadMedia = defaultLoadMedia, res
144
151
  const attachmentIds = [];
145
152
  if (Array.isArray(args.attachment_ids)) {
146
153
  for (const id of args.attachment_ids) {
147
- if (typeof id === 'string' && id)
154
+ if (typeof id === 'string' && id) {
148
155
  attachmentIds.push(id);
156
+ }
149
157
  }
150
158
  }
151
159
  if (attachmentId && attachmentIds.length) {
152
160
  return { error: 'pass attachment_id or attachment_ids, not both' };
153
161
  }
154
- if (attachmentId)
162
+ if (attachmentId) {
155
163
  attachmentIds.push(attachmentId);
164
+ }
156
165
  if (!ctx?.attach || !ctx.fetchAttachment) {
157
166
  return { error: 'this device cannot edit chat images' };
158
167
  }
@@ -161,16 +170,24 @@ export function createEditImageTool(runtime, { loadMedia = defaultLoadMedia, res
161
170
  if (!attachmentIds.length && turnImages.length > 1 && !inContext) {
162
171
  return { error: MULTI_SOURCE_UNSUPPORTED };
163
172
  }
164
- const resolved = await resolveSources(ctx.fetchAttachment, attachmentIds, turnImages, ctx.signal);
165
- if (ctx.signal?.aborted)
173
+ const resolved = await resolveSources(ctx.fetchAttachment, {
174
+ ids: attachmentIds,
175
+ turnImages,
176
+ signal: ctx.signal
177
+ });
178
+ if (ctx.signal?.aborted) {
166
179
  return { error: 'image generation canceled' };
167
- if ('error' in resolved)
180
+ }
181
+ if ('error' in resolved) {
168
182
  return resolved;
183
+ }
169
184
  const { sources, note } = resolved;
170
- if (sources.length > 1 && !inContext)
185
+ if (sources.length > 1 && !inContext) {
171
186
  return { error: MULTI_SOURCE_UNSUPPORTED };
172
- if (!runtime.acquire())
187
+ }
188
+ if (!runtime.acquire()) {
173
189
  return { error: BUSY_ERROR, code: 'busy' };
190
+ }
174
191
  const report = ctx.progress;
175
192
  const onTick = report && generationPercentTick((percentage) => report({ percentage }), sources.length);
176
193
  try {
@@ -186,7 +203,7 @@ export function createEditImageTool(runtime, { loadMedia = defaultLoadMedia, res
186
203
  for (const source of sources) {
187
204
  let decoded;
188
205
  try {
189
- decoded = await media.image.decode(Buffer.from(source.bytes), { maxFrames: 1 });
206
+ decoded = await media.image.decode(b4a.from(source.bytes), { maxFrames: 1 });
190
207
  }
191
208
  catch {
192
209
  return { error: `could not decode ${source.fileName} as an image` };
@@ -198,7 +215,7 @@ export function createEditImageTool(runtime, { loadMedia = defaultLoadMedia, res
198
215
  const fitted = frame.width === fitWidth && frame.height === fitHeight
199
216
  ? frame
200
217
  : await resample(frame, fitWidth, fitHeight);
201
- inits.push(Buffer.from(await media.image.encode(fitted, { mimetype: 'image/png' })));
218
+ inits.push(b4a.from(await media.image.encode(fitted, { mimetype: 'image/png' })));
202
219
  if (!width) {
203
220
  width = fitWidth;
204
221
  height = fitHeight;
@@ -207,24 +224,30 @@ export function createEditImageTool(runtime, { loadMedia = defaultLoadMedia, res
207
224
  const sdk = await runtime.loadSdk();
208
225
  const { modelId } = await runtime.ensureLoaded(sdk, ctx.signal, ctx.image?.modelChoice);
209
226
  const fusion = inits.length > 1;
210
- const image = await runDiffusion(sdk, modelId, {
211
- prompt: common.prompt,
212
- width,
213
- height,
214
- steps: effectiveSteps(common.steps, ctx.image?.steps, stepsCap),
215
- seed: common.seed,
216
- negative_prompt: common.negativePrompt,
217
- ...(inContext
218
- ? {
219
- init_images: inits,
220
- auto_resize_ref_image: true,
221
- guidance: FLUX2_GUIDANCE,
222
- cfg_scale: FLUX2_CFG_SCALE
223
- }
224
- : { init_image: inits[0], strength })
225
- }, ctx.signal, onTick);
226
- if (!(image instanceof Uint8Array))
227
+ const image = await runDiffusion(sdk, {
228
+ modelId,
229
+ params: {
230
+ prompt: common.prompt,
231
+ width,
232
+ height,
233
+ steps: effectiveSteps(common.steps, ctx.image?.steps, stepsCap),
234
+ seed: common.seed,
235
+ negative_prompt: common.negativePrompt,
236
+ ...(inContext
237
+ ? {
238
+ init_images: inits,
239
+ auto_resize_ref_image: true,
240
+ guidance: FLUX2_GUIDANCE,
241
+ cfg_scale: FLUX2_CFG_SCALE
242
+ }
243
+ : { init_image: inits[0], strength })
244
+ },
245
+ signal: ctx.signal,
246
+ onTick
247
+ });
248
+ if (!(image instanceof Uint8Array)) {
227
249
  return image;
250
+ }
228
251
  const record = await ctx.attach({
229
252
  fileName: `edited-${Date.now()}.png`,
230
253
  mimeType: 'image/png',
@@ -244,7 +267,7 @@ export function createEditImageTool(runtime, { loadMedia = defaultLoadMedia, res
244
267
  ...(sources.length === 1 && sources[0].id
245
268
  ? { sourceAttachmentId: sources[0].id }
246
269
  : { sourceFileNames: sources.map((source) => source.fileName) }),
247
- ...(notes.length ? { note: notes.join('; ') } : {}),
270
+ note: notes.length ? notes.join('; ') : undefined,
248
271
  fileName: record.fileName,
249
272
  byteLength: record.byteLength,
250
273
  width,
@@ -252,8 +275,9 @@ export function createEditImageTool(runtime, { loadMedia = defaultLoadMedia, res
252
275
  };
253
276
  }
254
277
  catch (err) {
255
- if (err instanceof AbortedError)
278
+ if (err instanceof AbortedError) {
256
279
  return { error: 'image generation canceled' };
280
+ }
257
281
  if (err instanceof Error && err.message === IMAGE_LOAD_STALL_ERROR) {
258
282
  return { error: IMAGE_LOAD_STALL_ERROR };
259
283
  }
@@ -1,14 +1,14 @@
1
1
  import type { AbortSignal as BareAbortSignal } from 'bare-abort-controller';
2
2
  import type { AttachFn, FetchAttachmentFn, RunBudget, ToolDecision } from '../../../capabilities/completion.ts';
3
3
  import type { ExecResult } from '../runner.ts';
4
- export type ExecutionOptions = {
4
+ export interface ExecutionOptions {
5
5
  readonly cwd?: string;
6
6
  readonly env?: Readonly<Record<string, string>>;
7
7
  readonly timeoutMs?: number;
8
8
  readonly maxOutputChars?: number;
9
9
  readonly signal?: BareAbortSignal;
10
- };
11
- export type ExecutionContext = {
10
+ }
11
+ export interface ExecutionContext {
12
12
  readonly attach?: AttachFn;
13
13
  readonly fetchAttachment?: FetchAttachmentFn;
14
14
  readonly turnImages?: readonly {
@@ -19,13 +19,13 @@ export type ExecutionContext = {
19
19
  readonly toolNames?: readonly string[];
20
20
  readonly approval?: ToolDecision;
21
21
  readonly confirmConnect?: (host: string) => Promise<boolean>;
22
- };
23
- export type ExecutionPlan = {
22
+ }
23
+ export interface ExecutionPlan {
24
24
  run(options: ExecutionOptions): Promise<ExecResult> | ExecResult;
25
- };
26
- export type ExecutionAdapter = {
25
+ }
26
+ export interface ExecutionAdapter {
27
27
  resolve(args: Record<string, unknown>, ctx?: ExecutionContext): ExecutionPlan | null;
28
- };
29
- export type FallbackExecutionAdapter = {
28
+ }
29
+ export interface FallbackExecutionAdapter {
30
30
  resolve(args: Record<string, unknown>, ctx?: ExecutionContext): ExecutionPlan;
31
- };
31
+ }
@@ -1,26 +1,32 @@
1
1
  import type { AbortSignal as BareAbortSignal } from 'bare-abort-controller';
2
2
  import type { AttachFn, FetchAttachmentFn, RunBudget } from '../../../../capabilities/completion.ts';
3
3
  import type { ExecAttachment, RejectedOutput } from '../../runner.ts';
4
- export type ExecInput = {
4
+ import { type ExecError } from './output-policy.ts';
5
+ export interface ExecInput {
5
6
  readonly attachmentId?: string;
6
7
  readonly path: string;
7
- };
8
- export type StagedInput = {
8
+ }
9
+ export interface StagedInput {
9
10
  readonly path: string;
10
11
  readonly bytes: Uint8Array;
11
- };
12
- export declare function stageInputs(fetchAttachment: FetchAttachmentFn, inputs: readonly ExecInput[], opts?: {
12
+ }
13
+ export interface StageInputsOptions {
13
14
  turnImages?: readonly {
14
15
  path: string;
15
16
  }[];
16
17
  signal?: BareAbortSignal;
17
- }): Promise<{
18
+ }
19
+ export interface StagedInputs {
18
20
  files: readonly StagedInput[];
19
- } | {
20
- error: string;
21
- }>;
22
- export declare function attachOutputs(attach: AttachFn, files: ReadonlyMap<string, Uint8Array>, declared: readonly string[], runBudget?: RunBudget): Promise<{
21
+ }
22
+ export declare function stageInputs(fetchAttachment: FetchAttachmentFn, inputs: readonly ExecInput[], opts?: StageInputsOptions): Promise<StagedInputs | ExecError>;
23
+ export interface AttachOutputsOptions {
24
+ readonly declared: readonly string[];
25
+ readonly runBudget?: RunBudget | undefined;
26
+ }
27
+ export interface AttachedOutputs {
23
28
  attachments: readonly ExecAttachment[];
24
29
  missingOutputs: readonly string[];
25
30
  rejectedOutputs: readonly RejectedOutput[];
26
- }>;
31
+ }
32
+ export declare function attachOutputs(attach: AttachFn, files: ReadonlyMap<string, Uint8Array>, { declared, runBudget }: AttachOutputsOptions): Promise<AttachedOutputs>;
@@ -1,5 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
+ import { errorMessage } from '../../../../guards.js';
3
4
  import { hlog } from '../../../../log.js';
4
5
  import { checkOutputBytes, MAX_INPUT_TOTAL_BYTES, RUN_OUTPUT_BUDGET_BYTES } from './output-policy.js';
5
6
  const STAGE_TIMEOUT_MS = 60_000;
@@ -15,8 +16,9 @@ function bounded(work, ms, message) {
15
16
  timer = setTimeout(() => reject(new Error(message)), ms);
16
17
  });
17
18
  return Promise.race([work, bound]).finally(() => {
18
- if (timer)
19
+ if (timer) {
19
20
  clearTimeout(timer);
21
+ }
20
22
  });
21
23
  }
22
24
  function hasBytes(record) {
@@ -25,12 +27,13 @@ function hasBytes(record) {
25
27
  function byteLengthOf(record) {
26
28
  return hasBytes(record) ? record.bytes.byteLength : record.byteLength;
27
29
  }
28
- async function uploadedBytes(fetchAttachment, turnImages, index, signal) {
30
+ async function uploadedBytes(fetchAttachment, index, { turnImages, signal }) {
29
31
  const image = turnImages[index];
30
32
  if (image) {
31
33
  const bytes = await fs.promises.readFile(image.path).catch(toNull);
32
- if (!bytes)
34
+ if (!bytes) {
33
35
  return { error: `could not read attached image ${path.basename(image.path)}` };
36
+ }
34
37
  return bytes;
35
38
  }
36
39
  if (turnImages.length) {
@@ -38,13 +41,32 @@ async function uploadedBytes(fetchAttachment, turnImages, index, signal) {
38
41
  error: `the user's latest message has only ${turnImages.length} image(s) — one id-less input per uploaded image`
39
42
  };
40
43
  }
41
- if (index > 0)
44
+ if (index > 0) {
42
45
  return { error: NO_UPLOAD_ERROR };
46
+ }
43
47
  const latest = await fetchAttachment({ signal });
44
- if (!latest || !hasBytes(latest))
48
+ if (!latest || !hasBytes(latest)) {
45
49
  return { error: NO_UPLOAD_ERROR };
50
+ }
46
51
  return latest.bytes;
47
52
  }
53
+ async function probeUpload(fetchAttachment, input, { index, turnImages, signal, deadline }) {
54
+ if (DOCUMENT_INPUT.test(input.path)) {
55
+ return { error: NO_DOCUMENT_ERROR };
56
+ }
57
+ const bytes = await bounded(uploadedBytes(fetchAttachment, index, { turnImages, signal }), deadline - Date.now(), STAGE_TIMEOUT_MESSAGE);
58
+ if ('error' in bytes) {
59
+ return bytes;
60
+ }
61
+ return { size: bytes.byteLength, bytes };
62
+ }
63
+ async function probeAttachment(fetchAttachment, id, { signal, deadline }) {
64
+ const head = await bounded(fetchAttachment({ attachmentId: id, meta: true, signal }), deadline - Date.now(), STAGE_TIMEOUT_MESSAGE);
65
+ if (!head) {
66
+ return { error: `attachment ${id} not found in this chat` };
67
+ }
68
+ return { size: byteLengthOf(head), bytes: hasBytes(head) ? head.bytes : null };
69
+ }
48
70
  export async function stageInputs(fetchAttachment, inputs, opts = {}) {
49
71
  const { turnImages = [], signal } = opts;
50
72
  const files = inputs.map(() => null);
@@ -52,32 +74,21 @@ export async function stageInputs(fetchAttachment, inputs, opts = {}) {
52
74
  const deadline = Date.now() + STAGE_TIMEOUT_MS;
53
75
  let total = 0;
54
76
  let uploads = 0;
55
- for (let i = 0; i < inputs.length; i++) {
56
- const input = inputs[i];
77
+ for (const [i, input] of inputs.entries()) {
57
78
  const id = input.attachmentId;
58
79
  try {
59
- if (id === undefined) {
60
- if (DOCUMENT_INPUT.test(input.path))
61
- return { error: NO_DOCUMENT_ERROR };
62
- const bytes = await bounded(uploadedBytes(fetchAttachment, turnImages, uploads++, signal), deadline - Date.now(), STAGE_TIMEOUT_MESSAGE);
63
- if ('error' in bytes)
64
- return bytes;
65
- total += bytes.byteLength;
66
- if (total > MAX_INPUT_TOTAL_BYTES) {
67
- hlog('python: input attachments over budget; skipping blob download', {
68
- total,
69
- cap: MAX_INPUT_TOTAL_BYTES,
70
- count: inputs.length
71
- });
72
- return { error: OVER_BUDGET_ERROR };
73
- }
74
- files[i] = { path: input.path, bytes };
75
- continue;
80
+ const probe = id === undefined
81
+ ? await probeUpload(fetchAttachment, input, {
82
+ index: uploads++,
83
+ turnImages,
84
+ signal,
85
+ deadline
86
+ })
87
+ : await probeAttachment(fetchAttachment, id, { signal, deadline });
88
+ if ('error' in probe) {
89
+ return probe;
76
90
  }
77
- const head = await bounded(fetchAttachment({ attachmentId: id, meta: true, signal }), deadline - Date.now(), STAGE_TIMEOUT_MESSAGE);
78
- if (!head)
79
- return { error: `attachment ${id} not found in this chat` };
80
- total += byteLengthOf(head);
91
+ total += probe.size;
81
92
  if (total > MAX_INPUT_TOTAL_BYTES) {
82
93
  hlog('python: input attachments over budget; skipping blob download', {
83
94
  total,
@@ -86,32 +97,33 @@ export async function stageInputs(fetchAttachment, inputs, opts = {}) {
86
97
  });
87
98
  return { error: OVER_BUDGET_ERROR };
88
99
  }
89
- if (hasBytes(head))
90
- files[i] = { path: input.path, bytes: head.bytes };
91
- else
92
- pending.push(i);
100
+ if (probe.bytes !== null) {
101
+ files[i] = { path: input.path, bytes: probe.bytes };
102
+ }
103
+ else {
104
+ pending.push({ index: i, input });
105
+ }
93
106
  }
94
107
  catch (error) {
95
- return { error: error instanceof Error ? error.message : String(error) };
108
+ return { error: errorMessage(error) };
96
109
  }
97
110
  }
98
- for (const i of pending) {
99
- const input = inputs[i];
111
+ for (const { index, input } of pending) {
100
112
  const id = input.attachmentId;
101
113
  try {
102
114
  const fetched = await bounded(fetchAttachment({ attachmentId: id, signal }), deadline - Date.now(), STAGE_TIMEOUT_MESSAGE);
103
115
  if (!fetched || !hasBytes(fetched)) {
104
116
  return { error: `attachment ${id} not found in this chat` };
105
117
  }
106
- files[i] = { path: input.path, bytes: fetched.bytes };
118
+ files[index] = { path: input.path, bytes: fetched.bytes };
107
119
  }
108
120
  catch (error) {
109
- return { error: error instanceof Error ? error.message : String(error) };
121
+ return { error: errorMessage(error) };
110
122
  }
111
123
  }
112
- return { files: files };
124
+ return { files: files.filter((file) => file !== null) };
113
125
  }
114
- export async function attachOutputs(attach, files, declared, runBudget) {
126
+ export async function attachOutputs(attach, files, { declared, runBudget }) {
115
127
  const attachments = [];
116
128
  const missingOutputs = [];
117
129
  const rejectedOutputs = [];
@@ -145,8 +157,9 @@ export async function attachOutputs(attach, files, declared, runBudget) {
145
157
  continue;
146
158
  }
147
159
  total += bytes.byteLength;
148
- if (runBudget)
160
+ if (runBudget) {
149
161
  runBudget.outputBytesUsed += bytes.byteLength;
162
+ }
150
163
  attachments.push({
151
164
  attachmentId: record.id,
152
165
  fileName: record.fileName,
@@ -1,7 +1,7 @@
1
- type SourceHalves = {
1
+ interface SourceHalves {
2
2
  code: string;
3
3
  text: string;
4
- };
4
+ }
5
5
  export declare function splitPythonSource(source: string): SourceHalves | null;
6
6
  export declare function pythonCreateEffect(args: Record<string, unknown>): 'read' | 'write';
7
7
  export {};