sensorium-mcp 3.1.4 → 3.1.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/dist/config/misc-settings.d.ts +1 -0
- package/dist/config/misc-settings.d.ts.map +1 -1
- package/dist/config/misc-settings.js +12 -6
- package/dist/config/misc-settings.js.map +1 -1
- package/dist/dashboard/routes/prompts.d.ts +2 -2
- package/dist/dashboard/routes/prompts.d.ts.map +1 -1
- package/dist/dashboard/routes/prompts.js +2 -2
- package/dist/dashboard/routes/prompts.js.map +1 -1
- package/dist/dashboard/spa.html +5 -5
- package/dist/data/memory/bootstrap.d.ts +0 -7
- package/dist/data/memory/bootstrap.d.ts.map +1 -1
- package/dist/data/memory/bootstrap.js +6 -25
- package/dist/data/memory/bootstrap.js.map +1 -1
- package/dist/data/memory/index.d.ts +0 -4
- package/dist/data/memory/index.d.ts.map +1 -1
- package/dist/data/memory/index.js +0 -4
- package/dist/data/memory/index.js.map +1 -1
- package/dist/data/memory/key-knowledge.d.ts +13 -0
- package/dist/data/memory/key-knowledge.d.ts.map +1 -1
- package/dist/data/memory/key-knowledge.js +11 -1
- package/dist/data/memory/key-knowledge.js.map +1 -1
- package/dist/data/memory/narrative-resolutions.d.ts +7 -9
- package/dist/data/memory/narrative-resolutions.d.ts.map +1 -1
- package/dist/data/memory/narrative-resolutions.js +7 -15
- package/dist/data/memory/narrative-resolutions.js.map +1 -1
- package/dist/data/memory/narrative.d.ts.map +1 -1
- package/dist/data/memory/narrative.js +2 -4
- package/dist/data/memory/narrative.js.map +1 -1
- package/dist/data/memory/note-embeddings.d.ts +7 -0
- package/dist/data/memory/note-embeddings.d.ts.map +1 -1
- package/dist/data/memory/note-embeddings.js +6 -2
- package/dist/data/memory/note-embeddings.js.map +1 -1
- package/dist/data/memory/semantic-notes.d.ts +4 -7
- package/dist/data/memory/semantic-notes.d.ts.map +1 -1
- package/dist/data/memory/semantic-notes.js +8 -15
- package/dist/data/memory/semantic-notes.js.map +1 -1
- package/dist/services/consolidation.service.d.ts.map +1 -1
- package/dist/services/consolidation.service.js +1 -43
- package/dist/services/consolidation.service.js.map +1 -1
- package/dist/services/daily-session.d.ts +2 -2
- package/dist/services/daily-session.d.ts.map +1 -1
- package/dist/services/daily-session.js +11 -11
- package/dist/services/daily-session.js.map +1 -1
- package/dist/services/dispatcher/poller.d.ts.map +1 -1
- package/dist/services/dispatcher/poller.js +8 -15
- package/dist/services/dispatcher/poller.js.map +1 -1
- package/dist/services/memory-briefing.service.d.ts.map +1 -1
- package/dist/services/memory-briefing.service.js +14 -63
- package/dist/services/memory-briefing.service.js.map +1 -1
- package/dist/services/predefined-prompts.d.ts +11 -0
- package/dist/services/predefined-prompts.d.ts.map +1 -0
- package/dist/services/predefined-prompts.js +25 -0
- package/dist/services/predefined-prompts.js.map +1 -0
- package/dist/tools/start-session-tool.d.ts.map +1 -1
- package/dist/tools/start-session-tool.js +12 -0
- package/dist/tools/start-session-tool.js.map +1 -1
- package/dist/tools/wait/drive-handler.d.ts.map +1 -1
- package/dist/tools/wait/drive-handler.js +1 -11
- package/dist/tools/wait/drive-handler.js.map +1 -1
- package/dist/tools/wait/message-delivery.d.ts.map +1 -1
- package/dist/tools/wait/message-delivery.js +4 -21
- package/dist/tools/wait/message-delivery.js.map +1 -1
- package/dist/tools/wait/poll-loop.d.ts.map +1 -1
- package/dist/tools/wait/poll-loop.js +6 -0
- package/dist/tools/wait/poll-loop.js.map +1 -1
- package/package.json +1 -1
- package/templates/increment-pr-pipeline.default.md +79 -0
- package/dist/data/memory/reflection-dedup.d.ts +0 -17
- package/dist/data/memory/reflection-dedup.d.ts.map +0 -1
- package/dist/data/memory/reflection-dedup.js +0 -55
- package/dist/data/memory/reflection-dedup.js.map +0 -1
- package/dist/data/memory/reflection-gates.d.ts +0 -40
- package/dist/data/memory/reflection-gates.d.ts.map +0 -1
- package/dist/data/memory/reflection-gates.js +0 -220
- package/dist/data/memory/reflection-gates.js.map +0 -1
- package/dist/data/memory/reflection-sources.d.ts +0 -13
- package/dist/data/memory/reflection-sources.d.ts.map +0 -1
- package/dist/data/memory/reflection-sources.js +0 -115
- package/dist/data/memory/reflection-sources.js.map +0 -1
- package/dist/data/memory/reflection.d.ts +0 -43
- package/dist/data/memory/reflection.d.ts.map +0 -1
- package/dist/data/memory/reflection.js +0 -329
- package/dist/data/memory/reflection.js.map +0 -1
- package/dist/llm/prompts/reflection.d.ts +0 -6
- package/dist/llm/prompts/reflection.d.ts.map +0 -1
- package/dist/llm/prompts/reflection.js +0 -77
- package/dist/llm/prompts/reflection.js.map +0 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Increment PR Pipeline
|
|
3
|
+
triggers:
|
|
4
|
+
- increment pipeline
|
|
5
|
+
- one increment per pr
|
|
6
|
+
- worktree per increment
|
|
7
|
+
- pr per increment
|
|
8
|
+
- board increment
|
|
9
|
+
- build increment by increment
|
|
10
|
+
- increment workflow
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Increment PR Pipeline — one atomic increment, one worktree, one PR, reviewed then merged
|
|
14
|
+
|
|
15
|
+
### What this is
|
|
16
|
+
The EXECUTION workflow for building a decomposed plan **increment by increment**, where every
|
|
17
|
+
increment is isolated in its own git worktree + branch and lands as a **real GitHub PR into the
|
|
18
|
+
feature branch** (e.g. the board branch), reviewed by a separate agent before the operator merges.
|
|
19
|
+
It complements:
|
|
20
|
+
- **Atomic Build Spec** — how to DECOMPOSE work into tiny, testable increments.
|
|
21
|
+
- **Phased Worker Pipeline** — the fresh-worker-per-step loop (this skill is its PR-based, worktree-
|
|
22
|
+
isolated form).
|
|
23
|
+
- **Handoff** — how to spawn a worker and wait for its result.
|
|
24
|
+
|
|
25
|
+
Use this when the operator wants small PRs, isolated worktrees, and per-increment review — NOT one
|
|
26
|
+
big branch with everything hammered in at once.
|
|
27
|
+
|
|
28
|
+
### The invariants
|
|
29
|
+
- **One increment in flight at a time, strictly serial.** The next increment branches off the
|
|
30
|
+
**updated** feature branch (after the previous PR merges). Do not parallelise dependent increments.
|
|
31
|
+
- **Own worktree + own branch per increment**, branched off the feature branch (NOT main).
|
|
32
|
+
- **Builder ≠ Reviewer.** A worker never reviews its own code; the reviewer is a fresh, separate
|
|
33
|
+
agent — ideally a DIFFERENT agent type than the builder, for independent perspective.
|
|
34
|
+
- **A regression is never merged.** Blocking review findings are fixed by the SAME builder in the
|
|
35
|
+
SAME PR before merge; cosmetic/non-blocking items become explicit fast-follows.
|
|
36
|
+
- **The operator does the final verify and merges the PR himself.** The orchestrator stays thin.
|
|
37
|
+
|
|
38
|
+
### The loop (orchestrator-driven), per increment
|
|
39
|
+
1. **Create the worktree + branch** off the feature branch:
|
|
40
|
+
`git worktree add -b <feat>/inc<N>-<slug> C:/src/rcm-inc<N>-<slug> <feature-branch>`.
|
|
41
|
+
2. **Spawn the BUILDER worker** (agentType per the operator's choice for this run), cwd = the
|
|
42
|
+
worktree. It MUST, as its FIRST action, load the **Clean Code** skill via `get_skill`. Give it:
|
|
43
|
+
the increment goal, the smallest-honest-slice scope, exact file list, invariants, and what is
|
|
44
|
+
explicitly OUT of scope (name later increments so it can't scope-creep).
|
|
45
|
+
3. Builder implements ONLY this increment + an automated test, then runs the FULL local gate and
|
|
46
|
+
**STOPS and reports back** — it does not start the next increment.
|
|
47
|
+
4. **Spawn a separate REVIEWER worker** (a different agentType than the builder, for independence),
|
|
48
|
+
read-only, adversarial / refute-mode, cwd = the same worktree (deps already installed). It loads
|
|
49
|
+
Clean Code first, reviews
|
|
50
|
+
the PR diff vs the feature branch, confirms the tests are REAL (not rubber-stamps) and the gate is
|
|
51
|
+
green, and returns a clear **GO-to-merge** or **CHANGES-NEEDED** verdict with ranked findings.
|
|
52
|
+
5. **Blocking findings** → hand back to the SAME builder to fix in the same PR; then a focused DELTA
|
|
53
|
+
re-review confirms the finding is CLOSED. Non-blockers → note as fast-follows.
|
|
54
|
+
6. **Operator verifies** (the builder supplies a ~30s click-checklist) and **merges** the PR.
|
|
55
|
+
7. **Cleanup**: `git worktree remove --force <path>` + `git worktree prune` + delete the local
|
|
56
|
+
branch. Advance to the next increment off the updated feature branch.
|
|
57
|
+
|
|
58
|
+
### The gate — ALL must be green before a PR is "ready" (builder runs these IN the worktree)
|
|
59
|
+
- `npm ci` **first** — a fresh worktree has NO `node_modules`; typecheck/tests won't run without it.
|
|
60
|
+
(Install can be slow on Windows; that's expected.)
|
|
61
|
+
- `npm run typecheck` — clean.
|
|
62
|
+
- `npm run format:check` — clean. **CI fails on format independently of tests**; running only tests
|
|
63
|
+
is not enough. Auto-fix with `npm run format` / `npx prettier --write` and re-check.
|
|
64
|
+
- `npm test` — all pass, including the new test for this increment.
|
|
65
|
+
|
|
66
|
+
### The PR
|
|
67
|
+
- **Base = the feature branch (e.g. feature/agent-task-board), NOT main.**
|
|
68
|
+
- Title: `<feat>(inc<N>): <what it does>`.
|
|
69
|
+
- Body: plain and accurate — what the increment does, files touched, gate status. No filler, no
|
|
70
|
+
AI/tool attribution.
|
|
71
|
+
- Commits use **explicit paths** — never `git add -A/./ -u`, never `commit -a`.
|
|
72
|
+
|
|
73
|
+
### Anti-patterns
|
|
74
|
+
- ❌ Skipping `npm ci` in a fresh worktree, then reporting "done" when the gate never actually ran.
|
|
75
|
+
- ❌ Running only `npm test` and missing the separate `format:check` → red CI on the PR.
|
|
76
|
+
- ❌ PR based on `main` instead of the feature branch.
|
|
77
|
+
- ❌ The building worker reviewing its own increment.
|
|
78
|
+
- ❌ Merging a PR with an unresolved regression instead of fixing it in the same PR.
|
|
79
|
+
- ❌ Leaving the merged increment's worktree/branch around instead of cleaning up before the next.
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reflection de-duplication — embedding-based checks that prevent saving
|
|
3
|
-
* insights or lessons that semantically duplicate existing reflections.
|
|
4
|
-
*/
|
|
5
|
-
import type { Database } from "./schema.js";
|
|
6
|
-
export declare function checkDuplicate(db: Database, content: string, apiKey: string, threadId: number): Promise<{
|
|
7
|
-
isDuplicate: boolean;
|
|
8
|
-
embedding: Float32Array | null;
|
|
9
|
-
}>;
|
|
10
|
-
/**
|
|
11
|
-
* Lesson-level dedup: checks if a semantically similar lesson already exists
|
|
12
|
-
* among reflection notes using a lower similarity threshold (0.75).
|
|
13
|
-
* Catches generic lessons like "Always do comprehensive code reviews" that are
|
|
14
|
-
* worded differently but carry the same meaning.
|
|
15
|
-
*/
|
|
16
|
-
export declare function checkLessonDuplicate(db: Database, lesson: string, apiKey: string, knowledgeThreadId: number): Promise<boolean>;
|
|
17
|
-
//# sourceMappingURL=reflection-dedup.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reflection-dedup.d.ts","sourceRoot":"","sources":["../../../src/data/memory/reflection-dedup.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAS5C,wBAAsB,cAAc,CAClC,EAAE,EAAE,QAAQ,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,YAAY,GAAG,IAAI,CAAA;CAAE,CAAC,CAkBnE;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,OAAO,CAAC,CAsBlB"}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reflection de-duplication — embedding-based checks that prevent saving
|
|
3
|
-
* insights or lessons that semantically duplicate existing reflections.
|
|
4
|
-
*/
|
|
5
|
-
import { searchByEmbedding } from "./note-embeddings.js";
|
|
6
|
-
import { generateEmbedding } from "../../integrations/openai/chat.js";
|
|
7
|
-
import { log } from "../../lib/logger.js";
|
|
8
|
-
import { errorMessage } from "../../lib/utils.js";
|
|
9
|
-
const DEDUP_SIMILARITY_THRESHOLD = 0.86;
|
|
10
|
-
const LESSON_DEDUP_THRESHOLD = 0.75;
|
|
11
|
-
export async function checkDuplicate(db, content, apiKey, threadId) {
|
|
12
|
-
try {
|
|
13
|
-
const embedding = await generateEmbedding(content, apiKey, threadId);
|
|
14
|
-
const matches = searchByEmbedding(db, embedding, {
|
|
15
|
-
maxResults: 8,
|
|
16
|
-
minSimilarity: DEDUP_SIMILARITY_THRESHOLD,
|
|
17
|
-
skipAccessTracking: true,
|
|
18
|
-
threadId,
|
|
19
|
-
});
|
|
20
|
-
const isDuplicate = matches.some((m) => m.similarity >= DEDUP_SIMILARITY_THRESHOLD && m.content.startsWith("[REFLECTION]"));
|
|
21
|
-
return { isDuplicate, embedding };
|
|
22
|
-
}
|
|
23
|
-
catch (err) {
|
|
24
|
-
log.warn(`[reflection] Dedup embedding lookup failed: ${errorMessage(err)}`);
|
|
25
|
-
// Embedding lookup failed — allow the insight through to avoid data loss
|
|
26
|
-
return { isDuplicate: false, embedding: null };
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Lesson-level dedup: checks if a semantically similar lesson already exists
|
|
31
|
-
* among reflection notes using a lower similarity threshold (0.75).
|
|
32
|
-
* Catches generic lessons like "Always do comprehensive code reviews" that are
|
|
33
|
-
* worded differently but carry the same meaning.
|
|
34
|
-
*/
|
|
35
|
-
export async function checkLessonDuplicate(db, lesson, apiKey, knowledgeThreadId) {
|
|
36
|
-
try {
|
|
37
|
-
const embedding = await generateEmbedding(lesson, apiKey, knowledgeThreadId);
|
|
38
|
-
const matches = searchByEmbedding(db, embedding, {
|
|
39
|
-
maxResults: 8,
|
|
40
|
-
minSimilarity: LESSON_DEDUP_THRESHOLD,
|
|
41
|
-
skipAccessTracking: true,
|
|
42
|
-
threadId: knowledgeThreadId,
|
|
43
|
-
});
|
|
44
|
-
if (matches.some((m) => m.similarity >= LESSON_DEDUP_THRESHOLD && m.content.startsWith("[REFLECTION]"))) {
|
|
45
|
-
return true;
|
|
46
|
-
}
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
catch (err) {
|
|
50
|
-
log.warn(`[reflection] Lesson dedup embedding lookup failed: ${errorMessage(err)}`);
|
|
51
|
-
// Embedding lookup failed — allow through to avoid data loss
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
//# sourceMappingURL=reflection-dedup.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reflection-dedup.js","sourceRoot":"","sources":["../../../src/data/memory/reflection-dedup.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,0BAA0B,GAAG,IAAI,CAAC;AACxC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAEpC,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAY,EACZ,OAAe,EACf,MAAc,EACd,QAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,iBAAiB,CAAC,EAAE,EAAE,SAAS,EAAE;YAC/C,UAAU,EAAE,CAAC;YACb,aAAa,EAAE,0BAA0B;YACzC,kBAAkB,EAAE,IAAI;YACxB,QAAQ;SACT,CAAC,CAAC;QACH,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAC9B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,0BAA0B,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAC1F,CAAC;QACF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,+CAA+C,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7E,yEAAyE;QACzE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACjD,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,EAAY,EACZ,MAAc,EACd,MAAc,EACd,iBAAyB;IAEzB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC;QAC7E,MAAM,OAAO,GAAG,iBAAiB,CAAC,EAAE,EAAE,SAAS,EAAE;YAC/C,UAAU,EAAE,CAAC;YACb,aAAa,EAAE,sBAAsB;YACrC,kBAAkB,EAAE,IAAI;YACxB,QAAQ,EAAE,iBAAiB;SAC5B,CAAC,CAAC;QACH,IACE,OAAO,CAAC,IAAI,CACV,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,sBAAsB,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CACtF,EACD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,sDAAsD,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpF,6DAA6D;QAC7D,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reflection quality gates — pure checks that reject vague, meta, or
|
|
3
|
-
* non-actionable insights, plus the structured-field parser.
|
|
4
|
-
*/
|
|
5
|
-
/** Check if an insight passes the quality gate (actionable, specific, non-vague, non-meta). */
|
|
6
|
-
export declare function passesQualityGate(content: string, confidence: number): {
|
|
7
|
-
pass: boolean;
|
|
8
|
-
reason?: string;
|
|
9
|
-
};
|
|
10
|
-
/** Parse reflection content into structured fields. Returns null if parsing fails. */
|
|
11
|
-
export declare function parseReflectionFields(content: string): {
|
|
12
|
-
decision: string;
|
|
13
|
-
context: string;
|
|
14
|
-
outcome: string;
|
|
15
|
-
root_cause: string;
|
|
16
|
-
lesson: string;
|
|
17
|
-
} | null;
|
|
18
|
-
/** True if the text names something specific rather than being an abstract platitude. */
|
|
19
|
-
export declare function hasConcreteAnchor(text: string): boolean;
|
|
20
|
-
/**
|
|
21
|
-
* Validate structural integrity of parsed insight fields.
|
|
22
|
-
*
|
|
23
|
-
* `requireAnchor` gates the lesson on a concrete anchor (identifier/file/version).
|
|
24
|
-
* It defaults ON for the generation path (reject new platitudes). The existing-notes
|
|
25
|
-
* cleanup sweep passes it OFF so tightening the anchor rule never retroactively
|
|
26
|
-
* expires historical reflections — legacy cleanup is a separate, backed-up step.
|
|
27
|
-
*/
|
|
28
|
-
export declare function passesStructuralGate(insight: {
|
|
29
|
-
decision: string;
|
|
30
|
-
context: string;
|
|
31
|
-
outcome: string;
|
|
32
|
-
root_cause: string;
|
|
33
|
-
lesson: string;
|
|
34
|
-
}, options?: {
|
|
35
|
-
requireAnchor?: boolean;
|
|
36
|
-
}): {
|
|
37
|
-
pass: boolean;
|
|
38
|
-
reason?: string;
|
|
39
|
-
};
|
|
40
|
-
//# sourceMappingURL=reflection-gates.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reflection-gates.d.ts","sourceRoot":"","sources":["../../../src/data/memory/reflection-gates.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqCH,+FAA+F;AAC/F,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAkBpC;AAED,sFAAsF;AACtF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,IAAI,CAgBP;AAiCD,yFAAyF;AACzF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAIvD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,EACD,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAO,GACxC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA4GpC"}
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reflection quality gates — pure checks that reject vague, meta, or
|
|
3
|
-
* non-actionable insights, plus the structured-field parser.
|
|
4
|
-
*/
|
|
5
|
-
const MIN_INSIGHT_LENGTH = 50;
|
|
6
|
-
const VAGUE_PATTERNS = [
|
|
7
|
-
/\bthe agent tends to\b/i,
|
|
8
|
-
/\bI tend to\b/i,
|
|
9
|
-
/\bthe agent demonstrates\b/i,
|
|
10
|
-
/\bthe agent frequently\b/i,
|
|
11
|
-
/\bshould consider\b/i,
|
|
12
|
-
/\bthis (is|was) (a |an )?(good|important|useful)\b/i,
|
|
13
|
-
/\bin general\b/i,
|
|
14
|
-
/\boverall\b.*\b(good|well|effective)\b/i,
|
|
15
|
-
/\bthe key (insight|takeaway|lesson) is\b/i,
|
|
16
|
-
/\bit('s| is) important to\b/i,
|
|
17
|
-
/\bthis (led|leads) to\b(?!\s+\w{4,})/i,
|
|
18
|
-
/\bgoing forward\b/i,
|
|
19
|
-
/\bmoving forward\b/i,
|
|
20
|
-
/\ba? ?valuable (lesson|experience|insight)\b/i,
|
|
21
|
-
/\bI (learned|realized|recognized|acknowledged) that\b/i,
|
|
22
|
-
/\bthis (highlights|underscores|demonstrates)\b/i,
|
|
23
|
-
/\bsignificant (progress|strides|developments?|evolution)\b/i,
|
|
24
|
-
/\bnotable improvements?\b/i,
|
|
25
|
-
/\bvarious features\b/i,
|
|
26
|
-
/\bseveral enhancements\b/i,
|
|
27
|
-
/\bI regularly (review|conduct|perform|check)\b/i,
|
|
28
|
-
/\bI frequently (create|manage|handle)\b/i,
|
|
29
|
-
];
|
|
30
|
-
const BANNED_TOPIC_PATTERNS = [
|
|
31
|
-
/\bmemory (system|audit|cleanup|quality|consolidat)/i,
|
|
32
|
-
/\bconsolidation (process|pipeline|prompt)\b/i,
|
|
33
|
-
/\breflection (quality|pipeline|system)\b/i,
|
|
34
|
-
/\bdeduplication\b/i,
|
|
35
|
-
/\bnote (archival|cleanup|expir)/i,
|
|
36
|
-
/\bI (conducted|scheduled|implemented) a (memory|cleanup|audit)\b/i,
|
|
37
|
-
];
|
|
38
|
-
/** Check if an insight passes the quality gate (actionable, specific, non-vague, non-meta). */
|
|
39
|
-
export function passesQualityGate(content, confidence) {
|
|
40
|
-
if (content.length < MIN_INSIGHT_LENGTH) {
|
|
41
|
-
return { pass: false, reason: "too short" };
|
|
42
|
-
}
|
|
43
|
-
if (confidence < 0.3) {
|
|
44
|
-
return { pass: false, reason: "confidence too low" };
|
|
45
|
-
}
|
|
46
|
-
for (const pattern of VAGUE_PATTERNS) {
|
|
47
|
-
if (pattern.test(content)) {
|
|
48
|
-
return { pass: false, reason: `matches vague pattern: ${pattern.source}` };
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
for (const pattern of BANNED_TOPIC_PATTERNS) {
|
|
52
|
-
if (pattern.test(content)) {
|
|
53
|
-
return { pass: false, reason: `banned topic: ${pattern.source}` };
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return { pass: true };
|
|
57
|
-
}
|
|
58
|
-
/** Parse reflection content into structured fields. Returns null if parsing fails. */
|
|
59
|
-
export function parseReflectionFields(content) {
|
|
60
|
-
const decisionMatch = content.match(/Decision:\s*(.+?)(?:\s*Context:|$)/s);
|
|
61
|
-
const contextMatch = content.match(/Context:\s*(.+?)(?:\s*Outcome:|$)/s);
|
|
62
|
-
const outcomeMatch = content.match(/Outcome:\s*(.+?)(?:\s*Root cause:|$)/s);
|
|
63
|
-
const rootCauseMatch = content.match(/Root cause:\s*(.+?)(?:\s*Lesson:|$)/s);
|
|
64
|
-
const lessonMatch = content.match(/Lesson:\s*(.+?)(?:\s*$)/s);
|
|
65
|
-
if (!decisionMatch || !lessonMatch)
|
|
66
|
-
return null;
|
|
67
|
-
return {
|
|
68
|
-
decision: decisionMatch[1]?.trim() ?? "",
|
|
69
|
-
context: contextMatch?.[1]?.trim() ?? "",
|
|
70
|
-
outcome: outcomeMatch?.[1]?.trim() ?? "",
|
|
71
|
-
root_cause: rootCauseMatch?.[1]?.trim() ?? "",
|
|
72
|
-
lesson: lessonMatch[1]?.trim() ?? "",
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
// A concrete anchor is a specific, project-referencing token: a code identifier,
|
|
76
|
-
// file/path, version, acronym, or number. Generic prose maxims ("Always
|
|
77
|
-
// communicate clearly", "Break tasks into steps") contain none of these and carry
|
|
78
|
-
// no reusable, project-specific value — they are the dominant reflection noise.
|
|
79
|
-
const ANCHOR_PATTERNS = [
|
|
80
|
-
/`[^`]+`/, // backticked code
|
|
81
|
-
/\b\w+\.(ts|js|tsx|jsx|cs|py|json|sql|md|ya?ml|sh|db)\b/i, // filename
|
|
82
|
-
/[/\\]\w/, // path segment
|
|
83
|
-
/\b[a-z][a-z0-9]*[A-Z][a-zA-Z0-9]*\b/, // camelCase identifier
|
|
84
|
-
/\b[A-Z][a-z0-9]+[A-Z][a-zA-Z0-9]*\b/, // PascalCase identifier
|
|
85
|
-
/\b[a-z0-9]+_[a-z0-9]+\b/, // snake_case identifier
|
|
86
|
-
/\bv?\d+\.\d+/, // version / decimal (5.2.2, v1.2)
|
|
87
|
-
];
|
|
88
|
-
// All-caps tokens that are filler, not project anchors — excluded from the acronym rule.
|
|
89
|
-
const NON_ANCHOR_ACRONYMS = new Set([
|
|
90
|
-
"OK",
|
|
91
|
-
"TODO",
|
|
92
|
-
"ASAP",
|
|
93
|
-
"FYI",
|
|
94
|
-
"AKA",
|
|
95
|
-
"ETA",
|
|
96
|
-
"YES",
|
|
97
|
-
"NO",
|
|
98
|
-
"AI",
|
|
99
|
-
"IT",
|
|
100
|
-
"OKAY",
|
|
101
|
-
"PM",
|
|
102
|
-
"IMO",
|
|
103
|
-
]);
|
|
104
|
-
/** True if the text names something specific rather than being an abstract platitude. */
|
|
105
|
-
export function hasConcreteAnchor(text) {
|
|
106
|
-
if (ANCHOR_PATTERNS.some((p) => p.test(text)))
|
|
107
|
-
return true;
|
|
108
|
-
const acronyms = text.match(/\b[A-Z]{2,}\b/g);
|
|
109
|
-
return Boolean(acronyms && acronyms.some((a) => !NON_ANCHOR_ACRONYMS.has(a)));
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Validate structural integrity of parsed insight fields.
|
|
113
|
-
*
|
|
114
|
-
* `requireAnchor` gates the lesson on a concrete anchor (identifier/file/version).
|
|
115
|
-
* It defaults ON for the generation path (reject new platitudes). The existing-notes
|
|
116
|
-
* cleanup sweep passes it OFF so tightening the anchor rule never retroactively
|
|
117
|
-
* expires historical reflections — legacy cleanup is a separate, backed-up step.
|
|
118
|
-
*/
|
|
119
|
-
export function passesStructuralGate(insight, options = {}) {
|
|
120
|
-
const { requireAnchor = true } = options;
|
|
121
|
-
// Check root_cause is meaningfully different from outcome (skip for very short fields)
|
|
122
|
-
const outcomeWords = new Set(insight.outcome
|
|
123
|
-
.toLowerCase()
|
|
124
|
-
.replace(/[.,:;!?]/g, "")
|
|
125
|
-
.split(/\s+/)
|
|
126
|
-
.filter((w) => w.length > 3));
|
|
127
|
-
const rootWords = new Set(insight.root_cause
|
|
128
|
-
.toLowerCase()
|
|
129
|
-
.replace(/[.,:;!?]/g, "")
|
|
130
|
-
.split(/\s+/)
|
|
131
|
-
.filter((w) => w.length > 3));
|
|
132
|
-
if (outcomeWords.size >= 3) {
|
|
133
|
-
const overlap = [...outcomeWords].filter((w) => rootWords.has(w)).length;
|
|
134
|
-
const overlapRatio = overlap / outcomeWords.size;
|
|
135
|
-
if (overlapRatio > 0.6) {
|
|
136
|
-
return { pass: false, reason: "root_cause restates outcome" };
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
// Check lesson starts with a verb (actionable)
|
|
140
|
-
const lessonStart = insight.lesson.trim().split(/\s/)[0]?.toLowerCase() ?? "";
|
|
141
|
-
const actionVerbs = [
|
|
142
|
-
"always",
|
|
143
|
-
"never",
|
|
144
|
-
"before",
|
|
145
|
-
"after",
|
|
146
|
-
"when",
|
|
147
|
-
"if",
|
|
148
|
-
"check",
|
|
149
|
-
"verify",
|
|
150
|
-
"ensure",
|
|
151
|
-
"use",
|
|
152
|
-
"avoid",
|
|
153
|
-
"run",
|
|
154
|
-
"test",
|
|
155
|
-
"add",
|
|
156
|
-
"remove",
|
|
157
|
-
"set",
|
|
158
|
-
"create",
|
|
159
|
-
"implement",
|
|
160
|
-
"review",
|
|
161
|
-
"validate",
|
|
162
|
-
"confirm",
|
|
163
|
-
"monitor",
|
|
164
|
-
"track",
|
|
165
|
-
"log",
|
|
166
|
-
"document",
|
|
167
|
-
"separate",
|
|
168
|
-
"isolate",
|
|
169
|
-
"prefer",
|
|
170
|
-
"prioritize",
|
|
171
|
-
"consider",
|
|
172
|
-
"evaluate",
|
|
173
|
-
"compare",
|
|
174
|
-
"measure",
|
|
175
|
-
"schedule",
|
|
176
|
-
"watch",
|
|
177
|
-
"build",
|
|
178
|
-
"configure",
|
|
179
|
-
"enable",
|
|
180
|
-
"define",
|
|
181
|
-
"wrap",
|
|
182
|
-
"cache",
|
|
183
|
-
"query",
|
|
184
|
-
"disable",
|
|
185
|
-
"expose",
|
|
186
|
-
"update",
|
|
187
|
-
"read",
|
|
188
|
-
"write",
|
|
189
|
-
"fetch",
|
|
190
|
-
"parse",
|
|
191
|
-
"handle",
|
|
192
|
-
"keep",
|
|
193
|
-
"limit",
|
|
194
|
-
"require",
|
|
195
|
-
"include",
|
|
196
|
-
"exclude",
|
|
197
|
-
"apply",
|
|
198
|
-
"deploy",
|
|
199
|
-
"migrate",
|
|
200
|
-
"start",
|
|
201
|
-
"stop",
|
|
202
|
-
];
|
|
203
|
-
if (!actionVerbs.some((v) => lessonStart.startsWith(v))) {
|
|
204
|
-
return { pass: false, reason: "lesson does not start with an action verb" };
|
|
205
|
-
}
|
|
206
|
-
// Check minimum field lengths (more strict than the 10-char check elsewhere)
|
|
207
|
-
if (insight.root_cause.length < 30) {
|
|
208
|
-
return { pass: false, reason: "root_cause too shallow (< 30 chars)" };
|
|
209
|
-
}
|
|
210
|
-
if (insight.lesson.length < 20) {
|
|
211
|
-
return { pass: false, reason: "lesson too short (< 20 chars)" };
|
|
212
|
-
}
|
|
213
|
-
// Lesson must name something concrete. A generic maxim with no file, component,
|
|
214
|
-
// version, identifier, or number is a platitude, not a project-specific lesson.
|
|
215
|
-
if (requireAnchor && !hasConcreteAnchor(insight.lesson)) {
|
|
216
|
-
return { pass: false, reason: "lesson has no concrete anchor (generic platitude)" };
|
|
217
|
-
}
|
|
218
|
-
return { pass: true };
|
|
219
|
-
}
|
|
220
|
-
//# sourceMappingURL=reflection-gates.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reflection-gates.js","sourceRoot":"","sources":["../../../src/data/memory/reflection-gates.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reflection source data — episode gathering, narrative building, and
|
|
3
|
-
* keyword extraction for the reflection pipeline.
|
|
4
|
-
*/
|
|
5
|
-
import type { Database } from "./schema.js";
|
|
6
|
-
import { type Episode } from "./episodes.js";
|
|
7
|
-
/** Build a time-ordered narrative from a list of episodes. */
|
|
8
|
-
export declare function buildNarrative(episodes: Episode[]): string;
|
|
9
|
-
/** Gather consolidated episodes: last N recent + random sample of older ones. */
|
|
10
|
-
export declare function gatherEpisodes(db: Database, threadId: number, maxRecent: number, oldSampleSize: number): Episode[];
|
|
11
|
-
/** Extract up to 5 meaningful keywords from free-text content. */
|
|
12
|
-
export declare function extractKeywords(text: string): string[];
|
|
13
|
-
//# sourceMappingURL=reflection-sources.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reflection-sources.d.ts","sourceRoot":"","sources":["../../../src/data/memory/reflection-sources.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,KAAK,OAAO,EAAgB,MAAM,eAAe,CAAC;AAS3D,8DAA8D;AAC9D,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAO1D;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAC5B,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,EAAE,CA+BX;AA2DD,kEAAkE;AAClE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CActD"}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reflection source data — episode gathering, narrative building, and
|
|
3
|
-
* keyword extraction for the reflection pipeline.
|
|
4
|
-
*/
|
|
5
|
-
import { rowToEpisode } from "./episodes.js";
|
|
6
|
-
/** Extract text from an episode's content object. */
|
|
7
|
-
function episodeText(ep) {
|
|
8
|
-
const c = ep.content;
|
|
9
|
-
if (typeof c === "string")
|
|
10
|
-
return c;
|
|
11
|
-
return c.text ?? c.caption ?? JSON.stringify(c);
|
|
12
|
-
}
|
|
13
|
-
/** Build a time-ordered narrative from a list of episodes. */
|
|
14
|
-
export function buildNarrative(episodes) {
|
|
15
|
-
return episodes
|
|
16
|
-
.sort((a, b) => a.timestamp.localeCompare(b.timestamp))
|
|
17
|
-
.map((ep) => `[${ep.episodeId}] (${ep.type}/${ep.modality}, ${ep.timestamp}) ${episodeText(ep)}`)
|
|
18
|
-
.join("\n");
|
|
19
|
-
}
|
|
20
|
-
/** Gather consolidated episodes: last N recent + random sample of older ones. */
|
|
21
|
-
export function gatherEpisodes(db, threadId, maxRecent, oldSampleSize) {
|
|
22
|
-
// Recent consolidated episodes
|
|
23
|
-
const recentRows = db
|
|
24
|
-
.prepare(`SELECT * FROM episodes
|
|
25
|
-
WHERE thread_id = ? AND consolidated = 1
|
|
26
|
-
ORDER BY timestamp DESC
|
|
27
|
-
LIMIT ?`)
|
|
28
|
-
.all(threadId, maxRecent);
|
|
29
|
-
const recentIds = new Set(recentRows.map((r) => r.episode_id));
|
|
30
|
-
// Random sample of older consolidated episodes from the past 7 days
|
|
31
|
-
// (excluding the ones already in the recent set)
|
|
32
|
-
const olderRows = db
|
|
33
|
-
.prepare(`SELECT * FROM episodes
|
|
34
|
-
WHERE thread_id = ? AND consolidated = 1
|
|
35
|
-
AND timestamp >= datetime('now', '-7 days')
|
|
36
|
-
ORDER BY RANDOM()
|
|
37
|
-
LIMIT ?`)
|
|
38
|
-
.all(threadId, oldSampleSize + recentRows.length);
|
|
39
|
-
const olderFiltered = olderRows
|
|
40
|
-
.filter((r) => !recentIds.has(r.episode_id))
|
|
41
|
-
.slice(0, oldSampleSize);
|
|
42
|
-
const allRows = [...recentRows, ...olderFiltered];
|
|
43
|
-
return allRows.map(rowToEpisode);
|
|
44
|
-
}
|
|
45
|
-
// ─── Keyword extraction ──────────────────────────────────────────────────────
|
|
46
|
-
const STOP_WORDS = new Set([
|
|
47
|
-
"this",
|
|
48
|
-
"that",
|
|
49
|
-
"with",
|
|
50
|
-
"from",
|
|
51
|
-
"have",
|
|
52
|
-
"been",
|
|
53
|
-
"will",
|
|
54
|
-
"would",
|
|
55
|
-
"could",
|
|
56
|
-
"should",
|
|
57
|
-
"about",
|
|
58
|
-
"there",
|
|
59
|
-
"their",
|
|
60
|
-
"which",
|
|
61
|
-
"when",
|
|
62
|
-
"what",
|
|
63
|
-
"were",
|
|
64
|
-
"they",
|
|
65
|
-
"than",
|
|
66
|
-
"then",
|
|
67
|
-
"also",
|
|
68
|
-
"just",
|
|
69
|
-
"more",
|
|
70
|
-
"some",
|
|
71
|
-
"into",
|
|
72
|
-
"over",
|
|
73
|
-
"after",
|
|
74
|
-
"before",
|
|
75
|
-
"other",
|
|
76
|
-
"very",
|
|
77
|
-
"your",
|
|
78
|
-
"here",
|
|
79
|
-
"does",
|
|
80
|
-
"because",
|
|
81
|
-
"instead",
|
|
82
|
-
"agent",
|
|
83
|
-
"operator",
|
|
84
|
-
"the",
|
|
85
|
-
"and",
|
|
86
|
-
"for",
|
|
87
|
-
"are",
|
|
88
|
-
"but",
|
|
89
|
-
"not",
|
|
90
|
-
"you",
|
|
91
|
-
"all",
|
|
92
|
-
"can",
|
|
93
|
-
"had",
|
|
94
|
-
"her",
|
|
95
|
-
"was",
|
|
96
|
-
"one",
|
|
97
|
-
"our",
|
|
98
|
-
"out",
|
|
99
|
-
]);
|
|
100
|
-
/** Extract up to 5 meaningful keywords from free-text content. */
|
|
101
|
-
export function extractKeywords(text) {
|
|
102
|
-
const words = text
|
|
103
|
-
.toLowerCase()
|
|
104
|
-
.replace(/[^a-z0-9\s]/g, " ")
|
|
105
|
-
.split(/\s+/)
|
|
106
|
-
.filter((w) => w.length > 3 && !STOP_WORDS.has(w));
|
|
107
|
-
const freq = new Map();
|
|
108
|
-
for (const w of words)
|
|
109
|
-
freq.set(w, (freq.get(w) ?? 0) + 1);
|
|
110
|
-
return [...freq.entries()]
|
|
111
|
-
.sort((a, b) => b[1] - a[1])
|
|
112
|
-
.slice(0, 5)
|
|
113
|
-
.map(([w]) => w);
|
|
114
|
-
}
|
|
115
|
-
//# sourceMappingURL=reflection-sources.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reflection-sources.js","sourceRoot":"","sources":["../../../src/data/memory/reflection-sources.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reflection pipeline — the "dreaming" phase that generates deeper insights
|
|
3
|
-
* from episodic memories after consolidation.
|
|
4
|
-
*
|
|
5
|
-
* Unlike consolidation (which extracts facts and preferences), reflection
|
|
6
|
-
* finds causal chains, recurring patterns, counterfactuals, and
|
|
7
|
-
* self-assessments across episodes. It runs post-consolidation when
|
|
8
|
-
* enough episodes exist, rate-limited to once per 4 hours.
|
|
9
|
-
*
|
|
10
|
-
* Split into: reflection-gates (quality/structural gates + field parsing),
|
|
11
|
-
* reflection-dedup (embedding-based duplicate checks), reflection-sources
|
|
12
|
-
* (episode gathering, narrative building, keyword extraction). This module
|
|
13
|
-
* keeps the orchestrating pipeline and buffer maintenance.
|
|
14
|
-
*/
|
|
15
|
-
import type { Database } from "./schema.js";
|
|
16
|
-
interface ReflectionInsight {
|
|
17
|
-
type: "causal" | "pattern" | "self_assessment" | "counterfactual";
|
|
18
|
-
content: string;
|
|
19
|
-
confidence: number;
|
|
20
|
-
relatedEpisodeIds: string[];
|
|
21
|
-
}
|
|
22
|
-
interface ReflectionResult {
|
|
23
|
-
insights: ReflectionInsight[];
|
|
24
|
-
processedEpisodeCount: number;
|
|
25
|
-
duration: number;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Run the reflection pipeline on recent consolidated episodes.
|
|
29
|
-
* Generates deeper insights beyond simple fact/preference extraction.
|
|
30
|
-
*
|
|
31
|
-
* Pipeline:
|
|
32
|
-
* 1. Gate check — enough episodes, rate limit, API key present
|
|
33
|
-
* 2. Gather episodes — recent + random sample of older ones
|
|
34
|
-
* 3. Build a narrative from episode content
|
|
35
|
-
* 4. Send to OpenAI with the reflection prompt
|
|
36
|
-
* 5. Parse insights, de-duplicate, and save as semantic notes
|
|
37
|
-
*/
|
|
38
|
-
export declare function runReflection(db: Database, threadId: number, options?: {
|
|
39
|
-
maxEpisodes?: number;
|
|
40
|
-
includeOldSample?: boolean;
|
|
41
|
-
}): Promise<ReflectionResult>;
|
|
42
|
-
export {};
|
|
43
|
-
//# sourceMappingURL=reflection.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reflection.d.ts","sourceRoot":"","sources":["../../../src/data/memory/reflection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAwB5C,UAAU,iBAAiB;IACzB,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,UAAU,gBAAgB;IACxB,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAiFD;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7D,OAAO,CAAC,gBAAgB,CAAC,CA4B3B"}
|