@narumitw/pi-subagents 1.0.0 → 1.0.2

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/src/subagents.ts CHANGED
@@ -21,11 +21,24 @@ import type {
21
21
  DelegationCwdPolicy,
22
22
  SubagentSettings,
23
23
  } from "./agents/types.js";
24
- import { registerSubagentAutomation } from "./automation.js";
25
- import { registerSubagentConfigCommand, registerSubagentConfigLifecycle } from "./config-ui.js";
26
- import { registerSubagentConsult } from "./consult.js";
27
- import { executeSubagent } from "./execution.js";
28
- import { registerSubagentInspect } from "./inspect.js";
24
+ import {
25
+ type AutomationRegistrationDependencies,
26
+ registerSubagentAutomation,
27
+ } from "./automation-registration.js";
28
+ import { cachedModuleLoader, throwIfAborted } from "./cached-module-loader.js";
29
+ import {
30
+ type ConfigRegistrationDependencies,
31
+ registerSubagentConfigCommand,
32
+ registerSubagentConfigLifecycle,
33
+ } from "./config-registration.js";
34
+ import {
35
+ type ConsultRegistrationDependencies,
36
+ registerSubagentConsult,
37
+ } from "./consult-registration.js";
38
+ import {
39
+ type InspectRegistrationDependencies,
40
+ registerSubagentInspect,
41
+ } from "./inspect-registration.js";
29
42
  import { MAX_BLOCKING_PARALLEL_CONCURRENCY } from "./limits.js";
30
43
  import { SubagentParams } from "./params.js";
31
44
  import { renderSubagentCall, renderSubagentResult } from "./render.js";
@@ -40,17 +53,34 @@ import {
40
53
  resolveBlockingMaxParallelTasks,
41
54
  } from "./settings.js";
42
55
  import { registerStatefulSubagents } from "./stateful.js";
56
+ import type { SubagentTransport } from "./transport.js";
57
+
58
+ type BlockingExecutionModule = Pick<typeof import("./execution.js"), "executeSubagent">;
59
+
60
+ export interface SubagentsDependencies {
61
+ loadBlockingExecution?: () => Promise<BlockingExecutionModule>;
62
+ loadStatefulTransport?: () => Promise<SubagentTransport>;
63
+ automation?: AutomationRegistrationDependencies;
64
+ config?: ConfigRegistrationDependencies;
65
+ consult?: ConsultRegistrationDependencies;
66
+ inspect?: InspectRegistrationDependencies;
67
+ }
43
68
 
44
- export default function (pi: ExtensionAPI) {
69
+ export default function (pi: ExtensionAPI, dependencies: SubagentsDependencies = {}) {
70
+ const loadBlockingExecution = cachedModuleLoader(
71
+ dependencies.loadBlockingExecution ?? (() => import("./execution.js")),
72
+ );
45
73
  const configOwner = registerSubagentConfigLifecycle(pi);
46
74
  const settings = readSubagentSettings();
47
75
  let currentSettings: SubagentSettings | undefined = settings;
48
76
  let currentCatalog = "";
49
77
  const blockingEnabled = settings?.blocking?.enabled !== false;
50
78
  const refreshBlockingCatalog = blockingEnabled
51
- ? registerBlockingSubagent(pi, () => currentSettings)
79
+ ? registerBlockingSubagent(pi, () => currentSettings, loadBlockingExecution)
52
80
  : () => undefined;
53
- if (blockingEnabled) registerSubagentAutomation(pi, { getSettings: () => currentSettings });
81
+ if (blockingEnabled) {
82
+ registerSubagentAutomation(pi, { getSettings: () => currentSettings }, dependencies.automation);
83
+ }
54
84
  let refreshStatefulCatalog: (catalog: string) => void = () => undefined;
55
85
  let refreshConsultCatalog: (catalog: string) => void = () => undefined;
56
86
 
@@ -78,6 +108,7 @@ export default function (pi: ExtensionAPI) {
78
108
  blockingEnabled,
79
109
  settings: settings?.stateful,
80
110
  getSettings: () => currentSettings,
111
+ loadTransport: dependencies.loadStatefulTransport,
81
112
  });
82
113
  refreshStatefulCatalog = statefulRuntime.setAgentCatalog;
83
114
  const getBlockingEnabled = () => blockingEnabled;
@@ -88,18 +119,24 @@ export default function (pi: ExtensionAPI) {
88
119
  currentSettings?.cwdPolicy?.consultation ?? DEFAULT_CONSULTATION_CWD_POLICY;
89
120
  const getDelegationCwdPolicy = () =>
90
121
  currentSettings?.cwdPolicy?.delegation ?? DEFAULT_DELEGATION_CWD_POLICY;
91
- registerSubagentInspect(pi, {
92
- ...statefulRuntime,
93
- getBlockingEnabled,
94
- getMaxParallelTasks,
95
- getConsultResourcePolicy,
96
- getConsultationCwdPolicy,
97
- getDelegationCwdPolicy,
98
- });
122
+ registerSubagentInspect(
123
+ pi,
124
+ {
125
+ ...statefulRuntime,
126
+ getBlockingEnabled,
127
+ getMaxParallelTasks,
128
+ getConsultResourcePolicy,
129
+ getConsultationCwdPolicy,
130
+ getDelegationCwdPolicy,
131
+ },
132
+ dependencies.inspect,
133
+ );
99
134
  if (blockingEnabled) {
100
- refreshConsultCatalog = registerSubagentConsult(pi, {
101
- getSettings: () => currentSettings,
102
- });
135
+ refreshConsultCatalog = registerSubagentConsult(
136
+ pi,
137
+ { getSettings: () => currentSettings },
138
+ dependencies.consult,
139
+ );
103
140
  }
104
141
  registerSubagentConfigCommand(
105
142
  pi,
@@ -155,12 +192,14 @@ export default function (pi: ExtensionAPI) {
155
192
  },
156
193
  },
157
194
  configOwner,
195
+ dependencies.config,
158
196
  );
159
197
  }
