/** * An agent is *content*: a system prompt, a model, a set of tools. * It is declared as Markdown + frontmatter, following the pi convention. * * This file knows nothing about sessions or workflows: it turns files into * data. Bringing an agent to life is `spawn()`'s job. */ import { type MarkdownFile } from "./markdown.ts"; /** Directory name under `~/.pi/agent/` and under `.pi/`. */ export declare const AGENTS_DIR = "agents"; /** * Lifetime of a subagent - the central choice of this library. * * - `"task"`: born and dies with each task. Minimal context, reproducible. * - `"workflow"`: lives for the duration of the workflow. Remembers iterations. * - `"session"`: lives as long as the pi session. Long memory, watch it. */ export type Lifetime = "task" | "workflow" | "session"; /** Every {@link Lifetime}, for whoever validates one - the tool's schema names them from here. */ export declare const LIFETIMES: readonly ["task", "workflow", "session"]; /** * Where an agent definition came from. * * `"builtin"` is what this package ships. It is the lowest priority of the * three: a `"user"` definition of the same name replaces it, and a `"project"` * one replaces both. */ export type AgentSource = "user" | "project" | "builtin"; /** Where to look for definitions. Defaults to `"user"` - see {@link loadAgents}. */ export type AgentScope = "user" | "project" | "both"; /** An agent: the "who". Inert data, no state, no session. */ export type Agent = { /** Unique name, and how every caller refers to it. Mandatory in the file. */ name: string; /** * What this agent is for, in one line. Mandatory in the file. * * Not decoration: `route` and `orchestrate` hand this text to a model to * decide who does the work, so a vague description produces vague routing * that no parser can repair. */ description: string; /** Markdown body, used verbatim as the system prompt. */ systemPrompt: string; /** * Allowed tools. Absent means the read-only default is applied at spawn; * an empty list means none at all. */ tools?: string[]; /** * Every turn must call at least one tool. A turn that answers without one * fails with {@link CALLED_NO_TOOL_ERROR}: for an agent whose job is to * read, an answer that read nothing is one that was not done. */ mustCallTool?: boolean; /** * Skills this agent may load, by name - an allowlist, exactly like `tools`. * * Absent means none: a subagent is offered no skill it did not ask for. * `resolveSkills` in `src/skills.ts` says where a name is looked up. */ skills?: string[]; /** Model pattern, e.g. `"anthropic/claude-sonnet-5"`. Absent means pi's default. */ model?: string; /** Default lifetime, in a workflow as in `spawn`. An explicit call always wins. */ lifetime?: Lifetime; /** * How many subagents this agent runs at once when it delegates. * * Only meaningful for an agent whose `tools:` names `subagent`. It is the * agent's own business rather than the caller's: how wide a split is worth * making depends on how the agent was told to think about its task, which is * what its definition says. */ concurrency?: number; /** * Default for "give this agent its own herdr split". An explicit call wins. * * Declaring it here is often what you want: a scout is worth watching every * time, whoever calls it. */ openInHerdr?: boolean; /** Where the definition was found - a repository's agents are loaded only on request. */ source: AgentSource; /** File path, or a free label for an agent built in memory. */ filePath: string; }; /** * The lifetime a subagent of `agent` runs with: the one `asked` for, then the * agent's frontmatter, then `"task"`. Every place that spawns reads it here, so * a workflow and a direct `spawn` cannot disagree on what a definition asked. */ export declare function lifetimeOf(agent: Agent, asked?: Lifetime): Lifetime; /** * An agent file that is not an agent: kept by a catalogue that reports it, * where {@link loadAgents} drops it. */ export type BrokenAgent = { /** The name it would be asked for by: its `name:` when it has one, else its file name without `.md`. */ name: string; filePath: string; source: AgentSource; /** Why it is not an agent, in one sentence. */ error: string; }; /** * Parses an agent definition. * * Returns `undefined` when the frontmatter is not valid YAML, or when `name` or * `description` is missing: this is pi's behaviour, a file that is not an agent * is ignored **silently**. Kept separate from {@link loadAgents} so it stays * testable without touching the disk. */ export declare function parseAgent(content: string, filePath: string, source: AgentSource): Agent | undefined; /** * Reads an agent file, and says why when it is not one: the YAML error, or the * keys it lacks. Where {@link parseAgent} drops a file in silence, this keeps * it, for a caller that validates before it runs and must not answer "unknown * agent" about a file sitting right there. */ export declare function readAgentFile(file: MarkdownFile, source: AgentSource): Agent | BrokenAgent; /** * The error of a turn that called no tool from an agent whose definition says * `mustCallTool: true`. A flow reads it as the failure kind `no-tool`. */ export declare const CALLED_NO_TOOL_ERROR = "called no tool (mustCallTool)"; /** * Discovers the available agents. * * The scope defaults to `"user"`, and that is not a detail: project agents * (`.pi/agents/`) are repository-controlled content, hence third-party * instructions. They are only loaded on explicit request. * * Precedence runs from the least specific to the most: the shipped definitions * first when `builtin` is set, then the user's, then the repository's. Whoever * is closer to the work wins the name. `builtin` is off by default: a script * that asks for "the user's agents" must not be handed ours as well. The * extension asks for them, because there it is the difference between working * out of the box and not working at all. * * Discovery happens on every call: editing a `.md` is enough to reload it. */ export declare function loadAgents(options?: { cwd?: string; scope?: AgentScope; builtin?: boolean; }): Agent[]; /** * Looks up an agent by name, or throws. * * An unknown agent name is a programming error, not a runtime failure: we do * not want a failed `Result` several steps later because of a typo in a * workflow. */ export declare function findAgent(agents: Agent[], name: string): Agent; /** * Reads every `.md` in a directory. * * A file that does not parse is **dropped in silence** - that is pi's own * behaviour for an agent, and we keep it. A missing or unreadable directory * yields `[]`. */ export declare function loadAgentsFromDir(dir: string, source: AgentSource): Agent[]; //# sourceMappingURL=agent.d.ts.map