@qvac/harness 0.7.1 → 1.0.0-rc.1

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 (201) hide show
  1. package/README.md +224 -0
  2. package/dist-lib/index.d.ts +55 -3
  3. package/dist-lib/index.js +721 -236
  4. package/dist-lib/lib/capabilities/completion-engine/abort-polyfill.d.ts +1 -0
  5. package/dist-lib/lib/capabilities/completion-engine/abort-polyfill.js +10 -0
  6. package/dist-lib/lib/capabilities/completion-engine/actors/answering.d.ts +3 -0
  7. package/dist-lib/lib/capabilities/completion-engine/actors/answering.js +17 -0
  8. package/dist-lib/lib/capabilities/completion-engine/actors/approval.d.ts +4 -0
  9. package/dist-lib/lib/capabilities/completion-engine/actors/approval.js +29 -0
  10. package/dist-lib/lib/capabilities/completion-engine/actors/direct-search.d.ts +4 -0
  11. package/dist-lib/lib/capabilities/completion-engine/actors/direct-search.js +73 -0
  12. package/dist-lib/lib/capabilities/completion-engine/actors/execute.d.ts +41 -0
  13. package/dist-lib/lib/capabilities/completion-engine/actors/execute.js +49 -0
  14. package/dist-lib/lib/capabilities/completion-engine/actors/executing.d.ts +3 -0
  15. package/dist-lib/lib/capabilities/completion-engine/actors/executing.js +102 -0
  16. package/dist-lib/lib/capabilities/completion-engine/actors/execution-plan.d.ts +47 -0
  17. package/dist-lib/lib/capabilities/completion-engine/actors/execution-plan.js +87 -0
  18. package/dist-lib/lib/capabilities/completion-engine/actors/finishing.d.ts +2 -0
  19. package/dist-lib/lib/capabilities/completion-engine/actors/finishing.js +32 -0
  20. package/dist-lib/lib/capabilities/completion-engine/actors/inspect-preload.d.ts +3 -0
  21. package/dist-lib/lib/capabilities/completion-engine/actors/inspect-preload.js +75 -0
  22. package/dist-lib/lib/capabilities/completion-engine/actors/inspecting.d.ts +3 -0
  23. package/dist-lib/lib/capabilities/completion-engine/actors/inspecting.js +152 -0
  24. package/dist-lib/lib/capabilities/completion-engine/actors/loading-skill.d.ts +3 -0
  25. package/dist-lib/lib/capabilities/completion-engine/actors/loading-skill.js +94 -0
  26. package/dist-lib/lib/capabilities/completion-engine/actors/preload-failure.d.ts +9 -0
  27. package/dist-lib/lib/capabilities/completion-engine/actors/preload-failure.js +11 -0
  28. package/dist-lib/lib/capabilities/completion-engine/actors/preloading.d.ts +3 -0
  29. package/dist-lib/lib/capabilities/completion-engine/actors/preloading.js +114 -0
  30. package/dist-lib/lib/capabilities/completion-engine/actors/preparing.d.ts +3 -0
  31. package/dist-lib/lib/capabilities/completion-engine/actors/preparing.js +198 -0
  32. package/dist-lib/lib/capabilities/completion-engine/actors/rejecting.d.ts +3 -0
  33. package/dist-lib/lib/capabilities/completion-engine/actors/rejecting.js +71 -0
  34. package/dist-lib/lib/capabilities/completion-engine/actors/rejection.d.ts +18 -0
  35. package/dist-lib/lib/capabilities/completion-engine/actors/rejection.js +70 -0
  36. package/dist-lib/lib/capabilities/completion-engine/actors/resolving.d.ts +3 -0
  37. package/dist-lib/lib/capabilities/completion-engine/actors/resolving.js +60 -0
  38. package/dist-lib/lib/capabilities/completion-engine/actors/stream.d.ts +21 -0
  39. package/dist-lib/lib/capabilities/completion-engine/actors/stream.js +48 -0
  40. package/dist-lib/lib/capabilities/completion-engine/actors/streaming.d.ts +3 -0
  41. package/dist-lib/lib/capabilities/completion-engine/actors/streaming.js +156 -0
  42. package/dist-lib/lib/capabilities/completion-engine/actors/wrap-up.d.ts +7 -0
  43. package/dist-lib/lib/capabilities/completion-engine/actors/wrap-up.js +61 -0
  44. package/dist-lib/lib/capabilities/completion-engine/driver.d.ts +25 -0
  45. package/dist-lib/lib/capabilities/completion-engine/driver.js +553 -0
  46. package/dist-lib/lib/capabilities/completion-engine/durable.d.ts +61 -0
  47. package/dist-lib/lib/capabilities/completion-engine/durable.js +150 -0
  48. package/dist-lib/lib/capabilities/completion-engine/operations.d.ts +6 -0
  49. package/dist-lib/lib/capabilities/completion-engine/operations.js +239 -0
  50. package/dist-lib/lib/capabilities/completion-engine/ports.d.ts +3 -0
  51. package/dist-lib/lib/capabilities/completion-engine/ports.js +267 -0
  52. package/dist-lib/lib/capabilities/completion-engine/session.d.ts +76 -0
  53. package/dist-lib/lib/capabilities/completion-engine/session.js +70 -0
  54. package/dist-lib/lib/capabilities/completion-loop/index.d.ts +80 -0
  55. package/dist-lib/lib/capabilities/completion-loop/index.js +158 -0
  56. package/dist-lib/lib/capabilities/completion-loop/metrics.d.ts +5 -0
  57. package/dist-lib/lib/capabilities/completion-loop/metrics.js +29 -0
  58. package/dist-lib/lib/capabilities/completion-loop/round.d.ts +33 -0
  59. package/dist-lib/lib/capabilities/completion-loop/round.js +353 -0
  60. package/dist-lib/lib/capabilities/completion-loop/tool-execution.d.ts +60 -0
  61. package/dist-lib/lib/capabilities/completion-loop/tool-execution.js +270 -0
  62. package/dist-lib/lib/capabilities/completion-loop/turns.d.ts +23 -0
  63. package/dist-lib/lib/capabilities/completion-loop/turns.js +112 -0
  64. package/dist-lib/lib/capabilities/completion-runtime.d.ts +46 -0
  65. package/dist-lib/lib/capabilities/completion-runtime.js +74 -0
  66. package/dist-lib/lib/capabilities/completion.d.ts +18 -335
  67. package/dist-lib/lib/capabilities/completion.js +20 -1301
  68. package/dist-lib/lib/capabilities/download.d.ts +1 -1
  69. package/dist-lib/lib/capabilities/download.js +7 -2
  70. package/dist-lib/lib/capabilities/invoke.js +5 -3
  71. package/dist-lib/lib/capabilities/tool-plan.d.ts +35 -0
  72. package/dist-lib/lib/capabilities/tool-plan.js +66 -0
  73. package/dist-lib/lib/capabilities/tool-turns.d.ts +11 -2
  74. package/dist-lib/lib/capabilities/tool-turns.js +30 -2
  75. package/dist-lib/lib/capabilities/types.d.ts +287 -0
  76. package/dist-lib/lib/capabilities/types.js +1 -0
  77. package/dist-lib/lib/completion-lifecycle.d.ts +14 -0
  78. package/dist-lib/lib/completion-lifecycle.js +126 -0
  79. package/dist-lib/lib/connect.d.ts +10 -3
  80. package/dist-lib/lib/connect.js +329 -23
  81. package/dist-lib/lib/contract-types.d.ts +19 -2
  82. package/dist-lib/lib/harness-lifecycle.d.ts +66 -0
  83. package/dist-lib/lib/harness-lifecycle.js +129 -0
  84. package/dist-lib/lib/helpers/detach-json.d.ts +1 -0
  85. package/dist-lib/lib/helpers/detach-json.js +146 -0
  86. package/dist-lib/lib/helpers/markup-scanner.d.ts +26 -0
  87. package/dist-lib/lib/helpers/markup-scanner.js +156 -0
  88. package/dist-lib/lib/helpers/markup-stream-filter.js +138 -35
  89. package/dist-lib/lib/helpers/race-abort.d.ts +9 -4
  90. package/dist-lib/lib/helpers/race-abort.js +2 -7
  91. package/dist-lib/lib/helpers/recovery-required.d.ts +1 -0
  92. package/dist-lib/lib/helpers/recovery-required.js +1 -0
  93. package/dist-lib/lib/helpers/run-outcome.d.ts +10 -2
  94. package/dist-lib/lib/helpers/run-outcome.js +8 -5
  95. package/dist-lib/lib/helpers/tool-call-markup.d.ts +2 -0
  96. package/dist-lib/lib/helpers/tool-call-markup.js +197 -82
  97. package/dist-lib/lib/hooks/built-in/arg-repair.d.ts +1 -0
  98. package/dist-lib/lib/hooks/built-in/arg-repair.js +1 -0
  99. package/dist-lib/lib/hooks/built-in/egress.d.ts +1 -0
  100. package/dist-lib/lib/hooks/built-in/egress.js +2 -1
  101. package/dist-lib/lib/hooks/built-in/sandbox.d.ts +1 -0
  102. package/dist-lib/lib/hooks/built-in/sandbox.js +6 -1
  103. package/dist-lib/lib/hooks/built-in/skill-catalog.d.ts +1 -0
  104. package/dist-lib/lib/hooks/built-in/skill-catalog.js +2 -1
  105. package/dist-lib/lib/hooks/pipeline.d.ts +4 -1
  106. package/dist-lib/lib/hooks/pipeline.js +24 -2
  107. package/dist-lib/lib/hooks/run.d.ts +2 -1
  108. package/dist-lib/lib/hooks/run.js +19 -7
  109. package/dist-lib/lib/hooks/types.d.ts +17 -6
  110. package/dist-lib/lib/machine/completion/actions/approval.d.ts +3 -0
  111. package/dist-lib/lib/machine/completion/actions/approval.js +16 -0
  112. package/dist-lib/lib/machine/completion/actions/completion.d.ts +23 -0
  113. package/dist-lib/lib/machine/completion/actions/completion.js +142 -0
  114. package/dist-lib/lib/machine/completion/actions/skills.d.ts +9 -0
  115. package/dist-lib/lib/machine/completion/actions/skills.js +83 -0
  116. package/dist-lib/lib/machine/completion/actions/tools.d.ts +16 -0
  117. package/dist-lib/lib/machine/completion/actions/tools.js +173 -0
  118. package/dist-lib/lib/machine/completion/context.d.ts +9 -0
  119. package/dist-lib/lib/machine/completion/context.js +44 -0
  120. package/dist-lib/lib/machine/completion/contract.d.ts +6 -0
  121. package/dist-lib/lib/machine/completion/contract.js +1 -0
  122. package/dist-lib/lib/machine/completion/guards/retry.d.ts +9 -0
  123. package/dist-lib/lib/machine/completion/guards/retry.js +25 -0
  124. package/dist-lib/lib/machine/completion/implementations.d.ts +81 -0
  125. package/dist-lib/lib/machine/completion/implementations.js +152 -0
  126. package/dist-lib/lib/machine/completion/machine.d.ts +375 -0
  127. package/dist-lib/lib/machine/completion/machine.js +511 -0
  128. package/dist-lib/lib/machine/completion/ports.d.ts +65 -0
  129. package/dist-lib/lib/machine/completion/ports.js +224 -0
  130. package/dist-lib/lib/machine/completion/rules.d.ts +39 -0
  131. package/dist-lib/lib/machine/completion/rules.js +115 -0
  132. package/dist-lib/lib/machine/completion/types.d.ts +493 -0
  133. package/dist-lib/lib/machine/completion/types.js +1 -0
  134. package/dist-lib/lib/machine/engine.d.ts +93 -0
  135. package/dist-lib/lib/machine/engine.js +483 -0
  136. package/dist-lib/lib/machine/errors.d.ts +44 -0
  137. package/dist-lib/lib/machine/errors.js +373 -0
  138. package/dist-lib/lib/machine/guards.d.ts +2 -0
  139. package/dist-lib/lib/machine/guards.js +6 -0
  140. package/dist-lib/lib/machine/index.d.ts +20 -0
  141. package/dist-lib/lib/machine/index.js +11 -0
  142. package/dist-lib/lib/machine/replay-output.d.ts +24 -0
  143. package/dist-lib/lib/machine/replay-output.js +50 -0
  144. package/dist-lib/lib/machine/stable-stringify.d.ts +1 -0
  145. package/dist-lib/lib/machine/stable-stringify.js +11 -0
  146. package/dist-lib/lib/models/model-pool.d.ts +14 -6
  147. package/dist-lib/lib/models/model-pool.js +95 -30
  148. package/dist-lib/lib/run-log/history-codec.d.ts +23 -0
  149. package/dist-lib/lib/run-log/history-codec.js +973 -0
  150. package/dist-lib/lib/run-log/patch.d.ts +6 -0
  151. package/dist-lib/lib/run-log/patch.js +93 -0
  152. package/dist-lib/lib/run-log/persisted-actor.d.ts +18 -0
  153. package/dist-lib/lib/run-log/persisted-actor.js +218 -0
  154. package/dist-lib/lib/run-log/protocol-types.d.ts +153 -0
  155. package/dist-lib/lib/run-log/protocol-types.js +1 -0
  156. package/dist-lib/lib/run-log/protocol.d.ts +27 -0
  157. package/dist-lib/lib/run-log/protocol.js +1056 -0
  158. package/dist-lib/lib/run-log/replay.d.ts +25 -0
  159. package/dist-lib/lib/run-log/replay.js +129 -0
  160. package/dist-lib/lib/run-log/run-journal.d.ts +125 -0
  161. package/dist-lib/lib/run-log/run-journal.js +783 -0
  162. package/dist-lib/lib/run-log-inspect.d.ts +25 -0
  163. package/dist-lib/lib/run-log-inspect.js +627 -0
  164. package/dist-lib/lib/run-log-protocol.d.ts +2 -0
  165. package/dist-lib/lib/run-log-protocol.js +1 -0
  166. package/dist-lib/lib/run-log-redact.d.ts +27 -0
  167. package/dist-lib/lib/run-log-redact.js +1107 -0
  168. package/dist-lib/lib/serve.js +307 -11
  169. package/dist-lib/lib/spawn.js +3 -2
  170. package/dist-lib/lib/tool-call-display.d.ts +1 -21
  171. package/dist-lib/lib/tools/exec/adapters/python/wheels.js +2 -1
  172. package/dist-lib/lib/tools/exec.d.ts +2 -1
  173. package/dist-lib/lib/tools/exec.js +57 -2
  174. package/dist-lib/lib/tools/generate-image.js +1 -1
  175. package/dist-lib/lib/tools/generate-music.js +1 -1
  176. package/dist-lib/lib/tools/http-request.d.ts +2 -1
  177. package/dist-lib/lib/tools/http-request.js +2 -1
  178. package/dist-lib/lib/tools/mcp-call.js +8 -1
  179. package/dist-lib/lib/tools/operations/builders.d.ts +1 -0
  180. package/dist-lib/lib/tools/operations/builders.js +1 -0
  181. package/dist-lib/lib/tools/operations/compile.js +11 -1
  182. package/dist-lib/lib/tools/operations/manifest.js +1 -0
  183. package/dist-lib/lib/tools/outbound-guard.d.ts +8 -6
  184. package/dist-lib/lib/tools/outbound-guard.js +25 -8
  185. package/dist-lib/lib/tools/skills/catalog.d.ts +1 -0
  186. package/dist-lib/lib/tools/skills/catalog.js +35 -0
  187. package/dist-lib/lib/tools/skills/cli-schema-types.d.ts +1 -0
  188. package/dist-lib/lib/tools/skills/cli-schema.js +25 -0
  189. package/dist-lib/lib/wire.d.ts +5 -0
  190. package/dist-lib/lib/wire.js +128 -5
  191. package/dist-lib/schema/harness.js +20 -5
  192. package/dist-lib/spec/hrpc/messages.js +95 -15
  193. package/dist-lib/spec/hyperschema/index.js +95 -15
  194. package/dist-lib/spec/hyperschema/schema.json +69 -1
  195. package/dist-lib/spec/hyperschema/types.d.ts +10 -3
  196. package/package.json +20 -2
  197. package/patches/@qvac%2Finference@0.20.0.patch +67 -0
  198. package/patches/bare-stow@0.1.5.patch +68 -0
  199. package/patches/hypercore-blob-server@1.15.0.patch +15 -0
  200. package/patches/localwatch@1.4.3.patch +13 -0
  201. package/patches/pyodide@314.0.2.patch +144 -0