160
198
 
161
199
  function registerBlockingSubagent(
162
200
  pi: ExtensionAPI,
163
201
  getSettings: () => SubagentSettings | undefined,
202
+ loadExecution: () => Promise<BlockingExecutionModule>,
164
203
  ): (catalog: string) => void {
165
204
  let catalog = "";
166
205
  const activeControllers = new Set<AbortController>();
@@ -212,14 +251,28 @@ function registerBlockingSubagent(
212
251
  const effectiveSignal = signal
213
252
  ? AbortSignal.any([signal, lifecycleController.signal])
214
253
  : lifecycleController.signal;
215
- const work = executeSubagent(
216
- toolCallId,
217
- params,
218
- effectiveSignal,
219
- onUpdate,
220
- ctx,
221
- getSettings(),
222
- );
254
+ const work = (async () => {
255
+ throwIfAborted(effectiveSignal, "Blocking subagent execution was cancelled");
256
+ let executionModule: BlockingExecutionModule;
257
+ try {
258
+ executionModule = await loadExecution();
259
+ } catch (error) {
260
+ throwIfAborted(
261
+ effectiveSignal,
262
+ "Blocking subagent execution was cancelled while loading",
263
+ );
264
+ throw error;
265
+ }
266
+ throwIfAborted(effectiveSignal, "Blocking subagent execution was cancelled while loading");
267
+ return executionModule.executeSubagent(
268
+ toolCallId,
269
+ params,
270
+ effectiveSignal,
271
+ onUpdate,
272
+ ctx,
273
+ getSettings(),
274
+ );
275
+ })();
223
276
  activeWork.add(work);
224
277
  try {
225
278
  return await work;
@@ -256,8 +309,7 @@ function appendAgentCatalog(baseDescription: string, catalog: string): string {
256
309
  }
257
310
 
258
311
  export { parsePositiveInteger } from "./execution/runtime-policy.js";
259
- export { formatTokens, formatUsageStats } from "./render.js";
260
- export { buildPiArgs } from "./runner.js";
312
+ export { buildPiArgs } from "./pi-args.js";
261
313
  export {
262
314
  DEFAULT_CONSULT_RESOURCE_POLICY,
263
315
  DEFAULT_CONSULTATION_CWD_POLICY,
@@ -286,3 +338,4 @@ export {
286
338
  updateDelegationWorkflowSetting,
287
339
  updateStatefulLimitSetting,
288
340
  } from "./settings.js";
341
+ export { formatTokens, formatUsageStats } from "./usage-format.js";
@@ -0,0 +1,42 @@
1
+ import type { SubagentThinkingLevel } from "./agents/types.js";
2
+ import { safeLine } from "./render-common.js";
3
+
4
+ export function formatTokens(count: number): string {
5
+ if (count < 1000) return count.toString();
6
+ if (count < 10000) return `${(count / 1000).toFixed(1)}k`;
7
+ if (count < 1000000) return `${Math.round(count / 1000)}k`;
8
+ return `${(count / 1000000).toFixed(1)}M`;
9
+ }
10
+
11
+ export function formatUsageStats(
12
+ usage: {
13
+ input: number;
14
+ output: number;
15
+ cacheRead: number;
16
+ cacheWrite: number;
17
+ cost: number;
18
+ contextTokens?: number;
19
+ turns?: number;
20
+ },
21
+ model?: string,
22
+ thinkingLevel?: SubagentThinkingLevel,
23
+ actualProvider?: string,
24
+ actualModel?: string,
25
+ ): string {
26
+ const parts: string[] = [];
27
+ if (usage.turns) parts.push(`${usage.turns} turn${usage.turns > 1 ? "s" : ""}`);
28
+ if (usage.input) parts.push(`↑${formatTokens(usage.input)}`);
29
+ if (usage.output) parts.push(`↓${formatTokens(usage.output)}`);
30
+ if (usage.cacheRead) parts.push(`R${formatTokens(usage.cacheRead)}`);
31
+ if (usage.cacheWrite) parts.push(`W${formatTokens(usage.cacheWrite)}`);
32
+ if (usage.cost) parts.push(`$${usage.cost.toFixed(4)}`);
33
+ if (usage.contextTokens && usage.contextTokens > 0)
34
+ parts.push(`ctx:${formatTokens(usage.contextTokens)}`);
35
+ const safeProvider = actualProvider ? safeLine(actualProvider, "", 256) : undefined;
36
+ const safeModel = actualModel ? safeLine(actualModel, "", 256) : undefined;
37
+ const actual =
38
+ safeProvider && safeModel ? `${safeProvider}/${safeModel}` : (safeModel ?? safeProvider);
39
+ if (actual ?? model) parts.push(actual ?? safeLine(model, "", 256));
40
+ if (thinkingLevel) parts.push(`requested-thinking:${safeLine(thinkingLevel, "", 128)}`);
41
+ return parts.join(" ");
42
+ }
@@ -1,41 +1,13 @@
1
- import { StringEnum } from "@earendil-works/pi-ai";
2
- import { type Static, Type } from "typebox";
3
1
  import { normalizeDelegationContract } from "./delegation-contract.js";
4
2
  import {
5
3
  type VerificationCheckRequest,
6
4
  validateVerificationChecks,
7
5
  } from "./verification-harness.js";
6
+ import type { VerifiedExecutionContract } from "./verified-execution-schema.js";
8
7
  import type { ResolvedWorkflowTask } from "./workflow-planning.js";
9
8
 
10
- const VerificationCheckSchema = Type.Object(
11
- {
12
- id: Type.String({
13
- minLength: 1,
14
- maxLength: 256,
15
- pattern: "^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$",
16
- }),
17
- command: StringEnum(["git", "node", "npm", "npx"] as const),
18
- args: Type.Optional(Type.Array(Type.String({ maxLength: 4096 }), { maxItems: 64 })),
19
- cwd: Type.Optional(Type.String({ minLength: 1, maxLength: 4096 })),
20
- timeoutMs: Type.Optional(Type.Integer({ minimum: 1, maximum: 600_000 })),
21
- },
22
- { additionalProperties: false },
23
- );
24
-
25
- export const VerifiedExecutionContractSchema = Type.Object(
26
- {
27
- verifierAgent: Type.String({ minLength: 1, maxLength: 256 }),
28
- maxReworkCycles: Type.Optional(Type.Integer({ minimum: 0, maximum: 1, default: 1 })),
29
- checks: Type.Optional(Type.Array(VerificationCheckSchema, { maxItems: 32 })),
30
- },
31
- {
32
- additionalProperties: false,
33
- description:
34
- "Explicitly gate mutating workflow success on executor-owned deterministic checks, one least-authority independent verifier, exact submitted-state identity, and managed integration acceptance.",
35
- },
36
- );
37
-
38
- export type VerifiedExecutionContract = Static<typeof VerifiedExecutionContractSchema>;
9
+ export type { VerifiedExecutionContract } from "./verified-execution-schema.js";
10
+ export { VerifiedExecutionContractSchema } from "./verified-execution-schema.js";
39
11
 
40
12
  export interface PreparedVerifiedWorkflow {
41
13
  tasks: ResolvedWorkflowTask[];
@@ -0,0 +1,32 @@
1
+ import { StringEnum } from "@earendil-works/pi-ai";
2
+ import { type Static, Type } from "typebox";
3
+
4
+ const VerificationCheckSchema = Type.Object(
5
+ {
6
+ id: Type.String({
7
+ minLength: 1,
8
+ maxLength: 256,
9
+ pattern: "^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$",
10
+ }),
11
+ command: StringEnum(["git", "node", "npm", "npx"] as const),
12
+ args: Type.Optional(Type.Array(Type.String({ maxLength: 4096 }), { maxItems: 64 })),
13
+ cwd: Type.Optional(Type.String({ minLength: 1, maxLength: 4096 })),
14
+ timeoutMs: Type.Optional(Type.Integer({ minimum: 1, maximum: 600_000 })),
15
+ },
16
+ { additionalProperties: false },
17
+ );
18
+
19
+ export const VerifiedExecutionContractSchema = Type.Object(
20
+ {
21
+ verifierAgent: Type.String({ minLength: 1, maxLength: 256 }),
22
+ maxReworkCycles: Type.Optional(Type.Integer({ minimum: 0, maximum: 1, default: 1 })),
23
+ checks: Type.Optional(Type.Array(VerificationCheckSchema, { maxItems: 32 })),
24
+ },
25
+ {
26
+ additionalProperties: false,
27
+ description:
28
+ "Explicitly gate mutating workflow success on executor-owned deterministic checks, one least-authority independent verifier, exact submitted-state identity, and managed integration acceptance.",
29
+ },
30
+ );
31
+
32
+ export type VerifiedExecutionContract = Static<typeof VerifiedExecutionContractSchema>;