akm-cli 0.9.0-beta.5 → 0.9.0-beta.51
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/CHANGELOG.md +711 -0
- package/README.md +12 -4
- package/dist/akm +38 -0
- package/dist/akm-migrate-storage +38 -0
- package/dist/assets/profiles/default.json +9 -4
- package/dist/assets/profiles/frequent.json +1 -1
- package/dist/assets/profiles/memory-focus.json +1 -1
- package/dist/assets/profiles/quick.json +1 -1
- package/dist/assets/profiles/synthesize.json +15 -0
- package/dist/assets/profiles/thorough.json +1 -1
- package/dist/assets/prompts/consolidate-system.md +23 -0
- package/dist/assets/prompts/contradiction-judge.md +33 -0
- package/dist/assets/prompts/distill-knowledge-system.md +22 -0
- package/dist/assets/prompts/distill-lesson-system.md +36 -0
- package/dist/assets/prompts/extract-session.md +6 -2
- package/dist/assets/prompts/graph-extract-system.md +1 -0
- package/dist/assets/prompts/graph-extract-user-prompt.md +1 -1
- package/dist/assets/prompts/memory-infer-system.md +1 -0
- package/dist/assets/prompts/memory-infer-user.md +5 -0
- package/dist/assets/prompts/metadata-enhance-system.md +1 -0
- package/dist/assets/prompts/procedural-system.md +44 -0
- package/dist/assets/prompts/recombine-system.md +40 -0
- package/dist/assets/prompts/staleness-detect-system.md +6 -0
- package/dist/assets/prompts/validate-summary-judge.md +1 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +39 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +40 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +43 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +43 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +40 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +43 -0
- package/dist/assets/templates/html/health.html +281 -111
- package/dist/assets/wiki/ingest-workflow-template.md +38 -10
- package/dist/cli/parse-args.js +46 -1
- package/dist/cli/shared.js +28 -0
- package/dist/cli.js +27 -11
- package/dist/commands/agent/agent-dispatch.js +2 -2
- package/dist/commands/agent/agent-support.js +0 -7
- package/dist/commands/agent/contribute-cli.js +17 -4
- package/dist/commands/config-cli.js +18 -2
- package/dist/commands/env/child-env.js +47 -0
- package/dist/commands/env/env-cli.js +33 -26
- package/dist/commands/env/secret-cli.js +36 -22
- package/dist/commands/feedback-cli.js +15 -6
- package/dist/commands/graph/graph-cli.js +5 -13
- package/dist/commands/graph/graph.js +76 -72
- package/dist/commands/health/checks.js +49 -1
- package/dist/commands/health/html-report.js +422 -80
- package/dist/commands/health.js +386 -9
- package/dist/commands/improve/calibration.js +161 -0
- package/dist/commands/improve/consolidate/chunking.js +141 -0
- package/dist/commands/improve/consolidate/eligibility.js +81 -0
- package/dist/commands/improve/consolidate/merge.js +145 -0
- package/dist/commands/improve/consolidate/sanitize.js +231 -0
- package/dist/commands/{lint.js → improve/consolidate/types.js} +1 -1
- package/dist/commands/improve/consolidate.js +635 -660
- package/dist/commands/improve/dedup.js +482 -0
- package/dist/commands/improve/distill.js +159 -69
- package/dist/commands/improve/eligibility.js +434 -0
- package/dist/commands/improve/encoding-salience.js +205 -0
- package/dist/commands/improve/extract-cli.js +124 -2
- package/dist/commands/improve/extract-prompt.js +39 -2
- package/dist/commands/improve/extract-watch.js +140 -0
- package/dist/commands/improve/extract.js +389 -40
- package/dist/commands/improve/feedback-valence.js +54 -0
- package/dist/commands/improve/homeostatic.js +467 -0
- package/dist/commands/improve/improve-auto-accept.js +138 -7
- package/dist/commands/improve/improve-cli.js +36 -61
- package/dist/commands/improve/improve-profiles.js +14 -0
- package/dist/commands/improve/improve-result-file.js +14 -25
- package/dist/commands/improve/improve-session.js +58 -0
- package/dist/commands/improve/improve.js +485 -2498
- package/dist/commands/improve/locks.js +154 -0
- package/dist/commands/improve/loop-stages.js +1083 -0
- package/dist/commands/improve/memory/memory-contradiction-detect.js +23 -28
- package/dist/commands/improve/outcome-loop.js +256 -0
- package/dist/commands/improve/preparation.js +1966 -0
- package/dist/commands/improve/proactive-maintenance.js +115 -0
- package/dist/commands/improve/procedural.js +418 -0
- package/dist/commands/improve/recombine.js +850 -0
- package/dist/commands/improve/reflect-noise.js +0 -0
- package/dist/commands/improve/reflect.js +183 -40
- package/dist/commands/improve/salience.js +438 -0
- package/dist/commands/improve/triage.js +93 -0
- package/dist/commands/lint/agent-linter.js +19 -24
- package/dist/commands/lint/base-linter.js +173 -60
- package/dist/commands/lint/command-linter.js +19 -24
- package/dist/commands/lint/env-key-rules.js +38 -1
- package/dist/commands/lint/fact-linter.js +39 -0
- package/dist/commands/lint/index.js +31 -13
- package/dist/commands/lint/memory-linter.js +1 -1
- package/dist/commands/lint/registry.js +7 -2
- package/dist/commands/lint/task-linter.js +3 -3
- package/dist/commands/lint/workflow-linter.js +26 -1
- package/dist/commands/proposal/drain-policies.js +5 -0
- package/dist/commands/proposal/drain.js +43 -50
- package/dist/commands/proposal/proposal-cli.js +21 -31
- package/dist/commands/proposal/proposal.js +5 -0
- package/dist/commands/proposal/propose.js +7 -2
- package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
- package/dist/commands/proposal/validators/proposals.js +189 -63
- package/dist/commands/read/curate.js +414 -94
- package/dist/commands/read/knowledge.js +6 -3
- package/dist/commands/read/search-cli.js +9 -4
- package/dist/commands/read/search.js +10 -6
- package/dist/commands/read/show.js +86 -7
- package/dist/commands/sources/init.js +49 -17
- package/dist/commands/sources/installed-stashes.js +11 -3
- package/dist/commands/sources/schema-repair.js +43 -45
- package/dist/commands/sources/self-update.js +2 -2
- package/dist/commands/sources/source-add.js +7 -3
- package/dist/commands/sources/stash-cli.js +28 -40
- package/dist/commands/sources/stash-skeleton.js +23 -8
- package/dist/commands/tasks/tasks-cli.js +19 -27
- package/dist/commands/tasks/tasks.js +39 -11
- package/dist/commands/wiki-cli.js +21 -35
- package/dist/core/asset/asset-registry.js +3 -1
- package/dist/core/asset/asset-spec.js +18 -2
- package/dist/core/asset/frontmatter.js +166 -167
- package/dist/core/asset/markdown.js +8 -0
- package/dist/core/authoring-rules.js +92 -0
- package/dist/core/common.js +0 -5
- package/dist/core/config/config-migration.js +12 -11
- package/dist/core/config/config-schema.js +340 -56
- package/dist/core/config/config-types.js +3 -3
- package/dist/core/config/config.js +28 -7
- package/dist/core/events.js +3 -7
- package/dist/core/improve-types.js +11 -8
- package/dist/core/logs-db.js +10 -66
- package/dist/core/parse.js +36 -16
- package/dist/core/paths.js +3 -0
- package/dist/core/standards/resolve-standards-context.js +87 -0
- package/dist/core/standards/resolve-stash-standards.js +99 -0
- package/dist/core/standards/resolve-type-conventions.js +66 -0
- package/dist/core/state/migrations.js +714 -0
- package/dist/core/state-db.js +525 -474
- package/dist/indexer/db/db.js +439 -247
- package/dist/indexer/db/graph-db.js +129 -86
- package/dist/indexer/ensure-index.js +152 -17
- package/dist/indexer/graph/graph-boost.js +51 -41
- package/dist/indexer/graph/graph-extraction.js +218 -4
- package/dist/indexer/index-writer-lock.js +99 -0
- package/dist/indexer/indexer.js +123 -221
- package/dist/indexer/passes/dir-staleness.js +114 -0
- package/dist/indexer/passes/memory-inference.js +13 -5
- package/dist/indexer/passes/staleness-detect.js +2 -5
- package/dist/indexer/search/db-search.js +19 -6
- package/dist/indexer/search/ranking-contributors.js +22 -0
- package/dist/indexer/search/ranking.js +4 -0
- package/dist/indexer/search/search-source.js +17 -18
- package/dist/indexer/search/semantic-status.js +4 -0
- package/dist/indexer/walk/matchers.js +9 -0
- package/dist/integrations/agent/config.js +6 -53
- package/dist/integrations/agent/index.js +2 -18
- package/dist/integrations/agent/prompts.js +75 -9
- package/dist/integrations/agent/runner-dispatch.js +59 -0
- package/dist/integrations/harnesses/claude/session-log.js +11 -1
- package/dist/integrations/harnesses/index.js +2 -3
- package/dist/integrations/harnesses/opencode/session-log.js +173 -3
- package/dist/integrations/harnesses/opencode-sdk/index.js +2 -2
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +0 -2
- package/dist/integrations/session-logs/index.js +16 -0
- package/dist/llm/client.js +45 -15
- package/dist/llm/embedder.js +42 -3
- package/dist/llm/embedders/deterministic.js +66 -0
- package/dist/llm/embedders/local.js +66 -2
- package/dist/llm/feature-gate.js +8 -4
- package/dist/llm/graph-extract.js +67 -44
- package/dist/llm/memory-infer-impl.js +138 -0
- package/dist/llm/memory-infer.js +1 -127
- package/dist/llm/metadata-enhance.js +44 -31
- package/dist/llm/structured-call.js +49 -0
- package/dist/migrate-storage-node.mjs +8 -0
- package/dist/output/context.js +5 -5
- package/dist/output/renderers.js +74 -2
- package/dist/output/shapes/curate.js +14 -2
- package/dist/output/shapes/passthrough.js +0 -1
- package/dist/output/text/helpers.js +16 -1
- package/dist/registry/providers/skills-sh.js +21 -147
- package/dist/registry/providers/static-index.js +15 -157
- package/dist/registry/resolve.js +22 -9
- package/dist/runtime.js +25 -1
- package/dist/scripts/migrate-storage.js +2617 -1961
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +759 -510
- package/dist/setup/setup.js +29 -8
- package/dist/sources/include.js +6 -2
- package/dist/sources/providers/filesystem.js +0 -1
- package/dist/sources/providers/git-install.js +210 -0
- package/dist/sources/providers/git-provider.js +234 -0
- package/dist/sources/providers/git-stash.js +248 -0
- package/dist/sources/providers/git.js +10 -661
- package/dist/sources/providers/npm.js +2 -6
- package/dist/sources/providers/provider-utils.js +13 -7
- package/dist/sources/providers/sync-from-ref.js +9 -1
- package/dist/sources/providers/tar-utils.js +16 -8
- package/dist/sources/providers/website.js +9 -5
- package/dist/sources/website-ingest.js +187 -29
- package/dist/sources/wiki-fetchers/registry.js +53 -0
- package/dist/sources/wiki-fetchers/youtube.js +239 -0
- package/dist/storage/database.js +45 -10
- package/dist/storage/managed-db.js +82 -0
- package/dist/storage/repositories/registry-cache.js +92 -0
- package/dist/storage/sqlite-pragmas.js +146 -0
- package/dist/tasks/backends/cron.js +1 -1
- package/dist/tasks/backends/launchd.js +1 -1
- package/dist/tasks/backends/schtasks.js +1 -1
- package/dist/tasks/{resolveAkmBin.js → resolve-akm-bin.js} +2 -2
- package/dist/tasks/runner.js +5 -13
- package/dist/text-import-hook.mjs +0 -0
- package/dist/wiki/wiki.js +37 -0
- package/dist/workflows/db.js +3 -4
- package/dist/workflows/runtime/runs.js +1 -117
- package/dist/workflows/runtime/workflow-asset-loader.js +125 -0
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/data-and-telemetry.md +3 -2
- package/docs/migration/release-notes/0.9.0.md +39 -0
- package/package.json +13 -11
- package/dist/commands/db-cli.js +0 -23
- package/dist/indexer/db/db-backup.js +0 -376
|
@@ -52,22 +52,33 @@
|
|
|
52
52
|
*/
|
|
53
53
|
import fs from "node:fs";
|
|
54
54
|
import path from "node:path";
|
|
55
|
+
import distillKnowledgeSystemPrompt from "../../assets/prompts/distill-knowledge-system.md" with { type: "text" };
|
|
56
|
+
import distillLessonSystemPrompt from "../../assets/prompts/distill-lesson-system.md" with { type: "text" };
|
|
55
57
|
import { parseAssetRef } from "../../core/asset/asset-ref.js";
|
|
56
58
|
import { assembleAssetFromString } from "../../core/asset/asset-serialize.js";
|
|
57
|
-
import { parseFrontmatter } from "../../core/asset/frontmatter.js";
|
|
59
|
+
import { parseFrontmatter, writeSalienceToFrontmatter } from "../../core/asset/frontmatter.js";
|
|
58
60
|
import { stripMarkdownFences } from "../../core/asset/markdown.js";
|
|
61
|
+
import { authoringRulesForType } from "../../core/authoring-rules.js";
|
|
59
62
|
import { resolveStashDir, timestampForFilename } from "../../core/common.js";
|
|
60
63
|
import { getDefaultLlmConfig, loadConfig } from "../../core/config/config.js";
|
|
61
64
|
import { ConfigError, UsageError } from "../../core/errors.js";
|
|
62
65
|
import { appendEvent, readEvents } from "../../core/events.js";
|
|
63
66
|
import { lintLessonContent } from "../../core/lesson-lint.js";
|
|
67
|
+
import { getDbPath } from "../../core/paths.js";
|
|
68
|
+
import { resolveStashStandards } from "../../core/standards/resolve-stash-standards.js";
|
|
69
|
+
import { withStateDb } from "../../core/state-db.js";
|
|
64
70
|
import { warnVerbose } from "../../core/warn.js";
|
|
71
|
+
import { closeDatabase, getAllEntries, openIndexDatabase } from "../../indexer/db/db.js";
|
|
65
72
|
import { resolveAssetPath } from "../../indexer/walk/path-resolver.js";
|
|
66
73
|
import { chatCompletion, parseEmbeddedJsonResponse } from "../../llm/client.js";
|
|
67
74
|
import { isLlmFeatureEnabled, tryLlmFeature } from "../../llm/feature-gate.js";
|
|
68
75
|
import { createProposal, isProposalSkipped, listProposals, } from "../proposal/validators/proposals.js";
|
|
69
76
|
import { akmSearch } from "../read/search.js";
|
|
77
|
+
import { stripFrontmatterBody as stripBodyForFidelity } from "./dedup.js";
|
|
70
78
|
import { assessMemoryKnowledgePromotionCandidate, deriveKnowledgeRef } from "./distill-promotion-policy.js";
|
|
79
|
+
import { buildRefVocabulary, scoreEncodingSalience } from "./encoding-salience.js";
|
|
80
|
+
import { buildClsContext, checkDistillFidelity } from "./homeostatic.js";
|
|
81
|
+
import { computeSalience, upsertAssetSalience } from "./salience.js";
|
|
71
82
|
/**
|
|
72
83
|
* Asset-ref types that `akm distill` structurally refuses as inputs.
|
|
73
84
|
*
|
|
@@ -122,68 +133,8 @@ import { repairTruncatedDescription } from "../../core/text-truncation.js";
|
|
|
122
133
|
import { detectDoubleFrontmatter, isValidDescription, isValidWhenToUse, } from "../proposal/validators/proposal-quality-validators.js";
|
|
123
134
|
export { detectDoubleFrontmatter, isValidDescription, isValidWhenToUse };
|
|
124
135
|
// ── Prompt assembly ─────────────────────────────────────────────────────────
|
|
125
|
-
const LESSON_SYSTEM_PROMPT =
|
|
126
|
-
|
|
127
|
-
"Given an asset and recent feedback events about it, produce a single",
|
|
128
|
-
"concise *lesson* an agent should remember next time it works on this",
|
|
129
|
-
"asset's domain.",
|
|
130
|
-
"",
|
|
131
|
-
"YOUR RESPONSE MUST START EXACTLY WITH `---` ON THE VERY FIRST LINE.",
|
|
132
|
-
"DO NOT output any prose, explanation, or code fences before or after.",
|
|
133
|
-
"",
|
|
134
|
-
"Required output format — copy this structure exactly:",
|
|
135
|
-
"---",
|
|
136
|
-
"description: <one complete sentence (ending with `.`) summarising what the lesson teaches>",
|
|
137
|
-
"when_to_use: <one complete sentence describing the concrete trigger condition>",
|
|
138
|
-
"---",
|
|
139
|
-
"",
|
|
140
|
-
"<lesson body — plain markdown, 1–3 short paragraphs of practical guidance>",
|
|
141
|
-
"",
|
|
142
|
-
"## description field (MANDATORY)",
|
|
143
|
-
"- A single complete sentence in present tense, 80-200 chars, NO markdown.",
|
|
144
|
-
"- Self-contained: a reviewer must understand the lesson from this field alone.",
|
|
145
|
-
'- DO NOT start with "When ", "If ", or a connector word — that belongs in when_to_use.',
|
|
146
|
-
'- DO NOT copy a section heading ("Key takeaways", "For example", "Key pitfalls").',
|
|
147
|
-
"- DO NOT begin with a numbered list marker, code fence, or markdown heading.",
|
|
148
|
-
"",
|
|
149
|
-
'GOOD: "Always validate ref existence before promoting a memory to knowledge; missing refs surface as silent 404s during accept."',
|
|
150
|
-
'BAD: "Key pitfalls"',
|
|
151
|
-
'BAD: "When working with the akm CLI"',
|
|
152
|
-
'BAD: "For example, you might..."',
|
|
153
|
-
'BAD: "1. Check the file"',
|
|
154
|
-
"",
|
|
155
|
-
"RULES:",
|
|
156
|
-
"- `when_to_use` MUST be a complete sentence describing a concrete trigger. Never write `When working with <asset-name>` — that is circular and useless.",
|
|
157
|
-
"- `description` and `when_to_use` MUST differ from each other.",
|
|
158
|
-
"- The lesson body MUST be non-empty markdown prose. Do NOT restate `description:` or `when_to_use:` inside the body (no `**description:** ...` or `**when_to_use:** ...` lines — the frontmatter is the only place those keys belong).",
|
|
159
|
-
"- Do NOT emit a second `---` fence after the opening frontmatter — there are exactly two `---` lines in the output, both belonging to the single frontmatter block at the top.",
|
|
160
|
-
"- Do NOT reproduce the source asset verbatim — distil what a caller needs to know.",
|
|
161
|
-
"- Output ONLY the lesson file. No preamble, no code fences, no trailing prose.",
|
|
162
|
-
].join("\n");
|
|
163
|
-
const KNOWLEDGE_SYSTEM_PROMPT = [
|
|
164
|
-
"You are the akm `distill` distiller.",
|
|
165
|
-
"Given an asset and recent feedback events about it, produce a concise",
|
|
166
|
-
"*knowledge* markdown document capturing the durable, reusable facts.",
|
|
167
|
-
"Prefer stable guidance over narrative recap.",
|
|
168
|
-
"",
|
|
169
|
-
"YOUR RESPONSE MUST START EXACTLY WITH `---` ON THE VERY FIRST LINE.",
|
|
170
|
-
"DO NOT output any prose, explanation, or code fences before or after.",
|
|
171
|
-
"",
|
|
172
|
-
"Required output format:",
|
|
173
|
-
"---",
|
|
174
|
-
"description: <one-line summary of the knowledge asset>",
|
|
175
|
-
"tags: [<tag1>, <tag2>]",
|
|
176
|
-
"---",
|
|
177
|
-
"",
|
|
178
|
-
"# <Title>",
|
|
179
|
-
"",
|
|
180
|
-
"<body — structured markdown, durable facts only>",
|
|
181
|
-
"",
|
|
182
|
-
"RULES:",
|
|
183
|
-
"- `description` MUST be a non-empty single-line string.",
|
|
184
|
-
"- Include a meaningful markdown body with a `# Title` heading.",
|
|
185
|
-
"- Output ONLY the knowledge file. No preamble, no code fences, no trailing prose.",
|
|
186
|
-
].join("\n");
|
|
136
|
+
const LESSON_SYSTEM_PROMPT = distillLessonSystemPrompt;
|
|
137
|
+
const KNOWLEDGE_SYSTEM_PROMPT = distillKnowledgeSystemPrompt;
|
|
187
138
|
// ── Structured-output schemas (responseSchema lift) ─────────────────────────
|
|
188
139
|
//
|
|
189
140
|
// PR 1 of the asset-writers decision (see knowledge:projects/akm/
|
|
@@ -358,6 +309,18 @@ export function buildDistillPrompt(input) {
|
|
|
358
309
|
const lines = [];
|
|
359
310
|
lines.push(`Asset ref: ${input.inputRef}`);
|
|
360
311
|
lines.push("");
|
|
312
|
+
if (input.standardsContext?.trim()) {
|
|
313
|
+
lines.push("Standards to follow (the rulebook for this target):");
|
|
314
|
+
lines.push(input.standardsContext.trim());
|
|
315
|
+
lines.push("");
|
|
316
|
+
}
|
|
317
|
+
{
|
|
318
|
+
const authoringRules = authoringRulesForType(input.proposalKind ?? "lesson");
|
|
319
|
+
if (authoringRules) {
|
|
320
|
+
lines.push(authoringRules);
|
|
321
|
+
lines.push("");
|
|
322
|
+
}
|
|
323
|
+
}
|
|
361
324
|
lines.push("Asset content:");
|
|
362
325
|
if (input.assetContent) {
|
|
363
326
|
const body = input.assetContent.trim().slice(0, 3000);
|
|
@@ -586,7 +549,7 @@ similarLessons) {
|
|
|
586
549
|
* @param reason - Human-readable rejection reason.
|
|
587
550
|
* @param extraMeta - Optional additional metadata for the event.
|
|
588
551
|
*/
|
|
589
|
-
function writeQualityRejection(stash, inputRef, lessonRef, content, score, reason, extraMeta = {}) {
|
|
552
|
+
function writeQualityRejection(stash, inputRef, lessonRef, content, score, reason, extraMeta = {}, eligibilitySource) {
|
|
590
553
|
// D-5 / #388: reviewNeeded flag selects "review_needed" vs "quality_rejected" outcome.
|
|
591
554
|
const outcome = extraMeta.reviewNeeded ? "review_needed" : "quality_rejected";
|
|
592
555
|
const rejectDir = path.join(stash, ".akm", "distill-rejected");
|
|
@@ -602,6 +565,9 @@ function writeQualityRejection(stash, inputRef, lessonRef, content, score, reaso
|
|
|
602
565
|
score,
|
|
603
566
|
reason,
|
|
604
567
|
...extraMeta,
|
|
568
|
+
// Attribution tagging: stamp the eligibility lane so distill_invoked can be
|
|
569
|
+
// sliced by lane downstream. See EligibilitySource.
|
|
570
|
+
...(eligibilitySource ? { eligibilitySource } : {}),
|
|
605
571
|
},
|
|
606
572
|
});
|
|
607
573
|
return {
|
|
@@ -629,6 +595,12 @@ export async function akmDistill(options) {
|
|
|
629
595
|
// Validate the ref shape up front so a typo never reaches the LLM.
|
|
630
596
|
const parsedInputRef = parseAssetRef(inputRef);
|
|
631
597
|
const targetKind = options.proposalKind ?? "lesson";
|
|
598
|
+
// Attribution tagging: spread into every distill_invoked event's metadata so
|
|
599
|
+
// the lane that selected this asset is recorded uniformly across all outcome
|
|
600
|
+
// branches. Empty object when no lane was supplied (direct `akm distill`).
|
|
601
|
+
const eligMeta = options.eligibilitySource
|
|
602
|
+
? { eligibilitySource: options.eligibilitySource }
|
|
603
|
+
: {};
|
|
632
604
|
// Recursive-distillation guard. Distill produces *lessons* from non-lesson
|
|
633
605
|
// sources (memory, skill, knowledge, etc.). Calling distill on an existing
|
|
634
606
|
// lesson would derive `lesson:lesson-<name>-lesson-lesson` (double `-lesson`
|
|
@@ -650,6 +622,7 @@ export async function akmDistill(options) {
|
|
|
650
622
|
lessonRef: skippedRef,
|
|
651
623
|
message: "distill refuses lesson inputs — lessons are the distilled form, not a source",
|
|
652
624
|
skipReason: "recursive_lesson_input",
|
|
625
|
+
...eligMeta,
|
|
653
626
|
},
|
|
654
627
|
});
|
|
655
628
|
return {
|
|
@@ -671,15 +644,74 @@ export async function akmDistill(options) {
|
|
|
671
644
|
// Best-effort load: when the asset is not yet indexed we still proceed —
|
|
672
645
|
// the LLM is asked to distil from "available signal" (feedback alone).
|
|
673
646
|
let assetContent = null;
|
|
647
|
+
let assetFilePath = null;
|
|
674
648
|
try {
|
|
675
649
|
const filePath = await lookup(inputRef);
|
|
676
650
|
if (filePath && fs.existsSync(filePath)) {
|
|
651
|
+
assetFilePath = filePath;
|
|
677
652
|
assetContent = fs.readFileSync(filePath, "utf8");
|
|
678
653
|
}
|
|
679
654
|
}
|
|
680
655
|
catch {
|
|
681
656
|
assetContent = null;
|
|
682
657
|
}
|
|
658
|
+
// ── #608: Encoding-time salience scoring ────────────────────────────────
|
|
659
|
+
// Score the source asset with the three-signal model (novelty × 0.40 +
|
|
660
|
+
// magnitude × 0.35 + predictionError × 0.25) and persist the result to:
|
|
661
|
+
// 1. The asset's frontmatter (human-readable mirror; idempotent delta gate).
|
|
662
|
+
// 2. state.db :: asset_salience (canonical; feeds improve's high-salience gate).
|
|
663
|
+
// Both writes are best-effort — a DB error never blocks distillation.
|
|
664
|
+
if (assetContent && assetFilePath) {
|
|
665
|
+
try {
|
|
666
|
+
const parsedRef = parseAssetRef(inputRef);
|
|
667
|
+
// Build bigram vocabulary from currently-indexed refs for novelty signal.
|
|
668
|
+
let existingRefVocabulary = new Set();
|
|
669
|
+
try {
|
|
670
|
+
const embCfg = config?.embedding;
|
|
671
|
+
const indexDb = openIndexDatabase(getDbPath(), embCfg?.dimension ? { embeddingDim: embCfg.dimension } : undefined);
|
|
672
|
+
try {
|
|
673
|
+
const allRefs = getAllEntries(indexDb).map((e) => e.entryKey);
|
|
674
|
+
existingRefVocabulary = buildRefVocabulary(allRefs);
|
|
675
|
+
}
|
|
676
|
+
finally {
|
|
677
|
+
closeDatabase(indexDb);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
catch {
|
|
681
|
+
// Index not available — novelty defaults to type-floor.
|
|
682
|
+
}
|
|
683
|
+
const salienceResult = scoreEncodingSalience({
|
|
684
|
+
body: assetContent,
|
|
685
|
+
type: parsedRef.type,
|
|
686
|
+
existingRefVocabulary,
|
|
687
|
+
revisionCount: 0,
|
|
688
|
+
});
|
|
689
|
+
// 1. Write salience to the source asset frontmatter (idempotent).
|
|
690
|
+
const updatedContent = writeSalienceToFrontmatter(assetContent, salienceResult.score, salienceResult);
|
|
691
|
+
if (updatedContent !== assetContent) {
|
|
692
|
+
fs.writeFileSync(assetFilePath, updatedContent, "utf8");
|
|
693
|
+
assetContent = updatedContent;
|
|
694
|
+
}
|
|
695
|
+
// 2. Persist encoding_salience to state.db.
|
|
696
|
+
try {
|
|
697
|
+
withStateDb((stateDb) => {
|
|
698
|
+
const vector = computeSalience({
|
|
699
|
+
ref: inputRef,
|
|
700
|
+
type: parsedRef.type,
|
|
701
|
+
retrievalFreq: 0,
|
|
702
|
+
encodingSalience: salienceResult.score,
|
|
703
|
+
});
|
|
704
|
+
upsertAssetSalience(stateDb, inputRef, vector);
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
catch {
|
|
708
|
+
// State DB unavailable — frontmatter mirror is the only persistence.
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
catch {
|
|
712
|
+
// Scoring errors never block distillation.
|
|
713
|
+
}
|
|
714
|
+
}
|
|
683
715
|
const { events } = readEventsImpl({
|
|
684
716
|
ref: inputRef,
|
|
685
717
|
type: "feedback",
|
|
@@ -766,6 +798,7 @@ export async function akmDistill(options) {
|
|
|
766
798
|
outcome: "skipped",
|
|
767
799
|
lessonRef: promotion.knowledgeRef,
|
|
768
800
|
message: "D-1: LLM resolved destination conflict as NOOP — existing content kept",
|
|
801
|
+
...eligMeta,
|
|
769
802
|
},
|
|
770
803
|
});
|
|
771
804
|
return {
|
|
@@ -814,9 +847,9 @@ export async function akmDistill(options) {
|
|
|
814
847
|
if (!judgeResult.pass) {
|
|
815
848
|
if (judgeResult.reviewNeeded) {
|
|
816
849
|
// Uncertainty band (2.5–3.5): queue as review_needed instead of rejecting.
|
|
817
|
-
return writeQualityRejection(stash, inputRef, promotion.knowledgeRef, resolvedPromotionContent, judgeResult.score, judgeResult.reason, { reviewNeeded: true });
|
|
850
|
+
return writeQualityRejection(stash, inputRef, promotion.knowledgeRef, resolvedPromotionContent, judgeResult.score, judgeResult.reason, { reviewNeeded: true }, options.eligibilitySource);
|
|
818
851
|
}
|
|
819
|
-
return writeQualityRejection(stash, inputRef, promotion.knowledgeRef, resolvedPromotionContent, judgeResult.score, judgeResult.reason);
|
|
852
|
+
return writeQualityRejection(stash, inputRef, promotion.knowledgeRef, resolvedPromotionContent, judgeResult.score, judgeResult.reason, {}, options.eligibilitySource);
|
|
820
853
|
}
|
|
821
854
|
// Normalize 1-5 judge score to [0, 1]. Score of -1 means pass-through
|
|
822
855
|
// (no LLM / timeout / parse failure) — leave confidence undefined so
|
|
@@ -834,6 +867,8 @@ export async function akmDistill(options) {
|
|
|
834
867
|
...(Object.keys(knowledgeParsed.data).length > 0 ? { frontmatter: knowledgeParsed.data } : {}),
|
|
835
868
|
},
|
|
836
869
|
...(knowledgeJudgeConfidence !== undefined ? { confidence: knowledgeJudgeConfidence } : {}),
|
|
870
|
+
// Attribution tagging: persist the eligibility lane on the proposal.
|
|
871
|
+
...(options.eligibilitySource ? { eligibilitySource: options.eligibilitySource } : {}),
|
|
837
872
|
}, options.ctx);
|
|
838
873
|
if (isProposalSkipped(proposalResult)) {
|
|
839
874
|
appendEvent({
|
|
@@ -844,6 +879,7 @@ export async function akmDistill(options) {
|
|
|
844
879
|
lessonRef: promotion.knowledgeRef,
|
|
845
880
|
message: proposalResult.message,
|
|
846
881
|
skipReason: proposalResult.reason,
|
|
882
|
+
...eligMeta,
|
|
847
883
|
},
|
|
848
884
|
});
|
|
849
885
|
return {
|
|
@@ -867,6 +903,7 @@ export async function akmDistill(options) {
|
|
|
867
903
|
proposalId: proposal.id,
|
|
868
904
|
...(options.sourceRun !== undefined ? { sourceRun: options.sourceRun } : {}),
|
|
869
905
|
...(exclusionSet.size > 0 ? { filteredFeedbackCount } : {}),
|
|
906
|
+
...eligMeta,
|
|
870
907
|
},
|
|
871
908
|
});
|
|
872
909
|
return {
|
|
@@ -894,13 +931,36 @@ export async function akmDistill(options) {
|
|
|
894
931
|
reason: p.review?.reason ?? "no reason given",
|
|
895
932
|
contentPreview: p.payload.content.slice(0, 500),
|
|
896
933
|
}));
|
|
897
|
-
|
|
934
|
+
// WS-3b CLS interleaving (step 9).
|
|
935
|
+
// When cls.enabled, inject embedding-retrieved adjacent lessons/knowledge
|
|
936
|
+
// into the distill prompt so the LLM avoids overwriting prior generalizations
|
|
937
|
+
// (catastrophic interference). DEFAULT OFF.
|
|
938
|
+
const clsConfig = config.profiles?.improve?.default?.processes?.distill?.cls ?? {};
|
|
939
|
+
let clsContext = "";
|
|
940
|
+
if (clsConfig.enabled) {
|
|
941
|
+
try {
|
|
942
|
+
const adjacentCount = clsConfig.adjacentCount ?? 3;
|
|
943
|
+
// Use the asset content or input ref as the query for adjacent retrieval.
|
|
944
|
+
const clsQuery = assetContent ? assetContent.slice(0, 500) : inputRef;
|
|
945
|
+
const adjacentItems = await fetchSimilarLessonsFn(clsQuery, adjacentCount);
|
|
946
|
+
clsContext = buildClsContext(adjacentItems, clsConfig);
|
|
947
|
+
}
|
|
948
|
+
catch {
|
|
949
|
+
// Fail open — CLS is supplemental, never required.
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
// Distill output is a lesson/knowledge (non-wiki) → stash authoring
|
|
953
|
+
// standards. Resolved once for this single call.
|
|
954
|
+
const standardsContext = resolveStashStandards(stash);
|
|
955
|
+
const baseUserPrompt = buildDistillPrompt({
|
|
898
956
|
inputRef,
|
|
899
957
|
assetContent,
|
|
900
958
|
feedback,
|
|
901
959
|
proposalKind: effectiveProposalKind,
|
|
902
960
|
...(rejectedForRef.length > 0 ? { rejectedProposals: rejectedForRef } : {}),
|
|
961
|
+
...(standardsContext.trim() ? { standardsContext } : {}),
|
|
903
962
|
});
|
|
963
|
+
const userPrompt = clsContext ? `${baseUserPrompt}${clsContext}` : baseUserPrompt;
|
|
904
964
|
const messages = [
|
|
905
965
|
{ role: "system", content: effectiveProposalKind === "knowledge" ? KNOWLEDGE_SYSTEM_PROMPT : LESSON_SYSTEM_PROMPT },
|
|
906
966
|
{ role: "user", content: userPrompt },
|
|
@@ -979,6 +1039,7 @@ export async function akmDistill(options) {
|
|
|
979
1039
|
lessonRef: effectiveLessonRef,
|
|
980
1040
|
proposalKind: effectiveProposalKind,
|
|
981
1041
|
...(exclusionSet.size > 0 ? { filteredFeedbackCount } : {}),
|
|
1042
|
+
...eligMeta,
|
|
982
1043
|
},
|
|
983
1044
|
});
|
|
984
1045
|
return {
|
|
@@ -1203,6 +1264,7 @@ export async function akmDistill(options) {
|
|
|
1203
1264
|
proposalKind: effectiveProposalKind,
|
|
1204
1265
|
findingKinds: findings.map((f) => f.kind),
|
|
1205
1266
|
...(exclusionSet.size > 0 ? { filteredFeedbackCount } : {}),
|
|
1267
|
+
...eligMeta,
|
|
1206
1268
|
},
|
|
1207
1269
|
});
|
|
1208
1270
|
const message = findings.map((f) => f.message).join("\n");
|
|
@@ -1224,9 +1286,9 @@ export async function akmDistill(options) {
|
|
|
1224
1286
|
return writeQualityRejection(stash, inputRef, effectiveLessonRef, content, judgeResult.score, judgeResult.reason, {
|
|
1225
1287
|
reviewNeeded: true,
|
|
1226
1288
|
...(exclusionSet.size > 0 ? { filteredFeedbackCount, feedbackFullyFiltered } : {}),
|
|
1227
|
-
});
|
|
1289
|
+
}, options.eligibilitySource);
|
|
1228
1290
|
}
|
|
1229
|
-
return writeQualityRejection(stash, inputRef, effectiveLessonRef, content, judgeResult.score, judgeResult.reason, exclusionSet.size > 0 ? { filteredFeedbackCount, feedbackFullyFiltered } : {});
|
|
1291
|
+
return writeQualityRejection(stash, inputRef, effectiveLessonRef, content, judgeResult.score, judgeResult.reason, exclusionSet.size > 0 ? { filteredFeedbackCount, feedbackFullyFiltered } : {}, options.eligibilitySource);
|
|
1230
1292
|
}
|
|
1231
1293
|
// Normalize 1-5 judge score to [0, 1]. Score of -1 means pass-through
|
|
1232
1294
|
// (no LLM / timeout / parse failure) — leave confidence undefined so
|
|
@@ -1234,6 +1296,30 @@ export async function akmDistill(options) {
|
|
|
1234
1296
|
if (judgeResult.score > 0)
|
|
1235
1297
|
lessonJudgeConfidence = judgeResult.score / 5;
|
|
1236
1298
|
}
|
|
1299
|
+
// WS-3b: Distill→source fidelity check (step 10).
|
|
1300
|
+
// When fidelityCheck.enabled, check the distill proposal against its cited
|
|
1301
|
+
// source memories. A contradiction flag routes to human review (not auto-accept).
|
|
1302
|
+
// DEFAULT OFF. Fail-open: any error is treated as no-contradiction.
|
|
1303
|
+
const fidelityConfig = config.profiles?.improve?.default?.processes?.distill?.fidelityCheck ?? {};
|
|
1304
|
+
if (fidelityConfig.enabled && assetContent) {
|
|
1305
|
+
try {
|
|
1306
|
+
const proposalBody = stripBodyForFidelity(content);
|
|
1307
|
+
const sourceBodies = [stripBodyForFidelity(assetContent)];
|
|
1308
|
+
const fidelityResult = checkDistillFidelity(proposalBody, sourceBodies, fidelityConfig);
|
|
1309
|
+
if (fidelityResult.contradictionDetected) {
|
|
1310
|
+
// Route to human review by writing a quality rejection with reviewNeeded=true.
|
|
1311
|
+
return writeQualityRejection(stash, inputRef, effectiveLessonRef, content, 2.0, // below auto-accept threshold, signals review needed
|
|
1312
|
+
fidelityResult.reason ?? "Proposal may contradict cited source memories.", {
|
|
1313
|
+
reviewNeeded: true,
|
|
1314
|
+
fidelityContradiction: true,
|
|
1315
|
+
...(exclusionSet.size > 0 ? { filteredFeedbackCount, feedbackFullyFiltered } : {}),
|
|
1316
|
+
}, options.eligibilitySource);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
catch {
|
|
1320
|
+
// Fail open — fidelity check is supplemental.
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1237
1323
|
// Round-trip the parsed frontmatter so the proposal carries it as a
|
|
1238
1324
|
// structured payload alongside the raw content (matches the shape used by
|
|
1239
1325
|
// other proposal sources).
|
|
@@ -1256,6 +1342,8 @@ export async function akmDistill(options) {
|
|
|
1256
1342
|
frontmatter: frontmatterWithSources,
|
|
1257
1343
|
},
|
|
1258
1344
|
...(lessonJudgeConfidence !== undefined ? { confidence: lessonJudgeConfidence } : {}),
|
|
1345
|
+
// Attribution tagging: persist the eligibility lane on the proposal.
|
|
1346
|
+
...(options.eligibilitySource ? { eligibilitySource: options.eligibilitySource } : {}),
|
|
1259
1347
|
}, options.ctx);
|
|
1260
1348
|
if (isProposalSkipped(proposalResult2)) {
|
|
1261
1349
|
appendEvent({
|
|
@@ -1266,6 +1354,7 @@ export async function akmDistill(options) {
|
|
|
1266
1354
|
lessonRef: effectiveLessonRef,
|
|
1267
1355
|
message: proposalResult2.message,
|
|
1268
1356
|
skipReason: proposalResult2.reason,
|
|
1357
|
+
...eligMeta,
|
|
1269
1358
|
},
|
|
1270
1359
|
});
|
|
1271
1360
|
return {
|
|
@@ -1290,6 +1379,7 @@ export async function akmDistill(options) {
|
|
|
1290
1379
|
...(options.sourceRun !== undefined ? { sourceRun: options.sourceRun } : {}),
|
|
1291
1380
|
...(exclusionSet.size > 0 ? { filteredFeedbackCount } : {}),
|
|
1292
1381
|
...(descriptionSwapped > 0 ? { descriptionSwapped } : {}),
|
|
1382
|
+
...eligMeta,
|
|
1293
1383
|
},
|
|
1294
1384
|
});
|
|
1295
1385
|
return {
|