system.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { Ripgrep } from "../file/ripgrep"
  2. import { Global } from "../global"
  3. import { Filesystem } from "../util/filesystem"
  4. import { Config } from "../config/config"
  5. import { Instance } from "../project/instance"
  6. import path from "path"
  7. import os from "os"
  8. import PROMPT_ANTHROPIC from "./prompt/anthropic.txt"
  9. import PROMPT_ANTHROPIC_WITHOUT_TODO from "./prompt/qwen.txt"
  10. import PROMPT_POLARIS from "./prompt/polaris.txt"
  11. import PROMPT_BEAST from "./prompt/beast.txt"
  12. import PROMPT_GEMINI from "./prompt/gemini.txt"
  13. import PROMPT_ANTHROPIC_SPOOF from "./prompt/anthropic_spoof.txt"
  14. import PROMPT_SUMMARIZE from "./prompt/summarize.txt"
  15. import PROMPT_TITLE from "./prompt/title.txt"
  16. import PROMPT_CODEX from "./prompt/codex.txt"
  17. export namespace SystemPrompt {
  18. export function header(providerID: string) {
  19. if (providerID.includes("anthropic")) return [PROMPT_ANTHROPIC_SPOOF.trim()]
  20. return []
  21. }
  22. export function provider(modelID: string) {
  23. if (modelID.includes("gpt-5")) return [PROMPT_CODEX]
  24. if (modelID.includes("gpt-") || modelID.includes("o1") || modelID.includes("o3")) return [PROMPT_BEAST]
  25. if (modelID.includes("gemini-")) return [PROMPT_GEMINI]
  26. if (modelID.includes("claude")) return [PROMPT_ANTHROPIC]
  27. if (modelID.includes("polaris-alpha")) return [PROMPT_POLARIS]
  28. return [PROMPT_ANTHROPIC_WITHOUT_TODO]
  29. }
  30. export async function environment() {
  31. const project = Instance.project
  32. return [
  33. [
  34. `Here is some useful information about the environment you are running in:`,
  35. `<env>`,
  36. ` Working directory: ${Instance.directory}`,
  37. ` Is directory a git repo: ${project.vcs === "git" ? "yes" : "no"}`,
  38. ` Platform: ${process.platform}`,
  39. ` Today's date: ${new Date().toDateString()}`,
  40. `</env>`,
  41. `<project>`,
  42. ` ${
  43. project.vcs === "git"
  44. ? await Ripgrep.tree({
  45. cwd: Instance.directory,
  46. limit: 200,
  47. })
  48. : ""
  49. }`,
  50. `</project>`,
  51. ].join("\n"),
  52. ]
  53. }
  54. const LOCAL_RULE_FILES = [
  55. "AGENTS.md",
  56. "CLAUDE.md",
  57. "CONTEXT.md", // deprecated
  58. ]
  59. const GLOBAL_RULE_FILES = [
  60. path.join(Global.Path.config, "AGENTS.md"),
  61. path.join(os.homedir(), ".claude", "CLAUDE.md"),
  62. ]
  63. export async function custom() {
  64. const config = await Config.get()
  65. const paths = new Set<string>()
  66. for (const localRuleFile of LOCAL_RULE_FILES) {
  67. const matches = await Filesystem.findUp(localRuleFile, Instance.directory, Instance.worktree)
  68. if (matches.length > 0) {
  69. matches.forEach((path) => paths.add(path))
  70. break
  71. }
  72. }
  73. for (const globalRuleFile of GLOBAL_RULE_FILES) {
  74. if (await Bun.file(globalRuleFile).exists()) {
  75. paths.add(globalRuleFile)
  76. break
  77. }
  78. }
  79. if (config.instructions) {
  80. for (let instruction of config.instructions) {
  81. if (instruction.startsWith("~/")) {
  82. instruction = path.join(os.homedir(), instruction.slice(2))
  83. }
  84. let matches: string[] = []
  85. if (path.isAbsolute(instruction)) {
  86. matches = await Array.fromAsync(
  87. new Bun.Glob(path.basename(instruction)).scan({
  88. cwd: path.dirname(instruction),
  89. absolute: true,
  90. onlyFiles: true,
  91. }),
  92. ).catch(() => [])
  93. } else {
  94. matches = await Filesystem.globUp(instruction, Instance.directory, Instance.worktree).catch(() => [])
  95. }
  96. matches.forEach((path) => paths.add(path))
  97. }
  98. }
  99. const found = Array.from(paths).map((p) =>
  100. Bun.file(p)
  101. .text()
  102. .catch(() => "")
  103. .then((x) => "Instructions from: " + p + "\n" + x),
  104. )
  105. return Promise.all(found).then((result) => result.filter(Boolean))
  106. }
  107. export function summarize(providerID: string) {
  108. switch (providerID) {
  109. case "anthropic":
  110. return [PROMPT_ANTHROPIC_SPOOF.trim(), PROMPT_SUMMARIZE]
  111. default:
  112. return [PROMPT_SUMMARIZE]
  113. }
  114. }
  115. export function title(providerID: string) {
  116. switch (providerID) {
  117. case "anthropic":
  118. return [PROMPT_ANTHROPIC_SPOOF.trim(), PROMPT_TITLE]
  119. default:
  120. return [PROMPT_TITLE]
  121. }
  122. }
  123. }