@dreb/coding-agent 2.65.0 → 2.66.0

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.
@@ -976,7 +976,9 @@ function clampCwd(defaultCwd, itemCwd) {
976
976
  }
977
977
  export async function executeSingle(agents, agentName, task, cwd, signal, onProgress, modelOverride, parentProvider, registry, sessionDir, parentModel, agentModels, parentSessionFile, onChildEvent, thinkingOverride, arbitration, onControlAvailable,
978
978
  /** Parent session UUID for spawn-time availability probes (issue 500). */
979
- parentSessionId) {
979
+ parentSessionId,
980
+ /** Single-model mode (issue 517): the child runs on the parent session's model, ignoring model specs and the dispatch arbiter. */
981
+ singleModelMode) {
980
982
  let name = agentName || DEFAULT_AGENT;
981
983
  let config = agents.get(name);
982
984
  if (!config) {
@@ -1008,7 +1010,45 @@ parentSessionId) {
1008
1010
  let resolvedModel;
1009
1011
  let warning;
1010
1012
  let skippedModels = [];
1011
- if (modelSpec) {
1013
+ if (singleModelMode) {
1014
+ // Single-model mode (issue 517): every child runs on the parent session's model.
1015
+ // The per-call model override, per-agent model fallback list, agent-definition model
1016
+ // spec, and dispatch arbiter are all bypassed; a requested spec is reported through
1017
+ // the `warning` that is prepended to the child's output below.
1018
+ if (!parentModel) {
1019
+ return {
1020
+ agent: name,
1021
+ task,
1022
+ exitCode: 1,
1023
+ output: "",
1024
+ stderr: "",
1025
+ errorMessage: "Single model mode is enabled, but the parent session's model is unavailable, so subagent " +
1026
+ `"${name}" cannot be spawned. Disable singleModelMode or run the parent session with a model.`,
1027
+ };
1028
+ }
1029
+ const parentResolution = resolveModelStringSingle(parentModel, parentProvider, registry);
1030
+ if (!parentResolution.ok) {
1031
+ return {
1032
+ agent: name,
1033
+ task,
1034
+ exitCode: 1,
1035
+ output: "",
1036
+ stderr: "",
1037
+ errorMessage: `Single model mode: ${parentResolution.error}`,
1038
+ };
1039
+ }
1040
+ effectiveConfig = { ...effectiveConfig, model: parentResolution.modelId };
1041
+ if (parentResolution.provider)
1042
+ resolvedProvider = parentResolution.provider;
1043
+ if (registry && resolvedProvider)
1044
+ resolvedModel = registry.find(resolvedProvider, parentResolution.modelId);
1045
+ if (configuredModelSpec) {
1046
+ warning =
1047
+ `The user has enabled "single model mode" in the settings, so the model selection for this subagent ` +
1048
+ `was ignored. Using parent model "${canonicalModelRef(resolvedProvider, parentResolution.modelId)}".`;
1049
+ }
1050
+ }
1051
+ else if (modelSpec) {
1012
1052
  const parentFallback = configuredModelSpec ? parentModel : undefined;
1013
1053
  const resolved = await resolveModelForSubagentSpawn(modelSpec, parentProvider, registry, parentFallback, signal, "[subagent]", parentSessionId);
1014
1054
  skippedModels = resolved.skippedModels;
@@ -1044,7 +1084,9 @@ parentSessionId) {
1044
1084
  const proposalSelectedModel = proposalModelId ? canonicalModelRef(resolvedProvider, proposalModelId) : undefined;
1045
1085
  let finalThinking = thinkingOverride;
1046
1086
  let arbitrationEnabled = false;
1047
- if (arbitration) {
1087
+ // Single-model mode (issue 517) bypasses the dispatch arbiter: the parent model is the
1088
+ // final route, and the requested thinking is validated against it below like any other.
1089
+ if (arbitration && !singleModelMode) {
1048
1090
  const proposed = {
1049
1091
  agent: name,
1050
1092
  model: proposalSelectedModel ?? "",
@@ -1220,7 +1262,13 @@ parentSessionId) {
1220
1262
  }
1221
1263
  async function executeChain(agents, chain, defaultCwd, signal, onProgress, parentProvider, registry, sessionBaseDir, defaultAgent, defaultModel, defaultThinking, parentModel, getAgentModelsForAgentFn, parentSessionFile, onChildEvent, arbitration, onControlAvailable,
1222
1264
  /** Parent session UUID for spawn-time availability probes (issue 500). */
1223
- parentSessionId) {
1265
+ parentSessionId,
1266
+ /**
1267
+ * Live single-model mode getter (issue 517): evaluated per step so each chain step
1268
+ * runs on the parent session's model when enabled, matching the per-spawn semantics
1269
+ * of single and parallel modes.
1270
+ */
1271
+ getSingleModelMode) {
1224
1272
  const results = [];
1225
1273
  let previousOutput = "";
1226
1274
  for (let i = 0; i < chain.length; i++) {
@@ -1257,7 +1305,10 @@ parentSessionId) {
1257
1305
  const stepSessionDir = sessionBaseDir ? join(sessionBaseDir, `step-${i + 1}`) : undefined;
1258
1306
  const stepAgentName = step.agent || defaultAgent || DEFAULT_AGENT;
1259
1307
  const stepMach6Models = getAgentModelsForAgentFn?.(stepAgentName);
1260
- const result = await executeSingle(agents, step.agent || defaultAgent, task, cwdResult.cwd, signal, onProgress, step.model || defaultModel, parentProvider, registry, stepSessionDir, parentModel, stepMach6Models, parentSessionFile, onChildEvent, resolveSubagentThinkingOverride(step.thinking, defaultThinking), arbitration ? { ...arbitration, step: i + 1 } : undefined, onControlAvailable, parentSessionId);
1308
+ // Single-model mode (issue 517) is re-read per step so a mid-chain settings
1309
+ // change applies from the next step onward.
1310
+ const singleModelMode = getSingleModelMode?.() ?? false;
1311
+ const result = await executeSingle(agents, step.agent || defaultAgent, task, cwdResult.cwd, signal, onProgress, step.model || defaultModel, parentProvider, registry, stepSessionDir, parentModel, stepMach6Models, parentSessionFile, onChildEvent, resolveSubagentThinkingOverride(step.thinking, defaultThinking), arbitration ? { ...arbitration, step: i + 1 } : undefined, onControlAvailable, parentSessionId, singleModelMode);
1261
1312
  results.push(result);
1262
1313
  if (result.exitCode !== 0) {
1263
1314
  break; // stop chain on error
@@ -1759,6 +1810,7 @@ export function createSubagentToolDefinition(cwd, options) {
1759
1810
  const getParentModel = options?.parentModel ?? (() => undefined);
1760
1811
  const getParentSessionFile = options?.parentSessionFile ?? (() => undefined);
1761
1812
  const getParentSessionId = options?.parentSessionId ?? (() => undefined);
1813
+ const getSingleModelMode = options?.singleModelMode ?? (() => false);
1762
1814
  const modelRegistry = options?.modelRegistry;
1763
1815
  const getAgentModelsForAgent = options?.getAgentModelsForAgent;
1764
1816
  const arbitrate = options?.arbitrate;
@@ -1978,7 +2030,7 @@ export function createSubagentToolDefinition(cwd, options) {
1978
2030
  defaultThinkingLevel: getDefaultThinkingLevel?.(),
1979
2031
  getAgentModelsForAgent,
1980
2032
  }
1981
- : undefined, onControlAvailable, getParentSessionId()));
2033
+ : undefined, onControlAvailable, getParentSessionId(), getSingleModelMode()));
1982
2034
  };
1983
2035
  if (params.task) {
1984
2036
  // Single background task
@@ -2051,7 +2103,7 @@ export function createSubagentToolDefinition(cwd, options) {
2051
2103
  defaultThinkingLevel: getDefaultThinkingLevel?.(),
2052
2104
  getAgentModelsForAgent,
2053
2105
  }
2054
- : undefined, onControlAvailable, getParentSessionId());
2106
+ : undefined, onControlAvailable, getParentSessionId(), getSingleModelMode);
2055
2107
  const resultText = results
2056
2108
  .map((r, i) => `### Step ${i + 1}\n${formatSingleResult(r)}`)
2057
2109
  .join("\n\n---\n\n");