@sema-agent/core
Version:
Stateless, task-oriented AI agent core
46 lines (45 loc) • 2.8 kB
TypeScript
/**
* The task root's CANONICAL spelling — and the one loud outlet for a host that hands in another one.
*
* Containment is judged on the canonical form: the roots fence resolves every target through the same
* `ExecutionEnv` and compares canonical keys, the shell read boundary compares a command's words
* against the declared roots, and every refusal message quotes them. A deployment that hands the
* runner a root which is NOT its own realpath (a symlinked temp directory; `/var` → `/private/var` on
* macOS) therefore reasons in one spelling while the engine judges in another, and a target the
* deployment considers inside the root can be judged outside it. Before this seat that difference was
* SILENT — the engine simply canonicalized and carried on.
*
* The bad-value discipline's announcement dialect applies (announce, do not refuse): an existing
* deployment may well be running correctly on the non-canonical spelling, so the judgment is unchanged
* and only the difference is disclosed. Nothing here repairs the host's spelling either — the engine
* cannot know which of the two the deployment's own gates key on, and rewriting one into the other
* would move a fence nobody asked to move.
*/
import type { ExecutionEnv } from "../../internal/harness.js";
import type { RunnerDeps } from "../runner-deps.js";
/** The canonical root plus whether the difference was announced (the pin's observable). */
export interface TaskRootCanonical {
/** The spelling every fence judges with — the env's canonical form, or the given spelling when the
* env cannot resolve it (an unresolvable root narrows nothing here; the fence's own skip speaks). */
canonical: string;
/** True exactly when the given spelling differed and the notice was delivered. */
announced: boolean;
}
/**
* Resolve the run's task root to the spelling its fences judge with, announcing a host spelling that is
* not that spelling.
*
* @contract task_root.canonical_is_the_judge — the engine judges containment on the task root's
* CANONICAL spelling; when the root the host handed in is not its own canonical form the run announces
* `config.task_root_not_canonical` exactly once, carrying both spellings, and then judges by the
* canonical form exactly as before. The notice discloses the difference — it never repairs the host's
* spelling, never narrows the fence, and never fires for a root that already is its own canonical form.
*/
export declare function resolveTaskRootCanonical(input: {
env: Pick<ExecutionEnv, "canonicalPath">;
/** The root as the host spelled it (`deps.rootPath` / the restored workspace root). */
given: string;
onNotice: RunnerDeps["onNotice"];
sessionId: string;
runId: string;
}): Promise<TaskRootCanonical>;