@@ -1,14 +1,18 @@
1
+ import type { HookRejection } from '../machine/index.ts';
1
2
  import type { AbortSignal as BareAbortSignal } from 'bare-abort-controller';
2
3
  import type { ToolExecutionOutcome } from '../tool-call-display.ts';
3
4
  import type { Message, ResourceDescriptor, ToolDefinition, ToolEffect } from '../capabilities/completion.ts';
4
- export type HookPhase = 'runStart' | 'preToolCall' | 'postToolCall' | 'runEnd';
5
+ export type HookPhase = 'runStart' | 'preToolCall' | 'postToolCall' | 'runEnd' | 'runPause' | 'runResume';
5
6
  export interface RunStartPayload {
6
7
  readonly phase: 'runStart';
8
+ readonly runId: string;
7
9
  readonly agentId: string | null;
8
10
  readonly messages: ReadonlyArray<Message>;
9
11
  }
10
12
  export interface PreToolCallPayload {
11
13
  readonly phase: 'preToolCall';
14
+ readonly runId: string;
15
+ readonly callId: string;
12
16
  readonly toolName: string;
13
17
  readonly agentId: string | null;
14
18
  readonly signal?: BareAbortSignal | undefined;
@@ -19,6 +23,8 @@ export interface PreToolCallPayload {
19
23
  }
20
24
  export interface PostToolCallPayload {
21
25
  readonly phase: 'postToolCall';
26
+ readonly runId: string;
27
+ readonly callId: string;
22
28
  readonly toolName: string;
23
29
  readonly executed: boolean;
24
30
  readonly effect: ToolEffect;
@@ -31,6 +37,7 @@ export interface PostToolCallPayload {
31
37
  }
32
38
  export interface RunEndPayload {
33
39
  readonly phase: 'runEnd';
40
+ readonly runId: string;
34
41
  readonly agentId: string | null;
35
42
  readonly stats: {
36
43
  readonly totalTokens: number;
@@ -40,19 +47,23 @@ export interface RunEndPayload {
40
47
  readonly outcome: 'done' | 'aborted' | 'error' | 'abandoned';
41
48
  readonly error?: unknown;
42
49
  }
43
- export type HookContext = RunStartPayload | PreToolCallPayload | PostToolCallPayload | RunEndPayload;
44
- export interface HookRejection {
45
- error: string;
46
- guidance: true;
50
+ export interface RunLifecyclePayload {
51
+ readonly phase: 'runPause' | 'runResume';
52
+ readonly runId: string;
53
+ readonly agentId: string | null;
47
54
  }
55
+ export type HookContext = RunLifecyclePayload | RunStartPayload | PreToolCallPayload | PostToolCallPayload | RunEndPayload;
56
+ export type { HookRejection };
48
57
  export interface PreToolCallResult {
49
58
  readonly args: Record<string, unknown>;
50
59
  }
51
60
  export interface PostToolCallResult {
52
61
  readonly result: unknown;
53
62
  }
54
- export type HookResult = PreToolCallResult | PostToolCallResult | HookRejection | void;
63
+ export type HookRejectionResult = Omit<HookRejection, 'hook' | 'phase'>;
64
+ export type HookResult = PreToolCallResult | PostToolCallResult | HookRejectionResult | void;
55
65
  export interface HarnessHook {
66
+ readonly name?: string;
56
67
  readonly phase: HookPhase;
57
68
  run(ctx: HookContext): Promise<HookResult> | HookResult;
58
69
  }
@@ -0,0 +1,3 @@
1
+ import type { ApprovalCall, CompletionActionArgs, CompletionContext } from '../types.ts';
2
+ export declare function requestApproval({ context, params: call }: CompletionActionArgs<ApprovalCall>): Partial<CompletionContext>;
3
+ export declare function approveCompletion({ context }: CompletionActionArgs): Partial<CompletionContext>;
@@ -0,0 +1,16 @@
1
+ export function requestApproval({ context, params: call }) {
2
+ const facts = context.execution?.gate?.facts;
3
+ if (!facts) {
4
+ throw new Error('Cannot request approval without tool preflight facts');
5
+ }
6
+ return {
7
+ pendingCall: call,
8
+ approval: { status: 'pending', key: facts.key }
9
+ };
10
+ }
11
+ export function approveCompletion({ context }) {
12
+ return {
13
+ pendingCall: null,
14
+ approval: { ...context.approval, status: 'approved' }
15
+ };
16
+ }
@@ -0,0 +1,23 @@
1
+ import type { AnsweredPayload, CompletionActionArgs, CompletionContext, RunOutcome, PreparingPayload, RoundDonePayload } from '../types.ts';
2
+ import type { EngineError } from '../../errors.ts';
3
+ export declare function startInitialRound({ context, params }: CompletionActionArgs<PreparingPayload>): Partial<CompletionContext>;
4
+ export declare function startNextRound({ context }: CompletionActionArgs): Partial<CompletionContext>;
5
+ export declare function retryMuteRound({ context }: CompletionActionArgs): Partial<CompletionContext>;
6
+ export declare function retryNarratedRound({ context, params }: CompletionActionArgs<AnsweredPayload>): Partial<CompletionContext>;
7
+ export declare function retryCappedSearch({ context }: CompletionActionArgs): Partial<CompletionContext>;
8
+ export declare function finishRound({ context, params }: CompletionActionArgs<RoundDonePayload>): Partial<CompletionContext>;
9
+ export declare function finishWrapRound({ context, params }: CompletionActionArgs<RoundDonePayload>): Partial<CompletionContext>;
10
+ export declare function wrapCompletion({ params }: CompletionActionArgs<RunOutcome>): Partial<CompletionContext>;
11
+ export declare function wrapMuteCompletion(_args: CompletionActionArgs): Partial<CompletionContext>;
12
+ export declare function wrapSearchCappedCompletion({ context }: CompletionActionArgs): Partial<CompletionContext>;
13
+ export declare function wrapExhaustedCompletion({ context }: CompletionActionArgs): Partial<CompletionContext>;
14
+ export declare function answerCompletion({ context, params }: CompletionActionArgs<AnsweredPayload>): Partial<CompletionContext>;
15
+ export interface CompletionFailureMessage {
16
+ error: string;
17
+ }
18
+ type FailedEngineError = Extract<EngineError, {
19
+ tag: 'failed';
20
+ }>;
21
+ export declare function failCompletion({ params }: CompletionActionArgs<FailedEngineError | CompletionFailureMessage>): Partial<CompletionContext>;
22
+ export declare function applyPreparation(context: Readonly<CompletionContext>, payload?: PreparingPayload): Partial<CompletionContext>;
23
+ export {};
@@ -0,0 +1,142 @@
1
+ import { applyHistorySplice, applySplice, foldMetrics, retainFailureResults, TOOL_CONTINUATION_NUDGE } from '../rules.js';
2
+ export function startInitialRound({ context, params }) {
3
+ return applyPreparation(context, params);
4
+ }
5
+ export function startNextRound({ context }) {
6
+ return {
7
+ ...applyPreparation(context),
8
+ ...closeFailureMemo(context),
9
+ history: endToolRound(context),
10
+ round: context.round + 1,
11
+ mute: 0,
12
+ narrated: false,
13
+ cappedRounds: 0
14
+ };
15
+ }
16
+ export function retryMuteRound({ context }) {
17
+ return { mute: context.mute + 1, round: context.round + 1 };
18
+ }
19
+ export function retryNarratedRound({ context, params }) {
20
+ return {
21
+ narrated: true,
22
+ history: [
23
+ ...context.history,
24
+ { role: 'assistant', content: params.narrated ?? '' },
25
+ { role: 'user', content: TOOL_CONTINUATION_NUDGE }
26
+ ],
27
+ round: context.round + 1
28
+ };
29
+ }
30
+ export function retryCappedSearch({ context }) {
31
+ return {
32
+ ...applyPreparation(context),
33
+ ...closeFailureMemo(context),
34
+ history: endToolRound(context),
35
+ round: context.round + 1,
36
+ mute: 0,
37
+ narrated: false,
38
+ cappedRounds: context.cappedRounds + 1
39
+ };
40
+ }
41
+ function closeFailureMemo(context) {
42
+ if (!context.roundProgressed)
43
+ return {};
44
+ return {
45
+ failedCalls: {},
46
+ failureResults: retainFailureResults(context.history, context.failureResults, {}),
47
+ blockedRepeats: 0,
48
+ roundProgressed: false
49
+ };
50
+ }
51
+ function endToolRound(context) {
52
+ return [...context.history, { role: 'user', content: TOOL_CONTINUATION_NUDGE }];
53
+ }
54
+ export function finishRound({ context, params }) {
55
+ const metrics = { ...context.metrics };
56
+ foldMetrics(metrics, params.stats, params.stopReason);
57
+ const historyState = applyHistorySplice(context, params.history);
58
+ return {
59
+ lastRound: { ...params, history: undefined },
60
+ roundsSent: context.round + 1,
61
+ cacheKey: params.cacheable === false ? null : context.cacheKey,
62
+ ...historyState,
63
+ promptPrefix: params.promptPrefix ?? context.promptPrefix,
64
+ metrics
65
+ };
66
+ }
67
+ export function finishWrapRound({ context, params }) {
68
+ const metrics = { ...context.metrics };
69
+ foldMetrics(metrics, params.stats, params.stopReason);
70
+ const historyState = applyHistorySplice(context, params.history);
71
+ return {
72
+ ...historyState,
73
+ lastRound: { ...params, history: undefined },
74
+ metrics
75
+ };
76
+ }
77
+ export function wrapCompletion({ params }) {
78
+ return { outcome: params };
79
+ }
80
+ export function wrapMuteCompletion(_args) {
81
+ return { outcome: 'mute' };
82
+ }
83
+ export function wrapSearchCappedCompletion({ context }) {
84
+ return { history: endToolRound(context), outcome: 'search-capped' };
85
+ }
86
+ export function wrapExhaustedCompletion({ context }) {
87
+ return { history: endToolRound(context), outcome: 'exhausted' };
88
+ }
89
+ export function answerCompletion({ context, params }) {
90
+ const historyState = applyHistorySplice(context, params.history);
91
+ const history = historyState.history;
92
+ const metrics = { ...context.metrics };
93
+ if ('stats' in params) {
94
+ foldMetrics(metrics, params.stats, params.stopReason);
95
+ }
96
+ return {
97
+ ...historyState,
98
+ history: params.response
99
+ ? [...history, { role: 'assistant', content: params.response }]
100
+ : history,
101
+ response: params.response || context.response,
102
+ metrics,
103
+ outcome: 'answered'
104
+ };
105
+ }
106
+ export function failCompletion({ params }) {
107
+ const failure = 'tag' in params
108
+ ? params
109
+ : {
110
+ tag: 'failed',
111
+ message: params.error,
112
+ name: 'Error'
113
+ };
114
+ return {
115
+ outcome: 'failed',
116
+ failMessage: failure.message,
117
+ failure
118
+ };
119
+ }
120
+ export function applyPreparation(context, payload) {
121
+ const historyState = applyHistorySplice(context, payload?.history);
122
+ return {
123
+ ...historyState,
124
+ skills: payload?.loadedSkills
125
+ ? { ...context.skills, snapshot: { loaded: [...payload.loadedSkills] } }
126
+ : context.skills,
127
+ webSearches: payload?.webSearches ?? context.webSearches,
128
+ deniedKeys: payload?.deniedKeys ? [...payload.deniedKeys] : context.deniedKeys,
129
+ sources: payload?.sources ? [...payload.sources] : context.sources,
130
+ availableTools: payload?.availableTools ? [...payload.availableTools] : context.availableTools,
131
+ promptPrefix: payload?.promptPrefix ?? context.promptPrefix,
132
+ currentCall: null,
133
+ execution: null,
134
+ rejectedCall: null,
135
+ toolQueue: [],
136
+ pendingCall: null,
137
+ skillPreload: null,
138
+ pendingSearch: null,
139
+ cappedCalls: 0,
140
+ resolvedCount: 0
141
+ };
142
+ }
@@ -0,0 +1,9 @@
1
+ import type { CompletionActionArgs, CompletionContext, SkillFailedPayload, PreloadInspectionOutput, SkillLoadOutput, SkillPreloadPayload, SkillReadyPayload, SkillToolExecutionSnapshot } from '../types.ts';
2
+ export declare function requestPreload({ context, params }: CompletionActionArgs<SkillPreloadPayload>): Partial<CompletionContext>;
3
+ export declare function authorizePreload({ params }: CompletionActionArgs<PreloadInspectionOutput>): Partial<CompletionContext>;
4
+ export declare function settlePreloadFailure({ context, params }: CompletionActionArgs<PreloadInspectionOutput | SkillLoadOutput>): Partial<CompletionContext>;
5
+ export declare function startSkillTool({ context, params }: CompletionActionArgs<SkillToolExecutionSnapshot>): Partial<CompletionContext>;
6
+ export declare function finishSkill({ context, params }: CompletionActionArgs<SkillReadyPayload>): Partial<CompletionContext>;
7
+ export declare function failSkill({ context, params }: CompletionActionArgs<SkillFailedPayload>): Partial<CompletionContext>;
8
+ export declare function finishToolSkill(args: CompletionActionArgs<SkillReadyPayload>): Partial<CompletionContext>;
9
+ export declare function failToolSkill(args: CompletionActionArgs<SkillFailedPayload>): Partial<CompletionContext>;
@@ -0,0 +1,83 @@
1
+ import { applyPreparation } from './completion.js';
2
+ import { applyHistorySplice } from '../rules.js';
3
+ export function requestPreload({ context, params }) {
4
+ const preparation = applyPreparation(context, params);
5
+ const skills = preparation.skills ?? context.skills;
6
+ return {
7
+ ...preparation,
8
+ skillPreload: { name: params.name },
9
+ pendingSearch: params.pendingSearch,
10
+ skills: {
11
+ ...skills,
12
+ loads: { ...skills.loads, [params.name]: { status: 'pending' } },
13
+ pending: skills.pending.includes(params.name)
14
+ ? skills.pending
15
+ : [...skills.pending, params.name]
16
+ }
17
+ };
18
+ }
19
+ export function authorizePreload({ params }) {
20
+ return {
21
+ skillPreload: { name: params.name, args: params.args, facts: params.facts ?? undefined }
22
+ };
23
+ }
24
+ export function settlePreloadFailure({ context, params }) {
25
+ const failure = 'failure' in params ? params.failure : null;
26
+ return failure ? failSkill({ context, params: failure }) : {};
27
+ }
28
+ export function startSkillTool({ context, params }) {
29
+ const name = params.skillName;
30
+ return {
31
+ execution: params,
32
+ skills: {
33
+ ...context.skills,
34
+ loads: { ...context.skills.loads, [name]: { status: 'pending' } },
35
+ pending: context.skills.pending.includes(name)
36
+ ? context.skills.pending
37
+ : [...context.skills.pending, name]
38
+ }
39
+ };
40
+ }
41
+ export function finishSkill({ context, params }) {
42
+ const loaded = context.skills.snapshot?.loaded ?? [];
43
+ const historyState = applyHistorySplice(context, params.history);
44
+ return {
45
+ skills: {
46
+ snapshot: { loaded: loaded.includes(params.name) ? loaded : [...loaded, params.name] },
47
+ loads: { ...context.skills.loads, [params.name]: { status: 'success' } },
48
+ pending: context.skills.pending.filter((name) => name !== params.name)
49
+ },
50
+ cacheKey: params.cacheable === false ? null : context.cacheKey,
51
+ ...historyState,
52
+ sources: params.source ? [...context.sources, params.source] : context.sources,
53
+ skillPreload: null
54
+ };
55
+ }
56
+ export function failSkill({ context, params }) {
57
+ const historyState = applyHistorySplice(context, params.history);
58
+ return {
59
+ skills: {
60
+ ...context.skills,
61
+ loads: { ...context.skills.loads, [params.name]: { status: 'error', error: params.error } },
62
+ pending: context.skills.pending.filter((name) => name !== params.name)
63
+ },
64
+ ...historyState,
65
+ skillPreload: null
66
+ };
67
+ }
68
+ export function finishToolSkill(args) {
69
+ return { ...finishSkill(args), ...finishSkillCall(args.context) };
70
+ }
71
+ export function failToolSkill(args) {
72
+ return { ...failSkill(args), ...finishSkillCall(args.context) };
73
+ }
74
+ function finishSkillCall(context) {
75
+ return {
76
+ pendingCall: null,
77
+ approval: { status: 'idle', key: null },
78
+ currentCall: null,
79
+ execution: null,
80
+ rejectedCall: null,
81
+ toolQueue: context.toolQueue.slice(1)
82
+ };
83
+ }
@@ -0,0 +1,16 @@
1
+ import type { CompletionActionArgs, CompletionContext, DirectToolOutput, GatedToolExecutionSnapshot, RejectDeniedApprovalParams, PreparingOutput, RepeatOfFailedCallParams, ResolvedCallSnapshot, ToolDonePayload, ToolExecutionSnapshot, ToolRejection, ToolsResolvedPayload } from '../types.ts';
2
+ export declare function resolveTools({ context, params }: CompletionActionArgs<ToolsResolvedPayload>): Partial<CompletionContext>;
3
+ export declare function selectNextTool({ params }: CompletionActionArgs<ResolvedCallSnapshot>): Partial<CompletionContext>;
4
+ export interface RejectToolParams {
5
+ call: ResolvedCallSnapshot;
6
+ execution: ToolExecutionSnapshot | null;
7
+ rejection: ToolRejection;
8
+ }
9
+ export declare function rejectTool({ context, params }: CompletionActionArgs<RejectToolParams>): Partial<CompletionContext>;
10
+ export declare function rejectDeniedApproval({ context, params }: CompletionActionArgs<RejectDeniedApprovalParams>): Partial<CompletionContext>;
11
+ export declare function queueDirectSearch({ context, params }: CompletionActionArgs<PreparingOutput>): Partial<CompletionContext>;
12
+ export declare function startDirectTool({ params }: CompletionActionArgs<DirectToolOutput>): Partial<CompletionContext>;
13
+ export declare function startTool({ params }: CompletionActionArgs<GatedToolExecutionSnapshot>): Partial<CompletionContext>;
14
+ export declare function finishTool({ context, params }: CompletionActionArgs<ToolDonePayload>): Partial<CompletionContext>;
15
+ export declare function finishDirectTool({ context, params }: CompletionActionArgs<ToolDonePayload>): Partial<CompletionContext>;
16
+ export declare function rejectRepeatedTool({ params }: CompletionActionArgs<RepeatOfFailedCallParams>): Partial<CompletionContext>;
@@ -0,0 +1,173 @@
1
+ import { applyHistorySplice, applySplice, failureResultRef, retainFailureResults, storeFailureResult, TOOL_DENIED_MESSAGE, toolDeniedResult } from '../rules.js';
2
+ import { applyPreparation } from './completion.js';
3
+ export function resolveTools({ context, params }) {
4
+ return {
5
+ toolQueue: [...params.calls],
6
+ cappedCalls: 0,
7
+ resolvedCount: params.calls.length,
8
+ ...applyHistorySplice(context, params.history)
9
+ };
10
+ }
11
+ export function selectNextTool({ params }) {
12
+ return { currentCall: params, rejectedCall: null };
13
+ }
14
+ export function rejectTool({ context, params }) {
15
+ const { call, execution, rejection } = params;
16
+ const memoized = memoizedFailure({
17
+ context,
18
+ call,
19
+ result: rejection.result,
20
+ outcome: rejection.outcome
21
+ });
22
+ return {
23
+ currentCall: call,
24
+ execution,
25
+ failureResults: memoized.failureResults ?? context.failureResults,
26
+ rejectedCall: rejectionPayload({
27
+ call,
28
+ ...memoized.value,
29
+ activity: rejection.activity,
30
+ effect: rejection.effect,
31
+ outcome: rejection.outcome,
32
+ deniedKey: rejection.deniedKey,
33
+ emitCall: rejection.emitCall ?? true,
34
+ emitResult: rejection.emitResult ?? true,
35
+ capped: rejection.capped ?? false,
36
+ source: rejection.source
37
+ })
38
+ };
39
+ }
40
+ export function rejectDeniedApproval({ context, params }) {
41
+ const { call, execution } = params;
42
+ const facts = execution.gate.facts;
43
+ const result = toolDeniedResult();
44
+ return {
45
+ pendingCall: null,
46
+ approval: { status: 'denied', key: context.approval.key },
47
+ rejectedCall: {
48
+ call,
49
+ result,
50
+ activity: {
51
+ type: 'tool-activity',
52
+ name: call.name,
53
+ args: call.args,
54
+ resource: facts.resource,
55
+ effect: facts.effect,
56
+ decision: 'denied'
57
+ },
58
+ effect: facts.effect,
59
+ outcome: { kind: 'denied', reason: TOOL_DENIED_MESSAGE },
60
+ deniedKey: facts.key,
61
+ emitCall: false,
62
+ emitResult: true,
63
+ capped: false,
64
+ source: execution.kind === 'skill' ? 'skill' : 'tool-result'
65
+ }
66
+ };
67
+ }
68
+ function memoizedFailure({ context, call, result, outcome }) {
69
+ if (!outcome || outcome.kind === 'denied') {
70
+ return { value: { result } };
71
+ }
72
+ const ref = failureResultRef(call.key, context.round, call.id);
73
+ const value = {
74
+ name: call.name,
75
+ result: storeFailureResult(result)
76
+ };
77
+ const prior = context.failureResults[ref];
78
+ if (prior) {
79
+ throw new Error(`Failure result reference collision: ${ref}`);
80
+ }
81
+ return {
82
+ value: { resultRef: ref },
83
+ failureResults: { ...context.failureResults, [ref]: value }
84
+ };
85
+ }
86
+ function rejectionPayload(payload) {
87
+ const result = payload.resultRef === undefined ? { result: payload.result } : { resultRef: payload.resultRef };
88
+ return {
89
+ call: payload.call,
90
+ ...result,
91
+ activity: payload.activity,
92
+ effect: payload.effect,
93
+ outcome: payload.outcome,
94
+ deniedKey: payload.deniedKey,
95
+ emitCall: payload.emitCall,
96
+ emitResult: payload.emitResult,
97
+ capped: payload.capped,
98
+ source: payload.source
99
+ };
100
+ }
101
+ export function queueDirectSearch({ context, params }) {
102
+ return {
103
+ ...applyPreparation(context, params.preparation),
104
+ pendingSearch: params.searchQuery
105
+ };
106
+ }
107
+ export function startDirectTool({ params }) {
108
+ return {
109
+ currentCall: params.call,
110
+ execution: params.execution
111
+ };
112
+ }
113
+ export function startTool({ params }) {
114
+ return { execution: params, pendingCall: null };
115
+ }
116
+ export function finishTool({ context, params }) {
117
+ return { ...applyToolResult(context, params), toolQueue: context.toolQueue.slice(1) };
118
+ }
119
+ export function finishDirectTool({ context, params }) {
120
+ return { ...applyToolResult(context, params), directSearchDone: true };
121
+ }
122
+ function applyToolResult(context, payload) {
123
+ const failedCalls = payload.failed
124
+ ? {
125
+ ...context.failedCalls,
126
+ [payload.failed.key]: {
127
+ resultRef: payload.failed.resultRef,
128
+ outcome: payload.failed.outcome
129
+ }
130
+ }
131
+ : context.failedCalls;
132
+ const failureResults = payload.failed?.value
133
+ ? { ...context.failureResults, [payload.failed.resultRef]: payload.failed.value }
134
+ : context.failureResults;
135
+ if (payload.failed && !failureResults[payload.failed.resultRef]) {
136
+ throw new Error(`Missing canonical failure result: ${payload.failed.resultRef}`);
137
+ }
138
+ const history = applySplice(context.history, payload.history);
139
+ return {
140
+ history,
141
+ failureResults: retainFailureResults(history, failureResults, failedCalls),
142
+ sources: payload.source ? [...context.sources, payload.source] : context.sources,
143
+ deniedKeys: payload.deniedKey && !context.deniedKeys.includes(payload.deniedKey)
144
+ ? [...context.deniedKeys, payload.deniedKey]
145
+ : context.deniedKeys,
146
+ failedCalls,
147
+ blockedRepeats: context.blockedRepeats + (payload.blockedRepeat ? 1 : 0),
148
+ roundProgressed: context.roundProgressed || payload.progressed === true,
149
+ webSearches: context.webSearches + (payload.webSearch ? 1 : 0),
150
+ cappedCalls: context.cappedCalls + (payload.searchCapped ? 1 : 0),
151
+ pendingCall: null,
152
+ approval: { status: 'idle', key: null },
153
+ currentCall: null,
154
+ execution: null,
155
+ rejectedCall: null
156
+ };
157
+ }
158
+ export function rejectRepeatedTool({ params }) {
159
+ const { call, prior } = params;
160
+ return {
161
+ currentCall: call,
162
+ rejectedCall: {
163
+ call,
164
+ resultRef: prior.resultRef,
165
+ activity: null,
166
+ emitCall: false,
167
+ emitResult: false,
168
+ capped: false,
169
+ source: 'tool-result',
170
+ repeat: prior.outcome
171
+ }
172
+ };
173
+ }
@@ -0,0 +1,9 @@
1
+ import type { CompletionContext, CompletionHistoryEntry } from './types.ts';
2
+ export interface EmptyCompletionContextOptions {
3
+ runId?: string;
4
+ history?: CompletionHistoryEntry[];
5
+ agentId?: string | null;
6
+ ctxSize?: number;
7
+ cacheKey?: string | null;
8
+ }
9
+ export declare function emptyCompletionContext(opts?: EmptyCompletionContextOptions): CompletionContext;
@@ -0,0 +1,44 @@
1
+ export function emptyCompletionContext(opts = {}) {
2
+ return {
3
+ runId: opts.runId ?? '',
4
+ timeUp: false,
5
+ pauseCount: 0,
6
+ durable: null,
7
+ recovery: undefined,
8
+ history: opts.history ?? [],
9
+ failureResults: {},
10
+ response: '',
11
+ sources: [],
12
+ availableTools: [],
13
+ promptPrefix: '',
14
+ round: 0,
15
+ roundsSent: 0,
16
+ mute: 0,
17
+ narrated: false,
18
+ webSearches: 0,
19
+ directSearchDone: false,
20
+ pendingSearch: null,
21
+ cappedRounds: 0,
22
+ deniedKeys: [],
23
+ failedCalls: {},
24
+ blockedRepeats: 0,
25
+ roundProgressed: false,
26
+ skills: { snapshot: null, loads: {}, pending: [] },
27
+ outcome: null,
28
+ metrics: { tokens: 0, timedTokens: 0, durationMs: 0, ctxSize: opts.ctxSize },
29
+ agentId: opts.agentId ?? null,
30
+ cacheKey: opts.cacheKey ?? null,
31
+ lastRound: null,
32
+ skillPreload: null,
33
+ pendingCall: null,
34
+ approval: { status: 'idle', key: null },
35
+ currentCall: null,
36
+ execution: null,
37
+ rejectedCall: null,
38
+ toolQueue: [],
39
+ cappedCalls: 0,
40
+ resolvedCount: 0,
41
+ failure: null,
42
+ failMessage: null
43
+ };
44
+ }
@@ -0,0 +1,6 @@
1
+ import type { ActorRefFrom, EventFrom, SnapshotFrom } from 'xstate';
2
+ import type { createCompletionMachine } from './machine.ts';
3
+ export type CompletionMachine = ReturnType<typeof createCompletionMachine>;
4
+ export type CompletionSnapshot = SnapshotFrom<CompletionMachine>;
5
+ export type CompletionActorRef = ActorRefFrom<CompletionMachine>;
6
+ export type CompletionAction = EventFrom<CompletionMachine>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { CompletionContext } from '../types.ts';
2
+ export declare function canMuteRetry(ctx: CompletionContext): boolean;
3
+ export declare function canRetrySearchCap(ctx: CompletionContext): boolean;
4
+ export declare function repeatsBlocked(ctx: CompletionContext): boolean;
5
+ export declare function hasRoundsLeft(ctx: CompletionContext): boolean;
6
+ export declare function canRetryNarrated(ctx: CompletionContext): boolean;
7
+ export declare function hasQueuedTool(ctx: CompletionContext): boolean;
8
+ export declare function allResolvedToolsCapped(ctx: CompletionContext): boolean;
9
+ export declare function searchPending(ctx: CompletionContext): boolean;
@@ -0,0 +1,25 @@
1
+ import { MAX_BLOCKED_REPEATS, MAX_CAPPED_ROUNDS, MAX_MUTE_ROUNDS, MAX_TOOL_ROUNDS } from '../rules.js';
2
+ export function canMuteRetry(ctx) {
3
+ return ctx.mute < MAX_MUTE_ROUNDS;
4
+ }
5
+ export function canRetrySearchCap(ctx) {
6
+ return ctx.cappedRounds < MAX_CAPPED_ROUNDS;
7
+ }
8
+ export function repeatsBlocked(ctx) {
9
+ return !ctx.roundProgressed && ctx.blockedRepeats >= MAX_BLOCKED_REPEATS;
10
+ }
11
+ export function hasRoundsLeft(ctx) {
12
+ return ctx.round + 1 < MAX_TOOL_ROUNDS;
13
+ }
14
+ export function canRetryNarrated(ctx) {
15
+ return !ctx.narrated && hasRoundsLeft(ctx);
16
+ }
17
+ export function hasQueuedTool(ctx) {
18
+ return ctx.toolQueue.length > 0;
19
+ }
20
+ export function allResolvedToolsCapped(ctx) {
21
+ return ctx.resolvedCount > 0 && ctx.cappedCalls === ctx.resolvedCount;
22
+ }
23
+ export function searchPending(ctx) {
24
+ return Boolean(ctx.pendingSearch);
25
+ }