diff --git a/plugins/plugin_rpbot.cpp b/plugins/plugin_rpbot.cpp index e14587e..343881f 100644 --- a/plugins/plugin_rpbot.cpp +++ b/plugins/plugin_rpbot.cpp @@ -36,13 +36,13 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api) try { auto* completion = PLUG_RESOLVE_INSTANCE(TextCompletionI); auto* conf = PLUG_RESOLVE_INSTANCE(ConfigModelI); - auto* cr = PLUG_RESOLVE_INSTANCE_VERSIONED(Contact3Registry, "1"); + auto* cs = PLUG_RESOLVE_INSTANCE(ContactStore4I); auto* rmm = PLUG_RESOLVE_INSTANCE(RegistryMessageModelI); auto* mcd = PLUG_RESOLVE_INSTANCE(MessageCommandDispatcher); // static store, could be anywhere tho // construct with fetched dependencies - g_rpbot = std::make_unique(*completion, *conf, *cr, *rmm, mcd); + g_rpbot = std::make_unique(*completion, *conf, *cs, *rmm, mcd); // register types PLUG_PROVIDE_INSTANCE(RPBot, plugin_name, g_rpbot.get()); diff --git a/src/solanaceae/rpbot/message_prompt_builder.cpp b/src/solanaceae/rpbot/message_prompt_builder.cpp index e957297..c33ca27 100644 --- a/src/solanaceae/rpbot/message_prompt_builder.cpp +++ b/src/solanaceae/rpbot/message_prompt_builder.cpp @@ -2,30 +2,32 @@ #include "./rpbot.hpp" +#include #include #include bool MessagePromptBuilder::buildNameLookup(void) { - if (_cr.all_of(_c)) { // group rpbot - const auto& subs = _cr.get(_c).subs; + const auto& cr = _cs.registry(); + if (cr.all_of(_c)) { // group rpbot + const auto& subs = cr.get(_c).subs; // should include self for (const auto sub_c : subs) { - if (_cr.all_of(sub_c)) { - names[sub_c] = _cr.get(sub_c).name; + if (cr.all_of(sub_c)) { + names[sub_c] = cr.get(sub_c).name; } } } else { // pm rpbot - if (_cr.all_of(_c)) { - names[_c] = _cr.get(_c).name; + if (cr.all_of(_c)) { + names[_c] = cr.get(_c).name; } else { std::cerr << "RPBot error: other missing name\n"; return false; } - if (_cr.all_of(_c)) { - const auto self = _cr.get(_c).self; - if (_cr.all_of(self)) { - names[self] = _cr.get(self).name; + if (cr.all_of(_c)) { + const auto self = cr.get(_c).self; + if (cr.all_of(self)) { + names[self] = cr.get(self).name; } else { std::cerr << "RPBot error: self missing name\n"; return false; @@ -87,7 +89,7 @@ std::string MessagePromptBuilder::buildPromptMessage(const Message3Handle m) { } std::string MessagePromptBuilder::promptMessagePrefixSimple(const Message3Handle m) { - const Contact3 from = m.get().c; + const Contact4 from = m.get().c; if (names.count(from)) { return std::string{names[from]}; } else { @@ -98,8 +100,8 @@ std::string MessagePromptBuilder::promptMessagePrefixSimple(const Message3Handle std::string MessagePromptBuilder::promptMessagePrefixDirected(const Message3Handle m) { // with both contacts (eg: "Name1 to Name2"; or "Name1 to Everyone" - const Contact3 from = m.get().c; - const Contact3 to = m.get().c; + const Contact4 from = m.get().c; + const Contact4 to = m.get().c; std::string res; diff --git a/src/solanaceae/rpbot/message_prompt_builder.hpp b/src/solanaceae/rpbot/message_prompt_builder.hpp index 58210d3..253d2e2 100644 --- a/src/solanaceae/rpbot/message_prompt_builder.hpp +++ b/src/solanaceae/rpbot/message_prompt_builder.hpp @@ -1,19 +1,19 @@ #pragma once #include -#include +#include #include #include // TODO: improve caching struct MessagePromptBuilder { - Contact3Registry& _cr; - const Contact3 _c; + ContactStore4I& _cs; + const Contact4 _c; RegistryMessageModelI& _rmm; // lookup table, string_view since no name-components are changed - entt::dense_map names; + entt::dense_map names; bool buildNameLookup(void); diff --git a/src/solanaceae/rpbot/rpbot.cpp b/src/solanaceae/rpbot/rpbot.cpp index 206fbfa..2b7813c 100644 --- a/src/solanaceae/rpbot/rpbot.cpp +++ b/src/solanaceae/rpbot/rpbot.cpp @@ -18,22 +18,24 @@ #include template<> -void RPBot::stateTransition(const Contact3 c, const StateIdle& from, StateNextActor& to) { +void RPBot::stateTransition(const Contact4 c, const StateIdle& from, StateNextActor& to) { // collect promp - MessagePromptBuilder mpb{_cr, c, _rmm, {}}; + MessagePromptBuilder mpb{_cs, c, _rmm, {}}; mpb.buildNameLookup(); + const auto& cr = _cs.registry(); + int64_t self {-1}; { // get set of possible usernames (even if forced, just to make sure) // copy mpb.names (contains string views, needs copies) for (const auto& [name_c, name] : mpb.names) { - if (_cr.all_of(name_c)) { + if (cr.all_of(name_c)) { self = to.possible_contacts.size(); to.possible_names.push_back(std::string{name}); to.possible_contacts.push_back(name_c); - } else if (_cr.all_of(name_c)) { - if (_cr.get(name_c).state != Contact::Components::ConnectionState::disconnected) { + } else if (cr.all_of(name_c)) { + if (cr.get(name_c).state != Contact::Components::ConnectionState::disconnected) { // online to.possible_names.push_back(std::string{name}); to.possible_contacts.push_back(name_c); @@ -55,7 +57,7 @@ void RPBot::stateTransition(const Contact3 c, const StateIdle& from, StateNextAc } { // - system promp (needs self name etc) - if (const auto* id_comp = _cr.try_get(c); id_comp != nullptr) { + if (const auto* id_comp = cr.try_get(c); id_comp != nullptr) { const auto id_hex = bin2hex(id_comp->data); to.prompt = _conf.get_string("RPBot", "system_prompt", id_hex).value(); } else { @@ -109,17 +111,18 @@ void RPBot::stateTransition(const Contact3 c, const StateIdle& from, StateNextAc } template<> -void RPBot::stateTransition(const Contact3, const StateNextActor&, StateIdle& to) { +void RPBot::stateTransition(const Contact4, const StateNextActor&, StateIdle& to) { to.timeout = std::uniform_real_distribution<>{30.f, 5.f*60.f}(_rng); } template<> -void RPBot::stateTransition(const Contact3 c, const StateNextActor& from, StateGenerateMsg& to) { +void RPBot::stateTransition(const Contact4 c, const StateNextActor& from, StateGenerateMsg& to) { + const auto& cr = _cs.registry(); to.prompt = from.prompt; // TODO: move from? - assert(_cr.all_of(c)); - const Contact3 self = _cr.get(c).self; + assert(cr.all_of(c)); + const Contact4 self = cr.get(c).self; - to.prompt += _cr.get(self).name + ":"; // TODO: remove space + to.prompt += cr.get(self).name + ":"; // TODO: remove space { // launch async to.future = std::async(std::launch::async, [&to, this]() -> std::string { @@ -129,7 +132,7 @@ void RPBot::stateTransition(const Contact3 c, const StateNextActor& from, StateG } template<> -void RPBot::stateTransition(const Contact3, const StateGenerateMsg&, StateIdle& to) { +void RPBot::stateTransition(const Contact4, const StateGenerateMsg&, StateIdle& to) { // relativly slow delay for multi line messages to.timeout = std::uniform_real_distribution<>{2.f, 15.f}(_rng); } @@ -137,10 +140,10 @@ void RPBot::stateTransition(const Contact3, const StateGenerateMsg&, StateIdle& RPBot::RPBot( TextCompletionI& completion, ConfigModelI& conf, - Contact3Registry& cr, + ContactStore4I& cs, RegistryMessageModelI& rmm, MessageCommandDispatcher* mcd -) : _completion(completion), _conf(conf), _cr(cr), _rmm(rmm), _rmm_sr(_rmm.newSubRef(this)), _mcd(mcd) { +) : _completion(completion), _conf(conf), _cs(cs), _rmm(rmm), _rmm_sr(_rmm.newSubRef(this)), _mcd(mcd) { //system_prompt = R"sys(Transcript of a group chat, where Bob talks to online strangers. //)sys"; @@ -172,15 +175,16 @@ float RPBot::tick(float time_delta) { } float RPBot::doAllIdle(float time_delta) { + auto& cr = _cs.registry(); float min_tick_interval = std::numeric_limits::max(); - std::vector to_remove_stateidle; - auto view = _cr.view(); + std::vector to_remove_stateidle; + auto view = cr.view(); - view.each([this, time_delta, &to_remove_stateidle, &min_tick_interval](const Contact3 c, StateIdle& state) { - if (_cr.all_of(c)) { + view.each([this, &cr, time_delta, &to_remove_stateidle, &min_tick_interval](const Contact4 c, StateIdle& state) { + if (cr.all_of(c)) { // marked for deletion, in idle (here) we remove them without adding next state to_remove_stateidle.push_back(c); - _cr.remove(c); + cr.remove(c); return; } @@ -204,7 +208,7 @@ float RPBot::doAllIdle(float time_delta) { auto view_it = tmp_view.begin(), view_last = tmp_view.end(); for (size_t i = 0; i < max_cont_messages && view_it != view_last; view_it++, i++) { // TODO: also test for weak self? - if (!_cr.any_of(tmp_view.get(*view_it).c)) { + if (!cr.any_of(tmp_view.get(*view_it).c)) { other_sender = true; break; } @@ -215,7 +219,7 @@ float RPBot::doAllIdle(float time_delta) { min_tick_interval = 0.1f; // transition to Next - emplaceStateTransition(_cr, c, state); + emplaceStateTransition(_cs, c, state); return; } } @@ -232,16 +236,17 @@ float RPBot::doAllIdle(float time_delta) { } }); - _cr.remove(to_remove_stateidle.cbegin(), to_remove_stateidle.cend()); + cr.remove(to_remove_stateidle.cbegin(), to_remove_stateidle.cend()); return min_tick_interval; } float RPBot::doAllNext(float) { + auto& cr = _cs.registry(); float min_tick_interval = std::numeric_limits::max(); - std::vector to_remove; - auto view = _cr.view(); + std::vector to_remove; + auto view = cr.view(); - view.each([this, &to_remove, &min_tick_interval](const Contact3 c, StateNextActor& state) { + view.each([this, &cr, &to_remove, &min_tick_interval](const Contact4 c, StateNextActor& state) { // TODO: how to timeout? if (state.future.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) { to_remove.push_back(c); @@ -251,9 +256,9 @@ float RPBot::doAllNext(float) { const auto selected = state.future.get(); if (selected >= 0 && size_t(selected) < state.possible_names.size()) { std::cout << "next is " << state.possible_names.at(selected) << "(" << selected << ")\n"; - if (_cr.all_of(state.possible_contacts.at(selected))) { + if (cr.all_of(state.possible_contacts.at(selected))) { // we predicted ourselfs - emplaceStateTransition(_cr, c, state); + emplaceStateTransition(_cs, c, state); return; } } else { @@ -261,21 +266,22 @@ float RPBot::doAllNext(float) { } // transition to Idle - emplaceStateTransition(_cr, c, state); + emplaceStateTransition(_cs, c, state); } }); - _cr.remove(to_remove.cbegin(), to_remove.cend()); + cr.remove(to_remove.cbegin(), to_remove.cend()); return min_tick_interval; } float RPBot::doAllGenerateMsg(float) { + auto& cr = _cs.registry(); float min_tick_interval = std::numeric_limits::max(); - std::vector to_remove; - auto view = _cr.view(); + std::vector to_remove; + auto view = cr.view(); - _cr.remove(to_remove.cbegin(), to_remove.cend()); - view.each([this, &to_remove, &min_tick_interval](const Contact3 c, StateGenerateMsg& state) { + cr.remove(to_remove.cbegin(), to_remove.cend()); + view.each([this, &to_remove, &min_tick_interval](const Contact4 c, StateGenerateMsg& state) { // TODO: how to timeout? if (state.future.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) { to_remove.push_back(c); @@ -293,11 +299,11 @@ float RPBot::doAllGenerateMsg(float) { // TODO: timing check? // transition to Idle - emplaceStateTransition(_cr, c, state); + emplaceStateTransition(_cs, c, state); } }); - _cr.remove(to_remove.cbegin(), to_remove.cend()); + cr.remove(to_remove.cbegin(), to_remove.cend()); return min_tick_interval; } @@ -311,39 +317,41 @@ bool RPBot::onEvent(const Message::Events::MessageConstruct& e) { return false; } + auto& cr = _cs.registry(); + const auto contact_to = e.e.get().c; const auto contact_from = e.e.get().c; - if (!_cr.valid(contact_to) || !_cr.valid(contact_from)) { + if (!cr.valid(contact_to) || !cr.valid(contact_from)) { std::cerr << "RPBot error: invalid contact in message\n"; return false; } - if (_cr.any_of(contact_from)) { + if (cr.any_of(contact_from)) { return false; // ignore own messages } - Contact3 rpbot_contact = entt::null; + Contact4 rpbot_contact = entt::null; // check ContactTo (public) // check ContactTo parent (group private) // check ContactFrom (private) - if (_cr.any_of(contact_to)) { + if (cr.any_of(contact_to)) { rpbot_contact = contact_to; - } else if (_cr.all_of(contact_to)) { - rpbot_contact = _cr.get(contact_to).parent; - } else if (_cr.any_of(contact_from)) { + } else if (cr.all_of(contact_to)) { + rpbot_contact = cr.get(contact_to).parent; + } else if (cr.any_of(contact_from)) { rpbot_contact = contact_from; } else { return false; // not a rpbot related message } - if (!_cr.all_of(rpbot_contact)) { + if (!cr.all_of(rpbot_contact)) { return false; // not idle } - auto& timeout = _cr.get(rpbot_contact).timeout; + auto& timeout = cr.get(rpbot_contact).timeout; // TODO: config with id timeout = std::clamp( timeout, diff --git a/src/solanaceae/rpbot/rpbot.hpp b/src/solanaceae/rpbot/rpbot.hpp index 28868cd..ec633f3 100644 --- a/src/solanaceae/rpbot/rpbot.hpp +++ b/src/solanaceae/rpbot/rpbot.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -19,7 +19,7 @@ struct StateTimingCheck; struct RPBot : public RegistryMessageModelEventI { TextCompletionI& _completion; ConfigModelI& _conf; - Contact3Registry& _cr; + ContactStore4I& _cs; RegistryMessageModelI& _rmm; RegistryMessageModelI::SubscriptionReference _rmm_sr; MessageCommandDispatcher* _mcd; @@ -30,7 +30,7 @@ struct RPBot : public RegistryMessageModelEventI { RPBot( TextCompletionI& completion, ConfigModelI& conf, - Contact3Registry& cr, + ContactStore4I& cs, RegistryMessageModelI& rmm, MessageCommandDispatcher* mcd ); @@ -42,13 +42,13 @@ struct RPBot : public RegistryMessageModelEventI { protected: // state transitions // all transitions need to be explicitly declared template - void stateTransition(const Contact3 c, const From& from, To& to) = delete; + void stateTransition(const Contact4 c, const From& from, To& to) = delete; // reg helper template - To& emplaceStateTransition(Contact3Registry& cr, Contact3 c, const From& state) { + To& emplaceStateTransition(ContactStore4I& cs, Contact4 c, const From& state) { std::cout << "RPBot: transition from " << From::name << " to " << To::name << "\n"; - To& to = cr.emplace_or_replace(c); + To& to = cs.registry().emplace_or_replace(c); stateTransition(c, state, to); return to; } diff --git a/src/solanaceae/rpbot/rpbot_commands.cpp b/src/solanaceae/rpbot/rpbot_commands.cpp index 38ffc95..6251494 100644 --- a/src/solanaceae/rpbot/rpbot_commands.cpp +++ b/src/solanaceae/rpbot/rpbot_commands.cpp @@ -18,16 +18,18 @@ void RPBot::registerCommands(void) { const auto contact_from = m.get().c; const auto contact_to = m.get().c; + auto& cr = _cs.registry(); + if (params.empty()) { // contact_to should be the contact this is for - if (_cr.any_of(contact_to)) { + if (cr.any_of(contact_to)) { _rmm.sendText( contact_from, "error: already running" ); return true; } - if (_cr.any_of(contact_from)) { + if (cr.any_of(contact_from)) { _rmm.sendText( contact_from, "error: already running" @@ -35,13 +37,13 @@ void RPBot::registerCommands(void) { return true; } - if (_cr.all_of(contact_to)) { + if (cr.all_of(contact_to)) { // group - auto& new_state = _cr.emplace(contact_to); + auto& new_state = cr.emplace(contact_to); new_state.timeout = 10.f; } else { // pm - auto& new_state = _cr.emplace(contact_from); + auto& new_state = cr.emplace(contact_from); new_state.timeout = 10.f; } @@ -62,10 +64,10 @@ void RPBot::registerCommands(void) { auto id_bin = hex2bin(params); - auto view = _cr.view(); + auto view = cr.view(); for (auto it = view.begin(), it_end = view.end(); it != it_end; it++) { if (view.get(*it).data == id_bin) { - if (_cr.any_of(*it)) { + if (cr.any_of(*it)) { _rmm.sendText( contact_from, "RPBot already running" @@ -73,7 +75,7 @@ void RPBot::registerCommands(void) { return true; } - auto& new_state = _cr.emplace(*it); + auto& new_state = cr.emplace(*it); new_state.timeout = 10.f; _rmm.sendText( @@ -102,18 +104,20 @@ void RPBot::registerCommands(void) { const auto contact_from = m.get().c; const auto contact_to = m.get().c; + auto& cr = _cs.registry(); + if (params.empty()) { // contact_to should be the contact this is for - if (_cr.any_of(contact_to)) { - _cr.emplace_or_replace(contact_to); + if (cr.any_of(contact_to)) { + cr.emplace_or_replace(contact_to); _rmm.sendText( contact_from, "stopped" ); return true; } - if (_cr.any_of(contact_from)) { - _cr.emplace_or_replace(contact_from); + if (cr.any_of(contact_from)) { + cr.emplace_or_replace(contact_from); _rmm.sendText( contact_from, "stopped" @@ -138,11 +142,11 @@ void RPBot::registerCommands(void) { auto id_bin = hex2bin(params); - auto view = _cr.view(); + auto view = cr.view(); for (auto it = view.begin(), it_end = view.end(); it != it_end; it++) { if (view.get(*it).data == id_bin) { - if (_cr.any_of(*it)) { - _cr.emplace_or_replace(*it); + if (cr.any_of(*it)) { + cr.emplace_or_replace(*it); _rmm.sendText( contact_from, "stopped" @@ -176,12 +180,14 @@ void RPBot::registerCommands(void) { const auto contact_from = m.get().c; const auto contact_to = m.get().c; + auto& cr = _cs.registry(); + if (params.empty()) { // contact_to should be the contact this is for - if (_cr.any_of(contact_to)) { - if (_cr.all_of(contact_to)) { - _cr.get(contact_to).force = true; - _cr.get(contact_to).timeout = 2.f; + if (cr.any_of(contact_to)) { + if (cr.all_of(contact_to)) { + cr.get(contact_to).force = true; + cr.get(contact_to).timeout = 2.f; _rmm.sendText( contact_from, "forced its hand" @@ -189,10 +195,10 @@ void RPBot::registerCommands(void) { } return true; } - if (_cr.any_of(contact_from)) { - if (_cr.all_of(contact_from)) { - _cr.get(contact_from).force = true; - _cr.get(contact_from).timeout = 2.f; + if (cr.any_of(contact_from)) { + if (cr.all_of(contact_from)) { + cr.get(contact_from).force = true; + cr.get(contact_from).timeout = 2.f; _rmm.sendText( contact_from, "forced its hand" @@ -218,13 +224,13 @@ void RPBot::registerCommands(void) { auto id_bin = hex2bin(params); - auto view = _cr.view(); + auto view = cr.view(); for (auto it = view.begin(), it_end = view.end(); it != it_end; it++) { if (view.get(*it).data == id_bin) { - if (_cr.any_of(*it)) { - if (_cr.all_of(*it)) { - _cr.get(*it).force = true; - _cr.get(*it).timeout = 2.f; + if (cr.any_of(*it)) { + if (cr.all_of(*it)) { + cr.get(*it).force = true; + cr.get(*it).timeout = 2.f; _rmm.sendText( contact_from, "forced its hand" diff --git a/src/solanaceae/rpbot/rpbot_states.hpp b/src/solanaceae/rpbot/rpbot_states.hpp index 92e5f70..7b0c6de 100644 --- a/src/solanaceae/rpbot/rpbot_states.hpp +++ b/src/solanaceae/rpbot/rpbot_states.hpp @@ -22,7 +22,7 @@ struct StateNextActor { std::string prompt; std::vector possible_names; - std::vector possible_contacts; + std::vector possible_contacts; std::future future; };