@mcoda/core 0.1.7 → 0.1.9

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 (71) hide show
  1. package/CHANGELOG.md +4 -1
  2. package/README.md +22 -3
  3. package/dist/api/AgentsApi.d.ts +8 -1
  4. package/dist/api/AgentsApi.d.ts.map +1 -1
  5. package/dist/api/AgentsApi.js +70 -0
  6. package/dist/api/QaTasksApi.d.ts.map +1 -1
  7. package/dist/api/QaTasksApi.js +2 -0
  8. package/dist/api/TasksApi.d.ts.map +1 -1
  9. package/dist/api/TasksApi.js +1 -0
  10. package/dist/index.d.ts +4 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +4 -0
  13. package/dist/prompts/PdrPrompts.d.ts.map +1 -1
  14. package/dist/prompts/PdrPrompts.js +3 -1
  15. package/dist/prompts/SdsPrompts.d.ts.map +1 -1
  16. package/dist/prompts/SdsPrompts.js +2 -0
  17. package/dist/services/agents/AgentRatingFormula.d.ts +27 -0
  18. package/dist/services/agents/AgentRatingFormula.d.ts.map +1 -0
  19. package/dist/services/agents/AgentRatingFormula.js +45 -0
  20. package/dist/services/agents/AgentRatingService.d.ts +41 -0
  21. package/dist/services/agents/AgentRatingService.d.ts.map +1 -0
  22. package/dist/services/agents/AgentRatingService.js +299 -0
  23. package/dist/services/agents/GatewayAgentService.d.ts +3 -0
  24. package/dist/services/agents/GatewayAgentService.d.ts.map +1 -1
  25. package/dist/services/agents/GatewayAgentService.js +68 -24
  26. package/dist/services/agents/GatewayHandoff.d.ts +7 -0
  27. package/dist/services/agents/GatewayHandoff.d.ts.map +1 -0
  28. package/dist/services/agents/GatewayHandoff.js +108 -0
  29. package/dist/services/backlog/TaskOrderingService.d.ts +1 -0
  30. package/dist/services/backlog/TaskOrderingService.d.ts.map +1 -1
  31. package/dist/services/backlog/TaskOrderingService.js +19 -16
  32. package/dist/services/docs/DocsService.d.ts +11 -1
  33. package/dist/services/docs/DocsService.d.ts.map +1 -1
  34. package/dist/services/docs/DocsService.js +240 -52
  35. package/dist/services/execution/GatewayTrioService.d.ts +133 -0
  36. package/dist/services/execution/GatewayTrioService.d.ts.map +1 -0
  37. package/dist/services/execution/GatewayTrioService.js +1125 -0
  38. package/dist/services/execution/QaFollowupService.d.ts +1 -0
  39. package/dist/services/execution/QaFollowupService.d.ts.map +1 -1
  40. package/dist/services/execution/QaFollowupService.js +1 -0
  41. package/dist/services/execution/QaProfileService.d.ts +6 -0
  42. package/dist/services/execution/QaProfileService.d.ts.map +1 -1
  43. package/dist/services/execution/QaProfileService.js +165 -3
  44. package/dist/services/execution/QaTasksService.d.ts +18 -0
  45. package/dist/services/execution/QaTasksService.d.ts.map +1 -1
  46. package/dist/services/execution/QaTasksService.js +712 -34
  47. package/dist/services/execution/WorkOnTasksService.d.ts +14 -0
  48. package/dist/services/execution/WorkOnTasksService.d.ts.map +1 -1
  49. package/dist/services/execution/WorkOnTasksService.js +1497 -240
  50. package/dist/services/openapi/OpenApiService.d.ts +10 -0
  51. package/dist/services/openapi/OpenApiService.d.ts.map +1 -1
  52. package/dist/services/openapi/OpenApiService.js +66 -10
  53. package/dist/services/planning/CreateTasksService.d.ts +6 -0
  54. package/dist/services/planning/CreateTasksService.d.ts.map +1 -1
  55. package/dist/services/planning/CreateTasksService.js +261 -28
  56. package/dist/services/planning/RefineTasksService.d.ts +5 -0
  57. package/dist/services/planning/RefineTasksService.d.ts.map +1 -1
  58. package/dist/services/planning/RefineTasksService.js +184 -35
  59. package/dist/services/review/CodeReviewService.d.ts +14 -0
  60. package/dist/services/review/CodeReviewService.d.ts.map +1 -1
  61. package/dist/services/review/CodeReviewService.js +657 -61
  62. package/dist/services/shared/ProjectGuidance.d.ts +6 -0
  63. package/dist/services/shared/ProjectGuidance.d.ts.map +1 -0
  64. package/dist/services/shared/ProjectGuidance.js +21 -0
  65. package/dist/services/tasks/TaskCommentFormatter.d.ts +20 -0
  66. package/dist/services/tasks/TaskCommentFormatter.d.ts.map +1 -0
  67. package/dist/services/tasks/TaskCommentFormatter.js +54 -0
  68. package/dist/workspace/WorkspaceManager.d.ts +4 -0
  69. package/dist/workspace/WorkspaceManager.d.ts.map +1 -1
  70. package/dist/workspace/WorkspaceManager.js +3 -0
  71. package/package.json +5 -5
