Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1015,14 +1015,24 @@ async function ensureDailyLogFile(dailyPath, dateStr) {
await writeFile(dailyPath, `# ${dateStr}\n\n`, "utf-8");
}
}
export function buildReflectionPrompt(conversation, maxInputChars, toolErrorSignals = []) {
// Slot split: system = identity + every static block (task, headings
// contract, hard rules, section/governance rules, notes, output template);
// user = only the dynamically generated content (tool error signals + the
// INPUT transcript fence). Both runners deliver the combined single-slot
// form today (the embedded raw run does not honor a separate system slot,
// and the CLI fallback carries a single user message); the parts keep the
// seam explicit so a host whose runner honors a system slot can deliver
// them split without changing the prompt text: system + blank line + user
// reproduces the single-slot form exactly, and the prompt hash is computed
// over that combined form.
export function buildReflectionPromptParts(conversation, maxInputChars, toolErrorSignals = []) {
const clipped = conversation.slice(-maxInputChars);
const errorHints = toolErrorSignals.length > 0
? toolErrorSignals
.map((e, i) => `${i + 1}. [${e.toolName}] ${e.summary} (sig:${e.signatureHash.slice(0, 8)})`)
.join("\n")
: "- (none)";
return [
const system = [
"You are generating a durable MEMORY REFLECTION entry for an AI assistant system.",
"",
"Output Markdown only. No intro text. No outro text. No extra headings.",
Expand Down Expand Up @@ -1119,7 +1129,8 @@ export function buildReflectionPrompt(conversation, maxInputChars, toolErrorSign
"",
"## Derived",
"- This run showed ...",
"",
].join("\n");
const user = [
"Recent tool error signals:",
errorHints,
"",
Expand All @@ -1128,6 +1139,13 @@ export function buildReflectionPrompt(conversation, maxInputChars, toolErrorSign
clipped,
"```",
].join("\n");
return { system, user };
}
// Combined single-slot form of the distiller prompt: what both runners
// send today, and what prompt-content tests assert on.
export function buildReflectionPrompt(conversation, maxInputChars, toolErrorSignals = []) {
const parts = buildReflectionPromptParts(conversation, maxInputChars, toolErrorSignals);
return `${parts.system}\n\n${parts.user}`;
}
function buildReflectionFallbackText() {
return [
Expand Down Expand Up @@ -1203,7 +1221,10 @@ export async function generateReflectionText(params) {
}
}
async function generateReflectionTextUnbounded(params) {
const prompt = buildReflectionPrompt(params.conversation, params.maxInputChars, params.toolErrorSignals ?? []);
const promptParts = buildReflectionPromptParts(params.conversation, params.maxInputChars, params.toolErrorSignals ?? []);
// The combined single-slot form: hashed for change detection and sent
// as one prompt by both runners (neither has an honored system slot).
const prompt = `${promptParts.system}\n\n${promptParts.user}`;
const promptHash = sha256Hex(prompt);
const tempSessionFile = join(tmpdir(), `memory-reflection-${Date.now()}-${Math.random().toString(36).slice(2)}.jsonl`);
let reflectionText = null;
Expand Down
38 changes: 33 additions & 5 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1462,18 +1462,30 @@ async function ensureDailyLogFile(dailyPath: string, dateStr: string): Promise<v
}
}

export function buildReflectionPrompt(
type ReflectionPromptParts = { system: string; user: string };

// Slot split: system = identity + every static block (task, headings
// contract, hard rules, section/governance rules, notes, output template);
// user = only the dynamically generated content (tool error signals + the
// INPUT transcript fence). Both runners deliver the combined single-slot
// form today (the embedded raw run does not honor a separate system slot,
// and the CLI fallback carries a single user message); the parts keep the
// seam explicit so a host whose runner honors a system slot can deliver
// them split without changing the prompt text: system + blank line + user
// reproduces the single-slot form exactly, and the prompt hash is computed
// over that combined form.
export function buildReflectionPromptParts(
conversation: string,
maxInputChars: number,
toolErrorSignals: ReflectionErrorSignal[] = []
): string {
): ReflectionPromptParts {
const clipped = conversation.slice(-maxInputChars);
const errorHints = toolErrorSignals.length > 0
? toolErrorSignals
.map((e, i) => `${i + 1}. [${e.toolName}] ${e.summary} (sig:${e.signatureHash.slice(0, 8)})`)
.join("\n")
: "- (none)";
return [
const system = [
"You are generating a durable MEMORY REFLECTION entry for an AI assistant system.",
"",
"Output Markdown only. No intro text. No outro text. No extra headings.",
Expand Down Expand Up @@ -1570,7 +1582,8 @@ export function buildReflectionPrompt(
"",
"## Derived",
"- This run showed ...",
"",
].join("\n");
const user = [
"Recent tool error signals:",
errorHints,
"",
Expand All @@ -1579,6 +1592,18 @@ export function buildReflectionPrompt(
clipped,
"```",
].join("\n");
return { system, user };
}

// Combined single-slot form of the distiller prompt: what both runners
// send today, and what prompt-content tests assert on.
export function buildReflectionPrompt(
conversation: string,
maxInputChars: number,
toolErrorSignals: ReflectionErrorSignal[] = []
): string {
const parts = buildReflectionPromptParts(conversation, maxInputChars, toolErrorSignals);
return `${parts.system}\n\n${parts.user}`;
}

function buildReflectionFallbackText(): string {
Expand Down Expand Up @@ -1682,11 +1707,14 @@ export async function generateReflectionText(
async function generateReflectionTextUnbounded(
params: GenerateReflectionTextParams
): Promise<GenerateReflectionTextResult> {
const prompt = buildReflectionPrompt(
const promptParts = buildReflectionPromptParts(
params.conversation,
params.maxInputChars,
params.toolErrorSignals ?? []
);
// The combined single-slot form: hashed for change detection and sent
// as one prompt by both runners (neither has an honored system slot).
const prompt = `${promptParts.system}\n\n${promptParts.user}`;
const promptHash = sha256Hex(prompt);
const tempSessionFile = join(
tmpdir(),
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"skills/**/*.md"
],
"scripts": {
"test": "node test/embedder-error-hints.test.mjs && node --test test/embedder-max-input-chars.test.mjs && node test/cjk-recursion-regression.test.mjs && node test/extraction-prompt-structural-noise.test.mjs && node test/i18n-memory-triggers.test.mjs && node test/migrate-legacy-schema.test.mjs && node --test test/config-session-strategy-migration.test.mjs && node --test test/scope-access-undefined.test.mjs && node --test test/reflection-bypass-hook.test.mjs && node --test test/smart-extractor-scope-filter.test.mjs && node --test test/store-empty-scope-filter.test.mjs && node --test test/recall-text-cleanup.test.mjs && node test/update-consistency-lancedb.test.mjs && node --test test/strip-envelope-metadata.test.mjs && node test/cli-smoke.mjs && node test/functional-e2e.mjs && node --test test/per-agent-auto-recall.test.mjs && node test/retriever-rerank-regression.mjs && node test/smart-memory-lifecycle.mjs && node test/smart-extractor-branches.mjs && node --test test/smart-extractor-noise-gating.test.mjs && node test/memory-capability-runtime.test.mjs && node --test test/startup-health-diagnostics.test.mjs && node test/corpus-indexer.test.mjs && node --test test/regex-fallback-bulk-store.test.mjs && node test/plugin-manifest-regression.mjs && node --test test/dreaming-engine.test.mjs && node --test test/session-summary-before-reset.test.mjs && node --test test/sync-plugin-version.test.mjs && node test/smart-metadata-v2.mjs && node test/vector-search-cosine.test.mjs && node test/context-support-e2e.mjs && node test/temporal-facts.test.mjs && node test/memory-update-supersede.test.mjs && node test/memory-update-metadata-refresh.test.mjs && node test/memory-upgrader-diagnostics.test.mjs && node --test test/llm-api-key-client.test.mjs && node --test test/llm-oauth-client.test.mjs && node --test test/cli-oauth-login.test.mjs && node --test test/workflow-fork-guards.test.mjs && node --test test/clawteam-scope.test.mjs && node --test test/cross-process-lock.test.mjs && node --test test/preference-slots.test.mjs && node test/is-latest-auto-supersede.test.mjs && node --test test/temporal-awareness.test.mjs && node --test test/command-reflection-guard.test.mjs && node --test test/tier1-counters.test.mjs && node --test test/startup-check-timeout.test.mjs && node --test test/memory-subsession-prompt-hooks.test.mjs && node --test test/read-consistency-interval.test.mjs && node --test test/reflection-distiller-hook-skip.test.mjs && node --test test/register-scope-dedup.test.mjs && node --test test/raw-run-distiller-hooks.test.mjs && node --test test/autocapture-watermark-reset.test.mjs && node --test test/autocapture-internal-session-guard.test.mjs && node --test test/memory-categories-storage-map.test.mjs && node --test test/delete-invalidate-reflection-caches.test.mjs && node --test test/reflection-mapped-rows-admission.test.mjs", "test:cli-smoke": "node scripts/run-ci-tests.mjs --group cli-smoke",
"test": "node test/embedder-error-hints.test.mjs && node --test test/embedder-max-input-chars.test.mjs && node test/cjk-recursion-regression.test.mjs && node test/extraction-prompt-structural-noise.test.mjs && node test/i18n-memory-triggers.test.mjs && node test/migrate-legacy-schema.test.mjs && node --test test/config-session-strategy-migration.test.mjs && node --test test/scope-access-undefined.test.mjs && node --test test/reflection-bypass-hook.test.mjs && node --test test/smart-extractor-scope-filter.test.mjs && node --test test/store-empty-scope-filter.test.mjs && node --test test/recall-text-cleanup.test.mjs && node test/update-consistency-lancedb.test.mjs && node --test test/strip-envelope-metadata.test.mjs && node test/cli-smoke.mjs && node test/functional-e2e.mjs && node --test test/per-agent-auto-recall.test.mjs && node test/retriever-rerank-regression.mjs && node test/smart-memory-lifecycle.mjs && node test/smart-extractor-branches.mjs && node --test test/smart-extractor-noise-gating.test.mjs && node test/memory-capability-runtime.test.mjs && node --test test/startup-health-diagnostics.test.mjs && node test/corpus-indexer.test.mjs && node --test test/regex-fallback-bulk-store.test.mjs && node test/plugin-manifest-regression.mjs && node --test test/dreaming-engine.test.mjs && node --test test/session-summary-before-reset.test.mjs && node --test test/sync-plugin-version.test.mjs && node test/smart-metadata-v2.mjs && node test/vector-search-cosine.test.mjs && node test/context-support-e2e.mjs && node test/temporal-facts.test.mjs && node test/memory-update-supersede.test.mjs && node test/memory-update-metadata-refresh.test.mjs && node test/memory-upgrader-diagnostics.test.mjs && node --test test/llm-api-key-client.test.mjs && node --test test/llm-oauth-client.test.mjs && node --test test/cli-oauth-login.test.mjs && node --test test/workflow-fork-guards.test.mjs && node --test test/clawteam-scope.test.mjs && node --test test/cross-process-lock.test.mjs && node --test test/preference-slots.test.mjs && node test/is-latest-auto-supersede.test.mjs && node --test test/temporal-awareness.test.mjs && node --test test/command-reflection-guard.test.mjs && node --test test/tier1-counters.test.mjs && node --test test/startup-check-timeout.test.mjs && node --test test/memory-subsession-prompt-hooks.test.mjs && node --test test/read-consistency-interval.test.mjs && node --test test/reflection-distiller-hook-skip.test.mjs && node --test test/register-scope-dedup.test.mjs && node --test test/raw-run-distiller-hooks.test.mjs && node --test test/autocapture-watermark-reset.test.mjs && node --test test/autocapture-internal-session-guard.test.mjs && node --test test/memory-categories-storage-map.test.mjs && node --test test/delete-invalidate-reflection-caches.test.mjs && node --test test/reflection-mapped-rows-admission.test.mjs && node --test test/reflection-prompt-split.test.mjs", "test:cli-smoke": "node scripts/run-ci-tests.mjs --group cli-smoke",
"test:core-regression": "node scripts/run-ci-tests.mjs --group core-regression",
"test:storage-and-schema": "node scripts/run-ci-tests.mjs --group storage-and-schema",
"test:llm-clients-and-auth": "node scripts/run-ci-tests.mjs --group llm-clients-and-auth",
Expand Down
1 change: 1 addition & 0 deletions scripts/ci-test-manifest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export const CI_TEST_MANIFEST = [
// Delete/delete-bulk must synchronously invalidate in-process reflection read caches
{ group: "core-regression", runner: "node", file: "test/delete-invalidate-reflection-caches.test.mjs", args: ["--test"] },
{ group: "core-regression", runner: "node", file: "test/reflection-mapped-rows-admission.test.mjs", args: ["--test"] },
{ group: "core-regression", runner: "node", file: "test/reflection-prompt-split.test.mjs", args: ["--test"] },
];

export function getEntriesForGroup(group) {
Expand Down
Loading
Loading