@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/panel-execution.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentToolResult, AgentToolUpdateCallback } from "@earendil-works/pi-agent-core";
|
|
2
2
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
import type { AgentConfig, AgentScope, SubagentThinkingLevel } from "./agents.js";
|
|
3
|
+
import type { AgentConfig, AgentScope, SubagentThinkingLevel } from "./agents/types.js";
|
|
4
4
|
import { panelReviewStatus, panelSynthesisStatus, startSubagentStatus } from "./blocking-status.js";
|
|
5
5
|
import { issueCapabilityGrant, revokeCapabilityGrant } from "./capability-grant.js";
|
|
6
6
|
import type { ResolvedSubagentTarget } from "./cwd-policy.js";
|
package/src/panel-planning.ts
CHANGED
package/src/params.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { StringEnum } from "@earendil-works/pi-ai";
|
|
2
2
|
import { type Static, Type } from "typebox";
|
|
3
|
-
import { THINKING_LEVELS } from "./agents.js";
|
|
3
|
+
import { THINKING_LEVELS } from "./agents/types.js";
|
|
4
4
|
import { DelegationContractSchema } from "./delegation-contract.js";
|
|
5
5
|
import { MAX_CONFIGURABLE_PARALLEL_TASKS, MAX_SUBAGENT_TIMEOUT_MS } from "./limits.js";
|
|
6
6
|
import { PANEL_PRESETS } from "./panel-planning.js";
|
|
7
7
|
import { SUBAGENT_RESULT_FORMATS } from "./result-contract.js";
|
|
8
8
|
import { MAX_SUBAGENT_TOOL_CALLS, MAX_SUBAGENT_TURNS } from "./turn-budget.js";
|
|
9
|
+
import { VerifiedExecutionContractSchema } from "./verified-execution-contract.js";
|
|
9
10
|
|
|
10
11
|
const TimeoutMs = Type.Number({
|
|
11
12
|
description:
|
|
@@ -221,6 +222,7 @@ export const SubagentParams = Type.Object({
|
|
|
221
222
|
Type.Object(
|
|
222
223
|
{
|
|
223
224
|
id: Type.Optional(Type.String({ minLength: 1, maxLength: 256 })),
|
|
225
|
+
verifiedExecution: Type.Optional(VerifiedExecutionContractSchema),
|
|
224
226
|
honorAdmission: Type.Optional(
|
|
225
227
|
Type.Boolean({
|
|
226
228
|
description:
|
package/src/persistence.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { getAgentDir, withFileMutationQueue } from "@earendil-works/pi-coding-agent";
|
|
5
5
|
import { projectAgentRecords } from "./agent-projection.js";
|
|
6
|
-
import { isThinkingLevel } from "./agents.js";
|
|
6
|
+
import { isThinkingLevel } from "./agents/types.js";
|
|
7
7
|
import { isCapabilityGrant, revokeCapabilityGrant } from "./capability-grant.js";
|
|
8
8
|
import { redactPrivateText } from "./context.js";
|
|
9
9
|
import { normalizeDelegationContract } from "./delegation-contract.js";
|
|
@@ -16,12 +16,13 @@ import { resolveStatefulLimits } from "./stateful-limits.js";
|
|
|
16
16
|
import { copyTurnTerminationReport, type TurnTerminationReport } from "./timeout-checkpoint.js";
|
|
17
17
|
import { MAX_SUBAGENT_TOOL_CALLS, MAX_SUBAGENT_TURNS } from "./turn-budget.js";
|
|
18
18
|
|
|
19
|
-
const STATE_VERSION =
|
|
19
|
+
const STATE_VERSION = 3;
|
|
20
|
+
const MAX_STORED_COMPLETIONS_PER_AGENT = 20;
|
|
20
21
|
const DEFAULT_STATEFUL_LIMITS = resolveStatefulLimits();
|
|
21
|
-
const MAX_STATE_BYTES = 1024 * 1024;
|
|
22
|
+
const MAX_STATE_BYTES = 5 * 1024 * 1024;
|
|
22
23
|
|
|
23
24
|
interface StoredState {
|
|
24
|
-
version:
|
|
25
|
+
version: 3;
|
|
25
26
|
updatedAt: number;
|
|
26
27
|
agents: ManagedAgent[];
|
|
27
28
|
}
|
|
@@ -86,8 +87,19 @@ export class AgentPersistence {
|
|
|
86
87
|
const state: StoredState = { version: STATE_VERSION, updatedAt: Date.now(), agents: records };
|
|
87
88
|
let content = `${JSON.stringify(state, null, "\t")}\n`;
|
|
88
89
|
while (Buffer.byteLength(content, "utf8") > MAX_STATE_BYTES && state.agents.length > 0) {
|
|
89
|
-
const
|
|
90
|
-
|
|
90
|
+
const rootsWithPendingCompletions = new Set(
|
|
91
|
+
state.agents
|
|
92
|
+
.filter((agent) => (agent.pendingCompletions?.length ?? 0) > 0)
|
|
93
|
+
.map((agent) => agent.rootId),
|
|
94
|
+
);
|
|
95
|
+
const droppableRoot = state.agents.find(
|
|
96
|
+
(agent) => !rootsWithPendingCompletions.has(agent.rootId),
|
|
97
|
+
)?.rootId;
|
|
98
|
+
if (droppableRoot) {
|
|
99
|
+
state.agents = state.agents.filter((agent) => agent.rootId !== droppableRoot);
|
|
100
|
+
} else if (!trimOldestHistory(state.agents) && !clearOldestContext(state.agents)) {
|
|
101
|
+
throw new Error("Subagent state exceeds its durable completion storage limit");
|
|
102
|
+
}
|
|
91
103
|
content = `${JSON.stringify(state, null, "\t")}\n`;
|
|
92
104
|
}
|
|
93
105
|
await fs.promises.mkdir(path.dirname(this.filePath), { recursive: true });
|
|
@@ -113,6 +125,27 @@ export class AgentPersistence {
|
|
|
113
125
|
}
|
|
114
126
|
}
|
|
115
127
|
|
|
128
|
+
function trimOldestHistory(agents: ManagedAgent[]): boolean {
|
|
129
|
+
const candidate = agents
|
|
130
|
+
.filter((agent) => agent.history.length > 0)
|
|
131
|
+
.sort(
|
|
132
|
+
(left, right) =>
|
|
133
|
+
(left.history[0]?.completedAt ?? Number.POSITIVE_INFINITY) -
|
|
134
|
+
(right.history[0]?.completedAt ?? Number.POSITIVE_INFINITY),
|
|
135
|
+
)[0];
|
|
136
|
+
if (!candidate) return false;
|
|
137
|
+
candidate.history.shift();
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function clearOldestContext(agents: ManagedAgent[]): boolean {
|
|
142
|
+
const candidate = agents.find((agent) => agent.context !== undefined);
|
|
143
|
+
if (!candidate) return false;
|
|
144
|
+
candidate.context = undefined;
|
|
145
|
+
candidate.contextTruncated = true;
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
116
149
|
function sanitizeAgent(agent: ManagedAgent): ManagedAgent {
|
|
117
150
|
return {
|
|
118
151
|
...agent,
|
|
@@ -126,6 +159,17 @@ function sanitizeAgent(agent: ManagedAgent): ManagedAgent {
|
|
|
126
159
|
})),
|
|
127
160
|
state: agent.state === "running" || agent.state === "starting" ? "interrupted" : agent.state,
|
|
128
161
|
currentTask: undefined,
|
|
162
|
+
currentRunId: undefined,
|
|
163
|
+
currentTurnGeneration: undefined,
|
|
164
|
+
turnGeneration: agent.turnGeneration ?? 0,
|
|
165
|
+
pendingCompletions: (agent.pendingCompletions ?? [])
|
|
166
|
+
.slice(-MAX_STORED_COMPLETIONS_PER_AGENT)
|
|
167
|
+
.map((completion) => ({
|
|
168
|
+
...completion,
|
|
169
|
+
task: redactPrivateText(completion.task),
|
|
170
|
+
output: redactPrivateText(completion.output),
|
|
171
|
+
error: completion.error ? redactPrivateText(completion.error) : undefined,
|
|
172
|
+
})),
|
|
129
173
|
currentTimeoutMs: undefined,
|
|
130
174
|
currentIdleTimeoutMs: undefined,
|
|
131
175
|
currentMaxTurns: undefined,
|
|
@@ -184,7 +228,10 @@ function sanitizeTermination(report: TurnTerminationReport): TurnTerminationRepo
|
|
|
184
228
|
function isStoredState(value: unknown): value is StoredState {
|
|
185
229
|
if (!value || typeof value !== "object") return false;
|
|
186
230
|
const state = value as { version?: unknown; agents?: unknown };
|
|
187
|
-
if (
|
|
231
|
+
if (
|
|
232
|
+
(state.version !== 1 && state.version !== 2 && state.version !== STATE_VERSION) ||
|
|
233
|
+
!Array.isArray(state.agents)
|
|
234
|
+
) {
|
|
188
235
|
return false;
|
|
189
236
|
}
|
|
190
237
|
return state.agents.every((agent) => {
|
|
@@ -208,6 +255,9 @@ function isStoredState(value: unknown): value is StoredState {
|
|
|
208
255
|
(record.termination === undefined || isTerminationReport(record.termination)) &&
|
|
209
256
|
(record.contextTurns === undefined || isNonNegativeInteger(record.contextTurns)) &&
|
|
210
257
|
(record.contextBytes === undefined || isNonNegativeInteger(record.contextBytes)) &&
|
|
258
|
+
(record.turnGeneration === undefined || isNonNegativeInteger(record.turnGeneration)) &&
|
|
259
|
+
(record.pendingCompletions === undefined ||
|
|
260
|
+
isCompletionOutbox(record.pendingCompletions, record.turnGeneration ?? 0)) &&
|
|
211
261
|
(record.spawnIdempotencyKey === undefined ||
|
|
212
262
|
(typeof record.spawnIdempotencyKey === "string" &&
|
|
213
263
|
record.spawnIdempotencyKey.length > 0 &&
|
|
@@ -356,10 +406,59 @@ function isTargetPolicyAudit(value: unknown): boolean {
|
|
|
356
406
|
);
|
|
357
407
|
}
|
|
358
408
|
|
|
409
|
+
function isCompletionOutbox(value: unknown, turnGeneration: number): boolean {
|
|
410
|
+
if (!Array.isArray(value) || value.length > MAX_STORED_COMPLETIONS_PER_AGENT) return false;
|
|
411
|
+
const ids = new Set<string>();
|
|
412
|
+
let previousGeneration = 0;
|
|
413
|
+
let previousCreatedAt = Number.NEGATIVE_INFINITY;
|
|
414
|
+
for (const completion of value) {
|
|
415
|
+
if (!isPersistedCompletion(completion, turnGeneration)) return false;
|
|
416
|
+
if (ids.has(completion.completionId)) return false;
|
|
417
|
+
if (completion.generation <= previousGeneration || completion.createdAt <= previousCreatedAt) {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
ids.add(completion.completionId);
|
|
421
|
+
previousGeneration = completion.generation;
|
|
422
|
+
previousCreatedAt = completion.createdAt;
|
|
423
|
+
}
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function isPersistedCompletion(
|
|
428
|
+
value: unknown,
|
|
429
|
+
turnGeneration: number,
|
|
430
|
+
): value is import("./registry.js").PersistedAgentCompletion {
|
|
431
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
432
|
+
const completion = value as Record<string, unknown>;
|
|
433
|
+
return (
|
|
434
|
+
typeof completion.completionId === "string" &&
|
|
435
|
+
completion.completionId.length > 0 &&
|
|
436
|
+
completion.completionId.length <= 256 &&
|
|
437
|
+
typeof completion.runId === "string" &&
|
|
438
|
+
completion.runId.length > 0 &&
|
|
439
|
+
completion.runId.length <= 256 &&
|
|
440
|
+
typeof completion.generation === "number" &&
|
|
441
|
+
Number.isSafeInteger(completion.generation) &&
|
|
442
|
+
completion.generation >= 1 &&
|
|
443
|
+
completion.generation <= turnGeneration &&
|
|
444
|
+
typeof completion.task === "string" &&
|
|
445
|
+
typeof completion.output === "string" &&
|
|
446
|
+
(completion.error === undefined || typeof completion.error === "string") &&
|
|
447
|
+
typeof completion.createdAt === "number" &&
|
|
448
|
+
Number.isFinite(completion.createdAt)
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
|
|
359
452
|
function isAgentTurn(value: unknown): boolean {
|
|
360
453
|
if (!value || typeof value !== "object") return false;
|
|
361
454
|
const turn = value as Record<string, unknown>;
|
|
362
455
|
return (
|
|
456
|
+
(turn.runId === undefined ||
|
|
457
|
+
(typeof turn.runId === "string" && turn.runId.length > 0 && turn.runId.length <= 256)) &&
|
|
458
|
+
(turn.generation === undefined ||
|
|
459
|
+
(typeof turn.generation === "number" &&
|
|
460
|
+
Number.isSafeInteger(turn.generation) &&
|
|
461
|
+
turn.generation >= 1)) &&
|
|
363
462
|
typeof turn.task === "string" &&
|
|
364
463
|
typeof turn.output === "string" &&
|
|
365
464
|
typeof turn.startedAt === "number" &&
|
package/src/registry-types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SubagentThinkingLevel } from "./agents.js";
|
|
1
|
+
import type { SubagentThinkingLevel } from "./agents/types.js";
|
|
2
2
|
import type { CapabilityGrant } from "./capability-grant.js";
|
|
3
3
|
import type { TargetPolicyAudit } from "./cwd-policy.js";
|
|
4
4
|
import type { DelegationContract } from "./delegation-contract.js";
|
|
@@ -23,6 +23,8 @@ export type AgentLifecycleState =
|
|
|
23
23
|
| "closed";
|
|
24
24
|
|
|
25
25
|
export interface AgentTurn {
|
|
26
|
+
runId?: string;
|
|
27
|
+
generation?: number;
|
|
26
28
|
task: string;
|
|
27
29
|
output: string;
|
|
28
30
|
startedAt: number;
|
|
@@ -32,6 +34,16 @@ export interface AgentTurn {
|
|
|
32
34
|
termination?: TurnTerminationReport;
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
export interface PersistedAgentCompletion {
|
|
38
|
+
completionId: string;
|
|
39
|
+
runId: string;
|
|
40
|
+
generation: number;
|
|
41
|
+
task: string;
|
|
42
|
+
output: string;
|
|
43
|
+
error?: string;
|
|
44
|
+
createdAt: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
35
47
|
export interface AgentMailboxMessage {
|
|
36
48
|
id: string;
|
|
37
49
|
senderId: string;
|
|
@@ -64,6 +76,10 @@ export interface ManagedAgent {
|
|
|
64
76
|
maxToolCalls?: number;
|
|
65
77
|
currentMaxToolCalls?: number;
|
|
66
78
|
currentTask?: string;
|
|
79
|
+
turnGeneration?: number;
|
|
80
|
+
currentRunId?: string;
|
|
81
|
+
currentTurnGeneration?: number;
|
|
82
|
+
pendingCompletions?: PersistedAgentCompletion[];
|
|
67
83
|
history: AgentTurn[];
|
|
68
84
|
error?: string;
|
|
69
85
|
context?: string;
|
|
@@ -98,6 +114,8 @@ export interface AgentRunInspectionSummary {
|
|
|
98
114
|
updatedAt: number;
|
|
99
115
|
historyCount: number;
|
|
100
116
|
unreadMessages: number;
|
|
117
|
+
turnGeneration: number;
|
|
118
|
+
pendingCompletionCount: number;
|
|
101
119
|
}
|
|
102
120
|
|
|
103
121
|
export interface AgentRunInspectionDetail extends AgentRunInspectionSummary {
|
|
@@ -112,6 +130,8 @@ export interface AgentRunInspectionDetail extends AgentRunInspectionSummary {
|
|
|
112
130
|
maxToolCalls?: number;
|
|
113
131
|
currentMaxToolCalls?: number;
|
|
114
132
|
currentTask?: string;
|
|
133
|
+
currentRunId?: string;
|
|
134
|
+
currentTurnGeneration?: number;
|
|
115
135
|
error?: string;
|
|
116
136
|
workspaceMode?: "worktree";
|
|
117
137
|
contextTurns?: number;
|
|
@@ -151,11 +171,8 @@ export interface TurnOutcome {
|
|
|
151
171
|
telemetry?: TransportTelemetry;
|
|
152
172
|
}
|
|
153
173
|
|
|
154
|
-
export interface AgentTurnCompletion {
|
|
174
|
+
export interface AgentTurnCompletion extends PersistedAgentCompletion {
|
|
155
175
|
agent: ManagedAgent;
|
|
156
|
-
task: string;
|
|
157
|
-
output: string;
|
|
158
|
-
error?: string;
|
|
159
176
|
}
|
|
160
177
|
|
|
161
178
|
export interface AgentRegistryOptions {
|