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

79 lines (78 loc) • 3.96 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/. /** * The gate judge built from the step's frozen judge target. Its outcome is * journaled (the gate row, or a blocked step's notes), so it goes through the * same dispatch redaction as every unit; its dispatch carries the real * run/step and gate unit ids the gate row records. A judge carries no `env:` * bindings (a step's environment belongs to the work, not the verifier). */ import { warn } from "../../core/warn.js"; import { collectWorkflowDispatchSensitiveValues, withDispatchRedaction } from "./dispatch-redaction.js"; import { dispatchWorkflowExecution, prepareWorkflowExecution, } from "./unit-dispatch.js"; /** The gate's node id — identical to what `journalGateEvaluationStart` writes. */ export function gateNodeId(stepId) { return `${stepId}.gate`; } /** Identity for one judge dispatch: the caller's row identity, else the run/step with the gate node id. */ function dispatchIdentity(owner, identity) { return identity ?? { ...owner, unitId: gateNodeId(owner.stepId) }; } function warnLoweringNotices(...groups) { const emitted = new Set(); for (const notices of groups) { for (const notice of notices ?? []) { const key = JSON.stringify([notice.code, notice.severity, notice.adapter, notice.field, notice.message]); if (emitted.has(key)) continue; emitted.add(key); warn(`Workflow judge lowering notice (${notice.code}; ${notice.adapter}; ${notice.field}): ${notice.message}`); } } } /** Build a gate judge from the frozen target without consulting live config; `eventSource` stamps it like a unit. */ export function frozenSummaryJudge(target, signal, dispatcher, owner, eventSource) { if (!target) return null; const dispatch = withDispatchRedaction(dispatcher ?? dispatchWorkflowExecution); return async ({ system, user }, identity) => { const id = dispatchIdentity(owner, identity); const commonRequest = { runId: id.runId, stepId: id.stepId, unitId: id.unitId, nodeId: gateNodeId(id.stepId), ...(id.attempt !== undefined ? { attempt: id.attempt } : {}), ...(id.dispatchId !== undefined ? { dispatchId: id.dispatchId } : {}), prompt: user, systemPrompt: system, ...(signal ? { signal } : {}), }; const request = { ...commonRequest, frozenTarget: target, timeoutMs: target.runner.timeoutMs ?? null, ...(eventSource !== undefined ? { eventSource } : {}), }; // Lowering and authorization precede every live credential/passthrough // sample. The injected dispatcher may be a test seam, but it receives the // exact same already-validated request and redaction declaration. const lowered = prepareWorkflowExecution(request); const sensitiveValues = collectWorkflowDispatchSensitiveValues({ runner: target.runner }, undefined); const outcome = await dispatch({ ...request, ...(sensitiveValues.length > 0 ? { sensitiveValues } : {}), }); if (outcome.usage && id.recordTokens) { id.recordTokens((outcome.usage.inputTokens ?? 0) + (outcome.usage.outputTokens ?? 0) + (outcome.usage.reasoningTokens ?? 0)); } // Only the common lowerer's own sanitized notices are loggable here. An // injected dispatcher is not trusted to supply prompt/body-free messages. warnLoweringNotices(lowered.notices); if (!outcome.ok) { throw new Error(outcome.error || `Verification engine "${target.request.engine.name}" failed.`); } return outcome.text ?? ""; }; }