@pi-ohm/subagents 0.6.4-dev.25620170147.1.0b6891f → 0.6.4-dev.25636965069.1.619ed5f

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.
@@ -1,5 +1,7 @@
1
1
  import { AgentToolResult, ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-agent";
2
- import { Static, Type } from "@earendil-works/pi-ai";
2
+ import { Api, Model, Static, Type } from "@earendil-works/pi-ai";
3
+ import { Result } from "better-result";
4
+ import { ThinkingLevel } from "@earendil-works/pi-agent-core";
3
5
 
4
6
  //#region src/agent-controller.d.ts
5
7
  declare const SpawnAgentArgsSchema: Type.TObject<{
@@ -41,8 +43,17 @@ type CloseAgentArgs = Static<typeof CloseAgentArgsSchema>;
41
43
  type ResumeAgentArgs = Static<typeof ResumeAgentArgsSchema>;
42
44
  type GetAgentResultArgs = Static<typeof GetAgentResultArgsSchema>;
43
45
  type ListAgentsArgs = Static<typeof ListAgentsArgsSchema>;
44
- declare function registerAgentControllerTool(pi: Pick<ExtensionAPI, "registerTool" | "appendEntry" | "on">): void;
45
- declare function createSubagentToolRuntime(pi: Pick<ExtensionAPI, "appendEntry">): SubagentToolRuntime;
46
+ interface ResolvedSpawnConfig {
47
+ readonly agentType: string;
48
+ readonly model: Model<Api>;
49
+ readonly modelKey: string;
50
+ readonly agentDir: string;
51
+ readonly thinking: ThinkingLevel;
52
+ readonly tools?: readonly string[];
53
+ readonly prompt: string;
54
+ }
55
+ declare function registerAgentControllerTool(pi: Pick<ExtensionAPI, "registerTool" | "appendEntry" | "getThinkingLevel" | "on">): void;
56
+ declare function createSubagentToolRuntime(pi: Pick<ExtensionAPI, "appendEntry" | "getThinkingLevel">): SubagentToolRuntime;
46
57
  interface SubagentToolRuntime {
47
58
  spawn(params: SpawnAgentArgs, ctx: ToolContext): Promise<AgentToolResult<unknown>>;
48
59
  send(params: SendAgentInputArgs, ctx: ToolContext): Promise<AgentToolResult<unknown>>;
@@ -55,5 +66,11 @@ interface SubagentToolRuntime {
55
66
  }
56
67
  type ToolContext = Parameters<ToolDefinition["execute"]>[4];
57
68
  declare function createSubagentTools(runtime: SubagentToolRuntime): readonly ToolDefinition[];
69
+ declare function resolveSpawnConfig(input: {
70
+ readonly cwd: string;
71
+ readonly params: SpawnAgentArgs;
72
+ readonly currentModel?: Model<Api>;
73
+ readonly currentThinking?: ThinkingLevel;
74
+ }): Promise<Result<ResolvedSpawnConfig, Error>>;
58
75
  //#endregion
59
- export { SubagentToolRuntime, createSubagentToolRuntime, createSubagentTools, registerAgentControllerTool };
76
+ export { SubagentToolRuntime, createSubagentToolRuntime, createSubagentTools, registerAgentControllerTool, resolveSpawnConfig };
@@ -1,7 +1,10 @@
1
- import { defineTool } from "@earendil-works/pi-coding-agent";
1
+ import { isSubagentRuntimeConfig, resolveSubagentProfileRuntimeConfig, subagentsConfigModule } from "./config.js";
2
+ import { AuthStorage, ModelRegistry, defineTool } from "@earendil-works/pi-coding-agent";
3
+ import path from "node:path";
2
4
  import { Type, getModels, getProviders } from "@earendil-works/pi-ai";
3
5
  import { Result } from "better-result";
4
6
  import { PipController, createSdkPipRunner } from "@pi-ohm/core/pip";
7
+ import { loadConfig, pickConfig, resolveExtensionConfigDir } from "@pi-ohm/core/config";
5
8
 
6
9
  //#region src/agent-controller.ts
7
10
  const defaultModel = "openai-codex/gpt-5.4-mini:medium";
@@ -54,11 +57,18 @@ function createSubagentToolRuntime(pi) {
54
57
  async spawn(params, ctx) {
55
58
  const parentSessionId = ctx.sessionManager.getSessionId();
56
59
  const record = getRecord(controllers, parentSessionId);
57
- const key = controllerKey(params);
60
+ const config = await resolveSpawnConfig({
61
+ cwd: ctx.cwd,
62
+ params,
63
+ currentModel: ctx.model,
64
+ currentThinking: pi.getThinkingLevel()
65
+ });
66
+ if (Result.isError(config)) return toolError(config.error.message);
67
+ const key = controllerKey(config.value);
58
68
  const currentController = record.controllers.get(key);
59
69
  const created = currentController ? Result.ok(currentController) : createPipController({
60
70
  pi,
61
- params
71
+ config: config.value
62
72
  });
63
73
  if (Result.isError(created)) return toolError(created.error.message);
64
74
  const controller = created.value;
@@ -66,10 +76,10 @@ function createSubagentToolRuntime(pi) {
66
76
  if (ctx.hasUI) ctx.ui.notify(`subagent spawned: ${params.task_name}`, "info");
67
77
  const spawned = await controller.spawn({
68
78
  ownerPackage: "@pi-ohm/subagents",
69
- role: params.agent_type ?? "default",
79
+ role: config.value.agentType,
70
80
  parentSessionId,
71
81
  cwd: ctx.cwd,
72
- prompt: params.prompt,
82
+ prompt: config.value.prompt,
73
83
  runInBackground: params.run_in_background ?? true,
74
84
  parentSessionFile: params.fork_context ? ctx.sessionManager.getSessionFile() : undefined
75
85
  });
@@ -250,16 +260,12 @@ function createControllerRecord() {
250
260
  };
251
261
  }
252
262
  function createPipController(input) {
253
- const modelSpec = Result.try({
254
- try: () => parseModelSpec(input.params.model),
255
- catch: (cause) => cause instanceof Error ? cause : new Error(String(cause))
256
- });
257
- if (Result.isError(modelSpec)) return Result.err(modelSpec.error);
258
- const thinkingLevel = input.params.thinking ?? modelSpec.value.thinkingLevel;
259
263
  return Result.ok(new PipController({
260
264
  runner: createSdkPipRunner({
261
- model: modelSpec.value.model,
262
- thinkingLevel
265
+ model: input.config.model,
266
+ agentDir: input.config.agentDir,
267
+ thinkingLevel: input.config.thinking,
268
+ tools: input.config.tools
263
269
  }),
264
270
  entries: { write(entry) {
265
271
  input.pi.appendEntry("pi-ohm.pip", entry);
@@ -267,8 +273,70 @@ function createPipController(input) {
267
273
  } }
268
274
  }));
269
275
  }
270
- function controllerKey(params) {
271
- return `${params.model ?? defaultModel}:${params.thinking ?? "default"}`;
276
+ function controllerKey(config) {
277
+ return `${config.modelKey}:${config.thinking}:${config.tools?.join(",") ?? "default"}`;
278
+ }
279
+ async function resolveSpawnConfig(input) {
280
+ const loaded = await loadConfig({
281
+ cwd: input.cwd,
282
+ modules: [subagentsConfigModule]
283
+ });
284
+ if (Result.isError(loaded)) return Result.err(loaded.error);
285
+ const subagents = pickConfig({
286
+ loaded: loaded.value,
287
+ module: subagentsConfigModule,
288
+ is: isSubagentRuntimeConfig
289
+ });
290
+ if (Result.isError(subagents)) return Result.err(subagents.error);
291
+ const agentType = input.params.agent_type?.trim() || input.params.task_name.trim();
292
+ const currentModelPattern = input.currentModel ? modelKey(input.currentModel) : undefined;
293
+ const baseProfile = resolveSubagentProfileRuntimeConfig({
294
+ config: { subagents: subagents.value },
295
+ subagentId: agentType,
296
+ modelPattern: input.params.model ?? currentModelPattern
297
+ });
298
+ const profile = resolveSubagentProfileRuntimeConfig({
299
+ config: { subagents: subagents.value },
300
+ subagentId: agentType,
301
+ modelPattern: input.params.model ?? baseProfile?.model ?? currentModelPattern
302
+ });
303
+ const agentDir = resolveExtensionConfigDir();
304
+ const modelSpec = Result.try({
305
+ try: () => parseModelSpec({
306
+ agentDir,
307
+ spec: input.params.model ?? profile?.model,
308
+ currentModel: input.currentModel
309
+ }),
310
+ catch: (cause) => cause instanceof Error ? cause : new Error(String(cause))
311
+ });
312
+ if (Result.isError(modelSpec)) return Result.err(modelSpec.error);
313
+ const thinking = input.params.thinking ?? profile?.thinking ?? (input.params.model || profile?.model ? modelSpec.value.thinkingLevel : input.currentThinking) ?? modelSpec.value.thinkingLevel;
314
+ return Result.ok({
315
+ agentType,
316
+ model: modelSpec.value.model,
317
+ modelKey: modelSpec.value.modelKey,
318
+ agentDir,
319
+ thinking,
320
+ tools: resolveTools(profile),
321
+ prompt: resolvePrompt({
322
+ profile,
323
+ prompt: input.params.prompt
324
+ })
325
+ });
326
+ }
327
+ function modelKey(model) {
328
+ return `${model.provider}/${model.id}`;
329
+ }
330
+ function resolveTools(profile) {
331
+ if (!profile?.tools) return undefined;
332
+ const denied = new Set(Object.entries(profile.permissions).filter((entry) => entry[1] === "deny").map((entry) => entry[0]));
333
+ const tools = profile.tools.filter((tool) => !denied.has(tool.trim().toLowerCase()));
334
+ if (tools.length === 0) return undefined;
335
+ return tools;
336
+ }
337
+ function resolvePrompt(input) {
338
+ if (!input.profile?.prompt) return input.prompt;
339
+ return `${input.profile.prompt}\n\nTask:\n${input.prompt}`;
272
340
  }
273
341
  function resolveTarget(record, target) {
274
342
  return record.taskIds.get(target) ?? target;
@@ -277,21 +345,66 @@ function resolveController(record, pipId) {
277
345
  return record.taskControllers.get(pipId);
278
346
  }
279
347
  function parseModelSpec(input) {
280
- const spec = input ?? defaultModel;
348
+ if (!input.spec && input.currentModel) {
349
+ return {
350
+ model: input.currentModel,
351
+ modelKey: modelKey(input.currentModel),
352
+ thinkingLevel: "medium"
353
+ };
354
+ }
355
+ const spec = input.spec ?? defaultModel;
281
356
  const slash = spec.indexOf("/");
357
+ if (slash <= 0 || slash >= spec.length - 1) {
358
+ throw new Error(`Invalid subagent model '${spec}'. Expected '<provider>/<model>'`);
359
+ }
282
360
  const colon = spec.lastIndexOf(":");
283
361
  const provider = spec.slice(0, slash).trim();
284
362
  const modelId = spec.slice(slash + 1, colon > slash ? colon : undefined).trim();
363
+ if (provider.length === 0 || modelId.length === 0) {
364
+ throw new Error(`Invalid subagent model '${spec}'. Expected '<provider>/<model>'`);
365
+ }
285
366
  const thinkingLevel = parseThinkingLevel(colon > slash ? spec.slice(colon + 1) : "medium");
367
+ const registry = ModelRegistry.create(AuthStorage.create(path.join(input.agentDir, "auth.json")), path.join(input.agentDir, "models.json"));
368
+ const registeredModel = registry.find(provider, modelId);
369
+ if (registeredModel) return {
370
+ model: registeredModel,
371
+ modelKey: `${provider}/${modelId}`,
372
+ thinkingLevel
373
+ };
286
374
  const knownProvider = getProviders().find((candidate) => candidate === provider);
287
- if (!knownProvider) throw new Error(`Unknown subagent model provider '${provider}'`);
288
- const model = getModels(knownProvider).find((candidate) => candidate.id === modelId);
289
- if (!model) throw new Error(`Unknown subagent model '${provider}/${modelId}'`);
375
+ const model = knownProvider ? getModels(knownProvider).find((candidate) => candidate.id === modelId) ?? createExternalModel({
376
+ provider,
377
+ modelId
378
+ }) : createExternalModel({
379
+ provider,
380
+ modelId
381
+ });
290
382
  return {
291
383
  model,
384
+ modelKey: `${provider}/${modelId}`,
292
385
  thinkingLevel
293
386
  };
294
387
  }
388
+ function createExternalModel(input) {
389
+ const api = input.provider;
390
+ return {
391
+ id: input.modelId,
392
+ name: input.modelId,
393
+ api,
394
+ provider: input.provider,
395
+ baseUrl: "",
396
+ reasoning: true,
397
+ input: ["text"],
398
+ cost: {
399
+ input: 0,
400
+ output: 0,
401
+ cacheRead: 0,
402
+ cacheWrite: 0
403
+ },
404
+ contextWindow: 128e3,
405
+ maxTokens: 8192
406
+ };
407
+ }
295
408
  function parseThinkingLevel(input) {
296
409
  const level = input.trim().toLowerCase();
297
410
  if (level === "off") return "off";
@@ -327,4 +440,4 @@ function toolError(message) {
327
440
  }
328
441
 
329
442
  //#endregion
330
- export { createSubagentToolRuntime, createSubagentTools, registerAgentControllerTool };
443
+ export { createSubagentToolRuntime, createSubagentTools, registerAgentControllerTool, resolveSpawnConfig };
package/dist/config.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { SubagentProfilePatch, SubagentProfilePatchSchema, SubagentProfileVariantMapPatchSchema, SubagentProfileVariantPatch, SubagentProfileVariantPatchSchema, SubagentToolPermissionDecisionPatch, SubagentToolPermissionDecisionSchema, SubagentToolPermissionMapSchema, parseSubagentProfilePatch, parseSubagentProfileVariantPatch } from "./schema.js";
2
- import { Type } from "typebox";
3
2
  import * as _$_pi_ohm_core_config0 from "@pi-ohm/core/config";
3
+ import { Type } from "typebox";
4
4
 
5
5
  //#region src/config.d.ts
6
6
  declare const SubagentsConfigSchema: Type.TRecord<"^.*$", Type.TUnknown>;
@@ -9,6 +9,9 @@ interface SubagentsConfig {
9
9
  }
10
10
  interface SubagentProfileRuntimeConfig {
11
11
  model?: string;
12
+ thinking?: SubagentThinkingLevel;
13
+ tools?: readonly string[];
14
+ maxTurns?: number;
12
15
  prompt?: string;
13
16
  description?: string;
14
17
  whenToUse?: readonly string[];
@@ -18,6 +21,9 @@ interface SubagentProfileRuntimeConfig {
18
21
  type SubagentToolPermissionDecision = "allow" | "deny" | "inherit";
19
22
  interface SubagentProfileVariantRuntimeConfig {
20
23
  model?: string;
24
+ thinking?: SubagentThinkingLevel;
25
+ tools?: readonly string[];
26
+ maxTurns?: number;
21
27
  prompt?: string;
22
28
  description?: string;
23
29
  whenToUse?: readonly string[];
@@ -25,6 +31,9 @@ interface SubagentProfileVariantRuntimeConfig {
25
31
  }
26
32
  interface ResolvedSubagentProfileRuntimeConfig {
27
33
  model?: string;
34
+ thinking?: SubagentThinkingLevel;
35
+ tools?: readonly string[];
36
+ maxTurns?: number;
28
37
  prompt?: string;
29
38
  description?: string;
30
39
  whenToUse?: readonly string[];
@@ -43,6 +52,7 @@ interface SubagentRuntimeConfig {
43
52
  profiles: Record<string, SubagentProfileRuntimeConfig>;
44
53
  }
45
54
  type SubagentBackend = "none" | "interactive-shell" | "interactive-sdk" | "custom-plugin";
55
+ type SubagentThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
46
56
  interface RuntimeConfigWithSubagents {
47
57
  readonly subagents?: SubagentRuntimeConfig;
48
58
  }
@@ -66,4 +76,4 @@ declare function resolveSubagentProfileRuntimeConfig(input: {
66
76
  }): ResolvedSubagentProfileRuntimeConfig | undefined;
67
77
  declare function isSubagentRuntimeConfig(value: unknown): value is SubagentRuntimeConfig;
68
78
  //#endregion
69
- export { DEFAULT_SUBAGENT_RUNTIME_CONFIG, ResolvedSubagentProfileRuntimeConfig, SubagentBackend, type SubagentProfilePatch, SubagentProfilePatchSchema, SubagentProfileRuntimeConfig, SubagentProfileVariantMapPatchSchema, type SubagentProfileVariantPatch, SubagentProfileVariantPatchSchema, SubagentProfileVariantRuntimeConfig, SubagentRuntimeConfig, SubagentToolPermissionDecision, type SubagentToolPermissionDecisionPatch, SubagentToolPermissionDecisionSchema, SubagentToolPermissionMapSchema, SubagentsConfig, SubagentsConfigSchema, getSubagentConfiguredModel, getSubagentProfileRuntimeConfig, isSubagentRuntimeConfig, mergeSubagentRuntimeConfig, normalizeSubagentModelOverride, parseSubagentProfilePatch, parseSubagentProfileVariantPatch, resolveSubagentProfileRuntimeConfig, resolveSubagentVariantPattern, subagentsConfigModule };
79
+ export { DEFAULT_SUBAGENT_RUNTIME_CONFIG, ResolvedSubagentProfileRuntimeConfig, SubagentBackend, type SubagentProfilePatch, SubagentProfilePatchSchema, SubagentProfileRuntimeConfig, SubagentProfileVariantMapPatchSchema, type SubagentProfileVariantPatch, SubagentProfileVariantPatchSchema, SubagentProfileVariantRuntimeConfig, SubagentRuntimeConfig, SubagentThinkingLevel, SubagentToolPermissionDecision, type SubagentToolPermissionDecisionPatch, SubagentToolPermissionDecisionSchema, SubagentToolPermissionMapSchema, SubagentsConfig, SubagentsConfigSchema, getSubagentConfiguredModel, getSubagentProfileRuntimeConfig, isSubagentRuntimeConfig, mergeSubagentRuntimeConfig, normalizeSubagentModelOverride, parseSubagentProfilePatch, parseSubagentProfileVariantPatch, resolveSubagentProfileRuntimeConfig, resolveSubagentVariantPattern, subagentsConfigModule };
package/dist/config.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { SubagentProfilePatchSchema, SubagentProfileVariantMapPatchSchema, SubagentProfileVariantPatchSchema, SubagentToolPermissionDecisionSchema, SubagentToolPermissionMapSchema, parseSubagentProfilePatch, parseSubagentProfileVariantPatch } from "./schema.js";
2
2
  import { Result } from "better-result";
3
- import { Type } from "typebox";
4
3
  import { registerConfig } from "@pi-ohm/core/config";
4
+ import { Type } from "typebox";
5
5
 
6
6
  //#region src/config.ts
7
7
  const SubagentsConfigSchema = Type.Record(Type.String({ minLength: 1 }), Type.Unknown());
@@ -34,14 +34,6 @@ const SUBAGENT_RUNTIME_RESERVED_KEYS = new Set([
34
34
  "permissions",
35
35
  "profiles"
36
36
  ]);
37
- const SUBAGENT_THINKING_LEVELS = new Set([
38
- "off",
39
- "minimal",
40
- "low",
41
- "medium",
42
- "high",
43
- "xhigh"
44
- ]);
45
37
  function isJsonMap(value) {
46
38
  return typeof value === "object" && value !== null && !Array.isArray(value);
47
39
  }
@@ -62,6 +54,26 @@ function normalizePositiveInteger(value, fallback) {
62
54
  if (!Number.isInteger(value) || value <= 0) return fallback;
63
55
  return value;
64
56
  }
57
+ function normalizeOptionalPositiveInteger(value) {
58
+ if (typeof value !== "number") return undefined;
59
+ if (!Number.isInteger(value) || value <= 0) return undefined;
60
+ return value;
61
+ }
62
+ function isSubagentThinkingLevel(value) {
63
+ return value === "off" || value === "minimal" || value === "low" || value === "medium" || value === "high" || value === "xhigh";
64
+ }
65
+ function normalizeThinking(value) {
66
+ if (typeof value !== "string") return undefined;
67
+ const normalized = value.trim().toLowerCase();
68
+ if (!isSubagentThinkingLevel(normalized)) return undefined;
69
+ return normalized;
70
+ }
71
+ function normalizeStringList(value) {
72
+ if (!Array.isArray(value)) return undefined;
73
+ const normalized = value.map((entry) => typeof entry === "string" ? entry.trim() : "").filter((entry) => entry.length > 0);
74
+ if (normalized.length === 0) return undefined;
75
+ return normalized;
76
+ }
65
77
  function normalizeSubagentBackend(value, fallback) {
66
78
  if (value === "none" || value === "interactive-shell" || value === "interactive-sdk" || value === "custom-plugin") {
67
79
  return value;
@@ -131,7 +143,7 @@ function stripThinkingSuffix(modelId) {
131
143
  return trimmed;
132
144
  }
133
145
  const suffix = trimmed.slice(colonIndex + 1).trim().toLowerCase();
134
- if (!SUBAGENT_THINKING_LEVELS.has(suffix)) {
146
+ if (!isSubagentThinkingLevel(suffix)) {
135
147
  return trimmed;
136
148
  }
137
149
  return trimmed.slice(0, colonIndex).trim();
@@ -140,6 +152,9 @@ function mergeSubagentVariantConfig(patch, fallback) {
140
152
  const parsedPatch = parseSubagentProfileVariantPatch(patch);
141
153
  if (!parsedPatch) return fallback;
142
154
  const model = normalizeSubagentModelOverride(parsedPatch.model);
155
+ const thinking = normalizeThinking(parsedPatch.thinking);
156
+ const tools = normalizeStringList(parsedPatch.tools);
157
+ const maxTurns = normalizeOptionalPositiveInteger(parsedPatch.maxTurns);
143
158
  const prompt = parsedPatch.prompt;
144
159
  const description = parsedPatch.description;
145
160
  const whenToUse = parsedPatch.whenToUse;
@@ -148,12 +163,15 @@ function mergeSubagentVariantConfig(patch, fallback) {
148
163
  const merged = {
149
164
  ...fallback,
150
165
  ...model ? { model } : {},
166
+ ...thinking ? { thinking } : {},
167
+ ...tools ? { tools } : {},
168
+ ...maxTurns ? { maxTurns } : {},
151
169
  ...prompt ? { prompt } : {},
152
170
  ...description ? { description } : {},
153
171
  ...whenToUse ? { whenToUse } : {},
154
172
  ...Object.keys(permissions).length > 0 ? { permissions } : {}
155
173
  };
156
- const hasValues = merged.model !== undefined || merged.prompt !== undefined || merged.description !== undefined || merged.whenToUse !== undefined || merged.permissions !== undefined;
174
+ const hasValues = merged.model !== undefined || merged.thinking !== undefined || merged.tools !== undefined || merged.maxTurns !== undefined || merged.prompt !== undefined || merged.description !== undefined || merged.whenToUse !== undefined || merged.permissions !== undefined;
157
175
  if (!hasValues) return undefined;
158
176
  return merged;
159
177
  }
@@ -174,6 +192,9 @@ function mergeSubagentProfileConfig(patch, fallback) {
174
192
  const parsedPatch = parseSubagentProfilePatch(patch);
175
193
  if (!parsedPatch) return fallback;
176
194
  const model = normalizeSubagentModelOverride(parsedPatch.model);
195
+ const thinking = normalizeThinking(parsedPatch.thinking);
196
+ const tools = normalizeStringList(parsedPatch.tools);
197
+ const maxTurns = normalizeOptionalPositiveInteger(parsedPatch.maxTurns);
177
198
  const prompt = parsedPatch.prompt;
178
199
  const description = parsedPatch.description;
179
200
  const whenToUse = parsedPatch.whenToUse;
@@ -183,13 +204,16 @@ function mergeSubagentProfileConfig(patch, fallback) {
183
204
  const merged = {
184
205
  ...fallback,
185
206
  ...model ? { model } : {},
207
+ ...thinking ? { thinking } : {},
208
+ ...tools ? { tools } : {},
209
+ ...maxTurns ? { maxTurns } : {},
186
210
  ...prompt ? { prompt } : {},
187
211
  ...description ? { description } : {},
188
212
  ...whenToUse ? { whenToUse } : {},
189
213
  ...Object.keys(permissions).length > 0 ? { permissions } : {},
190
214
  ...Object.keys(variants).length > 0 ? { variants } : {}
191
215
  };
192
- const hasValues = merged.model !== undefined || merged.prompt !== undefined || merged.description !== undefined || merged.whenToUse !== undefined || merged.permissions !== undefined || merged.variants !== undefined;
216
+ const hasValues = merged.model !== undefined || merged.thinking !== undefined || merged.tools !== undefined || merged.maxTurns !== undefined || merged.prompt !== undefined || merged.description !== undefined || merged.whenToUse !== undefined || merged.permissions !== undefined || merged.variants !== undefined;
193
217
  if (!hasValues) return undefined;
194
218
  return merged;
195
219
  }
@@ -320,6 +344,9 @@ function resolveSubagentProfileRuntimeConfig(input) {
320
344
  });
321
345
  return {
322
346
  model: variant?.model ?? profile.model,
347
+ thinking: variant?.thinking ?? profile.thinking,
348
+ tools: variant?.tools ?? profile.tools,
349
+ maxTurns: variant?.maxTurns ?? profile.maxTurns,
323
350
  prompt: variant?.prompt ?? profile.prompt,
324
351
  description: variant?.description ?? profile.description,
325
352
  whenToUse: variant?.whenToUse ?? profile.whenToUse,
@@ -1,9 +1,9 @@
1
- import { SubagentToolRuntime, createSubagentToolRuntime, createSubagentTools, registerAgentControllerTool } from "./agent-controller.js";
1
+ import { SubagentToolRuntime, createSubagentToolRuntime, createSubagentTools, registerAgentControllerTool, resolveSpawnConfig } from "./agent-controller.js";
2
2
  import { SubagentProfilePatch, SubagentProfilePatchSchema, SubagentProfileVariantMapPatchSchema, SubagentProfileVariantPatch, SubagentProfileVariantPatchSchema, SubagentToolPermissionDecisionPatch, SubagentToolPermissionDecisionSchema, SubagentToolPermissionMapSchema, parseSubagentProfilePatch, parseSubagentProfileVariantPatch } from "./schema.js";
3
- import { DEFAULT_SUBAGENT_RUNTIME_CONFIG, ResolvedSubagentProfileRuntimeConfig, SubagentBackend, SubagentProfileRuntimeConfig, SubagentProfileVariantRuntimeConfig, SubagentRuntimeConfig, SubagentToolPermissionDecision, SubagentsConfig, SubagentsConfigSchema, getSubagentConfiguredModel, getSubagentProfileRuntimeConfig, isSubagentRuntimeConfig, mergeSubagentRuntimeConfig, normalizeSubagentModelOverride, resolveSubagentProfileRuntimeConfig, resolveSubagentVariantPattern, subagentsConfigModule } from "./config.js";
3
+ import { DEFAULT_SUBAGENT_RUNTIME_CONFIG, ResolvedSubagentProfileRuntimeConfig, SubagentBackend, SubagentProfileRuntimeConfig, SubagentProfileVariantRuntimeConfig, SubagentRuntimeConfig, SubagentThinkingLevel, SubagentToolPermissionDecision, SubagentsConfig, SubagentsConfigSchema, getSubagentConfiguredModel, getSubagentProfileRuntimeConfig, isSubagentRuntimeConfig, mergeSubagentRuntimeConfig, normalizeSubagentModelOverride, resolveSubagentProfileRuntimeConfig, resolveSubagentVariantPattern, subagentsConfigModule } from "./config.js";
4
4
  import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
5
5
 
6
6
  //#region src/extension.d.ts
7
7
  declare function registerSubagentsExtension(pi: ExtensionAPI): void;
8
8
  //#endregion
9
- export { DEFAULT_SUBAGENT_RUNTIME_CONFIG, ResolvedSubagentProfileRuntimeConfig, SubagentBackend, SubagentProfilePatch, SubagentProfilePatchSchema, SubagentProfileRuntimeConfig, SubagentProfileVariantMapPatchSchema, SubagentProfileVariantPatch, SubagentProfileVariantPatchSchema, SubagentProfileVariantRuntimeConfig, SubagentRuntimeConfig, SubagentToolPermissionDecision, SubagentToolPermissionDecisionPatch, SubagentToolPermissionDecisionSchema, SubagentToolPermissionMapSchema, SubagentToolRuntime, SubagentsConfig, SubagentsConfigSchema, createSubagentToolRuntime, createSubagentTools, registerSubagentsExtension as default, getSubagentConfiguredModel, getSubagentProfileRuntimeConfig, isSubagentRuntimeConfig, mergeSubagentRuntimeConfig, normalizeSubagentModelOverride, parseSubagentProfilePatch, parseSubagentProfileVariantPatch, registerAgentControllerTool, resolveSubagentProfileRuntimeConfig, resolveSubagentVariantPattern, subagentsConfigModule };
9
+ export { DEFAULT_SUBAGENT_RUNTIME_CONFIG, ResolvedSubagentProfileRuntimeConfig, SubagentBackend, SubagentProfilePatch, SubagentProfilePatchSchema, SubagentProfileRuntimeConfig, SubagentProfileVariantMapPatchSchema, SubagentProfileVariantPatch, SubagentProfileVariantPatchSchema, SubagentProfileVariantRuntimeConfig, SubagentRuntimeConfig, SubagentThinkingLevel, SubagentToolPermissionDecision, SubagentToolPermissionDecisionPatch, SubagentToolPermissionDecisionSchema, SubagentToolPermissionMapSchema, SubagentToolRuntime, SubagentsConfig, SubagentsConfigSchema, createSubagentToolRuntime, createSubagentTools, registerSubagentsExtension as default, getSubagentConfiguredModel, getSubagentProfileRuntimeConfig, isSubagentRuntimeConfig, mergeSubagentRuntimeConfig, normalizeSubagentModelOverride, parseSubagentProfilePatch, parseSubagentProfileVariantPatch, registerAgentControllerTool, resolveSpawnConfig, resolveSubagentProfileRuntimeConfig, resolveSubagentVariantPattern, subagentsConfigModule };
package/dist/extension.js CHANGED
@@ -1,6 +1,6 @@
1
- import { createSubagentToolRuntime, createSubagentTools, registerAgentControllerTool } from "./agent-controller.js";
2
1
  import { SubagentProfilePatchSchema, SubagentProfileVariantMapPatchSchema, SubagentProfileVariantPatchSchema, SubagentToolPermissionDecisionSchema, SubagentToolPermissionMapSchema, parseSubagentProfilePatch, parseSubagentProfileVariantPatch } from "./schema.js";
3
2
  import { DEFAULT_SUBAGENT_RUNTIME_CONFIG, SubagentsConfigSchema, getSubagentConfiguredModel, getSubagentProfileRuntimeConfig, isSubagentRuntimeConfig, mergeSubagentRuntimeConfig, normalizeSubagentModelOverride, resolveSubagentProfileRuntimeConfig, resolveSubagentVariantPattern, subagentsConfigModule } from "./config.js";
3
+ import { createSubagentToolRuntime, createSubagentTools, registerAgentControllerTool, resolveSpawnConfig } from "./agent-controller.js";
4
4
 
5
5
  //#region src/extension.ts
6
6
  function registerSubagentsExtension(pi) {
@@ -8,4 +8,4 @@ function registerSubagentsExtension(pi) {
8
8
  }
9
9
 
10
10
  //#endregion
11
- export { DEFAULT_SUBAGENT_RUNTIME_CONFIG, SubagentProfilePatchSchema, SubagentProfileVariantMapPatchSchema, SubagentProfileVariantPatchSchema, SubagentToolPermissionDecisionSchema, SubagentToolPermissionMapSchema, SubagentsConfigSchema, createSubagentToolRuntime, createSubagentTools, registerSubagentsExtension as default, getSubagentConfiguredModel, getSubagentProfileRuntimeConfig, isSubagentRuntimeConfig, mergeSubagentRuntimeConfig, normalizeSubagentModelOverride, parseSubagentProfilePatch, parseSubagentProfileVariantPatch, registerAgentControllerTool, resolveSubagentProfileRuntimeConfig, resolveSubagentVariantPattern, subagentsConfigModule };
11
+ export { DEFAULT_SUBAGENT_RUNTIME_CONFIG, SubagentProfilePatchSchema, SubagentProfileVariantMapPatchSchema, SubagentProfileVariantPatchSchema, SubagentToolPermissionDecisionSchema, SubagentToolPermissionMapSchema, SubagentsConfigSchema, createSubagentToolRuntime, createSubagentTools, registerSubagentsExtension as default, getSubagentConfiguredModel, getSubagentProfileRuntimeConfig, isSubagentRuntimeConfig, mergeSubagentRuntimeConfig, normalizeSubagentModelOverride, parseSubagentProfilePatch, parseSubagentProfileVariantPatch, registerAgentControllerTool, resolveSpawnConfig, resolveSubagentProfileRuntimeConfig, resolveSubagentVariantPattern, subagentsConfigModule };
package/dist/schema.d.ts CHANGED
@@ -5,6 +5,9 @@ declare const SubagentToolPermissionDecisionSchema: Type.TUnion<[Type.TLiteral<"
5
5
  declare const SubagentToolPermissionMapSchema: Type.TRecord<"^.*$", Type.TUnion<[Type.TLiteral<"allow">, Type.TLiteral<"deny">, Type.TLiteral<"inherit">, Type.TLiteral<"ask">]>>;
6
6
  declare const SubagentProfileVariantPatchSchema: Type.TObject<{
7
7
  model: Type.TOptional<Type.TString>;
8
+ thinking: Type.TOptional<Type.TUnion<[Type.TLiteral<"off">, Type.TLiteral<"minimal">, Type.TLiteral<"low">, Type.TLiteral<"medium">, Type.TLiteral<"high">, Type.TLiteral<"xhigh">]>>;
9
+ tools: Type.TOptional<Type.TArray<Type.TString>>;
10
+ maxTurns: Type.TOptional<Type.TInteger>;
8
11
  prompt: Type.TOptional<Type.TString>;
9
12
  description: Type.TOptional<Type.TString>;
10
13
  whenToUse: Type.TOptional<Type.TArray<Type.TString>>;
@@ -12,6 +15,9 @@ declare const SubagentProfileVariantPatchSchema: Type.TObject<{
12
15
  }>;
13
16
  declare const SubagentProfileVariantMapPatchSchema: Type.TRecord<"^.*$", Type.TObject<{
14
17
  model: Type.TOptional<Type.TString>;
18
+ thinking: Type.TOptional<Type.TUnion<[Type.TLiteral<"off">, Type.TLiteral<"minimal">, Type.TLiteral<"low">, Type.TLiteral<"medium">, Type.TLiteral<"high">, Type.TLiteral<"xhigh">]>>;
19
+ tools: Type.TOptional<Type.TArray<Type.TString>>;
20
+ maxTurns: Type.TOptional<Type.TInteger>;
15
21
  prompt: Type.TOptional<Type.TString>;
16
22
  description: Type.TOptional<Type.TString>;
17
23
  whenToUse: Type.TOptional<Type.TArray<Type.TString>>;
@@ -19,12 +25,18 @@ declare const SubagentProfileVariantMapPatchSchema: Type.TRecord<"^.*$", Type.TO
19
25
  }>>;
20
26
  declare const SubagentProfilePatchSchema: Type.TObject<{
21
27
  model: Type.TOptional<Type.TString>;
28
+ thinking: Type.TOptional<Type.TUnion<[Type.TLiteral<"off">, Type.TLiteral<"minimal">, Type.TLiteral<"low">, Type.TLiteral<"medium">, Type.TLiteral<"high">, Type.TLiteral<"xhigh">]>>;
29
+ tools: Type.TOptional<Type.TArray<Type.TString>>;
30
+ maxTurns: Type.TOptional<Type.TInteger>;
22
31
  prompt: Type.TOptional<Type.TString>;
23
32
  description: Type.TOptional<Type.TString>;
24
33
  whenToUse: Type.TOptional<Type.TArray<Type.TString>>;
25
34
  permissions: Type.TOptional<Type.TRecord<"^.*$", Type.TUnion<[Type.TLiteral<"allow">, Type.TLiteral<"deny">, Type.TLiteral<"inherit">, Type.TLiteral<"ask">]>>>;
26
35
  variants: Type.TOptional<Type.TRecord<"^.*$", Type.TObject<{
27
36
  model: Type.TOptional<Type.TString>;
37
+ thinking: Type.TOptional<Type.TUnion<[Type.TLiteral<"off">, Type.TLiteral<"minimal">, Type.TLiteral<"low">, Type.TLiteral<"medium">, Type.TLiteral<"high">, Type.TLiteral<"xhigh">]>>;
38
+ tools: Type.TOptional<Type.TArray<Type.TString>>;
39
+ maxTurns: Type.TOptional<Type.TInteger>;
28
40
  prompt: Type.TOptional<Type.TString>;
29
41
  description: Type.TOptional<Type.TString>;
30
42
  whenToUse: Type.TOptional<Type.TArray<Type.TString>>;
package/dist/schema.js CHANGED
@@ -13,6 +13,16 @@ const SubagentToolPermissionDecisionSchema = Type.Union([
13
13
  const SubagentToolPermissionMapSchema = Type.Record(NonEmptyStringSchema, SubagentToolPermissionDecisionSchema);
14
14
  const SubagentProfileVariantPatchSchema = Type.Object({
15
15
  model: Type.Optional(NonEmptyStringSchema),
16
+ thinking: Type.Optional(Type.Union([
17
+ Type.Literal("off"),
18
+ Type.Literal("minimal"),
19
+ Type.Literal("low"),
20
+ Type.Literal("medium"),
21
+ Type.Literal("high"),
22
+ Type.Literal("xhigh")
23
+ ])),
24
+ tools: Type.Optional(NonEmptyStringArraySchema),
25
+ maxTurns: Type.Optional(Type.Integer({ minimum: 1 })),
16
26
  prompt: Type.Optional(NonEmptyStringSchema),
17
27
  description: Type.Optional(NonEmptyStringSchema),
18
28
  whenToUse: Type.Optional(NonEmptyStringArraySchema),
@@ -21,6 +31,16 @@ const SubagentProfileVariantPatchSchema = Type.Object({
21
31
  const SubagentProfileVariantMapPatchSchema = Type.Record(NonEmptyStringSchema, SubagentProfileVariantPatchSchema);
22
32
  const SubagentProfilePatchSchema = Type.Object({
23
33
  model: Type.Optional(NonEmptyStringSchema),
34
+ thinking: Type.Optional(Type.Union([
35
+ Type.Literal("off"),
36
+ Type.Literal("minimal"),
37
+ Type.Literal("low"),
38
+ Type.Literal("medium"),
39
+ Type.Literal("high"),
40
+ Type.Literal("xhigh")
41
+ ])),
42
+ tools: Type.Optional(NonEmptyStringArraySchema),
43
+ maxTurns: Type.Optional(Type.Integer({ minimum: 1 })),
24
44
  prompt: Type.Optional(NonEmptyStringSchema),
25
45
  description: Type.Optional(NonEmptyStringSchema),
26
46
  whenToUse: Type.Optional(NonEmptyStringArraySchema),
@@ -42,6 +62,19 @@ function toTrimmedStringArray(value) {
42
62
  if (normalized.length === 0) return undefined;
43
63
  return normalized;
44
64
  }
65
+ function toPositiveInteger(value) {
66
+ if (typeof value !== "number") return undefined;
67
+ if (!Number.isInteger(value) || value <= 0) return undefined;
68
+ return value;
69
+ }
70
+ function toThinking(value) {
71
+ const trimmed = toTrimmedString(value)?.toLowerCase();
72
+ if (!trimmed) return undefined;
73
+ if (trimmed !== "off" && trimmed !== "minimal" && trimmed !== "low" && trimmed !== "medium" && trimmed !== "high" && trimmed !== "xhigh") {
74
+ return undefined;
75
+ }
76
+ return trimmed;
77
+ }
45
78
  function normalizeSubagentPermissionMapInput(value) {
46
79
  if (!isObjectRecord(value)) return undefined;
47
80
  const normalized = {};
@@ -63,12 +96,18 @@ function normalizeSubagentPermissionMapInput(value) {
63
96
  function normalizeSubagentProfileVariantPatchInput(input) {
64
97
  if (!isObjectRecord(input)) return input;
65
98
  const model = toTrimmedString(Reflect.get(input, "model"));
99
+ const thinking = toThinking(Reflect.get(input, "thinking"));
100
+ const tools = toTrimmedStringArray(Reflect.get(input, "tools"));
101
+ const maxTurns = toPositiveInteger(Reflect.get(input, "maxTurns"));
66
102
  const prompt = toTrimmedString(Reflect.get(input, "prompt"));
67
103
  const description = toTrimmedString(Reflect.get(input, "description"));
68
104
  const whenToUse = toTrimmedStringArray(Reflect.get(input, "whenToUse"));
69
105
  const permissions = normalizeSubagentPermissionMapInput(Reflect.get(input, "permissions"));
70
106
  return {
71
107
  ...model ? { model } : {},
108
+ ...thinking ? { thinking } : {},
109
+ ...tools ? { tools } : {},
110
+ ...maxTurns ? { maxTurns } : {},
72
111
  ...prompt ? { prompt } : {},
73
112
  ...description ? { description } : {},
74
113
  ...whenToUse ? { whenToUse } : {},
@@ -95,6 +134,9 @@ function normalizeSubagentProfileVariantMapInput(input) {
95
134
  function normalizeSubagentProfilePatchInput(input) {
96
135
  if (!isObjectRecord(input)) return input;
97
136
  const model = toTrimmedString(Reflect.get(input, "model"));
137
+ const thinking = toThinking(Reflect.get(input, "thinking"));
138
+ const tools = toTrimmedStringArray(Reflect.get(input, "tools"));
139
+ const maxTurns = toPositiveInteger(Reflect.get(input, "maxTurns"));
98
140
  const prompt = toTrimmedString(Reflect.get(input, "prompt"));
99
141
  const description = toTrimmedString(Reflect.get(input, "description"));
100
142
  const whenToUse = toTrimmedStringArray(Reflect.get(input, "whenToUse"));
@@ -102,6 +144,9 @@ function normalizeSubagentProfilePatchInput(input) {
102
144
  const variants = normalizeSubagentProfileVariantMapInput(Reflect.get(input, "variants"));
103
145
  return {
104
146
  ...model ? { model } : {},
147
+ ...thinking ? { thinking } : {},
148
+ ...tools ? { tools } : {},
149
+ ...maxTurns ? { maxTurns } : {},
105
150
  ...prompt ? { prompt } : {},
106
151
  ...description ? { description } : {},
107
152
  ...whenToUse ? { whenToUse } : {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-ohm/subagents",
3
- "version": "0.6.4-dev.25620170147.1.0b6891f",
3
+ "version": "0.6.4-dev.25636965069.1.619ed5f",
4
4
  "homepage": "https://github.com/pi-ohm/pi-ohm/tree/dev/packages/subagents#readme",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,8 +36,8 @@
36
36
  "@earendil-works/pi-agent-core": "0.74.0",
37
37
  "@earendil-works/pi-ai": "0.74.0",
38
38
  "@earendil-works/pi-coding-agent": "0.74.0",
39
- "@pi-ohm/core": "0.6.4-dev.25620170147.1.0b6891f",
40
- "@pi-ohm/tui": "0.6.4-dev.25620170147.1.0b6891f",
39
+ "@pi-ohm/core": "0.6.4-dev.25636965069.1.619ed5f",
40
+ "@pi-ohm/tui": "0.6.4-dev.25636965069.1.619ed5f",
41
41
  "better-result": "2.9.2",
42
42
  "typebox": "^1.0.68",
43
43
  "zod": "^4"