@qvac/harness 0.7.0 → 1.0.0-rc.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 (204) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/README.md +239 -2
  3. package/dist-lib/index.d.ts +58 -3
  4. package/dist-lib/index.js +736 -239
  5. package/dist-lib/lib/capabilities/completion-engine/abort-polyfill.d.ts +1 -0
  6. package/dist-lib/lib/capabilities/completion-engine/abort-polyfill.js +10 -0
  7. package/dist-lib/lib/capabilities/completion-engine/actors/answering.d.ts +3 -0
  8. package/dist-lib/lib/capabilities/completion-engine/actors/answering.js +17 -0
  9. package/dist-lib/lib/capabilities/completion-engine/actors/approval.d.ts +4 -0
  10. package/dist-lib/lib/capabilities/completion-engine/actors/approval.js +29 -0
  11. package/dist-lib/lib/capabilities/completion-engine/actors/direct-search.d.ts +4 -0
  12. package/dist-lib/lib/capabilities/completion-engine/actors/direct-search.js +73 -0
  13. package/dist-lib/lib/capabilities/completion-engine/actors/execute.d.ts +41 -0
  14. package/dist-lib/lib/capabilities/completion-engine/actors/execute.js +49 -0
  15. package/dist-lib/lib/capabilities/completion-engine/actors/executing.d.ts +3 -0
  16. package/dist-lib/lib/capabilities/completion-engine/actors/executing.js +102 -0
  17. package/dist-lib/lib/capabilities/completion-engine/actors/execution-plan.d.ts +47 -0
  18. package/dist-lib/lib/capabilities/completion-engine/actors/execution-plan.js +87 -0
  19. package/dist-lib/lib/capabilities/completion-engine/actors/finishing.d.ts +2 -0
  20. package/dist-lib/lib/capabilities/completion-engine/actors/finishing.js +32 -0
  21. package/dist-lib/lib/capabilities/completion-engine/actors/inspect-preload.d.ts +3 -0
  22. package/dist-lib/lib/capabilities/completion-engine/actors/inspect-preload.js +75 -0
  23. package/dist-lib/lib/capabilities/completion-engine/actors/inspecting.d.ts +3 -0
  24. package/dist-lib/lib/capabilities/completion-engine/actors/inspecting.js +152 -0
  25. package/dist-lib/lib/capabilities/completion-engine/actors/loading-skill.d.ts +3 -0
  26. package/dist-lib/lib/capabilities/completion-engine/actors/loading-skill.js +94 -0
  27. package/dist-lib/lib/capabilities/completion-engine/actors/preload-failure.d.ts +9 -0
  28. package/dist-lib/lib/capabilities/completion-engine/actors/preload-failure.js +11 -0
  29. package/dist-lib/lib/capabilities/completion-engine/actors/preloading.d.ts +3 -0
  30. package/dist-lib/lib/capabilities/completion-engine/actors/preloading.js +114 -0
  31. package/dist-lib/lib/capabilities/completion-engine/actors/preparing.d.ts +3 -0
  32. package/dist-lib/lib/capabilities/completion-engine/actors/preparing.js +198 -0
  33. package/dist-lib/lib/capabilities/completion-engine/actors/rejecting.d.ts +3 -0
  34. package/dist-lib/lib/capabilities/completion-engine/actors/rejecting.js +71 -0
  35. package/dist-lib/lib/capabilities/completion-engine/actors/rejection.d.ts +18 -0
  36. package/dist-lib/lib/capabilities/completion-engine/actors/rejection.js +70 -0
  37. package/dist-lib/lib/capabilities/completion-engine/actors/resolving.d.ts +3 -0
  38. package/dist-lib/lib/capabilities/completion-engine/actors/resolving.js +60 -0
  39. package/dist-lib/lib/capabilities/completion-engine/actors/stream.d.ts +21 -0
  40. package/dist-lib/lib/capabilities/completion-engine/actors/stream.js +48 -0
  41. package/dist-lib/lib/capabilities/completion-engine/actors/streaming.d.ts +3 -0
  42. package/dist-lib/lib/capabilities/completion-engine/actors/streaming.js +156 -0
  43. package/dist-lib/lib/capabilities/completion-engine/actors/wrap-up.d.ts +7 -0
  44. package/dist-lib/lib/capabilities/completion-engine/actors/wrap-up.js +61 -0
  45. package/dist-lib/lib/capabilities/completion-engine/driver.d.ts +25 -0
  46. package/dist-lib/lib/capabilities/completion-engine/driver.js +553 -0
  47. package/dist-lib/lib/capabilities/completion-engine/durable.d.ts +61 -0
  48. package/dist-lib/lib/capabilities/completion-engine/durable.js +150 -0
  49. package/dist-lib/lib/capabilities/completion-engine/operations.d.ts +6 -0
  50. package/dist-lib/lib/capabilities/completion-engine/operations.js +239 -0
  51. package/dist-lib/lib/capabilities/completion-engine/ports.d.ts +3 -0
  52. package/dist-lib/lib/capabilities/completion-engine/ports.js +267 -0
  53. package/dist-lib/lib/capabilities/completion-engine/session.d.ts +76 -0
  54. package/dist-lib/lib/capabilities/completion-engine/session.js +70 -0
  55. package/dist-lib/lib/capabilities/completion-loop/index.d.ts +80 -0
  56. package/dist-lib/lib/capabilities/completion-loop/index.js +158 -0
  57. package/dist-lib/lib/capabilities/completion-loop/metrics.d.ts +5 -0
  58. package/dist-lib/lib/capabilities/completion-loop/metrics.js +29 -0
  59. package/dist-lib/lib/capabilities/completion-loop/round.d.ts +33 -0
  60. package/dist-lib/lib/capabilities/completion-loop/round.js +353 -0
  61. package/dist-lib/lib/capabilities/completion-loop/tool-execution.d.ts +60 -0
  62. package/dist-lib/lib/capabilities/completion-loop/tool-execution.js +270 -0
  63. package/dist-lib/lib/capabilities/completion-loop/turns.d.ts +23 -0
  64. package/dist-lib/lib/capabilities/completion-loop/turns.js +112 -0
  65. package/dist-lib/lib/capabilities/completion-runtime.d.ts +46 -0
  66. package/dist-lib/lib/capabilities/completion-runtime.js +74 -0
  67. package/dist-lib/lib/capabilities/completion.d.ts +18 -335
  68. package/dist-lib/lib/capabilities/completion.js +20 -1301
  69. package/dist-lib/lib/capabilities/download.d.ts +1 -1
  70. package/dist-lib/lib/capabilities/download.js +7 -2
  71. package/dist-lib/lib/capabilities/invoke.js +5 -3
  72. package/dist-lib/lib/capabilities/tool-plan.d.ts +35 -0
  73. package/dist-lib/lib/capabilities/tool-plan.js +66 -0
  74. package/dist-lib/lib/capabilities/tool-turns.d.ts +11 -2
  75. package/dist-lib/lib/capabilities/tool-turns.js +30 -2
  76. package/dist-lib/lib/capabilities/types.d.ts +287 -0
  77. package/dist-lib/lib/capabilities/types.js +1 -0
  78. package/dist-lib/lib/completion-lifecycle.d.ts +14 -0
  79. package/dist-lib/lib/completion-lifecycle.js +126 -0
  80. package/dist-lib/lib/connect.d.ts +10 -3
  81. package/dist-lib/lib/connect.js +329 -23
  82. package/dist-lib/lib/contract-types.d.ts +19 -2
  83. package/dist-lib/lib/harness-lifecycle.d.ts +66 -0
  84. package/dist-lib/lib/harness-lifecycle.js +129 -0
  85. package/dist-lib/lib/helpers/detach-json.d.ts +1 -0
  86. package/dist-lib/lib/helpers/detach-json.js +146 -0
  87. package/dist-lib/lib/helpers/markup-scanner.d.ts +26 -0
  88. package/dist-lib/lib/helpers/markup-scanner.js +156 -0
  89. package/dist-lib/lib/helpers/markup-stream-filter.js +138 -35
  90. package/dist-lib/lib/helpers/race-abort.d.ts +9 -4
  91. package/dist-lib/lib/helpers/race-abort.js +2 -7
  92. package/dist-lib/lib/helpers/recovery-required.d.ts +1 -0
  93. package/dist-lib/lib/helpers/recovery-required.js +1 -0
  94. package/dist-lib/lib/helpers/run-outcome.d.ts +10 -2
  95. package/dist-lib/lib/helpers/run-outcome.js +8 -5
  96. package/dist-lib/lib/helpers/tool-call-markup.d.ts +2 -0
  97. package/dist-lib/lib/helpers/tool-call-markup.js +197 -82
  98. package/dist-lib/lib/hooks/built-in/arg-repair.d.ts +1 -0
  99. package/dist-lib/lib/hooks/built-in/arg-repair.js +1 -0
  100. package/dist-lib/lib/hooks/built-in/egress.d.ts +1 -0
  101. package/dist-lib/lib/hooks/built-in/egress.js +2 -1
  102. package/dist-lib/lib/hooks/built-in/sandbox.d.ts +1 -0
  103. package/dist-lib/lib/hooks/built-in/sandbox.js +6 -1
  104. package/dist-lib/lib/hooks/built-in/skill-catalog.d.ts +1 -0
  105. package/dist-lib/lib/hooks/built-in/skill-catalog.js +2 -1
  106. package/dist-lib/lib/hooks/pipeline.d.ts +4 -1
  107. package/dist-lib/lib/hooks/pipeline.js +24 -2
  108. package/dist-lib/lib/hooks/run.d.ts +2 -1
  109. package/dist-lib/lib/hooks/run.js +19 -7
  110. package/dist-lib/lib/hooks/types.d.ts +17 -6
  111. package/dist-lib/lib/machine/completion/actions/approval.d.ts +3 -0
  112. package/dist-lib/lib/machine/completion/actions/approval.js +16 -0
  113. package/dist-lib/lib/machine/completion/actions/completion.d.ts +23 -0
  114. package/dist-lib/lib/machine/completion/actions/completion.js +142 -0
  115. package/dist-lib/lib/machine/completion/actions/skills.d.ts +9 -0
  116. package/dist-lib/lib/machine/completion/actions/skills.js +83 -0
  117. package/dist-lib/lib/machine/completion/actions/tools.d.ts +16 -0
  118. package/dist-lib/lib/machine/completion/actions/tools.js +173 -0
  119. package/dist-lib/lib/machine/completion/context.d.ts +9 -0
  120. package/dist-lib/lib/machine/completion/context.js +44 -0
  121. package/dist-lib/lib/machine/completion/contract.d.ts +6 -0
  122. package/dist-lib/lib/machine/completion/contract.js +1 -0
  123. package/dist-lib/lib/machine/completion/guards/retry.d.ts +9 -0
  124. package/dist-lib/lib/machine/completion/guards/retry.js +25 -0
  125. package/dist-lib/lib/machine/completion/implementations.d.ts +81 -0
  126. package/dist-lib/lib/machine/completion/implementations.js +152 -0
  127. package/dist-lib/lib/machine/completion/machine.d.ts +375 -0
  128. package/dist-lib/lib/machine/completion/machine.js +511 -0
  129. package/dist-lib/lib/machine/completion/ports.d.ts +65 -0
  130. package/dist-lib/lib/machine/completion/ports.js +224 -0
  131. package/dist-lib/lib/machine/completion/rules.d.ts +39 -0
  132. package/dist-lib/lib/machine/completion/rules.js +115 -0
  133. package/dist-lib/lib/machine/completion/types.d.ts +493 -0
  134. package/dist-lib/lib/machine/completion/types.js +1 -0
  135. package/dist-lib/lib/machine/engine.d.ts +93 -0
  136. package/dist-lib/lib/machine/engine.js +483 -0
  137. package/dist-lib/lib/machine/errors.d.ts +44 -0
  138. package/dist-lib/lib/machine/errors.js +373 -0
  139. package/dist-lib/lib/machine/guards.d.ts +2 -0
  140. package/dist-lib/lib/machine/guards.js +6 -0
  141. package/dist-lib/lib/machine/index.d.ts +20 -0
  142. package/dist-lib/lib/machine/index.js +11 -0
  143. package/dist-lib/lib/machine/replay-output.d.ts +24 -0
  144. package/dist-lib/lib/machine/replay-output.js +50 -0
  145. package/dist-lib/lib/machine/stable-stringify.d.ts +1 -0
  146. package/dist-lib/lib/machine/stable-stringify.js +11 -0
  147. package/dist-lib/lib/models/model-handle.d.ts +5 -1
  148. package/dist-lib/lib/models/model-handle.js +8 -3
  149. package/dist-lib/lib/models/model-list.d.ts +5 -3
  150. package/dist-lib/lib/models/model-pool.d.ts +18 -7
  151. package/dist-lib/lib/models/model-pool.js +126 -38
  152. package/dist-lib/lib/run-log/history-codec.d.ts +23 -0
  153. package/dist-lib/lib/run-log/history-codec.js +973 -0
  154. package/dist-lib/lib/run-log/patch.d.ts +6 -0
  155. package/dist-lib/lib/run-log/patch.js +93 -0
  156. package/dist-lib/lib/run-log/persisted-actor.d.ts +18 -0
  157. package/dist-lib/lib/run-log/persisted-actor.js +218 -0
  158. package/dist-lib/lib/run-log/protocol-types.d.ts +153 -0
  159. package/dist-lib/lib/run-log/protocol-types.js +1 -0
  160. package/dist-lib/lib/run-log/protocol.d.ts +27 -0
  161. package/dist-lib/lib/run-log/protocol.js +1056 -0
  162. package/dist-lib/lib/run-log/replay.d.ts +25 -0
  163. package/dist-lib/lib/run-log/replay.js +129 -0
  164. package/dist-lib/lib/run-log/run-journal.d.ts +125 -0
  165. package/dist-lib/lib/run-log/run-journal.js +783 -0
  166. package/dist-lib/lib/run-log-inspect.d.ts +25 -0
  167. package/dist-lib/lib/run-log-inspect.js +627 -0
  168. package/dist-lib/lib/run-log-protocol.d.ts +2 -0
  169. package/dist-lib/lib/run-log-protocol.js +1 -0
  170. package/dist-lib/lib/run-log-redact.d.ts +27 -0
  171. package/dist-lib/lib/run-log-redact.js +1107 -0
  172. package/dist-lib/lib/serve.js +308 -12
  173. package/dist-lib/lib/spawn.js +3 -2
  174. package/dist-lib/lib/tool-call-display.d.ts +1 -21
  175. package/dist-lib/lib/tools/exec.d.ts +2 -1
  176. package/dist-lib/lib/tools/exec.js +57 -2
  177. package/dist-lib/lib/tools/generate-image.js +1 -1
  178. package/dist-lib/lib/tools/generate-music.js +1 -1
  179. package/dist-lib/lib/tools/http-request.d.ts +2 -1
  180. package/dist-lib/lib/tools/http-request.js +2 -1
  181. package/dist-lib/lib/tools/mcp-call.js +8 -1
  182. package/dist-lib/lib/tools/operations/builders.d.ts +1 -0
  183. package/dist-lib/lib/tools/operations/builders.js +1 -0
  184. package/dist-lib/lib/tools/operations/compile.js +11 -1
  185. package/dist-lib/lib/tools/operations/manifest.js +1 -0
  186. package/dist-lib/lib/tools/outbound-guard.d.ts +8 -6
  187. package/dist-lib/lib/tools/outbound-guard.js +25 -8
  188. package/dist-lib/lib/tools/skills/catalog.d.ts +1 -0
  189. package/dist-lib/lib/tools/skills/catalog.js +35 -0
  190. package/dist-lib/lib/tools/skills/cli-schema-types.d.ts +1 -0
  191. package/dist-lib/lib/tools/skills/cli-schema.js +25 -0
  192. package/dist-lib/lib/wire.d.ts +5 -0
  193. package/dist-lib/lib/wire.js +128 -5
  194. package/dist-lib/schema/harness.js +22 -6
  195. package/dist-lib/spec/hrpc/messages.js +100 -18
  196. package/dist-lib/spec/hyperschema/index.js +100 -18
  197. package/dist-lib/spec/hyperschema/schema.json +74 -1
  198. package/dist-lib/spec/hyperschema/types.d.ts +11 -3
  199. package/package.json +19 -1
  200. package/patches/@qvac%2Finference@0.20.0.patch +67 -0
  201. package/patches/bare-stow@0.1.5.patch +68 -0
  202. package/patches/hypercore-blob-server@1.15.0.patch +15 -0
  203. package/patches/localwatch@1.4.3.patch +13 -0
  204. package/patches/pyodide@314.0.2.patch +144 -0
