@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
@@ -0,0 +1,152 @@
1
+ import { AbortedError } from '../../../helpers/race-abort.js';
2
+ import { hlog } from '../../../log.js';
3
+ import { skillIsActive } from '../../tool-selection.js';
4
+ import { WEB_SEARCH_TOOL_NAME } from '../../tool-names.js';
5
+ import { planToolCall } from '../../tool-plan.js';
6
+ import { approvalGate, resolvedCall, toolContext, trustedSources } from './execution-plan.js';
7
+ import { detachJson } from '../../../helpers/detach-json.js';
8
+ import { deniedWithoutApprover, gateRejection, policyActivity } from './rejection.js';
9
+ export const inspecting = async function inspecting({ input: deps, context }) {
10
+ const { args, session } = deps;
11
+ const snapshot = context.currentCall;
12
+ if (!snapshot) {
13
+ throw new Error('completion graph selected inspection without a current call');
14
+ }
15
+ const resolved = resolvedCall({ session, context });
16
+ if (args.signal?.aborted) {
17
+ throw new AbortedError();
18
+ }
19
+ const activation = {
20
+ ...session.activation,
21
+ loadedSkills: new Set(context.skills.snapshot?.loaded ?? [])
22
+ };
23
+ const executeContext = toolContext({ deps, context, name: resolved.call.name });
24
+ const plan = planToolCall(resolved, {
25
+ activation,
26
+ skillCatalog: args.skillCatalog ?? [],
27
+ loadedThisTurn: session.loadedThisTurn,
28
+ loadedFilesThisTurn: session.loadedFilesThisTurn,
29
+ webSearches: context.webSearches,
30
+ context: executeContext,
31
+ listShown: session.inContextSkills.some((skill) => skillIsActive(skill.name, session.activation))
32
+ });
33
+ if (plan.searchCapReached) {
34
+ hlog('tool capped', {
35
+ tool: resolved.call.name,
36
+ count: context.webSearches
37
+ });
38
+ }
39
+ const unavailableSkill = plan.skillCall && (!plan.toolAvailable || !plan.skillActive);
40
+ const hasEarlierRejection = plan.skillAlreadyLoaded ||
41
+ Boolean(plan.skillStatus) ||
42
+ unavailableSkill ||
43
+ plan.searchCapReached ||
44
+ Boolean(plan.hookRejection);
45
+ let resource = null;
46
+ if (!plan.skillAlreadyLoaded && !plan.searchCapReached && plan.toolAvailable) {
47
+ if (plan.skillStatus || unavailableSkill || plan.hookRejection) {
48
+ resource = detachJson(resolved.tool?.resource?.(detachJson(resolved.args), executeContext) ?? null);
49
+ }
50
+ }
51
+ let execution = null;
52
+ if (!hasEarlierRejection && resolved.tool) {
53
+ const inspectedGate = approvalGate({
54
+ deps,
55
+ context,
56
+ call: snapshot,
57
+ tool: resolved.tool,
58
+ effect: plan.effect ?? 'write',
59
+ sources: trustedSources(deps, context)
60
+ });
61
+ const gate = plan.skillCall ? { ...inspectedGate, approver: false } : inspectedGate;
62
+ resource = gate.facts.resource;
63
+ execution = {
64
+ kind: plan.skillCall ? 'skill' : 'tool',
65
+ effect: plan.effect ?? 'write',
66
+ skillName: plan.skillCall ? plan.skillName : null,
67
+ webSearch: resolved.call.name === WEB_SEARCH_TOOL_NAME,
68
+ gate
69
+ };
70
+ }
71
+ const rejection = inspectRejection({ context, plan, execution, resource, call: snapshot });
72
+ return {
73
+ call: snapshot,
74
+ toolAvailable: plan.toolAvailable,
75
+ skillCall: plan.skillCall,
76
+ skillAlreadyLoaded: plan.skillAlreadyLoaded,
77
+ skillStatus: plan.skillStatus,
78
+ skillActive: plan.skillActive,
79
+ skillName: plan.skillName,
80
+ alreadyLoadedLabel: plan.alreadyLoadedLabel,
81
+ unavailableSkillMessage: plan.unavailableSkillMessage,
82
+ searchCapReached: plan.searchCapReached,
83
+ searchCapMessage: plan.searchCapMessage,
84
+ hookRejection: plan.hookRejection,
85
+ source: plan.source,
86
+ effect: plan.effect,
87
+ resource,
88
+ execution,
89
+ rejection
90
+ };
91
+ };
92
+ const SKILL_WRITE_DENIED = 'Skill loaders must be read-only; this operation was not run.';
93
+ function inspectRejection({ context, plan, execution, resource, call }) {
94
+ const effect = plan.effect;
95
+ const source = plan.source;
96
+ const base = { activity: null, effect, source };
97
+ if (plan.skillAlreadyLoaded) {
98
+ const content = `${plan.alreadyLoadedLabel} is already loaded. Follow the instructions you were given and do not load it again.`;
99
+ return {
100
+ ...base,
101
+ result: { name: plan.skillName, content },
102
+ emitCall: false,
103
+ emitResult: false
104
+ };
105
+ }
106
+ if (plan.skillStatus) {
107
+ const error = `skill "${plan.skillName}" is ${plan.skillStatus} and cannot be used yet. Tell the user to open it in Skills and finish its setup; do not retry.`;
108
+ return { ...base, result: { error }, activity: policyActivity({ call, effect, resource }) };
109
+ }
110
+ if (plan.skillCall && (!plan.toolAvailable || !plan.skillActive)) {
111
+ return {
112
+ ...base,
113
+ result: { error: plan.unavailableSkillMessage },
114
+ activity: policyActivity({ call, effect, resource })
115
+ };
116
+ }
117
+ if (plan.searchCapReached) {
118
+ return {
119
+ ...base,
120
+ result: { content: plan.searchCapMessage },
121
+ emitCall: false,
122
+ emitResult: false,
123
+ capped: true
124
+ };
125
+ }
126
+ if (plan.hookRejection) {
127
+ return {
128
+ ...base,
129
+ result: plan.hookRejection,
130
+ activity: policyActivity({ call, effect, resource })
131
+ };
132
+ }
133
+ if (!plan.toolAvailable) {
134
+ return {
135
+ ...base,
136
+ result: { error: `unknown tool: ${call.name}` },
137
+ activity: policyActivity({ call, effect, resource: null })
138
+ };
139
+ }
140
+ const gated = gateRejection({ context, call, execution, resource, source });
141
+ if (gated) {
142
+ return gated;
143
+ }
144
+ if (plan.skillCall && plan.effect === 'write') {
145
+ return {
146
+ ...base,
147
+ result: { error: SKILL_WRITE_DENIED, guidance: true },
148
+ outcome: { kind: 'guidance', message: SKILL_WRITE_DENIED }
149
+ };
150
+ }
151
+ return deniedWithoutApprover({ context, call, execution, resource, source });
152
+ }
@@ -0,0 +1,3 @@
1
+ import { type SkillLoadOutput } from '../../../machine/index.ts';
2
+ import type { CompletionActor } from '../session.ts';
3
+ export declare const loadingSkill: CompletionActor<SkillLoadOutput>;
@@ -0,0 +1,94 @@
1
+ import { AbortedError } from '../../../helpers/race-abort.js';
2
+ import { RecoveryRequired, ToolPolicyChanged, spliceFrom } from '../../../machine/index.js';
3
+ import { labelOf, readyPreflightFromFacts, skillEmojiFrom } from '../../completion-loop/index.js';
4
+ import { skillFileKey } from '../../tool-plan.js';
5
+ import { toolResultTurn } from '../../tool-turns.js';
6
+ import { trustedSourceFacts } from '../../../tools/outbound-guard.js';
7
+ import { errorMessage, isRecord } from '../../../guards.js';
8
+ import { executionPlan, trustedSources } from './execution-plan.js';
9
+ import { runToolCall } from './execute.js';
10
+ export const loadingSkill = async function loadingSkill({ emit, input: deps, context }) {
11
+ const { args, session } = deps;
12
+ const plan = executionPlan(deps, context);
13
+ const { call, args: callArgs } = plan.resolved;
14
+ const skillName = plan.skillName;
15
+ if (skillName === null) {
16
+ throw new Error('skill loading route has no selected skill name');
17
+ }
18
+ if (args.signal?.aborted) {
19
+ throw new AbortedError();
20
+ }
21
+ const display = labelOf(call.name, callArgs, skillEmojiFrom(session.inContextSkills, skillName));
22
+ emit({
23
+ type: 'tool-call',
24
+ name: call.name,
25
+ args: callArgs,
26
+ rawCall: plan.resolved.rawCall,
27
+ effect: plan.effect,
28
+ display
29
+ });
30
+ const denied = new Set(context.deniedKeys);
31
+ const facts = context.execution?.gate?.facts;
32
+ if (!facts) {
33
+ throw new Error('selected skill load has no inspected policy facts');
34
+ }
35
+ const executed = await runToolCall(plan, {
36
+ approve: undefined,
37
+ signal: args.signal,
38
+ denied,
39
+ sources: trustedSources(deps, context),
40
+ pipeline: session.pipeline,
41
+ runId: session.runId,
42
+ callId: call.id,
43
+ skipApprovals: args.agent?.approvalMode === 'skip-all',
44
+ preflight: readyPreflightFromFacts(facts),
45
+ display
46
+ });
47
+ const { output, outcome, activity } = executed;
48
+ session.runOutcomes.record(output, outcome);
49
+ if (activity) {
50
+ emit(activity);
51
+ }
52
+ emit({ type: 'tool-result', name: call.name, result: output });
53
+ const turn = toolResultTurn(call.name, call.id, output);
54
+ const history = [
55
+ ...context.history,
56
+ { role: 'tool', content: turn }
57
+ ];
58
+ session.skillIcon = skillEmojiFrom(session.inContextSkills, skillName) ?? session.skillIcon;
59
+ if (hasContent(output)) {
60
+ if (isRecord(output) && typeof output.file === 'string') {
61
+ const files = session.loadedSkillFiles.get(skillName) ?? new Set();
62
+ files.add(output.file);
63
+ session.loadedSkillFiles.set(skillName, files);
64
+ }
65
+ const fileKey = skillFileKey(skillName, callArgs);
66
+ if (fileKey === null) {
67
+ session.loadedThisTurn.add(skillName);
68
+ }
69
+ else {
70
+ session.loadedFilesThisTurn.add(fileKey);
71
+ }
72
+ return {
73
+ name: skillName,
74
+ history: spliceFrom(context.history, history),
75
+ source: trustedSourceFacts('skill', turn)
76
+ };
77
+ }
78
+ return {
79
+ failure: {
80
+ name: skillName,
81
+ error: errorFrom(output),
82
+ history: spliceFrom(context.history, history)
83
+ }
84
+ };
85
+ };
86
+ function hasContent(output) {
87
+ return isRecord(output) && 'content' in output;
88
+ }
89
+ function errorFrom(output) {
90
+ if (isRecord(output) && 'error' in output) {
91
+ return String(output.error);
92
+ }
93
+ return 'skill did not return content';
94
+ }
@@ -0,0 +1,9 @@
1
+ import { type CompletionMachineContext } from '../../../machine/index.ts';
2
+ import type { SkillFailedPayload } from '../../../machine/index.ts';
3
+ export interface PreloadFailureInput {
4
+ history: CompletionMachineContext['history'];
5
+ startedAt: number;
6
+ name: string;
7
+ error: string;
8
+ }
9
+ export declare function preloadFailure({ history, startedAt, name, error }: PreloadFailureInput): SkillFailedPayload;
@@ -0,0 +1,11 @@
1
+ import { spliceFrom } from '../../../machine/index.js';
2
+ import { annotateCompletionHistoryLastUserTime, preloadLastUser } from '../../completion-loop/index.js';
3
+ export function preloadFailure({ history, startedAt, name, error }) {
4
+ const message = `Skill "${name}" could not be loaded: ${error}`;
5
+ const guided = preloadLastUser(history, name, message);
6
+ return {
7
+ name,
8
+ error: message,
9
+ history: spliceFrom(history, annotateCompletionHistoryLastUserTime(guided, new Date(startedAt)))
10
+ };
11
+ }
@@ -0,0 +1,3 @@
1
+ import { type SkillLoadOutput } from '../../../machine/index.ts';
2
+ import type { CompletionActor } from '../session.ts';
3
+ export declare const preloading: CompletionActor<SkillLoadOutput>;
@@ -0,0 +1,114 @@
1
+ import { AbortedError } from '../../../helpers/race-abort.js';
2
+ import { RecoveryRequired, ToolPolicyChanged, spliceFrom } from '../../../machine/index.js';
3
+ import { executeCall, annotateCompletionHistoryLastUserTime, labelOf, preloadLastUser, readyPreflightFromFacts, skillEmojiFrom } from '../../completion-loop/index.js';
4
+ import { withoutSkillLoadTurns } from '../../tool-turns.js';
5
+ import { SKILL_TOOL_NAME } from '../../tool-names.js';
6
+ import { trustedSourceFacts } from '../../../tools/outbound-guard.js';
7
+ import { errorMessage, isRecord } from '../../../guards.js';
8
+ import { toolContext } from './execution-plan.js';
9
+ import { preloadFailure } from './preload-failure.js';
10
+ import { detachJson } from '../../../helpers/detach-json.js';
11
+ export const preloading = async function preloading({ emit, input: deps, context }) {
12
+ const { args, session } = deps;
13
+ const pending = context.skillPreload;
14
+ if (!pending) {
15
+ throw new Error('preload execution requires an authorized skill');
16
+ }
17
+ const loader = session.enabled.find((tool) => tool.name === SKILL_TOOL_NAME);
18
+ if (!loader) {
19
+ throw new Error('skill preload requires the skill tool');
20
+ }
21
+ if (!pending.args || !pending.facts) {
22
+ throw new Error('skill preload has no authorized facts');
23
+ }
24
+ if (args.signal?.aborted) {
25
+ throw new AbortedError();
26
+ }
27
+ const preloadArgs = pending.args;
28
+ const contextForLoader = toolContext({ deps, context, name: loader.name });
29
+ const currentEffect = loader.effect(detachJson(preloadArgs), contextForLoader);
30
+ if (currentEffect !== pending.facts.effect || currentEffect !== 'read') {
31
+ return failure({
32
+ context,
33
+ startedAt: session.startedAt,
34
+ name: pending.name,
35
+ error: 'Skill loading is no longer classified as a read-only operation.'
36
+ });
37
+ }
38
+ const display = labelOf(SKILL_TOOL_NAME, preloadArgs, skillEmojiFrom(session.inContextSkills, pending.name));
39
+ const callId = `preload-${pending.name}`;
40
+ let activity = null;
41
+ let result;
42
+ try {
43
+ const executed = await executeCall(loader, preloadArgs, contextForLoader, {
44
+ runId: session.runId,
45
+ signal: args.signal,
46
+ sources: [],
47
+ pipeline: session.pipeline,
48
+ callId,
49
+ effect: currentEffect,
50
+ preflight: readyPreflightFromFacts(pending.facts),
51
+ display,
52
+ onToolActivity: (event) => (activity = event)
53
+ });
54
+ result = executed.result;
55
+ }
56
+ catch (error) {
57
+ if (error instanceof RecoveryRequired || error instanceof ToolPolicyChanged) {
58
+ throw error;
59
+ }
60
+ if (error instanceof AbortedError || args.signal?.aborted) {
61
+ throw new AbortedError();
62
+ }
63
+ const message = errorMessage(error);
64
+ return failure({ context, startedAt: session.startedAt, name: pending.name, error: message });
65
+ }
66
+ if (args.signal?.aborted) {
67
+ throw new AbortedError();
68
+ }
69
+ if (!context.skills.snapshot?.loaded.includes(pending.name)) {
70
+ emit({
71
+ type: 'tool-call',
72
+ name: SKILL_TOOL_NAME,
73
+ args: preloadArgs,
74
+ effect: 'read',
75
+ display
76
+ });
77
+ if (activity) {
78
+ emit(activity);
79
+ }
80
+ emit({ type: 'tool-result', name: SKILL_TOOL_NAME, result });
81
+ }
82
+ if (!hasContent(result)) {
83
+ return failure({
84
+ context,
85
+ startedAt: session.startedAt,
86
+ name: pending.name,
87
+ error: errorFrom(result) ?? 'skill did not return content'
88
+ });
89
+ }
90
+ const content = String(result.content);
91
+ session.loadedThisTurn.add(pending.name);
92
+ session.skillIcon = skillEmojiFrom(session.inContextSkills, pending.name) ?? session.skillIcon;
93
+ const inlined = preloadLastUser(context.history, pending.name, content);
94
+ const turns = withoutSkillLoadTurns(inlined, pending.name);
95
+ const history = annotateCompletionHistoryLastUserTime(turns, new Date(session.startedAt));
96
+ return {
97
+ name: pending.name,
98
+ history: spliceFrom(context.history, history),
99
+ source: trustedSourceFacts('skill', content),
100
+ cacheable: false
101
+ };
102
+ };
103
+ function failure({ context, startedAt, name, error }) {
104
+ return { failure: preloadFailure({ history: context.history, startedAt, name, error }) };
105
+ }
106
+ function hasContent(value) {
107
+ return isRecord(value) && 'content' in value;
108
+ }
109
+ function errorFrom(value) {
110
+ if (isRecord(value) && 'error' in value) {
111
+ return errorMessage(value.error);
112
+ }
113
+ return null;
114
+ }
@@ -0,0 +1,3 @@
1
+ import type { PreparingOutput } from '../../../machine/index.ts';
2
+ import type { CompletionActor } from '../session.ts';
3
+ export declare const preparing: CompletionActor<PreparingOutput>;
@@ -0,0 +1,198 @@
1
+ import { spliceFrom } from '../../../machine/index.js';
2
+ import { AbortedError } from '../../../helpers/race-abort.js';
3
+ import { resolveLlmGenerationParams } from '../../../models/llm-presets.js';
4
+ import { annotateLastUserTime, skillsPromptSection, systemPromptParts } from '../../../prompt.js';
5
+ import { resolveImplicitSkill, resolveSkillMention } from '../../../tools/skills/mention.js';
6
+ import { NETWORK_TOOLSETS, permittedTools } from '../../../tools/toolsets.js';
7
+ import { explicitWebSearchQuery, lastUserContent, lastUserImages, sanitizeTurn, skillInContext, toSdkTool, selectEnabledTools } from '../../completion-loop/index.js';
8
+ import { SKILL_TOOL_NAME } from '../../tool-names.js';
9
+ import { collectToolGrants, isSelected, skillIsActive, skillsAreSelected } from '../../tool-selection.js';
10
+ import { loadedSkillFilesFrom, loadedSkillsFrom } from '../../tool-turns.js';
11
+ import { promptPrefixHash } from '../../prompt-prefix.js';
12
+ import { promptUsageParts } from '../../usage-breakdown.js';
13
+ import { logToolPrompt } from '../../tool-prompt-log.js';
14
+ import { toolContext } from './execution-plan.js';
15
+ import { detachJson } from '../../../helpers/detach-json.js';
16
+ export const preparing = async function preparing({ input, context, reconstruct }) {
17
+ const { args, session } = input;
18
+ const { model, agent, thinkingDefault, generationParams: generationParamsOverride, responseFormat, messages: storedMessages, tools: allTools = [], skillCatalog = [], signal, fsRoots = [], fsWriteRoots = [] } = args;
19
+ if (signal?.aborted) {
20
+ throw new AbortedError();
21
+ }
22
+ const messages = storedMessages.map(sanitizeTurn);
23
+ if (!session.runStarted && !reconstruct) {
24
+ await session.pipeline.onRunStart({
25
+ runId: session.runId,
26
+ agentId: agent?.id ?? null,
27
+ messages
28
+ });
29
+ session.runStarted = true;
30
+ }
31
+ const disabledToolsets = agent?.sandboxMode
32
+ ? [...(agent.disabledToolsets ?? []), ...NETWORK_TOOLSETS]
33
+ : agent?.disabledToolsets;
34
+ const tools = permittedTools(allTools, disabledToolsets);
35
+ const writableRoots = [
36
+ ...fsWriteRoots,
37
+ ...fsRoots.filter((root) => root.kind === 'hyper' && root.writable && !fsWriteRoots.includes(root))
38
+ ];
39
+ const turnImages = lastUserImages(messages);
40
+ const toolsSelected = isSelected(agent?.toolsScope, agent?.enabledTools);
41
+ const skillsSelected = skillsAreSelected(agent?.skillsScope, Boolean(agent));
42
+ const inContextSkills = skillCatalog.filter(skillInContext);
43
+ const mention = resolveSkillMention(lastUserContent(messages), inContextSkills);
44
+ const loadedSkills = new Set([
45
+ ...loadedSkillsFrom(messages),
46
+ ...(context.skills.snapshot?.loaded ?? [])
47
+ ]);
48
+ const loadedSkillFiles = loadedSkillFilesFrom(messages);
49
+ const activation = {
50
+ skillsSelected,
51
+ enabledSkills: agent?.enabledSkills ?? [],
52
+ mention: mention?.name ?? null,
53
+ loadedSkills
54
+ };
55
+ const activeSkills = inContextSkills.filter((skill) => skillIsActive(skill.name, activation));
56
+ const { grantedNames, grantedOwners, grantedOps } = collectToolGrants(activeSkills);
57
+ const selection = {
58
+ responseFormat: Boolean(responseFormat),
59
+ tools,
60
+ toolsSelected,
61
+ allowlist: agent?.enabledTools ?? [],
62
+ activeSkills,
63
+ grantedNames,
64
+ grantedOwners,
65
+ hasRoots: fsRoots.length > 0,
66
+ hasWriteRoots: writableRoots.length > 0
67
+ };
68
+ const enabled = selectEnabledTools({ ...selection, loadedSkills });
69
+ const sdkTools = enabled.length ? enabled.map((tool) => toSdkTool(tool)) : undefined;
70
+ const reasoningEnabled = settingEnabled(agent?.reasoning);
71
+ const deviceReasoning = settingEnabled(thinkingDefault);
72
+ const resolvedGenerationParams = resolveLlmGenerationParams(model, reasoningEnabled, deviceReasoning);
73
+ const generationParams = generationParamsOverride
74
+ ? { ...resolvedGenerationParams, ...generationParamsOverride }
75
+ : resolvedGenerationParams;
76
+ const system = systemPromptParts({
77
+ bio: agent?.bio,
78
+ toolNames: enabled.map((tool) => tool.name),
79
+ skillsSection: skillsPromptSection(activeSkills)
80
+ });
81
+ const systemContent = system.text;
82
+ const promptPrefix = promptPrefixHash({ system: systemContent, tools: sdkTools });
83
+ const promptParts = promptUsageParts({ system, toolSchemas: sdkTools });
84
+ const logSelection = (prefix) => {
85
+ logToolPrompt({
86
+ promptPrefix: prefix,
87
+ modelId: args.modelId,
88
+ cacheKey: context.cacheKey ?? undefined,
89
+ agentId: agent?.id,
90
+ messageCount: messages.length,
91
+ responseFormat: responseFormat?.type,
92
+ tools: session.sdkTools,
93
+ definitions: session.enabled,
94
+ activeSkills: activeSkills.map((skill) => skill.name),
95
+ skillsSelected,
96
+ enabledSkills: agent?.enabledSkills ?? [],
97
+ mentionedSkill: mention?.name ?? null,
98
+ loadedSkills: session.activation.loadedSkills,
99
+ toolOps: session.grantedOps
100
+ });
101
+ };
102
+ session.reselectTools = (loaded) => {
103
+ const reselected = selectEnabledTools({ ...selection, loadedSkills: loaded });
104
+ const names = reselected.map((tool) => tool.name).join();
105
+ if (names === session.enabled.map((tool) => tool.name).join()) {
106
+ return null;
107
+ }
108
+ session.enabled = reselected;
109
+ session.sdkTools = reselected.length ? reselected.map((tool) => toSdkTool(tool)) : undefined;
110
+ const prefix = promptPrefixHash({ system: systemContent, tools: session.sdkTools });
111
+ session.promptParts = promptUsageParts({ system, toolSchemas: session.sdkTools });
112
+ logSelection(prefix);
113
+ return prefix;
114
+ };
115
+ const turns = messages;
116
+ const initialHistory = systemContent
117
+ ? [{ role: 'system', content: systemContent }, ...turns]
118
+ : turns;
119
+ const history = context.round > 0 || context.directSearchDone
120
+ ? [...context.history]
121
+ : annotateLastUserTime(initialHistory, new Date(session.startedAt));
122
+ const sources = context.round > 0 || context.directSearchDone ? [...context.sources] : [];
123
+ const preparation = {
124
+ history: spliceFrom(context.history, history),
125
+ loadedSkills: [...loadedSkills],
126
+ webSearches: context.webSearches,
127
+ deniedKeys: [...context.deniedKeys],
128
+ sources,
129
+ availableTools: enabled.map((tool) => tool.name),
130
+ promptPrefix
131
+ };
132
+ prepareSession(session, {
133
+ enabled,
134
+ sdkTools,
135
+ grantedOps,
136
+ activation,
137
+ inContextSkills,
138
+ loadedSkillFiles,
139
+ writableRoots,
140
+ turnImages,
141
+ generationParams,
142
+ promptParts
143
+ });
144
+ logSelection(promptPrefix);
145
+ const round = {
146
+ preparation,
147
+ skillCandidate: null,
148
+ skillLoaderAvailable: false,
149
+ skillLoaderEffect: null,
150
+ skillAlreadyLoaded: false,
151
+ preload: null,
152
+ searchQuery: null
153
+ };
154
+ if (reconstruct) {
155
+ return round;
156
+ }
157
+ const preload = mention ?? resolveImplicitSkill(lastUserContent(messages), activeSkills);
158
+ const loader = enabled.find((tool) => tool.name === SKILL_TOOL_NAME);
159
+ const skillAlreadyLoaded = preload ? session.loadedThisTurn.has(preload.name) : false;
160
+ const skillLoaderEffect = preload && loader
161
+ ? loader.effect(detachJson({ name: preload.name }), toolContext({
162
+ deps: input,
163
+ context,
164
+ name: loader.name
165
+ }))
166
+ : null;
167
+ const searchQuery = (skillPreloaded) => context.directSearchDone
168
+ ? null
169
+ : explicitWebSearchQuery(lastUserContent(messages), enabled, { skillPreloaded });
170
+ return {
171
+ ...round,
172
+ skillCandidate: preload?.name ?? null,
173
+ skillLoaderAvailable: Boolean(loader),
174
+ skillLoaderEffect,
175
+ skillAlreadyLoaded,
176
+ preload: preload
177
+ ? {
178
+ ...preparation,
179
+ history: spliceFrom(context.history, initialHistory),
180
+ name: preload.name,
181
+ pendingSearch: searchQuery(true)
182
+ }
183
+ : null,
184
+ searchQuery: searchQuery(false)
185
+ };
186
+ };
187
+ function settingEnabled(value) {
188
+ if (value === 'enabled') {
189
+ return true;
190
+ }
191
+ if (value === 'disabled') {
192
+ return false;
193
+ }
194
+ return undefined;
195
+ }
196
+ function prepareSession(session, prepared) {
197
+ Object.assign(session, prepared);
198
+ }
@@ -0,0 +1,3 @@
1
+ import { type ToolDonePayload } from '../../../machine/index.ts';
2
+ import type { CompletionActor } from '../session.ts';
3
+ export declare const rejecting: CompletionActor<ToolDonePayload>;
@@ -0,0 +1,71 @@
1
+ import { readFailureResult, spliceFrom } from '../../../machine/index.js';
2
+ import { directToolHistory, labelOf } from '../../completion-loop/index.js';
3
+ import { toolResultHistoryEntry, toolResultTurn } from '../../tool-turns.js';
4
+ import { trustedSourceFacts } from '../../../tools/outbound-guard.js';
5
+ export const rejecting = async function rejecting({ emit, input: { session }, context }) {
6
+ const rejected = context.rejectedCall;
7
+ if (!rejected) {
8
+ throw new Error('completion graph selected rejection without a rejected call');
9
+ }
10
+ const { call } = rejected;
11
+ const result = rejected.resultRef
12
+ ? failureResult(context, rejected.resultRef, call.name)
13
+ : rejected.result;
14
+ session.runOutcomes.record(result, rejected.repeat ?? rejected.outcome ?? { kind: 'blocked', reason: 'Tool call was rejected' });
15
+ if (rejected.emitCall) {
16
+ emit({
17
+ type: 'tool-call',
18
+ name: call.name,
19
+ args: call.args,
20
+ rawCall: call.rawCall,
21
+ effect: rejected.effect,
22
+ display: labelOf(call.name, call.args, session.skillIcon)
23
+ });
24
+ }
25
+ if (rejected.activity) {
26
+ emit(rejected.activity);
27
+ }
28
+ if (rejected.emitResult) {
29
+ emit({ type: 'tool-result', name: call.name, result });
30
+ }
31
+ const turn = toolResultTurn(call.name, call.id, result);
32
+ const history = context.execution?.kind === 'direct'
33
+ ? directToolHistory(context.history, call.args, result, rejected.resultRef)
34
+ : [
35
+ ...context.history,
36
+ toolResultHistoryEntry({
37
+ name: call.name,
38
+ id: call.id,
39
+ output: result,
40
+ resultRef: rejected.resultRef
41
+ })
42
+ ];
43
+ const failed = rejected.outcome && rejected.outcome.kind !== 'denied' && !rejected.repeat
44
+ ? {
45
+ key: call.key,
46
+ resultRef: requiredFailureRef(rejected.resultRef),
47
+ outcome: rejected.outcome
48
+ }
49
+ : undefined;
50
+ return {
51
+ deniedKey: rejected.deniedKey,
52
+ failed,
53
+ searchCapped: rejected.capped,
54
+ blockedRepeat: rejected.repeat ? true : undefined,
55
+ history: spliceFrom(context.history, history),
56
+ source: trustedSourceFacts(rejected.source, turn)
57
+ };
58
+ };
59
+ function failureResult(context, ref, name) {
60
+ const stored = context.failureResults[ref];
61
+ if (!stored || stored.name !== name) {
62
+ throw new Error(`Rejected call references missing or mismatched failure result: ${ref}`);
63
+ }
64
+ return readFailureResult(stored.result);
65
+ }
66
+ function requiredFailureRef(ref) {
67
+ if (ref === undefined) {
68
+ throw new Error('Memoized rejected call has no failure result reference');
69
+ }
70
+ return ref;
71
+ }