@kolisachint/hoocode-agent 0.4.133 → 0.4.135
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/CHANGELOG.md +4 -0
- package/dist/core/model-categories.d.ts +51 -12
- package/dist/core/model-categories.d.ts.map +1 -1
- package/dist/core/model-categories.js +89 -14
- package/dist/core/model-categories.js.map +1 -1
- package/dist/core/settings-types.d.ts +14 -2
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/subagent-pool-instance.d.ts +10 -2
- package/dist/core/subagent-pool-instance.d.ts.map +1 -1
- package/dist/core/subagent-pool-instance.js +10 -2
- package/dist/core/subagent-pool-instance.js.map +1 -1
- package/dist/core/subagent-pool.d.ts +9 -0
- package/dist/core/subagent-pool.d.ts.map +1 -1
- package/dist/core/subagent-pool.js +6 -3
- package/dist/core/subagent-pool.js.map +1 -1
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js +12 -4
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/core/warm-subagent-pool-instance.d.ts +9 -2
- package/dist/core/warm-subagent-pool-instance.d.ts.map +1 -1
- package/dist/core/warm-subagent-pool-instance.js +9 -3
- package/dist/core/warm-subagent-pool-instance.js.map +1 -1
- package/dist/core/warm-subagent-pool.d.ts +13 -2
- package/dist/core/warm-subagent-pool.d.ts.map +1 -1
- package/dist/core/warm-subagent-pool.js +16 -7
- package/dist/core/warm-subagent-pool.js.map +1 -1
- package/dist/modes/interactive/command-executor.d.ts.map +1 -1
- package/dist/modes/interactive/command-executor.js +1 -1
- package/dist/modes/interactive/command-executor.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,33 +2,72 @@
|
|
|
2
2
|
* Model categories for subagent model selection.
|
|
3
3
|
*
|
|
4
4
|
* A category (`fast` | `standard` | `capable`) is a provider-neutral indirection
|
|
5
|
-
* that maps to an explicit model id
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* default
|
|
5
|
+
* that maps to an explicit model id. Precedence:
|
|
6
|
+
*
|
|
7
|
+
* 1. An explicit `settings.modelCategories[category]` always wins.
|
|
8
|
+
* 2. Otherwise, when a set of available models is supplied, the category
|
|
9
|
+
* resolves to a default *derived* from those models (see
|
|
10
|
+
* `deriveDefaultModelCategories`) — never a hardcoded provider/model id.
|
|
11
|
+
* 3. Otherwise it resolves to `undefined`, which callers treat as "no override"
|
|
12
|
+
* and fall back to the agent's or parent's default model.
|
|
13
|
+
*
|
|
14
|
+
* No concrete model names are baked in here, so the feature never assumes a
|
|
15
|
+
* particular provider.
|
|
10
16
|
*/
|
|
17
|
+
import type { Api, Model } from "@kolisachint/hoocode-ai";
|
|
11
18
|
import type { Settings } from "./settings-manager.js";
|
|
12
19
|
/** Valid model category names */
|
|
13
20
|
export type ModelCategory = "fast" | "standard" | "capable";
|
|
14
21
|
/** Check if a string is a valid model category */
|
|
15
22
|
export declare function isModelCategory(value: string): value is ModelCategory;
|
|
16
23
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
24
|
+
* Derive a default model for each tier from the user's available models, used
|
|
25
|
+
* only when a tier is not explicitly configured in `settings.modelCategories`.
|
|
26
|
+
*
|
|
27
|
+
* The rule is deliberately transparent (config, not magic) and provider-neutral:
|
|
28
|
+
* nothing is hardcoded, everything is derived from what the user actually has.
|
|
29
|
+
*
|
|
30
|
+
* 1. `capable` = the user's PRIMARY model: the configured default
|
|
31
|
+
* (`settings.defaultProvider`/`defaultModel`) when it is in the available
|
|
32
|
+
* set, otherwise the most capable available model, using combined token
|
|
33
|
+
* price (input + output cost) as a stand-in for capability.
|
|
34
|
+
* 2. `fast` and `standard` are the cheapest and the upper-median of every
|
|
35
|
+
* available model priced at or below `capable`, ordered cheapest-first.
|
|
36
|
+
* Clamping to `capable`'s price keeps the tiers monotonic
|
|
37
|
+
* (`fast` <= `standard` <= `capable`), and drawing from the whole available
|
|
38
|
+
* set — not just `capable`'s own provider — still yields a genuinely cheap
|
|
39
|
+
* `fast` when the primary model's provider has nothing cheaper (a strict
|
|
40
|
+
* same-provider rule collapses every tier onto a single-model provider).
|
|
41
|
+
*
|
|
42
|
+
* Every ordering breaks ties on a fixed key (context window, then id) so the same
|
|
43
|
+
* available set always yields the same mapping. An empty available set yields an
|
|
44
|
+
* empty map (every tier resolves to `undefined`, i.e. inherit the parent model).
|
|
45
|
+
*/
|
|
46
|
+
export declare function deriveDefaultModelCategories(availableModels: readonly Model<Api>[], settings?: Settings): {
|
|
47
|
+
fast?: string;
|
|
48
|
+
standard?: string;
|
|
49
|
+
capable?: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Resolve a model category to a model id. An explicit
|
|
53
|
+
* `settings.modelCategories[category]` wins; otherwise a default is derived from
|
|
54
|
+
* `availableModels` (provider-neutral, see `deriveDefaultModelCategories`); when
|
|
55
|
+
* neither applies the category resolves to `undefined` (a no-op, so the caller
|
|
56
|
+
* keeps its existing model).
|
|
20
57
|
*
|
|
21
58
|
* @param category - The model category (fast, standard, capable)
|
|
22
59
|
* @param settings - The current settings (may contain modelCategories config)
|
|
60
|
+
* @param availableModels - The user's available/configured models to derive from
|
|
23
61
|
*/
|
|
24
|
-
export declare function resolveModelCategory(category: ModelCategory, settings?: Settings): string | undefined;
|
|
62
|
+
export declare function resolveModelCategory(category: ModelCategory, settings?: Settings, availableModels?: readonly Model<Api>[]): string | undefined;
|
|
25
63
|
/**
|
|
26
64
|
* Resolve a model string that might be a category reference. A category resolves
|
|
27
|
-
* to its configured model id (or `undefined` when
|
|
28
|
-
* is already a concrete model id or alias and is returned as-is.
|
|
65
|
+
* to its configured or derived model id (or `undefined` when neither applies);
|
|
66
|
+
* any other string is already a concrete model id or alias and is returned as-is.
|
|
29
67
|
*
|
|
30
68
|
* @param model - The model string (could be a category, alias, or full model ID)
|
|
31
69
|
* @param settings - The current settings (may contain modelCategories config)
|
|
70
|
+
* @param availableModels - The user's available/configured models to derive from
|
|
32
71
|
*/
|
|
33
|
-
export declare function resolveModelReference(model: string, settings?: Settings): string | undefined;
|
|
72
|
+
export declare function resolveModelReference(model: string, settings?: Settings, availableModels?: readonly Model<Api>[]): string | undefined;
|
|
34
73
|
//# sourceMappingURL=model-categories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-categories.d.ts","sourceRoot":"","sources":["../../src/core/model-categories.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"model-categories.d.ts","sourceRoot":"","sources":["../../src/core/model-categories.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,iCAAiC;AACjC,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;AAE5D,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,aAAa,CAErE;AAiBD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,4BAA4B,CAC3C,eAAe,EAAE,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,EACtC,QAAQ,CAAC,EAAE,QAAQ,GACjB;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CA8BxD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CACnC,QAAQ,EAAE,aAAa,EACvB,QAAQ,CAAC,EAAE,QAAQ,EACnB,eAAe,CAAC,EAAE,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,GACrC,MAAM,GAAG,SAAS,CAOpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,QAAQ,EACnB,eAAe,CAAC,EAAE,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,GACrC,MAAM,GAAG,SAAS,CAKpB","sourcesContent":["/**\n * Model categories for subagent model selection.\n *\n * A category (`fast` | `standard` | `capable`) is a provider-neutral indirection\n * that maps to an explicit model id. Precedence:\n *\n * 1. An explicit `settings.modelCategories[category]` always wins.\n * 2. Otherwise, when a set of available models is supplied, the category\n * resolves to a default *derived* from those models (see\n * `deriveDefaultModelCategories`) — never a hardcoded provider/model id.\n * 3. Otherwise it resolves to `undefined`, which callers treat as \"no override\"\n * and fall back to the agent's or parent's default model.\n *\n * No concrete model names are baked in here, so the feature never assumes a\n * particular provider.\n */\n\nimport type { Api, Model } from \"@kolisachint/hoocode-ai\";\nimport type { Settings } from \"./settings-manager.js\";\n\n/** Valid model category names */\nexport type ModelCategory = \"fast\" | \"standard\" | \"capable\";\n\n/** Check if a string is a valid model category */\nexport function isModelCategory(value: string): value is ModelCategory {\n\treturn value === \"fast\" || value === \"standard\" || value === \"capable\";\n}\n\n/** A category maps to a concrete model reference in `<provider>/<id>` form. */\nfunction modelRef(model: Model<Api>): string {\n\treturn `${model.provider}/${model.id}`;\n}\n\n/** Combined per-token price (input + output), used as a capability/cost proxy. */\nfunction combinedPrice(model: Model<Api>): number {\n\treturn model.cost.input + model.cost.output;\n}\n\n/** Deterministic tie-break so identical available sets always yield the same pick. */\nfunction compareById(a: Model<Api>, b: Model<Api>): number {\n\treturn a.id < b.id ? -1 : a.id > b.id ? 1 : 0;\n}\n\n/**\n * Derive a default model for each tier from the user's available models, used\n * only when a tier is not explicitly configured in `settings.modelCategories`.\n *\n * The rule is deliberately transparent (config, not magic) and provider-neutral:\n * nothing is hardcoded, everything is derived from what the user actually has.\n *\n * 1. `capable` = the user's PRIMARY model: the configured default\n * (`settings.defaultProvider`/`defaultModel`) when it is in the available\n * set, otherwise the most capable available model, using combined token\n * price (input + output cost) as a stand-in for capability.\n * 2. `fast` and `standard` are the cheapest and the upper-median of every\n * available model priced at or below `capable`, ordered cheapest-first.\n * Clamping to `capable`'s price keeps the tiers monotonic\n * (`fast` <= `standard` <= `capable`), and drawing from the whole available\n * set — not just `capable`'s own provider — still yields a genuinely cheap\n * `fast` when the primary model's provider has nothing cheaper (a strict\n * same-provider rule collapses every tier onto a single-model provider).\n *\n * Every ordering breaks ties on a fixed key (context window, then id) so the same\n * available set always yields the same mapping. An empty available set yields an\n * empty map (every tier resolves to `undefined`, i.e. inherit the parent model).\n */\nexport function deriveDefaultModelCategories(\n\tavailableModels: readonly Model<Api>[],\n\tsettings?: Settings,\n): { fast?: string; standard?: string; capable?: string } {\n\tif (availableModels.length === 0) return {};\n\n\t// capable = primary model.\n\tconst configuredDefault =\n\t\tsettings?.defaultProvider && settings?.defaultModel\n\t\t\t? availableModels.find((m) => m.provider === settings.defaultProvider && m.id === settings.defaultModel)\n\t\t\t: undefined;\n\t// Most capable = highest combined price; ties -> larger context window, then id.\n\tconst capable =\n\t\tconfiguredDefault ??\n\t\t[...availableModels].sort(\n\t\t\t(a, b) => combinedPrice(b) - combinedPrice(a) || b.contextWindow - a.contextWindow || compareById(a, b),\n\t\t)[0];\n\n\t// fast/standard: every model priced at or below capable, cheapest-first.\n\t// `capable` is always in this set (its price <= its own price), so it never empties.\n\tconst capablePrice = combinedPrice(capable);\n\tconst candidates = availableModels\n\t\t.filter((m) => combinedPrice(m) <= capablePrice)\n\t\t.sort((a, b) => combinedPrice(a) - combinedPrice(b) || a.contextWindow - b.contextWindow || compareById(a, b));\n\n\tconst fast = candidates[0] ?? capable;\n\tconst standard = candidates[Math.floor(candidates.length / 2)] ?? capable;\n\n\treturn {\n\t\tfast: modelRef(fast),\n\t\tstandard: modelRef(standard),\n\t\tcapable: modelRef(capable),\n\t};\n}\n\n/**\n * Resolve a model category to a model id. An explicit\n * `settings.modelCategories[category]` wins; otherwise a default is derived from\n * `availableModels` (provider-neutral, see `deriveDefaultModelCategories`); when\n * neither applies the category resolves to `undefined` (a no-op, so the caller\n * keeps its existing model).\n *\n * @param category - The model category (fast, standard, capable)\n * @param settings - The current settings (may contain modelCategories config)\n * @param availableModels - The user's available/configured models to derive from\n */\nexport function resolveModelCategory(\n\tcategory: ModelCategory,\n\tsettings?: Settings,\n\tavailableModels?: readonly Model<Api>[],\n): string | undefined {\n\tconst explicit = settings?.modelCategories?.[category];\n\tif (explicit) return explicit;\n\tif (availableModels && availableModels.length > 0) {\n\t\treturn deriveDefaultModelCategories(availableModels, settings)[category];\n\t}\n\treturn undefined;\n}\n\n/**\n * Resolve a model string that might be a category reference. A category resolves\n * to its configured or derived model id (or `undefined` when neither applies);\n * any other string is already a concrete model id or alias and is returned as-is.\n *\n * @param model - The model string (could be a category, alias, or full model ID)\n * @param settings - The current settings (may contain modelCategories config)\n * @param availableModels - The user's available/configured models to derive from\n */\nexport function resolveModelReference(\n\tmodel: string,\n\tsettings?: Settings,\n\tavailableModels?: readonly Model<Api>[],\n): string | undefined {\n\tif (isModelCategory(model)) {\n\t\treturn resolveModelCategory(model, settings, availableModels);\n\t}\n\treturn model;\n}\n"]}
|
|
@@ -2,38 +2,113 @@
|
|
|
2
2
|
* Model categories for subagent model selection.
|
|
3
3
|
*
|
|
4
4
|
* A category (`fast` | `standard` | `capable`) is a provider-neutral indirection
|
|
5
|
-
* that maps to an explicit model id
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* default
|
|
5
|
+
* that maps to an explicit model id. Precedence:
|
|
6
|
+
*
|
|
7
|
+
* 1. An explicit `settings.modelCategories[category]` always wins.
|
|
8
|
+
* 2. Otherwise, when a set of available models is supplied, the category
|
|
9
|
+
* resolves to a default *derived* from those models (see
|
|
10
|
+
* `deriveDefaultModelCategories`) — never a hardcoded provider/model id.
|
|
11
|
+
* 3. Otherwise it resolves to `undefined`, which callers treat as "no override"
|
|
12
|
+
* and fall back to the agent's or parent's default model.
|
|
13
|
+
*
|
|
14
|
+
* No concrete model names are baked in here, so the feature never assumes a
|
|
15
|
+
* particular provider.
|
|
10
16
|
*/
|
|
11
17
|
/** Check if a string is a valid model category */
|
|
12
18
|
export function isModelCategory(value) {
|
|
13
19
|
return value === "fast" || value === "standard" || value === "capable";
|
|
14
20
|
}
|
|
21
|
+
/** A category maps to a concrete model reference in `<provider>/<id>` form. */
|
|
22
|
+
function modelRef(model) {
|
|
23
|
+
return `${model.provider}/${model.id}`;
|
|
24
|
+
}
|
|
25
|
+
/** Combined per-token price (input + output), used as a capability/cost proxy. */
|
|
26
|
+
function combinedPrice(model) {
|
|
27
|
+
return model.cost.input + model.cost.output;
|
|
28
|
+
}
|
|
29
|
+
/** Deterministic tie-break so identical available sets always yield the same pick. */
|
|
30
|
+
function compareById(a, b) {
|
|
31
|
+
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Derive a default model for each tier from the user's available models, used
|
|
35
|
+
* only when a tier is not explicitly configured in `settings.modelCategories`.
|
|
36
|
+
*
|
|
37
|
+
* The rule is deliberately transparent (config, not magic) and provider-neutral:
|
|
38
|
+
* nothing is hardcoded, everything is derived from what the user actually has.
|
|
39
|
+
*
|
|
40
|
+
* 1. `capable` = the user's PRIMARY model: the configured default
|
|
41
|
+
* (`settings.defaultProvider`/`defaultModel`) when it is in the available
|
|
42
|
+
* set, otherwise the most capable available model, using combined token
|
|
43
|
+
* price (input + output cost) as a stand-in for capability.
|
|
44
|
+
* 2. `fast` and `standard` are the cheapest and the upper-median of every
|
|
45
|
+
* available model priced at or below `capable`, ordered cheapest-first.
|
|
46
|
+
* Clamping to `capable`'s price keeps the tiers monotonic
|
|
47
|
+
* (`fast` <= `standard` <= `capable`), and drawing from the whole available
|
|
48
|
+
* set — not just `capable`'s own provider — still yields a genuinely cheap
|
|
49
|
+
* `fast` when the primary model's provider has nothing cheaper (a strict
|
|
50
|
+
* same-provider rule collapses every tier onto a single-model provider).
|
|
51
|
+
*
|
|
52
|
+
* Every ordering breaks ties on a fixed key (context window, then id) so the same
|
|
53
|
+
* available set always yields the same mapping. An empty available set yields an
|
|
54
|
+
* empty map (every tier resolves to `undefined`, i.e. inherit the parent model).
|
|
55
|
+
*/
|
|
56
|
+
export function deriveDefaultModelCategories(availableModels, settings) {
|
|
57
|
+
if (availableModels.length === 0)
|
|
58
|
+
return {};
|
|
59
|
+
// capable = primary model.
|
|
60
|
+
const configuredDefault = settings?.defaultProvider && settings?.defaultModel
|
|
61
|
+
? availableModels.find((m) => m.provider === settings.defaultProvider && m.id === settings.defaultModel)
|
|
62
|
+
: undefined;
|
|
63
|
+
// Most capable = highest combined price; ties -> larger context window, then id.
|
|
64
|
+
const capable = configuredDefault ??
|
|
65
|
+
[...availableModels].sort((a, b) => combinedPrice(b) - combinedPrice(a) || b.contextWindow - a.contextWindow || compareById(a, b))[0];
|
|
66
|
+
// fast/standard: every model priced at or below capable, cheapest-first.
|
|
67
|
+
// `capable` is always in this set (its price <= its own price), so it never empties.
|
|
68
|
+
const capablePrice = combinedPrice(capable);
|
|
69
|
+
const candidates = availableModels
|
|
70
|
+
.filter((m) => combinedPrice(m) <= capablePrice)
|
|
71
|
+
.sort((a, b) => combinedPrice(a) - combinedPrice(b) || a.contextWindow - b.contextWindow || compareById(a, b));
|
|
72
|
+
const fast = candidates[0] ?? capable;
|
|
73
|
+
const standard = candidates[Math.floor(candidates.length / 2)] ?? capable;
|
|
74
|
+
return {
|
|
75
|
+
fast: modelRef(fast),
|
|
76
|
+
standard: modelRef(standard),
|
|
77
|
+
capable: modelRef(capable),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
15
80
|
/**
|
|
16
|
-
* Resolve a model category to
|
|
17
|
-
* `
|
|
18
|
-
*
|
|
81
|
+
* Resolve a model category to a model id. An explicit
|
|
82
|
+
* `settings.modelCategories[category]` wins; otherwise a default is derived from
|
|
83
|
+
* `availableModels` (provider-neutral, see `deriveDefaultModelCategories`); when
|
|
84
|
+
* neither applies the category resolves to `undefined` (a no-op, so the caller
|
|
85
|
+
* keeps its existing model).
|
|
19
86
|
*
|
|
20
87
|
* @param category - The model category (fast, standard, capable)
|
|
21
88
|
* @param settings - The current settings (may contain modelCategories config)
|
|
89
|
+
* @param availableModels - The user's available/configured models to derive from
|
|
22
90
|
*/
|
|
23
|
-
export function resolveModelCategory(category, settings) {
|
|
24
|
-
|
|
91
|
+
export function resolveModelCategory(category, settings, availableModels) {
|
|
92
|
+
const explicit = settings?.modelCategories?.[category];
|
|
93
|
+
if (explicit)
|
|
94
|
+
return explicit;
|
|
95
|
+
if (availableModels && availableModels.length > 0) {
|
|
96
|
+
return deriveDefaultModelCategories(availableModels, settings)[category];
|
|
97
|
+
}
|
|
98
|
+
return undefined;
|
|
25
99
|
}
|
|
26
100
|
/**
|
|
27
101
|
* Resolve a model string that might be a category reference. A category resolves
|
|
28
|
-
* to its configured model id (or `undefined` when
|
|
29
|
-
* is already a concrete model id or alias and is returned as-is.
|
|
102
|
+
* to its configured or derived model id (or `undefined` when neither applies);
|
|
103
|
+
* any other string is already a concrete model id or alias and is returned as-is.
|
|
30
104
|
*
|
|
31
105
|
* @param model - The model string (could be a category, alias, or full model ID)
|
|
32
106
|
* @param settings - The current settings (may contain modelCategories config)
|
|
107
|
+
* @param availableModels - The user's available/configured models to derive from
|
|
33
108
|
*/
|
|
34
|
-
export function resolveModelReference(model, settings) {
|
|
109
|
+
export function resolveModelReference(model, settings, availableModels) {
|
|
35
110
|
if (isModelCategory(model)) {
|
|
36
|
-
return resolveModelCategory(model, settings);
|
|
111
|
+
return resolveModelCategory(model, settings, availableModels);
|
|
37
112
|
}
|
|
38
113
|
return model;
|
|
39
114
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-categories.js","sourceRoot":"","sources":["../../src/core/model-categories.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"model-categories.js","sourceRoot":"","sources":["../../src/core/model-categories.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model categories for subagent model selection.\n *\n * A category (`fast` | `standard` | `capable`) is a provider-neutral indirection\n * that maps to an explicit model id. Precedence:\n *\n * 1. An explicit `settings.modelCategories[category]` always wins.\n * 2. Otherwise, when a set of available models is supplied, the category\n * resolves to a default *derived* from those models (see\n * `deriveDefaultModelCategories`) — never a hardcoded provider/model id.\n * 3. Otherwise it resolves to `undefined`, which callers treat as \"no override\"\n * and fall back to the agent's or parent's default model.\n *\n * No concrete model names are baked in here, so the feature never assumes a\n * particular provider.\n */\n\nimport type { Api, Model } from \"@kolisachint/hoocode-ai\";\nimport type { Settings } from \"./settings-manager.js\";\n\n/** Valid model category names */\nexport type ModelCategory = \"fast\" | \"standard\" | \"capable\";\n\n/** Check if a string is a valid model category */\nexport function isModelCategory(value: string): value is ModelCategory {\n\treturn value === \"fast\" || value === \"standard\" || value === \"capable\";\n}\n\n/** A category maps to a concrete model reference in `<provider>/<id>` form. */\nfunction modelRef(model: Model<Api>): string {\n\treturn `${model.provider}/${model.id}`;\n}\n\n/** Combined per-token price (input + output), used as a capability/cost proxy. */\nfunction combinedPrice(model: Model<Api>): number {\n\treturn model.cost.input + model.cost.output;\n}\n\n/** Deterministic tie-break so identical available sets always yield the same pick. */\nfunction compareById(a: Model<Api>, b: Model<Api>): number {\n\treturn a.id < b.id ? -1 : a.id > b.id ? 1 : 0;\n}\n\n/**\n * Derive a default model for each tier from the user's available models, used\n * only when a tier is not explicitly configured in `settings.modelCategories`.\n *\n * The rule is deliberately transparent (config, not magic) and provider-neutral:\n * nothing is hardcoded, everything is derived from what the user actually has.\n *\n * 1. `capable` = the user's PRIMARY model: the configured default\n * (`settings.defaultProvider`/`defaultModel`) when it is in the available\n * set, otherwise the most capable available model, using combined token\n * price (input + output cost) as a stand-in for capability.\n * 2. `fast` and `standard` are the cheapest and the upper-median of every\n * available model priced at or below `capable`, ordered cheapest-first.\n * Clamping to `capable`'s price keeps the tiers monotonic\n * (`fast` <= `standard` <= `capable`), and drawing from the whole available\n * set — not just `capable`'s own provider — still yields a genuinely cheap\n * `fast` when the primary model's provider has nothing cheaper (a strict\n * same-provider rule collapses every tier onto a single-model provider).\n *\n * Every ordering breaks ties on a fixed key (context window, then id) so the same\n * available set always yields the same mapping. An empty available set yields an\n * empty map (every tier resolves to `undefined`, i.e. inherit the parent model).\n */\nexport function deriveDefaultModelCategories(\n\tavailableModels: readonly Model<Api>[],\n\tsettings?: Settings,\n): { fast?: string; standard?: string; capable?: string } {\n\tif (availableModels.length === 0) return {};\n\n\t// capable = primary model.\n\tconst configuredDefault =\n\t\tsettings?.defaultProvider && settings?.defaultModel\n\t\t\t? availableModels.find((m) => m.provider === settings.defaultProvider && m.id === settings.defaultModel)\n\t\t\t: undefined;\n\t// Most capable = highest combined price; ties -> larger context window, then id.\n\tconst capable =\n\t\tconfiguredDefault ??\n\t\t[...availableModels].sort(\n\t\t\t(a, b) => combinedPrice(b) - combinedPrice(a) || b.contextWindow - a.contextWindow || compareById(a, b),\n\t\t)[0];\n\n\t// fast/standard: every model priced at or below capable, cheapest-first.\n\t// `capable` is always in this set (its price <= its own price), so it never empties.\n\tconst capablePrice = combinedPrice(capable);\n\tconst candidates = availableModels\n\t\t.filter((m) => combinedPrice(m) <= capablePrice)\n\t\t.sort((a, b) => combinedPrice(a) - combinedPrice(b) || a.contextWindow - b.contextWindow || compareById(a, b));\n\n\tconst fast = candidates[0] ?? capable;\n\tconst standard = candidates[Math.floor(candidates.length / 2)] ?? capable;\n\n\treturn {\n\t\tfast: modelRef(fast),\n\t\tstandard: modelRef(standard),\n\t\tcapable: modelRef(capable),\n\t};\n}\n\n/**\n * Resolve a model category to a model id. An explicit\n * `settings.modelCategories[category]` wins; otherwise a default is derived from\n * `availableModels` (provider-neutral, see `deriveDefaultModelCategories`); when\n * neither applies the category resolves to `undefined` (a no-op, so the caller\n * keeps its existing model).\n *\n * @param category - The model category (fast, standard, capable)\n * @param settings - The current settings (may contain modelCategories config)\n * @param availableModels - The user's available/configured models to derive from\n */\nexport function resolveModelCategory(\n\tcategory: ModelCategory,\n\tsettings?: Settings,\n\tavailableModels?: readonly Model<Api>[],\n): string | undefined {\n\tconst explicit = settings?.modelCategories?.[category];\n\tif (explicit) return explicit;\n\tif (availableModels && availableModels.length > 0) {\n\t\treturn deriveDefaultModelCategories(availableModels, settings)[category];\n\t}\n\treturn undefined;\n}\n\n/**\n * Resolve a model string that might be a category reference. A category resolves\n * to its configured or derived model id (or `undefined` when neither applies);\n * any other string is already a concrete model id or alias and is returned as-is.\n *\n * @param model - The model string (could be a category, alias, or full model ID)\n * @param settings - The current settings (may contain modelCategories config)\n * @param availableModels - The user's available/configured models to derive from\n */\nexport function resolveModelReference(\n\tmodel: string,\n\tsettings?: Settings,\n\tavailableModels?: readonly Model<Api>[],\n): string | undefined {\n\tif (isModelCategory(model)) {\n\t\treturn resolveModelCategory(model, settings, availableModels);\n\t}\n\treturn model;\n}\n"]}
|
|
@@ -59,8 +59,20 @@ export interface WarningSettings {
|
|
|
59
59
|
/**
|
|
60
60
|
* Model categories for subagent model selection.
|
|
61
61
|
* Categories map to explicit model IDs (e.g., "<provider>/<model-id>").
|
|
62
|
-
*
|
|
63
|
-
*
|
|
62
|
+
*
|
|
63
|
+
* A field set here always wins. When a tier is left unset, it does NOT become a
|
|
64
|
+
* no-op: it resolves to a default *derived* from the user's available models
|
|
65
|
+
* (nothing is hardcoded, so the feature stays provider-neutral). The derivation,
|
|
66
|
+
* implemented in `deriveDefaultModelCategories` (core/model-categories.ts), is:
|
|
67
|
+
* - `capable` = the user's primary model — the configured default
|
|
68
|
+
* (`defaultProvider`/`defaultModel`) when available, else the most capable
|
|
69
|
+
* available model (highest combined input+output token price as a proxy).
|
|
70
|
+
* - `fast` / `standard` = the cheapest / upper-median of every available model
|
|
71
|
+
* priced at or below `capable`, ordered cheapest-first. Clamping to
|
|
72
|
+
* `capable`'s price keeps tiers monotonic (`fast` <= `standard` <= `capable`).
|
|
73
|
+
* Ties break on a fixed key (context window, then id), so identical inputs always
|
|
74
|
+
* yield the same mapping. When no models are available, tiers stay unresolved and
|
|
75
|
+
* the agent's or parent's default model is used.
|
|
64
76
|
*/
|
|
65
77
|
export interface ModelCategories {
|
|
66
78
|
/** Quick, cheap models for read-only exploration (grep, find, file discovery) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-types.d.ts","sourceRoot":"","sources":["../../src/core/settings-types.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Settings schema shared across the app.\n *\n * The `Settings` interface and its nested option groups describe the on-disk\n * global/project settings.json shape. Extracted from settings-manager.ts so the\n * schema can be imported without pulling in the manager implementation.\n */\n\nimport type { Transport } from \"@kolisachint/hoocode-ai\";\n\nexport interface CompactionSettings {\n\tenabled?: boolean; // default: true\n\treserveTokens?: number; // default: 16384\n\tkeepRecentTokens?: number; // default: 20000\n\tmaxContextRatio?: number; // default: 0.75 - compact once context exceeds this fraction of the window, even before the reserveTokens rule fires (bounds transcript growth on large windows)\n}\n\nexport interface ToolOutputSettings {\n\tmaxBytes?: number; // default: 16384 (16KB) - byte cap on a single read/bash tool result before truncation\n\tmaxLines?: number; // default: 800 - line cap on a single read/bash tool result before truncation\n}\n\nexport interface ContextGcSettings {\n\tenabled?: boolean; // default: true - stub out superseded read results (file later edited/re-read) from the outgoing context\n}\n\nexport interface BranchSummarySettings {\n\treserveTokens?: number; // default: 16384 (tokens reserved for prompt + LLM response)\n\tskipPrompt?: boolean; // default: false - when true, skips \"Summarize branch?\" prompt and defaults to no summary\n}\n\nexport interface ProviderRetrySettings {\n\ttimeoutMs?: number; // SDK/provider request timeout in milliseconds\n\tmaxRetries?: number; // SDK/provider retry attempts\n\tmaxRetryDelayMs?: number; // default: 60000 (max server-requested delay before failing)\n}\n\nexport interface RetrySettings {\n\tenabled?: boolean; // default: true\n\tmaxRetries?: number; // default: 3\n\tbaseDelayMs?: number; // default: 2000 (exponential backoff: 2s, 4s, 8s)\n\tprovider?: ProviderRetrySettings;\n}\n\nexport interface TerminalSettings {\n\tshowImages?: boolean; // default: true (only relevant if terminal supports images)\n\timageWidthCells?: number; // default: 60 (preferred inline image width in terminal cells)\n\tclearOnShrink?: boolean; // default: false (clear empty rows when content shrinks)\n\tshowTerminalProgress?: boolean; // default: false (OSC 9;4 terminal progress indicators)\n}\n\nexport interface ImageSettings {\n\tautoResize?: boolean; // default: true (resize images to 2000x2000 max for better model compatibility)\n\tblockImages?: boolean; // default: false - when true, prevents all images from being sent to LLM providers\n}\n\nexport interface ThinkingBudgetsSettings {\n\tminimal?: number;\n\tlow?: number;\n\tmedium?: number;\n\thigh?: number;\n}\n\nexport interface MarkdownSettings {\n\tcodeBlockIndent?: string; // default: \" \"\n}\n\nexport interface WarningSettings {\n\tanthropicExtraUsage?: boolean; // default: true\n}\n\n/**\n * Model categories for subagent model selection.\n * Categories map to explicit model IDs (e.g., \"<provider>/<model-id>\").\n * When a category is not configured, no override is applied and the agent's or\n * parent's default model is used.\n */\nexport interface ModelCategories {\n\t/** Quick, cheap models for read-only exploration (grep, find, file discovery) */\n\tfast?: string;\n\t/** Balanced models for general work (planning, moderate complexity) */\n\tstandard?: string;\n\t/** Most capable models for complex reasoning (multi-file refactors) */\n\tcapable?: string;\n}\n\nexport type TransportSetting = Transport;\n\n/**\n * Package source for npm/git packages.\n * - String form: load all resources from the package\n * - Object form: filter which resources to load\n */\nexport type PackageSource =\n\t| string\n\t| {\n\t\t\tsource: string;\n\t\t\textensions?: string[];\n\t\t\tskills?: string[];\n\t\t\tprompts?: string[];\n\t\t\tthemes?: string[];\n\t };\n\nexport interface Settings {\n\tlastChangelogVersion?: string;\n\tdefaultProvider?: string;\n\tdefaultModel?: string;\n\tdefaultThinkingLevel?: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\tmodelCategories?: ModelCategories; // Model categories for subagent model selection (fast, standard, capable)\n\ttransport?: TransportSetting; // default: \"auto\"\n\tsteeringMode?: \"all\" | \"one-at-a-time\";\n\tfollowUpMode?: \"all\" | \"one-at-a-time\";\n\ttheme?: string;\n\tcompaction?: CompactionSettings;\n\ttoolOutput?: ToolOutputSettings; // caps on a single read/bash result (bounds per-turn transcript growth)\n\tcontextGc?: ContextGcSettings; // garbage-collect superseded read results from the outgoing context\n\tbranchSummary?: BranchSummarySettings;\n\tretry?: RetrySettings;\n\thideThinkingBlock?: boolean;\n\tshellPath?: string; // Custom shell path (e.g., for Cygwin users on Windows)\n\tquietStartup?: boolean;\n\tshellCommandPrefix?: string; // Prefix prepended to every bash command (e.g., \"shopt -s expand_aliases\" for alias support)\n\tnpmCommand?: string[]; // Command used for npm package lookup/install operations, argv-style (e.g., [\"mise\", \"exec\", \"node@20\", \"--\", \"npm\"])\n\tcollapseChangelog?: boolean; // Show condensed changelog after update (use /changelog for full)\n\tenableInstallTelemetry?: boolean; // default: true - anonymous version/update ping after changelog-detected updates\n\tpackages?: PackageSource[]; // Array of npm/git package sources (string or object with filtering)\n\textensions?: string[]; // Array of local extension file paths or directories\n\tskills?: string[]; // Array of local skill file paths or directories\n\tprompts?: string[]; // Array of local prompt template paths or directories\n\tslashCommands?: string[]; // Array of local slash-command paths or directories\n\tthemes?: string[]; // Array of local theme file paths or directories\n\tenableSkillCommands?: boolean; // default: true - register skills as /skill:name commands\n\tenableSubagent?: boolean; // default: true - enable the subagent tool (delegate tasks to isolated agent loops); set false to disable\n\twarmSubagents?: boolean; // default: false - dispatch eligible subagents on reused warm RPC workers (experimental)\n\tmaxSubagentDepth?: number; // default: 2 - tree-wide subagent nesting cap (2 = a subagent may spawn one more level; 1 = no nesting)\n\tnestedSubagentConcurrency?: number; // default: 2 - max concurrent subagents per pool at nesting depth >= 1\n\tenableTodoWrite?: boolean; // default: true - enable the TodoWrite tool (maintain a live todo list in the task panel)\n\tenablePluginTools?: boolean; // default: false - master switch for the whole autonomous plugin system: the plugin lifecycle tools (SearchPlugins, InstallPlugin, ...) and ProposePlugin on the top-level agent AND the runtime plugin-reuse nudge. Off by default; set true to opt in.\n\tsupportPlatform?: string | string[]; // Platform layout(s) hoocode targets when writing artifacts (authored plugins, /new-* scaffolds). Tokens: claude, copilot|github|gh, agents|native. Same as the --support-platform CLI flag (which overrides this).\n\tdeferMcpSchemas?: boolean; // default: true - defer MCP tool schemas (inject names only + ResolveMcpTools on demand) instead of registering every schema up front; set false to eagerly register every schema\n\tenableWebTools?: boolean; // default: false - enable the webfetch + websearch tools (network access)\n\tenableBrowserTools?: boolean; // default: false - enable the browser_run + browser_continue tools (browsertools engine)\n\tenableBrowserLivePreview?: boolean; // default: false - default the live viewer on for browser_run runs and auto-open it\n\tenableFileTools?: boolean; // default: false - enable the document tools: DocRead/DocEdit/DocWrite + DocScan/DocGrep/DocPeek (filetools binary)\n\tterminal?: TerminalSettings;\n\timages?: ImageSettings;\n\tenabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)\n\tdoubleEscapeAction?: \"fork\" | \"tree\" | \"none\"; // Action for double-escape with empty editor (default: \"tree\")\n\ttreeFilterMode?: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\"; // Default filter when opening /tree\n\tthinkingBudgets?: ThinkingBudgetsSettings; // Custom token budgets for thinking levels\n\tthinkingDisplay?: \"summarized\" | \"omitted\"; // How adaptive-thinking models return thinking content. Opus 4.8 defaults to \"omitted\" (faster tool use); set \"summarized\" to surface thinking text.\n\teditorPaddingX?: number; // Horizontal padding for input editor (default: 0)\n\tautocompleteMaxVisible?: number; // Max visible items in autocomplete dropdown (default: 5)\n\tshowHardwareCursor?: boolean; // Show terminal cursor while still positioning it for IME\n\tmarkdown?: MarkdownSettings;\n\twarnings?: WarningSettings;\n\tsessionDir?: string; // Custom session storage directory (same format as --session-dir CLI flag)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"settings-types.d.ts","sourceRoot":"","sources":["../../src/core/settings-types.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Settings schema shared across the app.\n *\n * The `Settings` interface and its nested option groups describe the on-disk\n * global/project settings.json shape. Extracted from settings-manager.ts so the\n * schema can be imported without pulling in the manager implementation.\n */\n\nimport type { Transport } from \"@kolisachint/hoocode-ai\";\n\nexport interface CompactionSettings {\n\tenabled?: boolean; // default: true\n\treserveTokens?: number; // default: 16384\n\tkeepRecentTokens?: number; // default: 20000\n\tmaxContextRatio?: number; // default: 0.75 - compact once context exceeds this fraction of the window, even before the reserveTokens rule fires (bounds transcript growth on large windows)\n}\n\nexport interface ToolOutputSettings {\n\tmaxBytes?: number; // default: 16384 (16KB) - byte cap on a single read/bash tool result before truncation\n\tmaxLines?: number; // default: 800 - line cap on a single read/bash tool result before truncation\n}\n\nexport interface ContextGcSettings {\n\tenabled?: boolean; // default: true - stub out superseded read results (file later edited/re-read) from the outgoing context\n}\n\nexport interface BranchSummarySettings {\n\treserveTokens?: number; // default: 16384 (tokens reserved for prompt + LLM response)\n\tskipPrompt?: boolean; // default: false - when true, skips \"Summarize branch?\" prompt and defaults to no summary\n}\n\nexport interface ProviderRetrySettings {\n\ttimeoutMs?: number; // SDK/provider request timeout in milliseconds\n\tmaxRetries?: number; // SDK/provider retry attempts\n\tmaxRetryDelayMs?: number; // default: 60000 (max server-requested delay before failing)\n}\n\nexport interface RetrySettings {\n\tenabled?: boolean; // default: true\n\tmaxRetries?: number; // default: 3\n\tbaseDelayMs?: number; // default: 2000 (exponential backoff: 2s, 4s, 8s)\n\tprovider?: ProviderRetrySettings;\n}\n\nexport interface TerminalSettings {\n\tshowImages?: boolean; // default: true (only relevant if terminal supports images)\n\timageWidthCells?: number; // default: 60 (preferred inline image width in terminal cells)\n\tclearOnShrink?: boolean; // default: false (clear empty rows when content shrinks)\n\tshowTerminalProgress?: boolean; // default: false (OSC 9;4 terminal progress indicators)\n}\n\nexport interface ImageSettings {\n\tautoResize?: boolean; // default: true (resize images to 2000x2000 max for better model compatibility)\n\tblockImages?: boolean; // default: false - when true, prevents all images from being sent to LLM providers\n}\n\nexport interface ThinkingBudgetsSettings {\n\tminimal?: number;\n\tlow?: number;\n\tmedium?: number;\n\thigh?: number;\n}\n\nexport interface MarkdownSettings {\n\tcodeBlockIndent?: string; // default: \" \"\n}\n\nexport interface WarningSettings {\n\tanthropicExtraUsage?: boolean; // default: true\n}\n\n/**\n * Model categories for subagent model selection.\n * Categories map to explicit model IDs (e.g., \"<provider>/<model-id>\").\n *\n * A field set here always wins. When a tier is left unset, it does NOT become a\n * no-op: it resolves to a default *derived* from the user's available models\n * (nothing is hardcoded, so the feature stays provider-neutral). The derivation,\n * implemented in `deriveDefaultModelCategories` (core/model-categories.ts), is:\n * - `capable` = the user's primary model — the configured default\n * (`defaultProvider`/`defaultModel`) when available, else the most capable\n * available model (highest combined input+output token price as a proxy).\n * - `fast` / `standard` = the cheapest / upper-median of every available model\n * priced at or below `capable`, ordered cheapest-first. Clamping to\n * `capable`'s price keeps tiers monotonic (`fast` <= `standard` <= `capable`).\n * Ties break on a fixed key (context window, then id), so identical inputs always\n * yield the same mapping. When no models are available, tiers stay unresolved and\n * the agent's or parent's default model is used.\n */\nexport interface ModelCategories {\n\t/** Quick, cheap models for read-only exploration (grep, find, file discovery) */\n\tfast?: string;\n\t/** Balanced models for general work (planning, moderate complexity) */\n\tstandard?: string;\n\t/** Most capable models for complex reasoning (multi-file refactors) */\n\tcapable?: string;\n}\n\nexport type TransportSetting = Transport;\n\n/**\n * Package source for npm/git packages.\n * - String form: load all resources from the package\n * - Object form: filter which resources to load\n */\nexport type PackageSource =\n\t| string\n\t| {\n\t\t\tsource: string;\n\t\t\textensions?: string[];\n\t\t\tskills?: string[];\n\t\t\tprompts?: string[];\n\t\t\tthemes?: string[];\n\t };\n\nexport interface Settings {\n\tlastChangelogVersion?: string;\n\tdefaultProvider?: string;\n\tdefaultModel?: string;\n\tdefaultThinkingLevel?: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\tmodelCategories?: ModelCategories; // Model categories for subagent model selection (fast, standard, capable)\n\ttransport?: TransportSetting; // default: \"auto\"\n\tsteeringMode?: \"all\" | \"one-at-a-time\";\n\tfollowUpMode?: \"all\" | \"one-at-a-time\";\n\ttheme?: string;\n\tcompaction?: CompactionSettings;\n\ttoolOutput?: ToolOutputSettings; // caps on a single read/bash result (bounds per-turn transcript growth)\n\tcontextGc?: ContextGcSettings; // garbage-collect superseded read results from the outgoing context\n\tbranchSummary?: BranchSummarySettings;\n\tretry?: RetrySettings;\n\thideThinkingBlock?: boolean;\n\tshellPath?: string; // Custom shell path (e.g., for Cygwin users on Windows)\n\tquietStartup?: boolean;\n\tshellCommandPrefix?: string; // Prefix prepended to every bash command (e.g., \"shopt -s expand_aliases\" for alias support)\n\tnpmCommand?: string[]; // Command used for npm package lookup/install operations, argv-style (e.g., [\"mise\", \"exec\", \"node@20\", \"--\", \"npm\"])\n\tcollapseChangelog?: boolean; // Show condensed changelog after update (use /changelog for full)\n\tenableInstallTelemetry?: boolean; // default: true - anonymous version/update ping after changelog-detected updates\n\tpackages?: PackageSource[]; // Array of npm/git package sources (string or object with filtering)\n\textensions?: string[]; // Array of local extension file paths or directories\n\tskills?: string[]; // Array of local skill file paths or directories\n\tprompts?: string[]; // Array of local prompt template paths or directories\n\tslashCommands?: string[]; // Array of local slash-command paths or directories\n\tthemes?: string[]; // Array of local theme file paths or directories\n\tenableSkillCommands?: boolean; // default: true - register skills as /skill:name commands\n\tenableSubagent?: boolean; // default: true - enable the subagent tool (delegate tasks to isolated agent loops); set false to disable\n\twarmSubagents?: boolean; // default: false - dispatch eligible subagents on reused warm RPC workers (experimental)\n\tmaxSubagentDepth?: number; // default: 2 - tree-wide subagent nesting cap (2 = a subagent may spawn one more level; 1 = no nesting)\n\tnestedSubagentConcurrency?: number; // default: 2 - max concurrent subagents per pool at nesting depth >= 1\n\tenableTodoWrite?: boolean; // default: true - enable the TodoWrite tool (maintain a live todo list in the task panel)\n\tenablePluginTools?: boolean; // default: false - master switch for the whole autonomous plugin system: the plugin lifecycle tools (SearchPlugins, InstallPlugin, ...) and ProposePlugin on the top-level agent AND the runtime plugin-reuse nudge. Off by default; set true to opt in.\n\tsupportPlatform?: string | string[]; // Platform layout(s) hoocode targets when writing artifacts (authored plugins, /new-* scaffolds). Tokens: claude, copilot|github|gh, agents|native. Same as the --support-platform CLI flag (which overrides this).\n\tdeferMcpSchemas?: boolean; // default: true - defer MCP tool schemas (inject names only + ResolveMcpTools on demand) instead of registering every schema up front; set false to eagerly register every schema\n\tenableWebTools?: boolean; // default: false - enable the webfetch + websearch tools (network access)\n\tenableBrowserTools?: boolean; // default: false - enable the browser_run + browser_continue tools (browsertools engine)\n\tenableBrowserLivePreview?: boolean; // default: false - default the live viewer on for browser_run runs and auto-open it\n\tenableFileTools?: boolean; // default: false - enable the document tools: DocRead/DocEdit/DocWrite + DocScan/DocGrep/DocPeek (filetools binary)\n\tterminal?: TerminalSettings;\n\timages?: ImageSettings;\n\tenabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)\n\tdoubleEscapeAction?: \"fork\" | \"tree\" | \"none\"; // Action for double-escape with empty editor (default: \"tree\")\n\ttreeFilterMode?: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\"; // Default filter when opening /tree\n\tthinkingBudgets?: ThinkingBudgetsSettings; // Custom token budgets for thinking levels\n\tthinkingDisplay?: \"summarized\" | \"omitted\"; // How adaptive-thinking models return thinking content. Opus 4.8 defaults to \"omitted\" (faster tool use); set \"summarized\" to surface thinking text.\n\teditorPaddingX?: number; // Horizontal padding for input editor (default: 0)\n\tautocompleteMaxVisible?: number; // Max visible items in autocomplete dropdown (default: 5)\n\tshowHardwareCursor?: boolean; // Show terminal cursor while still positioning it for IME\n\tmarkdown?: MarkdownSettings;\n\twarnings?: WarningSettings;\n\tsessionDir?: string; // Custom session storage directory (same format as --session-dir CLI flag)\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-types.js","sourceRoot":"","sources":["../../src/core/settings-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG","sourcesContent":["/**\n * Settings schema shared across the app.\n *\n * The `Settings` interface and its nested option groups describe the on-disk\n * global/project settings.json shape. Extracted from settings-manager.ts so the\n * schema can be imported without pulling in the manager implementation.\n */\n\nimport type { Transport } from \"@kolisachint/hoocode-ai\";\n\nexport interface CompactionSettings {\n\tenabled?: boolean; // default: true\n\treserveTokens?: number; // default: 16384\n\tkeepRecentTokens?: number; // default: 20000\n\tmaxContextRatio?: number; // default: 0.75 - compact once context exceeds this fraction of the window, even before the reserveTokens rule fires (bounds transcript growth on large windows)\n}\n\nexport interface ToolOutputSettings {\n\tmaxBytes?: number; // default: 16384 (16KB) - byte cap on a single read/bash tool result before truncation\n\tmaxLines?: number; // default: 800 - line cap on a single read/bash tool result before truncation\n}\n\nexport interface ContextGcSettings {\n\tenabled?: boolean; // default: true - stub out superseded read results (file later edited/re-read) from the outgoing context\n}\n\nexport interface BranchSummarySettings {\n\treserveTokens?: number; // default: 16384 (tokens reserved for prompt + LLM response)\n\tskipPrompt?: boolean; // default: false - when true, skips \"Summarize branch?\" prompt and defaults to no summary\n}\n\nexport interface ProviderRetrySettings {\n\ttimeoutMs?: number; // SDK/provider request timeout in milliseconds\n\tmaxRetries?: number; // SDK/provider retry attempts\n\tmaxRetryDelayMs?: number; // default: 60000 (max server-requested delay before failing)\n}\n\nexport interface RetrySettings {\n\tenabled?: boolean; // default: true\n\tmaxRetries?: number; // default: 3\n\tbaseDelayMs?: number; // default: 2000 (exponential backoff: 2s, 4s, 8s)\n\tprovider?: ProviderRetrySettings;\n}\n\nexport interface TerminalSettings {\n\tshowImages?: boolean; // default: true (only relevant if terminal supports images)\n\timageWidthCells?: number; // default: 60 (preferred inline image width in terminal cells)\n\tclearOnShrink?: boolean; // default: false (clear empty rows when content shrinks)\n\tshowTerminalProgress?: boolean; // default: false (OSC 9;4 terminal progress indicators)\n}\n\nexport interface ImageSettings {\n\tautoResize?: boolean; // default: true (resize images to 2000x2000 max for better model compatibility)\n\tblockImages?: boolean; // default: false - when true, prevents all images from being sent to LLM providers\n}\n\nexport interface ThinkingBudgetsSettings {\n\tminimal?: number;\n\tlow?: number;\n\tmedium?: number;\n\thigh?: number;\n}\n\nexport interface MarkdownSettings {\n\tcodeBlockIndent?: string; // default: \" \"\n}\n\nexport interface WarningSettings {\n\tanthropicExtraUsage?: boolean; // default: true\n}\n\n/**\n * Model categories for subagent model selection.\n * Categories map to explicit model IDs (e.g., \"<provider>/<model-id>\").\n * When a
|
|
1
|
+
{"version":3,"file":"settings-types.js","sourceRoot":"","sources":["../../src/core/settings-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG","sourcesContent":["/**\n * Settings schema shared across the app.\n *\n * The `Settings` interface and its nested option groups describe the on-disk\n * global/project settings.json shape. Extracted from settings-manager.ts so the\n * schema can be imported without pulling in the manager implementation.\n */\n\nimport type { Transport } from \"@kolisachint/hoocode-ai\";\n\nexport interface CompactionSettings {\n\tenabled?: boolean; // default: true\n\treserveTokens?: number; // default: 16384\n\tkeepRecentTokens?: number; // default: 20000\n\tmaxContextRatio?: number; // default: 0.75 - compact once context exceeds this fraction of the window, even before the reserveTokens rule fires (bounds transcript growth on large windows)\n}\n\nexport interface ToolOutputSettings {\n\tmaxBytes?: number; // default: 16384 (16KB) - byte cap on a single read/bash tool result before truncation\n\tmaxLines?: number; // default: 800 - line cap on a single read/bash tool result before truncation\n}\n\nexport interface ContextGcSettings {\n\tenabled?: boolean; // default: true - stub out superseded read results (file later edited/re-read) from the outgoing context\n}\n\nexport interface BranchSummarySettings {\n\treserveTokens?: number; // default: 16384 (tokens reserved for prompt + LLM response)\n\tskipPrompt?: boolean; // default: false - when true, skips \"Summarize branch?\" prompt and defaults to no summary\n}\n\nexport interface ProviderRetrySettings {\n\ttimeoutMs?: number; // SDK/provider request timeout in milliseconds\n\tmaxRetries?: number; // SDK/provider retry attempts\n\tmaxRetryDelayMs?: number; // default: 60000 (max server-requested delay before failing)\n}\n\nexport interface RetrySettings {\n\tenabled?: boolean; // default: true\n\tmaxRetries?: number; // default: 3\n\tbaseDelayMs?: number; // default: 2000 (exponential backoff: 2s, 4s, 8s)\n\tprovider?: ProviderRetrySettings;\n}\n\nexport interface TerminalSettings {\n\tshowImages?: boolean; // default: true (only relevant if terminal supports images)\n\timageWidthCells?: number; // default: 60 (preferred inline image width in terminal cells)\n\tclearOnShrink?: boolean; // default: false (clear empty rows when content shrinks)\n\tshowTerminalProgress?: boolean; // default: false (OSC 9;4 terminal progress indicators)\n}\n\nexport interface ImageSettings {\n\tautoResize?: boolean; // default: true (resize images to 2000x2000 max for better model compatibility)\n\tblockImages?: boolean; // default: false - when true, prevents all images from being sent to LLM providers\n}\n\nexport interface ThinkingBudgetsSettings {\n\tminimal?: number;\n\tlow?: number;\n\tmedium?: number;\n\thigh?: number;\n}\n\nexport interface MarkdownSettings {\n\tcodeBlockIndent?: string; // default: \" \"\n}\n\nexport interface WarningSettings {\n\tanthropicExtraUsage?: boolean; // default: true\n}\n\n/**\n * Model categories for subagent model selection.\n * Categories map to explicit model IDs (e.g., \"<provider>/<model-id>\").\n *\n * A field set here always wins. When a tier is left unset, it does NOT become a\n * no-op: it resolves to a default *derived* from the user's available models\n * (nothing is hardcoded, so the feature stays provider-neutral). The derivation,\n * implemented in `deriveDefaultModelCategories` (core/model-categories.ts), is:\n * - `capable` = the user's primary model — the configured default\n * (`defaultProvider`/`defaultModel`) when available, else the most capable\n * available model (highest combined input+output token price as a proxy).\n * - `fast` / `standard` = the cheapest / upper-median of every available model\n * priced at or below `capable`, ordered cheapest-first. Clamping to\n * `capable`'s price keeps tiers monotonic (`fast` <= `standard` <= `capable`).\n * Ties break on a fixed key (context window, then id), so identical inputs always\n * yield the same mapping. When no models are available, tiers stay unresolved and\n * the agent's or parent's default model is used.\n */\nexport interface ModelCategories {\n\t/** Quick, cheap models for read-only exploration (grep, find, file discovery) */\n\tfast?: string;\n\t/** Balanced models for general work (planning, moderate complexity) */\n\tstandard?: string;\n\t/** Most capable models for complex reasoning (multi-file refactors) */\n\tcapable?: string;\n}\n\nexport type TransportSetting = Transport;\n\n/**\n * Package source for npm/git packages.\n * - String form: load all resources from the package\n * - Object form: filter which resources to load\n */\nexport type PackageSource =\n\t| string\n\t| {\n\t\t\tsource: string;\n\t\t\textensions?: string[];\n\t\t\tskills?: string[];\n\t\t\tprompts?: string[];\n\t\t\tthemes?: string[];\n\t };\n\nexport interface Settings {\n\tlastChangelogVersion?: string;\n\tdefaultProvider?: string;\n\tdefaultModel?: string;\n\tdefaultThinkingLevel?: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\tmodelCategories?: ModelCategories; // Model categories for subagent model selection (fast, standard, capable)\n\ttransport?: TransportSetting; // default: \"auto\"\n\tsteeringMode?: \"all\" | \"one-at-a-time\";\n\tfollowUpMode?: \"all\" | \"one-at-a-time\";\n\ttheme?: string;\n\tcompaction?: CompactionSettings;\n\ttoolOutput?: ToolOutputSettings; // caps on a single read/bash result (bounds per-turn transcript growth)\n\tcontextGc?: ContextGcSettings; // garbage-collect superseded read results from the outgoing context\n\tbranchSummary?: BranchSummarySettings;\n\tretry?: RetrySettings;\n\thideThinkingBlock?: boolean;\n\tshellPath?: string; // Custom shell path (e.g., for Cygwin users on Windows)\n\tquietStartup?: boolean;\n\tshellCommandPrefix?: string; // Prefix prepended to every bash command (e.g., \"shopt -s expand_aliases\" for alias support)\n\tnpmCommand?: string[]; // Command used for npm package lookup/install operations, argv-style (e.g., [\"mise\", \"exec\", \"node@20\", \"--\", \"npm\"])\n\tcollapseChangelog?: boolean; // Show condensed changelog after update (use /changelog for full)\n\tenableInstallTelemetry?: boolean; // default: true - anonymous version/update ping after changelog-detected updates\n\tpackages?: PackageSource[]; // Array of npm/git package sources (string or object with filtering)\n\textensions?: string[]; // Array of local extension file paths or directories\n\tskills?: string[]; // Array of local skill file paths or directories\n\tprompts?: string[]; // Array of local prompt template paths or directories\n\tslashCommands?: string[]; // Array of local slash-command paths or directories\n\tthemes?: string[]; // Array of local theme file paths or directories\n\tenableSkillCommands?: boolean; // default: true - register skills as /skill:name commands\n\tenableSubagent?: boolean; // default: true - enable the subagent tool (delegate tasks to isolated agent loops); set false to disable\n\twarmSubagents?: boolean; // default: false - dispatch eligible subagents on reused warm RPC workers (experimental)\n\tmaxSubagentDepth?: number; // default: 2 - tree-wide subagent nesting cap (2 = a subagent may spawn one more level; 1 = no nesting)\n\tnestedSubagentConcurrency?: number; // default: 2 - max concurrent subagents per pool at nesting depth >= 1\n\tenableTodoWrite?: boolean; // default: true - enable the TodoWrite tool (maintain a live todo list in the task panel)\n\tenablePluginTools?: boolean; // default: false - master switch for the whole autonomous plugin system: the plugin lifecycle tools (SearchPlugins, InstallPlugin, ...) and ProposePlugin on the top-level agent AND the runtime plugin-reuse nudge. Off by default; set true to opt in.\n\tsupportPlatform?: string | string[]; // Platform layout(s) hoocode targets when writing artifacts (authored plugins, /new-* scaffolds). Tokens: claude, copilot|github|gh, agents|native. Same as the --support-platform CLI flag (which overrides this).\n\tdeferMcpSchemas?: boolean; // default: true - defer MCP tool schemas (inject names only + ResolveMcpTools on demand) instead of registering every schema up front; set false to eagerly register every schema\n\tenableWebTools?: boolean; // default: false - enable the webfetch + websearch tools (network access)\n\tenableBrowserTools?: boolean; // default: false - enable the browser_run + browser_continue tools (browsertools engine)\n\tenableBrowserLivePreview?: boolean; // default: false - default the live viewer on for browser_run runs and auto-open it\n\tenableFileTools?: boolean; // default: false - enable the document tools: DocRead/DocEdit/DocWrite + DocScan/DocGrep/DocPeek (filetools binary)\n\tterminal?: TerminalSettings;\n\timages?: ImageSettings;\n\tenabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)\n\tdoubleEscapeAction?: \"fork\" | \"tree\" | \"none\"; // Action for double-escape with empty editor (default: \"tree\")\n\ttreeFilterMode?: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\"; // Default filter when opening /tree\n\tthinkingBudgets?: ThinkingBudgetsSettings; // Custom token budgets for thinking levels\n\tthinkingDisplay?: \"summarized\" | \"omitted\"; // How adaptive-thinking models return thinking content. Opus 4.8 defaults to \"omitted\" (faster tool use); set \"summarized\" to surface thinking text.\n\teditorPaddingX?: number; // Horizontal padding for input editor (default: 0)\n\tautocompleteMaxVisible?: number; // Max visible items in autocomplete dropdown (default: 5)\n\tshowHardwareCursor?: boolean; // Show terminal cursor while still positioning it for IME\n\tmarkdown?: MarkdownSettings;\n\twarnings?: WarningSettings;\n\tsessionDir?: string; // Custom session storage directory (same format as --session-dir CLI flag)\n}\n"]}
|
|
@@ -6,9 +6,17 @@
|
|
|
6
6
|
* across every delegation in the session. Created lazily on first use and torn
|
|
7
7
|
* down on process exit.
|
|
8
8
|
*/
|
|
9
|
+
import type { Api, Model } from "@kolisachint/hoocode-ai";
|
|
9
10
|
import { SubagentPool } from "./subagent-pool.js";
|
|
10
|
-
/**
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Get the shared pool for a given working directory, creating it on first use.
|
|
13
|
+
*
|
|
14
|
+
* `availableModels` (the caller's `ModelRegistry.getAvailable()`) is snapshotted
|
|
15
|
+
* on first creation and used to derive default model-category mappings for any
|
|
16
|
+
* tier the user has not explicitly configured. Later calls reuse the existing
|
|
17
|
+
* pool, so pass it on the first dispatch of a session.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getSubagentPool(cwd: string, availableModels?: readonly Model<Api>[]): SubagentPool;
|
|
12
20
|
/**
|
|
13
21
|
* Return the shared pool if one already exists, without creating it. Use this for
|
|
14
22
|
* best-effort signaling (e.g. reporting external load) that must not spin up a pool
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-pool-instance.d.ts","sourceRoot":"","sources":["../../src/core/subagent-pool-instance.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"subagent-pool-instance.d.ts","sourceRoot":"","sources":["../../src/core/subagent-pool-instance.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAI1D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AASlD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,GAAE,SAAS,KAAK,CAAC,GAAG,CAAC,EAAO,GAAG,YAAY,CAgCtG;AAgCD;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,YAAY,GAAG,SAAS,CAE3D;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAG9D;AAED,mFAAmF;AACnF,wBAAgB,mBAAmB,IAAI,IAAI,CAI1C;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,CAElF","sourcesContent":["/**\n * Process-wide SubagentPool singleton.\n *\n * The subagent tool and the `/subagent` command both delegate through one pool\n * so concurrency limits, lifeguard monitoring, and token budgets are shared\n * across every delegation in the session. Created lazily on first use and torn\n * down on process exit.\n */\n\nimport type { Api, Model } from \"@kolisachint/hoocode-ai\";\nimport { getAgentDir, getSubagentSpawnCommand } from \"../config.js\";\nimport { SettingsManager } from \"./settings-manager.js\";\nimport { poolConcurrencyForDepth } from \"./subagent-depth.js\";\nimport { SubagentPool } from \"./subagent-pool.js\";\nimport { taskStore } from \"./task-store.js\";\n\nlet pool: SubagentPool | undefined;\nlet override: SubagentPool | undefined;\nlet exitHandlerRegistered = false;\n/** Latest non-default skill paths to forward to subagents, kept in sync with the resource loader. */\nlet latestSkillPaths: string[] = [];\n\n/**\n * Get the shared pool for a given working directory, creating it on first use.\n *\n * `availableModels` (the caller's `ModelRegistry.getAvailable()`) is snapshotted\n * on first creation and used to derive default model-category mappings for any\n * tier the user has not explicitly configured. Later calls reuse the existing\n * pool, so pass it on the first dispatch of a session.\n */\nexport function getSubagentPool(cwd: string, availableModels: readonly Model<Api>[] = []): SubagentPool {\n\tif (override) return override;\n\tif (!pool) {\n\t\tconst { executable, prefixArgs } = getSubagentSpawnCommand();\n\t\t// Pools created inside a nested subagent (depth >= 1) run with a reduced\n\t\t// concurrency cap so deep delegation trees stay bounded; the root keeps the\n\t\t// SubagentPool default.\n\t\t// Load settings for model category resolution\n\t\tconst settingsManager = SettingsManager.create(cwd, getAgentDir());\n\t\tconst globalSettings = settingsManager.getGlobalSettings();\n\t\tconst projectSettings = settingsManager.getProjectSettings();\n\t\t// Merge settings (project overrides global)\n\t\tconst settings = { ...globalSettings, ...projectSettings };\n\n\t\tpool = new SubagentPool({\n\t\t\texecutable,\n\t\t\tprefixArgs,\n\t\t\tcwd,\n\t\t\tskillPaths: latestSkillPaths,\n\t\t\tmaxConcurrency: poolConcurrencyForDepth(),\n\t\t\tsettings,\n\t\t\tavailableModels,\n\t\t});\n\n\t\twireProgressToTaskStore(pool);\n\n\t\tif (!exitHandlerRegistered) {\n\t\t\texitHandlerRegistered = true;\n\t\t\tprocess.once(\"exit\", () => pool?.dispose());\n\t\t}\n\t}\n\treturn pool;\n}\n\n/**\n * Surface live subagent progress on the task panel's agent roster row. The pool\n * forwards only coarse lifecycle events; we map the currently-executing tool onto\n * the run's `activity` and clear it between tools and on completion. Roster rows\n * are keyed per run by the pool task id (see registerSubagentDispatch), so\n * concurrent same-type subagents update their own rows; patching an unknown id\n * is a no-op. This touches only the roster row, never task nodes — so it cannot\n * collide with the end-of-run task-tree merge. Render coalescing is handled by\n * the TUI's `requestRender`, so per-event patches are fine.\n */\nfunction wireProgressToTaskStore(p: SubagentPool): void {\n\tp.on(\"task_progress\", (data: { task_id: string; event: { type?: string; toolName?: string } }) => {\n\t\tconst { task_id, event } = data;\n\t\tif (event.type === \"tool_execution_start\") {\n\t\t\ttaskStore.patchAgent(task_id, { activity: typeof event.toolName === \"string\" ? event.toolName : \"\" });\n\t\t} else if (event.type === \"turn_end\") {\n\t\t\t// Between turns the subagent is reasoning, not idle — mirror the inbox's\n\t\t\t// \"thinking\" so the panel and TaskOutput agree on what the run is doing.\n\t\t\ttaskStore.patchAgent(task_id, { activity: \"thinking\" });\n\t\t} else if (event.type === \"tool_execution_end\") {\n\t\t\ttaskStore.patchAgent(task_id, { activity: \"\" });\n\t\t}\n\t});\n\tfor (const terminal of [\"task_done\", \"task_failed\", \"task_stalled\", \"task_timeout\", \"task_cancelled\"] as const) {\n\t\tp.on(terminal, (data: { task_id?: string }) => {\n\t\t\tif (data.task_id) taskStore.patchAgent(data.task_id, { activity: \"\" });\n\t\t});\n\t}\n}\n\n/**\n * Return the shared pool if one already exists, without creating it. Use this for\n * best-effort signaling (e.g. reporting external load) that must not spin up a pool\n * and its lifeguard just because the signal fired before any subagent was dispatched.\n */\nexport function peekSubagentPool(): SubagentPool | undefined {\n\treturn override ?? pool;\n}\n\n/**\n * Update the skill paths forwarded to every subagent.\n * Call this after the resource loader reloads or extends its skill set.\n * If the pool has already been created, updates it immediately.\n * If not, the paths will be passed in when the pool is first created.\n */\nexport function updateSubagentSkillPaths(paths: string[]): void {\n\tlatestSkillPaths = paths;\n\tpool?.updateSkillPaths(paths);\n}\n\n/** Dispose and clear the shared pool. Intended for test isolation and shutdown. */\nexport function disposeSubagentPool(): void {\n\tpool?.dispose();\n\tpool = undefined;\n\tlatestSkillPaths = [];\n}\n\n/**\n * Inject a pool instance for tests, bypassing real child-process spawning.\n * Pass `undefined` to clear the override.\n */\nexport function setSubagentPoolForTesting(testPool: SubagentPool | undefined): void {\n\toverride = testPool;\n}\n"]}
|
|
@@ -16,8 +16,15 @@ let override;
|
|
|
16
16
|
let exitHandlerRegistered = false;
|
|
17
17
|
/** Latest non-default skill paths to forward to subagents, kept in sync with the resource loader. */
|
|
18
18
|
let latestSkillPaths = [];
|
|
19
|
-
/**
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Get the shared pool for a given working directory, creating it on first use.
|
|
21
|
+
*
|
|
22
|
+
* `availableModels` (the caller's `ModelRegistry.getAvailable()`) is snapshotted
|
|
23
|
+
* on first creation and used to derive default model-category mappings for any
|
|
24
|
+
* tier the user has not explicitly configured. Later calls reuse the existing
|
|
25
|
+
* pool, so pass it on the first dispatch of a session.
|
|
26
|
+
*/
|
|
27
|
+
export function getSubagentPool(cwd, availableModels = []) {
|
|
21
28
|
if (override)
|
|
22
29
|
return override;
|
|
23
30
|
if (!pool) {
|
|
@@ -38,6 +45,7 @@ export function getSubagentPool(cwd) {
|
|
|
38
45
|
skillPaths: latestSkillPaths,
|
|
39
46
|
maxConcurrency: poolConcurrencyForDepth(),
|
|
40
47
|
settings,
|
|
48
|
+
availableModels,
|
|
41
49
|
});
|
|
42
50
|
wireProgressToTaskStore(pool);
|
|
43
51
|
if (!exitHandlerRegistered) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-pool-instance.js","sourceRoot":"","sources":["../../src/core/subagent-pool-instance.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"subagent-pool-instance.js","sourceRoot":"","sources":["../../src/core/subagent-pool-instance.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Process-wide SubagentPool singleton.\n *\n * The subagent tool and the `/subagent` command both delegate through one pool\n * so concurrency limits, lifeguard monitoring, and token budgets are shared\n * across every delegation in the session. Created lazily on first use and torn\n * down on process exit.\n */\n\nimport type { Api, Model } from \"@kolisachint/hoocode-ai\";\nimport { getAgentDir, getSubagentSpawnCommand } from \"../config.js\";\nimport { SettingsManager } from \"./settings-manager.js\";\nimport { poolConcurrencyForDepth } from \"./subagent-depth.js\";\nimport { SubagentPool } from \"./subagent-pool.js\";\nimport { taskStore } from \"./task-store.js\";\n\nlet pool: SubagentPool | undefined;\nlet override: SubagentPool | undefined;\nlet exitHandlerRegistered = false;\n/** Latest non-default skill paths to forward to subagents, kept in sync with the resource loader. */\nlet latestSkillPaths: string[] = [];\n\n/**\n * Get the shared pool for a given working directory, creating it on first use.\n *\n * `availableModels` (the caller's `ModelRegistry.getAvailable()`) is snapshotted\n * on first creation and used to derive default model-category mappings for any\n * tier the user has not explicitly configured. Later calls reuse the existing\n * pool, so pass it on the first dispatch of a session.\n */\nexport function getSubagentPool(cwd: string, availableModels: readonly Model<Api>[] = []): SubagentPool {\n\tif (override) return override;\n\tif (!pool) {\n\t\tconst { executable, prefixArgs } = getSubagentSpawnCommand();\n\t\t// Pools created inside a nested subagent (depth >= 1) run with a reduced\n\t\t// concurrency cap so deep delegation trees stay bounded; the root keeps the\n\t\t// SubagentPool default.\n\t\t// Load settings for model category resolution\n\t\tconst settingsManager = SettingsManager.create(cwd, getAgentDir());\n\t\tconst globalSettings = settingsManager.getGlobalSettings();\n\t\tconst projectSettings = settingsManager.getProjectSettings();\n\t\t// Merge settings (project overrides global)\n\t\tconst settings = { ...globalSettings, ...projectSettings };\n\n\t\tpool = new SubagentPool({\n\t\t\texecutable,\n\t\t\tprefixArgs,\n\t\t\tcwd,\n\t\t\tskillPaths: latestSkillPaths,\n\t\t\tmaxConcurrency: poolConcurrencyForDepth(),\n\t\t\tsettings,\n\t\t\tavailableModels,\n\t\t});\n\n\t\twireProgressToTaskStore(pool);\n\n\t\tif (!exitHandlerRegistered) {\n\t\t\texitHandlerRegistered = true;\n\t\t\tprocess.once(\"exit\", () => pool?.dispose());\n\t\t}\n\t}\n\treturn pool;\n}\n\n/**\n * Surface live subagent progress on the task panel's agent roster row. The pool\n * forwards only coarse lifecycle events; we map the currently-executing tool onto\n * the run's `activity` and clear it between tools and on completion. Roster rows\n * are keyed per run by the pool task id (see registerSubagentDispatch), so\n * concurrent same-type subagents update their own rows; patching an unknown id\n * is a no-op. This touches only the roster row, never task nodes — so it cannot\n * collide with the end-of-run task-tree merge. Render coalescing is handled by\n * the TUI's `requestRender`, so per-event patches are fine.\n */\nfunction wireProgressToTaskStore(p: SubagentPool): void {\n\tp.on(\"task_progress\", (data: { task_id: string; event: { type?: string; toolName?: string } }) => {\n\t\tconst { task_id, event } = data;\n\t\tif (event.type === \"tool_execution_start\") {\n\t\t\ttaskStore.patchAgent(task_id, { activity: typeof event.toolName === \"string\" ? event.toolName : \"\" });\n\t\t} else if (event.type === \"turn_end\") {\n\t\t\t// Between turns the subagent is reasoning, not idle — mirror the inbox's\n\t\t\t// \"thinking\" so the panel and TaskOutput agree on what the run is doing.\n\t\t\ttaskStore.patchAgent(task_id, { activity: \"thinking\" });\n\t\t} else if (event.type === \"tool_execution_end\") {\n\t\t\ttaskStore.patchAgent(task_id, { activity: \"\" });\n\t\t}\n\t});\n\tfor (const terminal of [\"task_done\", \"task_failed\", \"task_stalled\", \"task_timeout\", \"task_cancelled\"] as const) {\n\t\tp.on(terminal, (data: { task_id?: string }) => {\n\t\t\tif (data.task_id) taskStore.patchAgent(data.task_id, { activity: \"\" });\n\t\t});\n\t}\n}\n\n/**\n * Return the shared pool if one already exists, without creating it. Use this for\n * best-effort signaling (e.g. reporting external load) that must not spin up a pool\n * and its lifeguard just because the signal fired before any subagent was dispatched.\n */\nexport function peekSubagentPool(): SubagentPool | undefined {\n\treturn override ?? pool;\n}\n\n/**\n * Update the skill paths forwarded to every subagent.\n * Call this after the resource loader reloads or extends its skill set.\n * If the pool has already been created, updates it immediately.\n * If not, the paths will be passed in when the pool is first created.\n */\nexport function updateSubagentSkillPaths(paths: string[]): void {\n\tlatestSkillPaths = paths;\n\tpool?.updateSkillPaths(paths);\n}\n\n/** Dispose and clear the shared pool. Intended for test isolation and shutdown. */\nexport function disposeSubagentPool(): void {\n\tpool?.dispose();\n\tpool = undefined;\n\tlatestSkillPaths = [];\n}\n\n/**\n * Inject a pool instance for tests, bypassing real child-process spawning.\n * Pass `undefined` to clear the override.\n */\nexport function setSubagentPoolForTesting(testPool: SubagentPool | undefined): void {\n\toverride = testPool;\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
|
+
import type { Api, Model } from "@kolisachint/hoocode-ai";
|
|
3
4
|
import type { Settings } from "./settings-manager.js";
|
|
4
5
|
export interface SubagentPoolTask {
|
|
5
6
|
task_id: string;
|
|
@@ -92,6 +93,12 @@ export interface SubagentPoolOptions {
|
|
|
92
93
|
skillPaths?: string[];
|
|
93
94
|
/** Settings for model category resolution. */
|
|
94
95
|
settings?: Settings;
|
|
96
|
+
/**
|
|
97
|
+
* Available/configured models used to derive default model-category mappings
|
|
98
|
+
* when a tier is not explicitly set in `settings.modelCategories`. Snapshotted
|
|
99
|
+
* at pool creation, mirroring how `settings` is captured.
|
|
100
|
+
*/
|
|
101
|
+
availableModels?: readonly Model<Api>[];
|
|
95
102
|
}
|
|
96
103
|
/**
|
|
97
104
|
* Default hard cap on assistant turns for a spawned subagent when its definition
|
|
@@ -178,6 +185,8 @@ export declare class SubagentPool extends EventEmitter {
|
|
|
178
185
|
private taskStatus;
|
|
179
186
|
/** Settings for model category resolution. */
|
|
180
187
|
private readonly settings?;
|
|
188
|
+
/** Available models used to derive default model-category mappings (snapshot). */
|
|
189
|
+
private readonly availableModels;
|
|
181
190
|
constructor(options: SubagentPoolOptions);
|
|
182
191
|
/** Update the non-default skill paths forwarded to new subagents. */
|
|
183
192
|
updateSkillPaths(paths: string[]): void;
|