@prbe.ai/electron-sdk 0.1.17 → 0.1.19
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.d.mts +18 -18
- package/dist/index.d.ts +18 -18
- package/dist/index.js +363 -471
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +363 -471
- package/dist/index.mjs.map +1 -1
- package/dist/{types-BmH_CmsO.d.mts → types-9iQH0zmA.d.mts} +108 -52
- package/dist/{types-BmH_CmsO.d.ts → types-9iQH0zmA.d.ts} +108 -52
- package/dist/types.d.mts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +11 -5
- package/dist/types.js.map +1 -1
- package/dist/types.mjs +11 -5
- package/dist/types.mjs.map +1 -1
- package/package.json +4 -2
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// package.json
|
|
2
|
-
var version = "0.1.
|
|
2
|
+
var version = "0.1.19";
|
|
3
3
|
|
|
4
4
|
// src/agent.ts
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
7
|
-
import * as
|
|
5
|
+
import * as fs2 from "fs";
|
|
6
|
+
import * as path4 from "path";
|
|
7
|
+
import * as os from "os";
|
|
8
8
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
9
9
|
|
|
10
10
|
// src/models.ts
|
|
@@ -25,6 +25,9 @@ var WSMessageType = /* @__PURE__ */ ((WSMessageType2) => {
|
|
|
25
25
|
WSMessageType2["COMPLETE"] = "complete";
|
|
26
26
|
WSMessageType2["ERROR"] = "error";
|
|
27
27
|
WSMessageType2["PING"] = "ping";
|
|
28
|
+
WSMessageType2["PRIVACY_SANITIZING"] = "privacy_sanitizing";
|
|
29
|
+
WSMessageType2["PRIVACY_REVIEW"] = "privacy_review";
|
|
30
|
+
WSMessageType2["PRIVACY_REVIEW_RESPONSE"] = "privacy_review_response";
|
|
28
31
|
return WSMessageType2;
|
|
29
32
|
})(WSMessageType || {});
|
|
30
33
|
var ConversationRole = /* @__PURE__ */ ((ConversationRole3) => {
|
|
@@ -82,6 +85,7 @@ var PRBEAgentStatusType = /* @__PURE__ */ ((PRBEAgentStatusType2) => {
|
|
|
82
85
|
PRBEAgentStatusType2["COMPLETED"] = "completed";
|
|
83
86
|
PRBEAgentStatusType2["ERROR"] = "error";
|
|
84
87
|
PRBEAgentStatusType2["AWAITING_INTERACTION"] = "awaiting_interaction";
|
|
88
|
+
PRBEAgentStatusType2["PRIVACY_SANITIZING"] = "privacy_sanitizing";
|
|
85
89
|
return PRBEAgentStatusType2;
|
|
86
90
|
})(PRBEAgentStatusType || {});
|
|
87
91
|
var PRBEAgentErrorType = /* @__PURE__ */ ((PRBEAgentErrorType2) => {
|
|
@@ -147,10 +151,14 @@ var InvestigationConnection = class {
|
|
|
147
151
|
return false;
|
|
148
152
|
}
|
|
149
153
|
}
|
|
150
|
-
sendConversationMessage(content) {
|
|
154
|
+
sendConversationMessage(content, role, label) {
|
|
155
|
+
const metadata = {};
|
|
156
|
+
if (role) metadata["role"] = role;
|
|
157
|
+
if (label) metadata["label"] = label;
|
|
151
158
|
this.send({
|
|
152
159
|
type: "conversation_message" /* CONVERSATION_MESSAGE */,
|
|
153
|
-
content
|
|
160
|
+
content,
|
|
161
|
+
...Object.keys(metadata).length > 0 ? { metadata } : {}
|
|
154
162
|
});
|
|
155
163
|
}
|
|
156
164
|
sendToolResult(callId, toolName, result, metadata) {
|
|
@@ -192,8 +200,8 @@ var PRBEStateEvent = /* @__PURE__ */ ((PRBEStateEvent2) => {
|
|
|
192
200
|
PRBEStateEvent2["EVENT"] = "event";
|
|
193
201
|
PRBEStateEvent2["COMPLETE"] = "complete";
|
|
194
202
|
PRBEStateEvent2["ERROR"] = "error";
|
|
195
|
-
PRBEStateEvent2["
|
|
196
|
-
PRBEStateEvent2["
|
|
203
|
+
PRBEStateEvent2["BACKGROUND_START"] = "background-start";
|
|
204
|
+
PRBEStateEvent2["BACKGROUND_COMPLETE"] = "background-complete";
|
|
197
205
|
PRBEStateEvent2["TICKETS_CHANGED"] = "tickets-changed";
|
|
198
206
|
PRBEStateEvent2["TICKET_INFO"] = "ticket-info";
|
|
199
207
|
PRBEStateEvent2["INTERACTION_REQUESTED"] = "interaction-requested";
|
|
@@ -213,20 +221,23 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
213
221
|
resolvedInteractions = [];
|
|
214
222
|
agentMessage;
|
|
215
223
|
conversationHistory = [];
|
|
224
|
+
isPrivacySanitizing = false;
|
|
216
225
|
// Completed user investigations (history)
|
|
217
226
|
completedInvestigations = [];
|
|
218
|
-
// Background context requests
|
|
219
|
-
|
|
220
|
-
|
|
227
|
+
// Background investigations (context requests, external requests, etc.)
|
|
228
|
+
activeBackgroundInvestigations = /* @__PURE__ */ new Map();
|
|
229
|
+
completedBackgroundInvestigations = [];
|
|
221
230
|
// Tracked tickets
|
|
222
231
|
trackedSessionIDs = [];
|
|
223
232
|
ticketInfo = [];
|
|
233
|
+
// Agent history
|
|
234
|
+
agentHistory = [];
|
|
224
235
|
// Computed
|
|
225
236
|
get hasActiveWork() {
|
|
226
|
-
return this.isInvestigating || this.
|
|
237
|
+
return this.isInvestigating || this.activeBackgroundInvestigations.size > 0;
|
|
227
238
|
}
|
|
228
|
-
get
|
|
229
|
-
return this.
|
|
239
|
+
get activeBackgroundCount() {
|
|
240
|
+
return this.activeBackgroundInvestigations.size;
|
|
230
241
|
}
|
|
231
242
|
get isActive() {
|
|
232
243
|
return this.isInvestigating || this.report.length > 0 || this.investigationError != null;
|
|
@@ -248,6 +259,12 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
248
259
|
this.conversationHistory.push(entry);
|
|
249
260
|
this.emit("status" /* STATUS */);
|
|
250
261
|
}
|
|
262
|
+
appendBackgroundConversation(backgroundId, entry) {
|
|
263
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
264
|
+
if (!bg) return;
|
|
265
|
+
bg.conversationHistory.push(entry);
|
|
266
|
+
this.emit("status" /* STATUS */);
|
|
267
|
+
}
|
|
251
268
|
resetInvestigation() {
|
|
252
269
|
this.isInvestigating = false;
|
|
253
270
|
this.events = [];
|
|
@@ -302,6 +319,7 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
302
319
|
});
|
|
303
320
|
this.report = report;
|
|
304
321
|
this.isInvestigating = false;
|
|
322
|
+
this.isPrivacySanitizing = false;
|
|
305
323
|
this.emit("complete" /* COMPLETE */, { report });
|
|
306
324
|
this.emit("status" /* STATUS */);
|
|
307
325
|
}
|
|
@@ -309,9 +327,14 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
309
327
|
this.appendEvent(`Error: ${message}`);
|
|
310
328
|
this.investigationError = message;
|
|
311
329
|
this.isInvestigating = false;
|
|
330
|
+
this.isPrivacySanitizing = false;
|
|
312
331
|
this.emit("error" /* ERROR */, { message });
|
|
313
332
|
this.emit("status" /* STATUS */);
|
|
314
333
|
}
|
|
334
|
+
setPrivacySanitizing(value) {
|
|
335
|
+
this.isPrivacySanitizing = value;
|
|
336
|
+
this.emit("status" /* STATUS */);
|
|
337
|
+
}
|
|
315
338
|
// ---------- Interaction state mutations ----------
|
|
316
339
|
setPendingInteraction(payload) {
|
|
317
340
|
this.pendingInteraction = payload;
|
|
@@ -323,17 +346,17 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
323
346
|
this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
|
|
324
347
|
this.emit("status" /* STATUS */);
|
|
325
348
|
}
|
|
326
|
-
|
|
327
|
-
const
|
|
328
|
-
if (!
|
|
329
|
-
|
|
349
|
+
setBackgroundPendingInteraction(backgroundId, payload) {
|
|
350
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
351
|
+
if (!bg) return;
|
|
352
|
+
bg.pendingInteraction = payload;
|
|
330
353
|
this.emit("interaction-requested" /* INTERACTION_REQUESTED */, payload);
|
|
331
354
|
this.emit("status" /* STATUS */);
|
|
332
355
|
}
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
if (!
|
|
336
|
-
|
|
356
|
+
clearBackgroundPendingInteraction(backgroundId) {
|
|
357
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
358
|
+
if (!bg) return;
|
|
359
|
+
bg.pendingInteraction = void 0;
|
|
337
360
|
this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
|
|
338
361
|
this.emit("status" /* STATUS */);
|
|
339
362
|
}
|
|
@@ -349,18 +372,18 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
349
372
|
this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
|
|
350
373
|
this.emit("status" /* STATUS */);
|
|
351
374
|
}
|
|
352
|
-
|
|
353
|
-
const
|
|
354
|
-
if (!
|
|
355
|
-
const resolved =
|
|
375
|
+
resolveBackgroundInteraction(backgroundId, response) {
|
|
376
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
377
|
+
if (!bg || !bg.pendingInteraction) return;
|
|
378
|
+
const resolved = bg.resolvedInteractions ?? [];
|
|
356
379
|
resolved.push({
|
|
357
|
-
interactionId:
|
|
358
|
-
payload:
|
|
380
|
+
interactionId: bg.pendingInteraction.interactionId,
|
|
381
|
+
payload: bg.pendingInteraction,
|
|
359
382
|
response,
|
|
360
|
-
eventIndex:
|
|
383
|
+
eventIndex: bg.events.length
|
|
361
384
|
});
|
|
362
|
-
|
|
363
|
-
|
|
385
|
+
bg.resolvedInteractions = resolved;
|
|
386
|
+
bg.pendingInteraction = void 0;
|
|
364
387
|
this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
|
|
365
388
|
this.emit("status" /* STATUS */);
|
|
366
389
|
}
|
|
@@ -369,10 +392,10 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
369
392
|
this.emit("agent-message" /* AGENT_MESSAGE */, { message });
|
|
370
393
|
this.emit("status" /* STATUS */);
|
|
371
394
|
}
|
|
372
|
-
|
|
373
|
-
const
|
|
374
|
-
if (!
|
|
375
|
-
|
|
395
|
+
setBackgroundAgentMessage(backgroundId, message) {
|
|
396
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
397
|
+
if (!bg) return;
|
|
398
|
+
bg.agentMessage = message;
|
|
376
399
|
this.emit("agent-message" /* AGENT_MESSAGE */, { message });
|
|
377
400
|
this.emit("status" /* STATUS */);
|
|
378
401
|
}
|
|
@@ -383,14 +406,17 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
383
406
|
this.emit("status" /* STATUS */);
|
|
384
407
|
}
|
|
385
408
|
}
|
|
386
|
-
// ----------
|
|
387
|
-
|
|
388
|
-
const
|
|
409
|
+
// ---------- Background investigation state mutations ----------
|
|
410
|
+
beginBackgroundInvestigation(id, query, slug, ticketId, source, sourceDetail) {
|
|
411
|
+
const bg = {
|
|
389
412
|
id,
|
|
390
413
|
query,
|
|
391
414
|
slug,
|
|
392
415
|
ticketId,
|
|
416
|
+
source,
|
|
417
|
+
sourceDetail,
|
|
393
418
|
events: [],
|
|
419
|
+
conversationHistory: [],
|
|
394
420
|
resolvedInteractions: [],
|
|
395
421
|
isRunning: true,
|
|
396
422
|
isCompleted: false,
|
|
@@ -399,20 +425,20 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
399
425
|
summary: "",
|
|
400
426
|
startedAt: /* @__PURE__ */ new Date()
|
|
401
427
|
};
|
|
402
|
-
this.
|
|
403
|
-
this.emit("
|
|
428
|
+
this.activeBackgroundInvestigations.set(id, bg);
|
|
429
|
+
this.emit("background-start" /* BACKGROUND_START */, bg);
|
|
404
430
|
this.emit("status" /* STATUS */);
|
|
405
431
|
}
|
|
406
|
-
|
|
407
|
-
const
|
|
408
|
-
if (!
|
|
409
|
-
if (
|
|
410
|
-
const last =
|
|
432
|
+
appendBackgroundEvent(backgroundId, label, detail, completed = false) {
|
|
433
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
434
|
+
if (!bg) return;
|
|
435
|
+
if (bg.events.length > 0) {
|
|
436
|
+
const last = bg.events[bg.events.length - 1];
|
|
411
437
|
if (!last.isCompleted && !completed) {
|
|
412
438
|
last.isCompleted = true;
|
|
413
439
|
}
|
|
414
440
|
}
|
|
415
|
-
|
|
441
|
+
bg.events.push({
|
|
416
442
|
id: randomUUID(),
|
|
417
443
|
label,
|
|
418
444
|
detail,
|
|
@@ -421,47 +447,47 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
421
447
|
});
|
|
422
448
|
this.emit("status" /* STATUS */);
|
|
423
449
|
}
|
|
424
|
-
|
|
425
|
-
const
|
|
426
|
-
if (!
|
|
427
|
-
|
|
450
|
+
attachBackgroundObservation(backgroundId, text) {
|
|
451
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
452
|
+
if (!bg || bg.events.length === 0) return;
|
|
453
|
+
bg.events[bg.events.length - 1].detail = text;
|
|
428
454
|
this.emit("status" /* STATUS */);
|
|
429
455
|
}
|
|
430
|
-
|
|
431
|
-
const
|
|
432
|
-
if (!
|
|
433
|
-
this.
|
|
434
|
-
if (
|
|
435
|
-
|
|
456
|
+
completeBackgroundInvestigation(id, report) {
|
|
457
|
+
const bg = this.activeBackgroundInvestigations.get(id);
|
|
458
|
+
if (!bg) return;
|
|
459
|
+
this.activeBackgroundInvestigations.delete(id);
|
|
460
|
+
if (bg.events.length > 0) {
|
|
461
|
+
bg.events[bg.events.length - 1].isCompleted = true;
|
|
436
462
|
}
|
|
437
|
-
|
|
463
|
+
bg.events.push({
|
|
438
464
|
id: randomUUID(),
|
|
439
465
|
label: "Done",
|
|
440
466
|
isCompleted: true,
|
|
441
467
|
isExpanded: false
|
|
442
468
|
});
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
this.
|
|
447
|
-
this.emit("
|
|
469
|
+
bg.isRunning = false;
|
|
470
|
+
bg.isCompleted = true;
|
|
471
|
+
bg.report = report;
|
|
472
|
+
this.completedBackgroundInvestigations.unshift(bg);
|
|
473
|
+
this.emit("background-complete" /* BACKGROUND_COMPLETE */, bg);
|
|
448
474
|
this.emit("status" /* STATUS */);
|
|
449
475
|
}
|
|
450
|
-
|
|
451
|
-
const
|
|
452
|
-
if (!
|
|
453
|
-
this.
|
|
454
|
-
|
|
476
|
+
failBackgroundInvestigation(id, message) {
|
|
477
|
+
const bg = this.activeBackgroundInvestigations.get(id);
|
|
478
|
+
if (!bg) return;
|
|
479
|
+
this.activeBackgroundInvestigations.delete(id);
|
|
480
|
+
bg.events.push({
|
|
455
481
|
id: randomUUID(),
|
|
456
482
|
label: `Error: ${message}`,
|
|
457
483
|
isCompleted: false,
|
|
458
484
|
isExpanded: false
|
|
459
485
|
});
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
this.
|
|
464
|
-
this.emit("
|
|
486
|
+
bg.isRunning = false;
|
|
487
|
+
bg.isFailed = true;
|
|
488
|
+
bg.errorMessage = message;
|
|
489
|
+
this.completedBackgroundInvestigations.unshift(bg);
|
|
490
|
+
this.emit("background-complete" /* BACKGROUND_COMPLETE */, bg);
|
|
465
491
|
this.emit("status" /* STATUS */);
|
|
466
492
|
}
|
|
467
493
|
// ---------- Tickets ----------
|
|
@@ -475,6 +501,10 @@ var PRBEAgentState = class extends EventEmitter {
|
|
|
475
501
|
this.emit("ticket-info" /* TICKET_INFO */, info);
|
|
476
502
|
this.emit("status" /* STATUS */);
|
|
477
503
|
}
|
|
504
|
+
updateAgentHistory(tickets) {
|
|
505
|
+
this.agentHistory = tickets;
|
|
506
|
+
this.emit("status" /* STATUS */);
|
|
507
|
+
}
|
|
478
508
|
};
|
|
479
509
|
|
|
480
510
|
// src/tools/index.ts
|
|
@@ -485,11 +515,13 @@ var InteractionType = /* @__PURE__ */ ((InteractionType2) => {
|
|
|
485
515
|
InteractionType2["ASK_QUESTION"] = "ask_question";
|
|
486
516
|
InteractionType2["REQUEST_PERMISSION"] = "request_permission";
|
|
487
517
|
InteractionType2["REQUEST_PATH_ACCESS"] = "request_path_access";
|
|
518
|
+
InteractionType2["REVIEW_SANITIZED_OUTPUT"] = "review_sanitized_output";
|
|
488
519
|
return InteractionType2;
|
|
489
520
|
})(InteractionType || {});
|
|
490
521
|
var InvestigationSource = /* @__PURE__ */ ((InvestigationSource2) => {
|
|
491
522
|
InvestigationSource2["USER"] = "user";
|
|
492
523
|
InvestigationSource2["CONTEXT_REQUEST"] = "context_request";
|
|
524
|
+
InvestigationSource2["EXTERNAL_REQUEST"] = "external_request";
|
|
493
525
|
return InvestigationSource2;
|
|
494
526
|
})(InvestigationSource || {});
|
|
495
527
|
|
|
@@ -1397,7 +1429,8 @@ var AskUserTool = class {
|
|
|
1397
1429
|
const response = await this.requester.requestUserInteraction({
|
|
1398
1430
|
type: "ask_question" /* ASK_QUESTION */,
|
|
1399
1431
|
interactionId: randomUUID3(),
|
|
1400
|
-
question
|
|
1432
|
+
question,
|
|
1433
|
+
context: reason
|
|
1401
1434
|
});
|
|
1402
1435
|
const askResponse = response;
|
|
1403
1436
|
return askResponse.answer;
|
|
@@ -1607,6 +1640,10 @@ var BashExecuteTool = class {
|
|
|
1607
1640
|
return `Error: working directory '${cwdArg}' is outside auto-approved directories`;
|
|
1608
1641
|
}
|
|
1609
1642
|
cwd = resolved;
|
|
1643
|
+
} else if (this.autoApprovedDirs.length > 0) {
|
|
1644
|
+
cwd = this.autoApprovedDirs[0];
|
|
1645
|
+
} else {
|
|
1646
|
+
return "Error: no approved directories configured and no working directory specified";
|
|
1610
1647
|
}
|
|
1611
1648
|
const isSafe = this.isCommandSafe(command);
|
|
1612
1649
|
if (!isSafe) {
|
|
@@ -1697,197 +1734,20 @@ var BashExecuteTool = class {
|
|
|
1697
1734
|
}
|
|
1698
1735
|
};
|
|
1699
1736
|
|
|
1700
|
-
// src/
|
|
1701
|
-
|
|
1702
|
-
import * as path4 from "path";
|
|
1703
|
-
import * as os from "os";
|
|
1704
|
-
import * as crypto from "crypto";
|
|
1705
|
-
var HKDF_SALT = Buffer.from("prbe-history-encryption-salt", "utf-8");
|
|
1706
|
-
var HKDF_INFO = Buffer.from("prbe-history-v1", "utf-8");
|
|
1707
|
-
function getAppDataDir() {
|
|
1737
|
+
// src/agent.ts
|
|
1738
|
+
function getPersistencePath() {
|
|
1708
1739
|
const appData = process.env["APPDATA"] || (process.platform === "darwin" ? path4.join(os.homedir(), "Library", "Application Support") : path4.join(os.homedir(), ".local", "share"));
|
|
1709
|
-
|
|
1710
|
-
}
|
|
1711
|
-
function getHistoryDir() {
|
|
1712
|
-
const dir = path4.join(getAppDataDir(), "history" /* HISTORY_DIR */);
|
|
1740
|
+
const dir = path4.join(appData, "prbe-agent");
|
|
1713
1741
|
if (!fs2.existsSync(dir)) {
|
|
1714
1742
|
fs2.mkdirSync(dir, { recursive: true });
|
|
1715
1743
|
}
|
|
1716
|
-
return dir;
|
|
1717
|
-
}
|
|
1718
|
-
function deriveKey(apiKey) {
|
|
1719
|
-
return Buffer.from(
|
|
1720
|
-
crypto.hkdfSync(
|
|
1721
|
-
"sha256",
|
|
1722
|
-
Buffer.from(apiKey, "utf-8"),
|
|
1723
|
-
HKDF_SALT,
|
|
1724
|
-
HKDF_INFO,
|
|
1725
|
-
32 /* KEY_LENGTH */
|
|
1726
|
-
)
|
|
1727
|
-
);
|
|
1728
|
-
}
|
|
1729
|
-
function encrypt(plaintext, key) {
|
|
1730
|
-
const iv = crypto.randomBytes(12 /* IV_LENGTH */);
|
|
1731
|
-
const cipher = crypto.createCipheriv(
|
|
1732
|
-
"aes-256-gcm" /* ALGORITHM */,
|
|
1733
|
-
key,
|
|
1734
|
-
iv,
|
|
1735
|
-
{ authTagLength: 16 /* AUTH_TAG_LENGTH */ }
|
|
1736
|
-
);
|
|
1737
|
-
const encrypted = Buffer.concat([cipher.update(plaintext, "utf-8"), cipher.final()]);
|
|
1738
|
-
const authTag = cipher.getAuthTag();
|
|
1739
|
-
return Buffer.concat([iv, authTag, encrypted]);
|
|
1740
|
-
}
|
|
1741
|
-
function decrypt(data, key) {
|
|
1742
|
-
const iv = data.subarray(0, 12 /* IV_LENGTH */);
|
|
1743
|
-
const authTag = data.subarray(
|
|
1744
|
-
12 /* IV_LENGTH */,
|
|
1745
|
-
12 /* IV_LENGTH */ + 16 /* AUTH_TAG_LENGTH */
|
|
1746
|
-
);
|
|
1747
|
-
const ciphertext = data.subarray(
|
|
1748
|
-
12 /* IV_LENGTH */ + 16 /* AUTH_TAG_LENGTH */
|
|
1749
|
-
);
|
|
1750
|
-
const decipher = crypto.createDecipheriv(
|
|
1751
|
-
"aes-256-gcm" /* ALGORITHM */,
|
|
1752
|
-
key,
|
|
1753
|
-
iv,
|
|
1754
|
-
{ authTagLength: 16 /* AUTH_TAG_LENGTH */ }
|
|
1755
|
-
);
|
|
1756
|
-
decipher.setAuthTag(authTag);
|
|
1757
|
-
return decipher.update(ciphertext) + decipher.final("utf-8");
|
|
1758
|
-
}
|
|
1759
|
-
var HistoryStore = class {
|
|
1760
|
-
key;
|
|
1761
|
-
constructor(apiKey) {
|
|
1762
|
-
this.key = deriveKey(apiKey);
|
|
1763
|
-
}
|
|
1764
|
-
load() {
|
|
1765
|
-
const investigations = [];
|
|
1766
|
-
const crs = [];
|
|
1767
|
-
try {
|
|
1768
|
-
const dir = getHistoryDir();
|
|
1769
|
-
let files;
|
|
1770
|
-
try {
|
|
1771
|
-
files = fs2.readdirSync(dir);
|
|
1772
|
-
} catch {
|
|
1773
|
-
return { investigations, crs };
|
|
1774
|
-
}
|
|
1775
|
-
for (const filename of files) {
|
|
1776
|
-
try {
|
|
1777
|
-
const filePath = path4.join(dir, filename);
|
|
1778
|
-
const raw = fs2.readFileSync(filePath);
|
|
1779
|
-
const json = decrypt(raw, this.key);
|
|
1780
|
-
if (filename.startsWith("inv-") && filename.endsWith(".json")) {
|
|
1781
|
-
const item = JSON.parse(json);
|
|
1782
|
-
investigations.push({
|
|
1783
|
-
...item,
|
|
1784
|
-
completedAt: new Date(item.completedAt)
|
|
1785
|
-
});
|
|
1786
|
-
} else if (filename.startsWith("cr-") && filename.endsWith(".json")) {
|
|
1787
|
-
const item = JSON.parse(json);
|
|
1788
|
-
crs.push({
|
|
1789
|
-
...item,
|
|
1790
|
-
startedAt: new Date(item.startedAt),
|
|
1791
|
-
resolvedInteractions: item.resolvedInteractions ?? []
|
|
1792
|
-
});
|
|
1793
|
-
}
|
|
1794
|
-
} catch {
|
|
1795
|
-
console.warn(`[PRBEAgent] Skipping unreadable history file: ${filename}`);
|
|
1796
|
-
}
|
|
1797
|
-
}
|
|
1798
|
-
} catch {
|
|
1799
|
-
}
|
|
1800
|
-
investigations.sort(
|
|
1801
|
-
(a, b) => b.completedAt.getTime() - a.completedAt.getTime()
|
|
1802
|
-
);
|
|
1803
|
-
crs.sort((a, b) => b.startedAt.getTime() - a.startedAt.getTime());
|
|
1804
|
-
return { investigations, crs };
|
|
1805
|
-
}
|
|
1806
|
-
save(investigations, crs) {
|
|
1807
|
-
try {
|
|
1808
|
-
const dir = getHistoryDir();
|
|
1809
|
-
const desiredFiles = /* @__PURE__ */ new Set();
|
|
1810
|
-
for (const inv of investigations) {
|
|
1811
|
-
const filename = `inv-${inv.id}.json`;
|
|
1812
|
-
desiredFiles.add(filename);
|
|
1813
|
-
const data = {
|
|
1814
|
-
id: inv.id,
|
|
1815
|
-
query: inv.query,
|
|
1816
|
-
report: inv.report,
|
|
1817
|
-
summary: inv.summary,
|
|
1818
|
-
ticketId: inv.ticketId,
|
|
1819
|
-
events: inv.events,
|
|
1820
|
-
resolvedInteractions: inv.resolvedInteractions,
|
|
1821
|
-
conversationHistory: inv.conversationHistory,
|
|
1822
|
-
completedAt: inv.completedAt.toISOString()
|
|
1823
|
-
};
|
|
1824
|
-
fs2.writeFileSync(
|
|
1825
|
-
path4.join(dir, filename),
|
|
1826
|
-
encrypt(JSON.stringify(data), this.key)
|
|
1827
|
-
);
|
|
1828
|
-
}
|
|
1829
|
-
for (const cr of crs) {
|
|
1830
|
-
const filename = `cr-${cr.id}.json`;
|
|
1831
|
-
desiredFiles.add(filename);
|
|
1832
|
-
const data = {
|
|
1833
|
-
id: cr.id,
|
|
1834
|
-
query: cr.query,
|
|
1835
|
-
slug: cr.slug,
|
|
1836
|
-
ticketId: cr.ticketId,
|
|
1837
|
-
events: cr.events,
|
|
1838
|
-
isRunning: cr.isRunning,
|
|
1839
|
-
isCompleted: cr.isCompleted,
|
|
1840
|
-
isFailed: cr.isFailed,
|
|
1841
|
-
report: cr.report,
|
|
1842
|
-
summary: cr.summary,
|
|
1843
|
-
errorMessage: cr.errorMessage,
|
|
1844
|
-
startedAt: cr.startedAt.toISOString(),
|
|
1845
|
-
pendingInteraction: cr.pendingInteraction,
|
|
1846
|
-
resolvedInteractions: cr.resolvedInteractions ?? []
|
|
1847
|
-
};
|
|
1848
|
-
fs2.writeFileSync(
|
|
1849
|
-
path4.join(dir, filename),
|
|
1850
|
-
encrypt(JSON.stringify(data), this.key)
|
|
1851
|
-
);
|
|
1852
|
-
}
|
|
1853
|
-
try {
|
|
1854
|
-
const existing = fs2.readdirSync(dir);
|
|
1855
|
-
for (const filename of existing) {
|
|
1856
|
-
if (!desiredFiles.has(filename)) {
|
|
1857
|
-
fs2.unlinkSync(path4.join(dir, filename));
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1860
|
-
} catch {
|
|
1861
|
-
}
|
|
1862
|
-
} catch {
|
|
1863
|
-
console.error("[PRBEAgent] Failed to save investigation history");
|
|
1864
|
-
}
|
|
1865
|
-
}
|
|
1866
|
-
static clear() {
|
|
1867
|
-
try {
|
|
1868
|
-
const dir = path4.join(getAppDataDir(), "history" /* HISTORY_DIR */);
|
|
1869
|
-
if (fs2.existsSync(dir)) {
|
|
1870
|
-
fs2.rmSync(dir, { recursive: true, force: true });
|
|
1871
|
-
}
|
|
1872
|
-
} catch {
|
|
1873
|
-
}
|
|
1874
|
-
}
|
|
1875
|
-
};
|
|
1876
|
-
|
|
1877
|
-
// src/agent.ts
|
|
1878
|
-
function getPersistencePath() {
|
|
1879
|
-
const appData = process.env["APPDATA"] || (process.platform === "darwin" ? path5.join(os2.homedir(), "Library", "Application Support") : path5.join(os2.homedir(), ".local", "share"));
|
|
1880
|
-
const dir = path5.join(appData, "prbe-agent");
|
|
1881
|
-
if (!fs3.existsSync(dir)) {
|
|
1882
|
-
fs3.mkdirSync(dir, { recursive: true });
|
|
1883
|
-
}
|
|
1884
|
-
return path5.join(dir, "agent-state.json");
|
|
1744
|
+
return path4.join(dir, "agent-state.json");
|
|
1885
1745
|
}
|
|
1886
1746
|
function loadPersistedData() {
|
|
1887
1747
|
try {
|
|
1888
1748
|
const filePath = getPersistencePath();
|
|
1889
|
-
if (
|
|
1890
|
-
const raw =
|
|
1749
|
+
if (fs2.existsSync(filePath)) {
|
|
1750
|
+
const raw = fs2.readFileSync(filePath, "utf-8");
|
|
1891
1751
|
return JSON.parse(raw);
|
|
1892
1752
|
}
|
|
1893
1753
|
} catch {
|
|
@@ -1897,7 +1757,7 @@ function loadPersistedData() {
|
|
|
1897
1757
|
function savePersistedData(data) {
|
|
1898
1758
|
try {
|
|
1899
1759
|
const filePath = getPersistencePath();
|
|
1900
|
-
|
|
1760
|
+
fs2.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
1901
1761
|
} catch {
|
|
1902
1762
|
console.error("[PRBEAgent] Failed to save persisted data");
|
|
1903
1763
|
}
|
|
@@ -1917,8 +1777,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
1917
1777
|
persistedData;
|
|
1918
1778
|
fetchAbortController = null;
|
|
1919
1779
|
currentInvestigationSource = "user" /* USER */;
|
|
1920
|
-
|
|
1921
|
-
historyStore;
|
|
1780
|
+
currentBackgroundId = null;
|
|
1922
1781
|
/** Files flagged during the current tool call — uploaded immediately after the tool returns. */
|
|
1923
1782
|
pendingFlaggedFiles = [];
|
|
1924
1783
|
// ---------- User Identifier ----------
|
|
@@ -1934,30 +1793,6 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
1934
1793
|
savePersistedData(this.persistedData);
|
|
1935
1794
|
return newID;
|
|
1936
1795
|
}
|
|
1937
|
-
get trackedSessionIDs() {
|
|
1938
|
-
return this.persistedData.sessionIds ?? [];
|
|
1939
|
-
}
|
|
1940
|
-
set trackedSessionIDs(ids) {
|
|
1941
|
-
this.persistedData.sessionIds = ids;
|
|
1942
|
-
savePersistedData(this.persistedData);
|
|
1943
|
-
this.state.updateTrackedSessionIDs(ids);
|
|
1944
|
-
this.syncPolling(ids.length > 0);
|
|
1945
|
-
}
|
|
1946
|
-
syncPolling(hasSessions) {
|
|
1947
|
-
if (this.config.backgroundPolling && hasSessions) {
|
|
1948
|
-
if (this.pollingTimer === null) {
|
|
1949
|
-
this.startPolling();
|
|
1950
|
-
}
|
|
1951
|
-
} else if (!hasSessions) {
|
|
1952
|
-
this.stopPolling();
|
|
1953
|
-
}
|
|
1954
|
-
}
|
|
1955
|
-
addTrackedSession(id) {
|
|
1956
|
-
const ids = this.trackedSessionIDs;
|
|
1957
|
-
if (!ids.includes(id)) {
|
|
1958
|
-
this.trackedSessionIDs = [...ids, id];
|
|
1959
|
-
}
|
|
1960
|
-
}
|
|
1961
1796
|
// ---------- Constructor ----------
|
|
1962
1797
|
constructor(config) {
|
|
1963
1798
|
this.config = {
|
|
@@ -1977,11 +1812,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
1977
1812
|
this.state = new PRBEAgentState();
|
|
1978
1813
|
this.logCapture = new PRBELogCapture(this.config.maxLogEntries);
|
|
1979
1814
|
this.persistedData = loadPersistedData();
|
|
1980
|
-
this.historyStore = new HistoryStore(this.config.apiKey);
|
|
1981
1815
|
void this.agentID;
|
|
1982
|
-
const history = this.historyStore.load();
|
|
1983
|
-
this.state.completedInvestigations = history.investigations;
|
|
1984
|
-
this.state.completedCRs = history.crs;
|
|
1985
1816
|
const roots = this.config.autoApprovedDirs;
|
|
1986
1817
|
const requester = this.interactionHandler ? this : void 0;
|
|
1987
1818
|
const grantedPaths = this.grantedPaths;
|
|
@@ -2013,8 +1844,8 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2013
1844
|
[{ name: "message", type: "STRING" /* STRING */, description: "Message for the user", required: true }],
|
|
2014
1845
|
async (args) => {
|
|
2015
1846
|
const message = args["message"] ?? "";
|
|
2016
|
-
if (this.currentInvestigationSource
|
|
2017
|
-
this.state.
|
|
1847
|
+
if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
|
|
1848
|
+
this.state.setBackgroundAgentMessage(this.currentBackgroundId, message);
|
|
2018
1849
|
} else {
|
|
2019
1850
|
this.state.setAgentMessage(message);
|
|
2020
1851
|
}
|
|
@@ -2031,9 +1862,8 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2031
1862
|
if (config.ipcMain) {
|
|
2032
1863
|
this.hookRendererLogs(config.ipcMain, config.rendererLogChannel ?? "prbe-renderer-log");
|
|
2033
1864
|
}
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
this.trackedSessionIDs = existingSessions;
|
|
1865
|
+
if (this.config.backgroundPolling) {
|
|
1866
|
+
this.startPolling();
|
|
2037
1867
|
}
|
|
2038
1868
|
}
|
|
2039
1869
|
// ---------- Log integration ----------
|
|
@@ -2077,8 +1907,8 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2077
1907
|
get investigationSource() {
|
|
2078
1908
|
return this.currentInvestigationSource;
|
|
2079
1909
|
}
|
|
2080
|
-
sendConversationMessage(content) {
|
|
2081
|
-
this.activeConnection?.sendConversationMessage(content);
|
|
1910
|
+
sendConversationMessage(content, role, label) {
|
|
1911
|
+
this.activeConnection?.sendConversationMessage(content, role, label);
|
|
2082
1912
|
}
|
|
2083
1913
|
async requestUserInteraction(payload) {
|
|
2084
1914
|
if (!this.interactionHandler) {
|
|
@@ -2087,15 +1917,31 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2087
1917
|
"No interaction handler configured"
|
|
2088
1918
|
);
|
|
2089
1919
|
}
|
|
2090
|
-
if (
|
|
2091
|
-
|
|
1920
|
+
if (payload.type === "request_permission" /* REQUEST_PERMISSION */) {
|
|
1921
|
+
const p = payload;
|
|
1922
|
+
const content = p.reason ? `${p.command}
|
|
1923
|
+
|
|
1924
|
+
${p.reason}` : p.command;
|
|
1925
|
+
this.sendConversationMessage(content, "agent" /* Agent */, p.action);
|
|
1926
|
+
} else if (payload.type === "request_path_access" /* REQUEST_PATH_ACCESS */) {
|
|
1927
|
+
const p = payload;
|
|
1928
|
+
const content = p.reason ? `${p.path}
|
|
1929
|
+
|
|
1930
|
+
${p.reason}` : p.path;
|
|
1931
|
+
this.sendConversationMessage(content, "agent" /* Agent */, "Request path access");
|
|
1932
|
+
} else if (payload.type === "ask_question" /* ASK_QUESTION */) {
|
|
1933
|
+
const p = payload;
|
|
1934
|
+
this.sendConversationMessage(p.question, "agent" /* Agent */);
|
|
1935
|
+
}
|
|
1936
|
+
if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
|
|
1937
|
+
this.state.setBackgroundPendingInteraction(this.currentBackgroundId, payload);
|
|
2092
1938
|
} else {
|
|
2093
1939
|
this.state.setPendingInteraction(payload);
|
|
2094
1940
|
}
|
|
2095
1941
|
try {
|
|
2096
1942
|
const response = await this.interactionHandler.handleInteraction(payload);
|
|
2097
|
-
if (this.currentInvestigationSource
|
|
2098
|
-
this.state.
|
|
1943
|
+
if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
|
|
1944
|
+
this.state.resolveBackgroundInteraction(this.currentBackgroundId, response);
|
|
2099
1945
|
} else {
|
|
2100
1946
|
this.state.resolveInteraction(response);
|
|
2101
1947
|
}
|
|
@@ -2108,8 +1954,8 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2108
1954
|
}
|
|
2109
1955
|
return response;
|
|
2110
1956
|
} catch (err) {
|
|
2111
|
-
if (this.currentInvestigationSource
|
|
2112
|
-
this.state.
|
|
1957
|
+
if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
|
|
1958
|
+
this.state.clearBackgroundPendingInteraction(this.currentBackgroundId);
|
|
2113
1959
|
} else {
|
|
2114
1960
|
this.state.clearPendingInteraction();
|
|
2115
1961
|
}
|
|
@@ -2181,58 +2027,100 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2181
2027
|
new PRBEClosureTool(name, description, parameters, handler, options)
|
|
2182
2028
|
);
|
|
2183
2029
|
}
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
this.currentInvestigationSource = "user" /* USER */;
|
|
2190
|
-
this.currentCRId = null;
|
|
2191
|
-
this.state.beginInvestigation(query);
|
|
2030
|
+
// ---------- Unified Investigation ----------
|
|
2031
|
+
async runInvestigation(opts) {
|
|
2032
|
+
this.currentInvestigationSource = opts.source;
|
|
2033
|
+
this.currentBackgroundId = opts.sourceId ?? null;
|
|
2034
|
+
const isBackground = opts.source !== "user" /* USER */;
|
|
2192
2035
|
const emitter = (status) => {
|
|
2193
2036
|
switch (status.type) {
|
|
2194
2037
|
case "started" /* STARTED */:
|
|
2195
|
-
|
|
2038
|
+
if (isBackground && opts.sourceId) {
|
|
2039
|
+
this.state.appendBackgroundEvent(opts.sourceId, "Starting investigation...");
|
|
2040
|
+
} else {
|
|
2041
|
+
this.state.appendEvent("Starting investigation...");
|
|
2042
|
+
}
|
|
2196
2043
|
break;
|
|
2197
2044
|
case "thinking" /* THINKING */:
|
|
2198
2045
|
break;
|
|
2199
2046
|
case "tool_call" /* TOOL_CALL */:
|
|
2200
|
-
|
|
2047
|
+
if (isBackground && opts.sourceId) {
|
|
2048
|
+
this.state.appendBackgroundEvent(opts.sourceId, status.label);
|
|
2049
|
+
} else {
|
|
2050
|
+
this.state.appendEvent(status.label);
|
|
2051
|
+
}
|
|
2201
2052
|
break;
|
|
2202
2053
|
case "observation" /* OBSERVATION */:
|
|
2203
|
-
|
|
2054
|
+
if (isBackground && opts.sourceId) {
|
|
2055
|
+
this.state.attachBackgroundObservation(opts.sourceId, status.text);
|
|
2056
|
+
} else {
|
|
2057
|
+
this.state.attachObservation(status.text);
|
|
2058
|
+
}
|
|
2204
2059
|
break;
|
|
2205
2060
|
case "thought" /* THOUGHT */:
|
|
2206
|
-
|
|
2061
|
+
if (isBackground && opts.sourceId) {
|
|
2062
|
+
this.state.appendBackgroundEvent(opts.sourceId, "Thinking", status.text);
|
|
2063
|
+
} else {
|
|
2064
|
+
this.state.appendEvent("Thinking", status.text);
|
|
2065
|
+
}
|
|
2207
2066
|
break;
|
|
2208
2067
|
case "completed" /* COMPLETED */:
|
|
2209
|
-
|
|
2210
|
-
|
|
2068
|
+
if (isBackground && opts.sourceId) {
|
|
2069
|
+
this.state.completeBackgroundInvestigation(opts.sourceId, status.report);
|
|
2070
|
+
} else {
|
|
2071
|
+
this.state.completeInvestigation(status.report, status.ticketId);
|
|
2072
|
+
}
|
|
2211
2073
|
break;
|
|
2212
2074
|
case "error" /* ERROR */:
|
|
2213
|
-
|
|
2075
|
+
if (isBackground && opts.sourceId) {
|
|
2076
|
+
this.state.failBackgroundInvestigation(opts.sourceId, status.message);
|
|
2077
|
+
} else {
|
|
2078
|
+
this.state.failInvestigation(status.message);
|
|
2079
|
+
}
|
|
2080
|
+
break;
|
|
2081
|
+
case "privacy_sanitizing" /* PRIVACY_SANITIZING */:
|
|
2082
|
+
if (isBackground && opts.sourceId) {
|
|
2083
|
+
this.state.appendBackgroundEvent(opts.sourceId, "Sanitizing data for privacy review...");
|
|
2084
|
+
} else {
|
|
2085
|
+
this.state.appendEvent("Sanitizing data for privacy review...");
|
|
2086
|
+
}
|
|
2087
|
+
this.state.setPrivacySanitizing(true);
|
|
2214
2088
|
break;
|
|
2215
2089
|
}
|
|
2216
2090
|
};
|
|
2217
2091
|
const result = await this.connectToProxy(
|
|
2218
|
-
query,
|
|
2219
|
-
|
|
2092
|
+
opts.query,
|
|
2093
|
+
opts.contextRequestId,
|
|
2094
|
+
opts.externalRequestId,
|
|
2095
|
+
opts.externalRequestSource,
|
|
2096
|
+
opts.externalRequestSourceDetail,
|
|
2220
2097
|
emitter,
|
|
2221
|
-
() => this.userCancelled
|
|
2098
|
+
opts.cancellable ? () => this.userCancelled : () => false,
|
|
2099
|
+
opts.ticketId
|
|
2222
2100
|
);
|
|
2223
2101
|
this.currentInvestigationSource = "user" /* USER */;
|
|
2224
|
-
this.
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2102
|
+
this.currentBackgroundId = null;
|
|
2103
|
+
return result;
|
|
2104
|
+
}
|
|
2105
|
+
/**
|
|
2106
|
+
* User-initiated investigation. Updates `state` events/report directly.
|
|
2107
|
+
*/
|
|
2108
|
+
async investigate(query, contextRequestID) {
|
|
2109
|
+
this.userCancelled = false;
|
|
2110
|
+
this.state.beginInvestigation(query);
|
|
2111
|
+
const result = await this.runInvestigation({
|
|
2112
|
+
query,
|
|
2113
|
+
source: "user" /* USER */,
|
|
2114
|
+
contextRequestId: contextRequestID,
|
|
2115
|
+
cancellable: true
|
|
2116
|
+
});
|
|
2117
|
+
if (!result && this.state.isInvestigating) {
|
|
2118
|
+
const message = this.userCancelled ? "Investigation cancelled" : "Investigation ended unexpectedly";
|
|
2119
|
+
this.state.failInvestigation(message);
|
|
2232
2120
|
}
|
|
2233
2121
|
}
|
|
2234
2122
|
/**
|
|
2235
|
-
* Cancel user-initiated investigation only (does not cancel background
|
|
2123
|
+
* Cancel user-initiated investigation only (does not cancel background investigations).
|
|
2236
2124
|
*/
|
|
2237
2125
|
cancelInvestigation() {
|
|
2238
2126
|
this.userCancelled = true;
|
|
@@ -2254,41 +2142,21 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2254
2142
|
this.stopPolling();
|
|
2255
2143
|
}
|
|
2256
2144
|
/**
|
|
2257
|
-
* Poll the backend for context requests
|
|
2258
|
-
* Resolves session IDs → ticket IDs first, then polls with ticket IDs.
|
|
2145
|
+
* Poll the backend for context requests and external requests.
|
|
2259
2146
|
*/
|
|
2260
2147
|
async poll() {
|
|
2261
|
-
const sessionIDs = this.trackedSessionIDs;
|
|
2262
|
-
if (sessionIDs.length === 0) return null;
|
|
2263
2148
|
try {
|
|
2264
|
-
const
|
|
2265
|
-
const
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
);
|
|
2271
|
-
const survivingSessions = sessionIDs.filter(
|
|
2272
|
-
(id) => returnedSessionIDs.has(id) && !resolvedSessionIDs.has(id)
|
|
2273
|
-
);
|
|
2274
|
-
if (survivingSessions.length !== sessionIDs.length) {
|
|
2275
|
-
this.trackedSessionIDs = survivingSessions;
|
|
2149
|
+
const request = { agent_id: this.agentID };
|
|
2150
|
+
const response = await this.post("/api/agent/poll", request);
|
|
2151
|
+
for (const cr of response.context_requests) {
|
|
2152
|
+
if (!cr.is_active) continue;
|
|
2153
|
+
if (this.state.activeBackgroundInvestigations.has(cr.id)) continue;
|
|
2154
|
+
await this.investigateForCR(cr, cr.ticket_id);
|
|
2276
2155
|
}
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
ticket_ids: ticketIDs
|
|
2282
|
-
};
|
|
2283
|
-
const response = await this.post(
|
|
2284
|
-
"/api/agent/poll",
|
|
2285
|
-
request
|
|
2286
|
-
);
|
|
2287
|
-
for (const ticket of response.tickets) {
|
|
2288
|
-
for (const cr of ticket.context_requests) {
|
|
2289
|
-
if (!cr.is_active) continue;
|
|
2290
|
-
await this.investigateForCR(cr, ticket.ticket_id);
|
|
2291
|
-
}
|
|
2156
|
+
for (const er of response.external_requests) {
|
|
2157
|
+
if (!er.is_active) continue;
|
|
2158
|
+
if (this.state.activeBackgroundInvestigations.has(er.id)) continue;
|
|
2159
|
+
await this.investigateForER(er);
|
|
2292
2160
|
}
|
|
2293
2161
|
return response;
|
|
2294
2162
|
} catch {
|
|
@@ -2296,27 +2164,44 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2296
2164
|
}
|
|
2297
2165
|
}
|
|
2298
2166
|
/**
|
|
2299
|
-
* Fetch
|
|
2300
|
-
* Resolves session IDs → ticket IDs first, then fetches ticket info.
|
|
2167
|
+
* Fetch agent history (tickets + sessions) from the backend.
|
|
2301
2168
|
*/
|
|
2302
|
-
async
|
|
2303
|
-
const sessionIDs = this.trackedSessionIDs;
|
|
2304
|
-
if (sessionIDs.length === 0) return [];
|
|
2169
|
+
async fetchHistory() {
|
|
2305
2170
|
try {
|
|
2306
|
-
const resolved = await this.resolveSessions(sessionIDs);
|
|
2307
|
-
const ticketIDs = resolved.tickets.map((t) => t.ticket_id);
|
|
2308
|
-
if (ticketIDs.length === 0) return [];
|
|
2309
|
-
const request = { ticket_ids: ticketIDs };
|
|
2310
2171
|
const response = await this.post(
|
|
2311
|
-
"/api/agent/
|
|
2312
|
-
|
|
2172
|
+
"/api/agent/history",
|
|
2173
|
+
{ agent_id: this.agentID }
|
|
2313
2174
|
);
|
|
2314
|
-
this.state.
|
|
2315
|
-
return response
|
|
2175
|
+
this.state.updateAgentHistory(response.tickets);
|
|
2176
|
+
return response;
|
|
2316
2177
|
} catch {
|
|
2317
|
-
return
|
|
2178
|
+
return null;
|
|
2318
2179
|
}
|
|
2319
2180
|
}
|
|
2181
|
+
async fetchSanitizedFile(url) {
|
|
2182
|
+
const res = await fetch(url, {
|
|
2183
|
+
headers: { "X-API-Key": this.config.apiKey }
|
|
2184
|
+
});
|
|
2185
|
+
if (!res.ok) throw new Error(`Failed to fetch sanitized file: ${res.status}`);
|
|
2186
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
2187
|
+
if (!_PRBEAgent.isTextContent(buffer)) {
|
|
2188
|
+
return { isText: false, url };
|
|
2189
|
+
}
|
|
2190
|
+
return { isText: true, content: buffer.toString("utf-8"), url };
|
|
2191
|
+
}
|
|
2192
|
+
/**
|
|
2193
|
+
* Detect whether a buffer contains text by checking for null bytes
|
|
2194
|
+
* and verifying the content is valid UTF-8.
|
|
2195
|
+
*/
|
|
2196
|
+
static isTextContent(buffer) {
|
|
2197
|
+
const checkLength = Math.min(buffer.length, 8192);
|
|
2198
|
+
for (let i = 0; i < checkLength; i++) {
|
|
2199
|
+
if (buffer[i] === 0) return false;
|
|
2200
|
+
}
|
|
2201
|
+
const decoded = buffer.toString("utf-8");
|
|
2202
|
+
const reEncoded = Buffer.from(decoded, "utf-8");
|
|
2203
|
+
return buffer.length === reEncoded.length;
|
|
2204
|
+
}
|
|
2320
2205
|
stopPolling() {
|
|
2321
2206
|
if (this.pollingTimer !== null) {
|
|
2322
2207
|
clearInterval(this.pollingTimer);
|
|
@@ -2324,7 +2209,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2324
2209
|
}
|
|
2325
2210
|
}
|
|
2326
2211
|
resumePolling() {
|
|
2327
|
-
if (this.
|
|
2212
|
+
if (!this.config.backgroundPolling) return;
|
|
2328
2213
|
this.startPolling();
|
|
2329
2214
|
}
|
|
2330
2215
|
/**
|
|
@@ -2342,13 +2227,11 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2342
2227
|
this.stopPolling();
|
|
2343
2228
|
this.persistedData = {};
|
|
2344
2229
|
savePersistedData(this.persistedData);
|
|
2345
|
-
HistoryStore.clear();
|
|
2346
2230
|
this.state.resetInvestigation();
|
|
2347
2231
|
this.state.completedInvestigations = [];
|
|
2348
|
-
this.state.
|
|
2349
|
-
this.state.
|
|
2350
|
-
this.state.
|
|
2351
|
-
this.state.ticketInfo = [];
|
|
2232
|
+
this.state.activeBackgroundInvestigations.clear();
|
|
2233
|
+
this.state.completedBackgroundInvestigations = [];
|
|
2234
|
+
this.state.agentHistory = [];
|
|
2352
2235
|
this.state.emit("status" /* STATUS */);
|
|
2353
2236
|
}
|
|
2354
2237
|
/**
|
|
@@ -2357,61 +2240,38 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2357
2240
|
static clearPersistedData() {
|
|
2358
2241
|
try {
|
|
2359
2242
|
const filePath = getPersistencePath();
|
|
2360
|
-
if (
|
|
2361
|
-
|
|
2243
|
+
if (fs2.existsSync(filePath)) {
|
|
2244
|
+
fs2.unlinkSync(filePath);
|
|
2362
2245
|
}
|
|
2363
|
-
HistoryStore.clear();
|
|
2364
2246
|
} catch {
|
|
2365
2247
|
}
|
|
2366
2248
|
}
|
|
2367
|
-
// ----------
|
|
2249
|
+
// ---------- Background Investigation ----------
|
|
2368
2250
|
async investigateForCR(cr, ticketId) {
|
|
2369
|
-
|
|
2370
|
-
this.
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
this.state.completeCR(crID, status.report);
|
|
2391
|
-
this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
|
|
2392
|
-
break;
|
|
2393
|
-
case "error" /* ERROR */:
|
|
2394
|
-
this.state.failCR(crID, status.message);
|
|
2395
|
-
this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
|
|
2396
|
-
break;
|
|
2397
|
-
}
|
|
2398
|
-
};
|
|
2399
|
-
const result = await this.connectToProxy(
|
|
2400
|
-
cr.query,
|
|
2401
|
-
crID,
|
|
2402
|
-
emitter,
|
|
2403
|
-
() => false,
|
|
2404
|
-
// CRs are not user-cancellable
|
|
2405
|
-
ticketId
|
|
2406
|
-
);
|
|
2407
|
-
this.currentInvestigationSource = "user" /* USER */;
|
|
2408
|
-
this.currentCRId = null;
|
|
2409
|
-
if (result?.sessionId) {
|
|
2410
|
-
this.addTrackedSession(result.sessionId);
|
|
2411
|
-
}
|
|
2251
|
+
this.state.beginBackgroundInvestigation(cr.id, cr.query, cr.slug ?? void 0, ticketId);
|
|
2252
|
+
await this.runInvestigation({
|
|
2253
|
+
query: cr.query,
|
|
2254
|
+
source: "context_request" /* CONTEXT_REQUEST */,
|
|
2255
|
+
sourceId: cr.id,
|
|
2256
|
+
contextRequestId: cr.id,
|
|
2257
|
+
ticketId,
|
|
2258
|
+
cancellable: false
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
async investigateForER(er) {
|
|
2262
|
+
this.state.beginBackgroundInvestigation(er.id, er.query, void 0, void 0, er.source, er.source_detail);
|
|
2263
|
+
await this.runInvestigation({
|
|
2264
|
+
query: er.query,
|
|
2265
|
+
source: "external_request" /* EXTERNAL_REQUEST */,
|
|
2266
|
+
sourceId: er.id,
|
|
2267
|
+
externalRequestId: er.id,
|
|
2268
|
+
externalRequestSource: er.source,
|
|
2269
|
+
externalRequestSourceDetail: er.source_detail,
|
|
2270
|
+
cancellable: false
|
|
2271
|
+
});
|
|
2412
2272
|
}
|
|
2413
2273
|
// ---------- WebSocket Investigation ----------
|
|
2414
|
-
connectToProxy(query, contextRequestID, emit, isCancelled, ticketId) {
|
|
2274
|
+
connectToProxy(query, contextRequestID, externalRequestId, externalRequestSource, externalRequestSourceDetail, emit, isCancelled, ticketId) {
|
|
2415
2275
|
return new Promise((resolve2) => {
|
|
2416
2276
|
const wsUrl = `${MIDDLEWARE_URL}/api/agent/client/ws`;
|
|
2417
2277
|
let uploadBaseUrl;
|
|
@@ -2431,8 +2291,8 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2431
2291
|
uploadBaseUrl = url;
|
|
2432
2292
|
}),
|
|
2433
2293
|
(message) => {
|
|
2434
|
-
if (!isCancelled()) emit({ type: "error" /* ERROR */, message });
|
|
2435
|
-
finish(null);
|
|
2294
|
+
if (!resolved && !isCancelled()) emit({ type: "error" /* ERROR */, message });
|
|
2295
|
+
if (!resolved) finish(null);
|
|
2436
2296
|
},
|
|
2437
2297
|
() => {
|
|
2438
2298
|
if (!resolved) {
|
|
@@ -2466,11 +2326,14 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2466
2326
|
const startMetadata = {
|
|
2467
2327
|
agent_id: this.agentID,
|
|
2468
2328
|
custom_tools: toolDeclarations,
|
|
2469
|
-
platform:
|
|
2470
|
-
os_version:
|
|
2471
|
-
arch:
|
|
2329
|
+
platform: os.platform(),
|
|
2330
|
+
os_version: os.release(),
|
|
2331
|
+
arch: os.arch()
|
|
2472
2332
|
};
|
|
2473
2333
|
if (contextRequestID) startMetadata["context_request_id"] = contextRequestID;
|
|
2334
|
+
if (externalRequestId) startMetadata["external_request_id"] = externalRequestId;
|
|
2335
|
+
if (externalRequestSource) startMetadata["external_request_source"] = externalRequestSource;
|
|
2336
|
+
if (externalRequestSourceDetail) startMetadata["external_request_source_detail"] = externalRequestSourceDetail;
|
|
2474
2337
|
if (ticketId) startMetadata["ticket_id"] = ticketId;
|
|
2475
2338
|
if (this.appDataPath) startMetadata["app_data_path"] = this.appDataPath;
|
|
2476
2339
|
const enrichedMetadata = { ...this.sessionMetadata };
|
|
@@ -2518,7 +2381,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2518
2381
|
const uploadPrefix = this.extractUploadPrefix(uploadBaseUrl);
|
|
2519
2382
|
const uploadedRefs = [];
|
|
2520
2383
|
for (const file of this.pendingFlaggedFiles) {
|
|
2521
|
-
const filename =
|
|
2384
|
+
const filename = path4.basename(file.originalPath);
|
|
2522
2385
|
const safeName = encodeURIComponent(filename);
|
|
2523
2386
|
const storagePath = `${uploadPrefix}/${safeName}`;
|
|
2524
2387
|
uploadedRefs.push({
|
|
@@ -2563,8 +2426,47 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2563
2426
|
case "conversation_update" /* CONVERSATION_UPDATE */: {
|
|
2564
2427
|
try {
|
|
2565
2428
|
const entry = JSON.parse(msg.content ?? "{}");
|
|
2566
|
-
this.
|
|
2429
|
+
if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
|
|
2430
|
+
this.state.appendBackgroundConversation(this.currentBackgroundId, entry);
|
|
2431
|
+
} else {
|
|
2432
|
+
this.state.appendConversation(entry);
|
|
2433
|
+
}
|
|
2434
|
+
} catch {
|
|
2435
|
+
}
|
|
2436
|
+
break;
|
|
2437
|
+
}
|
|
2438
|
+
case "privacy_sanitizing" /* PRIVACY_SANITIZING */: {
|
|
2439
|
+
emit({ type: "privacy_sanitizing" /* PRIVACY_SANITIZING */ });
|
|
2440
|
+
break;
|
|
2441
|
+
}
|
|
2442
|
+
case "privacy_review" /* PRIVACY_REVIEW */: {
|
|
2443
|
+
const sanitizedText = msg.content ?? "";
|
|
2444
|
+
const issues = msg.metadata?.issues ?? [];
|
|
2445
|
+
const files = msg.metadata?.files ?? [];
|
|
2446
|
+
const summary = msg.metadata?.summary ?? "";
|
|
2447
|
+
const payload = {
|
|
2448
|
+
type: "review_sanitized_output" /* REVIEW_SANITIZED_OUTPUT */,
|
|
2449
|
+
interactionId: randomUUID5(),
|
|
2450
|
+
sanitizedAnalysis: sanitizedText,
|
|
2451
|
+
files,
|
|
2452
|
+
summary,
|
|
2453
|
+
issues
|
|
2454
|
+
};
|
|
2455
|
+
try {
|
|
2456
|
+
const response = await this.requestUserInteraction(payload);
|
|
2457
|
+
const reviewResponse = response;
|
|
2458
|
+
conn.send({
|
|
2459
|
+
type: "privacy_review_response" /* PRIVACY_REVIEW_RESPONSE */,
|
|
2460
|
+
metadata: {
|
|
2461
|
+
approved: reviewResponse.approved,
|
|
2462
|
+
...reviewResponse.editedText ? { editedText: reviewResponse.editedText } : {}
|
|
2463
|
+
}
|
|
2464
|
+
});
|
|
2567
2465
|
} catch {
|
|
2466
|
+
conn.send({
|
|
2467
|
+
type: "privacy_review_response" /* PRIVACY_REVIEW_RESPONSE */,
|
|
2468
|
+
metadata: { approved: false }
|
|
2469
|
+
});
|
|
2568
2470
|
}
|
|
2569
2471
|
break;
|
|
2570
2472
|
}
|
|
@@ -2621,24 +2523,9 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2621
2523
|
startPolling() {
|
|
2622
2524
|
this.stopPolling();
|
|
2623
2525
|
this.pollingTimer = setInterval(() => {
|
|
2624
|
-
void this.poll()
|
|
2625
|
-
if (this.trackedSessionIDs.length === 0) {
|
|
2626
|
-
this.stopPolling();
|
|
2627
|
-
}
|
|
2628
|
-
});
|
|
2526
|
+
void this.poll();
|
|
2629
2527
|
}, this.config.pollingInterval);
|
|
2630
2528
|
}
|
|
2631
|
-
// ---------- Session Resolution ----------
|
|
2632
|
-
async resolveSessions(sessionIDs) {
|
|
2633
|
-
const request = {
|
|
2634
|
-
agent_id: this.agentID,
|
|
2635
|
-
session_ids: sessionIDs
|
|
2636
|
-
};
|
|
2637
|
-
return this.post(
|
|
2638
|
-
"/api/agent/resolve-sessions",
|
|
2639
|
-
request
|
|
2640
|
-
);
|
|
2641
|
-
}
|
|
2642
2529
|
// ---------- Networking ----------
|
|
2643
2530
|
/**
|
|
2644
2531
|
* Abort all in-flight fetch requests to prevent orphaned DNS lookups
|
|
@@ -2685,6 +2572,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2685
2572
|
// src/serialization.ts
|
|
2686
2573
|
var DEFAULT_PRBE_STATE = {
|
|
2687
2574
|
isInvestigating: false,
|
|
2575
|
+
isPrivacySanitizing: false,
|
|
2688
2576
|
events: [],
|
|
2689
2577
|
report: "",
|
|
2690
2578
|
summary: "",
|
|
@@ -2692,34 +2580,38 @@ var DEFAULT_PRBE_STATE = {
|
|
|
2692
2580
|
resolvedInteractions: [],
|
|
2693
2581
|
conversationHistory: [],
|
|
2694
2582
|
completedInvestigations: [],
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
trackedSessionIDs: [],
|
|
2583
|
+
activeBackgroundInvestigations: [],
|
|
2584
|
+
completedBackgroundInvestigations: [],
|
|
2698
2585
|
ticketInfo: [],
|
|
2586
|
+
agentHistory: [],
|
|
2699
2587
|
hasActiveWork: false
|
|
2700
2588
|
};
|
|
2701
|
-
function
|
|
2589
|
+
function serializeBackgroundInvestigation(bg) {
|
|
2702
2590
|
return {
|
|
2703
|
-
id:
|
|
2704
|
-
query:
|
|
2705
|
-
slug:
|
|
2706
|
-
ticketId:
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2591
|
+
id: bg.id,
|
|
2592
|
+
query: bg.query,
|
|
2593
|
+
slug: bg.slug,
|
|
2594
|
+
ticketId: bg.ticketId,
|
|
2595
|
+
source: bg.source,
|
|
2596
|
+
sourceDetail: bg.sourceDetail,
|
|
2597
|
+
events: bg.events,
|
|
2598
|
+
isRunning: bg.isRunning,
|
|
2599
|
+
isCompleted: bg.isCompleted,
|
|
2600
|
+
isFailed: bg.isFailed,
|
|
2601
|
+
report: bg.report,
|
|
2602
|
+
summary: bg.summary,
|
|
2603
|
+
errorMessage: bg.errorMessage,
|
|
2604
|
+
agentMessage: bg.agentMessage,
|
|
2605
|
+
startedAt: bg.startedAt.toISOString(),
|
|
2606
|
+
pendingInteraction: bg.pendingInteraction,
|
|
2607
|
+
resolvedInteractions: bg.resolvedInteractions ?? [],
|
|
2608
|
+
conversationHistory: bg.conversationHistory ?? []
|
|
2718
2609
|
};
|
|
2719
2610
|
}
|
|
2720
2611
|
function serializePRBEState(state) {
|
|
2721
2612
|
return {
|
|
2722
2613
|
isInvestigating: state.isInvestigating,
|
|
2614
|
+
isPrivacySanitizing: state.isPrivacySanitizing,
|
|
2723
2615
|
events: state.events,
|
|
2724
2616
|
report: state.report,
|
|
2725
2617
|
summary: state.summary,
|
|
@@ -2740,10 +2632,10 @@ function serializePRBEState(state) {
|
|
|
2740
2632
|
conversationHistory: inv.conversationHistory,
|
|
2741
2633
|
completedAt: inv.completedAt.toISOString()
|
|
2742
2634
|
})),
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
trackedSessionIDs: state.trackedSessionIDs,
|
|
2635
|
+
activeBackgroundInvestigations: Array.from(state.activeBackgroundInvestigations.values()).map(serializeBackgroundInvestigation),
|
|
2636
|
+
completedBackgroundInvestigations: state.completedBackgroundInvestigations.map(serializeBackgroundInvestigation),
|
|
2746
2637
|
ticketInfo: state.ticketInfo,
|
|
2638
|
+
agentHistory: state.agentHistory,
|
|
2747
2639
|
hasActiveWork: state.hasActiveWork
|
|
2748
2640
|
};
|
|
2749
2641
|
}
|