@narumitw/pi-subagents 0.49.2 → 0.51.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 +313 -53
- package/package.json +11 -8
- package/src/adaptive-scheduler.ts +196 -0
- package/src/admission-benchmark.ts +95 -0
- package/src/admission-policy.ts +78 -0
- package/src/agent-projection.ts +53 -0
- package/src/agents.ts +58 -1
- package/src/auto-transport.ts +114 -0
- package/src/blocking-status.ts +63 -0
- package/src/capabilities.ts +145 -0
- package/src/capability-grant.ts +115 -0
- package/src/capability-router.ts +107 -0
- package/src/completion-delivery.ts +257 -0
- package/src/config-status.ts +221 -0
- package/src/config-ui.ts +215 -236
- package/src/consult-resources.ts +4 -27
- package/src/consult.ts +9 -1
- package/src/create-stateful-transport.ts +55 -0
- package/src/delegation-contract.ts +417 -0
- package/src/execution-plan.ts +322 -0
- package/src/execution-profiles.ts +95 -0
- package/src/execution-ui.ts +320 -0
- package/src/execution.ts +848 -158
- package/src/in-process-transport.ts +269 -25
- package/src/inspect-render.ts +101 -1
- package/src/inspect.ts +296 -3
- package/src/integration-controller.ts +98 -0
- package/src/limits.ts +3 -0
- package/src/orchestration-metrics.ts +78 -0
- package/src/outcome.ts +61 -0
- package/src/panel-child-group.ts +35 -0
- package/src/panel-contract.ts +343 -0
- package/src/panel-evidence.ts +59 -0
- package/src/panel-execution.ts +772 -0
- package/src/panel-failure.ts +56 -0
- package/src/panel-planning.ts +175 -0
- package/src/panel-prompts.ts +132 -0
- package/src/panel-reconciliation.ts +57 -0
- package/src/panel-render.ts +103 -0
- package/src/parallel-limit-ui.ts +112 -0
- package/src/params.ts +172 -3
- package/src/persistence.ts +182 -32
- package/src/prompt-resources.ts +38 -0
- package/src/registry-types.ts +175 -0
- package/src/registry.ts +466 -143
- package/src/render.ts +72 -6
- package/src/result-contract.ts +416 -0
- package/src/retained-semantic-state.ts +100 -0
- package/src/rpc-timeout-finalization.ts +207 -0
- package/src/rpc-transport-metadata.ts +65 -0
- package/src/rpc-transport.ts +990 -0
- package/src/rpc-turn-capture.ts +142 -0
- package/src/runner-result.ts +55 -0
- package/src/runner-usage.ts +48 -0
- package/src/runner.ts +325 -73
- package/src/semantic-snapshot.ts +214 -0
- package/src/settings.ts +254 -35
- package/src/spawn-idempotency.ts +61 -0
- package/src/stateful-config.ts +13 -0
- package/src/stateful-guidance.ts +1 -0
- package/src/stateful-lifecycle.ts +45 -2
- package/src/stateful-limit-ui.ts +246 -0
- package/src/stateful-limits.ts +96 -0
- package/src/stateful-prompt.ts +11 -2
- package/src/stateful-render.ts +48 -3
- package/src/stateful.ts +467 -357
- package/src/subagents.ts +114 -46
- package/src/subprocess-transport.ts +64 -5
- package/src/supervision.ts +103 -0
- package/src/timeout-checkpoint.ts +305 -0
- package/src/timeout-finalization.ts +75 -0
- package/src/transport-types.ts +68 -0
- package/src/transport-ui.ts +169 -0
- package/src/transport.ts +16 -4
- package/src/turn-budget.ts +109 -0
- package/src/verification-policy.ts +17 -0
- package/src/work-item-ledger.ts +682 -0
- package/src/work-item-persistence.ts +218 -0
- package/src/workflow-planning.ts +150 -0
- package/src/workflow-ui.ts +61 -0
- package/src/workspace.ts +69 -12
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
type DelegationAdmissionDecision,
|
|
4
|
+
evaluateDelegationAdmission,
|
|
5
|
+
} from "./admission-policy.js";
|
|
6
|
+
import {
|
|
7
|
+
type AgentConfig,
|
|
8
|
+
type AgentSource,
|
|
9
|
+
resolveAgentToolNames,
|
|
10
|
+
type SubagentThinkingLevel,
|
|
11
|
+
} from "./agents.js";
|
|
12
|
+
import type { TargetPolicyAudit } from "./cwd-policy.js";
|
|
13
|
+
import type { DelegationContract } from "./delegation-contract.js";
|
|
14
|
+
import type { SubagentResultFormat } from "./result-contract.js";
|
|
15
|
+
|
|
16
|
+
export const EXECUTION_PLAN_VERSION = "pi-subagents:execution-plan:v1" as const;
|
|
17
|
+
export const EXECUTION_ACKNOWLEDGEMENT_VERSION = "pi-subagents:acknowledgement:v1" as const;
|
|
18
|
+
|
|
19
|
+
export type CapabilityFit = "match" | "mismatch" | "unknown";
|
|
20
|
+
export type ExecutionPlanTransport = "subprocess" | "in-process" | "rpc" | "auto";
|
|
21
|
+
|
|
22
|
+
export interface ExecutionPlanAgentProjection {
|
|
23
|
+
name: string;
|
|
24
|
+
source: AgentSource;
|
|
25
|
+
capabilitiesKnown: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ExecutionPlan {
|
|
29
|
+
version: typeof EXECUTION_PLAN_VERSION;
|
|
30
|
+
id: string;
|
|
31
|
+
mode: "audit" | "enforce";
|
|
32
|
+
taskId?: string;
|
|
33
|
+
taskGeneration: number;
|
|
34
|
+
cancellationLineage: string[];
|
|
35
|
+
admission: DelegationAdmissionDecision;
|
|
36
|
+
agent: ExecutionPlanAgentProjection;
|
|
37
|
+
capabilityFit: CapabilityFit;
|
|
38
|
+
missingCapabilities: string[];
|
|
39
|
+
requestedCapabilities: string[];
|
|
40
|
+
declaredCapabilities: string[];
|
|
41
|
+
requestedTools: string[];
|
|
42
|
+
effectiveTools?: string[];
|
|
43
|
+
missingTools: string[];
|
|
44
|
+
overgrantedTools: string[];
|
|
45
|
+
resultFormat: SubagentResultFormat;
|
|
46
|
+
sideEffectPolicy: "read-only" | "idempotent" | "mutating";
|
|
47
|
+
resultFormatSupported: boolean | "unknown";
|
|
48
|
+
target: TargetPolicyAudit;
|
|
49
|
+
workspaceMode: "shared" | "worktree";
|
|
50
|
+
transport: ExecutionPlanTransport;
|
|
51
|
+
model?: string;
|
|
52
|
+
thinkingLevel?: SubagentThinkingLevel;
|
|
53
|
+
timeoutMs?: number;
|
|
54
|
+
unsupportedGuarantees: string[];
|
|
55
|
+
warnings: string[];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface ExecutionAcknowledgement {
|
|
59
|
+
version: typeof EXECUTION_ACKNOWLEDGEMENT_VERSION;
|
|
60
|
+
status: "accepted" | "rejected";
|
|
61
|
+
reasonCodes: string[];
|
|
62
|
+
recoveryActions: string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface CreateExecutionPlanInput {
|
|
66
|
+
contract?: DelegationContract;
|
|
67
|
+
agent: AgentConfig;
|
|
68
|
+
effectiveTools?: string[];
|
|
69
|
+
target: TargetPolicyAudit;
|
|
70
|
+
workspaceMode: "shared" | "worktree";
|
|
71
|
+
transport: ExecutionPlanTransport;
|
|
72
|
+
resultFormat: SubagentResultFormat;
|
|
73
|
+
model?: string;
|
|
74
|
+
thinkingLevel?: SubagentThinkingLevel;
|
|
75
|
+
timeoutMs?: number;
|
|
76
|
+
taskGeneration?: number;
|
|
77
|
+
cancellationLineage?: string[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function createExecutionPlan(input: CreateExecutionPlanInput): ExecutionPlan {
|
|
81
|
+
const manifest = input.agent.capabilityManifest;
|
|
82
|
+
const requestedCapabilities = unique(input.contract?.requestedAuthority?.capabilities ?? []);
|
|
83
|
+
const declaredCapabilities = unique(manifest?.capabilities ?? []);
|
|
84
|
+
const missingCapabilities = requestedCapabilities.filter(
|
|
85
|
+
(capability) => !declaredCapabilities.includes(capability),
|
|
86
|
+
);
|
|
87
|
+
const capabilityFit: CapabilityFit = manifest
|
|
88
|
+
? missingCapabilities.length > 0
|
|
89
|
+
? "mismatch"
|
|
90
|
+
: "match"
|
|
91
|
+
: "unknown";
|
|
92
|
+
const requestedTools = unique(input.contract?.requestedAuthority?.tools ?? []);
|
|
93
|
+
const effectiveTools = input.effectiveTools ? unique(input.effectiveTools) : undefined;
|
|
94
|
+
const missingTools = requestedTools.filter((tool) => !(effectiveTools ?? []).includes(tool));
|
|
95
|
+
const overgrantedTools =
|
|
96
|
+
requestedTools.length === 0
|
|
97
|
+
? []
|
|
98
|
+
: (effectiveTools ?? []).filter((tool) => !requestedTools.includes(tool));
|
|
99
|
+
const resultFormatSupported = manifest
|
|
100
|
+
? manifest.resultFormats.includes(input.resultFormat)
|
|
101
|
+
: "unknown";
|
|
102
|
+
const unsupportedGuarantees = unsupported(input.contract);
|
|
103
|
+
const taskGeneration = input.taskGeneration ?? 0;
|
|
104
|
+
const cancellationLineage = [...(input.cancellationLineage ?? [])];
|
|
105
|
+
const admissionRequest = input.contract?.admission;
|
|
106
|
+
const admission = evaluateDelegationAdmission({
|
|
107
|
+
contextPressure: admissionRequest?.contextPressure ?? "low",
|
|
108
|
+
independentWorkItems: admissionRequest?.independentWorkItems ?? 1,
|
|
109
|
+
coupling: admissionRequest?.coupling ?? "dense",
|
|
110
|
+
verificationRequired: admissionRequest?.verificationRequired ?? false,
|
|
111
|
+
verificationAvailable: admissionRequest?.verificationAvailable ?? false,
|
|
112
|
+
capabilitiesSupported: capabilityFit === "match" && missingTools.length === 0,
|
|
113
|
+
budgetAllowsChildren: admissionRequest?.budgetAllowsChildren ?? true,
|
|
114
|
+
generationCurrent: true,
|
|
115
|
+
requirementsComplete: admissionRequest?.requirementsComplete ?? false,
|
|
116
|
+
});
|
|
117
|
+
const warnings: string[] = [];
|
|
118
|
+
if (!manifest) warnings.push("agent-capabilities-unknown");
|
|
119
|
+
if (missingCapabilities.length > 0) warnings.push("capability-mismatch");
|
|
120
|
+
if (missingTools.length > 0) warnings.push("requested-tools-missing");
|
|
121
|
+
if (overgrantedTools.length > 0) warnings.push("tools-overgranted");
|
|
122
|
+
if (resultFormatSupported === false) warnings.push("result-format-unsupported");
|
|
123
|
+
if (unsupportedGuarantees.length > 0) warnings.push("unsupported-guarantees");
|
|
124
|
+
const planWithoutId: Omit<ExecutionPlan, "id"> = {
|
|
125
|
+
version: EXECUTION_PLAN_VERSION,
|
|
126
|
+
mode: input.contract?.enforcement ?? "audit",
|
|
127
|
+
...(input.contract?.taskId ? { taskId: input.contract.taskId } : {}),
|
|
128
|
+
agent: {
|
|
129
|
+
name: input.agent.name,
|
|
130
|
+
source: input.agent.source,
|
|
131
|
+
capabilitiesKnown: manifest !== undefined,
|
|
132
|
+
},
|
|
133
|
+
capabilityFit,
|
|
134
|
+
missingCapabilities,
|
|
135
|
+
requestedCapabilities,
|
|
136
|
+
declaredCapabilities,
|
|
137
|
+
requestedTools,
|
|
138
|
+
...(effectiveTools === undefined ? {} : { effectiveTools }),
|
|
139
|
+
missingTools,
|
|
140
|
+
overgrantedTools,
|
|
141
|
+
resultFormat: input.resultFormat,
|
|
142
|
+
sideEffectPolicy: input.contract?.sideEffectPolicy ?? "mutating",
|
|
143
|
+
resultFormatSupported,
|
|
144
|
+
target: structuredClone(input.target),
|
|
145
|
+
workspaceMode: input.workspaceMode,
|
|
146
|
+
transport: input.transport,
|
|
147
|
+
...(input.model === undefined ? {} : { model: input.model }),
|
|
148
|
+
...(input.thinkingLevel === undefined ? {} : { thinkingLevel: input.thinkingLevel }),
|
|
149
|
+
...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),
|
|
150
|
+
unsupportedGuarantees,
|
|
151
|
+
warnings,
|
|
152
|
+
taskGeneration,
|
|
153
|
+
cancellationLineage,
|
|
154
|
+
admission,
|
|
155
|
+
};
|
|
156
|
+
return { ...planWithoutId, id: executionPlanId(planWithoutId) };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function resolveContractTools(
|
|
160
|
+
configuredTools: string[] | undefined,
|
|
161
|
+
contract: DelegationContract | undefined,
|
|
162
|
+
): string[] | undefined {
|
|
163
|
+
const requested = contract?.requestedAuthority?.tools;
|
|
164
|
+
if (contract?.enforcement !== "enforce" || !requested || requested.length === 0) {
|
|
165
|
+
return configuredTools ? unique(configuredTools) : undefined;
|
|
166
|
+
}
|
|
167
|
+
const availableTools = resolveAgentToolNames(configuredTools);
|
|
168
|
+
return unique(requested.filter((tool) => availableTools.includes(tool)));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function acknowledgeExecutionPlan(plan: ExecutionPlan): ExecutionAcknowledgement {
|
|
172
|
+
if (plan.mode === "audit") {
|
|
173
|
+
return {
|
|
174
|
+
version: EXECUTION_ACKNOWLEDGEMENT_VERSION,
|
|
175
|
+
status: "accepted",
|
|
176
|
+
reasonCodes: [],
|
|
177
|
+
recoveryActions: [],
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const reasonCodes: string[] = [];
|
|
181
|
+
const recoveryActions: string[] = [];
|
|
182
|
+
if (plan.capabilityFit === "unknown") {
|
|
183
|
+
reasonCodes.push("capabilities-unknown");
|
|
184
|
+
recoveryActions.push("declare-capabilities", "reroute");
|
|
185
|
+
}
|
|
186
|
+
if (plan.missingCapabilities.length > 0) {
|
|
187
|
+
reasonCodes.push("capability-mismatch");
|
|
188
|
+
recoveryActions.push("reroute");
|
|
189
|
+
}
|
|
190
|
+
if (plan.missingTools.length > 0) {
|
|
191
|
+
reasonCodes.push("authority-missing");
|
|
192
|
+
recoveryActions.push("grant-authority", "reroute");
|
|
193
|
+
}
|
|
194
|
+
if (plan.overgrantedTools.length > 0) {
|
|
195
|
+
reasonCodes.push("authority-overgranted");
|
|
196
|
+
recoveryActions.push("narrow-authority");
|
|
197
|
+
}
|
|
198
|
+
if (plan.resultFormatSupported !== true) {
|
|
199
|
+
reasonCodes.push("result-format-unsupported");
|
|
200
|
+
recoveryActions.push("reroute", "change-result-format");
|
|
201
|
+
}
|
|
202
|
+
if (plan.unsupportedGuarantees.length > 0) {
|
|
203
|
+
reasonCodes.push("unsupported-guarantee");
|
|
204
|
+
recoveryActions.push("stop");
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
version: EXECUTION_ACKNOWLEDGEMENT_VERSION,
|
|
208
|
+
status: reasonCodes.length === 0 ? "accepted" : "rejected",
|
|
209
|
+
reasonCodes: unique(reasonCodes),
|
|
210
|
+
recoveryActions: unique(recoveryActions),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function copyExecutionPlan(plan: ExecutionPlan): ExecutionPlan {
|
|
215
|
+
const { id: _storedId, ...cloned } = structuredClone(plan);
|
|
216
|
+
const legacyAdmission = evaluateDelegationAdmission({
|
|
217
|
+
contextPressure: "low",
|
|
218
|
+
independentWorkItems: 1,
|
|
219
|
+
coupling: "dense",
|
|
220
|
+
verificationRequired: false,
|
|
221
|
+
verificationAvailable: false,
|
|
222
|
+
capabilitiesSupported: false,
|
|
223
|
+
budgetAllowsChildren: true,
|
|
224
|
+
generationCurrent: true,
|
|
225
|
+
requirementsComplete: false,
|
|
226
|
+
});
|
|
227
|
+
const normalized = {
|
|
228
|
+
...cloned,
|
|
229
|
+
sideEffectPolicy: plan.sideEffectPolicy ?? "mutating",
|
|
230
|
+
taskGeneration: plan.taskGeneration ?? 0,
|
|
231
|
+
cancellationLineage: plan.cancellationLineage ?? [],
|
|
232
|
+
admission: plan.admission ?? legacyAdmission,
|
|
233
|
+
};
|
|
234
|
+
return { ...normalized, id: executionPlanId(normalized) };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export function rotateExecutionPlanGeneration(plan: ExecutionPlan): ExecutionPlan {
|
|
238
|
+
const normalized = copyExecutionPlan(plan);
|
|
239
|
+
const { id: previousId, ...withoutId } = normalized;
|
|
240
|
+
const rotated = {
|
|
241
|
+
...withoutId,
|
|
242
|
+
taskGeneration: normalized.taskGeneration + 1,
|
|
243
|
+
cancellationLineage: [...normalized.cancellationLineage, previousId],
|
|
244
|
+
};
|
|
245
|
+
return { ...rotated, id: executionPlanId(rotated) };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function isExecutionPlan(value: unknown): value is ExecutionPlan {
|
|
249
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
250
|
+
const plan = value as Partial<ExecutionPlan>;
|
|
251
|
+
return (
|
|
252
|
+
plan.version === EXECUTION_PLAN_VERSION &&
|
|
253
|
+
(plan.mode === "audit" || plan.mode === "enforce") &&
|
|
254
|
+
Boolean(plan.agent) &&
|
|
255
|
+
typeof plan.agent?.name === "string" &&
|
|
256
|
+
["built-in", "user", "project"].includes(String(plan.agent?.source)) &&
|
|
257
|
+
["match", "mismatch", "unknown"].includes(String(plan.capabilityFit)) &&
|
|
258
|
+
Array.isArray(plan.missingCapabilities) &&
|
|
259
|
+
plan.missingCapabilities.every((item) => typeof item === "string") &&
|
|
260
|
+
Array.isArray(plan.requestedCapabilities) &&
|
|
261
|
+
plan.requestedCapabilities.every((item) => typeof item === "string") &&
|
|
262
|
+
Array.isArray(plan.declaredCapabilities) &&
|
|
263
|
+
plan.declaredCapabilities.every((item) => typeof item === "string") &&
|
|
264
|
+
Array.isArray(plan.missingTools) &&
|
|
265
|
+
plan.missingTools.every((item) => typeof item === "string") &&
|
|
266
|
+
Array.isArray(plan.requestedTools) &&
|
|
267
|
+
plan.requestedTools.every((item) => typeof item === "string") &&
|
|
268
|
+
(plan.effectiveTools === undefined ||
|
|
269
|
+
(Array.isArray(plan.effectiveTools) &&
|
|
270
|
+
plan.effectiveTools.every((item) => typeof item === "string"))) &&
|
|
271
|
+
Array.isArray(plan.overgrantedTools) &&
|
|
272
|
+
plan.overgrantedTools.every((item) => typeof item === "string") &&
|
|
273
|
+
["text", "structured-v1", "structured-v2"].includes(String(plan.resultFormat)) &&
|
|
274
|
+
(typeof plan.resultFormatSupported === "boolean" || plan.resultFormatSupported === "unknown") &&
|
|
275
|
+
Boolean(plan.target) &&
|
|
276
|
+
typeof plan.target?.cwd === "string" &&
|
|
277
|
+
["current-workspace", "external"].includes(String(plan.target?.boundary)) &&
|
|
278
|
+
(plan.workspaceMode === "shared" || plan.workspaceMode === "worktree") &&
|
|
279
|
+
["subprocess", "in-process", "rpc", "auto"].includes(String(plan.transport)) &&
|
|
280
|
+
typeof plan.id === "string" &&
|
|
281
|
+
/^[a-f0-9]{64}$/u.test(plan.id) &&
|
|
282
|
+
(plan.taskGeneration === undefined ||
|
|
283
|
+
(Number.isSafeInteger(plan.taskGeneration) && Number(plan.taskGeneration) >= 0)) &&
|
|
284
|
+
(plan.cancellationLineage === undefined ||
|
|
285
|
+
(Array.isArray(plan.cancellationLineage) &&
|
|
286
|
+
plan.cancellationLineage.every((item) => typeof item === "string"))) &&
|
|
287
|
+
(plan.admission === undefined ||
|
|
288
|
+
(typeof plan.admission === "object" &&
|
|
289
|
+
plan.admission.auditOnly === true &&
|
|
290
|
+
typeof plan.admission.recommendation === "string" &&
|
|
291
|
+
Array.isArray(plan.admission.reasonCodes) &&
|
|
292
|
+
plan.admission.reasonCodes.every((item) => typeof item === "string"))) &&
|
|
293
|
+
(plan.sideEffectPolicy === undefined ||
|
|
294
|
+
["read-only", "idempotent", "mutating"].includes(String(plan.sideEffectPolicy))) &&
|
|
295
|
+
Array.isArray(plan.unsupportedGuarantees) &&
|
|
296
|
+
plan.unsupportedGuarantees.every((item) => typeof item === "string") &&
|
|
297
|
+
Array.isArray(plan.warnings) &&
|
|
298
|
+
plan.warnings.every((item) => typeof item === "string") &&
|
|
299
|
+
copyExecutionPlan(plan as ExecutionPlan).id === plan.id
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function executionPlanId(plan: Omit<ExecutionPlan, "id"> | Record<string, unknown>): string {
|
|
304
|
+
return createHash("sha256").update(JSON.stringify(plan)).digest("hex");
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function unsupported(contract: DelegationContract | undefined): string[] {
|
|
308
|
+
if (!contract?.requestedAuthority) return [];
|
|
309
|
+
const authority = contract.requestedAuthority;
|
|
310
|
+
const result: string[] = [];
|
|
311
|
+
if (authority.readPaths && authority.readPaths.length > 0) result.push("read-path-scope");
|
|
312
|
+
if (authority.writePaths && authority.writePaths.length > 0) result.push("write-path-scope");
|
|
313
|
+
if (authority.network === "denied") result.push("network-denial");
|
|
314
|
+
if (authority.network === "required") result.push("network-availability");
|
|
315
|
+
if (authority.secrets === "denied") result.push("secret-denial");
|
|
316
|
+
if (authority.secrets === "required") result.push("secret-availability");
|
|
317
|
+
return result;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function unique(values: readonly string[]): string[] {
|
|
321
|
+
return [...new Set(values)];
|
|
322
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { SubagentThinkingLevel } from "./agents.js";
|
|
2
|
+
import { readSubagentSettings, updateAgentSettingsPatch } from "./settings.js";
|
|
3
|
+
|
|
4
|
+
export const EXECUTION_PROFILES = ["fast", "balanced", "deep"] as const;
|
|
5
|
+
export type ExecutionProfile = (typeof EXECUTION_PROFILES)[number];
|
|
6
|
+
|
|
7
|
+
const PROFILE_AGENT_ORDER = [
|
|
8
|
+
"scout",
|
|
9
|
+
"planner",
|
|
10
|
+
"reviewer",
|
|
11
|
+
"worker",
|
|
12
|
+
"general",
|
|
13
|
+
"general-purpose",
|
|
14
|
+
] as const;
|
|
15
|
+
|
|
16
|
+
type ProfileAgent = (typeof PROFILE_AGENT_ORDER)[number];
|
|
17
|
+
|
|
18
|
+
export const EXECUTION_PROFILE_THINKING: Record<
|
|
19
|
+
ExecutionProfile,
|
|
20
|
+
Record<ProfileAgent, SubagentThinkingLevel>
|
|
21
|
+
> = {
|
|
22
|
+
fast: {
|
|
23
|
+
scout: "low",
|
|
24
|
+
planner: "low",
|
|
25
|
+
reviewer: "medium",
|
|
26
|
+
worker: "low",
|
|
27
|
+
general: "low",
|
|
28
|
+
"general-purpose": "low",
|
|
29
|
+
},
|
|
30
|
+
balanced: {
|
|
31
|
+
scout: "low",
|
|
32
|
+
planner: "medium",
|
|
33
|
+
reviewer: "medium",
|
|
34
|
+
worker: "medium",
|
|
35
|
+
general: "medium",
|
|
36
|
+
"general-purpose": "medium",
|
|
37
|
+
},
|
|
38
|
+
deep: {
|
|
39
|
+
scout: "medium",
|
|
40
|
+
planner: "high",
|
|
41
|
+
reviewer: "high",
|
|
42
|
+
worker: "high",
|
|
43
|
+
general: "high",
|
|
44
|
+
"general-purpose": "high",
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export function executionProfileLabel(profile: ExecutionProfile): string {
|
|
49
|
+
switch (profile) {
|
|
50
|
+
case "fast":
|
|
51
|
+
return "Fast";
|
|
52
|
+
case "balanced":
|
|
53
|
+
return "Balanced";
|
|
54
|
+
case "deep":
|
|
55
|
+
return "Deep";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function executionProfileDescription(profile: ExecutionProfile): string {
|
|
60
|
+
switch (profile) {
|
|
61
|
+
case "fast":
|
|
62
|
+
return "Prefer low thinking for bounded work and medium for review.";
|
|
63
|
+
case "balanced":
|
|
64
|
+
return "Use low for scouting and medium for planning, review, and implementation.";
|
|
65
|
+
case "deep":
|
|
66
|
+
return "Use medium scouting and high thinking for planning, review, and implementation.";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function executionProfilePreview(profile: ExecutionProfile): string[] {
|
|
71
|
+
const values = EXECUTION_PROFILE_THINKING[profile];
|
|
72
|
+
return PROFILE_AGENT_ORDER.map((agent) => `${agent}: ${values[agent]}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function inspectExecutionProfile(): ExecutionProfile | "custom" {
|
|
76
|
+
const configured = readSubagentSettings()?.agents ?? {};
|
|
77
|
+
for (const profile of EXECUTION_PROFILES) {
|
|
78
|
+
const expected = EXECUTION_PROFILE_THINKING[profile];
|
|
79
|
+
if (
|
|
80
|
+
PROFILE_AGENT_ORDER.every((agent) => configured[agent]?.thinkingLevel === expected[agent])
|
|
81
|
+
) {
|
|
82
|
+
return profile;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return "custom";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function applyExecutionProfile(profile: ExecutionProfile): void {
|
|
89
|
+
const values = EXECUTION_PROFILE_THINKING[profile];
|
|
90
|
+
updateAgentSettingsPatch(
|
|
91
|
+
Object.fromEntries(
|
|
92
|
+
PROFILE_AGENT_ORDER.map((agent) => [agent, { thinkingLevel: values[agent] }]),
|
|
93
|
+
),
|
|
94
|
+
);
|
|
95
|
+
}
|