@@ -0,0 +1,299 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs/promises";
3
+ import { AgentService } from "@mcoda/agents";
4
+ import { GlobalRepository, WorkspaceRepository } from "@mcoda/db";
5
+ import { RoutingService } from "./RoutingService.js";
6
+ import { computeAlpha, computeRunScore, DEFAULT_RATING_BUDGETS, DEFAULT_RATING_WEIGHTS, updateEmaRating, } from "./AgentRatingFormula.js";
7
+ const DEFAULT_REVIEW_PROMPT = [
8
+ "You are the system reviewer for mcoda.",
9
+ "Rate the agent's delivered work quality on a 0-10 scale.",
10
+ "Base your rating on correctness, completeness, and adherence to task requirements.",
11
+ "Return JSON only with this schema:",
12
+ "{",
13
+ ' "quality_score": number,',
14
+ ' "reasoning": "short explanation",',
15
+ ' "strengths": ["..."],',
16
+ ' "defects": ["..."]',
17
+ "}",
18
+ ].join("\n");
19
+ const COMPLEXITY_COOLDOWN_SECONDS = 60 * 60 * 24;
20
+ const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
21
+ const extractJson = (raw) => {
22
+ if (!raw)
23
+ return undefined;
24
+ const fenced = raw.match(/```json([\s\S]*?)```/);
25
+ const candidate = fenced ? fenced[1] : raw;
26
+ const start = candidate.indexOf("{");
27
+ const end = candidate.lastIndexOf("}");
28
+ if (start === -1 || end === -1 || end <= start)
29
+ return undefined;
30
+ try {
31
+ return JSON.parse(candidate.slice(start, end + 1));
32
+ }
33
+ catch {
34
+ return undefined;
35
+ }
36
+ };
37
+ export class AgentRatingService {
38
+ constructor(workspace, deps) {
39
+ this.workspace = workspace;
40
+ this.deps = deps;
41
+ }
42
+ static async create(workspace) {
43
+ const workspaceRepo = await WorkspaceRepository.create(workspace.workspaceRoot);
44
+ const globalRepo = await GlobalRepository.create();
45
+ const agentService = new AgentService(globalRepo);
46
+ const routingService = await RoutingService.create();
47
+ return new AgentRatingService(workspace, {
48
+ workspaceRepo,
49
+ globalRepo,
50
+ agentService,
51
+ routingService,
52
+ });
53
+ }
54
+ async close() {
55
+ await this.deps.workspaceRepo.close();
56
+ await this.deps.globalRepo.close();
57
+ if (this.deps.routingService?.close) {
58
+ await this.deps.routingService.close();
59
+ }
60
+ }
61
+ ratingPromptPath() {
62
+ return path.join(this.workspace.workspaceRoot, ".mcoda", "prompts", "agent-rating.md");
63
+ }
64
+ async loadRatingPrompt() {
65
+ const promptPath = this.ratingPromptPath();
66
+ try {
67
+ const raw = await fs.readFile(promptPath, "utf8");
68
+ const trimmed = raw.trim();
69
+ if (trimmed)
70
+ return trimmed;
71
+ }
72
+ catch {
73
+ await fs.mkdir(path.dirname(promptPath), { recursive: true });
74
+ await fs.writeFile(promptPath, DEFAULT_REVIEW_PROMPT, "utf8");
75
+ }
76
+ return DEFAULT_REVIEW_PROMPT;
77
+ }
78
+ async resolveReviewer(agentOverride) {
79
+ if (agentOverride) {
80
+ return this.deps.agentService.resolveAgent(agentOverride);
81
+ }
82
+ const resolved = await this.deps.routingService.resolveAgentForCommand({
83
+ commandName: "agent-rating",
84
+ workspace: this.workspace,
85
+ });
86
+ return resolved.agent;
87
+ }
88
+ async loadUsage(request) {
89
+ const db = this.deps.workspaceRepo.getDb();
90
+ const clauses = ["workspace_id = ?", "agent_id = ?"];
91
+ const params = [this.workspace.workspaceId, request.agentId];
92
+ if (request.commandRunId) {
93
+ clauses.push("command_run_id = ?");
94
+ params.push(request.commandRunId);
95
+ }
96
+ if (request.jobId) {
97
+ clauses.push("job_id = ?");
98
+ params.push(request.jobId);
99
+ }
100
+ if (request.taskId) {
101
+ clauses.push("task_id = ?");
102
+ params.push(request.taskId);
103
+ }
104
+ const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
105
+ return db.all(`SELECT tokens_total, duration_seconds, cost_estimate, metadata_json FROM token_usage ${where}`, ...params);
106
+ }
107
+ countIterations(rows) {
108
+ if (!rows.length)
109
+ return 0;
110
+ const attempts = rows.filter((row) => {
111
+ if (!row.metadata_json)
112
+ return false;
113
+ try {
114
+ const meta = JSON.parse(row.metadata_json);
115
+ const action = String(meta.action ?? meta.phase ?? "").toLowerCase();
116
+ return action.includes("agent") || action.includes("review") || action.includes("qa");
117
+ }
118
+ catch {
119
+ return false;
120
+ }
121
+ });
122
+ const count = attempts.length || rows.length;
123
+ return Math.max(1, count);
124
+ }
125
+ async loadDurationSeconds(request, usageRows) {
126
+ const sum = usageRows.reduce((acc, row) => acc + (row.duration_seconds ?? 0), 0);
127
+ if (sum > 0)
128
+ return sum;
129
+ const db = this.deps.workspaceRepo.getDb();
130
+ if (request.commandRunId) {
131
+ const row = await db.get("SELECT started_at, completed_at, duration_seconds FROM command_runs WHERE id = ?", request.commandRunId);
132
+ if (row?.duration_seconds)
133
+ return row.duration_seconds;
134
+ if (row?.started_at && row?.completed_at) {
135
+ return Math.max(0, (Date.parse(row.completed_at) - Date.parse(row.started_at)) / 1000);
136
+ }
137
+ }
138
+ if (request.jobId) {
139
+ const row = await db.get("SELECT created_at, completed_at FROM jobs WHERE id = ?", request.jobId);
140
+ if (row?.created_at && row?.completed_at) {
141
+ return Math.max(0, (Date.parse(row.completed_at) - Date.parse(row.created_at)) / 1000);
142
+ }
143
+ }
144
+ return 0;
145
+ }
146
+ async buildReviewContext(request) {
147
+ if (!request.taskId && !request.taskKey) {
148
+ return `Command: ${request.commandName}`;
149
+ }
150
+ let task = undefined;
151
+ if (request.taskId) {
152
+ task = await this.deps.workspaceRepo.getTaskById(request.taskId);
153
+ }
154
+ else if (request.taskKey) {
155
+ task = await this.deps.workspaceRepo.getTaskByKey(request.taskKey);
156
+ }
157
+ const comments = task ? await this.deps.workspaceRepo.listTaskComments(task.id, { limit: 5 }) : [];
158
+ const qaRuns = task ? await this.deps.workspaceRepo.listTaskQaRuns(task.id) : [];
159
+ const review = task ? await this.deps.workspaceRepo.getLatestTaskReview(task.id) : undefined;
160
+ const commentText = comments.map((c) => `- [${c.category ?? "comment"}] ${c.body}`).join("\n");
161
+ const qaText = qaRuns.slice(0, 2).map((q) => `- outcome=${q.recommendation ?? q.rawOutcome ?? "n/a"}`).join("\n");
162
+ return [
163
+ `Command: ${request.commandName}`,
164
+ task ? `Task: ${task.key} ${task.title}` : "",
165
+ task?.description ? `Description: ${task.description}` : "",
166
+ review ? `Latest review decision: ${review.decision}` : "",
167
+ qaText ? `Latest QA:\n${qaText}` : "",
168
+ commentText ? `Recent comments:\n${commentText}` : "",
169
+ ]
170
+ .filter(Boolean)
171
+ .join("\n");
172
+ }
173
+ async runReviewer(prompt, reviewer) {
174
+ const response = await this.deps.agentService.invoke(reviewer.id, { input: prompt, metadata: { command: "agent-rating" } });
175
+ const parsed = extractJson(response.output ?? "");
176
+ const qualityRaw = typeof parsed?.quality_score === "number" ? parsed?.quality_score : undefined;
177
+ const qualityScore = clamp(qualityRaw ?? 7, 0, 10);
178
+ return {
179
+ qualityScore,
180
+ raw: parsed ?? null,
181
+ reasoning: typeof parsed?.reasoning === "string" ? parsed?.reasoning : undefined,
182
+ };
183
+ }
184
+ computeBudgets(complexity) {
185
+ const factor = clamp(complexity / 5, 0.5, 2);
186
+ return {
187
+ costUsd: DEFAULT_RATING_BUDGETS.costUsd * factor,
188
+ durationSeconds: DEFAULT_RATING_BUDGETS.durationSeconds * factor,
189
+ iterations: Math.max(1, Math.round(DEFAULT_RATING_BUDGETS.iterations + complexity / 3)),
190
+ };
191
+ }
192
+ async rate(request) {
193
+ const agent = await this.deps.globalRepo.getAgentById(request.agentId);
194
+ if (!agent) {
195
+ throw new Error(`Agent ${request.agentId} not found for rating.`);
196
+ }
197
+ const usageRows = await this.loadUsage(request);
198
+ const tokensTotal = usageRows.reduce((acc, row) => acc + (row.tokens_total ?? 0), 0);
199
+ const durationSeconds = await this.loadDurationSeconds(request, usageRows);
200
+ const iterations = this.countIterations(usageRows);
201
+ const costEstimate = usageRows.reduce((acc, row) => acc + (row.cost_estimate ?? 0), 0);
202
+ const costPerMillion = agent.costPerMillion ?? 0;
203
+ const totalCost = costEstimate > 0 ? costEstimate : (tokensTotal * costPerMillion) / 1000000;
204
+ const complexity = clamp(Math.round(request.complexity ?? 5), 1, 10);
205
+ const budgets = this.computeBudgets(complexity);
206
+ const weights = DEFAULT_RATING_WEIGHTS;
207
+ const reviewContext = await this.buildReviewContext(request);
208
+ const reviewerPrompt = await this.loadRatingPrompt();
209
+ const reviewer = await this.resolveReviewer(request.reviewerAgentName);
210
+ const reviewerInput = [reviewerPrompt, "", reviewContext].filter(Boolean).join("\n");
211
+ const review = await this.runReviewer(reviewerInput, reviewer);
212
+ const runScore = computeRunScore({
213
+ qualityScore: review.qualityScore,
214
+ totalCost,
215
+ durationSeconds,
216
+ iterations,
217
+ budgets,
218
+ weights,
219
+ });
220
+ const alpha = computeAlpha(request.ratingWindow ?? 50);
221
+ const baseRating = agent.rating ?? runScore;
222
+ const updatedRating = updateEmaRating(baseRating, runScore, alpha);
223
+ const baseReasoning = agent.reasoningRating ?? baseRating;
224
+ const updatedReasoning = updateEmaRating(baseReasoning, runScore, alpha);
225
+ const updatedSamples = (agent.ratingSamples ?? 0) + 1;
226
+ const now = new Date().toISOString();
227
+ const nowMs = Date.parse(now);
228
+ let maxComplexity = agent.maxComplexity ?? 5;
229
+ let complexitySamples = agent.complexitySamples ?? 0;
230
+ let complexityUpdatedAt = agent.complexityUpdatedAt ?? undefined;
231
+ const promoteThreshold = 7.5;
232
+ const demoteThreshold = 4.0;
233
+ const lastComplexityUpdate = complexityUpdatedAt ? Date.parse(complexityUpdatedAt) : NaN;
234
+ const canAdjustComplexity = !Number.isFinite(lastComplexityUpdate) || nowMs - lastComplexityUpdate >= COMPLEXITY_COOLDOWN_SECONDS * 1000;
235
+ if (canAdjustComplexity) {
236
+ if (runScore >= promoteThreshold && review.qualityScore >= 7 && complexity >= maxComplexity) {
237
+ maxComplexity = Math.min(10, maxComplexity + 1);
238
+ complexityUpdatedAt = now;
239
+ complexitySamples += 1;
240
+ }
241
+ else if (runScore <= demoteThreshold && complexity <= maxComplexity) {
242
+ maxComplexity = Math.max(1, maxComplexity - 1);
243
+ complexityUpdatedAt = now;
244
+ complexitySamples += 1;
245
+ }
246
+ }
247
+ await this.deps.globalRepo.updateAgent(agent.id, {
248
+ rating: updatedRating,
249
+ reasoningRating: updatedReasoning,
250
+ ratingSamples: updatedSamples,
251
+ ratingLastScore: runScore,
252
+ ratingUpdatedAt: now,
253
+ maxComplexity,
254
+ complexitySamples,
255
+ complexityUpdatedAt,
256
+ });
257
+ await this.deps.globalRepo.insertAgentRunRating({
258
+ agentId: agent.id,
259
+ jobId: request.jobId ?? null,
260
+ commandRunId: request.commandRunId ?? null,
261
+ taskId: request.taskId ?? null,
262
+ taskKey: request.taskKey ?? null,
263
+ commandName: request.commandName,
264
+ discipline: request.discipline ?? null,
265
+ complexity,
266
+ qualityScore: review.qualityScore,
267
+ tokensTotal,
268
+ durationSeconds,
269
+ iterations,
270
+ totalCost,
271
+ runScore,
272
+ ratingVersion: "v1",
273
+ rawReview: review.raw,
274
+ createdAt: now,
275
+ });
276
+ await this.writeRatingArtifact(request.jobId, {
277
+ agentId: agent.id,
278
+ commandName: request.commandName,
279
+ taskKey: request.taskKey,
280
+ qualityScore: review.qualityScore,
281
+ tokensTotal,
282
+ durationSeconds,
283
+ iterations,
284
+ totalCost,
285
+ runScore,
286
+ rating: updatedRating,
287
+ maxComplexity,
288
+ reviewerAgent: reviewer.slug ?? reviewer.id,
289
+ });
290
+ }
291
+ async writeRatingArtifact(jobId, payload) {
292
+ if (!jobId)
293
+ return;
294
+ const outDir = path.join(this.workspace.workspaceRoot, ".mcoda", "jobs", jobId);
295
+ await fs.mkdir(outDir, { recursive: true });
296
+ const filePath = path.join(outDir, "rating.json");
297
+ await fs.writeFile(filePath, JSON.stringify(payload, null, 2), "utf8");
298
+ }
299
+ }
@@ -65,6 +65,9 @@ export interface GatewayAgentRequest extends TaskSelectionFilters {
65
65
  maxDocs?: number;
66
66
  agentStream?: boolean;
67
67
  onStreamChunk?: (chunk: string) => void;
68
+ rateAgents?: boolean;
69
+ avoidAgents?: string[];
70
+ forceStronger?: boolean;
68
71
  }
