mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 02:01:29 +00:00
Merge pull request #557 from cv/feat/no-tools-flag
feat(coding-agent): add --no-tools flag to disable built-in tools
This commit is contained in:
commit
7f38dbfba9
6 changed files with 123 additions and 15 deletions
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- `--no-tools` flag to disable all built-in tools, allowing extension-only tool setups ([#555](https://github.com/badlogic/pi-mono/issues/555))
|
||||
|
||||
## [0.38.0] - 2026-01-08
|
||||
|
||||
### Breaking Changes
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ export interface Args {
|
|||
sessionDir?: string;
|
||||
models?: string[];
|
||||
tools?: ToolName[];
|
||||
noTools?: boolean;
|
||||
extensions?: string[];
|
||||
noExtensions?: boolean;
|
||||
print?: boolean;
|
||||
|
|
@ -86,19 +87,27 @@ export function parseArgs(args: string[], extensionFlags?: Map<string, { type: "
|
|||
result.sessionDir = args[++i];
|
||||
} else if (arg === "--models" && i + 1 < args.length) {
|
||||
result.models = args[++i].split(",").map((s) => s.trim());
|
||||
} else if (arg === "--no-tools") {
|
||||
result.noTools = true;
|
||||
} else if (arg === "--tools" && i + 1 < args.length) {
|
||||
const toolNames = args[++i].split(",").map((s) => s.trim());
|
||||
const validTools: ToolName[] = [];
|
||||
for (const name of toolNames) {
|
||||
if (name in allTools) {
|
||||
validTools.push(name as ToolName);
|
||||
} else {
|
||||
console.error(
|
||||
chalk.yellow(`Warning: Unknown tool "${name}". Valid tools: ${Object.keys(allTools).join(", ")}`),
|
||||
);
|
||||
const toolsArg = args[++i];
|
||||
// Handle empty string as no tools (e.g., --tools '')
|
||||
if (toolsArg === "") {
|
||||
result.tools = [];
|
||||
} else {
|
||||
const toolNames = toolsArg.split(",").map((s) => s.trim());
|
||||
const validTools: ToolName[] = [];
|
||||
for (const name of toolNames) {
|
||||
if (name in allTools) {
|
||||
validTools.push(name as ToolName);
|
||||
} else {
|
||||
console.error(
|
||||
chalk.yellow(`Warning: Unknown tool "${name}". Valid tools: ${Object.keys(allTools).join(", ")}`),
|
||||
);
|
||||
}
|
||||
}
|
||||
result.tools = validTools;
|
||||
}
|
||||
result.tools = validTools;
|
||||
} else if (arg === "--thinking" && i + 1 < args.length) {
|
||||
const level = args[++i];
|
||||
if (isValidThinkingLevel(level)) {
|
||||
|
|
@ -174,6 +183,7 @@ ${chalk.bold("Options:")}
|
|||
--no-session Don't save session (ephemeral)
|
||||
--models <patterns> Comma-separated model patterns for Ctrl+P cycling
|
||||
Supports globs (anthropic/*, *sonnet*) and fuzzy matching
|
||||
--no-tools Disable all built-in tools (use with -e for extension-only tools)
|
||||
--tools <tools> Comma-separated list of tools to enable (default: read,bash,edit,write)
|
||||
Available: read, bash, edit, write, grep, find, ls
|
||||
--thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
|
|||
|
||||
// Build tools list based on selected tools
|
||||
const tools = selectedTools || (["read", "bash", "edit", "write"] as ToolName[]);
|
||||
const toolsList = tools.map((t) => `- ${t}: ${toolDescriptions[t]}`).join("\n");
|
||||
const toolsList = tools.length > 0 ? tools.map((t) => `- ${t}: ${toolDescriptions[t]}`).join("\n") : "(none)";
|
||||
|
||||
// Build guidelines based on which tools are actually available
|
||||
const guidelinesList: string[] = [];
|
||||
|
|
@ -222,8 +222,9 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
|
|||
const hasLs = tools.includes("ls");
|
||||
const hasRead = tools.includes("read");
|
||||
|
||||
// Read-only mode notice (no bash, edit, or write)
|
||||
if (!hasBash && !hasEdit && !hasWrite) {
|
||||
// Read-only mode notice (only if we have some read-only tools but no write tools)
|
||||
// Skip this if there are no built-in tools at all (extensions may provide write capabilities)
|
||||
if (tools.length > 0 && !hasBash && !hasEdit && !hasWrite) {
|
||||
guidelinesList.push("You are in READ-ONLY mode - you cannot modify files or execute arbitrary commands");
|
||||
}
|
||||
|
||||
|
|
@ -265,7 +266,9 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
|
|||
|
||||
// Always include these
|
||||
guidelinesList.push("Be concise in your responses");
|
||||
guidelinesList.push("Show file paths clearly when working with files");
|
||||
if (tools.length > 0) {
|
||||
guidelinesList.push("Show file paths clearly when working with files");
|
||||
}
|
||||
|
||||
const guidelines = guidelinesList.map((g) => `- ${g}`).join("\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -177,7 +177,15 @@ function buildSessionOptions(
|
|||
}
|
||||
|
||||
// Tools
|
||||
if (parsed.tools) {
|
||||
if (parsed.noTools) {
|
||||
// --no-tools: start with no built-in tools
|
||||
// --tools can still add specific ones back
|
||||
if (parsed.tools && parsed.tools.length > 0) {
|
||||
options.tools = parsed.tools.map((name) => allTools[name]);
|
||||
} else {
|
||||
options.tools = [];
|
||||
}
|
||||
} else if (parsed.tools) {
|
||||
options.tools = parsed.tools.map((name) => allTools[name]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,6 +170,24 @@ describe("parseArgs", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("--no-tools flag", () => {
|
||||
test("parses --no-tools flag", () => {
|
||||
const result = parseArgs(["--no-tools"]);
|
||||
expect(result.noTools).toBe(true);
|
||||
});
|
||||
|
||||
test("parses --no-tools with explicit --tools flags", () => {
|
||||
const result = parseArgs(["--no-tools", "--tools", "read,bash"]);
|
||||
expect(result.noTools).toBe(true);
|
||||
expect(result.tools).toEqual(["read", "bash"]);
|
||||
});
|
||||
|
||||
test("parses --tools with empty string", () => {
|
||||
const result = parseArgs(["--tools", ""]);
|
||||
expect(result.tools).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("messages and file args", () => {
|
||||
test("parses plain text messages", () => {
|
||||
const result = parseArgs(["hello", "world"]);
|
||||
|
|
|
|||
65
packages/coding-agent/test/system-prompt.test.ts
Normal file
65
packages/coding-agent/test/system-prompt.test.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import { describe, expect, test } from "vitest";
|
||||
import { buildSystemPrompt } from "../src/core/system-prompt.js";
|
||||
|
||||
describe("buildSystemPrompt", () => {
|
||||
describe("empty tools", () => {
|
||||
test("does not show READ-ONLY mode when no built-in tools", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: [],
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
});
|
||||
|
||||
// Should not mention READ-ONLY mode when there are no tools
|
||||
// (extensions may provide write capabilities)
|
||||
expect(prompt).not.toContain("READ-ONLY mode");
|
||||
});
|
||||
|
||||
test("shows (none) for empty tools list", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: [],
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
});
|
||||
|
||||
expect(prompt).toContain("Available tools:\n(none)");
|
||||
});
|
||||
|
||||
test("does not show file paths guideline when no tools", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: [],
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
});
|
||||
|
||||
expect(prompt).not.toContain("Show file paths clearly");
|
||||
});
|
||||
});
|
||||
|
||||
describe("read-only tools", () => {
|
||||
test("shows READ-ONLY mode when only read tools available", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: ["read", "grep", "find", "ls"],
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
});
|
||||
|
||||
expect(prompt).toContain("READ-ONLY mode");
|
||||
});
|
||||
});
|
||||
|
||||
describe("default tools", () => {
|
||||
test("does not show READ-ONLY mode with default tools", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
});
|
||||
|
||||
expect(prompt).not.toContain("READ-ONLY mode");
|
||||
expect(prompt).toContain("- read:");
|
||||
expect(prompt).toContain("- bash:");
|
||||
expect(prompt).toContain("- edit:");
|
||||
expect(prompt).toContain("- write:");
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue