feat: Implement collaboration and multimodal functionality in AgentChatWidget
This commit is contained in:
@@ -181,6 +181,18 @@ void AgentChatWidget::SetRomContext(Rom* rom) {
|
|||||||
agent_service_.SetRomContext(rom);
|
agent_service_.SetRomContext(rom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AgentChatWidget::SetToastManager(ToastManager* toast_manager) {
|
||||||
|
toast_manager_ = toast_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgentChatWidget::SetProposalDrawer(ProposalDrawer* drawer) {
|
||||||
|
proposal_drawer_ = drawer;
|
||||||
|
if (proposal_drawer_ && !pending_focus_proposal_id_.empty()) {
|
||||||
|
proposal_drawer_->FocusProposal(pending_focus_proposal_id_);
|
||||||
|
pending_focus_proposal_id_.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AgentChatWidget::EnsureHistoryLoaded() {
|
void AgentChatWidget::EnsureHistoryLoaded() {
|
||||||
if (history_loaded_) {
|
if (history_loaded_) {
|
||||||
return;
|
return;
|
||||||
@@ -272,6 +284,43 @@ void AgentChatWidget::EnsureHistoryLoaded() {
|
|||||||
ToastType::kInfo, 3.5f);
|
ToastType::kInfo, 3.5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (json.contains("collaboration") && json["collaboration"].is_object()) {
|
||||||
|
const auto& collab_json = json["collaboration"];
|
||||||
|
collaboration_state_.active = collab_json.value("active", false);
|
||||||
|
collaboration_state_.session_id = collab_json.value("session_id", "");
|
||||||
|
collaboration_state_.participants.clear();
|
||||||
|
if (collab_json.contains("participants") &&
|
||||||
|
collab_json["participants"].is_array()) {
|
||||||
|
for (const auto& participant : collab_json["participants"]) {
|
||||||
|
if (participant.is_string()) {
|
||||||
|
collaboration_state_.participants.push_back(
|
||||||
|
participant.get<std::string>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (collab_json.contains("last_synced")) {
|
||||||
|
collaboration_state_.last_synced =
|
||||||
|
ParseTimestamp(collab_json["last_synced"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.contains("multimodal") && json["multimodal"].is_object()) {
|
||||||
|
const auto& multimodal_json = json["multimodal"];
|
||||||
|
if (multimodal_json.contains("last_capture_path") &&
|
||||||
|
multimodal_json["last_capture_path"].is_string()) {
|
||||||
|
std::string path = multimodal_json["last_capture_path"].get<std::string>();
|
||||||
|
if (!path.empty()) {
|
||||||
|
multimodal_state_.last_capture_path = std::filesystem::path(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
multimodal_state_.status_message =
|
||||||
|
multimodal_json.value("status_message", "");
|
||||||
|
if (multimodal_json.contains("last_updated")) {
|
||||||
|
multimodal_state_.last_updated =
|
||||||
|
ParseTimestamp(multimodal_json["last_updated"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
if (toast_manager_) {
|
if (toast_manager_) {
|
||||||
toast_manager_->Show(
|
toast_manager_->Show(
|
||||||
@@ -328,6 +377,32 @@ void AgentChatWidget::PersistHistory() {
|
|||||||
json["messages"].push_back(std::move(entry));
|
json["messages"].push_back(std::move(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nlohmann::json collab_json;
|
||||||
|
collab_json["active"] = collaboration_state_.active;
|
||||||
|
collab_json["session_id"] = collaboration_state_.session_id;
|
||||||
|
collab_json["participants"] = collaboration_state_.participants;
|
||||||
|
if (collaboration_state_.last_synced != absl::InfinitePast()) {
|
||||||
|
collab_json["last_synced"] = absl::FormatTime(
|
||||||
|
absl::RFC3339_full, collaboration_state_.last_synced,
|
||||||
|
absl::UTCTimeZone());
|
||||||
|
}
|
||||||
|
json["collaboration"] = std::move(collab_json);
|
||||||
|
|
||||||
|
nlohmann::json multimodal_json;
|
||||||
|
if (multimodal_state_.last_capture_path.has_value()) {
|
||||||
|
multimodal_json["last_capture_path"] =
|
||||||
|
multimodal_state_.last_capture_path->string();
|
||||||
|
} else {
|
||||||
|
multimodal_json["last_capture_path"] = "";
|
||||||
|
}
|
||||||
|
multimodal_json["status_message"] = multimodal_state_.status_message;
|
||||||
|
if (multimodal_state_.last_updated != absl::InfinitePast()) {
|
||||||
|
multimodal_json["last_updated"] = absl::FormatTime(
|
||||||
|
absl::RFC3339_full, multimodal_state_.last_updated,
|
||||||
|
absl::UTCTimeZone());
|
||||||
|
}
|
||||||
|
json["multimodal"] = std::move(multimodal_json);
|
||||||
|
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
auto directory = history_path_.parent_path();
|
auto directory = history_path_.parent_path();
|
||||||
if (!directory.empty()) {
|
if (!directory.empty()) {
|
||||||
@@ -521,6 +596,7 @@ void AgentChatWidget::RenderProposalQuickActions(const ChatMessage& msg,
|
|||||||
void AgentChatWidget::RenderHistory() {
|
void AgentChatWidget::RenderHistory() {
|
||||||
const auto& history = agent_service_.GetHistory();
|
const auto& history = agent_service_.GetHistory();
|
||||||
float reserved_height = ImGui::GetFrameHeightWithSpacing() * 4.0f;
|
float reserved_height = ImGui::GetFrameHeightWithSpacing() * 4.0f;
|
||||||
|
reserved_height += 220.0f;
|
||||||
|
|
||||||
if (ImGui::BeginChild("History",
|
if (ImGui::BeginChild("History",
|
||||||
ImVec2(0, -reserved_height),
|
ImVec2(0, -reserved_height),
|
||||||
@@ -591,9 +667,289 @@ void AgentChatWidget::Draw() {
|
|||||||
|
|
||||||
ImGui::Begin(title_.c_str(), &active_);
|
ImGui::Begin(title_.c_str(), &active_);
|
||||||
RenderHistory();
|
RenderHistory();
|
||||||
|
RenderCollaborationPanel();
|
||||||
|
RenderMultimodalPanel();
|
||||||
RenderInputBox();
|
RenderInputBox();
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AgentChatWidget::RenderCollaborationPanel() {
|
||||||
|
if (!ImGui::CollapsingHeader("Collaborative Session (Preview)",
|
||||||
|
ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool connected = collaboration_state_.active;
|
||||||
|
ImGui::Text("Status: %s", connected ? "Connected" : "Not connected");
|
||||||
|
if (!collaboration_state_.session_id.empty()) {
|
||||||
|
ImGui::Text("Session ID: %s", collaboration_state_.session_id.c_str());
|
||||||
|
}
|
||||||
|
if (collaboration_state_.last_synced != absl::InfinitePast()) {
|
||||||
|
ImGui::TextDisabled(
|
||||||
|
"Last sync: %s",
|
||||||
|
absl::FormatTime("%H:%M:%S", collaboration_state_.last_synced,
|
||||||
|
absl::LocalTimeZone()).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
bool can_host = static_cast<bool>(collaboration_callbacks_.host_session);
|
||||||
|
bool can_join = static_cast<bool>(collaboration_callbacks_.join_session);
|
||||||
|
bool can_leave = static_cast<bool>(collaboration_callbacks_.leave_session);
|
||||||
|
|
||||||
|
ImGui::InputTextWithHint("##session_name", "Session name",
|
||||||
|
session_name_buffer_,
|
||||||
|
IM_ARRAYSIZE(session_name_buffer_));
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (!can_host) ImGui::BeginDisabled();
|
||||||
|
if (ImGui::Button("Host Session")) {
|
||||||
|
std::string name = session_name_buffer_;
|
||||||
|
if (name.empty()) {
|
||||||
|
if (toast_manager_) {
|
||||||
|
toast_manager_->Show("Enter a session name first",
|
||||||
|
ToastType::kWarning, 3.0f);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
absl::Status status =
|
||||||
|
collaboration_callbacks_.host_session(name);
|
||||||
|
if (status.ok()) {
|
||||||
|
collaboration_state_.active = true;
|
||||||
|
collaboration_state_.session_id = name;
|
||||||
|
collaboration_state_.participants.clear();
|
||||||
|
collaboration_state_.last_synced = absl::Now();
|
||||||
|
last_collaboration_action_ = absl::Now();
|
||||||
|
RefreshParticipants();
|
||||||
|
if (toast_manager_) {
|
||||||
|
toast_manager_->Show("Hosting collaborative session",
|
||||||
|
ToastType::kSuccess, 3.5f);
|
||||||
|
}
|
||||||
|
MarkHistoryDirty();
|
||||||
|
} else if (toast_manager_) {
|
||||||
|
toast_manager_->Show(
|
||||||
|
absl::StrFormat("Failed to host: %s", status.message()),
|
||||||
|
ToastType::kError, 5.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!can_host) {
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip("Provide host_session callback to enable hosting");
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::InputTextWithHint("##join_code", "Session code",
|
||||||
|
join_code_buffer_,
|
||||||
|
IM_ARRAYSIZE(join_code_buffer_));
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (!can_join) ImGui::BeginDisabled();
|
||||||
|
if (ImGui::Button("Join Session")) {
|
||||||
|
std::string code = join_code_buffer_;
|
||||||
|
if (code.empty()) {
|
||||||
|
if (toast_manager_) {
|
||||||
|
toast_manager_->Show("Enter a session code first",
|
||||||
|
ToastType::kWarning, 3.0f);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
absl::Status status =
|
||||||
|
collaboration_callbacks_.join_session(code);
|
||||||
|
if (status.ok()) {
|
||||||
|
collaboration_state_.active = true;
|
||||||
|
collaboration_state_.session_id = code;
|
||||||
|
collaboration_state_.last_synced = absl::Now();
|
||||||
|
last_collaboration_action_ = absl::Now();
|
||||||
|
RefreshParticipants();
|
||||||
|
if (toast_manager_) {
|
||||||
|
toast_manager_->Show(
|
||||||
|
absl::StrFormat("Joined session %s", code.c_str()),
|
||||||
|
ToastType::kSuccess, 3.5f);
|
||||||
|
}
|
||||||
|
MarkHistoryDirty();
|
||||||
|
} else if (toast_manager_) {
|
||||||
|
toast_manager_->Show(
|
||||||
|
absl::StrFormat("Failed to join: %s", status.message()),
|
||||||
|
ToastType::kError, 5.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!can_join) {
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip("Provide join_session callback to enable joining");
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connected) {
|
||||||
|
if (!can_leave) ImGui::BeginDisabled();
|
||||||
|
if (ImGui::Button("Leave Session")) {
|
||||||
|
absl::Status status = collaboration_callbacks_.leave_session
|
||||||
|
? collaboration_callbacks_.leave_session()
|
||||||
|
: absl::OkStatus();
|
||||||
|
if (status.ok()) {
|
||||||
|
collaboration_state_ = CollaborationState{};
|
||||||
|
if (toast_manager_) {
|
||||||
|
toast_manager_->Show("Left collaborative session",
|
||||||
|
ToastType::kInfo, 3.0f);
|
||||||
|
}
|
||||||
|
MarkHistoryDirty();
|
||||||
|
} else if (toast_manager_) {
|
||||||
|
toast_manager_->Show(
|
||||||
|
absl::StrFormat("Failed to leave: %s", status.message()),
|
||||||
|
ToastType::kError, 5.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!can_leave) ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connected) {
|
||||||
|
ImGui::Separator();
|
||||||
|
if (ImGui::Button("Refresh Participants")) {
|
||||||
|
RefreshParticipants();
|
||||||
|
}
|
||||||
|
if (collaboration_state_.participants.empty()) {
|
||||||
|
ImGui::TextDisabled("Awaiting participant list...");
|
||||||
|
} else {
|
||||||
|
ImGui::Text("Participants (%zu):",
|
||||||
|
collaboration_state_.participants.size());
|
||||||
|
for (const auto& participant : collaboration_state_.participants) {
|
||||||
|
ImGui::BulletText("%s", participant.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ImGui::TextDisabled("Start or join a session to collaborate in real time.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgentChatWidget::RenderMultimodalPanel() {
|
||||||
|
if (!ImGui::CollapsingHeader("Gemini Multimodal (Preview)",
|
||||||
|
ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool can_capture = static_cast<bool>(multimodal_callbacks_.capture_snapshot);
|
||||||
|
bool can_send = static_cast<bool>(multimodal_callbacks_.send_to_gemini);
|
||||||
|
|
||||||
|
if (!can_capture) ImGui::BeginDisabled();
|
||||||
|
if (ImGui::Button("Capture Map Snapshot")) {
|
||||||
|
if (multimodal_callbacks_.capture_snapshot) {
|
||||||
|
std::filesystem::path captured_path;
|
||||||
|
absl::Status status =
|
||||||
|
multimodal_callbacks_.capture_snapshot(&captured_path);
|
||||||
|
if (status.ok()) {
|
||||||
|
multimodal_state_.last_capture_path = captured_path;
|
||||||
|
multimodal_state_.status_message =
|
||||||
|
absl::StrFormat("Captured %s", captured_path.string());
|
||||||
|
multimodal_state_.last_updated = absl::Now();
|
||||||
|
if (toast_manager_) {
|
||||||
|
toast_manager_->Show("Snapshot captured",
|
||||||
|
ToastType::kSuccess, 3.0f);
|
||||||
|
}
|
||||||
|
MarkHistoryDirty();
|
||||||
|
} else {
|
||||||
|
multimodal_state_.status_message = status.message();
|
||||||
|
multimodal_state_.last_updated = absl::Now();
|
||||||
|
if (toast_manager_) {
|
||||||
|
toast_manager_->Show(
|
||||||
|
absl::StrFormat("Snapshot failed: %s", status.message()),
|
||||||
|
ToastType::kError, 5.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!can_capture) {
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip("Provide capture_snapshot callback to enable");
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (multimodal_state_.last_capture_path.has_value()) {
|
||||||
|
ImGui::TextDisabled("Last capture: %s",
|
||||||
|
multimodal_state_.last_capture_path->string().c_str());
|
||||||
|
} else {
|
||||||
|
ImGui::TextDisabled("No capture yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::InputTextMultiline("##gemini_prompt", multimodal_prompt_buffer_,
|
||||||
|
IM_ARRAYSIZE(multimodal_prompt_buffer_),
|
||||||
|
ImVec2(-1, 60.0f));
|
||||||
|
if (!can_send) ImGui::BeginDisabled();
|
||||||
|
if (ImGui::Button("Send to Gemini")) {
|
||||||
|
if (!multimodal_state_.last_capture_path.has_value()) {
|
||||||
|
if (toast_manager_) {
|
||||||
|
toast_manager_->Show("Capture a snapshot first",
|
||||||
|
ToastType::kWarning, 3.0f);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::string prompt = multimodal_prompt_buffer_;
|
||||||
|
absl::Status status = multimodal_callbacks_.send_to_gemini(
|
||||||
|
*multimodal_state_.last_capture_path, prompt);
|
||||||
|
if (status.ok()) {
|
||||||
|
multimodal_state_.status_message =
|
||||||
|
"Submitted image to Gemini";
|
||||||
|
multimodal_state_.last_updated = absl::Now();
|
||||||
|
if (toast_manager_) {
|
||||||
|
toast_manager_->Show("Gemini request sent",
|
||||||
|
ToastType::kSuccess, 3.0f);
|
||||||
|
}
|
||||||
|
MarkHistoryDirty();
|
||||||
|
} else {
|
||||||
|
multimodal_state_.status_message = status.message();
|
||||||
|
multimodal_state_.last_updated = absl::Now();
|
||||||
|
if (toast_manager_) {
|
||||||
|
toast_manager_->Show(
|
||||||
|
absl::StrFormat("Gemini request failed: %s", status.message()),
|
||||||
|
ToastType::kError, 5.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!can_send) {
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip("Provide send_to_gemini callback to enable");
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!multimodal_state_.status_message.empty()) {
|
||||||
|
ImGui::TextDisabled("Status: %s", multimodal_state_.status_message.c_str());
|
||||||
|
if (multimodal_state_.last_updated != absl::InfinitePast()) {
|
||||||
|
ImGui::TextDisabled(
|
||||||
|
"Updated: %s",
|
||||||
|
absl::FormatTime("%H:%M:%S", multimodal_state_.last_updated,
|
||||||
|
absl::LocalTimeZone()).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgentChatWidget::RefreshParticipants() {
|
||||||
|
if (!collaboration_callbacks_.refresh_participants) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto participants_or = collaboration_callbacks_.refresh_participants();
|
||||||
|
if (!participants_or.ok()) {
|
||||||
|
if (toast_manager_) {
|
||||||
|
toast_manager_->Show(
|
||||||
|
absl::StrFormat("Failed to refresh participants: %s",
|
||||||
|
participants_or.status().message()),
|
||||||
|
ToastType::kError, 5.0f);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
collaboration_state_.participants = participants_or.value();
|
||||||
|
collaboration_state_.last_synced = absl::Now();
|
||||||
|
MarkHistoryDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgentChatWidget::MarkHistoryDirty() {
|
||||||
|
history_dirty_ = true;
|
||||||
|
const absl::Time now = absl::Now();
|
||||||
|
if (last_persist_time_ == absl::InfinitePast() ||
|
||||||
|
now - last_persist_time_ > absl::Seconds(2)) {
|
||||||
|
PersistHistory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace editor
|
} // namespace editor
|
||||||
} // namespace yaze
|
} // namespace yaze
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
#define YAZE_SRC_APP_EDITOR_SYSTEM_AGENT_CHAT_WIDGET_H_
|
#define YAZE_SRC_APP_EDITOR_SYSTEM_AGENT_CHAT_WIDGET_H_
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "absl/status/status.h"
|
#include "absl/status/status.h"
|
||||||
#include "absl/status/statusor.h"
|
#include "absl/status/statusor.h"
|
||||||
@@ -26,12 +29,28 @@ class AgentChatWidget {
|
|||||||
|
|
||||||
void SetRomContext(Rom* rom);
|
void SetRomContext(Rom* rom);
|
||||||
|
|
||||||
void SetToastManager(ToastManager* toast_manager) {
|
struct CollaborationCallbacks {
|
||||||
toast_manager_ = toast_manager;
|
std::function<absl::Status(const std::string&)> host_session;
|
||||||
|
std::function<absl::Status(const std::string&)> join_session;
|
||||||
|
std::function<absl::Status()> leave_session;
|
||||||
|
std::function<absl::StatusOr<std::vector<std::string>>()> refresh_participants;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MultimodalCallbacks {
|
||||||
|
std::function<absl::Status(std::filesystem::path*)> capture_snapshot;
|
||||||
|
std::function<absl::Status(const std::filesystem::path&, const std::string&)> send_to_gemini;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetToastManager(ToastManager* toast_manager);
|
||||||
|
|
||||||
|
void SetProposalDrawer(ProposalDrawer* drawer);
|
||||||
|
|
||||||
|
void SetCollaborationCallbacks(const CollaborationCallbacks& callbacks) {
|
||||||
|
collaboration_callbacks_ = callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetProposalDrawer(ProposalDrawer* drawer) {
|
void SetMultimodalCallbacks(const MultimodalCallbacks& callbacks) {
|
||||||
proposal_drawer_ = drawer;
|
multimodal_callbacks_ = callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool* active() { return &active_; }
|
bool* active() { return &active_; }
|
||||||
@@ -39,19 +58,36 @@ class AgentChatWidget {
|
|||||||
void set_active(bool active) { active_ = active; }
|
void set_active(bool active) { active_ = active; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void EnsureHistoryLoaded();
|
struct CollaborationState {
|
||||||
void PersistHistory();
|
bool active = false;
|
||||||
void RenderHistory();
|
std::string session_id;
|
||||||
void RenderMessage(const cli::agent::ChatMessage& msg, int index);
|
std::vector<std::string> participants;
|
||||||
void RenderProposalQuickActions(const cli::agent::ChatMessage& msg,
|
absl::Time last_synced = absl::InfinitePast();
|
||||||
int index);
|
};
|
||||||
void RenderInputBox();
|
|
||||||
void HandleAgentResponse(
|
struct MultimodalState {
|
||||||
const absl::StatusOr<cli::agent::ChatMessage>& response);
|
std::optional<std::filesystem::path> last_capture_path;
|
||||||
int CountKnownProposals() const;
|
std::string status_message;
|
||||||
void FocusProposalDrawer(const std::string& proposal_id);
|
absl::Time last_updated = absl::InfinitePast();
|
||||||
void NotifyProposalCreated(const cli::agent::ChatMessage& msg,
|
};
|
||||||
int new_total_proposals);
|
|
||||||
|
void EnsureHistoryLoaded();
|
||||||
|
void PersistHistory();
|
||||||
|
void RenderHistory();
|
||||||
|
void RenderMessage(const cli::agent::ChatMessage& msg, int index);
|
||||||
|
void RenderProposalQuickActions(const cli::agent::ChatMessage& msg,
|
||||||
|
int index);
|
||||||
|
void RenderInputBox();
|
||||||
|
void HandleAgentResponse(
|
||||||
|
const absl::StatusOr<cli::agent::ChatMessage>& response);
|
||||||
|
int CountKnownProposals() const;
|
||||||
|
void FocusProposalDrawer(const std::string& proposal_id);
|
||||||
|
void NotifyProposalCreated(const cli::agent::ChatMessage& msg,
|
||||||
|
int new_total_proposals);
|
||||||
|
void RenderCollaborationPanel();
|
||||||
|
void RenderMultimodalPanel();
|
||||||
|
void RefreshParticipants();
|
||||||
|
void MarkHistoryDirty();
|
||||||
|
|
||||||
cli::agent::ConversationalAgentService agent_service_;
|
cli::agent::ConversationalAgentService agent_service_;
|
||||||
char input_buffer_[1024];
|
char input_buffer_[1024];
|
||||||
@@ -66,6 +102,14 @@ class AgentChatWidget {
|
|||||||
ProposalDrawer* proposal_drawer_ = nullptr;
|
ProposalDrawer* proposal_drawer_ = nullptr;
|
||||||
std::string pending_focus_proposal_id_;
|
std::string pending_focus_proposal_id_;
|
||||||
absl::Time last_persist_time_ = absl::InfinitePast();
|
absl::Time last_persist_time_ = absl::InfinitePast();
|
||||||
|
CollaborationState collaboration_state_;
|
||||||
|
CollaborationCallbacks collaboration_callbacks_;
|
||||||
|
MultimodalState multimodal_state_;
|
||||||
|
MultimodalCallbacks multimodal_callbacks_;
|
||||||
|
char session_name_buffer_[64] = {};
|
||||||
|
char join_code_buffer_[64] = {};
|
||||||
|
char multimodal_prompt_buffer_[256] = {};
|
||||||
|
absl::Time last_collaboration_action_ = absl::InfinitePast();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace editor
|
} // namespace editor
|
||||||
|
|||||||
Reference in New Issue
Block a user