@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.
- package/README.md +224 -0
- package/dist-lib/index.d.ts +55 -3
- package/dist-lib/index.js +721 -236
- package/dist-lib/lib/capabilities/completion-engine/abort-polyfill.d.ts +1 -0
- package/dist-lib/lib/capabilities/completion-engine/abort-polyfill.js +10 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/answering.d.ts +3 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/answering.js +17 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/approval.d.ts +4 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/approval.js +29 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/direct-search.d.ts +4 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/direct-search.js +73 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/execute.d.ts +41 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/execute.js +49 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/executing.d.ts +3 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/executing.js +102 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/execution-plan.d.ts +47 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/execution-plan.js +87 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/finishing.d.ts +2 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/finishing.js +32 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/inspect-preload.d.ts +3 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/inspect-preload.js +75 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/inspecting.d.ts +3 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/inspecting.js +152 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/loading-skill.d.ts +3 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/loading-skill.js +94 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/preload-failure.d.ts +9 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/preload-failure.js +11 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/preloading.d.ts +3 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/preloading.js +114 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/preparing.d.ts +3 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/preparing.js +198 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/rejecting.d.ts +3 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/rejecting.js +71 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/rejection.d.ts +18 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/rejection.js +70 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/resolving.d.ts +3 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/resolving.js +60 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/stream.d.ts +21 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/stream.js +48 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/streaming.d.ts +3 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/streaming.js +156 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/wrap-up.d.ts +7 -0
- package/dist-lib/lib/capabilities/completion-engine/actors/wrap-up.js +61 -0
- package/dist-lib/lib/capabilities/completion-engine/driver.d.ts +25 -0
- package/dist-lib/lib/capabilities/completion-engine/driver.js +553 -0
- package/dist-lib/lib/capabilities/completion-engine/durable.d.ts +61 -0
- package/dist-lib/lib/capabilities/completion-engine/durable.js +150 -0
- package/dist-lib/lib/capabilities/completion-engine/operations.d.ts +6 -0
- package/dist-lib/lib/capabilities/completion-engine/operations.js +239 -0
- package/dist-lib/lib/capabilities/completion-engine/ports.d.ts +3 -0
- package/dist-lib/lib/capabilities/completion-engine/ports.js +267 -0
- package/dist-lib/lib/capabilities/completion-engine/session.d.ts +76 -0
- package/dist-lib/lib/capabilities/completion-engine/session.js +70 -0
- package/dist-lib/lib/capabilities/completion-loop/index.d.ts +80 -0
- package/dist-lib/lib/capabilities/completion-loop/index.js +158 -0
- package/dist-lib/lib/capabilities/completion-loop/metrics.d.ts +5 -0
- package/dist-lib/lib/capabilities/completion-loop/metrics.js +29 -0
- package/dist-lib/lib/capabilities/completion-loop/round.d.ts +33 -0
- package/dist-lib/lib/capabilities/completion-loop/round.js +353 -0
- package/dist-lib/lib/capabilities/completion-loop/tool-execution.d.ts +60 -0
- package/dist-lib/lib/capabilities/completion-loop/tool-execution.js +270 -0
- package/dist-lib/lib/capabilities/completion-loop/turns.d.ts +23 -0
- package/dist-lib/lib/capabilities/completion-loop/turns.js +112 -0
- package/dist-lib/lib/capabilities/completion-runtime.d.ts +46 -0
- package/dist-lib/lib/capabilities/completion-runtime.js +74 -0
- package/dist-lib/lib/capabilities/completion.d.ts +18 -335
- package/dist-lib/lib/capabilities/completion.js +20 -1301
- package/dist-lib/lib/capabilities/download.d.ts +1 -1
- package/dist-lib/lib/capabilities/download.js +7 -2
- package/dist-lib/lib/capabilities/invoke.js +5 -3
- package/dist-lib/lib/capabilities/tool-plan.d.ts +35 -0
- package/dist-lib/lib/capabilities/tool-plan.js +66 -0
- package/dist-lib/lib/capabilities/tool-turns.d.ts +11 -2
- package/dist-lib/lib/capabilities/tool-turns.js +30 -2
- package/dist-lib/lib/capabilities/types.d.ts +287 -0
- package/dist-lib/lib/capabilities/types.js +1 -0
- package/dist-lib/lib/completion-lifecycle.d.ts +14 -0
- package/dist-lib/lib/completion-lifecycle.js +126 -0
- package/dist-lib/lib/connect.d.ts +10 -3
- package/dist-lib/lib/connect.js +329 -23
- package/dist-lib/lib/contract-types.d.ts +19 -2
- package/dist-lib/lib/harness-lifecycle.d.ts +66 -0
- package/dist-lib/lib/harness-lifecycle.js +129 -0
- package/dist-lib/lib/helpers/detach-json.d.ts +1 -0
- package/dist-lib/lib/helpers/detach-json.js +146 -0
- package/dist-lib/lib/helpers/markup-scanner.d.ts +26 -0
- package/dist-lib/lib/helpers/markup-scanner.js +156 -0
- package/dist-lib/lib/helpers/markup-stream-filter.js +138 -35
- package/dist-lib/lib/helpers/race-abort.d.ts +9 -4
- package/dist-lib/lib/helpers/race-abort.js +2 -7
- package/dist-lib/lib/helpers/recovery-required.d.ts +1 -0
- package/dist-lib/lib/helpers/recovery-required.js +1 -0
- package/dist-lib/lib/helpers/run-outcome.d.ts +10 -2
- package/dist-lib/lib/helpers/run-outcome.js +8 -5
- package/dist-lib/lib/helpers/tool-call-markup.d.ts +2 -0
- package/dist-lib/lib/helpers/tool-call-markup.js +197 -82
- package/dist-lib/lib/hooks/built-in/arg-repair.d.ts +1 -0
- package/dist-lib/lib/hooks/built-in/arg-repair.js +1 -0
- package/dist-lib/lib/hooks/built-in/egress.d.ts +1 -0
- package/dist-lib/lib/hooks/built-in/egress.js +2 -1
- package/dist-lib/lib/hooks/built-in/sandbox.d.ts +1 -0
- package/dist-lib/lib/hooks/built-in/sandbox.js +6 -1
- package/dist-lib/lib/hooks/built-in/skill-catalog.d.ts +1 -0
- package/dist-lib/lib/hooks/built-in/skill-catalog.js +2 -1
- package/dist-lib/lib/hooks/pipeline.d.ts +4 -1
- package/dist-lib/lib/hooks/pipeline.js +24 -2
- package/dist-lib/lib/hooks/run.d.ts +2 -1
- package/dist-lib/lib/hooks/run.js +19 -7
- package/dist-lib/lib/hooks/types.d.ts +17 -6
- package/dist-lib/lib/machine/completion/actions/approval.d.ts +3 -0
- package/dist-lib/lib/machine/completion/actions/approval.js +16 -0
- package/dist-lib/lib/machine/completion/actions/completion.d.ts +23 -0
- package/dist-lib/lib/machine/completion/actions/completion.js +142 -0
- package/dist-lib/lib/machine/completion/actions/skills.d.ts +9 -0
- package/dist-lib/lib/machine/completion/actions/skills.js +83 -0
- package/dist-lib/lib/machine/completion/actions/tools.d.ts +16 -0
- package/dist-lib/lib/machine/completion/actions/tools.js +173 -0
- package/dist-lib/lib/machine/completion/context.d.ts +9 -0
- package/dist-lib/lib/machine/completion/context.js +44 -0
- package/dist-lib/lib/machine/completion/contract.d.ts +6 -0
- package/dist-lib/lib/machine/completion/contract.js +1 -0
- package/dist-lib/lib/machine/completion/guards/retry.d.ts +9 -0
- package/dist-lib/lib/machine/completion/guards/retry.js +25 -0
- package/dist-lib/lib/machine/completion/implementations.d.ts +81 -0
- package/dist-lib/lib/machine/completion/implementations.js +152 -0
- package/dist-lib/lib/machine/completion/machine.d.ts +375 -0
- package/dist-lib/lib/machine/completion/machine.js +511 -0
- package/dist-lib/lib/machine/completion/ports.d.ts +65 -0
- package/dist-lib/lib/machine/completion/ports.js +224 -0
- package/dist-lib/lib/machine/completion/rules.d.ts +39 -0
- package/dist-lib/lib/machine/completion/rules.js +115 -0
- package/dist-lib/lib/machine/completion/types.d.ts +493 -0
- package/dist-lib/lib/machine/completion/types.js +1 -0
- package/dist-lib/lib/machine/engine.d.ts +93 -0
- package/dist-lib/lib/machine/engine.js +483 -0
- package/dist-lib/lib/machine/errors.d.ts +44 -0
- package/dist-lib/lib/machine/errors.js +373 -0
- package/dist-lib/lib/machine/guards.d.ts +2 -0
- package/dist-lib/lib/machine/guards.js +6 -0
- package/dist-lib/lib/machine/index.d.ts +20 -0
- package/dist-lib/lib/machine/index.js +11 -0
- package/dist-lib/lib/machine/replay-output.d.ts +24 -0
- package/dist-lib/lib/machine/replay-output.js +50 -0
- package/dist-lib/lib/machine/stable-stringify.d.ts +1 -0
- package/dist-lib/lib/machine/stable-stringify.js +11 -0
- package/dist-lib/lib/models/model-pool.d.ts +14 -6
- package/dist-lib/lib/models/model-pool.js +95 -30
- package/dist-lib/lib/run-log/history-codec.d.ts +23 -0
- package/dist-lib/lib/run-log/history-codec.js +973 -0
- package/dist-lib/lib/run-log/patch.d.ts +6 -0
- package/dist-lib/lib/run-log/patch.js +93 -0
- package/dist-lib/lib/run-log/persisted-actor.d.ts +18 -0
- package/dist-lib/lib/run-log/persisted-actor.js +218 -0
- package/dist-lib/lib/run-log/protocol-types.d.ts +153 -0
- package/dist-lib/lib/run-log/protocol-types.js +1 -0
- package/dist-lib/lib/run-log/protocol.d.ts +27 -0
- package/dist-lib/lib/run-log/protocol.js +1056 -0
- package/dist-lib/lib/run-log/replay.d.ts +25 -0
- package/dist-lib/lib/run-log/replay.js +129 -0
- package/dist-lib/lib/run-log/run-journal.d.ts +125 -0
- package/dist-lib/lib/run-log/run-journal.js +783 -0
- package/dist-lib/lib/run-log-inspect.d.ts +25 -0
- package/dist-lib/lib/run-log-inspect.js +627 -0
- package/dist-lib/lib/run-log-protocol.d.ts +2 -0
- package/dist-lib/lib/run-log-protocol.js +1 -0
- package/dist-lib/lib/run-log-redact.d.ts +27 -0
- package/dist-lib/lib/run-log-redact.js +1107 -0
- package/dist-lib/lib/serve.js +307 -11
- package/dist-lib/lib/spawn.js +3 -2
- package/dist-lib/lib/tool-call-display.d.ts +1 -21
- package/dist-lib/lib/tools/exec/adapters/python/wheels.js +2 -1
- package/dist-lib/lib/tools/exec.d.ts +2 -1
- package/dist-lib/lib/tools/exec.js +57 -2
- package/dist-lib/lib/tools/generate-image.js +1 -1
- package/dist-lib/lib/tools/generate-music.js +1 -1
- package/dist-lib/lib/tools/http-request.d.ts +2 -1
- package/dist-lib/lib/tools/http-request.js +2 -1
- package/dist-lib/lib/tools/mcp-call.js +8 -1
- package/dist-lib/lib/tools/operations/builders.d.ts +1 -0
- package/dist-lib/lib/tools/operations/builders.js +1 -0
- package/dist-lib/lib/tools/operations/compile.js +11 -1
- package/dist-lib/lib/tools/operations/manifest.js +1 -0
- package/dist-lib/lib/tools/outbound-guard.d.ts +8 -6
- package/dist-lib/lib/tools/outbound-guard.js +25 -8
- package/dist-lib/lib/tools/skills/catalog.d.ts +1 -0
- package/dist-lib/lib/tools/skills/catalog.js +35 -0
- package/dist-lib/lib/tools/skills/cli-schema-types.d.ts +1 -0
- package/dist-lib/lib/tools/skills/cli-schema.js +25 -0
- package/dist-lib/lib/wire.d.ts +5 -0
- package/dist-lib/lib/wire.js +128 -5
- package/dist-lib/schema/harness.js +20 -5
- package/dist-lib/spec/hrpc/messages.js +95 -15
- package/dist-lib/spec/hyperschema/index.js +95 -15
- package/dist-lib/spec/hyperschema/schema.json +69 -1
- package/dist-lib/spec/hyperschema/types.d.ts +10 -3
- package/package.json +20 -2
- package/patches/@qvac%2Finference@0.20.0.patch +67 -0
- package/patches/bare-stow@0.1.5.patch +68 -0
- package/patches/hypercore-blob-server@1.15.0.patch +15 -0
- package/patches/localwatch@1.4.3.patch +13 -0
- 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,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,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,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,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
|
+
}
|