2025-06-30 18:46:18 +00:00
import { Ripgrep } from "../file/ripgrep"
2025-06-20 19:14:12 +00:00
import { Global } from "../global"
2025-06-12 21:04:34 +00:00
import { Filesystem } from "../util/filesystem"
2025-07-03 03:27:04 +00:00
import { Config } from "../config/config"
2025-12-22 00:44:56 +00:00
import { Skill } from "../skill"
2025-09-01 21:15:49 +00:00
import { Instance } from "../project/instance"
2025-06-20 19:14:12 +00:00
import path from "path"
import os from "os"
2025-06-12 21:04:34 +00:00
import PROMPT_ANTHROPIC from "./prompt/anthropic.txt"
2025-07-29 15:27:18 +00:00
import PROMPT_ANTHROPIC_WITHOUT_TODO from "./prompt/qwen.txt"
2025-11-08 02:07:59 +00:00
import PROMPT_POLARIS from "./prompt/polaris.txt"
2025-07-09 16:11:54 +00:00
import PROMPT_BEAST from "./prompt/beast.txt"
2025-07-16 01:13:11 +00:00
import PROMPT_GEMINI from "./prompt/gemini.txt"
2025-06-12 21:04:34 +00:00
import PROMPT_ANTHROPIC_SPOOF from "./prompt/anthropic_spoof.txt"
2025-11-22 16:32:49 +00:00
import PROMPT_COMPACTION from "./prompt/compaction.txt"
2025-12-15 02:11:30 +00:00
2025-09-02 01:45:44 +00:00
import PROMPT_CODEX from "./prompt/codex.txt"
2025-12-04 02:09:03 +00:00
import type { Provider } from "@/provider/provider"
2025-06-12 21:04:34 +00:00
export namespace SystemPrompt {
2025-07-25 01:20:43 +00:00
export function header ( providerID : string ) {
if ( providerID . includes ( "anthropic" ) ) return [ PROMPT_ANTHROPIC_SPOOF . trim ( ) ]
return [ ]
}
2025-08-11 05:14:46 +00:00
2025-12-04 02:09:03 +00:00
export function provider ( model : Provider.Model ) {
if ( model . api . id . includes ( "gpt-5" ) ) return [ PROMPT_CODEX ]
if ( model . api . id . includes ( "gpt-" ) || model . api . id . includes ( "o1" ) || model . api . id . includes ( "o3" ) )
return [ PROMPT_BEAST ]
if ( model . api . id . includes ( "gemini-" ) ) return [ PROMPT_GEMINI ]
if ( model . api . id . includes ( "claude" ) ) return [ PROMPT_ANTHROPIC ]
if ( model . api . id . includes ( "polaris-alpha" ) ) return [ PROMPT_POLARIS ]
2025-07-29 15:27:18 +00:00
return [ PROMPT_ANTHROPIC_WITHOUT_TODO ]
2025-06-12 21:04:34 +00:00
}
2025-06-16 00:24:51 +00:00
export async function environment() {
2025-09-01 21:15:49 +00:00
const project = Instance . project
2025-06-12 21:04:34 +00:00
return [
[
` Here is some useful information about the environment you are running in: ` ,
` <env> ` ,
2025-09-01 21:15:49 +00:00
` Working directory: ${ Instance . directory } ` ,
` Is directory a git repo: ${ project . vcs === "git" ? "yes" : "no" } ` ,
2025-06-12 21:04:34 +00:00
` Platform: ${ process . platform } ` ,
` Today's date: ${ new Date ( ) . toDateString ( ) } ` ,
` </env> ` ,
2025-11-17 15:57:18 +00:00
` <files> ` ,
2025-06-30 18:46:18 +00:00
` ${
2025-09-01 21:15:49 +00:00
project . vcs === "git"
2025-06-30 18:46:18 +00:00
? await Ripgrep . tree ( {
2025-09-01 21:15:49 +00:00
cwd : Instance.directory ,
2025-06-30 18:46:18 +00:00
limit : 200 ,
} )
: ""
} ` ,
2025-11-17 15:57:18 +00:00
` </files> ` ,
2025-06-12 21:04:34 +00:00
] . join ( "\n" ) ,
]
}
2025-08-11 13:28:03 +00:00
const LOCAL_RULE_FILES = [
2025-06-12 21:04:34 +00:00
"AGENTS.md" ,
"CLAUDE.md" ,
"CONTEXT.md" , // deprecated
]
2025-08-11 13:28:03 +00:00
const GLOBAL_RULE_FILES = [
path . join ( Global . Path . config , "AGENTS.md" ) ,
path . join ( os . homedir ( ) , ".claude" , "CLAUDE.md" ) ,
]
2025-07-03 03:27:04 +00:00
2025-06-12 21:04:34 +00:00
export async function custom() {
2025-07-03 03:27:04 +00:00
const config = await Config . get ( )
2025-08-03 19:10:21 +00:00
const paths = new Set < string > ( )
2025-08-11 13:28:03 +00:00
for ( const localRuleFile of LOCAL_RULE_FILES ) {
2025-09-01 21:15:49 +00:00
const matches = await Filesystem . findUp ( localRuleFile , Instance . directory , Instance . worktree )
2025-08-11 13:28:03 +00:00
if ( matches . length > 0 ) {
matches . forEach ( ( path ) = > paths . add ( path ) )
break
}
2025-06-12 21:04:34 +00:00
}
2025-08-03 19:10:21 +00:00
2025-08-11 13:28:03 +00:00
for ( const globalRuleFile of GLOBAL_RULE_FILES ) {
if ( await Bun . file ( globalRuleFile ) . exists ( ) ) {
paths . add ( globalRuleFile )
break
}
}
2025-07-03 03:27:04 +00:00
if ( config . instructions ) {
2025-08-11 13:23:41 +00:00
for ( let instruction of config . instructions ) {
if ( instruction . startsWith ( "~/" ) ) {
instruction = path . join ( os . homedir ( ) , instruction . slice ( 2 ) )
}
let matches : string [ ] = [ ]
if ( path . isAbsolute ( instruction ) ) {
matches = await Array . fromAsync (
new Bun . Glob ( path . basename ( instruction ) ) . scan ( {
cwd : path.dirname ( instruction ) ,
absolute : true ,
onlyFiles : true ,
} ) ,
) . catch ( ( ) = > [ ] )
} else {
2025-11-08 01:59:02 +00:00
matches = await Filesystem . globUp ( instruction , Instance . directory , Instance . worktree ) . catch ( ( ) = > [ ] )
2025-08-11 13:23:41 +00:00
}
2025-08-03 19:10:21 +00:00
matches . forEach ( ( path ) = > paths . add ( path ) )
2025-07-03 03:27:04 +00:00
}
}
2025-08-03 19:10:21 +00:00
const found = Array . from ( paths ) . map ( ( p ) = >
Bun . file ( p )
. text ( )
2025-10-31 19:07:36 +00:00
. catch ( ( ) = > "" )
. then ( ( x ) = > "Instructions from: " + p + "\n" + x ) ,
2025-08-03 19:10:21 +00:00
)
2025-06-20 19:49:49 +00:00
return Promise . all ( found ) . then ( ( result ) = > result . filter ( Boolean ) )
2025-06-12 21:04:34 +00:00
}
2025-12-22 00:44:56 +00:00
export async function skills() {
const all = await Skill . all ( )
if ( all . length === 0 ) return [ ]
const lines = [
"You have access to skills listed in `<available_skills>`. When a task matches a skill's description, read its SKILL.md file to get detailed instructions." ,
"" ,
"<available_skills>" ,
]
for ( const skill of all ) {
lines . push ( " <skill>" )
lines . push ( ` <name> ${ skill . name } </name> ` )
lines . push ( ` <description> ${ skill . description } </description> ` )
lines . push ( ` <location> ${ skill . location } </location> ` )
lines . push ( " </skill>" )
}
lines . push ( "</available_skills>" )
return [ lines . join ( "\n" ) ]
}
2025-06-12 21:04:34 +00:00
}