@alan512/experienceengine 0.3.4 → 0.3.5
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/.mcp.json +11 -11
- package/README.md +8 -0
- package/README.zh-CN.md +8 -0
- package/dist/adapters/codex/action-registry.d.ts +3 -0
- package/dist/adapters/codex/action-registry.js +22 -0
- package/dist/adapters/codex/action-registry.js.map +1 -1
- package/dist/adapters/codex/broker-tools.d.ts +6 -0
- package/dist/adapters/codex/broker-tools.js +7 -1
- package/dist/adapters/codex/broker-tools.js.map +1 -1
- package/dist/adapters/codex/mcp-server.js +30 -0
- package/dist/adapters/codex/mcp-server.js.map +1 -1
- package/dist/cli/commands/inspect.js +41 -6
- package/dist/cli/commands/inspect.js.map +1 -1
- package/dist/cli/dispatch.js +11 -13
- package/dist/cli/dispatch.js.map +1 -1
- package/dist/install/openclaw-cli.d.ts +2 -0
- package/dist/install/openclaw-cli.js +5 -0
- package/dist/install/openclaw-cli.js.map +1 -1
- package/dist/install/openclaw-installer.js +65 -6
- package/dist/install/openclaw-installer.js.map +1 -1
- package/dist/interaction/quality-band.d.ts +30 -0
- package/dist/interaction/quality-band.js +149 -0
- package/dist/interaction/quality-band.js.map +1 -0
- package/dist/interaction/repo-summary.d.ts +3 -0
- package/dist/interaction/repo-summary.js +1 -0
- package/dist/interaction/repo-summary.js.map +1 -1
- package/dist/interaction/service.d.ts +3 -0
- package/dist/interaction/service.js +63 -81
- package/dist/interaction/service.js.map +1 -1
- package/dist/interaction/surface-tiers.d.ts +8 -0
- package/dist/interaction/surface-tiers.js +19 -0
- package/dist/interaction/surface-tiers.js.map +1 -0
- package/docs/releases/v0.3.5.md +42 -0
- package/docs/user-guide.md +30 -3
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
export const deriveNodeRisk = (node) => {
|
|
2
|
+
if (node.state === "candidate") {
|
|
3
|
+
return "high";
|
|
4
|
+
}
|
|
5
|
+
if (node.state === "priority_candidate") {
|
|
6
|
+
return "medium";
|
|
7
|
+
}
|
|
8
|
+
if (node.state === "cooling" || node.harmed_count > 0 || node.node_type === "warning") {
|
|
9
|
+
return node.harmed_count > node.helped_count ? "high" : "medium";
|
|
10
|
+
}
|
|
11
|
+
return "low";
|
|
12
|
+
};
|
|
13
|
+
export const deriveNodeConfidence = (node) => {
|
|
14
|
+
if (node.validation_state === "validated_by_reuse" && node.state === "active" && node.harmed_count === 0) {
|
|
15
|
+
return "high";
|
|
16
|
+
}
|
|
17
|
+
if (node.state === "candidate" || node.harmed_count > node.helped_count) {
|
|
18
|
+
return "low";
|
|
19
|
+
}
|
|
20
|
+
return "medium";
|
|
21
|
+
};
|
|
22
|
+
const firstUnique = (items) => [...new Set(items)];
|
|
23
|
+
const buildEvidenceRefs = (node) => [
|
|
24
|
+
{ kind: "node", id: node.id },
|
|
25
|
+
...node.origin_record_ids.map((id) => ({ kind: "origin_record", id })),
|
|
26
|
+
...node.helped_record_ids.map((id) => ({ kind: "helped_record", id })),
|
|
27
|
+
...node.harmed_record_ids.map((id) => ({ kind: "harmed_record", id }))
|
|
28
|
+
];
|
|
29
|
+
const actionForBand = (node, band) => {
|
|
30
|
+
if (band === "risky") {
|
|
31
|
+
return {
|
|
32
|
+
label: "Review this node before trusting it in live guidance.",
|
|
33
|
+
command: `ee inspect node ${node.id}`
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (band === "building") {
|
|
37
|
+
return {
|
|
38
|
+
label: "Use as tentative guidance and keep collecting outcome evidence.",
|
|
39
|
+
command: `ee inspect node ${node.id}`
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
};
|
|
44
|
+
export const deriveQualityBandExplanation = (node) => {
|
|
45
|
+
const reasonCodes = [];
|
|
46
|
+
const reasons = [];
|
|
47
|
+
const isHighHygieneRisk = node.delivery_state === "quarantined" || Boolean(node.quarantined_at);
|
|
48
|
+
const harmOutweighsHelp = node.harmed_count > node.helped_count;
|
|
49
|
+
let band = "building";
|
|
50
|
+
if (node.state === "retired" ||
|
|
51
|
+
node.state === "cooling" ||
|
|
52
|
+
node.validation_state === "invalidated" ||
|
|
53
|
+
harmOutweighsHelp ||
|
|
54
|
+
isHighHygieneRisk) {
|
|
55
|
+
band = "risky";
|
|
56
|
+
}
|
|
57
|
+
else if (node.state === "active" &&
|
|
58
|
+
node.validation_state === "validated_by_reuse" &&
|
|
59
|
+
node.harmed_count === 0 &&
|
|
60
|
+
(!node.delivery_state || node.delivery_state === "eligible")) {
|
|
61
|
+
band = "strong";
|
|
62
|
+
}
|
|
63
|
+
if (node.state === "active" && (!node.delivery_state || node.delivery_state === "eligible")) {
|
|
64
|
+
reasonCodes.push("active_eligible");
|
|
65
|
+
reasons.push("This node is active and eligible for normal delivery.");
|
|
66
|
+
}
|
|
67
|
+
if (node.validation_state === "validated_by_reuse") {
|
|
68
|
+
reasonCodes.push("validated_by_reuse");
|
|
69
|
+
reasons.push("This node has already been validated by successful reuse.");
|
|
70
|
+
}
|
|
71
|
+
if (node.helped_count > 0 && node.harmed_count === 0) {
|
|
72
|
+
reasonCodes.push("helped_without_harm");
|
|
73
|
+
reasons.push("Helpful outcomes exist and no harmful outcome has been recorded for this node.");
|
|
74
|
+
}
|
|
75
|
+
if (node.helped_count === 0 && node.harmed_count === 0) {
|
|
76
|
+
reasonCodes.push("limited_reuse_evidence");
|
|
77
|
+
reasons.push("This node still has limited reuse evidence.");
|
|
78
|
+
}
|
|
79
|
+
if (node.state === "candidate" || node.state === "priority_candidate") {
|
|
80
|
+
reasonCodes.push("early_lifecycle");
|
|
81
|
+
reasons.push("This node is still early in its lifecycle and needs more runtime evidence.");
|
|
82
|
+
}
|
|
83
|
+
if (node.delivery_state === "conservative_only") {
|
|
84
|
+
reasonCodes.push("conservative_only");
|
|
85
|
+
reasons.push("Delivery governance limits this node to conservative use.");
|
|
86
|
+
}
|
|
87
|
+
if (node.delivery_state === "shadow_only") {
|
|
88
|
+
reasonCodes.push("shadow_only");
|
|
89
|
+
reasons.push("Delivery governance keeps this node in shadow-only observation.");
|
|
90
|
+
}
|
|
91
|
+
if (node.state === "retired") {
|
|
92
|
+
reasonCodes.push("retired");
|
|
93
|
+
reasons.push("This node is retired and should not be reused without review.");
|
|
94
|
+
}
|
|
95
|
+
if (node.state === "cooling") {
|
|
96
|
+
reasonCodes.push("cooling");
|
|
97
|
+
reasons.push("This node is in cooling state because recent runtime evidence weakened confidence.");
|
|
98
|
+
}
|
|
99
|
+
if (harmOutweighsHelp) {
|
|
100
|
+
reasonCodes.push("harm_outweighs_help");
|
|
101
|
+
reasons.push("Harmful outcomes currently outweigh helpful ones for this node.");
|
|
102
|
+
}
|
|
103
|
+
else if (node.helped_count > node.harmed_count) {
|
|
104
|
+
reasons.push("Helpful outcomes still outweigh harmful ones for this node.");
|
|
105
|
+
}
|
|
106
|
+
if (node.delivery_state === "quarantined") {
|
|
107
|
+
reasonCodes.push("quarantined");
|
|
108
|
+
reasons.push(node.quarantine_reason ?? "Delivery governance has quarantined this node.");
|
|
109
|
+
}
|
|
110
|
+
if (isHighHygieneRisk) {
|
|
111
|
+
reasonCodes.push("high_hygiene_risk");
|
|
112
|
+
}
|
|
113
|
+
if (node.node_type === "warning") {
|
|
114
|
+
reasonCodes.push("warning_guidance");
|
|
115
|
+
reasons.push("This is warning guidance, so reuse should stay narrow and evidence-led.");
|
|
116
|
+
}
|
|
117
|
+
if (node.validation_state === "invalidated") {
|
|
118
|
+
reasonCodes.push("invalidated");
|
|
119
|
+
reasons.push("Reuse validation has invalidated this node.");
|
|
120
|
+
}
|
|
121
|
+
const summary = band === "strong"
|
|
122
|
+
? "Strong guidance: active, reuse-validated guidance with no harmful feedback."
|
|
123
|
+
: band === "risky"
|
|
124
|
+
? "Risky guidance: review before reuse because governance or outcome evidence weakened confidence."
|
|
125
|
+
: "Building guidance: usable with caution while ExperienceEngine gathers stronger reuse evidence.";
|
|
126
|
+
return {
|
|
127
|
+
band,
|
|
128
|
+
summary,
|
|
129
|
+
reasonCodes: firstUnique(reasonCodes),
|
|
130
|
+
reasons: firstUnique(reasons).slice(0, 4),
|
|
131
|
+
evidenceRefs: buildEvidenceRefs(node),
|
|
132
|
+
recommendedAction: actionForBand(node, band)
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
export const summarizeQualityBandDistribution = (explanations) => {
|
|
136
|
+
const distribution = explanations.reduce((counts, explanation) => {
|
|
137
|
+
counts[explanation.band] += 1;
|
|
138
|
+
return counts;
|
|
139
|
+
}, { strong: 0, building: 0, risky: 0 });
|
|
140
|
+
const total = explanations.length;
|
|
141
|
+
const summary = total === 0
|
|
142
|
+
? "No experience nodes are available for this scope yet."
|
|
143
|
+
: `${distribution.strong} strong, ${distribution.building} building, ${distribution.risky} risky node(s) in this scope.`;
|
|
144
|
+
return {
|
|
145
|
+
...distribution,
|
|
146
|
+
summary
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
//# sourceMappingURL=quality-band.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-band.js","sourceRoot":"","sources":["../../src/interaction/quality-band.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import type { BenchmarkSummary } from "../evaluation/benchmark-summary.js";
|
|
|
2
2
|
import type { RepoPolicyInspection } from "../experience-management/repo-policy.js";
|
|
3
3
|
import type { RepoPolicy } from "../types/domain.js";
|
|
4
4
|
import type { ExperienceLastInspection, ExperienceLearningSummary } from "./service.js";
|
|
5
|
+
import type { QualityBandDistribution } from "./quality-band.js";
|
|
5
6
|
export type ExperienceRepoSummary = {
|
|
6
7
|
scope: {
|
|
7
8
|
scopeId: string;
|
|
@@ -19,6 +20,7 @@ export type ExperienceRepoSummary = {
|
|
|
19
20
|
latestTrustSummary?: ExperienceLastInspection["trustSummary"];
|
|
20
21
|
};
|
|
21
22
|
benchmark: BenchmarkSummary;
|
|
23
|
+
quality: QualityBandDistribution;
|
|
22
24
|
policy?: {
|
|
23
25
|
configuredMode: RepoPolicy["configured_mode"];
|
|
24
26
|
effectiveMode: RepoPolicy["effective_mode"];
|
|
@@ -42,6 +44,7 @@ export declare const buildRepoSummary: (input: {
|
|
|
42
44
|
};
|
|
43
45
|
latest?: ExperienceLastInspection;
|
|
44
46
|
learning: ExperienceLearningSummary;
|
|
47
|
+
quality: QualityBandDistribution;
|
|
45
48
|
policy?: RepoPolicy;
|
|
46
49
|
policyInspection?: RepoPolicyInspection;
|
|
47
50
|
}) => ExperienceRepoSummary;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repo-summary.js","sourceRoot":"","sources":["../../src/interaction/repo-summary.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"repo-summary.js","sourceRoot":"","sources":["../../src/interaction/repo-summary.ts"],"names":[],"mappings":"AAwCA,MAAM,uBAAuB,GAAG,CAAC,SAA2B,EAAU,EAAE;IACtE,QAAQ,SAAS,CAAC,OAAO,EAAE,CAAC;QAC1B,KAAK,SAAS;YACZ,OAAO,gFAAgF,CAAC;QAC1F,KAAK,YAAY;YACf,OAAO,yGAAyG,CAAC;QACnH,KAAK,SAAS;YACZ,OAAO,sGAAsG,CAAC;QAChH;YACE,OAAO,uHAAuH,CAAC;IACnI,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAWhC,EAAyB,EAAE;IAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,gBAAgB,EAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;IAE9D,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM,EAAE;YACN,eAAe,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS;YACxC,iBAAiB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;YACxC,gBAAgB,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS;YACzC,kBAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,YAAY;YAC9C,kBAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,YAAY;YAC9C,wBAAwB,EAAE,KAAK,CAAC,MAAM,EAAE,kBAAkB;YAC1D,yBAAyB,EAAE,KAAK,CAAC,MAAM,EAAE,mBAAmB;YAC5D,kBAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,YAAY;SAC/C;QACD,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,SAAS;QACnC,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAE,MAAM;YACZ,CAAC,CAAC;gBACE,cAAc,EAAE,MAAM,CAAC,eAAe;gBACtC,aAAa,EAAE,MAAM,CAAC,cAAc;gBACpC,YAAY,EAAE,MAAM,CAAC,aAAa;gBAClC,aAAa,EAAE,MAAM,CAAC,cAAc;gBACpC,uBAAuB,EAAE,MAAM,CAAC,yBAAyB;gBACzD,SAAS,EAAE,MAAM,CAAC,UAAU;gBAC5B,aAAa,EAAE,MAAM,CAAC,eAAe;gBACrC,UAAU,EAAE,MAAM,CAAC,WAAW;gBAC9B,eAAe,EAAE,KAAK,CAAC,gBAAgB,EAAE,eAAe;gBACxD,QAAQ,EAAE,KAAK,CAAC,gBAAgB,EAAE,QAAQ;gBAC1C,eAAe,EAAE,KAAK,CAAC,gBAAgB,EAAE,eAAe;aACzD;YACH,CAAC,CAAC,SAAS;QACb,qBAAqB,EAAE,uBAAuB,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;KACzE,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -7,6 +7,7 @@ import { type HybridRouteDecision } from "../hybrid/router.js";
|
|
|
7
7
|
import type { CandidateLifecycleState, DistillationSource, DistillationJobState, EvaluationMode, ExperienceInputRecord, FeedbackAttributionReason, AttributionRecord, EpisodeProjection, InjectionEvent, InjectionScorecard, ExperienceNode, ExperienceNodeType, ExperienceState, TaskRun } from "../types/domain.js";
|
|
8
8
|
import { type ExperienceRepoSummary } from "./repo-summary.js";
|
|
9
9
|
import { type RetrievalPolicyInspectionSummary } from "./retrieval-policy-inspection.js";
|
|
10
|
+
import { type ExperienceQualityBandExplanation } from "./quality-band.js";
|
|
10
11
|
export type ExperienceNodeSummary = {
|
|
11
12
|
id: string;
|
|
12
13
|
type: ExperienceNode["node_type"];
|
|
@@ -30,6 +31,7 @@ export type ExperienceNodeSummary = {
|
|
|
30
31
|
hint: string;
|
|
31
32
|
qualityBand: "strong" | "building" | "risky";
|
|
32
33
|
qualityDrivers: string[];
|
|
34
|
+
quality: ExperienceQualityBandExplanation;
|
|
33
35
|
applicabilityProfile: {
|
|
34
36
|
bestFit: string;
|
|
35
37
|
scopeValidity: string;
|
|
@@ -74,6 +76,7 @@ export type ExperienceLastInspection = {
|
|
|
74
76
|
scorecard?: InjectionScorecard;
|
|
75
77
|
decisionExplanation?: string;
|
|
76
78
|
trustSummary?: string;
|
|
79
|
+
qualityContext?: ExperienceQualityBandExplanation;
|
|
77
80
|
retrievalNotes: string[];
|
|
78
81
|
retrievalPolicySummary?: RetrievalPolicyInspectionSummary;
|
|
79
82
|
timeline: ExperienceTimelineEntry[];
|
|
@@ -30,6 +30,7 @@ import { nowIso } from "../utils/clock.js";
|
|
|
30
30
|
import { createId, stableId } from "../utils/ids.js";
|
|
31
31
|
import { buildRepoSummary } from "./repo-summary.js";
|
|
32
32
|
import { buildRetrievalPolicyInspectionSummary } from "./retrieval-policy-inspection.js";
|
|
33
|
+
import { deriveNodeConfidence, deriveNodeRisk, deriveQualityBandExplanation, summarizeQualityBandDistribution } from "./quality-band.js";
|
|
33
34
|
const normalizeHybridExplainPrompt = (value) => value
|
|
34
35
|
.toLowerCase()
|
|
35
36
|
.replace(/\s+/g, " ")
|
|
@@ -163,90 +164,43 @@ const toManualOverrideAttributionRecord = (input) => {
|
|
|
163
164
|
resolved_at: timestamp
|
|
164
165
|
};
|
|
165
166
|
};
|
|
166
|
-
const deriveNodeRisk = (node) => {
|
|
167
|
-
if (node.state === "candidate") {
|
|
168
|
-
return "high";
|
|
169
|
-
}
|
|
170
|
-
if (node.state === "priority_candidate") {
|
|
171
|
-
return "medium";
|
|
172
|
-
}
|
|
173
|
-
if (node.state === "cooling" || node.harmed_count > 0 || node.node_type === "warning") {
|
|
174
|
-
return node.harmed_count > node.helped_count ? "high" : "medium";
|
|
175
|
-
}
|
|
176
|
-
return "low";
|
|
177
|
-
};
|
|
178
|
-
const deriveQualityBand = (node) => {
|
|
179
|
-
if (node.state === "retired" || node.harmed_count > node.helped_count || deriveNodeRisk(node) === "high") {
|
|
180
|
-
return "risky";
|
|
181
|
-
}
|
|
182
|
-
if (node.state === "active" &&
|
|
183
|
-
node.validation_state === "validated_by_reuse" &&
|
|
184
|
-
node.harmed_count === 0) {
|
|
185
|
-
return "strong";
|
|
186
|
-
}
|
|
187
|
-
return "building";
|
|
188
|
-
};
|
|
189
|
-
const buildQualityDrivers = (node) => {
|
|
190
|
-
const drivers = [];
|
|
191
|
-
if (node.validation_state === "validated_by_reuse") {
|
|
192
|
-
drivers.push("This node has already been validated by successful reuse.");
|
|
193
|
-
}
|
|
194
|
-
if (node.helped_count > node.harmed_count) {
|
|
195
|
-
drivers.push("Helpful outcomes still outweigh harmful ones for this node.");
|
|
196
|
-
}
|
|
197
|
-
else if (node.harmed_count > node.helped_count) {
|
|
198
|
-
drivers.push("Harmful outcomes currently outweigh helpful ones for this node.");
|
|
199
|
-
}
|
|
200
|
-
if (node.state === "candidate" || node.state === "priority_candidate") {
|
|
201
|
-
drivers.push("This node is still early in its lifecycle and needs more runtime evidence.");
|
|
202
|
-
}
|
|
203
|
-
else if (node.state === "cooling") {
|
|
204
|
-
drivers.push("This node is in cooling state because recent runtime evidence weakened confidence.");
|
|
205
|
-
}
|
|
206
|
-
return drivers.slice(0, 3);
|
|
207
|
-
};
|
|
208
|
-
const deriveConfidence = (node) => {
|
|
209
|
-
if (node.validation_state === "validated_by_reuse" && node.state === "active" && node.harmed_count === 0) {
|
|
210
|
-
return "high";
|
|
211
|
-
}
|
|
212
|
-
if (node.state === "candidate" || node.harmed_count > node.helped_count) {
|
|
213
|
-
return "low";
|
|
214
|
-
}
|
|
215
|
-
return "medium";
|
|
216
|
-
};
|
|
217
167
|
const formatTaskFamily = (taskType) => taskType === "general" ? "general tasks" : `${taskType} tasks`;
|
|
218
168
|
const buildApplicabilityProfile = (node) => ({
|
|
219
169
|
bestFit: `${formatTaskFamily(node.task_type)} in this repo scope`,
|
|
220
170
|
scopeValidity: node.applicability_notes ?? "Use within the same repo scope unless fresh evidence says otherwise.",
|
|
221
|
-
confidence:
|
|
171
|
+
confidence: deriveNodeConfidence(node),
|
|
222
172
|
risk: deriveNodeRisk(node),
|
|
223
173
|
avoidWhen: node.stop_condition ?? node.escalation_condition ?? node.avoid_steps?.[0]
|
|
224
174
|
});
|
|
225
|
-
const toNodeSummary = (node) =>
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
175
|
+
const toNodeSummary = (node) => {
|
|
176
|
+
const quality = deriveQualityBandExplanation(node);
|
|
177
|
+
return {
|
|
178
|
+
id: node.id,
|
|
179
|
+
type: node.node_type,
|
|
180
|
+
taskType: node.task_type,
|
|
181
|
+
state: node.state,
|
|
182
|
+
sourceKind: node.source_kind,
|
|
183
|
+
distillationMode: node.distillation_mode_used,
|
|
184
|
+
distillationSource: node.distillation_source,
|
|
185
|
+
redistilledFrom: node.redistilled_from,
|
|
186
|
+
promotionSignal: node.promotion_signal,
|
|
187
|
+
promotionReason: node.promotion_reason,
|
|
188
|
+
mergeDecision: node.merge_decision,
|
|
189
|
+
mergeReason: node.merge_reason,
|
|
190
|
+
priorityPromotionApplied: node.priority_promotion_applied,
|
|
191
|
+
triggerPattern: node.trigger_pattern,
|
|
192
|
+
evidenceSummary: node.evidence_summary,
|
|
193
|
+
originRecordIds: node.origin_record_ids,
|
|
194
|
+
helped: node.helped_count,
|
|
195
|
+
harmed: node.harmed_count,
|
|
196
|
+
lastUsedAt: node.last_used_at,
|
|
197
|
+
hint: node.compact_hint,
|
|
198
|
+
qualityBand: quality.band,
|
|
199
|
+
qualityDrivers: quality.reasons,
|
|
200
|
+
quality,
|
|
201
|
+
applicabilityProfile: buildApplicabilityProfile(node)
|
|
202
|
+
};
|
|
203
|
+
};
|
|
250
204
|
const toNodeDetail = (node) => ({
|
|
251
205
|
...toNodeSummary(node),
|
|
252
206
|
scopeId: node.scope_id,
|
|
@@ -390,6 +344,18 @@ const buildTrustSummary = (input) => {
|
|
|
390
344
|
const confidence = scorecard.confidence ? ` ${scorecard.confidence}-confidence` : "";
|
|
391
345
|
return `${scorecard.riskLevel}-risk${confidence} ${primaryNode.state} guidance with ${primaryNode.helped} helped and ${primaryNode.harmed} harmed signal(s).`;
|
|
392
346
|
};
|
|
347
|
+
const buildQualityContext = (input) => {
|
|
348
|
+
const primaryInjected = input.injectedNodes[0]?.quality;
|
|
349
|
+
if (primaryInjected) {
|
|
350
|
+
return primaryInjected;
|
|
351
|
+
}
|
|
352
|
+
const topCandidateId = input.scorecard?.topCandidates?.[0]?.id;
|
|
353
|
+
if (!topCandidateId) {
|
|
354
|
+
return undefined;
|
|
355
|
+
}
|
|
356
|
+
const candidateNode = input.lookupNode(topCandidateId);
|
|
357
|
+
return candidateNode ? deriveQualityBandExplanation(candidateNode) : undefined;
|
|
358
|
+
};
|
|
393
359
|
const buildRetrievalNotes = (scorecard) => {
|
|
394
360
|
if (!scorecard) {
|
|
395
361
|
return [];
|
|
@@ -579,6 +545,12 @@ export class ExperienceInteractionService {
|
|
|
579
545
|
outcome: record.outcome_signal
|
|
580
546
|
});
|
|
581
547
|
const decisionExplanation = buildDecisionExplanation({ intervention, scorecard });
|
|
548
|
+
const injectedNodeSummaries = injectedNodes.map(toNodeSummary);
|
|
549
|
+
const qualityContext = buildQualityContext({
|
|
550
|
+
scorecard,
|
|
551
|
+
injectedNodes: injectedNodeSummaries,
|
|
552
|
+
lookupNode: (nodeId) => this.nodeRepo.getById(nodeId)
|
|
553
|
+
});
|
|
582
554
|
return {
|
|
583
555
|
sessionId: record.session_id,
|
|
584
556
|
episodeId: record.episode_id,
|
|
@@ -592,12 +564,13 @@ export class ExperienceInteractionService {
|
|
|
592
564
|
attributionRecords,
|
|
593
565
|
episodeProjection,
|
|
594
566
|
outcome: record.outcome_signal,
|
|
595
|
-
injectedNodes:
|
|
567
|
+
injectedNodes: injectedNodeSummaries,
|
|
596
568
|
hints: injectedNodes.map((node) => node.compact_hint),
|
|
597
569
|
evidence: record.evidence,
|
|
598
570
|
scorecard,
|
|
599
571
|
decisionExplanation,
|
|
600
|
-
trustSummary: buildTrustSummary({ scorecard, injectedNodes:
|
|
572
|
+
trustSummary: buildTrustSummary({ scorecard, injectedNodes: injectedNodeSummaries }),
|
|
573
|
+
qualityContext,
|
|
601
574
|
retrievalNotes: buildRetrievalNotes(scorecard),
|
|
602
575
|
retrievalPolicySummary: buildRetrievalPolicyInspectionSummary(scorecard),
|
|
603
576
|
timeline: buildLatestTimeline({
|
|
@@ -645,6 +618,12 @@ export class ExperienceInteractionService {
|
|
|
645
618
|
(taskRun?.final_status === "success" ? "success" : taskRun?.final_status === "failure" ? "failure" : "unknown");
|
|
646
619
|
const summary = event.task_summary ?? taskRun?.task_summary ?? "Latest injection event";
|
|
647
620
|
const decisionExplanation = buildDecisionExplanation({ intervention, scorecard: event.scorecard });
|
|
621
|
+
const injectedNodeSummaries = injectedNodes.map(toNodeSummary);
|
|
622
|
+
const qualityContext = buildQualityContext({
|
|
623
|
+
scorecard: event.scorecard,
|
|
624
|
+
injectedNodes: injectedNodeSummaries,
|
|
625
|
+
lookupNode: (nodeId) => this.nodeRepo.getById(nodeId)
|
|
626
|
+
});
|
|
648
627
|
return {
|
|
649
628
|
sessionId: event.session_id,
|
|
650
629
|
episodeId: event.episode_id,
|
|
@@ -663,12 +642,13 @@ export class ExperienceInteractionService {
|
|
|
663
642
|
attributionRecords,
|
|
664
643
|
episodeProjection,
|
|
665
644
|
outcome,
|
|
666
|
-
injectedNodes:
|
|
645
|
+
injectedNodes: injectedNodeSummaries,
|
|
667
646
|
hints: injectedNodes.map((node) => node.compact_hint),
|
|
668
647
|
evidence: [],
|
|
669
648
|
scorecard: event.scorecard,
|
|
670
649
|
decisionExplanation,
|
|
671
|
-
trustSummary: buildTrustSummary({ scorecard: event.scorecard, injectedNodes:
|
|
650
|
+
trustSummary: buildTrustSummary({ scorecard: event.scorecard, injectedNodes: injectedNodeSummaries }),
|
|
651
|
+
qualityContext,
|
|
672
652
|
retrievalNotes: buildRetrievalNotes(event.scorecard),
|
|
673
653
|
retrievalPolicySummary: buildRetrievalPolicyInspectionSummary(event.scorecard),
|
|
674
654
|
timeline: buildLatestTimeline({
|
|
@@ -889,6 +869,7 @@ export class ExperienceInteractionService {
|
|
|
889
869
|
const latest = latestRecord ? this.inspectRecord(latestRecord) : undefined;
|
|
890
870
|
const learning = this.buildLearningSummary(scope.scope_id);
|
|
891
871
|
const policyInspection = this.inspectRepoPolicy(cwd);
|
|
872
|
+
const quality = summarizeQualityBandDistribution(this.nodeRepo.listByScope(scope.scope_id).map((node) => deriveQualityBandExplanation(node)));
|
|
892
873
|
return buildRepoSummary({
|
|
893
874
|
scope: {
|
|
894
875
|
scopeId: scope.scope_id,
|
|
@@ -897,6 +878,7 @@ export class ExperienceInteractionService {
|
|
|
897
878
|
},
|
|
898
879
|
latest: latest && latest.scopeId === scope.scope_id ? latest : undefined,
|
|
899
880
|
learning,
|
|
881
|
+
quality,
|
|
900
882
|
policyInspection
|
|
901
883
|
});
|
|
902
884
|
}
|