@alan512/experienceengine 0.2.0 → 0.3.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/.claude-plugin/plugin.json +1 -1
- package/.mcp.json +5 -6
- package/README.md +65 -54
- package/README.zh-CN.md +64 -53
- package/dist/adapters/codex/action-registry.d.ts +23 -1
- package/dist/adapters/codex/action-registry.js +73 -0
- package/dist/adapters/codex/action-registry.js.map +1 -1
- package/dist/adapters/codex/behavior-loop.d.ts +80 -0
- package/dist/adapters/codex/behavior-loop.js +189 -0
- package/dist/adapters/codex/behavior-loop.js.map +1 -0
- package/dist/adapters/codex/mcp-server.d.ts +27 -72
- package/dist/adapters/codex/mcp-server.js +36 -160
- package/dist/adapters/codex/mcp-server.js.map +1 -1
- package/dist/cli/commands/claude-hook.d.ts +4 -0
- package/dist/cli/commands/claude-hook.js +105 -21
- package/dist/cli/commands/claude-hook.js.map +1 -1
- package/dist/cli/commands/codex-hook.d.ts +22 -0
- package/dist/cli/commands/codex-hook.js +298 -0
- package/dist/cli/commands/codex-hook.js.map +1 -0
- package/dist/cli/commands/config.js +9 -1
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/doctor.js +77 -2
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/inspect.d.ts +1 -1
- package/dist/cli/commands/inspect.js +329 -4
- package/dist/cli/commands/inspect.js.map +1 -1
- package/dist/cli/commands/install.js +2 -0
- package/dist/cli/commands/install.js.map +1 -1
- package/dist/cli/commands/maintenance.js +4 -0
- package/dist/cli/commands/maintenance.js.map +1 -1
- package/dist/cli/commands/repair.js +33 -3
- package/dist/cli/commands/repair.js.map +1 -1
- package/dist/cli/commands/status.js +33 -0
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/dispatch.js +8 -3
- package/dist/cli/dispatch.js.map +1 -1
- package/dist/cli/index.js +0 -0
- package/dist/config/config-schema.d.ts +8 -0
- package/dist/config/config-schema.js +6 -0
- package/dist/config/config-schema.js.map +1 -1
- package/dist/config/default-config.js +1 -0
- package/dist/config/default-config.js.map +1 -1
- package/dist/config/load-config.js +3 -0
- package/dist/config/load-config.js.map +1 -1
- package/dist/controller/candidate-retriever.d.ts +5 -1
- package/dist/controller/candidate-retriever.js +237 -13
- package/dist/controller/candidate-retriever.js.map +1 -1
- package/dist/controller/injection-renderer.d.ts +2 -2
- package/dist/controller/injection-renderer.js +22 -3
- package/dist/controller/injection-renderer.js.map +1 -1
- package/dist/controller/injection-scorecard.js +3 -0
- package/dist/controller/injection-scorecard.js.map +1 -1
- package/dist/controller/intervention-controller.d.ts +2 -2
- package/dist/controller/intervention-controller.js +185 -25
- package/dist/controller/intervention-controller.js.map +1 -1
- package/dist/controller/model-reranker-mode.d.ts +4 -0
- package/dist/controller/model-reranker-mode.js +14 -0
- package/dist/controller/model-reranker-mode.js.map +1 -0
- package/dist/controller/model-reranker.d.ts +0 -1
- package/dist/controller/model-reranker.js +1 -13
- package/dist/controller/model-reranker.js.map +1 -1
- package/dist/controller/policy-enricher.d.ts +2 -1
- package/dist/controller/policy-enricher.js +71 -11
- package/dist/controller/policy-enricher.js.map +1 -1
- package/dist/controller/trigger-evaluator.d.ts +2 -1
- package/dist/controller/trigger-evaluator.js +24 -0
- package/dist/controller/trigger-evaluator.js.map +1 -1
- package/dist/evaluation/openclaw-scenarios.js +12 -5
- package/dist/evaluation/openclaw-scenarios.js.map +1 -1
- package/dist/experience-management/repo-policy.d.ts +53 -0
- package/dist/experience-management/repo-policy.js +175 -0
- package/dist/experience-management/repo-policy.js.map +1 -0
- package/dist/hybrid/capsule-builder.js +2 -0
- package/dist/hybrid/capsule-builder.js.map +1 -1
- package/dist/input/scope-resolver.js +16 -4
- package/dist/input/scope-resolver.js.map +1 -1
- package/dist/install/claude-cli.js +38 -21
- package/dist/install/claude-cli.js.map +1 -1
- package/dist/install/claude-code-doctor.js +8 -3
- package/dist/install/claude-code-doctor.js.map +1 -1
- package/dist/install/claude-code-installer.js +5 -2
- package/dist/install/claude-code-installer.js.map +1 -1
- package/dist/install/claude-runtime-target.d.ts +5 -0
- package/dist/install/claude-runtime-target.js +32 -2
- package/dist/install/claude-runtime-target.js.map +1 -1
- package/dist/install/codex-cli.d.ts +7 -0
- package/dist/install/codex-cli.js +43 -20
- package/dist/install/codex-cli.js.map +1 -1
- package/dist/install/codex-hooks.d.ts +42 -0
- package/dist/install/codex-hooks.js +258 -0
- package/dist/install/codex-hooks.js.map +1 -0
- package/dist/install/codex-installer.d.ts +28 -3
- package/dist/install/codex-installer.js +120 -9
- package/dist/install/codex-installer.js.map +1 -1
- package/dist/install/codex-runtime-target.d.ts +20 -0
- package/dist/install/codex-runtime-target.js +85 -17
- package/dist/install/codex-runtime-target.js.map +1 -1
- package/dist/install/openclaw-cli.d.ts +1 -0
- package/dist/install/openclaw-cli.js +52 -3
- package/dist/install/openclaw-cli.js.map +1 -1
- package/dist/install/openclaw-installer.d.ts +5 -0
- package/dist/install/openclaw-installer.js +24 -5
- package/dist/install/openclaw-installer.js.map +1 -1
- package/dist/interaction/repo-summary.d.ts +17 -0
- package/dist/interaction/repo-summary.js +33 -15
- package/dist/interaction/repo-summary.js.map +1 -1
- package/dist/interaction/retrieval-policy-inspection.d.ts +19 -0
- package/dist/interaction/retrieval-policy-inspection.js +33 -0
- package/dist/interaction/retrieval-policy-inspection.js.map +1 -0
- package/dist/interaction/service.d.ts +24 -1
- package/dist/interaction/service.js +186 -23
- package/dist/interaction/service.js.map +1 -1
- package/dist/maintenance/claude-validate-print.d.ts +8 -1
- package/dist/maintenance/claude-validate-print.js +52 -2
- package/dist/maintenance/claude-validate-print.js.map +1 -1
- package/dist/maintenance/experience-export-drafts.d.ts +56 -0
- package/dist/maintenance/experience-export-drafts.js +217 -0
- package/dist/maintenance/experience-export-drafts.js.map +1 -0
- package/dist/maintenance/experience-hygiene.d.ts +38 -0
- package/dist/maintenance/experience-hygiene.js +266 -0
- package/dist/maintenance/experience-hygiene.js.map +1 -0
- package/dist/maintenance/operator-review-flow.d.ts +81 -0
- package/dist/maintenance/operator-review-flow.js +172 -0
- package/dist/maintenance/operator-review-flow.js.map +1 -0
- package/dist/plugin/openclaw-plugin.d.ts +5 -0
- package/dist/plugin/runtime-helpers.js +43 -1
- package/dist/plugin/runtime-helpers.js.map +1 -1
- package/dist/runtime/prompt-service.d.ts +51 -0
- package/dist/runtime/prompt-service.js +209 -0
- package/dist/runtime/prompt-service.js.map +1 -0
- package/dist/runtime/service.d.ts +8 -2
- package/dist/runtime/service.js +234 -44
- package/dist/runtime/service.js.map +1 -1
- package/dist/store/sqlite/db.js +15 -0
- package/dist/store/sqlite/db.js.map +1 -1
- package/dist/store/sqlite/repositories/attribution-record-repo.d.ts +15 -0
- package/dist/store/sqlite/repositories/attribution-record-repo.js +111 -0
- package/dist/store/sqlite/repositories/attribution-record-repo.js.map +1 -0
- package/dist/store/sqlite/repositories/episode-repo.d.ts +14 -0
- package/dist/store/sqlite/repositories/episode-repo.js +84 -0
- package/dist/store/sqlite/repositories/episode-repo.js.map +1 -0
- package/dist/store/sqlite/repositories/injection-repo.d.ts +2 -0
- package/dist/store/sqlite/repositories/injection-repo.js +32 -5
- package/dist/store/sqlite/repositories/injection-repo.js.map +1 -1
- package/dist/store/sqlite/repositories/input-record-repo.d.ts +1 -0
- package/dist/store/sqlite/repositories/input-record-repo.js +23 -10
- package/dist/store/sqlite/repositories/input-record-repo.js.map +1 -1
- package/dist/store/sqlite/repositories/node-repo.d.ts +2 -0
- package/dist/store/sqlite/repositories/node-repo.js +19 -0
- package/dist/store/sqlite/repositories/node-repo.js.map +1 -1
- package/dist/store/sqlite/repositories/outcome-record-repo.d.ts +1 -0
- package/dist/store/sqlite/repositories/outcome-record-repo.js +11 -2
- package/dist/store/sqlite/repositories/outcome-record-repo.js.map +1 -1
- package/dist/store/sqlite/repositories/repo-policy-repo.d.ts +11 -0
- package/dist/store/sqlite/repositories/repo-policy-repo.js +87 -0
- package/dist/store/sqlite/repositories/repo-policy-repo.js.map +1 -0
- package/dist/store/sqlite/repositories/review-event-repo.d.ts +1 -0
- package/dist/store/sqlite/repositories/review-event-repo.js +11 -2
- package/dist/store/sqlite/repositories/review-event-repo.js.map +1 -1
- package/dist/store/sqlite/repositories/task-run-repo.d.ts +1 -0
- package/dist/store/sqlite/repositories/task-run-repo.js +11 -2
- package/dist/store/sqlite/repositories/task-run-repo.js.map +1 -1
- package/dist/store/sqlite/schema.sql +43 -0
- package/dist/store/vector/api-embedding-provider.js +14 -3
- package/dist/store/vector/api-embedding-provider.js.map +1 -1
- package/dist/store/vector/embeddings.js +7 -1
- package/dist/store/vector/embeddings.js.map +1 -1
- package/dist/types/domain.d.ts +105 -3
- package/dist/utils/text.js +5 -1
- package/dist/utils/text.js.map +1 -1
- package/docs/assets/readme/inspect-last-example.svg +37 -0
- package/docs/releases/v0.2.1.md +30 -0
- package/docs/releases/v0.3.0.md +17 -0
- package/docs/user-guide.md +91 -5
- package/openclaw.plugin.json +1 -1
- package/package.json +16 -14
- package/plugins/claude-code-experienceengine/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-code-experienceengine/.mcp.json +3 -9
- package/plugins/claude-code-experienceengine/scripts/install-deps.sh +1 -1
- package/plugins/claude-code-experienceengine/scripts/mcp-server.sh +43 -0
- package/scripts/claude-plugin/claude-hook.sh +6 -1
- package/scripts/claude-plugin/mcp-server.sh +45 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { InjectionScorecard, PolicyEnrichmentComponent, RetrievalPolicyStageDiagnostic } from "../types/domain.js";
|
|
2
|
+
export type RetrievalPolicyStageInspection = {
|
|
3
|
+
stage: RetrievalPolicyStageDiagnostic["stage"];
|
|
4
|
+
acceptedCount?: number;
|
|
5
|
+
rejectedCount?: number;
|
|
6
|
+
passedCount?: number;
|
|
7
|
+
reasonCodes: string[];
|
|
8
|
+
};
|
|
9
|
+
export type RetrievalPolicyComponentInspection = PolicyEnrichmentComponent;
|
|
10
|
+
export type RetrievalPolicyInspectionSummary = {
|
|
11
|
+
stages: RetrievalPolicyStageInspection[];
|
|
12
|
+
semanticMode?: "skipped" | "rerank" | "backfill";
|
|
13
|
+
topPolicyComponents: RetrievalPolicyComponentInspection[];
|
|
14
|
+
rejectedCandidates: Array<{
|
|
15
|
+
id: string;
|
|
16
|
+
reasonCodes: string[];
|
|
17
|
+
}>;
|
|
18
|
+
};
|
|
19
|
+
export declare const buildRetrievalPolicyInspectionSummary: (scorecard?: InjectionScorecard) => RetrievalPolicyInspectionSummary | undefined;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const SEMANTIC_STAGE = "semantic_rerank_backfill";
|
|
2
|
+
const inferSemanticMode = (stage) => {
|
|
3
|
+
const modeReason = stage?.reasonCodes.find((reason) => reason.startsWith("semantic_mode:"));
|
|
4
|
+
const mode = modeReason?.slice("semantic_mode:".length);
|
|
5
|
+
return mode === "skipped" || mode === "rerank" || mode === "backfill" ? mode : undefined;
|
|
6
|
+
};
|
|
7
|
+
export const buildRetrievalPolicyInspectionSummary = (scorecard) => {
|
|
8
|
+
const stages = scorecard?.retrievalPolicyDiagnostics?.stages ?? [];
|
|
9
|
+
const topCandidate = scorecard?.topCandidates?.[0];
|
|
10
|
+
const topPolicyComponents = [...(topCandidate?.policyComponents ?? [])]
|
|
11
|
+
.sort((left, right) => Math.abs(right.value) - Math.abs(left.value))
|
|
12
|
+
.slice(0, 5);
|
|
13
|
+
const rejectedCandidates = scorecard?.rejectedCandidates?.slice(0, 5).map((candidate) => ({
|
|
14
|
+
id: candidate.id,
|
|
15
|
+
reasonCodes: candidate.reasonCodes
|
|
16
|
+
})) ?? [];
|
|
17
|
+
if (!stages.length && !topPolicyComponents.length && !rejectedCandidates.length) {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
stages: stages.map((stage) => ({
|
|
22
|
+
stage: stage.stage,
|
|
23
|
+
acceptedCount: stage.acceptedCount,
|
|
24
|
+
rejectedCount: stage.rejectedCount,
|
|
25
|
+
passedCount: stage.passedCount,
|
|
26
|
+
reasonCodes: stage.reasonCodes
|
|
27
|
+
})),
|
|
28
|
+
semanticMode: inferSemanticMode(stages.find((stage) => stage.stage === SEMANTIC_STAGE)),
|
|
29
|
+
topPolicyComponents,
|
|
30
|
+
rejectedCandidates
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=retrieval-policy-inspection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retrieval-policy-inspection.js","sourceRoot":"","sources":["../../src/interaction/retrieval-policy-inspection.ts"],"names":[],"mappings":"AA0BA,MAAM,cAAc,GAAG,0BAA0B,CAAC;AAElD,MAAM,iBAAiB,GAAG,CACxB,KAAiD,EACC,EAAE;IACpD,MAAM,UAAU,GAAG,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC5F,MAAM,IAAI,GAAG,UAAU,EAAE,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACxD,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3F,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qCAAqC,GAAG,CACnD,SAA8B,EACgB,EAAE;IAChD,MAAM,MAAM,GAAG,SAAS,EAAE,0BAA0B,EAAE,MAAM,IAAI,EAAE,CAAC;IACnE,MAAM,YAAY,GAAG,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,mBAAmB,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,IAAI,EAAE,CAAC,CAAC;SACpE,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;SACnE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACf,MAAM,kBAAkB,GACtB,SAAS,EAAE,kBAAkB,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAC7D,EAAE,EAAE,SAAS,CAAC,EAAE;QAChB,WAAW,EAAE,SAAS,CAAC,WAAW;KACnC,CAAC,CAAC,IAAI,EAAE,CAAC;IAEZ,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,mBAAmB,CAAC,MAAM,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC;QAChF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC7B,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAAC,CAAC;QACH,YAAY,EAAE,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,cAAc,CAAC,CAAC;QACvF,mBAAmB;QACnB,kBAAkB;KACnB,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import type { ExperienceEngineConfig } from "../config/config-schema.js";
|
|
2
2
|
import { type BenchmarkSummary } from "../evaluation/benchmark-summary.js";
|
|
3
|
+
import { type HygieneReviewFilters, type HygieneReviewReport } from "../maintenance/experience-hygiene.js";
|
|
4
|
+
import { type ExperienceExportDraftFilters, type ExperienceExportDraftReport } from "../maintenance/experience-export-drafts.js";
|
|
5
|
+
import { type OperatorReviewReport } from "../maintenance/operator-review-flow.js";
|
|
3
6
|
import { type HybridRouteDecision } from "../hybrid/router.js";
|
|
4
|
-
import type { CandidateLifecycleState, DistillationSource, DistillationJobState, EvaluationMode, ExperienceInputRecord, FeedbackAttributionReason, InjectionEvent, InjectionScorecard, ExperienceNode, ExperienceNodeType, ExperienceState, TaskRun } from "../types/domain.js";
|
|
7
|
+
import type { CandidateLifecycleState, DistillationSource, DistillationJobState, EvaluationMode, ExperienceInputRecord, FeedbackAttributionReason, AttributionRecord, EpisodeProjection, InjectionEvent, InjectionScorecard, ExperienceNode, ExperienceNodeType, ExperienceState, TaskRun } from "../types/domain.js";
|
|
5
8
|
import { type ExperienceRepoSummary } from "./repo-summary.js";
|
|
9
|
+
import { type RetrievalPolicyInspectionSummary } from "./retrieval-policy-inspection.js";
|
|
6
10
|
export type ExperienceNodeSummary = {
|
|
7
11
|
id: string;
|
|
8
12
|
type: ExperienceNode["node_type"];
|
|
@@ -53,6 +57,7 @@ export type ExperienceTimelineEntry = {
|
|
|
53
57
|
};
|
|
54
58
|
export type ExperienceLastInspection = {
|
|
55
59
|
sessionId?: string;
|
|
60
|
+
episodeId?: string;
|
|
56
61
|
scopeId: string;
|
|
57
62
|
taskType: ExperienceInputRecord["task_type"];
|
|
58
63
|
intervention: "inject" | "skip" | "shadow" | "holdout";
|
|
@@ -60,6 +65,8 @@ export type ExperienceLastInspection = {
|
|
|
60
65
|
delivered?: boolean;
|
|
61
66
|
autoFeedback: "helped" | "harmed" | "none";
|
|
62
67
|
autoFeedbackReason?: InjectionEvent["attribution_reason"];
|
|
68
|
+
attributionRecords: AttributionRecord[];
|
|
69
|
+
episodeProjection?: EpisodeProjection;
|
|
63
70
|
outcome: ExperienceInputRecord["outcome_signal"];
|
|
64
71
|
injectedNodes: ExperienceNodeSummary[];
|
|
65
72
|
hints: string[];
|
|
@@ -68,6 +75,7 @@ export type ExperienceLastInspection = {
|
|
|
68
75
|
decisionExplanation?: string;
|
|
69
76
|
trustSummary?: string;
|
|
70
77
|
retrievalNotes: string[];
|
|
78
|
+
retrievalPolicySummary?: RetrievalPolicyInspectionSummary;
|
|
71
79
|
timeline: ExperienceTimelineEntry[];
|
|
72
80
|
learningStatus?: TaskRun["learning_status"];
|
|
73
81
|
learningReason?: string;
|
|
@@ -171,6 +179,9 @@ export declare class ExperienceInteractionService {
|
|
|
171
179
|
private readonly hybridWorkerClient;
|
|
172
180
|
private readonly inputRepo;
|
|
173
181
|
private readonly injectionRepo;
|
|
182
|
+
private readonly attributionRecordRepo;
|
|
183
|
+
private readonly repoPolicyRepo;
|
|
184
|
+
private readonly episodeRepo;
|
|
174
185
|
private readonly nodeRepo;
|
|
175
186
|
private readonly candidateRepo;
|
|
176
187
|
private readonly jobRepo;
|
|
@@ -197,8 +208,20 @@ export declare class ExperienceInteractionService {
|
|
|
197
208
|
listNodesByState(state: ExperienceState): ExperienceNodeSummary[];
|
|
198
209
|
listNodesByType(nodeType: ExperienceNodeType): ExperienceNodeSummary[];
|
|
199
210
|
inspectLearningSummary(): ExperienceLearningSummary;
|
|
211
|
+
inspectHygiene(cwd?: string, filters?: Omit<HygieneReviewFilters, "scopeId"> & {
|
|
212
|
+
scopeId?: string;
|
|
213
|
+
}): HygieneReviewReport;
|
|
214
|
+
inspectExportDrafts(cwd?: string, filters?: Omit<ExperienceExportDraftFilters, "scopeId"> & {
|
|
215
|
+
scopeId?: string;
|
|
216
|
+
}): ExperienceExportDraftReport;
|
|
217
|
+
inspectReview(cwd?: string, filters?: {
|
|
218
|
+
scopeId?: string;
|
|
219
|
+
limit?: number;
|
|
220
|
+
}): OperatorReviewReport;
|
|
200
221
|
private buildLearningSummary;
|
|
201
222
|
inspectRepoSummary(cwd?: string): ExperienceRepoSummary;
|
|
223
|
+
inspectRepoPolicy(cwd?: string): import("../experience-management/repo-policy.js").RepoPolicyInspection;
|
|
224
|
+
restoreRepoPolicy(cwd?: string): import("../types/domain.js").RepoPolicy;
|
|
202
225
|
inspectFirstValueReadiness(cwd?: string): ExperienceFirstValueReadiness;
|
|
203
226
|
inspectDecisionHealth(cwd?: string, limit?: number): ExperienceDecisionHealth;
|
|
204
227
|
feedbackLast(feedback: FeedbackValue, cwd?: string): FeedbackResult;
|
|
@@ -3,6 +3,10 @@ import { buildBenchmarkSummary } from "../evaluation/benchmark-summary.js";
|
|
|
3
3
|
import { buildExplainDecisionCapsule } from "../hybrid/capsule-builder.js";
|
|
4
4
|
import { resolveHybridExplainProviderEndpoint } from "../hybrid/explain-provider-client.js";
|
|
5
5
|
import { resolveHybridRolloutState } from "../hybrid/rollout.js";
|
|
6
|
+
import { buildDefaultRepoPolicy, inspectRepoPolicyEvidence } from "../experience-management/repo-policy.js";
|
|
7
|
+
import { buildHygieneReviewReport } from "../maintenance/experience-hygiene.js";
|
|
8
|
+
import { buildExperienceExportDraftReport } from "../maintenance/experience-export-drafts.js";
|
|
9
|
+
import { buildOperatorReviewFlow } from "../maintenance/operator-review-flow.js";
|
|
6
10
|
import { selectHybridRoute } from "../hybrid/router.js";
|
|
7
11
|
import { HybridWorkerClient } from "../hybrid/worker-client.js";
|
|
8
12
|
import { resolveScope } from "../input/scope-resolver.js";
|
|
@@ -12,6 +16,9 @@ import { DistillationJobRepository } from "../store/sqlite/repositories/distilla
|
|
|
12
16
|
import { HybridInvocationTraceRepository } from "../store/sqlite/repositories/hybrid-invocation-trace-repo.js";
|
|
13
17
|
import { InputRecordRepository } from "../store/sqlite/repositories/input-record-repo.js";
|
|
14
18
|
import { InjectionRepository } from "../store/sqlite/repositories/injection-repo.js";
|
|
19
|
+
import { AttributionRecordRepository } from "../store/sqlite/repositories/attribution-record-repo.js";
|
|
20
|
+
import { RepoPolicyRepository } from "../store/sqlite/repositories/repo-policy-repo.js";
|
|
21
|
+
import { EpisodeRepository } from "../store/sqlite/repositories/episode-repo.js";
|
|
15
22
|
import { NodeRepository } from "../store/sqlite/repositories/node-repo.js";
|
|
16
23
|
import { OutcomeRecordRepository } from "../store/sqlite/repositories/outcome-record-repo.js";
|
|
17
24
|
import { ReviewEventRepository } from "../store/sqlite/repositories/review-event-repo.js";
|
|
@@ -20,8 +27,9 @@ import { TaskRunRepository } from "../store/sqlite/repositories/task-run-repo.js
|
|
|
20
27
|
import { applyGovernedNodeFeedback, deriveNodeOriginProfileForNode } from "../experience-management/node-lifecycle-governance.js";
|
|
21
28
|
import { deriveGovernanceSignals, isPotentialMisfire } from "../experience-management/governance-observability.js";
|
|
22
29
|
import { nowIso } from "../utils/clock.js";
|
|
23
|
-
import { createId } from "../utils/ids.js";
|
|
30
|
+
import { createId, stableId } from "../utils/ids.js";
|
|
24
31
|
import { buildRepoSummary } from "./repo-summary.js";
|
|
32
|
+
import { buildRetrievalPolicyInspectionSummary } from "./retrieval-policy-inspection.js";
|
|
25
33
|
const normalizeHybridExplainPrompt = (value) => value
|
|
26
34
|
.toLowerCase()
|
|
27
35
|
.replace(/\s+/g, " ")
|
|
@@ -89,14 +97,41 @@ export const deriveStructuredSilenceReason = (input) => {
|
|
|
89
97
|
}
|
|
90
98
|
return "unknown";
|
|
91
99
|
};
|
|
92
|
-
const toReviewEvent = (nodeId, eventType, source, taskRunId) => ({
|
|
100
|
+
const toReviewEvent = (nodeId, eventType, source, taskRunId, episodeId) => ({
|
|
93
101
|
id: createId("review"),
|
|
102
|
+
episode_id: episodeId,
|
|
94
103
|
node_id: nodeId,
|
|
95
104
|
task_run_id: taskRunId,
|
|
96
105
|
event_type: eventType,
|
|
97
106
|
source,
|
|
98
107
|
created_at: nowIso()
|
|
99
108
|
});
|
|
109
|
+
const toManualOverrideAttributionRecord = (input) => {
|
|
110
|
+
const timestamp = nowIso();
|
|
111
|
+
return {
|
|
112
|
+
id: stableId("attr", `${input.injectionEvent?.injection_id ?? "manual"}:${input.nodeId}:manual_override:${input.feedback}:${timestamp}`),
|
|
113
|
+
injection_id: input.injectionEvent?.injection_id,
|
|
114
|
+
node_id: input.nodeId,
|
|
115
|
+
episode_id: input.episodeId ?? input.injectionEvent?.episode_id,
|
|
116
|
+
intervention_strength: input.injectionEvent?.scorecard?.interventionStrength,
|
|
117
|
+
injection_mode: input.injectionEvent?.mode,
|
|
118
|
+
delivery_mode: input.injectionEvent?.delivery_mode,
|
|
119
|
+
delivered: Boolean(input.injectionEvent?.delivered),
|
|
120
|
+
outcome: input.injectionEvent?.was_successful === true
|
|
121
|
+
? "success"
|
|
122
|
+
: input.injectionEvent?.was_successful === false
|
|
123
|
+
? "failure"
|
|
124
|
+
: "unknown",
|
|
125
|
+
attribution_verdict: input.feedback === "helped" ? "strong_helped" : "strong_harmed",
|
|
126
|
+
confidence: "high",
|
|
127
|
+
evidence_refs: input.evidenceRefs,
|
|
128
|
+
user_override: input.feedback,
|
|
129
|
+
source: "manual_override",
|
|
130
|
+
attribution_reason: "manual_override",
|
|
131
|
+
created_at: timestamp,
|
|
132
|
+
resolved_at: timestamp
|
|
133
|
+
};
|
|
134
|
+
};
|
|
100
135
|
const deriveNodeRisk = (node) => {
|
|
101
136
|
if (node.state === "candidate") {
|
|
102
137
|
return "high";
|
|
@@ -353,6 +388,9 @@ export class ExperienceInteractionService {
|
|
|
353
388
|
hybridWorkerClient;
|
|
354
389
|
inputRepo;
|
|
355
390
|
injectionRepo;
|
|
391
|
+
attributionRecordRepo;
|
|
392
|
+
repoPolicyRepo;
|
|
393
|
+
episodeRepo;
|
|
356
394
|
nodeRepo;
|
|
357
395
|
candidateRepo;
|
|
358
396
|
jobRepo;
|
|
@@ -367,6 +405,9 @@ export class ExperienceInteractionService {
|
|
|
367
405
|
bootstrapDatabase(db);
|
|
368
406
|
this.inputRepo = new InputRecordRepository(db);
|
|
369
407
|
this.injectionRepo = new InjectionRepository(db);
|
|
408
|
+
this.attributionRecordRepo = new AttributionRecordRepository(db);
|
|
409
|
+
this.repoPolicyRepo = new RepoPolicyRepository(db);
|
|
410
|
+
this.episodeRepo = new EpisodeRepository(db);
|
|
370
411
|
this.nodeRepo = new NodeRepository(db);
|
|
371
412
|
this.candidateRepo = new CandidateRepository(db);
|
|
372
413
|
this.jobRepo = new DistillationJobRepository(db);
|
|
@@ -458,15 +499,19 @@ export class ExperienceInteractionService {
|
|
|
458
499
|
if (!record) {
|
|
459
500
|
return undefined;
|
|
460
501
|
}
|
|
461
|
-
const
|
|
502
|
+
const episodeProjection = record.episode_id ? this.episodeRepo.getByEpisodeId(record.episode_id) : undefined;
|
|
503
|
+
const injectionEvent = episodeProjection?.injection_events[0] ?? (record.session_id
|
|
462
504
|
? this.injectionRepo.getLatestBySessionId(record.session_id)
|
|
463
505
|
: record.injected_node_ids.length
|
|
464
506
|
? this.injectionRepo.getLatest()
|
|
465
|
-
: undefined;
|
|
507
|
+
: undefined);
|
|
466
508
|
const selectedNodeIds = injectionEvent?.injected_node_ids?.length
|
|
467
509
|
? injectionEvent.injected_node_ids
|
|
468
510
|
: record.injected_node_ids;
|
|
469
511
|
const injectedNodes = this.nodeRepo.listByIds(selectedNodeIds);
|
|
512
|
+
const attributionRecords = episodeProjection?.attribution_records ?? (injectionEvent
|
|
513
|
+
? this.attributionRecordRepo.listByInjectionId(injectionEvent.injection_id)
|
|
514
|
+
: selectedNodeIds.flatMap((nodeId) => this.attributionRecordRepo.listByNodeId(nodeId)));
|
|
470
515
|
const scorecard = injectionEvent?.scorecard ??
|
|
471
516
|
(selectedNodeIds.length
|
|
472
517
|
? buildInjectionScorecard({
|
|
@@ -479,17 +524,19 @@ export class ExperienceInteractionService {
|
|
|
479
524
|
injected_node_ids: selectedNodeIds
|
|
480
525
|
}, "inject", injectedNodes, record.session_id)
|
|
481
526
|
: undefined);
|
|
482
|
-
const taskRun = record.session_id ? this.taskRunRepo.getLatestBySessionId(record.session_id) : undefined;
|
|
483
|
-
const reviewEvents = taskRun?.id ? this.reviewEventRepo.listByTaskRunId(taskRun.id) : [];
|
|
527
|
+
const taskRun = episodeProjection?.task_run ?? (record.session_id ? this.taskRunRepo.getLatestBySessionId(record.session_id) : undefined);
|
|
528
|
+
const reviewEvents = episodeProjection?.review_events ?? (taskRun?.id ? this.reviewEventRepo.listByTaskRunId(taskRun.id) : []);
|
|
484
529
|
const autoFeedback = summarizeAutomaticFeedback(reviewEvents);
|
|
485
|
-
const intervention =
|
|
530
|
+
const intervention = injectionEvent?.mode === "skip"
|
|
486
531
|
? "skip"
|
|
487
|
-
:
|
|
488
|
-
?
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
532
|
+
: selectedNodeIds.length === 0
|
|
533
|
+
? "skip"
|
|
534
|
+
: injectionEvent && !injectionEvent.delivered
|
|
535
|
+
? injectionEvent.delivery_mode === "holdout"
|
|
536
|
+
? "holdout"
|
|
537
|
+
: "shadow"
|
|
538
|
+
: "inject";
|
|
539
|
+
const outcomeRecord = episodeProjection?.outcome_records[0] ?? (taskRun?.id ? this.outcomeRepo.listByTaskRunId(taskRun.id)[0] : undefined);
|
|
493
540
|
const latestAutomaticFeedback = reviewEvents.find((event) => event.source === "automatic");
|
|
494
541
|
const autoFeedbackReason = inferAutoFeedbackReason({
|
|
495
542
|
explicitReason: injectionEvent?.attribution_reason,
|
|
@@ -500,6 +547,7 @@ export class ExperienceInteractionService {
|
|
|
500
547
|
const decisionExplanation = buildDecisionExplanation({ intervention, scorecard });
|
|
501
548
|
return {
|
|
502
549
|
sessionId: record.session_id,
|
|
550
|
+
episodeId: record.episode_id,
|
|
503
551
|
scopeId: record.scope_id,
|
|
504
552
|
taskType: record.task_type,
|
|
505
553
|
intervention,
|
|
@@ -507,6 +555,8 @@ export class ExperienceInteractionService {
|
|
|
507
555
|
delivered: injectionEvent?.delivered,
|
|
508
556
|
autoFeedback,
|
|
509
557
|
autoFeedbackReason,
|
|
558
|
+
attributionRecords,
|
|
559
|
+
episodeProjection,
|
|
510
560
|
outcome: record.outcome_signal,
|
|
511
561
|
injectedNodes: injectedNodes.map(toNodeSummary),
|
|
512
562
|
hints: injectedNodes.map((node) => node.compact_hint),
|
|
@@ -515,6 +565,7 @@ export class ExperienceInteractionService {
|
|
|
515
565
|
decisionExplanation,
|
|
516
566
|
trustSummary: buildTrustSummary({ scorecard, injectedNodes: injectedNodes.map(toNodeSummary) }),
|
|
517
567
|
retrievalNotes: buildRetrievalNotes(scorecard),
|
|
568
|
+
retrievalPolicySummary: buildRetrievalPolicyInspectionSummary(scorecard),
|
|
518
569
|
timeline: buildLatestTimeline({
|
|
519
570
|
record,
|
|
520
571
|
taskRunCreatedAt: taskRun?.created_at,
|
|
@@ -537,27 +588,32 @@ export class ExperienceInteractionService {
|
|
|
537
588
|
if (!event) {
|
|
538
589
|
return undefined;
|
|
539
590
|
}
|
|
540
|
-
const
|
|
591
|
+
const episodeProjection = event.episode_id ? this.episodeRepo.getByEpisodeId(event.episode_id) : undefined;
|
|
592
|
+
const taskRun = episodeProjection?.task_run ?? (event.session_id ? this.taskRunRepo.getLatestBySessionId(event.session_id) : undefined);
|
|
541
593
|
const latestRecord = event.session_id ? this.inputRepo.getLatestBySessionId(event.session_id) : undefined;
|
|
542
594
|
if (latestRecord) {
|
|
543
595
|
return this.inspectRecord(latestRecord);
|
|
544
596
|
}
|
|
545
597
|
const injectedNodes = this.nodeRepo.listByIds(event.injected_node_ids);
|
|
546
|
-
const
|
|
598
|
+
const attributionRecords = episodeProjection?.attribution_records ?? this.attributionRecordRepo.listByInjectionId(event.injection_id);
|
|
599
|
+
const reviewEvents = episodeProjection?.review_events ?? (taskRun?.id ? this.reviewEventRepo.listByTaskRunId(taskRun.id) : []);
|
|
547
600
|
const autoFeedback = summarizeAutomaticFeedback(reviewEvents);
|
|
548
601
|
const latestAutomaticFeedback = reviewEvents.find((reviewEvent) => reviewEvent.source === "automatic");
|
|
549
|
-
const intervention =
|
|
550
|
-
?
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
602
|
+
const intervention = event.mode === "skip"
|
|
603
|
+
? "skip"
|
|
604
|
+
: !event.delivered
|
|
605
|
+
? event.delivery_mode === "holdout"
|
|
606
|
+
? "holdout"
|
|
607
|
+
: "shadow"
|
|
608
|
+
: "inject";
|
|
609
|
+
const outcomeRecord = episodeProjection?.outcome_records[0] ?? (taskRun?.id ? this.outcomeRepo.listByTaskRunId(taskRun.id)[0] : undefined);
|
|
555
610
|
const outcome = outcomeRecord?.outcome_signal ??
|
|
556
611
|
(taskRun?.final_status === "success" ? "success" : taskRun?.final_status === "failure" ? "failure" : "unknown");
|
|
557
612
|
const summary = event.task_summary ?? taskRun?.task_summary ?? "Latest injection event";
|
|
558
613
|
const decisionExplanation = buildDecisionExplanation({ intervention, scorecard: event.scorecard });
|
|
559
614
|
return {
|
|
560
615
|
sessionId: event.session_id,
|
|
616
|
+
episodeId: event.episode_id,
|
|
561
617
|
scopeId: event.scope_id,
|
|
562
618
|
taskType: event.task_type,
|
|
563
619
|
intervention,
|
|
@@ -570,6 +626,8 @@ export class ExperienceInteractionService {
|
|
|
570
626
|
intervention,
|
|
571
627
|
outcome
|
|
572
628
|
}),
|
|
629
|
+
attributionRecords,
|
|
630
|
+
episodeProjection,
|
|
573
631
|
outcome,
|
|
574
632
|
injectedNodes: injectedNodes.map(toNodeSummary),
|
|
575
633
|
hints: injectedNodes.map((node) => node.compact_hint),
|
|
@@ -578,6 +636,7 @@ export class ExperienceInteractionService {
|
|
|
578
636
|
decisionExplanation,
|
|
579
637
|
trustSummary: buildTrustSummary({ scorecard: event.scorecard, injectedNodes: injectedNodes.map(toNodeSummary) }),
|
|
580
638
|
retrievalNotes: buildRetrievalNotes(event.scorecard),
|
|
639
|
+
retrievalPolicySummary: buildRetrievalPolicyInspectionSummary(event.scorecard),
|
|
581
640
|
timeline: buildLatestTimeline({
|
|
582
641
|
record: {
|
|
583
642
|
record_id: `injection:${event.injection_id}`,
|
|
@@ -661,6 +720,77 @@ export class ExperienceInteractionService {
|
|
|
661
720
|
inspectLearningSummary() {
|
|
662
721
|
return this.buildLearningSummary();
|
|
663
722
|
}
|
|
723
|
+
inspectHygiene(cwd = process.cwd(), filters = {}) {
|
|
724
|
+
const scopeId = filters.scopeId ?? resolveScope(cwd).scope_id;
|
|
725
|
+
const candidateStates = ["pending", "distilled", "failed", "discarded"];
|
|
726
|
+
return buildHygieneReviewReport({
|
|
727
|
+
nodes: this.nodeRepo.listByScope(scopeId),
|
|
728
|
+
candidates: candidateStates.flatMap((state) => this.candidateRepo.listByLifecycleState(state)).filter((candidate) => candidate.scope_id === scopeId),
|
|
729
|
+
attributionRecords: this.attributionRecordRepo.listRecentByScope(scopeId, Math.max(50, filters.limit ?? 20)),
|
|
730
|
+
filters: {
|
|
731
|
+
...filters,
|
|
732
|
+
scopeId
|
|
733
|
+
}
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
inspectExportDrafts(cwd = process.cwd(), filters = {}) {
|
|
737
|
+
const scopeId = filters.scopeId ?? resolveScope(cwd).scope_id;
|
|
738
|
+
const candidateStates = ["pending", "distilled", "failed", "discarded"];
|
|
739
|
+
const nodes = this.nodeRepo.listByScope(scopeId);
|
|
740
|
+
const explicitLowReadiness = Boolean(filters.nodeId || filters.risk || filters.state || filters.deliveryState);
|
|
741
|
+
const candidateNodes = nodes
|
|
742
|
+
.filter((node) => !filters.nodeId || node.id === filters.nodeId)
|
|
743
|
+
.filter((node) => !filters.nodeType || node.node_type === filters.nodeType)
|
|
744
|
+
.filter((node) => !filters.taskFamily || node.task_type === filters.taskFamily)
|
|
745
|
+
.filter((node) => !filters.state || node.state === filters.state)
|
|
746
|
+
.filter((node) => !filters.deliveryState || node.delivery_state === filters.deliveryState)
|
|
747
|
+
.filter((node) => explicitLowReadiness || (node.state === "active" && (!node.delivery_state || node.delivery_state === "eligible") && node.harmed_count <= node.helped_count));
|
|
748
|
+
const candidates = candidateStates
|
|
749
|
+
.flatMap((state) => this.candidateRepo.listByLifecycleState(state))
|
|
750
|
+
.filter((candidate) => candidate.scope_id === scopeId);
|
|
751
|
+
const attributionRecordsById = new Map();
|
|
752
|
+
for (const record of this.attributionRecordRepo.listRecentByScope(scopeId, Math.max(50, filters.limit ?? 20))) {
|
|
753
|
+
attributionRecordsById.set(record.id, record);
|
|
754
|
+
}
|
|
755
|
+
for (const node of candidateNodes) {
|
|
756
|
+
for (const record of this.attributionRecordRepo.listByNodeId(node.id)) {
|
|
757
|
+
attributionRecordsById.set(record.id, record);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
const attributionRecords = [...attributionRecordsById.values()];
|
|
761
|
+
const hygiene = buildHygieneReviewReport({
|
|
762
|
+
nodes,
|
|
763
|
+
candidates,
|
|
764
|
+
attributionRecords,
|
|
765
|
+
filters: {
|
|
766
|
+
scopeId,
|
|
767
|
+
limit: Math.max(50, filters.limit ?? 20)
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
return buildExperienceExportDraftReport({
|
|
771
|
+
nodes,
|
|
772
|
+
candidates,
|
|
773
|
+
attributionRecords,
|
|
774
|
+
hygieneFindings: hygiene.findings,
|
|
775
|
+
filters: {
|
|
776
|
+
...filters,
|
|
777
|
+
scopeId
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
inspectReview(cwd = process.cwd(), filters = {}) {
|
|
782
|
+
const scopeId = filters.scopeId ?? resolveScope(cwd).scope_id;
|
|
783
|
+
const limit = filters.limit ?? 5;
|
|
784
|
+
const repo = this.inspectRepoSummary(cwd);
|
|
785
|
+
const hygiene = this.inspectHygiene(cwd, { scopeId, limit });
|
|
786
|
+
const exportDrafts = this.inspectExportDrafts(cwd, { scopeId, limit });
|
|
787
|
+
return buildOperatorReviewFlow({
|
|
788
|
+
repo,
|
|
789
|
+
hygiene,
|
|
790
|
+
exportDrafts,
|
|
791
|
+
limit
|
|
792
|
+
});
|
|
793
|
+
}
|
|
664
794
|
buildLearningSummary(scopeId) {
|
|
665
795
|
const candidateStates = ["pending", "distilled", "failed", "discarded"];
|
|
666
796
|
const jobStates = ["pending", "processing", "succeeded", "failed", "discarded"];
|
|
@@ -724,6 +854,7 @@ export class ExperienceInteractionService {
|
|
|
724
854
|
const latestRecord = this.inputRepo.getLatestByScope(scope.scope_id);
|
|
725
855
|
const latest = latestRecord ? this.inspectRecord(latestRecord) : undefined;
|
|
726
856
|
const learning = this.buildLearningSummary(scope.scope_id);
|
|
857
|
+
const policyInspection = this.inspectRepoPolicy(cwd);
|
|
727
858
|
return buildRepoSummary({
|
|
728
859
|
scope: {
|
|
729
860
|
scopeId: scope.scope_id,
|
|
@@ -731,9 +862,20 @@ export class ExperienceInteractionService {
|
|
|
731
862
|
rootPath: scope.root_path
|
|
732
863
|
},
|
|
733
864
|
latest: latest && latest.scopeId === scope.scope_id ? latest : undefined,
|
|
734
|
-
learning
|
|
865
|
+
learning,
|
|
866
|
+
policyInspection
|
|
735
867
|
});
|
|
736
868
|
}
|
|
869
|
+
inspectRepoPolicy(cwd = process.cwd()) {
|
|
870
|
+
const scope = resolveScope(cwd);
|
|
871
|
+
const policy = this.repoPolicyRepo.get(scope.scope_id) ??
|
|
872
|
+
buildDefaultRepoPolicy(scope.scope_id, this.config.repoExperienceMode);
|
|
873
|
+
return inspectRepoPolicyEvidence(policy, this.attributionRecordRepo.listRecentEligibleByScope(scope.scope_id), this.injectionRepo.listRecentResolvedByScope(scope.scope_id));
|
|
874
|
+
}
|
|
875
|
+
restoreRepoPolicy(cwd = process.cwd()) {
|
|
876
|
+
const scope = resolveScope(cwd);
|
|
877
|
+
return this.repoPolicyRepo.restore(scope.scope_id, this.config.repoExperienceMode);
|
|
878
|
+
}
|
|
737
879
|
inspectFirstValueReadiness(cwd = process.cwd()) {
|
|
738
880
|
const scope = resolveScope(cwd);
|
|
739
881
|
const summary = this.buildLearningSummary(scope.scope_id);
|
|
@@ -869,9 +1011,25 @@ export class ExperienceInteractionService {
|
|
|
869
1011
|
const taskRunId = record.session_id
|
|
870
1012
|
? this.taskRunRepo.getLatestBySessionId(record.session_id)?.id
|
|
871
1013
|
: undefined;
|
|
1014
|
+
const episodeId = record.episode_id;
|
|
1015
|
+
const injectionEvent = record.session_id
|
|
1016
|
+
? this.injectionRepo.getLatestBySessionId(record.session_id)
|
|
1017
|
+
: undefined;
|
|
1018
|
+
const evidenceRefs = [
|
|
1019
|
+
record.record_id,
|
|
1020
|
+
taskRunId,
|
|
1021
|
+
injectionEvent?.injection_id
|
|
1022
|
+
].filter((value) => Boolean(value));
|
|
872
1023
|
for (const node of nodes) {
|
|
873
1024
|
this.nodeRepo.upsert(applyGovernedNodeFeedback(node, feedback, this.deriveOriginProfile(node)));
|
|
874
|
-
this.reviewEventRepo.upsert(toReviewEvent(node.id, feedback === "helped" ? "mark_helped" : "mark_harmed", "user", taskRunId));
|
|
1025
|
+
this.reviewEventRepo.upsert(toReviewEvent(node.id, feedback === "helped" ? "mark_helped" : "mark_harmed", "user", taskRunId, episodeId));
|
|
1026
|
+
this.attributionRecordRepo.insert(toManualOverrideAttributionRecord({
|
|
1027
|
+
nodeId: node.id,
|
|
1028
|
+
feedback,
|
|
1029
|
+
injectionEvent,
|
|
1030
|
+
episodeId,
|
|
1031
|
+
evidenceRefs
|
|
1032
|
+
}));
|
|
875
1033
|
}
|
|
876
1034
|
return {
|
|
877
1035
|
status: "updated",
|
|
@@ -890,6 +1048,11 @@ export class ExperienceInteractionService {
|
|
|
890
1048
|
}
|
|
891
1049
|
this.nodeRepo.upsert(applyGovernedNodeFeedback(node, feedback, this.deriveOriginProfile(node)));
|
|
892
1050
|
this.reviewEventRepo.upsert(toReviewEvent(nodeId, feedback === "helped" ? "mark_helped" : "mark_harmed", "user"));
|
|
1051
|
+
this.attributionRecordRepo.insert(toManualOverrideAttributionRecord({
|
|
1052
|
+
nodeId,
|
|
1053
|
+
feedback,
|
|
1054
|
+
evidenceRefs: [`manual:${nodeId}`]
|
|
1055
|
+
}));
|
|
893
1056
|
return {
|
|
894
1057
|
status: "updated",
|
|
895
1058
|
feedback,
|