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,730 @@
|
|
|
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 { cloneExecutionJson, cloneExecutionJsonObject, sortExecutionJson } from "./json.js";
|
|
5
|
+
import { EXECUTION_MAX_TIMEOUT_MS } from "./limits.js";
|
|
6
|
+
import { assertSnapshotKeys, requireSnapshotField, snapshotStrictRecord } from "./record.js";
|
|
7
|
+
import { cloneAdapterExtensions, cloneToolSelection, decodeExecutionSourceIdentity, executionPersonaMatchesSelector, isAdapterRenderedCommandSource, isAdapterRenderedPersonaSource, isPortableExecutionAgentSelector, requireStableExecutionSelector, } from "./source.js";
|
|
8
|
+
export const RESOLVED_EXECUTION_SCHEMA_VERSION = 1;
|
|
9
|
+
const resolvedCommandBrand = Symbol("akm.resolved-command");
|
|
10
|
+
const resolvedPersonaBrand = Symbol("akm.resolved-persona");
|
|
11
|
+
const resolvedCommandInstances = new WeakSet();
|
|
12
|
+
const resolvedPersonaInstances = new WeakSet();
|
|
13
|
+
const resolvedRequestInstances = new WeakSet();
|
|
14
|
+
function defineBrand(value, brand, instances) {
|
|
15
|
+
Object.defineProperty(value, brand, { value: true, enumerable: false });
|
|
16
|
+
const frozen = Object.freeze(value);
|
|
17
|
+
instances.add(frozen);
|
|
18
|
+
return frozen;
|
|
19
|
+
}
|
|
20
|
+
function cloneIdentity(value) {
|
|
21
|
+
return decodeExecutionSourceIdentity(value);
|
|
22
|
+
}
|
|
23
|
+
function copyArgumentInput(input, output) {
|
|
24
|
+
if (!Object.hasOwn(input, "argumentInput"))
|
|
25
|
+
return;
|
|
26
|
+
if (typeof input.argumentInput !== "string") {
|
|
27
|
+
throw new TypeError("command argumentInput must be omitted or a string");
|
|
28
|
+
}
|
|
29
|
+
output.argumentInput = input.argumentInput;
|
|
30
|
+
}
|
|
31
|
+
export function createResolvedCommand(input) {
|
|
32
|
+
const record = requireObject(input, "resolved command input");
|
|
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")
|
|
40
|
+
throw new TypeError("resolved command content must be a string");
|
|
41
|
+
const out = {
|
|
42
|
+
template: source.content,
|
|
43
|
+
content,
|
|
44
|
+
source: cloneIdentity(source.identity),
|
|
45
|
+
...(source.extensions
|
|
46
|
+
? { extensions: cloneAdapterExtensions(source.extensions, "resolved command extensions") }
|
|
47
|
+
: {}),
|
|
48
|
+
};
|
|
49
|
+
copyArgumentInput(record, out);
|
|
50
|
+
return defineBrand(out, resolvedCommandBrand, resolvedCommandInstances);
|
|
51
|
+
}
|
|
52
|
+
export function createInlineResolvedCommand(input) {
|
|
53
|
+
const record = requireObject(input, "inline resolved command input");
|
|
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") {
|
|
58
|
+
throw new TypeError("inline command template and content must be strings");
|
|
59
|
+
}
|
|
60
|
+
const out = { template, content, source: null };
|
|
61
|
+
copyArgumentInput(record, out);
|
|
62
|
+
return defineBrand(out, resolvedCommandBrand, resolvedCommandInstances);
|
|
63
|
+
}
|
|
64
|
+
export function createResolvedPersona(source) {
|
|
65
|
+
if (!isAdapterRenderedPersonaSource(source)) {
|
|
66
|
+
throw new TypeError("source must be an adapter-rendered persona source");
|
|
67
|
+
}
|
|
68
|
+
const out = {
|
|
69
|
+
content: source.content,
|
|
70
|
+
source: cloneIdentity(source.identity),
|
|
71
|
+
...(source.extensions
|
|
72
|
+
? { extensions: cloneAdapterExtensions(source.extensions, "resolved persona extensions") }
|
|
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
|
+
}
|
|
373
|
+
}
|
|
374
|
+
/** Validate and freeze one request without normalizing away optional-field presence. */
|
|
375
|
+
export function createResolvedExecutionRequest(input) {
|
|
376
|
+
const record = requireObject(input, "resolved execution request input");
|
|
377
|
+
assertOnlyKeys(record, [
|
|
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");
|
|
485
|
+
}
|
|
486
|
+
const out = {
|
|
487
|
+
template,
|
|
488
|
+
content,
|
|
489
|
+
source: source === null ? null : decodeExecutionSourceIdentity(source, "command.source"),
|
|
490
|
+
};
|
|
491
|
+
if (Object.hasOwn(input, "argumentInput")) {
|
|
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);
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Strictly rehydrate a frozen JSON request after workflow resume/replay.
|
|
546
|
+
* Symbol construction brands are restored only after every wire field has
|
|
547
|
+
* been validated; raw/frontmatter lookalike fields are rejected as unknown.
|
|
548
|
+
*/
|
|
549
|
+
export function decodeResolvedExecutionRequest(value) {
|
|
550
|
+
const input = requireObject(value, "resolved execution request");
|
|
551
|
+
assertOnlyKeys(input, [
|
|
552
|
+
"schemaVersion",
|
|
553
|
+
"command",
|
|
554
|
+
"conversation",
|
|
555
|
+
"agent",
|
|
556
|
+
"persona",
|
|
557
|
+
"engine",
|
|
558
|
+
"model",
|
|
559
|
+
"inference",
|
|
560
|
+
"outputSchema",
|
|
561
|
+
"tools",
|
|
562
|
+
"authorization",
|
|
563
|
+
"runtime",
|
|
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)}`);
|
|
569
|
+
}
|
|
570
|
+
const notices = requireOwn(input, "notices", "resolved execution request");
|
|
571
|
+
const clonedNotices = cloneExecutionJson(notices, "resolved execution request.notices");
|
|
572
|
+
if (!Array.isArray(clonedNotices))
|
|
573
|
+
throw new TypeError("resolved execution request.notices must be an array");
|
|
574
|
+
const request = {
|
|
575
|
+
command: decodeResolvedCommand(requireOwn(input, "command", "resolved execution request")),
|
|
576
|
+
engine: decodeEngine(requireOwn(input, "engine", "resolved execution request")),
|
|
577
|
+
authorization: decodeAuthorization(requireOwn(input, "authorization", "resolved execution request")),
|
|
578
|
+
runtime: decodeRuntime(requireOwn(input, "runtime", "resolved execution request")),
|
|
579
|
+
notices: clonedNotices.map(decodeNotice),
|
|
580
|
+
};
|
|
581
|
+
if (Object.hasOwn(input, "conversation")) {
|
|
582
|
+
request.conversation = cloneConversation(input.conversation, "resolved execution request.conversation");
|
|
583
|
+
}
|
|
584
|
+
if (Object.hasOwn(input, "agent")) {
|
|
585
|
+
request.agent = cloneAgentSelector(input.agent, "resolved execution request.agent");
|
|
586
|
+
}
|
|
587
|
+
if (Object.hasOwn(input, "persona")) {
|
|
588
|
+
request.persona = input.persona === null ? null : decodeResolvedPersona(input.persona);
|
|
589
|
+
}
|
|
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
|
+
return createResolvedExecutionRequest(request);
|
|
601
|
+
}
|
|
602
|
+
function projectIdentity(identity) {
|
|
603
|
+
return {
|
|
604
|
+
ref: identity.ref,
|
|
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 = {
|
|
681
|
+
schemaVersion: RESOLVED_EXECUTION_SCHEMA_VERSION,
|
|
682
|
+
command: projectCommand(request.command),
|
|
683
|
+
engine: projectEngine(request.engine),
|
|
684
|
+
authorization: projectAuthorization(request.authorization),
|
|
685
|
+
runtime: projectRuntime(request.runtime),
|
|
686
|
+
notices: request.notices.map(projectNotice),
|
|
687
|
+
};
|
|
688
|
+
if (Object.hasOwn(request, "conversation")) {
|
|
689
|
+
if (request.conversation === undefined) {
|
|
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;
|
|
698
|
+
}
|
|
699
|
+
if (Object.hasOwn(request, "persona")) {
|
|
700
|
+
if (request.persona === undefined)
|
|
701
|
+
throw new TypeError("constructed request persona cannot be undefined");
|
|
702
|
+
out.persona = request.persona === null ? null : projectPersona(request.persona);
|
|
703
|
+
}
|
|
704
|
+
if (Object.hasOwn(request, "model")) {
|
|
705
|
+
if (request.model === undefined)
|
|
706
|
+
throw new TypeError("constructed request model cannot be undefined");
|
|
707
|
+
out.model = request.model === null ? null : projectModel(request.model);
|
|
708
|
+
}
|
|
709
|
+
for (const key of ["inference", "outputSchema", "tools", "extensions"]) {
|
|
710
|
+
if (Object.hasOwn(request, key))
|
|
711
|
+
out[key] = request[key];
|
|
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");
|
|
728
|
+
}
|
|
729
|
+
return canonical;
|
|
730
|
+
}
|