feat(coding-agent): allowed toggling workspace tree in system prompt
- Added `includeWorkspaceTree` configuration setting to optionally render the workspace directory tree. - Configured the system prompt template and SDK to respect this toggle, allowing users to disable the tree to prevent prompt cache invalidation.
This commit is contained in:
@@ -967,6 +967,18 @@ export const SETTINGS_SCHEMA = {
|
||||
},
|
||||
},
|
||||
|
||||
includeWorkspaceTree: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
ui: {
|
||||
tab: "model",
|
||||
group: "Prompt",
|
||||
label: "Include Workspace Tree",
|
||||
description:
|
||||
"Render the workspace directory tree in the system prompt. WARNING: This can bust prompt caching across sessions when files are modified.",
|
||||
},
|
||||
},
|
||||
|
||||
personality: {
|
||||
type: "enum",
|
||||
values: ["default", "friendly", "pragmatic", "none"] as const,
|
||||
|
||||
@@ -29,6 +29,7 @@ Before making changes within these directories, you MUST read:
|
||||
The context files above are loaded automatically. You NEVER `search`/`find` for `AGENTS.md`, `CLAUDE.md`, `.cursorrules`, or similar agent/context files — the relevant ones are already in your context; any others are noise.
|
||||
{{/ifAny}}
|
||||
|
||||
{{#if includeWorkspaceTree}}
|
||||
{{#if workspaceTree.rendered}}
|
||||
<workspace-tree>
|
||||
Working directory layout (sorted by mtime, recent first; depth ≤ 3):
|
||||
@@ -38,6 +39,7 @@ Working directory layout (sorted by mtime, recent first; depth ≤ 3):
|
||||
{{/if}}
|
||||
</workspace-tree>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
Today is {{date}}, and the current working directory is '{{cwd}}'.
|
||||
|
||||
|
||||
@@ -796,6 +796,7 @@ export interface BuildSystemPromptOptions {
|
||||
customPrompt?: string;
|
||||
appendPrompt?: string;
|
||||
inlineToolDescriptors?: boolean;
|
||||
includeWorkspaceTree?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -813,6 +814,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
||||
contextFiles: options.contextFiles,
|
||||
appendSystemPrompt: options.appendPrompt,
|
||||
inlineToolDescriptors: options.inlineToolDescriptors,
|
||||
includeWorkspaceTree: options.includeWorkspaceTree,
|
||||
toolNames: options.tools?.map(tool => tool.name),
|
||||
tools: toolMap ? buildSystemPromptToolMetadata(toolMap) : undefined,
|
||||
});
|
||||
@@ -1120,9 +1122,12 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||
// startup does not perform a second recursive filesystem search. Subagents
|
||||
// inherit the parent's resolved values via options.
|
||||
const STARTUP_SCAN_DEADLINE_MS = 5000;
|
||||
const includeWorkspaceTree = settings.get("includeWorkspaceTree") ?? false;
|
||||
const workspaceTreePromise: Promise<WorkspaceTree> = options.workspaceTree
|
||||
? Promise.resolve(options.workspaceTree)
|
||||
: logger.time("buildWorkspaceTree", () => buildWorkspaceTree(cwd, { timeoutMs: STARTUP_SCAN_DEADLINE_MS }));
|
||||
: includeWorkspaceTree
|
||||
? logger.time("buildWorkspaceTree", () => buildWorkspaceTree(cwd, { timeoutMs: STARTUP_SCAN_DEADLINE_MS }))
|
||||
: Promise.resolve({ rootPath: cwd, rendered: "", truncated: false, totalLines: 0, agentsMdFiles: [] });
|
||||
workspaceTreePromise.catch(() => {});
|
||||
|
||||
// Independent discoveries that depend only on cwd/agentDir — kicked off in parallel and awaited
|
||||
@@ -2101,6 +2106,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||
const eagerTasks = settings.get("task.eager") !== "default";
|
||||
const eagerTasksAlways = settings.get("task.eager") === "always";
|
||||
const intentField = $flag("PI_INTENT_TRACING", settings.get("tools.intentTracing")) ? INTENT_FIELD : undefined;
|
||||
const includeWorkspaceTree = settings.get("includeWorkspaceTree") ?? false;
|
||||
const rebuildSystemPrompt = async (
|
||||
toolNames: string[],
|
||||
tools: Map<string, AgentTool>,
|
||||
@@ -2194,6 +2200,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||
taskBatch: settings.get("task.batch"),
|
||||
secretsEnabled,
|
||||
workspaceTree: workspaceTreePromise,
|
||||
includeWorkspaceTree,
|
||||
memoryRootEnabled: memoryBackend.id === "local",
|
||||
model: settings.get("includeModelInPrompt") ? getActiveModelString() : undefined,
|
||||
personality: agentKind === "sub" ? "none" : settings.get("personality"),
|
||||
|
||||
@@ -421,6 +421,8 @@ export interface BuildSystemPromptOptions {
|
||||
model?: string;
|
||||
/** Personality preset rendered into the default system prompt. "none" omits the block. Default: "default" */
|
||||
personality?: Personality;
|
||||
/** Whether to include the workspace directory tree in the system prompt. Default: false */
|
||||
includeWorkspaceTree?: boolean;
|
||||
}
|
||||
|
||||
/** Result of building provider-facing system prompt messages. */
|
||||
@@ -461,6 +463,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
||||
memoryRootEnabled = false,
|
||||
model,
|
||||
personality = "default",
|
||||
includeWorkspaceTree = false,
|
||||
} = options;
|
||||
const inlineToolDescriptors = providedInlineToolDescriptors ?? false;
|
||||
const resolvedCwd = cwd ?? getProjectDir();
|
||||
@@ -523,9 +526,17 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
||||
const workspaceTreePromise =
|
||||
providedWorkspaceTree !== undefined
|
||||
? Promise.resolve(providedWorkspaceTree)
|
||||
: logger.time("buildWorkspaceTree", () =>
|
||||
buildWorkspaceTree(resolvedCwd, { timeoutMs: SYSTEM_PROMPT_PREP_TIMEOUT_MS }),
|
||||
);
|
||||
: includeWorkspaceTree
|
||||
? logger.time("buildWorkspaceTree", () =>
|
||||
buildWorkspaceTree(resolvedCwd, { timeoutMs: SYSTEM_PROMPT_PREP_TIMEOUT_MS }),
|
||||
)
|
||||
: Promise.resolve({
|
||||
rootPath: resolvedCwd,
|
||||
rendered: "",
|
||||
truncated: false,
|
||||
totalLines: 0,
|
||||
agentsMdFiles: [],
|
||||
});
|
||||
const skillsPromise: Promise<Skill[]> =
|
||||
providedSkills !== undefined
|
||||
? Promise.resolve(providedSkills)
|
||||
@@ -670,6 +681,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
||||
secretsEnabled,
|
||||
hasMemoryRoot: memoryRootEnabled,
|
||||
hasObsidian: hasObsidian(),
|
||||
includeWorkspaceTree,
|
||||
};
|
||||
const rendered = prompt.render(resolvedCustomPrompt ? customSystemPromptTemplate : systemPromptTemplate, data);
|
||||
const systemPrompt = [rendered];
|
||||
|
||||
@@ -121,6 +121,7 @@ describe("SYSTEM.md prompt assembly", () => {
|
||||
rules: [],
|
||||
toolNames: ["read"],
|
||||
tools: READ_TOOL,
|
||||
includeWorkspaceTree: true,
|
||||
workspaceTree: {
|
||||
rootPath: projectDir,
|
||||
rendered: ".\n - nested/",
|
||||
|
||||
Reference in New Issue
Block a user