@enderfga/claw-orchestrator 5.1.0 → 6.0.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.
- package/README.md +26 -26
- package/dist/bin/cli.js +107 -1
- package/dist/bin/cli.js.map +1 -1
- package/dist/src/acp-server.d.ts +5 -5
- package/dist/src/acp-server.js +3 -3
- package/dist/src/acp-server.js.map +1 -1
- package/dist/src/autoloop/dispatcher.d.ts +22 -0
- package/dist/src/autoloop/dispatcher.js +71 -13
- package/dist/src/autoloop/dispatcher.js.map +1 -1
- package/dist/src/autoloop/messages.d.ts +10 -0
- package/dist/src/autoloop/messages.js.map +1 -1
- package/dist/src/autoloop/runner.js +6 -0
- package/dist/src/autoloop/runner.js.map +1 -1
- package/dist/src/constants.d.ts +0 -6
- package/dist/src/constants.js +0 -6
- package/dist/src/constants.js.map +1 -1
- package/dist/src/council.d.ts +15 -0
- package/dist/src/council.js +48 -35
- package/dist/src/council.js.map +1 -1
- package/dist/src/dashboard/index.html +191 -6
- package/dist/src/embedded-server.js +132 -9
- package/dist/src/embedded-server.js.map +1 -1
- package/dist/src/fanout.d.ts +30 -1
- package/dist/src/fanout.js +32 -3
- package/dist/src/fanout.js.map +1 -1
- package/dist/src/index.js +359 -4
- package/dist/src/index.js.map +1 -1
- package/dist/src/kernel/agent-step.d.ts +59 -0
- package/dist/src/kernel/agent-step.js +100 -0
- package/dist/src/kernel/agent-step.js.map +1 -0
- package/dist/src/kernel/conditions.d.ts +11 -0
- package/dist/src/kernel/conditions.js +24 -0
- package/dist/src/kernel/conditions.js.map +1 -0
- package/dist/src/kernel/engine.d.ts +319 -0
- package/dist/src/kernel/engine.js +1047 -0
- package/dist/src/kernel/engine.js.map +1 -0
- package/dist/src/kernel/exec.d.ts +43 -0
- package/dist/src/kernel/exec.js +112 -0
- package/dist/src/kernel/exec.js.map +1 -0
- package/dist/src/kernel/file-lock.d.ts +50 -0
- package/dist/src/kernel/file-lock.js +135 -0
- package/dist/src/kernel/file-lock.js.map +1 -0
- package/dist/src/kernel/nodes/agent.d.ts +4 -0
- package/dist/src/kernel/nodes/agent.js +35 -0
- package/dist/src/kernel/nodes/agent.js.map +1 -0
- package/dist/src/kernel/nodes/autoloop.d.ts +78 -0
- package/dist/src/kernel/nodes/autoloop.js +75 -0
- package/dist/src/kernel/nodes/autoloop.js.map +1 -0
- package/dist/src/kernel/nodes/council.d.ts +12 -0
- package/dist/src/kernel/nodes/council.js +88 -0
- package/dist/src/kernel/nodes/council.js.map +1 -0
- package/dist/src/kernel/nodes/fanout.d.ts +11 -0
- package/dist/src/kernel/nodes/fanout.js +63 -0
- package/dist/src/kernel/nodes/fanout.js.map +1 -0
- package/dist/src/kernel/nodes/human-gate.d.ts +4 -0
- package/dist/src/kernel/nodes/human-gate.js +7 -0
- package/dist/src/kernel/nodes/human-gate.js.map +1 -0
- package/dist/src/kernel/nodes/index.d.ts +12 -0
- package/dist/src/kernel/nodes/index.js +21 -0
- package/dist/src/kernel/nodes/index.js.map +1 -0
- package/dist/src/kernel/nodes/router.d.ts +4 -0
- package/dist/src/kernel/nodes/router.js +12 -0
- package/dist/src/kernel/nodes/router.js.map +1 -0
- package/dist/src/kernel/nodes/subflow.d.ts +13 -0
- package/dist/src/kernel/nodes/subflow.js +38 -0
- package/dist/src/kernel/nodes/subflow.js.map +1 -0
- package/dist/src/kernel/nodes/ultraapp.d.ts +60 -0
- package/dist/src/kernel/nodes/ultraapp.js +62 -0
- package/dist/src/kernel/nodes/ultraapp.js.map +1 -0
- package/dist/src/kernel/nodes/verifier.d.ts +14 -0
- package/dist/src/kernel/nodes/verifier.js +84 -0
- package/dist/src/kernel/nodes/verifier.js.map +1 -0
- package/dist/src/kernel/projections.d.ts +42 -0
- package/dist/src/kernel/projections.js +133 -0
- package/dist/src/kernel/projections.js.map +1 -0
- package/dist/src/kernel/repo.d.ts +13 -0
- package/dist/src/kernel/repo.js +64 -0
- package/dist/src/kernel/repo.js.map +1 -0
- package/dist/src/kernel/secrets.d.ts +25 -0
- package/dist/src/kernel/secrets.js +48 -0
- package/dist/src/kernel/secrets.js.map +1 -0
- package/dist/src/kernel/store.d.ts +225 -0
- package/dist/src/kernel/store.js +838 -0
- package/dist/src/kernel/store.js.map +1 -0
- package/dist/src/kernel/templates/index.d.ts +140 -0
- package/dist/src/kernel/templates/index.js +266 -0
- package/dist/src/kernel/templates/index.js.map +1 -0
- package/dist/src/kernel/types.d.ts +326 -0
- package/dist/src/kernel/types.js +19 -0
- package/dist/src/kernel/types.js.map +1 -0
- package/dist/src/run-ledger.d.ts +57 -3
- package/dist/src/run-ledger.js +45 -2
- package/dist/src/run-ledger.js.map +1 -1
- package/dist/src/session-manager.d.ts +176 -129
- package/dist/src/session-manager.js +652 -603
- package/dist/src/session-manager.js.map +1 -1
- package/dist/src/types.d.ts +33 -3
- package/dist/src/ultraapp/build.d.ts +117 -3
- package/dist/src/ultraapp/build.js +319 -3
- package/dist/src/ultraapp/build.js.map +1 -1
- package/dist/src/ultraapp/contract.d.ts +52 -0
- package/dist/src/ultraapp/contract.js +83 -0
- package/dist/src/ultraapp/contract.js.map +1 -0
- package/dist/src/ultraapp/conventions.js +9 -2
- package/dist/src/ultraapp/conventions.js.map +1 -1
- package/dist/src/ultraapp/fix-on-failure.d.ts +21 -2
- package/dist/src/ultraapp/fix-on-failure.js +46 -62
- package/dist/src/ultraapp/fix-on-failure.js.map +1 -1
- package/dist/src/ultraapp/manager.d.ts +107 -2
- package/dist/src/ultraapp/manager.js +305 -86
- package/dist/src/ultraapp/manager.js.map +1 -1
- package/dist/src/verify/baseline.d.ts +73 -0
- package/dist/src/verify/baseline.js +186 -0
- package/dist/src/verify/baseline.js.map +1 -0
- package/dist/src/verify/contract.d.ts +116 -0
- package/dist/src/verify/contract.js +142 -0
- package/dist/src/verify/contract.js.map +1 -0
- package/dist/src/verify/evidence.d.ts +61 -0
- package/dist/src/verify/evidence.js +133 -0
- package/dist/src/verify/evidence.js.map +1 -0
- package/dist/src/verify/runner.d.ts +63 -0
- package/dist/src/verify/runner.js +317 -0
- package/dist/src/verify/runner.js.map +1 -0
- package/openclaw.plugin.json +8 -0
- package/package.json +2 -2
- package/skills/SKILL.md +120 -79
- package/skills/references/acp.md +17 -17
- package/skills/references/autoloop.md +139 -65
- package/skills/references/claude-cli-tracking.md +4 -4
- package/skills/references/cli.md +101 -59
- package/skills/references/council.md +109 -37
- package/skills/references/dashboard.md +34 -6
- package/skills/references/getting-started.md +13 -13
- package/skills/references/inbox.md +4 -4
- package/skills/references/mcp.md +39 -34
- package/skills/references/multi-engine.md +51 -47
- package/skills/references/observability.md +88 -28
- package/skills/references/openai-compat.md +39 -39
- package/skills/references/sessions.md +43 -25
- package/skills/references/tools.md +402 -309
- package/skills/references/ultra.md +45 -45
- package/skills/references/ultraapp.md +126 -50
- package/skills/references/verification.md +187 -0
- package/skills/references/workflow.md +362 -0
- package/dist/src/ultraapp/fix-on-failure-session.d.ts +0 -23
- package/dist/src/ultraapp/fix-on-failure-session.js +0 -51
- package/dist/src/ultraapp/fix-on-failure-session.js.map +0 -1
package/dist/src/index.js
CHANGED
|
@@ -13,6 +13,9 @@ import { createProxyHandler } from './proxy/handler.js';
|
|
|
13
13
|
import { EmbeddedServer } from './embedded-server.js';
|
|
14
14
|
import { sanitizeCwd, validateRegex } from './validation.js';
|
|
15
15
|
import { ENGINE_TYPES, } from './types.js';
|
|
16
|
+
import { councilWorkflow, fanoutWorkflow, solveWorkflow } from './kernel/templates/index.js';
|
|
17
|
+
import { readEvents as readKernelEvents } from './kernel/store.js';
|
|
18
|
+
import { resolveSecretRefs } from './kernel/secrets.js';
|
|
16
19
|
// ─── Standalone Export ───────────────────────────────────────────────────────
|
|
17
20
|
export { SessionManager } from './session-manager.js';
|
|
18
21
|
export { PersistentClaudeSession } from './persistent-session.js';
|
|
@@ -940,7 +943,7 @@ const plugin = {
|
|
|
940
943
|
required: ['task', 'projectDir', 'agents'],
|
|
941
944
|
},
|
|
942
945
|
execute: async (_id, args) => {
|
|
943
|
-
const session = getManager().fanoutStart({
|
|
946
|
+
const session = await getManager().fanoutStart({
|
|
944
947
|
task: args.task,
|
|
945
948
|
projectDir: sanitizeCwd(args.projectDir),
|
|
946
949
|
agents: args.agents,
|
|
@@ -977,6 +980,358 @@ const plugin = {
|
|
|
977
980
|
return { ok: true };
|
|
978
981
|
},
|
|
979
982
|
});
|
|
983
|
+
// ─── Tools: workflow_* (durable run kernel) ─────────────────────────
|
|
984
|
+
api.registerTool({
|
|
985
|
+
name: 'workflow_start',
|
|
986
|
+
description: "Start a durable workflow run. Nodes: agent | fanout | council | verifier | human_gate | router | subflow. Every state transition is checkpointed to disk, so a run survives a process restart and can be resumed. When a contract is supplied the run cannot reach `completed` unless the runtime's own checks pass — without one it completes as `unverified`, which means nothing checked it. Runs in background; poll with workflow_status.",
|
|
987
|
+
parameters: {
|
|
988
|
+
type: 'object',
|
|
989
|
+
properties: {
|
|
990
|
+
spec: {
|
|
991
|
+
type: 'object',
|
|
992
|
+
description: 'WorkflowSpec: { name, nodes[], cwd?, contract?, maxNodeVisits? }. See skills/references/workflow.md for the node shapes.',
|
|
993
|
+
},
|
|
994
|
+
template: {
|
|
995
|
+
type: 'string',
|
|
996
|
+
enum: ['solve', 'council', 'fanout'],
|
|
997
|
+
description: 'Build a built-in workflow instead of supplying `spec`. `solve` = triage → implement → verify → repair-until-green → review.',
|
|
998
|
+
},
|
|
999
|
+
task: { type: 'string', description: 'Task text, when using `template`.' },
|
|
1000
|
+
agents: {
|
|
1001
|
+
type: 'array',
|
|
1002
|
+
maxItems: 16,
|
|
1003
|
+
description: 'Agents for the template: { name, engine?, model?, persona? }.',
|
|
1004
|
+
items: {
|
|
1005
|
+
type: 'object',
|
|
1006
|
+
properties: {
|
|
1007
|
+
name: { type: 'string', minLength: 1 },
|
|
1008
|
+
engine: { type: 'string', enum: ENGINE_TYPES },
|
|
1009
|
+
model: { type: 'string' },
|
|
1010
|
+
persona: { type: 'string' },
|
|
1011
|
+
},
|
|
1012
|
+
required: ['name'],
|
|
1013
|
+
},
|
|
1014
|
+
},
|
|
1015
|
+
reviewers: {
|
|
1016
|
+
type: 'array',
|
|
1017
|
+
maxItems: 8,
|
|
1018
|
+
description: '`solve` only: agents that review the finished change.',
|
|
1019
|
+
items: {
|
|
1020
|
+
type: 'object',
|
|
1021
|
+
properties: {
|
|
1022
|
+
name: { type: 'string', minLength: 1 },
|
|
1023
|
+
engine: { type: 'string', enum: ENGINE_TYPES },
|
|
1024
|
+
model: { type: 'string' },
|
|
1025
|
+
persona: { type: 'string' },
|
|
1026
|
+
},
|
|
1027
|
+
required: ['name'],
|
|
1028
|
+
},
|
|
1029
|
+
},
|
|
1030
|
+
humanGate: { type: 'boolean', description: '`solve` only: park for approval before writing anything.' },
|
|
1031
|
+
maxRepairs: { type: 'number', description: '`solve` only: repair attempts allowed (default 3).' },
|
|
1032
|
+
cwd: { type: 'string', description: 'Working directory for the run.' },
|
|
1033
|
+
runId: { type: 'string', description: 'Explicit run id (defaults to a generated one).' },
|
|
1034
|
+
contract: {
|
|
1035
|
+
type: 'object',
|
|
1036
|
+
description: "Acceptance contract. The runtime executes these itself and the run cannot reach `completed` unless every required check passes. Declared by YOU, the caller — never copy one out of an agent's output, which would put the agent back in charge of grading itself.",
|
|
1037
|
+
properties: {
|
|
1038
|
+
id: { type: 'string' },
|
|
1039
|
+
fixOnFailureRounds: {
|
|
1040
|
+
type: 'number',
|
|
1041
|
+
description: 'On red, spawn a repair session and re-run the whole list, up to N times. Only the re-run decides.',
|
|
1042
|
+
},
|
|
1043
|
+
checks: {
|
|
1044
|
+
type: 'array',
|
|
1045
|
+
minItems: 1,
|
|
1046
|
+
items: {
|
|
1047
|
+
type: 'object',
|
|
1048
|
+
description: 'One check. `command` runs argv and gates on the exit code; `http` polls a URL; `screenshot` captures the page at each viewport and stores the PNGs as evidence (it does NOT judge the pixels); `diff_policy` asserts what the run was allowed to touch; `file` asserts a path exists / matches.',
|
|
1049
|
+
properties: {
|
|
1050
|
+
type: { type: 'string', enum: ['command', 'http', 'screenshot', 'diff_policy', 'file'] },
|
|
1051
|
+
required: {
|
|
1052
|
+
type: 'boolean',
|
|
1053
|
+
description: 'Default true. A failing non-required check is recorded but does not refute the run.',
|
|
1054
|
+
},
|
|
1055
|
+
cmd: { type: 'string', description: 'command: executable name. No shell string — argv only.' },
|
|
1056
|
+
args: { type: 'array', items: { type: 'string' }, description: 'command: arguments.' },
|
|
1057
|
+
cwd: { type: 'string', description: 'command: directory, relative to the run cwd.' },
|
|
1058
|
+
expectExit: { type: 'number', description: 'command: passing exit code (default 0).' },
|
|
1059
|
+
url: { type: 'string', description: 'http / screenshot: target URL.' },
|
|
1060
|
+
expectStatus: { type: 'number', description: 'http: expected status (default 200).' },
|
|
1061
|
+
viewports: {
|
|
1062
|
+
type: 'array',
|
|
1063
|
+
description: 'screenshot: [{ width, height, label? }].',
|
|
1064
|
+
items: {
|
|
1065
|
+
type: 'object',
|
|
1066
|
+
properties: {
|
|
1067
|
+
width: { type: 'number' },
|
|
1068
|
+
height: { type: 'number' },
|
|
1069
|
+
label: { type: 'string' },
|
|
1070
|
+
},
|
|
1071
|
+
required: ['width', 'height'],
|
|
1072
|
+
},
|
|
1073
|
+
},
|
|
1074
|
+
maxFiles: { type: 'number', description: 'diff_policy: cap on changed files.' },
|
|
1075
|
+
forbidPaths: {
|
|
1076
|
+
type: 'array',
|
|
1077
|
+
items: { type: 'string' },
|
|
1078
|
+
description: 'diff_policy: paths that must not be touched.',
|
|
1079
|
+
},
|
|
1080
|
+
requirePaths: {
|
|
1081
|
+
type: 'array',
|
|
1082
|
+
items: { type: 'string' },
|
|
1083
|
+
description: 'diff_policy: at least one change must land under one of these.',
|
|
1084
|
+
},
|
|
1085
|
+
path: { type: 'string', description: 'file: path relative to the run cwd.' },
|
|
1086
|
+
exists: { type: 'boolean', description: 'file: default true; false asserts absence.' },
|
|
1087
|
+
matches: { type: 'string', description: 'file: regex the contents must match.' },
|
|
1088
|
+
timeoutMs: { type: 'number', description: 'Per-check wall clock.' },
|
|
1089
|
+
},
|
|
1090
|
+
required: ['type'],
|
|
1091
|
+
},
|
|
1092
|
+
},
|
|
1093
|
+
},
|
|
1094
|
+
required: ['checks'],
|
|
1095
|
+
},
|
|
1096
|
+
},
|
|
1097
|
+
required: [],
|
|
1098
|
+
},
|
|
1099
|
+
execute: async (_id, args) => {
|
|
1100
|
+
const cwd = sanitizeCwd(args.cwd);
|
|
1101
|
+
let spec = args.spec;
|
|
1102
|
+
if (!spec) {
|
|
1103
|
+
const template = args.template || 'solve';
|
|
1104
|
+
const task = args.task;
|
|
1105
|
+
if (!task)
|
|
1106
|
+
throw new Error('workflow_start needs `spec`, or `template` with `task`');
|
|
1107
|
+
const agents = args.agents ?? [{ name: 'agent' }];
|
|
1108
|
+
if (template === 'council') {
|
|
1109
|
+
spec = councilWorkflow({ task, cwd, agents });
|
|
1110
|
+
}
|
|
1111
|
+
else if (template === 'fanout') {
|
|
1112
|
+
spec = fanoutWorkflow({ task, cwd, agents, synthesize: agents.length >= 2 });
|
|
1113
|
+
}
|
|
1114
|
+
else {
|
|
1115
|
+
spec = solveWorkflow({
|
|
1116
|
+
task,
|
|
1117
|
+
cwd,
|
|
1118
|
+
scouts: agents,
|
|
1119
|
+
reviewers: args.reviewers,
|
|
1120
|
+
humanGate: args.humanGate,
|
|
1121
|
+
maxRepairs: args.maxRepairs,
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
const record = await getManager().workflowStart(spec, {
|
|
1126
|
+
cwd,
|
|
1127
|
+
runId: args.runId,
|
|
1128
|
+
contract: args.contract,
|
|
1129
|
+
});
|
|
1130
|
+
return {
|
|
1131
|
+
ok: true,
|
|
1132
|
+
runId: record.runId,
|
|
1133
|
+
workflow: record.workflow,
|
|
1134
|
+
state: record.state,
|
|
1135
|
+
nodes: Object.keys(record.nodes),
|
|
1136
|
+
note: 'Workflow running in background. Poll with workflow_status.',
|
|
1137
|
+
};
|
|
1138
|
+
},
|
|
1139
|
+
});
|
|
1140
|
+
api.registerTool({
|
|
1141
|
+
name: 'workflow_status',
|
|
1142
|
+
description: 'Poll a workflow run. Returns state, per-node status, and the outcome: `verified` (a contract passed), `refuted` (it failed), or `unverified` (none was declared — nothing checked the work).',
|
|
1143
|
+
parameters: {
|
|
1144
|
+
type: 'object',
|
|
1145
|
+
properties: {
|
|
1146
|
+
runId: { type: 'string' },
|
|
1147
|
+
events: { type: 'number', description: 'Also return the last N events from the run log.' },
|
|
1148
|
+
},
|
|
1149
|
+
required: ['runId'],
|
|
1150
|
+
},
|
|
1151
|
+
execute: async (_id, args) => {
|
|
1152
|
+
const record = getManager().workflowStatus(args.runId);
|
|
1153
|
+
const limit = args.events;
|
|
1154
|
+
return {
|
|
1155
|
+
ok: true,
|
|
1156
|
+
runId: record.runId,
|
|
1157
|
+
workflow: record.workflow,
|
|
1158
|
+
state: record.state,
|
|
1159
|
+
outcome: record.outcome,
|
|
1160
|
+
currentNode: record.currentNode,
|
|
1161
|
+
evidenceId: record.evidenceId,
|
|
1162
|
+
costUsd: record.costUsd,
|
|
1163
|
+
error: record.error,
|
|
1164
|
+
nodes: record.nodes,
|
|
1165
|
+
consensusVotes: record.consensusVotes,
|
|
1166
|
+
events: limit ? readKernelEvents(record.runId, limit) : undefined,
|
|
1167
|
+
};
|
|
1168
|
+
},
|
|
1169
|
+
});
|
|
1170
|
+
api.registerTool({
|
|
1171
|
+
name: 'workflow_list',
|
|
1172
|
+
description: 'List workflow runs on this machine, newest first. Survives restarts.',
|
|
1173
|
+
parameters: {
|
|
1174
|
+
type: 'object',
|
|
1175
|
+
properties: {
|
|
1176
|
+
workflow: { type: 'string' },
|
|
1177
|
+
state: {
|
|
1178
|
+
type: 'string',
|
|
1179
|
+
enum: ['pending', 'running', 'awaiting_human', 'verifying', 'completed', 'failed', 'cancelled'],
|
|
1180
|
+
},
|
|
1181
|
+
limit: { type: 'number' },
|
|
1182
|
+
},
|
|
1183
|
+
},
|
|
1184
|
+
execute: async (_id, args) => ({
|
|
1185
|
+
ok: true,
|
|
1186
|
+
runs: getManager().workflowList({
|
|
1187
|
+
workflow: args.workflow,
|
|
1188
|
+
state: args.state,
|
|
1189
|
+
limit: args.limit ?? 25,
|
|
1190
|
+
}),
|
|
1191
|
+
}),
|
|
1192
|
+
});
|
|
1193
|
+
api.registerTool({
|
|
1194
|
+
name: 'workflow_resume',
|
|
1195
|
+
description: 'Re-attach to a workflow whose process died. Nodes already marked succeeded are not re-run; the node that was in flight is retried, because a half-finished node left no result to trust.',
|
|
1196
|
+
parameters: {
|
|
1197
|
+
type: 'object',
|
|
1198
|
+
properties: {
|
|
1199
|
+
runId: { type: 'string' },
|
|
1200
|
+
agentCustomEngineRefs: {
|
|
1201
|
+
type: 'object',
|
|
1202
|
+
description: 'Per-agent custom-engine credentials, by name: { "<agent>": "<REF>" }. The orchestrator resolves each REF from CLAWO_CUSTOM_ENGINE_<REF> on its own host — the credentials themselves are never persisted with the run and never travel here. Required to resume a run whose agents used a custom engine.',
|
|
1203
|
+
additionalProperties: { type: 'string' },
|
|
1204
|
+
},
|
|
1205
|
+
},
|
|
1206
|
+
required: ['runId'],
|
|
1207
|
+
},
|
|
1208
|
+
execute: async (_id, args) => {
|
|
1209
|
+
const refs = args.agentCustomEngineRefs;
|
|
1210
|
+
const record = await getManager().workflowResume(args.runId, {
|
|
1211
|
+
secrets: refs ? { agentCustomEngines: resolveSecretRefs(refs) } : undefined,
|
|
1212
|
+
});
|
|
1213
|
+
return { ok: true, runId: record.runId, state: record.state, currentNode: record.currentNode };
|
|
1214
|
+
},
|
|
1215
|
+
});
|
|
1216
|
+
api.registerTool({
|
|
1217
|
+
name: 'workflow_cancel',
|
|
1218
|
+
description: 'Cancel a running workflow. The current node is asked to stop; the run ends in `cancelled`.',
|
|
1219
|
+
parameters: { type: 'object', properties: { runId: { type: 'string' } }, required: ['runId'] },
|
|
1220
|
+
execute: async (_id, args) => ({ ok: true, ...getManager().workflowCancel(args.runId) }),
|
|
1221
|
+
});
|
|
1222
|
+
api.registerTool({
|
|
1223
|
+
name: 'workflow_steer',
|
|
1224
|
+
description: "Queue a correction for a running workflow. The text is prepended to the next agent node's prompt — corrections belong before the task, not after it.",
|
|
1225
|
+
parameters: {
|
|
1226
|
+
type: 'object',
|
|
1227
|
+
properties: { runId: { type: 'string' }, text: { type: 'string' } },
|
|
1228
|
+
required: ['runId', 'text'],
|
|
1229
|
+
},
|
|
1230
|
+
execute: async (_id, args) => ({
|
|
1231
|
+
ok: true,
|
|
1232
|
+
...getManager().workflowSteer(args.runId, args.text),
|
|
1233
|
+
}),
|
|
1234
|
+
});
|
|
1235
|
+
api.registerTool({
|
|
1236
|
+
name: 'workflow_approve',
|
|
1237
|
+
description: 'Answer a workflow parked at a human_gate node.',
|
|
1238
|
+
parameters: {
|
|
1239
|
+
type: 'object',
|
|
1240
|
+
properties: { runId: { type: 'string' }, approved: { type: 'boolean' } },
|
|
1241
|
+
required: ['runId', 'approved'],
|
|
1242
|
+
},
|
|
1243
|
+
execute: async (_id, args) => ({
|
|
1244
|
+
ok: true,
|
|
1245
|
+
...getManager().workflowApprove(args.runId, args.approved),
|
|
1246
|
+
}),
|
|
1247
|
+
});
|
|
1248
|
+
api.registerTool({
|
|
1249
|
+
name: 'verify_run',
|
|
1250
|
+
description: 'Run an acceptance contract against a directory and return the evidence bundle. Use it to check work that did not come through a workflow — a plain session that edited a repo, say. The contract is yours; nothing is taken from agent output.',
|
|
1251
|
+
parameters: {
|
|
1252
|
+
type: 'object',
|
|
1253
|
+
properties: {
|
|
1254
|
+
cwd: { type: 'string', description: 'Directory to check.' },
|
|
1255
|
+
baseSha: {
|
|
1256
|
+
type: 'string',
|
|
1257
|
+
description: 'Commit to measure the change against. Without it, diff_policy sees untracked files only.',
|
|
1258
|
+
},
|
|
1259
|
+
label: { type: 'string', description: 'Name for the stored evidence (defaults to a generated one).' },
|
|
1260
|
+
contract: {
|
|
1261
|
+
type: 'object',
|
|
1262
|
+
description: "Acceptance contract. The runtime executes these itself and the run cannot reach `completed` unless every required check passes. Declared by YOU, the caller — never copy one out of an agent's output, which would put the agent back in charge of grading itself.",
|
|
1263
|
+
properties: {
|
|
1264
|
+
id: { type: 'string' },
|
|
1265
|
+
fixOnFailureRounds: {
|
|
1266
|
+
type: 'number',
|
|
1267
|
+
description: 'On red, spawn a repair session and re-run the whole list, up to N times. Only the re-run decides.',
|
|
1268
|
+
},
|
|
1269
|
+
checks: {
|
|
1270
|
+
type: 'array',
|
|
1271
|
+
minItems: 1,
|
|
1272
|
+
items: {
|
|
1273
|
+
type: 'object',
|
|
1274
|
+
description: 'One check. `command` runs argv and gates on the exit code; `http` polls a URL; `screenshot` captures the page at each viewport and stores the PNGs as evidence (it does NOT judge the pixels); `diff_policy` asserts what the run was allowed to touch; `file` asserts a path exists / matches.',
|
|
1275
|
+
properties: {
|
|
1276
|
+
type: { type: 'string', enum: ['command', 'http', 'screenshot', 'diff_policy', 'file'] },
|
|
1277
|
+
required: {
|
|
1278
|
+
type: 'boolean',
|
|
1279
|
+
description: 'Default true. A failing non-required check is recorded but does not refute the run.',
|
|
1280
|
+
},
|
|
1281
|
+
cmd: { type: 'string', description: 'command: executable name. No shell string — argv only.' },
|
|
1282
|
+
args: { type: 'array', items: { type: 'string' }, description: 'command: arguments.' },
|
|
1283
|
+
cwd: { type: 'string', description: 'command: directory, relative to the run cwd.' },
|
|
1284
|
+
expectExit: { type: 'number', description: 'command: passing exit code (default 0).' },
|
|
1285
|
+
url: { type: 'string', description: 'http / screenshot: target URL.' },
|
|
1286
|
+
expectStatus: { type: 'number', description: 'http: expected status (default 200).' },
|
|
1287
|
+
viewports: {
|
|
1288
|
+
type: 'array',
|
|
1289
|
+
description: 'screenshot: [{ width, height, label? }].',
|
|
1290
|
+
items: {
|
|
1291
|
+
type: 'object',
|
|
1292
|
+
properties: {
|
|
1293
|
+
width: { type: 'number' },
|
|
1294
|
+
height: { type: 'number' },
|
|
1295
|
+
label: { type: 'string' },
|
|
1296
|
+
},
|
|
1297
|
+
required: ['width', 'height'],
|
|
1298
|
+
},
|
|
1299
|
+
},
|
|
1300
|
+
maxFiles: { type: 'number', description: 'diff_policy: cap on changed files.' },
|
|
1301
|
+
forbidPaths: {
|
|
1302
|
+
type: 'array',
|
|
1303
|
+
items: { type: 'string' },
|
|
1304
|
+
description: 'diff_policy: paths that must not be touched.',
|
|
1305
|
+
},
|
|
1306
|
+
requirePaths: {
|
|
1307
|
+
type: 'array',
|
|
1308
|
+
items: { type: 'string' },
|
|
1309
|
+
description: 'diff_policy: at least one change must land under one of these.',
|
|
1310
|
+
},
|
|
1311
|
+
path: { type: 'string', description: 'file: path relative to the run cwd.' },
|
|
1312
|
+
exists: { type: 'boolean', description: 'file: default true; false asserts absence.' },
|
|
1313
|
+
matches: { type: 'string', description: 'file: regex the contents must match.' },
|
|
1314
|
+
timeoutMs: { type: 'number', description: 'Per-check wall clock.' },
|
|
1315
|
+
},
|
|
1316
|
+
required: ['type'],
|
|
1317
|
+
},
|
|
1318
|
+
},
|
|
1319
|
+
},
|
|
1320
|
+
required: ['checks'],
|
|
1321
|
+
},
|
|
1322
|
+
},
|
|
1323
|
+
required: ['cwd', 'contract'],
|
|
1324
|
+
},
|
|
1325
|
+
execute: async (_id, args) => {
|
|
1326
|
+
const bundle = await getManager().verifyRun({
|
|
1327
|
+
cwd: sanitizeCwd(args.cwd),
|
|
1328
|
+
contract: args.contract,
|
|
1329
|
+
baseSha: args.baseSha,
|
|
1330
|
+
label: args.label,
|
|
1331
|
+
});
|
|
1332
|
+
return { ok: true, ...bundle };
|
|
1333
|
+
},
|
|
1334
|
+
});
|
|
980
1335
|
// ─── Tool: council_start ────────────────────────────────────────────
|
|
981
1336
|
api.registerTool({
|
|
982
1337
|
name: 'council_start',
|
|
@@ -1042,7 +1397,7 @@ const plugin = {
|
|
|
1042
1397
|
maxBudgetUsd: args.maxBudgetUsd,
|
|
1043
1398
|
defaultPermissionMode: args.defaultPermissionMode,
|
|
1044
1399
|
};
|
|
1045
|
-
const session = getManager().councilStart(args.task, config);
|
|
1400
|
+
const session = await getManager().councilStart(args.task, config);
|
|
1046
1401
|
return { ok: true, ...session, note: 'Council running in background. Poll with council_status.' };
|
|
1047
1402
|
},
|
|
1048
1403
|
});
|
|
@@ -1206,7 +1561,7 @@ const plugin = {
|
|
|
1206
1561
|
required: ['task'],
|
|
1207
1562
|
},
|
|
1208
1563
|
execute: async (_id, args) => {
|
|
1209
|
-
const result = getManager().ultraplanStart(args.task, {
|
|
1564
|
+
const result = await getManager().ultraplanStart(args.task, {
|
|
1210
1565
|
cwd: sanitizeCwd(args.cwd),
|
|
1211
1566
|
model: args.model,
|
|
1212
1567
|
timeout: args.timeout,
|
|
@@ -1254,7 +1609,7 @@ const plugin = {
|
|
|
1254
1609
|
required: ['cwd'],
|
|
1255
1610
|
},
|
|
1256
1611
|
execute: async (_id, args) => {
|
|
1257
|
-
const result = getManager().ultrareviewStart(sanitizeCwd(args.cwd), {
|
|
1612
|
+
const result = await getManager().ultrareviewStart(sanitizeCwd(args.cwd), {
|
|
1258
1613
|
agentCount: args.agentCount,
|
|
1259
1614
|
maxDurationMinutes: args.maxDurationMinutes,
|
|
1260
1615
|
model: args.model,
|