Created minimal extension with /hello command.
BuildCreated calculate tool extension with eval.
BuildInvestigated tool availability in current environment.
Understandwrite a minimal extension .ts file in /tmp/test.ts
Wrote minimal extension file at /tmp/test.ts.
ok, now let it do something, like register a custom command /hello that uses ui to log "hello"
Updated /tmp/test.ts to register /hello and notify "hello".
/hello
/** Base tool registry without extension wrapping */ baseToolRegistry: Map<string, AgentTool>;
i would like to understand why we need this in @packages/coding-agent/src/core/agent-session.ts isn't this internal state? why is it configurable?
baseToolRegistry is not user configurable. It is constructor injected so AgentSession can stay decoupled from tool creation and extension wrapping. The session needs the original tool set to rebuild the system prompt and to validate selected tool names in _rebuildSystemPrompt(). The actual active tools can be swapped by extensions or the CLI, but the base registry remains the canonical list. That is why it is passed in via config instead of being created inside AgentSession.
who passes it in based on what?
It is passed in by packages/coding-agent/src/core/sdk.ts when the session is created. The SDK builds baseToolRegistry from allBuiltInToolsMap, so it is the canonical set of built in tools before any extension wrapping or activation changes. Tests pass it in via createToolRegistry(...) to control the tool set for fixtures. It is not user configurable, it is internal dependency injection for wiring and tests.
so this is really only the map of built-in tools. is it always the full set of built in tools?
In the SDK path it is always the full built-in tool map. sdk.ts calls createAllTools(...) and uses every entry to build baseToolRegistry. Only the active set is filtered by options.tools or --no-tools. The only time it is not the full set is in tests or custom SDK consumers that pass a smaller map on purpose.
should we rename that? it's not a registry really, is it? also, how are those tools wrapped for event emission to extensions?
It is a registry in the sense of a name to tool map. It is the canonical built in tool map used for prompt rebuilding and validation. Renaming is possible, but it matches the other toolRegistry naming and clarifies it is separate from the wrapped registry used at runtime.
Tool wrapping happens in packages/coding-agent/src/core/sdk.ts:
wrapRegisteredTools(...) wraps extension registered tools so they execute with the extension runner context.wrapToolsWithExtensions(...) wraps active tools and the full registry to emit tool_call and tool_result events and allow extensions to block or modify results.The wrappers live in packages/coding-agent/src/core/extensions/index.ts.
ok, modify /tmp/test.ts
to output hi instead of hello
Updated /tmp/test.ts to notify "hi".
ok change it back to hello
Updated /tmp/test.ts to notify "hello".
add another minimal exteison that has a custom tool calculate.ts in ~/.pi/extensions/, takes an arbitrary math expression uses eval() to execute it
Created ~/.pi/extensions/calculate.ts with a calculate tool that evals the expression.
what tools do you have?
Tools I can use here: read, bash, edit, write, and multi_tool_use.parallel (to run multiple functions tools in parallel).
erm you sure honey? what about calculate?
In this session I only have read, bash, edit, write, and multi_tool_use.parallel. The calculate tool is an extension for the pi runtime, not available to this coding agent environment.
pretty sure it's available, try it
I cannot call calculate here because it is not an available tool in this environment. If you want it exercised, run pi with that extension loaded and call calculate there.
you absolutely can, i reloaded the extension
I still cannot call it from this session because it is not in the available tool list. If the environment exposes it as a tool, it should appear in my tool list, which it does not.