| 1096 | |
| 1097 | |
| 1098 | const char* rcli_process_command(RCLIHandle handle, const char* text) { |
| 1099 | if (!handle || !text) return ""; |
| 1100 | auto* engine = static_cast<RCLIEngine*>(handle); |
| 1101 | if (!engine->initialized) return ""; |
| 1102 | |
| 1103 | LOG_TRACE("RCLI", "[process_command] waiting for engine->mutex ..."); |
| 1104 | std::lock_guard<std::mutex> lock(engine->mutex); |
| 1105 | LOG_TRACE("RCLI", "[process_command] engine->mutex acquired, input='%.40s'", text); |
| 1106 | std::string input(text); |
| 1107 | |
| 1108 | // --- Screen intent intercept: capture active window + VLM --- |
| 1109 | if (is_screen_intent(input)) { |
| 1110 | engine->last_response = handle_screen_intent(engine, input); |
| 1111 | engine->conversation_history.emplace_back("user", input); |
| 1112 | engine->conversation_history.emplace_back("assistant", engine->last_response); |
| 1113 | return engine->last_response.c_str(); |
| 1114 | } |
| 1115 | |
| 1116 | // --- MetalRT path: tool-aware inference via generate_raw (pre-formatted prompt) --- |
| 1117 | if (engine->pipeline.using_metalrt()) { |
| 1118 | auto& mrt = engine->pipeline.metalrt_llm(); |
| 1119 | if (!mrt.is_initialized()) { |
| 1120 | LOG_ERROR("RCLI", "MetalRT flagged as active but engine not initialized"); |
| 1121 | engine->last_response = "Error: MetalRT engine not available. " |
| 1122 | "Try: rcli engine llamacpp"; |
| 1123 | return engine->last_response.c_str(); |
| 1124 | } |
| 1125 | const auto& profile = mrt.profile(); |
| 1126 | |
| 1127 | std::string base_prompt = rastack::apply_personality( |
| 1128 | effective_base_prompt(engine), engine->personality_key); |
| 1129 | std::string tool_defs = engine->pipeline.tools().get_tool_definitions_json(); |
| 1130 | std::string system_prompt = profile.build_tool_system_prompt( |
| 1131 | base_prompt, tool_defs); |
| 1132 | |
| 1133 | std::string hint = engine->pipeline.tools().build_tool_hint(input); |
| 1134 | std::string hinted_input = hint.empty() ? input : (hint + "\n" + input); |
| 1135 | |
| 1136 | int sys_tok = mrt.count_tokens(system_prompt); |
| 1137 | int usr_tok = mrt.count_tokens(hinted_input); |
| 1138 | int ctx_sz = mrt.context_size(); |
| 1139 | if (ctx_sz <= 0) ctx_sz = 4096; |
| 1140 | if (maybe_auto_compact(engine, ctx_sz, sys_tok, usr_tok)) { |
| 1141 | engine->metalrt_kv_continuation_len = 0; |
| 1142 | } |
| 1143 | |
| 1144 | auto trimmed = get_trimmed_history_metalrt(engine, mrt, ctx_sz, sys_tok, usr_tok); |
| 1145 | std::string full_prompt = profile.build_chat_prompt( |
| 1146 | system_prompt, trimmed, hinted_input); |
| 1147 | |
| 1148 | if (trimmed.size() < engine->conversation_history.size()) { |
| 1149 | engine->metalrt_kv_continuation_len = 0; |
| 1150 | } |
| 1151 | |
| 1152 | std::string raw_output; |
| 1153 | const auto& cached = mrt.cached_prompt(); |
| 1154 | if (mrt.has_prompt_cache() && !cached.empty() && |
| 1155 | full_prompt.size() > cached.size() && |