@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.
- package/CHANGELOG.md +4 -1
- package/README.md +22 -3
- package/dist/api/AgentsApi.d.ts +8 -1
- package/dist/api/AgentsApi.d.ts.map +1 -1
- package/dist/api/AgentsApi.js +70 -0
- package/dist/api/QaTasksApi.d.ts.map +1 -1
- package/dist/api/QaTasksApi.js +2 -0
- package/dist/api/TasksApi.d.ts.map +1 -1
- package/dist/api/TasksApi.js +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/prompts/PdrPrompts.d.ts.map +1 -1
- package/dist/prompts/PdrPrompts.js +3 -1
- package/dist/prompts/SdsPrompts.d.ts.map +1 -1
- package/dist/prompts/SdsPrompts.js +2 -0
- package/dist/services/agents/AgentRatingFormula.d.ts +27 -0
- package/dist/services/agents/AgentRatingFormula.d.ts.map +1 -0
- package/dist/services/agents/AgentRatingFormula.js +45 -0
- package/dist/services/agents/AgentRatingService.d.ts +41 -0
- package/dist/services/agents/AgentRatingService.d.ts.map +1 -0
- package/dist/services/agents/AgentRatingService.js +299 -0
- package/dist/services/agents/GatewayAgentService.d.ts +3 -0
- package/dist/services/agents/GatewayAgentService.d.ts.map +1 -1
- package/dist/services/agents/GatewayAgentService.js +68 -24
- package/dist/services/agents/GatewayHandoff.d.ts +7 -0
- package/dist/services/agents/GatewayHandoff.d.ts.map +1 -0
- package/dist/services/agents/GatewayHandoff.js +108 -0
- package/dist/services/backlog/TaskOrderingService.d.ts +1 -0
- package/dist/services/backlog/TaskOrderingService.d.ts.map +1 -1
- package/dist/services/backlog/TaskOrderingService.js +19 -16
- package/dist/services/docs/DocsService.d.ts +11 -1
- package/dist/services/docs/DocsService.d.ts.map +1 -1
- package/dist/services/docs/DocsService.js +240 -52
- package/dist/services/execution/GatewayTrioService.d.ts +133 -0
- package/dist/services/execution/GatewayTrioService.d.ts.map +1 -0
- package/dist/services/execution/GatewayTrioService.js +1125 -0
- package/dist/services/execution/QaFollowupService.d.ts +1 -0
- package/dist/services/execution/QaFollowupService.d.ts.map +1 -1
- package/dist/services/execution/QaFollowupService.js +1 -0
- package/dist/services/execution/QaProfileService.d.ts +6 -0
- package/dist/services/execution/QaProfileService.d.ts.map +1 -1
- package/dist/services/execution/QaProfileService.js +165 -3
- package/dist/services/execution/QaTasksService.d.ts +18 -0
- package/dist/services/execution/QaTasksService.d.ts.map +1 -1
- package/dist/services/execution/QaTasksService.js +712 -34
- package/dist/services/execution/WorkOnTasksService.d.ts +14 -0
- package/dist/services/execution/WorkOnTasksService.d.ts.map +1 -1
- package/dist/services/execution/WorkOnTasksService.js +1497 -240
- package/dist/services/openapi/OpenApiService.d.ts +10 -0
- package/dist/services/openapi/OpenApiService.d.ts.map +1 -1
- package/dist/services/openapi/OpenApiService.js +66 -10
- package/dist/services/planning/CreateTasksService.d.ts +6 -0
- package/dist/services/planning/CreateTasksService.d.ts.map +1 -1
- package/dist/services/planning/CreateTasksService.js +261 -28
- package/dist/services/planning/RefineTasksService.d.ts +5 -0
- package/dist/services/planning/RefineTasksService.d.ts.map +1 -1
- package/dist/services/planning/RefineTasksService.js +184 -35
- package/dist/services/review/CodeReviewService.d.ts +14 -0
- package/dist/services/review/CodeReviewService.d.ts.map +1 -1
- package/dist/services/review/CodeReviewService.js +657 -61
- package/dist/services/shared/ProjectGuidance.d.ts +6 -0
- package/dist/services/shared/ProjectGuidance.d.ts.map +1 -0
- package/dist/services/shared/ProjectGuidance.js +21 -0
- package/dist/services/tasks/TaskCommentFormatter.d.ts +20 -0
- package/dist/services/tasks/TaskCommentFormatter.d.ts.map +1 -0
- package/dist/services/tasks/TaskCommentFormatter.js +54 -0
- package/dist/workspace/WorkspaceManager.d.ts +4 -0
- package/dist/workspace/WorkspaceManager.d.ts.map +1 -1
- package/dist/workspace/WorkspaceManager.js +3 -0
- 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":"AAMA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAE1E,OAAO,EAAwB,oBAAoB,EAAgB,MAAM,sCAAsC,CAAC;
|
|
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 (
|
|
366
|
-
|
|
366
|
+
if (health?.status === "unreachable") {
|
|
367
|
+
warnings.push(`Override agent ${overrideAgent.slug} is unreachable; ignoring override.`);
|
|
367
368
|
}
|
|
368
|
-
if (missing.length) {
|
|
369
|
-
|
|
369
|
+
else if (missing.length === 0) {
|
|
370
|
+
return overrideAgent;
|
|
370
371
|
}
|
|
371
|
-
else
|
|
372
|
-
warnings.push(`Override agent ${overrideAgent.slug} is
|
|
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
|
|
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 (
|
|
694
|
-
const pick =
|
|
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 ${
|
|
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 (
|
|
711
|
-
const
|
|
712
|
-
const pick = (
|
|
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 ${
|
|
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 =
|
|
727
|
-
const
|
|
728
|
-
const base =
|
|
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 ${
|
|
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
|
|
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
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskOrderingService.d.ts","sourceRoot":"","sources":["../../../src/services/backlog/TaskOrderingService.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AA+C1E,UAAU,UAAU;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,UAAU,OAAO;IACf,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAoCD,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,UAAU,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"TaskOrderingService.d.ts","sourceRoot":"","sources":["../../../src/services/backlog/TaskOrderingService.ts"],"names":[],"mappings":"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"}
|