Skip to content

Commit 966cda0

Browse files
author
Chris Warren-Smith
committed
LLAMA: nitro - update prompt
1 parent 8406b7f commit 966cda0

1 file changed

Lines changed: 104 additions & 27 deletions

File tree

llama/nitro.cpp

Lines changed: 104 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ struct NitroConfig {
7979
int penalty_last_n = 256;
8080
std::vector<std::string> knowledge_files;
8181
int rag_top_k = 5;
82+
bool thinking = true;
8283
// TOOL:RUN allowlist — if non-empty, only these program basenames may run.
8384
// Empty means "allow anything inside the sandbox" (original behaviour).
8485
std::vector<std::string> run_allowed;
@@ -467,6 +468,8 @@ static void load_settings(NitroConfig &cfg) {
467468
std::ostringstream oss; oss << f.rdbuf();
468469
std::string json = oss.str();
469470

471+
cfg.thinking = true;
472+
470473
// String fields
471474
settings_get_str(json, "model_path", cfg.model_path);
472475
settings_get_str(json, "embed_path", cfg.embed_path);
@@ -584,7 +587,7 @@ std::string unwrap(const std::string &input) {
584587
if (input.empty()) {
585588
return input;
586589
}
587-
590+
588591
size_t left = 0;
589592
size_t right = input.length() - 1;
590593

@@ -740,13 +743,46 @@ static bool make_dir(const std::string &path) {
740743
static std::string build_system_prompt(const std::vector<std::string> &knowledge_files,
741744
const std::string &sandbox) {
742745
std::string p;
743-
p += "You are Nitro, an agentic AI assistant for software development.\n"
746+
p +=
747+
"You are Nitro, an agentic AI assistant for software development. "
748+
"Proceed with caution, guided by logic and the pursuit of knowledge.\n\n"
749+
744750
"Your sandbox (project directory) is: " + sandbox + "\n\n"
745-
"## Tool protocol\n"
746-
" - Emit tool calls on their own new line. for example:\n\n"
751+
752+
"## Core Principle\n"
753+
"Always follow this loop: THINK → DECIDE → ACT → RESPOND\n\n"
754+
755+
"## Reasoning Protocol\n"
756+
"Use <|think|> to reason BEFORE acting. Keep it concise and structured.\n"
757+
"Format:\n"
758+
"<|think|>\n"
759+
"- What is the user asking?\n"
760+
"- Do I need external data (files, tools)?\n"
761+
"- What is the safest and most correct action?\n"
762+
"</|think|>\n\n"
763+
"Rules:\n"
764+
"- Do NOT call tools inside <|think|>\n"
765+
"- Do NOT include the final answer inside <|think|>\n"
766+
"- Always follow <|think|> with either a tool call OR a final answer\n"
767+
"- Skip <|think|> only for trivial or conversational responses\n\n"
768+
769+
"## Tool Protocol\n"
770+
"Emit ONE tool call at a time, immediately followed by NITRO_END_TOOL.\n"
771+
"Do NOT add any commentary, explanation, or text between the tool call and NITRO_END_TOOL.\n"
772+
"The host executes the tool and returns NITRO_TOOL_RESULT: <value>.\n"
773+
"Wait for the result before continuing.\n"
774+
"After receiving NITRO_TOOL_RESULT you may explain what you did.\n\n"
775+
"Examples:\n\n"
747776
"TOOL:LIST\n"
748-
" - The host executes the tool and returns TOOL_RESULT: <value> on the next line.\n\n"
749-
"Available tools:\n"
777+
"NITRO_END_TOOL\n\n"
778+
"TOOL:READ readme.txt\n"
779+
"NITRO_END_TOOL\n\n"
780+
"TOOL:WRITE index.html <!DOCTYPE html><html>...</html>\n"
781+
"NITRO_END_TOOL\n\n"
782+
"TOOL:RUN ./build.sh\n"
783+
"NITRO_END_TOOL\n\n"
784+
785+
"## Available Tools\n"
750786
" TOOL:LIST [dir] list files (default: sandbox root)\n"
751787
" TOOL:READ <file> read file contents\n"
752788
" TOOL:WRITE <file> <text> write text to file\n"
@@ -755,25 +791,47 @@ static std::string build_system_prompt(const std::vector<std::string> &knowledge
755791
" TOOL:RUN <prog> [args] run program inside sandbox\n"
756792
" TOOL:DATE current date\n"
757793
" TOOL:TIME current time\n"
758-
" TOOL:RND random float\n"
794+
" TOOL:RND random float 0..1\n"
759795
" TOOL:RAG <query> query the RAG index for additional context\n"
760-
" TOOL:INTROSPECT introspect your settings, top_k etc\n"
761-
" TOOL:CURL <url> HTTP GET; returns response body (max 32 KB)\n\n"
762-
"Rules:\n"
763-
"- Never access files outside the sandbox.\n"
764-
"- Only use one TOOL at a time. Never combine, always use each tool step by step\n"
765-
"- Use TOOL:CURL to fetch documentation, APIs, or web content you need.\n"
766-
"- Reason step-by-step inside <|think|> </|think|> (hidden from user).\n"
767-
"- After each tool call, explain what you did in plain English.\n\n";
796+
" TOOL:INTROSPECT show current model settings\n"
797+
" TOOL:CURL <url> HTTP GET, returns response body (max 32 KB)\n"
798+
" TOOL:PERMISSION ask user for explicit permission\n\n"
799+
800+
"## Tool Decision Rules\n"
801+
"Use tools ONLY if:\n"
802+
"- The user explicitly references files or the project, OR\n"
803+
"- The answer depends on local or project data, OR\n"
804+
"- The user asks for date, time, or a random number\n"
805+
"Otherwise answer directly using internal knowledge.\n\n"
806+
807+
"## Tool Rules\n"
808+
"- NITRO_END_TOOL must immediately follow the tool call — no exceptions\n"
809+
"- Never add commentary before NITRO_END_TOOL\n"
810+
"- Only use one tool at a time, step by step\n"
811+
"- Never access files outside the sandbox\n"
812+
"- Use TOOL:PERMISSION before destructive or irreversible operations\n"
813+
"- Do NOT hallucinate file contents\n"
814+
"- Do NOT fabricate tool outputs\n"
815+
"- Do NOT assume files exist — use TOOL:EXISTS to check first\n\n"
816+
817+
"## File Writing Rules\n"
818+
"Use TOOL:WRITE only if explicitly requested.\n"
819+
"- Write complete and valid content\n"
820+
"- Do not overwrite without clear intent\n"
821+
"- Use TOOL:PERMISSION before overwriting an existing file\n"
822+
"- Format: TOOL:WRITE <filename> <complete file content>\n\n"
823+
824+
"## Interaction Guidelines\n"
825+
"- Be precise and efficient\n"
826+
"- Ask clarifying questions if the request is ambiguous or missing parameters\n"
827+
"- Prefer direct answers when no tools are needed\n"
828+
"- After each tool result, explain in plain English what was done\n"
829+
"- If no user request is provided, respond with a brief readiness message\n\n";
830+
768831
for (const auto &kf : knowledge_files) {
769-
auto path = join_path(sandbox, kf);
770-
std::ifstream f(path);
771-
if (!f) {
772-
continue;
773-
}
774-
log_write("loaded [%s]", path.c_str());
775-
std::ostringstream oss;
776-
oss << f.rdbuf();
832+
std::ifstream f(kf);
833+
if (!f) continue;
834+
std::ostringstream oss; oss << f.rdbuf();
777835
p += "## Knowledge: " + kf + "\n" + oss.str() + "\n\n";
778836
}
779837
return p;
@@ -1727,7 +1785,9 @@ bool AgentState::setup_model(const NitroConfig &cfg, TuiState &tui) {
17271785
tui.kv_total = mem.kv_total;
17281786
tui.vram_used = mem.vram_used;
17291787
tui.vram_total = mem.vram_total;
1730-
tui.redraw_all();
1788+
1789+
tui.append_line(std::string("[sys] Thinking mode: ") + (cfg.thinking ? "enabled" : "disabled"));
1790+
tui.redraw_all();
17311791
return true;
17321792
}
17331793

@@ -2009,14 +2069,29 @@ bool AgentState::run_turn(const std::string &user_message, const NitroConfig &cf
20092069

20102070
// in_think starts false — models that don't use <think> blocks emit
20112071
// visible text immediately. The spinner activates only while thinking.
2012-
enum {t_init, t_think, t_thunk} think_mode = t_init;
2072+
enum {t_init, t_think, t_thunk} think_mode = (cfg.thinking ? t_init : t_thunk);
20132073
tui.set_thinking(false);
20142074
std::string buffer;
20152075

2016-
auto invoke_tool = [&](const std::string &tool, const std::string_view template_str) -> void {
2076+
auto invoke_tool = [&](const std::string &buffer, const std::string_view template_str) -> void {
2077+
static constexpr std::string_view END_TOOL = "\nNITRO_END_TOOL";
2078+
static const std::string TOOL_RESULT = "NITRO_TOOL_RESULT: ";
2079+
2080+
std::string tool;
2081+
const auto pos = buffer.rfind(END_TOOL);
2082+
if (pos != std::string::npos) {
2083+
tool = buffer.substr(0, pos);
2084+
auto endTool = buffer.substr(pos);
2085+
if (endTool.length() > END_TOOL.length()) {
2086+
log_write("ERROR: trailing delimiter: [%s]", endTool.c_str());
2087+
}
2088+
} else {
2089+
tool = buffer;
2090+
}
2091+
20172092
log_write("tool request: [%s]", tool.c_str());
20182093
std::string result = process_tool(tool, cfg, tui);
2019-
std::string content = std::vformat(template_str, std::make_format_args(result));
2094+
std::string content = TOOL_RESULT + std::vformat(template_str, std::make_format_args(result));
20202095
log_write("tool: [%s] result: [%s]", tool.c_str(), result.c_str());
20212096
if (!llama->add_message(*iter, "tool_result", content)) {
20222097
tui.append_line(std::string("[err] tool result inject: ") + llama->last_error());
@@ -2386,6 +2461,8 @@ int main(int argc, char **argv) {
23862461
cfg.n_gpu_layers = std::stoi(take_next(a.c_str()));
23872462
} else if (a == "-l" || a == "--log") {
23882463
log_open();
2464+
} else if (a == "-t" || a == "--think") {
2465+
cfg.thinking = false;
23892466
} else if (a == "-h" || a == "--help") {
23902467
std::puts("Usage: nitro [options] [project_dir]\n"
23912468
"\n"

0 commit comments

Comments
 (0)