@harness-engineering/orchestrator 0.13.0 → 0.15.0
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/dist/index.d.mts +615 -22
- package/dist/index.d.ts +615 -22
- package/dist/index.js +747 -133
- package/dist/index.mjs +712 -98
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
AdaptiveRouter: () => AdaptiveRouter,
|
|
34
34
|
AnalysisArchive: () => AnalysisArchive,
|
|
35
|
+
BRAINSTORM_RUBRIC: () => BRAINSTORM_RUBRIC,
|
|
35
36
|
BUILT_IN_TASKS: () => BUILT_IN_TASKS,
|
|
36
37
|
BackendDefSchema: () => BackendDefSchema,
|
|
37
38
|
BackendRouter: () => BackendRouter,
|
|
@@ -74,8 +75,10 @@ __export(index_exports, {
|
|
|
74
75
|
WorkspaceManager: () => WorkspaceManager,
|
|
75
76
|
applyEvent: () => applyEvent,
|
|
76
77
|
artifactPresenceFromIssue: () => artifactPresenceFromIssue,
|
|
78
|
+
brainstormInputFromIssue: () => brainstormInputFromIssue,
|
|
77
79
|
buildArchiveHooks: () => buildArchiveHooks,
|
|
78
80
|
buildCapabilityRegistry: () => buildCapabilityRegistry,
|
|
81
|
+
buildProbeInput: () => buildProbeInput,
|
|
79
82
|
buildWorkflowContext: () => buildWorkflowContext,
|
|
80
83
|
calculateRetryDelay: () => calculateRetryDelay,
|
|
81
84
|
canDispatch: () => canDispatch,
|
|
@@ -95,6 +98,7 @@ __export(index_exports, {
|
|
|
95
98
|
emitProposalApproved: () => emitProposalApproved,
|
|
96
99
|
emitProposalCreated: () => emitProposalCreated,
|
|
97
100
|
emitProposalRejected: () => emitProposalRejected,
|
|
101
|
+
enrichIssueWithSpec: () => enrichIssueWithSpec,
|
|
98
102
|
estimateCost: () => estimateCost,
|
|
99
103
|
explicitFindingsCount: () => explicitFindingsCount,
|
|
100
104
|
extractHighlights: () => extractHighlights,
|
|
@@ -109,22 +113,30 @@ __export(index_exports, {
|
|
|
109
113
|
launchTUI: () => launchTUI,
|
|
110
114
|
loadPublishedIndex: () => loadPublishedIndex,
|
|
111
115
|
makeBackendResolver: () => makeBackendResolver,
|
|
116
|
+
makeGraphScope: () => makeGraphScope,
|
|
117
|
+
makeSelForkGenerator: () => makeSelForkGenerator,
|
|
118
|
+
markApprovedForDispatch: () => markApprovedForDispatch,
|
|
112
119
|
migrateAgentConfig: () => migrateAgentConfig,
|
|
113
120
|
normalizeFts5Query: () => normalizeFts5Query,
|
|
114
121
|
normalizeHarnessCommand: () => normalizeHarnessCommand,
|
|
115
122
|
normalizeLocalModel: () => normalizeLocalModel,
|
|
116
123
|
openSearchIndex: () => openSearchIndex,
|
|
124
|
+
pilotScore: () => import_intelligence13.pilotScore,
|
|
125
|
+
precedentLookupFromStored: () => precedentLookupFromStored,
|
|
117
126
|
promote: () => promote,
|
|
127
|
+
rankTriageCandidates: () => import_intelligence13.rankTriageCandidates,
|
|
118
128
|
reconcile: () => reconcile,
|
|
119
129
|
recoverFindingsCount: () => recoverFindingsCount,
|
|
120
130
|
reindexFromArchive: () => reindexFromArchive,
|
|
121
131
|
renderAnalysisComment: () => renderAnalysisComment,
|
|
122
132
|
renderLlmSummaryMarkdown: () => renderLlmSummaryMarkdown,
|
|
123
133
|
renderPRComment: () => renderPRComment,
|
|
134
|
+
renderSpecMarkdown: () => renderSpecMarkdown,
|
|
124
135
|
resolveEscalationConfig: () => resolveEscalationConfig,
|
|
125
136
|
resolveOrchestratorId: () => resolveOrchestratorId,
|
|
126
137
|
routeIssue: () => routeIssue,
|
|
127
138
|
routingWarnings: () => routingWarnings,
|
|
139
|
+
runBrainstormForIssue: () => runBrainstormForIssue,
|
|
128
140
|
runGate: () => runGate,
|
|
129
141
|
runHarnessCheck: () => runHarnessCheck,
|
|
130
142
|
savePublishedIndex: () => savePublishedIndex,
|
|
@@ -132,10 +144,11 @@ __export(index_exports, {
|
|
|
132
144
|
selectCandidates: () => selectCandidates,
|
|
133
145
|
selectCheapestQualifying: () => selectCheapestQualifying,
|
|
134
146
|
selectTasks: () => selectTasks,
|
|
147
|
+
slugFor: () => slugFor,
|
|
135
148
|
sortCandidates: () => sortCandidates,
|
|
136
149
|
summarizeArchivedSession: () => summarizeArchivedSession,
|
|
137
150
|
syncMain: () => syncMain,
|
|
138
|
-
triageIssue: () =>
|
|
151
|
+
triageIssue: () => triageIssue2,
|
|
139
152
|
truncateForBudget: () => truncateForBudget,
|
|
140
153
|
validateCustomTasks: () => validateCustomTasks,
|
|
141
154
|
validateWorkflowConfig: () => validateWorkflowConfig,
|
|
@@ -2054,26 +2067,60 @@ var ModelSchema = import_zod.z.union([import_zod.z.string().min(1), import_zod.z
|
|
|
2054
2067
|
message: "model must be a non-empty string or array of strings"
|
|
2055
2068
|
})
|
|
2056
2069
|
});
|
|
2070
|
+
var CAPABILITY_TIER = import_zod.z.enum(["fast", "standard", "strong"]);
|
|
2071
|
+
var COMPLEXITY_LEVEL = import_zod.z.enum(["trivial", "simple", "moderate", "complex"]);
|
|
2072
|
+
var PRIVACY_CLASS = import_zod.z.enum(["on-device", "pooled-isolated", "byo-endpoint", "shared-cloud"]);
|
|
2073
|
+
var BackendCapabilitiesSchema = import_zod.z.object({
|
|
2074
|
+
tier: CAPABILITY_TIER,
|
|
2075
|
+
costPer1kTokens: import_zod.z.number().nonnegative(),
|
|
2076
|
+
privacyClass: PRIVACY_CLASS,
|
|
2077
|
+
contextWindow: import_zod.z.number().int().positive(),
|
|
2078
|
+
vision: import_zod.z.boolean().optional(),
|
|
2079
|
+
toolUse: import_zod.z.boolean().optional()
|
|
2080
|
+
}).strict();
|
|
2081
|
+
var RoutingPolicySchema = import_zod.z.object({
|
|
2082
|
+
complexityTierMatrix: import_zod.z.record(COMPLEXITY_LEVEL, CAPABILITY_TIER).optional(),
|
|
2083
|
+
skillTierOverrides: import_zod.z.record(import_zod.z.string(), CAPABILITY_TIER).optional(),
|
|
2084
|
+
privacyFloor: PRIVACY_CLASS.optional(),
|
|
2085
|
+
budget: import_zod.z.object({
|
|
2086
|
+
capUsd: import_zod.z.number(),
|
|
2087
|
+
degradeAtPct: import_zod.z.number().optional(),
|
|
2088
|
+
onBudgetExhausted: import_zod.z.enum(["degrade", "pause", "human"])
|
|
2089
|
+
}).optional(),
|
|
2090
|
+
sensitivePaths: import_zod.z.array(import_zod.z.string()).optional(),
|
|
2091
|
+
escalationThreshold: import_zod.z.number().optional(),
|
|
2092
|
+
// string[], NOT the finite BackendDef['type'] union: an unknown provider must
|
|
2093
|
+
// fail CLOSED at tier selection, not reject the whole policy (Shuttle wire).
|
|
2094
|
+
allowedProviders: import_zod.z.array(import_zod.z.string()).optional(),
|
|
2095
|
+
acceptanceEval: import_zod.z.object({
|
|
2096
|
+
enabled: import_zod.z.boolean(),
|
|
2097
|
+
model: import_zod.z.string().optional()
|
|
2098
|
+
}).optional()
|
|
2099
|
+
});
|
|
2057
2100
|
var BackendDefSchema = import_zod.z.discriminatedUnion("type", [
|
|
2058
|
-
import_zod.z.object({ type: import_zod.z.literal("mock") }).strict(),
|
|
2101
|
+
import_zod.z.object({ type: import_zod.z.literal("mock"), capabilities: BackendCapabilitiesSchema.optional() }).strict(),
|
|
2059
2102
|
import_zod.z.object({
|
|
2060
2103
|
type: import_zod.z.literal("claude"),
|
|
2061
|
-
command: import_zod.z.string().optional()
|
|
2104
|
+
command: import_zod.z.string().optional(),
|
|
2105
|
+
capabilities: BackendCapabilitiesSchema.optional()
|
|
2062
2106
|
}).strict(),
|
|
2063
2107
|
import_zod.z.object({
|
|
2064
2108
|
type: import_zod.z.literal("anthropic"),
|
|
2065
2109
|
model: import_zod.z.string().min(1),
|
|
2066
|
-
apiKey: import_zod.z.string().optional()
|
|
2110
|
+
apiKey: import_zod.z.string().optional(),
|
|
2111
|
+
capabilities: BackendCapabilitiesSchema.optional()
|
|
2067
2112
|
}).strict(),
|
|
2068
2113
|
import_zod.z.object({
|
|
2069
2114
|
type: import_zod.z.literal("openai"),
|
|
2070
2115
|
model: import_zod.z.string().min(1),
|
|
2071
|
-
apiKey: import_zod.z.string().optional()
|
|
2116
|
+
apiKey: import_zod.z.string().optional(),
|
|
2117
|
+
capabilities: BackendCapabilitiesSchema.optional()
|
|
2072
2118
|
}).strict(),
|
|
2073
2119
|
import_zod.z.object({
|
|
2074
2120
|
type: import_zod.z.literal("gemini"),
|
|
2075
2121
|
model: import_zod.z.string().min(1),
|
|
2076
|
-
apiKey: import_zod.z.string().optional()
|
|
2122
|
+
apiKey: import_zod.z.string().optional(),
|
|
2123
|
+
capabilities: BackendCapabilitiesSchema.optional()
|
|
2077
2124
|
}).strict(),
|
|
2078
2125
|
import_zod.z.object({
|
|
2079
2126
|
type: import_zod.z.literal("local"),
|
|
@@ -2081,7 +2128,8 @@ var BackendDefSchema = import_zod.z.discriminatedUnion("type", [
|
|
|
2081
2128
|
model: ModelSchema,
|
|
2082
2129
|
apiKey: import_zod.z.string().optional(),
|
|
2083
2130
|
timeoutMs: import_zod.z.number().int().positive().optional(),
|
|
2084
|
-
probeIntervalMs: import_zod.z.number().int().min(1e3).optional()
|
|
2131
|
+
probeIntervalMs: import_zod.z.number().int().min(1e3).optional(),
|
|
2132
|
+
capabilities: BackendCapabilitiesSchema.optional()
|
|
2085
2133
|
}).strict(),
|
|
2086
2134
|
import_zod.z.object({
|
|
2087
2135
|
type: import_zod.z.literal("pi"),
|
|
@@ -2089,7 +2137,8 @@ var BackendDefSchema = import_zod.z.discriminatedUnion("type", [
|
|
|
2089
2137
|
model: ModelSchema,
|
|
2090
2138
|
apiKey: import_zod.z.string().optional(),
|
|
2091
2139
|
timeoutMs: import_zod.z.number().int().positive().optional(),
|
|
2092
|
-
probeIntervalMs: import_zod.z.number().int().min(1e3).optional()
|
|
2140
|
+
probeIntervalMs: import_zod.z.number().int().min(1e3).optional(),
|
|
2141
|
+
capabilities: BackendCapabilitiesSchema.optional()
|
|
2093
2142
|
}).strict()
|
|
2094
2143
|
]);
|
|
2095
2144
|
var RoutingValueSchema = import_zod.z.union([
|
|
@@ -2114,7 +2163,36 @@ var RoutingConfigSchema = import_zod.z.object({
|
|
|
2114
2163
|
}).strict().optional(),
|
|
2115
2164
|
// --- Spec B Phase 0: new optional maps (resolver wired in Phase 1) ---
|
|
2116
2165
|
skills: import_zod.z.record(import_zod.z.string().min(1), RoutingValueSchema).optional(),
|
|
2117
|
-
modes: import_zod.z.record(import_zod.z.string().min(1), RoutingValueSchema).optional()
|
|
2166
|
+
modes: import_zod.z.record(import_zod.z.string().min(1), RoutingValueSchema).optional(),
|
|
2167
|
+
// --- AMR: opt-in adaptive-routing policy. Its PRESENCE flips the orchestrator
|
|
2168
|
+
// from identity/default dispatch to complexity-aware tier routing (default-off
|
|
2169
|
+
// when absent). Previously accepted by the runtime PUT endpoint only. ---
|
|
2170
|
+
policy: RoutingPolicySchema.optional()
|
|
2171
|
+
}).strict();
|
|
2172
|
+
var CONFIDENCE = import_zod.z.enum(["low", "medium", "high"]);
|
|
2173
|
+
var V1_MAX_RATCHET_STAGE = 2;
|
|
2174
|
+
var RATCHET_STAGE = import_zod.z.union([import_zod.z.literal(1), import_zod.z.literal(2), import_zod.z.literal(3), import_zod.z.literal(4)]).refine((s) => s <= V1_MAX_RATCHET_STAGE, {
|
|
2175
|
+
message: `ratchetStage ${">"} ${V1_MAX_RATCHET_STAGE} is deferred post-v1 (stages 3\u20134 not yet supported); use 1 or 2`
|
|
2176
|
+
});
|
|
2177
|
+
var RoadmapAutoTriageSchema = import_zod.z.object({
|
|
2178
|
+
enabled: import_zod.z.boolean(),
|
|
2179
|
+
schedule: import_zod.z.string().min(1).optional(),
|
|
2180
|
+
ratchetStage: RATCHET_STAGE,
|
|
2181
|
+
thresholds: import_zod.z.object({
|
|
2182
|
+
dispatchConfidence: CONFIDENCE,
|
|
2183
|
+
boundedScopeMax: import_zod.z.number(),
|
|
2184
|
+
brainstormConfidence: import_zod.z.number(),
|
|
2185
|
+
exceededByBands: import_zod.z.number(),
|
|
2186
|
+
ratchetAdvanceRate: import_zod.z.number(),
|
|
2187
|
+
ratchetMinSample: import_zod.z.number()
|
|
2188
|
+
}).strict(),
|
|
2189
|
+
depthBudget: import_zod.z.object({
|
|
2190
|
+
trivial: import_zod.z.number(),
|
|
2191
|
+
simple: import_zod.z.number()
|
|
2192
|
+
}).strict()
|
|
2193
|
+
}).strict();
|
|
2194
|
+
var RoadmapConfigSchema = import_zod.z.object({
|
|
2195
|
+
autoTriage: RoadmapAutoTriageSchema.optional()
|
|
2118
2196
|
}).strict();
|
|
2119
2197
|
var WorkflowStepSchema = import_zod.z.object({
|
|
2120
2198
|
skill: import_zod.z.string().min(1),
|
|
@@ -2153,12 +2231,12 @@ var BackendsMapSchema = import_zod2.z.record(import_zod2.z.string(), BackendDefS
|
|
|
2153
2231
|
function crossFieldRoutingIssues(backends, routing) {
|
|
2154
2232
|
const issues = [];
|
|
2155
2233
|
const names = new Set(Object.keys(backends));
|
|
2156
|
-
const checkRef = (
|
|
2234
|
+
const checkRef = (path25, value) => {
|
|
2157
2235
|
if (value === void 0) return;
|
|
2158
2236
|
const entries = Array.isArray(value) ? value : [value];
|
|
2159
2237
|
entries.forEach((name, idx) => {
|
|
2160
2238
|
if (names.has(name)) return;
|
|
2161
|
-
const pathWithIdx = Array.isArray(value) ? [...
|
|
2239
|
+
const pathWithIdx = Array.isArray(value) ? [...path25, String(idx)] : path25;
|
|
2162
2240
|
issues.push({
|
|
2163
2241
|
path: pathWithIdx,
|
|
2164
2242
|
message: `routing.${pathWithIdx.join(".")} references unknown backend '${name}'. Defined: [${[...names].join(", ")}].`
|
|
@@ -2255,6 +2333,10 @@ function validateWorkflowConfig(config, options = {}) {
|
|
|
2255
2333
|
const parsed = import_zod2.z.array(StagedWorkflowDeclSchema).safeParse(c.workflows);
|
|
2256
2334
|
if (!parsed.success) return (0, import_types2.Err)(new Error(`workflows: ${parsed.error.message}`));
|
|
2257
2335
|
}
|
|
2336
|
+
if (c.roadmap !== void 0) {
|
|
2337
|
+
const parsed = RoadmapConfigSchema.safeParse(c.roadmap);
|
|
2338
|
+
if (!parsed.success) return (0, import_types2.Err)(new Error(`roadmap: ${parsed.error.message}`));
|
|
2339
|
+
}
|
|
2258
2340
|
return (0, import_types2.Ok)({ config, warnings });
|
|
2259
2341
|
}
|
|
2260
2342
|
function getDefaultConfig() {
|
|
@@ -3497,7 +3579,65 @@ var path21 = __toESM(require("path"));
|
|
|
3497
3579
|
var import_node_crypto15 = require("crypto");
|
|
3498
3580
|
var import_types34 = require("@harness-engineering/types");
|
|
3499
3581
|
var import_core16 = require("@harness-engineering/core");
|
|
3500
|
-
var
|
|
3582
|
+
var import_intelligence12 = require("@harness-engineering/intelligence");
|
|
3583
|
+
|
|
3584
|
+
// src/agent/triage-outcome.ts
|
|
3585
|
+
var import_intelligence = require("@harness-engineering/intelligence");
|
|
3586
|
+
function signalsFromDiff(hunks, textOnly) {
|
|
3587
|
+
const files = /* @__PURE__ */ new Set();
|
|
3588
|
+
const layers = /* @__PURE__ */ new Set();
|
|
3589
|
+
let addedLines = 0;
|
|
3590
|
+
for (const h of hunks) {
|
|
3591
|
+
files.add(h.file);
|
|
3592
|
+
layers.add(layerOfPath(h.file));
|
|
3593
|
+
addedLines += h.addedContent === "" ? 0 : h.addedContent.split("\n").length;
|
|
3594
|
+
}
|
|
3595
|
+
return {
|
|
3596
|
+
...textOnly,
|
|
3597
|
+
filesTouched: files.size,
|
|
3598
|
+
layersTouched: layers.size,
|
|
3599
|
+
blastRadius: addedLines
|
|
3600
|
+
};
|
|
3601
|
+
}
|
|
3602
|
+
function layerOfPath(file) {
|
|
3603
|
+
const parts = file.split("/").filter((p) => p.length > 0);
|
|
3604
|
+
if (parts.length === 0) return "<root>";
|
|
3605
|
+
if (parts[0] === "packages" && parts.length >= 4 && parts[2] === "src") {
|
|
3606
|
+
return `${parts[1] ?? ""}/${parts[3] ?? ""}`;
|
|
3607
|
+
}
|
|
3608
|
+
return parts.length === 1 ? "<root>" : parts[0] ?? "<root>";
|
|
3609
|
+
}
|
|
3610
|
+
async function runRetrospective(deps, provider) {
|
|
3611
|
+
const signals = signalsFromDiff(deps.hunks, deps.textOnly);
|
|
3612
|
+
const actual = await (0, import_intelligence.classify)(
|
|
3613
|
+
{ signals, phase: "post-diff", riskHigh: deps.riskHigh, prompt: deps.prompt },
|
|
3614
|
+
provider
|
|
3615
|
+
);
|
|
3616
|
+
const comparison = deps.comparatorConfig ? (0, import_intelligence.compareToPrediction)(deps.prediction, actual, deps.comparatorConfig) : (0, import_intelligence.compareToPrediction)(deps.prediction, actual);
|
|
3617
|
+
return { actual, comparison };
|
|
3618
|
+
}
|
|
3619
|
+
function buildTriageOutcomeInput(externalId, shapeKey, result) {
|
|
3620
|
+
return {
|
|
3621
|
+
externalId,
|
|
3622
|
+
shapeKey,
|
|
3623
|
+
actual: result.actual,
|
|
3624
|
+
exceededBy: result.comparison.exceededBy,
|
|
3625
|
+
matched: result.comparison.matched
|
|
3626
|
+
};
|
|
3627
|
+
}
|
|
3628
|
+
function precedentLookupFromStored(records) {
|
|
3629
|
+
const bridged = records.map((r) => ({
|
|
3630
|
+
externalId: "",
|
|
3631
|
+
shapeKey: r.shapeKey,
|
|
3632
|
+
ts: "",
|
|
3633
|
+
...r.outcome ? { outcome: { actual: void 0, exceededBy: 0, matched: r.outcome.matched } } : {}
|
|
3634
|
+
}));
|
|
3635
|
+
return {
|
|
3636
|
+
rateForShape: (shapeKey) => (0, import_intelligence.aggregatePrecedent)(bridged, shapeKey)
|
|
3637
|
+
};
|
|
3638
|
+
}
|
|
3639
|
+
|
|
3640
|
+
// src/orchestrator.ts
|
|
3501
3641
|
var import_graph2 = require("@harness-engineering/graph");
|
|
3502
3642
|
|
|
3503
3643
|
// src/core/stall-detector.ts
|
|
@@ -3518,7 +3658,7 @@ function detectStalledIssues(running, nowMs, stallTimeoutMs) {
|
|
|
3518
3658
|
|
|
3519
3659
|
// src/intelligence/pipeline-runner.ts
|
|
3520
3660
|
var path9 = __toESM(require("path"));
|
|
3521
|
-
var
|
|
3661
|
+
var import_intelligence2 = require("@harness-engineering/intelligence");
|
|
3522
3662
|
var import_core2 = require("@harness-engineering/core");
|
|
3523
3663
|
var CONNECTION_ERROR_PATTERNS = [
|
|
3524
3664
|
"Connection error",
|
|
@@ -3623,7 +3763,7 @@ var IntelligencePipelineRunner = class {
|
|
|
3623
3763
|
refreshSpecializationProfiles() {
|
|
3624
3764
|
if (!this.ctx.graphStore) return;
|
|
3625
3765
|
try {
|
|
3626
|
-
const store = (0,
|
|
3766
|
+
const store = (0, import_intelligence2.refreshProfiles)(this.ctx.projectRoot, this.ctx.graphStore);
|
|
3627
3767
|
const personaCount = Object.keys(store.profiles).length;
|
|
3628
3768
|
if (personaCount > 0) {
|
|
3629
3769
|
this.ctx.logger.info(`Refreshed specialization profiles for ${personaCount} persona(s)`);
|
|
@@ -3866,7 +4006,7 @@ var IntelligencePipelineRunner = class {
|
|
|
3866
4006
|
for (const issue of candidates) {
|
|
3867
4007
|
const systemNodeIds = issue.labels.filter((l) => l.startsWith("system:") || l.startsWith("module:")).map((l) => l.split(":")[1]).filter((id) => id.length > 0);
|
|
3868
4008
|
if (systemNodeIds.length === 0) continue;
|
|
3869
|
-
const recs = (0,
|
|
4009
|
+
const recs = (0, import_intelligence2.weightedRecommendPersona)(this.ctx.graphStore, { systemNodeIds });
|
|
3870
4010
|
if (recs.length > 0) {
|
|
3871
4011
|
results.set(issue.id, recs);
|
|
3872
4012
|
}
|
|
@@ -4775,11 +4915,11 @@ function detectLegacyFields(agent) {
|
|
|
4775
4915
|
}
|
|
4776
4916
|
function buildCase1Warnings(presentLegacy, suppressLocalGroup) {
|
|
4777
4917
|
const warnings = [];
|
|
4778
|
-
for (const
|
|
4779
|
-
if (CASE1_ALWAYS_SUPPRESS.has(
|
|
4780
|
-
if (suppressLocalGroup && CASE1_LOCAL_GROUP.has(
|
|
4918
|
+
for (const path25 of presentLegacy) {
|
|
4919
|
+
if (CASE1_ALWAYS_SUPPRESS.has(path25)) continue;
|
|
4920
|
+
if (suppressLocalGroup && CASE1_LOCAL_GROUP.has(path25)) continue;
|
|
4781
4921
|
warnings.push(
|
|
4782
|
-
`Ignoring legacy field '${
|
|
4922
|
+
`Ignoring legacy field '${path25}': 'agent.backends' is set and takes precedence. See ${MIGRATION_GUIDE}.`
|
|
4783
4923
|
);
|
|
4784
4924
|
}
|
|
4785
4925
|
return warnings;
|
|
@@ -4807,7 +4947,7 @@ function migrateAgentConfig(agent) {
|
|
|
4807
4947
|
}
|
|
4808
4948
|
const { backends, routing } = synthesizeBackendsAndRouting(agent);
|
|
4809
4949
|
const warnings = presentLegacy.map(
|
|
4810
|
-
(
|
|
4950
|
+
(path25) => `Deprecated config field '${path25}' is in use. Migrate to 'agent.backends' / 'agent.routing'. See ${MIGRATION_GUIDE}.`
|
|
4811
4951
|
);
|
|
4812
4952
|
return {
|
|
4813
4953
|
config: { ...agent, backends, routing },
|
|
@@ -4892,12 +5032,12 @@ var BackendRouter = class {
|
|
|
4892
5032
|
*/
|
|
4893
5033
|
resolve(useCase, opts) {
|
|
4894
5034
|
const startedAt = performance.now();
|
|
4895
|
-
const
|
|
5035
|
+
const path25 = [];
|
|
4896
5036
|
const tryChain = (source, value) => {
|
|
4897
5037
|
if (value === void 0) return void 0;
|
|
4898
5038
|
for (const name of toArray(value)) {
|
|
4899
5039
|
const step = { source, candidate: name, outcome: "considered" };
|
|
4900
|
-
|
|
5040
|
+
path25.push(step);
|
|
4901
5041
|
if (this.backends[name]) {
|
|
4902
5042
|
step.outcome = "chosen";
|
|
4903
5043
|
return name;
|
|
@@ -4916,7 +5056,7 @@ var BackendRouter = class {
|
|
|
4916
5056
|
return {
|
|
4917
5057
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4918
5058
|
useCase,
|
|
4919
|
-
resolutionPath:
|
|
5059
|
+
resolutionPath: path25,
|
|
4920
5060
|
backendName,
|
|
4921
5061
|
backendType: def.type,
|
|
4922
5062
|
durationMs: performance.now() - startedAt
|
|
@@ -4949,7 +5089,7 @@ var BackendRouter = class {
|
|
|
4949
5089
|
if (fromDefault) return emitAndReturn(decide(fromDefault));
|
|
4950
5090
|
const knownList = Object.keys(this.backends).join(", ") || "(none)";
|
|
4951
5091
|
throw new Error(
|
|
4952
|
-
`BackendRouter.resolve: routing.default produced no available backend for useCase=${JSON.stringify(useCase)}. Resolution path: ${JSON.stringify(
|
|
5092
|
+
`BackendRouter.resolve: routing.default produced no available backend for useCase=${JSON.stringify(useCase)}. Resolution path: ${JSON.stringify(path25)}. Known backends: [${knownList}].`
|
|
4953
5093
|
);
|
|
4954
5094
|
}
|
|
4955
5095
|
/**
|
|
@@ -5042,7 +5182,7 @@ var BackendRouter = class {
|
|
|
5042
5182
|
check(`modes.${mode}`, value);
|
|
5043
5183
|
}
|
|
5044
5184
|
if (missing.length > 0) {
|
|
5045
|
-
const detail = missing.map(({ path:
|
|
5185
|
+
const detail = missing.map(({ path: path25, name }) => `routing.${path25} -> '${name}'`).join("; ");
|
|
5046
5186
|
const known_ = [...known].join(", ") || "(none)";
|
|
5047
5187
|
throw new Error(
|
|
5048
5188
|
`BackendRouter: routing references unknown backend(s): ${detail}. Defined backends: [${known_}].`
|
|
@@ -7435,11 +7575,11 @@ function createAgentDispatcher(deps) {
|
|
|
7435
7575
|
var import_node_child_process13 = require("child_process");
|
|
7436
7576
|
|
|
7437
7577
|
// src/agent/intelligence-factory.ts
|
|
7438
|
-
var
|
|
7578
|
+
var import_intelligence4 = require("@harness-engineering/intelligence");
|
|
7439
7579
|
var import_graph = require("@harness-engineering/graph");
|
|
7440
7580
|
|
|
7441
7581
|
// src/agent/analysis-provider-factory.ts
|
|
7442
|
-
var
|
|
7582
|
+
var import_intelligence3 = require("@harness-engineering/intelligence");
|
|
7443
7583
|
function buildAnalysisProvider(args) {
|
|
7444
7584
|
const { def, backendName, layer, intelligence, logger } = args;
|
|
7445
7585
|
const layerModel = layer === "sel" ? intelligence?.models?.sel : intelligence?.models?.pesl;
|
|
@@ -7479,7 +7619,7 @@ function buildLocalLikeProvider(def, args, layerModel) {
|
|
|
7479
7619
|
logger.info(
|
|
7480
7620
|
`Intelligence pipeline using backend '${backendName}' (${def.type}) at ${def.endpoint} (model: ${model ?? "(default)"})`
|
|
7481
7621
|
);
|
|
7482
|
-
return new
|
|
7622
|
+
return new import_intelligence3.OpenAICompatibleAnalysisProvider({
|
|
7483
7623
|
apiKey,
|
|
7484
7624
|
baseUrl: def.endpoint,
|
|
7485
7625
|
...model !== void 0 && { defaultModel: model },
|
|
@@ -7497,7 +7637,7 @@ function buildAnthropicProvider(def, args, layerModel) {
|
|
|
7497
7637
|
const apiKey = def.apiKey ?? process.env.ANTHROPIC_API_KEY;
|
|
7498
7638
|
const model = layerModel ?? def.model;
|
|
7499
7639
|
if (apiKey) {
|
|
7500
|
-
return new
|
|
7640
|
+
return new import_intelligence3.AnthropicAnalysisProvider({
|
|
7501
7641
|
apiKey,
|
|
7502
7642
|
...model !== void 0 && { defaultModel: model }
|
|
7503
7643
|
});
|
|
@@ -7505,7 +7645,7 @@ function buildAnthropicProvider(def, args, layerModel) {
|
|
|
7505
7645
|
args.logger.info(
|
|
7506
7646
|
`Intelligence pipeline routed to '${args.backendName}' (anthropic) without API key \u2014 using Claude CLI fallback.`
|
|
7507
7647
|
);
|
|
7508
|
-
return new
|
|
7648
|
+
return new import_intelligence3.ClaudeCliAnalysisProvider({
|
|
7509
7649
|
...model !== void 0 && { defaultModel: model },
|
|
7510
7650
|
...args.intelligence?.requestTimeoutMs !== void 0 && {
|
|
7511
7651
|
timeoutMs: args.intelligence.requestTimeoutMs
|
|
@@ -7521,7 +7661,7 @@ function buildOpenAIProvider(def, args, layerModel) {
|
|
|
7521
7661
|
return null;
|
|
7522
7662
|
}
|
|
7523
7663
|
const model = layerModel ?? def.model;
|
|
7524
|
-
return new
|
|
7664
|
+
return new import_intelligence3.OpenAICompatibleAnalysisProvider({
|
|
7525
7665
|
apiKey,
|
|
7526
7666
|
baseUrl: "https://api.openai.com/v1",
|
|
7527
7667
|
...model !== void 0 && { defaultModel: model },
|
|
@@ -7531,7 +7671,7 @@ function buildOpenAIProvider(def, args, layerModel) {
|
|
|
7531
7671
|
});
|
|
7532
7672
|
}
|
|
7533
7673
|
function buildClaudeCliProvider(def, args, layerModel) {
|
|
7534
|
-
return new
|
|
7674
|
+
return new import_intelligence3.ClaudeCliAnalysisProvider({
|
|
7535
7675
|
...def.command !== void 0 && { command: def.command },
|
|
7536
7676
|
...layerModel !== void 0 && { defaultModel: layerModel },
|
|
7537
7677
|
...args.intelligence?.requestTimeoutMs !== void 0 && {
|
|
@@ -7552,7 +7692,7 @@ function buildIntelligencePipeline(deps) {
|
|
|
7552
7692
|
const peslProvider = peslName !== selName ? buildAnalysisProviderForLayer("pesl", deps) : null;
|
|
7553
7693
|
const peslModel = intel.models?.pesl ?? config.agent.model;
|
|
7554
7694
|
const graphStore = new import_graph.GraphStore();
|
|
7555
|
-
const pipeline = new
|
|
7695
|
+
const pipeline = new import_intelligence4.IntelligencePipeline(selProvider, graphStore, {
|
|
7556
7696
|
...peslModel !== void 0 && { peslModel },
|
|
7557
7697
|
...peslProvider !== null && peslProvider !== void 0 && { peslProvider }
|
|
7558
7698
|
});
|
|
@@ -7618,13 +7758,13 @@ function buildExplicitProvider(provider, selModel, config) {
|
|
|
7618
7758
|
if (!apiKey2) {
|
|
7619
7759
|
throw new Error("Intelligence pipeline: no Anthropic API key found.");
|
|
7620
7760
|
}
|
|
7621
|
-
return new
|
|
7761
|
+
return new import_intelligence4.AnthropicAnalysisProvider({
|
|
7622
7762
|
apiKey: apiKey2,
|
|
7623
7763
|
...selModel !== void 0 && { defaultModel: selModel }
|
|
7624
7764
|
});
|
|
7625
7765
|
}
|
|
7626
7766
|
if (provider.kind === "claude-cli") {
|
|
7627
|
-
return new
|
|
7767
|
+
return new import_intelligence4.ClaudeCliAnalysisProvider({
|
|
7628
7768
|
command: config.agent.command,
|
|
7629
7769
|
...selModel !== void 0 && { defaultModel: selModel },
|
|
7630
7770
|
...config.intelligence?.requestTimeoutMs !== void 0 && {
|
|
@@ -7635,7 +7775,7 @@ function buildExplicitProvider(provider, selModel, config) {
|
|
|
7635
7775
|
const apiKey = provider.apiKey ?? config.agent.apiKey ?? "ollama";
|
|
7636
7776
|
const baseUrl = provider.baseUrl ?? "http://localhost:11434/v1";
|
|
7637
7777
|
const intel = config.intelligence;
|
|
7638
|
-
return new
|
|
7778
|
+
return new import_intelligence4.OpenAICompatibleAnalysisProvider({
|
|
7639
7779
|
apiKey,
|
|
7640
7780
|
baseUrl,
|
|
7641
7781
|
...selModel !== void 0 && { defaultModel: selModel },
|
|
@@ -7646,13 +7786,13 @@ function buildExplicitProvider(provider, selModel, config) {
|
|
|
7646
7786
|
}
|
|
7647
7787
|
|
|
7648
7788
|
// src/agent/adaptive-router.ts
|
|
7649
|
-
var
|
|
7789
|
+
var import_intelligence7 = require("@harness-engineering/intelligence");
|
|
7650
7790
|
var import_types24 = require("@harness-engineering/types");
|
|
7651
7791
|
|
|
7652
7792
|
// src/agent/capability-registry.ts
|
|
7653
7793
|
var import_types23 = require("@harness-engineering/types");
|
|
7654
7794
|
var import_local_models2 = require("@harness-engineering/local-models");
|
|
7655
|
-
var
|
|
7795
|
+
var import_intelligence5 = require("@harness-engineering/intelligence");
|
|
7656
7796
|
var PrivacyNoMatch = class extends import_types23.RoutingError {
|
|
7657
7797
|
code = "privacy-no-match";
|
|
7658
7798
|
constructor(message) {
|
|
@@ -7667,7 +7807,7 @@ var PRIVACY_RANK = {
|
|
|
7667
7807
|
"shared-cloud": 3
|
|
7668
7808
|
};
|
|
7669
7809
|
function selectCheapestQualifying(registry, requiredTier, constraints, providerOf) {
|
|
7670
|
-
const requiredRank =
|
|
7810
|
+
const requiredRank = import_intelligence5.TIER_RANK[requiredTier];
|
|
7671
7811
|
const entries = [...registry.entries()].map(([name, capabilities]) => ({
|
|
7672
7812
|
name,
|
|
7673
7813
|
capabilities
|
|
@@ -7689,7 +7829,7 @@ function selectCheapestQualifying(registry, requiredTier, constraints, providerO
|
|
|
7689
7829
|
}
|
|
7690
7830
|
const qualifying = passesPrivacyAllow.filter((e) => {
|
|
7691
7831
|
const c = e.capabilities;
|
|
7692
|
-
if (
|
|
7832
|
+
if (import_intelligence5.TIER_RANK[c.tier] < requiredRank) return false;
|
|
7693
7833
|
if (constraints.needsVision && !c.vision) return false;
|
|
7694
7834
|
if (constraints.needsToolUse && !c.toolUse) return false;
|
|
7695
7835
|
if (constraints.minContextTokens !== void 0 && c.contextWindow < constraints.minContextTokens)
|
|
@@ -7728,7 +7868,7 @@ function estimateCost(def, _req) {
|
|
|
7728
7868
|
}
|
|
7729
7869
|
|
|
7730
7870
|
// src/agent/escalation-state.ts
|
|
7731
|
-
var
|
|
7871
|
+
var import_intelligence6 = require("@harness-engineering/intelligence");
|
|
7732
7872
|
var EscalationState = class {
|
|
7733
7873
|
constructor(threshold = 2) {
|
|
7734
7874
|
this.threshold = threshold;
|
|
@@ -7757,7 +7897,7 @@ var EscalationState = class {
|
|
|
7757
7897
|
climbedUnits() {
|
|
7758
7898
|
const out = [];
|
|
7759
7899
|
for (const [coherenceUnit, state] of this.units) {
|
|
7760
|
-
if (
|
|
7900
|
+
if (import_intelligence6.TIER_RANK[state.floorTier] > import_intelligence6.TIER_RANK.fast) {
|
|
7761
7901
|
out.push({ coherenceUnit, floor: state.floorTier });
|
|
7762
7902
|
}
|
|
7763
7903
|
}
|
|
@@ -7796,14 +7936,14 @@ var EscalationState = class {
|
|
|
7796
7936
|
return "ok";
|
|
7797
7937
|
}
|
|
7798
7938
|
state.failures = 0;
|
|
7799
|
-
const currentRank =
|
|
7800
|
-
if (currentRank >=
|
|
7939
|
+
const currentRank = import_intelligence6.TIER_RANK[state.floorTier];
|
|
7940
|
+
if (currentRank >= import_intelligence6.TIER_RANK.strong) {
|
|
7801
7941
|
state.floorTier = "strong";
|
|
7802
7942
|
state.escalated = true;
|
|
7803
7943
|
this.units.set(coherenceUnit, state);
|
|
7804
7944
|
return "exhausted";
|
|
7805
7945
|
}
|
|
7806
|
-
state.floorTier =
|
|
7946
|
+
state.floorTier = import_intelligence6.RANK_TIER[currentRank + 1];
|
|
7807
7947
|
state.escalated = true;
|
|
7808
7948
|
this.units.set(coherenceUnit, state);
|
|
7809
7949
|
return "escalated";
|
|
@@ -7939,7 +8079,7 @@ var AdaptiveRouter = class _AdaptiveRouter {
|
|
|
7939
8079
|
let budgetStatus = null;
|
|
7940
8080
|
if (budget && budget.capUsd > 0) {
|
|
7941
8081
|
const spentUsd = this.getSpentUsd();
|
|
7942
|
-
const degradeAtPct = budget.degradeAtPct ??
|
|
8082
|
+
const degradeAtPct = budget.degradeAtPct ?? import_intelligence7.DEFAULT_DEGRADE_AT_PCT;
|
|
7943
8083
|
budgetStatus = {
|
|
7944
8084
|
spentUsd,
|
|
7945
8085
|
capUsd: budget.capUsd,
|
|
@@ -7971,8 +8111,8 @@ var AdaptiveRouter = class _AdaptiveRouter {
|
|
|
7971
8111
|
);
|
|
7972
8112
|
}
|
|
7973
8113
|
const unitFloor = this.deps.escalation?.floorFor(req.coherenceUnit) ?? "fast";
|
|
7974
|
-
const escalationFloor =
|
|
7975
|
-
const requiredTier = (0,
|
|
8114
|
+
const escalationFloor = import_intelligence7.RANK_TIER[Math.max(import_intelligence7.TIER_RANK[unitFloor], import_intelligence7.TIER_RANK[req.floor ?? "fast"])];
|
|
8115
|
+
const requiredTier = (0, import_intelligence7.deriveRequiredTier)(
|
|
7976
8116
|
complexity,
|
|
7977
8117
|
req.risk,
|
|
7978
8118
|
this.deps.policy,
|
|
@@ -8129,10 +8269,10 @@ var RoutingDecisionBus = class {
|
|
|
8129
8269
|
};
|
|
8130
8270
|
|
|
8131
8271
|
// src/workflow/execute-workflow.ts
|
|
8132
|
-
var
|
|
8272
|
+
var import_intelligence8 = require("@harness-engineering/intelligence");
|
|
8133
8273
|
function nextTier(t) {
|
|
8134
|
-
const next = Math.min(
|
|
8135
|
-
return
|
|
8274
|
+
const next = Math.min(import_intelligence8.TIER_RANK[t] + 1, import_intelligence8.TIER_RANK.strong);
|
|
8275
|
+
return import_intelligence8.RANK_TIER[next];
|
|
8136
8276
|
}
|
|
8137
8277
|
var DEFAULT_STAGE_DEADLINE_MS = 12e4;
|
|
8138
8278
|
function stageAttemptKey(stageIndex, attempt) {
|
|
@@ -8354,7 +8494,7 @@ function buildRoutingUseCase(issue, backendParam, catalog) {
|
|
|
8354
8494
|
}
|
|
8355
8495
|
|
|
8356
8496
|
// src/agent/live-classify.ts
|
|
8357
|
-
var
|
|
8497
|
+
var import_intelligence9 = require("@harness-engineering/intelligence");
|
|
8358
8498
|
var CONSERVATIVE = {
|
|
8359
8499
|
level: "moderate",
|
|
8360
8500
|
confidence: "low",
|
|
@@ -8377,7 +8517,7 @@ function makeLiveClassify(resolveProvider) {
|
|
|
8377
8517
|
riskHigh,
|
|
8378
8518
|
prompt: taskText.prompt
|
|
8379
8519
|
};
|
|
8380
|
-
return (0,
|
|
8520
|
+
return (0, import_intelligence9.classify)(input, resolveProvider());
|
|
8381
8521
|
};
|
|
8382
8522
|
}
|
|
8383
8523
|
|
|
@@ -8900,7 +9040,7 @@ function extractChunks(event) {
|
|
|
8900
9040
|
}
|
|
8901
9041
|
|
|
8902
9042
|
// src/server/routes/analyze.ts
|
|
8903
|
-
var
|
|
9043
|
+
var import_intelligence10 = require("@harness-engineering/intelligence");
|
|
8904
9044
|
var import_zod7 = require("zod");
|
|
8905
9045
|
var AnalyzeRequestSchema = import_zod7.z.object({
|
|
8906
9046
|
title: import_zod7.z.string().min(1),
|
|
@@ -8930,7 +9070,7 @@ async function runPipeline(res, pipeline, parsed) {
|
|
|
8930
9070
|
disconnected = true;
|
|
8931
9071
|
});
|
|
8932
9072
|
emit2(res, { type: "status", text: "Converting to work item..." });
|
|
8933
|
-
const rawItem = (0,
|
|
9073
|
+
const rawItem = (0, import_intelligence10.manualToRawWorkItem)({
|
|
8934
9074
|
title: parsed.title,
|
|
8935
9075
|
description: parsed.description ?? "",
|
|
8936
9076
|
labels: parsed.labels ?? []
|
|
@@ -8973,7 +9113,7 @@ async function runPipeline(res, pipeline, parsed) {
|
|
|
8973
9113
|
}
|
|
8974
9114
|
}
|
|
8975
9115
|
if (disconnected) return;
|
|
8976
|
-
const signals = (0,
|
|
9116
|
+
const signals = (0, import_intelligence10.scoreToConcernSignals)(score);
|
|
8977
9117
|
if (signals.length > 0) {
|
|
8978
9118
|
emit2(res, { type: "signals", data: signals });
|
|
8979
9119
|
}
|
|
@@ -10633,7 +10773,7 @@ function handleV1LocalModelsMutationRoute(req, res, deps) {
|
|
|
10633
10773
|
|
|
10634
10774
|
// src/server/routes/v1/routing.ts
|
|
10635
10775
|
var import_zod14 = require("zod");
|
|
10636
|
-
var
|
|
10776
|
+
var import_intelligence11 = require("@harness-engineering/intelligence");
|
|
10637
10777
|
var CONFIG_RE = /^\/api\/v1\/routing\/config(?:\?.*)?$/;
|
|
10638
10778
|
var DECISIONS_RE = /^\/api\/v1\/routing\/decisions(?:\?.*)?$/;
|
|
10639
10779
|
var TRACE_RE = /^\/api\/v1\/routing\/trace(?:\?.*)?$/;
|
|
@@ -10737,7 +10877,7 @@ function deriveTraceCost(body, decision, def, routing, backends) {
|
|
|
10737
10877
|
source: "static"
|
|
10738
10878
|
};
|
|
10739
10879
|
const risk = body.risk === "high" ? { blastRadius: 10, sensitivePath: true } : { blastRadius: 0, sensitivePath: false };
|
|
10740
|
-
const tierRequired = (0,
|
|
10880
|
+
const tierRequired = (0, import_intelligence11.deriveRequiredTier)(
|
|
10741
10881
|
verdict,
|
|
10742
10882
|
risk,
|
|
10743
10883
|
routing.policy ?? {},
|
|
@@ -10752,7 +10892,12 @@ function deriveTraceCost(body, decision, def, routing, backends) {
|
|
|
10752
10892
|
backends
|
|
10753
10893
|
);
|
|
10754
10894
|
const estCostUsd = estimateCost(costedDef, { useCase: body.useCase });
|
|
10755
|
-
return {
|
|
10895
|
+
return {
|
|
10896
|
+
tierRequired,
|
|
10897
|
+
estCostUsd,
|
|
10898
|
+
costedBackendName: costedName,
|
|
10899
|
+
costedBackendType: costedDef.type
|
|
10900
|
+
};
|
|
10756
10901
|
}
|
|
10757
10902
|
function selectCostedBackend(tierRequired, decision, def, routing, backends) {
|
|
10758
10903
|
const registry = buildCapabilityRegistry(backends);
|
|
@@ -10817,7 +10962,7 @@ async function handleTrace(req, res, deps) {
|
|
|
10817
10962
|
opts
|
|
10818
10963
|
);
|
|
10819
10964
|
if (r.data.complexity !== void 0 || r.data.risk !== void 0) {
|
|
10820
|
-
const { tierRequired, estCostUsd, costedBackendName } = deriveTraceCost(
|
|
10965
|
+
const { tierRequired, estCostUsd, costedBackendName, costedBackendType } = deriveTraceCost(
|
|
10821
10966
|
r.data,
|
|
10822
10967
|
decision,
|
|
10823
10968
|
def,
|
|
@@ -10829,9 +10974,12 @@ async function handleTrace(req, res, deps) {
|
|
|
10829
10974
|
def: { type: def.type },
|
|
10830
10975
|
tierRequired,
|
|
10831
10976
|
estCostUsd,
|
|
10832
|
-
//
|
|
10833
|
-
//
|
|
10834
|
-
|
|
10977
|
+
// The backend AMR would ACTUALLY dispatch to at this tier (cheapest
|
|
10978
|
+
// qualifying) + its type — distinct from the identity-chain `decision`
|
|
10979
|
+
// above. The CLI shows this as the effective backend so tier↔cost↔backend
|
|
10980
|
+
// read consistently (was implicit + divergent before).
|
|
10981
|
+
costedBackendName,
|
|
10982
|
+
costedBackendType
|
|
10835
10983
|
});
|
|
10836
10984
|
return true;
|
|
10837
10985
|
}
|
|
@@ -10841,26 +10989,6 @@ async function handleTrace(req, res, deps) {
|
|
|
10841
10989
|
}
|
|
10842
10990
|
return true;
|
|
10843
10991
|
}
|
|
10844
|
-
var CAPABILITY_TIER = import_zod14.z.enum(["fast", "standard", "strong"]);
|
|
10845
|
-
var COMPLEXITY_LEVEL = import_zod14.z.enum(["trivial", "simple", "moderate", "complex"]);
|
|
10846
|
-
var PRIVACY_CLASS = import_zod14.z.enum(["on-device", "byo-endpoint", "shared-cloud"]);
|
|
10847
|
-
var RoutingPolicySchema = import_zod14.z.object({
|
|
10848
|
-
complexityTierMatrix: import_zod14.z.record(COMPLEXITY_LEVEL, CAPABILITY_TIER).optional(),
|
|
10849
|
-
skillTierOverrides: import_zod14.z.record(import_zod14.z.string(), CAPABILITY_TIER).optional(),
|
|
10850
|
-
privacyFloor: PRIVACY_CLASS.optional(),
|
|
10851
|
-
budget: import_zod14.z.object({
|
|
10852
|
-
capUsd: import_zod14.z.number(),
|
|
10853
|
-
degradeAtPct: import_zod14.z.number().optional(),
|
|
10854
|
-
onBudgetExhausted: import_zod14.z.enum(["degrade", "pause", "human"])
|
|
10855
|
-
}).optional(),
|
|
10856
|
-
sensitivePaths: import_zod14.z.array(import_zod14.z.string()).optional(),
|
|
10857
|
-
escalationThreshold: import_zod14.z.number().optional(),
|
|
10858
|
-
allowedProviders: import_zod14.z.array(import_zod14.z.string()).optional(),
|
|
10859
|
-
acceptanceEval: import_zod14.z.object({
|
|
10860
|
-
enabled: import_zod14.z.boolean(),
|
|
10861
|
-
model: import_zod14.z.string().optional()
|
|
10862
|
-
}).optional()
|
|
10863
|
-
});
|
|
10864
10992
|
async function handlePolicy(req, res, deps) {
|
|
10865
10993
|
if (!deps.ingestRoutingPolicy || deps.router === null) return unavailable(res);
|
|
10866
10994
|
let raw;
|
|
@@ -11406,8 +11534,8 @@ function parseToken(raw) {
|
|
|
11406
11534
|
return { id: raw.slice(0, dot), secret: raw.slice(dot + 1) };
|
|
11407
11535
|
}
|
|
11408
11536
|
var TokenStore = class {
|
|
11409
|
-
constructor(
|
|
11410
|
-
this.path =
|
|
11537
|
+
constructor(path25) {
|
|
11538
|
+
this.path = path25;
|
|
11411
11539
|
}
|
|
11412
11540
|
path;
|
|
11413
11541
|
cache = null;
|
|
@@ -11514,8 +11642,8 @@ var import_promises2 = require("fs/promises");
|
|
|
11514
11642
|
var import_node_path2 = require("path");
|
|
11515
11643
|
var import_types29 = require("@harness-engineering/types");
|
|
11516
11644
|
var AuditLogger = class {
|
|
11517
|
-
constructor(
|
|
11518
|
-
this.path =
|
|
11645
|
+
constructor(path25, opts = {}) {
|
|
11646
|
+
this.path = path25;
|
|
11519
11647
|
this.opts = opts;
|
|
11520
11648
|
}
|
|
11521
11649
|
path;
|
|
@@ -11753,9 +11881,9 @@ var V1_BRIDGE_ROUTES = [
|
|
|
11753
11881
|
function isV1Bridge(method, url) {
|
|
11754
11882
|
return V1_BRIDGE_ROUTES.some((r) => r.method === method && r.pattern.test(url));
|
|
11755
11883
|
}
|
|
11756
|
-
function requiredBridgeScope(method,
|
|
11884
|
+
function requiredBridgeScope(method, path25) {
|
|
11757
11885
|
for (const r of V1_BRIDGE_ROUTES) {
|
|
11758
|
-
if (r.method === method && r.pattern.test(
|
|
11886
|
+
if (r.method === method && r.pattern.test(path25)) return r.scope;
|
|
11759
11887
|
}
|
|
11760
11888
|
return null;
|
|
11761
11889
|
}
|
|
@@ -11765,11 +11893,11 @@ function hasScope(held, required) {
|
|
|
11765
11893
|
if (held.includes("admin")) return true;
|
|
11766
11894
|
return held.includes(required);
|
|
11767
11895
|
}
|
|
11768
|
-
function exactScopeForRoute(method,
|
|
11769
|
-
if (
|
|
11770
|
-
if (
|
|
11771
|
-
if (/^\/api\/v1\/auth\/tokens\/[^/]+$/.test(
|
|
11772
|
-
if ((
|
|
11896
|
+
function exactScopeForRoute(method, path25) {
|
|
11897
|
+
if (path25 === "/api/v1/auth/token" && method === "POST") return "admin";
|
|
11898
|
+
if (path25 === "/api/v1/auth/tokens" && method === "GET") return "admin";
|
|
11899
|
+
if (/^\/api\/v1\/auth\/tokens\/[^/]+$/.test(path25) && method === "DELETE") return "admin";
|
|
11900
|
+
if ((path25 === "/api/state" || path25 === "/api/v1/state") && method === "GET") return "read-status";
|
|
11773
11901
|
return null;
|
|
11774
11902
|
}
|
|
11775
11903
|
var PREFIX_SCOPES = [
|
|
@@ -11786,19 +11914,19 @@ var PREFIX_SCOPES = [
|
|
|
11786
11914
|
["/api/sessions", "read-status"],
|
|
11787
11915
|
["/api/chat-proxy", "trigger-job"]
|
|
11788
11916
|
];
|
|
11789
|
-
function prefixScopeForPath(
|
|
11790
|
-
if (
|
|
11917
|
+
function prefixScopeForPath(path25) {
|
|
11918
|
+
if (path25 === "/api/chat") return "trigger-job";
|
|
11791
11919
|
for (const [prefix, scope] of PREFIX_SCOPES) {
|
|
11792
|
-
if (
|
|
11920
|
+
if (path25.startsWith(prefix)) return scope;
|
|
11793
11921
|
}
|
|
11794
11922
|
return null;
|
|
11795
11923
|
}
|
|
11796
|
-
function requiredScopeForRoute(method,
|
|
11797
|
-
const bridgeScope = requiredBridgeScope(method,
|
|
11924
|
+
function requiredScopeForRoute(method, path25) {
|
|
11925
|
+
const bridgeScope = requiredBridgeScope(method, path25);
|
|
11798
11926
|
if (bridgeScope) return bridgeScope;
|
|
11799
|
-
const exactScope = exactScopeForRoute(method,
|
|
11927
|
+
const exactScope = exactScopeForRoute(method, path25);
|
|
11800
11928
|
if (exactScope) return exactScope;
|
|
11801
|
-
return prefixScopeForPath(
|
|
11929
|
+
return prefixScopeForPath(path25);
|
|
11802
11930
|
}
|
|
11803
11931
|
|
|
11804
11932
|
// src/server/http.ts
|
|
@@ -12327,8 +12455,8 @@ function genSecret2() {
|
|
|
12327
12455
|
return (0, import_node_crypto10.randomBytes)(32).toString("base64url");
|
|
12328
12456
|
}
|
|
12329
12457
|
var WebhookStore = class {
|
|
12330
|
-
constructor(
|
|
12331
|
-
this.path =
|
|
12458
|
+
constructor(path25) {
|
|
12459
|
+
this.path = path25;
|
|
12332
12460
|
}
|
|
12333
12461
|
path;
|
|
12334
12462
|
cache = null;
|
|
@@ -15173,8 +15301,8 @@ function validateCheckShape(prefix, task, errors) {
|
|
|
15173
15301
|
});
|
|
15174
15302
|
}
|
|
15175
15303
|
if (hasScript) {
|
|
15176
|
-
const
|
|
15177
|
-
if (!
|
|
15304
|
+
const path25 = task.checkScript?.path;
|
|
15305
|
+
if (!path25 || path25.trim().length === 0) {
|
|
15178
15306
|
errors.push({ path: `${prefix}.checkScript.path`, message: "checkScript.path is required" });
|
|
15179
15307
|
}
|
|
15180
15308
|
if (task.checkScript?.timeoutMs !== void 0 && task.checkScript.timeoutMs <= 0) {
|
|
@@ -15300,9 +15428,9 @@ function handleEdge(top, next, color, stack, errors, reported) {
|
|
|
15300
15428
|
stack.push({ id: next, nextIdx: 0, path: [...top.path, next] });
|
|
15301
15429
|
}
|
|
15302
15430
|
}
|
|
15303
|
-
function reportCycle(
|
|
15304
|
-
const cycleStart =
|
|
15305
|
-
const cyclePath = cycleStart >= 0 ? [...
|
|
15431
|
+
function reportCycle(path25, next, errors, reported) {
|
|
15432
|
+
const cycleStart = path25.indexOf(next);
|
|
15433
|
+
const cyclePath = cycleStart >= 0 ? [...path25.slice(cycleStart), next] : [...path25, next];
|
|
15306
15434
|
const key = cyclePath.join("\u2192");
|
|
15307
15435
|
if (reported.has(key)) return;
|
|
15308
15436
|
reported.add(key);
|
|
@@ -16790,7 +16918,9 @@ ${messages}`);
|
|
|
16790
16918
|
await this.emitWorkerExit(issue.id, "error", attempt, "Stopped by reconciliation");
|
|
16791
16919
|
}
|
|
16792
16920
|
} else {
|
|
16793
|
-
const
|
|
16921
|
+
const qualityClass = await this.deriveSingleAgentQualityVerdict(issue, workspacePath);
|
|
16922
|
+
const retroClass = await this.deriveRoutingRetrospectiveVerdict(issue, workspacePath);
|
|
16923
|
+
const outcomeClass = qualityClass ?? retroClass;
|
|
16794
16924
|
await this.emitWorkerExit(issue.id, "normal", attempt, void 0, outcomeClass);
|
|
16795
16925
|
}
|
|
16796
16926
|
} catch (error) {
|
|
@@ -16865,7 +16995,7 @@ ${messages}`);
|
|
|
16865
16995
|
try {
|
|
16866
16996
|
const diff = await this.workspace.getIntroducedDiffText(issue.identifier);
|
|
16867
16997
|
if (diff.trim() === "") return void 0;
|
|
16868
|
-
const evaluator = new
|
|
16998
|
+
const evaluator = new import_intelligence12.OutcomeEvaluator(provider, this.graphStore ?? new import_graph2.GraphStore(), {
|
|
16869
16999
|
...acceptanceEval.model !== void 0 ? { model: acceptanceEval.model } : {}
|
|
16870
17000
|
});
|
|
16871
17001
|
const verdict = await evaluator.evaluate({
|
|
@@ -16892,6 +17022,150 @@ ${messages}`);
|
|
|
16892
17022
|
return void 0;
|
|
16893
17023
|
}
|
|
16894
17024
|
}
|
|
17025
|
+
/**
|
|
17026
|
+
* Roadmap Auto-Triage Phase 4 (SC1–SC3, SC5, SC7): the post-diff routing
|
|
17027
|
+
* retrospective — a SIBLING quality-verdict source to the 4c feeder above,
|
|
17028
|
+
* extending (not replacing) the proven escalation path. On a normal exit, when AMR
|
|
17029
|
+
* is live AND auto-triage is enabled AND this unit carries a stored pre-dispatch
|
|
17030
|
+
* prediction, it classifies the ACTUAL introduced diff at full strength
|
|
17031
|
+
* (phase:'post-diff') and grades it against that prediction:
|
|
17032
|
+
* - MATCH → records the graded outcome + annotates the PR "AI autonomous —
|
|
17033
|
+
* verify" (stage-2 human-verify handling, SC4) → returns `undefined`
|
|
17034
|
+
* (neutral: a match is not an escalation).
|
|
17035
|
+
* - MISMATCH (diff exceeded prediction, or a missing/garbled prediction, or ANY
|
|
17036
|
+
* error) → records the outcome (when a shape is known) + returns
|
|
17037
|
+
* `'quality-fail'`, which climbs the coherence unit's escalation floor
|
|
17038
|
+
* via `recordAmrOutcome`; exhaustion queues `needs-human` (SC3/SC7).
|
|
17039
|
+
*
|
|
17040
|
+
* Fail-safe & guarded (SC7): an error never a silent pass — it takes the MISMATCH
|
|
17041
|
+
* (block+escalate) path. No-op (byte-identical) when AMR is off, auto-triage is
|
|
17042
|
+
* off, or the unit was not dispatched through triage (no stored prediction) — the
|
|
17043
|
+
* last means an ordinary non-triaged run is never graded.
|
|
17044
|
+
*/
|
|
17045
|
+
async deriveRoutingRetrospectiveVerdict(issue, _workspacePath) {
|
|
17046
|
+
if (this.adaptiveRouter === null) return void 0;
|
|
17047
|
+
if (this.config.roadmap?.autoTriage?.enabled !== true) return void 0;
|
|
17048
|
+
const externalId = issue.externalId;
|
|
17049
|
+
if (externalId === null || externalId === "") return void 0;
|
|
17050
|
+
let record;
|
|
17051
|
+
try {
|
|
17052
|
+
const loaded = await import_core17.eventSourcing.loadTriageRecords(this.projectRoot);
|
|
17053
|
+
if (!loaded.ok) throw loaded.error;
|
|
17054
|
+
record = loaded.value.find((r) => r.externalId === externalId);
|
|
17055
|
+
} catch (err) {
|
|
17056
|
+
this.logger.debug("amr retrospective skipped (record load failed)", {
|
|
17057
|
+
issueId: issue.id,
|
|
17058
|
+
error: err instanceof Error ? err.message : String(err)
|
|
17059
|
+
});
|
|
17060
|
+
if (issue.spec !== null && issue.spec !== void 0 && issue.spec !== "") {
|
|
17061
|
+
this.logger.info(
|
|
17062
|
+
"amr:quality-fail \u2014 spec-bearing (triaged) unit but the triage store is unreadable (fail-safe block: a triaged unit whose prediction we cannot read never silently passes)",
|
|
17063
|
+
{ issueId: issue.id, externalId }
|
|
17064
|
+
);
|
|
17065
|
+
return "quality-fail";
|
|
17066
|
+
}
|
|
17067
|
+
return void 0;
|
|
17068
|
+
}
|
|
17069
|
+
if (record === void 0) return void 0;
|
|
17070
|
+
const stored = record.prediction;
|
|
17071
|
+
if (stored === void 0) {
|
|
17072
|
+
this.logger.info(
|
|
17073
|
+
"amr:quality-fail \u2014 triaged unit has no stored prediction (fail-safe block)",
|
|
17074
|
+
{
|
|
17075
|
+
issueId: issue.id,
|
|
17076
|
+
externalId
|
|
17077
|
+
}
|
|
17078
|
+
);
|
|
17079
|
+
return "quality-fail";
|
|
17080
|
+
}
|
|
17081
|
+
const prediction = {
|
|
17082
|
+
verdict: stored.verdict,
|
|
17083
|
+
levers: stored.levers,
|
|
17084
|
+
scopeEstimate: stored.scopeEstimate,
|
|
17085
|
+
ratchetStage: stored.ratchetStage
|
|
17086
|
+
};
|
|
17087
|
+
try {
|
|
17088
|
+
const hunks = await this.workspace.getIntroducedDiff(issue.identifier);
|
|
17089
|
+
const taskText = buildTaskText(issue);
|
|
17090
|
+
const exceededByBands = this.config.roadmap?.autoTriage?.thresholds?.exceededByBands ?? 1;
|
|
17091
|
+
const result = await runRetrospective(
|
|
17092
|
+
{
|
|
17093
|
+
hunks,
|
|
17094
|
+
textOnly: {
|
|
17095
|
+
descriptionLength: taskText.descriptionLength,
|
|
17096
|
+
specExists: taskText.specExists,
|
|
17097
|
+
acceptanceMeasurable: taskText.acceptanceMeasurable
|
|
17098
|
+
},
|
|
17099
|
+
prediction,
|
|
17100
|
+
riskHigh: false,
|
|
17101
|
+
prompt: taskText.prompt,
|
|
17102
|
+
comparatorConfig: { exceededByBands }
|
|
17103
|
+
},
|
|
17104
|
+
this.resolveComplexityProvider()
|
|
17105
|
+
);
|
|
17106
|
+
const outcomeInput = buildTriageOutcomeInput(externalId, record.shapeKey, result);
|
|
17107
|
+
const recorded = await import_core17.eventSourcing.recordTriageOutcome(this.projectRoot, outcomeInput);
|
|
17108
|
+
if (!recorded.ok) {
|
|
17109
|
+
this.logger.warn("amr retrospective outcome record failed (best-effort)", {
|
|
17110
|
+
issueId: issue.id,
|
|
17111
|
+
error: recorded.error.message
|
|
17112
|
+
});
|
|
17113
|
+
}
|
|
17114
|
+
if (result.comparison.action === "block-escalate") {
|
|
17115
|
+
this.logger.info("amr:quality-fail \u2014 post-diff retrospective mispredict (block+escalate)", {
|
|
17116
|
+
issueId: issue.id,
|
|
17117
|
+
externalId,
|
|
17118
|
+
predicted: prediction.verdict.level,
|
|
17119
|
+
actual: result.actual.level,
|
|
17120
|
+
exceededBy: result.comparison.exceededBy
|
|
17121
|
+
});
|
|
17122
|
+
return "quality-fail";
|
|
17123
|
+
}
|
|
17124
|
+
await this.annotateRetrospectiveMatch(issue, externalId, result.actual.level);
|
|
17125
|
+
return void 0;
|
|
17126
|
+
} catch (err) {
|
|
17127
|
+
this.logger.info("amr:quality-fail \u2014 post-diff retrospective errored (fail-safe block)", {
|
|
17128
|
+
issueId: issue.id,
|
|
17129
|
+
externalId,
|
|
17130
|
+
error: err instanceof Error ? err.message : String(err)
|
|
17131
|
+
});
|
|
17132
|
+
return "quality-fail";
|
|
17133
|
+
}
|
|
17134
|
+
}
|
|
17135
|
+
/**
|
|
17136
|
+
* v1 stage-2 match handling (SC4): annotate the unit's PR/issue with a "verify this
|
|
17137
|
+
* autonomous change" note so a human reviews every autonomous PR. Best-effort — a
|
|
17138
|
+
* missing tracker config / token / a failed comment never breaks completion (the
|
|
17139
|
+
* grade already recorded above). Mirrors `postLifecycleComment`'s adapter wiring.
|
|
17140
|
+
*/
|
|
17141
|
+
async annotateRetrospectiveMatch(issue, externalId, actualLevel) {
|
|
17142
|
+
try {
|
|
17143
|
+
const trackerConfig = (0, import_core17.loadTrackerSyncConfig)(this.projectRoot);
|
|
17144
|
+
if (!trackerConfig) return;
|
|
17145
|
+
const token = process.env.GITHUB_TOKEN;
|
|
17146
|
+
if (!token) return;
|
|
17147
|
+
const orchestratorId = await this.orchestratorIdPromise;
|
|
17148
|
+
const adapter = new import_core17.GitHubIssuesSyncAdapter({ token, config: trackerConfig });
|
|
17149
|
+
const body = [
|
|
17150
|
+
`**AI autonomous change \u2014 please verify** \`${orchestratorId}\``,
|
|
17151
|
+
"",
|
|
17152
|
+
"The post-diff retrospective classified this change WITHIN its pre-dispatch",
|
|
17153
|
+
`prediction (actual complexity: \`${actualLevel}\`). Under autonomy ratchet`,
|
|
17154
|
+
"stage 2, a human must verify every autonomous PR before it merges."
|
|
17155
|
+
].join("\n");
|
|
17156
|
+
const result = await adapter.addComment(externalId, body);
|
|
17157
|
+
if (!result.ok) {
|
|
17158
|
+
this.logger.warn(`amr retrospective annotation failed for ${issue.identifier}`, {
|
|
17159
|
+
error: result.error.message
|
|
17160
|
+
});
|
|
17161
|
+
}
|
|
17162
|
+
} catch (err) {
|
|
17163
|
+
this.logger.debug("amr retrospective annotation skipped (best-effort)", {
|
|
17164
|
+
issueId: issue.id,
|
|
17165
|
+
error: err instanceof Error ? err.message : String(err)
|
|
17166
|
+
});
|
|
17167
|
+
}
|
|
17168
|
+
}
|
|
16895
17169
|
/**
|
|
16896
17170
|
* Informs the state machine that an agent worker has exited.
|
|
16897
17171
|
*/
|
|
@@ -17978,6 +18252,333 @@ function launchTUI(orchestrator) {
|
|
|
17978
18252
|
return { waitUntilExit };
|
|
17979
18253
|
}
|
|
17980
18254
|
|
|
18255
|
+
// src/agent/triage-wiring.ts
|
|
18256
|
+
var import_graph3 = require("@harness-engineering/graph");
|
|
18257
|
+
var import_intelligence13 = require("@harness-engineering/intelligence");
|
|
18258
|
+
function buildProbeInput(issue) {
|
|
18259
|
+
const taskText = buildTaskText(issue);
|
|
18260
|
+
const combined = `${issue.title ?? ""}
|
|
18261
|
+
${issue.description ?? ""}`.trim();
|
|
18262
|
+
return {
|
|
18263
|
+
// An item lacking a stable externalId is not dispatch-eligible (proposal Assumptions);
|
|
18264
|
+
// we still probe it (read-only report), keyed by its identifier as a fallback.
|
|
18265
|
+
externalId: issue.externalId ?? issue.identifier ?? issue.id,
|
|
18266
|
+
taskText,
|
|
18267
|
+
entityCandidates: (0, import_intelligence13.extractEntities)(combined),
|
|
18268
|
+
labels: issue.labels ?? []
|
|
18269
|
+
};
|
|
18270
|
+
}
|
|
18271
|
+
function findNode(store, candidate) {
|
|
18272
|
+
const trimmed = candidate.trim();
|
|
18273
|
+
if (trimmed.length === 0) return null;
|
|
18274
|
+
const byName = store.findNodes({ name: trimmed });
|
|
18275
|
+
if (byName.length > 0) return byName[0] ?? null;
|
|
18276
|
+
const byPath = store.findNodes({ path: trimmed });
|
|
18277
|
+
if (byPath.length > 0) return byPath[0] ?? null;
|
|
18278
|
+
const byId = store.getNode(`file:${trimmed}`);
|
|
18279
|
+
if (byId) return byId;
|
|
18280
|
+
return null;
|
|
18281
|
+
}
|
|
18282
|
+
function makeGraphScope(store) {
|
|
18283
|
+
const simulator = new import_graph3.CascadeSimulator(store);
|
|
18284
|
+
return {
|
|
18285
|
+
resolve(candidate) {
|
|
18286
|
+
try {
|
|
18287
|
+
const node = findNode(store, candidate);
|
|
18288
|
+
if (!node) return null;
|
|
18289
|
+
const result = simulator.simulate(node.id);
|
|
18290
|
+
return {
|
|
18291
|
+
candidate,
|
|
18292
|
+
nodeId: node.id,
|
|
18293
|
+
blastRadius: result.summary.totalAffected
|
|
18294
|
+
};
|
|
18295
|
+
} catch {
|
|
18296
|
+
return null;
|
|
18297
|
+
}
|
|
18298
|
+
}
|
|
18299
|
+
};
|
|
18300
|
+
}
|
|
18301
|
+
async function triageIssue2(issue, deps = {}) {
|
|
18302
|
+
const input = buildProbeInput(issue);
|
|
18303
|
+
const graph = deps.graphStore ? makeGraphScope(deps.graphStore) : void 0;
|
|
18304
|
+
return (0, import_intelligence13.runScopingProbe)(input, {
|
|
18305
|
+
...deps.provider ? { provider: deps.provider } : {},
|
|
18306
|
+
...graph ? { graph } : {},
|
|
18307
|
+
...deps.precedent ? { precedent: deps.precedent } : {},
|
|
18308
|
+
...deps.config ? { config: deps.config } : {},
|
|
18309
|
+
...deps.models ? { models: deps.models } : {}
|
|
18310
|
+
});
|
|
18311
|
+
}
|
|
18312
|
+
|
|
18313
|
+
// src/agent/brainstorm-wiring.ts
|
|
18314
|
+
var fs16 = __toESM(require("fs"));
|
|
18315
|
+
var path22 = __toESM(require("path"));
|
|
18316
|
+
var import_zod18 = require("zod");
|
|
18317
|
+
var import_intelligence14 = require("@harness-engineering/intelligence");
|
|
18318
|
+
var ForkStepSchema = import_zod18.z.object({
|
|
18319
|
+
done: import_zod18.z.boolean().describe("true when there are no more design forks to decide"),
|
|
18320
|
+
forkId: import_zod18.z.string().describe('short stable id for this fork, e.g. "storage-backend"').optional(),
|
|
18321
|
+
question: import_zod18.z.string().describe("the design question this fork decides").optional(),
|
|
18322
|
+
options: import_zod18.z.array(import_zod18.z.string()).describe("the mutually-exclusive options considered").optional(),
|
|
18323
|
+
// The AUTHORITATIVE recommendation validity checks (non-empty AND one of `options`) live in
|
|
18324
|
+
// the GENERATOR, where `fork.options` is known and where a degenerate value must map to a
|
|
18325
|
+
// `confidence:'low'` DOWNGRADE (→ runner halts with reason 'low-confidence'), not a hard
|
|
18326
|
+
// schema/provider throw. We deliberately keep this `optional()`/unconstrained so an empty or
|
|
18327
|
+
// absent recommendation still reaches the generator's semantic gate rather than short-
|
|
18328
|
+
// circuiting to `halted{ reason:'error' }`. See makeSelForkGenerator's SAFETY GATE 2.
|
|
18329
|
+
recommendation: import_zod18.z.string().describe("the recommended option (one of options)").optional(),
|
|
18330
|
+
confidence: import_zod18.z.enum(["high", "medium", "low"]).describe("self-assessed confidence in the recommendation").optional(),
|
|
18331
|
+
rationale: import_zod18.z.string().describe("why this option").optional()
|
|
18332
|
+
});
|
|
18333
|
+
var BRAINSTORM_RUBRIC = 'You are running an AUTONOMOUS brainstorm over one backlog item: enumerate each design fork (a decision with mutually-exclusive options), then recommend a default for the NEXT unresolved fork with a self-assessed confidence. Report confidence HIGH only when the recommendation is clearly correct on technical grounds alone. Report LOW (so a human decides) whenever the fork involves ANY of: a product or UX tradeoff, an unrevealed business priority, a security-sensitive or irreversible/outward-facing action, or a genuine judgment call between comparable options. Never invent forks to pad the spec; set done=true once every real fork is resolved. Be conservative \u2014 a false "high" is far more costly than asking a human.';
|
|
18334
|
+
function makeSelForkGenerator(provider, input, opts = {}) {
|
|
18335
|
+
const samples = Math.max(2, opts.samples ?? 3);
|
|
18336
|
+
const maxTokens = opts.maxTokens ?? 512;
|
|
18337
|
+
return {
|
|
18338
|
+
async next(index, priorDecisions) {
|
|
18339
|
+
const prompt = buildForkPrompt(input, priorDecisions, index);
|
|
18340
|
+
const steps = [];
|
|
18341
|
+
for (let s = 0; s < samples; s++) {
|
|
18342
|
+
const { result } = await provider.analyze({
|
|
18343
|
+
prompt,
|
|
18344
|
+
systemPrompt: BRAINSTORM_RUBRIC,
|
|
18345
|
+
responseSchema: ForkStepSchema,
|
|
18346
|
+
maxTokens,
|
|
18347
|
+
...opts.model !== void 0 ? { model: opts.model } : {}
|
|
18348
|
+
});
|
|
18349
|
+
steps.push(result);
|
|
18350
|
+
}
|
|
18351
|
+
if (steps.some((st) => st.done)) return null;
|
|
18352
|
+
const first = steps[0];
|
|
18353
|
+
if (!first) return null;
|
|
18354
|
+
const fork = {
|
|
18355
|
+
id: first.forkId ?? `fork-${index}`,
|
|
18356
|
+
question: first.question ?? "unspecified fork",
|
|
18357
|
+
options: first.options ?? []
|
|
18358
|
+
};
|
|
18359
|
+
const recommendation = first.recommendation ?? "";
|
|
18360
|
+
const normQ = (q) => (q ?? "").trim().toLowerCase();
|
|
18361
|
+
const firstForkId = first.forkId ?? "";
|
|
18362
|
+
const firstQuestion = normQ(first.question);
|
|
18363
|
+
const identityStable = steps.every(
|
|
18364
|
+
(st) => (st.forkId ?? "") === firstForkId && normQ(st.question) === firstQuestion
|
|
18365
|
+
);
|
|
18366
|
+
const recStable = steps.every((st) => (st.recommendation ?? "") === recommendation);
|
|
18367
|
+
const recEmpty = recommendation.trim() === "";
|
|
18368
|
+
const recNotAnOption = !recEmpty && fork.options.length > 0 && !fork.options.includes(recommendation);
|
|
18369
|
+
const stable = identityStable && recStable && !recEmpty && !recNotAnOption;
|
|
18370
|
+
const reported = first.confidence ?? "low";
|
|
18371
|
+
const confidence = stable ? reported : "low";
|
|
18372
|
+
let downgradeReason = "";
|
|
18373
|
+
if (!identityStable) {
|
|
18374
|
+
downgradeReason = `fork identity drift across ${samples} samples (self-consistency downgrade to low): ` + steps.map((st) => `${st.forkId ?? "\u2205"}:"${(st.question ?? "\u2205").trim()}"`).join(" / ");
|
|
18375
|
+
} else if (recEmpty) {
|
|
18376
|
+
downgradeReason = "recommendation was empty/absent (a content-free recommendation is not a confident decision; downgrade to low)";
|
|
18377
|
+
} else if (recNotAnOption) {
|
|
18378
|
+
downgradeReason = `recommendation '${recommendation}' is not one of the offered options [${fork.options.join(", ")}] (downgrade to low)`;
|
|
18379
|
+
} else if (!recStable) {
|
|
18380
|
+
downgradeReason = `recommendation was unstable across ${samples} samples (self-consistency downgrade to low): ` + steps.map((st) => st.recommendation ?? "\u2205").join(" / ");
|
|
18381
|
+
}
|
|
18382
|
+
return {
|
|
18383
|
+
fork,
|
|
18384
|
+
recommendation,
|
|
18385
|
+
confidence,
|
|
18386
|
+
rationale: stable ? first.rationale ?? "" : downgradeReason
|
|
18387
|
+
};
|
|
18388
|
+
}
|
|
18389
|
+
};
|
|
18390
|
+
}
|
|
18391
|
+
function buildForkPrompt(input, priorDecisions, index) {
|
|
18392
|
+
const resolved = priorDecisions.length === 0 ? "(none yet)" : priorDecisions.map((d, i) => `${i + 1}. ${d.fork.question} \u2192 ${d.recommendation}`).join("\n");
|
|
18393
|
+
return `Item: ${input.title}
|
|
18394
|
+
Summary: ${input.summary}
|
|
18395
|
+
Complexity: ${input.level}
|
|
18396
|
+
|
|
18397
|
+
Forks already resolved:
|
|
18398
|
+
${resolved}
|
|
18399
|
+
|
|
18400
|
+
Decide fork #${index + 1}: the NEXT unresolved design fork. If every real fork is already resolved, return { "done": true }.`;
|
|
18401
|
+
}
|
|
18402
|
+
function brainstormInputFromIssue(issue, level) {
|
|
18403
|
+
return {
|
|
18404
|
+
externalId: issue.externalId ?? issue.identifier ?? issue.id,
|
|
18405
|
+
title: issue.title ?? issue.identifier ?? issue.id,
|
|
18406
|
+
summary: issue.description ?? "",
|
|
18407
|
+
level
|
|
18408
|
+
};
|
|
18409
|
+
}
|
|
18410
|
+
async function runBrainstormForIssue(issue, level, deps) {
|
|
18411
|
+
const input = brainstormInputFromIssue(issue, level);
|
|
18412
|
+
const generator = deps.generator ?? (deps.provider ? makeSelForkGenerator(deps.provider, input, deps.generatorOptions ?? {}) : void 0);
|
|
18413
|
+
if (!generator) {
|
|
18414
|
+
return {
|
|
18415
|
+
outcome: {
|
|
18416
|
+
kind: "halted",
|
|
18417
|
+
fork: { id: "no-generator", question: "no fork generator or provider wired", options: [] },
|
|
18418
|
+
reason: "error",
|
|
18419
|
+
detail: "runBrainstormForIssue requires either an injected generator or a SEL provider"
|
|
18420
|
+
}
|
|
18421
|
+
};
|
|
18422
|
+
}
|
|
18423
|
+
const depth = (0, import_intelligence14.depthForLevel)(level);
|
|
18424
|
+
const outcome = await (0, import_intelligence14.runAutoBrainstorm)(input, generator, depth);
|
|
18425
|
+
if (outcome.kind !== "completed") {
|
|
18426
|
+
return { outcome };
|
|
18427
|
+
}
|
|
18428
|
+
const result = { outcome };
|
|
18429
|
+
if (deps.docsRoot) {
|
|
18430
|
+
try {
|
|
18431
|
+
result.specPath = writeSpecDoc(deps.docsRoot, outcome.spec);
|
|
18432
|
+
} catch {
|
|
18433
|
+
}
|
|
18434
|
+
}
|
|
18435
|
+
if (deps.rescore) {
|
|
18436
|
+
try {
|
|
18437
|
+
const enrichedIssue = enrichIssueWithSpec(issue, outcome.spec);
|
|
18438
|
+
result.rescore = await triageIssue2(enrichedIssue, {
|
|
18439
|
+
...deps.rescore.graphStore ? { graphStore: deps.rescore.graphStore } : {},
|
|
18440
|
+
...deps.rescore.provider ? { provider: deps.rescore.provider } : {},
|
|
18441
|
+
...deps.rescore.precedent ? { precedent: deps.rescore.precedent } : {},
|
|
18442
|
+
...deps.rescore.config ? { config: deps.rescore.config } : {},
|
|
18443
|
+
...deps.rescore.models ? { models: deps.rescore.models } : {}
|
|
18444
|
+
});
|
|
18445
|
+
} catch {
|
|
18446
|
+
}
|
|
18447
|
+
}
|
|
18448
|
+
return result;
|
|
18449
|
+
}
|
|
18450
|
+
function slugFor(spec) {
|
|
18451
|
+
const base = spec.title || spec.externalId;
|
|
18452
|
+
return base.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "item";
|
|
18453
|
+
}
|
|
18454
|
+
function renderSpecMarkdown(spec) {
|
|
18455
|
+
const lines = [];
|
|
18456
|
+
lines.push(`# ${spec.title}`);
|
|
18457
|
+
lines.push("");
|
|
18458
|
+
lines.push("Status: **Auto-drafted (autonomous brainstorm \u2014 awaiting human review)**");
|
|
18459
|
+
lines.push("");
|
|
18460
|
+
lines.push(`Item: \`${spec.externalId}\``);
|
|
18461
|
+
lines.push("");
|
|
18462
|
+
lines.push("## Summary");
|
|
18463
|
+
lines.push("");
|
|
18464
|
+
lines.push(spec.summary || "_No summary provided._");
|
|
18465
|
+
lines.push("");
|
|
18466
|
+
lines.push("## Design decisions");
|
|
18467
|
+
lines.push("");
|
|
18468
|
+
if (spec.decisions.length === 0) {
|
|
18469
|
+
lines.push("_No forks required a decision \u2014 the item was unambiguous._");
|
|
18470
|
+
} else {
|
|
18471
|
+
for (const [i, d] of spec.decisions.entries()) {
|
|
18472
|
+
lines.push(`### ${i + 1}. ${d.fork.question}`);
|
|
18473
|
+
lines.push("");
|
|
18474
|
+
if (d.fork.options.length > 0) {
|
|
18475
|
+
lines.push(`Options considered: ${d.fork.options.map((o) => `\`${o}\``).join(", ")}`);
|
|
18476
|
+
lines.push("");
|
|
18477
|
+
}
|
|
18478
|
+
lines.push(`**Recommendation:** ${d.recommendation} (confidence: ${d.confidence})`);
|
|
18479
|
+
lines.push("");
|
|
18480
|
+
if (d.rationale) {
|
|
18481
|
+
lines.push(d.rationale);
|
|
18482
|
+
lines.push("");
|
|
18483
|
+
}
|
|
18484
|
+
}
|
|
18485
|
+
}
|
|
18486
|
+
lines.push("---");
|
|
18487
|
+
lines.push("");
|
|
18488
|
+
lines.push(
|
|
18489
|
+
"_This spec was drafted autonomously. Every fork above cleared the high-confidence bar; any fork the system could not confidently resolve would have halted the brainstorm and handed that fork to a human instead._"
|
|
18490
|
+
);
|
|
18491
|
+
lines.push("");
|
|
18492
|
+
return lines.join("\n");
|
|
18493
|
+
}
|
|
18494
|
+
function writeSpecDoc(docsRoot, spec) {
|
|
18495
|
+
const dir = path22.join(docsRoot, "changes", slugFor(spec));
|
|
18496
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
18497
|
+
const file = path22.join(dir, "proposal.md");
|
|
18498
|
+
fs16.writeFileSync(file, renderSpecMarkdown(spec), "utf-8");
|
|
18499
|
+
return file;
|
|
18500
|
+
}
|
|
18501
|
+
function enrichIssueWithSpec(issue, spec) {
|
|
18502
|
+
const decisionText = spec.decisions.map((d) => `${d.fork.question} \u2192 ${d.recommendation}. ${d.rationale}`).join("\n");
|
|
18503
|
+
const enrichedDescription = [issue.description ?? "", decisionText].filter(Boolean).join("\n\n");
|
|
18504
|
+
return {
|
|
18505
|
+
...issue,
|
|
18506
|
+
description: enrichedDescription,
|
|
18507
|
+
// The item now HAS a drafted spec — reflect it so the re-score's spec-exists signal is true.
|
|
18508
|
+
spec: issue.spec ?? `changes/${slugFor(spec)}/proposal.md`
|
|
18509
|
+
};
|
|
18510
|
+
}
|
|
18511
|
+
|
|
18512
|
+
// src/agent/triage-mark.ts
|
|
18513
|
+
var import_core20 = require("@harness-engineering/core");
|
|
18514
|
+
var import_intelligence15 = require("@harness-engineering/intelligence");
|
|
18515
|
+
var ELIGIBLE_STATUS = "planned";
|
|
18516
|
+
async function markApprovedForDispatch(items, deps) {
|
|
18517
|
+
const { store, config, recordPrediction, selfAssignee } = deps;
|
|
18518
|
+
if (!config.enabled) {
|
|
18519
|
+
return { ok: true, value: { marked: [], skipped: [] } };
|
|
18520
|
+
}
|
|
18521
|
+
const loaded = await store.load();
|
|
18522
|
+
if (!loaded.ok) return { ok: false, error: loaded.error };
|
|
18523
|
+
const bySlug = /* @__PURE__ */ new Map();
|
|
18524
|
+
for (const m of loaded.value.milestones) {
|
|
18525
|
+
for (const f of m.features) bySlug.set((0, import_core20.slugifyFeatureName)(f.name), f);
|
|
18526
|
+
}
|
|
18527
|
+
const marked = [];
|
|
18528
|
+
const skipped = [];
|
|
18529
|
+
for (const it of items) {
|
|
18530
|
+
const externalId = it.candidate.externalId;
|
|
18531
|
+
if (!it.candidate.humanApproved) {
|
|
18532
|
+
skipped.push({ externalId, reason: "not-approved" });
|
|
18533
|
+
continue;
|
|
18534
|
+
}
|
|
18535
|
+
const slug = (0, import_core20.slugifyFeatureName)(it.featureName);
|
|
18536
|
+
const target = bySlug.get(slug);
|
|
18537
|
+
if (!target) {
|
|
18538
|
+
skipped.push({ externalId, reason: "feature-not-found" });
|
|
18539
|
+
continue;
|
|
18540
|
+
}
|
|
18541
|
+
if (selfAssignee !== void 0 && target.assignee != null && target.assignee !== selfAssignee) {
|
|
18542
|
+
skipped.push({ externalId, reason: "assigned-elsewhere" });
|
|
18543
|
+
continue;
|
|
18544
|
+
}
|
|
18545
|
+
const mutate = (f) => ({
|
|
18546
|
+
...f,
|
|
18547
|
+
spec: it.specPath,
|
|
18548
|
+
status: isActiveStatus(f.status) ? f.status : ELIGIBLE_STATUS
|
|
18549
|
+
});
|
|
18550
|
+
const patched = await store.patchFeature(slug, mutate);
|
|
18551
|
+
if (!patched.ok) return { ok: false, error: patched.error };
|
|
18552
|
+
const key = (0, import_intelligence15.dispatchableShapeKey)(it.labels, it.verdict.level);
|
|
18553
|
+
const prediction = {
|
|
18554
|
+
externalId,
|
|
18555
|
+
shapeKey: key,
|
|
18556
|
+
verdict: it.verdict,
|
|
18557
|
+
// `levers` is an OPAQUE DIAGNOSTIC SNAPSHOT (the verdict's static signals), NOT the
|
|
18558
|
+
// typed ProbeLevers. The Phase-4 comparator grades on `verdict.level` +
|
|
18559
|
+
// `scopeEstimate` ONLY (see retrospective.ts) and never reads `levers`, so this
|
|
18560
|
+
// human-legible signal dump cannot mislead the grade. The full typed ProbeLevers
|
|
18561
|
+
// are not threaded here on purpose (it would balloon ReadyCandidate→marker for a
|
|
18562
|
+
// field nothing downstream consumes); `record.ts` re-documents the field to match.
|
|
18563
|
+
levers: it.verdict.signals,
|
|
18564
|
+
scopeEstimate: it.scopeEstimate,
|
|
18565
|
+
// Prefer the per-shape evidence-derived stage (SC6) when the caller resolved one;
|
|
18566
|
+
// fall back to the uniform config stage (Phase-3 behavior). Cold-start ⇒ the caller
|
|
18567
|
+
// resolves stage 1, so this is byte-identical to `config.ratchetStage` at cold-start.
|
|
18568
|
+
ratchetStage: it.effectiveStage ?? config.ratchetStage
|
|
18569
|
+
};
|
|
18570
|
+
const recorded = await recordPrediction(prediction);
|
|
18571
|
+
if (!recorded.ok) {
|
|
18572
|
+
return { ok: false, error: recorded.error ?? new Error("recordPrediction failed") };
|
|
18573
|
+
}
|
|
18574
|
+
marked.push(externalId);
|
|
18575
|
+
}
|
|
18576
|
+
return { ok: true, value: { marked, skipped } };
|
|
18577
|
+
}
|
|
18578
|
+
function isActiveStatus(status) {
|
|
18579
|
+
return status === "planned" || status === "in-progress";
|
|
18580
|
+
}
|
|
18581
|
+
|
|
17981
18582
|
// src/maintenance/sync-main.ts
|
|
17982
18583
|
var import_node_child_process14 = require("child_process");
|
|
17983
18584
|
var import_node_util5 = require("util");
|
|
@@ -18171,8 +18772,8 @@ function selectTasks(tasks, history, filter) {
|
|
|
18171
18772
|
}
|
|
18172
18773
|
|
|
18173
18774
|
// src/sessions/search-index.ts
|
|
18174
|
-
var
|
|
18175
|
-
var
|
|
18775
|
+
var fs17 = __toESM(require("fs"));
|
|
18776
|
+
var path23 = __toESM(require("path"));
|
|
18176
18777
|
var import_better_sqlite32 = __toESM(require("better-sqlite3"));
|
|
18177
18778
|
var import_types35 = require("@harness-engineering/types");
|
|
18178
18779
|
var SEARCH_INDEX_FILE = "search-index.sqlite";
|
|
@@ -18217,7 +18818,7 @@ function normalizeFts5Query(query) {
|
|
|
18217
18818
|
return query.split(/\s+/).filter((tok) => tok.length > 0).map((tok) => `"${tok.replace(/"/g, '""')}"`).join(" ");
|
|
18218
18819
|
}
|
|
18219
18820
|
function searchIndexPath(projectPath) {
|
|
18220
|
-
return
|
|
18821
|
+
return path23.join(projectPath, ".harness", SEARCH_INDEX_FILE);
|
|
18221
18822
|
}
|
|
18222
18823
|
var FILE_KIND_TO_FILENAME = {
|
|
18223
18824
|
summary: "summary.md",
|
|
@@ -18232,7 +18833,7 @@ var SqliteSearchIndex = class {
|
|
|
18232
18833
|
removeSessionStmt;
|
|
18233
18834
|
totalStmt;
|
|
18234
18835
|
constructor(dbPath) {
|
|
18235
|
-
|
|
18836
|
+
fs17.mkdirSync(path23.dirname(dbPath), { recursive: true });
|
|
18236
18837
|
this.db = new import_better_sqlite32.default(dbPath);
|
|
18237
18838
|
this.db.pragma("journal_mode = WAL");
|
|
18238
18839
|
this.db.pragma("synchronous = NORMAL");
|
|
@@ -18337,14 +18938,14 @@ function indexSessionDirectory(idx, args) {
|
|
|
18337
18938
|
let docsWritten = 0;
|
|
18338
18939
|
for (const kind of kinds) {
|
|
18339
18940
|
const fileName = FILE_KIND_TO_FILENAME[kind];
|
|
18340
|
-
const filePath =
|
|
18341
|
-
if (!
|
|
18342
|
-
let body =
|
|
18941
|
+
const filePath = path23.join(args.sessionDir, fileName);
|
|
18942
|
+
if (!fs17.existsSync(filePath)) continue;
|
|
18943
|
+
let body = fs17.readFileSync(filePath, "utf8");
|
|
18343
18944
|
if (Buffer.byteLength(body, "utf8") > cap) {
|
|
18344
18945
|
body = body.slice(0, cap) + "\n\n[TRUNCATED]";
|
|
18345
18946
|
}
|
|
18346
|
-
const stat =
|
|
18347
|
-
const relPath =
|
|
18947
|
+
const stat = fs17.statSync(filePath);
|
|
18948
|
+
const relPath = path23.relative(args.projectPath, filePath).replaceAll("\\", "/");
|
|
18348
18949
|
idx.upsertSessionDoc({
|
|
18349
18950
|
sessionId: args.sessionId,
|
|
18350
18951
|
archived: args.archived,
|
|
@@ -18359,17 +18960,17 @@ function indexSessionDirectory(idx, args) {
|
|
|
18359
18960
|
}
|
|
18360
18961
|
function reindexFromArchive(projectPath, opts = {}) {
|
|
18361
18962
|
const start = Date.now();
|
|
18362
|
-
const archiveBase =
|
|
18963
|
+
const archiveBase = path23.join(projectPath, ".harness", "archive", "sessions");
|
|
18363
18964
|
const idx = openSearchIndex(projectPath);
|
|
18364
18965
|
try {
|
|
18365
18966
|
idx.resetArchived();
|
|
18366
18967
|
let sessionsIndexed = 0;
|
|
18367
18968
|
let docsWritten = 0;
|
|
18368
|
-
if (
|
|
18369
|
-
const entries =
|
|
18969
|
+
if (fs17.existsSync(archiveBase)) {
|
|
18970
|
+
const entries = fs17.readdirSync(archiveBase, { withFileTypes: true });
|
|
18370
18971
|
for (const entry of entries) {
|
|
18371
18972
|
if (!entry.isDirectory()) continue;
|
|
18372
|
-
const sessionDir =
|
|
18973
|
+
const sessionDir = path23.join(archiveBase, entry.name);
|
|
18373
18974
|
const result = indexSessionDirectory(idx, {
|
|
18374
18975
|
sessionId: entry.name,
|
|
18375
18976
|
sessionDir,
|
|
@@ -18389,8 +18990,8 @@ function reindexFromArchive(projectPath, opts = {}) {
|
|
|
18389
18990
|
}
|
|
18390
18991
|
|
|
18391
18992
|
// src/sessions/summarize.ts
|
|
18392
|
-
var
|
|
18393
|
-
var
|
|
18993
|
+
var fs18 = __toESM(require("fs"));
|
|
18994
|
+
var path24 = __toESM(require("path"));
|
|
18394
18995
|
var import_types36 = require("@harness-engineering/types");
|
|
18395
18996
|
var import_types37 = require("@harness-engineering/types");
|
|
18396
18997
|
var LLM_SUMMARY_FILE = "llm-summary.md";
|
|
@@ -18418,10 +19019,10 @@ var USER_PROMPT_PREAMBLE = `Below are the archived files for a single harness-en
|
|
|
18418
19019
|
function readInputCorpus(archiveDir) {
|
|
18419
19020
|
const parts = [];
|
|
18420
19021
|
for (const { filename, kind } of SUMMARY_INPUT_FILES) {
|
|
18421
|
-
const p =
|
|
18422
|
-
if (!
|
|
19022
|
+
const p = path24.join(archiveDir, filename);
|
|
19023
|
+
if (!fs18.existsSync(p)) continue;
|
|
18423
19024
|
try {
|
|
18424
|
-
const content =
|
|
19025
|
+
const content = fs18.readFileSync(p, "utf8");
|
|
18425
19026
|
if (content.trim().length === 0) continue;
|
|
18426
19027
|
parts.push(`## FILE: ${kind}
|
|
18427
19028
|
|
|
@@ -18472,7 +19073,7 @@ function renderLlmSummaryMarkdown(summary, meta) {
|
|
|
18472
19073
|
return lines.join("\n");
|
|
18473
19074
|
}
|
|
18474
19075
|
function writeStubMarkdown(archiveDir, reason) {
|
|
18475
|
-
const filePath =
|
|
19076
|
+
const filePath = path24.join(archiveDir, LLM_SUMMARY_FILE);
|
|
18476
19077
|
const body = `---
|
|
18477
19078
|
generatedAt: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
18478
19079
|
schemaVersion: 1
|
|
@@ -18483,12 +19084,12 @@ status: failed
|
|
|
18483
19084
|
|
|
18484
19085
|
- reason: ${reason}
|
|
18485
19086
|
`;
|
|
18486
|
-
|
|
19087
|
+
fs18.writeFileSync(filePath, body, "utf8");
|
|
18487
19088
|
return filePath;
|
|
18488
19089
|
}
|
|
18489
19090
|
async function summarizeArchivedSession(ctx) {
|
|
18490
19091
|
const writeStubOnError = ctx.writeStubOnError ?? true;
|
|
18491
|
-
if (!
|
|
19092
|
+
if (!fs18.existsSync(ctx.archiveDir)) {
|
|
18492
19093
|
return (0, import_types37.Err)(new Error(`archive directory not found: ${ctx.archiveDir}`));
|
|
18493
19094
|
}
|
|
18494
19095
|
const corpus = readInputCorpus(ctx.archiveDir);
|
|
@@ -18549,9 +19150,9 @@ async function summarizeArchivedSession(ctx) {
|
|
|
18549
19150
|
outputTokens: response.tokenUsage.outputTokens,
|
|
18550
19151
|
schemaVersion: 1
|
|
18551
19152
|
};
|
|
18552
|
-
const filePath =
|
|
19153
|
+
const filePath = path24.join(ctx.archiveDir, LLM_SUMMARY_FILE);
|
|
18553
19154
|
const body = renderLlmSummaryMarkdown(parsed.data, meta);
|
|
18554
|
-
|
|
19155
|
+
fs18.writeFileSync(filePath, body, "utf8");
|
|
18555
19156
|
return (0, import_types37.Ok)({ summary: parsed.data, meta, filePath });
|
|
18556
19157
|
}
|
|
18557
19158
|
function isSummaryEnabled(config) {
|
|
@@ -18633,6 +19234,7 @@ var import_local_models7 = require("@harness-engineering/local-models");
|
|
|
18633
19234
|
0 && (module.exports = {
|
|
18634
19235
|
AdaptiveRouter,
|
|
18635
19236
|
AnalysisArchive,
|
|
19237
|
+
BRAINSTORM_RUBRIC,
|
|
18636
19238
|
BUILT_IN_TASKS,
|
|
18637
19239
|
BackendDefSchema,
|
|
18638
19240
|
BackendRouter,
|
|
@@ -18675,8 +19277,10 @@ var import_local_models7 = require("@harness-engineering/local-models");
|
|
|
18675
19277
|
WorkspaceManager,
|
|
18676
19278
|
applyEvent,
|
|
18677
19279
|
artifactPresenceFromIssue,
|
|
19280
|
+
brainstormInputFromIssue,
|
|
18678
19281
|
buildArchiveHooks,
|
|
18679
19282
|
buildCapabilityRegistry,
|
|
19283
|
+
buildProbeInput,
|
|
18680
19284
|
buildWorkflowContext,
|
|
18681
19285
|
calculateRetryDelay,
|
|
18682
19286
|
canDispatch,
|
|
@@ -18696,6 +19300,7 @@ var import_local_models7 = require("@harness-engineering/local-models");
|
|
|
18696
19300
|
emitProposalApproved,
|
|
18697
19301
|
emitProposalCreated,
|
|
18698
19302
|
emitProposalRejected,
|
|
19303
|
+
enrichIssueWithSpec,
|
|
18699
19304
|
estimateCost,
|
|
18700
19305
|
explicitFindingsCount,
|
|
18701
19306
|
extractHighlights,
|
|
@@ -18710,22 +19315,30 @@ var import_local_models7 = require("@harness-engineering/local-models");
|
|
|
18710
19315
|
launchTUI,
|
|
18711
19316
|
loadPublishedIndex,
|
|
18712
19317
|
makeBackendResolver,
|
|
19318
|
+
makeGraphScope,
|
|
19319
|
+
makeSelForkGenerator,
|
|
19320
|
+
markApprovedForDispatch,
|
|
18713
19321
|
migrateAgentConfig,
|
|
18714
19322
|
normalizeFts5Query,
|
|
18715
19323
|
normalizeHarnessCommand,
|
|
18716
19324
|
normalizeLocalModel,
|
|
18717
19325
|
openSearchIndex,
|
|
19326
|
+
pilotScore,
|
|
19327
|
+
precedentLookupFromStored,
|
|
18718
19328
|
promote,
|
|
19329
|
+
rankTriageCandidates,
|
|
18719
19330
|
reconcile,
|
|
18720
19331
|
recoverFindingsCount,
|
|
18721
19332
|
reindexFromArchive,
|
|
18722
19333
|
renderAnalysisComment,
|
|
18723
19334
|
renderLlmSummaryMarkdown,
|
|
18724
19335
|
renderPRComment,
|
|
19336
|
+
renderSpecMarkdown,
|
|
18725
19337
|
resolveEscalationConfig,
|
|
18726
19338
|
resolveOrchestratorId,
|
|
18727
19339
|
routeIssue,
|
|
18728
19340
|
routingWarnings,
|
|
19341
|
+
runBrainstormForIssue,
|
|
18729
19342
|
runGate,
|
|
18730
19343
|
runHarnessCheck,
|
|
18731
19344
|
savePublishedIndex,
|
|
@@ -18733,6 +19346,7 @@ var import_local_models7 = require("@harness-engineering/local-models");
|
|
|
18733
19346
|
selectCandidates,
|
|
18734
19347
|
selectCheapestQualifying,
|
|
18735
19348
|
selectTasks,
|
|
19349
|
+
slugFor,
|
|
18736
19350
|
sortCandidates,
|
|
18737
19351
|
summarizeArchivedSession,
|
|
18738
19352
|
syncMain,
|