@mcoda/core 0.1.8 → 0.1.11
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 +3 -0
- package/README.md +2 -2
- package/dist/api/AgentsApi.d.ts +9 -1
- package/dist/api/AgentsApi.d.ts.map +1 -1
- package/dist/api/AgentsApi.js +201 -6
- package/dist/api/QaTasksApi.d.ts.map +1 -1
- package/dist/api/QaTasksApi.js +6 -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 +9 -1
- package/dist/prompts/SdsPrompts.d.ts.map +1 -1
- package/dist/prompts/SdsPrompts.js +9 -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 +60 -0
- package/dist/services/agents/AgentRatingService.d.ts.map +1 -0
- package/dist/services/agents/AgentRatingService.js +363 -0
- package/dist/services/agents/GatewayAgentService.d.ts +11 -0
- package/dist/services/agents/GatewayAgentService.d.ts.map +1 -1
- package/dist/services/agents/GatewayAgentService.js +525 -84
- package/dist/services/agents/GatewayHandoff.d.ts +11 -0
- package/dist/services/agents/GatewayHandoff.d.ts.map +1 -0
- package/dist/services/agents/GatewayHandoff.js +141 -0
- package/dist/services/agents/RoutingService.d.ts +1 -0
- package/dist/services/agents/RoutingService.d.ts.map +1 -1
- package/dist/services/agents/RoutingService.js +4 -4
- package/dist/services/backlog/BacklogService.d.ts +23 -0
- package/dist/services/backlog/BacklogService.d.ts.map +1 -1
- package/dist/services/backlog/BacklogService.js +62 -7
- package/dist/services/backlog/TaskOrderingHeuristics.d.ts +12 -0
- package/dist/services/backlog/TaskOrderingHeuristics.d.ts.map +1 -0
- package/dist/services/backlog/TaskOrderingHeuristics.js +56 -0
- package/dist/services/backlog/TaskOrderingService.d.ts +17 -4
- package/dist/services/backlog/TaskOrderingService.d.ts.map +1 -1
- package/dist/services/backlog/TaskOrderingService.js +538 -79
- package/dist/services/docs/DocInventory.d.ts +11 -0
- package/dist/services/docs/DocInventory.d.ts.map +1 -0
- package/dist/services/docs/DocInventory.js +230 -0
- package/dist/services/docs/DocgenRunContext.d.ts +59 -0
- package/dist/services/docs/DocgenRunContext.d.ts.map +1 -0
- package/dist/services/docs/DocgenRunContext.js +4 -0
- package/dist/services/docs/DocsService.d.ts +70 -3
- package/dist/services/docs/DocsService.d.ts.map +1 -1
- package/dist/services/docs/DocsService.js +1930 -89
- package/dist/services/docs/alignment/DocAlignmentGraph.d.ts +23 -0
- package/dist/services/docs/alignment/DocAlignmentGraph.d.ts.map +1 -0
- package/dist/services/docs/alignment/DocAlignmentGraph.js +78 -0
- package/dist/services/docs/alignment/DocAlignmentPatcher.d.ts +19 -0
- package/dist/services/docs/alignment/DocAlignmentPatcher.d.ts.map +1 -0
- package/dist/services/docs/alignment/DocAlignmentPatcher.js +222 -0
- package/dist/services/docs/patch/DocPatchEngine.d.ts +57 -0
- package/dist/services/docs/patch/DocPatchEngine.d.ts.map +1 -0
- package/dist/services/docs/patch/DocPatchEngine.js +331 -0
- package/dist/services/docs/review/Glossary.d.ts +16 -0
- package/dist/services/docs/review/Glossary.d.ts.map +1 -0
- package/dist/services/docs/review/Glossary.js +47 -0
- package/dist/services/docs/review/ReviewReportRenderer.d.ts +3 -0
- package/dist/services/docs/review/ReviewReportRenderer.d.ts.map +1 -0
- package/dist/services/docs/review/ReviewReportRenderer.js +133 -0
- package/dist/services/docs/review/ReviewReportSchema.d.ts +39 -0
- package/dist/services/docs/review/ReviewReportSchema.d.ts.map +1 -0
- package/dist/services/docs/review/ReviewReportSchema.js +47 -0
- package/dist/services/docs/review/ReviewTypes.d.ts +76 -0
- package/dist/services/docs/review/ReviewTypes.d.ts.map +1 -0
- package/dist/services/docs/review/ReviewTypes.js +94 -0
- package/dist/services/docs/review/gates/AdminOpenApiSpecGate.d.ts +7 -0
- package/dist/services/docs/review/gates/AdminOpenApiSpecGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/AdminOpenApiSpecGate.js +93 -0
- package/dist/services/docs/review/gates/ApiPathConsistencyGate.d.ts +7 -0
- package/dist/services/docs/review/gates/ApiPathConsistencyGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/ApiPathConsistencyGate.js +308 -0
- package/dist/services/docs/review/gates/BuildReadyCompletenessGate.d.ts +8 -0
- package/dist/services/docs/review/gates/BuildReadyCompletenessGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/BuildReadyCompletenessGate.js +278 -0
- package/dist/services/docs/review/gates/DeploymentBlueprintGate.d.ts +8 -0
- package/dist/services/docs/review/gates/DeploymentBlueprintGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/DeploymentBlueprintGate.js +487 -0
- package/dist/services/docs/review/gates/NoMaybesGate.d.ts +8 -0
- package/dist/services/docs/review/gates/NoMaybesGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/NoMaybesGate.js +145 -0
- package/dist/services/docs/review/gates/OpenApiCoverageGate.d.ts +7 -0
- package/dist/services/docs/review/gates/OpenApiCoverageGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/OpenApiCoverageGate.js +266 -0
- package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.d.ts +7 -0
- package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.js +59 -0
- package/dist/services/docs/review/gates/OpenQuestionsGate.d.ts +7 -0
- package/dist/services/docs/review/gates/OpenQuestionsGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/OpenQuestionsGate.js +200 -0
- package/dist/services/docs/review/gates/PdrInterfacesGate.d.ts +7 -0
- package/dist/services/docs/review/gates/PdrInterfacesGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/PdrInterfacesGate.js +159 -0
- package/dist/services/docs/review/gates/PdrOpenQuestionsGate.d.ts +8 -0
- package/dist/services/docs/review/gates/PdrOpenQuestionsGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/PdrOpenQuestionsGate.js +129 -0
- package/dist/services/docs/review/gates/PdrOwnershipGate.d.ts +7 -0
- package/dist/services/docs/review/gates/PdrOwnershipGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/PdrOwnershipGate.js +169 -0
- package/dist/services/docs/review/gates/PlaceholderArtifactGate.d.ts +10 -0
- package/dist/services/docs/review/gates/PlaceholderArtifactGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/PlaceholderArtifactGate.js +261 -0
- package/dist/services/docs/review/gates/RfpConsentGate.d.ts +6 -0
- package/dist/services/docs/review/gates/RfpConsentGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/RfpConsentGate.js +127 -0
- package/dist/services/docs/review/gates/RfpDefinitionGate.d.ts +7 -0
- package/dist/services/docs/review/gates/RfpDefinitionGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/RfpDefinitionGate.js +173 -0
- package/dist/services/docs/review/gates/SdsAdaptersGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SdsAdaptersGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SdsAdaptersGate.js +196 -0
- package/dist/services/docs/review/gates/SdsDecisionsGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SdsDecisionsGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SdsDecisionsGate.js +89 -0
- package/dist/services/docs/review/gates/SdsOpsGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SdsOpsGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SdsOpsGate.js +162 -0
- package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.js +166 -0
- package/dist/services/docs/review/gates/SqlRequiredTablesGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SqlRequiredTablesGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SqlRequiredTablesGate.js +273 -0
- package/dist/services/docs/review/gates/SqlSyntaxGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SqlSyntaxGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SqlSyntaxGate.js +203 -0
- package/dist/services/docs/review/gates/TerminologyNormalizationGate.d.ts +9 -0
- package/dist/services/docs/review/gates/TerminologyNormalizationGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/TerminologyNormalizationGate.js +217 -0
- package/dist/services/docs/review/glossary.json +47 -0
- package/dist/services/estimate/EstimateService.d.ts +2 -0
- package/dist/services/estimate/EstimateService.d.ts.map +1 -1
- package/dist/services/estimate/EstimateService.js +66 -18
- package/dist/services/estimate/VelocityService.d.ts +4 -0
- package/dist/services/estimate/VelocityService.d.ts.map +1 -1
- package/dist/services/estimate/VelocityService.js +179 -36
- package/dist/services/estimate/types.d.ts +1 -0
- package/dist/services/estimate/types.d.ts.map +1 -1
- package/dist/services/execution/GatewayTrioService.d.ts +200 -0
- package/dist/services/execution/GatewayTrioService.d.ts.map +1 -0
- package/dist/services/execution/GatewayTrioService.js +2492 -0
- package/dist/services/execution/QaApiRunner.d.ts +30 -0
- package/dist/services/execution/QaApiRunner.d.ts.map +1 -0
- package/dist/services/execution/QaApiRunner.js +881 -0
- package/dist/services/execution/QaFollowupService.d.ts +2 -0
- package/dist/services/execution/QaFollowupService.d.ts.map +1 -1
- package/dist/services/execution/QaFollowupService.js +9 -2
- package/dist/services/execution/QaPlanValidator.d.ts +10 -0
- package/dist/services/execution/QaPlanValidator.d.ts.map +1 -0
- package/dist/services/execution/QaPlanValidator.js +128 -0
- package/dist/services/execution/QaProfileService.d.ts +27 -1
- package/dist/services/execution/QaProfileService.d.ts.map +1 -1
- package/dist/services/execution/QaProfileService.js +354 -7
- package/dist/services/execution/QaTasksService.d.ts +59 -1
- package/dist/services/execution/QaTasksService.d.ts.map +1 -1
- package/dist/services/execution/QaTasksService.js +3347 -318
- package/dist/services/execution/QaTestCommandBuilder.d.ts +51 -0
- package/dist/services/execution/QaTestCommandBuilder.d.ts.map +1 -0
- package/dist/services/execution/QaTestCommandBuilder.js +495 -0
- package/dist/services/execution/TaskSelectionService.d.ts +4 -2
- package/dist/services/execution/TaskSelectionService.d.ts.map +1 -1
- package/dist/services/execution/TaskSelectionService.js +144 -28
- package/dist/services/execution/TaskStateService.d.ts +19 -6
- package/dist/services/execution/TaskStateService.d.ts.map +1 -1
- package/dist/services/execution/TaskStateService.js +128 -13
- package/dist/services/execution/WorkOnTasksService.d.ts +32 -1
- package/dist/services/execution/WorkOnTasksService.d.ts.map +1 -1
- package/dist/services/execution/WorkOnTasksService.js +4667 -722
- package/dist/services/jobs/JobInsightsService.d.ts +4 -0
- package/dist/services/jobs/JobInsightsService.d.ts.map +1 -1
- package/dist/services/jobs/JobInsightsService.js +51 -5
- package/dist/services/jobs/JobResumeService.d.ts.map +1 -1
- package/dist/services/jobs/JobResumeService.js +23 -10
- package/dist/services/jobs/JobService.d.ts +56 -4
- package/dist/services/jobs/JobService.d.ts.map +1 -1
- package/dist/services/jobs/JobService.js +232 -1
- package/dist/services/openapi/OpenApiService.d.ts +51 -0
- package/dist/services/openapi/OpenApiService.d.ts.map +1 -1
- package/dist/services/openapi/OpenApiService.js +953 -106
- package/dist/services/planning/CreateTasksService.d.ts +21 -0
- package/dist/services/planning/CreateTasksService.d.ts.map +1 -1
- package/dist/services/planning/CreateTasksService.js +569 -31
- package/dist/services/planning/RefineTasksService.d.ts +9 -0
- package/dist/services/planning/RefineTasksService.d.ts.map +1 -1
- package/dist/services/planning/RefineTasksService.js +409 -59
- package/dist/services/review/CodeReviewService.d.ts +18 -0
- package/dist/services/review/CodeReviewService.d.ts.map +1 -1
- package/dist/services/review/CodeReviewService.js +1309 -167
- package/dist/services/review/ReviewNormalizer.d.ts +9 -0
- package/dist/services/review/ReviewNormalizer.d.ts.map +1 -0
- package/dist/services/review/ReviewNormalizer.js +147 -0
- package/dist/services/shared/AuthErrors.d.ts +3 -0
- package/dist/services/shared/AuthErrors.d.ts.map +1 -0
- package/dist/services/shared/AuthErrors.js +17 -0
- package/dist/services/shared/DocdexGuidance.d.ts +7 -0
- package/dist/services/shared/DocdexGuidance.d.ts.map +1 -0
- package/dist/services/shared/DocdexGuidance.js +12 -0
- package/dist/services/shared/ProjectGuidance.d.ts +17 -0
- package/dist/services/shared/ProjectGuidance.d.ts.map +1 -0
- package/dist/services/shared/ProjectGuidance.js +78 -0
- package/dist/services/system/ToolDenylist.d.ts +13 -0
- package/dist/services/system/ToolDenylist.d.ts.map +1 -0
- package/dist/services/system/ToolDenylist.js +85 -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/services/telemetry/TelemetryService.d.ts.map +1 -1
- package/dist/services/telemetry/TelemetryService.js +39 -7
- package/dist/workspace/WorkspaceManager.d.ts +26 -0
- package/dist/workspace/WorkspaceManager.d.ts.map +1 -1
- package/dist/workspace/WorkspaceManager.js +206 -32
- package/package.json +6 -5
|
@@ -0,0 +1,363 @@
|
|
|
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
|
+
const uniqueList = (values) => Array.from(new Set(values.map((value) => (value ?? "").trim()).filter(Boolean)));
|
|
38
|
+
const countMatches = (caps, required) => required.reduce((total, cap) => (caps.includes(cap) ? total + 1 : total), 0);
|
|
39
|
+
export const selectBestAgentForCapabilities = (input) => {
|
|
40
|
+
const required = uniqueList(input.required ?? []);
|
|
41
|
+
const preferred = uniqueList(input.preferred ?? []);
|
|
42
|
+
const scored = input.candidates
|
|
43
|
+
.filter((candidate) => candidate.agent)
|
|
44
|
+
.filter((candidate) => candidate.healthStatus !== "unreachable")
|
|
45
|
+
.map((candidate) => {
|
|
46
|
+
const caps = uniqueList(candidate.capabilities ?? []);
|
|
47
|
+
const requiredMatches = countMatches(caps, required);
|
|
48
|
+
const preferredMatches = countMatches(caps, preferred);
|
|
49
|
+
const hasRequired = required.length === 0 || requiredMatches === required.length;
|
|
50
|
+
const rating = Number(candidate.agent.rating ?? 0);
|
|
51
|
+
const reasoning = Number(candidate.agent.reasoningRating ?? rating);
|
|
52
|
+
const cost = Number.isFinite(candidate.agent.costPerMillion)
|
|
53
|
+
? Number(candidate.agent.costPerMillion)
|
|
54
|
+
: Number.POSITIVE_INFINITY;
|
|
55
|
+
const slug = candidate.agent.slug ?? candidate.agent.id;
|
|
56
|
+
return {
|
|
57
|
+
...candidate,
|
|
58
|
+
caps,
|
|
59
|
+
requiredMatches,
|
|
60
|
+
preferredMatches,
|
|
61
|
+
hasRequired,
|
|
62
|
+
rating,
|
|
63
|
+
reasoning,
|
|
64
|
+
cost,
|
|
65
|
+
slug,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
if (scored.length === 0)
|
|
69
|
+
return undefined;
|
|
70
|
+
const hasFullRequired = scored.some((candidate) => candidate.hasRequired);
|
|
71
|
+
scored.sort((a, b) => {
|
|
72
|
+
if (a.hasRequired !== b.hasRequired)
|
|
73
|
+
return a.hasRequired ? -1 : 1;
|
|
74
|
+
if (a.requiredMatches !== b.requiredMatches)
|
|
75
|
+
return b.requiredMatches - a.requiredMatches;
|
|
76
|
+
if (a.preferredMatches !== b.preferredMatches)
|
|
77
|
+
return b.preferredMatches - a.preferredMatches;
|
|
78
|
+
if (a.rating !== b.rating)
|
|
79
|
+
return b.rating - a.rating;
|
|
80
|
+
if (a.reasoning !== b.reasoning)
|
|
81
|
+
return b.reasoning - a.reasoning;
|
|
82
|
+
if (a.cost !== b.cost)
|
|
83
|
+
return a.cost - b.cost;
|
|
84
|
+
return a.slug.localeCompare(b.slug);
|
|
85
|
+
});
|
|
86
|
+
const pick = scored[0];
|
|
87
|
+
const missingRequired = required.filter((cap) => !pick.caps.includes(cap));
|
|
88
|
+
const missingPreferred = preferred.filter((cap) => !pick.caps.includes(cap));
|
|
89
|
+
const reason = hasFullRequired
|
|
90
|
+
? `selected highest-ranked agent with ${pick.preferredMatches}/${preferred.length} preferred capabilities`
|
|
91
|
+
: `no agent satisfies all required capabilities; selected highest-ranked match (${pick.requiredMatches}/${required.length} required)`;
|
|
92
|
+
return {
|
|
93
|
+
agent: pick.agent,
|
|
94
|
+
capabilities: pick.caps,
|
|
95
|
+
missingRequired,
|
|
96
|
+
missingPreferred,
|
|
97
|
+
meetsRequired: missingRequired.length === 0,
|
|
98
|
+
reason,
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
export class AgentRatingService {
|
|
102
|
+
constructor(workspace, deps) {
|
|
103
|
+
this.workspace = workspace;
|
|
104
|
+
this.deps = deps;
|
|
105
|
+
}
|
|
106
|
+
static async create(workspace) {
|
|
107
|
+
const workspaceRepo = await WorkspaceRepository.create(workspace.workspaceRoot);
|
|
108
|
+
const globalRepo = await GlobalRepository.create();
|
|
109
|
+
const agentService = new AgentService(globalRepo);
|
|
110
|
+
const routingService = await RoutingService.create();
|
|
111
|
+
return new AgentRatingService(workspace, {
|
|
112
|
+
workspaceRepo,
|
|
113
|
+
globalRepo,
|
|
114
|
+
agentService,
|
|
115
|
+
routingService,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async close() {
|
|
119
|
+
await this.deps.workspaceRepo.close();
|
|
120
|
+
await this.deps.globalRepo.close();
|
|
121
|
+
if (this.deps.routingService?.close) {
|
|
122
|
+
await this.deps.routingService.close();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
ratingPromptPath() {
|
|
126
|
+
return path.join(this.workspace.mcodaDir, "prompts", "agent-rating.md");
|
|
127
|
+
}
|
|
128
|
+
async loadRatingPrompt() {
|
|
129
|
+
const promptPath = this.ratingPromptPath();
|
|
130
|
+
try {
|
|
131
|
+
const raw = await fs.readFile(promptPath, "utf8");
|
|
132
|
+
const trimmed = raw.trim();
|
|
133
|
+
if (trimmed)
|
|
134
|
+
return trimmed;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
await fs.mkdir(path.dirname(promptPath), { recursive: true });
|
|
138
|
+
await fs.writeFile(promptPath, DEFAULT_REVIEW_PROMPT, "utf8");
|
|
139
|
+
}
|
|
140
|
+
return DEFAULT_REVIEW_PROMPT;
|
|
141
|
+
}
|
|
142
|
+
async resolveReviewer(agentOverride) {
|
|
143
|
+
if (agentOverride) {
|
|
144
|
+
return this.deps.agentService.resolveAgent(agentOverride);
|
|
145
|
+
}
|
|
146
|
+
const resolved = await this.deps.routingService.resolveAgentForCommand({
|
|
147
|
+
commandName: "agent-rating",
|
|
148
|
+
workspace: this.workspace,
|
|
149
|
+
});
|
|
150
|
+
return resolved.agent;
|
|
151
|
+
}
|
|
152
|
+
async loadUsage(request) {
|
|
153
|
+
const db = this.deps.workspaceRepo.getDb();
|
|
154
|
+
const clauses = ["workspace_id = ?", "agent_id = ?"];
|
|
155
|
+
const params = [this.workspace.workspaceId, request.agentId];
|
|
156
|
+
if (request.commandRunId) {
|
|
157
|
+
clauses.push("command_run_id = ?");
|
|
158
|
+
params.push(request.commandRunId);
|
|
159
|
+
}
|
|
160
|
+
if (request.jobId) {
|
|
161
|
+
clauses.push("job_id = ?");
|
|
162
|
+
params.push(request.jobId);
|
|
163
|
+
}
|
|
164
|
+
if (request.taskId) {
|
|
165
|
+
clauses.push("task_id = ?");
|
|
166
|
+
params.push(request.taskId);
|
|
167
|
+
}
|
|
168
|
+
const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
|
|
169
|
+
return db.all(`SELECT tokens_total, duration_seconds, cost_estimate, metadata_json FROM token_usage ${where}`, ...params);
|
|
170
|
+
}
|
|
171
|
+
countIterations(rows) {
|
|
172
|
+
if (!rows.length)
|
|
173
|
+
return 0;
|
|
174
|
+
const attempts = rows.filter((row) => {
|
|
175
|
+
if (!row.metadata_json)
|
|
176
|
+
return false;
|
|
177
|
+
try {
|
|
178
|
+
const meta = JSON.parse(row.metadata_json);
|
|
179
|
+
const action = String(meta.action ?? meta.phase ?? "").toLowerCase();
|
|
180
|
+
return action.includes("agent") || action.includes("review") || action.includes("qa");
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
const count = attempts.length || rows.length;
|
|
187
|
+
return Math.max(1, count);
|
|
188
|
+
}
|
|
189
|
+
async loadDurationSeconds(request, usageRows) {
|
|
190
|
+
const sum = usageRows.reduce((acc, row) => acc + (row.duration_seconds ?? 0), 0);
|
|
191
|
+
if (sum > 0)
|
|
192
|
+
return sum;
|
|
193
|
+
const db = this.deps.workspaceRepo.getDb();
|
|
194
|
+
if (request.commandRunId) {
|
|
195
|
+
const row = await db.get("SELECT started_at, completed_at, duration_seconds FROM command_runs WHERE id = ?", request.commandRunId);
|
|
196
|
+
if (row?.duration_seconds)
|
|
197
|
+
return row.duration_seconds;
|
|
198
|
+
if (row?.started_at && row?.completed_at) {
|
|
199
|
+
return Math.max(0, (Date.parse(row.completed_at) - Date.parse(row.started_at)) / 1000);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (request.jobId) {
|
|
203
|
+
const row = await db.get("SELECT created_at, completed_at FROM jobs WHERE id = ?", request.jobId);
|
|
204
|
+
if (row?.created_at && row?.completed_at) {
|
|
205
|
+
return Math.max(0, (Date.parse(row.completed_at) - Date.parse(row.created_at)) / 1000);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return 0;
|
|
209
|
+
}
|
|
210
|
+
async buildReviewContext(request) {
|
|
211
|
+
if (!request.taskId && !request.taskKey) {
|
|
212
|
+
return `Command: ${request.commandName}`;
|
|
213
|
+
}
|
|
214
|
+
let task = undefined;
|
|
215
|
+
if (request.taskId) {
|
|
216
|
+
task = await this.deps.workspaceRepo.getTaskById(request.taskId);
|
|
217
|
+
}
|
|
218
|
+
else if (request.taskKey) {
|
|
219
|
+
task = await this.deps.workspaceRepo.getTaskByKey(request.taskKey);
|
|
220
|
+
}
|
|
221
|
+
const comments = task ? await this.deps.workspaceRepo.listTaskComments(task.id, { limit: 5 }) : [];
|
|
222
|
+
const qaRuns = task ? await this.deps.workspaceRepo.listTaskQaRuns(task.id) : [];
|
|
223
|
+
const review = task ? await this.deps.workspaceRepo.getLatestTaskReview(task.id) : undefined;
|
|
224
|
+
const commentText = comments.map((c) => `- [${c.category ?? "comment"}] ${c.body}`).join("\n");
|
|
225
|
+
const qaText = qaRuns.slice(0, 2).map((q) => `- outcome=${q.recommendation ?? q.rawOutcome ?? "n/a"}`).join("\n");
|
|
226
|
+
return [
|
|
227
|
+
`Command: ${request.commandName}`,
|
|
228
|
+
task ? `Task: ${task.key} ${task.title}` : "",
|
|
229
|
+
task?.description ? `Description: ${task.description}` : "",
|
|
230
|
+
review ? `Latest review decision: ${review.decision}` : "",
|
|
231
|
+
qaText ? `Latest QA:\n${qaText}` : "",
|
|
232
|
+
commentText ? `Recent comments:\n${commentText}` : "",
|
|
233
|
+
]
|
|
234
|
+
.filter(Boolean)
|
|
235
|
+
.join("\n");
|
|
236
|
+
}
|
|
237
|
+
async runReviewer(prompt, reviewer) {
|
|
238
|
+
const response = await this.deps.agentService.invoke(reviewer.id, { input: prompt, metadata: { command: "agent-rating" } });
|
|
239
|
+
const parsed = extractJson(response.output ?? "");
|
|
240
|
+
const qualityRaw = typeof parsed?.quality_score === "number" ? parsed?.quality_score : undefined;
|
|
241
|
+
const qualityScore = clamp(qualityRaw ?? 7, 0, 10);
|
|
242
|
+
return {
|
|
243
|
+
qualityScore,
|
|
244
|
+
raw: parsed ?? null,
|
|
245
|
+
reasoning: typeof parsed?.reasoning === "string" ? parsed?.reasoning : undefined,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
computeBudgets(complexity) {
|
|
249
|
+
const factor = clamp(complexity / 5, 0.5, 2);
|
|
250
|
+
return {
|
|
251
|
+
costUsd: DEFAULT_RATING_BUDGETS.costUsd * factor,
|
|
252
|
+
durationSeconds: DEFAULT_RATING_BUDGETS.durationSeconds * factor,
|
|
253
|
+
iterations: Math.max(1, Math.round(DEFAULT_RATING_BUDGETS.iterations + complexity / 3)),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
async rate(request) {
|
|
257
|
+
const agent = await this.deps.globalRepo.getAgentById(request.agentId);
|
|
258
|
+
if (!agent) {
|
|
259
|
+
throw new Error(`Agent ${request.agentId} not found for rating.`);
|
|
260
|
+
}
|
|
261
|
+
const usageRows = await this.loadUsage(request);
|
|
262
|
+
const tokensTotal = usageRows.reduce((acc, row) => acc + (row.tokens_total ?? 0), 0);
|
|
263
|
+
const durationSeconds = await this.loadDurationSeconds(request, usageRows);
|
|
264
|
+
const iterations = this.countIterations(usageRows);
|
|
265
|
+
const costEstimate = usageRows.reduce((acc, row) => acc + (row.cost_estimate ?? 0), 0);
|
|
266
|
+
const costPerMillion = agent.costPerMillion ?? 0;
|
|
267
|
+
const totalCost = costEstimate > 0 ? costEstimate : (tokensTotal * costPerMillion) / 1000000;
|
|
268
|
+
const complexity = clamp(Math.round(request.complexity ?? 5), 1, 10);
|
|
269
|
+
const budgets = this.computeBudgets(complexity);
|
|
270
|
+
const weights = DEFAULT_RATING_WEIGHTS;
|
|
271
|
+
const reviewContext = await this.buildReviewContext(request);
|
|
272
|
+
const reviewerPrompt = await this.loadRatingPrompt();
|
|
273
|
+
const reviewer = await this.resolveReviewer(request.reviewerAgentName);
|
|
274
|
+
const reviewerInput = [reviewerPrompt, "", reviewContext].filter(Boolean).join("\n");
|
|
275
|
+
const review = await this.runReviewer(reviewerInput, reviewer);
|
|
276
|
+
const runScore = computeRunScore({
|
|
277
|
+
qualityScore: review.qualityScore,
|
|
278
|
+
totalCost,
|
|
279
|
+
durationSeconds,
|
|
280
|
+
iterations,
|
|
281
|
+
budgets,
|
|
282
|
+
weights,
|
|
283
|
+
});
|
|
284
|
+
const alpha = computeAlpha(request.ratingWindow ?? 50);
|
|
285
|
+
const baseRating = agent.rating ?? runScore;
|
|
286
|
+
const updatedRating = updateEmaRating(baseRating, runScore, alpha);
|
|
287
|
+
const baseReasoning = agent.reasoningRating ?? baseRating;
|
|
288
|
+
const updatedReasoning = updateEmaRating(baseReasoning, runScore, alpha);
|
|
289
|
+
const updatedSamples = (agent.ratingSamples ?? 0) + 1;
|
|
290
|
+
const now = new Date().toISOString();
|
|
291
|
+
const nowMs = Date.parse(now);
|
|
292
|
+
let maxComplexity = agent.maxComplexity ?? 5;
|
|
293
|
+
let complexitySamples = agent.complexitySamples ?? 0;
|
|
294
|
+
let complexityUpdatedAt = agent.complexityUpdatedAt ?? undefined;
|
|
295
|
+
const promoteThreshold = 7.5;
|
|
296
|
+
const demoteThreshold = 4.0;
|
|
297
|
+
const lastComplexityUpdate = complexityUpdatedAt ? Date.parse(complexityUpdatedAt) : NaN;
|
|
298
|
+
const canAdjustComplexity = !Number.isFinite(lastComplexityUpdate) || nowMs - lastComplexityUpdate >= COMPLEXITY_COOLDOWN_SECONDS * 1000;
|
|
299
|
+
if (canAdjustComplexity) {
|
|
300
|
+
if (runScore >= promoteThreshold && review.qualityScore >= 7 && complexity >= maxComplexity) {
|
|
301
|
+
maxComplexity = Math.min(10, maxComplexity + 1);
|
|
302
|
+
complexityUpdatedAt = now;
|
|
303
|
+
complexitySamples += 1;
|
|
304
|
+
}
|
|
305
|
+
else if (runScore <= demoteThreshold && complexity <= maxComplexity) {
|
|
306
|
+
maxComplexity = Math.max(1, maxComplexity - 1);
|
|
307
|
+
complexityUpdatedAt = now;
|
|
308
|
+
complexitySamples += 1;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
await this.deps.globalRepo.updateAgent(agent.id, {
|
|
312
|
+
rating: updatedRating,
|
|
313
|
+
reasoningRating: updatedReasoning,
|
|
314
|
+
ratingSamples: updatedSamples,
|
|
315
|
+
ratingLastScore: runScore,
|
|
316
|
+
ratingUpdatedAt: now,
|
|
317
|
+
maxComplexity,
|
|
318
|
+
complexitySamples,
|
|
319
|
+
complexityUpdatedAt,
|
|
320
|
+
});
|
|
321
|
+
await this.deps.globalRepo.insertAgentRunRating({
|
|
322
|
+
agentId: agent.id,
|
|
323
|
+
jobId: request.jobId ?? null,
|
|
324
|
+
commandRunId: request.commandRunId ?? null,
|
|
325
|
+
taskId: request.taskId ?? null,
|
|
326
|
+
taskKey: request.taskKey ?? null,
|
|
327
|
+
commandName: request.commandName,
|
|
328
|
+
discipline: request.discipline ?? null,
|
|
329
|
+
complexity,
|
|
330
|
+
qualityScore: review.qualityScore,
|
|
331
|
+
tokensTotal,
|
|
332
|
+
durationSeconds,
|
|
333
|
+
iterations,
|
|
334
|
+
totalCost,
|
|
335
|
+
runScore,
|
|
336
|
+
ratingVersion: "v1",
|
|
337
|
+
rawReview: review.raw,
|
|
338
|
+
createdAt: now,
|
|
339
|
+
});
|
|
340
|
+
await this.writeRatingArtifact(request.jobId, {
|
|
341
|
+
agentId: agent.id,
|
|
342
|
+
commandName: request.commandName,
|
|
343
|
+
taskKey: request.taskKey,
|
|
344
|
+
qualityScore: review.qualityScore,
|
|
345
|
+
tokensTotal,
|
|
346
|
+
durationSeconds,
|
|
347
|
+
iterations,
|
|
348
|
+
totalCost,
|
|
349
|
+
runScore,
|
|
350
|
+
rating: updatedRating,
|
|
351
|
+
maxComplexity,
|
|
352
|
+
reviewerAgent: reviewer.slug ?? reviewer.id,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
async writeRatingArtifact(jobId, payload) {
|
|
356
|
+
if (!jobId)
|
|
357
|
+
return;
|
|
358
|
+
const outDir = path.join(this.workspace.mcodaDir, "jobs", jobId);
|
|
359
|
+
await fs.mkdir(outDir, { recursive: true });
|
|
360
|
+
const filePath = path.join(outDir, "rating.json");
|
|
361
|
+
await fs.writeFile(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
362
|
+
}
|
|
363
|
+
}
|
|
@@ -31,6 +31,7 @@ export interface GatewayAnalysis {
|
|
|
31
31
|
discipline: string;
|
|
32
32
|
filesLikelyTouched: string[];
|
|
33
33
|
filesToCreate: string[];
|
|
34
|
+
dirsToCreate: string[];
|
|
34
35
|
assumptions: string[];
|
|
35
36
|
risks: string[];
|
|
36
37
|
docdexNotes: string[];
|
|
@@ -57,6 +58,7 @@ export interface GatewayAgentResult {
|
|
|
57
58
|
chosenAgent: GatewayAgentDecision;
|
|
58
59
|
warnings: string[];
|
|
59
60
|
}
|
|
61
|
+
type AgentTierHint = "strong" | "specialist";
|
|
60
62
|
export interface GatewayAgentRequest extends TaskSelectionFilters {
|
|
61
63
|
workspace: WorkspaceResolution;
|
|
62
64
|
job: string;
|
|
@@ -65,6 +67,10 @@ export interface GatewayAgentRequest extends TaskSelectionFilters {
|
|
|
65
67
|
maxDocs?: number;
|
|
66
68
|
agentStream?: boolean;
|
|
67
69
|
onStreamChunk?: (chunk: string) => void;
|
|
70
|
+
rateAgents?: boolean;
|
|
71
|
+
avoidAgents?: string[];
|
|
72
|
+
forceStronger?: boolean;
|
|
73
|
+
forceTier?: AgentTierHint;
|
|
68
74
|
}
|
|
69
75
|
export declare class GatewayAgentService {
|
|
70
76
|
private workspace;
|
|
@@ -74,6 +80,9 @@ export declare class GatewayAgentService {
|
|
|
74
80
|
static create(workspace: WorkspaceResolution): Promise<GatewayAgentService>;
|
|
75
81
|
private readPromptFiles;
|
|
76
82
|
close(): Promise<void>;
|
|
83
|
+
setDocdexAvailability(available: boolean, reason?: string): void;
|
|
84
|
+
saveRepoMemory(text: string): Promise<void>;
|
|
85
|
+
savePreference(category: string, content: string, agentId?: string): Promise<void>;
|
|
77
86
|
private loadGatewayPrompts;
|
|
78
87
|
private resolveGatewayAgent;
|
|
79
88
|
private invokeGatewayAgent;
|
|
@@ -87,6 +96,8 @@ export declare class GatewayAgentService {
|
|
|
87
96
|
private listCandidates;
|
|
88
97
|
private chooseCandidate;
|
|
89
98
|
private selectAgentForJob;
|
|
99
|
+
preflightExecutionAgents(job: string, overrideAgent?: string): Promise<void>;
|
|
90
100
|
run(request: GatewayAgentRequest): Promise<GatewayAgentResult>;
|
|
91
101
|
}
|
|
102
|
+
export {};
|
|
92
103
|
//# sourceMappingURL=GatewayAgentService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GatewayAgentService.d.ts","sourceRoot":"","sources":["../../../src/services/agents/GatewayAgentService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GatewayAgentService.d.ts","sourceRoot":"","sources":["../../../src/services/agents/GatewayAgentService.ts"],"names":[],"mappings":"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"}
|