Skip to content

Commit 14e884c

Browse files
author
Chris Warren-Smith
committed
LLAMA: nitro: added mechanism for agent to restart when KV is low
1 parent 608ac68 commit 14e884c

2 files changed

Lines changed: 62 additions & 12 deletions

File tree

llama/llama.cpp

llama/nitro.cpp

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ struct TuiState {
235235
InputHistory history;
236236
// Advance spinner by one frame and redraw the header.
237237
void tick_spinner();
238+
238239
// Toggle thinking mode; redraws header immediately.
239240
void set_thinking(bool on);
240241
void update_usage(int tokens_sec, const LlamaMemoryInfo &mem);
@@ -288,21 +289,23 @@ struct AgentState {
288289
std::unique_ptr<Llama> llama;
289290
std::unique_ptr<LlamaIter> iter;
290291
std::unique_ptr<Llama> embed_llama;
291-
std::unique_ptr<RagDB> rag_db;
292+
std::unique_ptr<RagDB> rag_db;
292293
std::unique_ptr<RagSession> rag_session;
293294
bool model_loaded = false;
294295
std::string system_prompt;
295296

296297
bool rag_index(const std::string &path, const NitroConfig &cfg, TuiState &tui) const;
297298
bool rag_load_index(const std::string &path, TuiState &tui) const;
298-
bool run_turn(const std::string &user_message, const NitroConfig &cfg, TuiState &tui) const;
299+
bool run_turn(const std::string &user_message, const NitroConfig &cfg, TuiState &tui);
299300
bool setup_embed(const std::string &path, TuiState &tui);
300301
bool setup_model(const NitroConfig &cfg, TuiState &tui);
301302
void apply_generation_params(const NitroConfig &cfg) const;
302303
void reset_conversation(const std::string &sysprompt, TuiState &tui);
304+
std::string memory_info_status() const;
303305
std::string memory_info_text() const;
304-
std::string process_tool(const std::string &cmd, const NitroConfig &cfg, TuiState &tui) const;
306+
std::string process_tool(const std::string &cmd, const NitroConfig &cfg, TuiState &tui);
305307
std::string rag_tool(const NitroConfig &cfg, const std::string &agent_query) const;
308+
std::string restart(const NitroConfig &cfg, TuiState &tui);
306309
float tokens_per_sec() const;
307310
};
308311

@@ -826,7 +829,7 @@ static bool make_dir(const std::string &path) {
826829
//
827830
// System prompt
828831
//
829-
static std::string build_system_prompt(NitroConfig &cfg) {
832+
static std::string build_system_prompt(const NitroConfig &cfg) {
830833
std::string p;
831834
p +=
832835
"You are Nitro, an agentic AI assistant for software development. "
@@ -881,7 +884,8 @@ static std::string build_system_prompt(NitroConfig &cfg) {
881884
" TOOL:ASK <query> ask the user for clarification or additional context\n"
882885
" TOOL:INTROSPECT show current model settings\n"
883886
" TOOL:CURL <url> HTTP GET, returns response body (max 32 KB)\n"
884-
" TOOL:PERMISSION ask user for explicit permission\n\n"
887+
" TOOL:PERMISSION ask user for explicit permission\n"
888+
" TOOL:RESTART restart after writing current task context to `SESSION.md`\n\n"
885889

886890
"## Tool Decision Rules\n"
887891
"Use tools ONLY if:\n"
@@ -912,7 +916,27 @@ static std::string build_system_prompt(NitroConfig &cfg) {
912916
"- Ask clarifying questions if the request is ambiguous or missing parameters\n"
913917
"- Prefer direct answers when no tools are needed\n"
914918
"- After each tool result, explain in plain English what was done\n"
915-
"- If no user request is provided, respond with a brief readiness message\n\n";
919+
"- If no user request is provided, respond with a brief readiness message\n\n"
920+
921+
"## Auto-Restart Protocol\n"
922+
"**When:** - When KV >= 80% (as reported in the tool results footer).\n"
923+
"**Steps:**\n"
924+
"1. **Save State:** Write current task context to `SESSION.md` using `TOOL:WRITE`.\n"
925+
" - Include: Timestamp, KV usage, current task description, pending actions, and last conversation summary.\n"
926+
" - Don't check if SESSION.md already exists from another session. just use TOOL:WRITE.\n"
927+
"2. **Trigger Restart:** Call `TOOL:RESTART`.\n"
928+
"**Example `SESSION.md` Content:**\n"
929+
"```markdown\n"
930+
"# Session State Snapshot\n"
931+
"**Timestamp:** <date> <time>\n"
932+
"**KV Usage:** <percentage>%\n"
933+
"**Current Task:** <task description>\n"
934+
"**Pending Actions:**\n"
935+
"- <action 1>\n"
936+
"- <action 2>\n"
937+
"**Last Output:**\n"
938+
"<last few lines of conversation>\n"
939+
"```\n\n";
916940

917941
for (const auto &kf : cfg.knowledge_files) {
918942
std::ifstream f(kf);
@@ -1954,6 +1978,12 @@ float AgentState::tokens_per_sec() const {
19541978
return (float)(iter->_tokens_generated / elapsed);
19551979
}
19561980

1981+
std::string AgentState::memory_info_status() const {
1982+
LlamaMemoryInfo m = llama->memory_info();
1983+
auto message = m.kv_percent > 75 ? "(Warning: Approaching limit)" : "";
1984+
return std::format("\n[INFO] KV Cache: {}%{}", m.kv_percent, message);
1985+
}
1986+
19571987
std::string AgentState::memory_info_text() const {
19581988
if (!model_loaded) return "No model loaded.";
19591989
LlamaMemoryInfo m = llama->memory_info();
@@ -2037,10 +2067,22 @@ bool AgentState::rag_index(const std::string &path, const NitroConfig &cfg, TuiS
20372067
return true;
20382068
}
20392069

2070+
std::string AgentState::restart(const NitroConfig &cfg, TuiState &tui) {
2071+
if (fs::exists("SESSION.md")) {
2072+
std::vector<std::string> knowledge_files;
2073+
std::string sysp = build_system_prompt(cfg);
2074+
reset_conversation(sysp, tui);
2075+
tui.append_line(ICON_ERR + "Session restarted");
2076+
tui.redraw_all();
2077+
return "continue the pending actions found SESSION.md";
2078+
}
2079+
return "save work context to SESSION.md then try again";
2080+
}
2081+
20402082
//
20412083
// Tool dispatch
20422084
//
2043-
std::string AgentState::process_tool(const std::string &cmd, const NitroConfig &cfg, TuiState &tui) const {
2085+
std::string AgentState::process_tool(const std::string &cmd, const NitroConfig &cfg, TuiState &tui) {
20442086
const std::string &sandbox = cfg.sandbox;
20452087
const std::vector<std::string> &run_allowed = cfg.run_allowed;
20462088

@@ -2159,6 +2201,10 @@ std::string AgentState::process_tool(const std::string &cmd, const NitroConfig &
21592201
show_tool("asking: " + arg1 + " " + arg2);
21602202
return tui.readline_blocking();
21612203
}
2204+
if (op == "TOOL:RESTART") {
2205+
show_tool("restart ...");
2206+
return restart(cfg, tui);
2207+
}
21622208
if (op == "TOOL:PERMISSION") {
21632209
tui.set_thinking(false);
21642210
show_tool("asking permission: " + arg1 + " " + arg2);
@@ -2197,7 +2243,7 @@ std::string AgentState::process_tool(const std::string &cmd, const NitroConfig &
21972243
//
21982244
// Agent turn
21992245
//
2200-
bool AgentState::run_turn(const std::string &user_message, const NitroConfig &cfg, TuiState &tui) const {
2246+
bool AgentState::run_turn(const std::string &user_message, const NitroConfig &cfg, TuiState &tui) {
22012247
if (!model_loaded) {
22022248
tui.append_line(ICON_ERR + "No model loaded. Use /model <path>");
22032249
tui.redraw_all();
@@ -2250,9 +2296,11 @@ bool AgentState::run_turn(const std::string &user_message, const NitroConfig &cf
22502296

22512297
log_write("tool request: mode:[%d] [%s]", think_mode, tool.c_str());
22522298
std::string result = process_tool(tool, cfg, tui);
2253-
std::string content = TOOL_RESULT + std::vformat(template_str, std::make_format_args(result));
2299+
if (result.empty()) {
2300+
return;
2301+
}
2302+
std::string content = TOOL_RESULT + std::vformat(template_str, std::make_format_args(result)) + memory_info_status();
22542303
log_write("tool: [%s] result: [%s]", tool.c_str(), result.c_str());
2255-
22562304
if (content.size() > llama->max_tool_result_size()) {
22572305
// Index the content into RAG and tell the model where to find it
22582306
if (embed_llama && rag_db && rag_session) {
@@ -2711,7 +2759,9 @@ int main(int argc, char **argv) {
27112759

27122760
// ── Auto-discover knowledge files ─────────────────────────────────
27132761
for (const char *kf : {"nitro.md", "AGENTS.md", "README.md"}) {
2714-
if (fs::exists(kf)) cfg.knowledge_files.emplace_back(kf);
2762+
if (fs::exists(kf)) {
2763+
cfg.knowledge_files.emplace_back(kf);
2764+
}
27152765
}
27162766

27172767
// ── Init curl globally ────────────────────────────────────────────

0 commit comments

Comments
 (0)