69
72
  export declare class GatewayAgentService {
70
73
  private workspace;
@@ -1 +1 @@
1
- {"version":3,"file":"GatewayAgentService.d.ts","sourceRoot":"","sources":["../../../src/services/agents/GatewayAgentService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GatewayAgentService.d.ts","sourceRoot":"","sources":["../../../src/services/agents/GatewayAgentService.ts"],"names":[],"mappings":"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"}
@@ -174,6 +174,7 @@ const scoreUsage = (discipline, bestUsage, capabilities) => {
174
174
  score += 0.5;
175
175
  return score;
176
176
  };
177
+ const EXPLORATION_RATE = 0.1;
177
178
  const DEFAULT_STATUS_FILTER = [
178
179
  "not_started",
179
180
  "in_progress",
@@ -362,14 +363,15 @@ export class GatewayAgentService {
362
363
  const caps = await this.deps.globalRepo.getAgentCapabilities(overrideAgent.id);
363
364
  const missing = requiredCaps.filter((cap) => !caps.includes(cap));
364
365
  const health = await this.deps.globalRepo.getAgentHealth(overrideAgent.id);
365
- if (missing.length === 0 && health?.status !== "unreachable") {
366
- return overrideAgent;
366
+ if (health?.status === "unreachable") {
367
+ warnings.push(`Override agent ${overrideAgent.slug} is unreachable; ignoring override.`);
367
368
  }
368
- if (missing.length) {
369
- warnings.push(`Override agent ${overrideAgent.slug} is missing gateway capabilities (${missing.join(", ")}); ignoring override.`);
369
+ else if (missing.length === 0) {
370
+ return overrideAgent;
370
371
  }
371
- else if (health?.status === "unreachable") {
372
- warnings.push(`Override agent ${overrideAgent.slug} is unreachable; ignoring override.`);
372
+ else {
373
+ warnings.push(`Override agent ${overrideAgent.slug} is missing gateway capabilities (${missing.join(", ")}); proceeding with override as requested.`);
374
+ return overrideAgent;
373
375
  }
374
376
  }
375
377
  catch (overrideError) {
@@ -648,15 +650,19 @@ export class GatewayAgentService {
648
650
  filesToCreate: created,
649
651
  };
650
652
  }
651
- async listCandidates(requiredCaps, discipline) {
653
+ async listCandidates(requiredCaps, discipline, avoidAgents = []) {
652
654
  const agents = await this.deps.globalRepo.listAgents();
653
655
  if (agents.length === 0) {
654
656
  throw new Error("No agents available; register one with mcoda agent add");
655
657
  }
658
+ const avoidSet = new Set(avoidAgents.map((value) => value.toLowerCase()));
656
659
  const health = await this.deps.globalRepo.listAgentHealthSummary();
657
660
  const healthById = new Map(health.map((row) => [row.agentId, row]));
658
661
  const candidates = [];
659
662
  for (const agent of agents) {
663
+ const slug = agent.slug ?? agent.id;
664
+ if (avoidSet.has(agent.id.toLowerCase()) || avoidSet.has(slug.toLowerCase()))
665
+ continue;
660
666
  const capabilities = await this.deps.globalRepo.getAgentCapabilities(agent.id);
661
667
  const missing = requiredCaps.filter((cap) => !capabilities.includes(cap));
662
668
  if (missing.length)
@@ -672,6 +678,9 @@ export class GatewayAgentService {
672
678
  const usageScore = scoreUsage(discipline, agent.bestUsage, capabilities);
673
679
  const cost = agent.costPerMillion ?? Number.POSITIVE_INFINITY;
674
680
  const adjustedQuality = healthEntry?.status === "degraded" ? quality - 0.5 : quality;
681
+ const maxComplexity = typeof agent.maxComplexity === "number" && Number.isFinite(agent.maxComplexity)
682
+ ? clamp(Math.round(agent.maxComplexity), 1, 10)
683
+ : 5;
675
684
  candidates.push({
676
685
  agent,
677
686
  capabilities,
@@ -680,6 +689,7 @@ export class GatewayAgentService {
680
689
  reasoning,
681
690
  usageScore,
682
691
  cost,
692
+ maxComplexity,
683
693
  });
684
694
  }
685
695
  return candidates;
@@ -688,10 +698,42 @@ export class GatewayAgentService {
688
698
  if (candidates.length === 0) {
689
699
  throw new Error("No eligible agents available for this job");
690
700
  }
691
- const sortedQuality = candidates.map((c) => c.quality);
701
+ const normalizedComplexity = clamp(Math.round(complexity), 1, 10);
702
+ const eligible = candidates.filter((c) => c.maxComplexity >= normalizedComplexity);
703
+ let pool = eligible;
704
+ let gatingNote = "";
705
+ if (!eligible.length) {
706
+ const fallback = normalizedComplexity > 1
707
+ ? candidates.filter((c) => c.maxComplexity >= normalizedComplexity - 1)
708
+ : candidates;
709
+ pool = fallback.length ? fallback : candidates;
710
+ gatingNote = fallback.length
711
+ ? ` No agents meet max complexity ${normalizedComplexity}; allowing ${normalizedComplexity - 1} fallback.`
712
+ : ` No agents meet max complexity ${normalizedComplexity}; using best available.`;
713
+ }
714
+ if (Math.random() < EXPLORATION_RATE) {
715
+ const stretchPool = normalizedComplexity > 1
716
+ ? candidates.filter((c) => c.maxComplexity < normalizedComplexity && c.maxComplexity >= normalizedComplexity - 1)
717
+ : [];
718
+ const allowRedemption = normalizedComplexity <= 4;
719
+ const sortedByQuality = pool.slice().sort((a, b) => a.quality - b.quality);
720
+ const redemptionPool = allowRedemption ? sortedByQuality.slice(0, Math.max(1, Math.ceil(pool.length * 0.2))) : [];
721
+ const canUseStretch = stretchPool.length > 0;
722
+ const canUseRedemption = redemptionPool.length > 0;
723
+ if (canUseStretch || canUseRedemption) {
724
+ const useStretch = canUseStretch && (!canUseRedemption || Math.random() < 0.5);
725
+ const explorePool = useStretch ? stretchPool : redemptionPool;
726
+ const pick = explorePool[Math.floor(Math.random() * explorePool.length)];
727
+ const rationale = useStretch
728
+ ? `Exploration: stretching an agent (max complexity ${pick.maxComplexity}) for task complexity ${normalizedComplexity}/10.${gatingNote}`
729
+ : `Exploration: redemption run for a lower-rated agent to reassess performance.${gatingNote}`;
730
+ return { pick, rationale };
731
+ }
732
+ }
733
+ const sortedQuality = pool.map((c) => c.quality);
692
734
  const maxQuality = Math.max(...sortedQuality);
693
- if (complexity >= 9) {
694
- const pick = candidates
735
+ if (normalizedComplexity >= 9) {
736
+ const pick = pool
695
737
  .slice()
696
738
  .sort((a, b) => {
697
739
  if (b.quality !== a.quality)
@@ -704,12 +746,12 @@ export class GatewayAgentService {
704
746
  })[0];
705
747
  return {
706
748
  pick,
707
- rationale: `Complexity ${complexity}/10 requires the highest capability; selected top-rated agent with best fit for ${discipline}.`,
749
+ rationale: `Complexity ${normalizedComplexity}/10 requires the highest capability; selected top-rated agent with best fit for ${discipline}.${gatingNote}`,
708
750
  };
709
751
  }
710
- if (complexity >= 8) {
711
- const pool = candidates.filter((c) => c.quality >= maxQuality - 1);
712
- const pick = (pool.length ? pool : candidates)
752
+ if (normalizedComplexity >= 8) {
753
+ const qualityPool = pool.filter((c) => c.quality >= maxQuality - 1);
754
+ const pick = (qualityPool.length ? qualityPool : pool)
713
755
  .slice()
714
756
  .sort((a, b) => {
715
757
  if (b.usageScore !== a.usageScore)
@@ -720,12 +762,12 @@ export class GatewayAgentService {
720
762
  })[0];
721
763
  return {
722
764
  pick,
723
- rationale: `Complexity ${complexity}/10 favors strong agents with good cost/fit balance; selected best-fit candidate.`,
765
+ rationale: `Complexity ${normalizedComplexity}/10 favors strong agents with good cost/fit balance; selected best-fit candidate.${gatingNote}`,
724
766
  };
725
767
  }
726
- const target = complexity;
727
- const pool = candidates.filter((c) => c.quality >= target);
728
- const base = pool.length ? pool : candidates;
768
+ const target = normalizedComplexity;
769
+ const qualityPool = pool.filter((c) => c.quality >= target);
770
+ const base = qualityPool.length ? qualityPool : pool;
729
771
  const pick = base
730
772
  .slice()
731
773
  .sort((a, b) => {
@@ -741,14 +783,16 @@ export class GatewayAgentService {
741
783
  })[0];
742
784
  return {
743
785
  pick,
744
- rationale: `Complexity ${complexity}/10 targets a comparable tier agent; selected closest match with discipline fit and cost awareness.`,
786
+ rationale: `Complexity ${normalizedComplexity}/10 targets a comparable tier agent; selected closest match with discipline fit and cost awareness.${gatingNote}`,
745
787
  };
746
788
  }
747
- async selectAgentForJob(job, analysis) {
789
+ async selectAgentForJob(job, analysis, avoidAgents = [], forceStronger = false) {
748
790
  const normalizedJob = canonicalizeCommandName(job);
749
791
  const requiredCaps = getCommandRequiredCapabilities(normalizedJob);
750
- const candidates = await this.listCandidates(requiredCaps, analysis.discipline);
751
- const { pick, rationale } = this.chooseCandidate(candidates, analysis.complexity, analysis.discipline);
792
+ const candidates = await this.listCandidates(requiredCaps, analysis.discipline, avoidAgents);
793
+ const boostedComplexity = forceStronger ? clamp(Math.round(analysis.complexity) + 1, 1, 10) : analysis.complexity;
794
+ const { pick, rationale } = this.chooseCandidate(candidates, boostedComplexity, analysis.discipline);
795
+ const finalRationale = forceStronger ? `${rationale} (force_stronger applied)` : rationale;
752
796
  return {
753
797
  agentId: pick.agent.id,
754
798
  agentSlug: pick.agent.slug ?? pick.agent.id,
@@ -756,7 +800,7 @@ export class GatewayAgentService {
756
800
  reasoningRating: pick.agent.reasoningRating ?? undefined,
757
801
  bestUsage: pick.agent.bestUsage ?? undefined,
758
802
  costPerMillion: Number.isFinite(pick.cost) ? pick.cost : undefined,
759
- rationale,
803
+ rationale: finalRationale,
760
804
  };
761
805
  }
762
806
  async run(request) {
@@ -849,7 +893,7 @@ export class GatewayAgentService {
849
893
  analysis.docdexNotes.push(...docdexWarnings);
850
894
  }
851
895
  analysis = await this.validateFilePlan(analysis, warnings);
852
- const chosenAgent = await this.selectAgentForJob(normalizedJob, analysis);
896
+ const chosenAgent = await this.selectAgentForJob(normalizedJob, analysis, request.avoidAgents ?? [], request.forceStronger ?? false);
853
897
  await this.deps.jobService.finishCommandRun(commandRun.id, "succeeded");
854
898
  return {
855
899
  commandRunId: commandRun.id,
@@ -0,0 +1,7 @@
1
+ import type { GatewayAgentResult } from "./GatewayAgentService.js";
2
+ export declare const GATEWAY_HANDOFF_ENV_PATH = "MCODA_GATEWAY_HANDOFF_PATH";
3
+ export declare const buildGatewayHandoffDocdexUsage: () => string;
4
+ export declare const buildGatewayHandoffContent: (result: GatewayAgentResult) => string;
5
+ export declare const writeGatewayHandoffFile: (workspaceRoot: string, commandRunId: string, content: string, prefix?: string) => Promise<string>;
6
+ export declare const withGatewayHandoff: <T>(handoffPath: string | undefined, fn: () => Promise<T>) => Promise<T>;
7
+ //# sourceMappingURL=GatewayHandoff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GatewayHandoff.d.ts","sourceRoot":"","sources":["../../../src/services/agents/GatewayHandoff.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,eAAO,MAAM,wBAAwB,+BAA+B,CAAC;AAErE,eAAO,MAAM,8BAA8B,QAAO,MAiBjD,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAI,QAAQ,kBAAkB,KAAG,MA+DvE,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,eAAe,MAAM,EACrB,cAAc,MAAM,EACpB,SAAS,MAAM,EACf,eAAkB,KACjB,OAAO,CAAC,MAAM,CAMhB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAU,CAAC,EAAE,aAAa,MAAM,GAAG,SAAS,EAAE,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,CAAC,CAc5G,CAAC"}
@@ -0,0 +1,108 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ export const GATEWAY_HANDOFF_ENV_PATH = "MCODA_GATEWAY_HANDOFF_PATH";
4
+ export const buildGatewayHandoffDocdexUsage = () => {
5
+ const lines = [];
6
+ lines.push("## Docdex Usage (required)");
7
+ lines.push("- Use docdexd CLI (daemon-backed), not curl or MCP.");
8
+ lines.push("- Search: `docdexd chat --repo <repo> --query \"...\" --limit 8` (HTTP: `GET /search`).");
9
+ lines.push("- Web: `docdexd web-search`, `docdexd web-fetch`, `docdexd web-rag` (HTTP: `/v1/web/*`).");
10
+ lines.push("- Memory: `docdexd memory-store` / `memory-recall` (HTTP: `/v1/memory/store`, `/v1/memory/recall`).");
11
+ lines.push("- Agent profile: `docdexd profile add/search` (HTTP: `/v1/profile/add`, `/v1/profile/search`, `/v1/profile/save`).");
12
+ lines.push("- AST/impact/snippets use daemon endpoints (`/v1/ast`, `/v1/graph/impact`, `/snippet/:doc_id`).");
13
+ lines.push("- Reasoning DAG: capture session_id (docdex request_id) and export with `docdexd dag view --repo <repo> <session_id> --format text|dot|json`.");
14
+ lines.push("- HTTP DAG export: `GET /v1/dag/export?session_id=<id>&format=json|text|dot&max_nodes=<n>`.");
15
+ lines.push("- Note any docdex failures/disabled memory/profile in task comments or docdexNotes.");
16
+ return lines.join("\n");
17
+ };
18
+ export const buildGatewayHandoffContent = (result) => {
19
+ const lines = [];
20
+ lines.push("# Gateway Handoff");
21
+ lines.push("");
22
+ lines.push(`Job: ${result.job}`);
23
+ lines.push(`Gateway agent: ${result.gatewayAgent.slug}`);
24
+ lines.push(`Chosen agent: ${result.chosenAgent.agentSlug}`);
25
+ lines.push("");
26
+ if (result.analysis.reasoningSummary?.trim()) {
27
+ lines.push("## Reasoning Summary");
28
+ lines.push(result.analysis.reasoningSummary.trim());
29
+ lines.push("");
30
+ }
31
+ lines.push("## Summary");
32
+ lines.push(result.analysis.summary || "(none)");
33
+ lines.push("");
34
+ lines.push("## Current State");
35
+ lines.push(result.analysis.currentState || "(none)");
36
+ lines.push("");
37
+ lines.push("## Todo");
38
+ lines.push(result.analysis.todo || "(none)");
39
+ lines.push("");
40
+ lines.push("## Understanding");
41
+ lines.push(result.analysis.understanding || "(none)");
42
+ lines.push("");
43
+ lines.push("## Plan");
44
+ if (result.analysis.plan.length) {
45
+ result.analysis.plan.forEach((step, idx) => lines.push(`${idx + 1}. ${step}`));
46
+ }
47
+ else {
48
+ lines.push("(none)");
49
+ }
50
+ lines.push("");
51
+ lines.push("## Files Likely Touched");
52
+ if (result.analysis.filesLikelyTouched.length) {
53
+ result.analysis.filesLikelyTouched.forEach((file) => lines.push(`- ${file}`));
54
+ }
55
+ else {
56
+ lines.push("(none)");
57
+ }
58
+ lines.push("");
59
+ lines.push("## Files To Create");
60
+ if (result.analysis.filesToCreate.length) {
61
+ result.analysis.filesToCreate.forEach((file) => lines.push(`- ${file}`));
62
+ }
63
+ else {
64
+ lines.push("(none)");
65
+ }
66
+ if (result.analysis.assumptions.length) {
67
+ lines.push("");
68
+ lines.push("## Assumptions");
69
+ result.analysis.assumptions.forEach((item) => lines.push(`- ${item}`));
70
+ }
71
+ if (result.analysis.risks.length) {
72
+ lines.push("");
73
+ lines.push("## Risks");
74
+ result.analysis.risks.forEach((item) => lines.push(`- ${item}`));
75
+ }
76
+ if (result.analysis.docdexNotes.length) {
77
+ lines.push("");
78
+ lines.push("## Docdex Notes");
79
+ result.analysis.docdexNotes.forEach((item) => lines.push(`- ${item}`));
80
+ }
81
+ lines.push("");
82
+ lines.push(buildGatewayHandoffDocdexUsage());
83
+ return lines.join("\n");
84
+ };
85
+ export const writeGatewayHandoffFile = async (workspaceRoot, commandRunId, content, prefix = "gateway") => {
86
+ const handoffDir = path.join(workspaceRoot, ".mcoda", "handoffs");
87
+ await fs.mkdir(handoffDir, { recursive: true });
88
+ const handoffPath = path.join(handoffDir, `${prefix}-${commandRunId}.md`);
89
+ await fs.writeFile(handoffPath, content, "utf8");
90
+ return handoffPath;
91
+ };
92
+ export const withGatewayHandoff = async (handoffPath, fn) => {
93
+ const previousHandoff = process.env[GATEWAY_HANDOFF_ENV_PATH];
94
+ if (handoffPath) {
95
+ process.env[GATEWAY_HANDOFF_ENV_PATH] = handoffPath;
96
+ }
97
+ try {
98
+ return await fn();
99
+ }
100
+ finally {
101
+ if (previousHandoff === undefined) {
102
+ delete process.env[GATEWAY_HANDOFF_ENV_PATH];
103
+ }
104
+ else {
105
+ process.env[GATEWAY_HANDOFF_ENV_PATH] = previousHandoff;
106
+ }
107
+ }
108
+ };
@@ -51,6 +51,7 @@ export interface TaskOrderingRequest {
51
51
  includeBlocked?: boolean;
52
52
  agentName?: string;
53
53
  agentStream?: boolean;
54
+ rateAgents?: boolean;
54
55
  }
55
56
  export declare class TaskOrderingService {
56
57
  private workspace;
@@ -1 +1 @@
1
- {"version":3,"file":"TaskOrderingService.d.ts","sourceRoot":"","sources":["../../../src/services/backlog/TaskOrderingService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TaskOrderingService.d.ts","sourceRoot":"","sources":["../../../src/services/backlog/TaskOrderingService.ts"],"names":[],"mappings":"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"}