Skip to content

The SDK entry point

ContextFile

class ContextFile(path: Path, content: str)

tau_agent_core.sdk.ContextFile

One discovered context file: its resolved path and its text.

Constructor parameters

  • path: Path — (no description)
  • content: str — (no description)

ContextFileError

tau_agent_core.sdk.ContextFileError

A context file was found but could not be used.

Fail-Early: discovery deliberately looked for this file and located it, so a read failure (permissions, a truncated mount, non-UTF-8 bytes) is a real problem and not a reason to quietly prompt the model with less context than the user wrote. pi warns to stderr and continues here (resource-loader.ts:82); τ raises, and names the path plus the escape hatch, because a prompt silently missing its project instructions looks exactly like a model that ignored them.

Settings

class Settings(default_model: str = 'gpt-4o', thinking_level: str = 'off', compaction_enabled: bool = True, context_margin: int = 2000, extension_dirs: list[str] = (lambda: [str(Path.home() / '.tau' / 'extensions')])(), api_keys: dict[str, str] = dict(), custom_system_prompt: str | None = None, tool_execution_mode: str = 'parallel', max_retries: int = 3, temperature: float | None = None, max_tokens: int | None = None, reasoning_level: str = 'off')

tau_agent_core.settings.Settings

τ settings (from ~/.tau/settings.json).

Constructor parameters

  • default_model: str = 'gpt-4o' — Default model identifier for LLM calls
  • thinking_level: str = 'off' — Thinking mode ("off", "low", "high")
  • compaction_enabled: bool = True — Whether automatic session compaction is enabled
  • context_margin: int = 2000 — Token margin before hitting context limit
  • extension_dirs: list[str] = (lambda: [str(Path.home() / '.tau' / 'extensions')])() — Directories to search for extension modules
  • api_keys: dict[str, str] = dict() — Mapping of provider name to API key
  • custom_system_prompt: str | None = None — Optional custom system prompt override
  • tool_execution_mode: str = 'parallel' — Default tool execution mode ("parallel", "sequential")
  • max_retries: int = 3 — Maximum number of retries for failed LLM calls
  • temperature: float | None = None — Default sampling temperature (None = let the endpoint choose)
  • max_tokens: int | None = None — Maximum output tokens (None = provider default)
  • reasoning_level: str = 'off' — Reasoning mode ("off", "low", "high")

load

load(cwd: str | None = None) -> 'Settings'

tau_agent_core.settings.Settings.load

Load settings from ~/.tau/settings.json and project-local override.

Settings are loaded in order of precedence (later overrides earlier): 1. Default values (built-in) 2. Global settings from ~/.tau/settings.json 3. Project-local settings from {cwd}/.tau/settings.json

Parameters

  • cwd: str | None = None — Working directory for project-local settings lookup.

Returns

A fully resolved Settings instance.

SystemPromptFieldError

tau_agent_core.sdk.SystemPromptFieldError

A {{field}} in a system prompt names something τ cannot supply.

Raised rather than rendered literally. A misspelled {{tols}} left in the text would reach the model as the four characters it is, say nothing, and look exactly like a prompt that worked — the silent failure the whole "loud failure over a quiet guess" rule exists to prevent.

append_system_prompt

append_system_prompt(base: str, sections: list[str] | None) -> str

tau_agent_core.sdk.append_system_prompt

Append --append-system-prompt sections to a base system prompt.

Sections augment rather than replace the base (pi appendSystemPrompt, system-prompt.ts:48), joined by blank lines. An empty/absent list returns the base unchanged; an empty base with sections yields just the sections.

Lives here, beside :func:_build_system_prompt, because it composes the base text slot and nothing else — the appended sections land ahead of the project context and the tool list, not after them. It was previously a private helper in tau_coding_agent.headless that three frontends reached across for; headless re-exports this name so those imports keep working.

Parameters

  • base: str — (no description)
  • sections: list[str] | None — (no description)

create_agent_session

