@ddtcorex/dsh-maestro-supervisor 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/debug-agent.js +60 -20
  2. package/package.json +1 -1
@@ -203,17 +203,17 @@ async function defaultDryBoot() {
203
203
  }
204
204
  }
205
205
  async function defaultFetchLLM(prompt) {
206
- const key = await resolveApiKey();
207
- if (!key)
208
- throw new Error('no api key — set DEEPSEEK_API_KEY or ~/.dsh/.credentials.yaml');
209
- const res = await fetch('https://api.deepseek.com/v1/chat/completions', {
206
+ const cfg = await resolveLLMConfig();
207
+ if (!cfg.key)
208
+ throw new Error('no api key — set DEEPSEEK_API_KEY / OMNI_ROUTE_API_KEY / OPENCODE_GO_API_KEY / OPENAI_API_KEY or ~/.dsh/.credentials.yaml or AI_API_KEY');
209
+ const res = await fetch(cfg.url, {
210
210
  method: 'POST',
211
211
  headers: {
212
212
  'Content-Type': 'application/json',
213
- 'Authorization': `Bearer ${key}`,
213
+ 'Authorization': `Bearer ${cfg.key}`,
214
214
  },
215
215
  body: JSON.stringify({
216
- model: 'deepseek-chat',
216
+ model: cfg.model,
217
217
  temperature: 0.2,
218
218
  messages: [
219
219
  { role: 'system', content: 'You are a systematic-debugging agent for DSH Web resilience. Follow the 4 phases: root cause, pattern analysis, hypothesis, implementation. Always propose minimal single-file fix.' },
@@ -226,25 +226,65 @@ async function defaultFetchLLM(prompt) {
226
226
  const j = await res.json();
227
227
  return j.choices?.[0]?.message?.content ?? JSON.stringify(j);
228
228
  }
229
- async function resolveApiKey() {
230
- if (process.env.DEEPSEEK_API_KEY)
231
- return process.env.DEEPSEEK_API_KEY;
232
- if (process.env.OPENCODE_GO_API_KEY)
233
- return process.env.OPENCODE_GO_API_KEY;
229
+ async function resolveLLMConfig() {
230
+ // Custom AI provider: env overrides, then credentials.yaml, then settings.json, then defaults
231
+ // Url: AI_API_URL / DEEPSEEK_API_URL / OPENAI_API_BASE / OMNI_ROUTE_API_URL -> default deepseek
232
+ const url = process.env.AI_API_URL ??
233
+ process.env.DEAPSEEK_API_URL ??
234
+ process.env.DEEPSEEK_API_URL ??
235
+ process.env.OPENAI_API_BASE ??
236
+ process.env.OMNI_ROUTE_API_URL ??
237
+ process.env.OPENCODE_API_URL ??
238
+ 'https://api.deepseek.com/v1/chat/completions';
239
+ // Model: AI_MODEL / DEEPSEEK_MODEL / settings.json domains.review.model
240
+ let model = process.env.AI_MODEL ?? process.env.DEEPSEEK_MODEL ?? process.env.OPENAI_MODEL ?? 'deepseek-chat';
234
241
  try {
235
242
  const { readFileSync } = await import('node:fs');
236
243
  const { homedir } = await import('node:os');
237
- const p = `${homedir()}/.dsh/.credentials.yaml`;
238
- const content = readFileSync(p, 'utf-8');
239
- const m = content.match(/DEEPSEEK_API_KEY:\s*["']?([^"'\n]+)["']?/);
240
- if (m)
241
- return m[1].trim();
242
- const m2 = content.match(/OPENCODE_GO_API_KEY:\s*["']?([^"'\n]+)["']?/);
243
- if (m2)
244
- return m2[1].trim();
244
+ const settingsPath = `${homedir()}/.dsh/maestro/settings.json`;
245
+ const raw = readFileSync(settingsPath, 'utf-8');
246
+ const j = JSON.parse(raw);
247
+ const m = j?.domains?.review?.model?.model ?? j?.domains?.review?.model;
248
+ if (typeof m === 'string' && !process.env.AI_MODEL && !process.env.DEEPSEEK_MODEL)
249
+ model = m;
250
+ else if (m?.model && typeof m.model === 'string' && !process.env.AI_MODEL)
251
+ model = m.model;
245
252
  }
246
253
  catch { }
247
- return null;
254
+ // Key: AI_API_KEY / DEEPSEEK_API_KEY / OMNI_ROUTE_API_KEY / OPENCODE_GO_API_KEY / OPENAI_API_KEY
255
+ let key = process.env.AI_API_KEY ??
256
+ process.env.DEEPSEEK_API_KEY ??
257
+ process.env.OMNI_ROUTE_API_KEY ??
258
+ process.env.OPENCODE_GO_API_KEY ??
259
+ process.env.OPENAI_API_KEY ??
260
+ null;
261
+ if (!key) {
262
+ try {
263
+ const { readFileSync } = await import('node:fs');
264
+ const { homedir } = await import('node:os');
265
+ const p = `${homedir()}/.dsh/.credentials.yaml`;
266
+ const content = readFileSync(p, 'utf-8');
267
+ const keys = ['AI_API_KEY', 'DEEPSEEK_API_KEY', 'OMNI_ROUTE_API_KEY', 'OPENCODE_GO_API_KEY', 'OPENAI_API_KEY'];
268
+ for (const k of keys) {
269
+ const m = content.match(new RegExp(`${k}:\\s*["']?([^"'\\n]+)["']?`));
270
+ if (m) {
271
+ key = m[1].trim();
272
+ break;
273
+ }
274
+ }
275
+ }
276
+ catch { }
277
+ }
278
+ // If url is base without /v1/chat/completions, append
279
+ let finalUrl = url;
280
+ if (!url.includes('/v1/') && !url.includes('/chat/completions')) {
281
+ finalUrl = url.replace(/\/$/, '') + '/v1/chat/completions';
282
+ }
283
+ return { key, url: finalUrl, model };
284
+ }
285
+ async function resolveApiKey() {
286
+ const cfg = await resolveLLMConfig();
287
+ return cfg.key;
248
288
  }
249
289
  export function _resetDebugAgentForTest() {
250
290
  lastRun = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ddtcorex/dsh-maestro-supervisor",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Supervisor daemon for DSH Web resilience — auto-detect crashes, rollback to LKG, report",
5
5
  "type": "module",
6
6
  "bin": {