@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
@@ -5,8 +5,9 @@ function isTurnBoundary(message) {
5
5
  }
6
6
  export function contextCandidates(history) {
7
7
  const { prefix, turns } = splitTurns(history);
8
- if (!turns.length)
8
+ if (!turns.length) {
9
9
  return [{ history, droppedTurns: 0 }];
10
+ }
10
11
  const maxDropped = Math.max(0, turns.length - 1);
11
12
  const candidates = dropCounts(maxDropped).map((droppedTurns) => ({
12
13
  history: droppedTurns ? [...prefix, ...turns.slice(droppedTurns).flat()] : history,
@@ -17,57 +18,60 @@ export function contextCandidates(history) {
17
18
  }
18
19
  function splitTurns(history) {
19
20
  const firstUser = history.findIndex(isTurnBoundary);
20
- if (firstUser === -1)
21
+ if (firstUser === -1) {
21
22
  return { prefix: history, turns: [] };
23
+ }
22
24
  const prefix = history.slice(0, firstUser);
23
25
  const starts = [];
24
- for (let i = firstUser; i < history.length; i++) {
25
- if (isTurnBoundary(history[i]))
26
+ for (const [i, message] of history.entries()) {
27
+ if (i >= firstUser && isTurnBoundary(message)) {
26
28
  starts.push(i);
29
+ }
27
30
  }
28
31
  const turns = starts.map((start, index) => history.slice(start, starts[index + 1]));
29
32
  return { prefix, turns };
30
33
  }
31
34
  function dropCounts(max) {
32
35
  const counts = [0];
33
- for (let step = 1; counts[counts.length - 1] < max; step *= 2) {
36
+ let last = 0;
37
+ for (let step = 1; last < max; step *= 2) {
34
38
  const next = Math.min(max, step);
35
- if (next !== counts[counts.length - 1])
36
- counts.push(next);
39
+ if (next === last) {
40
+ continue;
41
+ }
42
+ counts.push(next);
43
+ last = next;
37
44
  }
38
45
  return counts;
39
46
  }
40
47
  function appendToolCompactions(candidates) {
41
48
  const last = candidates[candidates.length - 1];
42
- if (!last)
49
+ if (!last) {
43
50
  return;
51
+ }
44
52
  const tools = compactableTools(last.history);
45
53
  let history = last.history;
46
54
  while (true) {
47
55
  const selected = longestTool(tools);
48
- if (!selected)
56
+ if (!selected) {
49
57
  return;
58
+ }
50
59
  selected.target = Math.max(TOOL_RESULT_TRUNCATION_MARKER.length, Math.floor(selected.target / 2));
51
60
  history = history.map(compactTool.bind(null, selected));
52
61
  candidates.push({ history, droppedTurns: last.droppedTurns });
53
62
  }
54
63
  }
55
64
  function compactableTools(history) {
56
- let newestUser = -1;
57
- for (let index = history.length - 1; index >= 0; index--) {
58
- if (!isTurnBoundary(history[index]))
59
- continue;
60
- newestUser = index;
61
- break;
62
- }
63
- if (newestUser === -1)
65
+ const newestUser = history.findLastIndex(isTurnBoundary);
66
+ if (newestUser === -1) {
64
67
  return [];
68
+ }
65
69
  const tools = [];
66
- for (let index = newestUser + 1; index < history.length; index++) {
67
- const message = history[index];
68
- if (message.role !== 'tool' || message.content.length <= TOOL_RESULT_TRUNCATION_MARKER.length) {
70
+ for (const [index, message] of history.entries()) {
71
+ if (index <= newestUser || message.role !== 'tool')
72
+ continue;
73
+ if (message.content.length <= TOOL_RESULT_TRUNCATION_MARKER.length)
69
74
  continue;
70
- }
71
75
  tools.push({ index, original: message.content, target: message.content.length });
72
76
  }
73
77
  return tools;
@@ -165,6 +165,24 @@ export interface CapabilityInfo {
165
165
  recommendedModelName: string;
166
166
  memoryBudget?: MemoryBudget;
167
167
  }
168
+ export interface CredentialEntry {
169
+ key: string;
170
+ token?: string | null;
171
+ expiresAt?: number | null;
172
+ agentId?: string | null;
173
+ skill?: string | null;
174
+ }
175
+ export interface SkillsOptions {
176
+ readonly refresh?: boolean;
177
+ readonly skipCredentialProbe?: boolean;
178
+ }
179
+ export interface SkillWriteResult {
180
+ ok: boolean;
181
+ }
182
+ export interface InfraModel {
183
+ name: string;
184
+ addon: string;
185
+ }
168
186
  export interface HarnessContract {
169
187
  completion(context: CompletionContext): AsyncIterable<HarnessEvent>;
170
188
  invoke?(context: InvokeContext): AsyncIterable<HarnessEvent>;
@@ -183,24 +201,16 @@ export interface HarnessContract {
183
201
  suspend?(): Promise<void> | void;
184
202
  wakeup?(): Promise<void> | void;
185
203
  resume?(): Promise<void> | void;
186
- skills?(agentId?: string | null, modelName?: string | null, options?: {
187
- readonly refresh?: boolean;
188
- readonly skipCredentialProbe?: boolean;
189
- }): Promise<ResolvedSkillCatalogEntry[]>;
204
+ skills?(agentId?: string | null, modelName?: string | null, options?: SkillsOptions): Promise<ResolvedSkillCatalogEntry[]>;
190
205
  tools?(): Promise<ToolCatalogEntry[]>;
191
- setCredentials?(entries: ReadonlyArray<{
192
- key: string;
193
- token?: string | null;
194
- expiresAt?: number | null;
195
- agentId?: string | null;
196
- skill?: string | null;
197
- }>): void | Promise<void>;
206
+ setCredentials?(entries: ReadonlyArray<CredentialEntry>): void | Promise<void>;
198
207
  setSkillSettings?(entries: ReadonlyArray<{
199
208
  skill: string;
200
209
  key: string;
201
210
  value: string;
202
211
  agentId?: string | null;
203
212
  }>): void | Promise<void>;
213
+ setModelIdleTimeout?(ms: number): void | Promise<void>;
204
214
  listManagedSkills?(): Promise<ManagedSkill[]>;
205
215
  readSkillFile?(name: string): Promise<SkillFileContent | null>;
206
216
  writeSkillFile?(name: string, content: string): Promise<{
@@ -217,10 +227,7 @@ export interface HarnessContract {
217
227
  deleteModel?(name: string): Promise<DeleteModelSummary>;
218
228
  clearKvCache?(): Promise<KvCacheDeletionResult>;
219
229
  deleteKvCache?(kvCacheKey: string): Promise<KvCacheDeletionResult>;
220
- infraModels?(profile: string): Promise<ReadonlyArray<{
221
- name: string;
222
- addon: string;
223
- }>>;
230
+ infraModels?(profile: string): Promise<ReadonlyArray<InfraModel>>;
224
231
  setCustomModels?(entries: ReadonlyArray<CustomModelEntry>): void | Promise<void>;
225
232
  previewModelSource?(context: PreviewModelSourceContext): Promise<ModelSourcePreview>;
226
233
  capability?(): Promise<CapabilityInfo>;
@@ -4,18 +4,18 @@ export declare function diagramRepairPromptCount(content: string, parentRunId?:
4
4
  export declare function isDiagramRepairPrompt(content: string): boolean;
5
5
  export declare function completeMermaidDiagramCount(content: string): number;
6
6
  export declare function diagramRepairAccepted(text: string): boolean;
7
- type DiagramRepairRecord = {
7
+ interface DiagramRepairRecord {
8
8
  readonly id: string;
9
9
  readonly seq: number;
10
10
  readonly runId?: string | null;
11
11
  readonly parentId?: string | null;
12
- };
13
- export type DiagramRepairLink = {
12
+ }
13
+ export interface DiagramRepairLink {
14
14
  readonly expectedCount: number;
15
15
  readonly parentId: string;
16
16
  readonly promptId: string;
17
17
  readonly promptText: string;
18
18
  readonly runId: string;
19
- };
19
+ }
20
20
  export declare function diagramRepairLinks<T extends DiagramRepairRecord>(records: ReadonlyArray<T>, textOf: (record: T) => string | null): ReadonlyArray<DiagramRepairLink>;
21
21
  export {};
@@ -3,8 +3,9 @@ export const DIAGRAM_REPAIR_PROMPT_SUFFIX = 'Rewrite the complete previous answe
3
3
  'Common fixes: put every label with spaces or punctuation in double quotes like A["Send (HTTP)"]; never use lowercase end as a node label - write "End"; the first line inside the fence must be the diagram type; close the fence before any prose - never leave a sentence inside it; give every node a unique id.';
4
4
  export function diagramRepairPromptCount(content, parentRunId) {
5
5
  const match = /^<!-- qvac:diagram-repair:(\d+):([^\s>]+) -->\n(\d+) Mermaid diagram(?:s)? in your previous answer fail(?:s)? to render\.\n/.exec(content);
6
- if (!match || !content.endsWith(`\n\n${DIAGRAM_REPAIR_PROMPT_SUFFIX}`))
6
+ if (!match || !content.endsWith(`\n\n${DIAGRAM_REPAIR_PROMPT_SUFFIX}`)) {
7
7
  return null;
8
+ }
8
9
  const expected = Number(match[1]);
9
10
  return Number.isSafeInteger(expected) &&
10
11
  expected > 0 &&
@@ -31,8 +32,9 @@ export function diagramRepairLinks(records, textOf) {
31
32
  if (!child.runId || !child.parentId)
32
33
  return [];
33
34
  const parent = byId.get(child.parentId);
34
- if (!parent?.runId)
35
+ if (!parent?.runId) {
35
36
  return [];
37
+ }
36
38
  const prompt = [...ordered]
37
39
  .reverse()
38
40
  .find((candidate) => candidate.seq > parent.seq &&
@@ -41,8 +43,9 @@ export function diagramRepairLinks(records, textOf) {
41
43
  diagramRepairPromptCount(textOf(candidate) ?? '', parent.runId ?? undefined) !== null);
42
44
  const promptText = prompt ? textOf(prompt) : null;
43
45
  const expectedCount = diagramRepairPromptCount(promptText ?? '', parent.runId);
44
- if (prompt)
46
+ if (prompt) {
45
47
  used.add(prompt.id);
48
+ }
46
49
  return prompt && promptText && expectedCount
47
50
  ? [
48
51
  {
@@ -1,5 +1,6 @@
1
1
  import type { AbortSignal } from 'bare-abort-controller';
2
2
  export { closePythonWorker as closeDocxWorker } from '../tools/exec/adapters/python/worker/client.ts';
3
- export declare function extractDocxText(bytes: Uint8Array, fileName: string, options?: {
3
+ export interface DocxExtractOptions {
4
4
  readonly signal?: AbortSignal;
5
- }): Promise<string>;
5
+ }
6
+ export declare function extractDocxText(bytes: Uint8Array, fileName: string, options?: DocxExtractOptions): Promise<string>;
@@ -1,2 +1,3 @@
1
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
1
2
  export declare function errorMessage(err: unknown): string;
2
3
  export declare function errorCode(err: unknown): string | undefined;
@@ -1,3 +1,6 @@
1
+ export function isRecord(value) {
2
+ return typeof value === 'object' && value !== null;
3
+ }
1
4
  export function errorMessage(err) {
2
5
  return err instanceof Error ? err.message : String(err);
3
6
  }
@@ -13,8 +13,9 @@ function pickTier(availableBytes) {
13
13
  return 'xhigh';
14
14
  if (availableBytes >= 30 * GIB)
15
15
  return 'high';
16
- if (availableBytes >= 8 * GIB)
16
+ if (availableBytes >= 8 * GIB) {
17
17
  return 'mid';
18
+ }
18
19
  return 'low';
19
20
  }
20
21
  function tierProfile(budget) {
@@ -38,8 +39,9 @@ function recommend(budget) {
38
39
  async function probeSysfs(reads) {
39
40
  for (const path of SYSFS_VRAM_PATHS) {
40
41
  const raw = await reads.readFile(path);
41
- if (!raw)
42
+ if (!raw) {
42
43
  continue;
44
+ }
43
45
  const bytes = Number.parseInt(raw.trim(), 10);
44
46
  if (!Number.isNaN(bytes) && bytes > 0) {
45
47
  return { totalBytes: bytes, availableBytes: bytes, source: 'vram' };
@@ -50,25 +52,31 @@ async function probeSysfs(reads) {
50
52
  async function probeDesktop(reads) {
51
53
  const ram = reads.totalmem();
52
54
  const addon = probeWithAddon(await reads.readGpuStats(), ram);
53
- if (addon && addon.source === 'vram')
55
+ if (addon && addon.source === 'vram') {
54
56
  return addon;
57
+ }
55
58
  const nvidia = await reads.run('nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits');
56
59
  const nvidiaBudget = nvidia ? parseNvidiaSmiOutput(nvidia) : null;
57
- if (nvidiaBudget)
60
+ if (nvidiaBudget) {
58
61
  return nvidiaBudget;
62
+ }
59
63
  const rocm = await reads.run('rocm-smi --showmeminfo vram');
60
64
  const rocmBudget = rocm ? parseRocmSmiOutput(rocm) : null;
61
- if (rocmBudget)
65
+ if (rocmBudget) {
62
66
  return rocmBudget;
67
+ }
63
68
  const sysfs = await probeSysfs(reads);
64
- if (sysfs)
69
+ if (sysfs) {
65
70
  return sysfs;
71
+ }
66
72
  const registry = await reads.run(`powershell -Command "${WINDOWS_REGISTRY_QUERY}"`);
67
73
  const registryBudget = registry ? parseWindowsRegistryOutput(registry, ram) : null;
68
- if (registryBudget)
74
+ if (registryBudget) {
69
75
  return registryBudget;
70
- if (addon)
76
+ }
77
+ if (addon) {
71
78
  return addon;
79
+ }
72
80
  return { ...sharedRamBudget(ram), source: 'no-gpu' };
73
81
  }
74
82
  async function isPixel(reads) {
@@ -77,10 +85,12 @@ async function isPixel(reads) {
77
85
  }
78
86
  async function probeMemoryBudget(reads) {
79
87
  const os = reads.platform();
80
- if (os === 'android' || os === 'ios')
88
+ if (os === 'android' || os === 'ios') {
81
89
  return mobileBudget(reads.totalmem(), await isPixel(reads));
82
- if (os === 'darwin')
90
+ }
91
+ if (os === 'darwin') {
83
92
  return sharedRamBudget(reads.totalmem());
93
+ }
84
94
  return probeDesktop(reads);
85
95
  }
86
96
  function forcedProfile() {
@@ -19,14 +19,17 @@ const INTEGRATED_GPU = [
19
19
  ];
20
20
  const SOFTWARE_GPU = [/llvmpipe/i, /swrast/i, /mesa/i];
21
21
  export function classifyGpu(name) {
22
- for (const re of DISCRETE_GPU)
22
+ for (const re of DISCRETE_GPU) {
23
23
  if (re.test(name))
24
24
  return 'discrete';
25
- for (const re of INTEGRATED_GPU)
25
+ }
26
+ for (const re of INTEGRATED_GPU) {
26
27
  if (re.test(name))
27
28
  return 'integrated';
28
- for (const re of SOFTWARE_GPU)
29
+ }
30
+ for (const re of SOFTWARE_GPU) {
29
31
  if (re.test(name))
30
32
  return 'software';
33
+ }
31
34
  return 'integrated';
32
35
  }
@@ -12,8 +12,9 @@ const StatsSchema = z.object({
12
12
  function classifyBestDevice(devices, systemRamBytes) {
13
13
  for (const device of devices) {
14
14
  const cls = classifyGpu(device.name);
15
- if (cls === 'software')
15
+ if (cls === 'software') {
16
16
  continue;
17
+ }
17
18
  if (cls === 'discrete') {
18
19
  const vram = device.videoMemoryBytes;
19
20
  if (vram > systemRamBytes * IGPU_LIE_THRESHOLD) {
@@ -26,15 +27,18 @@ function classifyBestDevice(devices, systemRamBytes) {
26
27
  }
27
28
  export function probeWithAddon(rawStats, systemRamBytes) {
28
29
  const parsed = StatsSchema.safeParse(rawStats);
29
- if (!parsed.success)
30
+ if (!parsed.success) {
30
31
  return null;
32
+ }
31
33
  const devices = parsed.data.gpu?.devices ?? [];
32
- if (devices.length === 0)
34
+ if (devices.length === 0) {
33
35
  return null;
36
+ }
34
37
  const totalRamBytes = parsed.data.memory?.totalBytes ?? systemRamBytes;
35
38
  const best = classifyBestDevice(devices, totalRamBytes);
36
- if (best)
39
+ if (best) {
37
40
  return best;
41
+ }
38
42
  if (devices.every((device) => classifyGpu(device.name) === 'software')) {
39
43
  return { ...sharedRamBudget(totalRamBytes), source: 'software' };
40
44
  }
@@ -1,3 +1,4 @@
1
+ import b4a from 'b4a';
1
2
  import { spawn } from 'child_process';
2
3
  import os from 'os';
3
4
  import { readSystemStats } from '#hw-gpu-stats';
@@ -11,8 +12,9 @@ export function runGpuProbeIfRequested() {
11
12
  }
12
13
  export function parseGpuProbeOutput(output) {
13
14
  const line = output.trim().split('\n').at(-1) ?? '';
14
- if (line.length === 0)
15
+ if (line.length === 0) {
15
16
  return null;
17
+ }
16
18
  try {
17
19
  const parsed = JSON.parse(line);
18
20
  return typeof parsed === 'object' ? parsed : null;
@@ -32,7 +34,7 @@ export function spawnGpuProbe(entry = Bare.argv[1]) {
32
34
  resolve({ ok: false, stats: null });
33
35
  }, TIMEOUT_MS);
34
36
  child.stdout?.on('data', (chunk) => {
35
- output += Buffer.from(chunk).toString();
37
+ output += b4a.toString(chunk);
36
38
  });
37
39
  child.stderr?.on('data', () => { });
38
40
  child.on('error', () => {
@@ -1,22 +1,21 @@
1
1
  const os = require('os')
2
2
 
3
- // loaded on first read: the addon drags the graphics stack (and on Linux a
4
- // second LLVM) into whichever process imports it
3
+ // lazy: the addon drags the graphics stack (and on Linux a second LLVM) into its importer
5
4
  let GPUInfo
6
5
 
7
- // Shaped for probeWithAddon (gpu-probe-addon.ts): the probe only wants each
8
- // device's name and VRAM total, plus system RAM to catch integrated-GPU lies.
6
+ // system RAM is here to catch integrated-GPU lies
9
7
  exports.readSystemStats = function readSystemStats() {
10
8
  try {
11
9
  GPUInfo ??= require('bare-gpu-info')
12
10
  const info = new GPUInfo()
13
11
  try {
14
- const devices = []
15
- for (const gpu of info) {
16
- if (typeof gpu.memory !== 'number' || !gpu.name) continue
17
- devices.push({ name: gpu.name, videoMemoryBytes: gpu.memory })
12
+ const devices = [...info]
13
+ .filter((gpu) => typeof gpu.memory === 'number' && gpu.name)
14
+ .map((gpu) => ({ name: gpu.name, videoMemoryBytes: gpu.memory }))
15
+ if (devices.length === 0) {
16
+ return null
18
17
  }
19
- if (devices.length === 0) return null
18
+
20
19
  return { memory: { totalBytes: os.totalmem() }, gpu: { devices } }
21
20
  } finally {
22
21
  info.destroy()
@@ -7,25 +7,29 @@ export const IGPU_LIE_THRESHOLD = 0.9;
7
7
  export function parseNvidiaSmiOutput(stdout) {
8
8
  const firstLine = stdout.split('\n')[0] ?? '';
9
9
  const mib = Number.parseInt(firstLine, 10);
10
- if (Number.isNaN(mib) || mib <= 0)
10
+ if (Number.isNaN(mib) || mib <= 0) {
11
11
  return null;
12
+ }
12
13
  const bytes = mib * 1024 * 1024;
13
14
  return { totalBytes: bytes, availableBytes: bytes, source: 'vram', gpuClass: 'discrete' };
14
15
  }
15
16
  export function parseRocmSmiOutput(stdout) {
16
17
  const match = /Total.*?:\s*(\d+)/i.exec(stdout);
17
- if (!match)
18
+ if (!match) {
18
19
  return null;
20
+ }
19
21
  const bytes = Number.parseInt(match[1] ?? '', 10);
20
- if (Number.isNaN(bytes) || bytes <= 0)
22
+ if (Number.isNaN(bytes) || bytes <= 0) {
21
23
  return null;
24
+ }
22
25
  return { totalBytes: bytes, availableBytes: bytes, source: 'vram' };
23
26
  }
24
27
  export function parseWindowsRegistryOutput(stdout, systemRamBytes) {
25
28
  const firstLine = stdout.split('\n')[0] ?? '';
26
29
  const bytes = Number.parseInt(firstLine, 10);
27
- if (Number.isNaN(bytes) || bytes <= 0)
30
+ if (Number.isNaN(bytes) || bytes <= 0) {
28
31
  return null;
32
+ }
29
33
  if (bytes > systemRamBytes * IGPU_LIE_THRESHOLD) {
30
34
  return { ...sharedRamBudget(systemRamBytes), source: 'integrated' };
31
35
  }
@@ -7,14 +7,16 @@ export async function* bufferBurst(tokens, ms) {
7
7
  continue;
8
8
  }
9
9
  if (Date.now() >= deadline) {
10
- if (burst)
10
+ if (burst) {
11
11
  yield burst;
12
+ }
12
13
  burst = null;
13
14
  yield token;
14
15
  continue;
15
16
  }
16
17
  burst += token;
17
18
  }
18
- if (burst)
19
+ if (burst) {
19
20
  yield burst;
21
+ }
20
22
  }
@@ -19,14 +19,16 @@ export async function* stopAtControlToken(tokens, onStop) {
19
19
  const safe = scanner({ stop: STOP_MARKERS });
20
20
  for await (const token of tokens) {
21
21
  const shown = safe.push(token);
22
- if (shown)
22
+ if (shown) {
23
23
  yield shown;
24
+ }
24
25
  if (safe.stopped !== null) {
25
26
  onStop?.(safe.stopped);
26
27
  return;
27
28
  }
28
29
  }
29
30
  const rest = safe.flush();
30
- if (rest)
31
+ if (rest) {
31
32
  yield rest;
33
+ }
32
34
  }
@@ -1,6 +1,6 @@
1
- export type JoinGuard = {
1
+ export interface JoinGuard {
2
2
  readonly push: (text: string) => string;
3
3
  readonly cut: () => void;
4
4
  readonly flush: () => string;
5
- };
5
+ }
6
6
  export declare function createJoinGuard(markers: readonly string[]): JoinGuard;
@@ -30,8 +30,9 @@ export function createJoinGuard(markers) {
30
30
  function mend(text, at, markers) {
31
31
  for (;;) {
32
32
  const found = spanning(text, at, markers);
33
- if (found === null)
33
+ if (found === null) {
34
34
  return { text, at };
35
+ }
35
36
  text = text.slice(0, found.index) + text.slice(found.index + found.marker.length);
36
37
  at = found.index;
37
38
  }
@@ -39,8 +40,9 @@ function mend(text, at, markers) {
39
40
  function spanning(text, at, markers) {
40
41
  for (const marker of markers) {
41
42
  const index = text.indexOf(marker, Math.max(0, at - marker.length + 1));
42
- if (index !== -1 && index < at)
43
+ if (index !== -1 && index < at) {
43
44
  return { index, marker };
45
+ }
44
46
  }
45
47
  return null;
46
48
  }
@@ -5,8 +5,9 @@ export function createLoadStall(ms, message) {
5
5
  rejectStall = reject;
6
6
  });
7
7
  const arm = () => {
8
- if (timer !== null)
8
+ if (timer !== null) {
9
9
  clearTimeout(timer);
10
+ }
10
11
  timer = setTimeout(() => {
11
12
  rejectStall?.(new Error(message));
12
13
  }, ms);
@@ -15,8 +16,9 @@ export function createLoadStall(ms, message) {
15
16
  return {
16
17
  bump: arm,
17
18
  clear: () => {
18
- if (timer !== null)
19
+ if (timer !== null) {
19
20
  clearTimeout(timer);
21
+ }
20
22
  timer = null;
21
23
  },
22
24
  promise
@@ -1,5 +1,5 @@
1
- export type MarkupStreamFilter = {
1
+ export interface MarkupStreamFilter {
2
2
  readonly push: (token: string) => string;
3
3
  readonly flush: () => string;
4
- };
4
+ }
5
5
  export declare function createMarkupStreamFilter(): MarkupStreamFilter;
@@ -22,8 +22,9 @@ export function createMarkupStreamFilter() {
22
22
  for (;;) {
23
23
  const step = state.closer ? consumeSuppressed(state) : emitUntilOpener(state);
24
24
  out += step.out;
25
- if (step.done)
25
+ if (step.done) {
26
26
  return out;
27
+ }
27
28
  }
28
29
  },
29
30
  flush() {
@@ -52,8 +53,9 @@ function dropResumeNewline(state) {
52
53
  if (!state.stripNewline || state.buffer.length === 0)
53
54
  return;
54
55
  state.stripNewline = false;
55
- if (state.buffer[0] === '\n')
56
+ if (state.buffer[0] === '\n') {
56
57
  state.buffer = state.buffer.slice(1);
58
+ }
57
59
  }
58
60
  function emitUntilOpener(state) {
59
61
  dropResumeNewline(state);
@@ -63,8 +65,9 @@ function emitUntilOpener(state) {
63
65
  state.guard.cut();
64
66
  state.buffer = state.buffer.slice(marker.index + marker.marker.length);
65
67
  const closer = MARKUP_CLOSERS[marker.marker];
66
- if (closer === undefined)
68
+ if (closer === undefined) {
67
69
  state.stripNewline = true;
70
+ }
68
71
  state.closer = closer ?? null;
69
72
  return { out, done: false };
70
73
  }
@@ -8,8 +8,9 @@ export class AbortedError extends Error {
8
8
  export function raceAbort(promise, signal) {
9
9
  if (!signal)
10
10
  return promise;
11
- if (signal.aborted)
11
+ if (signal.aborted) {
12
12
  return Promise.reject(new AbortedError());
13
+ }
13
14
  return new Promise((resolve, reject) => {
14
15
  const onAbort = () => reject(new AbortedError());
15
16
  signal.addEventListener('abort', onAbort, { once: true });
@@ -0,0 +1,5 @@
1
+ export interface RaceTimeoutOptions<T> {
2
+ ms: number;
3
+ fallback: T;
4
+ }
5
+ export declare function raceTimeout<T>(pending: Promise<T>, { ms, fallback }: RaceTimeoutOptions<T>): Promise<T>;
@@ -0,0 +1,14 @@
1
+ export async function raceTimeout(pending, { ms, fallback }) {
2
+ let timer = null;
3
+ const expired = new Promise((resolve) => {
4
+ timer = setTimeout(() => resolve(fallback), ms);
5
+ });
6
+ try {
7
+ return await Promise.race([pending, expired]);
8
+ }
9
+ finally {
10
+ if (timer !== null) {
11
+ clearTimeout(timer);
12
+ }
13
+ }
14
+ }
@@ -9,6 +9,10 @@ export interface RunOutcomeFacts {
9
9
  readonly latestFailure: string | null;
10
10
  readonly confirmedWrites: ReadonlyArray<string>;
11
11
  }
12
+ export interface HistoryTurn {
13
+ readonly role: string;
14
+ readonly content: string;
15
+ }
12
16
  export interface RunOutcomeTracker {
13
17
  readonly confirmedWrites: string[];
14
18
  beginRound(): void;
@@ -20,14 +24,8 @@ export interface RunOutcomeTracker {
20
24
  export declare function createRunOutcomeTracker(): RunOutcomeTracker;
21
25
  export declare function normalizeToolExecutionOutcome(result: unknown, outcome: ToolExecutionOutcome): ToolExecutionOutcome;
22
26
  export declare function failureFromToolExecution(result: unknown, outcome: ToolExecutionOutcome): string | null;
23
- export declare function degenerateAnswer(outcome: Exclude<RunOutcome, 'answered'>, history: ReadonlyArray<{
24
- role: string;
25
- content: string;
26
- }>, facts?: RunOutcomeFacts): string;
27
- export declare function lastFailedToolAnswer(history: ReadonlyArray<{
28
- role: string;
29
- content: string;
30
- }>): string | null;
27
+ export declare function degenerateAnswer(outcome: Exclude<RunOutcome, 'answered'>, history: ReadonlyArray<HistoryTurn>, facts?: RunOutcomeFacts): string;
28
+ export declare function lastFailedToolAnswer(history: ReadonlyArray<HistoryTurn>): string | null;
31
29
  export declare function writeResult(output: unknown): string | null;
32
30
  export declare function unnamedWrites(answer: string, landed: ReadonlyArray<string>): ReadonlyArray<string>;
33
31
  export declare function writeReport(landed: ReadonlyArray<string>): string | null;