@akalsey/sapience-feedback 0.2.0 → 0.3.1
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/src/calibration-bridge.js +10 -3
- package/dist/src/events.js +12 -0
- package/dist/src/feedback-handler.js +32 -1
- package/dist/src/service.js +3 -0
- package/dist/src/types.js +1 -0
- package/package.json +1 -1
|
@@ -17,10 +17,10 @@ async function saveProfile(profile, path) {
|
|
|
17
17
|
export async function applyFeedbackToProfile(signal, calibrationPath) {
|
|
18
18
|
const profile = await loadProfile(calibrationPath);
|
|
19
19
|
if (profile.length === 0)
|
|
20
|
-
return;
|
|
20
|
+
return { status: "orphaned" };
|
|
21
21
|
const idx = profile.findIndex(e => e.domain === signal.domain && e.action_class === signal.action_class);
|
|
22
22
|
if (idx === -1)
|
|
23
|
-
return;
|
|
23
|
+
return { status: "orphaned" };
|
|
24
24
|
const entry = profile[idx];
|
|
25
25
|
let updated;
|
|
26
26
|
if (signal.type === "confirmation") {
|
|
@@ -33,7 +33,14 @@ export async function applyFeedbackToProfile(signal, calibrationPath) {
|
|
|
33
33
|
updated = { ...entry, tier: signal.suggested_tier, last_calibrated: new Date().toISOString() };
|
|
34
34
|
}
|
|
35
35
|
else {
|
|
36
|
-
return;
|
|
36
|
+
return { status: "noop" };
|
|
37
37
|
}
|
|
38
38
|
await saveProfile(profile.map((e, i) => i === idx ? updated : e), calibrationPath);
|
|
39
|
+
return {
|
|
40
|
+
status: "applied",
|
|
41
|
+
old_confidence: entry.confidence,
|
|
42
|
+
new_confidence: updated.confidence,
|
|
43
|
+
old_tier: entry.tier,
|
|
44
|
+
new_tier: updated.tier,
|
|
45
|
+
};
|
|
39
46
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { appendFile, mkdir } from "fs/promises";
|
|
2
|
+
import { dirname } from "path";
|
|
3
|
+
export async function appendEvent(eventsPath, event) {
|
|
4
|
+
try {
|
|
5
|
+
const full = { ...event, ts: event.ts ?? new Date().toISOString() };
|
|
6
|
+
await mkdir(dirname(eventsPath), { recursive: true });
|
|
7
|
+
await appendFile(eventsPath, JSON.stringify(full) + "\n", "utf-8");
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
// Observability must never break the host plugin.
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -2,6 +2,7 @@ import { parseMessage } from "./feedback-parser.js";
|
|
|
2
2
|
import { classifyWithLlm } from "./llm-classifier.js";
|
|
3
3
|
import { appendFeedback } from "./log-writer.js";
|
|
4
4
|
import { applyFeedbackToProfile } from "./calibration-bridge.js";
|
|
5
|
+
import { appendEvent } from "./events.js";
|
|
5
6
|
import { generateId } from "./utils.js";
|
|
6
7
|
export function shouldClassify(text, config) {
|
|
7
8
|
const trimmed = text.trim();
|
|
@@ -35,12 +36,42 @@ export async function persistSignal(signal, ctx) {
|
|
|
35
36
|
meta_pointer: metaPointer,
|
|
36
37
|
};
|
|
37
38
|
await appendFeedback(entry, ctx.config.logPath);
|
|
38
|
-
await applyFeedbackToProfile(signal, ctx.config.calibrationPath);
|
|
39
|
+
const result = await applyFeedbackToProfile(signal, ctx.config.calibrationPath);
|
|
39
40
|
if (metaPointer && ctx.config.memoryEnabled && ctx.memoryAdd) {
|
|
40
41
|
await ctx.memoryAdd({
|
|
41
42
|
content: metaPointer,
|
|
42
43
|
metadata: { tags: ["feedback", "behavioral-correction", signal.domain], source: "feedback" },
|
|
43
44
|
});
|
|
44
45
|
}
|
|
46
|
+
await appendEvent(ctx.config.eventsPath, {
|
|
47
|
+
plugin: "feedback",
|
|
48
|
+
type: "signal_detected",
|
|
49
|
+
signal_type: signal.type,
|
|
50
|
+
domain: signal.domain,
|
|
51
|
+
action_class: signal.action_class,
|
|
52
|
+
source: signal.source ?? "regex",
|
|
53
|
+
});
|
|
54
|
+
if (result.status === "orphaned") {
|
|
55
|
+
await appendEvent(ctx.config.eventsPath, {
|
|
56
|
+
plugin: "feedback",
|
|
57
|
+
type: "signal_orphaned",
|
|
58
|
+
signal_type: signal.type,
|
|
59
|
+
domain: signal.domain,
|
|
60
|
+
action_class: signal.action_class,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else if (result.status === "applied") {
|
|
64
|
+
await appendEvent(ctx.config.eventsPath, {
|
|
65
|
+
plugin: "feedback",
|
|
66
|
+
type: "calibration_change",
|
|
67
|
+
domain: signal.domain,
|
|
68
|
+
action_class: signal.action_class,
|
|
69
|
+
old_confidence: result.old_confidence,
|
|
70
|
+
new_confidence: result.new_confidence,
|
|
71
|
+
old_tier: result.old_tier,
|
|
72
|
+
new_tier: result.new_tier,
|
|
73
|
+
source: "feedback",
|
|
74
|
+
});
|
|
75
|
+
}
|
|
45
76
|
return entry;
|
|
46
77
|
}
|
package/dist/src/service.js
CHANGED
|
@@ -10,6 +10,7 @@ function mergeConfig(raw, workspaceDir) {
|
|
|
10
10
|
...raw,
|
|
11
11
|
logPath: resolveDataPath(raw.logPath, workspaceDir, DEFAULT_CONFIG.logPath),
|
|
12
12
|
calibrationPath: resolveDataPath(raw.calibrationPath, workspaceDir, DEFAULT_CONFIG.calibrationPath),
|
|
13
|
+
eventsPath: resolveDataPath(raw.eventsPath, workspaceDir, DEFAULT_CONFIG.eventsPath),
|
|
13
14
|
semanticDetection: { ...DEFAULT_CONFIG.semanticDetection, ...rawSemantic },
|
|
14
15
|
};
|
|
15
16
|
}
|
|
@@ -24,6 +25,8 @@ export default definePluginEntry({
|
|
|
24
25
|
name: "Sapience Feedback",
|
|
25
26
|
description: "Persists behavioral corrections and confirmations into the sapience calibration profile",
|
|
26
27
|
register(api) {
|
|
28
|
+
if (!api.runtime?.agent?.resolveAgentWorkspaceDir)
|
|
29
|
+
return;
|
|
27
30
|
const workspaceDir = api.runtime.agent.resolveAgentWorkspaceDir(api.pluginConfig);
|
|
28
31
|
const config = mergeConfig(api.pluginConfig, workspaceDir);
|
|
29
32
|
const llm = getLlmClient(api);
|
package/dist/src/types.js
CHANGED