@narumitw/pi-subagents 2.0.6 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +171 -60
- package/dist/chunks/{auto-transport-SY2VHUFH.ts → auto-transport-FUUKFDIG.ts} +6 -6
- package/dist/chunks/{capability-grant-CGEWOEKE.ts → capability-grant-PR72SWWS.ts} +4 -4
- package/dist/chunks/{chunk-CBP76ARQ.ts → chunk-2LMJU25E.ts} +172 -74
- package/dist/chunks/chunk-2LMJU25E.ts.map +7 -0
- package/dist/chunks/{chunk-DPPVEQAM.ts → chunk-4AQSF7AS.ts} +1 -1
- package/dist/chunks/chunk-4AQSF7AS.ts.map +7 -0
- package/dist/chunks/chunk-6H6TBBED.ts +108 -0
- package/dist/chunks/chunk-6H6TBBED.ts.map +7 -0
- package/dist/chunks/{chunk-YBUWBRF7.ts → chunk-6NSJVPXX.ts} +6 -16
- package/dist/chunks/{chunk-YBUWBRF7.ts.map → chunk-6NSJVPXX.ts.map} +2 -2
- package/dist/chunks/{chunk-DSOOH73Y.ts → chunk-7AAJEUSL.ts} +3 -3
- package/dist/chunks/{chunk-DSOOH73Y.ts.map → chunk-7AAJEUSL.ts.map} +2 -2
- package/dist/chunks/{chunk-7QPPBBXZ.ts → chunk-D4CR7T73.ts} +21 -3
- package/dist/chunks/chunk-D4CR7T73.ts.map +7 -0
- package/dist/chunks/{chunk-NIF42QMF.ts → chunk-FEVPWRMU.ts} +7 -4
- package/dist/chunks/chunk-FEVPWRMU.ts.map +7 -0
- package/dist/chunks/{chunk-S2IWVK3J.ts → chunk-ILEQ27AL.ts} +3 -2
- package/dist/chunks/chunk-ILEQ27AL.ts.map +7 -0
- package/dist/chunks/{chunk-DQMN4OYM.ts → chunk-ITVWPNU4.ts} +12 -106
- package/dist/chunks/chunk-ITVWPNU4.ts.map +7 -0
- package/dist/chunks/{chunk-QDVGH2X7.ts → chunk-IWC32VPY.ts} +2 -1
- package/dist/chunks/{chunk-QDVGH2X7.ts.map → chunk-IWC32VPY.ts.map} +2 -2
- package/dist/chunks/{chunk-I2FAK44T.ts → chunk-JSZIP73U.ts} +48 -10
- package/dist/chunks/chunk-JSZIP73U.ts.map +7 -0
- package/dist/chunks/{chunk-ZHTNCZIA.ts → chunk-JU6LUNLP.ts} +2 -2
- package/dist/chunks/{chunk-PSK43Y6A.ts → chunk-LASD73CM.ts} +2 -2
- package/dist/chunks/{chunk-C4L6P266.ts → chunk-LEOYDZI3.ts} +1 -1
- package/dist/chunks/{chunk-C4L6P266.ts.map → chunk-LEOYDZI3.ts.map} +2 -2
- package/dist/chunks/{chunk-H3BFJ7HJ.ts → chunk-LL4LP2T7.ts} +5 -5
- package/dist/chunks/chunk-N2T5IN4X.ts +18 -0
- package/dist/chunks/chunk-N2T5IN4X.ts.map +7 -0
- package/dist/chunks/chunk-NLT67IZS.ts +322 -0
- package/dist/chunks/chunk-NLT67IZS.ts.map +7 -0
- package/dist/chunks/{chunk-G3RSMSXJ.ts → chunk-NTRPLF46.ts} +1 -1
- package/dist/chunks/chunk-NTRPLF46.ts.map +7 -0
- package/dist/chunks/{chunk-EFBPISNT.ts → chunk-PBZMBTNJ.ts} +104 -103
- package/dist/chunks/chunk-PBZMBTNJ.ts.map +7 -0
- package/dist/chunks/{chunk-SCZ33MYW.ts → chunk-PGLSFLYW.ts} +2 -2
- package/dist/chunks/{chunk-O4VO6JUJ.ts → chunk-TM2R67J3.ts} +3 -3
- package/dist/chunks/{chunk-QBORTI4W.ts → chunk-TMZRHIIK.ts} +32 -3
- package/dist/chunks/chunk-TMZRHIIK.ts.map +7 -0
- package/dist/chunks/chunk-TZ34IQ3M.ts +59 -0
- package/dist/chunks/chunk-TZ34IQ3M.ts.map +7 -0
- package/dist/chunks/{chunk-7OBINKFM.ts → chunk-VDG7LTYE.ts} +11 -11
- package/dist/chunks/chunk-VDG7LTYE.ts.map +7 -0
- package/dist/chunks/{chunk-AEUYS7JC.ts → chunk-X4NMONPE.ts} +1 -1
- package/dist/chunks/chunk-X4NMONPE.ts.map +7 -0
- package/dist/chunks/{chunk-HKC4ES4B.ts → chunk-YPJEN6NU.ts} +2 -2
- package/dist/chunks/{chunk-434NII74.ts → chunk-YU53SHA7.ts} +54 -8
- package/dist/chunks/chunk-YU53SHA7.ts.map +7 -0
- package/dist/chunks/{completion-delivery-YPOWSSV3.ts → completion-delivery-RSJU6BXL.ts} +5 -4
- package/dist/chunks/{config-status-J4GPWP46.ts → config-status-FKGDECZ3.ts} +7 -6
- package/dist/chunks/{config-ui-2YUCUEBM.ts → config-ui-ABHYNGQ7.ts} +297 -231
- package/dist/chunks/config-ui-ABHYNGQ7.ts.map +7 -0
- package/dist/chunks/{consult-IV7UBNQQ.ts → consult-LJU3IQY5.ts} +14 -13
- package/dist/chunks/consult-LJU3IQY5.ts.map +7 -0
- package/dist/chunks/{create-stateful-transport-ZP3IXNV3.ts → create-stateful-transport-JWC2EFYL.ts} +6 -6
- package/dist/chunks/{delegation-contract-WJPT4FVS.ts → delegation-contract-LA56I5DT.ts} +2 -2
- package/dist/chunks/{discovery-K25T3SH4.ts → discovery-MIFB2U4Y.ts} +3 -3
- package/dist/chunks/{execution-LA7HN5YF.ts → execution-Q2JZLKJA.ts} +19 -16
- package/dist/chunks/execution-Q2JZLKJA.ts.map +7 -0
- package/dist/chunks/{in-process-transport-4RF3J6XK.ts → in-process-transport-HJ6TZXC3.ts} +9 -9
- package/dist/chunks/{inspect-XV2QALMR.ts → inspect-UH2TKH6E.ts} +25 -10
- package/dist/chunks/inspect-UH2TKH6E.ts.map +7 -0
- package/dist/chunks/{persistence-VSGXAW4P.ts → persistence-UY3PY6E5.ts} +11 -7
- package/dist/chunks/persistence-UY3PY6E5.ts.map +7 -0
- package/dist/chunks/{registry-E6XPJB7L.ts → registry-BT54L6CY.ts} +136 -15
- package/dist/chunks/registry-BT54L6CY.ts.map +7 -0
- package/dist/chunks/{retained-semantic-state-7WXSGRJU.ts → retained-semantic-state-GM75FZGE.ts} +3 -3
- package/dist/chunks/{rpc-transport-NEHBHWX4.ts → rpc-transport-7R7DVCEB.ts} +12 -16
- package/dist/chunks/rpc-transport-7R7DVCEB.ts.map +7 -0
- package/dist/chunks/{spawn-idempotency-QGHO2WKC.ts → spawn-idempotency-BNHOSMZW.ts} +2 -2
- package/dist/chunks/{subprocess-transport-NSHOGDC4.ts → subprocess-transport-VHZJRBTW.ts} +15 -14
- package/dist/chunks/subprocess-transport-VHZJRBTW.ts.map +7 -0
- package/dist/chunks/usage-recording-store-CW3EH2SZ.ts +164 -0
- package/dist/chunks/usage-recording-store-CW3EH2SZ.ts.map +7 -0
- package/dist/index.ts +682 -82
- package/dist/index.ts.map +3 -3
- package/docs/async-runtime-protocol.md +83 -0
- package/docs/implementation-notes/pi-subagents-capability-matrix.md +62 -0
- package/docs/implementation-notes/pi-subagents-current-direction.md +99 -0
- package/docs/implementation-notes/pi-subagents-rpc-v1.md +153 -0
- package/docs/pi-subagents-diagrams.md +183 -0
- package/package.json +9 -8
- package/src/agents/types.ts +2 -0
- package/src/async-subagent-benchmark.ts +532 -0
- package/src/completion-delivery.ts +71 -4
- package/src/completion-render.ts +1 -0
- package/src/completion-requirement.ts +479 -0
- package/src/config-registration.ts +5 -5
- package/src/config-status.ts +66 -70
- package/src/config-ui.ts +244 -150
- package/src/consult-registration.ts +4 -12
- package/src/consult-resources.ts +1 -1
- package/src/consult.ts +3 -8
- package/src/delegation-contract.ts +55 -9
- package/src/execution-plan.ts +1 -1
- package/src/execution-ui.ts +40 -29
- package/src/execution.ts +2 -3
- package/src/inspect.ts +24 -1
- package/src/orchestration-metrics.ts +1 -1
- package/src/panel-execution.ts +2 -3
- package/src/panel-failure.ts +1 -1
- package/src/panel-render.ts +1 -1
- package/src/parallel-limit-ui.ts +6 -5
- package/src/params.ts +2 -1
- package/src/persistence.ts +9 -0
- package/src/process-control.ts +43 -0
- package/src/registry-types.ts +5 -0
- package/src/registry.ts +162 -18
- package/src/render.ts +2 -1
- package/src/rpc-transport.ts +1 -1
- package/src/runner-outcome.ts +1 -1
- package/src/runner-result.ts +1 -1
- package/src/runner-types.ts +102 -0
- package/src/runner.ts +11 -192
- package/src/session-guidance-contract.ts +309 -0
- package/src/settings/inspection.ts +27 -0
- package/src/settings/schema.ts +9 -0
- package/src/settings-reader.ts +7 -0
- package/src/settings.ts +20 -0
- package/src/spawn-idempotency.ts +5 -0
- package/src/stateful-agent-view.ts +15 -19
- package/src/stateful-guidance.ts +11 -18
- package/src/stateful-limit-ui.ts +23 -20
- package/src/stateful-limits.ts +10 -10
- package/src/stateful-registration.ts +126 -36
- package/src/stateful-render.ts +27 -2
- package/src/subagent-details.ts +43 -0
- package/src/subagents-extension.ts +116 -68
- package/src/subagents.ts +2 -0
- package/src/subprocess-transport.ts +2 -1
- package/src/supervision.ts +2 -1
- package/src/timeout-finalization.ts +1 -1
- package/src/tool-schema-compatibility.ts +73 -0
- package/src/transport-types.ts +6 -0
- package/src/transport-ui.ts +18 -46
- package/src/usage-recording-config.ts +13 -0
- package/src/usage-recording-store.ts +183 -0
- package/src/usage-recording.ts +478 -0
- package/src/verification-harness.ts +1 -1
- package/src/workflow-ui.ts +17 -9
- package/dist/chunks/chunk-434NII74.ts.map +0 -7
- package/dist/chunks/chunk-7OBINKFM.ts.map +0 -7
- package/dist/chunks/chunk-7QPPBBXZ.ts.map +0 -7
- package/dist/chunks/chunk-AEUYS7JC.ts.map +0 -7
- package/dist/chunks/chunk-CBP76ARQ.ts.map +0 -7
- package/dist/chunks/chunk-DPPVEQAM.ts.map +0 -7
- package/dist/chunks/chunk-DQMN4OYM.ts.map +0 -7
- package/dist/chunks/chunk-EFBPISNT.ts.map +0 -7
- package/dist/chunks/chunk-G3RSMSXJ.ts.map +0 -7
- package/dist/chunks/chunk-I2FAK44T.ts.map +0 -7
- package/dist/chunks/chunk-NIF42QMF.ts.map +0 -7
- package/dist/chunks/chunk-QBORTI4W.ts.map +0 -7
- package/dist/chunks/chunk-S2IWVK3J.ts.map +0 -7
- package/dist/chunks/config-ui-2YUCUEBM.ts.map +0 -7
- package/dist/chunks/consult-IV7UBNQQ.ts.map +0 -7
- package/dist/chunks/execution-LA7HN5YF.ts.map +0 -7
- package/dist/chunks/inspect-XV2QALMR.ts.map +0 -7
- package/dist/chunks/persistence-VSGXAW4P.ts.map +0 -7
- package/dist/chunks/registry-E6XPJB7L.ts.map +0 -7
- package/dist/chunks/rpc-transport-NEHBHWX4.ts.map +0 -7
- package/dist/chunks/subprocess-transport-NSHOGDC4.ts.map +0 -7
- /package/dist/chunks/{auto-transport-SY2VHUFH.ts.map → auto-transport-FUUKFDIG.ts.map} +0 -0
- /package/dist/chunks/{capability-grant-CGEWOEKE.ts.map → capability-grant-PR72SWWS.ts.map} +0 -0
- /package/dist/chunks/{chunk-ZHTNCZIA.ts.map → chunk-JU6LUNLP.ts.map} +0 -0
- /package/dist/chunks/{chunk-PSK43Y6A.ts.map → chunk-LASD73CM.ts.map} +0 -0
- /package/dist/chunks/{chunk-H3BFJ7HJ.ts.map → chunk-LL4LP2T7.ts.map} +0 -0
- /package/dist/chunks/{chunk-SCZ33MYW.ts.map → chunk-PGLSFLYW.ts.map} +0 -0
- /package/dist/chunks/{chunk-O4VO6JUJ.ts.map → chunk-TM2R67J3.ts.map} +0 -0
- /package/dist/chunks/{chunk-HKC4ES4B.ts.map → chunk-YPJEN6NU.ts.map} +0 -0
- /package/dist/chunks/{completion-delivery-YPOWSSV3.ts.map → completion-delivery-RSJU6BXL.ts.map} +0 -0
- /package/dist/chunks/{config-status-J4GPWP46.ts.map → config-status-FKGDECZ3.ts.map} +0 -0
- /package/dist/chunks/{create-stateful-transport-ZP3IXNV3.ts.map → create-stateful-transport-JWC2EFYL.ts.map} +0 -0
- /package/dist/chunks/{delegation-contract-WJPT4FVS.ts.map → delegation-contract-LA56I5DT.ts.map} +0 -0
- /package/dist/chunks/{discovery-K25T3SH4.ts.map → discovery-MIFB2U4Y.ts.map} +0 -0
- /package/dist/chunks/{in-process-transport-4RF3J6XK.ts.map → in-process-transport-HJ6TZXC3.ts.map} +0 -0
- /package/dist/chunks/{retained-semantic-state-7WXSGRJU.ts.map → retained-semantic-state-GM75FZGE.ts.map} +0 -0
- /package/dist/chunks/{spawn-idempotency-QGHO2WKC.ts.map → spawn-idempotency-BNHOSMZW.ts.map} +0 -0
|
@@ -3,10 +3,6 @@ import { cachedModuleLoader, throwIfAborted } from "./cached-module-loader.js";
|
|
|
3
3
|
import type { RegisterSubagentConsultOptions } from "./consult.js";
|
|
4
4
|
import { renderConsultCall, renderConsultResult } from "./consult-render.js";
|
|
5
5
|
import { type ConsultDetails, SubagentConsultParams } from "./consult-tool.js";
|
|
6
|
-
import {
|
|
7
|
-
DEFAULT_CONSULT_RESOURCE_POLICY,
|
|
8
|
-
DEFAULT_CONSULTATION_CWD_POLICY,
|
|
9
|
-
} from "./settings/inspection.js";
|
|
10
6
|
|
|
11
7
|
interface ConsultExecutionModule {
|
|
12
8
|
executeSubagentConsult: typeof import("./consult.js").executeSubagentConsult;
|
|
@@ -20,7 +16,7 @@ export function registerSubagentConsult(
|
|
|
20
16
|
pi: ExtensionAPI,
|
|
21
17
|
options: RegisterSubagentConsultOptions,
|
|
22
18
|
dependencies: ConsultRegistrationDependencies = {},
|
|
23
|
-
):
|
|
19
|
+
): void {
|
|
24
20
|
const loadExecution = cachedModuleLoader(
|
|
25
21
|
dependencies.loadExecution ?? (() => import("./consult.js")),
|
|
26
22
|
);
|
|
@@ -41,12 +37,12 @@ export function registerSubagentConsult(
|
|
|
41
37
|
pi.on("session_start", () => cancelAndWaitForWork("Subagent consultation session replaced"));
|
|
42
38
|
pi.on("session_shutdown", () => cancelAndWaitForWork("Subagent consultation session shut down"));
|
|
43
39
|
|
|
44
|
-
const
|
|
45
|
-
|
|
40
|
+
const description =
|
|
41
|
+
"Run one ephemeral subagent synchronously under enforced read-only tool and resource policies and return its answer. The child can use only the effective subset of Pi's built-in read, grep, find, and ls tools. Shell commands, file writes, extension tools, detached lifecycle operations, and persistent agent state are disabled. The current working-directory policy, trusted-target resource policy, and available agent definitions are published in the pi-subagents session-guidance message. Allowed targets without effective trust inherit no target or project resources. This is not a filesystem sandbox.";
|
|
46
42
|
const definition: ToolDefinition<typeof SubagentConsultParams, ConsultDetails> = {
|
|
47
43
|
name: "subagent_consult",
|
|
48
44
|
label: "Consult Read-only Subagent",
|
|
49
|
-
description
|
|
45
|
+
description,
|
|
50
46
|
promptSnippet: "Consult one constrained read-only subagent and wait for its answer",
|
|
51
47
|
promptGuidelines: [
|
|
52
48
|
"Use subagent_consult only for bounded read-only evidence gathering when an independent perspective is worth making the main agent wait.",
|
|
@@ -103,10 +99,6 @@ export function registerSubagentConsult(
|
|
|
103
99
|
if (event.toolName !== "subagent_consult") return;
|
|
104
100
|
if ((event.details as ConsultDetails | undefined)?.isError) return { isError: true };
|
|
105
101
|
});
|
|
106
|
-
return (catalog: string) => {
|
|
107
|
-
definition.description = catalog ? `${baseDescription()}\n\n${catalog}` : baseDescription();
|
|
108
|
-
pi.registerTool<typeof SubagentConsultParams, ConsultDetails>(definition);
|
|
109
|
-
};
|
|
110
102
|
}
|
|
111
103
|
|
|
112
104
|
function combineAbortSignals(
|
package/src/consult-resources.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ConsultResourcePolicy } from "./agents/types.js";
|
|
2
2
|
import { DEFAULT_MAX_CONTEXT_BYTES, truncateUtf8 } from "./limits.js";
|
|
3
3
|
import { resolvePiPromptResources } from "./prompt-resources.js";
|
|
4
|
-
import type { ChildLaunchPolicy } from "./runner.js";
|
|
4
|
+
import type { ChildLaunchPolicy } from "./runner-types.js";
|
|
5
5
|
|
|
6
6
|
const MINIMAL_CONSULT_SYSTEM_PROMPT =
|
|
7
7
|
"You are a read-only consultation assistant. Analyze the delegated task using only executor-provided capabilities and return a grounded answer.";
|
package/src/consult.ts
CHANGED
|
@@ -34,20 +34,15 @@ import {
|
|
|
34
34
|
DEFAULT_MAX_STDERR_BYTES,
|
|
35
35
|
MAX_SUBAGENT_TIMEOUT_MS,
|
|
36
36
|
} from "./limits.js";
|
|
37
|
-
import {
|
|
38
|
-
|
|
39
|
-
getResultFinalOutput,
|
|
40
|
-
isResultError,
|
|
41
|
-
runSingleAgent,
|
|
42
|
-
type SingleResult,
|
|
43
|
-
type SubagentDetails,
|
|
44
|
-
} from "./runner.js";
|
|
37
|
+
import { getResultFinalOutput, isResultError, runSingleAgent } from "./runner.js";
|
|
38
|
+
import type { ChildLaunchPolicy, SingleResult } from "./runner-types.js";
|
|
45
39
|
import { boundedPrivateText, boundText, safeDisplayPath, safeTerminalLine } from "./safe-text.js";
|
|
46
40
|
import {
|
|
47
41
|
DEFAULT_CONSULT_RESOURCE_POLICY,
|
|
48
42
|
DEFAULT_CONSULTATION_CWD_POLICY,
|
|
49
43
|
} from "./settings/inspection.js";
|
|
50
44
|
import { resolveSubagentThinkingLevel } from "./settings.js";
|
|
45
|
+
import type { SubagentDetails } from "./subagent-details.js";
|
|
51
46
|
|
|
52
47
|
export { registerSubagentConsult } from "./consult-registration.js";
|
|
53
48
|
export type {
|
|
@@ -39,14 +39,51 @@ export const DelegationContractSchema = Type.Object(
|
|
|
39
39
|
requestedAuthority: Type.Optional(
|
|
40
40
|
Type.Object(
|
|
41
41
|
{
|
|
42
|
-
capabilities: Type.Optional(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
capabilities: Type.Optional(
|
|
43
|
+
Type.Array(BoundedItem, {
|
|
44
|
+
maxItems: MAX_ITEMS,
|
|
45
|
+
description: "Capabilities requested from the selected agent manifest.",
|
|
46
|
+
}),
|
|
47
|
+
),
|
|
48
|
+
tools: Type.Optional(
|
|
49
|
+
Type.Array(BoundedItem, {
|
|
50
|
+
maxItems: MAX_ITEMS,
|
|
51
|
+
description:
|
|
52
|
+
"Tools that enforcement may narrow to the selected agent's available set.",
|
|
53
|
+
}),
|
|
54
|
+
),
|
|
55
|
+
readPaths: Type.Optional(
|
|
56
|
+
Type.Array(BoundedItem, {
|
|
57
|
+
maxItems: MAX_ITEMS,
|
|
58
|
+
description:
|
|
59
|
+
'Audit metadata only; enforcement "enforce" rejects non-empty readPaths because path scope is unsupported.',
|
|
60
|
+
}),
|
|
61
|
+
),
|
|
62
|
+
writePaths: Type.Optional(
|
|
63
|
+
Type.Array(BoundedItem, {
|
|
64
|
+
maxItems: MAX_ITEMS,
|
|
65
|
+
description:
|
|
66
|
+
'Audit metadata only; enforcement "enforce" rejects non-empty writePaths because path scope is unsupported.',
|
|
67
|
+
}),
|
|
68
|
+
),
|
|
69
|
+
network: Type.Optional(
|
|
70
|
+
StringEnum(AUTHORITY_REQUIREMENTS, {
|
|
71
|
+
description:
|
|
72
|
+
'Audit metadata only; enforcement "enforce" rejects denied or required network guarantees as unsupported.',
|
|
73
|
+
}),
|
|
74
|
+
),
|
|
75
|
+
secrets: Type.Optional(
|
|
76
|
+
StringEnum(AUTHORITY_REQUIREMENTS, {
|
|
77
|
+
description:
|
|
78
|
+
'Audit metadata only; enforcement "enforce" rejects denied or required secret guarantees as unsupported.',
|
|
79
|
+
}),
|
|
80
|
+
),
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
additionalProperties: false,
|
|
84
|
+
description:
|
|
85
|
+
"Only capabilities and tools have executor enforcement; readPaths, writePaths, network, and secrets are unsupported guarantees.",
|
|
48
86
|
},
|
|
49
|
-
{ additionalProperties: false },
|
|
50
87
|
),
|
|
51
88
|
),
|
|
52
89
|
acceptanceCriteria: Type.Optional(BoundedItems),
|
|
@@ -76,9 +113,18 @@ export const DelegationContractSchema = Type.Object(
|
|
|
76
113
|
),
|
|
77
114
|
),
|
|
78
115
|
sideEffectPolicy: Type.Optional(StringEnum(DELEGATION_SIDE_EFFECT_POLICIES)),
|
|
79
|
-
enforcement: Type.Optional(
|
|
116
|
+
enforcement: Type.Optional(
|
|
117
|
+
StringEnum(DELEGATION_ENFORCEMENT_MODES, {
|
|
118
|
+
description:
|
|
119
|
+
"Defaults to audit; enforce rejects unsupported requestedAuthority guarantees before child launch.",
|
|
120
|
+
}),
|
|
121
|
+
),
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
additionalProperties: false,
|
|
125
|
+
description:
|
|
126
|
+
"Advanced delegation contract. For ordinary delegation omit this object; use it only for explicit acceptance, authority, evidence, or admission semantics.",
|
|
80
127
|
},
|
|
81
|
-
{ additionalProperties: false },
|
|
82
128
|
);
|
|
83
129
|
|
|
84
130
|
export interface DelegationDependency {
|
package/src/execution-plan.ts
CHANGED
|
@@ -201,7 +201,7 @@ export function acknowledgeExecutionPlan(plan: ExecutionPlan): ExecutionAcknowle
|
|
|
201
201
|
}
|
|
202
202
|
if (plan.unsupportedGuarantees.length > 0) {
|
|
203
203
|
reasonCodes.push("unsupported-guarantee");
|
|
204
|
-
recoveryActions.push("stop");
|
|
204
|
+
recoveryActions.push("repair-contract", "stop");
|
|
205
205
|
}
|
|
206
206
|
return {
|
|
207
207
|
version: EXECUTION_ACKNOWLEDGEMENT_VERSION,
|
package/src/execution-ui.ts
CHANGED
|
@@ -8,8 +8,8 @@ export function executionAgentPickerScreen(agents: readonly AgentConfig[]) {
|
|
|
8
8
|
const configured = readSubagentSettings()?.agents ?? {};
|
|
9
9
|
return {
|
|
10
10
|
kind: "actions" as const,
|
|
11
|
-
title: "
|
|
12
|
-
lines: ["Choose
|
|
11
|
+
title: "Model, Thinking, and Time Limit",
|
|
12
|
+
lines: ["Choose a subagent. A specific request can override these starting values."],
|
|
13
13
|
items: [
|
|
14
14
|
...agents.map((agent) => {
|
|
15
15
|
const value = configured[agent.name];
|
|
@@ -17,7 +17,7 @@ export function executionAgentPickerScreen(agents: readonly AgentConfig[]) {
|
|
|
17
17
|
id: agent.name,
|
|
18
18
|
label: safeTerminalText(agent.name),
|
|
19
19
|
description: safeTerminalText(
|
|
20
|
-
`${agent.source} · model ${value?.model ?? agent.model ?? "
|
|
20
|
+
`${agent.source} · model ${value?.model ?? agent.model ?? "default"} · thinking ${value?.thinkingLevel ?? agent.thinkingLevel ?? "default"} · time limit ${value?.timeoutMs ?? agent.timeoutMs ?? "default"}`,
|
|
21
21
|
),
|
|
22
22
|
action: "pick-execution-agent" as const,
|
|
23
23
|
};
|
|
@@ -32,8 +32,8 @@ export function executionAgentScreen(agent: AgentConfig | undefined) {
|
|
|
32
32
|
if (!agent) {
|
|
33
33
|
return {
|
|
34
34
|
kind: "actions" as const,
|
|
35
|
-
title: "
|
|
36
|
-
lines: ["No
|
|
35
|
+
title: "Model, Thinking, and Time Limit",
|
|
36
|
+
lines: ["No subagent selected."],
|
|
37
37
|
items: [{ id: "back", label: "Back", action: "back" as const }],
|
|
38
38
|
hint: "back" as const,
|
|
39
39
|
};
|
|
@@ -41,21 +41,21 @@ export function executionAgentScreen(agent: AgentConfig | undefined) {
|
|
|
41
41
|
const configured = readSubagentSettings()?.agents?.[agent.name];
|
|
42
42
|
return {
|
|
43
43
|
kind: "actions" as const,
|
|
44
|
-
title: `${safeTerminalText(agent.name)}
|
|
44
|
+
title: `${safeTerminalText(agent.name)} defaults`,
|
|
45
45
|
lines: [
|
|
46
|
-
`Model: ${safeTerminalText(configured?.model ?? agent.model ?? "
|
|
47
|
-
`Thinking: ${configured?.thinkingLevel ?? agent.thinkingLevel ?? "
|
|
48
|
-
`
|
|
49
|
-
"
|
|
46
|
+
`Model: ${safeTerminalText(configured?.model ?? agent.model ?? "agent or Pi default")}`,
|
|
47
|
+
`Thinking: ${configured?.thinkingLevel ?? agent.thinkingLevel ?? "agent or Pi default"}`,
|
|
48
|
+
`Time limit: ${configured?.timeoutMs ?? agent.timeoutMs ?? "agent or Pi default"}`,
|
|
49
|
+
"A specific subagent request can override these defaults.",
|
|
50
50
|
],
|
|
51
51
|
items: [
|
|
52
52
|
{ id: "thinking", label: "Thinking level", to: "execution-thinking" as const },
|
|
53
53
|
{ id: "model", label: "Model", to: "execution-model" as const },
|
|
54
|
-
{ id: "timeout", label: "
|
|
54
|
+
{ id: "timeout", label: "Time limit", to: "execution-timeout" as const },
|
|
55
55
|
{
|
|
56
56
|
id: "reset",
|
|
57
|
-
label: "
|
|
58
|
-
description: "
|
|
57
|
+
label: "Use agent or Pi defaults",
|
|
58
|
+
description: "Remove custom model, thinking, and time limit without changing tools",
|
|
59
59
|
action: "reset-agent-execution" as const,
|
|
60
60
|
},
|
|
61
61
|
{ id: "back", label: "Back", action: "back" as const },
|
|
@@ -74,9 +74,19 @@ export function executionThinkingScreen(agent: AgentConfig | undefined) {
|
|
|
74
74
|
{
|
|
75
75
|
id: "thinking",
|
|
76
76
|
label: "Default thinking level",
|
|
77
|
-
description: "
|
|
78
|
-
currentValue:
|
|
79
|
-
|
|
77
|
+
description: "A specific subagent request can override this value.",
|
|
78
|
+
currentValue:
|
|
79
|
+
configured?.thinkingLevel ?? agent.thinkingLevel ?? "Use agent or Pi default",
|
|
80
|
+
values: [
|
|
81
|
+
"Use agent or Pi default",
|
|
82
|
+
"off",
|
|
83
|
+
"minimal",
|
|
84
|
+
"low",
|
|
85
|
+
"medium",
|
|
86
|
+
"high",
|
|
87
|
+
"xhigh",
|
|
88
|
+
"max",
|
|
89
|
+
],
|
|
80
90
|
action: "set-agent-thinking" as const,
|
|
81
91
|
},
|
|
82
92
|
]
|
|
@@ -96,15 +106,15 @@ export function executionModelScreen(agent: AgentConfig | undefined, ctx: Extens
|
|
|
96
106
|
kind: "actions" as const,
|
|
97
107
|
title: agent ? `${safeTerminalText(agent.name)} model` : "Agent model",
|
|
98
108
|
lines: [
|
|
99
|
-
`Current: ${safeTerminalText(configured?.model ?? agent?.model ?? "
|
|
100
|
-
"Choose
|
|
109
|
+
`Current: ${safeTerminalText(configured?.model ?? agent?.model ?? "agent or Pi default")}`,
|
|
110
|
+
"Choose an available model or enter a custom Pi model pattern.",
|
|
101
111
|
],
|
|
102
112
|
items: agent
|
|
103
113
|
? [
|
|
104
114
|
{
|
|
105
115
|
id: "model:__inherited__",
|
|
106
|
-
label: "
|
|
107
|
-
description: "
|
|
116
|
+
label: "Use agent or Pi default",
|
|
117
|
+
description: "Remove the custom model setting",
|
|
108
118
|
action: "set-agent-model" as const,
|
|
109
119
|
},
|
|
110
120
|
...models.map((model) => ({
|
|
@@ -131,9 +141,9 @@ export function executionModelInputScreen(agent: AgentConfig | undefined) {
|
|
|
131
141
|
kind: "input" as const,
|
|
132
142
|
title: agent ? `${safeTerminalText(agent.name)} model` : "Agent model",
|
|
133
143
|
lines: [
|
|
134
|
-
`Current: ${safeTerminalText(configured?.model ?? agent?.model ?? "
|
|
144
|
+
`Current: ${safeTerminalText(configured?.model ?? agent?.model ?? "agent or Pi default")}`,
|
|
135
145
|
"Enter a Pi CLI model pattern, including an optional :thinking suffix.",
|
|
136
|
-
"Use
|
|
146
|
+
"Use agent or Pi defaults to remove this custom value.",
|
|
137
147
|
],
|
|
138
148
|
placeholder: "provider/model or model pattern",
|
|
139
149
|
action: "set-agent-model" as const,
|
|
@@ -145,13 +155,13 @@ export function executionTimeoutInputScreen(agent: AgentConfig | undefined) {
|
|
|
145
155
|
const configured = agent ? readSubagentSettings()?.agents?.[agent.name] : undefined;
|
|
146
156
|
return {
|
|
147
157
|
kind: "input" as const,
|
|
148
|
-
title: agent ? `${safeTerminalText(agent.name)}
|
|
158
|
+
title: agent ? `${safeTerminalText(agent.name)} time limit` : "Agent time limit",
|
|
149
159
|
lines: [
|
|
150
|
-
`Current: ${configured?.timeoutMs ?? agent?.timeoutMs ?? "
|
|
160
|
+
`Current: ${configured?.timeoutMs ?? agent?.timeoutMs ?? "agent or Pi default"}`,
|
|
151
161
|
`Allowed: 1-${MAX_SUBAGENT_TIMEOUT_MS} milliseconds.`,
|
|
152
|
-
"Use
|
|
162
|
+
"Use agent or Pi defaults to remove this custom value.",
|
|
153
163
|
],
|
|
154
|
-
placeholder: "
|
|
164
|
+
placeholder: "Time limit in milliseconds",
|
|
155
165
|
action: "set-agent-timeout" as const,
|
|
156
166
|
hint: "back" as const,
|
|
157
167
|
};
|
|
@@ -163,7 +173,8 @@ export function applyAgentThinking(
|
|
|
163
173
|
ctx: ExtensionCommandContext,
|
|
164
174
|
) {
|
|
165
175
|
if (!agent) return { kind: "rejected" as const };
|
|
166
|
-
const thinkingLevel =
|
|
176
|
+
const thinkingLevel =
|
|
177
|
+
value === "Use agent or Pi default" ? undefined : (value as SubagentThinkingLevel);
|
|
167
178
|
if (
|
|
168
179
|
thinkingLevel !== undefined &&
|
|
169
180
|
!["off", "minimal", "low", "medium", "high", "xhigh", "max"].includes(thinkingLevel)
|
|
@@ -196,12 +207,12 @@ export function applyAgentTimeout(
|
|
|
196
207
|
if (!agent) return { kind: "rejected" as const };
|
|
197
208
|
const normalized = value?.trim() ?? "";
|
|
198
209
|
if (!/^\d+$/u.test(normalized)) {
|
|
199
|
-
ctx.ui.notify("
|
|
210
|
+
ctx.ui.notify("Time limit must be a whole number of milliseconds.", "warning");
|
|
200
211
|
return { kind: "rejected" as const };
|
|
201
212
|
}
|
|
202
213
|
const timeoutMs = Number(normalized);
|
|
203
214
|
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > MAX_SUBAGENT_TIMEOUT_MS) {
|
|
204
|
-
ctx.ui.notify(`
|
|
215
|
+
ctx.ui.notify(`Time limit must be between 1 and ${MAX_SUBAGENT_TIMEOUT_MS}.`, "warning");
|
|
205
216
|
return { kind: "rejected" as const };
|
|
206
217
|
}
|
|
207
218
|
return saveAgentPatch(agent.name, { timeoutMs }, ctx, "timeout");
|
package/src/execution.ts
CHANGED
|
@@ -65,17 +65,16 @@ import {
|
|
|
65
65
|
getResultFinalOutput,
|
|
66
66
|
isResultError,
|
|
67
67
|
mapWithConcurrencyLimit,
|
|
68
|
-
type OnUpdateCallback,
|
|
69
68
|
runSingleAgent,
|
|
70
|
-
type SingleResult,
|
|
71
|
-
type SubagentDetails,
|
|
72
69
|
} from "./runner.js";
|
|
70
|
+
import type { SingleResult } from "./runner-types.js";
|
|
73
71
|
import { safeTerminalLine } from "./safe-text.js";
|
|
74
72
|
import {
|
|
75
73
|
DEFAULT_DELEGATION_CWD_POLICY,
|
|
76
74
|
resolveBlockingMaxParallelTasks,
|
|
77
75
|
} from "./settings/inspection.js";
|
|
78
76
|
import { readSubagentSettings, resolveSubagentThinkingLevel } from "./settings.js";
|
|
77
|
+
import type { OnUpdateCallback, SubagentDetails } from "./subagent-details.js";
|
|
79
78
|
import { isRetryableResult, runHedgedAttempt, supervisionDelay } from "./supervision.js";
|
|
80
79
|
import { TimeoutProgressJournal, TURN_TERMINATION_VERSION } from "./timeout-checkpoint.js";
|
|
81
80
|
import type { TurnLimits } from "./turn-budget.js";
|
package/src/inspect.ts
CHANGED
|
@@ -25,8 +25,10 @@ import {
|
|
|
25
25
|
inspectStatefulLimitSettings,
|
|
26
26
|
inspectStatefulTransportSettings,
|
|
27
27
|
inspectSubagentSettings,
|
|
28
|
+
inspectUsageRecordingSettings,
|
|
28
29
|
} from "./settings.js";
|
|
29
30
|
import type { StatefulSubagentRuntimeStatus } from "./stateful.js";
|
|
31
|
+
import type { UsageRecordingStatus } from "./usage-recording.js";
|
|
30
32
|
import type { WorkItemLedgerSnapshot } from "./work-item-ledger.js";
|
|
31
33
|
import { inspectSessionWorkflows } from "./work-item-persistence.js";
|
|
32
34
|
|
|
@@ -41,6 +43,7 @@ export interface SubagentInspectRuntime {
|
|
|
41
43
|
getConsultResourcePolicy(): "project-context" | "none" | "all";
|
|
42
44
|
getConsultationCwdPolicy(): ConsultationCwdPolicy;
|
|
43
45
|
getDelegationCwdPolicy(): DelegationCwdPolicy;
|
|
46
|
+
getUsageRecordingStatus?(): UsageRecordingStatus;
|
|
44
47
|
getRuntimeStatus(): StatefulSubagentRuntimeStatus;
|
|
45
48
|
listRunInspection(includeClosed?: boolean): AgentRunInspectionSummary[];
|
|
46
49
|
getRunInspection(agentId: string): AgentRunInspectionDetail | undefined;
|
|
@@ -344,6 +347,9 @@ function projectRunSummary(run: AgentRunInspectionSummary): Record<string, unkno
|
|
|
344
347
|
unreadMessages: run.unreadMessages,
|
|
345
348
|
turnGeneration: run.turnGeneration,
|
|
346
349
|
pendingCompletionCount: run.pendingCompletionCount,
|
|
350
|
+
...(run.pendingRequiredCompletionCount === undefined
|
|
351
|
+
? {}
|
|
352
|
+
: { pendingRequiredCompletionCount: run.pendingRequiredCompletionCount }),
|
|
347
353
|
};
|
|
348
354
|
}
|
|
349
355
|
|
|
@@ -379,6 +385,9 @@ function projectRun(run: AgentRunInspectionDetail, ctx: ExtensionContext): Recor
|
|
|
379
385
|
}
|
|
380
386
|
: undefined,
|
|
381
387
|
resultFormat: run.resultFormat ?? "text",
|
|
388
|
+
completionRequirements: (run.completionRequirements ?? []).map((requirement) => ({
|
|
389
|
+
...requirement,
|
|
390
|
+
})),
|
|
382
391
|
structuredResult: run.structuredResult,
|
|
383
392
|
termination: run.termination,
|
|
384
393
|
outcome: run.outcome,
|
|
@@ -577,6 +586,8 @@ function projectStatus(runtime: SubagentInspectRuntime): Record<string, unknown>
|
|
|
577
586
|
const parallelLimit = inspectBlockingParallelLimitSettings();
|
|
578
587
|
const detachedLimits = inspectStatefulLimitSettings();
|
|
579
588
|
const transport = inspectStatefulTransportSettings();
|
|
589
|
+
const usageRecording = inspectUsageRecordingSettings();
|
|
590
|
+
const usageStatus = runtime.getUsageRecordingStatus?.();
|
|
580
591
|
const configuredDetachedLimits = detachedLimits.values
|
|
581
592
|
? Object.fromEntries(
|
|
582
593
|
Object.entries(detachedLimits.values).map(([field, snapshot]) => [field, snapshot.value]),
|
|
@@ -599,6 +610,16 @@ function projectStatus(runtime: SubagentInspectRuntime): Record<string, unknown>
|
|
|
599
610
|
configuredStatefulLimitSources: configuredDetachedLimitSources,
|
|
600
611
|
configuredCompletionDelivery: completion.value,
|
|
601
612
|
configuredCompletionDeliverySource: completion.source,
|
|
613
|
+
usageRecording: usageStatus
|
|
614
|
+
? {
|
|
615
|
+
enabled: usageStatus.enabled,
|
|
616
|
+
retentionDays: usageStatus.retentionDays,
|
|
617
|
+
recordedEvents: usageStatus.recordedEvents,
|
|
618
|
+
writeFailure: usageStatus.writeFailure,
|
|
619
|
+
}
|
|
620
|
+
: { enabled: false },
|
|
621
|
+
configuredUsageRecording: usageRecording.enabled,
|
|
622
|
+
configuredUsageRecordingSource: usageRecording.source,
|
|
602
623
|
maxParallelTasks: runtime.getMaxParallelTasks(),
|
|
603
624
|
configuredMaxParallelTasks: parallelLimit.value,
|
|
604
625
|
configuredMaxParallelTasksSource: parallelLimit.source,
|
|
@@ -619,7 +640,8 @@ function projectStatus(runtime: SubagentInspectRuntime): Record<string, unknown>
|
|
|
619
640
|
completion.error ||
|
|
620
641
|
parallelLimit.error ||
|
|
621
642
|
detachedLimits.error ||
|
|
622
|
-
transport.error
|
|
643
|
+
transport.error ||
|
|
644
|
+
usageRecording.error
|
|
623
645
|
? boundedPrivateText(
|
|
624
646
|
configured.error ??
|
|
625
647
|
resources.error ??
|
|
@@ -628,6 +650,7 @@ function projectStatus(runtime: SubagentInspectRuntime): Record<string, unknown>
|
|
|
628
650
|
parallelLimit.error ??
|
|
629
651
|
detachedLimits.error ??
|
|
630
652
|
transport.error ??
|
|
653
|
+
usageRecording.error ??
|
|
631
654
|
"",
|
|
632
655
|
2 * 1024,
|
|
633
656
|
)
|
package/src/panel-execution.ts
CHANGED
|
@@ -31,15 +31,14 @@ import { buildPanelReviewerPrompt, buildPanelSynthesisPrompt } from "./panel-pro
|
|
|
31
31
|
import { reconcilePanel } from "./panel-reconciliation.js";
|
|
32
32
|
import type { SubagentParams } from "./params.js";
|
|
33
33
|
import {
|
|
34
|
-
type ChildLaunchPolicy,
|
|
35
34
|
getResultFinalOutput,
|
|
36
35
|
isResultError,
|
|
37
36
|
mapWithConcurrencyLimit,
|
|
38
37
|
runSingleAgent,
|
|
39
|
-
type SingleResult,
|
|
40
|
-
type SubagentDetails,
|
|
41
38
|
} from "./runner.js";
|
|
39
|
+
import type { ChildLaunchPolicy, SingleResult } from "./runner-types.js";
|
|
42
40
|
import { boundedPrivateText, boundText } from "./safe-text.js";
|
|
41
|
+
import type { SubagentDetails } from "./subagent-details.js";
|
|
43
42
|
import { createSessionWorkItemPersistence } from "./work-item-persistence.js";
|
|
44
43
|
import { assertWorkspaceIsolationReady } from "./workspace.js";
|
|
45
44
|
|
package/src/panel-failure.ts
CHANGED
package/src/panel-render.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
|
2
2
|
import { Text } from "@earendil-works/pi-tui";
|
|
3
3
|
import type { SubagentParams } from "./params.js";
|
|
4
4
|
import { safeBlock, safeLine } from "./render-common.js";
|
|
5
|
-
import type { SubagentDetails } from "./
|
|
5
|
+
import type { SubagentDetails } from "./subagent-details.js";
|
|
6
6
|
|
|
7
7
|
export function renderPanelCall(args: SubagentParams, theme: Theme): Text | undefined {
|
|
8
8
|
const panel = args.panel;
|
package/src/parallel-limit-ui.ts
CHANGED
|
@@ -14,11 +14,12 @@ export function blockingParallelLimitScreen(runtime: BlockingParallelLimitRuntim
|
|
|
14
14
|
const limit = inspectBlockingParallelLimitSettings();
|
|
15
15
|
return {
|
|
16
16
|
kind: "input" as const,
|
|
17
|
-
title: "
|
|
17
|
+
title: "Blocking Worker Limit",
|
|
18
18
|
lines: [
|
|
19
|
-
|
|
19
|
+
"This applies only to requests that make Pi wait for delegated work.",
|
|
20
|
+
`Current: ${runtime.getMaxParallelTasks()} subagents per blocking request`,
|
|
20
21
|
`Allowed: 1-${MAX_CONFIGURABLE_PARALLEL_TASKS}`,
|
|
21
|
-
`
|
|
22
|
+
`Pi still starts at most ${MAX_BLOCKING_PARALLEL_CONCURRENCY} of them at once.`,
|
|
22
23
|
safeTerminalText(limit.path),
|
|
23
24
|
],
|
|
24
25
|
placeholder: "Enter a whole number",
|
|
@@ -89,7 +90,7 @@ export function applyBlockingParallelLimitSetting(
|
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
92
|
ctx.ui.notify(
|
|
92
|
-
`${settingsChanged ? "Saved and " : ""}applied: maximum ${next}
|
|
93
|
+
`${settingsChanged ? "Saved and " : ""}applied: maximum ${next} subagents per blocking request.`,
|
|
93
94
|
"info",
|
|
94
95
|
);
|
|
95
96
|
return { kind: "back" as const };
|
|
@@ -97,7 +98,7 @@ export function applyBlockingParallelLimitSetting(
|
|
|
97
98
|
|
|
98
99
|
function notifyValidationError(ctx: ExtensionCommandContext): void {
|
|
99
100
|
ctx.ui.notify(
|
|
100
|
-
`
|
|
101
|
+
`Blocking worker limit must be a whole number from 1 to ${MAX_CONFIGURABLE_PARALLEL_TASKS}.`,
|
|
101
102
|
"warning",
|
|
102
103
|
);
|
|
103
104
|
}
|
package/src/params.ts
CHANGED
|
@@ -5,6 +5,7 @@ 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-presets.js";
|
|
7
7
|
import { SUBAGENT_RESULT_FORMATS } from "./result-contract.js";
|
|
8
|
+
import { grammarSafeToolObject } from "./tool-schema-compatibility.js";
|
|
8
9
|
import { MAX_SUBAGENT_TOOL_CALLS, MAX_SUBAGENT_TURNS } from "./turn-budget.js";
|
|
9
10
|
import { VerifiedExecutionContractSchema } from "./verified-execution-schema.js";
|
|
10
11
|
|
|
@@ -202,7 +203,7 @@ const AgentScopeSchema = StringEnum(["user", "project", "both"] as const, {
|
|
|
202
203
|
default: "user",
|
|
203
204
|
});
|
|
204
205
|
|
|
205
|
-
export const SubagentParams =
|
|
206
|
+
export const SubagentParams = grammarSafeToolObject({
|
|
206
207
|
agent: Type.Optional(
|
|
207
208
|
Type.String({ description: "Name of the agent to invoke (for single mode)" }),
|
|
208
209
|
),
|
package/src/persistence.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { getAgentDir, withFileMutationQueue } from "@earendil-works/pi-coding-ag
|
|
|
5
5
|
import { projectAgentRecords } from "./agent-projection.js";
|
|
6
6
|
import { isThinkingLevel } from "./agents/types.js";
|
|
7
7
|
import { isCapabilityGrant, revokeCapabilityGrant } from "./capability-grant.js";
|
|
8
|
+
import { isCompletionRequirementRecord } from "./completion-requirement.js";
|
|
8
9
|
import { redactPrivateText } from "./context.js";
|
|
9
10
|
import { normalizeDelegationContract } from "./delegation-contract.js";
|
|
10
11
|
import { copyExecutionPlan, isExecutionPlan } from "./execution-plan.js";
|
|
@@ -171,6 +172,10 @@ function sanitizeAgent(agent: ManagedAgent): ManagedAgent {
|
|
|
171
172
|
output: redactPrivateText(completion.output),
|
|
172
173
|
error: completion.error ? redactPrivateText(completion.error) : undefined,
|
|
173
174
|
})),
|
|
175
|
+
completionRequirements: (agent.completionRequirements ?? [])
|
|
176
|
+
.filter(isCompletionRequirementRecord)
|
|
177
|
+
.slice(-MAX_STORED_COMPLETIONS_PER_AGENT)
|
|
178
|
+
.map((record) => ({ ...record })),
|
|
174
179
|
currentTimeoutMs: undefined,
|
|
175
180
|
currentIdleTimeoutMs: undefined,
|
|
176
181
|
currentMaxTurns: undefined,
|
|
@@ -261,6 +266,10 @@ function isStoredState(value: unknown): value is StoredState {
|
|
|
261
266
|
(record.turnGeneration === undefined || isNonNegativeInteger(record.turnGeneration)) &&
|
|
262
267
|
(record.pendingCompletions === undefined ||
|
|
263
268
|
isCompletionOutbox(record.pendingCompletions, record.turnGeneration ?? 0)) &&
|
|
269
|
+
(record.completionRequirements === undefined ||
|
|
270
|
+
(Array.isArray(record.completionRequirements) &&
|
|
271
|
+
record.completionRequirements.length <= MAX_STORED_COMPLETIONS_PER_AGENT &&
|
|
272
|
+
record.completionRequirements.every(isCompletionRequirementRecord))) &&
|
|
264
273
|
(record.spawnIdempotencyKey === undefined ||
|
|
265
274
|
(typeof record.spawnIdempotencyKey === "string" &&
|
|
266
275
|
record.spawnIdempotencyKey.length > 0 &&
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { spawn } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
export const KILL_GRACE_MS = 5000;
|
|
4
|
+
|
|
5
|
+
function signalProcess(proc: ReturnType<typeof spawn>, signal: NodeJS.Signals): void {
|
|
6
|
+
if (process.platform !== "win32" && proc.pid) {
|
|
7
|
+
try {
|
|
8
|
+
process.kill(-proc.pid, signal);
|
|
9
|
+
return;
|
|
10
|
+
} catch {
|
|
11
|
+
// Fall back to signaling the immediate child when process-group signaling is unavailable.
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
proc.kill(signal);
|
|
16
|
+
} catch {
|
|
17
|
+
// The process may already have exited.
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function terminateProcess(
|
|
22
|
+
proc: ReturnType<typeof spawn>,
|
|
23
|
+
graceMs = KILL_GRACE_MS,
|
|
24
|
+
): () => void {
|
|
25
|
+
const leaderExited = proc.exitCode !== null || proc.signalCode !== null;
|
|
26
|
+
const capturedOutputClosed = [proc.stdout, proc.stderr].every(
|
|
27
|
+
(stream) => !stream || stream.readableEnded || stream.destroyed,
|
|
28
|
+
);
|
|
29
|
+
let closed = leaderExited && capturedOutputClosed;
|
|
30
|
+
const onClose = () => {
|
|
31
|
+
closed = true;
|
|
32
|
+
};
|
|
33
|
+
proc.once("close", onClose);
|
|
34
|
+
if (!closed) signalProcess(proc, "SIGTERM");
|
|
35
|
+
const escalation = setTimeout(() => {
|
|
36
|
+
if (!closed) signalProcess(proc, "SIGKILL");
|
|
37
|
+
}, graceMs);
|
|
38
|
+
escalation.unref();
|
|
39
|
+
return () => {
|
|
40
|
+
clearTimeout(escalation);
|
|
41
|
+
proc.off("close", onClose);
|
|
42
|
+
};
|
|
43
|
+
}
|
package/src/registry-types.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { SubagentThinkingLevel } from "./agents/types.js";
|
|
2
2
|
import type { CapabilityGrant } from "./capability-grant.js";
|
|
3
|
+
import type { CompletionRequirementRecord } from "./completion-requirement.js";
|
|
3
4
|
import type { TargetPolicyAudit } from "./cwd-policy.js";
|
|
4
5
|
import type { DelegationContract } from "./delegation-contract.js";
|
|
5
6
|
import type { ExecutionPlan } from "./execution-plan.js";
|
|
@@ -14,6 +15,7 @@ export type AgentLifecycleState =
|
|
|
14
15
|
| "running"
|
|
15
16
|
| "idle"
|
|
16
17
|
| "completed"
|
|
18
|
+
| "partial"
|
|
17
19
|
| "blocked"
|
|
18
20
|
| "needs-input"
|
|
19
21
|
| "abstained"
|
|
@@ -85,6 +87,7 @@ export interface ManagedAgent {
|
|
|
85
87
|
currentRunId?: string;
|
|
86
88
|
currentTurnGeneration?: number;
|
|
87
89
|
pendingCompletions?: PersistedAgentCompletion[];
|
|
90
|
+
completionRequirements?: CompletionRequirementRecord[];
|
|
88
91
|
history: AgentTurn[];
|
|
89
92
|
error?: string;
|
|
90
93
|
context?: string;
|
|
@@ -123,6 +126,7 @@ export interface AgentRunInspectionSummary {
|
|
|
123
126
|
unreadMessages: number;
|
|
124
127
|
turnGeneration: number;
|
|
125
128
|
pendingCompletionCount: number;
|
|
129
|
+
pendingRequiredCompletionCount?: number;
|
|
126
130
|
}
|
|
127
131
|
|
|
128
132
|
export interface AgentRunInspectionDetail extends AgentRunInspectionSummary {
|
|
@@ -156,6 +160,7 @@ export interface AgentRunInspectionDetail extends AgentRunInspectionSummary {
|
|
|
156
160
|
semanticSnapshot?: SemanticSnapshot;
|
|
157
161
|
semanticCompatibility?: SemanticCompatibility;
|
|
158
162
|
termination?: TurnTerminationReport;
|
|
163
|
+
completionRequirements?: CompletionRequirementRecord[];
|
|
159
164
|
telemetry?: TransportTelemetry;
|
|
160
165
|
}
|
|
161
166
|
|