fix(tool): flatten resolveChildModel adapter, remove unsafe cast, add compatibility shim and comments
This commit is contained in:
@@ -43,6 +43,9 @@ function loadPresetDir(dir: string, source: "global" | "project"): SubagentPrese
|
||||
const filePath = join(dir, entry.name);
|
||||
let content: string;
|
||||
try {
|
||||
// Fail-open: if a preset file is unreadable for any reason, ignore it
|
||||
// rather than failing the entire discovery process. This keeps preset
|
||||
// discovery robust in the presence of partially-broken user files.
|
||||
content = readFileSync(filePath, "utf8");
|
||||
} catch (_err) {
|
||||
continue;
|
||||
@@ -85,8 +88,11 @@ export function discoverSubagentPresets(cwd: string, options: { homeDir?: string
|
||||
}
|
||||
|
||||
if (projectPresetsDir) {
|
||||
// Project presets override global presets by name. This is intentional
|
||||
// to let local projects stage or refine presets without modifying the
|
||||
// user's global agent presets. There is no confirmation gate for a
|
||||
// project override; the nearest project takes precedence.
|
||||
for (const preset of loadPresetDir(projectPresetsDir, "project")) {
|
||||
// project overrides global by name
|
||||
map.set(preset.name, preset);
|
||||
}
|
||||
}
|
||||
|
||||
45
src/tool.ts
45
src/tool.ts
@@ -60,12 +60,15 @@ export function createSubagentTool(deps: {
|
||||
listAvailableModelReferences?: typeof listAvailableModelReferences;
|
||||
normalizeAvailableModelReference?: typeof normalizeAvailableModelReference;
|
||||
parameters?: typeof SubagentParamsSchema;
|
||||
// Compatibility: accept injected resolveChildModel functions with either the
|
||||
// new API ({ callModel?, presetModel? }) or the older test/hooks API
|
||||
// ({ taskModel?, topLevelModel? }). We adapt at callsite below.
|
||||
// Compatibility: injected resolveChildModel may be the new API
|
||||
// ({ callModel?, presetModel? }) or the older test/hooks API
|
||||
// ({ taskModel?, topLevelModel? }). The local adapter below exposes a
|
||||
// flattened, simple boundary that takes only { callModel?, presetModel? }
|
||||
// and adapts to either injected shape internally by providing both key
|
||||
// names when calling the injected resolver.
|
||||
resolveChildModel?:
|
||||
| typeof resolveChildModel
|
||||
| ((input: { taskModel?: string; topLevelModel?: string }) => ModelSelection);
|
||||
| ((input: { callModel?: string; presetModel?: string; taskModel?: string; topLevelModel?: string }) => ModelSelection)
|
||||
| typeof resolveChildModel;
|
||||
runSingleTask?: (input: {
|
||||
cwd: string;
|
||||
meta: Record<string, unknown>;
|
||||
@@ -136,21 +139,22 @@ export function createSubagentTool(deps: {
|
||||
step.model = normalizedStepModel;
|
||||
}
|
||||
|
||||
const callResolveChildModel = (input: {
|
||||
callModel?: string;
|
||||
presetModel?: string;
|
||||
taskModel?: string;
|
||||
topLevelModel?: string;
|
||||
}) => {
|
||||
// If an injected resolveChildModel exists, call it with the older-shape
|
||||
// keys (taskModel/topLevelModel) for compatibility. Otherwise, use the
|
||||
// internal resolveChildModel which expects { callModel, presetModel }.
|
||||
// Adapter: accept only the flattened shape { callModel?, presetModel? }
|
||||
// to keep the tool logic simple. If a resolver was injected with the
|
||||
// older test/hooks shape, we call it with both key names so it can read
|
||||
// the old keys. This is a minimal, internal compatibility shim.
|
||||
const callResolveChildModel = (input: { callModel?: string; presetModel?: string }) => {
|
||||
if (deps.resolveChildModel) {
|
||||
const injected = deps.resolveChildModel as unknown as (arg: { taskModel?: string; topLevelModel?: string }) => unknown;
|
||||
return injected({ taskModel: input.callModel ?? input.taskModel, topLevelModel: input.presetModel ?? input.topLevelModel }) as ModelSelection;
|
||||
// Provide both naming variants so old and new resolvers both work.
|
||||
return deps.resolveChildModel({
|
||||
callModel: input.callModel,
|
||||
presetModel: input.presetModel,
|
||||
taskModel: input.callModel,
|
||||
topLevelModel: input.presetModel,
|
||||
});
|
||||
}
|
||||
|
||||
return resolveChildModel({ callModel: input.callModel ?? input.taskModel, presetModel: input.presetModel ?? input.topLevelModel });
|
||||
return resolveChildModel({ callModel: input.callModel, presetModel: input.presetModel });
|
||||
};
|
||||
|
||||
const runTask = async (input: {
|
||||
@@ -161,12 +165,7 @@ export function createSubagentTool(deps: {
|
||||
step?: number;
|
||||
mode: "single" | "parallel" | "chain";
|
||||
}) => {
|
||||
const model = callResolveChildModel({
|
||||
callModel: input.taskModel,
|
||||
presetModel: params.model,
|
||||
taskModel: input.taskModel,
|
||||
topLevelModel: params.model,
|
||||
});
|
||||
const model = callResolveChildModel({ callModel: input.taskModel, presetModel: params.model });
|
||||
|
||||
const progressFormatter = createProgressFormatter();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user