akm-cli 0.9.17-alpha.2 → 0.9.17-alpha.4
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 +756 -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/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 +7 -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/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/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 +43937 -93313
- package/dist/scripts/akm-migrate.js +43697 -93071
- 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 +363 -679
- 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 -427
- 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
|
@@ -1,730 +1,176 @@
|
|
|
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
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { assertSnapshotKeys, requireSnapshotField, snapshotStrictRecord } from "./record.js";
|
|
7
|
-
import { cloneAdapterExtensions, cloneToolSelection, decodeExecutionSourceIdentity, executionPersonaMatchesSelector, isAdapterRenderedCommandSource, isAdapterRenderedPersonaSource, isPortableExecutionAgentSelector, requireStableExecutionSelector, } from "./source.js";
|
|
4
|
+
import { sortExecutionJson } from "./json.js";
|
|
5
|
+
import { decodeExecutionSourceIdentity, } from "./source.js";
|
|
8
6
|
export const RESOLVED_EXECUTION_SCHEMA_VERSION = 1;
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
7
|
+
const COMMAND_KEYS = ["template", "argumentInput", "content", "source", "extensions"];
|
|
8
|
+
const PERSONA_KEYS = ["content", "source", "extensions"];
|
|
9
|
+
const ENGINE_KEYS = ["name", "kind", "platform", "settings", "extensions"];
|
|
10
|
+
const MODEL_KEYS = ["input", "interpretation", "resolved", "extensions"];
|
|
11
|
+
const AUTHORIZATION_KEYS = ["status", "reason", "policy"];
|
|
12
|
+
const RUNTIME_KEYS = ["timeoutMs", "workspace", "environment", "settings", "extensions"];
|
|
13
|
+
const NOTICE_KEYS = ["code", "severity", "adapter", "field", "message", "details"];
|
|
14
|
+
const IDENTITY_KEYS = ["ref", "bundle", "adapter", "file", "hash"];
|
|
15
|
+
const OPTIONAL_REQUEST_KEYS = [
|
|
16
|
+
"conversation",
|
|
17
|
+
"agent",
|
|
18
|
+
"persona",
|
|
19
|
+
"model",
|
|
20
|
+
"inference",
|
|
21
|
+
"outputSchema",
|
|
22
|
+
"tools",
|
|
23
|
+
"extensions",
|
|
24
|
+
];
|
|
25
|
+
/** Copy the own, defined fields named by `keys`; omitted stays omitted, `null` stays `null`. */
|
|
26
|
+
function pick(value, keys) {
|
|
27
|
+
const record = value;
|
|
28
|
+
const out = {};
|
|
29
|
+
for (const key of keys) {
|
|
30
|
+
if (Object.hasOwn(record, key) && record[key] !== undefined)
|
|
31
|
+
out[key] = record[key];
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
22
34
|
}
|
|
23
|
-
function
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
if (typeof input.argumentInput !== "string") {
|
|
27
|
-
throw new TypeError("command argumentInput must be omitted or a string");
|
|
35
|
+
function requireRecord(value, path) {
|
|
36
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
37
|
+
throw new TypeError(`${path} must be an object`);
|
|
28
38
|
}
|
|
29
|
-
|
|
39
|
+
return value;
|
|
30
40
|
}
|
|
31
41
|
export function createResolvedCommand(input) {
|
|
32
|
-
|
|
33
|
-
assertOnlyKeys(record, ["source", "argumentInput", "content"], "resolved command input");
|
|
34
|
-
const source = requireOwn(record, "source", "resolved command input");
|
|
35
|
-
const content = requireOwn(record, "content", "resolved command input");
|
|
36
|
-
if (!isAdapterRenderedCommandSource(source)) {
|
|
37
|
-
throw new TypeError("source must be an adapter-rendered command source");
|
|
38
|
-
}
|
|
39
|
-
if (typeof content !== "string")
|
|
42
|
+
if (typeof input.content !== "string")
|
|
40
43
|
throw new TypeError("resolved command content must be a string");
|
|
41
|
-
|
|
42
|
-
template: source.content,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
};
|
|
49
|
-
copyArgumentInput(record, out);
|
|
50
|
-
return defineBrand(out, resolvedCommandBrand, resolvedCommandInstances);
|
|
44
|
+
return Object.freeze({
|
|
45
|
+
template: input.source.content,
|
|
46
|
+
...(input.argumentInput !== undefined ? { argumentInput: input.argumentInput } : {}),
|
|
47
|
+
content: input.content,
|
|
48
|
+
source: decodeExecutionSourceIdentity(input.source.identity),
|
|
49
|
+
...(input.source.extensions ? { extensions: input.source.extensions } : {}),
|
|
50
|
+
});
|
|
51
51
|
}
|
|
52
52
|
export function createInlineResolvedCommand(input) {
|
|
53
|
-
|
|
54
|
-
assertOnlyKeys(record, ["template", "argumentInput", "content"], "inline resolved command input");
|
|
55
|
-
const template = requireOwn(record, "template", "inline resolved command input");
|
|
56
|
-
const content = requireOwn(record, "content", "inline resolved command input");
|
|
57
|
-
if (typeof template !== "string" || typeof content !== "string") {
|
|
53
|
+
if (typeof input.template !== "string" || typeof input.content !== "string") {
|
|
58
54
|
throw new TypeError("inline command template and content must be strings");
|
|
59
55
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
return Object.freeze({
|
|
57
|
+
template: input.template,
|
|
58
|
+
...(input.argumentInput !== undefined ? { argumentInput: input.argumentInput } : {}),
|
|
59
|
+
content: input.content,
|
|
60
|
+
source: null,
|
|
61
|
+
});
|
|
63
62
|
}
|
|
64
63
|
export function createResolvedPersona(source) {
|
|
65
|
-
|
|
66
|
-
throw new TypeError("source must be an adapter-rendered persona source");
|
|
67
|
-
}
|
|
68
|
-
const out = {
|
|
64
|
+
return Object.freeze({
|
|
69
65
|
content: source.content,
|
|
70
|
-
source:
|
|
71
|
-
...(source.extensions
|
|
72
|
-
|
|
73
|
-
: {}),
|
|
74
|
-
};
|
|
75
|
-
return defineBrand(out, resolvedPersonaBrand, resolvedPersonaInstances);
|
|
76
|
-
}
|
|
77
|
-
function hasOwnFrozenBrand(value, brand, instances) {
|
|
78
|
-
if (typeof value !== "object" ||
|
|
79
|
-
value === null ||
|
|
80
|
-
!instances.has(value) ||
|
|
81
|
-
Object.getPrototypeOf(value) !== Object.prototype ||
|
|
82
|
-
!Object.isFrozen(value) ||
|
|
83
|
-
!Object.hasOwn(value, brand)) {
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
const descriptor = Object.getOwnPropertyDescriptor(value, brand);
|
|
87
|
-
return (descriptor?.value === true &&
|
|
88
|
-
descriptor.enumerable === false &&
|
|
89
|
-
descriptor.configurable === false &&
|
|
90
|
-
descriptor.writable === false);
|
|
91
|
-
}
|
|
92
|
-
function isResolvedCommand(value) {
|
|
93
|
-
if (!hasOwnFrozenBrand(value, resolvedCommandBrand, resolvedCommandInstances))
|
|
94
|
-
return false;
|
|
95
|
-
try {
|
|
96
|
-
const allowedSymbols = new Set([resolvedCommandBrand]);
|
|
97
|
-
const record = requireObject(value, "command", allowedSymbols);
|
|
98
|
-
assertOnlyKeys(record, ["template", "argumentInput", "content", "source", "extensions"], "command", allowedSymbols);
|
|
99
|
-
const template = requireOwn(record, "template", "command");
|
|
100
|
-
const content = requireOwn(record, "content", "command");
|
|
101
|
-
const source = requireOwn(record, "source", "command");
|
|
102
|
-
if (typeof template !== "string" || typeof content !== "string")
|
|
103
|
-
return false;
|
|
104
|
-
if (Object.hasOwn(record, "argumentInput") && typeof record.argumentInput !== "string")
|
|
105
|
-
return false;
|
|
106
|
-
if (source !== null)
|
|
107
|
-
decodeExecutionSourceIdentity(source, "command.source");
|
|
108
|
-
if (Object.hasOwn(record, "extensions"))
|
|
109
|
-
cloneAdapterExtensions(record.extensions, "command.extensions");
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
112
|
-
catch {
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
function isResolvedPersona(value) {
|
|
117
|
-
if (!hasOwnFrozenBrand(value, resolvedPersonaBrand, resolvedPersonaInstances))
|
|
118
|
-
return false;
|
|
119
|
-
try {
|
|
120
|
-
const allowedSymbols = new Set([resolvedPersonaBrand]);
|
|
121
|
-
const record = requireObject(value, "persona", allowedSymbols);
|
|
122
|
-
assertOnlyKeys(record, ["content", "source", "extensions"], "persona", allowedSymbols);
|
|
123
|
-
if (typeof requireOwn(record, "content", "persona") !== "string")
|
|
124
|
-
return false;
|
|
125
|
-
decodeExecutionSourceIdentity(requireOwn(record, "source", "persona"), "persona.source");
|
|
126
|
-
if (Object.hasOwn(record, "extensions"))
|
|
127
|
-
cloneAdapterExtensions(record.extensions, "persona.extensions");
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
catch {
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
function requireString(value, path) {
|
|
135
|
-
if (typeof value !== "string" || value.length === 0)
|
|
136
|
-
throw new TypeError(`${path} must be a non-empty string`);
|
|
137
|
-
return value;
|
|
138
|
-
}
|
|
139
|
-
function cloneEngine(input) {
|
|
140
|
-
const record = requireObject(input, "engine");
|
|
141
|
-
assertOnlyKeys(record, ["name", "kind", "platform", "settings", "extensions"], "engine");
|
|
142
|
-
const name = requireString(requireOwn(record, "name", "engine"), "engine.name");
|
|
143
|
-
const kind = requireOwn(record, "kind", "engine");
|
|
144
|
-
if (!(kind === "agent" || kind === "sdk" || kind === "llm"))
|
|
145
|
-
throw new TypeError("engine.kind is invalid");
|
|
146
|
-
const out = { name, kind };
|
|
147
|
-
for (const key of ["platform", "settings", "extensions"]) {
|
|
148
|
-
if (!Object.hasOwn(record, key))
|
|
149
|
-
continue;
|
|
150
|
-
const value = record[key];
|
|
151
|
-
if (value === undefined)
|
|
152
|
-
throw new TypeError(`engine.${key} must be omitted rather than undefined`);
|
|
153
|
-
if (key === "platform") {
|
|
154
|
-
if (value !== null && typeof value !== "string")
|
|
155
|
-
throw new TypeError("engine.platform must be a string or null");
|
|
156
|
-
out.platform = value;
|
|
157
|
-
}
|
|
158
|
-
else if (key === "settings") {
|
|
159
|
-
out.settings = value === null ? null : cloneExecutionJsonObject(value, "engine.settings");
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
out.extensions = cloneAdapterExtensions(value, "engine.extensions");
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return Object.freeze(out);
|
|
166
|
-
}
|
|
167
|
-
function cloneModel(input) {
|
|
168
|
-
const record = requireObject(input, "model");
|
|
169
|
-
assertOnlyKeys(record, ["input", "interpretation", "resolved", "extensions"], "model");
|
|
170
|
-
const modelInput = requireString(requireOwn(record, "input", "model"), "model.input");
|
|
171
|
-
const interpretation = requireOwn(record, "interpretation", "model");
|
|
172
|
-
const resolved = requireString(requireOwn(record, "resolved", "model"), "model.resolved");
|
|
173
|
-
if (interpretation !== "alias" && interpretation !== "exact") {
|
|
174
|
-
throw new TypeError("model.interpretation is invalid");
|
|
175
|
-
}
|
|
176
|
-
if (interpretation === "exact" && modelInput !== resolved) {
|
|
177
|
-
throw new TypeError("model.input must match model.resolved when interpretation is exact");
|
|
178
|
-
}
|
|
179
|
-
const out = {
|
|
180
|
-
input: modelInput,
|
|
181
|
-
interpretation,
|
|
182
|
-
resolved,
|
|
183
|
-
};
|
|
184
|
-
if (Object.hasOwn(record, "extensions")) {
|
|
185
|
-
if (record.extensions === null || record.extensions === undefined) {
|
|
186
|
-
throw new TypeError("model.extensions must be omitted or an adapter-owned extension object");
|
|
187
|
-
}
|
|
188
|
-
out.extensions = cloneAdapterExtensions(record.extensions, "model.extensions");
|
|
189
|
-
}
|
|
190
|
-
return Object.freeze(out);
|
|
191
|
-
}
|
|
192
|
-
function cloneAuthorization(input) {
|
|
193
|
-
const record = requireObject(input, "authorization");
|
|
194
|
-
assertOnlyKeys(record, ["status", "reason", "policy"], "authorization");
|
|
195
|
-
const status = requireOwn(record, "status", "authorization");
|
|
196
|
-
if (!(status === "allowed" || status === "denied" || status === "not-required")) {
|
|
197
|
-
throw new TypeError("authorization.status is invalid");
|
|
198
|
-
}
|
|
199
|
-
const out = { status };
|
|
200
|
-
if (Object.hasOwn(record, "reason")) {
|
|
201
|
-
if (record.reason !== null && typeof record.reason !== "string") {
|
|
202
|
-
throw new TypeError("authorization.reason must be a string or null");
|
|
203
|
-
}
|
|
204
|
-
out.reason = record.reason;
|
|
205
|
-
}
|
|
206
|
-
if (Object.hasOwn(record, "policy")) {
|
|
207
|
-
out.policy = record.policy === null ? null : cloneExecutionJsonObject(record.policy, "authorization.policy");
|
|
208
|
-
}
|
|
209
|
-
return Object.freeze(out);
|
|
210
|
-
}
|
|
211
|
-
function cloneRuntime(input) {
|
|
212
|
-
const record = requireObject(input, "runtime");
|
|
213
|
-
assertOnlyKeys(record, ["timeoutMs", "workspace", "environment", "settings", "extensions"], "runtime");
|
|
214
|
-
const out = {};
|
|
215
|
-
if (Object.hasOwn(record, "timeoutMs")) {
|
|
216
|
-
const timeoutMs = record.timeoutMs;
|
|
217
|
-
if (timeoutMs !== null &&
|
|
218
|
-
(typeof timeoutMs !== "number" ||
|
|
219
|
-
!Number.isInteger(timeoutMs) ||
|
|
220
|
-
timeoutMs < 0 ||
|
|
221
|
-
timeoutMs > EXECUTION_MAX_TIMEOUT_MS)) {
|
|
222
|
-
throw new TypeError(`runtime.timeoutMs must be null or an integer from 0 through ${EXECUTION_MAX_TIMEOUT_MS}`);
|
|
223
|
-
}
|
|
224
|
-
out.timeoutMs = timeoutMs;
|
|
225
|
-
}
|
|
226
|
-
if (Object.hasOwn(record, "workspace")) {
|
|
227
|
-
if (record.workspace !== null && typeof record.workspace !== "string") {
|
|
228
|
-
throw new TypeError("runtime.workspace must be a string or null");
|
|
229
|
-
}
|
|
230
|
-
out.workspace = record.workspace;
|
|
231
|
-
}
|
|
232
|
-
if (Object.hasOwn(record, "environment")) {
|
|
233
|
-
if (record.environment === null)
|
|
234
|
-
out.environment = null;
|
|
235
|
-
else {
|
|
236
|
-
const environment = cloneExecutionJsonObject(record.environment, "runtime.environment");
|
|
237
|
-
if (Object.values(environment).some((value) => typeof value !== "string")) {
|
|
238
|
-
throw new TypeError("runtime.environment values must be strings");
|
|
239
|
-
}
|
|
240
|
-
out.environment = environment;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
if (Object.hasOwn(record, "settings")) {
|
|
244
|
-
out.settings = record.settings === null ? null : cloneExecutionJsonObject(record.settings, "runtime.settings");
|
|
245
|
-
}
|
|
246
|
-
if (Object.hasOwn(record, "extensions")) {
|
|
247
|
-
out.extensions = cloneAdapterExtensions(record.extensions, "runtime.extensions");
|
|
248
|
-
}
|
|
249
|
-
return Object.freeze(out);
|
|
250
|
-
}
|
|
251
|
-
function cloneNotice(input, index) {
|
|
252
|
-
const path = `notices[${index}]`;
|
|
253
|
-
const record = requireObject(input, path);
|
|
254
|
-
assertOnlyKeys(record, ["code", "severity", "adapter", "field", "message", "details"], path);
|
|
255
|
-
const code = requireString(requireOwn(record, "code", path), `${path}.code`);
|
|
256
|
-
const severity = requireOwn(record, "severity", path);
|
|
257
|
-
const adapter = requireString(requireOwn(record, "adapter", path), `${path}.adapter`);
|
|
258
|
-
const message = requireString(requireOwn(record, "message", path), `${path}.message`);
|
|
259
|
-
if (severity !== "info" && severity !== "warning") {
|
|
260
|
-
throw new TypeError(`notices[${index}].severity is invalid`);
|
|
261
|
-
}
|
|
262
|
-
const out = {
|
|
263
|
-
code,
|
|
264
|
-
severity,
|
|
265
|
-
adapter,
|
|
266
|
-
message,
|
|
267
|
-
};
|
|
268
|
-
if (Object.hasOwn(record, "field")) {
|
|
269
|
-
if (record.field !== null && typeof record.field !== "string") {
|
|
270
|
-
throw new TypeError(`notices[${index}].field must be a string or null`);
|
|
271
|
-
}
|
|
272
|
-
out.field = record.field;
|
|
273
|
-
}
|
|
274
|
-
if (Object.hasOwn(record, "details")) {
|
|
275
|
-
out.details = record.details === null ? null : cloneExecutionJsonObject(record.details, `${path}.details`);
|
|
276
|
-
}
|
|
277
|
-
return Object.freeze(out);
|
|
278
|
-
}
|
|
279
|
-
function cloneConversation(input, path = "conversation") {
|
|
280
|
-
const cloned = cloneExecutionJson(input, path);
|
|
281
|
-
if (!Array.isArray(cloned))
|
|
282
|
-
throw new TypeError(`${path} must be an array`);
|
|
283
|
-
return Object.freeze(cloned.map((message, index) => {
|
|
284
|
-
const messagePath = `${path}[${index}]`;
|
|
285
|
-
const record = requireObject(message, messagePath);
|
|
286
|
-
assertOnlyKeys(record, ["role", "content"], messagePath);
|
|
287
|
-
const role = requireOwn(record, "role", messagePath);
|
|
288
|
-
const content = requireOwn(record, "content", messagePath);
|
|
289
|
-
if (role !== "system" && role !== "user" && role !== "assistant") {
|
|
290
|
-
throw new TypeError(`${messagePath}.role must be system, user, or assistant`);
|
|
291
|
-
}
|
|
292
|
-
if (typeof content !== "string")
|
|
293
|
-
throw new TypeError(`${messagePath}.content must be a string`);
|
|
294
|
-
return Object.freeze({ role, content });
|
|
295
|
-
}));
|
|
296
|
-
}
|
|
297
|
-
function cloneResolvedCommandLeaf(input) {
|
|
298
|
-
if (!isResolvedCommand(input))
|
|
299
|
-
throw new TypeError("command must be constructed by the execution boundary");
|
|
300
|
-
const allowedSymbols = new Set([resolvedCommandBrand]);
|
|
301
|
-
const record = requireObject(input, "command", allowedSymbols);
|
|
302
|
-
assertOnlyKeys(record, ["template", "argumentInput", "content", "source", "extensions"], "command", allowedSymbols);
|
|
303
|
-
const template = requireOwn(record, "template", "command");
|
|
304
|
-
const content = requireOwn(record, "content", "command");
|
|
305
|
-
const source = requireOwn(record, "source", "command");
|
|
306
|
-
if (typeof template !== "string" || typeof content !== "string") {
|
|
307
|
-
throw new TypeError("command template and content must be strings");
|
|
308
|
-
}
|
|
309
|
-
const out = {
|
|
310
|
-
template,
|
|
311
|
-
content,
|
|
312
|
-
source: source === null ? null : decodeExecutionSourceIdentity(source, "command.source"),
|
|
313
|
-
};
|
|
314
|
-
copyArgumentInput(record, out);
|
|
315
|
-
if (Object.hasOwn(record, "extensions")) {
|
|
316
|
-
out.extensions = cloneAdapterExtensions(record.extensions, "command.extensions");
|
|
317
|
-
}
|
|
318
|
-
return defineBrand(out, resolvedCommandBrand, resolvedCommandInstances);
|
|
319
|
-
}
|
|
320
|
-
function cloneResolvedPersonaLeaf(input) {
|
|
321
|
-
if (!isResolvedPersona(input))
|
|
322
|
-
throw new TypeError("persona must be constructed by the execution boundary");
|
|
323
|
-
const allowedSymbols = new Set([resolvedPersonaBrand]);
|
|
324
|
-
const record = requireObject(input, "persona", allowedSymbols);
|
|
325
|
-
assertOnlyKeys(record, ["content", "source", "extensions"], "persona", allowedSymbols);
|
|
326
|
-
const content = requireOwn(record, "content", "persona");
|
|
327
|
-
if (typeof content !== "string")
|
|
328
|
-
throw new TypeError("persona.content must be a string");
|
|
329
|
-
const out = {
|
|
330
|
-
content,
|
|
331
|
-
source: decodeExecutionSourceIdentity(requireOwn(record, "source", "persona"), "persona.source"),
|
|
332
|
-
};
|
|
333
|
-
if (Object.hasOwn(record, "extensions")) {
|
|
334
|
-
out.extensions = cloneAdapterExtensions(record.extensions, "persona.extensions");
|
|
335
|
-
}
|
|
336
|
-
return defineBrand(out, resolvedPersonaBrand, resolvedPersonaInstances);
|
|
337
|
-
}
|
|
338
|
-
/** Revalidate and detach one command leaf before any caller dereferences it. */
|
|
339
|
-
export function cloneResolvedCommandContent(input) {
|
|
340
|
-
return cloneResolvedCommandLeaf(input);
|
|
341
|
-
}
|
|
342
|
-
/** Revalidate and detach one persona leaf before any caller dereferences it. */
|
|
343
|
-
export function cloneResolvedPersonaContent(input) {
|
|
344
|
-
return cloneResolvedPersonaLeaf(input);
|
|
345
|
-
}
|
|
346
|
-
function cloneAgentSelector(input, path) {
|
|
347
|
-
if (input === null)
|
|
348
|
-
return null;
|
|
349
|
-
return requireStableExecutionSelector(input, path);
|
|
350
|
-
}
|
|
351
|
-
function assertAgentPersonaInvariant(request, path) {
|
|
352
|
-
if (!Object.hasOwn(request, "agent"))
|
|
353
|
-
return;
|
|
354
|
-
if (!Object.hasOwn(request, "persona")) {
|
|
355
|
-
throw new TypeError(`${path}.persona must be present when ${path}.agent is selected or explicitly null`);
|
|
356
|
-
}
|
|
357
|
-
const agent = request.agent;
|
|
358
|
-
const persona = request.persona;
|
|
359
|
-
if (agent === null) {
|
|
360
|
-
if (persona !== null)
|
|
361
|
-
throw new TypeError(`${path}.agent null requires ${path}.persona null`);
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
if (isPortableExecutionAgentSelector(agent)) {
|
|
365
|
-
if (persona === null || !executionPersonaMatchesSelector(agent, persona.source.ref)) {
|
|
366
|
-
throw new TypeError(`${path}.agent portable selector must match the non-null persona source`);
|
|
367
|
-
}
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
if (persona !== null) {
|
|
371
|
-
throw new TypeError(`${path}.agent native selector requires ${path}.persona null`);
|
|
372
|
-
}
|
|
66
|
+
source: decodeExecutionSourceIdentity(source.identity),
|
|
67
|
+
...(source.extensions ? { extensions: source.extensions } : {}),
|
|
68
|
+
});
|
|
373
69
|
}
|
|
374
|
-
/**
|
|
70
|
+
/** Freeze one request without normalizing away optional-field presence. */
|
|
375
71
|
export function createResolvedExecutionRequest(input) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
"command",
|
|
379
|
-
"conversation",
|
|
380
|
-
"agent",
|
|
381
|
-
"persona",
|
|
382
|
-
"engine",
|
|
383
|
-
"model",
|
|
384
|
-
"inference",
|
|
385
|
-
"outputSchema",
|
|
386
|
-
"tools",
|
|
387
|
-
"authorization",
|
|
388
|
-
"runtime",
|
|
389
|
-
"notices",
|
|
390
|
-
"extensions",
|
|
391
|
-
], "resolved execution request input");
|
|
392
|
-
const command = requireOwn(record, "command", "resolved execution request input");
|
|
393
|
-
const engine = requireOwn(record, "engine", "resolved execution request input");
|
|
394
|
-
const authorization = requireOwn(record, "authorization", "resolved execution request input");
|
|
395
|
-
const runtime = requireOwn(record, "runtime", "resolved execution request input");
|
|
396
|
-
const notices = requireOwn(record, "notices", "resolved execution request input");
|
|
397
|
-
if (!isResolvedCommand(command))
|
|
398
|
-
throw new TypeError("command must be constructed by the execution boundary");
|
|
399
|
-
const clonedNotices = cloneExecutionJson(notices, "notices");
|
|
400
|
-
if (!Array.isArray(clonedNotices))
|
|
401
|
-
throw new TypeError("notices must be an array");
|
|
402
|
-
const out = {
|
|
403
|
-
schemaVersion: RESOLVED_EXECUTION_SCHEMA_VERSION,
|
|
404
|
-
command: cloneResolvedCommandLeaf(command),
|
|
405
|
-
engine: cloneEngine(engine),
|
|
406
|
-
authorization: cloneAuthorization(authorization),
|
|
407
|
-
runtime: cloneRuntime(runtime),
|
|
408
|
-
notices: Object.freeze(clonedNotices.map((notice, index) => cloneNotice(notice, index))),
|
|
409
|
-
};
|
|
410
|
-
if (Object.hasOwn(record, "conversation"))
|
|
411
|
-
out.conversation = cloneConversation(record.conversation);
|
|
412
|
-
if (Object.hasOwn(record, "agent")) {
|
|
413
|
-
if (record.agent === undefined)
|
|
414
|
-
throw new TypeError("agent must be omitted, null, or a selected agent string");
|
|
415
|
-
out.agent = cloneAgentSelector(record.agent, "agent");
|
|
416
|
-
}
|
|
417
|
-
if (Object.hasOwn(record, "persona")) {
|
|
418
|
-
if (record.persona !== null && !isResolvedPersona(record.persona)) {
|
|
419
|
-
throw new TypeError("persona must be null or constructed by the execution boundary");
|
|
420
|
-
}
|
|
421
|
-
out.persona = record.persona === null ? null : cloneResolvedPersonaLeaf(record.persona);
|
|
422
|
-
}
|
|
423
|
-
assertAgentPersonaInvariant(out, "resolved execution request");
|
|
424
|
-
if (Object.hasOwn(record, "model")) {
|
|
425
|
-
if (record.model === undefined)
|
|
426
|
-
throw new TypeError("model must be omitted, null, or a model selection");
|
|
427
|
-
out.model = record.model === null ? null : cloneModel(record.model);
|
|
428
|
-
}
|
|
429
|
-
if (Object.hasOwn(record, "inference")) {
|
|
430
|
-
out.inference = record.inference === null ? null : cloneExecutionJsonObject(record.inference, "inference");
|
|
431
|
-
}
|
|
432
|
-
if (Object.hasOwn(record, "outputSchema")) {
|
|
433
|
-
out.outputSchema =
|
|
434
|
-
record.outputSchema === null ? null : cloneExecutionJsonObject(record.outputSchema, "outputSchema");
|
|
435
|
-
}
|
|
436
|
-
if (Object.hasOwn(record, "tools"))
|
|
437
|
-
out.tools = cloneToolSelection(record.tools, "tools");
|
|
438
|
-
const toolsRequireAuthorization = toolSelectionRequiresAuthorization(out.tools, Object.hasOwn(out, "tools"));
|
|
439
|
-
const authorizationStatus = out.authorization.status;
|
|
440
|
-
if (toolsRequireAuthorization && authorizationStatus === "not-required") {
|
|
441
|
-
throw new TypeError("authorization.status not-required is valid only when no tools are selected");
|
|
442
|
-
}
|
|
443
|
-
if (!toolsRequireAuthorization && authorizationStatus !== "not-required") {
|
|
444
|
-
throw new TypeError("empty or omitted tool selection requires authorization.status not-required");
|
|
445
|
-
}
|
|
446
|
-
if (Object.hasOwn(record, "extensions")) {
|
|
447
|
-
out.extensions = cloneAdapterExtensions(record.extensions, "request.extensions");
|
|
448
|
-
}
|
|
449
|
-
const frozen = Object.freeze(out);
|
|
450
|
-
resolvedRequestInstances.add(frozen);
|
|
451
|
-
return frozen;
|
|
452
|
-
}
|
|
453
|
-
function toolSelectionRequiresAuthorization(value, present) {
|
|
454
|
-
// WP1's transport-level invariant is intentionally syntax based: omitted,
|
|
455
|
-
// null, "", [], and {} are the only empty spellings. Adapters/resolvers own
|
|
456
|
-
// any format-specific normalization before they construct this request.
|
|
457
|
-
if (!present || value === null)
|
|
458
|
-
return false;
|
|
459
|
-
if (typeof value === "string")
|
|
460
|
-
return value.length > 0;
|
|
461
|
-
if (Array.isArray(value))
|
|
462
|
-
return value.length > 0;
|
|
463
|
-
return typeof value === "object" && value !== null && Object.keys(value).length > 0;
|
|
464
|
-
}
|
|
465
|
-
function requireObject(value, path, allowedSymbols = new Set()) {
|
|
466
|
-
return snapshotStrictRecord(value, path, { allowedSymbols });
|
|
467
|
-
}
|
|
468
|
-
function assertOnlyKeys(value, allowed, path, allowedSymbols = new Set()) {
|
|
469
|
-
assertSnapshotKeys(value, allowed, path, allowedSymbols);
|
|
470
|
-
}
|
|
471
|
-
function requireOwn(value, key, path) {
|
|
472
|
-
return requireSnapshotField(value, key, path);
|
|
473
|
-
}
|
|
474
|
-
function decodeExtensions(value, path) {
|
|
475
|
-
return cloneAdapterExtensions(requireObject(value, path), path);
|
|
476
|
-
}
|
|
477
|
-
function decodeResolvedCommand(value) {
|
|
478
|
-
const input = requireObject(value, "command");
|
|
479
|
-
assertOnlyKeys(input, ["template", "argumentInput", "content", "source", "extensions"], "command");
|
|
480
|
-
const template = requireOwn(input, "template", "command");
|
|
481
|
-
const content = requireOwn(input, "content", "command");
|
|
482
|
-
const source = requireOwn(input, "source", "command");
|
|
483
|
-
if (typeof template !== "string" || typeof content !== "string") {
|
|
484
|
-
throw new TypeError("command template and content must be strings");
|
|
72
|
+
if (!input.command || !input.engine || !input.authorization || !input.runtime || !input.notices) {
|
|
73
|
+
throw new TypeError("resolved execution request requires command, engine, authorization, runtime, and notices");
|
|
485
74
|
}
|
|
486
75
|
const out = {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
76
|
+
schemaVersion: RESOLVED_EXECUTION_SCHEMA_VERSION,
|
|
77
|
+
command: input.command,
|
|
78
|
+
engine: input.engine,
|
|
79
|
+
authorization: input.authorization,
|
|
80
|
+
runtime: input.runtime,
|
|
81
|
+
notices: input.notices,
|
|
82
|
+
...pick(input, OPTIONAL_REQUEST_KEYS),
|
|
490
83
|
};
|
|
491
|
-
|
|
492
|
-
if (typeof input.argumentInput !== "string")
|
|
493
|
-
throw new TypeError("command.argumentInput must be a string");
|
|
494
|
-
out.argumentInput = input.argumentInput;
|
|
495
|
-
}
|
|
496
|
-
if (Object.hasOwn(input, "extensions"))
|
|
497
|
-
out.extensions = decodeExtensions(input.extensions, "command.extensions");
|
|
498
|
-
return defineBrand(out, resolvedCommandBrand, resolvedCommandInstances);
|
|
499
|
-
}
|
|
500
|
-
function decodeResolvedPersona(value) {
|
|
501
|
-
const input = requireObject(value, "persona");
|
|
502
|
-
assertOnlyKeys(input, ["content", "source", "extensions"], "persona");
|
|
503
|
-
const content = requireOwn(input, "content", "persona");
|
|
504
|
-
if (typeof content !== "string")
|
|
505
|
-
throw new TypeError("persona.content must be a string");
|
|
506
|
-
const source = decodeExecutionSourceIdentity(requireOwn(input, "source", "persona"), "persona.source");
|
|
507
|
-
const out = { content, source };
|
|
508
|
-
if (Object.hasOwn(input, "extensions"))
|
|
509
|
-
out.extensions = decodeExtensions(input.extensions, "persona.extensions");
|
|
510
|
-
return defineBrand(out, resolvedPersonaBrand, resolvedPersonaInstances);
|
|
511
|
-
}
|
|
512
|
-
function decodeEngine(value) {
|
|
513
|
-
const input = requireObject(value, "engine");
|
|
514
|
-
assertOnlyKeys(input, ["name", "kind", "platform", "settings", "extensions"], "engine");
|
|
515
|
-
requireOwn(input, "name", "engine");
|
|
516
|
-
requireOwn(input, "kind", "engine");
|
|
517
|
-
return cloneEngine(input);
|
|
518
|
-
}
|
|
519
|
-
function decodeModel(value) {
|
|
520
|
-
const input = requireObject(value, "model");
|
|
521
|
-
assertOnlyKeys(input, ["input", "interpretation", "resolved", "extensions"], "model");
|
|
522
|
-
for (const key of ["input", "interpretation", "resolved"])
|
|
523
|
-
requireOwn(input, key, "model");
|
|
524
|
-
return cloneModel(input);
|
|
525
|
-
}
|
|
526
|
-
function decodeAuthorization(value) {
|
|
527
|
-
const input = requireObject(value, "authorization");
|
|
528
|
-
assertOnlyKeys(input, ["status", "reason", "policy"], "authorization");
|
|
529
|
-
requireOwn(input, "status", "authorization");
|
|
530
|
-
return cloneAuthorization(input);
|
|
531
|
-
}
|
|
532
|
-
function decodeRuntime(value) {
|
|
533
|
-
const input = requireObject(value, "runtime");
|
|
534
|
-
assertOnlyKeys(input, ["timeoutMs", "workspace", "environment", "settings", "extensions"], "runtime");
|
|
535
|
-
return cloneRuntime(input);
|
|
536
|
-
}
|
|
537
|
-
function decodeNotice(value, index) {
|
|
538
|
-
const input = requireObject(value, `notices[${index}]`);
|
|
539
|
-
assertOnlyKeys(input, ["code", "severity", "adapter", "field", "message", "details"], `notices[${index}]`);
|
|
540
|
-
for (const key of ["code", "severity", "adapter", "message"])
|
|
541
|
-
requireOwn(input, key, `notices[${index}]`);
|
|
542
|
-
return cloneNotice(input, index);
|
|
84
|
+
return Object.freeze(out);
|
|
543
85
|
}
|
|
544
86
|
/**
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
* been validated; raw/frontmatter lookalike fields are rejected as unknown.
|
|
87
|
+
* Rehydrate a frozen JSON request after workflow resume/replay. Tolerant of
|
|
88
|
+
* unknown keys; refuses only a request written by a newer schema.
|
|
548
89
|
*/
|
|
549
90
|
export function decodeResolvedExecutionRequest(value) {
|
|
550
|
-
const input =
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
"
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
"
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
"
|
|
564
|
-
"notices",
|
|
565
|
-
"extensions",
|
|
566
|
-
], "resolved execution request");
|
|
567
|
-
if (requireOwn(input, "schemaVersion", "resolved execution request") !== RESOLVED_EXECUTION_SCHEMA_VERSION) {
|
|
568
|
-
throw new TypeError(`unsupported resolved execution schemaVersion: ${String(input.schemaVersion)}`);
|
|
91
|
+
const input = requireRecord(value, "resolved execution request");
|
|
92
|
+
const version = input.schemaVersion;
|
|
93
|
+
if (version !== RESOLVED_EXECUTION_SCHEMA_VERSION) {
|
|
94
|
+
throw new TypeError(typeof version === "number" && version > RESOLVED_EXECUTION_SCHEMA_VERSION
|
|
95
|
+
? `resolved execution request schemaVersion ${version} was written by a newer akm; upgrade akm to run it`
|
|
96
|
+
: `unsupported resolved execution schemaVersion: ${String(version)}`);
|
|
97
|
+
}
|
|
98
|
+
const command = requireRecord(input.command, "command");
|
|
99
|
+
if (typeof command.template !== "string" || typeof command.content !== "string") {
|
|
100
|
+
throw new TypeError("command template and content must be strings");
|
|
101
|
+
}
|
|
102
|
+
const engine = requireRecord(input.engine, "engine");
|
|
103
|
+
if (typeof engine.name !== "string" || (engine.kind !== "agent" && engine.kind !== "sdk" && engine.kind !== "llm")) {
|
|
104
|
+
throw new TypeError("engine.name must be a string and engine.kind must be agent, sdk, or llm");
|
|
569
105
|
}
|
|
570
|
-
const notices =
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
throw new TypeError("resolved execution request.notices must be an array");
|
|
106
|
+
const notices = input.notices;
|
|
107
|
+
if (!Array.isArray(notices))
|
|
108
|
+
throw new TypeError("notices must be an array");
|
|
574
109
|
const request = {
|
|
575
|
-
command:
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
110
|
+
command: Object.freeze({
|
|
111
|
+
...pick(command, COMMAND_KEYS),
|
|
112
|
+
source: command.source === null ? null : decodeExecutionSourceIdentity(command.source, "command.source"),
|
|
113
|
+
}),
|
|
114
|
+
engine: Object.freeze(pick(engine, ENGINE_KEYS)),
|
|
115
|
+
authorization: Object.freeze(pick(requireRecord(input.authorization, "authorization"), AUTHORIZATION_KEYS)),
|
|
116
|
+
runtime: Object.freeze(pick(requireRecord(input.runtime, "runtime"), RUNTIME_KEYS)),
|
|
117
|
+
notices: Object.freeze(notices.map((notice, index) => Object.freeze(pick(requireRecord(notice, `notices[${index}]`), NOTICE_KEYS)))),
|
|
580
118
|
};
|
|
581
|
-
if (
|
|
582
|
-
request.conversation =
|
|
119
|
+
if (Array.isArray(input.conversation)) {
|
|
120
|
+
request.conversation = Object.freeze(input.conversation.map((message, index) => Object.freeze(pick(requireRecord(message, `conversation[${index}]`), ["role", "content"]))));
|
|
121
|
+
}
|
|
122
|
+
if (Object.hasOwn(input, "agent") && input.agent !== undefined)
|
|
123
|
+
request.agent = input.agent;
|
|
124
|
+
if (Object.hasOwn(input, "persona") && input.persona !== undefined) {
|
|
125
|
+
if (input.persona === null)
|
|
126
|
+
request.persona = null;
|
|
127
|
+
else {
|
|
128
|
+
const persona = requireRecord(input.persona, "persona");
|
|
129
|
+
request.persona = Object.freeze({
|
|
130
|
+
...pick(persona, PERSONA_KEYS),
|
|
131
|
+
source: decodeExecutionSourceIdentity(persona.source, "persona.source"),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
583
134
|
}
|
|
584
|
-
if (Object.hasOwn(input, "
|
|
585
|
-
request.
|
|
135
|
+
if (Object.hasOwn(input, "model") && input.model !== undefined) {
|
|
136
|
+
request.model = input.model === null ? null : Object.freeze(pick(requireRecord(input.model, "model"), MODEL_KEYS));
|
|
586
137
|
}
|
|
587
|
-
|
|
588
|
-
|
|
138
|
+
for (const key of ["inference", "outputSchema", "tools", "extensions"]) {
|
|
139
|
+
if (Object.hasOwn(input, key) && input[key] !== undefined)
|
|
140
|
+
request[key] = input[key];
|
|
589
141
|
}
|
|
590
|
-
if (Object.hasOwn(input, "model"))
|
|
591
|
-
request.model = input.model === null ? null : decodeModel(input.model);
|
|
592
|
-
if (Object.hasOwn(input, "inference"))
|
|
593
|
-
request.inference = input.inference;
|
|
594
|
-
if (Object.hasOwn(input, "outputSchema"))
|
|
595
|
-
request.outputSchema = input.outputSchema;
|
|
596
|
-
if (Object.hasOwn(input, "tools"))
|
|
597
|
-
request.tools = input.tools;
|
|
598
|
-
if (Object.hasOwn(input, "extensions"))
|
|
599
|
-
request.extensions = decodeExtensions(input.extensions, "request.extensions");
|
|
600
142
|
return createResolvedExecutionRequest(request);
|
|
601
143
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
bundle: identity.bundle,
|
|
606
|
-
adapter: identity.adapter,
|
|
607
|
-
file: identity.file,
|
|
608
|
-
hash: identity.hash,
|
|
609
|
-
};
|
|
610
|
-
}
|
|
611
|
-
function projectCommand(command) {
|
|
612
|
-
const out = {
|
|
613
|
-
template: command.template,
|
|
614
|
-
content: command.content,
|
|
615
|
-
source: command.source === null ? null : projectIdentity(command.source),
|
|
616
|
-
};
|
|
617
|
-
if (Object.hasOwn(command, "argumentInput"))
|
|
618
|
-
out.argumentInput = command.argumentInput;
|
|
619
|
-
if (Object.hasOwn(command, "extensions"))
|
|
620
|
-
out.extensions = command.extensions;
|
|
621
|
-
return out;
|
|
622
|
-
}
|
|
623
|
-
function projectPersona(persona) {
|
|
624
|
-
const out = { content: persona.content, source: projectIdentity(persona.source) };
|
|
625
|
-
if (Object.hasOwn(persona, "extensions"))
|
|
626
|
-
out.extensions = persona.extensions;
|
|
627
|
-
return out;
|
|
628
|
-
}
|
|
629
|
-
function projectEngine(engine) {
|
|
630
|
-
const out = { name: engine.name, kind: engine.kind };
|
|
631
|
-
for (const key of ["platform", "settings", "extensions"]) {
|
|
632
|
-
if (Object.hasOwn(engine, key))
|
|
633
|
-
out[key] = engine[key];
|
|
634
|
-
}
|
|
635
|
-
return out;
|
|
636
|
-
}
|
|
637
|
-
function projectModel(model) {
|
|
638
|
-
const out = {
|
|
639
|
-
input: model.input,
|
|
640
|
-
interpretation: model.interpretation,
|
|
641
|
-
resolved: model.resolved,
|
|
642
|
-
};
|
|
643
|
-
if (Object.hasOwn(model, "extensions"))
|
|
644
|
-
out.extensions = model.extensions;
|
|
645
|
-
return out;
|
|
646
|
-
}
|
|
647
|
-
function projectAuthorization(authorization) {
|
|
648
|
-
const out = { status: authorization.status };
|
|
649
|
-
for (const key of ["reason", "policy"]) {
|
|
650
|
-
if (Object.hasOwn(authorization, key))
|
|
651
|
-
out[key] = authorization[key];
|
|
652
|
-
}
|
|
653
|
-
return out;
|
|
654
|
-
}
|
|
655
|
-
function projectRuntime(runtime) {
|
|
656
|
-
const out = {};
|
|
657
|
-
for (const key of ["timeoutMs", "workspace", "environment", "settings", "extensions"]) {
|
|
658
|
-
if (Object.hasOwn(runtime, key))
|
|
659
|
-
out[key] = runtime[key];
|
|
660
|
-
}
|
|
661
|
-
return out;
|
|
662
|
-
}
|
|
663
|
-
function projectNotice(notice) {
|
|
664
|
-
const out = {
|
|
665
|
-
code: notice.code,
|
|
666
|
-
severity: notice.severity,
|
|
667
|
-
adapter: notice.adapter,
|
|
668
|
-
message: notice.message,
|
|
669
|
-
};
|
|
670
|
-
for (const key of ["field", "details"]) {
|
|
671
|
-
if (Object.hasOwn(notice, key))
|
|
672
|
-
out[key] = notice[key];
|
|
673
|
-
}
|
|
674
|
-
return out;
|
|
675
|
-
}
|
|
676
|
-
function projectConversationMessage(message) {
|
|
677
|
-
return { role: message.role, content: message.content };
|
|
678
|
-
}
|
|
679
|
-
function projectResolvedExecutionWire(request) {
|
|
680
|
-
const out = {
|
|
144
|
+
/** Stable bytes for freeze hashes and entrypoint-equivalence projections. */
|
|
145
|
+
export function canonicalResolvedExecutionRequest(request) {
|
|
146
|
+
const wire = {
|
|
681
147
|
schemaVersion: RESOLVED_EXECUTION_SCHEMA_VERSION,
|
|
682
|
-
command:
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
148
|
+
command: {
|
|
149
|
+
...pick(request.command, COMMAND_KEYS),
|
|
150
|
+
source: request.command.source === null ? null : pick(request.command.source, IDENTITY_KEYS),
|
|
151
|
+
},
|
|
152
|
+
engine: pick(request.engine, ENGINE_KEYS),
|
|
153
|
+
authorization: pick(request.authorization, AUTHORIZATION_KEYS),
|
|
154
|
+
runtime: pick(request.runtime, RUNTIME_KEYS),
|
|
155
|
+
notices: request.notices.map((notice) => pick(notice, NOTICE_KEYS)),
|
|
687
156
|
};
|
|
688
|
-
if (
|
|
689
|
-
|
|
690
|
-
throw new TypeError("constructed request conversation cannot be undefined");
|
|
691
|
-
}
|
|
692
|
-
out.conversation = request.conversation.map(projectConversationMessage);
|
|
693
|
-
}
|
|
694
|
-
if (Object.hasOwn(request, "agent")) {
|
|
695
|
-
if (request.agent === undefined)
|
|
696
|
-
throw new TypeError("constructed request agent cannot be undefined");
|
|
697
|
-
out.agent = request.agent;
|
|
157
|
+
if (request.conversation !== undefined) {
|
|
158
|
+
wire.conversation = request.conversation.map((message) => ({ role: message.role, content: message.content }));
|
|
698
159
|
}
|
|
699
|
-
if (Object.hasOwn(request, "
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
160
|
+
if (Object.hasOwn(request, "agent") && request.agent !== undefined)
|
|
161
|
+
wire.agent = request.agent;
|
|
162
|
+
if (Object.hasOwn(request, "persona") && request.persona !== undefined) {
|
|
163
|
+
wire.persona =
|
|
164
|
+
request.persona === null
|
|
165
|
+
? null
|
|
166
|
+
: { ...pick(request.persona, PERSONA_KEYS), source: pick(request.persona.source, IDENTITY_KEYS) };
|
|
703
167
|
}
|
|
704
|
-
if (Object.hasOwn(request, "model")) {
|
|
705
|
-
|
|
706
|
-
throw new TypeError("constructed request model cannot be undefined");
|
|
707
|
-
out.model = request.model === null ? null : projectModel(request.model);
|
|
168
|
+
if (Object.hasOwn(request, "model") && request.model !== undefined) {
|
|
169
|
+
wire.model = request.model === null ? null : pick(request.model, MODEL_KEYS);
|
|
708
170
|
}
|
|
709
171
|
for (const key of ["inference", "outputSchema", "tools", "extensions"]) {
|
|
710
|
-
if (Object.hasOwn(request, key))
|
|
711
|
-
|
|
712
|
-
}
|
|
713
|
-
return out;
|
|
714
|
-
}
|
|
715
|
-
function encodeResolvedExecutionWire(request) {
|
|
716
|
-
const json = cloneExecutionJson(projectResolvedExecutionWire(request), "resolved execution request wire DTO");
|
|
717
|
-
return `${JSON.stringify(sortExecutionJson(json))}\n`;
|
|
718
|
-
}
|
|
719
|
-
/** Stable bytes for freeze hashes and entrypoint-equivalence projections. */
|
|
720
|
-
export function canonicalResolvedExecutionRequest(request) {
|
|
721
|
-
if (typeof request !== "object" || request === null || !resolvedRequestInstances.has(request)) {
|
|
722
|
-
throw new TypeError("resolved execution request must be constructed by the execution boundary");
|
|
723
|
-
}
|
|
724
|
-
const canonical = encodeResolvedExecutionWire(request);
|
|
725
|
-
const decoded = decodeResolvedExecutionRequest(JSON.parse(canonical));
|
|
726
|
-
if (encodeResolvedExecutionWire(decoded) !== canonical) {
|
|
727
|
-
throw new TypeError("resolved execution request failed canonical decode/re-encode validation");
|
|
172
|
+
if (Object.hasOwn(request, key) && request[key] !== undefined)
|
|
173
|
+
wire[key] = request[key];
|
|
728
174
|
}
|
|
729
|
-
return
|
|
175
|
+
return `${JSON.stringify(sortExecutionJson(wire))}\n`;
|
|
730
176
|
}
|