akm-cli 0.9.0-beta.9 → 0.9.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +715 -0
- package/README.md +12 -4
- package/dist/akm +38 -0
- package/dist/akm-migrate-storage +38 -0
- package/dist/assets/help/help-improve.md +9 -6
- package/dist/assets/hints/cli-hints-full.md +6 -5
- 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/proactive-maintenance.json +25 -0
- package/dist/assets/profiles/quick.json +1 -1
- package/dist/assets/profiles/recombine-only.json +21 -0
- package/dist/assets/profiles/reflect-distill.json +30 -0
- 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 +11 -3
- 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/prompts/workflow-unit-preamble.md +26 -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 +45 -16
- package/dist/assets/wiki/schema-template.md +4 -4
- package/dist/cli/clack.js +56 -0
- package/dist/cli/config-migrate.js +7 -1
- package/dist/cli/confirm.js +1 -1
- package/dist/cli/parse-args.js +46 -1
- package/dist/cli/shared.js +28 -0
- package/dist/cli.js +25 -21
- package/dist/commands/agent/agent-dispatch.js +3 -2
- package/dist/commands/agent/agent-support.js +0 -7
- package/dist/commands/agent/contribute-cli.js +26 -7
- package/dist/commands/config-cli.js +26 -13
- package/dist/commands/env/child-env.js +47 -0
- package/dist/commands/env/env-binding.js +95 -0
- package/dist/commands/env/env-cli.js +228 -292
- package/dist/commands/env/env.js +14 -67
- package/dist/commands/env/secret-cli.js +140 -138
- package/dist/commands/feedback-cli.js +156 -155
- package/dist/commands/graph/graph-cli.js +5 -13
- package/dist/commands/graph/graph.js +3 -3
- package/dist/commands/health/advisories.js +151 -0
- package/dist/commands/health/checks.js +103 -16
- package/dist/commands/health/html-report.js +447 -81
- package/dist/commands/health/improve-metrics.js +771 -0
- package/dist/commands/health/llm-usage.js +65 -0
- package/dist/commands/health/md-report.js +103 -0
- package/dist/commands/health/metrics.js +278 -0
- package/dist/commands/health/stash-exposure.js +46 -0
- package/dist/commands/health/surfaces.js +216 -0
- package/dist/commands/health/task-runs.js +135 -0
- package/dist/commands/health/types.js +26 -0
- package/dist/commands/health/windows.js +195 -0
- package/dist/commands/health.js +91 -1091
- package/dist/commands/improve/anti-collapse.js +170 -0
- package/dist/commands/improve/calibration.js +161 -0
- package/dist/commands/improve/collapse-detector.js +421 -0
- package/dist/commands/improve/consolidate/chunking.js +141 -0
- package/dist/commands/improve/consolidate/eligibility.js +64 -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 +1295 -1277
- package/dist/commands/improve/dedup.js +482 -0
- package/dist/commands/improve/distill/content-repair.js +202 -0
- package/dist/commands/improve/distill/promote-memory.js +229 -0
- package/dist/commands/improve/distill/quality-gate.js +236 -0
- package/dist/commands/improve/distill-guards.js +127 -0
- package/dist/commands/improve/distill-promotion-policy.js +826 -167
- package/dist/commands/improve/distill.js +228 -605
- package/dist/commands/improve/eligibility.js +434 -0
- package/dist/commands/improve/encoding-salience.js +205 -0
- package/dist/commands/improve/extract-cli.js +179 -59
- package/dist/commands/improve/extract-prompt.js +54 -3
- package/dist/commands/improve/extract-watch.js +140 -0
- package/dist/commands/improve/extract.js +409 -43
- package/dist/commands/improve/feedback-valence.js +54 -0
- package/dist/commands/improve/hot-probation.js +45 -0
- package/dist/commands/improve/improve-auto-accept.js +157 -10
- package/dist/commands/improve/improve-cli.js +115 -73
- package/dist/commands/improve/improve-profiles.js +28 -8
- package/dist/commands/improve/improve-result-file.js +15 -25
- package/dist/commands/improve/improve-session.js +58 -0
- package/dist/commands/improve/improve.js +485 -2764
- package/dist/commands/improve/locks.js +154 -0
- package/dist/commands/improve/loop-stages.js +1100 -0
- package/dist/commands/improve/memory/memory-belief.js +14 -15
- package/dist/commands/improve/memory/memory-contradiction-detect.js +83 -60
- package/dist/commands/improve/memory/memory-improve.js +27 -27
- package/dist/commands/improve/outcome-loop.js +270 -0
- package/dist/commands/improve/preparation.js +2002 -0
- package/dist/commands/improve/proactive-maintenance.js +37 -35
- package/dist/commands/improve/procedural.js +398 -0
- package/dist/commands/improve/recombine.js +818 -0
- package/dist/commands/improve/reflect-noise.js +0 -0
- package/dist/commands/improve/reflect.js +206 -45
- package/dist/commands/improve/salience.js +455 -0
- package/dist/commands/improve/schema-similarity-gate.js +168 -0
- package/dist/commands/improve/shared.js +51 -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/observability-cli.js +4 -4
- package/dist/commands/proposal/drain-policies.js +13 -4
- package/dist/commands/proposal/drain.js +45 -51
- package/dist/commands/proposal/legacy-import.js +115 -0
- package/dist/commands/proposal/proposal-cli.js +24 -34
- package/dist/commands/proposal/proposal.js +2 -1
- package/dist/commands/proposal/propose.js +8 -3
- package/dist/commands/proposal/repository.js +829 -0
- package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
- package/dist/commands/proposal/validators/proposals.js +93 -895
- package/dist/commands/read/curate.js +410 -111
- package/dist/commands/read/knowledge.js +10 -3
- package/dist/commands/read/remember-cli.js +133 -138
- package/dist/commands/read/search-cli.js +15 -8
- package/dist/commands/read/search.js +22 -11
- package/dist/commands/read/show.js +106 -14
- package/dist/commands/registry-cli.js +76 -87
- package/dist/commands/remember.js +11 -12
- package/dist/commands/sources/add-cli.js +91 -95
- package/dist/commands/sources/history.js +1 -1
- package/dist/commands/sources/init.js +66 -18
- package/dist/commands/sources/installed-stashes.js +11 -3
- package/dist/commands/sources/migration-help.js +7 -4
- package/dist/commands/sources/schema-repair.js +44 -46
- package/dist/commands/sources/self-update.js +2 -2
- package/dist/commands/sources/source-add.js +7 -3
- package/dist/commands/sources/sources-cli.js +3 -3
- package/dist/commands/sources/stash-cli.js +19 -39
- package/dist/commands/sources/stash-skeleton.js +57 -8
- package/dist/commands/tasks/default-tasks.js +15 -2
- package/dist/commands/tasks/tasks-cli.js +20 -29
- package/dist/commands/tasks/tasks.js +39 -11
- package/dist/commands/wiki-cli.js +23 -38
- package/dist/commands/workflow-cli.js +291 -13
- package/dist/core/asset/asset-registry.js +3 -1
- package/dist/core/asset/asset-spec.js +79 -5
- package/dist/core/asset/frontmatter.js +188 -167
- package/dist/core/asset/markdown.js +8 -0
- package/dist/core/authoring-rules.js +92 -0
- package/dist/core/common.js +4 -23
- package/dist/core/concurrent.js +10 -1
- package/dist/core/config/config-io.js +10 -1
- package/dist/core/config/config-migration.js +18 -40
- package/dist/core/config/config-schema.js +403 -62
- package/dist/core/config/config-types.js +3 -3
- package/dist/core/config/config.js +67 -22
- package/dist/core/deep-merge.js +38 -0
- package/dist/core/errors.js +1 -0
- package/dist/core/eval/rank-metrics.js +113 -0
- package/dist/core/events.js +4 -7
- package/dist/core/improve-types.js +47 -8
- package/dist/core/json-schema.js +142 -0
- package/dist/core/logs-db.js +14 -75
- package/dist/core/parse.js +36 -16
- package/dist/core/paths.js +18 -18
- 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 +770 -0
- package/dist/core/state-db.js +132 -1126
- package/dist/core/structured.js +69 -0
- package/dist/core/time.js +53 -0
- package/dist/core/warn.js +21 -0
- package/dist/core/write-source.js +37 -0
- package/dist/indexer/db/db.js +261 -770
- package/dist/indexer/db/entry-mapper.js +41 -0
- package/dist/indexer/db/graph-db.js +129 -86
- package/dist/indexer/db/llm-cache.js +2 -2
- package/dist/indexer/db/schema.js +516 -0
- package/dist/indexer/ensure-index.js +36 -92
- package/dist/indexer/feedback/utility-policy.js +75 -0
- package/dist/indexer/graph/graph-boost.js +51 -41
- package/dist/indexer/graph/graph-extraction.js +207 -4
- package/dist/indexer/index-writer-lock.js +18 -11
- package/dist/indexer/index-written-assets.js +105 -0
- package/dist/indexer/indexer.js +182 -204
- package/dist/indexer/passes/dir-staleness.js +114 -0
- package/dist/indexer/passes/memory-inference.js +13 -5
- package/dist/indexer/passes/metadata.js +20 -0
- package/dist/indexer/read-preflight.js +23 -0
- package/dist/indexer/search/db-search.js +89 -13
- package/dist/indexer/search/fts-query.js +51 -0
- package/dist/indexer/search/ranking-contributors.js +95 -9
- package/dist/indexer/search/ranking.js +79 -3
- package/dist/indexer/search/search-fields.js +6 -0
- package/dist/indexer/search/search-source.js +32 -21
- package/dist/indexer/search/semantic-status.js +4 -0
- package/dist/indexer/walk/matchers.js +48 -0
- package/dist/indexer/walk/walker.js +21 -13
- package/dist/integrations/agent/builders.js +41 -13
- package/dist/integrations/agent/config.js +20 -59
- package/dist/integrations/agent/detect.js +9 -0
- package/dist/integrations/agent/index.js +3 -19
- package/dist/integrations/agent/model-aliases.js +16 -2
- package/dist/integrations/agent/profiles.js +79 -6
- package/dist/integrations/agent/prompts.js +75 -9
- package/dist/integrations/agent/runner-dispatch.js +83 -0
- package/dist/integrations/agent/runner.js +13 -9
- package/dist/integrations/agent/spawn.js +206 -81
- package/dist/integrations/harnesses/aider/agent-builder.js +113 -0
- package/dist/integrations/harnesses/aider/index.js +58 -0
- package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
- package/dist/integrations/harnesses/amazonq/agent-builder.js +153 -0
- package/dist/integrations/harnesses/amazonq/index.js +59 -0
- package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
- package/dist/integrations/harnesses/claude/agent-builder.js +46 -7
- package/dist/integrations/harnesses/claude/index.js +27 -23
- package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
- package/dist/integrations/harnesses/claude/session-log.js +10 -0
- package/dist/integrations/harnesses/codex/agent-builder.js +137 -0
- package/dist/integrations/harnesses/codex/index.js +63 -0
- package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
- package/dist/integrations/harnesses/copilot/agent-builder.js +122 -0
- package/dist/integrations/harnesses/copilot/index.js +60 -0
- package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
- package/dist/integrations/harnesses/gemini/agent-builder.js +121 -0
- package/dist/integrations/harnesses/gemini/index.js +60 -0
- package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
- package/dist/integrations/harnesses/index.js +28 -7
- package/dist/integrations/harnesses/opencode/agent-builder.js +1 -1
- package/dist/integrations/harnesses/opencode/index.js +17 -16
- package/dist/integrations/harnesses/opencode/session-log.js +173 -3
- package/dist/integrations/harnesses/opencode-sdk/harness.js +65 -0
- package/dist/integrations/harnesses/opencode-sdk/index.js +10 -34
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +642 -71
- package/dist/integrations/harnesses/openhands/agent-builder.js +126 -0
- package/dist/integrations/harnesses/openhands/index.js +58 -0
- package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
- package/dist/integrations/harnesses/pi/agent-builder.js +104 -0
- package/dist/integrations/harnesses/pi/index.js +58 -0
- package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
- package/dist/integrations/harnesses/types.js +8 -0
- package/dist/integrations/session-logs/index.js +40 -11
- package/dist/llm/call-ai.js +2 -2
- package/dist/llm/client.js +34 -11
- package/dist/llm/embedder.js +67 -4
- package/dist/llm/embedders/cache.js +3 -1
- package/dist/llm/embedders/deterministic.js +66 -0
- package/dist/llm/embedders/local.js +73 -3
- package/dist/llm/feature-gate.js +16 -15
- 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 +87 -15
- package/dist/output/shapes/curate.js +14 -2
- package/dist/output/shapes/helpers.js +0 -3
- package/dist/output/shapes/passthrough.js +6 -1
- package/dist/output/text/helpers.js +241 -2
- package/dist/output/text/workflow.js +4 -1
- package/dist/registry/providers/skills-sh.js +21 -147
- package/dist/registry/providers/static-index.js +15 -157
- package/dist/registry/resolve.js +27 -9
- package/dist/runtime.js +25 -1
- package/dist/schemas/akm-config.json +14225 -0
- package/dist/schemas/akm-workflow.json +328 -0
- package/dist/scripts/migrate-storage.js +2743 -8390
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +1652 -607
- package/dist/setup/detect.js +9 -0
- package/dist/setup/legacy-config.js +106 -0
- package/dist/setup/prompt.js +57 -0
- package/dist/setup/providers.js +14 -0
- package/dist/setup/registry-stash-loader.js +12 -0
- package/dist/setup/semantic-assets.js +124 -0
- package/dist/setup/setup.js +52 -1614
- package/dist/setup/steps/connection.js +734 -0
- package/dist/setup/steps/output.js +31 -0
- package/dist/setup/steps/platforms.js +124 -0
- package/dist/setup/steps/semantic.js +27 -0
- package/dist/setup/steps/sources.js +222 -0
- package/dist/setup/steps/stashdir.js +42 -0
- package/dist/setup/steps/tasks.js +152 -0
- 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/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/canaries-repository.js +107 -0
- package/dist/storage/repositories/consolidation-repository.js +38 -0
- package/dist/storage/repositories/embeddings-repository.js +72 -0
- package/dist/storage/repositories/events-repository.js +187 -0
- package/dist/storage/repositories/extract-sessions-repository.js +96 -0
- package/dist/storage/repositories/improve-runs-repository.js +146 -0
- package/dist/storage/repositories/index-db.js +14 -8
- package/dist/storage/repositories/proposals-repository.js +220 -0
- package/dist/storage/repositories/recombine-repository.js +213 -0
- package/dist/storage/repositories/registry-cache.js +93 -0
- package/dist/storage/repositories/registry-index-cache-repository.js +46 -0
- package/dist/storage/repositories/task-history-repository.js +93 -0
- package/dist/storage/repositories/workflow-runs-repository.js +189 -1
- package/dist/storage/sqlite-pragmas.js +146 -0
- package/dist/tasks/backends/cron.js +1 -1
- package/dist/tasks/backends/index.js +9 -0
- 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 +15 -13
- package/dist/text-import-hook.mjs +1 -1
- package/dist/wiki/wiki.js +52 -11
- package/dist/workflows/authoring/authoring.js +123 -10
- package/dist/workflows/authoring/workflow-program-template.yaml +31 -0
- package/dist/workflows/cli.js +5 -0
- package/dist/workflows/db.js +138 -4
- package/dist/workflows/exec/brief.js +484 -0
- package/dist/workflows/exec/native-executor.js +975 -0
- package/dist/workflows/exec/param-secrets.js +115 -0
- package/dist/workflows/exec/report.js +1295 -0
- package/dist/workflows/exec/run-workflow.js +596 -0
- package/dist/workflows/exec/scheduler.js +100 -0
- package/dist/workflows/exec/step-work.js +1156 -0
- package/dist/workflows/exec/unit-writer.js +23 -0
- package/dist/workflows/exec/watch.js +116 -0
- package/dist/workflows/exec/worktree.js +171 -0
- package/dist/workflows/ir/compile.js +388 -0
- package/dist/workflows/ir/params.js +54 -0
- package/dist/workflows/ir/plan-hash.js +33 -0
- package/dist/workflows/ir/schema.js +4 -0
- package/dist/workflows/parser.js +3 -1
- package/dist/workflows/program/expressions.js +369 -0
- package/dist/workflows/program/parser.js +760 -0
- package/dist/workflows/program/project.js +105 -0
- package/dist/workflows/program/schema.js +54 -0
- package/dist/workflows/renderer.js +82 -5
- package/dist/workflows/runtime/agent-identity.js +59 -14
- package/dist/workflows/runtime/runs.js +248 -153
- package/dist/workflows/runtime/unit-checkin.js +45 -0
- package/dist/workflows/runtime/workflow-asset-loader.js +188 -0
- package/dist/workflows/validate-summary.js +26 -10
- package/dist/workflows/validator.js +1 -1
- package/docs/README.md +69 -18
- package/docs/data-and-telemetry.md +7 -5
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.9.0-beta.60.md +19 -0
- package/docs/migration/release-notes/0.9.0.md +39 -0
- package/package.json +10 -10
- package/dist/assets/tasks/core/update-stashes.yml +0 -4
- package/dist/commands/db-cli.js +0 -23
- package/dist/indexer/db/db-backup.js +0 -376
- package/dist/indexer/passes/staleness-detect.js +0 -488
|
@@ -20,11 +20,13 @@
|
|
|
20
20
|
* the connection via `resolveIndexPassLLM("graph", config)` and pass it
|
|
21
21
|
* straight through.
|
|
22
22
|
*/
|
|
23
|
+
import systemPromptTemplate from "../assets/prompts/graph-extract-system.md" with { type: "text" };
|
|
23
24
|
import userPromptTemplate from "../assets/prompts/graph-extract-user-prompt.md" with { type: "text" };
|
|
24
25
|
import { toErrorMessage } from "../core/common.js";
|
|
25
26
|
import { warn, warnVerbose } from "../core/warn.js";
|
|
26
|
-
import { chatCompletion,
|
|
27
|
+
import { chatCompletion, isContextSizeError, parseEmbeddedJsonResponse } from "./client.js";
|
|
27
28
|
import { tryLlmFeature } from "./feature-gate.js";
|
|
29
|
+
import { callStructured } from "./structured-call.js";
|
|
28
30
|
/**
|
|
29
31
|
* Separator token used between assets in a batch prompt.
|
|
30
32
|
* Chosen to be visually clear and unlikely to appear verbatim in asset bodies.
|
|
@@ -41,30 +43,15 @@ const NON_ARRAY_BATCH_DISABLE_THRESHOLD = 2;
|
|
|
41
43
|
const MAX_ENTITIES_PER_ASSET = 32;
|
|
42
44
|
/** Hard cap on relations returned per asset. */
|
|
43
45
|
const MAX_RELATIONS_PER_ASSET = 32;
|
|
44
|
-
const SYSTEM_PROMPT =
|
|
46
|
+
const SYSTEM_PROMPT = systemPromptTemplate;
|
|
45
47
|
const USER_PROMPT_PREFIX = userPromptTemplate
|
|
46
48
|
.replace("{{MAX_ENTITIES}}", String(MAX_ENTITIES_PER_ASSET))
|
|
47
49
|
.replace("{{MAX_RELATIONS}}", String(MAX_RELATIONS_PER_ASSET));
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
* model prose merely mentioning "context size" / "context length" (e.g. gemma
|
|
54
|
-
* narrating about a document) does not get misclassified as a provider
|
|
55
|
-
* context-limit error (#496).
|
|
56
|
-
*/
|
|
57
|
-
export function isContextSizeError(message) {
|
|
58
|
-
const lower = message.toLowerCase();
|
|
59
|
-
const contextKw = /context (size|length|window)|prompt too long|exceeds.*context/.test(lower);
|
|
60
|
-
if (!contextKw) {
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
const evidence = /\b\d+\s*(token|tokens|tk)\b/.test(lower) ||
|
|
64
|
-
/max(imum)?\s+(context|token|input)/.test(lower) ||
|
|
65
|
-
/exceeded|over.*limit|too.*long/.test(lower);
|
|
66
|
-
return evidence;
|
|
67
|
-
}
|
|
50
|
+
// `isContextSizeError` is defined in `./client` and re-exported here so the
|
|
51
|
+
// graph extractor and the retry classifier (`isRetryable`) share one
|
|
52
|
+
// definition (#496). Re-exported (not just imported) to preserve existing
|
|
53
|
+
// importers of this module — including its unit test.
|
|
54
|
+
export { isContextSizeError } from "./client.js";
|
|
68
55
|
const GENERIC_ENTITIES = new Set([
|
|
69
56
|
"agent",
|
|
70
57
|
"application",
|
|
@@ -327,7 +314,13 @@ function parseGraphExtraction(raw) {
|
|
|
327
314
|
if (!normalized)
|
|
328
315
|
continue;
|
|
329
316
|
const normalizedKey = normalized.toLowerCase();
|
|
330
|
-
|
|
317
|
+
// Drop generic/empty entities AND raw file/dir paths (anything with a
|
|
318
|
+
// path separator) — the prompt no longer asks for them and isJunkEntity
|
|
319
|
+
// discards them downstream, so emitting them is pure waste/junk (#632).
|
|
320
|
+
if (!/[a-z0-9]/i.test(normalized) ||
|
|
321
|
+
GENERIC_ENTITIES.has(normalizedKey) ||
|
|
322
|
+
normalized.includes("/") ||
|
|
323
|
+
normalized.includes("\\")) {
|
|
331
324
|
filteredGenericEntities += 1;
|
|
332
325
|
continue;
|
|
333
326
|
}
|
|
@@ -432,6 +425,18 @@ function buildBatchSystemPrompt() {
|
|
|
432
425
|
"The array length MUST equal the number of assets provided. " +
|
|
433
426
|
'Use {"entities":[],"relations":[]} for assets with no extractable graph content.');
|
|
434
427
|
}
|
|
428
|
+
/**
|
|
429
|
+
* Hardened system prompt for the single batch retry (#635). Used only after a
|
|
430
|
+
* first response failed array salvage — leans harder on "raw array only" so a
|
|
431
|
+
* model that wrapped the array in prose/fences corrects itself before we pay
|
|
432
|
+
* the per-asset fallback.
|
|
433
|
+
*/
|
|
434
|
+
function buildBatchRetrySystemPrompt() {
|
|
435
|
+
return (`${buildBatchSystemPrompt()} ` +
|
|
436
|
+
"Your previous response could NOT be parsed as a JSON array. " +
|
|
437
|
+
"Respond with ONLY the raw JSON array — start with '[' and end with ']'. " +
|
|
438
|
+
"No prose, no explanation, no markdown code fences, no preamble.");
|
|
439
|
+
}
|
|
435
440
|
function buildBatchUserPrompt(bodies) {
|
|
436
441
|
const count = bodies.length;
|
|
437
442
|
const assetBlocks = bodies.map((body, i) => `${BATCH_ASSET_SEPARATOR} ${i + 1} ===\n${body.trim()}`).join("\n\n");
|
|
@@ -541,7 +546,21 @@ export async function extractGraphFromBodies(llmConfig, bodies, signal, akmConfi
|
|
|
541
546
|
});
|
|
542
547
|
if (!raw)
|
|
543
548
|
return null;
|
|
544
|
-
|
|
549
|
+
// Array-preferring salvage (#635): the batch contract is a top-level
|
|
550
|
+
// JSON array. A leading/example `{…}` object in the response must not
|
|
551
|
+
// mask a valid `[…]` array as a false "non-array" failure.
|
|
552
|
+
let parsed = parseEmbeddedJsonResponse(raw, { expect: "array" });
|
|
553
|
+
if (!Array.isArray(parsed)) {
|
|
554
|
+
// One stricter-reprompt retry before paying the per-asset fallback
|
|
555
|
+
// (#635). Many genuine non-array responses recover when the model is
|
|
556
|
+
// told explicitly to emit only the raw array.
|
|
557
|
+
bumpTelemetry(options.telemetry, "retryAttempts");
|
|
558
|
+
const retryRaw = await chatCompletion(llmConfig, [
|
|
559
|
+
{ role: "system", content: buildBatchRetrySystemPrompt() },
|
|
560
|
+
{ role: "user", content: userPrompt },
|
|
561
|
+
], { temperature: 0, timeoutMs: llmConfig.timeoutMs, signal });
|
|
562
|
+
parsed = retryRaw ? parseEmbeddedJsonResponse(retryRaw, { expect: "array" }) : undefined;
|
|
563
|
+
}
|
|
545
564
|
if (!Array.isArray(parsed)) {
|
|
546
565
|
nonArrayResponse = true;
|
|
547
566
|
bumpTelemetry(options.telemetry, "nonArrayBatchFailures");
|
|
@@ -551,8 +570,9 @@ export async function extractGraphFromBodies(llmConfig, bodies, signal, akmConfi
|
|
|
551
570
|
batchState.batchingDisabled = true;
|
|
552
571
|
}
|
|
553
572
|
}
|
|
554
|
-
warn(`graph extraction (batch): LLM response was not a JSON array for ${nonEmptyBodies.length} asset(s)
|
|
555
|
-
`will fall back per-asset.
|
|
573
|
+
warn(`graph extraction (batch): LLM response was not a JSON array for ${nonEmptyBodies.length} asset(s) ` +
|
|
574
|
+
`even after a stricter retry; will fall back per-asset. ` +
|
|
575
|
+
`promptChars=${userPrompt.length}${formatContextHint(llmConfig)}`);
|
|
556
576
|
return null;
|
|
557
577
|
}
|
|
558
578
|
return parsed;
|
|
@@ -675,17 +695,21 @@ export async function extractGraphFromBody(llmConfig, body, signal, akmConfig, o
|
|
|
675
695
|
return merged;
|
|
676
696
|
}
|
|
677
697
|
const userPrompt = `${USER_PROMPT_PREFIX}${trimmedBody}`;
|
|
678
|
-
return
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
698
|
+
return callStructured({
|
|
699
|
+
feature: "graph_extraction",
|
|
700
|
+
akmConfig,
|
|
701
|
+
config: llmConfig,
|
|
702
|
+
messages: [
|
|
703
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
|
704
|
+
{ role: "user", content: userPrompt },
|
|
705
|
+
],
|
|
706
|
+
request: {
|
|
707
|
+
temperature: 0.1,
|
|
708
|
+
timeoutMs: llmConfig.timeoutMs,
|
|
709
|
+
signal,
|
|
710
|
+
onRetryAttempt: () => bumpTelemetry(options.telemetry, "retryAttempts"),
|
|
711
|
+
},
|
|
712
|
+
parse: (raw) => {
|
|
689
713
|
if (!raw)
|
|
690
714
|
return empty();
|
|
691
715
|
const parsed = parseEmbeddedJsonResponse(raw);
|
|
@@ -701,16 +725,16 @@ export async function extractGraphFromBody(llmConfig, body, signal, akmConfig, o
|
|
|
701
725
|
if (extraction.status === "failed")
|
|
702
726
|
bumpTelemetry(options.telemetry, "failureCount");
|
|
703
727
|
return extraction;
|
|
704
|
-
}
|
|
705
|
-
|
|
728
|
+
},
|
|
729
|
+
onError: (cls, err) => {
|
|
706
730
|
const errMsg = toErrorMessage(err);
|
|
707
|
-
if (
|
|
731
|
+
if (cls === "context_limit") {
|
|
708
732
|
bumpTelemetry(options.telemetry, "failureCount");
|
|
709
733
|
warn(`graph extraction: context size exceeded for asset; promptChars=${userPrompt.length}${formatContextHint(llmConfig)}. ` +
|
|
710
734
|
`Consider increasing llm.contextLength in config.json.`);
|
|
711
735
|
return empty("context_limit", "failed");
|
|
712
736
|
}
|
|
713
|
-
else if (
|
|
737
|
+
else if (cls === "html") {
|
|
714
738
|
bumpTelemetry(options.telemetry, "htmlErrorCount");
|
|
715
739
|
warn(`graph extraction: provider returned HTML instead of JSON for asset; promptChars=${userPrompt.length}${formatContextHint(llmConfig)}: ${errMsg}`);
|
|
716
740
|
return empty("llm_error", "failed");
|
|
@@ -720,9 +744,8 @@ export async function extractGraphFromBody(llmConfig, body, signal, akmConfig, o
|
|
|
720
744
|
warn(`graph extraction failed for asset; promptChars=${userPrompt.length}${formatContextHint(llmConfig)}: ${errMsg}`);
|
|
721
745
|
return empty("llm_error", "failed");
|
|
722
746
|
}
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
timeoutMs: llmConfig.timeoutMs,
|
|
747
|
+
},
|
|
748
|
+
fallback: empty(),
|
|
726
749
|
onFallback,
|
|
727
750
|
});
|
|
728
751
|
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
/**
|
|
5
|
+
* LLM helper for the `akm index` memory-inference pass (#201).
|
|
6
|
+
*
|
|
7
|
+
* Compresses a single memory body into one higher-signal derived memory. The
|
|
8
|
+
* pass itself (in `src/indexer/memory-inference.ts`) is responsible for
|
|
9
|
+
* deciding which memories are pending, persisting the derived memory with the
|
|
10
|
+
* correct frontmatter (`inferred: true`, `source: <parent-ref>`), and marking
|
|
11
|
+
* the parent as processed for idempotency.
|
|
12
|
+
*
|
|
13
|
+
* This module is intentionally tiny and stateless so tests can stub it via
|
|
14
|
+
* `mock.module("../src/llm/memory-infer", ...)` without hitting a network.
|
|
15
|
+
*
|
|
16
|
+
* Locked v1 contract (#208): the LLM connection always comes from the
|
|
17
|
+
* shared `akm.llm` block — never from a per-pass override. Callers obtain
|
|
18
|
+
* the connection via `resolveIndexPassLLM("memory", config)` and pass it
|
|
19
|
+
* straight through.
|
|
20
|
+
*/
|
|
21
|
+
import memoryInferSystemPrompt from "../assets/prompts/memory-infer-system.md" with { type: "text" };
|
|
22
|
+
import memoryInferUserPrompt from "../assets/prompts/memory-infer-user.md" with { type: "text" };
|
|
23
|
+
import { toErrorMessage } from "../core/common.js";
|
|
24
|
+
import { warn } from "../core/warn.js";
|
|
25
|
+
import { parseEmbeddedJsonResponse } from "./client.js";
|
|
26
|
+
import { callStructured } from "./structured-call.js";
|
|
27
|
+
/** Hard cap on body chars sent to the model — pragmatic and matches `runLlmEnrich`. */
|
|
28
|
+
const MAX_BODY_CHARS = 4000;
|
|
29
|
+
const SYSTEM_PROMPT = memoryInferSystemPrompt;
|
|
30
|
+
const USER_PROMPT_PREFIX = memoryInferUserPrompt;
|
|
31
|
+
/**
|
|
32
|
+
* Strict JSON Schema for the derived-memory payload. Sent to providers that
|
|
33
|
+
* opt in via `LlmConnectionConfig.supportsJsonSchema = true`; the client
|
|
34
|
+
* silently drops the schema for providers that don't.
|
|
35
|
+
*
|
|
36
|
+
* Extends the responseSchema lift (PR 1, asset-writers-investigation §5) to
|
|
37
|
+
* the memory-inference path. Mirrors the validation gate below
|
|
38
|
+
* (title/description/content + non-empty tags/searchHints) so a
|
|
39
|
+
* schema-compliant response is guaranteed to pass the downstream check
|
|
40
|
+
* — no more "incomplete derived memory payload from LLM; skipping memory"
|
|
41
|
+
* for shape-only failures.
|
|
42
|
+
*/
|
|
43
|
+
const DERIVED_MEMORY_JSON_SCHEMA = {
|
|
44
|
+
type: "object",
|
|
45
|
+
properties: {
|
|
46
|
+
title: { type: "string", minLength: 1 },
|
|
47
|
+
description: { type: "string", minLength: 1 },
|
|
48
|
+
content: { type: "string", minLength: 1 },
|
|
49
|
+
tags: { type: "array", items: { type: "string" }, minItems: 1, maxItems: 8 },
|
|
50
|
+
searchHints: { type: "array", items: { type: "string" }, minItems: 1, maxItems: 6 },
|
|
51
|
+
},
|
|
52
|
+
required: ["title", "description", "content", "tags", "searchHints"],
|
|
53
|
+
additionalProperties: false,
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Compress a single memory body into one derived memory via the configured LLM.
|
|
57
|
+
*
|
|
58
|
+
* Returns `undefined` on any failure (timeout, invalid JSON, empty response).
|
|
59
|
+
* Errors are logged via `warn()` but never thrown — a failed split for one memory
|
|
60
|
+
* must not abort the rest of the index pass.
|
|
61
|
+
*
|
|
62
|
+
* Routes through `callStructured({ feature: "memory_inference", ... })` so the
|
|
63
|
+
* feature gate, error classification, and onFallback hook are honoured uniformly
|
|
64
|
+
* (Fix C5).
|
|
65
|
+
*/
|
|
66
|
+
export async function compressMemoryToDerivedMemory(llmConfig, body, signal, akmConfig, onFallback, telemetry, onRetryAttempt) {
|
|
67
|
+
const trimmedBody = body.trim();
|
|
68
|
+
if (!trimmedBody)
|
|
69
|
+
return undefined;
|
|
70
|
+
const userPrompt = `${USER_PROMPT_PREFIX}${trimmedBody.slice(0, MAX_BODY_CHARS)}`;
|
|
71
|
+
// Memory-inference is ALWAYS gated: no `akmConfig` ⇒ gate closed (no chat,
|
|
72
|
+
// `disabled` fallback), never the seam's ungated/propagate path (which is for
|
|
73
|
+
// direct callers like `enhanceMetadata`). This is the gate-closed branch
|
|
74
|
+
// `tryLlmFeature(_, undefined, _)` took before the migration.
|
|
75
|
+
if (!akmConfig) {
|
|
76
|
+
onFallback?.({ feature: "memory_inference", reason: "disabled" });
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
return callStructured({
|
|
80
|
+
feature: "memory_inference",
|
|
81
|
+
akmConfig,
|
|
82
|
+
config: llmConfig,
|
|
83
|
+
messages: [
|
|
84
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
|
85
|
+
{ role: "user", content: userPrompt },
|
|
86
|
+
],
|
|
87
|
+
request: {
|
|
88
|
+
temperature: 0.1,
|
|
89
|
+
timeoutMs: llmConfig.timeoutMs,
|
|
90
|
+
signal,
|
|
91
|
+
responseSchema: DERIVED_MEMORY_JSON_SCHEMA,
|
|
92
|
+
onRetryAttempt,
|
|
93
|
+
},
|
|
94
|
+
parse: (raw) => {
|
|
95
|
+
if (!raw)
|
|
96
|
+
return undefined;
|
|
97
|
+
const parsed = parseEmbeddedJsonResponse(raw);
|
|
98
|
+
if (!parsed) {
|
|
99
|
+
warn("memory inference: invalid JSON response from LLM; skipping memory.");
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
const title = typeof parsed.title === "string" ? parsed.title.trim() : "";
|
|
103
|
+
const description = typeof parsed.description === "string" ? parsed.description.trim() : "";
|
|
104
|
+
const content = typeof parsed.content === "string" ? parsed.content.trim() : "";
|
|
105
|
+
const tags = Array.isArray(parsed.tags)
|
|
106
|
+
? parsed.tags
|
|
107
|
+
.filter((t) => typeof t === "string")
|
|
108
|
+
.map((t) => t.trim())
|
|
109
|
+
.filter(Boolean)
|
|
110
|
+
.slice(0, 8)
|
|
111
|
+
: [];
|
|
112
|
+
const searchHints = Array.isArray(parsed.searchHints)
|
|
113
|
+
? parsed.searchHints
|
|
114
|
+
.filter((h) => typeof h === "string")
|
|
115
|
+
.map((h) => h.trim())
|
|
116
|
+
.filter(Boolean)
|
|
117
|
+
.slice(0, 6)
|
|
118
|
+
: [];
|
|
119
|
+
if (!title || !description || !content || tags.length === 0 || searchHints.length === 0) {
|
|
120
|
+
warn("memory inference: incomplete derived memory payload from LLM; skipping memory.");
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
return { title, description, tags, searchHints, content };
|
|
124
|
+
},
|
|
125
|
+
onError: (cls, err) => {
|
|
126
|
+
if (cls === "html") {
|
|
127
|
+
if (telemetry)
|
|
128
|
+
telemetry.htmlErrorCount = (telemetry.htmlErrorCount ?? 0) + 1;
|
|
129
|
+
warn(`memory inference: provider returned HTML instead of JSON; skipping memory: ${toErrorMessage(err)}`);
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
warn(`memory inference failed: ${toErrorMessage(err)}`);
|
|
133
|
+
return undefined;
|
|
134
|
+
},
|
|
135
|
+
fallback: undefined,
|
|
136
|
+
onFallback,
|
|
137
|
+
});
|
|
138
|
+
}
|
package/dist/llm/memory-infer.js
CHANGED
|
@@ -1,130 +1,4 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
|
|
5
|
-
* LLM helper for the `akm index` memory-inference pass (#201).
|
|
6
|
-
*
|
|
7
|
-
* Compresses a single memory body into one higher-signal derived memory. The
|
|
8
|
-
* pass itself (in `src/indexer/memory-inference.ts`) is responsible for
|
|
9
|
-
* deciding which memories are pending, persisting the derived memory with the
|
|
10
|
-
* correct frontmatter (`inferred: true`, `source: <parent-ref>`), and marking
|
|
11
|
-
* the parent as processed for idempotency.
|
|
12
|
-
*
|
|
13
|
-
* This module is intentionally tiny and stateless so tests can stub it via
|
|
14
|
-
* `mock.module("../src/llm/memory-infer", ...)` without hitting a network.
|
|
15
|
-
*
|
|
16
|
-
* Locked v1 contract (#208): the LLM connection always comes from the
|
|
17
|
-
* shared `akm.llm` block — never from a per-pass override. Callers obtain
|
|
18
|
-
* the connection via `resolveIndexPassLLM("memory", config)` and pass it
|
|
19
|
-
* straight through.
|
|
20
|
-
*/
|
|
21
|
-
import { toErrorMessage } from "../core/common.js";
|
|
22
|
-
import { warn } from "../core/warn.js";
|
|
23
|
-
import { chatCompletion, LlmCallError, parseEmbeddedJsonResponse } from "./client.js";
|
|
24
|
-
import { tryLlmFeature } from "./feature-gate.js";
|
|
25
|
-
/** Hard cap on body chars sent to the model — pragmatic and matches `runLlmEnrich`. */
|
|
26
|
-
const MAX_BODY_CHARS = 4000;
|
|
27
|
-
const SYSTEM_PROMPT = "You compress a developer memory into one high-signal derived memory for later retrieval. " +
|
|
28
|
-
"Return only valid JSON. No prose outside the JSON object. No markdown fences.";
|
|
29
|
-
const USER_PROMPT_PREFIX = `Compress the memory below into one derived memory. Output ONLY JSON:
|
|
30
|
-
{"title":"short title string","description":"one sentence summary string","tags":["tag1","tag2"],"searchHints":["search phrase 1","search phrase 2"],"content":"2-3 sentence compressed body preserving key facts verbatim"}
|
|
31
|
-
Rules: be specific, no vague generalizations, preserve key facts (names/versions/paths/config keys verbatim), merge related points, 3-8 tags, 3-6 searchHints. The content field must be a plain string with 2-3 sentences.
|
|
32
|
-
|
|
33
|
-
Memory:
|
|
34
|
-
`;
|
|
35
|
-
/**
|
|
36
|
-
* Strict JSON Schema for the derived-memory payload. Sent to providers that
|
|
37
|
-
* opt in via `LlmConnectionConfig.supportsJsonSchema = true`; the client
|
|
38
|
-
* silently drops the schema for providers that don't.
|
|
39
|
-
*
|
|
40
|
-
* Extends the responseSchema lift (PR 1, asset-writers-investigation §5) to
|
|
41
|
-
* the memory-inference path. Mirrors the validation gate below
|
|
42
|
-
* (title/description/content + non-empty tags/searchHints) so a
|
|
43
|
-
* schema-compliant response is guaranteed to pass the downstream check
|
|
44
|
-
* — no more "incomplete derived memory payload from LLM; skipping memory"
|
|
45
|
-
* for shape-only failures.
|
|
46
|
-
*/
|
|
47
|
-
const DERIVED_MEMORY_JSON_SCHEMA = {
|
|
48
|
-
type: "object",
|
|
49
|
-
properties: {
|
|
50
|
-
title: { type: "string", minLength: 1 },
|
|
51
|
-
description: { type: "string", minLength: 1 },
|
|
52
|
-
content: { type: "string", minLength: 1 },
|
|
53
|
-
tags: { type: "array", items: { type: "string" }, minItems: 1, maxItems: 8 },
|
|
54
|
-
searchHints: { type: "array", items: { type: "string" }, minItems: 1, maxItems: 6 },
|
|
55
|
-
},
|
|
56
|
-
required: ["title", "description", "content", "tags", "searchHints"],
|
|
57
|
-
additionalProperties: false,
|
|
58
|
-
};
|
|
59
|
-
/**
|
|
60
|
-
* Compress a single memory body into one derived memory via the configured LLM.
|
|
61
|
-
*
|
|
62
|
-
* Returns `undefined` on any failure (timeout, invalid JSON, empty response).
|
|
63
|
-
* Errors are logged via `warn()` but never thrown — a failed split for one memory
|
|
64
|
-
* must not abort the rest of the index pass.
|
|
65
|
-
*
|
|
66
|
-
* Routes through `tryLlmFeature("memory_inference", ...)` so the feature gate
|
|
67
|
-
* and onFallback hook are honoured uniformly (Fix C5).
|
|
68
|
-
*/
|
|
69
|
-
export async function compressMemoryToDerivedMemory(llmConfig, body, signal, akmConfig, onFallback, telemetry, onRetryAttempt) {
|
|
70
|
-
const trimmedBody = body.trim();
|
|
71
|
-
if (!trimmedBody)
|
|
72
|
-
return undefined;
|
|
73
|
-
const userPrompt = `${USER_PROMPT_PREFIX}${trimmedBody.slice(0, MAX_BODY_CHARS)}`;
|
|
74
|
-
return tryLlmFeature("memory_inference", akmConfig, async () => {
|
|
75
|
-
try {
|
|
76
|
-
const raw = await chatCompletion(llmConfig, [
|
|
77
|
-
{ role: "system", content: SYSTEM_PROMPT },
|
|
78
|
-
{ role: "user", content: userPrompt },
|
|
79
|
-
], {
|
|
80
|
-
temperature: 0.1,
|
|
81
|
-
timeoutMs: llmConfig.timeoutMs,
|
|
82
|
-
signal,
|
|
83
|
-
responseSchema: DERIVED_MEMORY_JSON_SCHEMA,
|
|
84
|
-
onRetryAttempt,
|
|
85
|
-
});
|
|
86
|
-
if (!raw)
|
|
87
|
-
return undefined;
|
|
88
|
-
const parsed = parseEmbeddedJsonResponse(raw);
|
|
89
|
-
if (!parsed) {
|
|
90
|
-
warn("memory inference: invalid JSON response from LLM; skipping memory.");
|
|
91
|
-
return undefined;
|
|
92
|
-
}
|
|
93
|
-
const title = typeof parsed.title === "string" ? parsed.title.trim() : "";
|
|
94
|
-
const description = typeof parsed.description === "string" ? parsed.description.trim() : "";
|
|
95
|
-
const content = typeof parsed.content === "string" ? parsed.content.trim() : "";
|
|
96
|
-
const tags = Array.isArray(parsed.tags)
|
|
97
|
-
? parsed.tags
|
|
98
|
-
.filter((t) => typeof t === "string")
|
|
99
|
-
.map((t) => t.trim())
|
|
100
|
-
.filter(Boolean)
|
|
101
|
-
.slice(0, 8)
|
|
102
|
-
: [];
|
|
103
|
-
const searchHints = Array.isArray(parsed.searchHints)
|
|
104
|
-
? parsed.searchHints
|
|
105
|
-
.filter((h) => typeof h === "string")
|
|
106
|
-
.map((h) => h.trim())
|
|
107
|
-
.filter(Boolean)
|
|
108
|
-
.slice(0, 6)
|
|
109
|
-
: [];
|
|
110
|
-
if (!title || !description || !content || tags.length === 0 || searchHints.length === 0) {
|
|
111
|
-
warn("memory inference: incomplete derived memory payload from LLM; skipping memory.");
|
|
112
|
-
return undefined;
|
|
113
|
-
}
|
|
114
|
-
return { title, description, tags, searchHints, content };
|
|
115
|
-
}
|
|
116
|
-
catch (err) {
|
|
117
|
-
if (err instanceof LlmCallError && err.code === "provider_html_error") {
|
|
118
|
-
if (telemetry)
|
|
119
|
-
telemetry.htmlErrorCount = (telemetry.htmlErrorCount ?? 0) + 1;
|
|
120
|
-
warn(`memory inference: provider returned HTML instead of JSON; skipping memory: ${toErrorMessage(err)}`);
|
|
121
|
-
return undefined;
|
|
122
|
-
}
|
|
123
|
-
warn(`memory inference failed: ${toErrorMessage(err)}`);
|
|
124
|
-
return undefined;
|
|
125
|
-
}
|
|
126
|
-
}, undefined, {
|
|
127
|
-
timeoutMs: llmConfig.timeoutMs,
|
|
128
|
-
onFallback,
|
|
129
|
-
});
|
|
130
|
-
}
|
|
4
|
+
export { compressMemoryToDerivedMemory, } from "./memory-infer-impl.js";
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
/**
|
|
5
|
+
* LLM-driven metadata enhancement for stash entries.
|
|
6
|
+
*
|
|
7
|
+
* Split out of `llm.ts` so the higher-level workflow (prompting the LLM to
|
|
8
|
+
* improve descriptions/tags/searchHints) lives separately from the low-level
|
|
9
|
+
* transport client in `client.ts`.
|
|
10
|
+
*/
|
|
11
|
+
import metadataEnhanceSystemPrompt from "../assets/prompts/metadata-enhance-system.md" with { type: "text" };
|
|
12
|
+
import { parseJsonResponse } from "./client.js";
|
|
13
|
+
import { callStructured } from "./structured-call.js";
|
|
14
|
+
const SYSTEM_PROMPT = metadataEnhanceSystemPrompt;
|
|
7
15
|
/**
|
|
8
16
|
* Use an LLM to enhance a stash entry's metadata: improve description,
|
|
9
17
|
* generate searchHints, and suggest tags.
|
|
@@ -33,34 +41,39 @@ Generate improved metadata for this ${entry.type}. Return JSON with these fields
|
|
|
33
41
|
- "tags": an array of 3-8 relevant keyword tags
|
|
34
42
|
|
|
35
43
|
Return ONLY the JSON object, no explanation.`;
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
// `parse` owns the raw response: the `!raw`/unparseable case ⇒ `{}`, plus the
|
|
45
|
+
// description/searchHints/tags shaping. `enhanceMetadata` never warns and
|
|
46
|
+
// never bumps telemetry, so `onError` (gated path only) just swallows to `{}`
|
|
47
|
+
// — identical to the surrounding control flow's pre-migration behaviour. The
|
|
48
|
+
// ungated path (akmConfig === undefined) propagates errors via callStructured.
|
|
49
|
+
return callStructured({
|
|
50
|
+
feature: "metadata_enhance",
|
|
51
|
+
akmConfig,
|
|
52
|
+
config,
|
|
53
|
+
messages: [
|
|
38
54
|
{ role: "system", content: SYSTEM_PROMPT },
|
|
39
55
|
{ role: "user", content: userPrompt },
|
|
40
|
-
],
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
result
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return runLlm();
|
|
64
|
-
}
|
|
65
|
-
return tryLlmFeature("metadata_enhance", akmConfig, runLlm, {}, { timeoutMs: config.timeoutMs });
|
|
56
|
+
],
|
|
57
|
+
request: { signal, timeoutMs: config.timeoutMs },
|
|
58
|
+
parse: (raw) => {
|
|
59
|
+
const parsed = raw ? parseJsonResponse(raw) : undefined;
|
|
60
|
+
if (!parsed)
|
|
61
|
+
return {};
|
|
62
|
+
const result = {};
|
|
63
|
+
if (typeof parsed.description === "string" && parsed.description) {
|
|
64
|
+
result.description = parsed.description;
|
|
65
|
+
}
|
|
66
|
+
if (Array.isArray(parsed.searchHints)) {
|
|
67
|
+
result.searchHints = parsed.searchHints
|
|
68
|
+
.filter((s) => typeof s === "string" && s.trim().length > 0)
|
|
69
|
+
.slice(0, 8);
|
|
70
|
+
}
|
|
71
|
+
if (Array.isArray(parsed.tags)) {
|
|
72
|
+
result.tags = parsed.tags.filter((s) => typeof s === "string" && s.trim().length > 0).slice(0, 10);
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
},
|
|
76
|
+
onError: () => ({}),
|
|
77
|
+
fallback: {},
|
|
78
|
+
});
|
|
66
79
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
import { chatCompletion, isContextSizeError, LlmCallError } from "./client.js";
|
|
5
|
+
import { tryLlmFeature } from "./feature-gate.js";
|
|
6
|
+
/**
|
|
7
|
+
* Classify a thrown LLM error into one of the three buckets. This is the single
|
|
8
|
+
* home for the `isContextSizeError -> html -> other` ladder that was previously
|
|
9
|
+
* inlined at every call site.
|
|
10
|
+
*/
|
|
11
|
+
export function classifyLlmError(err) {
|
|
12
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
13
|
+
if (isContextSizeError(message))
|
|
14
|
+
return "context_limit";
|
|
15
|
+
if (err instanceof LlmCallError && err.code === "provider_html_error")
|
|
16
|
+
return "html";
|
|
17
|
+
return "other";
|
|
18
|
+
}
|
|
19
|
+
export async function callStructured(opts) {
|
|
20
|
+
const { feature, akmConfig, config, messages, request, parse, onError, fallback, onFallback } = opts;
|
|
21
|
+
const chat = request?.chat ?? chatCompletion;
|
|
22
|
+
const chatOptions = {
|
|
23
|
+
temperature: request?.temperature,
|
|
24
|
+
timeoutMs: request?.timeoutMs,
|
|
25
|
+
signal: request?.signal,
|
|
26
|
+
responseSchema: request?.responseSchema,
|
|
27
|
+
onRetryAttempt: request?.onRetryAttempt,
|
|
28
|
+
};
|
|
29
|
+
// UNGATED: run the chat+parse directly. Errors propagate — no `onError`
|
|
30
|
+
// funnel — matching the pre-gate behaviour of direct callers.
|
|
31
|
+
if (akmConfig === undefined) {
|
|
32
|
+
const raw = await chat(config, messages, chatOptions);
|
|
33
|
+
return parse(raw);
|
|
34
|
+
}
|
|
35
|
+
// GATED: run through `tryLlmFeature`. A throw inside is classified ONCE and
|
|
36
|
+
// routed to `onError`; `tryLlmFeature` returns `fallback` on disablement/timeout.
|
|
37
|
+
return tryLlmFeature(feature, akmConfig, async () => {
|
|
38
|
+
try {
|
|
39
|
+
const raw = await chat(config, messages, chatOptions);
|
|
40
|
+
return parse(raw);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
return onError(classifyLlmError(err), err);
|
|
44
|
+
}
|
|
45
|
+
}, fallback, {
|
|
46
|
+
timeoutMs: request?.timeoutMs,
|
|
47
|
+
onFallback,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
+
|
|
6
|
+
const { main } = await import("./scripts/migrate-storage.js");
|
|
7
|
+
|
|
8
|
+
await main();
|
package/dist/output/context.js
CHANGED
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
* Initialized from `cli.ts` before `runMain`.
|
|
13
13
|
*/
|
|
14
14
|
import { UsageError } from "../core/errors.js";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
const OUTPUT_FORMATS = ["json", "yaml", "text", "jsonl", "md", "html"];
|
|
16
|
+
const DETAIL_LEVELS = ["brief", "normal", "full"];
|
|
17
|
+
const SHAPE_MODES = ["human", "agent", "summary"];
|
|
18
|
+
function parseOutputFormat(value) {
|
|
19
19
|
if (!value)
|
|
20
20
|
return undefined;
|
|
21
21
|
if (OUTPUT_FORMATS.includes(value))
|
|
@@ -29,7 +29,7 @@ export function parseDetailLevel(value) {
|
|
|
29
29
|
return value;
|
|
30
30
|
throw new UsageError(`Invalid value for --detail: ${value}. Expected one of: ${DETAIL_LEVELS.join("|")}`, "INVALID_DETAIL_VALUE");
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
function parseShapeMode(value) {
|
|
33
33
|
if (!value)
|
|
34
34
|
return undefined;
|
|
35
35
|
if (SHAPE_MODES.includes(value))
|