@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 @@
|
|
|
1
|
+
export declare function installAbortControllerPolyfill(): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AbortController as BareAbortController } from 'bare-abort-controller';
|
|
2
|
+
export function installAbortControllerPolyfill() {
|
|
3
|
+
if (typeof globalThis.AbortController === 'undefined') {
|
|
4
|
+
Object.defineProperty(globalThis, 'AbortController', {
|
|
5
|
+
value: BareAbortController,
|
|
6
|
+
writable: true,
|
|
7
|
+
configurable: true
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { assembleAnswer } from './stream.js';
|
|
2
|
+
import { stripToolCallMarkup } from '../../../helpers/tool-call-markup.js';
|
|
3
|
+
export const answering = async function answering({ emit, input: { session }, context }) {
|
|
4
|
+
const round = context.lastRound;
|
|
5
|
+
if (round.response && !round.contentText.trim() && !round.replay) {
|
|
6
|
+
emit({ type: 'content', text: round.response });
|
|
7
|
+
return { response: round.response };
|
|
8
|
+
}
|
|
9
|
+
const replay = round.replay ? stripToolCallMarkup(round.replay) : '';
|
|
10
|
+
const response = await assembleAnswer({
|
|
11
|
+
contentText: round.contentText,
|
|
12
|
+
replay,
|
|
13
|
+
landed: session.landed,
|
|
14
|
+
emit
|
|
15
|
+
});
|
|
16
|
+
return { response };
|
|
17
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { raceAbort } from '../../../helpers/race-abort.js';
|
|
2
|
+
import { detachJson } from '../../../helpers/detach-json.js';
|
|
3
|
+
export const approval = async function approval({ emit, input: { args, operations }, context, signal }) {
|
|
4
|
+
const call = context.pendingCall;
|
|
5
|
+
const approve = args.approve;
|
|
6
|
+
if (!call || !approve) {
|
|
7
|
+
return { approved: false };
|
|
8
|
+
}
|
|
9
|
+
const currentCall = context.currentCall;
|
|
10
|
+
const rawCall = context.currentCall?.rawCall;
|
|
11
|
+
emit({
|
|
12
|
+
type: 'tool-call',
|
|
13
|
+
name: call.name,
|
|
14
|
+
args: call.arguments,
|
|
15
|
+
rawCall,
|
|
16
|
+
effect: call.effect ?? 'write',
|
|
17
|
+
display: call.display ?? undefined
|
|
18
|
+
});
|
|
19
|
+
const id = `${context.runId}:round-${context.round}:${currentCall?.id ?? call.name}:approve`;
|
|
20
|
+
const approved = await operations.operation({ id, name: 'human:approve', args: call.arguments, effect: 'read' }, () => raceAbort(raceAbort(approve({
|
|
21
|
+
...call,
|
|
22
|
+
arguments: detachJson(call.arguments),
|
|
23
|
+
resource: detachJson(call.resource),
|
|
24
|
+
display: detachJson(call.display),
|
|
25
|
+
callId: currentCall?.id,
|
|
26
|
+
round: context.round
|
|
27
|
+
}), args.signal), signal), undefined, signal);
|
|
28
|
+
return { approved };
|
|
29
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CompletionMachineContext as CompletionContext, DirectToolOutput, SearchingOutput } from '../../../machine/index.ts';
|
|
2
|
+
import type { CompletionActor, CompletionDeps } from '../session.ts';
|
|
3
|
+
export declare const directSearch: CompletionActor<SearchingOutput>;
|
|
4
|
+
export declare function startDirectSearch(deps: CompletionDeps, context: CompletionContext, query: string): Promise<DirectToolOutput | null>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { AbortedError } from '../../../helpers/race-abort.js';
|
|
2
|
+
import { WEB_SEARCH_TOOL_NAME } from '../../tool-names.js';
|
|
3
|
+
import { DIRECT_CALL_ID } from '../../tool-turns.js';
|
|
4
|
+
import { approvalGate, trustedSources } from './execution-plan.js';
|
|
5
|
+
import { detachJson } from '../../../helpers/detach-json.js';
|
|
6
|
+
import { deniedWithoutApprover, gateRejection, policyActivity } from './rejection.js';
|
|
7
|
+
export const directSearch = async function directSearch({ input: deps, context }) {
|
|
8
|
+
return {
|
|
9
|
+
directTool: context.pendingSearch
|
|
10
|
+
? await startDirectSearch(deps, context, context.pendingSearch)
|
|
11
|
+
: null
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export async function startDirectSearch(deps, context, query) {
|
|
15
|
+
const { args, session } = deps;
|
|
16
|
+
const webSearch = session.enabled.find((tool) => tool.name === WEB_SEARCH_TOOL_NAME);
|
|
17
|
+
if (!webSearch) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const fold = await session.pipeline.runPreToolFold({
|
|
21
|
+
runId: session.runId,
|
|
22
|
+
callId: DIRECT_CALL_ID,
|
|
23
|
+
toolName: webSearch.name,
|
|
24
|
+
args: { query },
|
|
25
|
+
agentId: args.agent?.id ?? null,
|
|
26
|
+
signal: args.signal
|
|
27
|
+
});
|
|
28
|
+
const searchArgs = fold.ok ? detachJson(fold.args) : { query };
|
|
29
|
+
if (args.signal?.aborted) {
|
|
30
|
+
throw new AbortedError();
|
|
31
|
+
}
|
|
32
|
+
const call = {
|
|
33
|
+
id: DIRECT_CALL_ID,
|
|
34
|
+
key: session.callKey(webSearch.name, searchArgs),
|
|
35
|
+
name: webSearch.name,
|
|
36
|
+
args: searchArgs
|
|
37
|
+
};
|
|
38
|
+
const effect = webSearch.effect(detachJson(searchArgs));
|
|
39
|
+
const execution = { kind: 'direct', effect, skillName: null, webSearch: true };
|
|
40
|
+
if (fold.ok) {
|
|
41
|
+
const sources = trustedSources(deps, context);
|
|
42
|
+
const gate = approvalGate({
|
|
43
|
+
deps,
|
|
44
|
+
context,
|
|
45
|
+
call,
|
|
46
|
+
tool: webSearch,
|
|
47
|
+
effect,
|
|
48
|
+
sources
|
|
49
|
+
});
|
|
50
|
+
const gated = { ...execution, gate };
|
|
51
|
+
const resource = gate.call.resource ?? null;
|
|
52
|
+
const rejection = { context, call, execution: gated, resource, source: 'tool-result' };
|
|
53
|
+
return {
|
|
54
|
+
call,
|
|
55
|
+
execution: gated,
|
|
56
|
+
hookRejection: null,
|
|
57
|
+
resource,
|
|
58
|
+
rejection: gateRejection(rejection) ?? deniedWithoutApprover(rejection)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
call,
|
|
63
|
+
execution,
|
|
64
|
+
hookRejection: fold.rejection,
|
|
65
|
+
resource: null,
|
|
66
|
+
rejection: {
|
|
67
|
+
result: fold.rejection,
|
|
68
|
+
activity: policyActivity({ call, effect, resource: null }),
|
|
69
|
+
effect,
|
|
70
|
+
source: 'tool-result'
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type ToolCallDisplay, type ToolExecutionOutcome, type ToolPreflight, type ToolActivityEvent } from '../../../machine/index.ts';
|
|
2
|
+
import type { ToolDefinition, ToolExecuteContext } from '../../completion.ts';
|
|
3
|
+
import type { AbortSignal as BareAbortSignal } from 'bare-abort-controller';
|
|
4
|
+
import type { ToolPolicySources } from './execution-plan.ts';
|
|
5
|
+
import type { HookPipeline } from '../../../hooks/pipeline.ts';
|
|
6
|
+
export interface ToolCallPlan {
|
|
7
|
+
resolved: {
|
|
8
|
+
call: {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
arguments: Record<string, unknown>;
|
|
12
|
+
rawCall?: string;
|
|
13
|
+
};
|
|
14
|
+
tool: ToolDefinition;
|
|
15
|
+
};
|
|
16
|
+
context: ToolExecuteContext;
|
|
17
|
+
effect: 'read' | 'write';
|
|
18
|
+
skillName: string | null;
|
|
19
|
+
webSearch: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface ToolCallRunOptions {
|
|
22
|
+
approve?: () => Promise<boolean>;
|
|
23
|
+
sources: ToolPolicySources;
|
|
24
|
+
preflight: ToolPreflight;
|
|
25
|
+
onDisplay?: (event: ToolActivityEvent) => void;
|
|
26
|
+
signal?: BareAbortSignal;
|
|
27
|
+
denied: Set<string>;
|
|
28
|
+
pipeline: HookPipeline;
|
|
29
|
+
runId: string;
|
|
30
|
+
callId: string;
|
|
31
|
+
skipApprovals: boolean;
|
|
32
|
+
intent?: string;
|
|
33
|
+
display?: ToolCallDisplay;
|
|
34
|
+
}
|
|
35
|
+
export interface ToolCallRunResult {
|
|
36
|
+
output: unknown;
|
|
37
|
+
outcome: ToolExecutionOutcome;
|
|
38
|
+
executed: boolean;
|
|
39
|
+
activity: ToolActivityEvent | null;
|
|
40
|
+
}
|
|
41
|
+
export declare function runToolCall(plan: ToolCallPlan, options: ToolCallRunOptions): Promise<ToolCallRunResult>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { AbortedError } from '../../../helpers/race-abort.js';
|
|
2
|
+
import { RecoveryRequired, ToolPolicyChanged } from '../../../machine/index.js';
|
|
3
|
+
import { executeCall } from '../../completion-loop/index.js';
|
|
4
|
+
import { errorMessage } from '../../../guards.js';
|
|
5
|
+
export async function runToolCall(plan, options) {
|
|
6
|
+
let activity = null;
|
|
7
|
+
try {
|
|
8
|
+
const executed = await executeCall(plan.resolved.tool, plan.resolved.call.arguments, plan.context, {
|
|
9
|
+
runId: options.runId,
|
|
10
|
+
approve: options.approve,
|
|
11
|
+
signal: options.signal,
|
|
12
|
+
denied: options.denied,
|
|
13
|
+
preflight: options.preflight,
|
|
14
|
+
sources: options.sources.sources,
|
|
15
|
+
sourceFacts: options.sources.sourceFacts,
|
|
16
|
+
pipeline: options.pipeline,
|
|
17
|
+
effect: plan.effect,
|
|
18
|
+
callId: options.callId,
|
|
19
|
+
skipApprovals: options.skipApprovals,
|
|
20
|
+
intent: options.intent,
|
|
21
|
+
display: options.display,
|
|
22
|
+
onToolActivity: (value) => {
|
|
23
|
+
activity = value;
|
|
24
|
+
options.onDisplay?.(value);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
output: executed.result,
|
|
29
|
+
outcome: executed.outcome,
|
|
30
|
+
executed: executed.executed,
|
|
31
|
+
activity
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error instanceof RecoveryRequired || error instanceof ToolPolicyChanged) {
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
if (error instanceof AbortedError || options.signal?.aborted) {
|
|
39
|
+
throw new AbortedError();
|
|
40
|
+
}
|
|
41
|
+
const message = errorMessage(error);
|
|
42
|
+
return {
|
|
43
|
+
output: { error: message },
|
|
44
|
+
outcome: { kind: 'error', message, error },
|
|
45
|
+
executed: false,
|
|
46
|
+
activity
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { AbortedError } from '../../../helpers/race-abort.js';
|
|
2
|
+
import { failureResultRef, storeFailureResult, spliceFrom } from '../../../machine/index.js';
|
|
3
|
+
import { callSucceeded, directToolHistory, labelOf, readyPreflightFromFacts, settledFailure } from '../../completion-loop/index.js';
|
|
4
|
+
import { DIRECT_CALL_ID, toolResultHistoryEntry, toolResultTurn } from '../../tool-turns.js';
|
|
5
|
+
import { trustedSourceFacts } from '../../../tools/outbound-guard.js';
|
|
6
|
+
import { executionPlan, trustedSources } from './execution-plan.js';
|
|
7
|
+
import { runToolCall } from './execute.js';
|
|
8
|
+
export const executing = async function executing({ emit, input: deps, context }) {
|
|
9
|
+
const { args, session } = deps;
|
|
10
|
+
const plan = executionPlan(deps, context);
|
|
11
|
+
const { call, args: callArgs, rawCall, intent } = plan.resolved;
|
|
12
|
+
const callKey = plan.resolved.key;
|
|
13
|
+
const display = labelOf(call.name, callArgs, session.skillIcon);
|
|
14
|
+
if (args.signal?.aborted) {
|
|
15
|
+
throw new AbortedError();
|
|
16
|
+
}
|
|
17
|
+
const denied = new Set(context.deniedKeys);
|
|
18
|
+
const sources = trustedSources(deps, context);
|
|
19
|
+
const facts = context.execution?.gate?.facts;
|
|
20
|
+
if (!facts) {
|
|
21
|
+
throw new Error('selected tool has no inspected policy facts');
|
|
22
|
+
}
|
|
23
|
+
const preflight = readyPreflightFromFacts(facts);
|
|
24
|
+
if (context.approval.status === 'idle') {
|
|
25
|
+
emit({
|
|
26
|
+
type: 'tool-call',
|
|
27
|
+
name: call.name,
|
|
28
|
+
args: callArgs,
|
|
29
|
+
rawCall,
|
|
30
|
+
effect: plan.effect,
|
|
31
|
+
display
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
let output;
|
|
35
|
+
let outcome;
|
|
36
|
+
let ran = false;
|
|
37
|
+
let activity = null;
|
|
38
|
+
const landedBefore = session.landed.length;
|
|
39
|
+
const executed = await runToolCall(plan, {
|
|
40
|
+
approve: context.approval.status === 'idle'
|
|
41
|
+
? undefined
|
|
42
|
+
: () => Promise.resolve(context.approval.status === 'approved'),
|
|
43
|
+
signal: args.signal,
|
|
44
|
+
denied,
|
|
45
|
+
preflight,
|
|
46
|
+
sources,
|
|
47
|
+
pipeline: session.pipeline,
|
|
48
|
+
runId: session.runId,
|
|
49
|
+
callId: call.id,
|
|
50
|
+
skipApprovals: args.agent?.approvalMode === 'skip-all',
|
|
51
|
+
intent,
|
|
52
|
+
display
|
|
53
|
+
});
|
|
54
|
+
output = executed.output;
|
|
55
|
+
outcome = executed.outcome;
|
|
56
|
+
ran = executed.executed;
|
|
57
|
+
activity = executed.activity;
|
|
58
|
+
if (outcome.kind !== 'success' && session.landed.length > landedBefore) {
|
|
59
|
+
session.landed.length = landedBefore;
|
|
60
|
+
}
|
|
61
|
+
session.runOutcomes.record(output, outcome);
|
|
62
|
+
if (activity) {
|
|
63
|
+
emit(activity);
|
|
64
|
+
}
|
|
65
|
+
emit({ type: 'tool-result', name: call.name, result: output });
|
|
66
|
+
const failed = settledFailure(output, outcome);
|
|
67
|
+
const direct = context.execution?.kind === 'direct';
|
|
68
|
+
const resultTurnId = direct ? DIRECT_CALL_ID : call.id;
|
|
69
|
+
const failure = failed
|
|
70
|
+
? {
|
|
71
|
+
key: callKey,
|
|
72
|
+
resultRef: failureResultRef(callKey, context.round, call.id),
|
|
73
|
+
outcome,
|
|
74
|
+
value: {
|
|
75
|
+
name: call.name,
|
|
76
|
+
result: storeFailureResult(output)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
: undefined;
|
|
80
|
+
const turn = toolResultTurn(call.name, resultTurnId, output);
|
|
81
|
+
const history = direct
|
|
82
|
+
? directToolHistory(context.history, callArgs, output, failure?.resultRef)
|
|
83
|
+
: [
|
|
84
|
+
...context.history,
|
|
85
|
+
toolResultHistoryEntry({
|
|
86
|
+
name: call.name,
|
|
87
|
+
id: resultTurnId,
|
|
88
|
+
output,
|
|
89
|
+
resultRef: failure?.resultRef
|
|
90
|
+
})
|
|
91
|
+
];
|
|
92
|
+
const deniedKey = [...denied].find((key) => !context.deniedKeys.includes(key));
|
|
93
|
+
const progressed = ran && callSucceeded(output, outcome) ? true : undefined;
|
|
94
|
+
return {
|
|
95
|
+
deniedKey,
|
|
96
|
+
webSearch: plan.webSearch,
|
|
97
|
+
history: spliceFrom(context.history, history),
|
|
98
|
+
source: trustedSourceFacts('tool-result', turn),
|
|
99
|
+
failed: failure,
|
|
100
|
+
progressed
|
|
101
|
+
};
|
|
102
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ToolDefinition, ToolExecuteContext } from '../../completion.ts';
|
|
2
|
+
import { type ResolvedCall } from '../../completion-loop/index.ts';
|
|
3
|
+
import type { CompletionDeps } from '../session.ts';
|
|
4
|
+
import type { ApprovalGate, CompletionMachineContext as CompletionContext, ResolvedCallSnapshot, ToolEffect, TrustedSource, TrustedSourceFacts } from '../../../machine/index.ts';
|
|
5
|
+
export interface ToolPolicySources {
|
|
6
|
+
sources: TrustedSource[];
|
|
7
|
+
sourceFacts: TrustedSourceFacts[];
|
|
8
|
+
}
|
|
9
|
+
interface ResolvedToolCall extends ResolvedCall {
|
|
10
|
+
key: string;
|
|
11
|
+
tool: ToolDefinition;
|
|
12
|
+
}
|
|
13
|
+
interface OpaqueResolvedCall extends ResolvedCall {
|
|
14
|
+
key: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ToolExecutionPlan {
|
|
17
|
+
type: 'execute';
|
|
18
|
+
route: 'tool' | 'skill';
|
|
19
|
+
resolved: ResolvedToolCall;
|
|
20
|
+
context: ToolExecuteContext;
|
|
21
|
+
effect: ToolEffect;
|
|
22
|
+
skillName: string | null;
|
|
23
|
+
webSearch: boolean;
|
|
24
|
+
}
|
|
25
|
+
interface ResolvedCallInput {
|
|
26
|
+
session: CompletionDeps['session'];
|
|
27
|
+
context: CompletionContext;
|
|
28
|
+
}
|
|
29
|
+
export declare function resolvedCall({ session, context }: ResolvedCallInput): OpaqueResolvedCall;
|
|
30
|
+
interface ToolContextInput {
|
|
31
|
+
deps: CompletionDeps;
|
|
32
|
+
context: CompletionContext;
|
|
33
|
+
name: string;
|
|
34
|
+
}
|
|
35
|
+
export declare function toolContext({ deps, context, name }: ToolContextInput): ToolExecuteContext;
|
|
36
|
+
export declare function executionPlan(deps: CompletionDeps, context: CompletionContext): ToolExecutionPlan;
|
|
37
|
+
export declare function trustedSources({ args }: CompletionDeps, context: Pick<CompletionContext, 'sources'>): ToolPolicySources;
|
|
38
|
+
interface ApprovalGateInput {
|
|
39
|
+
deps: CompletionDeps;
|
|
40
|
+
context: CompletionContext;
|
|
41
|
+
call: ResolvedCallSnapshot;
|
|
42
|
+
tool: ToolDefinition;
|
|
43
|
+
effect: ToolEffect;
|
|
44
|
+
sources: ToolPolicySources;
|
|
45
|
+
}
|
|
46
|
+
export declare function approvalGate({ deps, context, call, tool, effect, sources }: ApprovalGateInput): ApprovalGate;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { labelOf, inspectToolPolicy, sanitizeTurn, trustedSourcesFrom } from '../../completion-loop/index.js';
|
|
2
|
+
export function resolvedCall({ session, context }) {
|
|
3
|
+
const call = context.currentCall;
|
|
4
|
+
if (!call) {
|
|
5
|
+
throw new Error('completion graph selected a tool without a current call');
|
|
6
|
+
}
|
|
7
|
+
const tool = session.enabled.find((tool) => tool.name === call.name);
|
|
8
|
+
return {
|
|
9
|
+
key: call.key,
|
|
10
|
+
call: { id: call.id, name: call.name, arguments: call.args },
|
|
11
|
+
args: call.args,
|
|
12
|
+
tool,
|
|
13
|
+
rawCall: call.rawCall,
|
|
14
|
+
intent: call.intent,
|
|
15
|
+
rejection: call.rejection
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function toolContext({ deps, context, name }) {
|
|
19
|
+
const { args, session, commitFacts } = deps;
|
|
20
|
+
const { skillsSelected, enabledSkills, mention } = session.activation;
|
|
21
|
+
return {
|
|
22
|
+
...session.toolContext(session.turnImages, args.ctxSize, args.signal),
|
|
23
|
+
skills: (context.skills.snapshot?.loaded ?? []).filter((skill) => !skillsSelected || enabledSkills.includes(skill) || skill === mention),
|
|
24
|
+
settings: args.toolConfigs?.[name],
|
|
25
|
+
toolOps: session.grantedOps,
|
|
26
|
+
fsRoots: args.fsRoots ?? [],
|
|
27
|
+
fsWriteRoots: session.writableRoots,
|
|
28
|
+
sandboxMode: args.agent?.sandboxMode === true,
|
|
29
|
+
toolNames: session.enabled.map((tool) => tool.name),
|
|
30
|
+
reportBackend: (use) => {
|
|
31
|
+
session.backends.push(use);
|
|
32
|
+
commitFacts?.();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function executionPlan(deps, context) {
|
|
37
|
+
const execution = context.execution;
|
|
38
|
+
if (!execution) {
|
|
39
|
+
throw new Error('completion graph selected execution without execution facts');
|
|
40
|
+
}
|
|
41
|
+
const resolved = resolvedCall({ session: deps.session, context });
|
|
42
|
+
if (!resolved.tool) {
|
|
43
|
+
throw new Error(`tool implementation not found: ${resolved.call.name}`);
|
|
44
|
+
}
|
|
45
|
+
const resolvedWithTool = { ...resolved, tool: resolved.tool };
|
|
46
|
+
return {
|
|
47
|
+
type: 'execute',
|
|
48
|
+
route: execution.kind === 'skill' ? 'skill' : 'tool',
|
|
49
|
+
resolved: resolvedWithTool,
|
|
50
|
+
context: toolContext({ deps, context, name: resolved.call.name }),
|
|
51
|
+
effect: execution.effect,
|
|
52
|
+
skillName: execution.skillName,
|
|
53
|
+
webSearch: execution.webSearch
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const requestSources = new WeakMap();
|
|
57
|
+
export function trustedSources({ args }, context) {
|
|
58
|
+
let sources = requestSources.get(args.messages);
|
|
59
|
+
if (!sources) {
|
|
60
|
+
sources = trustedSourcesFrom(args.messages.map(sanitizeTurn));
|
|
61
|
+
requestSources.set(args.messages, sources);
|
|
62
|
+
}
|
|
63
|
+
return { sources, sourceFacts: context.sources };
|
|
64
|
+
}
|
|
65
|
+
export function approvalGate({ deps, context, call, tool, effect, sources }) {
|
|
66
|
+
const { args, session } = deps;
|
|
67
|
+
const facts = inspectToolPolicy(tool, call.args, toolContext({ deps, context, name: call.name }), {
|
|
68
|
+
sources: sources.sources,
|
|
69
|
+
sourceFacts: sources.sourceFacts,
|
|
70
|
+
denied: new Set(context.deniedKeys),
|
|
71
|
+
effect,
|
|
72
|
+
key: call.key,
|
|
73
|
+
skipApprovals: args.agent?.approvalMode === 'skip-all'
|
|
74
|
+
});
|
|
75
|
+
return {
|
|
76
|
+
facts,
|
|
77
|
+
approver: Boolean(args.approve),
|
|
78
|
+
call: {
|
|
79
|
+
name: call.name,
|
|
80
|
+
arguments: call.args,
|
|
81
|
+
resource: facts.resource,
|
|
82
|
+
effect: facts.effect,
|
|
83
|
+
intent: call.intent ?? null,
|
|
84
|
+
display: labelOf(call.name, call.args, session.skillIcon)
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AbortedError } from '../../../helpers/race-abort.js';
|
|
2
|
+
import { rehydrateError } from '../../../machine/index.js';
|
|
3
|
+
export const finishing = async ({ input: deps, context, signal }) => {
|
|
4
|
+
if (signal.aborted)
|
|
5
|
+
throw new AbortedError();
|
|
6
|
+
if (!deps.session.runStarted)
|
|
7
|
+
return;
|
|
8
|
+
const { failure } = context;
|
|
9
|
+
const payload = {
|
|
10
|
+
runId: context.runId,
|
|
11
|
+
agentId: context.agentId,
|
|
12
|
+
stats: {
|
|
13
|
+
totalTokens: context.metrics.tokens,
|
|
14
|
+
durationMs: Math.round(context.metrics.durationMs),
|
|
15
|
+
timeToFirstToken: context.metrics.ttft
|
|
16
|
+
},
|
|
17
|
+
outcome: context.outcome === 'failed' ? 'error' : 'done',
|
|
18
|
+
error: failure ? rehydrateError(failure, failure.message) : undefined
|
|
19
|
+
};
|
|
20
|
+
if (!deps.session.pipeline.hasPhase('runEnd')) {
|
|
21
|
+
await deps.session.pipeline.onRunEnd(payload);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
await deps.operations.operation({
|
|
25
|
+
id: `${context.runId}:hook-runEnd`,
|
|
26
|
+
name: 'hook:runEnd',
|
|
27
|
+
args: { outcome: context.outcome },
|
|
28
|
+
effect: 'write'
|
|
29
|
+
}, async () => {
|
|
30
|
+
await deps.session.pipeline.onRunEnd(payload);
|
|
31
|
+
});
|
|
32
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { AbortedError } from '../../../helpers/race-abort.js';
|
|
2
|
+
import { copy, toolDeniedResult } from '../../../machine/index.js';
|
|
3
|
+
import { inspectToolPolicy } from '../../completion-loop/index.js';
|
|
4
|
+
import { SKILL_TOOL_NAME } from '../../tool-names.js';
|
|
5
|
+
import { toolContext, trustedSources } from './execution-plan.js';
|
|
6
|
+
import { preloadFailure } from './preload-failure.js';
|
|
7
|
+
export const inspectPreload = async function inspectPreload({ input: deps, context }) {
|
|
8
|
+
const { args, session } = deps;
|
|
9
|
+
const pending = context.skillPreload;
|
|
10
|
+
if (!pending) {
|
|
11
|
+
throw new Error('preload inspection requires a pending skill');
|
|
12
|
+
}
|
|
13
|
+
const loader = session.enabled.find((tool) => tool.name === SKILL_TOOL_NAME);
|
|
14
|
+
if (!loader) {
|
|
15
|
+
throw new Error('skill preload requires the skill tool');
|
|
16
|
+
}
|
|
17
|
+
if (args.signal?.aborted) {
|
|
18
|
+
throw new AbortedError();
|
|
19
|
+
}
|
|
20
|
+
const loaderArgs = { name: pending.name };
|
|
21
|
+
const callId = `preload-${pending.name}`;
|
|
22
|
+
const executeContext = toolContext({ deps, context, name: loader.name });
|
|
23
|
+
const fold = await session.pipeline.runPreToolFold({
|
|
24
|
+
runId: session.runId,
|
|
25
|
+
callId,
|
|
26
|
+
toolName: loader.name,
|
|
27
|
+
agentId: args.agent?.id ?? null,
|
|
28
|
+
args: loaderArgs,
|
|
29
|
+
skillNames: session.inContextSkills.map((skill) => skill.name),
|
|
30
|
+
parameters: loader.parameters,
|
|
31
|
+
sandboxMode: args.agent?.sandboxMode === true,
|
|
32
|
+
signal: args.signal
|
|
33
|
+
});
|
|
34
|
+
if (args.signal?.aborted) {
|
|
35
|
+
throw new AbortedError();
|
|
36
|
+
}
|
|
37
|
+
if (!fold.ok) {
|
|
38
|
+
return {
|
|
39
|
+
name: pending.name,
|
|
40
|
+
args: loaderArgs,
|
|
41
|
+
facts: null,
|
|
42
|
+
hookRejection: fold.rejection,
|
|
43
|
+
failure: preloadFailure({
|
|
44
|
+
history: context.history,
|
|
45
|
+
startedAt: session.startedAt,
|
|
46
|
+
name: pending.name,
|
|
47
|
+
error: fold.rejection.error
|
|
48
|
+
})
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const facts = inspectToolPolicy(loader, fold.args, executeContext, {
|
|
52
|
+
...trustedSources(deps, context),
|
|
53
|
+
denied: new Set(context.deniedKeys),
|
|
54
|
+
key: session.callKey(loader.name, fold.args),
|
|
55
|
+
skipApprovals: false
|
|
56
|
+
});
|
|
57
|
+
const failureReason = facts.validationError ??
|
|
58
|
+
facts.refusal ??
|
|
59
|
+
(facts.deniedKey ? toolDeniedResult().error : null) ??
|
|
60
|
+
(facts.effect !== 'read' ? 'Skill loading requires a read-only tool.' : null);
|
|
61
|
+
return {
|
|
62
|
+
name: pending.name,
|
|
63
|
+
args: copy(fold.args),
|
|
64
|
+
facts,
|
|
65
|
+
hookRejection: null,
|
|
66
|
+
failure: failureReason
|
|
67
|
+
? preloadFailure({
|
|
68
|
+
history: context.history,
|
|
69
|
+
startedAt: session.startedAt,
|
|
70
|
+
name: pending.name,
|
|
71
|
+
error: failureReason
|
|
72
|
+
})
|
|
73
|
+
: null
|
|
74
|
+
};
|
|
75
|
+
};
|