-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Expand file tree
/
Copy pathsystem-prompt.ts
More file actions
172 lines (142 loc) · 5.97 KB
/
system-prompt.ts
File metadata and controls
172 lines (142 loc) · 5.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/**
* System prompt construction and project context loading
*/
import { getDocsPath, getExamplesPath, getReadmePath } from "../config.js";
import { formatSkillsForPrompt, type Skill } from "./skills.js";
export interface BuildSystemPromptOptions {
/** Custom system prompt (replaces default). */
customPrompt?: string;
/** Tools to include in prompt. Default: [read, bash, edit, write] */
selectedTools?: string[];
/** Optional one-line tool snippets keyed by tool name. */
toolSnippets?: Record<string, string>;
/** Additional guideline bullets appended to the default system prompt guidelines. */
promptGuidelines?: string[];
/** Text to append to system prompt. */
appendSystemPrompt?: string;
/** Working directory. Default: process.cwd() */
cwd?: string;
/** Pre-loaded context files. */
contextFiles?: Array<{ path: string; content: string }>;
/** Pre-loaded skills. */
skills?: Skill[];
}
/** Build the system prompt with tools, guidelines, and context */
export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {
const {
customPrompt,
selectedTools,
toolSnippets,
promptGuidelines,
appendSystemPrompt,
cwd,
contextFiles: providedContextFiles,
skills: providedSkills,
} = options;
const resolvedCwd = cwd ?? process.cwd();
const promptCwd = resolvedCwd.replace(/\\/g, "/");
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, "0");
const day = String(now.getDate()).padStart(2, "0");
const date = `${year}-${month}-${day}`;
const appendSection = appendSystemPrompt ? `\n\n${appendSystemPrompt}` : "";
const contextFiles = providedContextFiles ?? [];
const skills = providedSkills ?? [];
if (customPrompt) {
let prompt = customPrompt;
if (appendSection) {
prompt += appendSection;
}
// Append project context files
if (contextFiles.length > 0) {
prompt += "\n\n# Project Context\n\n";
prompt += "Project-specific instructions and guidelines:\n\n";
for (const { path: filePath, content } of contextFiles) {
prompt += `## ${filePath}\n\n${content}\n\n`;
}
}
// Append skills section (only if read tool is available)
const customPromptHasRead = !selectedTools || selectedTools.includes("read");
if (customPromptHasRead && skills.length > 0) {
prompt += formatSkillsForPrompt(skills);
}
// Add date and working directory last
prompt += `\nCurrent date: ${date}`;
prompt += `\nCurrent working directory: ${promptCwd}`;
return prompt;
}
// Get absolute paths to documentation and examples
const readmePath = getReadmePath();
const docsPath = getDocsPath();
const examplesPath = getExamplesPath();
// Build tools list based on selected tools.
// A tool appears in Available tools only when the caller provides a one-line snippet.
const tools = selectedTools || ["read", "bash", "edit", "write"];
const visibleTools = tools.filter((name) => !!toolSnippets?.[name]);
const toolsList =
visibleTools.length > 0 ? visibleTools.map((name) => `- ${name}: ${toolSnippets![name]}`).join("\n") : "(none)";
// Build guidelines based on which tools are actually available
const guidelinesList: string[] = [];
const guidelinesSet = new Set<string>();
const addGuideline = (guideline: string): void => {
if (guidelinesSet.has(guideline)) {
return;
}
guidelinesSet.add(guideline);
guidelinesList.push(guideline);
};
const hasBash = tools.includes("bash");
const hasGrep = tools.includes("grep");
const hasFind = tools.includes("find");
const hasLs = tools.includes("ls");
const hasRead = tools.includes("read");
// File exploration guidelines
if (hasBash && !hasGrep && !hasFind && !hasLs) {
addGuideline("Use bash for file operations like ls, rg, find");
} else if (hasBash && (hasGrep || hasFind || hasLs)) {
addGuideline("Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)");
}
for (const guideline of promptGuidelines ?? []) {
const normalized = guideline.trim();
if (normalized.length > 0) {
addGuideline(normalized);
}
}
// Always include these
addGuideline("Be concise in your responses");
addGuideline("Show file paths clearly when working with files");
const guidelines = guidelinesList.map((g) => `- ${g}`).join("\n");
let prompt = `You are an expert coding assistant operating inside pi, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.
Available tools:
${toolsList}
In addition to the tools above, you may have access to other custom tools depending on the project.
Guidelines:
${guidelines}
Pi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI):
- Main documentation: ${readmePath}
- Additional docs: ${docsPath}
- Examples: ${examplesPath} (extensions, custom tools, SDK)
- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), pi packages (docs/packages.md)
- When working on pi topics, read the docs and examples, and follow .md cross-references before implementing
- Always read pi .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;
if (appendSection) {
prompt += appendSection;
}
// Append project context files
if (contextFiles.length > 0) {
prompt += "\n\n# Project Context\n\n";
prompt += "Project-specific instructions and guidelines:\n\n";
for (const { path: filePath, content } of contextFiles) {
prompt += `## ${filePath}\n\n${content}\n\n`;
}
}
// Append skills section (only if read tool is available)
if (hasRead && skills.length > 0) {
prompt += formatSkillsForPrompt(skills);
}
// Add date and working directory last
prompt += `\nCurrent date: ${date}`;
prompt += `\nCurrent working directory: ${promptCwd}`;
return prompt;
}