@prbe.ai/electron-sdk 0.1.12 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -34,6 +34,7 @@ __export(src_exports, {
34
34
  AskUserTool: () => AskUserTool,
35
35
  BashExecuteTool: () => BashExecuteTool,
36
36
  ClearAppLogsTool: () => ClearAppLogsTool,
37
+ ConversationRole: () => ConversationRole,
37
38
  DEFAULT_PRBE_STATE: () => DEFAULT_PRBE_STATE,
38
39
  FindFilesTool: () => FindFilesTool,
39
40
  FlagAppLogsTool: () => FlagAppLogsTool,
@@ -79,6 +80,7 @@ var WSMessageType = /* @__PURE__ */ ((WSMessageType2) => {
79
80
  WSMessageType2["START"] = "start";
80
81
  WSMessageType2["TOOL_RESULT"] = "tool_result";
81
82
  WSMessageType2["UPLOAD_REQUEST"] = "upload_request";
83
+ WSMessageType2["CONVERSATION_MESSAGE"] = "conversation_message";
82
84
  WSMessageType2["CANCEL"] = "cancel";
83
85
  WSMessageType2["PONG"] = "pong";
84
86
  WSMessageType2["THOUGHT"] = "thought";
@@ -87,11 +89,17 @@ var WSMessageType = /* @__PURE__ */ ((WSMessageType2) => {
87
89
  WSMessageType2["SERVER_OBSERVATION"] = "server_observation";
88
90
  WSMessageType2["UPLOAD_URL"] = "upload_url";
89
91
  WSMessageType2["SESSION_CONFIG"] = "session_config";
92
+ WSMessageType2["CONVERSATION_UPDATE"] = "conversation_update";
90
93
  WSMessageType2["COMPLETE"] = "complete";
91
94
  WSMessageType2["ERROR"] = "error";
92
95
  WSMessageType2["PING"] = "ping";
93
96
  return WSMessageType2;
94
97
  })(WSMessageType || {});
98
+ var ConversationRole = /* @__PURE__ */ ((ConversationRole3) => {
99
+ ConversationRole3["User"] = "user";
100
+ ConversationRole3["Agent"] = "agent";
101
+ return ConversationRole3;
102
+ })(ConversationRole || {});
95
103
  var ToolParamType = /* @__PURE__ */ ((ToolParamType2) => {
96
104
  ToolParamType2["STRING"] = "STRING";
97
105
  ToolParamType2["BOOLEAN"] = "BOOLEAN";
@@ -161,6 +169,83 @@ function redactPII(text) {
161
169
  var API_URL = "https://api.prbe.ai";
162
170
  var MIDDLEWARE_URL = "wss://middleware.prbe.ai";
163
171
 
172
+ // src/connection.ts
173
+ var InvestigationConnection = class {
174
+ constructor(url, apiKey, onMessage, onError, onClose) {
175
+ this.onMessage = onMessage;
176
+ this.onError = onError;
177
+ this.onClose = onClose;
178
+ this.ws = new WebSocket(url, {
179
+ headers: { "X-API-Key": apiKey }
180
+ });
181
+ this.ws.onmessage = (event) => {
182
+ const raw = typeof event.data === "string" ? event.data : event.data instanceof Buffer ? event.data.toString("utf-8") : null;
183
+ if (!raw) return;
184
+ try {
185
+ const msg = JSON.parse(raw);
186
+ this.onMessage(msg);
187
+ } catch {
188
+ }
189
+ };
190
+ this.ws.onerror = (event) => {
191
+ const errorEvent = event;
192
+ this.onError(errorEvent.message || "WebSocket connection error");
193
+ };
194
+ this.ws.onclose = () => {
195
+ this.onClose();
196
+ };
197
+ }
198
+ ws;
199
+ closed = false;
200
+ get isOpen() {
201
+ return !this.closed && this.ws.readyState === WebSocket.OPEN;
202
+ }
203
+ send(msg) {
204
+ if (!this.isOpen) return false;
205
+ try {
206
+ this.ws.send(JSON.stringify(msg));
207
+ return true;
208
+ } catch {
209
+ return false;
210
+ }
211
+ }
212
+ sendConversationMessage(content) {
213
+ this.send({
214
+ type: "conversation_message" /* CONVERSATION_MESSAGE */,
215
+ content
216
+ });
217
+ }
218
+ sendToolResult(callId, toolName, result, metadata) {
219
+ this.send({
220
+ type: "tool_result" /* TOOL_RESULT */,
221
+ id: callId,
222
+ name: toolName,
223
+ content: result,
224
+ metadata
225
+ });
226
+ }
227
+ sendCancel() {
228
+ this.send({ type: "cancel" /* CANCEL */ });
229
+ }
230
+ sendPong() {
231
+ this.send({ type: "pong" /* PONG */ });
232
+ }
233
+ close(code = 1e3, reason) {
234
+ if (this.closed) return;
235
+ this.closed = true;
236
+ try {
237
+ this.ws.close(code, reason);
238
+ } catch {
239
+ }
240
+ }
241
+ /**
242
+ * Set the onopen handler. Called when the connection is ready to send messages.
243
+ */
244
+ set onopen(handler) {
245
+ this.ws.onopen = handler;
246
+ }
247
+ };
248
+
164
249
  // src/state.ts
165
250
  var import_events = require("events");
166
251
  var import_crypto = require("crypto");
@@ -189,6 +274,7 @@ var PRBEAgentState = class extends import_events.EventEmitter {
189
274
  pendingInteraction;
190
275
  resolvedInteractions = [];
191
276
  agentMessage;
277
+ conversationHistory = [];
192
278
  // Completed user investigations (history)
193
279
  completedInvestigations = [];
194
280
  // Background context requests
@@ -212,6 +298,7 @@ var PRBEAgentState = class extends import_events.EventEmitter {
212
298
  this.isInvestigating = true;
213
299
  this.events = [];
214
300
  this.resolvedInteractions = [];
301
+ this.conversationHistory = [];
215
302
  this.report = "";
216
303
  this.summary = "";
217
304
  this.currentQuery = query;
@@ -219,10 +306,15 @@ var PRBEAgentState = class extends import_events.EventEmitter {
219
306
  this.agentMessage = void 0;
220
307
  this.emit("status" /* STATUS */);
221
308
  }
309
+ appendConversation(entry) {
310
+ this.conversationHistory.push(entry);
311
+ this.emit("status" /* STATUS */);
312
+ }
222
313
  resetInvestigation() {
223
314
  this.isInvestigating = false;
224
315
  this.events = [];
225
316
  this.resolvedInteractions = [];
317
+ this.conversationHistory = [];
226
318
  this.report = "";
227
319
  this.summary = "";
228
320
  this.currentQuery = "";
@@ -255,7 +347,7 @@ var PRBEAgentState = class extends import_events.EventEmitter {
255
347
  this.emit("status" /* STATUS */);
256
348
  }
257
349
  }
258
- completeInvestigation(report, summary, ticketId) {
350
+ completeInvestigation(report, ticketId) {
259
351
  if (this.events.length > 0) {
260
352
  this.events[this.events.length - 1].isCompleted = true;
261
353
  }
@@ -264,16 +356,15 @@ var PRBEAgentState = class extends import_events.EventEmitter {
264
356
  id: (0, import_crypto.randomUUID)(),
265
357
  query: this.currentQuery,
266
358
  report,
267
- summary,
268
359
  ticketId,
269
360
  events: [...this.events],
270
361
  resolvedInteractions: [...this.resolvedInteractions],
362
+ conversationHistory: [...this.conversationHistory],
271
363
  completedAt: /* @__PURE__ */ new Date()
272
364
  });
273
365
  this.report = report;
274
- this.summary = summary;
275
366
  this.isInvestigating = false;
276
- this.emit("complete" /* COMPLETE */, { report, summary });
367
+ this.emit("complete" /* COMPLETE */, { report });
277
368
  this.emit("status" /* STATUS */);
278
369
  }
279
370
  failInvestigation(message) {
@@ -398,7 +489,7 @@ var PRBEAgentState = class extends import_events.EventEmitter {
398
489
  cr.events[cr.events.length - 1].detail = text;
399
490
  this.emit("status" /* STATUS */);
400
491
  }
401
- completeCR(id, report, summary) {
492
+ completeCR(id, report) {
402
493
  const cr = this.activeCRs.get(id);
403
494
  if (!cr) return;
404
495
  this.activeCRs.delete(id);
@@ -414,7 +505,6 @@ var PRBEAgentState = class extends import_events.EventEmitter {
414
505
  cr.isRunning = false;
415
506
  cr.isCompleted = true;
416
507
  cr.report = report;
417
- cr.summary = summary;
418
508
  this.completedCRs.unshift(cr);
419
509
  this.emit("cr-complete" /* CR_COMPLETE */, cr);
420
510
  this.emit("status" /* STATUS */);
@@ -1351,9 +1441,9 @@ var AskUserTool = class {
1351
1441
  required: true
1352
1442
  },
1353
1443
  {
1354
- name: "context",
1444
+ name: "reason",
1355
1445
  type: "STRING" /* STRING */,
1356
- description: "Optional context explaining why you need this information",
1446
+ description: "Short reason displayed alongside the input prompt explaining why you need this information",
1357
1447
  required: false
1358
1448
  }
1359
1449
  ]
@@ -1365,12 +1455,11 @@ var AskUserTool = class {
1365
1455
  if (this.requester.investigationSource !== "user" /* USER */) {
1366
1456
  return "This is a context request investigation \u2014 you cannot ask the user questions. Use the available tools to answer the query autonomously.";
1367
1457
  }
1368
- const context = args["context"];
1458
+ const reason = args["reason"] ?? "Waiting for your response";
1369
1459
  const response = await this.requester.requestUserInteraction({
1370
1460
  type: "ask_question" /* ASK_QUESTION */,
1371
1461
  interactionId: (0, import_crypto3.randomUUID)(),
1372
- question,
1373
- context
1462
+ question: reason
1374
1463
  });
1375
1464
  const askResponse = response;
1376
1465
  return askResponse.answer;
@@ -1791,6 +1880,7 @@ var HistoryStore = class {
1791
1880
  ticketId: inv.ticketId,
1792
1881
  events: inv.events,
1793
1882
  resolvedInteractions: inv.resolvedInteractions,
1883
+ conversationHistory: inv.conversationHistory,
1794
1884
  completedAt: inv.completedAt.toISOString()
1795
1885
  };
1796
1886
  fs2.writeFileSync(
@@ -1883,7 +1973,7 @@ var PRBEAgent = class _PRBEAgent {
1883
1973
  registry = new PRBEToolRegistry();
1884
1974
  grantedPaths = /* @__PURE__ */ new Set();
1885
1975
  userCancelled = false;
1886
- activeWS = null;
1976
+ activeConnection = null;
1887
1977
  pollingTimer = null;
1888
1978
  persistedData;
1889
1979
  fetchAbortController = null;
@@ -1911,13 +2001,6 @@ var PRBEAgent = class _PRBEAgent {
1911
2001
  this.state.updateTrackedSessionIDs(ids);
1912
2002
  this.syncPolling(ids.length > 0);
1913
2003
  }
1914
- get respondedCRIDs() {
1915
- return new Set(this.persistedData.respondedCRIds ?? []);
1916
- }
1917
- set respondedCRIDs(ids) {
1918
- this.persistedData.respondedCRIds = Array.from(ids);
1919
- savePersistedData(this.persistedData);
1920
- }
1921
2004
  syncPolling(hasSessions) {
1922
2005
  if (this.config.backgroundPolling && hasSessions) {
1923
2006
  if (this.pollingTimer === null) {
@@ -2050,6 +2133,9 @@ var PRBEAgent = class _PRBEAgent {
2050
2133
  get investigationSource() {
2051
2134
  return this.currentInvestigationSource;
2052
2135
  }
2136
+ sendConversationMessage(content) {
2137
+ this.activeConnection?.sendConversationMessage(content);
2138
+ }
2053
2139
  async requestUserInteraction(payload) {
2054
2140
  if (!this.interactionHandler) {
2055
2141
  throw new PRBEAgentError(
@@ -2069,6 +2155,13 @@ var PRBEAgent = class _PRBEAgent {
2069
2155
  } else {
2070
2156
  this.state.resolveInteraction(response);
2071
2157
  }
2158
+ if (response.type === "request_permission" /* REQUEST_PERMISSION */) {
2159
+ const approved = response.approved;
2160
+ this.sendConversationMessage(approved ? "Approved" : "Denied");
2161
+ } else if (response.type === "request_path_access" /* REQUEST_PATH_ACCESS */) {
2162
+ const granted = response.granted;
2163
+ this.sendConversationMessage(granted ? "Allowed" : "Denied");
2164
+ }
2072
2165
  return response;
2073
2166
  } catch (err) {
2074
2167
  if (this.currentInvestigationSource === "context_request" /* CONTEXT_REQUEST */ && this.currentCRId) {
@@ -2121,7 +2214,7 @@ var PRBEAgent = class _PRBEAgent {
2121
2214
  this.state.appendEvent("Thinking", status.text);
2122
2215
  break;
2123
2216
  case "completed" /* COMPLETED */:
2124
- this.state.completeInvestigation(status.report, status.userSummary, status.ticketId);
2217
+ this.state.completeInvestigation(status.report, status.ticketId);
2125
2218
  this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
2126
2219
  break;
2127
2220
  case "error" /* ERROR */:
@@ -2151,9 +2244,9 @@ var PRBEAgent = class _PRBEAgent {
2151
2244
  */
2152
2245
  cancelInvestigation() {
2153
2246
  this.userCancelled = true;
2154
- if (this.activeWS) {
2155
- this.activeWS.close(1e3, "User cancelled");
2156
- this.activeWS = null;
2247
+ if (this.activeConnection) {
2248
+ this.activeConnection.close(1e3, "User cancelled");
2249
+ this.activeConnection = null;
2157
2250
  }
2158
2251
  }
2159
2252
  /**
@@ -2161,9 +2254,9 @@ var PRBEAgent = class _PRBEAgent {
2161
2254
  */
2162
2255
  cancel() {
2163
2256
  this.userCancelled = true;
2164
- if (this.activeWS) {
2165
- this.activeWS.close(1e3, "User cancelled");
2166
- this.activeWS = null;
2257
+ if (this.activeConnection) {
2258
+ this.activeConnection.close(1e3, "User cancelled");
2259
+ this.activeConnection = null;
2167
2260
  }
2168
2261
  this.abortInFlightRequests();
2169
2262
  this.stopPolling();
@@ -2199,27 +2292,12 @@ var PRBEAgent = class _PRBEAgent {
2199
2292
  "/api/agent/poll",
2200
2293
  request
2201
2294
  );
2202
- const knownCRIDs = /* @__PURE__ */ new Set();
2203
2295
  for (const ticket of response.tickets) {
2204
2296
  for (const cr of ticket.context_requests) {
2205
- knownCRIDs.add(cr.id);
2206
- if (!cr.is_active || this.respondedCRIDs.has(cr.id)) continue;
2297
+ if (!cr.is_active) continue;
2207
2298
  await this.investigateForCR(cr, ticket.ticket_id);
2208
- const ids = this.respondedCRIDs;
2209
- ids.add(cr.id);
2210
- this.respondedCRIDs = ids;
2211
2299
  }
2212
2300
  }
2213
- const currentRespondedIDs = this.respondedCRIDs;
2214
- const stale = new Set(
2215
- [...currentRespondedIDs].filter((id) => !knownCRIDs.has(id))
2216
- );
2217
- if (stale.size > 0) {
2218
- const pruned = new Set(
2219
- [...currentRespondedIDs].filter((id) => !stale.has(id))
2220
- );
2221
- this.respondedCRIDs = pruned;
2222
- }
2223
2301
  return response;
2224
2302
  } catch {
2225
2303
  return null;
@@ -2317,7 +2395,7 @@ var PRBEAgent = class _PRBEAgent {
2317
2395
  this.state.appendCREvent(crID, "Thinking", status.text);
2318
2396
  break;
2319
2397
  case "completed" /* COMPLETED */:
2320
- this.state.completeCR(crID, status.report, status.userSummary);
2398
+ this.state.completeCR(crID, status.report);
2321
2399
  this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
2322
2400
  break;
2323
2401
  case "error" /* ERROR */:
@@ -2344,31 +2422,44 @@ var PRBEAgent = class _PRBEAgent {
2344
2422
  connectToProxy(query, contextRequestID, emit, isCancelled, ticketId) {
2345
2423
  return new Promise((resolve2) => {
2346
2424
  const wsUrl = `${MIDDLEWARE_URL}/api/agent/client/ws`;
2347
- let ws;
2348
- try {
2349
- ws = new WebSocket(wsUrl, {
2350
- headers: {
2351
- "X-API-Key": this.config.apiKey
2352
- }
2353
- });
2354
- } catch (err) {
2355
- emit({
2356
- type: "error" /* ERROR */,
2357
- message: `Failed to create WebSocket: ${err}`
2358
- });
2359
- resolve2(null);
2360
- return;
2361
- }
2362
- this.activeWS = ws;
2363
2425
  let uploadBaseUrl;
2364
2426
  let resolved = false;
2365
2427
  const finish = (result) => {
2366
2428
  if (resolved) return;
2367
2429
  resolved = true;
2368
- this.activeWS = null;
2430
+ this.activeConnection = null;
2369
2431
  resolve2(result);
2370
2432
  };
2371
- ws.onopen = () => {
2433
+ let conn;
2434
+ try {
2435
+ conn = new InvestigationConnection(
2436
+ wsUrl,
2437
+ this.config.apiKey,
2438
+ (msg) => this.handleMessage(msg, conn, emit, isCancelled, finish, () => uploadBaseUrl, (url) => {
2439
+ uploadBaseUrl = url;
2440
+ }),
2441
+ (message) => {
2442
+ if (!isCancelled()) emit({ type: "error" /* ERROR */, message });
2443
+ finish(null);
2444
+ },
2445
+ () => {
2446
+ if (!resolved) {
2447
+ if (isCancelled()) {
2448
+ finish(null);
2449
+ } else {
2450
+ emit({ type: "error" /* ERROR */, message: "WebSocket connection closed unexpectedly" });
2451
+ finish(null);
2452
+ }
2453
+ }
2454
+ }
2455
+ );
2456
+ } catch (err) {
2457
+ emit({ type: "error" /* ERROR */, message: `Failed to create WebSocket: ${err}` });
2458
+ resolve2(null);
2459
+ return;
2460
+ }
2461
+ this.activeConnection = conn;
2462
+ conn.onopen = () => {
2372
2463
  const toolDeclarations = this.registry.allDeclarations().map((decl) => ({
2373
2464
  name: decl.name,
2374
2465
  description: decl.description,
@@ -2387,206 +2478,99 @@ var PRBEAgent = class _PRBEAgent {
2387
2478
  os_version: os2.release(),
2388
2479
  arch: os2.arch()
2389
2480
  };
2390
- if (contextRequestID) {
2391
- startMetadata["context_request_id"] = contextRequestID;
2392
- }
2393
- if (ticketId) {
2394
- startMetadata["ticket_id"] = ticketId;
2395
- }
2396
- if (this.appDataPath) {
2397
- startMetadata["app_data_path"] = this.appDataPath;
2398
- }
2399
- const startMsg = {
2400
- type: "start" /* START */,
2401
- content: query,
2402
- metadata: startMetadata
2403
- };
2404
- try {
2405
- ws.send(JSON.stringify(startMsg));
2406
- } catch (err) {
2407
- emit({
2408
- type: "error" /* ERROR */,
2409
- message: `Failed to send start message: ${err}`
2410
- });
2481
+ if (contextRequestID) startMetadata["context_request_id"] = contextRequestID;
2482
+ if (ticketId) startMetadata["ticket_id"] = ticketId;
2483
+ if (this.appDataPath) startMetadata["app_data_path"] = this.appDataPath;
2484
+ if (!conn.send({ type: "start" /* START */, content: query, metadata: startMetadata })) {
2485
+ emit({ type: "error" /* ERROR */, message: "Failed to send start message" });
2411
2486
  finish(null);
2412
2487
  return;
2413
2488
  }
2414
2489
  emit({ type: "started" /* STARTED */ });
2415
2490
  this.pendingFlaggedFiles = [];
2416
2491
  };
2417
- ws.onmessage = async (event) => {
2418
- if (isCancelled()) {
2419
- this.sendCancel(ws);
2420
- ws.close(1e3, "Cancelled");
2421
- finish(null);
2422
- return;
2423
- }
2424
- let raw;
2425
- if (typeof event.data === "string") {
2426
- raw = event.data;
2427
- } else if (event.data instanceof Buffer) {
2428
- raw = event.data.toString("utf-8");
2429
- } else {
2430
- return;
2431
- }
2432
- let msg;
2433
- try {
2434
- msg = JSON.parse(raw);
2435
- } catch {
2436
- return;
2437
- }
2438
- switch (msg.type) {
2439
- case "thought" /* THOUGHT */:
2440
- emit({
2441
- type: "thought" /* THOUGHT */,
2442
- text: msg.content ?? ""
2443
- });
2444
- break;
2445
- case "tool_call" /* TOOL_CALL */: {
2446
- const toolName = msg.name ?? "";
2447
- const callId = msg.id ?? "";
2448
- const args = this.extractArgs(msg.metadata);
2449
- emit({
2450
- type: "tool_call" /* TOOL_CALL */,
2451
- name: toolName,
2452
- label: msg.content ?? `Running ${toolName}`
2453
- });
2454
- this.pendingFlaggedFiles = [];
2455
- const toolResult = redactPII(
2456
- await this.registry.execute(toolName, args)
2457
- );
2458
- emit({
2459
- type: "observation" /* OBSERVATION */,
2460
- text: toolResult.substring(0, 200)
2461
- });
2462
- let resultMetadata;
2463
- if (this.pendingFlaggedFiles.length > 0 && uploadBaseUrl) {
2464
- const uploadPrefix = this.extractUploadPrefix(uploadBaseUrl);
2465
- const uploadedRefs = [];
2466
- for (const file of this.pendingFlaggedFiles) {
2467
- const filename = path5.basename(file.originalPath);
2468
- const safeName = encodeURIComponent(filename);
2469
- const storagePath = `${uploadPrefix}/${safeName}`;
2470
- uploadedRefs.push({
2471
- original_path: file.originalPath,
2472
- reason: file.reason ?? "",
2473
- storage_path: storagePath,
2474
- file_size_bytes: file.data.length
2475
- });
2476
- const uploadUrl = `${uploadBaseUrl}/${safeName}`;
2477
- const fileData = file.data;
2478
- const contentType = file.isText ? "text/plain" : "application/octet-stream";
2479
- void _PRBEAgent.backgroundUpload(
2480
- fileData,
2481
- uploadUrl,
2482
- this.config.apiKey,
2483
- contentType,
2484
- this.getFetchSignal()
2485
- );
2486
- }
2487
- resultMetadata = { flagged_files: uploadedRefs };
2488
- this.pendingFlaggedFiles = [];
2489
- }
2490
- const resultMsg = {
2491
- type: "tool_result" /* TOOL_RESULT */,
2492
- id: callId,
2493
- name: toolName,
2494
- content: toolResult,
2495
- metadata: resultMetadata
2496
- };
2497
- try {
2498
- ws.send(JSON.stringify(resultMsg));
2499
- } catch {
2500
- }
2501
- break;
2502
- }
2503
- case "server_tool_call" /* SERVER_TOOL_CALL */:
2504
- emit({
2505
- type: "tool_call" /* TOOL_CALL */,
2506
- name: msg.name ?? "",
2507
- label: msg.content ?? ""
2508
- });
2509
- break;
2510
- case "server_observation" /* SERVER_OBSERVATION */:
2511
- emit({
2512
- type: "observation" /* OBSERVATION */,
2513
- text: (msg.content ?? "").substring(0, 200)
2514
- });
2515
- break;
2516
- case "complete" /* COMPLETE */: {
2517
- const report = msg.content ?? "";
2518
- const userSummary = msg.metadata?.["user_summary"] ?? "";
2519
- const ticketId2 = msg.metadata?.["ticket_id"];
2520
- const sessionId = msg.metadata?.["session_id"];
2521
- emit({
2522
- type: "completed" /* COMPLETED */,
2523
- report,
2524
- userSummary,
2525
- ticketId: ticketId2
2526
- });
2527
- ws.close(1e3, "Complete");
2528
- finish({ report, userSummary, ticketId: ticketId2, sessionId });
2529
- break;
2530
- }
2531
- case "error" /* ERROR */:
2532
- emit({
2533
- type: "error" /* ERROR */,
2534
- message: msg.content || "Unknown error"
2492
+ });
2493
+ }
2494
+ async handleMessage(msg, conn, emit, isCancelled, finish, getUploadBaseUrl, setUploadBaseUrl) {
2495
+ if (isCancelled()) {
2496
+ conn.sendCancel();
2497
+ conn.close(1e3, "Cancelled");
2498
+ finish(null);
2499
+ return;
2500
+ }
2501
+ switch (msg.type) {
2502
+ case "thought" /* THOUGHT */:
2503
+ emit({ type: "thought" /* THOUGHT */, text: msg.content ?? "" });
2504
+ break;
2505
+ case "tool_call" /* TOOL_CALL */: {
2506
+ const toolName = msg.name ?? "";
2507
+ const callId = msg.id ?? "";
2508
+ const args = this.extractArgs(msg.metadata);
2509
+ emit({ type: "tool_call" /* TOOL_CALL */, name: toolName, label: msg.content ?? `Running ${toolName}` });
2510
+ this.pendingFlaggedFiles = [];
2511
+ const toolResult = redactPII(await this.registry.execute(toolName, args));
2512
+ emit({ type: "observation" /* OBSERVATION */, text: toolResult.substring(0, 200) });
2513
+ let resultMetadata;
2514
+ const uploadBaseUrl = getUploadBaseUrl();
2515
+ if (this.pendingFlaggedFiles.length > 0 && uploadBaseUrl) {
2516
+ const uploadPrefix = this.extractUploadPrefix(uploadBaseUrl);
2517
+ const uploadedRefs = [];
2518
+ for (const file of this.pendingFlaggedFiles) {
2519
+ const filename = path5.basename(file.originalPath);
2520
+ const safeName = encodeURIComponent(filename);
2521
+ const storagePath = `${uploadPrefix}/${safeName}`;
2522
+ uploadedRefs.push({
2523
+ original_path: file.originalPath,
2524
+ reason: file.reason ?? "",
2525
+ storage_path: storagePath,
2526
+ file_size_bytes: file.data.length
2535
2527
  });
2536
- ws.close(1e3, "Error received");
2537
- finish(null);
2538
- break;
2539
- case "session_config" /* SESSION_CONFIG */:
2540
- uploadBaseUrl = msg.metadata?.["upload_url"];
2541
- break;
2542
- case "ping" /* PING */: {
2543
- const pongMsg = { type: "pong" /* PONG */ };
2544
- try {
2545
- ws.send(JSON.stringify(pongMsg));
2546
- } catch {
2547
- }
2548
- break;
2528
+ const uploadUrl = `${uploadBaseUrl}/${safeName}`;
2529
+ const contentType = file.isText ? "text/plain" : "application/octet-stream";
2530
+ void _PRBEAgent.backgroundUpload(file.data, uploadUrl, this.config.apiKey, contentType, this.getFetchSignal());
2549
2531
  }
2550
- // SDK-originated types and upload_url — ignore
2551
- case "start" /* START */:
2552
- case "tool_result" /* TOOL_RESULT */:
2553
- case "upload_request" /* UPLOAD_REQUEST */:
2554
- case "cancel" /* CANCEL */:
2555
- case "pong" /* PONG */:
2556
- case "upload_url" /* UPLOAD_URL */:
2557
- break;
2558
- }
2559
- };
2560
- ws.onerror = (event) => {
2561
- if (isCancelled()) {
2562
- finish(null);
2563
- return;
2532
+ resultMetadata = { flagged_files: uploadedRefs };
2533
+ this.pendingFlaggedFiles = [];
2564
2534
  }
2565
- const errorEvent = event;
2566
- const message = errorEvent.message || "WebSocket connection error";
2567
- emit({ type: "error" /* ERROR */, message });
2535
+ conn.sendToolResult(callId, toolName, toolResult, resultMetadata);
2536
+ break;
2537
+ }
2538
+ case "server_tool_call" /* SERVER_TOOL_CALL */:
2539
+ emit({ type: "tool_call" /* TOOL_CALL */, name: msg.name ?? "", label: msg.content ?? "" });
2540
+ break;
2541
+ case "server_observation" /* SERVER_OBSERVATION */:
2542
+ emit({ type: "observation" /* OBSERVATION */, text: (msg.content ?? "").substring(0, 200) });
2543
+ break;
2544
+ case "complete" /* COMPLETE */: {
2545
+ const report = msg.content ?? "";
2546
+ const completedTicketId = msg.metadata?.["ticket_id"];
2547
+ const sessionId = msg.metadata?.["session_id"];
2548
+ emit({ type: "completed" /* COMPLETED */, report, ticketId: completedTicketId });
2549
+ conn.close(1e3, "Complete");
2550
+ finish({ report, ticketId: completedTicketId, sessionId });
2551
+ break;
2552
+ }
2553
+ case "error" /* ERROR */:
2554
+ emit({ type: "error" /* ERROR */, message: msg.content || "Unknown error" });
2555
+ conn.close(1e3, "Error received");
2568
2556
  finish(null);
2569
- };
2570
- ws.onclose = (_event) => {
2571
- if (!resolved) {
2572
- if (isCancelled()) {
2573
- finish(null);
2574
- } else {
2575
- emit({
2576
- type: "error" /* ERROR */,
2577
- message: "WebSocket connection closed unexpectedly"
2578
- });
2579
- finish(null);
2580
- }
2557
+ break;
2558
+ case "session_config" /* SESSION_CONFIG */:
2559
+ setUploadBaseUrl(msg.metadata?.["upload_url"]);
2560
+ break;
2561
+ case "conversation_update" /* CONVERSATION_UPDATE */: {
2562
+ try {
2563
+ const entry = JSON.parse(msg.content ?? "{}");
2564
+ this.state.appendConversation(entry);
2565
+ } catch {
2581
2566
  }
2582
- };
2583
- });
2584
- }
2585
- sendCancel(ws) {
2586
- try {
2587
- const cancelMsg = { type: "cancel" /* CANCEL */ };
2588
- ws.send(JSON.stringify(cancelMsg));
2589
- } catch {
2567
+ break;
2568
+ }
2569
+ case "ping" /* PING */:
2570
+ conn.sendPong();
2571
+ break;
2572
+ default:
2573
+ break;
2590
2574
  }
2591
2575
  }
2592
2576
  extractArgs(metadata) {
@@ -2704,6 +2688,7 @@ var DEFAULT_PRBE_STATE = {
2704
2688
  summary: "",
2705
2689
  currentQuery: "",
2706
2690
  resolvedInteractions: [],
2691
+ conversationHistory: [],
2707
2692
  completedInvestigations: [],
2708
2693
  activeCRs: [],
2709
2694
  completedCRs: [],
@@ -2741,6 +2726,7 @@ function serializePRBEState(state) {
2741
2726
  pendingInteraction: state.pendingInteraction,
2742
2727
  resolvedInteractions: state.resolvedInteractions,
2743
2728
  agentMessage: state.agentMessage,
2729
+ conversationHistory: state.conversationHistory,
2744
2730
  completedInvestigations: state.completedInvestigations.map((inv) => ({
2745
2731
  id: inv.id,
2746
2732
  query: inv.query,
@@ -2749,6 +2735,7 @@ function serializePRBEState(state) {
2749
2735
  ticketId: inv.ticketId,
2750
2736
  events: inv.events,
2751
2737
  resolvedInteractions: inv.resolvedInteractions,
2738
+ conversationHistory: inv.conversationHistory,
2752
2739
  completedAt: inv.completedAt.toISOString()
2753
2740
  })),
2754
2741
  activeCRs: Array.from(state.activeCRs.values()).map(serializeCR),
@@ -2771,6 +2758,7 @@ var PROBE_MARK_SVG = `<svg width="256" height="256" viewBox="0 0 256 256" fill="
2771
2758
  AskUserTool,
2772
2759
  BashExecuteTool,
2773
2760
  ClearAppLogsTool,
2761
+ ConversationRole,
2774
2762
  DEFAULT_PRBE_STATE,
2775
2763
  FindFilesTool,
2776
2764
  FlagAppLogsTool,