@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
@@ -7,18 +7,18 @@ export type DownloadProgressEvent = {
7
7
  type: 'progress';
8
8
  transferred?: boolean;
9
9
  } & DownloadProgress;
10
- export type DownloadCompleteEvent = {
10
+ export interface DownloadCompleteEvent {
11
11
  type: 'complete';
12
12
  assetId: string;
13
13
  downloaded?: boolean;
14
- };
15
- export type DownloadErrorEvent = {
14
+ }
15
+ export interface DownloadErrorEvent {
16
16
  type: 'error';
17
17
  message: string;
18
- };
19
- export type DownloadAbortedEvent = {
18
+ }
19
+ export interface DownloadAbortedEvent {
20
20
  type: 'aborted';
21
- };
21
+ }
22
22
  export type DownloadEvent = DownloadProgressEvent | DownloadCompleteEvent | DownloadErrorEvent | DownloadAbortedEvent;
23
23
  export interface DownloadSdk extends ModelRegistrySdk {
24
24
  downloadAsset(options: {
@@ -1,5 +1,5 @@
1
1
  import { Readable } from 'streamx';
2
- import { errorMessage } from '../error-fields.js';
2
+ import { errorMessage } from '../guards.js';
3
3
  import { resolveModelSrc } from '../models/model-source.js';
4
4
  const noop = () => { };
5
5
  export function download(sdkOrLoader, args, onSettled) {
@@ -30,12 +30,14 @@ export function download(sdkOrLoader, args, onSettled) {
30
30
  finish({ type: 'aborted' });
31
31
  };
32
32
  const onProgress = (p) => {
33
- if (!settled)
33
+ if (!settled) {
34
34
  stream.push({ ...p, type: 'progress', transferred });
35
+ }
35
36
  };
36
37
  const start = async () => {
37
- if (signal?.aborted)
38
+ if (signal?.aborted) {
38
39
  return finish({ type: 'aborted' });
40
+ }
39
41
  try {
40
42
  sdkRef = await loadSdk();
41
43
  const resolved = await resolveModelSrc(sdkRef, model, addon);
@@ -44,8 +46,9 @@ export function download(sdkOrLoader, args, onSettled) {
44
46
  const aggregate = aggregateLayout(srcs, assetSizes);
45
47
  let mainAssetId = '';
46
48
  for (let i = 0; i < srcs.length; i++) {
47
- if (signal?.aborted)
49
+ if (signal?.aborted) {
48
50
  return finish({ type: 'aborted' });
51
+ }
49
52
  const progress = aggregate
50
53
  ? aggregateProgressHandler(onProgress, {
51
54
  setKey: mainSrc,
@@ -61,23 +64,26 @@ export function download(sdkOrLoader, args, onSettled) {
61
64
  assetSrc: srcs[i],
62
65
  seed,
63
66
  onProgress: (update) => {
64
- if (update.percentage < 100)
67
+ if (update.percentage < 100) {
65
68
  transferred = true;
69
+ }
66
70
  progress(update);
67
71
  }
68
72
  });
69
73
  requestId = op.requestId;
70
74
  const assetId = await op;
71
- if (i === 0)
75
+ if (i === 0) {
72
76
  mainAssetId = assetId;
77
+ }
73
78
  }
74
79
  opDone = true;
75
80
  finish({ type: 'complete', assetId: mainAssetId, downloaded: transferred });
76
81
  }
77
82
  catch (err) {
78
83
  opDone = true;
79
- if (signal?.aborted)
84
+ if (signal?.aborted) {
80
85
  return finish({ type: 'aborted' });
86
+ }
81
87
  finish({ type: 'error', message: errorMessage(err) });
82
88
  }
83
89
  };
@@ -103,8 +109,9 @@ function aggregateLayout(sources, assetSizes) {
103
109
  let totalBytes = 0;
104
110
  for (const source of sources) {
105
111
  const size = assetSizes[source];
106
- if (!Number.isFinite(size) || size <= 0)
112
+ if (!Number.isFinite(size) || size <= 0) {
107
113
  return null;
114
+ }
108
115
  offsets.push(totalBytes);
109
116
  sizes.push(size);
110
117
  totalBytes += size;
@@ -7,7 +7,8 @@ export function createEmbedLane() {
7
7
  const { embedding } = await sdk.embed({ modelId, text: texts });
8
8
  return embedding;
9
9
  });
10
- tail = job.catch(() => { });
10
+ tail = job.catch(noop);
11
11
  return job;
12
12
  };
13
13
  }
14
+ function noop() { }
@@ -7,4 +7,9 @@ export interface EnhanceResult {
7
7
  totalTokens?: number;
8
8
  }
9
9
  export type Enhancer = (prompt: string, signal?: BareAbortSignal) => Promise<EnhanceResult | null>;
10
- export declare function expandImagePrompt(sdk: CompletionSdk, modelId: string, model: string, prompt: string, signal?: BareAbortSignal): Promise<EnhanceResult | null>;
10
+ export interface ExpandImagePromptOptions {
11
+ modelId: string;
12
+ model: string;
13
+ signal?: BareAbortSignal | undefined;
14
+ }
15
+ export declare function expandImagePrompt(sdk: CompletionSdk, prompt: string, { modelId, model, signal }: ExpandImagePromptOptions): Promise<EnhanceResult | null>;
@@ -3,7 +3,7 @@ import { raceAbort } from '../helpers/race-abort.js';
3
3
  const SYSTEM = "Rewrite the user's description as a single vivid prompt for an image generator. " +
4
4
  'Answer with the prompt alone: no preamble, no quotes, no explanation.';
5
5
  const MAX_PROMPT_CHARS = 400;
6
- export async function expandImagePrompt(sdk, modelId, model, prompt, signal) {
6
+ export async function expandImagePrompt(sdk, prompt, { modelId, model, signal }) {
7
7
  const run = sdk.completion({
8
8
  modelId,
9
9
  history: [
@@ -18,12 +18,15 @@ export async function expandImagePrompt(sdk, modelId, model, prompt, signal) {
18
18
  final = await raceAbort(run.final, signal);
19
19
  }
20
20
  catch (err) {
21
- if (run.requestId)
22
- void sdk.cancel?.({ requestId: run.requestId }).catch(() => { });
21
+ if (run.requestId) {
22
+ void sdk.cancel?.({ requestId: run.requestId }).catch(noop);
23
+ }
23
24
  throw err;
24
25
  }
25
26
  const text = cleanAnswer(final.contentText).slice(0, MAX_PROMPT_CHARS);
26
- if (!text)
27
+ if (!text) {
27
28
  return null;
29
+ }
28
30
  return { text, model, totalTokens: final.stats?.generatedTokens };
29
31
  }
32
+ function noop() { }
@@ -1,9 +1,10 @@
1
+ import { errorMessage } from '../guards.js';
1
2
  import { AbortedError } from '../helpers/race-abort.js';
2
3
  const CAPABILITY_TOOLS = {
3
4
  image: { tool: 'generate_image', enhances: 'prompt' },
4
5
  translate: { tool: 'translate' }
5
6
  };
6
- export const CAPABILITIES = Object.keys(CAPABILITY_TOOLS);
7
+ export const CAPABILITIES = Object.keys(CAPABILITY_TOOLS).filter(isCapability);
7
8
  export function isCapability(name) {
8
9
  return name in CAPABILITY_TOOLS;
9
10
  }
@@ -30,13 +31,15 @@ export async function* invoke({ capability, args, tools, ctx, enhance = 'never',
30
31
  }
31
32
  }
32
33
  }
33
- if (ctx.signal?.aborted)
34
+ if (ctx.signal?.aborted) {
34
35
  return yield { type: 'aborted' };
36
+ }
35
37
  yield { type: 'tool-call', name: entry.tool, args: called, effect: tool.effect(called, ctx) };
36
38
  try {
37
39
  const result = await tool.execute(called, ctx);
38
- if (ctx.signal?.aborted)
40
+ if (ctx.signal?.aborted) {
39
41
  return yield { type: 'aborted' };
42
+ }
40
43
  yield { type: 'tool-result', name: entry.tool, result };
41
44
  }
42
45
  catch (err) {
@@ -44,7 +47,7 @@ export async function* invoke({ capability, args, tools, ctx, enhance = 'never',
44
47
  yield { type: 'aborted' };
45
48
  return;
46
49
  }
47
- yield { type: 'error', message: err instanceof Error ? err.message : String(err) };
50
+ yield { type: 'error', message: errorMessage(err) };
48
51
  return;
49
52
  }
50
53
  yield {
@@ -1,3 +1,4 @@
1
+ import { errorMessage } from '../guards.js';
1
2
  export async function deleteAllKvCaches(loadSdk) {
2
3
  return deleteCacheWith(loadSdk, { all: true });
3
4
  }
@@ -15,7 +16,7 @@ async function deleteCacheWith(loadSdk, params) {
15
16
  catch (error) {
16
17
  return {
17
18
  status: 'failure',
18
- error: error instanceof Error ? error.message : String(error)
19
+ error: errorMessage(error)
19
20
  };
20
21
  }
21
22
  }
@@ -48,13 +48,15 @@ export interface FitQuery {
48
48
  }
49
49
  export interface PreviewDeps {
50
50
  fetch?: PreviewFetch;
51
- stat?(path: string): Promise<{
52
- size: number;
53
- } | null>;
54
- assessFit?(query: FitQuery): Promise<{
55
- fit: ModelFitVerdict;
56
- fitReasons: string[];
57
- }>;
51
+ stat?(path: string): Promise<FileStat | null>;
52
+ assessFit?(query: FitQuery): Promise<FitAssessment>;
53
+ }
54
+ export interface FileStat {
55
+ size: number;
56
+ }
57
+ export interface FitAssessment {
58
+ fit: ModelFitVerdict;
59
+ fitReasons: string[];
58
60
  }
59
61
  interface HuggingFaceRef {
60
62
  repo: string;
@@ -1,7 +1,9 @@
1
1
  import fs from 'fs';
2
2
  import defaultFetch from '#fetch';
3
+ import { errorMessage } from '../guards.js';
3
4
  import { defaultContextSize } from '../models/context.js';
4
5
  import { isRemoteSource, localSourcePath, parseGgufHeader, readGgufHeaderBytes } from '../models/gguf-header.js';
6
+ import { shardSet } from '../models/shards.js';
5
7
  const HUGGING_FACE = 'https://huggingface.co';
6
8
  const HUGGING_FACE_HOSTS = new Set(['huggingface.co', 'www.huggingface.co', 'hf.co']);
7
9
  const NON_MODEL_NAMESPACES = new Set(['api', 'datasets', 'spaces', 'docs', 'models']);
@@ -32,11 +34,13 @@ export async function previewModelSource(context, deps = {}) {
32
34
  return refuse('invalid-source', 'Paste a Hugging Face link, a direct link to a .gguf file, or a local path.');
33
35
  }
34
36
  const weight = await inspectModelFile(src, fetch, deps);
35
- if ('answer' in weight)
37
+ if ('answer' in weight) {
36
38
  return weight.answer;
39
+ }
37
40
  const problem = modelProblem(weight.header);
38
- if (problem)
41
+ if (problem) {
39
42
  return refuse(problem[0], problem[1]);
43
+ }
40
44
  const taskType = taskTypeFor({
41
45
  pipelineTag: weight.file.pipelineTag,
42
46
  tags: [...(weight.file.tags ?? []), ...(weight.header.tags ?? [])],
@@ -58,7 +62,7 @@ export async function previewModelSource(context, deps = {}) {
58
62
  projectionBytes = projection.file.sizeBytes;
59
63
  projectionSrc = projection.file.src;
60
64
  }
61
- const { fit, fitReasons } = await assess(weight.file, weight.header, taskType, deps);
65
+ const { fit, fitReasons } = await assess(weight, taskType, deps);
62
66
  return defined({
63
67
  ok: true,
64
68
  src: weight.file.src,
@@ -105,14 +109,17 @@ export function parseHuggingFaceRef(src) {
105
109
  catch {
106
110
  return null;
107
111
  }
108
- if (!HUGGING_FACE_HOSTS.has(url.hostname))
112
+ if (!HUGGING_FACE_HOSTS.has(url.hostname)) {
109
113
  return null;
114
+ }
110
115
  const segments = pathSegments(url.pathname);
111
- if (!segments)
116
+ if (!segments) {
112
117
  return null;
118
+ }
113
119
  const [org, name, kind, revision, ...rest] = segments;
114
- if (!org || !name || NON_MODEL_NAMESPACES.has(org))
120
+ if (!org || !name || NON_MODEL_NAMESPACES.has(org)) {
115
121
  return null;
122
+ }
116
123
  const repo = `${org}/${name}`;
117
124
  if (!kind) {
118
125
  const shown = url.searchParams.get('show_file_info');
@@ -121,17 +128,17 @@ export function parseHuggingFaceRef(src) {
121
128
  if ((kind === 'blob' || kind === 'resolve') && revision && rest.length > 0) {
122
129
  return { repo, revision, file: rest.join('/') };
123
130
  }
124
- if (kind === 'tree' && revision)
131
+ if (kind === 'tree' && revision) {
125
132
  return { repo, revision };
133
+ }
126
134
  return null;
127
135
  }
128
136
  async function inspectModelFile(src, fetch, deps) {
129
137
  const inspection = await inspect(src, fetch, deps);
130
- if (inspection.kind === 'answer')
138
+ if (inspection.kind === 'answer') {
131
139
  return { answer: inspection.preview };
132
- const bytes = await readGgufHeaderBytes(inspection.file.src, {
133
- fetch: fetch
134
- });
140
+ }
141
+ const bytes = await readGgufHeaderBytes(inspection.file.src, { fetch });
135
142
  if (!bytes) {
136
143
  return {
137
144
  answer: refuse('unreachable', 'Could not read the start of the file to check it is a model.')
@@ -147,8 +154,9 @@ async function inspectModelFile(src, fetch, deps) {
147
154
  }
148
155
  function inspect(src, fetch, deps) {
149
156
  const ref = parseHuggingFaceRef(src);
150
- if (ref)
157
+ if (ref) {
151
158
  return inspectHuggingFace(ref, fetch);
159
+ }
152
160
  if (isRemoteSource(src)) {
153
161
  return wellFormedUrl(src)
154
162
  ? inspectUrl(src, fetch)
@@ -191,8 +199,9 @@ async function inspectHuggingFace(ref, fetch) {
191
199
  const wanted = ref.file;
192
200
  if (wanted) {
193
201
  const sibling = siblings.find((entry) => entry.rfilename === wanted);
194
- if (!sibling)
202
+ if (!sibling) {
195
203
  return answer(refuse('not-found', `${ref.repo} has no file ${wanted}.`));
204
+ }
196
205
  if (!/\.gguf$/i.test(wanted)) {
197
206
  return answer(refuse('not-gguf', `${wanted} is not a GGUF file. Only GGUF models run on this device.`));
198
207
  }
@@ -236,15 +245,45 @@ async function inspectUrl(src, fetch) {
236
245
  if ((response.headers.get('content-type') ?? '').includes('text/html')) {
237
246
  return answer(refuse('web-page', 'This link opens a web page, not a model file. Link to the .gguf file itself.'));
238
247
  }
239
- const sizeBytes = positive(response.headers.get('x-linked-size')) ??
248
+ const set = shardSet(src);
249
+ if (set && set.shards.length > 1) {
250
+ return inspectShards(set, fetch);
251
+ }
252
+ return { kind: 'file', file: { src, label: basename(src), sizeBytes: sizeOfResponse(response) } };
253
+ }
254
+ async function inspectShards(set, fetch) {
255
+ let responses;
256
+ try {
257
+ responses = await Promise.all(set.shards.map((shard) => fetch(shard.url, { method: 'HEAD', redirect: 'follow' })));
258
+ }
259
+ catch {
260
+ return answer(refuse('unreachable', `Could not reach every part of ${set.base}.`));
261
+ }
262
+ const missing = responses.findIndex((response) => !response.ok);
263
+ if (missing !== -1) {
264
+ const { status } = responses[missing];
265
+ return answer(refuse(status === 404 || status === 410 ? 'not-found' : 'unreachable', `Part ${missing + 1} of ${set.shards.length}, ${set.shards[missing].filename}, answered HTTP ${status}.`));
266
+ }
267
+ const sizes = responses.map(sizeOfResponse);
268
+ return {
269
+ kind: 'file',
270
+ file: {
271
+ src: set.shards[0].url,
272
+ label: `${set.base}${set.extension} (${set.shards.length} parts)`,
273
+ sizeBytes: sizes.includes(0) ? 0 : sizes.reduce((sum, size) => sum + size, 0)
274
+ }
275
+ };
276
+ }
277
+ function sizeOfResponse(response) {
278
+ return (positive(response.headers.get('x-linked-size')) ??
240
279
  positive(response.headers.get('content-length')) ??
241
- 0;
242
- return { kind: 'file', file: { src, label: basename(src), sizeBytes } };
280
+ 0);
243
281
  }
244
282
  async function inspectLocal(src, file, deps) {
245
283
  const stat = await (deps.stat ?? statFile)(file);
246
- if (!stat)
284
+ if (!stat) {
247
285
  return answer(refuse('not-found', `There is no file at ${file}.`));
286
+ }
248
287
  return { kind: 'file', file: { src, label: basename(file), sizeBytes: stat.size } };
249
288
  }
250
289
  async function statFile(file) {
@@ -261,8 +300,9 @@ function modelFiles(ref, siblings) {
261
300
  const shardSets = new Map();
262
301
  for (const sibling of siblings) {
263
302
  const name = sibling.rfilename;
264
- if (!/\.gguf$/i.test(name) || /mmproj/i.test(name))
303
+ if (!/\.gguf$/i.test(name) || /mmproj/i.test(name)) {
265
304
  continue;
305
+ }
266
306
  const shard = SHARD.exec(name);
267
307
  if (!shard) {
268
308
  singles.push({ ...fileOf(ref, sibling), members: [name] });
@@ -298,8 +338,9 @@ function modelProblem(header) {
298
338
  'This is a vision projection (mmproj), not a model. Add the model file and pass this as its projection.'
299
339
  ];
300
340
  }
301
- if (header.type === 'adapter')
341
+ if (header.type === 'adapter') {
302
342
  return ['not-a-model', 'This is a LoRA adapter, not a model.'];
343
+ }
303
344
  return null;
304
345
  }
305
346
  function isProjection(header) {
@@ -307,28 +348,32 @@ function isProjection(header) {
307
348
  }
308
349
  function taskTypeFor({ pipelineTag, tags = [], architecture }) {
309
350
  const tagged = [pipelineTag, ...tags].find((tag) => tag !== undefined && Object.hasOwn(PIPELINE_TASKS, tag));
310
- if (tagged)
351
+ if (tagged) {
311
352
  return PIPELINE_TASKS[tagged];
353
+ }
312
354
  return ARCHITECTURE_TASKS.find(([pattern]) => pattern.test(architecture ?? ''))?.[1] ?? 'llm';
313
355
  }
314
- async function assess(file, header, taskType, deps) {
315
- if (taskType !== 'llm')
356
+ async function assess({ file, header }, taskType, deps) {
357
+ if (taskType !== 'llm') {
316
358
  return { fit: 'unknown', fitReasons: [NOT_LLM_REASON] };
317
- if (!file.sha256)
359
+ }
360
+ if (!file.sha256) {
318
361
  return { fit: 'unknown', fitReasons: [NO_CHECKSUM_REASON] };
319
- if (!deps.assessFit)
362
+ }
363
+ if (!deps.assessFit) {
320
364
  return { fit: 'unknown', fitReasons: [NO_ESTIMATOR_REASON] };
365
+ }
321
366
  try {
322
367
  return await deps.assessFit({
323
368
  sha256Checksum: file.sha256,
324
369
  name: header.name ?? file.label,
325
- contextTokens: Math.min(header.contextLength || defaultContextSize(file.src), defaultContextSize(file.src))
370
+ contextTokens: defaultContextSize(file.src, header.contextLength)
326
371
  });
327
372
  }
328
373
  catch (err) {
329
374
  return {
330
375
  fit: 'unknown',
331
- fitReasons: [`The fit estimate failed: ${err instanceof Error ? err.message : String(err)}`]
376
+ fitReasons: [`The fit estimate failed: ${errorMessage(err)}`]
332
377
  };
333
378
  }
334
379
  }
@@ -360,8 +405,9 @@ function wellFormedUrl(src) {
360
405
  }
361
406
  function licenseOf(info) {
362
407
  const license = info.cardData?.license;
363
- if (Array.isArray(license))
408
+ if (Array.isArray(license)) {
364
409
  return license.length ? license.join(', ') : undefined;
410
+ }
365
411
  return license || undefined;
366
412
  }
367
413
  function sizeOf(sibling) {
@@ -383,5 +429,11 @@ function answer(preview) {
383
429
  return { kind: 'answer', preview };
384
430
  }
385
431
  function defined(value) {
386
- return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
432
+ const copy = { ...value };
433
+ for (const [key, entry] of Object.entries(value)) {
434
+ if (entry === undefined) {
435
+ Reflect.deleteProperty(copy, key);
436
+ }
437
+ }
438
+ return copy;
387
439
  }
@@ -31,9 +31,9 @@ function verbalize(text, lang) {
31
31
  let spoken = text.replace(/#(?=\d)/g, ' number ');
32
32
  for (const [symbol, code] of CURRENCY_CODES) {
33
33
  spoken = spoken.replace(amountAfter(symbol), (_match, amount) => {
34
- return ` ${amount} ${currencyName(code, lang, amount === '1')} `;
34
+ return ` ${amount} ${currencyName(code, lang, { singular: amount === '1' })} `;
35
35
  });
36
- spoken = spoken.split(symbol).join(` ${currencyName(code, lang, false)} `);
36
+ spoken = spoken.split(symbol).join(` ${currencyName(code, lang)} `);
37
37
  }
38
38
  for (const [symbol, spokenForm] of SPEECH_LEXICON[lang]) {
39
39
  spoken = spoken.split(symbol).join(spokenForm);
@@ -46,11 +46,12 @@ function amountAfter(symbol) {
46
46
  function escapeRegExp(text) {
47
47
  return text.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
48
48
  }
49
- function currencyName(code, lang, singular) {
49
+ function currencyName(code, lang, { singular = false } = {}) {
50
50
  const key = `${lang}:${code}:${singular}`;
51
51
  const hit = CURRENCY_NAMES.get(key);
52
- if (hit !== undefined)
52
+ if (hit !== undefined) {
53
53
  return hit;
54
+ }
54
55
  const parts = new Intl.NumberFormat(lang, {
55
56
  style: 'currency',
56
57
  currency: code,
@@ -13,12 +13,10 @@ export function collectToolGrants(skills) {
13
13
  const owners = grants.grantedOwners.get(name) ?? new Set();
14
14
  owners.add(skill.name);
15
15
  grants.grantedOwners.set(name, owners);
16
- if (scope) {
17
- if (skill.cliValidator && skill.cliValidator.bin === scope.toLowerCase()) {
18
- const list = grants.grantedOps.get(scope.toLowerCase()) ?? [];
19
- list.push(skill.cliValidator);
20
- grants.grantedOps.set(scope.toLowerCase(), list);
21
- }
16
+ if (scope && skill.cliValidator && skill.cliValidator.bin === scope.toLowerCase()) {
17
+ const list = grants.grantedOps.get(scope.toLowerCase()) ?? [];
18
+ list.push(skill.cliValidator);
19
+ grants.grantedOps.set(scope.toLowerCase(), list);
22
20
  }
23
21
  }
24
22
  }
@@ -49,12 +47,15 @@ export function enabledTools(tools, { toolsSelected, allowlist, grantedNames, gr
49
47
  }
50
48
  if (tool.rootsRequired)
51
49
  return hasRoots;
52
- if (tool.writeRootsRequired)
50
+ if (tool.writeRootsRequired) {
53
51
  return hasWriteRoots;
54
- if (tool.skillGated)
52
+ }
53
+ if (tool.skillGated) {
55
54
  return loadedGrantedNames.has(tool.name);
56
- if (!toolsSelected)
55
+ }
56
+ if (!toolsSelected) {
57
57
  return true;
58
+ }
58
59
  return allowlist.includes(tool.name) || grantedNames.has(tool.name);
59
60
  });
60
61
  }
@@ -1,3 +1,4 @@
1
+ import { isRecord } from '../guards.js';
1
2
  import { SKILL_TOOL_NAME } from './tool-names.js';
2
3
  export const DIRECT_CALL_ID = 'call-direct';
3
4
  export const TOOL_CONTINUATION_NUDGE = "[Tool results above. Continue the user's request: call the next tool, or answer.]";
@@ -13,37 +14,43 @@ export function skillLoadedTurn(name) {
13
14
  function refFrom(value) {
14
15
  if (!value || typeof value !== 'object')
15
16
  return null;
16
- const record = value;
17
- if (typeof record.attachmentId !== 'string')
17
+ if (!('attachmentId' in value) || typeof value.attachmentId !== 'string') {
18
18
  return null;
19
- const ref = { attachmentId: record.attachmentId };
20
- const name = typeof record.fileName === 'string' ? record.fileName : '';
19
+ }
20
+ const ref = { attachmentId: value.attachmentId };
21
+ const name = 'fileName' in value && typeof value.fileName === 'string' ? value.fileName : '';
21
22
  const dot = name.lastIndexOf('.');
22
- if (dot > 0)
23
+ if (dot > 0) {
23
24
  ref.type = name.slice(dot + 1).toLowerCase();
25
+ }
24
26
  return ref;
25
27
  }
26
28
  export function attachmentTurn(name, result) {
27
29
  const direct = refFrom(result);
28
- if (direct)
30
+ if (direct) {
29
31
  return toolResultTurn(name, DIRECT_CALL_ID, direct);
30
- const listed = result?.attachments;
31
- if (!Array.isArray(listed))
32
+ }
33
+ const listed = isRecord(result) ? result.attachments : undefined;
34
+ if (!Array.isArray(listed)) {
32
35
  return null;
36
+ }
33
37
  const refs = [];
34
38
  for (const entry of listed) {
35
39
  const ref = refFrom(entry);
36
- if (ref)
40
+ if (ref) {
37
41
  refs.push(ref);
42
+ }
38
43
  }
39
- if (!refs.length)
44
+ if (!refs.length) {
40
45
  return null;
46
+ }
41
47
  return toolResultTurn(name, DIRECT_CALL_ID, { attachments: refs });
42
48
  }
43
49
  export function loadedSkillsFrom(messages) {
44
50
  const loaded = new Set();
45
- for (const { name } of skillLoadPayloads(messages))
51
+ for (const { name } of skillLoadPayloads(messages)) {
46
52
  loaded.add(name);
53
+ }
47
54
  return loaded;
48
55
  }
49
56
  export function loadedSkillFilesFrom(messages) {
@@ -66,21 +73,27 @@ export function withoutSkillLoadTurns(messages, name) {
66
73
  function* skillLoadPayloads(messages) {
67
74
  for (const turn of messages) {
68
75
  const payload = skillLoadPayload(turn);
69
- if (payload)
76
+ if (payload) {
70
77
  yield payload;
78
+ }
71
79
  }
72
80
  }
73
81
  function skillLoadPayload(turn) {
74
82
  if (turn.role !== 'tool')
75
83
  return null;
76
84
  const text = String(turn.content ?? '');
77
- if (!text.startsWith(`[Tool: ${SKILL_TOOL_NAME} (`))
85
+ if (!text.startsWith(`[Tool: ${SKILL_TOOL_NAME} (`)) {
78
86
  return null;
87
+ }
79
88
  try {
80
89
  const payload = JSON.parse(text.slice(text.indexOf('\n') + 1));
81
- if (typeof payload.name !== 'string')
90
+ if (typeof payload !== 'object' || payload === null) {
82
91
  return null;
83
- return typeof payload.file === 'string'
92
+ }
93
+ if (!('name' in payload) || typeof payload.name !== 'string') {
94
+ return null;
95
+ }
96
+ return 'file' in payload && typeof payload.file === 'string'
84
97
  ? { name: payload.name, file: payload.file }
85
98
  : { name: payload.name };
86
99
  }
@@ -95,7 +108,8 @@ function historyPayload(output) {
95
108
  if (!HOST_ONLY_KEYS.some((key) => key in output))
96
109
  return output;
97
110
  const rest = { ...output };
98
- for (const key of HOST_ONLY_KEYS)
111
+ for (const key of HOST_ONLY_KEYS) {
99
112
  delete rest[key];
113
+ }
100
114
  return rest;
101
115
  }
@@ -27,8 +27,9 @@ export function usageBreakdown(chars, totalTokens, modelName) {
27
27
  : 0
28
28
  };
29
29
  const prompt = rows.systemPrompt + rows.agentInstructions + rows.activeSkills + rows.tools;
30
- if (prompt > totalTokens)
30
+ if (prompt > totalTokens) {
31
31
  return scaledToWindow(rows, totalTokens);
32
+ }
32
33
  return { ...rows, conversation: totalTokens - prompt, totalTokens };
33
34
  }
34
35
  function scaledToWindow(rows, totalTokens) {
@@ -71,7 +71,11 @@ export interface SpeakStreamContext {
71
71
  export type VoiceLane = <T>(job: () => Promise<T>) => Promise<T>;
72
72
  export declare function createVoiceLane(): VoiceLane;
73
73
  export declare function transcribeOnce(sdk: VoiceSdk, modelId: string, audio: Buffer): Promise<string>;
74
- export declare function transcribeStreaming(sdk: VoiceSdk, modelId: string, pcm: Buffer, signal?: BareAbortSignal): Promise<string>;
74
+ export interface TranscribeStreamingOptions {
75
+ modelId: string;
76
+ signal?: BareAbortSignal | undefined;
77
+ }
78
+ export declare function transcribeStreaming(sdk: VoiceSdk, pcm: Uint8Array, { modelId, signal }: TranscribeStreamingOptions): Promise<string>;
75
79
  export declare function speakStreamOnce(sdk: VoiceSdk, modelId: string, text: AsyncIterable<string>): AsyncGenerator<SpeakResult>;
76
80
  export declare function speakable(text: string): string;
77
81
  export declare function speakOnce(sdk: VoiceSdk, modelId: string, text: string): Promise<number[]>;