|
2 | 2 | // A standalone agentic LLM shell with notcurses TUI. |
3 | 3 | // Uses llama-sb.h as the sole llama.cpp integration layer. |
4 | 4 | // |
5 | | -// Build (example): |
6 | | -// g++ -std=c++20 -O2 nitro.cpp llama-sb.cpp \ |
7 | | -// -I/path/to/llama.cpp/include \ |
8 | | -// -L/path/to/llama.cpp/build/src \ |
9 | | -// -lllama -lggml -lnotcurses-core -lnotcurses -lcurl \ |
10 | | -// -o nitro |
11 | | -// |
12 | 5 | // Usage: |
13 | 6 | // ./nitro [options] [project_dir] |
14 | 7 | // |
@@ -2247,6 +2240,7 @@ bool AgentState::run_turn(const std::string &user_message, const NitroConfig &cf |
2247 | 2240 | } |
2248 | 2241 | tui.append_line(ICON_ERR + content); |
2249 | 2242 | } |
| 2243 | + tui.tokens_per_sec = tokens_per_sec(); |
2250 | 2244 | if (!llama->add_message(*iter, "tool_result", content)) { |
2251 | 2245 | tui.append_line(ICON_ERR + "tool result inject: " + llama->last_error()); |
2252 | 2246 | } |
@@ -2289,11 +2283,15 @@ bool AgentState::run_turn(const std::string &user_message, const NitroConfig &cf |
2289 | 2283 | return ni.id == NCKEY_ESC; |
2290 | 2284 | }; |
2291 | 2285 |
|
2292 | | - auto fetch_all = [&]() -> void { |
| 2286 | + auto fetch_tool = [&]() -> void { |
2293 | 2287 | while (iter->_has_next && !is_escape()) { |
2294 | 2288 | std::string tok = llama->next(*iter); |
2295 | 2289 | buffer += tok; |
2296 | 2290 | tui.tick_spinner(); |
| 2291 | + auto pos = buffer.find("</think>"); |
| 2292 | + if (pos != std::string::npos) { |
| 2293 | + break; |
| 2294 | + } |
2297 | 2295 | } |
2298 | 2296 | }; |
2299 | 2297 |
|
@@ -2328,46 +2326,42 @@ bool AgentState::run_turn(const std::string &user_message, const NitroConfig &cf |
2328 | 2326 | end_think("<think|>"); |
2329 | 2327 | end_think("<channel|>"); |
2330 | 2328 | } |
2331 | | - if (think_mode == t_thunk) { |
2332 | | - auto tool_start = buffer.find("TOOL:"); |
2333 | | - if (tool_start == 0) { |
2334 | | - fetch_all(); |
2335 | | - invoke_tool(trim(buffer), "TOOL_RESULT: {}"); |
2336 | | - buffer.clear(); |
2337 | | - think_mode = t_init; |
2338 | | - continue; |
2339 | | - } |
2340 | | - tool_start = buffer.find("<|tool_call>call:"); |
2341 | | - if (tool_start != std::string::npos) { |
2342 | | - // see https://ai.google.dev/gemma/docs/core/prompt-formatting-gemma4 |
2343 | | - fetch_all(); |
2344 | | - auto pos = buffer.find_last_not_of("}<tool_call|>"); |
2345 | | - if (pos != std::string::npos) { |
2346 | | - buffer = buffer.substr(0, pos); |
2347 | | - } |
2348 | | - pos = buffer.find_first_not_of('{'); |
2349 | | - if (pos != std::string::npos) { |
2350 | | - buffer = buffer.substr(0, pos) + buffer.substr(pos + 1); |
2351 | | - } |
2352 | | - invoke_tool(trim(buffer), "<|tool_response>{}<tool_response|>"); |
2353 | | - buffer.clear(); |
2354 | | - think_mode = t_init; |
2355 | | - continue; |
2356 | | - } |
2357 | | - auto pos = buffer.find('\n'); |
| 2329 | + auto tool_start = buffer.find("TOOL:"); |
| 2330 | + if (tool_start == 0) { |
| 2331 | + fetch_tool(); |
| 2332 | + invoke_tool(trim(buffer), "TOOL_RESULT: {}"); |
| 2333 | + buffer.clear(); |
| 2334 | + think_mode = t_init; |
| 2335 | + continue; |
| 2336 | + } |
| 2337 | + tool_start = buffer.find("<|tool_call>call:"); |
| 2338 | + if (tool_start != std::string::npos) { |
| 2339 | + // see https://ai.google.dev/gemma/docs/core/prompt-formatting-gemma4 |
| 2340 | + fetch_tool(); |
| 2341 | + auto pos = buffer.find_last_not_of("}<tool_call|>"); |
2358 | 2342 | if (pos != std::string::npos) { |
2359 | | - tui.append_token(buffer.substr(0, pos + 1)); |
2360 | | - buffer = buffer.substr(pos + 1); |
| 2343 | + buffer = buffer.substr(0, pos); |
2361 | 2344 | } |
2362 | | - } else { |
2363 | | - auto pos = buffer.find('\n'); |
| 2345 | + pos = buffer.find_first_not_of('{'); |
2364 | 2346 | if (pos != std::string::npos) { |
| 2347 | + buffer = buffer.substr(0, pos) + buffer.substr(pos + 1); |
| 2348 | + } |
| 2349 | + invoke_tool(trim(buffer), "<|tool_response>{}<tool_response|>"); |
| 2350 | + buffer.clear(); |
| 2351 | + think_mode = t_init; |
| 2352 | + continue; |
| 2353 | + } |
| 2354 | + auto pos = buffer.find('\n'); |
| 2355 | + if (pos != std::string::npos) { |
| 2356 | + if (think_mode == t_think) { |
2365 | 2357 | auto thought = buffer.substr(0, pos + 1); |
2366 | 2358 | if (thought.length() > 1) { |
2367 | 2359 | tui.append_token(ICON_THINK + thought); |
2368 | 2360 | } |
2369 | | - buffer = buffer.substr(pos + 1); |
| 2361 | + } else { |
| 2362 | + tui.append_token(buffer.substr(0, pos + 1)); |
2370 | 2363 | } |
| 2364 | + buffer = buffer.substr(pos + 1); |
2371 | 2365 | } |
2372 | 2366 | } |
2373 | 2367 |
|
|
0 commit comments