UNPKG

akm-cli

Version:

akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cur

177 lines (176 loc) • 8.42 kB
// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. import { sortExecutionJson } from "./json.js"; import { decodeExecutionSourceIdentity, } from "./source.js"; export const RESOLVED_EXECUTION_SCHEMA_VERSION = 1; const COMMAND_KEYS = ["template", "argumentInput", "content", "source", "extensions"]; const PERSONA_KEYS = ["content", "source", "extensions"]; const ENGINE_KEYS = ["name", "kind", "platform", "settings", "extensions"]; const MODEL_KEYS = ["input", "interpretation", "resolved", "extensions"]; const AUTHORIZATION_KEYS = ["status", "reason", "policy"]; const RUNTIME_KEYS = ["timeoutMs", "workspace", "environment", "settings", "extensions"]; const NOTICE_KEYS = ["code", "severity", "adapter", "field", "message", "details"]; const IDENTITY_KEYS = ["ref", "bundle", "adapter", "file", "hash"]; const OPTIONAL_REQUEST_KEYS = [ "conversation", "agent", "persona", "model", "inference", "outputSchema", "tools", "extensions", ]; /** Copy the own, defined fields named by `keys`; omitted stays omitted, `null` stays `null`. */ function pick(value, keys) { const record = value; const out = {}; for (const key of keys) { if (Object.hasOwn(record, key) && record[key] !== undefined) out[key] = record[key]; } return out; } function requireRecord(value, path) { if (value === null || typeof value !== "object" || Array.isArray(value)) { throw new TypeError(`${path} must be an object`); } return value; } export function createResolvedCommand(input) { if (typeof input.content !== "string") throw new TypeError("resolved command content must be a string"); return Object.freeze({ template: input.source.content, ...(input.argumentInput !== undefined ? { argumentInput: input.argumentInput } : {}), content: input.content, source: decodeExecutionSourceIdentity(input.source.identity), ...(input.source.extensions ? { extensions: input.source.extensions } : {}), }); } export function createInlineResolvedCommand(input) { if (typeof input.template !== "string" || typeof input.content !== "string") { throw new TypeError("inline command template and content must be strings"); } return Object.freeze({ template: input.template, ...(input.argumentInput !== undefined ? { argumentInput: input.argumentInput } : {}), content: input.content, source: null, }); } export function createResolvedPersona(source) { return Object.freeze({ content: source.content, source: decodeExecutionSourceIdentity(source.identity), ...(source.extensions ? { extensions: source.extensions } : {}), }); } /** Freeze one request without normalizing away optional-field presence. */ export function createResolvedExecutionRequest(input) { if (!input.command || !input.engine || !input.authorization || !input.runtime || !input.notices) { throw new TypeError("resolved execution request requires command, engine, authorization, runtime, and notices"); } const out = { schemaVersion: RESOLVED_EXECUTION_SCHEMA_VERSION, command: input.command, engine: input.engine, authorization: input.authorization, runtime: input.runtime, notices: input.notices, ...pick(input, OPTIONAL_REQUEST_KEYS), }; return Object.freeze(out); } /** * Rehydrate a frozen JSON request after workflow resume/replay. Tolerant of * unknown keys; refuses only a request written by a newer schema. */ export function decodeResolvedExecutionRequest(value) { const input = requireRecord(value, "resolved execution request"); const version = input.schemaVersion; if (version !== RESOLVED_EXECUTION_SCHEMA_VERSION) { throw new TypeError(typeof version === "number" && version > RESOLVED_EXECUTION_SCHEMA_VERSION ? `resolved execution request schemaVersion ${version} was written by a newer akm; upgrade akm to run it` : `unsupported resolved execution schemaVersion: ${String(version)}`); } const command = requireRecord(input.command, "command"); if (typeof command.template !== "string" || typeof command.content !== "string") { throw new TypeError("command template and content must be strings"); } const engine = requireRecord(input.engine, "engine"); if (typeof engine.name !== "string" || (engine.kind !== "agent" && engine.kind !== "sdk" && engine.kind !== "llm")) { throw new TypeError("engine.name must be a string and engine.kind must be agent, sdk, or llm"); } const notices = input.notices; if (!Array.isArray(notices)) throw new TypeError("notices must be an array"); const request = { command: Object.freeze({ ...pick(command, COMMAND_KEYS), source: command.source === null ? null : decodeExecutionSourceIdentity(command.source, "command.source"), }), engine: Object.freeze(pick(engine, ENGINE_KEYS)), authorization: Object.freeze(pick(requireRecord(input.authorization, "authorization"), AUTHORIZATION_KEYS)), runtime: Object.freeze(pick(requireRecord(input.runtime, "runtime"), RUNTIME_KEYS)), notices: Object.freeze(notices.map((notice, index) => Object.freeze(pick(requireRecord(notice, `notices[${index}]`), NOTICE_KEYS)))), }; if (Array.isArray(input.conversation)) { request.conversation = Object.freeze(input.conversation.map((message, index) => Object.freeze(pick(requireRecord(message, `conversation[${index}]`), ["role", "content"])))); } if (Object.hasOwn(input, "agent") && input.agent !== undefined) request.agent = input.agent; if (Object.hasOwn(input, "persona") && input.persona !== undefined) { if (input.persona === null) request.persona = null; else { const persona = requireRecord(input.persona, "persona"); request.persona = Object.freeze({ ...pick(persona, PERSONA_KEYS), source: decodeExecutionSourceIdentity(persona.source, "persona.source"), }); } } if (Object.hasOwn(input, "model") && input.model !== undefined) { request.model = input.model === null ? null : Object.freeze(pick(requireRecord(input.model, "model"), MODEL_KEYS)); } for (const key of ["inference", "outputSchema", "tools", "extensions"]) { if (Object.hasOwn(input, key) && input[key] !== undefined) request[key] = input[key]; } return createResolvedExecutionRequest(request); } /** Stable bytes for freeze hashes and entrypoint-equivalence projections. */ export function canonicalResolvedExecutionRequest(request) { const wire = { schemaVersion: RESOLVED_EXECUTION_SCHEMA_VERSION, command: { ...pick(request.command, COMMAND_KEYS), source: request.command.source === null ? null : pick(request.command.source, IDENTITY_KEYS), }, engine: pick(request.engine, ENGINE_KEYS), authorization: pick(request.authorization, AUTHORIZATION_KEYS), runtime: pick(request.runtime, RUNTIME_KEYS), notices: request.notices.map((notice) => pick(notice, NOTICE_KEYS)), }; if (request.conversation !== undefined) { wire.conversation = request.conversation.map((message) => ({ role: message.role, content: message.content })); } if (Object.hasOwn(request, "agent") && request.agent !== undefined) wire.agent = request.agent; if (Object.hasOwn(request, "persona") && request.persona !== undefined) { wire.persona = request.persona === null ? null : { ...pick(request.persona, PERSONA_KEYS), source: pick(request.persona.source, IDENTITY_KEYS) }; } if (Object.hasOwn(request, "model") && request.model !== undefined) { wire.model = request.model === null ? null : pick(request.model, MODEL_KEYS); } for (const key of ["inference", "outputSchema", "tools", "extensions"]) { if (Object.hasOwn(request, key) && request[key] !== undefined) wire[key] = request[key]; } return `${JSON.stringify(sortExecutionJson(wire))}\n`; }