@prbe.ai/electron-sdk 0.1.13 → 0.1.15

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";
@@ -125,6 +133,7 @@ var PRBEAgentConfigKey = /* @__PURE__ */ ((PRBEAgentConfigKey3) => {
125
133
  PRBEAgentConfigKey3["IPC_MAIN"] = "ipcMain";
126
134
  PRBEAgentConfigKey3["RENDERER_LOG_CHANNEL"] = "rendererLogChannel";
127
135
  PRBEAgentConfigKey3["APP_DATA_PATH"] = "appDataPath";
136
+ PRBEAgentConfigKey3["SESSION_METADATA"] = "sessionMetadata";
128
137
  return PRBEAgentConfigKey3;
129
138
  })(PRBEAgentConfigKey || {});
130
139
  var PRBEAgentStatusType = /* @__PURE__ */ ((PRBEAgentStatusType2) => {
@@ -161,6 +170,83 @@ function redactPII(text) {
161
170
  var API_URL = "https://api.prbe.ai";
162
171
  var MIDDLEWARE_URL = "wss://middleware.prbe.ai";
163
172
 
173
+ // src/connection.ts
174
+ var InvestigationConnection = class {
175
+ constructor(url, apiKey, onMessage, onError, onClose) {
176
+ this.onMessage = onMessage;
177
+ this.onError = onError;
178
+ this.onClose = onClose;
179
+ this.ws = new WebSocket(url, {
180
+ headers: { "X-API-Key": apiKey }
181
+ });
182
+ this.ws.onmessage = (event) => {
183
+ const raw = typeof event.data === "string" ? event.data : event.data instanceof Buffer ? event.data.toString("utf-8") : null;
184
+ if (!raw) return;
185
+ try {
186
+ const msg = JSON.parse(raw);
187
+ this.onMessage(msg);
188
+ } catch {
189
+ }
190
+ };
191
+ this.ws.onerror = (event) => {
192
+ const errorEvent = event;
193
+ this.onError(errorEvent.message || "WebSocket connection error");
194
+ };
195
+ this.ws.onclose = () => {
196
+ this.onClose();
197
+ };
198
+ }
199
+ ws;
200
+ closed = false;
201
+ get isOpen() {
202
+ return !this.closed && this.ws.readyState === WebSocket.OPEN;
203
+ }
204
+ send(msg) {
205
+ if (!this.isOpen) return false;
206
+ try {
207
+ this.ws.send(JSON.stringify(msg));
208
+ return true;
209
+ } catch {
210
+ return false;
211
+ }
212
+ }
213
+ sendConversationMessage(content) {
214
+ this.send({
215
+ type: "conversation_message" /* CONVERSATION_MESSAGE */,
216
+ content
217
+ });
218
+ }
219
+ sendToolResult(callId, toolName, result, metadata) {
220
+ this.send({
221
+ type: "tool_result" /* TOOL_RESULT */,
222
+ id: callId,
223
+ name: toolName,
224
+ content: result,
225
+ metadata
226
+ });
227
+ }
228
+ sendCancel() {
229
+ this.send({ type: "cancel" /* CANCEL */ });
230
+ }
231
+ sendPong() {
232
+ this.send({ type: "pong" /* PONG */ });
233
+ }
234
+ close(code = 1e3, reason) {
235
+ if (this.closed) return;
236
+ this.closed = true;
237
+ try {
238
+ this.ws.close(code, reason);
239
+ } catch {
240
+ }
241
+ }
242
+ /**
243
+ * Set the onopen handler. Called when the connection is ready to send messages.
244
+ */
245
+ set onopen(handler) {
246
+ this.ws.onopen = handler;
247
+ }
248
+ };
249
+
164
250
  // src/state.ts
165
251
  var import_events = require("events");
166
252
  var import_crypto = require("crypto");
@@ -189,6 +275,7 @@ var PRBEAgentState = class extends import_events.EventEmitter {
189
275
  pendingInteraction;
190
276
  resolvedInteractions = [];
191
277
  agentMessage;
278
+ conversationHistory = [];
192
279
  // Completed user investigations (history)
193
280
  completedInvestigations = [];
194
281
  // Background context requests
@@ -212,6 +299,7 @@ var PRBEAgentState = class extends import_events.EventEmitter {
212
299
  this.isInvestigating = true;
213
300
  this.events = [];
214
301
  this.resolvedInteractions = [];
302
+ this.conversationHistory = [];
215
303
  this.report = "";
216
304
  this.summary = "";
217
305
  this.currentQuery = query;
@@ -219,10 +307,15 @@ var PRBEAgentState = class extends import_events.EventEmitter {
219
307
  this.agentMessage = void 0;
220
308
  this.emit("status" /* STATUS */);
221
309
  }
310
+ appendConversation(entry) {
311
+ this.conversationHistory.push(entry);
312
+ this.emit("status" /* STATUS */);
313
+ }
222
314
  resetInvestigation() {
223
315
  this.isInvestigating = false;
224
316
  this.events = [];
225
317
  this.resolvedInteractions = [];
318
+ this.conversationHistory = [];
226
319
  this.report = "";
227
320
  this.summary = "";
228
321
  this.currentQuery = "";
@@ -255,7 +348,7 @@ var PRBEAgentState = class extends import_events.EventEmitter {
255
348
  this.emit("status" /* STATUS */);
256
349
  }
257
350
  }
258
- completeInvestigation(report, summary, ticketId) {
351
+ completeInvestigation(report, ticketId) {
259
352
  if (this.events.length > 0) {
260
353
  this.events[this.events.length - 1].isCompleted = true;
261
354
  }
@@ -264,16 +357,15 @@ var PRBEAgentState = class extends import_events.EventEmitter {
264
357
  id: (0, import_crypto.randomUUID)(),
265
358
  query: this.currentQuery,
266
359
  report,
267
- summary,
268
360
  ticketId,
269
361
  events: [...this.events],
270
362
  resolvedInteractions: [...this.resolvedInteractions],
363
+ conversationHistory: [...this.conversationHistory],
271
364
  completedAt: /* @__PURE__ */ new Date()
272
365
  });
273
366
  this.report = report;
274
- this.summary = summary;
275
367
  this.isInvestigating = false;
276
- this.emit("complete" /* COMPLETE */, { report, summary });
368
+ this.emit("complete" /* COMPLETE */, { report });
277
369
  this.emit("status" /* STATUS */);
278
370
  }
279
371
  failInvestigation(message) {
@@ -398,7 +490,7 @@ var PRBEAgentState = class extends import_events.EventEmitter {
398
490
  cr.events[cr.events.length - 1].detail = text;
399
491
  this.emit("status" /* STATUS */);
400
492
  }
401
- completeCR(id, report, summary) {
493
+ completeCR(id, report) {
402
494
  const cr = this.activeCRs.get(id);
403
495
  if (!cr) return;
404
496
  this.activeCRs.delete(id);
@@ -414,7 +506,6 @@ var PRBEAgentState = class extends import_events.EventEmitter {
414
506
  cr.isRunning = false;
415
507
  cr.isCompleted = true;
416
508
  cr.report = report;
417
- cr.summary = summary;
418
509
  this.completedCRs.unshift(cr);
419
510
  this.emit("cr-complete" /* CR_COMPLETE */, cr);
420
511
  this.emit("status" /* STATUS */);
@@ -1351,9 +1442,9 @@ var AskUserTool = class {
1351
1442
  required: true
1352
1443
  },
1353
1444
  {
1354
- name: "context",
1445
+ name: "reason",
1355
1446
  type: "STRING" /* STRING */,
1356
- description: "Optional context explaining why you need this information",
1447
+ description: "Short reason displayed alongside the input prompt explaining why you need this information",
1357
1448
  required: false
1358
1449
  }
1359
1450
  ]
@@ -1365,12 +1456,11 @@ var AskUserTool = class {
1365
1456
  if (this.requester.investigationSource !== "user" /* USER */) {
1366
1457
  return "This is a context request investigation \u2014 you cannot ask the user questions. Use the available tools to answer the query autonomously.";
1367
1458
  }
1368
- const context = args["context"];
1459
+ const reason = args["reason"] ?? "Waiting for your response";
1369
1460
  const response = await this.requester.requestUserInteraction({
1370
1461
  type: "ask_question" /* ASK_QUESTION */,
1371
1462
  interactionId: (0, import_crypto3.randomUUID)(),
1372
- question,
1373
- context
1463
+ question: reason
1374
1464
  });
1375
1465
  const askResponse = response;
1376
1466
  return askResponse.answer;
@@ -1791,6 +1881,7 @@ var HistoryStore = class {
1791
1881
  ticketId: inv.ticketId,
1792
1882
  events: inv.events,
1793
1883
  resolvedInteractions: inv.resolvedInteractions,
1884
+ conversationHistory: inv.conversationHistory,
1794
1885
  completedAt: inv.completedAt.toISOString()
1795
1886
  };
1796
1887
  fs2.writeFileSync(
@@ -1879,11 +1970,12 @@ var PRBEAgent = class _PRBEAgent {
1879
1970
  logCapture;
1880
1971
  config;
1881
1972
  appDataPath;
1973
+ sessionMetadata;
1882
1974
  interactionHandler;
1883
1975
  registry = new PRBEToolRegistry();
1884
1976
  grantedPaths = /* @__PURE__ */ new Set();
1885
1977
  userCancelled = false;
1886
- activeWS = null;
1978
+ activeConnection = null;
1887
1979
  pollingTimer = null;
1888
1980
  persistedData;
1889
1981
  fetchAbortController = null;
@@ -1938,6 +2030,7 @@ var PRBEAgent = class _PRBEAgent {
1938
2030
  };
1939
2031
  this.interactionHandler = config.interactionHandler;
1940
2032
  this.appDataPath = config.appDataPath;
2033
+ this.sessionMetadata = config.sessionMetadata ?? {};
1941
2034
  if (this.appDataPath && !this.config.autoApprovedDirs.includes(this.appDataPath)) {
1942
2035
  this.config.autoApprovedDirs.push(this.appDataPath);
1943
2036
  }
@@ -2043,6 +2136,9 @@ var PRBEAgent = class _PRBEAgent {
2043
2136
  get investigationSource() {
2044
2137
  return this.currentInvestigationSource;
2045
2138
  }
2139
+ sendConversationMessage(content) {
2140
+ this.activeConnection?.sendConversationMessage(content);
2141
+ }
2046
2142
  async requestUserInteraction(payload) {
2047
2143
  if (!this.interactionHandler) {
2048
2144
  throw new PRBEAgentError(
@@ -2062,6 +2158,13 @@ var PRBEAgent = class _PRBEAgent {
2062
2158
  } else {
2063
2159
  this.state.resolveInteraction(response);
2064
2160
  }
2161
+ if (response.type === "request_permission" /* REQUEST_PERMISSION */) {
2162
+ const approved = response.approved;
2163
+ this.sendConversationMessage(approved ? "Approved" : "Denied");
2164
+ } else if (response.type === "request_path_access" /* REQUEST_PATH_ACCESS */) {
2165
+ const granted = response.granted;
2166
+ this.sendConversationMessage(granted ? "Allowed" : "Denied");
2167
+ }
2065
2168
  return response;
2066
2169
  } catch (err) {
2067
2170
  if (this.currentInvestigationSource === "context_request" /* CONTEXT_REQUEST */ && this.currentCRId) {
@@ -2081,6 +2184,13 @@ var PRBEAgent = class _PRBEAgent {
2081
2184
  }
2082
2185
  }
2083
2186
  // ---------- Public API ----------
2187
+ /**
2188
+ * Update session metadata. Merged with existing metadata.
2189
+ * Call this to add user profile data, app version, etc. after async initialization.
2190
+ */
2191
+ updateSessionMetadata(metadata) {
2192
+ this.sessionMetadata = { ...this.sessionMetadata, ...metadata };
2193
+ }
2084
2194
  /**
2085
2195
  * Register a custom tool that the middleware can invoke during investigations.
2086
2196
  */
@@ -2114,7 +2224,7 @@ var PRBEAgent = class _PRBEAgent {
2114
2224
  this.state.appendEvent("Thinking", status.text);
2115
2225
  break;
2116
2226
  case "completed" /* COMPLETED */:
2117
- this.state.completeInvestigation(status.report, status.userSummary, status.ticketId);
2227
+ this.state.completeInvestigation(status.report, status.ticketId);
2118
2228
  this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
2119
2229
  break;
2120
2230
  case "error" /* ERROR */:
@@ -2144,9 +2254,9 @@ var PRBEAgent = class _PRBEAgent {
2144
2254
  */
2145
2255
  cancelInvestigation() {
2146
2256
  this.userCancelled = true;
2147
- if (this.activeWS) {
2148
- this.activeWS.close(1e3, "User cancelled");
2149
- this.activeWS = null;
2257
+ if (this.activeConnection) {
2258
+ this.activeConnection.close(1e3, "User cancelled");
2259
+ this.activeConnection = null;
2150
2260
  }
2151
2261
  }
2152
2262
  /**
@@ -2154,9 +2264,9 @@ var PRBEAgent = class _PRBEAgent {
2154
2264
  */
2155
2265
  cancel() {
2156
2266
  this.userCancelled = true;
2157
- if (this.activeWS) {
2158
- this.activeWS.close(1e3, "User cancelled");
2159
- this.activeWS = null;
2267
+ if (this.activeConnection) {
2268
+ this.activeConnection.close(1e3, "User cancelled");
2269
+ this.activeConnection = null;
2160
2270
  }
2161
2271
  this.abortInFlightRequests();
2162
2272
  this.stopPolling();
@@ -2295,7 +2405,7 @@ var PRBEAgent = class _PRBEAgent {
2295
2405
  this.state.appendCREvent(crID, "Thinking", status.text);
2296
2406
  break;
2297
2407
  case "completed" /* COMPLETED */:
2298
- this.state.completeCR(crID, status.report, status.userSummary);
2408
+ this.state.completeCR(crID, status.report);
2299
2409
  this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
2300
2410
  break;
2301
2411
  case "error" /* ERROR */:
@@ -2322,31 +2432,44 @@ var PRBEAgent = class _PRBEAgent {
2322
2432
  connectToProxy(query, contextRequestID, emit, isCancelled, ticketId) {
2323
2433
  return new Promise((resolve2) => {
2324
2434
  const wsUrl = `${MIDDLEWARE_URL}/api/agent/client/ws`;
2325
- let ws;
2326
- try {
2327
- ws = new WebSocket(wsUrl, {
2328
- headers: {
2329
- "X-API-Key": this.config.apiKey
2330
- }
2331
- });
2332
- } catch (err) {
2333
- emit({
2334
- type: "error" /* ERROR */,
2335
- message: `Failed to create WebSocket: ${err}`
2336
- });
2337
- resolve2(null);
2338
- return;
2339
- }
2340
- this.activeWS = ws;
2341
2435
  let uploadBaseUrl;
2342
2436
  let resolved = false;
2343
2437
  const finish = (result) => {
2344
2438
  if (resolved) return;
2345
2439
  resolved = true;
2346
- this.activeWS = null;
2440
+ this.activeConnection = null;
2347
2441
  resolve2(result);
2348
2442
  };
2349
- ws.onopen = () => {
2443
+ let conn;
2444
+ try {
2445
+ conn = new InvestigationConnection(
2446
+ wsUrl,
2447
+ this.config.apiKey,
2448
+ (msg) => this.handleMessage(msg, conn, emit, isCancelled, finish, () => uploadBaseUrl, (url) => {
2449
+ uploadBaseUrl = url;
2450
+ }),
2451
+ (message) => {
2452
+ if (!isCancelled()) emit({ type: "error" /* ERROR */, message });
2453
+ finish(null);
2454
+ },
2455
+ () => {
2456
+ if (!resolved) {
2457
+ if (isCancelled()) {
2458
+ finish(null);
2459
+ } else {
2460
+ emit({ type: "error" /* ERROR */, message: "WebSocket connection closed unexpectedly" });
2461
+ finish(null);
2462
+ }
2463
+ }
2464
+ }
2465
+ );
2466
+ } catch (err) {
2467
+ emit({ type: "error" /* ERROR */, message: `Failed to create WebSocket: ${err}` });
2468
+ resolve2(null);
2469
+ return;
2470
+ }
2471
+ this.activeConnection = conn;
2472
+ conn.onopen = () => {
2350
2473
  const toolDeclarations = this.registry.allDeclarations().map((decl) => ({
2351
2474
  name: decl.name,
2352
2475
  description: decl.description,
@@ -2365,206 +2488,102 @@ var PRBEAgent = class _PRBEAgent {
2365
2488
  os_version: os2.release(),
2366
2489
  arch: os2.arch()
2367
2490
  };
2368
- if (contextRequestID) {
2369
- startMetadata["context_request_id"] = contextRequestID;
2370
- }
2371
- if (ticketId) {
2372
- startMetadata["ticket_id"] = ticketId;
2491
+ if (contextRequestID) startMetadata["context_request_id"] = contextRequestID;
2492
+ if (ticketId) startMetadata["ticket_id"] = ticketId;
2493
+ if (this.appDataPath) startMetadata["app_data_path"] = this.appDataPath;
2494
+ if (Object.keys(this.sessionMetadata).length > 0) {
2495
+ startMetadata["session_metadata"] = this.sessionMetadata;
2373
2496
  }
2374
- if (this.appDataPath) {
2375
- startMetadata["app_data_path"] = this.appDataPath;
2376
- }
2377
- const startMsg = {
2378
- type: "start" /* START */,
2379
- content: query,
2380
- metadata: startMetadata
2381
- };
2382
- try {
2383
- ws.send(JSON.stringify(startMsg));
2384
- } catch (err) {
2385
- emit({
2386
- type: "error" /* ERROR */,
2387
- message: `Failed to send start message: ${err}`
2388
- });
2497
+ if (!conn.send({ type: "start" /* START */, content: query, metadata: startMetadata })) {
2498
+ emit({ type: "error" /* ERROR */, message: "Failed to send start message" });
2389
2499
  finish(null);
2390
2500
  return;
2391
2501
  }
2392
2502
  emit({ type: "started" /* STARTED */ });
2393
2503
  this.pendingFlaggedFiles = [];
2394
2504
  };
2395
- ws.onmessage = async (event) => {
2396
- if (isCancelled()) {
2397
- this.sendCancel(ws);
2398
- ws.close(1e3, "Cancelled");
2399
- finish(null);
2400
- return;
2401
- }
2402
- let raw;
2403
- if (typeof event.data === "string") {
2404
- raw = event.data;
2405
- } else if (event.data instanceof Buffer) {
2406
- raw = event.data.toString("utf-8");
2407
- } else {
2408
- return;
2409
- }
2410
- let msg;
2411
- try {
2412
- msg = JSON.parse(raw);
2413
- } catch {
2414
- return;
2415
- }
2416
- switch (msg.type) {
2417
- case "thought" /* THOUGHT */:
2418
- emit({
2419
- type: "thought" /* THOUGHT */,
2420
- text: msg.content ?? ""
2421
- });
2422
- break;
2423
- case "tool_call" /* TOOL_CALL */: {
2424
- const toolName = msg.name ?? "";
2425
- const callId = msg.id ?? "";
2426
- const args = this.extractArgs(msg.metadata);
2427
- emit({
2428
- type: "tool_call" /* TOOL_CALL */,
2429
- name: toolName,
2430
- label: msg.content ?? `Running ${toolName}`
2431
- });
2432
- this.pendingFlaggedFiles = [];
2433
- const toolResult = redactPII(
2434
- await this.registry.execute(toolName, args)
2435
- );
2436
- emit({
2437
- type: "observation" /* OBSERVATION */,
2438
- text: toolResult.substring(0, 200)
2439
- });
2440
- let resultMetadata;
2441
- if (this.pendingFlaggedFiles.length > 0 && uploadBaseUrl) {
2442
- const uploadPrefix = this.extractUploadPrefix(uploadBaseUrl);
2443
- const uploadedRefs = [];
2444
- for (const file of this.pendingFlaggedFiles) {
2445
- const filename = path5.basename(file.originalPath);
2446
- const safeName = encodeURIComponent(filename);
2447
- const storagePath = `${uploadPrefix}/${safeName}`;
2448
- uploadedRefs.push({
2449
- original_path: file.originalPath,
2450
- reason: file.reason ?? "",
2451
- storage_path: storagePath,
2452
- file_size_bytes: file.data.length
2453
- });
2454
- const uploadUrl = `${uploadBaseUrl}/${safeName}`;
2455
- const fileData = file.data;
2456
- const contentType = file.isText ? "text/plain" : "application/octet-stream";
2457
- void _PRBEAgent.backgroundUpload(
2458
- fileData,
2459
- uploadUrl,
2460
- this.config.apiKey,
2461
- contentType,
2462
- this.getFetchSignal()
2463
- );
2464
- }
2465
- resultMetadata = { flagged_files: uploadedRefs };
2466
- this.pendingFlaggedFiles = [];
2467
- }
2468
- const resultMsg = {
2469
- type: "tool_result" /* TOOL_RESULT */,
2470
- id: callId,
2471
- name: toolName,
2472
- content: toolResult,
2473
- metadata: resultMetadata
2474
- };
2475
- try {
2476
- ws.send(JSON.stringify(resultMsg));
2477
- } catch {
2478
- }
2479
- break;
2480
- }
2481
- case "server_tool_call" /* SERVER_TOOL_CALL */:
2482
- emit({
2483
- type: "tool_call" /* TOOL_CALL */,
2484
- name: msg.name ?? "",
2485
- label: msg.content ?? ""
2486
- });
2487
- break;
2488
- case "server_observation" /* SERVER_OBSERVATION */:
2489
- emit({
2490
- type: "observation" /* OBSERVATION */,
2491
- text: (msg.content ?? "").substring(0, 200)
2492
- });
2493
- break;
2494
- case "complete" /* COMPLETE */: {
2495
- const report = msg.content ?? "";
2496
- const userSummary = msg.metadata?.["user_summary"] ?? "";
2497
- const ticketId2 = msg.metadata?.["ticket_id"];
2498
- const sessionId = msg.metadata?.["session_id"];
2499
- emit({
2500
- type: "completed" /* COMPLETED */,
2501
- report,
2502
- userSummary,
2503
- ticketId: ticketId2
2504
- });
2505
- ws.close(1e3, "Complete");
2506
- finish({ report, userSummary, ticketId: ticketId2, sessionId });
2507
- break;
2508
- }
2509
- case "error" /* ERROR */:
2510
- emit({
2511
- type: "error" /* ERROR */,
2512
- message: msg.content || "Unknown error"
2505
+ });
2506
+ }
2507
+ async handleMessage(msg, conn, emit, isCancelled, finish, getUploadBaseUrl, setUploadBaseUrl) {
2508
+ if (isCancelled()) {
2509
+ conn.sendCancel();
2510
+ conn.close(1e3, "Cancelled");
2511
+ finish(null);
2512
+ return;
2513
+ }
2514
+ switch (msg.type) {
2515
+ case "thought" /* THOUGHT */:
2516
+ emit({ type: "thought" /* THOUGHT */, text: msg.content ?? "" });
2517
+ break;
2518
+ case "tool_call" /* TOOL_CALL */: {
2519
+ const toolName = msg.name ?? "";
2520
+ const callId = msg.id ?? "";
2521
+ const args = this.extractArgs(msg.metadata);
2522
+ emit({ type: "tool_call" /* TOOL_CALL */, name: toolName, label: msg.content ?? `Running ${toolName}` });
2523
+ this.pendingFlaggedFiles = [];
2524
+ const toolResult = redactPII(await this.registry.execute(toolName, args));
2525
+ emit({ type: "observation" /* OBSERVATION */, text: toolResult.substring(0, 200) });
2526
+ let resultMetadata;
2527
+ const uploadBaseUrl = getUploadBaseUrl();
2528
+ if (this.pendingFlaggedFiles.length > 0 && uploadBaseUrl) {
2529
+ const uploadPrefix = this.extractUploadPrefix(uploadBaseUrl);
2530
+ const uploadedRefs = [];
2531
+ for (const file of this.pendingFlaggedFiles) {
2532
+ const filename = path5.basename(file.originalPath);
2533
+ const safeName = encodeURIComponent(filename);
2534
+ const storagePath = `${uploadPrefix}/${safeName}`;
2535
+ uploadedRefs.push({
2536
+ original_path: file.originalPath,
2537
+ reason: file.reason ?? "",
2538
+ storage_path: storagePath,
2539
+ file_size_bytes: file.data.length
2513
2540
  });
2514
- ws.close(1e3, "Error received");
2515
- finish(null);
2516
- break;
2517
- case "session_config" /* SESSION_CONFIG */:
2518
- uploadBaseUrl = msg.metadata?.["upload_url"];
2519
- break;
2520
- case "ping" /* PING */: {
2521
- const pongMsg = { type: "pong" /* PONG */ };
2522
- try {
2523
- ws.send(JSON.stringify(pongMsg));
2524
- } catch {
2525
- }
2526
- break;
2541
+ const uploadUrl = `${uploadBaseUrl}/${safeName}`;
2542
+ const contentType = file.isText ? "text/plain" : "application/octet-stream";
2543
+ void _PRBEAgent.backgroundUpload(file.data, uploadUrl, this.config.apiKey, contentType, this.getFetchSignal());
2527
2544
  }
2528
- // SDK-originated types and upload_url — ignore
2529
- case "start" /* START */:
2530
- case "tool_result" /* TOOL_RESULT */:
2531
- case "upload_request" /* UPLOAD_REQUEST */:
2532
- case "cancel" /* CANCEL */:
2533
- case "pong" /* PONG */:
2534
- case "upload_url" /* UPLOAD_URL */:
2535
- break;
2545
+ resultMetadata = { flagged_files: uploadedRefs };
2546
+ this.pendingFlaggedFiles = [];
2536
2547
  }
2537
- };
2538
- ws.onerror = (event) => {
2539
- if (isCancelled()) {
2540
- finish(null);
2541
- return;
2542
- }
2543
- const errorEvent = event;
2544
- const message = errorEvent.message || "WebSocket connection error";
2545
- emit({ type: "error" /* ERROR */, message });
2548
+ conn.sendToolResult(callId, toolName, toolResult, resultMetadata);
2549
+ break;
2550
+ }
2551
+ case "server_tool_call" /* SERVER_TOOL_CALL */:
2552
+ emit({ type: "tool_call" /* TOOL_CALL */, name: msg.name ?? "", label: msg.content ?? "" });
2553
+ break;
2554
+ case "server_observation" /* SERVER_OBSERVATION */:
2555
+ emit({ type: "observation" /* OBSERVATION */, text: (msg.content ?? "").substring(0, 200) });
2556
+ break;
2557
+ case "complete" /* COMPLETE */: {
2558
+ const report = msg.content ?? "";
2559
+ const completedTicketId = msg.metadata?.["ticket_id"];
2560
+ const sessionId = msg.metadata?.["session_id"];
2561
+ emit({ type: "completed" /* COMPLETED */, report, ticketId: completedTicketId });
2562
+ conn.close(1e3, "Complete");
2563
+ finish({ report, ticketId: completedTicketId, sessionId });
2564
+ break;
2565
+ }
2566
+ case "error" /* ERROR */:
2567
+ emit({ type: "error" /* ERROR */, message: msg.content || "Unknown error" });
2568
+ conn.close(1e3, "Error received");
2546
2569
  finish(null);
2547
- };
2548
- ws.onclose = (_event) => {
2549
- if (!resolved) {
2550
- if (isCancelled()) {
2551
- finish(null);
2552
- } else {
2553
- emit({
2554
- type: "error" /* ERROR */,
2555
- message: "WebSocket connection closed unexpectedly"
2556
- });
2557
- finish(null);
2558
- }
2570
+ break;
2571
+ case "session_config" /* SESSION_CONFIG */:
2572
+ setUploadBaseUrl(msg.metadata?.["upload_url"]);
2573
+ break;
2574
+ case "conversation_update" /* CONVERSATION_UPDATE */: {
2575
+ try {
2576
+ const entry = JSON.parse(msg.content ?? "{}");
2577
+ this.state.appendConversation(entry);
2578
+ } catch {
2559
2579
  }
2560
- };
2561
- });
2562
- }
2563
- sendCancel(ws) {
2564
- try {
2565
- const cancelMsg = { type: "cancel" /* CANCEL */ };
2566
- ws.send(JSON.stringify(cancelMsg));
2567
- } catch {
2580
+ break;
2581
+ }
2582
+ case "ping" /* PING */:
2583
+ conn.sendPong();
2584
+ break;
2585
+ default:
2586
+ break;
2568
2587
  }
2569
2588
  }
2570
2589
  extractArgs(metadata) {
@@ -2682,6 +2701,7 @@ var DEFAULT_PRBE_STATE = {
2682
2701
  summary: "",
2683
2702
  currentQuery: "",
2684
2703
  resolvedInteractions: [],
2704
+ conversationHistory: [],
2685
2705
  completedInvestigations: [],
2686
2706
  activeCRs: [],
2687
2707
  completedCRs: [],
@@ -2719,6 +2739,7 @@ function serializePRBEState(state) {
2719
2739
  pendingInteraction: state.pendingInteraction,
2720
2740
  resolvedInteractions: state.resolvedInteractions,
2721
2741
  agentMessage: state.agentMessage,
2742
+ conversationHistory: state.conversationHistory,
2722
2743
  completedInvestigations: state.completedInvestigations.map((inv) => ({
2723
2744
  id: inv.id,
2724
2745
  query: inv.query,
@@ -2727,6 +2748,7 @@ function serializePRBEState(state) {
2727
2748
  ticketId: inv.ticketId,
2728
2749
  events: inv.events,
2729
2750
  resolvedInteractions: inv.resolvedInteractions,
2751
+ conversationHistory: inv.conversationHistory,
2730
2752
  completedAt: inv.completedAt.toISOString()
2731
2753
  })),
2732
2754
  activeCRs: Array.from(state.activeCRs.values()).map(serializeCR),
@@ -2749,6 +2771,7 @@ var PROBE_MARK_SVG = `<svg width="256" height="256" viewBox="0 0 256 256" fill="
2749
2771
  AskUserTool,
2750
2772
  BashExecuteTool,
2751
2773
  ClearAppLogsTool,
2774
+ ConversationRole,
2752
2775
  DEFAULT_PRBE_STATE,
2753
2776
  FindFilesTool,
2754
2777
  FlagAppLogsTool,