UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

74 lines (73 loc) • 5.28 kB
import { readArtifactHostCapabilities } from "../artifact-host.js"; import { ARTIFACT_TOOL_NAME } from "../tool-catalog-entries.js"; import { deliverEngineNotice } from "../engine-notice.js"; import { RosterBuilder } from "../tool-roster.js"; import { defineTool } from "../tools.js"; import { inlineUntrusted } from "../untrusted-text.js"; import { physicalPathOfExisting } from "../physical-path.js"; import { resolveKey, violationDetails, violationText } from "../../tools/fs/safety.js"; import { rootAdmittingArtifactStore, withdrawStandingGrantsAdmitting } from "./read-root-grant.js"; import { emitTrace } from "../trace.js"; import { createArtifactTool } from "../../tools/artifact/artifact-tool.js"; import { thrownText } from "../thrown-value.js"; export function prepareArtifact(input) { const { deps, runId, taskId, sessionId, agentName, onAsk, permissionMode, executionEnv, rootCanonical, additionalRootsCanonical, readDenyMatcher, resolvedReadFace, handsCwdRef, roster, firstPartyOffload, envHandToolNames, artifactStoreRef } = input; const host = deps.artifactHost; if (host === undefined) return { artifactPlane: undefined }; const refuse = (problem) => { deliverEngineNotice(deps.onNotice, { code: "config.artifact_host_invalid", message: `RunnerDeps.artifactHost is wired but unusable, so no Artifact tool is mounted for this task: ${problem}`, detail: { problem, sessionId, runId }, }); return { artifactPlane: undefined }; }; const verdict = readArtifactHostCapabilities(host); if (!verdict.ok) return refuse(verdict.problem); const storageDir = verdict.capabilities.storageDir; const storePhysical = storageDir !== undefined && rootCanonical !== undefined ? physicalPathOfExisting(storageDir) : undefined; if (artifactStoreRef !== undefined) artifactStoreRef.current = storePhysical; if (artifactStoreRef !== undefined && storePhysical !== undefined) { for (const entry of withdrawStandingGrantsAdmitting(storePhysical, artifactStoreRef)) { emitTrace(deps.tracer, () => ({ kind: "config.additional_directory_skipped", version: 1, taskId, entry, field: "persistedReadRule", reason: `admits_artifact_store: the local artifact store ${storageDir} lies inside it or it inside the store — the Artifact tool's ledger and stored files stay outside every root the file tools reach`, ts: Date.now() })); } } if (storePhysical !== undefined && rootCanonical !== undefined) { const overlapping = rootAdmittingArtifactStore(storePhysical, [rootCanonical, ...additionalRootsCanonical()]); if (overlapping !== undefined) return refuse(`the local artifact store ${storageDir} and a root this run may reach through its file tools (${overlapping}) overlap — the store lies inside a root, or the root inside the store; put the store outside every task root and additional directory`); } try { host.onMount?.(runId); } catch (err) { return refuse(`artifactHost.onMount threw: ${thrownText(err)}`); } const readLocalFile = async (path, maxBytes, signal) => { if (rootCanonical === undefined) return { ok: false, reason: "refused", text: "Error (Artifact): this task has no filesystem root, so a local file cannot be published." }; const rk = await resolveKey(executionEnv, rootCanonical, path, signal, handsCwdRef?.current, additionalRootsCanonical, undefined, readDenyMatcher, resolvedReadFace); if (!rk.ok) return { ok: false, reason: "refused", text: violationText("Artifact", rk.violation), details: violationDetails(rk.violation) }; const meta = await executionEnv.fileInfo(rk.key, signal); if (!meta.ok) return { ok: false, reason: "refused", text: `Error (Artifact): cannot stat ${inlineUntrusted(path, 200)} (${inlineUntrusted(meta.error.code, 40)}).` }; if (meta.value.kind !== "file") return { ok: false, reason: "not_a_file", kind: meta.value.kind }; if (meta.value.size > maxBytes) return { ok: false, reason: "too_large", size: meta.value.size, limit: maxBytes, judgedOn: "metadata" }; const r = await executionEnv.readBinaryFile(rk.key, signal); if (!r.ok) return { ok: false, reason: "refused", text: `Error (Artifact): cannot read ${inlineUntrusted(path, 200)} (${inlineUntrusted(r.error.code, 40)}).` }; if (r.value.byteLength > maxBytes) return { ok: false, reason: "too_large", size: r.value.byteLength, limit: maxBytes, judgedOn: "bytes" }; return { ok: true, key: rk.key, bytes: r.value }; }; const artifactSpec = createArtifactTool({ host, capabilities: verdict.capabilities, runId, taskId, sessionId, ...(agentName !== undefined ? { agentName } : {}), readLocalFile, ...(onAsk !== undefined ? { onAsk } : {}), permissionMode: () => permissionMode.current, ...(deps.onNotice !== undefined ? { onNotice: deps.onNotice } : {}) }); roster.mount(firstPartyOffload(defineTool(artifactSpec)), { source: "builtin", mountedBy: "optional" }); envHandToolNames.add(ARTIFACT_TOOL_NAME); return { artifactPlane: verdict.capabilities.plane }; }