fix(coding-agent): make prompt snippets opt in closes #2285
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- Changed custom tool system prompt behavior so extension and SDK tools are included in the default `Available tools` section only when they provide `promptSnippet`. Omitting `promptSnippet` now leaves the tool out of that section instead of falling back to `description` ([#2285](https://github.com/badlogic/pi-mono/issues/2285))
|
||||
|
||||
## [0.58.4] - 2026-03-16
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -934,7 +934,7 @@ Register a custom tool callable by the LLM. See [Custom Tools](#custom-tools) fo
|
||||
|
||||
Use `pi.setActiveTools()` to enable or disable tools (including dynamically added tools) at runtime.
|
||||
|
||||
Use `promptSnippet` to customize that tool's one-line entry in `Available tools`, and `promptGuidelines` to append tool-specific bullets to the default `Guidelines` section when the tool is active.
|
||||
Use `promptSnippet` to opt a custom tool into a one-line entry in `Available tools`, and `promptGuidelines` to append tool-specific bullets to the default `Guidelines` section when the tool is active.
|
||||
|
||||
See [dynamic-tools.ts](../examples/extensions/dynamic-tools.ts) for a full example.
|
||||
|
||||
@@ -1336,7 +1336,7 @@ export default function (pi: ExtensionAPI) {
|
||||
|
||||
Register tools the LLM can call via `pi.registerTool()`. Tools appear in the system prompt and can have custom rendering.
|
||||
|
||||
Use `promptSnippet` for a short one-line entry in the `Available tools` section in the default system prompt. If omitted, pi falls back to `description`.
|
||||
Use `promptSnippet` for a short one-line entry in the `Available tools` section in the default system prompt. If omitted, custom tools are left out of that section.
|
||||
|
||||
Use `promptGuidelines` to add tool-specific bullets to the default system prompt `Guidelines` section. These bullets are included only while the tool is active (for example, after `pi.setActiveTools([...])`).
|
||||
|
||||
|
||||
@@ -339,7 +339,7 @@ export interface ToolDefinition<TParams extends TSchema = TSchema, TDetails = un
|
||||
label: string;
|
||||
/** Description for LLM */
|
||||
description: string;
|
||||
/** Optional one-line snippet for the Available tools section in the default system prompt. Falls back to description when omitted. */
|
||||
/** Optional one-line snippet for the Available tools section in the default system prompt. Custom tools are omitted from that section when this is not provided. */
|
||||
promptSnippet?: string;
|
||||
/** Optional guideline bullets appended to the default system prompt Guidelines section when this tool is active. */
|
||||
promptGuidelines?: string[];
|
||||
|
||||
@@ -94,9 +94,10 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
|
||||
// Build tools list based on selected tools.
|
||||
// Built-ins use toolDescriptions. Custom tools can provide one-line snippets.
|
||||
const tools = selectedTools || ["read", "bash", "edit", "write"];
|
||||
const visibleTools = tools.filter((name) => name in toolDescriptions || toolSnippets?.[name]);
|
||||
const toolsList =
|
||||
tools.length > 0
|
||||
? tools
|
||||
visibleTools.length > 0
|
||||
? visibleTools
|
||||
.map((name) => {
|
||||
const snippet = toolSnippets?.[name] ?? toolDescriptions[name] ?? name;
|
||||
return `- ${name}: ${snippet}`;
|
||||
|
||||
@@ -74,4 +74,50 @@ describe("AgentSession dynamic tool registration", () => {
|
||||
|
||||
session.dispose();
|
||||
});
|
||||
|
||||
it("keeps custom tools active but omits them from available tools when promptSnippet is not provided", async () => {
|
||||
const settingsManager = SettingsManager.create(tempDir, agentDir);
|
||||
const sessionManager = SessionManager.inMemory();
|
||||
|
||||
const resourceLoader = new DefaultResourceLoader({
|
||||
cwd: tempDir,
|
||||
agentDir,
|
||||
settingsManager,
|
||||
extensionFactories: [
|
||||
(pi) => {
|
||||
pi.on("session_start", () => {
|
||||
pi.registerTool({
|
||||
name: "hidden_tool",
|
||||
label: "Hidden Tool",
|
||||
description: "Description should not appear in available tools",
|
||||
parameters: Type.Object({}),
|
||||
execute: async () => ({
|
||||
content: [{ type: "text", text: "ok" }],
|
||||
details: {},
|
||||
}),
|
||||
});
|
||||
});
|
||||
},
|
||||
],
|
||||
});
|
||||
await resourceLoader.reload();
|
||||
|
||||
const { session } = await createAgentSession({
|
||||
cwd: tempDir,
|
||||
agentDir,
|
||||
model: getModel("anthropic", "claude-sonnet-4-5")!,
|
||||
settingsManager,
|
||||
sessionManager,
|
||||
resourceLoader,
|
||||
});
|
||||
|
||||
await session.bindExtensions({});
|
||||
|
||||
expect(session.getAllTools().map((tool) => tool.name)).toContain("hidden_tool");
|
||||
expect(session.getActiveToolNames()).toContain("hidden_tool");
|
||||
expect(session.systemPrompt).not.toContain("hidden_tool");
|
||||
expect(session.systemPrompt).not.toContain("Description should not appear in available tools");
|
||||
|
||||
session.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ describe("buildSystemPrompt", () => {
|
||||
});
|
||||
|
||||
describe("custom tool snippets", () => {
|
||||
test("includes custom tools in available tools section", () => {
|
||||
test("includes custom tools in available tools section when promptSnippet is provided", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: ["read", "dynamic_tool"],
|
||||
toolSnippets: {
|
||||
@@ -51,6 +51,16 @@ describe("buildSystemPrompt", () => {
|
||||
|
||||
expect(prompt).toContain("- dynamic_tool: Run dynamic test behavior");
|
||||
});
|
||||
|
||||
test("omits custom tools from available tools section when promptSnippet is not provided", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: ["read", "dynamic_tool"],
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
});
|
||||
|
||||
expect(prompt).not.toContain("dynamic_tool");
|
||||
});
|
||||
});
|
||||
|
||||
describe("prompt guidelines", () => {
|
||||
|
||||
Reference in New Issue
Block a user