system.ts 4.0 KB

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