yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
agent_editor_collaboration.cc
Go to the documentation of this file.
1#include <cstdlib>
2#include <cstring>
3#include <filesystem>
4#include <memory>
5#include <optional>
6#include <string>
7
8#include "absl/status/status.h"
9#include "absl/status/statusor.h"
10#include "absl/strings/str_format.h"
11#include "absl/time/clock.h"
18
19#ifdef YAZE_WITH_GRPC
22#endif
23
24namespace yaze {
25namespace editor {
26
27absl::StatusOr<AgentEditor::SessionInfo> AgentEditor::HostSession(
28 const std::string& session_name, CollaborationMode mode) {
29 current_mode_ = mode;
30
31 if (mode == CollaborationMode::kLocal) {
32 auto session_or = local_coordinator_->HostSession(session_name);
33 if (!session_or.ok())
34 return session_or.status();
35
36 SessionInfo info;
37 info.session_id = session_or->session_id;
38 info.session_name = session_or->session_name;
39 info.participants = session_or->participants;
40
41 in_session_ = true;
45
46 if (toast_manager_) {
48 absl::StrFormat("Hosting local session: %s", session_name),
50 }
51 return info;
52 }
53
54#ifdef YAZE_WITH_GRPC
55 if (mode == CollaborationMode::kNetwork) {
56 if (!network_coordinator_) {
57 return absl::FailedPreconditionError(
58 "Network coordinator not initialized. Connect to a server first.");
59 }
60
61 const char* username = std::getenv("USER");
62 if (!username) {
63 username = std::getenv("USERNAME");
64 }
65 if (!username) {
66 username = "unknown";
67 }
68
69 auto session_or = network_coordinator_->HostSession(session_name, username);
70 if (!session_or.ok())
71 return session_or.status();
72
73 SessionInfo info;
74 info.session_id = session_or->session_id;
75 info.session_name = session_or->session_name;
76 info.participants = session_or->participants;
77
78 in_session_ = true;
82
83 if (toast_manager_) {
85 absl::StrFormat("Hosting network session: %s", session_name),
87 }
88
89 return info;
90 }
91#endif
92
93 return absl::InvalidArgumentError("Unsupported collaboration mode");
94}
95
96absl::StatusOr<AgentEditor::SessionInfo> AgentEditor::JoinSession(
97 const std::string& session_code, CollaborationMode mode) {
98 current_mode_ = mode;
99
100 if (mode == CollaborationMode::kLocal) {
101 auto session_or = local_coordinator_->JoinSession(session_code);
102 if (!session_or.ok())
103 return session_or.status();
104
105 SessionInfo info;
106 info.session_id = session_or->session_id;
107 info.session_name = session_or->session_name;
108 info.participants = session_or->participants;
109
110 in_session_ = true;
114
115 if (toast_manager_) {
117 absl::StrFormat("Joined local session: %s", session_code),
118 ToastType::kSuccess, 3.0f);
119 }
120
121 return info;
122 }
123
124#ifdef YAZE_WITH_GRPC
125 if (mode == CollaborationMode::kNetwork) {
126 if (!network_coordinator_) {
127 return absl::FailedPreconditionError(
128 "Network coordinator not initialized. Connect to a server first.");
129 }
130
131 const char* username = std::getenv("USER");
132 if (!username) {
133 username = std::getenv("USERNAME");
134 }
135 if (!username) {
136 username = "unknown";
137 }
138
139 auto session_or = network_coordinator_->JoinSession(session_code, username);
140 if (!session_or.ok())
141 return session_or.status();
142
143 SessionInfo info;
144 info.session_id = session_or->session_id;
145 info.session_name = session_or->session_name;
146 info.participants = session_or->participants;
147
148 in_session_ = true;
152
153 if (toast_manager_) {
155 absl::StrFormat("Joined network session: %s", session_code),
156 ToastType::kSuccess, 3.0f);
157 }
158
159 return info;
160 }
161#endif
162
163 return absl::InvalidArgumentError("Unsupported collaboration mode");
164}
165
167 if (!in_session_) {
168 return absl::FailedPreconditionError("Not in a session");
169 }
170
172 auto status = local_coordinator_->LeaveSession();
173 if (!status.ok())
174 return status;
175 }
176#ifdef YAZE_WITH_GRPC
178 if (network_coordinator_) {
179 auto status = network_coordinator_->LeaveSession();
180 if (!status.ok())
181 return status;
182 }
183 }
184#endif
185
186 in_session_ = false;
187 current_session_id_.clear();
188 current_session_name_.clear();
189 current_participants_.clear();
190
191 if (toast_manager_) {
192 toast_manager_->Show("Left collaboration session", ToastType::kInfo, 3.0f);
193 }
194
195 return absl::OkStatus();
196}
197
198absl::StatusOr<AgentEditor::SessionInfo> AgentEditor::RefreshSession() {
199 if (!in_session_) {
200 return absl::FailedPreconditionError("Not in a session");
201 }
202
204 auto session_or = local_coordinator_->RefreshSession();
205 if (!session_or.ok())
206 return session_or.status();
207
208 SessionInfo info;
209 info.session_id = session_or->session_id;
210 info.session_name = session_or->session_name;
211 info.participants = session_or->participants;
213 return info;
214 }
215
216 SessionInfo info;
220 return info;
221}
222
223absl::Status AgentEditor::CaptureSnapshot(std::filesystem::path* output_path,
224 const CaptureConfig& config) {
225#ifdef YAZE_WITH_GRPC
226 using yaze::test::CaptureActiveWindow;
227 using yaze::test::CaptureHarnessScreenshot;
228 using yaze::test::CaptureWindowByName;
229
230 absl::StatusOr<yaze::test::ScreenshotArtifact> result;
231 switch (config.mode) {
233 result = CaptureHarnessScreenshot("");
234 break;
236 result = CaptureActiveWindow("");
237 if (!result.ok()) {
238 result = CaptureHarnessScreenshot("");
239 }
240 break;
242 if (!config.specific_window_name.empty()) {
243 result = CaptureWindowByName(config.specific_window_name, "");
244 } else {
245 result = CaptureActiveWindow("");
246 }
247 if (!result.ok()) {
248 result = CaptureHarnessScreenshot("");
249 }
250 break;
251 }
252 }
253
254 if (!result.ok()) {
255 return result.status();
256 }
257 *output_path = result->file_path;
258 return absl::OkStatus();
259#else
260 (void)output_path;
261 (void)config;
262 return absl::UnimplementedError("Screenshot capture requires YAZE_WITH_GRPC");
263#endif
264}
265
266absl::Status AgentEditor::SendToGemini(const std::filesystem::path& image_path,
267 const std::string& prompt) {
268#ifdef YAZE_WITH_GRPC
269 const char* api_key = current_profile_.gemini_api_key.empty()
270 ? std::getenv("GEMINI_API_KEY")
272 if (!api_key || std::strlen(api_key) == 0) {
273 return absl::FailedPreconditionError(
274 "Gemini API key not configured (set GEMINI_API_KEY)");
275 }
276
277 cli::GeminiConfig config;
278 config.api_key = api_key;
279 config.model = current_profile_.model.empty() ? "gemini-2.5-flash"
282
283 cli::GeminiAIService gemini_service(config);
284 auto response =
285 gemini_service.GenerateMultimodalResponse(image_path.string(), prompt);
286 if (!response.ok()) {
287 return response.status();
288 }
289
290 if (agent_chat_) {
291 auto* service = agent_chat_->GetAgentService();
292 if (service) {
293 auto history = service->GetHistory();
294 cli::agent::ChatMessage agent_msg;
296 agent_msg.message = response->text_response;
297 agent_msg.timestamp = absl::Now();
298 history.push_back(agent_msg);
299 service->ReplaceHistory(history);
300 }
301 }
302
303 if (toast_manager_) {
304 toast_manager_->Show("Gemini vision response added to chat",
305 ToastType::kSuccess, 2.5f);
306 }
307 return absl::OkStatus();
308#else
309 (void)image_path;
310 (void)prompt;
311 return absl::UnimplementedError("Gemini integration requires YAZE_WITH_GRPC");
312#endif
313}
314
315#ifdef YAZE_WITH_GRPC
316absl::Status AgentEditor::ConnectToServer(const std::string& server_url) {
317 try {
318 network_coordinator_ =
319 std::make_unique<NetworkCollaborationCoordinator>(server_url);
320
321 if (toast_manager_) {
323 absl::StrFormat("Connected to server: %s", server_url),
324 ToastType::kSuccess, 3.0f);
325 }
326
327 return absl::OkStatus();
328 } catch (const std::exception& e) {
329 return absl::InternalError(
330 absl::StrFormat("Failed to connect to server: %s", e.what()));
331 }
332}
333
334void AgentEditor::DisconnectFromServer() {
336 LeaveSession();
337 }
338 network_coordinator_.reset();
339
340 if (toast_manager_) {
341 toast_manager_->Show("Disconnected from server", ToastType::kInfo, 2.5f);
342 }
343}
344
345bool AgentEditor::IsConnectedToServer() const {
346 return network_coordinator_ && network_coordinator_->IsConnected();
347}
348#endif
349
351 return in_session_;
352}
353
357
358std::optional<AgentEditor::SessionInfo> AgentEditor::GetCurrentSession() const {
359 if (!in_session_)
360 return std::nullopt;
363}
364
366
368
369} // namespace editor
370} // namespace yaze
absl::StatusOr< AgentResponse > GenerateMultimodalResponse(const std::string &, const std::string &)
absl::StatusOr< SessionInfo > JoinSession(const std::string &session_code, CollaborationMode mode=CollaborationMode::kLocal)
absl::StatusOr< SessionInfo > RefreshSession()
std::string current_session_name_
CollaborationMode GetCurrentMode() const
absl::Status SendToGemini(const std::filesystem::path &image_path, const std::string &prompt)
CollaborationMode current_mode_
ToastManager * toast_manager_
absl::StatusOr< SessionInfo > HostSession(const std::string &session_name, CollaborationMode mode=CollaborationMode::kLocal)
std::unique_ptr< AgentCollaborationCoordinator > local_coordinator_
absl::Status CaptureSnapshot(std::filesystem::path *output_path, const CaptureConfig &config)
std::vector< std::string > current_participants_
std::unique_ptr< AgentChat > agent_chat_
std::optional< SessionInfo > GetCurrentSession() const
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f)
std::vector< std::string > participants