UNPKG

@beignet/core

Version:

Core framework primitives for Beignet

282 lines 10.9 kB
import { createProviderInstrumentation, } from "../providers/index.js"; import { runWithResolvedTracingContext } from "../tracing/execution.js"; /** Bind application context and principal types once for capability definitions. */ export function createAgentCapabilities() { return { defineAgentCapability(name, options) { return { kind: "agentCapability", name, description: options.description, input: options.input, output: options.output, handle: options.handle, }; }, defineAgentCapabilityRegistry, }; } /** Error thrown when a capability registry is ambiguous. */ export class AgentCapabilityRegistryError extends Error { constructor(message) { super(message); this.name = "AgentCapabilityRegistryError"; } } /** Build a capability registry and reject duplicate external names. */ function defineAgentCapabilityRegistry(definitions) { const byName = new Map(); for (const capability of definitions) { if (byName.has(capability.name)) { throw new AgentCapabilityRegistryError(`Duplicate agent capability definition "${capability.name}" in registry.`); } byName.set(capability.name, capability); } return { definitions: [...definitions], get(name) { return byName.get(name); }, }; } /** Error raised by capability lookup, validation, or execution. */ export class AgentCapabilityError extends Error { code; capabilityName; issues; cause; constructor(args) { super(args.message); this.name = "AgentCapabilityError"; this.code = args.code; this.capabilityName = args.capabilityName; this.issues = args.issues; this.cause = args.cause; } } function formatPath(path) { if (!path?.length) return ""; return path .map((segment) => typeof segment === "object" && segment !== null && "key" in segment ? String(segment.key) : String(segment)) .join("."); } function formatIssues(issues) { return issues .map((issue) => { const path = formatPath(issue.path); return path ? `${path}: ${issue.message}` : issue.message; }) .join("; "); } async function parseCapabilitySchema(schema, input, args) { const result = await schema["~standard"].validate(input); if (result.issues?.length) { throw new AgentCapabilityError({ code: args.code, capabilityName: args.capabilityName, message: `Agent capability "${args.capabilityName}" ${args.code === "invalid_input" ? "input" : "output"} validation failed: ${formatIssues(result.issues)}`, issues: result.issues, }); } if ("value" in result) { return result.value; } throw new AgentCapabilityError({ code: args.code, capabilityName: args.capabilityName, message: `Agent capability "${args.capabilityName}" schema returned no value.`, }); } function instrumentationTarget(ctx) { if (!ctx || typeof ctx !== "object") return undefined; if ("ports" in ctx) { return ctx.ports; } return ctx; } async function notifyHooks(hooks, event) { await Promise.all(hooks.map(async (hook) => { try { await hook(event); } catch { // Observers must not alter application behavior. } })); } /** Create a validated, traced executor for a capability registry. */ export function createAgentCapabilityExecutor(options) { const hooks = options.hooks ?? []; const instrumentationConfig = { providerName: "agent-capabilities", watcher: "agentCapabilities", }; async function executeDynamic(invocation) { const startedAt = Date.now(); let stage = "lookup"; let ctx; let capability; let input; let hasValidatedInput = false; let instrumentation = createProviderInstrumentation(options.instrumentation, instrumentationConfig); try { capability = options.registry.get(invocation.name); const observedName = capability?.name ?? "unknown"; instrumentation.custom({ name: "agentCapability.started", label: `Agent capability ${observedName}`, summary: "Capability execution started", details: { capabilityName: observedName, phase: "start" }, }); await notifyHooks(hooks, { name: invocation.name, phase: "start", stage, principal: invocation.principal, }); if (!capability) { throw new AgentCapabilityError({ code: "unknown_capability", capabilityName: invocation.name, message: `Unknown agent capability "${invocation.name}".`, }); } const registeredCapability = capability; const runtimeCapability = registeredCapability; return await runWithResolvedTracingContext({ tracing: options.tracing, ctx: async () => { stage = "input"; input = await parseCapabilitySchema(runtimeCapability.input, invocation.input, { capabilityName: runtimeCapability.name, code: "invalid_input", }); hasValidatedInput = true; if (invocation.authorize) { stage = "authorization"; await invocation.authorize({ capability: registeredCapability, name: registeredCapability.name, principal: invocation.principal, input, }); } stage = "context"; ctx = await options.createContext({ capability: registeredCapability, name: registeredCapability.name, principal: invocation.principal, input, }); return ctx; }, operation: { name: `beignet.agent_capability ${registeredCapability.name}`, type: "agentCapability", kind: "internal", attributes: { "beignet.agent_capability.name": registeredCapability.name, }, metricAttributes: { "beignet.agent_capability.name": registeredCapability.name, }, }, async run(resolvedCtx) { ctx = resolvedCtx; if (options.instrumentation === undefined) { instrumentation = createProviderInstrumentation(instrumentationTarget(ctx), instrumentationConfig); instrumentation.custom({ name: "agentCapability.started", label: `Agent capability ${registeredCapability.name}`, summary: "Capability execution started", details: { capabilityName: registeredCapability.name, phase: "start", }, }); } stage = "handler"; const rawOutput = await runtimeCapability.handle({ capability: runtimeCapability, ctx, principal: invocation.principal, input, }); stage = "output"; const output = await parseCapabilitySchema(runtimeCapability.output, rawOutput, { capabilityName: registeredCapability.name, code: "invalid_output", }); const durationMs = Date.now() - startedAt; instrumentation.custom({ name: "agentCapability.completed", label: `Agent capability ${registeredCapability.name}`, summary: "Capability execution completed", details: { capabilityName: registeredCapability.name, phase: "end", durationMs, }, }); await notifyHooks(hooks, { name: registeredCapability.name, phase: "end", stage, capability: registeredCapability, ctx, principal: invocation.principal, input, output, durationMs, }); return output; }, }); } catch (error) { const wrapped = error instanceof AgentCapabilityError ? error : new AgentCapabilityError({ code: "execution_failed", capabilityName: capability?.name ?? invocation.name, message: `Agent capability "${capability?.name ?? invocation.name}" execution failed.`, cause: error, }); const durationMs = Date.now() - startedAt; const observedName = capability?.name ?? "unknown"; instrumentation.custom({ name: "agentCapability.failed", label: `Agent capability ${observedName}`, summary: "Capability execution failed", details: { capabilityName: observedName, phase: "error", stage, durationMs, code: wrapped.code, }, }); await notifyHooks(hooks, { name: invocation.name, phase: "error", stage, ...(capability ? { capability } : {}), ctx, principal: invocation.principal, durationMs, error: wrapped, ...(hasValidatedInput ? { input } : {}), }); throw wrapped; } } return { execute: executeDynamic, executeDynamic, }; } //# sourceMappingURL=index.js.map