create_agent_session(model: str | Model = 'gpt-4o', provider: str = 'openai', base_url: str | None = None, api_key: str | None = None, tools: list[str] | None = None, session_log: SessionLog | None = None, extensions: list[Callable] | None = None, system_prompt: str | None = None, no_context_files: bool = False, thinking_level: str = 'off', cwd: str | None = None, tool_execution_mode: Literal['sequential', 'parallel'] = 'parallel', compaction_policy: CompactionPolicy | None = None, bus_available: bool = False, no_tools: Literal['all', 'builtin'] | None = None, max_turns: int | None = None, tool_options: dict[str, dict[str, Any]] | None = None) -> AgentSession

tau_agent_core.sdk.create_agent_session

Create an AgentSession with all defaults.

This is the main SDK entry point. It handles: - Model resolution (string → Model object) - Tool discovery (string names → AgentTool objects) - Extension registration (inline factory callables invoked at construction) - System prompt building (base prompt + discovered context files + tools)

It does NOT load ~/.tau/settings.json. Nothing in any package reads Settings outside tests; every value this factory uses is either passed in by the caller or defaulted here.

There is deliberately no settings parameter (B5). One was accepted here and never read — a caller passing settings={...} got a session that ignored it and looked fine, which is the same "declared and not consulted" failure H1 fixed for execution_mode, and pi's agent package has no settings concept to port from. It is removed rather than made to raise, because a parameter whose only behaviour is rejection still advertises a capability that does not exist; an unexpected-keyword TypeError says the true thing. Deciding what such a dict would mean — how it composes with the ~/.tau/config.json the CLI and TUI actually read — is the config-precedence design question (B2) and is not settled here.

