@narumitw/pi-subagents 0.53.0 → 1.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 +85 -15
- package/package.json +1 -1
- package/src/agents/built-ins.ts +124 -0
- package/src/agents/catalog.ts +224 -0
- package/src/agents/discovery.ts +249 -0
- package/src/agents/types.ts +98 -0
- package/src/agents.ts +47 -670
- package/src/auto-transport.ts +2 -1
- package/src/automation.ts +7 -2
- package/src/capability-router.ts +1 -1
- package/src/completion-delivery.ts +82 -11
- package/src/config-status.ts +2 -2
- package/src/config-ui.ts +8 -8
- package/src/consult-resources.ts +1 -1
- package/src/consult.ts +9 -7
- package/src/create-stateful-transport.ts +2 -1
- package/src/cwd-policy.ts +1 -1
- package/src/execution/budget.ts +56 -0
- package/src/execution/runtime-policy.ts +19 -0
- package/src/execution-plan.ts +1 -1
- package/src/execution-profiles.ts +1 -1
- package/src/execution-ui.ts +1 -1
- package/src/execution.ts +269 -100
- package/src/in-process-transport.ts +3 -2
- package/src/inspect.ts +39 -8
- package/src/limits.ts +1 -0
- package/src/orchestration-metrics.ts +12 -5
- package/src/panel-execution.ts +1 -1
- package/src/panel-planning.ts +1 -1
- package/src/params.ts +3 -1
- package/src/persistence.ts +106 -7
- package/src/registry-types.ts +22 -5
- package/src/registry.ts +205 -37
- package/src/render.ts +1 -1
- package/src/retained-semantic-state.ts +1 -1
- package/src/rpc-transport-metadata.ts +1 -1
- package/src/rpc-transport.ts +2 -1
- package/src/runner.ts +6 -1
- package/src/settings/inspection.ts +275 -0
- package/src/settings/schema.ts +186 -0
- package/src/settings.ts +72 -420
- package/src/spawn-idempotency.ts +1 -1
- package/src/stateful-agent-view.ts +87 -0
- package/src/stateful-config.ts +1 -1
- package/src/stateful-guidance.ts +2 -2
- package/src/stateful-limits.ts +1 -1
- package/src/stateful-prompt.ts +2 -2
- package/src/stateful-render.ts +0 -1
- package/src/stateful-safety.ts +2 -1
- package/src/stateful-tool-params.ts +13 -20
- package/src/stateful.ts +36 -117
- package/src/subagents.ts +8 -9
- package/src/subprocess-transport.ts +2 -6
- package/src/transport-types.ts +1 -1
- package/src/transport-ui.ts +1 -1
- package/src/verification-harness.ts +516 -0
- package/src/verification-receipt.ts +275 -0
- package/src/verified-execution-benchmark.ts +86 -0
- package/src/verified-execution-contract.ts +219 -0
- package/src/work-item-ledger.ts +510 -37
- package/src/work-item-persistence.ts +31 -0
- package/src/workflow-completion-controller.ts +397 -0
- package/src/workflow-plan-compiler.ts +1 -1
- package/src/workflow-plan-patch.ts +1 -1
- package/src/workflow-planning.ts +11 -1
- package/src/workflow-ui.ts +1 -1
package/src/settings.ts
CHANGED
|
@@ -3,26 +3,44 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
5
5
|
import lockfile from "proper-lockfile";
|
|
6
|
+
import type {
|
|
7
|
+
AgentConfig,
|
|
8
|
+
CompletionDelivery,
|
|
9
|
+
ConsultationCwdPolicy,
|
|
10
|
+
ConsultResourcePolicy,
|
|
11
|
+
DelegationCwdPolicy,
|
|
12
|
+
SubagentAgentConfig,
|
|
13
|
+
SubagentSettings,
|
|
14
|
+
SubagentThinkingLevel,
|
|
15
|
+
SubagentTransportKind,
|
|
16
|
+
} from "./agents/types.js";
|
|
17
|
+
import { MAX_CONFIGURABLE_PARALLEL_TASKS } from "./limits.js";
|
|
6
18
|
import {
|
|
7
|
-
type
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
type
|
|
17
|
-
type
|
|
18
|
-
type
|
|
19
|
-
type
|
|
20
|
-
|
|
19
|
+
type BlockingParallelLimitSettingsSnapshot,
|
|
20
|
+
buildBlockingParallelLimitSettingsSnapshot,
|
|
21
|
+
buildCompletionDeliverySettingsSnapshot,
|
|
22
|
+
buildConsultResourceSettingsSnapshot,
|
|
23
|
+
buildCwdPolicySettingsSnapshot,
|
|
24
|
+
buildDelegationWorkflowSettingsSnapshot,
|
|
25
|
+
buildStatefulLimitSettingsSnapshot,
|
|
26
|
+
buildStatefulTransportSettingsSnapshot,
|
|
27
|
+
buildSubagentSettingsSnapshot,
|
|
28
|
+
type CompletionDeliverySettingsSnapshot,
|
|
29
|
+
type ConsultResourceSettingsSnapshot,
|
|
30
|
+
type CwdPolicySettingsSnapshot,
|
|
31
|
+
type DelegationWorkflow,
|
|
32
|
+
type DelegationWorkflowSettingsSnapshot,
|
|
33
|
+
type InspectedSubagentSettingsDocument,
|
|
34
|
+
type StatefulLimitSettingsSnapshot,
|
|
35
|
+
type StatefulTransportSettingsSnapshot,
|
|
36
|
+
type SubagentSettingsSnapshot,
|
|
37
|
+
} from "./settings/inspection.js";
|
|
21
38
|
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
39
|
+
hasOwn,
|
|
40
|
+
isPlainObject,
|
|
41
|
+
isPositiveInteger,
|
|
42
|
+
normalizeSubagentSettings,
|
|
43
|
+
} from "./settings/schema.js";
|
|
26
44
|
import {
|
|
27
45
|
isValidStatefulLimit,
|
|
28
46
|
resolveStatefulLimits,
|
|
@@ -32,185 +50,32 @@ import {
|
|
|
32
50
|
statefulLimitDefinition,
|
|
33
51
|
} from "./stateful-limits.js";
|
|
34
52
|
|
|
35
|
-
export
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const config: SubagentAgentConfig = {};
|
|
59
|
-
let hasKnownField = false;
|
|
60
|
-
|
|
61
|
-
if (hasOwn(value, "tools")) {
|
|
62
|
-
if (!isStringArray(value.tools)) return undefined;
|
|
63
|
-
config.tools = value.tools;
|
|
64
|
-
hasKnownField = true;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (hasOwn(value, "model")) {
|
|
68
|
-
if (value.model !== null && typeof value.model !== "string") return undefined;
|
|
69
|
-
config.model = value.model;
|
|
70
|
-
hasKnownField = true;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (hasOwn(value, "thinkingLevel")) {
|
|
74
|
-
if (value.thinkingLevel !== null && !isThinkingLevel(value.thinkingLevel)) return undefined;
|
|
75
|
-
config.thinkingLevel = value.thinkingLevel;
|
|
76
|
-
hasKnownField = true;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (hasOwn(value, "timeoutMs")) {
|
|
80
|
-
if (
|
|
81
|
-
value.timeoutMs !== null &&
|
|
82
|
-
(!isPositiveNumber(value.timeoutMs) || value.timeoutMs > MAX_SUBAGENT_TIMEOUT_MS)
|
|
83
|
-
) {
|
|
84
|
-
return undefined;
|
|
85
|
-
}
|
|
86
|
-
config.timeoutMs = value.timeoutMs;
|
|
87
|
-
hasKnownField = true;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return hasKnownField ? config : undefined;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function normalizeSubagentSettings(value: unknown): SubagentSettings | undefined {
|
|
94
|
-
if (!isPlainObject(value)) return undefined;
|
|
95
|
-
const settings: SubagentSettings = {};
|
|
96
|
-
if (hasOwn(value, "agents")) {
|
|
97
|
-
if (!isPlainObject(value.agents)) return undefined;
|
|
98
|
-
const agents: Record<string, SubagentAgentConfig> = {};
|
|
99
|
-
for (const [name, rawConfig] of Object.entries(value.agents)) {
|
|
100
|
-
const config = normalizeAgentSettings(rawConfig);
|
|
101
|
-
if (config) agents[name] = config;
|
|
102
|
-
}
|
|
103
|
-
if (Object.keys(agents).length > 0) settings.agents = agents;
|
|
104
|
-
}
|
|
105
|
-
if (hasOwn(value, "blocking")) {
|
|
106
|
-
if (!isPlainObject(value.blocking)) return undefined;
|
|
107
|
-
const blocking: NonNullable<SubagentSettings["blocking"]> = {};
|
|
108
|
-
if (hasOwn(value.blocking, "enabled")) {
|
|
109
|
-
if (typeof value.blocking.enabled !== "boolean") return undefined;
|
|
110
|
-
blocking.enabled = value.blocking.enabled;
|
|
111
|
-
}
|
|
112
|
-
if (hasOwn(value.blocking, "maxParallelTasks")) {
|
|
113
|
-
if (
|
|
114
|
-
!isPositiveInteger(value.blocking.maxParallelTasks) ||
|
|
115
|
-
value.blocking.maxParallelTasks > MAX_CONFIGURABLE_PARALLEL_TASKS
|
|
116
|
-
) {
|
|
117
|
-
return undefined;
|
|
118
|
-
}
|
|
119
|
-
blocking.maxParallelTasks = value.blocking.maxParallelTasks;
|
|
120
|
-
}
|
|
121
|
-
settings.blocking = blocking;
|
|
122
|
-
}
|
|
123
|
-
if (hasOwn(value, "stateful")) {
|
|
124
|
-
if (!isPlainObject(value.stateful)) return undefined;
|
|
125
|
-
const runtime: NonNullable<SubagentSettings["stateful"]> = {};
|
|
126
|
-
if (hasOwn(value.stateful, "transport")) {
|
|
127
|
-
if (
|
|
128
|
-
value.stateful.transport !== "subprocess" &&
|
|
129
|
-
value.stateful.transport !== "in-process" &&
|
|
130
|
-
value.stateful.transport !== "rpc" &&
|
|
131
|
-
value.stateful.transport !== "auto"
|
|
132
|
-
) {
|
|
133
|
-
return undefined;
|
|
134
|
-
}
|
|
135
|
-
runtime.transport = value.stateful.transport;
|
|
136
|
-
}
|
|
137
|
-
if (hasOwn(value.stateful, "completionDelivery")) {
|
|
138
|
-
if (
|
|
139
|
-
value.stateful.completionDelivery !== "next-turn" &&
|
|
140
|
-
value.stateful.completionDelivery !== "auto-resume"
|
|
141
|
-
) {
|
|
142
|
-
return undefined;
|
|
143
|
-
}
|
|
144
|
-
runtime.completionDelivery = value.stateful.completionDelivery;
|
|
145
|
-
}
|
|
146
|
-
for (const key of STATEFUL_LIMIT_FIELDS) {
|
|
147
|
-
if (hasOwn(value.stateful, key)) {
|
|
148
|
-
if (!isValidStatefulLimit(key, value.stateful[key])) return undefined;
|
|
149
|
-
runtime[key] = value.stateful[key];
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
for (const key of ["maxMailboxMessages", "maxMailboxMessageBytes", "idleTtlMs"] as const) {
|
|
153
|
-
if (hasOwn(value.stateful, key)) {
|
|
154
|
-
if (!isPositiveInteger(value.stateful[key])) return undefined;
|
|
155
|
-
runtime[key] = value.stateful[key];
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
if (hasOwn(value.stateful, "retentionDays")) {
|
|
159
|
-
if (!isPositiveNumber(value.stateful.retentionDays)) return undefined;
|
|
160
|
-
runtime.retentionDays = value.stateful.retentionDays;
|
|
161
|
-
}
|
|
162
|
-
if (hasOwn(value.stateful, "enabled")) {
|
|
163
|
-
if (typeof value.stateful.enabled !== "boolean") return undefined;
|
|
164
|
-
runtime.enabled = value.stateful.enabled;
|
|
165
|
-
}
|
|
166
|
-
settings.stateful = runtime;
|
|
167
|
-
}
|
|
168
|
-
if (hasOwn(value, "consult")) {
|
|
169
|
-
if (!isPlainObject(value.consult)) return undefined;
|
|
170
|
-
const consult: NonNullable<SubagentSettings["consult"]> = {};
|
|
171
|
-
if (hasOwn(value.consult, "resources")) {
|
|
172
|
-
if (
|
|
173
|
-
typeof value.consult.resources !== "string" ||
|
|
174
|
-
!CONSULT_RESOURCE_POLICIES.includes(value.consult.resources as ConsultResourcePolicy)
|
|
175
|
-
) {
|
|
176
|
-
return undefined;
|
|
177
|
-
}
|
|
178
|
-
consult.resources = value.consult.resources as ConsultResourcePolicy;
|
|
179
|
-
}
|
|
180
|
-
settings.consult = consult;
|
|
181
|
-
}
|
|
182
|
-
if (hasOwn(value, "cwdPolicy")) {
|
|
183
|
-
if (!isPlainObject(value.cwdPolicy)) return undefined;
|
|
184
|
-
const cwdPolicy: NonNullable<SubagentSettings["cwdPolicy"]> = {};
|
|
185
|
-
if (hasOwn(value.cwdPolicy, "consultation")) {
|
|
186
|
-
if (
|
|
187
|
-
typeof value.cwdPolicy.consultation !== "string" ||
|
|
188
|
-
!CONSULTATION_CWD_POLICIES.includes(value.cwdPolicy.consultation as ConsultationCwdPolicy)
|
|
189
|
-
) {
|
|
190
|
-
return undefined;
|
|
191
|
-
}
|
|
192
|
-
cwdPolicy.consultation = value.cwdPolicy.consultation as ConsultationCwdPolicy;
|
|
193
|
-
}
|
|
194
|
-
if (hasOwn(value.cwdPolicy, "delegation")) {
|
|
195
|
-
if (
|
|
196
|
-
typeof value.cwdPolicy.delegation !== "string" ||
|
|
197
|
-
!DELEGATION_CWD_POLICIES.includes(value.cwdPolicy.delegation as DelegationCwdPolicy)
|
|
198
|
-
) {
|
|
199
|
-
return undefined;
|
|
200
|
-
}
|
|
201
|
-
cwdPolicy.delegation = value.cwdPolicy.delegation as DelegationCwdPolicy;
|
|
202
|
-
}
|
|
203
|
-
settings.cwdPolicy = cwdPolicy;
|
|
204
|
-
}
|
|
205
|
-
return settings;
|
|
206
|
-
}
|
|
53
|
+
export {
|
|
54
|
+
type BlockingParallelLimitSettingsSnapshot,
|
|
55
|
+
type CompletionDeliverySettingsSnapshot,
|
|
56
|
+
type ConsultResourceSettingsSnapshot,
|
|
57
|
+
type CwdPolicyFieldSnapshot,
|
|
58
|
+
type CwdPolicySettingsSnapshot,
|
|
59
|
+
DEFAULT_CONSULT_RESOURCE_POLICY,
|
|
60
|
+
DEFAULT_CONSULTATION_CWD_POLICY,
|
|
61
|
+
DEFAULT_DELEGATION_CWD_POLICY,
|
|
62
|
+
type DelegationWorkflow,
|
|
63
|
+
type DelegationWorkflowSettingsSnapshot,
|
|
64
|
+
resolveBlockingMaxParallelTasks,
|
|
65
|
+
resolveDelegationWorkflow,
|
|
66
|
+
type StatefulLimitFieldSnapshot,
|
|
67
|
+
type StatefulLimitSettingsSnapshot,
|
|
68
|
+
type StatefulTransportSettingsSnapshot,
|
|
69
|
+
type SubagentSettingsSnapshot,
|
|
70
|
+
} from "./settings/inspection.js";
|
|
71
|
+
export {
|
|
72
|
+
hasOwn,
|
|
73
|
+
normalizeAgentSettings,
|
|
74
|
+
normalizeSubagentSettings,
|
|
75
|
+
} from "./settings/schema.js";
|
|
207
76
|
|
|
208
77
|
const SETTINGS_FILE = "pi-subagents.json";
|
|
209
78
|
const LEGACY_SETTINGS_FILE = "pi-subagents-config.json";
|
|
210
|
-
const DEFAULT_COMPLETION_DELIVERY: CompletionDelivery = "next-turn";
|
|
211
|
-
export const DEFAULT_CONSULT_RESOURCE_POLICY: ConsultResourcePolicy = "project-context";
|
|
212
|
-
export const DEFAULT_CONSULTATION_CWD_POLICY: ConsultationCwdPolicy = "anywhere";
|
|
213
|
-
export const DEFAULT_DELEGATION_CWD_POLICY: DelegationCwdPolicy = "trusted-targets";
|
|
214
79
|
const SETTINGS_LOCK_FS_ADAPTER = {
|
|
215
80
|
mkdir: fs.mkdir,
|
|
216
81
|
mkdirSync: fs.mkdirSync,
|
|
@@ -284,94 +149,11 @@ export function saveSubagentConfig(settings: SubagentSettings): void {
|
|
|
284
149
|
writeSettingsObject(settings);
|
|
285
150
|
}
|
|
286
151
|
|
|
287
|
-
export type DelegationWorkflow = "all" | "async-only" | "blocking-only" | "disabled";
|
|
288
|
-
|
|
289
|
-
export interface DelegationWorkflowSettingsSnapshot {
|
|
290
|
-
path: string;
|
|
291
|
-
value: DelegationWorkflow;
|
|
292
|
-
source: "default" | "user settings";
|
|
293
|
-
error?: string;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
export interface CompletionDeliverySettingsSnapshot {
|
|
297
|
-
path: string;
|
|
298
|
-
value: CompletionDelivery;
|
|
299
|
-
source: "default" | "user settings";
|
|
300
|
-
error?: string;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
export interface StatefulTransportSettingsSnapshot {
|
|
304
|
-
path: string;
|
|
305
|
-
value: SubagentTransportKind;
|
|
306
|
-
source: "default" | "user settings";
|
|
307
|
-
error?: string;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
export interface BlockingParallelLimitSettingsSnapshot {
|
|
311
|
-
path: string;
|
|
312
|
-
value: number;
|
|
313
|
-
source: "default" | "user settings";
|
|
314
|
-
error?: string;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
export interface StatefulLimitFieldSnapshot {
|
|
318
|
-
value: number;
|
|
319
|
-
source: "default" | "user settings";
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
export interface StatefulLimitSettingsSnapshot {
|
|
323
|
-
path: string;
|
|
324
|
-
writePath: string;
|
|
325
|
-
values?: Record<StatefulLimitField, StatefulLimitFieldSnapshot>;
|
|
326
|
-
error?: string;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
export interface ConsultResourceSettingsSnapshot {
|
|
330
|
-
path: string;
|
|
331
|
-
value: ConsultResourcePolicy;
|
|
332
|
-
source: "default" | "user settings";
|
|
333
|
-
error?: string;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
export interface CwdPolicyFieldSnapshot<T> {
|
|
337
|
-
value: T;
|
|
338
|
-
source: "default" | "user settings";
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
export interface CwdPolicySettingsSnapshot {
|
|
342
|
-
path: string;
|
|
343
|
-
consultation: CwdPolicyFieldSnapshot<ConsultationCwdPolicy>;
|
|
344
|
-
delegation: CwdPolicyFieldSnapshot<DelegationCwdPolicy>;
|
|
345
|
-
error?: string;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
export interface SubagentSettingsSnapshot {
|
|
349
|
-
path: string;
|
|
350
|
-
settings?: SubagentSettings;
|
|
351
|
-
source: "default" | "user settings";
|
|
352
|
-
error?: string;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
152
|
export function subagentSettingsFilePath(): string {
|
|
356
153
|
return path.join(getAgentDir(), SETTINGS_FILE);
|
|
357
154
|
}
|
|
358
155
|
|
|
359
|
-
|
|
360
|
-
blockingEnabled: boolean,
|
|
361
|
-
statefulEnabled: boolean,
|
|
362
|
-
): DelegationWorkflow {
|
|
363
|
-
if (blockingEnabled && statefulEnabled) return "all";
|
|
364
|
-
if (statefulEnabled) return "async-only";
|
|
365
|
-
if (blockingEnabled) return "blocking-only";
|
|
366
|
-
return "disabled";
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
function inspectSubagentSettingsDocument(): {
|
|
370
|
-
path: string;
|
|
371
|
-
raw?: Record<string, unknown>;
|
|
372
|
-
settings?: SubagentSettings;
|
|
373
|
-
error?: string;
|
|
374
|
-
} {
|
|
156
|
+
function inspectSubagentSettingsDocument(): InspectedSubagentSettingsDocument {
|
|
375
157
|
const { canonicalPath, activePath } = resolveSubagentSettingsPaths();
|
|
376
158
|
if (activePath === undefined) return { path: canonicalPath };
|
|
377
159
|
const inspected = inspectSubagentSettingsPath(activePath);
|
|
@@ -380,12 +162,7 @@ function inspectSubagentSettingsDocument(): {
|
|
|
380
162
|
: inspected;
|
|
381
163
|
}
|
|
382
164
|
|
|
383
|
-
function inspectSubagentSettingsPath(configPath: string): {
|
|
384
|
-
path: string;
|
|
385
|
-
raw?: Record<string, unknown>;
|
|
386
|
-
settings?: SubagentSettings;
|
|
387
|
-
error?: string;
|
|
388
|
-
} {
|
|
165
|
+
function inspectSubagentSettingsPath(configPath: string): InspectedSubagentSettingsDocument {
|
|
389
166
|
const fileName = path.basename(configPath);
|
|
390
167
|
let contents: string;
|
|
391
168
|
try {
|
|
@@ -411,163 +188,38 @@ function inspectSubagentSettingsPath(configPath: string): {
|
|
|
411
188
|
}
|
|
412
189
|
|
|
413
190
|
export function inspectSubagentSettings(): SubagentSettingsSnapshot {
|
|
414
|
-
|
|
415
|
-
return {
|
|
416
|
-
path: inspected.path,
|
|
417
|
-
settings: inspected.settings,
|
|
418
|
-
source: inspected.settings ? "user settings" : "default",
|
|
419
|
-
...(inspected.error ? { error: inspected.error } : {}),
|
|
420
|
-
};
|
|
191
|
+
return buildSubagentSettingsSnapshot(inspectSubagentSettingsDocument());
|
|
421
192
|
}
|
|
422
193
|
|
|
423
194
|
export function inspectConsultResourceSettings(): ConsultResourceSettingsSnapshot {
|
|
424
|
-
|
|
425
|
-
if (!inspected.raw || !inspected.settings) {
|
|
426
|
-
return {
|
|
427
|
-
path: inspected.path,
|
|
428
|
-
value: DEFAULT_CONSULT_RESOURCE_POLICY,
|
|
429
|
-
source: "default",
|
|
430
|
-
...(inspected.error ? { error: inspected.error } : {}),
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
const explicit =
|
|
434
|
-
isPlainObject(inspected.raw.consult) && hasOwn(inspected.raw.consult, "resources");
|
|
435
|
-
return {
|
|
436
|
-
path: inspected.path,
|
|
437
|
-
value: inspected.settings.consult?.resources ?? DEFAULT_CONSULT_RESOURCE_POLICY,
|
|
438
|
-
source: explicit ? "user settings" : "default",
|
|
439
|
-
};
|
|
195
|
+
return buildConsultResourceSettingsSnapshot(inspectSubagentSettingsDocument());
|
|
440
196
|
}
|
|
441
197
|
|
|
442
198
|
export function inspectCwdPolicySettings(): CwdPolicySettingsSnapshot {
|
|
443
|
-
|
|
444
|
-
if (!inspected.raw || !inspected.settings) {
|
|
445
|
-
return {
|
|
446
|
-
path: inspected.path,
|
|
447
|
-
consultation: { value: DEFAULT_CONSULTATION_CWD_POLICY, source: "default" },
|
|
448
|
-
delegation: { value: DEFAULT_DELEGATION_CWD_POLICY, source: "default" },
|
|
449
|
-
...(inspected.error ? { error: inspected.error } : {}),
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
const rawPolicy = isPlainObject(inspected.raw.cwdPolicy) ? inspected.raw.cwdPolicy : undefined;
|
|
453
|
-
return {
|
|
454
|
-
path: inspected.path,
|
|
455
|
-
consultation: {
|
|
456
|
-
value: inspected.settings.cwdPolicy?.consultation ?? DEFAULT_CONSULTATION_CWD_POLICY,
|
|
457
|
-
source: rawPolicy && hasOwn(rawPolicy, "consultation") ? "user settings" : "default",
|
|
458
|
-
},
|
|
459
|
-
delegation: {
|
|
460
|
-
value: inspected.settings.cwdPolicy?.delegation ?? DEFAULT_DELEGATION_CWD_POLICY,
|
|
461
|
-
source: rawPolicy && hasOwn(rawPolicy, "delegation") ? "user settings" : "default",
|
|
462
|
-
},
|
|
463
|
-
};
|
|
199
|
+
return buildCwdPolicySettingsSnapshot(inspectSubagentSettingsDocument());
|
|
464
200
|
}
|
|
465
201
|
|
|
466
202
|
export function inspectDelegationWorkflowSettings(): DelegationWorkflowSettingsSnapshot {
|
|
467
|
-
|
|
468
|
-
if (!inspected.raw || !inspected.settings) {
|
|
469
|
-
return {
|
|
470
|
-
path: inspected.path,
|
|
471
|
-
value: "all",
|
|
472
|
-
source: "default",
|
|
473
|
-
...(inspected.error ? { error: inspected.error } : {}),
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
const explicit =
|
|
477
|
-
(isPlainObject(inspected.raw.blocking) && hasOwn(inspected.raw.blocking, "enabled")) ||
|
|
478
|
-
(isPlainObject(inspected.raw.stateful) && hasOwn(inspected.raw.stateful, "enabled"));
|
|
479
|
-
return {
|
|
480
|
-
path: inspected.path,
|
|
481
|
-
value: resolveDelegationWorkflow(
|
|
482
|
-
inspected.settings.blocking?.enabled !== false,
|
|
483
|
-
inspected.settings.stateful?.enabled !== false,
|
|
484
|
-
),
|
|
485
|
-
source: explicit ? "user settings" : "default",
|
|
486
|
-
};
|
|
203
|
+
return buildDelegationWorkflowSettingsSnapshot(inspectSubagentSettingsDocument());
|
|
487
204
|
}
|
|
488
205
|
|
|
489
206
|
export function inspectCompletionDeliverySettings(): CompletionDeliverySettingsSnapshot {
|
|
490
|
-
|
|
491
|
-
if (!inspected.raw || !inspected.settings) {
|
|
492
|
-
return {
|
|
493
|
-
path: inspected.path,
|
|
494
|
-
value: DEFAULT_COMPLETION_DELIVERY,
|
|
495
|
-
source: "default",
|
|
496
|
-
...(inspected.error ? { error: inspected.error } : {}),
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
const explicit =
|
|
500
|
-
isPlainObject(inspected.raw.stateful) && hasOwn(inspected.raw.stateful, "completionDelivery");
|
|
501
|
-
return {
|
|
502
|
-
path: inspected.path,
|
|
503
|
-
value: inspected.settings.stateful?.completionDelivery ?? DEFAULT_COMPLETION_DELIVERY,
|
|
504
|
-
source: explicit ? "user settings" : "default",
|
|
505
|
-
};
|
|
207
|
+
return buildCompletionDeliverySettingsSnapshot(inspectSubagentSettingsDocument());
|
|
506
208
|
}
|
|
507
209
|
|
|
508
210
|
export function inspectStatefulTransportSettings(): StatefulTransportSettingsSnapshot {
|
|
509
|
-
|
|
510
|
-
if (!inspected.raw || !inspected.settings) {
|
|
511
|
-
return {
|
|
512
|
-
path: inspected.path,
|
|
513
|
-
value: "subprocess",
|
|
514
|
-
source: "default",
|
|
515
|
-
...(inspected.error ? { error: inspected.error } : {}),
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
const explicit =
|
|
519
|
-
isPlainObject(inspected.raw.stateful) && hasOwn(inspected.raw.stateful, "transport");
|
|
520
|
-
return {
|
|
521
|
-
path: inspected.path,
|
|
522
|
-
value: inspected.settings.stateful?.transport ?? "subprocess",
|
|
523
|
-
source: explicit ? "user settings" : "default",
|
|
524
|
-
};
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
export function resolveBlockingMaxParallelTasks(settings?: SubagentSettings): number {
|
|
528
|
-
return settings?.blocking?.maxParallelTasks ?? DEFAULT_MAX_PARALLEL_TASKS;
|
|
211
|
+
return buildStatefulTransportSettingsSnapshot(inspectSubagentSettingsDocument());
|
|
529
212
|
}
|
|
530
213
|
|
|
531
214
|
export function inspectBlockingParallelLimitSettings(): BlockingParallelLimitSettingsSnapshot {
|
|
532
|
-
|
|
533
|
-
if (!inspected.raw || !inspected.settings) {
|
|
534
|
-
return {
|
|
535
|
-
path: inspected.path,
|
|
536
|
-
value: DEFAULT_MAX_PARALLEL_TASKS,
|
|
537
|
-
source: "default",
|
|
538
|
-
...(inspected.error ? { error: inspected.error } : {}),
|
|
539
|
-
};
|
|
540
|
-
}
|
|
541
|
-
const explicit =
|
|
542
|
-
isPlainObject(inspected.raw.blocking) && hasOwn(inspected.raw.blocking, "maxParallelTasks");
|
|
543
|
-
return {
|
|
544
|
-
path: inspected.path,
|
|
545
|
-
value: resolveBlockingMaxParallelTasks(inspected.settings),
|
|
546
|
-
source: explicit ? "user settings" : "default",
|
|
547
|
-
};
|
|
215
|
+
return buildBlockingParallelLimitSettingsSnapshot(inspectSubagentSettingsDocument());
|
|
548
216
|
}
|
|
549
217
|
|
|
550
218
|
export function inspectStatefulLimitSettings(): StatefulLimitSettingsSnapshot {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
}
|
|
556
|
-
const resolved = resolveStatefulLimits(inspected.settings?.stateful);
|
|
557
|
-
const rawStateful = isPlainObject(inspected.raw?.stateful) ? inspected.raw.stateful : undefined;
|
|
558
|
-
return {
|
|
559
|
-
path: inspected.path,
|
|
560
|
-
writePath,
|
|
561
|
-
values: Object.fromEntries(
|
|
562
|
-
STATEFUL_LIMIT_FIELDS.map((field) => [
|
|
563
|
-
field,
|
|
564
|
-
{
|
|
565
|
-
value: resolved[field],
|
|
566
|
-
source: rawStateful && hasOwn(rawStateful, field) ? "user settings" : "default",
|
|
567
|
-
},
|
|
568
|
-
]),
|
|
569
|
-
) as unknown as Record<StatefulLimitField, StatefulLimitFieldSnapshot>,
|
|
570
|
-
};
|
|
219
|
+
return buildStatefulLimitSettingsSnapshot(
|
|
220
|
+
inspectSubagentSettingsDocument(),
|
|
221
|
+
subagentSettingsFilePath(),
|
|
222
|
+
);
|
|
571
223
|
}
|
|
572
224
|
|
|
573
225
|
export function updateDelegationWorkflowSetting(
|
package/src/spawn-idempotency.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import type { AgentScope, SubagentThinkingLevel } from "./agents.js";
|
|
2
|
+
import type { AgentScope, SubagentThinkingLevel } from "./agents/types.js";
|
|
3
3
|
import type { DelegationContract } from "./delegation-contract.js";
|
|
4
4
|
import type { SubagentResultFormat } from "./result-contract.js";
|
|
5
5
|
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { MAX_TOOL_MESSAGE_BYTES, truncateUtf8 } from "./limits.js";
|
|
2
|
+
import type { ManagedAgent } from "./registry.js";
|
|
3
|
+
|
|
4
|
+
export function formatStatefulAgentLine(agent: ManagedAgent, now = Date.now()): string {
|
|
5
|
+
const elapsedSeconds = Math.max(0, Math.floor((now - agent.updatedAt) / 1000));
|
|
6
|
+
const actions =
|
|
7
|
+
agent.state === "running" || agent.state === "starting"
|
|
8
|
+
? "interrupt, close"
|
|
9
|
+
: agent.state === "closed"
|
|
10
|
+
? "inspect"
|
|
11
|
+
: "send, close";
|
|
12
|
+
const task = agent.currentTask ? ` — ${sanitizeStatusLine(agent.currentTask, 80)}` : "";
|
|
13
|
+
const unread = agent.mailbox.filter((message) => !message.readAt).length;
|
|
14
|
+
const indent = " ".repeat(agent.depth);
|
|
15
|
+
const thinking = agent.thinkingLevel ? ` thinking:${agent.thinkingLevel}` : "";
|
|
16
|
+
const timeout = agent.currentTimeoutMs ?? agent.timeoutMs;
|
|
17
|
+
const timeoutText = timeout ? ` timeout:${timeout}ms` : "";
|
|
18
|
+
const idleTimeout = agent.currentIdleTimeoutMs ?? agent.idleTimeoutMs;
|
|
19
|
+
const idleText = idleTimeout ? ` idle:${idleTimeout}ms` : "";
|
|
20
|
+
const maxTurns = agent.currentMaxTurns ?? agent.maxTurns;
|
|
21
|
+
const turnsText = maxTurns ? ` turns:${maxTurns}` : "";
|
|
22
|
+
const maxToolCalls = agent.currentMaxToolCalls ?? agent.maxToolCalls;
|
|
23
|
+
const toolsText = maxToolCalls ? ` tools:${maxToolCalls}` : "";
|
|
24
|
+
const transport = agent.telemetry?.transport ? ` transport:${agent.telemetry.transport}` : "";
|
|
25
|
+
const phase = agent.telemetry?.phase ? ` phase:${agent.telemetry.phase}` : "";
|
|
26
|
+
const queued = agent.telemetry?.queuePosition ? ` queue:${agent.telemetry.queuePosition}` : "";
|
|
27
|
+
return `${indent}${sanitizeStatusLine(agent.id, 128)} ${sanitizeStatusLine(agent.agent, 128)} ${agent.state} ${elapsedSeconds}s${thinking}${timeoutText}${idleText}${turnsText}${toolsText}${transport}${phase}${queued} unread:${unread} [${actions}]${task}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function summarizeStatefulAgent(agent: ManagedAgent) {
|
|
31
|
+
return {
|
|
32
|
+
id: agent.id,
|
|
33
|
+
agent: agent.agent,
|
|
34
|
+
parentId: agent.parentId,
|
|
35
|
+
rootId: agent.rootId,
|
|
36
|
+
depth: agent.depth,
|
|
37
|
+
children: [...agent.children],
|
|
38
|
+
state: agent.state,
|
|
39
|
+
createdAt: agent.createdAt,
|
|
40
|
+
updatedAt: agent.updatedAt,
|
|
41
|
+
cwd: agent.cwd,
|
|
42
|
+
workspaceMode: agent.workspaceMode ?? "shared",
|
|
43
|
+
thinkingLevel: agent.thinkingLevel,
|
|
44
|
+
timeoutMs: agent.timeoutMs,
|
|
45
|
+
currentTimeoutMs: agent.currentTimeoutMs,
|
|
46
|
+
idleTimeoutMs: agent.idleTimeoutMs,
|
|
47
|
+
currentIdleTimeoutMs: agent.currentIdleTimeoutMs,
|
|
48
|
+
maxTurns: agent.maxTurns,
|
|
49
|
+
currentMaxTurns: agent.currentMaxTurns,
|
|
50
|
+
maxToolCalls: agent.maxToolCalls,
|
|
51
|
+
currentMaxToolCalls: agent.currentMaxToolCalls,
|
|
52
|
+
currentTask: agent.currentTask
|
|
53
|
+
? truncateUtf8(agent.currentTask, MAX_TOOL_MESSAGE_BYTES).text
|
|
54
|
+
: undefined,
|
|
55
|
+
historyCount: agent.history.length,
|
|
56
|
+
unreadMessages: agent.mailbox.filter((message) => !message.readAt).length,
|
|
57
|
+
context: {
|
|
58
|
+
turns: agent.contextTurns ?? 0,
|
|
59
|
+
sources: agent.contextSourceIds?.length ?? 0,
|
|
60
|
+
bytes: agent.contextBytes ?? 0,
|
|
61
|
+
truncated: agent.contextTruncated === true,
|
|
62
|
+
},
|
|
63
|
+
resultFormat: agent.resultFormat ?? "text",
|
|
64
|
+
structuredResult: agent.structuredResult,
|
|
65
|
+
termination: agent.termination,
|
|
66
|
+
outcome: agent.outcome,
|
|
67
|
+
executionPlan: agent.executionPlan,
|
|
68
|
+
capabilityGrant: agent.capabilityGrant,
|
|
69
|
+
semanticCompatibility: agent.semanticCompatibility,
|
|
70
|
+
semanticSnapshotDigest: agent.semanticSnapshot?.digest,
|
|
71
|
+
telemetry: agent.telemetry,
|
|
72
|
+
error: agent.error ? truncateUtf8(agent.error, MAX_TOOL_MESSAGE_BYTES).text : undefined,
|
|
73
|
+
target: agent.target,
|
|
74
|
+
policy: agent.policy,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function sanitizeStatusLine(value: string, maxLength: number): string {
|
|
79
|
+
return (
|
|
80
|
+
value
|
|
81
|
+
.slice(0, maxLength)
|
|
82
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: Escape untrusted terminal controls.
|
|
83
|
+
.replace(/[\u0000-\u001f\u007f-\u009f]/gu, " ")
|
|
84
|
+
.replace(/\s+/gu, " ")
|
|
85
|
+
.trim()
|
|
86
|
+
);
|
|
87
|
+
}
|
package/src/stateful-config.ts
CHANGED
package/src/stateful-guidance.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CompletionDelivery } from "./agents.js";
|
|
1
|
+
import type { CompletionDelivery } from "./agents/types.js";
|
|
2
2
|
|
|
3
3
|
export function createSpawnPromptGuidelines(
|
|
4
4
|
completionDelivery: CompletionDelivery,
|
|
@@ -31,6 +31,6 @@ export function createSpawnPromptGuidelines(
|
|
|
31
31
|
"Add another subagent_spawn only for truly independent work with safe workspace concurrency.",
|
|
32
32
|
noLocalWorkGuidance,
|
|
33
33
|
'Consume and synthesize available subagent_spawn completion messages; use subagent_manage with action "interrupt" or "close" for agents that are no longer needed.',
|
|
34
|
-
'Completion from subagent_spawn is delivered automatically. Do not poll with
|
|
34
|
+
'Completion from subagent_spawn is delivered automatically. Do not poll with subagent_inspect or subagent_mailbox action "read", repeatedly check progress, or duplicate the delegated work.',
|
|
35
35
|
];
|
|
36
36
|
}
|
package/src/stateful-limits.ts
CHANGED
package/src/stateful-prompt.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { AgentConfig } from "./agents.js";
|
|
1
|
+
import type { AgentConfig } from "./agents/types.js";
|
|
2
2
|
import { redactPrivateText } from "./context.js";
|
|
3
3
|
import { appendDelegationContract } from "./delegation-contract.js";
|
|
4
|
-
import { resolveDefaultSubagentTimeoutMs } from "./execution.js";
|
|
4
|
+
import { resolveDefaultSubagentTimeoutMs } from "./execution/runtime-policy.js";
|
|
5
5
|
import { DEFAULT_MAX_CONTEXT_BYTES, truncateUtf8 } from "./limits.js";
|
|
6
6
|
import type { ManagedAgent } from "./registry.js";
|
|
7
7
|
import { appendResultInstruction } from "./result-contract.js";
|