@pi-ohm/config 0.6.3 → 0.6.4-dev.22132458683.1.8646f56

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.
Files changed (3) hide show
  1. package/README.md +8 -0
  2. package/package.json +1 -1
  3. package/src/index.ts +113 -0
package/README.md CHANGED
@@ -11,3 +11,11 @@ Responsibilities:
11
11
  - `${configDir}/ohm.json`
12
12
  - `${configDir}/ohm.providers.json`
13
13
  - expose typed runtime config helpers to feature packages
14
+
15
+ Subagents runtime config highlights:
16
+
17
+ - `subagents.taskMaxConcurrency`
18
+ - `subagents.taskRetentionMs`
19
+ - `subagents.permissions.default` (`allow|deny`)
20
+ - `subagents.permissions.subagents` (per-subagent overrides)
21
+ - `subagents.permissions.allowInternalRouting`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-ohm/config",
3
- "version": "0.6.3",
3
+ "version": "0.6.4-dev.22132458683.1.8646f56",
4
4
  "homepage": "https://github.com/pi-ohm/pi-ohm/tree/dev/packages/config#readme",
5
5
  "repository": {
6
6
  "type": "git",
package/src/index.ts CHANGED
@@ -38,11 +38,22 @@ export interface OhmPainterProviders {
38
38
  };
39
39
  }
40
40
 
41
+ export interface OhmSubagentRuntimeConfig {
42
+ taskMaxConcurrency: number;
43
+ taskRetentionMs: number;
44
+ permissions: {
45
+ default: "allow" | "deny";
46
+ subagents: Record<string, "allow" | "deny">;
47
+ allowInternalRouting: boolean;
48
+ };
49
+ }
50
+
41
51
  export interface OhmRuntimeConfig {
42
52
  defaultMode: OhmMode;
43
53
  subagentBackend: OhmSubagentBackend;
44
54
  features: OhmFeatureFlags;
45
55
  painter: OhmPainterProviders;
56
+ subagents?: OhmSubagentRuntimeConfig;
46
57
  }
47
58
 
48
59
  export interface OhmConfigPaths {
@@ -84,6 +95,15 @@ const DEFAULT_OHM_CONFIG: OhmRuntimeConfig = {
84
95
  apiVersion: "2025-04-01-preview",
85
96
  },
86
97
  },
98
+ subagents: {
99
+ taskMaxConcurrency: 3,
100
+ taskRetentionMs: 1000 * 60 * 60 * 24,
101
+ permissions: {
102
+ default: "allow",
103
+ subagents: {},
104
+ allowInternalRouting: false,
105
+ },
106
+ },
87
107
  };
88
108
 
89
109
  type JsonMap = Record<string, unknown>;
@@ -156,6 +176,41 @@ function normalizeString(value: unknown, fallback: string): string {
156
176
  return fallback;
157
177
  }
158
178
 
179
+ function normalizePositiveInteger(value: unknown, fallback: number): number {
180
+ if (typeof value !== "number") return fallback;
181
+ if (!Number.isInteger(value) || value <= 0) return fallback;
182
+ return value;
183
+ }
184
+
185
+ function normalizePermissionDecision(value: unknown, fallback: "allow" | "deny"): "allow" | "deny" {
186
+ if (value === "allow" || value === "deny") return value;
187
+
188
+ // Legacy compatibility: treat deprecated "ask" as deny-safe behavior.
189
+ if (value === "ask") return "deny";
190
+
191
+ return fallback;
192
+ }
193
+
194
+ function normalizePermissionDecisionMap(
195
+ value: unknown,
196
+ fallback: Record<string, "allow" | "deny">,
197
+ ): Record<string, "allow" | "deny"> {
198
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
199
+ return fallback;
200
+ }
201
+
202
+ const normalized: Record<string, "allow" | "deny"> = {};
203
+ for (const [key, decision] of Object.entries(value)) {
204
+ const trimmedKey = key.trim().toLowerCase();
205
+ if (trimmedKey.length === 0) continue;
206
+
207
+ const normalizedDecision = normalizePermissionDecision(decision, "allow");
208
+ normalized[trimmedKey] = normalizedDecision;
209
+ }
210
+
211
+ return normalized;
212
+ }
213
+
159
214
  function mergeConfig(base: OhmRuntimeConfig, patch: JsonMap): OhmRuntimeConfig {
160
215
  const next: OhmRuntimeConfig = structuredClone(base);
161
216
 
@@ -232,6 +287,64 @@ function mergeConfig(base: OhmRuntimeConfig, patch: JsonMap): OhmRuntimeConfig {
232
287
  next.painter.azureOpenai.apiVersion,
233
288
  );
234
289
 
290
+ const subagentPatch =
291
+ patch.subagents && typeof patch.subagents === "object"
292
+ ? (patch.subagents as JsonMap)
293
+ : undefined;
294
+
295
+ const subagentDefaults =
296
+ next.subagents ??
297
+ ({
298
+ taskMaxConcurrency: DEFAULT_OHM_CONFIG.subagents?.taskMaxConcurrency ?? 3,
299
+ taskRetentionMs: DEFAULT_OHM_CONFIG.subagents?.taskRetentionMs ?? 1000 * 60 * 60 * 24,
300
+ permissions: {
301
+ default: DEFAULT_OHM_CONFIG.subagents?.permissions.default ?? "allow",
302
+ subagents: DEFAULT_OHM_CONFIG.subagents?.permissions.subagents ?? {},
303
+ allowInternalRouting:
304
+ DEFAULT_OHM_CONFIG.subagents?.permissions.allowInternalRouting ?? false,
305
+ },
306
+ } satisfies OhmSubagentRuntimeConfig);
307
+
308
+ const taskMaxConcurrency = normalizePositiveInteger(
309
+ subagentPatch?.taskMaxConcurrency,
310
+ subagentDefaults.taskMaxConcurrency,
311
+ );
312
+
313
+ const taskRetentionMs = normalizePositiveInteger(
314
+ subagentPatch?.taskRetentionMs,
315
+ subagentDefaults.taskRetentionMs,
316
+ );
317
+
318
+ const permissionsPatch =
319
+ subagentPatch?.permissions && typeof subagentPatch.permissions === "object"
320
+ ? (subagentPatch.permissions as JsonMap)
321
+ : undefined;
322
+
323
+ const permissionsDefault = normalizePermissionDecision(
324
+ permissionsPatch?.default,
325
+ subagentDefaults.permissions.default,
326
+ );
327
+
328
+ const permissionsSubagents = normalizePermissionDecisionMap(
329
+ permissionsPatch?.subagents,
330
+ subagentDefaults.permissions.subagents,
331
+ );
332
+
333
+ const allowInternalRouting = normalizeBoolean(
334
+ permissionsPatch?.allowInternalRouting,
335
+ subagentDefaults.permissions.allowInternalRouting,
336
+ );
337
+
338
+ next.subagents = {
339
+ taskMaxConcurrency,
340
+ taskRetentionMs,
341
+ permissions: {
342
+ default: permissionsDefault,
343
+ subagents: permissionsSubagents,
344
+ allowInternalRouting,
345
+ },
346
+ };
347
+
235
348
  return next;
236
349
  }
237
350