akm-cli 0.9.1 → 0.9.2-alpha.2
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 +103 -28
- package/README.md +3 -1
- package/SECURITY.md +1 -1
- package/STABILITY.md +1 -1
- package/dist/akm +2 -2
- package/dist/akm-migrate +2 -2
- package/dist/assets/hints/cli-hints-full.md +14 -9
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -1
- package/dist/assets/improve-strategies/reflect-distill.json +1 -1
- package/dist/assets/models.json +35 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +3 -4
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +1 -3
- package/dist/assets/tasks/core/extract.yml +6 -5
- package/dist/assets/tasks/core/improve.yml +6 -5
- package/dist/assets/tasks/core/index-refresh.yml +6 -5
- package/dist/assets/tasks/core/sync.yml +6 -5
- package/dist/assets/tasks/core/version-check.yml +6 -5
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +6 -5
- package/dist/cli/confirm.js +2 -2
- package/dist/cli/parse-args.js +3 -24
- package/dist/cli/retired-commands.js +1 -1
- package/dist/cli/shared.js +2 -2
- package/dist/cli.js +11 -9
- package/dist/commands/agent/agent-dispatch.js +55 -89
- package/dist/commands/agent/contribute-cli.js +12 -45
- package/dist/commands/command/builtin-action.js +32 -0
- package/dist/commands/command/command-cli.js +99 -0
- package/dist/commands/command/command-execution.js +308 -0
- package/dist/commands/command/execution-source-loader.js +176 -0
- package/dist/commands/command/portable-template.js +60 -0
- package/dist/commands/config-cli.js +10 -4
- package/dist/commands/env/env.js +4 -2
- package/dist/commands/feedback-cli.js +1 -1
- package/dist/commands/health/checks.js +241 -29
- package/dist/commands/health/html-report.js +0 -14
- package/dist/commands/health/report-view-model.js +0 -1
- package/dist/commands/health/surfaces.js +6 -7
- package/dist/commands/health/types.js +0 -2
- package/dist/commands/health.js +63 -18
- package/dist/commands/improve/collapse-detector.js +5 -6
- package/dist/commands/improve/consolidate.js +251 -214
- package/dist/commands/improve/distill/promote-memory.js +71 -34
- package/dist/commands/improve/distill/quality-gate.js +17 -5
- package/dist/commands/improve/distill.js +232 -155
- package/dist/commands/improve/eligibility.js +112 -79
- package/dist/commands/improve/execution.js +57 -0
- package/dist/commands/improve/extract-cli.js +5 -5
- package/dist/commands/improve/extract-prompt.js +64 -22
- package/dist/commands/improve/extract.js +608 -360
- package/dist/commands/improve/improve-strategies.js +43 -14
- package/dist/commands/improve/improve.js +249 -29
- package/dist/commands/improve/loop-stages.js +11 -17
- package/dist/commands/improve/memory/memory-contradiction-detect.js +90 -66
- package/dist/commands/improve/outcome-loop.js +22 -38
- package/dist/commands/improve/planner.js +134 -0
- package/dist/commands/improve/preparation.js +730 -409
- package/dist/commands/improve/reflect.js +386 -223
- package/dist/commands/improve/run-context.js +3 -4
- package/dist/commands/improve/salience.js +6 -58
- package/dist/commands/improve/session-asset.js +12 -12
- package/dist/commands/lint/index.js +101 -29
- package/dist/commands/migrate-cli.js +11 -69
- package/dist/commands/migration-tool.js +6 -9
- package/dist/commands/models-cli.js +27 -0
- package/dist/commands/proposal/drain.js +258 -186
- package/dist/commands/proposal/proposal-cli.js +32 -10
- package/dist/commands/proposal/proposal.js +2 -5
- package/dist/commands/proposal/propose.js +192 -172
- package/dist/commands/proposal/repository.js +54 -91
- package/dist/commands/proposal/validators/proposal-validators.js +9 -7
- package/dist/commands/read/curate.js +53 -22
- package/dist/commands/read/registry-search.js +25 -9
- package/dist/commands/read/remember-cli.js +14 -2
- package/dist/commands/read/search.js +10 -4
- package/dist/commands/read/show.js +139 -153
- package/dist/commands/registry-cli.js +16 -7
- package/dist/commands/remember.js +33 -18
- package/dist/commands/sources/add-cli.js +19 -178
- package/dist/commands/sources/bundle-cli.js +15 -3
- package/dist/commands/sources/dangerous-env-audit.js +135 -0
- package/dist/commands/sources/info.js +2 -1
- package/dist/commands/sources/installed-stashes.js +901 -177
- package/dist/commands/sources/schema-repair.js +174 -95
- package/dist/commands/sources/self-update.js +30 -74
- package/dist/commands/sources/source-add.js +3 -5
- package/dist/commands/sources/sources-cli.js +2 -15
- package/dist/commands/sources/update-transaction.js +220 -0
- package/dist/commands/tasks/tasks-cli.js +3 -3
- package/dist/commands/tasks/tasks.js +736 -317
- package/dist/commands/workflow-cli.js +2 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +3 -0
- package/dist/core/adapter/adapters/akm-adapter.js +85 -35
- package/dist/core/adapter/adapters/akm-lint.js +54 -39
- package/dist/core/adapter/adapters/akm-metadata.js +45 -45
- package/dist/core/adapter/adapters/akm-task-adapter.js +32 -49
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +38 -23
- package/dist/core/adapter/adapters/dotenv-adapter.js +30 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +11 -0
- package/dist/core/adapter/adapters/index.js +0 -9
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +4 -0
- package/dist/core/adapter/adapters/okf-adapter.js +4 -0
- package/dist/core/adapter/adapters/opencode-adapter.js +5 -8
- package/dist/core/adapter/adapters/tool-dir-shared.js +63 -6
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -0
- package/dist/core/adapter/execution-source.js +308 -0
- package/dist/core/adapter/recognize-match.js +36 -13
- package/dist/core/adapter/registry.js +0 -9
- package/dist/core/asset/stash-meta.js +94 -4
- package/dist/core/common.js +6 -11
- package/dist/core/config/config-io.js +3 -3
- package/dist/core/config/config-schema.js +18 -40
- package/dist/core/config/config-sources.js +11 -21
- package/dist/core/config/config-walker.js +31 -13
- package/dist/core/config/config.js +23 -26
- package/dist/core/config/schema/engines.js +8 -7
- package/dist/core/config/schema/improve-processes.js +29 -5
- package/dist/core/config/schema/index-config.js +0 -27
- package/dist/core/config/schema/primitives.js +1 -23
- package/dist/core/config/schema/sources-bundles.js +13 -16
- package/dist/core/errors.js +2 -0
- package/dist/core/events.js +68 -32
- package/dist/core/extra-params.js +1 -0
- package/dist/core/improve-result.js +315 -0
- package/dist/core/lesson-lint.js +0 -6
- package/dist/core/maintenance-barrier.js +4 -4
- package/dist/core/network-policy.js +152 -0
- package/dist/core/paths.js +1 -1
- package/dist/core/recognition-util.js +4 -4
- package/dist/core/registry-url.js +456 -0
- package/dist/core/state/migrations.js +161 -47
- package/dist/core/state-db.js +453 -80
- package/dist/core/system-error.js +32 -0
- package/dist/core/time.js +2 -12
- package/dist/core/write-source.js +0 -18
- package/dist/execution/directory-identity.js +52 -0
- package/dist/execution/executable-identity.js +107 -0
- package/dist/execution/guarded-source.js +398 -0
- package/dist/execution/json.js +95 -0
- package/dist/{commands/health/types-session-log.js → execution/limits.js} +2 -1
- package/dist/execution/record.js +55 -0
- package/dist/execution/resolved-request.js +730 -0
- package/dist/execution/source.js +320 -0
- package/dist/indexer/bundle-identity-guard.js +5 -4
- package/dist/indexer/db/graph-db.js +33 -0
- package/dist/indexer/graph/graph-boost.js +3 -4
- package/dist/indexer/graph/graph-extraction.js +562 -373
- package/dist/indexer/index-written-assets.js +78 -39
- package/dist/indexer/indexer.js +471 -432
- package/dist/indexer/installations.js +6 -0
- package/dist/indexer/lookup/adapter-concept-owner.js +283 -0
- package/dist/indexer/materialize-embeddings.js +155 -0
- package/dist/indexer/passes/memory-inference.js +227 -174
- package/dist/indexer/passes/metadata.js +263 -118
- package/dist/indexer/scan/doc-to-entry.js +7 -10
- package/dist/indexer/scan/drain-dir.js +51 -23
- package/dist/indexer/search/db-search.js +156 -50
- package/dist/indexer/search/fts-query.js +40 -40
- package/dist/indexer/search/ranking.js +36 -1
- package/dist/indexer/search/search-attribution.js +3 -1
- package/dist/indexer/search/search-fields.js +23 -14
- package/dist/indexer/search/search-hit-enrichers.js +1 -1
- package/dist/indexer/search/search-source.js +7 -16
- package/dist/indexer/search/semantic-status.js +10 -1
- package/dist/indexer/usage/show-usage.js +105 -0
- package/dist/indexer/usage/usage-events.js +7 -2
- package/dist/indexer/walk/matchers.js +40 -10
- package/dist/indexer/walk/path-resolver.js +5 -2
- package/dist/indexer/walk/walker.js +20 -2
- package/dist/integrations/agent/builder-shared.js +3 -6
- package/dist/integrations/agent/conversation-fallback.js +16 -0
- package/dist/integrations/agent/engine-resolution.js +87 -87
- package/dist/integrations/agent/execution-cascade.js +566 -0
- package/dist/integrations/agent/execution-definitions.js +211 -0
- package/dist/integrations/agent/execution-lowering.js +811 -0
- package/dist/integrations/agent/execution-preparation.js +67 -0
- package/dist/integrations/agent/index.js +0 -2
- package/dist/integrations/agent/inline-execution.js +74 -0
- package/dist/integrations/agent/model-map.js +515 -0
- package/dist/integrations/agent/persona-fallback.js +30 -0
- package/dist/integrations/agent/request-lowering.js +186 -0
- package/dist/integrations/agent/runner-dispatch.js +230 -37
- package/dist/integrations/agent/runner.js +12 -83
- package/dist/integrations/harnesses/aider/agent-builder.js +8 -0
- package/dist/integrations/harnesses/aider/index.js +0 -1
- package/dist/integrations/harnesses/amazonq/agent-builder.js +8 -0
- package/dist/integrations/harnesses/amazonq/index.js +0 -1
- package/dist/integrations/harnesses/claude/agent-builder.js +14 -1
- package/dist/integrations/harnesses/claude/index.js +1 -5
- package/dist/integrations/harnesses/claude/session-log.js +3 -33
- package/dist/integrations/harnesses/codex/agent-builder.js +8 -0
- package/dist/integrations/harnesses/codex/index.js +0 -1
- package/dist/integrations/harnesses/copilot/agent-builder.js +8 -0
- package/dist/integrations/harnesses/copilot/index.js +0 -1
- package/dist/integrations/harnesses/gemini/agent-builder.js +8 -0
- package/dist/integrations/harnesses/gemini/index.js +0 -1
- package/dist/integrations/harnesses/index.js +4 -44
- package/dist/integrations/harnesses/opencode/agent-builder.js +16 -9
- package/dist/integrations/harnesses/opencode/index.js +0 -2
- package/dist/integrations/harnesses/opencode/session-log.js +14 -204
- package/dist/integrations/harnesses/opencode-sdk/harness.js +12 -1
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +40 -42
- package/dist/integrations/harnesses/openhands/agent-builder.js +8 -0
- package/dist/integrations/harnesses/openhands/index.js +0 -1
- package/dist/integrations/harnesses/pi/agent-builder.js +8 -0
- package/dist/integrations/harnesses/pi/index.js +0 -1
- package/dist/integrations/harnesses/shared.js +0 -1
- package/dist/integrations/harnesses/types.js +1 -3
- package/dist/integrations/lockfile.js +82 -79
- package/dist/integrations/session-logs/index.js +6 -17
- package/dist/integrations/session-logs/provider-base.js +1 -29
- package/dist/llm/client.js +10 -5
- package/dist/llm/embedder.js +6 -7
- package/dist/llm/embedders/local.js +37 -88
- package/dist/llm/embedders/types.js +1 -1
- package/dist/llm/graph-extract.js +75 -50
- package/dist/llm/index-passes.js +43 -5
- package/dist/llm/memory-infer.js +8 -6
- package/dist/llm/metadata-enhance.js +5 -3
- package/dist/llm/structured-call.js +122 -25
- package/dist/output/format-exempt.js +1 -1
- package/dist/output/render-registry.js +0 -16
- package/dist/output/renderers.js +12 -7
- package/dist/output/shapes/curate.js +1 -0
- package/dist/output/shapes/helpers.js +10 -2
- package/dist/output/shapes/passthrough.js +2 -0
- package/dist/output/text/command-format.js +31 -33
- package/dist/output/text/health-format.js +1 -29
- package/dist/output/text/migrate.js +6 -56
- package/dist/output/text/proposal-format.js +16 -1
- package/dist/output/text/workflow-format.js +16 -0
- package/dist/registry/network.js +279 -0
- package/dist/registry/pinned-request-helper.js +247 -0
- package/dist/registry/pinned-transport.js +717 -0
- package/dist/registry/providers/skills-sh.js +18 -6
- package/dist/registry/providers/static-index.js +20 -7
- package/dist/registry/resolve.js +53 -28
- package/dist/scripts/akm-migrate-node.js +19334 -52269
- package/dist/scripts/akm-migrate.js +19270 -51612
- package/dist/setup/registry-stash-loader.js +64 -20
- package/dist/setup/semantic-assets.js +9 -34
- package/dist/setup/setup.js +12 -30
- package/dist/setup/source-identity.js +17 -0
- package/dist/setup/steps/sources.js +36 -15
- package/dist/setup/steps/tasks.js +39 -11
- package/dist/sources/providers/git-provider.js +3 -3
- package/dist/sources/providers/npm.js +2 -2
- package/dist/sources/providers/provider-utils.js +4 -3
- package/dist/sources/providers/website.js +11 -7
- package/dist/sources/snapshot-fetchers/host-guard.js +9 -136
- package/dist/sources/snapshot-fetchers/website-ingest.js +25 -109
- package/dist/sources/website-url.js +73 -0
- package/dist/storage/engines/sqlite-migrations.js +81 -26
- package/dist/storage/managed-db.js +27 -24
- package/dist/storage/repositories/events-repository.js +3 -0
- package/dist/storage/repositories/index-connection.js +42 -10
- package/dist/storage/repositories/index-entries-repository.js +203 -229
- package/dist/storage/repositories/index-entry-mapper.js +8 -12
- package/dist/storage/repositories/index-entry-schema.js +255 -0
- package/dist/storage/repositories/index-fts-repository.js +64 -71
- package/dist/storage/repositories/index-llm-cache-repository.js +8 -13
- package/dist/storage/repositories/index-meta-repository.js +0 -11
- package/dist/storage/repositories/index-schema.js +74 -350
- package/dist/storage/repositories/index-utility-repository.js +12 -17
- package/dist/storage/repositories/index-vec-repository.js +56 -7
- package/dist/storage/repositories/proposals-repository.js +4 -127
- package/dist/storage/repositories/registry-cache.js +2 -1
- package/dist/storage/repositories/task-history-repository.js +20 -40
- package/dist/storage/repositories/workflow-runs-repository.js +228 -129
- package/dist/storage/sqlite-read-snapshot.js +148 -0
- package/dist/tasks/backends/cron.js +170 -42
- package/dist/tasks/backends/index.js +1 -1
- package/dist/tasks/backends/launchd.js +787 -202
- package/dist/tasks/backends/schtasks.js +282 -83
- package/dist/tasks/embedded.js +7 -7
- package/dist/tasks/frozen-script.js +50 -0
- package/dist/tasks/resolve-akm-bin.js +5 -1
- package/dist/tasks/runner.js +239 -251
- package/dist/tasks/runtime-v3.js +281 -0
- package/dist/tasks/scheduler-binding.js +272 -0
- package/dist/tasks/scheduler-invocation.js +57 -43
- package/dist/tasks/scheduler-sync.js +654 -0
- package/dist/tasks/source-v3.js +752 -0
- package/dist/tasks/standalone-script-entry.js +5 -0
- package/dist/tasks/task-id.js +29 -0
- package/dist/workflows/authoring/authoring.js +15 -32
- package/dist/workflows/exec/dispatch-redaction.js +14 -8
- package/dist/workflows/exec/exec-unit.js +7 -28
- package/dist/workflows/exec/frozen-judge.js +57 -89
- package/dist/workflows/exec/lowering-notices.js +23 -0
- package/dist/workflows/exec/native-executor.js +301 -458
- package/dist/workflows/exec/param-secrets.js +4 -3
- package/dist/workflows/exec/run-workflow.js +26 -32
- package/dist/workflows/exec/step-work.js +105 -109
- package/dist/workflows/exec/unit-dispatch.js +103 -27
- package/dist/workflows/exec/unit-writer.js +3 -3
- package/dist/workflows/exec/worktree.js +2 -2
- package/dist/workflows/ir/compile.js +86 -72
- package/dist/workflows/ir/environment-v4.js +328 -0
- package/dist/workflows/ir/freeze-v4.js +122 -0
- package/dist/workflows/ir/plan-hash.js +13 -7
- package/dist/workflows/ir/schema-v4.js +525 -0
- package/dist/workflows/ir/schema.js +25 -284
- package/dist/workflows/ir/source-freeze-v4.js +506 -0
- package/dist/workflows/parser.js +27 -24
- package/dist/workflows/program/schema.js +1 -2
- package/dist/workflows/renderer.js +42 -29
- package/dist/workflows/resource-limits.js +4 -5
- package/dist/workflows/runtime/agent-identity.js +11 -13
- package/dist/workflows/runtime/plan-classifier.js +8 -8
- package/dist/workflows/runtime/runs.js +27 -43
- package/dist/workflows/runtime/workflow-asset-loader.js +45 -205
- package/dist/workflows/source-files.js +373 -0
- package/dist/workflows/source-ir/compile.js +196 -0
- package/dist/workflows/source-ir/github-yaml.js +577 -0
- package/dist/workflows/source-ir/ordering.js +38 -0
- package/dist/workflows/source-ir/program.js +50 -0
- package/dist/workflows/source-ir/result.js +26 -0
- package/dist/workflows/source-ir/schema.js +772 -0
- package/dist/workflows/source-ir/semantics.js +242 -0
- package/dist/workflows/source-ir/uses.js +14 -0
- package/docs/README.md +2 -0
- package/docs/migration/README.md +3 -1
- package/docs/migration/release-notes/0.9.2.md +55 -0
- package/docs/migration/release-notes/README.md +5 -0
- package/docs/migration/v0.8-to-v0.9.md +76 -1077
- package/docs/migration/v0.9.0-troubleshooting.md +104 -516
- package/docs/migration/v0.9.1-to-v0.9.2.md +150 -0
- package/docs/reference/README.md +1 -0
- package/docs/reference/cli.md +230 -98
- package/docs/reference/configuration.md +159 -36
- package/docs/reference/data-and-telemetry.md +19 -1
- package/docs/reference/supported-formats.md +23 -3
- package/docs/reference/tasks.md +182 -0
- package/docs/reference/workflow-schema.md +91 -40
- package/docs/reference/workflows.md +33 -6
- package/package.json +10 -6
- package/schemas/akm-config.json +372 -224
- package/schemas/akm-task.json +324 -80
- package/schemas/akm-workflow.json +6 -9
- package/dist/core/migration-operation.js +0 -75
- package/dist/integrations/agent/model-aliases.js +0 -74
- package/dist/tasks/parser.js +0 -380
- package/dist/tasks/schema.js +0 -123
- package/dist/tasks/validator.js +0 -80
- package/dist/workflows/ir/freeze.js +0 -320
- package/dist/workflows/runtime/document-cache.js +0 -13
|
@@ -0,0 +1,5 @@
|
|
|
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
|
+
/** Fixed private dispatch mode embedded into Bun standalone AKM artifacts. */
|
|
5
|
+
export const STANDALONE_FROZEN_SCRIPT_ARG = "__akm_internal_frozen_script_v1__";
|
package/dist/tasks/task-id.js
CHANGED
|
@@ -25,6 +25,9 @@ export function validateTaskId(id) {
|
|
|
25
25
|
if (TASK_FILE_SUFFIX_RE.test(id)) {
|
|
26
26
|
throw new UsageError(`Task id "${id}" is invalid. Use the bare task id without a .yml or .yaml suffix.`, "INVALID_FLAG_VALUE");
|
|
27
27
|
}
|
|
28
|
+
if (id.endsWith(".")) {
|
|
29
|
+
throw new UsageError(`Task id "${id}" is invalid. Trailing periods are not portable across native schedulers.`, "INVALID_FLAG_VALUE");
|
|
30
|
+
}
|
|
28
31
|
if (WINDOWS_RESERVED_DEVICE_RE.test(id)) {
|
|
29
32
|
throw new UsageError(`Task id "${id}" uses a reserved Windows device name. Choose a different task id.`, "INVALID_FLAG_VALUE");
|
|
30
33
|
}
|
|
@@ -33,3 +36,29 @@ export function validateTaskId(id) {
|
|
|
33
36
|
export function normaliseTaskId(raw) {
|
|
34
37
|
return validateTaskId(raw.trim());
|
|
35
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Validate an adapter component-relative task identity.
|
|
41
|
+
*
|
|
42
|
+
* Native `akm` task authoring remains deliberately flat and continues to use
|
|
43
|
+
* {@link validateTaskId}. The standalone `akm-task` adapter, however, derives
|
|
44
|
+
* identity from the complete extensionless path beneath its configured
|
|
45
|
+
* component root. Validate every path segment with the portable task-id rules
|
|
46
|
+
* without collapsing the `/` separators that distinguish physical owners.
|
|
47
|
+
*/
|
|
48
|
+
export function validateTaskConceptId(id) {
|
|
49
|
+
if (!id)
|
|
50
|
+
throw new UsageError("Task id must be non-empty.", "MISSING_REQUIRED_ARGUMENT");
|
|
51
|
+
if (id.includes("\\")) {
|
|
52
|
+
throw new UsageError(`Task id "${id}" is invalid. Use canonical forward slashes between path segments.`, "INVALID_FLAG_VALUE");
|
|
53
|
+
}
|
|
54
|
+
const segments = id.split("/");
|
|
55
|
+
if (segments.some((segment) => segment.length === 0)) {
|
|
56
|
+
throw new UsageError(`Task id "${id}" is invalid. Empty path segments are not allowed.`, "INVALID_FLAG_VALUE");
|
|
57
|
+
}
|
|
58
|
+
for (const segment of segments)
|
|
59
|
+
validateTaskId(segment);
|
|
60
|
+
return id;
|
|
61
|
+
}
|
|
62
|
+
export function normaliseTaskConceptId(raw) {
|
|
63
|
+
return validateTaskConceptId(raw.trim());
|
|
64
|
+
}
|
|
@@ -14,7 +14,7 @@ import { canonicalizeWorkflowName, WORKFLOW_EXTENSIONS } from "../../core/recogn
|
|
|
14
14
|
import { warn } from "../../core/warn.js";
|
|
15
15
|
import { prepareWriteTargetForMutation, resolveWriteTarget, withWriteTargetMutation } from "../../core/write-source.js";
|
|
16
16
|
import { compileWorkflowPlan } from "../ir/compile.js";
|
|
17
|
-
import {
|
|
17
|
+
import { compileWorkflowSource } from "../source-ir/compile.js";
|
|
18
18
|
const DEFAULT_WORKFLOW_TEMPLATE = renderWorkflowTemplate("New Workflow");
|
|
19
19
|
export function getWorkflowTemplate() {
|
|
20
20
|
return DEFAULT_WORKFLOW_TEMPLATE;
|
|
@@ -22,33 +22,33 @@ export function getWorkflowTemplate() {
|
|
|
22
22
|
export function buildWorkflowTemplate(name) {
|
|
23
23
|
if (!name)
|
|
24
24
|
return DEFAULT_WORKFLOW_TEMPLATE;
|
|
25
|
-
// Only the H1 is customized. Step ids are STRUCTURAL
|
|
25
|
+
// Only the H1 is customized. Step ids are STRUCTURAL in the Markdown authoring form
|
|
26
26
|
// — each appears in `steps[].id`, as a body `## <id>` heading, and possibly in
|
|
27
27
|
// another step's `inputs:` — so rewriting them from a name would have to patch
|
|
28
28
|
// three places consistently to stay parseable. Generic `first-step`/
|
|
29
29
|
// `second-step` are the author's to rename.
|
|
30
30
|
const customized = renderWorkflowTemplate(humanizeWorkflowName(name));
|
|
31
|
-
validateWorkflowContent(customized, `<template:${name}
|
|
31
|
+
validateWorkflowContent(customized, `<template:${name}>.md`);
|
|
32
32
|
return customized;
|
|
33
33
|
}
|
|
34
34
|
/** Parse AND compile `content`, so a create never writes an asset that `show`/`start`/`validate` would then reject. */
|
|
35
35
|
function validateWorkflowContent(content, sourcePath) {
|
|
36
|
-
const result =
|
|
36
|
+
const result = compileWorkflowSource(content, { path: sourcePath });
|
|
37
37
|
if (!result.ok) {
|
|
38
38
|
throw new UsageError(formatWorkflowErrors(sourcePath, result.errors));
|
|
39
39
|
}
|
|
40
|
-
const compiled = compileWorkflowPlan(result.
|
|
40
|
+
const compiled = compileWorkflowPlan(result.ir, slugifyWorkflowStepId(sourcePath));
|
|
41
41
|
if (!compiled.ok) {
|
|
42
42
|
throw new UsageError(formatWorkflowErrors(sourcePath, compiled.errors));
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
/**
|
|
45
|
+
/** Peer YAML is executable, but `akm workflow create` emits the Markdown authoring form only. */
|
|
46
46
|
const YAML_SUFFIX_RE = /\.ya?ml$/i;
|
|
47
47
|
export function assertWorkflowMarkdownName(name) {
|
|
48
48
|
if (!YAML_SUFFIX_RE.test(name.trim()))
|
|
49
49
|
return;
|
|
50
|
-
throw new UsageError(`
|
|
51
|
-
`Use a plain name (no ".yaml"/".yml" suffix)
|
|
50
|
+
throw new UsageError(`akm workflow create is markdown-only: it emits Markdown and cannot create "${name}". ` +
|
|
51
|
+
`Use a plain name (no ".yaml"/".yml" suffix), or author a peer GitHub-shaped ".yml" workflow directly.`);
|
|
52
52
|
}
|
|
53
53
|
export function createWorkflowAsset(input) {
|
|
54
54
|
assertWorkflowMarkdownName(input.name);
|
|
@@ -67,11 +67,10 @@ export function createWorkflowAsset(input) {
|
|
|
67
67
|
path.isAbsolute(relativeAssetPath)) {
|
|
68
68
|
throw new UsageError(`Resolved workflow path escapes the bundle: "${normalizedName}"`, "PATH_ESCAPE_VIOLATION");
|
|
69
69
|
}
|
|
70
|
-
// A file whose canonical name matches
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
// so writing the target would silently clobber or shadow the existing asset.
|
|
70
|
+
// A peer `.md` or `.yml` file whose canonical name matches already owns this
|
|
71
|
+
// ref. Case variants (`upper.MD` vs `upper.md`) may also name one physical
|
|
72
|
+
// file on a case-insensitive filesystem, so writing the Markdown create
|
|
73
|
+
// target would silently clobber or shadow the existing asset.
|
|
75
74
|
const shadowing = findExistingWorkflowPaths(typeRoot, normalizedName).find((p) => p !== assetPath);
|
|
76
75
|
if (shadowing !== undefined) {
|
|
77
76
|
throw new UsageError(`Workflow "${normalizedName}" already exists as ${path.relative(stashDir, shadowing)} — the ` +
|
|
@@ -159,27 +158,11 @@ export function formatWorkflowErrors(path, errors) {
|
|
|
159
158
|
const heading = errors.length === 1 ? "Workflow has 1 error:" : `Workflow has ${errors.length} errors:`;
|
|
160
159
|
return [heading, ...lines].join("\n");
|
|
161
160
|
}
|
|
162
|
-
/**
|
|
163
|
-
* Validate a workflow filesystem path.
|
|
164
|
-
*
|
|
165
|
-
* Returns the parse result plus the source-relative path used. Throws
|
|
166
|
-
* `UsageError` only when the target cannot be located on disk; parse
|
|
167
|
-
* failures are returned as `{ ok: false, errors }` so callers can
|
|
168
|
-
* format them however they like.
|
|
169
|
-
*/
|
|
170
|
-
export function validateWorkflowSource(target) {
|
|
171
|
-
const resolved = path.resolve(target);
|
|
172
|
-
if (!fs.existsSync(resolved)) {
|
|
173
|
-
throw new UsageError(`Workflow file not found: "${target}".`);
|
|
174
|
-
}
|
|
175
|
-
const content = fs.readFileSync(resolved, "utf8");
|
|
176
|
-
return { path: target, parse: parseWorkflow(content, { path: target }) };
|
|
177
|
-
}
|
|
178
161
|
/**
|
|
179
162
|
* Every file under `typeRoot` whose canonical workflow name equals
|
|
180
|
-
* `normalizedName`.
|
|
181
|
-
*
|
|
182
|
-
* rather than silently clobber
|
|
163
|
+
* `normalizedName`. Peer `.md`/`.yml` extension matching is case-INSENSITIVE,
|
|
164
|
+
* so both cross-format owners and case variants are returned for the create
|
|
165
|
+
* path to refuse rather than silently clobber or shadow them.
|
|
183
166
|
*/
|
|
184
167
|
function findExistingWorkflowPaths(typeRoot, normalizedName) {
|
|
185
168
|
const parent = path.join(typeRoot, path.dirname(normalizedName));
|
|
@@ -32,26 +32,32 @@ import { collectSensitiveValues, isEnvPassthroughValueSafeToExpose, redactSensit
|
|
|
32
32
|
* the set.
|
|
33
33
|
*/
|
|
34
34
|
export function collectWorkflowDispatchSensitiveValues(dispatch, env) {
|
|
35
|
-
const values = new Set(Object.values(env ?? {}));
|
|
36
|
-
const addCredential = (
|
|
37
|
-
if (!
|
|
35
|
+
const values = new Set([...Object.values(env ?? {}), ...(dispatch.sensitiveValues ?? [])]);
|
|
36
|
+
const addCredential = (runner) => {
|
|
37
|
+
if (!runner)
|
|
38
38
|
return;
|
|
39
|
-
if (
|
|
40
|
-
for (const name of
|
|
39
|
+
if (runner.kind === "llm") {
|
|
40
|
+
for (const name of runner.credential?.names ?? []) {
|
|
41
41
|
const value = process.env[name]?.trim();
|
|
42
42
|
if (value)
|
|
43
43
|
values.add(value);
|
|
44
44
|
}
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
|
-
for (const name of
|
|
47
|
+
for (const name of runner.profile.envPassthrough ?? []) {
|
|
48
48
|
const value = process.env[name];
|
|
49
49
|
if (!isEnvPassthroughValueSafeToExpose(name, value) && value)
|
|
50
50
|
values.add(value);
|
|
51
51
|
}
|
|
52
|
+
if (runner.kind === "sdk") {
|
|
53
|
+
for (const name of runner.fallbackCredential?.names ?? []) {
|
|
54
|
+
const value = process.env[name]?.trim();
|
|
55
|
+
if (value)
|
|
56
|
+
values.add(value);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
52
59
|
};
|
|
53
|
-
addCredential(dispatch.
|
|
54
|
-
addCredential(dispatch.fallbackEngine);
|
|
60
|
+
addCredential(dispatch.runner);
|
|
55
61
|
return collectSensitiveValues(values);
|
|
56
62
|
}
|
|
57
63
|
/**
|
|
@@ -30,8 +30,7 @@
|
|
|
30
30
|
* - ALLOWLISTED ENVIRONMENT. The child does NOT inherit akm's environment: it
|
|
31
31
|
* starts EMPTY and receives exactly {@link EXEC_DEFAULT_ENV_PASSTHROUGH}
|
|
32
32
|
* plus the unit's `exec.passEnv`, then the resolved `env:` bindings, then
|
|
33
|
-
* the engine-authored `AKM_*` context.
|
|
34
|
-
* inheritance. See {@link childEnv}.
|
|
33
|
+
* the engine-authored `AKM_*` context. See {@link childEnv}.
|
|
35
34
|
*
|
|
36
35
|
* Secrets: `env` values reaching this module are already resolved from `env:`
|
|
37
36
|
* bindings by NAME (`resolveEnvBinding`) — the plan never carries inline secrets
|
|
@@ -48,7 +47,7 @@
|
|
|
48
47
|
import fs from "node:fs";
|
|
49
48
|
import path from "node:path";
|
|
50
49
|
import { isWithinAsync } from "../../core/common.js";
|
|
51
|
-
import { COMMON_SPAWN_ENV_PASSTHROUGH, collectAllowlistedEnv,
|
|
50
|
+
import { COMMON_SPAWN_ENV_PASSTHROUGH, collectAllowlistedEnv, WIN32_SPAWN_ENV_FLOOR } from "../../core/spawn-env.js";
|
|
52
51
|
import { runManagedSubprocess, streamCaptureFailure, } from "../../core/subprocess.js";
|
|
53
52
|
import { warn } from "../../core/warn.js";
|
|
54
53
|
import { execContextLimits, utf8Bytes, WORKFLOW_EXEC_OUTPUT_TRUNCATED_MARKER, WORKFLOW_MAX_EXEC_OUTPUT_BYTES, WORKFLOW_UNIT_DIAGNOSTIC_CLIP, } from "../resource-limits.js";
|
|
@@ -113,8 +112,8 @@ const EXEC_STDERR_DIAGNOSTIC_CLIP = WORKFLOW_UNIT_DIAGNOSTIC_CLIP - 500;
|
|
|
113
112
|
* demand, exactly as the agent passthrough list does
|
|
114
113
|
* (`integrations/agent/profiles.ts`, DRIFT-6).
|
|
115
114
|
*
|
|
116
|
-
* Deliberately ABSENT and reachable only through `exec.passEnv` / `env
|
|
117
|
-
*
|
|
115
|
+
* Deliberately ABSENT and reachable only through `exec.passEnv` / `env:`:
|
|
116
|
+
* credentials of every kind, cloud/CI vars, and the proxy
|
|
118
117
|
* family (`HTTP_PROXY` & friends) — proxy URLs routinely embed credentials,
|
|
119
118
|
* which is why akm's redaction policy already treats URL-shaped passthrough
|
|
120
119
|
* values as credential-bearing.
|
|
@@ -460,9 +459,8 @@ async function isExistingDirectory(candidate) {
|
|
|
460
459
|
/**
|
|
461
460
|
* The child's environment, in three layers with fixed precedence:
|
|
462
461
|
*
|
|
463
|
-
* 1. the BASE —
|
|
464
|
-
*
|
|
465
|
-
* environment when the unit opted in with `exec.inheritEnv`;
|
|
462
|
+
* 1. the BASE — {@link EXEC_DEFAULT_ENV_PASSTHROUGH} plus the unit's
|
|
463
|
+
* `exec.passEnv` names;
|
|
466
464
|
* 2. the unit's resolved `env:` bindings;
|
|
467
465
|
* 3. the engine-authored `AKM_*` context, LAST so a workflow-supplied binding
|
|
468
466
|
* can never shadow the ids/item the engine is telling the command the
|
|
@@ -490,14 +488,9 @@ async function isExistingDirectory(candidate) {
|
|
|
490
488
|
* {@link collectAllowlistedEnv} does it here, so there is one mechanism to
|
|
491
489
|
* review instead of two.
|
|
492
490
|
*
|
|
493
|
-
* `inheritEnv` is the honest escape hatch for a command that genuinely needs the
|
|
494
|
-
* caller's whole environment. It passes everything through, PATH included —
|
|
495
|
-
* supplemented for scheduler contexts exactly as {@link collectAllowlistedEnv}
|
|
496
|
-
* does it, because the MORE permissive branch must never hand a command a WORSE
|
|
497
|
-
* PATH than the restrictive default does under cron/launchd.
|
|
498
491
|
*/
|
|
499
492
|
function childEnv(exec, bindings, context) {
|
|
500
|
-
const env =
|
|
493
|
+
const env = collectAllowlistedEnv(execAllowlist(exec));
|
|
501
494
|
for (const [name, value] of Object.entries(bindings ?? {}))
|
|
502
495
|
env[name] = value;
|
|
503
496
|
for (const [name, value] of Object.entries(context ?? {}))
|
|
@@ -508,20 +501,6 @@ function childEnv(exec, bindings, context) {
|
|
|
508
501
|
function execAllowlist(exec) {
|
|
509
502
|
return exec.passEnv ? [...EXEC_DEFAULT_ENV_PASSTHROUGH, ...exec.passEnv] : [...EXEC_DEFAULT_ENV_PASSTHROUGH];
|
|
510
503
|
}
|
|
511
|
-
/**
|
|
512
|
-
* The akm process's own environment (`exec.inheritEnv`), with the same
|
|
513
|
-
* scheduler-context PATH supplementation {@link collectAllowlistedEnv} applies.
|
|
514
|
-
*/
|
|
515
|
-
function inheritedProcessEnv() {
|
|
516
|
-
const env = {};
|
|
517
|
-
for (const [name, value] of Object.entries(process.env)) {
|
|
518
|
-
if (typeof value === "string")
|
|
519
|
-
env[name] = value;
|
|
520
|
-
}
|
|
521
|
-
if (env.PATH !== undefined)
|
|
522
|
-
env.PATH = supplementPathForSchedulerContext(env.PATH);
|
|
523
|
-
return env;
|
|
524
|
-
}
|
|
525
504
|
/** `argv[0]` plus its argument count — never the full argv, which can carry values. */
|
|
526
505
|
function describeCommand(command) {
|
|
527
506
|
const rest = command.length - 1;
|
|
@@ -2,7 +2,7 @@
|
|
|
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
4
|
/**
|
|
5
|
-
* The gate judge built from
|
|
5
|
+
* The gate judge built from the workflow's frozen current execution target.
|
|
6
6
|
*
|
|
7
7
|
* Two contracts this module owns, both of which the rest of the engine already
|
|
8
8
|
* enforces for ordinary units and neither of which the judge may opt out of:
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
* notes. So the judge outcome goes through the SAME scrub every unit outcome
|
|
14
14
|
* goes through: {@link collectWorkflowDispatchSensitiveValues} +
|
|
15
15
|
* {@link withDispatchRedaction} (exec/dispatch-redaction.ts). Nothing about
|
|
16
|
-
* a judge call reaches durable state before that scrub.
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* a judge call reaches durable state before that scrub. Agent and direct-LLM
|
|
17
|
+
* judges share one prepared/lowered dispatch request; the manual completion
|
|
18
|
+
* path uses the same config-free dispatcher without opening an executor
|
|
19
|
+
* import cycle.
|
|
20
20
|
*
|
|
21
21
|
* 2. **Identity.** The dispatch request carries the REAL run/step and the gate's
|
|
22
22
|
* real node/unit ids — the same ids `journalGateEvaluationStart/Finish` write
|
|
@@ -25,17 +25,22 @@
|
|
|
25
25
|
* The identity is threaded in from the caller that writes the row
|
|
26
26
|
* ({@link SummaryJudge}'s `identity` argument); it is never synthesized here.
|
|
27
27
|
*
|
|
28
|
-
* A judge dispatch carries NO `env` bindings:
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* A judge dispatch carries NO `env` bindings: the normalized gate target has
|
|
29
|
+
* no environment key, so there is nothing authored to thread — and a step's
|
|
30
|
+
* unit environment is scoped to the WORK,
|
|
31
31
|
* not to the verifier. Redaction is unaffected: the sensitive-value set below
|
|
32
32
|
* still covers the judge engine's credential and unsafe passthrough values.
|
|
33
|
+
* Lowering notices are live execution metadata: units expose a typed result,
|
|
34
|
+
* while judges retain their public string contract and emit only the common
|
|
35
|
+
* lowerer's prompt/body-free notice projection through `warn()`. Current
|
|
36
|
+
* result/evidence journal writers intentionally exclude these diagnostics;
|
|
37
|
+
* this boundary makes no claim about future persistence ownership.
|
|
33
38
|
*
|
|
34
39
|
* @module workflows/exec/frozen-judge
|
|
35
40
|
*/
|
|
36
|
-
import {
|
|
41
|
+
import { warn } from "../../core/warn.js";
|
|
37
42
|
import { collectWorkflowDispatchSensitiveValues, withDispatchRedaction } from "./dispatch-redaction.js";
|
|
38
|
-
import {
|
|
43
|
+
import { dispatchWorkflowExecution, prepareWorkflowExecution, } from "./unit-dispatch.js";
|
|
39
44
|
/** The gate's node id — identical to what `journalGateEvaluationStart` writes. */
|
|
40
45
|
export function gateNodeId(stepId) {
|
|
41
46
|
return `${stepId}.gate`;
|
|
@@ -50,96 +55,59 @@ export function gateNodeId(stepId) {
|
|
|
50
55
|
function dispatchIdentity(owner, identity) {
|
|
51
56
|
return identity ?? { ...owner, unitId: gateNodeId(owner.stepId) };
|
|
52
57
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
throw new ConfigError(`Frozen agent gate engine "${invocation.engine}" has no unit dispatcher.`, "INVALID_CONFIG_FILE");
|
|
58
|
+
function warnLoweringNotices(...groups) {
|
|
59
|
+
const emitted = new Set();
|
|
60
|
+
for (const notices of groups) {
|
|
61
|
+
for (const notice of notices ?? []) {
|
|
62
|
+
const key = JSON.stringify([notice.code, notice.severity, notice.adapter, notice.field, notice.message]);
|
|
63
|
+
if (emitted.has(key))
|
|
64
|
+
continue;
|
|
65
|
+
emitted.add(key);
|
|
66
|
+
warn(`Workflow judge lowering notice (${notice.code}; ${notice.adapter}; ${notice.field}): ${notice.message}`);
|
|
63
67
|
}
|
|
64
|
-
const fallbackEngine = engine.fallbackLlmEngine ? plan.execution.engines[engine.fallbackLlmEngine] : undefined;
|
|
65
|
-
const fallback = fallbackEngine?.kind === "llm" ? fallbackEngine : undefined;
|
|
66
|
-
// Scrub at the seam: every outcome this judge's dispatcher returns — and
|
|
67
|
-
// every error it throws — is redacted BEFORE the verdict (or the failure
|
|
68
|
-
// message) can reach the gate row / the blocked step's notes. Identical
|
|
69
|
-
// contract to the llm branch below and to the unit path, including the
|
|
70
|
-
// failureReason downgrade when redaction altered it.
|
|
71
|
-
const dispatch = withDispatchRedaction(dispatcher);
|
|
72
|
-
return async ({ system, user }, identity) => {
|
|
73
|
-
const id = dispatchIdentity(owner, identity);
|
|
74
|
-
// Collected per dispatch, not once per judge: the engine PAIR is fixed at
|
|
75
|
-
// build time but its secrets are not — they are read from `process.env`,
|
|
76
|
-
// which the dispatch itself re-reads, so a build-time set would miss a
|
|
77
|
-
// credential set or rotated between the two reads. Same collector the unit
|
|
78
|
-
// path uses; see the module doc on why `env` is absent here but the
|
|
79
|
-
// credential/passthrough values are still collected.
|
|
80
|
-
const sensitiveValues = collectWorkflowDispatchSensitiveValues({ engine, ...(fallback ? { fallbackEngine: fallback } : {}) }, undefined);
|
|
81
|
-
const outcome = await dispatch({
|
|
82
|
-
runId: id.runId,
|
|
83
|
-
stepId: id.stepId,
|
|
84
|
-
unitId: id.unitId,
|
|
85
|
-
nodeId: gateNodeId(id.stepId),
|
|
86
|
-
prompt: user,
|
|
87
|
-
systemPrompt: system,
|
|
88
|
-
engine,
|
|
89
|
-
...(fallback ? { fallbackEngine: fallback } : {}),
|
|
90
|
-
invocation,
|
|
91
|
-
timeoutMs: invocation.timeoutMs,
|
|
92
|
-
...(sensitiveValues.length > 0 ? { sensitiveValues } : {}),
|
|
93
|
-
...(signal ? { signal } : {}),
|
|
94
|
-
});
|
|
95
|
-
if (!outcome.ok) {
|
|
96
|
-
throw new Error(outcome.error || `Verification engine "${invocation.engine}" failed.`);
|
|
97
|
-
}
|
|
98
|
-
return outcome.text ?? "";
|
|
99
|
-
};
|
|
100
68
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
// Inline chatCompletion rather than the injected unit dispatcher ON PURPOSE:
|
|
108
|
-
// the manual completion path (`runtime/runs.ts`) builds an llm judge with no
|
|
109
|
-
// dispatcher, and a static runs → native-executor edge would close an import
|
|
110
|
-
// cycle. The materialization itself is the shared {@link materializeFrozenLlm},
|
|
111
|
-
// so the two llm dispatch paths cannot drift.
|
|
112
|
-
const dispatch = withDispatchRedaction(async (request) => {
|
|
113
|
-
const { chatCompletion } = await import("../../llm/client.js");
|
|
114
|
-
const text = await chatCompletion(materializeFrozenLlm(engine, invocation), [
|
|
115
|
-
{ role: "system", content: request.systemPrompt ?? "" },
|
|
116
|
-
{ role: "user", content: request.prompt },
|
|
117
|
-
], {
|
|
118
|
-
timeoutMs: request.timeoutMs,
|
|
119
|
-
...(signal ? { signal } : {}),
|
|
120
|
-
});
|
|
121
|
-
return { ok: true, text };
|
|
122
|
-
});
|
|
69
|
+
}
|
|
70
|
+
/** Build a gate judge from the normalized frozen target without consulting live config. */
|
|
71
|
+
export function frozenSummaryJudge(target, signal, dispatcher, owner) {
|
|
72
|
+
if (!target)
|
|
73
|
+
return null;
|
|
74
|
+
const dispatch = withDispatchRedaction(dispatcher ?? dispatchWorkflowExecution);
|
|
123
75
|
return async ({ system, user }, identity) => {
|
|
124
76
|
const id = dispatchIdentity(owner, identity);
|
|
125
|
-
|
|
126
|
-
// `materializeFrozenLlm` resolves out of `process.env` inside the dispatch
|
|
127
|
-
// below — so the set is collected here, per dispatch, and cannot predate the
|
|
128
|
-
// value the call actually authenticates with.
|
|
129
|
-
const sensitiveValues = collectWorkflowDispatchSensitiveValues({ engine }, undefined);
|
|
130
|
-
const outcome = await dispatch({
|
|
77
|
+
const commonRequest = {
|
|
131
78
|
runId: id.runId,
|
|
132
79
|
stepId: id.stepId,
|
|
133
80
|
unitId: id.unitId,
|
|
134
81
|
nodeId: gateNodeId(id.stepId),
|
|
82
|
+
...(id.attempt !== undefined ? { attempt: id.attempt } : {}),
|
|
83
|
+
...(id.dispatchId !== undefined ? { dispatchId: id.dispatchId } : {}),
|
|
135
84
|
prompt: user,
|
|
136
85
|
systemPrompt: system,
|
|
137
|
-
engine,
|
|
138
|
-
invocation,
|
|
139
|
-
timeoutMs: invocation.timeoutMs,
|
|
140
|
-
...(sensitiveValues.length > 0 ? { sensitiveValues } : {}),
|
|
141
86
|
...(signal ? { signal } : {}),
|
|
87
|
+
};
|
|
88
|
+
const request = {
|
|
89
|
+
...commonRequest,
|
|
90
|
+
frozenTarget: target,
|
|
91
|
+
timeoutMs: target.runner.timeoutMs ?? null,
|
|
92
|
+
};
|
|
93
|
+
// Lowering and authorization precede every live credential/passthrough
|
|
94
|
+
// sample. The injected dispatcher may be a test seam, but it receives the
|
|
95
|
+
// exact same already-validated request and redaction declaration.
|
|
96
|
+
const lowered = prepareWorkflowExecution(request);
|
|
97
|
+
const sensitiveValues = collectWorkflowDispatchSensitiveValues({ runner: target.runner }, undefined);
|
|
98
|
+
const outcome = await dispatch({
|
|
99
|
+
...request,
|
|
100
|
+
...(sensitiveValues.length > 0 ? { sensitiveValues } : {}),
|
|
142
101
|
});
|
|
143
|
-
|
|
102
|
+
if (outcome.usage && id.recordTokens) {
|
|
103
|
+
id.recordTokens((outcome.usage.inputTokens ?? 0) + (outcome.usage.outputTokens ?? 0) + (outcome.usage.reasoningTokens ?? 0));
|
|
104
|
+
}
|
|
105
|
+
// Only the common lowerer's own sanitized notices are loggable here. An
|
|
106
|
+
// injected dispatcher is not trusted to supply prompt/body-free messages.
|
|
107
|
+
warnLoweringNotices(lowered.notices);
|
|
108
|
+
if (!outcome.ok) {
|
|
109
|
+
throw new Error(outcome.error || `Verification engine "${target.request.engine.name}" failed.`);
|
|
110
|
+
}
|
|
111
|
+
return outcome.text ?? "";
|
|
144
112
|
};
|
|
145
113
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
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 { canonicalJson } from "../ir/plan-hash.js";
|
|
5
|
+
/**
|
|
6
|
+
* Merge safe lowerer diagnostics in first-seen order.
|
|
7
|
+
*
|
|
8
|
+
* Notices are live execution metadata only: this helper is deliberately used
|
|
9
|
+
* by executor/report/output paths, never by result/evidence journal writers.
|
|
10
|
+
* Canonical JSON includes `details`, so two genuinely different structured
|
|
11
|
+
* diagnostics are not collapsed merely because their headline fields match.
|
|
12
|
+
*/
|
|
13
|
+
export function mergeLoweringNotices(...groups) {
|
|
14
|
+
const merged = new Map();
|
|
15
|
+
for (const group of groups) {
|
|
16
|
+
for (const notice of group ?? []) {
|
|
17
|
+
const key = canonicalJson(notice);
|
|
18
|
+
if (!merged.has(key))
|
|
19
|
+
merged.set(key, notice);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return merged.size > 0 ? [...merged.values()] : undefined;
|
|
23
|
+
}
|