akm-cli 0.9.17-alpha.3 → 0.9.17-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +760 -0
- package/dist/akm +94 -196
- package/dist/cli/shared.js +6 -2
- package/dist/cli.js +22 -9
- package/dist/commands/agent/agent-dispatch.js +1 -1
- package/dist/commands/command/command-execution.js +24 -62
- package/dist/commands/feedback-cli.js +0 -1
- package/dist/commands/health/accept-rate.js +2 -2
- package/dist/commands/health/checks.js +30 -75
- package/dist/commands/health/config-skew.js +38 -0
- package/dist/commands/health/egress.js +54 -0
- package/dist/commands/health/html-report.js +0 -38
- package/dist/commands/health/improve-metrics.js +123 -562
- package/dist/commands/health/plugin-staleness.js +53 -3
- package/dist/commands/health/renderers.js +12 -4
- package/dist/commands/health/report-view-model.js +11 -106
- package/dist/commands/health/types-improve.js +4 -19
- package/dist/commands/health/windows.js +64 -73
- package/dist/commands/health.js +122 -143
- package/dist/commands/improve/consolidate/chunking.js +25 -100
- package/dist/commands/improve/consolidate/sanitize.js +54 -149
- package/dist/commands/improve/consolidate.js +538 -1075
- package/dist/commands/improve/content-hash.js +16 -24
- package/dist/commands/improve/distill/content-repair.js +18 -100
- package/dist/commands/improve/distill-guards.js +20 -81
- package/dist/commands/improve/distill-promotion-policy.js +23 -243
- package/dist/commands/improve/distill.js +608 -1075
- package/dist/commands/improve/eligibility.js +126 -400
- package/dist/commands/improve/execution.js +3 -5
- package/dist/commands/improve/extract.js +487 -1046
- package/dist/commands/improve/feedback-valence.js +0 -25
- package/dist/commands/improve/improve-cli.js +29 -166
- package/dist/commands/improve/improve-result-file.js +10 -66
- package/dist/commands/improve/improve-strategies.js +12 -7
- package/dist/commands/improve/improve-usage-report.js +18 -64
- package/dist/commands/improve/improve.js +443 -1063
- package/dist/commands/improve/ledger.js +114 -0
- package/dist/commands/improve/locks.js +2 -8
- package/dist/commands/improve/loop-stages.js +459 -1172
- package/dist/commands/improve/memory/derived-ref.js +12 -77
- package/dist/commands/improve/memory/memory-belief.js +14 -118
- package/dist/commands/improve/memory/memory-improve.js +4 -3
- package/dist/commands/improve/outcome-loop.js +28 -156
- package/dist/commands/improve/planner.js +5 -10
- package/dist/commands/improve/preparation.js +851 -2339
- package/dist/commands/improve/proactive-maintenance.js +34 -101
- package/dist/commands/improve/reflect-noise.js +104 -280
- package/dist/commands/improve/reflect.js +621 -1367
- package/dist/commands/improve/salience.js +46 -232
- package/dist/commands/improve/session-asset.js +19 -100
- package/dist/commands/improve/stage.js +323 -0
- package/dist/commands/lint/base-linter.js +19 -5
- package/dist/commands/proposal/drain.js +251 -644
- package/dist/commands/proposal/proposal-cli.js +3 -18
- package/dist/commands/proposal/proposal-types.js +20 -41
- package/dist/commands/proposal/proposal.js +1 -2
- package/dist/commands/proposal/propose.js +134 -160
- package/dist/commands/proposal/repository.js +502 -1487
- package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
- package/dist/commands/proposal/validators/proposal-validators.js +1 -1
- package/dist/commands/proposal/validators/proposals.js +13 -89
- package/dist/commands/read/curate.js +63 -413
- package/dist/commands/read/search-cli.js +16 -33
- package/dist/commands/read/search.js +17 -23
- package/dist/commands/read/show.js +2 -13
- package/dist/commands/sources/bundle-cli.js +25 -2
- package/dist/commands/sources/bundle-config-ops.js +4 -0
- package/dist/commands/sources/dangerous-env-audit.js +1 -2
- package/dist/commands/sources/info.js +2 -11
- package/dist/commands/sources/installed-stashes.js +197 -746
- package/dist/commands/sources/schema-repair.js +98 -129
- package/dist/commands/sources/source-add.js +62 -12
- package/dist/commands/sources/source-manage.js +9 -2
- package/dist/commands/sources/stash-cli.js +1 -1
- package/dist/commands/tasks/explain.js +10 -13
- package/dist/commands/tasks/tasks-cli.js +9 -8
- package/dist/commands/tasks/tasks.js +326 -930
- package/dist/commands/tasks/validate.js +42 -21
- package/dist/commands/workflow/plan.js +22 -29
- package/dist/commands/workflow-cli.js +4 -4
- package/dist/core/adapter/adapters/akm-adapter.js +0 -1
- package/dist/core/adapter/adapters/akm-lint.js +2 -3
- package/dist/core/adapter/adapters/akm-metadata.js +11 -12
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
- package/dist/core/adapter/execution-source.js +17 -29
- package/dist/core/asset/asset-placement.js +4 -13
- package/dist/core/asset/resolve-ref.js +1 -1
- package/dist/core/bundle-id.js +42 -5
- package/dist/core/bundle-rename.js +291 -0
- package/dist/core/config/config-io.js +1 -2
- package/dist/core/config/config-schema.js +1 -33
- package/dist/core/config/config-walker.js +1 -1
- package/dist/core/config/config.js +163 -68
- package/dist/core/config/legacy-source-shape-shim.js +38 -9
- package/dist/core/config/schema/embedding.js +20 -5
- package/dist/core/config/schema/engines.js +5 -0
- package/dist/core/config/schema/execution.js +1 -1
- package/dist/core/config/schema/experimental.js +1 -1
- package/dist/core/config/schema/improve-processes.js +21 -95
- package/dist/core/config/schema/improve.js +4 -42
- package/dist/core/config/schema/scheduler.js +12 -12
- package/dist/core/config/schema/search.js +6 -22
- package/dist/core/env-secret-ref.js +0 -1
- package/dist/core/errors.js +8 -9
- package/dist/core/file-lock.js +76 -173
- package/dist/core/logs-db.js +2 -2
- package/dist/core/paths.js +0 -27
- package/dist/core/redaction.js +109 -2
- package/dist/core/run-lock.js +2 -5
- package/dist/core/spawn-env.js +1 -1
- package/dist/core/state/migrations.js +108 -61
- package/dist/core/state-db-scope.js +2 -4
- package/dist/core/state-db.js +126 -692
- package/dist/core/type-presentation.js +1 -9
- package/dist/core/write-source.js +293 -1012
- package/dist/execution/input-contract.js +1 -1
- package/dist/execution/resolved-request.js +135 -689
- package/dist/execution/source.js +63 -257
- package/dist/execution/target-ref.js +1 -1
- package/dist/indexer/bundle-identity-guard.js +2 -2
- package/dist/indexer/db/graph-db.js +106 -46
- package/dist/indexer/ensure-index.js +44 -85
- package/dist/indexer/graph/graph-extraction.js +340 -562
- package/dist/indexer/graph/graph-related.js +130 -0
- package/dist/indexer/index-rebuild-lock.js +3 -11
- package/dist/indexer/index-writer-lock.js +8 -17
- package/dist/indexer/index-written-assets.js +139 -151
- package/dist/indexer/indexer.js +524 -846
- package/dist/indexer/materialize-embeddings.js +60 -397
- package/dist/indexer/passes/memory-inference.js +81 -90
- package/dist/indexer/passes/metadata.js +132 -200
- package/dist/indexer/read-preflight.js +0 -7
- package/dist/indexer/scan/doc-to-entry.js +1 -3
- package/dist/indexer/scan/drain-dir.js +1 -1
- package/dist/indexer/search/db-search.js +181 -590
- package/dist/indexer/search/fts-query.js +30 -41
- package/dist/indexer/search/ranking.js +28 -154
- package/dist/indexer/search/search-attribution.js +12 -32
- package/dist/indexer/search/search-fields.js +11 -15
- package/dist/indexer/search/search-hit-enrichers.js +54 -85
- package/dist/indexer/search/search-source.js +1 -4
- package/dist/indexer/usage/usage-events.js +2 -7
- package/dist/integrations/agent/engine-fallback.js +23 -40
- package/dist/integrations/agent/engine-resolution.js +93 -183
- package/dist/integrations/agent/execution.js +507 -0
- package/dist/integrations/agent/model-map.js +28 -156
- package/dist/integrations/agent/request-lowering.js +66 -141
- package/dist/integrations/agent/runner-dispatch.js +143 -321
- package/dist/integrations/agent/runner.js +54 -14
- package/dist/integrations/lockfile.js +53 -101
- package/dist/llm/embedders/deterministic.js +2 -3
- package/dist/llm/embedders/profile.js +71 -0
- package/dist/llm/embedders/remote.js +10 -15
- package/dist/llm/graph-extract.js +3 -12
- package/dist/llm/index-passes.js +3 -5
- package/dist/llm/memory-infer.js +1 -2
- package/dist/llm/metadata-enhance.js +1 -2
- package/dist/llm/structured-call.js +5 -24
- package/dist/output/generic-render.js +23 -11
- package/dist/output/html-render.js +13 -10
- package/dist/output/render-registry.js +3 -32
- package/dist/output/shapes/helpers.js +2 -34
- package/dist/output/shapes/passthrough.js +1 -9
- package/dist/{indexer/search/ranking-types.js → output/text/bundle-rename.js} +4 -1
- package/dist/output/text/command-format.js +60 -23
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +5 -14
- package/dist/output/text/proposal-format.js +1 -2
- package/dist/output/text/workflow-format.js +0 -32
- package/dist/output/text.js +2 -0
- package/dist/registry/factory.js +4 -19
- package/dist/registry/network.js +66 -220
- package/dist/registry/providers/index.js +0 -2
- package/dist/registry/providers/skills-sh.js +3 -14
- package/dist/registry/providers/static-index.js +24 -26
- package/dist/registry/resolve.js +55 -131
- package/dist/scripts/akm-migrate-node.js +43940 -93320
- package/dist/scripts/akm-migrate.js +43700 -93078
- package/dist/setup/registry-stash-loader.js +4 -13
- package/dist/setup/semantic-assets.js +3 -44
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/tasks.js +25 -15
- package/dist/sources/provider-factory.js +17 -18
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +7 -1
- package/dist/sources/providers/git-provider.js +0 -3
- package/dist/sources/providers/git-stash.js +0 -17
- package/dist/sources/providers/npm.js +2 -4
- package/dist/sources/providers/provider-utils.js +5 -10
- package/dist/sources/providers/website.js +0 -2
- package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
- package/dist/sources/website-url.js +2 -2
- package/dist/storage/database.js +9 -35
- package/dist/storage/repositories/improve-ledger-repository.js +168 -0
- package/dist/storage/repositories/index-connection.js +34 -70
- package/dist/storage/repositories/index-entries-repository.js +69 -111
- package/dist/storage/repositories/index-entry-mapper.js +1 -2
- package/dist/storage/repositories/index-entry-schema.js +83 -269
- package/dist/storage/repositories/index-fts-repository.js +86 -256
- package/dist/storage/repositories/index-llm-cache-repository.js +17 -0
- package/dist/storage/repositories/index-meta-repository.js +6 -4
- package/dist/storage/repositories/index-schema.js +192 -220
- package/dist/storage/repositories/index-utility-repository.js +8 -29
- package/dist/storage/repositories/index-vec-repository.js +133 -414
- package/dist/storage/repositories/outcome-repository.js +2 -1
- package/dist/storage/repositories/proposals-repository.js +35 -0
- package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
- package/dist/storage/repositories/task-history-repository.js +26 -4
- package/dist/storage/repositories/workflow-runs-repository.js +53 -244
- package/dist/storage/sqlite-migrations.js +136 -0
- package/dist/storage/sqlite-pragmas.js +11 -9
- package/dist/storage/sqlite-transaction.js +170 -0
- package/dist/storage/state-db-integrity.js +34 -27
- package/dist/tasks/activation-config.js +134 -62
- package/dist/tasks/backends/cron.js +129 -277
- package/dist/tasks/backends/exec-utils.js +2 -5
- package/dist/tasks/backends/launchd.js +125 -745
- package/dist/tasks/backends/schtasks.js +101 -620
- package/dist/tasks/prepare/prepare-support.js +5 -15
- package/dist/tasks/prepare/prepare.js +0 -2
- package/dist/tasks/resolve-akm-bin.js +20 -79
- package/dist/tasks/run/attempt-lifecycle.js +0 -1
- package/dist/tasks/scheduler-binding.js +18 -238
- package/dist/tasks/scheduler-invocation.js +52 -52
- package/dist/tasks/scheduler-lock.js +53 -0
- package/dist/tasks/scheduler-sync.js +361 -751
- package/dist/tasks/source/parse-task-source.js +160 -10
- package/dist/tasks/source/task-source-v3-frozen.js +3 -4
- package/dist/tasks/source/task-to-v4.js +2 -2
- package/dist/workflows/authoring/authoring.js +3 -12
- package/dist/workflows/compile.js +211 -0
- package/dist/workflows/concurrency-policy.js +13 -74
- package/dist/workflows/exec/child-invocation.js +3 -17
- package/dist/workflows/exec/child-workflow.js +32 -141
- package/dist/workflows/exec/dispatch-redaction.js +13 -53
- package/dist/workflows/exec/environment.js +98 -0
- package/dist/workflows/exec/exec-unit.js +33 -140
- package/dist/workflows/exec/frozen-judge.js +7 -59
- package/dist/workflows/exec/native-executor.js +82 -341
- package/dist/workflows/exec/param-secrets.js +29 -47
- package/dist/workflows/exec/run-workflow.js +154 -387
- package/dist/workflows/exec/scheduler.js +9 -36
- package/dist/workflows/exec/step-work.js +127 -430
- package/dist/workflows/exec/unit-dispatch.js +11 -63
- package/dist/workflows/exec/unit-writer.js +8 -52
- package/dist/workflows/exec/worktree.js +39 -273
- package/dist/workflows/freeze/child-output-references.js +4 -15
- package/dist/workflows/freeze/environment.js +99 -92
- package/dist/workflows/freeze/freeze.js +172 -0
- package/dist/workflows/freeze/step-values.js +19 -21
- package/dist/workflows/freeze/targets/child-workflow.js +23 -92
- package/dist/workflows/freeze/targets/command.js +10 -33
- package/dist/workflows/freeze/targets/script.js +5 -12
- package/dist/workflows/freeze/targets/shell.js +3 -6
- package/dist/workflows/freeze/targets/task.js +25 -80
- package/dist/workflows/freeze/task-bindings.js +20 -67
- package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
- package/dist/workflows/ir/params.js +6 -51
- package/dist/workflows/ir/plan-hash.js +2 -34
- package/dist/workflows/parser.js +140 -43
- package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
- package/dist/workflows/renderer.js +36 -69
- package/dist/workflows/resource-limits.js +12 -120
- package/dist/workflows/runtime/agent-identity.js +8 -40
- package/dist/workflows/runtime/run-outputs.js +3 -6
- package/dist/workflows/runtime/run-plan.js +316 -0
- package/dist/workflows/runtime/runs.js +48 -200
- package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
- package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/integration/bundling-akm.md +49 -42
- package/docs/migration/README.md +1 -0
- package/docs/migration/release-notes/0.9.17.md +41 -0
- package/docs/migration/v0.9.1-to-v0.9.2.md +19 -7
- package/docs/reference/cli.md +182 -125
- package/docs/reference/configuration.md +49 -56
- package/docs/reference/data-and-telemetry.md +19 -20
- package/docs/reference/tasks.md +86 -38
- package/docs/reference/workflow-schema.md +14 -18
- package/docs/reference/workflows.md +6 -9
- package/package.json +1 -1
- package/schemas/akm-config.json +87 -406
- package/dist/commands/health/advisories.js +0 -150
- package/dist/commands/health/metrics.js +0 -329
- package/dist/commands/health/surfaces.js +0 -102
- package/dist/commands/improve/anti-collapse.js +0 -83
- package/dist/commands/improve/collapse-detector.js +0 -432
- package/dist/commands/improve/consolidate/eligibility.js +0 -48
- package/dist/commands/improve/consolidate/merge.js +0 -146
- package/dist/commands/improve/distill/promote-memory.js +0 -329
- package/dist/commands/improve/distill/quality-gate.js +0 -500
- package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
- package/dist/commands/improve/proposal-envelope.js +0 -31
- package/dist/commands/improve/run-context.js +0 -123
- package/dist/commands/improve/shared.js +0 -21
- package/dist/commands/improve/source-identity.js +0 -28
- package/dist/commands/improve/triage.js +0 -96
- package/dist/commands/proposal/drain-policies.js +0 -151
- package/dist/commands/sources/update-transaction.js +0 -220
- package/dist/core/action-contributors.js +0 -28
- package/dist/core/config/config-version-shim.js +0 -101
- package/dist/core/config/retired-experimental-keys-shim.js +0 -62
- package/dist/core/fs-txn.js +0 -405
- package/dist/core/lexical-score.js +0 -25
- package/dist/core/maintenance-barrier.js +0 -167
- package/dist/execution/executable-identity.js +0 -105
- package/dist/execution/guarded-source.js +0 -441
- package/dist/indexer/graph/graph-boost.js +0 -427
- package/dist/indexer/graph/graph-dedup.js +0 -95
- package/dist/indexer/search/name-match.js +0 -35
- package/dist/indexer/search/ranking-contributors.js +0 -515
- package/dist/indexer/walk/project-context.js +0 -192
- package/dist/integrations/agent/execution-cascade.js +0 -566
- package/dist/integrations/agent/execution-definitions.js +0 -202
- package/dist/integrations/agent/execution-lowering.js +0 -841
- package/dist/integrations/agent/execution-preparation.js +0 -98
- package/dist/integrations/agent/inline-execution.js +0 -74
- package/dist/registry/create-provider-registry.js +0 -29
- package/dist/registry/pinned-request-helper.js +0 -247
- package/dist/registry/pinned-transport.js +0 -717
- package/dist/sources/providers/index.js +0 -14
- package/dist/storage/engines/sqlite-migrations.js +0 -271
- package/dist/storage/repositories/canaries-repository.js +0 -107
- package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
- package/dist/storage/repositories/registry-cache.js +0 -113
- package/dist/tasks/scheduler-sync-preview.js +0 -52
- package/dist/workflows/freeze/resolve-steps.js +0 -86
- package/dist/workflows/freeze/source-freeze.js +0 -64
- package/dist/workflows/ir/compile.js +0 -321
- package/dist/workflows/ir/environment-v4.js +0 -330
- package/dist/workflows/ir/freeze-v4.js +0 -153
- package/dist/workflows/ir/schema-v4.js +0 -745
- package/dist/workflows/ir/schema.js +0 -354
- package/dist/workflows/program/schema.js +0 -78
- package/dist/workflows/runtime/checkin.js +0 -57
- package/dist/workflows/runtime/plan-classifier.js +0 -196
- package/dist/workflows/runtime/unit-checkin.js +0 -45
- package/dist/workflows/runtime/unit-phases.js +0 -20
- package/dist/workflows/schema.js +0 -4
- package/dist/workflows/source-ir/compile.js +0 -200
- package/dist/workflows/source-ir/program.js +0 -50
- package/dist/workflows/source-ir/result.js +0 -26
- package/dist/workflows/source-ir/schema.js +0 -786
- package/dist/workflows/source-ir/triggers.js +0 -79
- package/dist/workflows/source-ir/uses.js +0 -40
- package/dist/workflows/validator.js +0 -60
|
@@ -0,0 +1,323 @@
|
|
|
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 { getImproveProcessConfig } from "../../core/config/config.js";
|
|
5
|
+
import { ConfigError } from "../../core/errors.js";
|
|
6
|
+
import { parseEmbeddedJsonResponse } from "../../core/parse.js";
|
|
7
|
+
import { warn } from "../../core/warn.js";
|
|
8
|
+
import { LlmCallError } from "../../llm/client.js";
|
|
9
|
+
import { callStructured } from "../../llm/structured-call.js";
|
|
10
|
+
import { withLlmStage } from "../../llm/usage-telemetry.js";
|
|
11
|
+
import { isProceduralRejection } from "../proposal/proposal-types.js";
|
|
12
|
+
import { createProposal, listProposalsReadOnly, proposalContentHash, recordGateDecision, } from "../proposal/repository.js";
|
|
13
|
+
import { resolveImproveLlmExecution } from "./execution.js";
|
|
14
|
+
/** Normalize an unknown thrown value to a message. */
|
|
15
|
+
export function errMessage(e) {
|
|
16
|
+
return e instanceof Error ? e.message : String(e);
|
|
17
|
+
}
|
|
18
|
+
/** The lowering notices a stage's dispatches emitted, each once. */
|
|
19
|
+
export function noticeSet(forward) {
|
|
20
|
+
const byKey = new Map();
|
|
21
|
+
const add = (notices) => {
|
|
22
|
+
for (const notice of notices)
|
|
23
|
+
byKey.set(JSON.stringify(notice), notice);
|
|
24
|
+
forward?.(notices);
|
|
25
|
+
};
|
|
26
|
+
const list = () => Object.freeze([...byKey.values()]);
|
|
27
|
+
return { add, list, fields: () => (byKey.size > 0 ? { notices: list() } : {}) };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A stage's LLM runner: the one the improve plan froze for it (an own
|
|
31
|
+
* `llmRunner` key, `null` meaning "none"), else the process engine cascade.
|
|
32
|
+
*/
|
|
33
|
+
export function stageRunner(frozen, config, profile, processName, onNotices) {
|
|
34
|
+
if (Object.hasOwn(frozen, "llmRunner"))
|
|
35
|
+
return frozen.llmRunner ?? undefined;
|
|
36
|
+
const resolved = resolveImproveLlmExecution({
|
|
37
|
+
config,
|
|
38
|
+
profile,
|
|
39
|
+
process: getImproveProcessConfig(processName, profile),
|
|
40
|
+
processName,
|
|
41
|
+
});
|
|
42
|
+
if (resolved)
|
|
43
|
+
onNotices?.(resolved.notices);
|
|
44
|
+
return resolved?.runner;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* One model call. Provider trouble (transport error, timeout, a disabled
|
|
48
|
+
* feature) comes back as `{ ok: false }`; only a configuration failure throws.
|
|
49
|
+
*/
|
|
50
|
+
export async function callStage(call) {
|
|
51
|
+
const messages = [
|
|
52
|
+
...(call.system ? [{ role: "system", content: call.system }] : []),
|
|
53
|
+
...(call.history ?? []),
|
|
54
|
+
{ role: "user", content: call.prompt },
|
|
55
|
+
];
|
|
56
|
+
let failure;
|
|
57
|
+
try {
|
|
58
|
+
const raw = await callStructured({
|
|
59
|
+
feature: call.feature,
|
|
60
|
+
...(call.gate
|
|
61
|
+
? { akmConfig: call.gate.config, ...(call.gate.enabled !== undefined ? { enabled: call.gate.enabled } : {}) }
|
|
62
|
+
: {}),
|
|
63
|
+
runner: call.runner,
|
|
64
|
+
messages,
|
|
65
|
+
...(call.request ? { request: call.request } : {}),
|
|
66
|
+
...(call.onNotices ? { onNotices: call.onNotices } : {}),
|
|
67
|
+
parse: (r) => r ?? "",
|
|
68
|
+
onError: (_cls, err) => {
|
|
69
|
+
failure = { ok: false, reason: "error", error: errMessage(err) };
|
|
70
|
+
return undefined;
|
|
71
|
+
},
|
|
72
|
+
fallback: undefined,
|
|
73
|
+
onFallback: (event) => {
|
|
74
|
+
failure ??= { ok: false, reason: event.reason, ...(event.error ? { error: event.error.message } : {}) };
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
return raw === undefined ? (failure ?? { ok: false, reason: "error" }) : { ok: true, raw };
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
if (err instanceof ConfigError)
|
|
81
|
+
throw err;
|
|
82
|
+
const timedOut = err instanceof LlmCallError && err.code === "timeout";
|
|
83
|
+
return { ok: false, reason: timedOut ? "timeout" : "error", error: errMessage(err) };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Attribute a stage's LLM calls to its process and planned engine (the usage report). */
|
|
87
|
+
const STAGE_LABELS = {
|
|
88
|
+
reflect: "reflect",
|
|
89
|
+
distill: "distill",
|
|
90
|
+
consolidate: "consolidate",
|
|
91
|
+
extract: "session-extraction",
|
|
92
|
+
memoryInference: "memory-inference",
|
|
93
|
+
graphExtraction: "graph-extraction",
|
|
94
|
+
validation: "validation",
|
|
95
|
+
};
|
|
96
|
+
export function attributeStage(plan, process, fn) {
|
|
97
|
+
return withLlmStage(STAGE_LABELS[process], fn, { engine: plan?.processes[process].runner?.engine, process });
|
|
98
|
+
}
|
|
99
|
+
/** How many prior rejected proposals are shown to the model as "don't repeat this". */
|
|
100
|
+
export const MAX_REJECTED_PROPOSALS = 3;
|
|
101
|
+
/**
|
|
102
|
+
* Reflexion context: the newest reviewer rejections for `ref`. Procedural
|
|
103
|
+
* refusals (expiry, stale target, missing asset) are not judgements on the
|
|
104
|
+
* content and are left out. Reads never create state.db.
|
|
105
|
+
*/
|
|
106
|
+
export function rejectedProposalContext(stash, ref, ctx) {
|
|
107
|
+
if (!ref)
|
|
108
|
+
return [];
|
|
109
|
+
return listProposalsReadOnly(stash, { ref, status: "rejected", includeArchive: true }, ctx)
|
|
110
|
+
.filter((p) => !isProceduralRejection(p))
|
|
111
|
+
.sort((a, b) => new Date(b.updatedAt ?? 0).getTime() - new Date(a.updatedAt ?? 0).getTime())
|
|
112
|
+
.slice(0, MAX_REJECTED_PROPOSALS)
|
|
113
|
+
.map((p) => ({
|
|
114
|
+
ref: p.ref,
|
|
115
|
+
reason: p.review?.reason ?? "no reason given",
|
|
116
|
+
// `payload.content` is populated on every row, including legacy ones.
|
|
117
|
+
contentPreview: p.payload.content.slice(0, 500),
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
// ── Mint ─────────────────────────────────────────────────────────────────────
|
|
121
|
+
/**
|
|
122
|
+
* Create a stage's proposal. `judged` stamps a `staged` gate decision with the
|
|
123
|
+
* judged content's hash (the triage drain accepts it while the content still
|
|
124
|
+
* matches); `review` leaves it `deferred` for a human (`review_needed` in the
|
|
125
|
+
* improve ledger).
|
|
126
|
+
*/
|
|
127
|
+
export function mintProposal(stash, proposalsCtx, input, verdict = {}) {
|
|
128
|
+
const proposal = createProposal(stash, input, proposalsCtx);
|
|
129
|
+
if (verdict.review) {
|
|
130
|
+
return recordGateDecision(stash, proposal.id, { outcome: "deferred", ...verdict.review }, proposalsCtx) ?? proposal;
|
|
131
|
+
}
|
|
132
|
+
return verdict.judged ? stageJudgedProposal(stash, proposal, proposalsCtx) : proposal;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Stamp a proposal the quality judge passed. Best-effort: a failed stamp only
|
|
136
|
+
* means the triage drain judges it again.
|
|
137
|
+
*/
|
|
138
|
+
export function stageJudgedProposal(stash, proposal, proposalsCtx) {
|
|
139
|
+
try {
|
|
140
|
+
return (recordGateDecision(stash, proposal.id, {
|
|
141
|
+
outcome: "staged",
|
|
142
|
+
reason: "quality-judge",
|
|
143
|
+
gate: "quality-gate",
|
|
144
|
+
contentHash: proposalContentHash(proposal),
|
|
145
|
+
}, proposalsCtx) ?? proposal);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
warn(`[akm] failed to record the quality-judge pass for ${proposal.id}: ${errMessage(error)}`);
|
|
149
|
+
return proposal;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/** Lesson judge prompt; similar existing lessons let it mark near-duplicates down. */
|
|
153
|
+
export function buildJudgePrompt(lessonContent, sourceContent, similarLessons) {
|
|
154
|
+
const lines = [
|
|
155
|
+
"You are evaluating a proposed lesson asset for an akm knowledge base.",
|
|
156
|
+
"",
|
|
157
|
+
"Score this lesson on each criterion from 1 (poor) to 5 (excellent):",
|
|
158
|
+
"1. NOVELTY: Does the lesson add information not already present in the source asset?",
|
|
159
|
+
"2. NON-REDUNDANCY: Is this lesson meaningfully different from what the source already says?",
|
|
160
|
+
"",
|
|
161
|
+
"Source asset content:",
|
|
162
|
+
"```",
|
|
163
|
+
sourceContent.slice(0, 2000),
|
|
164
|
+
"```",
|
|
165
|
+
];
|
|
166
|
+
if (similarLessons && similarLessons.length > 0) {
|
|
167
|
+
lines.push("", "Existing similar lessons (top-3 by similarity). Rate lower if the proposed lesson is substantially similar to any of these:");
|
|
168
|
+
for (const sl of similarLessons)
|
|
169
|
+
lines.push(`\nExisting lesson ref: ${sl.ref}`, "```", sl.content.slice(0, 500), "```");
|
|
170
|
+
}
|
|
171
|
+
lines.push("", "Proposed lesson content:", "```", lessonContent.slice(0, 1000), "```", "", 'Return ONLY valid JSON, no prose: {"scores": {"novelty": <1-5 integer>, "nonRedundancy": <1-5 integer>}, "reason": "<one sentence>"}');
|
|
172
|
+
return lines.join("\n");
|
|
173
|
+
}
|
|
174
|
+
function boundedDocument(content, maxChars = 6000) {
|
|
175
|
+
if (content.length <= maxChars)
|
|
176
|
+
return content;
|
|
177
|
+
const half = Math.floor((maxChars - 80) / 2);
|
|
178
|
+
return `${content.slice(0, half)}\n\n[... middle omitted for bounded judge context ...]\n\n${content.slice(-half)}`;
|
|
179
|
+
}
|
|
180
|
+
function buildChangedRegion(sourceContent, candidateContent) {
|
|
181
|
+
const source = sourceContent.split("\n");
|
|
182
|
+
const candidate = candidateContent.split("\n");
|
|
183
|
+
let prefix = 0;
|
|
184
|
+
while (prefix < source.length && prefix < candidate.length && source[prefix] === candidate[prefix])
|
|
185
|
+
prefix++;
|
|
186
|
+
let suffix = 0;
|
|
187
|
+
while (suffix < source.length - prefix &&
|
|
188
|
+
suffix < candidate.length - prefix &&
|
|
189
|
+
source[source.length - 1 - suffix] === candidate[candidate.length - 1 - suffix]) {
|
|
190
|
+
suffix++;
|
|
191
|
+
}
|
|
192
|
+
const removed = source.slice(prefix, source.length - suffix).join("\n");
|
|
193
|
+
const added = candidate.slice(prefix, candidate.length - suffix).join("\n");
|
|
194
|
+
return boundedDocument(`Removed or replaced:\n${removed || "(none)"}\n\nAdded or replacement:\n${added || "(none)"}`);
|
|
195
|
+
}
|
|
196
|
+
/** Judge prompt for an in-place revision (overlap with the source is expected). */
|
|
197
|
+
export function buildReflectJudgePrompt(candidateContent, sourceContent, feedback) {
|
|
198
|
+
return [
|
|
199
|
+
"You are evaluating a proposed revision to an existing akm asset.",
|
|
200
|
+
"",
|
|
201
|
+
"Score this revision on each criterion from 1 (poor) to 5 (excellent):",
|
|
202
|
+
"1. FEEDBACK ALIGNMENT: Does the revision address the supplied feedback or improve retrieval and clarity?",
|
|
203
|
+
"2. PRESERVATION: Does it retain the source's concrete facts, code, commands, examples, and structure without truncation?",
|
|
204
|
+
"3. QUALITY: Is the revision coherent, actionable, complete, and free of unsupported claims?",
|
|
205
|
+
"",
|
|
206
|
+
"Overlap with the source is expected and must not lower the score by itself; this is an in-place revision, not a new lesson.",
|
|
207
|
+
"",
|
|
208
|
+
"Feedback:",
|
|
209
|
+
"```",
|
|
210
|
+
(feedback.length > 0 ? feedback.join("\n") : "No explicit feedback supplied.").slice(0, 1000),
|
|
211
|
+
"```",
|
|
212
|
+
"",
|
|
213
|
+
"Source asset content:",
|
|
214
|
+
"```",
|
|
215
|
+
boundedDocument(sourceContent),
|
|
216
|
+
"```",
|
|
217
|
+
"",
|
|
218
|
+
"Proposed revision:",
|
|
219
|
+
"```",
|
|
220
|
+
boundedDocument(candidateContent),
|
|
221
|
+
"```",
|
|
222
|
+
"",
|
|
223
|
+
"Changed region:",
|
|
224
|
+
"```",
|
|
225
|
+
buildChangedRegion(sourceContent, candidateContent),
|
|
226
|
+
"```",
|
|
227
|
+
"",
|
|
228
|
+
'Return ONLY valid JSON, no prose: {"scores": {"feedbackAlignment": <1-5 integer>, "preservation": <1-5 integer>, "quality": <1-5 integer>}, "reason": "<one sentence>"}',
|
|
229
|
+
].join("\n");
|
|
230
|
+
}
|
|
231
|
+
const LESSON_JUDGE_CRITERIA = ["novelty", "nonRedundancy"];
|
|
232
|
+
const REFLECT_JUDGE_CRITERIA = ["feedbackAlignment", "preservation", "quality"];
|
|
233
|
+
/**
|
|
234
|
+
* Read a judge response: the per-criterion shape (averaged here) or the older
|
|
235
|
+
* `{"score"}` shape. Only the expected criteria are read; any missing or
|
|
236
|
+
* out-of-range (1..5) value is a parse failure, extra keys are ignored.
|
|
237
|
+
*/
|
|
238
|
+
function parseJudgeResponse(raw, keys) {
|
|
239
|
+
const parsed = parseEmbeddedJsonResponse(raw);
|
|
240
|
+
if (!parsed || typeof parsed.reason !== "string")
|
|
241
|
+
return undefined;
|
|
242
|
+
const reason = parsed.reason;
|
|
243
|
+
const inRange = (value) => typeof value === "number" && Number.isFinite(value) && value >= 1 && value <= 5;
|
|
244
|
+
if (parsed.scores !== undefined) {
|
|
245
|
+
if (typeof parsed.scores !== "object" || parsed.scores === null || Array.isArray(parsed.scores))
|
|
246
|
+
return undefined;
|
|
247
|
+
const scores = parsed.scores;
|
|
248
|
+
const criteria = {};
|
|
249
|
+
for (const key of keys) {
|
|
250
|
+
const value = scores[key];
|
|
251
|
+
if (!inRange(value))
|
|
252
|
+
return undefined;
|
|
253
|
+
criteria[key] = value;
|
|
254
|
+
}
|
|
255
|
+
return { score: Object.values(criteria).reduce((a, b) => a + b, 0) / keys.length, reason, criteria };
|
|
256
|
+
}
|
|
257
|
+
return inRange(parsed.score) ? { score: parsed.score, reason } : undefined;
|
|
258
|
+
}
|
|
259
|
+
function judgeResponseSchema(keys) {
|
|
260
|
+
return {
|
|
261
|
+
type: "object",
|
|
262
|
+
required: ["scores", "reason"],
|
|
263
|
+
additionalProperties: false,
|
|
264
|
+
properties: {
|
|
265
|
+
scores: {
|
|
266
|
+
type: "object",
|
|
267
|
+
required: [...keys],
|
|
268
|
+
additionalProperties: false,
|
|
269
|
+
properties: Object.fromEntries(keys.map((key) => [key, { type: "integer", minimum: 1, maximum: 5 }])),
|
|
270
|
+
},
|
|
271
|
+
reason: { type: "string" },
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* The quality judge. Fails closed: no runner, an unparseable verdict or a
|
|
277
|
+
* provider failure never passes content. Bands: >= 3.5 pass, 2.5-3.5 review,
|
|
278
|
+
* < 2.5 reject. Temperature is pinned to 0 so verdicts do not flip.
|
|
279
|
+
*/
|
|
280
|
+
async function runQualityJudge(feature, config, prompt, keys, chat, options) {
|
|
281
|
+
const resolved = !options.runnerSelectionFrozen && !options.llmRunner
|
|
282
|
+
? resolveImproveLlmExecution({ config, processName: `${feature}-judge` })
|
|
283
|
+
: null;
|
|
284
|
+
if (resolved)
|
|
285
|
+
options.onNotices?.(resolved.notices);
|
|
286
|
+
const runner = options.llmRunner ?? resolved?.runner;
|
|
287
|
+
if (!runner)
|
|
288
|
+
return { pass: false, score: -1, reason: "no LLM configured — cannot judge, failing closed" };
|
|
289
|
+
const outcome = await callStage({
|
|
290
|
+
feature,
|
|
291
|
+
runner,
|
|
292
|
+
system: "Return only valid JSON. No prose.",
|
|
293
|
+
prompt,
|
|
294
|
+
request: {
|
|
295
|
+
enableThinking: false,
|
|
296
|
+
temperature: 0,
|
|
297
|
+
responseSchema: judgeResponseSchema(keys),
|
|
298
|
+
...(Object.hasOwn(options, "timeoutMs") ? { timeoutMs: options.timeoutMs } : {}),
|
|
299
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
300
|
+
...(chat ? { chat } : {}),
|
|
301
|
+
},
|
|
302
|
+
...(options.onNotices ? { onNotices: options.onNotices } : {}),
|
|
303
|
+
});
|
|
304
|
+
if (!outcome.ok) {
|
|
305
|
+
return { pass: false, score: -1, reason: "judge timeout/error — routed to review", reviewNeeded: true };
|
|
306
|
+
}
|
|
307
|
+
const parsed = parseJudgeResponse(outcome.raw, keys);
|
|
308
|
+
if (!parsed)
|
|
309
|
+
return { pass: false, score: -1, reason: "judge parse failed — routed to review", reviewNeeded: true };
|
|
310
|
+
const { score, reason, criteria } = parsed;
|
|
311
|
+
const verdict = score >= 3.5 ? { pass: true } : score >= 2.5 ? { pass: false, reviewNeeded: true } : { pass: false };
|
|
312
|
+
return { ...verdict, score, reason, ...(criteria ? { criteria } : {}) };
|
|
313
|
+
}
|
|
314
|
+
/** Judge a proposed lesson (or knowledge promotion) against its source. */
|
|
315
|
+
export function runLessonQualityJudge(config, lessonContent, sourceContent, chat, options = {}) {
|
|
316
|
+
const prompt = buildJudgePrompt(lessonContent, sourceContent, options.similarLessons);
|
|
317
|
+
return runQualityJudge("lesson_quality_gate", config, prompt, LESSON_JUDGE_CRITERIA, chat, options);
|
|
318
|
+
}
|
|
319
|
+
/** Judge an in-place reflect revision without new-lesson novelty criteria. */
|
|
320
|
+
export function runReflectQualityJudge(config, candidateContent, sourceContent, feedback, chat, options = {}) {
|
|
321
|
+
const prompt = buildReflectJudgePrompt(candidateContent, sourceContent, feedback);
|
|
322
|
+
return runQualityJudge("proposal_quality_gate", config, prompt, REFLECT_JUDGE_CRITERIA, chat, options);
|
|
323
|
+
}
|
|
@@ -42,6 +42,7 @@ import { isArchivedRelPath } from "../../core/asset/memory-archive.js";
|
|
|
42
42
|
import { conceptIdFromTypeName, typeNameFromConceptId } from "../../core/asset/resolve-ref.js";
|
|
43
43
|
import { localDateStamp } from "../../core/common.js";
|
|
44
44
|
import { containsRedactedContent, REDACTED_CONTENT_MARKER } from "../../core/content-safety.js";
|
|
45
|
+
import { DERIVED_SUFFIX } from "../../core/recognition-util.js";
|
|
45
46
|
import { findFenceRegions } from "./markdown-insertion.js";
|
|
46
47
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
47
48
|
/** Fold physically wrapped prose the same way a YAML plain scalar does. */
|
|
@@ -216,10 +217,23 @@ export function refExistsInAnyStash(relPath, refType, refName, stashRoots) {
|
|
|
216
217
|
// record while leaving the live stash untouched.
|
|
217
218
|
return memoryArchiveHasRef(refType, refName, stashRoots);
|
|
218
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* The stash-relative files that satisfy a ref, in preference order: its own
|
|
222
|
+
* placement spellings, then, for a memory, the `<name>.derived.md` child (#882),
|
|
223
|
+
* so an edge to a parent whose plain `.md` is gone still reaches the child it was
|
|
224
|
+
* distilled into. This is lint's reachability rule only; the child owns
|
|
225
|
+
* `memories/<name>.derived`, never `memories/<name>`.
|
|
226
|
+
*/
|
|
227
|
+
function refPathCandidates(refType, typeDir, refName) {
|
|
228
|
+
const candidates = assetPathCandidatesForName(refType, typeDir, refName);
|
|
229
|
+
if (refType !== "memory" || refName.endsWith(DERIVED_SUFFIX))
|
|
230
|
+
return candidates;
|
|
231
|
+
return [...candidates, assetPathForName(refType, typeDir, `${refName}${DERIVED_SUFFIX}`)];
|
|
232
|
+
}
|
|
219
233
|
/**
|
|
220
234
|
* True when `(refType, refName)` names a memory that prune archived in any
|
|
221
235
|
* root. Mirrors `resolveRefPathInStash`'s candidate set so a ref that resolved
|
|
222
|
-
* through the `.derived.md`
|
|
236
|
+
* through the `.derived.md` child (#882) still resolves once archived.
|
|
223
237
|
*/
|
|
224
238
|
function memoryArchiveHasRef(refType, refName, stashRoots) {
|
|
225
239
|
if (refType !== "memory")
|
|
@@ -227,7 +241,7 @@ function memoryArchiveHasRef(refType, refName, stashRoots) {
|
|
|
227
241
|
const typeDir = stashDirFor(refType);
|
|
228
242
|
if (typeDir === undefined)
|
|
229
243
|
return false;
|
|
230
|
-
const candidates =
|
|
244
|
+
const candidates = refPathCandidates(refType, typeDir, refName);
|
|
231
245
|
for (const root of stashRoots) {
|
|
232
246
|
for (const candidate of candidates) {
|
|
233
247
|
if (isArchivedRelPath(candidate, root))
|
|
@@ -241,8 +255,8 @@ function memoryArchiveHasRef(refType, refName, stashRoots) {
|
|
|
241
255
|
* the same reachability rules (in the same order) as
|
|
242
256
|
* {@link refExistsInAnyStash}, which delegates here. Returns the absolute path
|
|
243
257
|
* of the file that makes the ref "exist" — for a multi-file skill directory
|
|
244
|
-
* that is its `SKILL.md` primary, for a `memory` ref its `.derived.md`
|
|
245
|
-
* when the plain `.md` is absent (#882, see
|
|
258
|
+
* that is its `SKILL.md` primary, for a `memory` ref its `.derived.md` child
|
|
259
|
+
* when the plain `.md` is absent (#882, see {@link refPathCandidates}) —
|
|
246
260
|
* or `null` when the ref does not resolve in this root.
|
|
247
261
|
*
|
|
248
262
|
* Extracted for SPEC-5 (`--supersedes` demotion): write commands need the
|
|
@@ -253,7 +267,7 @@ function memoryArchiveHasRef(refType, refName, stashRoots) {
|
|
|
253
267
|
*/
|
|
254
268
|
export function resolveRefPathInStash(relPath, refType, refName, root) {
|
|
255
269
|
const typeDir = stashDirFor(refType);
|
|
256
|
-
const candidates = typeDir === undefined ? [relPath] :
|
|
270
|
+
const candidates = typeDir === undefined ? [relPath] : refPathCandidates(refType, typeDir, refName);
|
|
257
271
|
for (const candidate of candidates) {
|
|
258
272
|
const absPath = path.join(root, candidate);
|
|
259
273
|
if (fs.existsSync(absPath))
|