@dreb/coding-agent 2.59.2 → 2.60.1

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.
@@ -36,7 +36,7 @@ import { PerformanceTracker } from "./performance-tracker.js";
36
36
  import { expandPromptTemplate } from "./prompt-templates.js";
37
37
  import { scrubSecrets } from "./secret-scrubber.js";
38
38
  import { isSensitivePath } from "./sensitive-paths.js";
39
- import { CURRENT_SESSION_VERSION, getLatestCompactionEntry } from "./session-manager.js";
39
+ import { CURRENT_SESSION_VERSION, getLatestCompactionEntry, SessionManager, } from "./session-manager.js";
40
40
  import { DEFAULT_BG_PARENT_TURN_LIMIT, DEFAULT_MAX_CONCURRENT_SUBAGENTS, } from "./settings-manager.js";
41
41
  import { createSyntheticSourceInfo } from "./source-info.js";
42
42
  import { buildSystemPrompt } from "./system-prompt.js";
@@ -1217,6 +1217,17 @@ export class AgentSession {
1217
1217
  _getFilteredSkills() {
1218
1218
  return this.getFilteredSkills();
1219
1219
  }
1220
+ _resolveModelPromptSettings(model) {
1221
+ if (!model)
1222
+ return undefined;
1223
+ const modelRef = `${model.provider}/${model.id}`;
1224
+ const modelsJsonSettings = this._modelRegistry.getModelPromptSettings(model.provider, model.id);
1225
+ const settingsJsonSettings = this.settingsManager.getModelPromptSettings(model.provider, model.id);
1226
+ if (modelsJsonSettings && settingsJsonSettings) {
1227
+ throw new Error(`System prompt behavior for ${modelRef} is configured in both models.json and settings.json; remove one source`);
1228
+ }
1229
+ return modelsJsonSettings ?? settingsJsonSettings;
1230
+ }
1220
1231
  _rebuildSystemPrompt(toolNames) {
1221
1232
  const validToolNames = toolNames.filter((name) => this._toolRegistry.has(name));
1222
1233
  const toolSnippets = {};
@@ -1233,7 +1244,13 @@ export class AgentSession {
1233
1244
  }
1234
1245
  const loaderSystemPrompt = this._resourceLoader.getSystemPrompt();
1235
1246
  const loaderAppendSystemPrompt = this._resourceLoader.getAppendSystemPrompt();
1236
- const appendSystemPrompt = loaderAppendSystemPrompt.length > 0 ? loaderAppendSystemPrompt.join("\n\n") : undefined;
1247
+ const modelPromptSettings = this._resolveModelPromptSettings(this.model);
1248
+ const customPrompt = loaderSystemPrompt ?? modelPromptSettings?.systemPrompt;
1249
+ const appendPromptParts = [...loaderAppendSystemPrompt];
1250
+ if (modelPromptSettings?.appendSystemPrompt) {
1251
+ appendPromptParts.push(modelPromptSettings.appendSystemPrompt);
1252
+ }
1253
+ const appendSystemPrompt = appendPromptParts.length > 0 ? appendPromptParts.join("\n\n") : undefined;
1237
1254
  const loadedSkills = this._getFilteredSkills();
1238
1255
  const loadedContextFiles = this._resourceLoader.getAgentsFiles().agentsFiles;
1239
1256
  const memoryIndexes = this._resourceLoader.getMemoryIndexes();
@@ -1242,7 +1259,7 @@ export class AgentSession {
1242
1259
  skills: loadedSkills,
1243
1260
  contextFiles: loadedContextFiles,
1244
1261
  memoryIndexes,
1245
- customPrompt: loaderSystemPrompt,
1262
+ customPrompt,
1246
1263
  appendSystemPrompt,
1247
1264
  selectedTools: validToolNames,
1248
1265
  toolSnippets,
@@ -1723,6 +1740,7 @@ export class AgentSession {
1723
1740
  if (!apiKey) {
1724
1741
  throw new Error(`No API key for ${model.provider}/${model.id}`);
1725
1742
  }
1743
+ this._validateModelPromptSettings(model);
1726
1744
  const previousModel = this.model;
1727
1745
  const thinkingLevel = this._getThinkingLevelForModelSwitch();
1728
1746
  this.agent.setModel(this._applyContextTier(model));
@@ -1744,6 +1762,10 @@ export class AgentSession {
1744
1762
  _refreshThinkingDisplay(model) {
1745
1763
  this.agent.thinkingDisplay = resolveThinkingDisplay(model, this.settingsManager.getModelThinkingDisplay(model.id));
1746
1764
  }
1765
+ /** Reject malformed or conflicting target-model prompt settings before mutating session state. */
1766
+ _validateModelPromptSettings(model) {
1767
+ this._resolveModelPromptSettings(model);
1768
+ }
1747
1769
  /**
1748
1770
  * Cycle to next/previous model.
1749
1771
  * Uses scoped models (from --models flag) if available, otherwise all available models.
@@ -1786,6 +1808,7 @@ export class AgentSession {
1786
1808
  const len = scopedModels.length;
1787
1809
  const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
1788
1810
  const next = scopedModels[nextIndex];
1811
+ this._validateModelPromptSettings(next.model);
1789
1812
  const thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);
1790
1813
  // Apply model
1791
1814
  this.agent.setModel(this._applyContextTier(next.model));
@@ -1817,6 +1840,7 @@ export class AgentSession {
1817
1840
  if (!apiKey) {
1818
1841
  throw new Error(`No API key for ${nextModel.provider}/${nextModel.id}`);
1819
1842
  }
1843
+ this._validateModelPromptSettings(nextModel);
1820
1844
  const thinkingLevel = this._getThinkingLevelForModelSwitch();
1821
1845
  this.agent.setModel(this._applyContextTier(nextModel));
1822
1846
  this._refreshThinkingDisplay(nextModel);
@@ -2705,9 +2729,19 @@ export class AgentSession {
2705
2729
  });
2706
2730
  }
2707
2731
  async reload() {
2732
+ // Refresh and validate prompt configuration before tearing down the active runtime.
2733
+ // A bad external edit must leave the current prompt and extension runtime usable.
2734
+ this.settingsManager.reload();
2735
+ this._modelRegistry.refresh();
2736
+ const modelRegistryError = this._modelRegistry.getError();
2737
+ if (modelRegistryError) {
2738
+ throw new Error(modelRegistryError);
2739
+ }
2740
+ if (this.model) {
2741
+ this._validateModelPromptSettings(this.model);
2742
+ }
2708
2743
  const previousFlagValues = this._extensionRunner?.getFlagValues();
2709
2744
  await this._extensionRunner?.emit({ type: "session_shutdown" });
2710
- this.settingsManager.reload();
2711
2745
  resetApiProviders();
2712
2746
  await this._resourceLoader.reload();
2713
2747
  this._buildRuntime({
@@ -2959,6 +2993,17 @@ export class AgentSession {
2959
2993
  return false;
2960
2994
  }
2961
2995
  }
2996
+ // Resolve and validate the target model before disconnecting or mutating the active session.
2997
+ // Prompt validation can throw for malformed settings, so it belongs in this preflight phase.
2998
+ const targetModel = SessionManager.open(sessionPath).buildSessionContext().model;
2999
+ let restoredModel;
3000
+ if (targetModel) {
3001
+ const availableModels = await this._modelRegistry.getAvailable();
3002
+ restoredModel = availableModels.find((m) => m.provider === targetModel.provider && m.id === targetModel.modelId);
3003
+ if (restoredModel) {
3004
+ this._validateModelPromptSettings(restoredModel);
3005
+ }
3006
+ }
2962
3007
  this._disconnectFromAgent();
2963
3008
  await this.abort();
2964
3009
  this._steeringMessages = [];
@@ -2980,16 +3025,12 @@ export class AgentSession {
2980
3025
  }
2981
3026
  // Emit session event to custom tools
2982
3027
  this.agent.replaceMessages(sessionContext.messages);
2983
- // Restore model if saved
2984
- if (sessionContext.model) {
3028
+ // Restore the preflighted model if the target session saved one that is still available.
3029
+ if (restoredModel) {
2985
3030
  const previousModel = this.model;
2986
- const availableModels = await this._modelRegistry.getAvailable();
2987
- const match = availableModels.find((m) => m.provider === sessionContext.model.provider && m.id === sessionContext.model.modelId);
2988
- if (match) {
2989
- this.agent.setModel(this._applyContextTier(match));
2990
- this._refreshThinkingDisplay(match);
2991
- await this._emitModelSelect(match, previousModel, "restore");
2992
- }
3031
+ this.agent.setModel(this._applyContextTier(restoredModel));
3032
+ this._refreshThinkingDisplay(restoredModel);
3033
+ await this._emitModelSelect(restoredModel, previousModel, "restore");
2993
3034
  }
2994
3035
  const hasThinkingEntry = this.sessionManager.getBranch().some((entry) => entry.type === "thinking_level_change");
2995
3036
  const defaultThinkingLevel = this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;
@@ -3009,6 +3050,7 @@ export class AgentSession {
3009
3050
  this._gitRepoState = getGitRepoState(this._cwd) ?? undefined;
3010
3051
  this._resourceLoader.refreshDreamLastRun();
3011
3052
  this._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());
3053
+ this.agent.setSystemPrompt(this._baseSystemPrompt);
3012
3054
  this._reconnectToAgent();
3013
3055
  return true;
3014
3056
  }