remove built-in SYSTEM_PROMPT.md loading
System prompt is now assembled via x/prime in the agent prompt array, same as all other prompt fragments. Remove expandSystemPrompt and the agentPrompt field — resolved prompt goes directly into preamble.
This commit is contained in:
parent
d0e1b6f6ef
commit
cafeff4a1e
|
|
@ -186,7 +186,6 @@ func (s *agent) handleCommand(ctx context.Context, input string, handler EventHa
|
|||
s.cfg.Tools = env.tools
|
||||
s.cfg.Exec = env.exec
|
||||
s.cfg.GenerationParams = env.genParams
|
||||
s.agentPrompt = env.agentPrompt
|
||||
s.agentName = name
|
||||
s.session = nil
|
||||
s.sessionID = NewSessionID()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"slices"
|
||||
"strconv"
|
||||
|
|
@ -32,7 +31,6 @@ type AgentEnv struct {
|
|||
exec toolExecutor
|
||||
Hooks Hooks
|
||||
preamble string
|
||||
agentPrompt string // agent-specific suffix appended after the base system prompt
|
||||
genParams backend.GenerationParams
|
||||
Messages []string
|
||||
}
|
||||
|
|
@ -57,14 +55,14 @@ func BuildAgentEnv(cfg *config.Config, d tools.Dispatcher, cwd string) AgentEnv
|
|||
allTools := toolInfosToBackend(allToolInfos)
|
||||
|
||||
hooks := Hooks{}
|
||||
agentPrompt := ""
|
||||
var preamble string
|
||||
var genParams backend.GenerationParams
|
||||
if cfg != nil {
|
||||
for k, v := range cfg.Hooks {
|
||||
hooks[k] = []string(v)
|
||||
}
|
||||
if resolved, err := resolvePrompt(cfg.Prompt, cwd); err == nil {
|
||||
agentPrompt = resolved
|
||||
preamble = resolved
|
||||
}
|
||||
genParams = backend.GenerationParams{
|
||||
MaxTokens: cfg.MaxTokens,
|
||||
|
|
@ -81,13 +79,6 @@ func BuildAgentEnv(cfg *config.Config, d tools.Dispatcher, cwd string) AgentEnv
|
|||
}
|
||||
}
|
||||
|
||||
path := DefaultPromptsDir() + "/SYSTEM_PROMPT.md"
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("loadSystemPrompt: %s: %v", path, err))
|
||||
}
|
||||
preamble := expandSystemPrompt(string(data), cwd)
|
||||
|
||||
exec := func(ctx context.Context, name string, args json.RawMessage) (string, error) {
|
||||
server, ok := serverOf[name]
|
||||
if !ok {
|
||||
|
|
@ -110,7 +101,6 @@ func BuildAgentEnv(cfg *config.Config, d tools.Dispatcher, cwd string) AgentEnv
|
|||
exec: exec,
|
||||
Hooks: hooks,
|
||||
preamble: preamble,
|
||||
agentPrompt: agentPrompt,
|
||||
genParams: genParams,
|
||||
Messages: messages,
|
||||
}
|
||||
|
|
@ -122,31 +112,6 @@ func DefaultPromptsDir() string {
|
|||
return paths.CfgDir() + "/prompts"
|
||||
}
|
||||
|
||||
func expandSystemPrompt(content, cwd string) string {
|
||||
if cwd == "" {
|
||||
cwd, _ = os.Getwd()
|
||||
}
|
||||
isGit := "false"
|
||||
if _, err := os.Stat(filepath.Join(cwd, ".git")); err == nil {
|
||||
isGit = "true"
|
||||
}
|
||||
mapper := func(key string) string {
|
||||
switch key {
|
||||
case "PWD":
|
||||
return cwd
|
||||
case "PRIME_DATE":
|
||||
return time.Now().Format("2006-01-02")
|
||||
case "PRIME_PLATFORM":
|
||||
return strings.ToLower(runtime.GOOS)
|
||||
case "PRIME_IS_GIT_REPO":
|
||||
return isGit
|
||||
default:
|
||||
return os.Getenv(key)
|
||||
}
|
||||
}
|
||||
return os.Expand(content, mapper)
|
||||
}
|
||||
|
||||
|
||||
// AgentConfigPath resolves the config file path for a named agent.
|
||||
func AgentConfigPath(agentsDir, name string) string {
|
||||
|
|
@ -204,7 +169,6 @@ type agent struct {
|
|||
newDispatcher func() tools.Dispatcher
|
||||
newBackend func(string) (backend.Backend, error)
|
||||
cwd string
|
||||
agentPrompt string // agent-specific prompt suffix; kept for system prompt rebuilds
|
||||
startupMessages []string
|
||||
currentAction atomic.Pointer[actionHandle]
|
||||
fifo PromptFIFO
|
||||
|
|
@ -318,7 +282,6 @@ func NewAgentCore(cfg AgentCoreConfig) Core {
|
|||
sessionsDir: cfg.SessionsDir,
|
||||
sessionID: cfg.SessionID,
|
||||
cwd: paths.ExpandHome(cfg.CWD),
|
||||
agentPrompt: cfg.Env.agentPrompt,
|
||||
startupMessages: cfg.Env.Messages,
|
||||
dispatcher: cfg.Env.dispatcher,
|
||||
newDispatcher: cfg.NewDispatcher,
|
||||
|
|
@ -512,9 +475,6 @@ func (s *agent) spawnContext(ctx context.Context, handler EventHandler) string {
|
|||
handler(infoEvent(result.Warning))
|
||||
}
|
||||
var parts []string
|
||||
if s.agentPrompt != "" {
|
||||
parts = append(parts, s.agentPrompt)
|
||||
}
|
||||
if result.Context != "" {
|
||||
parts = append(parts, result.Context)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -526,45 +526,6 @@ func TestAgentSpawnFiresOnce(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// --- expandSystemPrompt ---
|
||||
|
||||
func TestExpandSystemPrompt_IsGitTrue(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
os.Mkdir(filepath.Join(dir, ".git"), 0700)
|
||||
got := expandSystemPrompt("${PRIME_IS_GIT_REPO}", dir)
|
||||
if got != "true" {
|
||||
t.Errorf("got %q; want true", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpandSystemPrompt_IsGitFalse(t *testing.T) {
|
||||
got := expandSystemPrompt("${PRIME_IS_GIT_REPO}", t.TempDir())
|
||||
if got != "false" {
|
||||
t.Errorf("got %q; want false", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpandSystemPrompt_PWDUsesCWD(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
got := expandSystemPrompt("${PWD}", dir)
|
||||
if got != dir {
|
||||
t.Errorf("got %q; want %q", got, dir)
|
||||
}
|
||||
}
|
||||
|
||||
// --- BuildAgentEnv: missing system prompt ---
|
||||
|
||||
func TestBuildAgentEnv_MissingSystemPrompt(t *testing.T) {
|
||||
t.Setenv("OLLIE_CFG_PATH", t.TempDir()) // no SYSTEM_PROMPT.md written
|
||||
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Error("expected panic from BuildAgentEnv; got none")
|
||||
}
|
||||
}()
|
||||
BuildAgentEnv(nil, tools.NewDispatcher(), "")
|
||||
}
|
||||
|
||||
// --- panic recovery ---
|
||||
|
||||
func TestSubmit_PanicRecovery(t *testing.T) {
|
||||
|
|
@ -2237,26 +2198,20 @@ func TestFirstSentence_ShortNoSentenceEnd(t *testing.T) {
|
|||
|
||||
// --- BuildAgentEnv (nil config path) ---
|
||||
|
||||
func setupCfgDir(t *testing.T, preamble string) string {
|
||||
func setupCfgDir(t *testing.T) string {
|
||||
t.Helper()
|
||||
dir := t.TempDir()
|
||||
if err := os.MkdirAll(dir+"/prompts", 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(dir+"/prompts/SYSTEM_PROMPT.md", []byte(preamble), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("OLLIE_CFG_PATH", dir)
|
||||
return dir
|
||||
}
|
||||
|
||||
func TestBuildAgentEnv_NilConfig(t *testing.T) {
|
||||
setupCfgDir(t, "base prompt")
|
||||
setupCfgDir(t)
|
||||
d := tools.NewDispatcher()
|
||||
env := BuildAgentEnv(nil, d, t.TempDir())
|
||||
|
||||
if env.preamble != "base prompt" {
|
||||
t.Errorf("preamble = %q; want %q", env.preamble, "base prompt")
|
||||
if env.preamble != "" {
|
||||
t.Errorf("preamble = %q; want empty", env.preamble)
|
||||
}
|
||||
if len(env.Hooks) != 0 {
|
||||
t.Errorf("expected no hooks; got %v", env.Hooks)
|
||||
|
|
@ -2269,23 +2224,19 @@ func TestBuildAgentEnv_NilConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestBuildAgentEnv_AgentPromptAppended(t *testing.T) {
|
||||
setupCfgDir(t, "base prompt")
|
||||
func TestBuildAgentEnv_PromptBecomesPreamble(t *testing.T) {
|
||||
setupCfgDir(t)
|
||||
d := tools.NewDispatcher()
|
||||
cfg := &config.Config{Prompt: config.Prompt{Value: []string{"agent suffix"}}}
|
||||
cfg := &config.Config{Prompt: config.Prompt{Value: []string{"the prompt"}}}
|
||||
env := BuildAgentEnv(cfg, d, t.TempDir())
|
||||
|
||||
// preamble contains only the system prompt; agent prompt is kept separate
|
||||
if !strings.Contains(env.preamble, "base prompt") {
|
||||
t.Errorf("preamble missing base: %q", env.preamble)
|
||||
}
|
||||
if env.agentPrompt != "agent suffix" {
|
||||
t.Errorf("agentPrompt = %q; want %q", env.agentPrompt, "agent suffix")
|
||||
if env.preamble != "the prompt" {
|
||||
t.Errorf("preamble = %q; want %q", env.preamble, "the prompt")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildAgentEnv_HooksAndParams(t *testing.T) {
|
||||
setupCfgDir(t, "base")
|
||||
setupCfgDir(t)
|
||||
d := tools.NewDispatcher()
|
||||
temp := 0.7
|
||||
cfg := &config.Config{
|
||||
|
|
@ -2307,7 +2258,7 @@ func TestBuildAgentEnv_HooksAndParams(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBuildAgentEnv_ExecUnknownTool(t *testing.T) {
|
||||
setupCfgDir(t, "base")
|
||||
setupCfgDir(t)
|
||||
d := tools.NewDispatcher()
|
||||
env := BuildAgentEnv(nil, d, t.TempDir())
|
||||
|
||||
|
|
@ -2360,7 +2311,7 @@ func (m *mockTrustedSetter) CallTool(ctx context.Context, tool string, args json
|
|||
}
|
||||
|
||||
func TestBuildAgentEnv_ListToolsError(t *testing.T) {
|
||||
setupCfgDir(t, "")
|
||||
setupCfgDir(t)
|
||||
d := &mockDispatcher{listErr: fmt.Errorf("boom")}
|
||||
env := BuildAgentEnv(nil, d, t.TempDir())
|
||||
if len(env.Messages) != 1 || !strings.Contains(env.Messages[0], "boom") {
|
||||
|
|
@ -2369,7 +2320,7 @@ func TestBuildAgentEnv_ListToolsError(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBuildAgentEnv_ToolsPopulated(t *testing.T) {
|
||||
setupCfgDir(t, "")
|
||||
setupCfgDir(t)
|
||||
d := &mockDispatcher{
|
||||
tools: []tools.ToolInfo{{Server: "s1", Name: "mytool", Description: "desc", InputSchema: json.RawMessage(`{}`)}},
|
||||
}
|
||||
|
|
@ -2380,7 +2331,7 @@ func TestBuildAgentEnv_ToolsPopulated(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBuildAgentEnv_TrustedTools(t *testing.T) {
|
||||
setupCfgDir(t, "")
|
||||
setupCfgDir(t)
|
||||
setter := &mockTrustedSetter{}
|
||||
d := &mockDispatcher{servers: map[string]tools.Server{"execute": setter}}
|
||||
cfg := &config.Config{TrustedTools: []string{"bash"}}
|
||||
|
|
@ -2390,19 +2341,18 @@ func TestBuildAgentEnv_TrustedTools(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestBuildAgentEnv_AgentPromptNoSystemPrompt(t *testing.T) {
|
||||
// Empty system prompt file — agentPrompt is kept separate from preamble.
|
||||
setupCfgDir(t, "")
|
||||
func TestBuildAgentEnv_PromptOnly(t *testing.T) {
|
||||
setupCfgDir(t)
|
||||
d := tools.NewDispatcher()
|
||||
cfg := &config.Config{Prompt: config.Prompt{Value: []string{"only agent"}}}
|
||||
env := BuildAgentEnv(cfg, d, t.TempDir())
|
||||
if env.agentPrompt != "only agent" {
|
||||
t.Errorf("agentPrompt = %q; want %q", env.agentPrompt, "only agent")
|
||||
if env.preamble != "only agent" {
|
||||
t.Errorf("preamble = %q; want %q", env.preamble, "only agent")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildAgentEnv_ExecDispatchSuccess(t *testing.T) {
|
||||
setupCfgDir(t, "")
|
||||
setupCfgDir(t)
|
||||
d := &mockDispatcher{
|
||||
tools: []tools.ToolInfo{{Server: "s1", Name: "mytool"}},
|
||||
dispatch: func(ctx context.Context, server, tool string, args json.RawMessage) (json.RawMessage, error) {
|
||||
|
|
@ -2420,7 +2370,7 @@ func TestBuildAgentEnv_ExecDispatchSuccess(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBuildAgentEnv_ExecDispatchError(t *testing.T) {
|
||||
setupCfgDir(t, "")
|
||||
setupCfgDir(t)
|
||||
d := &mockDispatcher{
|
||||
tools: []tools.ToolInfo{{Server: "s1", Name: "mytool"}},
|
||||
dispatch: func(ctx context.Context, server, tool string, args json.RawMessage) (json.RawMessage, error) {
|
||||
|
|
@ -2435,7 +2385,7 @@ func TestBuildAgentEnv_ExecDispatchError(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBuildAgentEnv_ExecToolResultIsError(t *testing.T) {
|
||||
setupCfgDir(t, "")
|
||||
setupCfgDir(t)
|
||||
d := &mockDispatcher{
|
||||
tools: []tools.ToolInfo{{Server: "s1", Name: "mytool"}},
|
||||
dispatch: func(ctx context.Context, server, tool string, args json.RawMessage) (json.RawMessage, error) {
|
||||
|
|
|
|||
Reference in New Issue