@sema-agent/core
Version:
Stateless, task-oriented AI agent core
51 lines (50 loc) • 3.4 kB
TypeScript
/**
* The READ station of the file tools (Read / Grep / Glob) — the read face's twin of the shell read station, one gate
* input shape ({@link ShellReadCheck}) so the gate, the approved-edit re-judge and the resumed leg's belt read both:
* before approval, where the call's declared path target lands is resolved exactly as the tool will resolve it
* (`resolveKey` over the same spelling, base, roots, deny table and containment face), and a target OUTSIDE the read
* roots is an ORDINARY question — a person answers it, a persisted `Read(//dir/**)` row or the auto-mode classifier
* may, a permission mode arbitrates it — with the directory whose grant clears it on the card. The deny table and
* every other refusal stay the tool's own: this station judges containment only, after the deny judgment.
*
* A call whose out-of-root read the gate put to a question is ADMITTED for that one target when the gate applies the
* verdict ({@link ShellReadVerdict.admit}): the tool reads it once ({@link FileReadStation.admitted}), on the canonical
* key the station judged — a target that resolves elsewhere by then is refused by the tool's own fence, and a verdict
* the gate never received (its wait elapsed, the judgment threw) admits nothing.
*/
import type { ExecutionEnv } from "../../internal/harness-types.js";
import type { ContainmentFace } from "./containment-face.js";
import { type ReadDenyMatcher } from "./read-deny.js";
import { type ShellReadCheck } from "./shell-read-check.js";
export interface FileReadStation {
readonly check: ShellReadCheck;
/** The station's membership: the tool names whose declared read target it judges. */
readonly tools: ReadonlySet<string>;
/** Did the gate put THIS call's read of `canonicalKey` outside the roots to a question it then let through? Consumed
* on a match: the admission covers one read of one target. */
readonly admitted: (toolCallId: string | undefined, canonicalKey: string) => boolean;
}
export interface FileReadStationOptions {
readonly env: ExecutionEnv;
readonly rootCanonical: string;
/** The extra read roots, read per call (a grant widens the live set). */
readonly roots: () => readonly string[];
readonly readDeny?: ReadDenyMatcher;
readonly readFace?: ContainmentFace;
readonly homeDir?: string;
/** The file tools this leg mounts (their catalog path target is the one judged). */
readonly tools: ReadonlySet<string>;
/** A target no answer may admit (the store-isolation rule's judgment, `rootAdmittingArtifactStore`): it is left to
* the tool's own refusal, no question is raised for it. */
readonly excluded?: (canonicalKey: string) => boolean;
/** A target the tools' own fence admits without the roots (the engine's background output file,
* `backgroundOutputReadExemption`): no question is put for it. */
readonly exempt?: (canonicalKey: string) => boolean;
}
export declare function createFileReadStation(opts: FileReadStationOptions): FileReadStation;
/** One gate input over the leg's read stations: each call is judged by the station whose membership holds the first of
* its names any station holds (the spelling first). */
export declare function composeReadChecks(stations: ReadonlyArray<{
readonly check: ShellReadCheck;
readonly tools: ReadonlySet<string>;
}>): ShellReadCheck | undefined;