Parameters

  • model: str | Model = 'gpt-4o' — Model identifier string or Model object (default: "gpt-4o").
  • provider: str = 'openai' — Provider name for model resolution (default: "openai").
  • base_url: str | None = None — Optional custom API base URL.
  • api_key: str | None = None — Optional API key.
  • tools: list[str] | None = None — List of BUILT-IN tool name strings (e.g., ["read", "bash"]), resolved by :func:_resolve_tools, which raises ValueError on any name it does not recognize (NODE-ADDRESSABLE-AGENTS.md §5/W5). This parameter does not accept :class:~tau_agent_core.tools.base.AgentTool instances and gains no fallback that does — a custom tool must go through the :class:~tau_agent_core.agent_session.AgentSession constructor's tools= directly, or be registered by an extension (ExtensionAPI tool registration, loaded via extensions=/ load_extensions). Passing a non-empty list together with no_tools raises — see that parameter.
  • session_log: SessionLog | None = None — Optional SessionLog to persist through (the coding-agent's file Session on the live path). Defaults to an in-memory log.
  • extensions: list[Callable] | None = None — List of extension factory callables.
  • system_prompt: str | None = None — Optional custom system prompt. Replaces the base prompt ONLY — project context files still load and are appended after it. Pass no_context_files=True to suppress those as well.
  • no_context_files: bool = False — Skip context-file discovery entirely (--no-context-files/-nc). The prompt is then the base (or custom) text plus the tool list, and nothing read from disk.
  • thinking_level: str = 'off' — Thinking level ("off", "minimal", "low", "medium", "high", "xhigh"). A non-"off" level marks the model reasoning-capable and is forwarded to the provider as reasoning_effort.
  • cwd: str | None = None — Current working directory.
  • tool_execution_mode: Literal['sequential', 'parallel'] = 'parallel' — Batch-level tool execution policy ("sequential" or "parallel", default "parallel") forwarded to AgentSession, which threads it into every AgentLoopConfig the session builds. A tool declaring a per-tool "sequential" execution_mode still forces its batch to run sequentially regardless of this setting.
  • compaction_policy: CompactionPolicy | None = None — Optional declared :class:~tau_agent_core.compaction_policy.CompactionPolicy (H5, SIM_SPEC_v2 §16.8). None — the default — is the shipped behaviour: auto-compaction on, summarising through this session's own model. A MEASUREMENT run declares one, because a compaction is a model call at the tail of a prompt and an undeclared one lands inside §5.2's headline latency number and on the far side of §11.1's partition. Declaring a policy never makes compaction quieter — it adds construction-time and runtime checks that raise.
  • bus_available: bool = False — Whether this session has a bus transport a loaded extension may declare against (H8, SIM_SPEC_v2 §16.10). False — the default — refuses to load any file extension that declares TOUCHES_BUS = True (see :func:_load_one_extension); no NATS wiring exists in this package yet (tau-007), so there is nothing to back that capability with until a caller sets this True.
  • no_tools: Literal['all', 'builtin'] | None = None — Tool-suppression policy, the SDK equivalent of the CLI's --no-tools/-nt and --no-builtin-tools/-nbt. One resolved value rather than two booleans, for the reason headless.resolve_no_tools gives: flags that only have meaning against each other become the same flag once each consumer re-derives the interaction. - "all" — the model is offered nothing: no built-ins, and no extension-registered tools either. Extensions still LOAD; hooks, event subscriptions, slash commands and message injections are untouched. Only callable tools are withheld. - "builtin" — built-ins only. Extension-registered tools survive and are offered. - None — the default — no suppression. Either value resolves zero built-ins here, which is what gives "builtin" behaviour inside this package rather than leaving it a display label that only the coding-agent's argv boundary honoured. An unrecognised value raises in AgentSession.
  • max_turns: int | None = None — Stop the loop after this many LLM calls. None — the default — is no ceiling, which is also AgentLoopConfig's default and pi's behaviour. This factory did not take the parameter at all until now, and neither did any CLI flag or config key, so the ceiling that did exist (a hardcoded 50) was unreachable from every caller τ ships. What bounds a runaway run without one is the abort signal: an extension's budget guard, or Escape in the TUI.
  • tool_options: dict[str, dict[str, Any]] | None = None — Keyword arguments for individual built-in tools, keyed by tool name — e.g. {"read": {"max_image_dimension": 2000}}. Ignored for tools not in tools, and irrelevant when no_tools is set, since then no built-in is constructed at all. See :func:_resolve_tools.

Returns

Fully configured AgentSession instance.

Raises

  • ValueError — if no_tools is given together with a non-empty tools (a contradictory request, refused rather than silently resolved), or if tools names a tool that is not a built-in (:func:_resolve_tools).

Example

session = create_agent_session(model="gpt-4o", tools=["read", "bash"]) messages = await session.prompt("Hello, world!")

load_project_context_files

load_project_context_files(cwd: str | Path | None = None, agent_dir: str | Path | None = None) -> list[ContextFile]

tau_agent_core.sdk.load_project_context_files

Discover the context files that apply to cwd, weakest first.

A port of pi's loadProjectContextFiles (resource-loader.ts:119 at 5cd93f688), plus τ's own .tau/SYSTEM.md. The returned order is the order they belong in a prompt — general first, specific last — because the nearest file is the one that should have the last word:

  1. ~/.tau's context file (:data:_AGENT_DIR), the user's global one.
  2. Every ancestor of cwd that has one, root-most first, ending with cwd's own — so a repo's AGENTS.md is read after $HOME's and a package's after its monorepo's.
  3. cwd's .tau/SYSTEM.md, τ's own slot (see :data:TAU_SYSTEM_FILE).

Deduplicated by resolved path, so running τ from ~ does not load the same file as both the agent-dir entry and an ancestor.

On walking all the way to /: this is pi's behaviour and it is kept deliberately, because "put your standing instructions in ~/AGENTS.md" is a real workflow. The cost is a handful of stat calls per ancestor, once per session — not per turn. The surprise is answered by :func:_build_system_prompt, which labels every block with the absolute path it came from, so a prompt can never carry instructions whose origin it does not name; and by --no-context-files for a run that wants none.

Parameters

  • cwd: str | Path | None = None — (no description)
  • agent_dir: str | Path | None = None — (no description)

resolve_model

resolve_model(model: str, provider: str = 'openai', base_url: str | None = None) -> Model

tau_agent_core.sdk.resolve_model

Resolve a model string to a Model object.

Parameters

  • model: str — Model identifier (e.g., "gpt-4o").
  • provider: str = 'openai' — Provider name (default: "openai").
  • base_url: str | None = None — Optional custom API base URL.

Returns

Model object with provider configuration.

Raises

  • KeyError — If model string is not found in defaults.