@@ -45,4 +45,4 @@ export type SdkOrLoader = DownloadSdk | (() => Promise<DownloadSdk>);
45
45
  export interface DownloadEventStream extends Readable {
46
46
  [Symbol.asyncIterator](): AsyncIterableIterator<DownloadEvent>;
47
47
  }
48
- export declare function download(sdkOrLoader: SdkOrLoader, args: DownloadArgs, onSettled?: () => void): DownloadEventStream;
48
+ export declare function download(sdkOrLoader: SdkOrLoader, args: DownloadArgs, onSettled?: () => void, onDrained?: () => void): DownloadEventStream;
@@ -2,7 +2,7 @@ import { Readable } from 'streamx';
2
2
  import { errorMessage } from '../guards.js';
3
3
  import { resolveModelSrc } from '../models/model-source.js';
4
4
  const noop = () => { };
5
- export function download(sdkOrLoader, args, onSettled) {
5
+ export function download(sdkOrLoader, args, onSettled, onDrained) {
6
6
  const { model, addon = 'llm', seed, signal, projection, companions = [], assetSizes } = args;
7
7
  const loadSdk = typeof sdkOrLoader === 'function' ? sdkOrLoader : () => Promise.resolve(sdkOrLoader);
8
8
  let transferred = false;
@@ -36,7 +36,9 @@ export function download(sdkOrLoader, args, onSettled) {
36
36
  };
37
37
  const start = async () => {
38
38
  if (signal?.aborted) {
39
- return finish({ type: 'aborted' });
39
+ finish({ type: 'aborted' });
40
+ onDrained?.();
41
+ return;
40
42
  }
41
43
  try {
42
44
  sdkRef = await loadSdk();
@@ -86,6 +88,9 @@ export function download(sdkOrLoader, args, onSettled) {
86
88
  }
87
89
  finish({ type: 'error', message: errorMessage(err) });
88
90
  }
91
+ finally {
92
+ onDrained?.();
93
+ }
89
94
  };
90
95
  const stream = new Readable({
91
96
  open(cb) {
@@ -1,5 +1,6 @@
1
1
  import { errorMessage } from '../guards.js';
2
2
  import { AbortedError } from '../helpers/race-abort.js';
3
+ import { detachJson } from '../helpers/detach-json.js';
3
4
  const CAPABILITY_TOOLS = {
4
5
  image: { tool: 'generate_image', enhances: 'prompt' },
5
6
  translate: { tool: 'translate' }
@@ -34,13 +35,14 @@ export async function* invoke({ capability, args, tools, ctx, enhance = 'never',
34
35
  if (ctx.signal?.aborted) {
35
36
  return yield { type: 'aborted' };
36
37
  }
37
- yield { type: 'tool-call', name: entry.tool, args: called, effect: tool.effect(called, ctx) };
38
+ const effect = tool.effect(detachJson(called), ctx);
39
+ yield { type: 'tool-call', name: entry.tool, args: detachJson(called), effect };
38
40
  try {
39
- const result = await tool.execute(called, ctx);
41
+ const result = await tool.execute(detachJson(called), ctx);
40
42
  if (ctx.signal?.aborted) {
41
43
  return yield { type: 'aborted' };
42
44
  }
43
- yield { type: 'tool-result', name: entry.tool, result };
45
+ yield { type: 'tool-result', name: entry.tool, result: detachJson(result) };
44
46
  }
45
47
  catch (err) {
46
48
  if (err instanceof AbortedError || ctx.signal?.aborted) {
@@ -0,0 +1,35 @@
1
+ import type { ToolEffect, ToolExecuteContext } from './completion.ts';
2
+ import type { CompletionSkillEntry, ResolvedCall } from './completion-loop/index.ts';
3
+ import { type SkillActivation } from './tool-selection.ts';
4
+ import type { HookRejection, ResolvedCallSnapshot } from '../machine/index.ts';
5
+ export interface ToolPolicyFacts {
6
+ readonly call: ResolvedCallSnapshot;
7
+ readonly toolAvailable: boolean;
8
+ readonly skillCall: boolean;
9
+ readonly skillAlreadyLoaded: boolean;
10
+ readonly skillStatus: string | null;
11
+ readonly skillActive: boolean;
12
+ readonly skillName: string;
13
+ readonly alreadyLoadedLabel: string;
14
+ readonly unavailableSkillMessage: string;
15
+ readonly searchCapReached: boolean;
16
+ readonly searchCapMessage: string;
17
+ readonly hookRejection: HookRejection | null;
18
+ readonly source: 'skill' | 'tool-result';
19
+ readonly effect: ToolEffect | undefined;
20
+ }
21
+ export interface PlanToolCallOptions {
22
+ readonly activation: SkillActivation;
23
+ readonly skillCatalog: readonly CompletionSkillEntry[];
24
+ readonly loadedThisTurn: ReadonlySet<string>;
25
+ readonly loadedFilesThisTurn: ReadonlySet<string>;
26
+ readonly webSearches: number;
27
+ readonly context: ToolExecuteContext;
28
+ readonly listShown: boolean;
29
+ }
30
+ interface KeyedResolvedCall extends ResolvedCall {
31
+ key: string;
32
+ }
33
+ export declare function planToolCall(resolved: KeyedResolvedCall, opts: PlanToolCallOptions): ToolPolicyFacts;
34
+ export declare function skillFileKey(skillName: string, args: Record<string, unknown>): string | null;
35
+ export {};
@@ -0,0 +1,66 @@
1
+ import { MAX_WEB_SEARCHES_PER_TURN, unreadySkillState, WEB_SEARCH_LIMIT_MESSAGE } from './completion-loop/index.js';
2
+ import { unquoteArg } from '../tools/model-args.js';
3
+ import { mainFileRequested, skillFileArg, skillFileStem } from '../tools/skill.js';
4
+ import { SKILL_TOOL_NAME, WEB_SEARCH_TOOL_NAME } from './tool-names.js';
5
+ import { skillIsActive } from './tool-selection.js';
6
+ import { detachJson } from '../helpers/detach-json.js';
7
+ function skillCallFacts({ skillCall, skillName, args, fileKey, tool, reloaded, opts }) {
8
+ const skillActive = skillIsActive(skillName, opts.activation);
9
+ return {
10
+ skillAlreadyLoaded: tool?.name === SKILL_TOOL_NAME && reloaded,
11
+ skillStatus: skillCall ? unreadySkillState(skillName, opts.skillCatalog) : null,
12
+ skillActive,
13
+ skillName: tool?.name === SKILL_TOOL_NAME ? skillName : '',
14
+ alreadyLoadedLabel: fileKey === null ? skillName : `${skillName} ${unquoteArg(skillFileArg(args))}`,
15
+ unavailableSkillMessage: skillCall && (!tool || !skillActive)
16
+ ? blockedSkillMessage(skillName, opts.skillCatalog, opts.listShown)
17
+ : ''
18
+ };
19
+ }
20
+ function blockedSkillMessage(name, catalog, listShown) {
21
+ if (catalog.some((entry) => entry.name === name)) {
22
+ return (`skill "${name}" is not enabled for this agent. Do not rebuild what it does with another ` +
23
+ `tool — answer from what you already have, or tell the user to enable it in Skills.`);
24
+ }
25
+ return listShown
26
+ ? `there is no skill named "${name}". Load one from the skills list you were shown, or ` +
27
+ `answer from what you already have — do not guess another name.`
28
+ : `there is no skill named "${name}". You were not shown a skills list, which means no ` +
29
+ `skill is available this turn — do not guess another name, and answer from what you ` +
30
+ `already have.`;
31
+ }
32
+ export function planToolCall(resolved, opts) {
33
+ const { call, tool, args, rejection } = resolved;
34
+ const skillCall = call.name === SKILL_TOOL_NAME;
35
+ const effect = tool?.effect(detachJson(args), opts.context) ?? (skillCall ? 'read' : undefined);
36
+ const source = skillCall ? 'skill' : 'tool-result';
37
+ const skillName = unquoteArg(args.name ?? args.skill_name ?? args.skill);
38
+ const fileKey = skillFileKey(skillName, args);
39
+ const reloaded = fileKey === null ? opts.loadedThisTurn.has(skillName) : opts.loadedFilesThisTurn.has(fileKey);
40
+ const skillFacts = skillCallFacts({ skillCall, skillName, args, fileKey, tool, reloaded, opts });
41
+ return {
42
+ call: {
43
+ id: call.id,
44
+ key: resolved.key,
45
+ name: call.name,
46
+ args,
47
+ rawCall: call.raw,
48
+ intent: resolved.intent,
49
+ rejection
50
+ },
51
+ toolAvailable: Boolean(tool),
52
+ skillCall,
53
+ ...skillFacts,
54
+ searchCapReached: tool?.name === WEB_SEARCH_TOOL_NAME && opts.webSearches >= MAX_WEB_SEARCHES_PER_TURN,
55
+ searchCapMessage: WEB_SEARCH_LIMIT_MESSAGE,
56
+ hookRejection: rejection ?? null,
57
+ source,
58
+ effect
59
+ };
60
+ }
61
+ export function skillFileKey(skillName, args) {
62
+ const file = skillFileArg(args);
63
+ return mainFileRequested(skillName, file)
64
+ ? null
65
+ : `${skillName}\0${skillFileStem(unquoteArg(file))}`;
66
+ }
@@ -1,9 +1,18 @@
1
1
  import type { Message } from './completion.ts';
2
+ import { type CompletionHistoryEntry, type FailureResultValue } from '../machine/index.ts';
2
3
  export declare const DIRECT_CALL_ID = "call-direct";
3
- export declare const TOOL_CONTINUATION_NUDGE = "[Tool results above. Continue the user's request: call the next tool, or answer.]";
4
+ export { TOOL_CONTINUATION_NUDGE } from '../machine/index.ts';
4
5
  export declare function toolResultTurn(name: string, id: string, output: unknown): string;
6
+ interface ToolResultHistoryInput {
7
+ name: string;
8
+ id: string;
9
+ output: unknown;
10
+ resultRef?: string;
11
+ }
12
+ export declare function toolResultHistoryEntry({ name, id, output, resultRef }: ToolResultHistoryInput): CompletionHistoryEntry;
13
+ export declare function materializeCompletionHistory(history: readonly CompletionHistoryEntry[], values: Readonly<Record<string, FailureResultValue>>): Message[];
5
14
  export declare function skillLoadedTurn(name: string): string;
6
15
  export declare function attachmentTurn(name: string, result: unknown): string | null;
7
16
  export declare function loadedSkillsFrom(messages: readonly Message[]): Set<string>;
8
17
  export declare function loadedSkillFilesFrom(messages: readonly Message[]): Map<string, Set<string>>;
9
- export declare function withoutSkillLoadTurns(messages: readonly Message[], name: string): Message[];
18
+ export declare function withoutSkillLoadTurns(messages: readonly CompletionHistoryEntry[], name: string): CompletionHistoryEntry[];
@@ -1,10 +1,35 @@
1
1
  import { isRecord } from '../guards.js';
2
2
  import { SKILL_TOOL_NAME } from './tool-names.js';
3
+ import { isFailureResultReference, readFailureResult } from '../machine/index.js';
3
4
  export const DIRECT_CALL_ID = 'call-direct';
4
- export const TOOL_CONTINUATION_NUDGE = "[Tool results above. Continue the user's request: call the next tool, or answer.]";
5
+ export { TOOL_CONTINUATION_NUDGE } from '../machine/index.js';
5
6
  export function toolResultTurn(name, id, output) {
6
7
  return `[Tool: ${name} (${id})]\n${JSON.stringify(historyPayload(output))}`;
7
8
  }
9
+ export function toolResultHistoryEntry({ name, id, output, resultRef }) {
10
+ return resultRef
11
+ ? {
12
+ type: 'qvac-failure-result-ref',
13
+ ref: resultRef,
14
+ callId: id
15
+ }
16
+ : { role: 'tool', content: toolResultTurn(name, id, output) };
17
+ }
18
+ export function materializeCompletionHistory(history, values) {
19
+ return history.map((entry) => {
20
+ if (!isFailureResultReference(entry)) {
21
+ return entry;
22
+ }
23
+ const stored = values[entry.ref];
24
+ if (!stored) {
25
+ throw new Error(`History references missing failed tool result: ${entry.ref}`);
26
+ }
27
+ return {
28
+ role: 'tool',
29
+ content: toolResultTurn(stored.name, entry.callId, readFailureResult(stored.result))
30
+ };
31
+ });
32
+ }
8
33
  export function skillLoadedTurn(name) {
9
34
  return toolResultTurn(SKILL_TOOL_NAME, DIRECT_CALL_ID, {
10
35
  name,
@@ -12,8 +37,9 @@ export function skillLoadedTurn(name) {
12
37
  });
13
38
  }
14
39
  function refFrom(value) {
15
- if (!value || typeof value !== 'object')
40
+ if (!value || typeof value !== 'object') {
16
41
  return null;
42
+ }
17
43
  if (!('attachmentId' in value) || typeof value.attachmentId !== 'string') {
18
44
  return null;
19
45
  }
@@ -66,6 +92,8 @@ export function loadedSkillFilesFrom(messages) {
66
92
  }
67
93
  export function withoutSkillLoadTurns(messages, name) {
68
94
  return messages.filter((turn) => {
95
+ if (isFailureResultReference(turn))
96
+ return true;
69
97
  const payload = skillLoadPayload(turn);
70
98
  return !payload || payload.name !== name || payload.file !== undefined;
71
99
  });
@@ -0,0 +1,287 @@
1
+ import type { CompletionFinal, Tool as SdkTool, ToolDialect } from '@qvac/sdk';
2
+ import type { AbortSignal as BareAbortSignal } from 'bare-abort-controller';
3
+ import type { TextEvent } from '../helpers/thinking.ts';
4
+ import type { LlmGenerationParams } from '../models/llm-presets.ts';
5
+ import type { DriveRoot } from '../tools/fs/scope.ts';
6
+ import type { CliValidator } from '../tools/skills/cli-schema.ts';
7
+ import type { Toolset } from '../tools/toolsets.ts';
8
+ import type { ToolCallDisplay } from '../tool-call-display.ts';
9
+ import type { UsageBreakdown } from './usage-breakdown.ts';
10
+ import type { Message, ResourceDescriptor, RunBackendUse, RunBudget, RunLifecycleEvent, ToolActivityEvent, ToolDecision, ToolEffect } from '../machine/index.ts';
11
+ export type { Message, ResourceDescriptor, RunBackendUse, RunBudget, RunLifecycleEvent, ToolActivityEvent, ToolDecision, ToolEffect };
12
+ export interface Agent {
13
+ id?: string;
14
+ name?: string;
15
+ bio?: string;
16
+ enabledTools?: string[] | null;
17
+ enabledSkills?: string[] | null;
18
+ toolsScope?: 'all' | 'selected' | null;
19
+ skillsScope?: 'all' | 'selected' | null;
20
+ reasoning?: 'inherit' | 'enabled' | 'disabled' | null;
21
+ ctxSize?: number | null;
22
+ kvCacheK?: string | null;
23
+ kvCacheV?: string | null;
24
+ imageModelChoice?: string | null;
25
+ imageSteps?: number | null;
26
+ imageWidth?: number | null;
27
+ imageHeight?: number | null;
28
+ approvalMode?: 'ask' | 'skip-all' | null;
29
+ disabledToolsets?: string[] | null;
30
+ sandboxMode?: boolean | null;
31
+ }
32
+ export interface ImageSettings {
33
+ modelChoice?: string;
34
+ steps?: number;
35
+ width?: number;
36
+ height?: number;
37
+ }
38
+ export interface MusicSettings {
39
+ modelChoice?: string;
40
+ steps?: number;
41
+ duration?: number;
42
+ }
43
+ export type ApproveFn = (call: {
44
+ name: string;
45
+ arguments: Record<string, unknown>;
46
+ callId?: string;
47
+ round?: number;
48
+ resource?: ResourceDescriptor | null;
49
+ effect?: ToolEffect;
50
+ intent?: string | null;
51
+ display?: ToolCallDisplay | null;
52
+ }) => Promise<boolean>;
53
+ export type ToolActivityFn = (entry: ToolActivityEvent) => void;
54
+ export interface AttachInput {
55
+ fileName: string;
56
+ mimeType: string;
57
+ bytes: Uint8Array;
58
+ raw?: boolean;
59
+ }
60
+ export interface AttachmentRecord {
61
+ id: string;
62
+ fileName: string;
63
+ mimeType: string;
64
+ byteLength: number;
65
+ }
66
+ export type AttachFn = (input: AttachInput) => Promise<AttachmentRecord>;
67
+ export interface AttachmentMeta {
68
+ id: string;
69
+ fileName: string;
70
+ mimeType: string;
71
+ byteLength: number;
72
+ }
73
+ export interface FetchedAttachment extends AttachmentMeta {
74
+ bytes: Uint8Array;
75
+ }
76
+ export type FetchAttachmentFn = (query: {
77
+ attachmentId?: string;
78
+ signal?: BareAbortSignal;
79
+ meta?: boolean;
80
+ }) => Promise<FetchedAttachment | AttachmentMeta | null>;
81
+ export type ProgressFn = (update: {
82
+ percentage: number;
83
+ } | null) => void;
84
+ export type RagSearchFn = (input: {
85
+ query: string;
86
+ limit?: number;
87
+ }) => Promise<RagSearchResult>;
88
+ export interface RagSearchResult {
89
+ enabled: boolean;
90
+ indexEmpty: boolean;
91
+ hasKnowledge: boolean;
92
+ pendingReferenced?: boolean;
93
+ errorMessage?: string | null;
94
+ hits: ReadonlyArray<{
95
+ content: string;
96
+ metadataJson?: string | null;
97
+ score: number;
98
+ }>;
99
+ }
100
+ export type AskUserFn = (question: {
101
+ question: string;
102
+ options?: string[];
103
+ }) => Promise<string | null>;
104
+ export interface ToolExecuteContext {
105
+ agentId?: string | null | undefined;
106
+ skills?: readonly string[] | undefined;
107
+ runId?: string;
108
+ callId?: string;
109
+ ctxSize?: number | undefined;
110
+ image?: ImageSettings | undefined;
111
+ settings?: Record<string, unknown> | undefined;
112
+ turnImages?: {
113
+ path: string;
114
+ }[] | undefined;
115
+ attach?: AttachFn | undefined;
116
+ fetchAttachment?: FetchAttachmentFn | undefined;
117
+ ragSearch?: RagSearchFn | undefined;
118
+ progress?: ProgressFn | undefined;
119
+ askUser?: AskUserFn | undefined;
120
+ signal?: BareAbortSignal | undefined;
121
+ fsRoots?: readonly DriveRoot[] | undefined;
122
+ fsWriteRoots?: readonly DriveRoot[] | undefined;
123
+ toolOps?: ReadonlyMap<string, readonly CliValidator[]> | undefined;
124
+ runBudget?: RunBudget | undefined;
125
+ reportBackend?: ((use: RunBackendUse) => void) | undefined;
126
+ uncappedResponse?: boolean | undefined;
127
+ sandboxMode?: boolean | undefined;
128
+ toolNames?: readonly string[] | undefined;
129
+ approval?: ToolDecision | undefined;
130
+ }
131
+ export type ToolParameterType = 'string' | 'number' | 'boolean' | 'object' | 'integer' | 'array' | 'null';
132
+ export interface ToolParameterSchema {
133
+ type: ToolParameterType | readonly ToolParameterType[];
134
+ sensitive?: true;
135
+ description?: string;
136
+ enum?: string[];
137
+ items?: ToolParameterSchema;
138
+ properties?: Record<string, ToolParameterSchema>;
139
+ required?: string[];
140
+ }
141
+ export interface ToolParameters {
142
+ type: 'object';
143
+ properties: Record<string, ToolParameterSchema>;
144
+ required?: string[];
145
+ }
146
+ export interface ToolPromptDefinition {
147
+ description?: string;
148
+ parameters?: ToolParameters;
149
+ }
150
+ export interface ToolDefinition {
151
+ name: string;
152
+ policyVersion?: string;
153
+ description: string;
154
+ parameters: ToolParameters;
155
+ prompt?: ToolPromptDefinition;
156
+ autoApprove?: boolean;
157
+ skillGated?: boolean;
158
+ rootsRequired?: boolean;
159
+ writeRootsRequired?: boolean;
160
+ externalWrite?: boolean;
161
+ owningSkill?: string;
162
+ toolset: Toolset | null;
163
+ validate?: (args: Record<string, unknown>, ctx?: ToolExecuteContext) => string | null;
164
+ effect: (args: Record<string, unknown>, ctx?: ToolExecuteContext) => ToolEffect;
165
+ resource?: (args: Record<string, unknown>, ctx?: ToolExecuteContext) => ResourceDescriptor | null;
166
+ compiled?: true;
167
+ landedWrite?: (args: Record<string, unknown>, output: unknown) => string | null;
168
+ execute: (args: Record<string, unknown>, ctx?: ToolExecuteContext) => Promise<unknown>;
169
+ }
170
+ export interface ToolCallEvent {
171
+ type: 'tool-call';
172
+ name: string;
173
+ args: Record<string, unknown>;
174
+ rawCall?: string | undefined;
175
+ effect?: ToolEffect | undefined;
176
+ display?: ToolCallDisplay | undefined;
177
+ }
178
+ export interface ToolResultEvent {
179
+ type: 'tool-result';
180
+ name: string;
181
+ result: unknown;
182
+ }
183
+ export interface ErrorEvent {
184
+ type: 'error';
185
+ message: string;
186
+ name?: string;
187
+ code?: string;
188
+ kind?: 'machine' | 'log' | 'xstate';
189
+ found?: string;
190
+ expected?: string;
191
+ forkAt?: number | null;
192
+ forkSafe?: boolean;
193
+ recoveryOperationIds?: string[];
194
+ }
195
+ export interface AbortedEvent {
196
+ type: 'aborted';
197
+ }
198
+ export interface MetricsEvent {
199
+ type: 'metrics';
200
+ totalTokens: number;
201
+ durationMs: number;
202
+ timeToFirstToken?: number | undefined;
203
+ tokensPerSecond?: number | undefined;
204
+ promptTokensPerSecond?: number | undefined;
205
+ promptTokens?: number | undefined;
206
+ cacheTokens?: number | undefined;
207
+ ctxSize?: number | undefined;
208
+ backends?: RunBackendUse[] | undefined;
209
+ usage?: UsageBreakdown | undefined;
210
+ stopReason?: string | undefined;
211
+ route?: 'direct' | 'enhanced' | undefined;
212
+ routeModel?: string | undefined;
213
+ }
214
+ export interface InferenceCall {
215
+ round: number;
216
+ droppedTurns: number;
217
+ modelId: string;
218
+ messages: Message[];
219
+ tools: SdkTool[] | undefined;
220
+ generationParams: LlmGenerationParams | undefined;
221
+ responseFormat: ResponseFormat | undefined;
222
+ toolDialect: ToolDialect | undefined;
223
+ cacheKey: string | undefined;
224
+ promptPrefix: string;
225
+ }
226
+ export interface InferenceCallEvent {
227
+ type: 'inference-call';
228
+ call: InferenceCall;
229
+ }
230
+ export interface InferenceSentEvent {
231
+ type: 'inference-sent';
232
+ round: number;
233
+ droppedTurns: number;
234
+ messages: Message[] | undefined;
235
+ tokens: InferenceTokens | undefined;
236
+ outcome: 'completed' | 'overflowed' | 'failed';
237
+ reason: string | undefined;
238
+ }
239
+ export interface InferenceTokens {
240
+ prompt?: number | undefined;
241
+ generated?: number | undefined;
242
+ cached?: number | undefined;
243
+ timeToFirstToken?: number | undefined;
244
+ }
245
+ export type CompletionEvent = (RunLifecycleEvent | TextEvent | ToolCallEvent | ToolResultEvent | ToolActivityEvent | ErrorEvent | AbortedEvent | MetricsEvent | InferenceCallEvent | InferenceSentEvent) & {
246
+ runId?: string;
247
+ round?: number;
248
+ callId?: string;
249
+ };
250
+ export interface CompletionSdkResult {
251
+ requestId?: string;
252
+ tokenStream: AsyncIterable<string>;
253
+ final: Promise<CompletionFinal>;
254
+ }
255
+ export type ResponseFormat = {
256
+ type: 'text';
257
+ } | {
258
+ type: 'json_object';
259
+ } | {
260
+ type: 'json_schema';
261
+ json_schema: {
262
+ name: string;
263
+ description?: string;
264
+ schema: Record<string, unknown>;
265
+ strict?: boolean;
266
+ };
267
+ };
268
+ export interface CompletionSdk {
269
+ completion(params: {
270
+ modelId: string;
271
+ history: Message[];
272
+ stream: true;
273
+ tools?: SdkTool[] | undefined;
274
+ generationParams?: LlmGenerationParams | undefined;
275
+ responseFormat?: ResponseFormat | undefined;
276
+ toolDialect?: ToolDialect | undefined;
277
+ kvCache?: string | boolean;
278
+ }): CompletionSdkResult;
279
+ cancel?(params: {
280
+ requestId: string;
281
+ }): Promise<void>;
282
+ }
283
+ export interface RoundModelLease {
284
+ modelId: string;
285
+ sdk?: CompletionSdk;
286
+ release: () => void;
287
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { type AbortSignal as BareAbortSignal } from 'bare-abort-controller';
2
+ import type { CompletionEvent } from './capabilities/completion.ts';
3
+ export interface CompletionRun {
4
+ abort: () => void;
5
+ close: () => Promise<void>;
6
+ readonly started: boolean;
7
+ }
8
+ type CompletionIterator = AsyncGenerator<CompletionEvent, unknown, unknown>;
9
+ export declare function trackCompletion(createSource: (signal: BareAbortSignal) => CompletionIterator, signal: BareAbortSignal | undefined, onFinish: (run: CompletionRun) => void): TrackedCompletionResult;
10
+ interface TrackedCompletionResult {
11
+ iterator: CompletionIterator;
12
+ run: CompletionRun;
13
+ }
14
+ export {};
@@ -0,0 +1,126 @@
1
+ import { AbortController } from 'bare-abort-controller';
2
+ import { raceDrain } from './machine/index.js';
3
+ export function trackCompletion(createSource, signal, onFinish) {
4
+ const controller = new AbortController();
5
+ const abort = () => {
6
+ if (!controller.signal.aborted) {
7
+ controller.abort(undefined);
8
+ }
9
+ };
10
+ const onAbort = () => abort();
11
+ if (signal?.aborted) {
12
+ abort();
13
+ }
14
+ else {
15
+ signal?.addEventListener('abort', onAbort);
16
+ }
17
+ let started = false;
18
+ const source = createSource(controller.signal);
19
+ let settled = false;
20
+ let run;
21
+ const finish = () => {
22
+ if (settled) {
23
+ return;
24
+ }
25
+ settled = true;
26
+ signal?.removeEventListener('abort', onAbort);
27
+ onFinish(run);
28
+ };
29
+ const iterator = new TrackedCompletionIterator({
30
+ source,
31
+ start: () => {
32
+ started = true;
33
+ },
34
+ finish,
35
+ abort
36
+ });
37
+ run = {
38
+ abort,
39
+ get started() {
40
+ return started;
41
+ },
42
+ close: async () => {
43
+ abort();
44
+ await raceDrain(iterator.return());
45
+ }
46
+ };
47
+ return { iterator, run };
48
+ }
49
+ class TrackedCompletionIterator {
50
+ _source;
51
+ _start;
52
+ _finish;
53
+ _abort;
54
+ _started = false;
55
+ _closed = false;
56
+ _returnResult = null;
57
+ constructor({ source, start, finish, abort }) {
58
+ this._source = source;
59
+ this._start = start;
60
+ this._finish = finish;
61
+ this._abort = abort;
62
+ }
63
+ [Symbol.asyncIterator]() {
64
+ return this;
65
+ }
66
+ [Symbol.asyncDispose]() {
67
+ return this.return().then(() => { });
68
+ }
69
+ next(value) {
70
+ if (this._closed) {
71
+ return Promise.resolve({ done: true, value: undefined });
72
+ }
73
+ this._started = true;
74
+ this._start();
75
+ return this._source.next(value).then((result) => {
76
+ if (result.done) {
77
+ this._closed = true;
78
+ this._finish();
79
+ }
80
+ return result;
81
+ }, (error) => {
82
+ this._closed = true;
83
+ this._finish();
84
+ throw error;
85
+ });
86
+ }
87
+ return(value) {
88
+ if (this._returnResult) {
89
+ return this._returnResult;
90
+ }
91
+ this._closed = true;
92
+ this._abort();
93
+ if (!this._started) {
94
+ this._finish();
95
+ this._returnResult = Promise.resolve({ done: true, value });
96
+ return this._returnResult;
97
+ }
98
+ this._returnResult = this._source.return(value).then((result) => {
99
+ this._finish();
100
+ return result;
101
+ }, (error) => {
102
+ this._finish();
103
+ throw error;
104
+ });
105
+ return this._returnResult;
106
+ }
107
+ throw(error) {
108
+ if (this._closed) {
109
+ return Promise.reject(error);
110
+ }
111
+ this._abort();
112
+ this._started = true;
113
+ this._start();
114
+ return this._source.throw(error).then((result) => {
115
+ if (result.done) {
116
+ this._closed = true;
117
+ this._finish();
118
+ }
119
+ return result;
120
+ }, (reason) => {
121
+ this._closed = true;
122
+ this._finish();
123
+ throw reason;
124
+ });
125
+ }
126
+ }