openclaw-topic-shift-reset 0.4.1 → 0.4.3
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/README.md +2 -2
- package/docs/configuration.md +1 -1
- package/package.json +1 -1
- package/src/index.ts +40 -25
package/README.md
CHANGED
|
@@ -154,8 +154,8 @@ All plugin logs are prefixed with `topic-shift-reset:`.
|
|
|
154
154
|
|
|
155
155
|
### Debug (`debug: true`)
|
|
156
156
|
|
|
157
|
-
- `classify source=<...> kind=<warmup|stable|suspect|rotate-hard|rotate-soft> reason=<...>
|
|
158
|
-
Full classifier output and metrics for a processed message.
|
|
157
|
+
- `classify source=<...> kind=<warmup|stable|suspect|rotate-hard|rotate-soft> reason=<...> ... textHash=<...> tokens=[...] text="..."`
|
|
158
|
+
Full classifier output and metrics plus a compact message preview for a processed message.
|
|
159
159
|
- `suspect-queued session=<...>`
|
|
160
160
|
Soft-suspect state queued for clarification steering.
|
|
161
161
|
- `ask-injected session=<...>`
|
package/docs/configuration.md
CHANGED
|
@@ -47,7 +47,7 @@ With `softSuspect.mode: "strict"` (default), a soft-confirm reset is blocked unt
|
|
|
47
47
|
- `softSuspect.prompt`: optional steer text injected on soft-suspect.
|
|
48
48
|
- `softSuspect.ttlSeconds`: expiry for pending soft-suspect steer.
|
|
49
49
|
- `dryRun`: logs would-rotate events without session resets.
|
|
50
|
-
- `debug`: emits per-message classifier diagnostics.
|
|
50
|
+
- `debug`: emits per-message classifier diagnostics, including compact message previews.
|
|
51
51
|
|
|
52
52
|
## Built-in preset defaults
|
|
53
53
|
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -329,6 +329,8 @@ const STALE_SESSION_STATE_MS = 4 * 60 * 60 * 1000;
|
|
|
329
329
|
const MAX_RECENT_MESSAGE_EVENTS = 20_000;
|
|
330
330
|
const MESSAGE_EVENT_TTL_MS = 5 * 60 * 1000;
|
|
331
331
|
const ROTATION_DEDUPE_MS = 25_000;
|
|
332
|
+
const DEBUG_LOG_TEXT_PREVIEW_CHARS = 180;
|
|
333
|
+
const DEBUG_LOG_TOKEN_PREVIEW_COUNT = 12;
|
|
332
334
|
const PERSISTENCE_SCHEMA_VERSION = 1;
|
|
333
335
|
const PERSISTENCE_FILE_NAME = "runtime-state.v1.json";
|
|
334
336
|
const PERSISTENCE_FLUSH_DEBOUNCE_MS = 1_200;
|
|
@@ -1250,8 +1252,9 @@ function classifyMessage(params: {
|
|
|
1250
1252
|
now: number;
|
|
1251
1253
|
}): ClassificationDecision {
|
|
1252
1254
|
const { cfg, state, now } = params;
|
|
1255
|
+
const hasSimilarity = params.usedEmbedding && typeof params.similarity === "number";
|
|
1253
1256
|
const score =
|
|
1254
|
-
|
|
1257
|
+
hasSimilarity
|
|
1255
1258
|
? 0.7 * (1 - params.similarity) +
|
|
1256
1259
|
0.15 * params.lexical.lexicalDistance +
|
|
1257
1260
|
0.15 * params.lexical.novelty
|
|
@@ -1279,21 +1282,25 @@ function classifyMessage(params: {
|
|
|
1279
1282
|
return { kind: "stable", metrics, reason: "cooldown" };
|
|
1280
1283
|
}
|
|
1281
1284
|
|
|
1285
|
+
const lexicalHardSignal =
|
|
1286
|
+
params.lexical.score >= cfg.hardScoreThreshold ||
|
|
1287
|
+
(params.lexical.novelty >= cfg.hardNoveltyThreshold &&
|
|
1288
|
+
params.lexical.lexicalDistance >= 0.65);
|
|
1282
1289
|
const hardSignal =
|
|
1283
|
-
|
|
1284
|
-
(
|
|
1285
|
-
|
|
1286
|
-
params.lexical.novelty >= cfg.hardNoveltyThreshold
|
|
1287
|
-
: params.lexical.novelty >= cfg.hardNoveltyThreshold &&
|
|
1288
|
-
params.lexical.lexicalDistance >= 0.65);
|
|
1290
|
+
hasSimilarity &&
|
|
1291
|
+
(score >= cfg.hardScoreThreshold ||
|
|
1292
|
+
(params.similarity <= cfg.hardSimilarityThreshold &&
|
|
1293
|
+
params.lexical.novelty >= cfg.hardNoveltyThreshold));
|
|
1289
1294
|
|
|
1290
1295
|
if (hardSignal) {
|
|
1291
1296
|
return { kind: "rotate-hard", metrics, reason: "hard-threshold" };
|
|
1292
1297
|
}
|
|
1293
1298
|
|
|
1299
|
+
const forceSoftPathFromLexicalHard = !hasSimilarity && lexicalHardSignal;
|
|
1294
1300
|
const softSignal =
|
|
1301
|
+
forceSoftPathFromLexicalHard ||
|
|
1295
1302
|
score >= cfg.softScoreThreshold ||
|
|
1296
|
-
(
|
|
1303
|
+
(hasSimilarity
|
|
1297
1304
|
? params.similarity <= cfg.softSimilarityThreshold &&
|
|
1298
1305
|
params.lexical.novelty >= cfg.softNoveltyThreshold
|
|
1299
1306
|
: params.lexical.novelty >= cfg.softNoveltyThreshold &&
|
|
@@ -2057,23 +2064,31 @@ export default function register(api: OpenClawPluginApi): void {
|
|
|
2057
2064
|
}
|
|
2058
2065
|
|
|
2059
2066
|
if (cfg.debug) {
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2067
|
+
const textPreview = truncateText(text, DEBUG_LOG_TEXT_PREVIEW_CHARS);
|
|
2068
|
+
const rawPreview = truncateText(rawText, DEBUG_LOG_TEXT_PREVIEW_CHARS);
|
|
2069
|
+
const debugFields = [
|
|
2070
|
+
`topic-shift-reset: classify`,
|
|
2071
|
+
`source=${params.source}`,
|
|
2072
|
+
`kind=${decision.kind}`,
|
|
2073
|
+
`reason=${decision.reason}`,
|
|
2074
|
+
`session=${sessionKey}`,
|
|
2075
|
+
`score=${decision.metrics.score.toFixed(3)}`,
|
|
2076
|
+
`novelty=${decision.metrics.novelty.toFixed(3)}`,
|
|
2077
|
+
`lex=${decision.metrics.lexicalDistance.toFixed(3)}`,
|
|
2078
|
+
`uniq=${decision.metrics.uniqueTokenRatio.toFixed(3)}`,
|
|
2079
|
+
`entropy=${decision.metrics.entropy.toFixed(3)}`,
|
|
2080
|
+
`sim=${typeof decision.metrics.similarity === "number" ? decision.metrics.similarity.toFixed(3) : "n/a"}`,
|
|
2081
|
+
`embed=${decision.metrics.usedEmbedding ? "1" : "0"}`,
|
|
2082
|
+
`pending=${state.pendingSoftSignals}`,
|
|
2083
|
+
`baseline=${baselineTokens.size}`,
|
|
2084
|
+
`textHash=${contentHash}`,
|
|
2085
|
+
`tokens=${maybeJson(tokenList.slice(0, DEBUG_LOG_TOKEN_PREVIEW_COUNT))}`,
|
|
2086
|
+
`text=${maybeJson(textPreview)}`,
|
|
2087
|
+
];
|
|
2088
|
+
if (rawPreview !== textPreview) {
|
|
2089
|
+
debugFields.push(`raw=${maybeJson(rawPreview)}`);
|
|
2090
|
+
}
|
|
2091
|
+
api.logger.debug(debugFields.join(" "));
|
|
2077
2092
|
}
|
|
2078
2093
|
|
|
2079
2094
|
if (decision.kind === "warmup") {
|