-
Notifications
You must be signed in to change notification settings - Fork 0
packages coding agent tools
Active contributors: Mario Zechner, kt, Armin Ronacher
The tools are the actions the model can invoke during a turn. The default built-in tool is ipython, a persistent Jupyter kernel that also hosts %%bash shell cells; bash and edit tool definitions exist as factories and are wired in by custom runtimes (via baseToolsOverride in packages/coding-agent/src/core/agent-session.ts) or by the TUI renderer for replay. All built-in tool factories and the registry live in packages/coding-agent/src/core/tools/, and the kernel implementation lives in packages/coding-agent/src/core/kernel/.
- Give the model a small, safe tool surface: a persistent Python kernel (
ipython), shell execution (bash), and exact-text file edits (edit), plus extension-defined custom tools. - Stream partial output to clients while a tool runs and deliver a final result (or error) when it finishes.
- Keep tool implementations replaceable:
BashOperations,EditOperations, andIpythonKernelProvisionerare the seams for remote or custom execution.
packages/coding-agent/src/core/tools/
├── index.ts # tool registry: createTool, createToolDefinition, createAllToolDefinitions
├── ipython.ts # ipython tool + IpythonKernelProvisioner
├── ipython-cell-code.ts # parseIpythonBashCell (%%bash cell handling)
├── bash.ts # bash tool definition + BashOperations + createLocalBashOperations
├── edit.ts # edit tool definition + EditOperations
├── edit-diff.ts # fuzzy matching, edit application, unified diff generation
├── code-preview.ts # previewBashCommand: classify and preview command/code text
├── file-mutation-queue.ts# withFileMutationQueue: serialize writes per file
├── output-accumulator.ts # bounded-memory streaming output with temp-file fallback
├── truncate.ts # DEFAULT_MAX_BYTES / DEFAULT_MAX_LINES, truncateHead/Tail/Line
├── path-utils.ts # resolveToCwd
├── render-utils.ts # getTextOutput, invalidArgText, shortenPath
└── tool-definition-wrapper.ts # wrapToolDefinition (AgentTool <-> ToolDefinition)
packages/coding-agent/src/core/kernel/
├── index.ts # KernelManager (Jupyter over ZeroMQ), host request bridge
├── bootstrap.ts # ensureKernelPython: builds the kernel venv (ipykernel + prime-agent-runtime)
├── boot-gate.ts # withKernelBootPermit: bounded concurrent kernel boots
├── fork-server.ts # Linux forkserver fast path for kernel spawn
├── fork-server-script.ts # Python side of the forkserver
├── state-snapshot.ts # dill-based namespace snapshot + restore
└── bootstrap-cli.ts # CLI entry for test bootstrap
packages/coding-agent/src/core/
├── bash-executor.ts # executeBashWithOperations: user-initiated bash (AgentSession.executeBash)
└── exec.ts # execCommand: shared shell execution for extensions and custom tools
| Type / function | Full path | One-line description |
|---|---|---|
createAllToolDefinitions |
packages/coding-agent/src/core/tools/index.ts |
Built-in registry; returns the ipython tool definition (the default active tool) |
createIpythonToolDefinition / createIpythonTool
|
packages/coding-agent/src/core/tools/ipython.ts |
The ipython tool: executes Python or %%bash cells in a persistent kernel |
IpythonKernelProvisioner |
packages/coding-agent/src/core/tools/ipython.ts |
Owns lazy create, start, bootstrap, prewarm, kill, and dispose of one session's kernel |
KernelManager |
packages/coding-agent/src/core/kernel/index.ts |
Jupyter kernel client over ZeroMQ: start, execute, shutdown, restart, kill, snapshots |
ensureKernelPython |
packages/coding-agent/src/core/kernel/bootstrap.ts |
Ensures a kernel venv with ipykernel and prime-agent-runtime, then runs an rlm bootstrap cell |
withKernelBootPermit |
packages/coding-agent/src/core/kernel/boot-gate.ts |
Semaphore bounding concurrent kernel startups |
createBashToolDefinition / createBashTool
|
packages/coding-agent/src/core/tools/bash.ts |
The bash tool: streams a shell command with truncation and timeout |
BashOperations |
packages/coding-agent/src/core/tools/bash.ts |
Pluggable exec backend; createLocalBashOperations is the local shell default |
createEditToolDefinition / createEditTool
|
packages/coding-agent/src/core/tools/edit.ts |
The edit tool: exact-text replacement with a rendered diff |
applyEditsToNormalizedContent |
packages/coding-agent/src/core/tools/edit-diff.ts |
Applies edits with exact-then-fuzzy matching and overlap checks |
computeEditsDiff |
packages/coding-agent/src/core/tools/edit-diff.ts |
Computes a preview diff without applying the edit |
withFileMutationQueue |
packages/coding-agent/src/core/tools/file-mutation-queue.ts |
Serializes read-modify-write operations per file path |
previewBashCommand |
packages/coding-agent/src/core/tools/code-preview.ts |
Classifies text as bash or python and returns a redacted one-line preview |
executeBashWithOperations |
packages/coding-agent/src/core/bash-executor.ts |
Streaming bash execution for user-initiated commands (!, !!) |
execCommand |
packages/coding-agent/src/core/exec.ts |
Simple spawn wrapper (stdout/stderr/code) for extensions and custom tools |
The registry in packages/coding-agent/src/core/tools/index.ts currently produces one built-in tool, ipython (createAllToolDefinitions returns { ipython }). AgentSession._buildRuntime in packages/coding-agent/src/core/agent-session.ts constructs an IpythonKernelProvisioner per session, builds the base tool definitions, then merges them with extension-registered tools and SDK custom tools into a definition registry; only names in the active set are exposed to the model, defaulting to ["ipython"] unless baseToolsOverride provides others. createBashTool and createEditTool are exported from packages/coding-agent/src/core/tools/index.ts for callers that want those tools with a custom cwd, and the interactive renderer (packages/coding-agent/src/modes/interactive/components/tool-execution.ts) uses createBashToolDefinition and createEditToolDefinition to render and replay built-in bash and edit calls.
The ipython tool is the default and the most complex. Its execute in packages/coding-agent/src/core/tools/ipython.ts routes the cell through IpythonKernelProvisioner.ensure(), which lazily starts the kernel on first use (or joins an in-flight or prewarmed startup). KernelManager.start in packages/coding-agent/src/core/kernel/index.ts resolves the Python interpreter via ensureKernelPython (which builds a venv containing ipykernel and prime-agent-runtime when needed), connects to the kernel's ZeroMQ shell, iopub, and control channels, and on Linux can fork a pre-imported kernel through packages/coding-agent/src/core/kernel/fork-server.ts instead of a full cold boot. After start, the provisioner restores the prior session's namespace from the dill snapshot in packages/coding-agent/src/core/kernel/state-snapshot.ts and runs the rlm bootstrap cell.
Cell execution goes through KernelManager.execute, serialized by an execution queue. Cells can make typed host requests back to the TypeScript session over a Jupyter comm (HOST_COMM_TARGET), which is how rlm.run, goal management, and skills call into the session. A cell that ignores an interrupt triggers a busy-kernel choice (wait, kill and restart, or cancel). Results carry stdout, stderr, result, tracebacks on error, attachments, diffs, and sent agent messages; the tool returns text plus optional image blocks. The tool is marked executionMode: "sequential" because the kernel is single-threaded.
The model-facing bash tool in packages/coding-agent/src/core/tools/bash.ts runs a command through BashOperations.exec (defaulting to createLocalBashOperations, which spawns the configured shell, streams stdout/stderr, and kills the process tree on abort or timeout). Output accumulates in packages/coding-agent/src/core/tools/output-accumulator.ts, which keeps a bounded tail and spills full output to a temp file; truncation metadata (lines shown, full path) is attached to the result details. Streamed chunks are emitted through the tool's onUpdate callback.
User-initiated bash is separate. AgentSession.executeBash and runUserBash in packages/coding-agent/src/core/agent-session.ts back the ! and !! prefixes, using executeBashWithOperations in packages/coding-agent/src/core/bash-executor.ts, which sanitizes output and stores full output to a temp file when truncated. Commands run with !! are excluded from LLM context. packages/coding-agent/src/core/exec.ts provides a smaller execCommand (no streaming, returns stdout/stderr/code) for extensions and custom tools.
The edit tool in packages/coding-agent/src/core/tools/edit.ts takes a path and one or more exact-text replacements. applyEditsToNormalizedContent in packages/coding-agent/src/core/tools/edit-diff.ts normalizes line endings and BOM, matches each oldText exactly first and then with fuzzy matching (trailing whitespace, Unicode quotes and dashes normalized), rejects non-unique or overlapping edits, applies replacements in reverse offset order, and restores the original line endings. The tool returns a unified diff with line numbers via generateDiffString, and the TUI pre-renders the diff before execution using computeEditsDiff. Writes go through withFileMutationQueue so concurrent edits to the same file serialize.
The model's tool calls surface to clients as three agent events emitted by the Agent loop in packages/agent: tool_execution_start (call id, name, args), tool_execution_update (partial output while running), and tool_execution_end (final result and isError). Tools push partial output through their onUpdate callback; the bash tool throttles these updates at 100ms and the ipython tool streams cell output chunks. Clients render this as a per-call lifecycle: input-streaming while the call renders and streams, output-available when partial or final output exists, and output-error when the call ends with isError (see Glossary). Extensions observe the same calls through the tool_call and tool_result events in packages/coding-agent/src/core/extensions/types.ts, where the input is typed per tool (BashToolCallEvent, EditToolCallEvent, IpythonToolCallEvent, CustomToolCallEvent).
sequenceDiagram
participant A as Agent (pi-agent-core)
participant AS as AgentSession
participant T as ipython tool
participant P as IpythonKernelProvisioner
participant K as KernelManager
participant PY as IPython kernel
participant S as Subscribers (clients)
A->>T: execute(toolCallId, {code})
T->>P: ensure() (lazy start or prewarm)
P->>K: start (venv bootstrap, rlm runtime)
K->>PY: execute cell over ZMQ
PY-->>K: stdout / result / error (or host request)
K-->>T: ExecuteResult
T-->>A: content + details (status, diffs, attachments)
A-->>AS: tool_execution_end event
AS-->>S: AgentSessionEvent (tool result)
Note over A,S: bash and ipython stream partial output via onUpdate -> tool_execution_update
-
AgentSessionbuilds and owns the provisioner in_buildRuntime(packages/coding-agent/src/core/agent-session.ts), prewarming the kernel when configured or when a resume has a snapshot, and disposing it on session dispose so a final snapshot flushes. -
web/serverconsumesIpythonKernelProvisionerfor kernel readiness and restarts; see Web server. - Extensions add tools via
defineTooland thetool_call/tool_resulthooks; see Extensions. - The SDK exports
createBashTool,createEditTool,createIpythonTool, andwithFileMutationQueuefor custom tool setups (e.g. custom cwd) frompackages/coding-agent/src/core/sdk.ts. - Kernel host requests are how the Python runtime (
prime-agent-runtime) calls back into the session forrlm.runand skills; see RLM runtime and prime-agent-runtime.
- Add a built-in tool: add a factory in
packages/coding-agent/src/core/tools/, register it inpackages/coding-agent/src/core/tools/index.ts, and wire it in_buildRuntimeinpackages/coding-agent/src/core/agent-session.ts. - Change kernel startup or the Python environment:
packages/coding-agent/src/core/kernel/bootstrap.ts(venv and rlm bootstrap) andpackages/coding-agent/src/core/kernel/index.ts(kernel spawn, execute, dispose). - Change how output is truncated or streamed:
packages/coding-agent/src/core/tools/output-accumulator.tsandpackages/coding-agent/src/core/tools/truncate.ts. - Change edit matching or diff rendering:
packages/coding-agent/src/core/tools/edit-diff.ts. - Add a remote execution backend: implement
BashOperationsorEditOperationsand pass them tocreateBashTool/createEditTool.
| File | Purpose |
|---|---|
packages/coding-agent/src/core/tools/index.ts |
Tool registry and factories |
packages/coding-agent/src/core/tools/ipython.ts |
The ipython tool and IpythonKernelProvisioner
|
packages/coding-agent/src/core/kernel/index.ts |
KernelManager, host request comm bridge |
packages/coding-agent/src/core/kernel/bootstrap.ts |
Kernel venv bootstrap and rlm runtime cell |
packages/coding-agent/src/core/kernel/boot-gate.ts |
Concurrent boot semaphore |
packages/coding-agent/src/core/kernel/state-snapshot.ts |
Kernel namespace snapshot and restore |
packages/coding-agent/src/core/kernel/fork-server.ts |
Linux forkserver fast kernel spawn |
packages/coding-agent/src/core/tools/bash.ts |
The bash tool and BashOperations
|
packages/coding-agent/src/core/tools/edit.ts |
The edit tool and EditOperations
|
packages/coding-agent/src/core/tools/edit-diff.ts |
Edit application and diff generation |
packages/coding-agent/src/core/bash-executor.ts |
User-initiated bash execution |
packages/coding-agent/src/core/exec.ts |
Shared execCommand for extensions and custom tools |
- Coding agent - package overview
- Session runtime - how the session runs tools and persists results
-
Extensions - custom tools and
tool_call/tool_resulthooks - Skills - Python skills that run in the kernel and use host requests
- RLM runtime - recursive subagents spawned from the kernel
- Daemon - kernels in worker processes