@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.mjs CHANGED
@@ -9,6 +9,7 @@ var WSMessageType = /* @__PURE__ */ ((WSMessageType2) => {
9
9
  WSMessageType2["START"] = "start";
10
10
  WSMessageType2["TOOL_RESULT"] = "tool_result";
11
11
  WSMessageType2["UPLOAD_REQUEST"] = "upload_request";
12
+ WSMessageType2["CONVERSATION_MESSAGE"] = "conversation_message";
12
13
  WSMessageType2["CANCEL"] = "cancel";
13
14
  WSMessageType2["PONG"] = "pong";
14
15
  WSMessageType2["THOUGHT"] = "thought";
@@ -17,11 +18,17 @@ var WSMessageType = /* @__PURE__ */ ((WSMessageType2) => {
17
18
  WSMessageType2["SERVER_OBSERVATION"] = "server_observation";
18
19
  WSMessageType2["UPLOAD_URL"] = "upload_url";
19
20
  WSMessageType2["SESSION_CONFIG"] = "session_config";
21
+ WSMessageType2["CONVERSATION_UPDATE"] = "conversation_update";
20
22
  WSMessageType2["COMPLETE"] = "complete";
21
23
  WSMessageType2["ERROR"] = "error";
22
24
  WSMessageType2["PING"] = "ping";
23
25
  return WSMessageType2;
24
26
  })(WSMessageType || {});
27
+ var ConversationRole = /* @__PURE__ */ ((ConversationRole3) => {
28
+ ConversationRole3["User"] = "user";
29
+ ConversationRole3["Agent"] = "agent";
30
+ return ConversationRole3;
31
+ })(ConversationRole || {});
25
32
  var ToolParamType = /* @__PURE__ */ ((ToolParamType2) => {
26
33
  ToolParamType2["STRING"] = "STRING";
27
34
  ToolParamType2["BOOLEAN"] = "BOOLEAN";
@@ -91,6 +98,83 @@ function redactPII(text) {
91
98
  var API_URL = "https://api.prbe.ai";
92
99
  var MIDDLEWARE_URL = "wss://middleware.prbe.ai";
93
100
 
101
+ // src/connection.ts
102
+ var InvestigationConnection = class {
103
+ constructor(url, apiKey, onMessage, onError, onClose) {
104
+ this.onMessage = onMessage;
105
+ this.onError = onError;
106
+ this.onClose = onClose;
107
+ this.ws = new WebSocket(url, {
108
+ headers: { "X-API-Key": apiKey }
109
+ });
110
+ this.ws.onmessage = (event) => {
111
+ const raw = typeof event.data === "string" ? event.data : event.data instanceof Buffer ? event.data.toString("utf-8") : null;
112
+ if (!raw) return;
113
+ try {
114
+ const msg = JSON.parse(raw);
115
+ this.onMessage(msg);
116
+ } catch {
117
+ }
118
+ };
119
+ this.ws.onerror = (event) => {
120
+ const errorEvent = event;
121
+ this.onError(errorEvent.message || "WebSocket connection error");
122
+ };
123
+ this.ws.onclose = () => {
124
+ this.onClose();
125
+ };
126
+ }
127
+ ws;
128
+ closed = false;
129
+ get isOpen() {
130
+ return !this.closed && this.ws.readyState === WebSocket.OPEN;
131
+ }
132
+ send(msg) {
133
+ if (!this.isOpen) return false;
134
+ try {
135
+ this.ws.send(JSON.stringify(msg));
136
+ return true;
137
+ } catch {
138
+ return false;
139
+ }
140
+ }
141
+ sendConversationMessage(content) {
142
+ this.send({
143
+ type: "conversation_message" /* CONVERSATION_MESSAGE */,
144
+ content
145
+ });
146
+ }
147
+ sendToolResult(callId, toolName, result, metadata) {
148
+ this.send({
149
+ type: "tool_result" /* TOOL_RESULT */,
150
+ id: callId,
151
+ name: toolName,
152
+ content: result,
153
+ metadata
154
+ });
155
+ }
156
+ sendCancel() {
157
+ this.send({ type: "cancel" /* CANCEL */ });
158
+ }
159
+ sendPong() {
160
+ this.send({ type: "pong" /* PONG */ });
161
+ }
162
+ close(code = 1e3, reason) {
163
+ if (this.closed) return;
164
+ this.closed = true;
165
+ try {
166
+ this.ws.close(code, reason);
167
+ } catch {
168
+ }
169
+ }
170
+ /**
171
+ * Set the onopen handler. Called when the connection is ready to send messages.
172
+ */
173
+ set onopen(handler) {
174
+ this.ws.onopen = handler;
175
+ }
176
+ };
177
+
94
178
  // src/state.ts
95
179
  import { EventEmitter } from "events";
96
180
  import { randomUUID } from "crypto";
@@ -119,6 +203,7 @@ var PRBEAgentState = class extends EventEmitter {
119
203
  pendingInteraction;
120
204
  resolvedInteractions = [];
121
205
  agentMessage;
206
+ conversationHistory = [];
122
207
  // Completed user investigations (history)
123
208
  completedInvestigations = [];
124
209
  // Background context requests
@@ -142,6 +227,7 @@ var PRBEAgentState = class extends EventEmitter {
142
227
  this.isInvestigating = true;
143
228
  this.events = [];
144
229
  this.resolvedInteractions = [];
230
+ this.conversationHistory = [];
145
231
  this.report = "";
146
232
  this.summary = "";
147
233
  this.currentQuery = query;
@@ -149,10 +235,15 @@ var PRBEAgentState = class extends EventEmitter {
149
235
  this.agentMessage = void 0;
150
236
  this.emit("status" /* STATUS */);
151
237
  }
238
+ appendConversation(entry) {
239
+ this.conversationHistory.push(entry);
240
+ this.emit("status" /* STATUS */);
241
+ }
152
242
  resetInvestigation() {
153
243
  this.isInvestigating = false;
154
244
  this.events = [];
155
245
  this.resolvedInteractions = [];
246
+ this.conversationHistory = [];
156
247
  this.report = "";
157
248
  this.summary = "";
158
249
  this.currentQuery = "";
@@ -185,7 +276,7 @@ var PRBEAgentState = class extends EventEmitter {
185
276
  this.emit("status" /* STATUS */);
186
277
  }
187
278
  }
188
- completeInvestigation(report, summary, ticketId) {
279
+ completeInvestigation(report, ticketId) {
189
280
  if (this.events.length > 0) {
190
281
  this.events[this.events.length - 1].isCompleted = true;
191
282
  }
@@ -194,16 +285,15 @@ var PRBEAgentState = class extends EventEmitter {
194
285
  id: randomUUID(),
195
286
  query: this.currentQuery,
196
287
  report,
197
- summary,
198
288
  ticketId,
199
289
  events: [...this.events],
200
290
  resolvedInteractions: [...this.resolvedInteractions],
291
+ conversationHistory: [...this.conversationHistory],
201
292
  completedAt: /* @__PURE__ */ new Date()
202
293
  });
203
294
  this.report = report;
204
- this.summary = summary;
205
295
  this.isInvestigating = false;
206
- this.emit("complete" /* COMPLETE */, { report, summary });
296
+ this.emit("complete" /* COMPLETE */, { report });
207
297
  this.emit("status" /* STATUS */);
208
298
  }
209
299
  failInvestigation(message) {
@@ -328,7 +418,7 @@ var PRBEAgentState = class extends EventEmitter {
328
418
  cr.events[cr.events.length - 1].detail = text;
329
419
  this.emit("status" /* STATUS */);
330
420
  }
331
- completeCR(id, report, summary) {
421
+ completeCR(id, report) {
332
422
  const cr = this.activeCRs.get(id);
333
423
  if (!cr) return;
334
424
  this.activeCRs.delete(id);
@@ -344,7 +434,6 @@ var PRBEAgentState = class extends EventEmitter {
344
434
  cr.isRunning = false;
345
435
  cr.isCompleted = true;
346
436
  cr.report = report;
347
- cr.summary = summary;
348
437
  this.completedCRs.unshift(cr);
349
438
  this.emit("cr-complete" /* CR_COMPLETE */, cr);
350
439
  this.emit("status" /* STATUS */);
@@ -1281,9 +1370,9 @@ var AskUserTool = class {
1281
1370
  required: true
1282
1371
  },
1283
1372
  {
1284
- name: "context",
1373
+ name: "reason",
1285
1374
  type: "STRING" /* STRING */,
1286
- description: "Optional context explaining why you need this information",
1375
+ description: "Short reason displayed alongside the input prompt explaining why you need this information",
1287
1376
  required: false
1288
1377
  }
1289
1378
  ]
@@ -1295,12 +1384,11 @@ var AskUserTool = class {
1295
1384
  if (this.requester.investigationSource !== "user" /* USER */) {
1296
1385
  return "This is a context request investigation \u2014 you cannot ask the user questions. Use the available tools to answer the query autonomously.";
1297
1386
  }
1298
- const context = args["context"];
1387
+ const reason = args["reason"] ?? "Waiting for your response";
1299
1388
  const response = await this.requester.requestUserInteraction({
1300
1389
  type: "ask_question" /* ASK_QUESTION */,
1301
1390
  interactionId: randomUUID3(),
1302
- question,
1303
- context
1391
+ question: reason
1304
1392
  });
1305
1393
  const askResponse = response;
1306
1394
  return askResponse.answer;
@@ -1721,6 +1809,7 @@ var HistoryStore = class {
1721
1809
  ticketId: inv.ticketId,
1722
1810
  events: inv.events,
1723
1811
  resolvedInteractions: inv.resolvedInteractions,
1812
+ conversationHistory: inv.conversationHistory,
1724
1813
  completedAt: inv.completedAt.toISOString()
1725
1814
  };
1726
1815
  fs2.writeFileSync(
@@ -1813,7 +1902,7 @@ var PRBEAgent = class _PRBEAgent {
1813
1902
  registry = new PRBEToolRegistry();
1814
1903
  grantedPaths = /* @__PURE__ */ new Set();
1815
1904
  userCancelled = false;
1816
- activeWS = null;
1905
+ activeConnection = null;
1817
1906
  pollingTimer = null;
1818
1907
  persistedData;
1819
1908
  fetchAbortController = null;
@@ -1841,13 +1930,6 @@ var PRBEAgent = class _PRBEAgent {
1841
1930
  this.state.updateTrackedSessionIDs(ids);
1842
1931
  this.syncPolling(ids.length > 0);
1843
1932
  }
1844
- get respondedCRIDs() {
1845
- return new Set(this.persistedData.respondedCRIds ?? []);
1846
- }
1847
- set respondedCRIDs(ids) {
1848
- this.persistedData.respondedCRIds = Array.from(ids);
1849
- savePersistedData(this.persistedData);
1850
- }
1851
1933
  syncPolling(hasSessions) {
1852
1934
  if (this.config.backgroundPolling && hasSessions) {
1853
1935
  if (this.pollingTimer === null) {
@@ -1980,6 +2062,9 @@ var PRBEAgent = class _PRBEAgent {
1980
2062
  get investigationSource() {
1981
2063
  return this.currentInvestigationSource;
1982
2064
  }
2065
+ sendConversationMessage(content) {
2066
+ this.activeConnection?.sendConversationMessage(content);
2067
+ }
1983
2068
  async requestUserInteraction(payload) {
1984
2069
  if (!this.interactionHandler) {
1985
2070
  throw new PRBEAgentError(
@@ -1999,6 +2084,13 @@ var PRBEAgent = class _PRBEAgent {
1999
2084
  } else {
2000
2085
  this.state.resolveInteraction(response);
2001
2086
  }
2087
+ if (response.type === "request_permission" /* REQUEST_PERMISSION */) {
2088
+ const approved = response.approved;
2089
+ this.sendConversationMessage(approved ? "Approved" : "Denied");
2090
+ } else if (response.type === "request_path_access" /* REQUEST_PATH_ACCESS */) {
2091
+ const granted = response.granted;
2092
+ this.sendConversationMessage(granted ? "Allowed" : "Denied");
2093
+ }
2002
2094
  return response;
2003
2095
  } catch (err) {
2004
2096
  if (this.currentInvestigationSource === "context_request" /* CONTEXT_REQUEST */ && this.currentCRId) {
@@ -2051,7 +2143,7 @@ var PRBEAgent = class _PRBEAgent {
2051
2143
  this.state.appendEvent("Thinking", status.text);
2052
2144
  break;
2053
2145
  case "completed" /* COMPLETED */:
2054
- this.state.completeInvestigation(status.report, status.userSummary, status.ticketId);
2146
+ this.state.completeInvestigation(status.report, status.ticketId);
2055
2147
  this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
2056
2148
  break;
2057
2149
  case "error" /* ERROR */:
@@ -2081,9 +2173,9 @@ var PRBEAgent = class _PRBEAgent {
2081
2173
  */
2082
2174
  cancelInvestigation() {
2083
2175
  this.userCancelled = true;
2084
- if (this.activeWS) {
2085
- this.activeWS.close(1e3, "User cancelled");
2086
- this.activeWS = null;
2176
+ if (this.activeConnection) {
2177
+ this.activeConnection.close(1e3, "User cancelled");
2178
+ this.activeConnection = null;
2087
2179
  }
2088
2180
  }
2089
2181
  /**
@@ -2091,9 +2183,9 @@ var PRBEAgent = class _PRBEAgent {
2091
2183
  */
2092
2184
  cancel() {
2093
2185
  this.userCancelled = true;
2094
- if (this.activeWS) {
2095
- this.activeWS.close(1e3, "User cancelled");
2096
- this.activeWS = null;
2186
+ if (this.activeConnection) {
2187
+ this.activeConnection.close(1e3, "User cancelled");
2188
+ this.activeConnection = null;
2097
2189
  }
2098
2190
  this.abortInFlightRequests();
2099
2191
  this.stopPolling();
@@ -2129,27 +2221,12 @@ var PRBEAgent = class _PRBEAgent {
2129
2221
  "/api/agent/poll",
2130
2222
  request
2131
2223
  );
2132
- const knownCRIDs = /* @__PURE__ */ new Set();
2133
2224
  for (const ticket of response.tickets) {
2134
2225
  for (const cr of ticket.context_requests) {
2135
- knownCRIDs.add(cr.id);
2136
- if (!cr.is_active || this.respondedCRIDs.has(cr.id)) continue;
2226
+ if (!cr.is_active) continue;
2137
2227
  await this.investigateForCR(cr, ticket.ticket_id);
2138
- const ids = this.respondedCRIDs;
2139
- ids.add(cr.id);
2140
- this.respondedCRIDs = ids;
2141
2228
  }
2142
2229
  }
2143
- const currentRespondedIDs = this.respondedCRIDs;
2144
- const stale = new Set(
2145
- [...currentRespondedIDs].filter((id) => !knownCRIDs.has(id))
2146
- );
2147
- if (stale.size > 0) {
2148
- const pruned = new Set(
2149
- [...currentRespondedIDs].filter((id) => !stale.has(id))
2150
- );
2151
- this.respondedCRIDs = pruned;
2152
- }
2153
2230
  return response;
2154
2231
  } catch {
2155
2232
  return null;
@@ -2247,7 +2324,7 @@ var PRBEAgent = class _PRBEAgent {
2247
2324
  this.state.appendCREvent(crID, "Thinking", status.text);
2248
2325
  break;
2249
2326
  case "completed" /* COMPLETED */:
2250
- this.state.completeCR(crID, status.report, status.userSummary);
2327
+ this.state.completeCR(crID, status.report);
2251
2328
  this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
2252
2329
  break;
2253
2330
  case "error" /* ERROR */:
@@ -2274,31 +2351,44 @@ var PRBEAgent = class _PRBEAgent {
2274
2351
  connectToProxy(query, contextRequestID, emit, isCancelled, ticketId) {
2275
2352
  return new Promise((resolve2) => {
2276
2353
  const wsUrl = `${MIDDLEWARE_URL}/api/agent/client/ws`;
2277
- let ws;
2278
- try {
2279
- ws = new WebSocket(wsUrl, {
2280
- headers: {
2281
- "X-API-Key": this.config.apiKey
2282
- }
2283
- });
2284
- } catch (err) {
2285
- emit({
2286
- type: "error" /* ERROR */,
2287
- message: `Failed to create WebSocket: ${err}`
2288
- });
2289
- resolve2(null);
2290
- return;
2291
- }
2292
- this.activeWS = ws;
2293
2354
  let uploadBaseUrl;
2294
2355
  let resolved = false;
2295
2356
  const finish = (result) => {
2296
2357
  if (resolved) return;
2297
2358
  resolved = true;
2298
- this.activeWS = null;
2359
+ this.activeConnection = null;
2299
2360
  resolve2(result);
2300
2361
  };
2301
- ws.onopen = () => {
2362
+ let conn;
2363
+ try {
2364
+ conn = new InvestigationConnection(
2365
+ wsUrl,
2366
+ this.config.apiKey,
2367
+ (msg) => this.handleMessage(msg, conn, emit, isCancelled, finish, () => uploadBaseUrl, (url) => {
2368
+ uploadBaseUrl = url;
2369
+ }),
2370
+ (message) => {
2371
+ if (!isCancelled()) emit({ type: "error" /* ERROR */, message });
2372
+ finish(null);
2373
+ },
2374
+ () => {
2375
+ if (!resolved) {
2376
+ if (isCancelled()) {
2377
+ finish(null);
2378
+ } else {
2379
+ emit({ type: "error" /* ERROR */, message: "WebSocket connection closed unexpectedly" });
2380
+ finish(null);
2381
+ }
2382
+ }
2383
+ }
2384
+ );
2385
+ } catch (err) {
2386
+ emit({ type: "error" /* ERROR */, message: `Failed to create WebSocket: ${err}` });
2387
+ resolve2(null);
2388
+ return;
2389
+ }
2390
+ this.activeConnection = conn;
2391
+ conn.onopen = () => {
2302
2392
  const toolDeclarations = this.registry.allDeclarations().map((decl) => ({
2303
2393
  name: decl.name,
2304
2394
  description: decl.description,
@@ -2317,206 +2407,99 @@ var PRBEAgent = class _PRBEAgent {
2317
2407
  os_version: os2.release(),
2318
2408
  arch: os2.arch()
2319
2409
  };
2320
- if (contextRequestID) {
2321
- startMetadata["context_request_id"] = contextRequestID;
2322
- }
2323
- if (ticketId) {
2324
- startMetadata["ticket_id"] = ticketId;
2325
- }
2326
- if (this.appDataPath) {
2327
- startMetadata["app_data_path"] = this.appDataPath;
2328
- }
2329
- const startMsg = {
2330
- type: "start" /* START */,
2331
- content: query,
2332
- metadata: startMetadata
2333
- };
2334
- try {
2335
- ws.send(JSON.stringify(startMsg));
2336
- } catch (err) {
2337
- emit({
2338
- type: "error" /* ERROR */,
2339
- message: `Failed to send start message: ${err}`
2340
- });
2410
+ if (contextRequestID) startMetadata["context_request_id"] = contextRequestID;
2411
+ if (ticketId) startMetadata["ticket_id"] = ticketId;
2412
+ if (this.appDataPath) startMetadata["app_data_path"] = this.appDataPath;
2413
+ if (!conn.send({ type: "start" /* START */, content: query, metadata: startMetadata })) {
2414
+ emit({ type: "error" /* ERROR */, message: "Failed to send start message" });
2341
2415
  finish(null);
2342
2416
  return;
2343
2417
  }
2344
2418
  emit({ type: "started" /* STARTED */ });
2345
2419
  this.pendingFlaggedFiles = [];
2346
2420
  };
2347
- ws.onmessage = async (event) => {
2348
- if (isCancelled()) {
2349
- this.sendCancel(ws);
2350
- ws.close(1e3, "Cancelled");
2351
- finish(null);
2352
- return;
2353
- }
2354
- let raw;
2355
- if (typeof event.data === "string") {
2356
- raw = event.data;
2357
- } else if (event.data instanceof Buffer) {
2358
- raw = event.data.toString("utf-8");
2359
- } else {
2360
- return;
2361
- }
2362
- let msg;
2363
- try {
2364
- msg = JSON.parse(raw);
2365
- } catch {
2366
- return;
2367
- }
2368
- switch (msg.type) {
2369
- case "thought" /* THOUGHT */:
2370
- emit({
2371
- type: "thought" /* THOUGHT */,
2372
- text: msg.content ?? ""
2373
- });
2374
- break;
2375
- case "tool_call" /* TOOL_CALL */: {
2376
- const toolName = msg.name ?? "";
2377
- const callId = msg.id ?? "";
2378
- const args = this.extractArgs(msg.metadata);
2379
- emit({
2380
- type: "tool_call" /* TOOL_CALL */,
2381
- name: toolName,
2382
- label: msg.content ?? `Running ${toolName}`
2383
- });
2384
- this.pendingFlaggedFiles = [];
2385
- const toolResult = redactPII(
2386
- await this.registry.execute(toolName, args)
2387
- );
2388
- emit({
2389
- type: "observation" /* OBSERVATION */,
2390
- text: toolResult.substring(0, 200)
2391
- });
2392
- let resultMetadata;
2393
- if (this.pendingFlaggedFiles.length > 0 && uploadBaseUrl) {
2394
- const uploadPrefix = this.extractUploadPrefix(uploadBaseUrl);
2395
- const uploadedRefs = [];
2396
- for (const file of this.pendingFlaggedFiles) {
2397
- const filename = path5.basename(file.originalPath);
2398
- const safeName = encodeURIComponent(filename);
2399
- const storagePath = `${uploadPrefix}/${safeName}`;
2400
- uploadedRefs.push({
2401
- original_path: file.originalPath,
2402
- reason: file.reason ?? "",
2403
- storage_path: storagePath,
2404
- file_size_bytes: file.data.length
2405
- });
2406
- const uploadUrl = `${uploadBaseUrl}/${safeName}`;
2407
- const fileData = file.data;
2408
- const contentType = file.isText ? "text/plain" : "application/octet-stream";
2409
- void _PRBEAgent.backgroundUpload(
2410
- fileData,
2411
- uploadUrl,
2412
- this.config.apiKey,
2413
- contentType,
2414
- this.getFetchSignal()
2415
- );
2416
- }
2417
- resultMetadata = { flagged_files: uploadedRefs };
2418
- this.pendingFlaggedFiles = [];
2419
- }
2420
- const resultMsg = {
2421
- type: "tool_result" /* TOOL_RESULT */,
2422
- id: callId,
2423
- name: toolName,
2424
- content: toolResult,
2425
- metadata: resultMetadata
2426
- };
2427
- try {
2428
- ws.send(JSON.stringify(resultMsg));
2429
- } catch {
2430
- }
2431
- break;
2432
- }
2433
- case "server_tool_call" /* SERVER_TOOL_CALL */:
2434
- emit({
2435
- type: "tool_call" /* TOOL_CALL */,
2436
- name: msg.name ?? "",
2437
- label: msg.content ?? ""
2438
- });
2439
- break;
2440
- case "server_observation" /* SERVER_OBSERVATION */:
2441
- emit({
2442
- type: "observation" /* OBSERVATION */,
2443
- text: (msg.content ?? "").substring(0, 200)
2444
- });
2445
- break;
2446
- case "complete" /* COMPLETE */: {
2447
- const report = msg.content ?? "";
2448
- const userSummary = msg.metadata?.["user_summary"] ?? "";
2449
- const ticketId2 = msg.metadata?.["ticket_id"];
2450
- const sessionId = msg.metadata?.["session_id"];
2451
- emit({
2452
- type: "completed" /* COMPLETED */,
2453
- report,
2454
- userSummary,
2455
- ticketId: ticketId2
2456
- });
2457
- ws.close(1e3, "Complete");
2458
- finish({ report, userSummary, ticketId: ticketId2, sessionId });
2459
- break;
2460
- }
2461
- case "error" /* ERROR */:
2462
- emit({
2463
- type: "error" /* ERROR */,
2464
- message: msg.content || "Unknown error"
2421
+ });
2422
+ }
2423
+ async handleMessage(msg, conn, emit, isCancelled, finish, getUploadBaseUrl, setUploadBaseUrl) {
2424
+ if (isCancelled()) {
2425
+ conn.sendCancel();
2426
+ conn.close(1e3, "Cancelled");
2427
+ finish(null);
2428
+ return;
2429
+ }
2430
+ switch (msg.type) {
2431
+ case "thought" /* THOUGHT */:
2432
+ emit({ type: "thought" /* THOUGHT */, text: msg.content ?? "" });
2433
+ break;
2434
+ case "tool_call" /* TOOL_CALL */: {
2435
+ const toolName = msg.name ?? "";
2436
+ const callId = msg.id ?? "";
2437
+ const args = this.extractArgs(msg.metadata);
2438
+ emit({ type: "tool_call" /* TOOL_CALL */, name: toolName, label: msg.content ?? `Running ${toolName}` });
2439
+ this.pendingFlaggedFiles = [];
2440
+ const toolResult = redactPII(await this.registry.execute(toolName, args));
2441
+ emit({ type: "observation" /* OBSERVATION */, text: toolResult.substring(0, 200) });
2442
+ let resultMetadata;
2443
+ const uploadBaseUrl = getUploadBaseUrl();
2444
+ if (this.pendingFlaggedFiles.length > 0 && uploadBaseUrl) {
2445
+ const uploadPrefix = this.extractUploadPrefix(uploadBaseUrl);
2446
+ const uploadedRefs = [];
2447
+ for (const file of this.pendingFlaggedFiles) {
2448
+ const filename = path5.basename(file.originalPath);
2449
+ const safeName = encodeURIComponent(filename);
2450
+ const storagePath = `${uploadPrefix}/${safeName}`;
2451
+ uploadedRefs.push({
2452
+ original_path: file.originalPath,
2453
+ reason: file.reason ?? "",
2454
+ storage_path: storagePath,
2455
+ file_size_bytes: file.data.length
2465
2456
  });
2466
- ws.close(1e3, "Error received");
2467
- finish(null);
2468
- break;
2469
- case "session_config" /* SESSION_CONFIG */:
2470
- uploadBaseUrl = msg.metadata?.["upload_url"];
2471
- break;
2472
- case "ping" /* PING */: {
2473
- const pongMsg = { type: "pong" /* PONG */ };
2474
- try {
2475
- ws.send(JSON.stringify(pongMsg));
2476
- } catch {
2477
- }
2478
- break;
2457
+ const uploadUrl = `${uploadBaseUrl}/${safeName}`;
2458
+ const contentType = file.isText ? "text/plain" : "application/octet-stream";
2459
+ void _PRBEAgent.backgroundUpload(file.data, uploadUrl, this.config.apiKey, contentType, this.getFetchSignal());
2479
2460
  }
2480
- // SDK-originated types and upload_url — ignore
2481
- case "start" /* START */:
2482
- case "tool_result" /* TOOL_RESULT */:
2483
- case "upload_request" /* UPLOAD_REQUEST */:
2484
- case "cancel" /* CANCEL */:
2485
- case "pong" /* PONG */:
2486
- case "upload_url" /* UPLOAD_URL */:
2487
- break;
2488
- }
2489
- };
2490
- ws.onerror = (event) => {
2491
- if (isCancelled()) {
2492
- finish(null);
2493
- return;
2461
+ resultMetadata = { flagged_files: uploadedRefs };
2462
+ this.pendingFlaggedFiles = [];
2494
2463
  }
2495
- const errorEvent = event;
2496
- const message = errorEvent.message || "WebSocket connection error";
2497
- emit({ type: "error" /* ERROR */, message });
2464
+ conn.sendToolResult(callId, toolName, toolResult, resultMetadata);
2465
+ break;
2466
+ }
2467
+ case "server_tool_call" /* SERVER_TOOL_CALL */:
2468
+ emit({ type: "tool_call" /* TOOL_CALL */, name: msg.name ?? "", label: msg.content ?? "" });
2469
+ break;
2470
+ case "server_observation" /* SERVER_OBSERVATION */:
2471
+ emit({ type: "observation" /* OBSERVATION */, text: (msg.content ?? "").substring(0, 200) });
2472
+ break;
2473
+ case "complete" /* COMPLETE */: {
2474
+ const report = msg.content ?? "";
2475
+ const completedTicketId = msg.metadata?.["ticket_id"];
2476
+ const sessionId = msg.metadata?.["session_id"];
2477
+ emit({ type: "completed" /* COMPLETED */, report, ticketId: completedTicketId });
2478
+ conn.close(1e3, "Complete");
2479
+ finish({ report, ticketId: completedTicketId, sessionId });
2480
+ break;
2481
+ }
2482
+ case "error" /* ERROR */:
2483
+ emit({ type: "error" /* ERROR */, message: msg.content || "Unknown error" });
2484
+ conn.close(1e3, "Error received");
2498
2485
  finish(null);
2499
- };
2500
- ws.onclose = (_event) => {
2501
- if (!resolved) {
2502
- if (isCancelled()) {
2503
- finish(null);
2504
- } else {
2505
- emit({
2506
- type: "error" /* ERROR */,
2507
- message: "WebSocket connection closed unexpectedly"
2508
- });
2509
- finish(null);
2510
- }
2486
+ break;
2487
+ case "session_config" /* SESSION_CONFIG */:
2488
+ setUploadBaseUrl(msg.metadata?.["upload_url"]);
2489
+ break;
2490
+ case "conversation_update" /* CONVERSATION_UPDATE */: {
2491
+ try {
2492
+ const entry = JSON.parse(msg.content ?? "{}");
2493
+ this.state.appendConversation(entry);
2494
+ } catch {
2511
2495
  }
2512
- };
2513
- });
2514
- }
2515
- sendCancel(ws) {
2516
- try {
2517
- const cancelMsg = { type: "cancel" /* CANCEL */ };
2518
- ws.send(JSON.stringify(cancelMsg));
2519
- } catch {
2496
+ break;
2497
+ }
2498
+ case "ping" /* PING */:
2499
+ conn.sendPong();
2500
+ break;
2501
+ default:
2502
+ break;
2520
2503
  }
2521
2504
  }
2522
2505
  extractArgs(metadata) {
@@ -2634,6 +2617,7 @@ var DEFAULT_PRBE_STATE = {
2634
2617
  summary: "",
2635
2618
  currentQuery: "",
2636
2619
  resolvedInteractions: [],
2620
+ conversationHistory: [],
2637
2621
  completedInvestigations: [],
2638
2622
  activeCRs: [],
2639
2623
  completedCRs: [],
@@ -2671,6 +2655,7 @@ function serializePRBEState(state) {
2671
2655
  pendingInteraction: state.pendingInteraction,
2672
2656
  resolvedInteractions: state.resolvedInteractions,
2673
2657
  agentMessage: state.agentMessage,
2658
+ conversationHistory: state.conversationHistory,
2674
2659
  completedInvestigations: state.completedInvestigations.map((inv) => ({
2675
2660
  id: inv.id,
2676
2661
  query: inv.query,
@@ -2679,6 +2664,7 @@ function serializePRBEState(state) {
2679
2664
  ticketId: inv.ticketId,
2680
2665
  events: inv.events,
2681
2666
  resolvedInteractions: inv.resolvedInteractions,
2667
+ conversationHistory: inv.conversationHistory,
2682
2668
  completedAt: inv.completedAt.toISOString()
2683
2669
  })),
2684
2670
  activeCRs: Array.from(state.activeCRs.values()).map(serializeCR),
@@ -2700,6 +2686,7 @@ export {
2700
2686
  AskUserTool,
2701
2687
  BashExecuteTool,
2702
2688
  ClearAppLogsTool,
2689
+ ConversationRole,
2703
2690
  DEFAULT_PRBE_STATE,
2704
2691
  FindFilesTool,
2705
2692
  FlagAppLogsTool,