@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.js
CHANGED
|
@@ -72,12 +72,12 @@ __export(src_exports, {
|
|
|
72
72
|
module.exports = __toCommonJS(src_exports);
|
|
73
73
|
|
|
74
74
|
// package.json
|
|
75
|
-
var version = "0.1.
|
|
75
|
+
var version = "0.1.19";
|
|
76
76
|
|
|
77
77
|
// src/agent.ts
|
|
78
|
-
var
|
|
79
|
-
var
|
|
80
|
-
var
|
|
78
|
+
var fs2 = __toESM(require("fs"));
|
|
79
|
+
var path4 = __toESM(require("path"));
|
|
80
|
+
var os = __toESM(require("os"));
|
|
81
81
|
var import_crypto5 = require("crypto");
|
|
82
82
|
|
|
83
83
|
// src/models.ts
|
|
@@ -98,6 +98,9 @@ var WSMessageType = /* @__PURE__ */ ((WSMessageType2) => {
|
|
|
98
98
|
WSMessageType2["COMPLETE"] = "complete";
|
|
99
99
|
WSMessageType2["ERROR"] = "error";
|
|
100
100
|
WSMessageType2["PING"] = "ping";
|
|
101
|
+
WSMessageType2["PRIVACY_SANITIZING"] = "privacy_sanitizing";
|
|
102
|
+
WSMessageType2["PRIVACY_REVIEW"] = "privacy_review";
|
|
103
|
+
WSMessageType2["PRIVACY_REVIEW_RESPONSE"] = "privacy_review_response";
|
|
101
104
|
return WSMessageType2;
|
|
102
105
|
})(WSMessageType || {});
|
|
103
106
|
var ConversationRole = /* @__PURE__ */ ((ConversationRole3) => {
|
|
@@ -155,6 +158,7 @@ var PRBEAgentStatusType = /* @__PURE__ */ ((PRBEAgentStatusType2) => {
|
|
|
155
158
|
PRBEAgentStatusType2["COMPLETED"] = "completed";
|
|
156
159
|
PRBEAgentStatusType2["ERROR"] = "error";
|
|
157
160
|
PRBEAgentStatusType2["AWAITING_INTERACTION"] = "awaiting_interaction";
|
|
161
|
+
PRBEAgentStatusType2["PRIVACY_SANITIZING"] = "privacy_sanitizing";
|
|
158
162
|
return PRBEAgentStatusType2;
|
|
159
163
|
})(PRBEAgentStatusType || {});
|
|
160
164
|
var PRBEAgentErrorType = /* @__PURE__ */ ((PRBEAgentErrorType2) => {
|
|
@@ -220,10 +224,14 @@ var InvestigationConnection = class {
|
|
|
220
224
|
return false;
|
|
221
225
|
}
|
|
222
226
|
}
|
|
223
|
-
sendConversationMessage(content) {
|
|
227
|
+
sendConversationMessage(content, role, label) {
|
|
228
|
+
const metadata = {};
|
|
229
|
+
if (role) metadata["role"] = role;
|
|
230
|
+
if (label) metadata["label"] = label;
|
|
224
231
|
this.send({
|
|
225
232
|
type: "conversation_message" /* CONVERSATION_MESSAGE */,
|
|
226
|
-
content
|
|
233
|
+
content,
|
|
234
|
+
...Object.keys(metadata).length > 0 ? { metadata } : {}
|
|
227
235
|
});
|
|
228
236
|
}
|
|
229
237
|
sendToolResult(callId, toolName, result, metadata) {
|
|
@@ -265,8 +273,8 @@ var PRBEStateEvent = /* @__PURE__ */ ((PRBEStateEvent2) => {
|
|
|
265
273
|
PRBEStateEvent2["EVENT"] = "event";
|
|
266
274
|
PRBEStateEvent2["COMPLETE"] = "complete";
|
|
267
275
|
PRBEStateEvent2["ERROR"] = "error";
|
|
268
|
-
PRBEStateEvent2["
|
|
269
|
-
PRBEStateEvent2["
|
|
276
|
+
PRBEStateEvent2["BACKGROUND_START"] = "background-start";
|
|
277
|
+
PRBEStateEvent2["BACKGROUND_COMPLETE"] = "background-complete";
|
|
270
278
|
PRBEStateEvent2["TICKETS_CHANGED"] = "tickets-changed";
|
|
271
279
|
PRBEStateEvent2["TICKET_INFO"] = "ticket-info";
|
|
272
280
|
PRBEStateEvent2["INTERACTION_REQUESTED"] = "interaction-requested";
|
|
@@ -286,20 +294,23 @@ var PRBEAgentState = class extends import_events.EventEmitter {
|
|
|
286
294
|
resolvedInteractions = [];
|
|
287
295
|
agentMessage;
|
|
288
296
|
conversationHistory = [];
|
|
297
|
+
isPrivacySanitizing = false;
|
|
289
298
|
// Completed user investigations (history)
|
|
290
299
|
completedInvestigations = [];
|
|
291
|
-
// Background context requests
|
|
292
|
-
|
|
293
|
-
|
|
300
|
+
// Background investigations (context requests, external requests, etc.)
|
|
301
|
+
activeBackgroundInvestigations = /* @__PURE__ */ new Map();
|
|
302
|
+
completedBackgroundInvestigations = [];
|
|
294
303
|
// Tracked tickets
|
|
295
304
|
trackedSessionIDs = [];
|
|
296
305
|
ticketInfo = [];
|
|
306
|
+
// Agent history
|
|
307
|
+
agentHistory = [];
|
|
297
308
|
// Computed
|
|
298
309
|
get hasActiveWork() {
|
|
299
|
-
return this.isInvestigating || this.
|
|
310
|
+
return this.isInvestigating || this.activeBackgroundInvestigations.size > 0;
|
|
300
311
|
}
|
|
301
|
-
get
|
|
302
|
-
return this.
|
|
312
|
+
get activeBackgroundCount() {
|
|
313
|
+
return this.activeBackgroundInvestigations.size;
|
|
303
314
|
}
|
|
304
315
|
get isActive() {
|
|
305
316
|
return this.isInvestigating || this.report.length > 0 || this.investigationError != null;
|
|
@@ -321,6 +332,12 @@ var PRBEAgentState = class extends import_events.EventEmitter {
|
|
|
321
332
|
this.conversationHistory.push(entry);
|
|
322
333
|
this.emit("status" /* STATUS */);
|
|
323
334
|
}
|
|
335
|
+
appendBackgroundConversation(backgroundId, entry) {
|
|
336
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
337
|
+
if (!bg) return;
|
|
338
|
+
bg.conversationHistory.push(entry);
|
|
339
|
+
this.emit("status" /* STATUS */);
|
|
340
|
+
}
|
|
324
341
|
resetInvestigation() {
|
|
325
342
|
this.isInvestigating = false;
|
|
326
343
|
this.events = [];
|
|
@@ -375,6 +392,7 @@ var PRBEAgentState = class extends import_events.EventEmitter {
|
|
|
375
392
|
});
|
|
376
393
|
this.report = report;
|
|
377
394
|
this.isInvestigating = false;
|
|
395
|
+
this.isPrivacySanitizing = false;
|
|
378
396
|
this.emit("complete" /* COMPLETE */, { report });
|
|
379
397
|
this.emit("status" /* STATUS */);
|
|
380
398
|
}
|
|
@@ -382,9 +400,14 @@ var PRBEAgentState = class extends import_events.EventEmitter {
|
|
|
382
400
|
this.appendEvent(`Error: ${message}`);
|
|
383
401
|
this.investigationError = message;
|
|
384
402
|
this.isInvestigating = false;
|
|
403
|
+
this.isPrivacySanitizing = false;
|
|
385
404
|
this.emit("error" /* ERROR */, { message });
|
|
386
405
|
this.emit("status" /* STATUS */);
|
|
387
406
|
}
|
|
407
|
+
setPrivacySanitizing(value) {
|
|
408
|
+
this.isPrivacySanitizing = value;
|
|
409
|
+
this.emit("status" /* STATUS */);
|
|
410
|
+
}
|
|
388
411
|
// ---------- Interaction state mutations ----------
|
|
389
412
|
setPendingInteraction(payload) {
|
|
390
413
|
this.pendingInteraction = payload;
|
|
@@ -396,17 +419,17 @@ var PRBEAgentState = class extends import_events.EventEmitter {
|
|
|
396
419
|
this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
|
|
397
420
|
this.emit("status" /* STATUS */);
|
|
398
421
|
}
|
|
399
|
-
|
|
400
|
-
const
|
|
401
|
-
if (!
|
|
402
|
-
|
|
422
|
+
setBackgroundPendingInteraction(backgroundId, payload) {
|
|
423
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
424
|
+
if (!bg) return;
|
|
425
|
+
bg.pendingInteraction = payload;
|
|
403
426
|
this.emit("interaction-requested" /* INTERACTION_REQUESTED */, payload);
|
|
404
427
|
this.emit("status" /* STATUS */);
|
|
405
428
|
}
|
|
406
|
-
|
|
407
|
-
const
|
|
408
|
-
if (!
|
|
409
|
-
|
|
429
|
+
clearBackgroundPendingInteraction(backgroundId) {
|
|
430
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
431
|
+
if (!bg) return;
|
|
432
|
+
bg.pendingInteraction = void 0;
|
|
410
433
|
this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
|
|
411
434
|
this.emit("status" /* STATUS */);
|
|
412
435
|
}
|
|
@@ -422,18 +445,18 @@ var PRBEAgentState = class extends import_events.EventEmitter {
|
|
|
422
445
|
this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
|
|
423
446
|
this.emit("status" /* STATUS */);
|
|
424
447
|
}
|
|
425
|
-
|
|
426
|
-
const
|
|
427
|
-
if (!
|
|
428
|
-
const resolved =
|
|
448
|
+
resolveBackgroundInteraction(backgroundId, response) {
|
|
449
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
450
|
+
if (!bg || !bg.pendingInteraction) return;
|
|
451
|
+
const resolved = bg.resolvedInteractions ?? [];
|
|
429
452
|
resolved.push({
|
|
430
|
-
interactionId:
|
|
431
|
-
payload:
|
|
453
|
+
interactionId: bg.pendingInteraction.interactionId,
|
|
454
|
+
payload: bg.pendingInteraction,
|
|
432
455
|
response,
|
|
433
|
-
eventIndex:
|
|
456
|
+
eventIndex: bg.events.length
|
|
434
457
|
});
|
|
435
|
-
|
|
436
|
-
|
|
458
|
+
bg.resolvedInteractions = resolved;
|
|
459
|
+
bg.pendingInteraction = void 0;
|
|
437
460
|
this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
|
|
438
461
|
this.emit("status" /* STATUS */);
|
|
439
462
|
}
|
|
@@ -442,10 +465,10 @@ var PRBEAgentState = class extends import_events.EventEmitter {
|
|
|
442
465
|
this.emit("agent-message" /* AGENT_MESSAGE */, { message });
|
|
443
466
|
this.emit("status" /* STATUS */);
|
|
444
467
|
}
|
|
445
|
-
|
|
446
|
-
const
|
|
447
|
-
if (!
|
|
448
|
-
|
|
468
|
+
setBackgroundAgentMessage(backgroundId, message) {
|
|
469
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
470
|
+
if (!bg) return;
|
|
471
|
+
bg.agentMessage = message;
|
|
449
472
|
this.emit("agent-message" /* AGENT_MESSAGE */, { message });
|
|
450
473
|
this.emit("status" /* STATUS */);
|
|
451
474
|
}
|
|
@@ -456,14 +479,17 @@ var PRBEAgentState = class extends import_events.EventEmitter {
|
|
|
456
479
|
this.emit("status" /* STATUS */);
|
|
457
480
|
}
|
|
458
481
|
}
|
|
459
|
-
// ----------
|
|
460
|
-
|
|
461
|
-
const
|
|
482
|
+
// ---------- Background investigation state mutations ----------
|
|
483
|
+
beginBackgroundInvestigation(id, query, slug, ticketId, source, sourceDetail) {
|
|
484
|
+
const bg = {
|
|
462
485
|
id,
|
|
463
486
|
query,
|
|
464
487
|
slug,
|
|
465
488
|
ticketId,
|
|
489
|
+
source,
|
|
490
|
+
sourceDetail,
|
|
466
491
|
events: [],
|
|
492
|
+
conversationHistory: [],
|
|
467
493
|
resolvedInteractions: [],
|
|
468
494
|
isRunning: true,
|
|
469
495
|
isCompleted: false,
|
|
@@ -472,20 +498,20 @@ var PRBEAgentState = class extends import_events.EventEmitter {
|
|
|
472
498
|
summary: "",
|
|
473
499
|
startedAt: /* @__PURE__ */ new Date()
|
|
474
500
|
};
|
|
475
|
-
this.
|
|
476
|
-
this.emit("
|
|
501
|
+
this.activeBackgroundInvestigations.set(id, bg);
|
|
502
|
+
this.emit("background-start" /* BACKGROUND_START */, bg);
|
|
477
503
|
this.emit("status" /* STATUS */);
|
|
478
504
|
}
|
|
479
|
-
|
|
480
|
-
const
|
|
481
|
-
if (!
|
|
482
|
-
if (
|
|
483
|
-
const last =
|
|
505
|
+
appendBackgroundEvent(backgroundId, label, detail, completed = false) {
|
|
506
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
507
|
+
if (!bg) return;
|
|
508
|
+
if (bg.events.length > 0) {
|
|
509
|
+
const last = bg.events[bg.events.length - 1];
|
|
484
510
|
if (!last.isCompleted && !completed) {
|
|
485
511
|
last.isCompleted = true;
|
|
486
512
|
}
|
|
487
513
|
}
|
|
488
|
-
|
|
514
|
+
bg.events.push({
|
|
489
515
|
id: (0, import_crypto.randomUUID)(),
|
|
490
516
|
label,
|
|
491
517
|
detail,
|
|
@@ -494,47 +520,47 @@ var PRBEAgentState = class extends import_events.EventEmitter {
|
|
|
494
520
|
});
|
|
495
521
|
this.emit("status" /* STATUS */);
|
|
496
522
|
}
|
|
497
|
-
|
|
498
|
-
const
|
|
499
|
-
if (!
|
|
500
|
-
|
|
523
|
+
attachBackgroundObservation(backgroundId, text) {
|
|
524
|
+
const bg = this.activeBackgroundInvestigations.get(backgroundId);
|
|
525
|
+
if (!bg || bg.events.length === 0) return;
|
|
526
|
+
bg.events[bg.events.length - 1].detail = text;
|
|
501
527
|
this.emit("status" /* STATUS */);
|
|
502
528
|
}
|
|
503
|
-
|
|
504
|
-
const
|
|
505
|
-
if (!
|
|
506
|
-
this.
|
|
507
|
-
if (
|
|
508
|
-
|
|
529
|
+
completeBackgroundInvestigation(id, report) {
|
|
530
|
+
const bg = this.activeBackgroundInvestigations.get(id);
|
|
531
|
+
if (!bg) return;
|
|
532
|
+
this.activeBackgroundInvestigations.delete(id);
|
|
533
|
+
if (bg.events.length > 0) {
|
|
534
|
+
bg.events[bg.events.length - 1].isCompleted = true;
|
|
509
535
|
}
|
|
510
|
-
|
|
536
|
+
bg.events.push({
|
|
511
537
|
id: (0, import_crypto.randomUUID)(),
|
|
512
538
|
label: "Done",
|
|
513
539
|
isCompleted: true,
|
|
514
540
|
isExpanded: false
|
|
515
541
|
});
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
this.
|
|
520
|
-
this.emit("
|
|
542
|
+
bg.isRunning = false;
|
|
543
|
+
bg.isCompleted = true;
|
|
544
|
+
bg.report = report;
|
|
545
|
+
this.completedBackgroundInvestigations.unshift(bg);
|
|
546
|
+
this.emit("background-complete" /* BACKGROUND_COMPLETE */, bg);
|
|
521
547
|
this.emit("status" /* STATUS */);
|
|
522
548
|
}
|
|
523
|
-
|
|
524
|
-
const
|
|
525
|
-
if (!
|
|
526
|
-
this.
|
|
527
|
-
|
|
549
|
+
failBackgroundInvestigation(id, message) {
|
|
550
|
+
const bg = this.activeBackgroundInvestigations.get(id);
|
|
551
|
+
if (!bg) return;
|
|
552
|
+
this.activeBackgroundInvestigations.delete(id);
|
|
553
|
+
bg.events.push({
|
|
528
554
|
id: (0, import_crypto.randomUUID)(),
|
|
529
555
|
label: `Error: ${message}`,
|
|
530
556
|
isCompleted: false,
|
|
531
557
|
isExpanded: false
|
|
532
558
|
});
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
this.
|
|
537
|
-
this.emit("
|
|
559
|
+
bg.isRunning = false;
|
|
560
|
+
bg.isFailed = true;
|
|
561
|
+
bg.errorMessage = message;
|
|
562
|
+
this.completedBackgroundInvestigations.unshift(bg);
|
|
563
|
+
this.emit("background-complete" /* BACKGROUND_COMPLETE */, bg);
|
|
538
564
|
this.emit("status" /* STATUS */);
|
|
539
565
|
}
|
|
540
566
|
// ---------- Tickets ----------
|
|
@@ -548,6 +574,10 @@ var PRBEAgentState = class extends import_events.EventEmitter {
|
|
|
548
574
|
this.emit("ticket-info" /* TICKET_INFO */, info);
|
|
549
575
|
this.emit("status" /* STATUS */);
|
|
550
576
|
}
|
|
577
|
+
updateAgentHistory(tickets) {
|
|
578
|
+
this.agentHistory = tickets;
|
|
579
|
+
this.emit("status" /* STATUS */);
|
|
580
|
+
}
|
|
551
581
|
};
|
|
552
582
|
|
|
553
583
|
// src/tools/index.ts
|
|
@@ -558,11 +588,13 @@ var InteractionType = /* @__PURE__ */ ((InteractionType2) => {
|
|
|
558
588
|
InteractionType2["ASK_QUESTION"] = "ask_question";
|
|
559
589
|
InteractionType2["REQUEST_PERMISSION"] = "request_permission";
|
|
560
590
|
InteractionType2["REQUEST_PATH_ACCESS"] = "request_path_access";
|
|
591
|
+
InteractionType2["REVIEW_SANITIZED_OUTPUT"] = "review_sanitized_output";
|
|
561
592
|
return InteractionType2;
|
|
562
593
|
})(InteractionType || {});
|
|
563
594
|
var InvestigationSource = /* @__PURE__ */ ((InvestigationSource2) => {
|
|
564
595
|
InvestigationSource2["USER"] = "user";
|
|
565
596
|
InvestigationSource2["CONTEXT_REQUEST"] = "context_request";
|
|
597
|
+
InvestigationSource2["EXTERNAL_REQUEST"] = "external_request";
|
|
566
598
|
return InvestigationSource2;
|
|
567
599
|
})(InvestigationSource || {});
|
|
568
600
|
|
|
@@ -1470,7 +1502,8 @@ var AskUserTool = class {
|
|
|
1470
1502
|
const response = await this.requester.requestUserInteraction({
|
|
1471
1503
|
type: "ask_question" /* ASK_QUESTION */,
|
|
1472
1504
|
interactionId: (0, import_crypto3.randomUUID)(),
|
|
1473
|
-
question
|
|
1505
|
+
question,
|
|
1506
|
+
context: reason
|
|
1474
1507
|
});
|
|
1475
1508
|
const askResponse = response;
|
|
1476
1509
|
return askResponse.answer;
|
|
@@ -1680,6 +1713,10 @@ var BashExecuteTool = class {
|
|
|
1680
1713
|
return `Error: working directory '${cwdArg}' is outside auto-approved directories`;
|
|
1681
1714
|
}
|
|
1682
1715
|
cwd = resolved;
|
|
1716
|
+
} else if (this.autoApprovedDirs.length > 0) {
|
|
1717
|
+
cwd = this.autoApprovedDirs[0];
|
|
1718
|
+
} else {
|
|
1719
|
+
return "Error: no approved directories configured and no working directory specified";
|
|
1683
1720
|
}
|
|
1684
1721
|
const isSafe = this.isCommandSafe(command);
|
|
1685
1722
|
if (!isSafe) {
|
|
@@ -1770,197 +1807,20 @@ var BashExecuteTool = class {
|
|
|
1770
1807
|
}
|
|
1771
1808
|
};
|
|
1772
1809
|
|
|
1773
|
-
// src/
|
|
1774
|
-
|
|
1775
|
-
var path4 = __toESM(require("path"));
|
|
1776
|
-
var os = __toESM(require("os"));
|
|
1777
|
-
var crypto = __toESM(require("crypto"));
|
|
1778
|
-
var HKDF_SALT = Buffer.from("prbe-history-encryption-salt", "utf-8");
|
|
1779
|
-
var HKDF_INFO = Buffer.from("prbe-history-v1", "utf-8");
|
|
1780
|
-
function getAppDataDir() {
|
|
1810
|
+
// src/agent.ts
|
|
1811
|
+
function getPersistencePath() {
|
|
1781
1812
|
const appData = process.env["APPDATA"] || (process.platform === "darwin" ? path4.join(os.homedir(), "Library", "Application Support") : path4.join(os.homedir(), ".local", "share"));
|
|
1782
|
-
|
|
1783
|
-
}
|
|
1784
|
-
function getHistoryDir() {
|
|
1785
|
-
const dir = path4.join(getAppDataDir(), "history" /* HISTORY_DIR */);
|
|
1813
|
+
const dir = path4.join(appData, "prbe-agent");
|
|
1786
1814
|
if (!fs2.existsSync(dir)) {
|
|
1787
1815
|
fs2.mkdirSync(dir, { recursive: true });
|
|
1788
1816
|
}
|
|
1789
|
-
return dir;
|
|
1790
|
-
}
|
|
1791
|
-
function deriveKey(apiKey) {
|
|
1792
|
-
return Buffer.from(
|
|
1793
|
-
crypto.hkdfSync(
|
|
1794
|
-
"sha256",
|
|
1795
|
-
Buffer.from(apiKey, "utf-8"),
|
|
1796
|
-
HKDF_SALT,
|
|
1797
|
-
HKDF_INFO,
|
|
1798
|
-
32 /* KEY_LENGTH */
|
|
1799
|
-
)
|
|
1800
|
-
);
|
|
1801
|
-
}
|
|
1802
|
-
function encrypt(plaintext, key) {
|
|
1803
|
-
const iv = crypto.randomBytes(12 /* IV_LENGTH */);
|
|
1804
|
-
const cipher = crypto.createCipheriv(
|
|
1805
|
-
"aes-256-gcm" /* ALGORITHM */,
|
|
1806
|
-
key,
|
|
1807
|
-
iv,
|
|
1808
|
-
{ authTagLength: 16 /* AUTH_TAG_LENGTH */ }
|
|
1809
|
-
);
|
|
1810
|
-
const encrypted = Buffer.concat([cipher.update(plaintext, "utf-8"), cipher.final()]);
|
|
1811
|
-
const authTag = cipher.getAuthTag();
|
|
1812
|
-
return Buffer.concat([iv, authTag, encrypted]);
|
|
1813
|
-
}
|
|
1814
|
-
function decrypt(data, key) {
|
|
1815
|
-
const iv = data.subarray(0, 12 /* IV_LENGTH */);
|
|
1816
|
-
const authTag = data.subarray(
|
|
1817
|
-
12 /* IV_LENGTH */,
|
|
1818
|
-
12 /* IV_LENGTH */ + 16 /* AUTH_TAG_LENGTH */
|
|
1819
|
-
);
|
|
1820
|
-
const ciphertext = data.subarray(
|
|
1821
|
-
12 /* IV_LENGTH */ + 16 /* AUTH_TAG_LENGTH */
|
|
1822
|
-
);
|
|
1823
|
-
const decipher = crypto.createDecipheriv(
|
|
1824
|
-
"aes-256-gcm" /* ALGORITHM */,
|
|
1825
|
-
key,
|
|
1826
|
-
iv,
|
|
1827
|
-
{ authTagLength: 16 /* AUTH_TAG_LENGTH */ }
|
|
1828
|
-
);
|
|
1829
|
-
decipher.setAuthTag(authTag);
|
|
1830
|
-
return decipher.update(ciphertext) + decipher.final("utf-8");
|
|
1831
|
-
}
|
|
1832
|
-
var HistoryStore = class {
|
|
1833
|
-
key;
|
|
1834
|
-
constructor(apiKey) {
|
|
1835
|
-
this.key = deriveKey(apiKey);
|
|
1836
|
-
}
|
|
1837
|
-
load() {
|
|
1838
|
-
const investigations = [];
|
|
1839
|
-
const crs = [];
|
|
1840
|
-
try {
|
|
1841
|
-
const dir = getHistoryDir();
|
|
1842
|
-
let files;
|
|
1843
|
-
try {
|
|
1844
|
-
files = fs2.readdirSync(dir);
|
|
1845
|
-
} catch {
|
|
1846
|
-
return { investigations, crs };
|
|
1847
|
-
}
|
|
1848
|
-
for (const filename of files) {
|
|
1849
|
-
try {
|
|
1850
|
-
const filePath = path4.join(dir, filename);
|
|
1851
|
-
const raw = fs2.readFileSync(filePath);
|
|
1852
|
-
const json = decrypt(raw, this.key);
|
|
1853
|
-
if (filename.startsWith("inv-") && filename.endsWith(".json")) {
|
|
1854
|
-
const item = JSON.parse(json);
|
|
1855
|
-
investigations.push({
|
|
1856
|
-
...item,
|
|
1857
|
-
completedAt: new Date(item.completedAt)
|
|
1858
|
-
});
|
|
1859
|
-
} else if (filename.startsWith("cr-") && filename.endsWith(".json")) {
|
|
1860
|
-
const item = JSON.parse(json);
|
|
1861
|
-
crs.push({
|
|
1862
|
-
...item,
|
|
1863
|
-
startedAt: new Date(item.startedAt),
|
|
1864
|
-
resolvedInteractions: item.resolvedInteractions ?? []
|
|
1865
|
-
});
|
|
1866
|
-
}
|
|
1867
|
-
} catch {
|
|
1868
|
-
console.warn(`[PRBEAgent] Skipping unreadable history file: ${filename}`);
|
|
1869
|
-
}
|
|
1870
|
-
}
|
|
1871
|
-
} catch {
|
|
1872
|
-
}
|
|
1873
|
-
investigations.sort(
|
|
1874
|
-
(a, b) => b.completedAt.getTime() - a.completedAt.getTime()
|
|
1875
|
-
);
|
|
1876
|
-
crs.sort((a, b) => b.startedAt.getTime() - a.startedAt.getTime());
|
|
1877
|
-
return { investigations, crs };
|
|
1878
|
-
}
|
|
1879
|
-
save(investigations, crs) {
|
|
1880
|
-
try {
|
|
1881
|
-
const dir = getHistoryDir();
|
|
1882
|
-
const desiredFiles = /* @__PURE__ */ new Set();
|
|
1883
|
-
for (const inv of investigations) {
|
|
1884
|
-
const filename = `inv-${inv.id}.json`;
|
|
1885
|
-
desiredFiles.add(filename);
|
|
1886
|
-
const data = {
|
|
1887
|
-
id: inv.id,
|
|
1888
|
-
query: inv.query,
|
|
1889
|
-
report: inv.report,
|
|
1890
|
-
summary: inv.summary,
|
|
1891
|
-
ticketId: inv.ticketId,
|
|
1892
|
-
events: inv.events,
|
|
1893
|
-
resolvedInteractions: inv.resolvedInteractions,
|
|
1894
|
-
conversationHistory: inv.conversationHistory,
|
|
1895
|
-
completedAt: inv.completedAt.toISOString()
|
|
1896
|
-
};
|
|
1897
|
-
fs2.writeFileSync(
|
|
1898
|
-
path4.join(dir, filename),
|
|
1899
|
-
encrypt(JSON.stringify(data), this.key)
|
|
1900
|
-
);
|
|
1901
|
-
}
|
|
1902
|
-
for (const cr of crs) {
|
|
1903
|
-
const filename = `cr-${cr.id}.json`;
|
|
1904
|
-
desiredFiles.add(filename);
|
|
1905
|
-
const data = {
|
|
1906
|
-
id: cr.id,
|
|
1907
|
-
query: cr.query,
|
|
1908
|
-
slug: cr.slug,
|
|
1909
|
-
ticketId: cr.ticketId,
|
|
1910
|
-
events: cr.events,
|
|
1911
|
-
isRunning: cr.isRunning,
|
|
1912
|
-
isCompleted: cr.isCompleted,
|
|
1913
|
-
isFailed: cr.isFailed,
|
|
1914
|
-
report: cr.report,
|
|
1915
|
-
summary: cr.summary,
|
|
1916
|
-
errorMessage: cr.errorMessage,
|
|
1917
|
-
startedAt: cr.startedAt.toISOString(),
|
|
1918
|
-
pendingInteraction: cr.pendingInteraction,
|
|
1919
|
-
resolvedInteractions: cr.resolvedInteractions ?? []
|
|
1920
|
-
};
|
|
1921
|
-
fs2.writeFileSync(
|
|
1922
|
-
path4.join(dir, filename),
|
|
1923
|
-
encrypt(JSON.stringify(data), this.key)
|
|
1924
|
-
);
|
|
1925
|
-
}
|
|
1926
|
-
try {
|
|
1927
|
-
const existing = fs2.readdirSync(dir);
|
|
1928
|
-
for (const filename of existing) {
|
|
1929
|
-
if (!desiredFiles.has(filename)) {
|
|
1930
|
-
fs2.unlinkSync(path4.join(dir, filename));
|
|
1931
|
-
}
|
|
1932
|
-
}
|
|
1933
|
-
} catch {
|
|
1934
|
-
}
|
|
1935
|
-
} catch {
|
|
1936
|
-
console.error("[PRBEAgent] Failed to save investigation history");
|
|
1937
|
-
}
|
|
1938
|
-
}
|
|
1939
|
-
static clear() {
|
|
1940
|
-
try {
|
|
1941
|
-
const dir = path4.join(getAppDataDir(), "history" /* HISTORY_DIR */);
|
|
1942
|
-
if (fs2.existsSync(dir)) {
|
|
1943
|
-
fs2.rmSync(dir, { recursive: true, force: true });
|
|
1944
|
-
}
|
|
1945
|
-
} catch {
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
};
|
|
1949
|
-
|
|
1950
|
-
// src/agent.ts
|
|
1951
|
-
function getPersistencePath() {
|
|
1952
|
-
const appData = process.env["APPDATA"] || (process.platform === "darwin" ? path5.join(os2.homedir(), "Library", "Application Support") : path5.join(os2.homedir(), ".local", "share"));
|
|
1953
|
-
const dir = path5.join(appData, "prbe-agent");
|
|
1954
|
-
if (!fs3.existsSync(dir)) {
|
|
1955
|
-
fs3.mkdirSync(dir, { recursive: true });
|
|
1956
|
-
}
|
|
1957
|
-
return path5.join(dir, "agent-state.json");
|
|
1817
|
+
return path4.join(dir, "agent-state.json");
|
|
1958
1818
|
}
|
|
1959
1819
|
function loadPersistedData() {
|
|
1960
1820
|
try {
|
|
1961
1821
|
const filePath = getPersistencePath();
|
|
1962
|
-
if (
|
|
1963
|
-
const raw =
|
|
1822
|
+
if (fs2.existsSync(filePath)) {
|
|
1823
|
+
const raw = fs2.readFileSync(filePath, "utf-8");
|
|
1964
1824
|
return JSON.parse(raw);
|
|
1965
1825
|
}
|
|
1966
1826
|
} catch {
|
|
@@ -1970,7 +1830,7 @@ function loadPersistedData() {
|
|
|
1970
1830
|
function savePersistedData(data) {
|
|
1971
1831
|
try {
|
|
1972
1832
|
const filePath = getPersistencePath();
|
|
1973
|
-
|
|
1833
|
+
fs2.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
1974
1834
|
} catch {
|
|
1975
1835
|
console.error("[PRBEAgent] Failed to save persisted data");
|
|
1976
1836
|
}
|
|
@@ -1990,8 +1850,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
1990
1850
|
persistedData;
|
|
1991
1851
|
fetchAbortController = null;
|
|
1992
1852
|
currentInvestigationSource = "user" /* USER */;
|
|
1993
|
-
|
|
1994
|
-
historyStore;
|
|
1853
|
+
currentBackgroundId = null;
|
|
1995
1854
|
/** Files flagged during the current tool call — uploaded immediately after the tool returns. */
|
|
1996
1855
|
pendingFlaggedFiles = [];
|
|
1997
1856
|
// ---------- User Identifier ----------
|
|
@@ -2007,30 +1866,6 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2007
1866
|
savePersistedData(this.persistedData);
|
|
2008
1867
|
return newID;
|
|
2009
1868
|
}
|
|
2010
|
-
get trackedSessionIDs() {
|
|
2011
|
-
return this.persistedData.sessionIds ?? [];
|
|
2012
|
-
}
|
|
2013
|
-
set trackedSessionIDs(ids) {
|
|
2014
|
-
this.persistedData.sessionIds = ids;
|
|
2015
|
-
savePersistedData(this.persistedData);
|
|
2016
|
-
this.state.updateTrackedSessionIDs(ids);
|
|
2017
|
-
this.syncPolling(ids.length > 0);
|
|
2018
|
-
}
|
|
2019
|
-
syncPolling(hasSessions) {
|
|
2020
|
-
if (this.config.backgroundPolling && hasSessions) {
|
|
2021
|
-
if (this.pollingTimer === null) {
|
|
2022
|
-
this.startPolling();
|
|
2023
|
-
}
|
|
2024
|
-
} else if (!hasSessions) {
|
|
2025
|
-
this.stopPolling();
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
addTrackedSession(id) {
|
|
2029
|
-
const ids = this.trackedSessionIDs;
|
|
2030
|
-
if (!ids.includes(id)) {
|
|
2031
|
-
this.trackedSessionIDs = [...ids, id];
|
|
2032
|
-
}
|
|
2033
|
-
}
|
|
2034
1869
|
// ---------- Constructor ----------
|
|
2035
1870
|
constructor(config) {
|
|
2036
1871
|
this.config = {
|
|
@@ -2050,11 +1885,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2050
1885
|
this.state = new PRBEAgentState();
|
|
2051
1886
|
this.logCapture = new PRBELogCapture(this.config.maxLogEntries);
|
|
2052
1887
|
this.persistedData = loadPersistedData();
|
|
2053
|
-
this.historyStore = new HistoryStore(this.config.apiKey);
|
|
2054
1888
|
void this.agentID;
|
|
2055
|
-
const history = this.historyStore.load();
|
|
2056
|
-
this.state.completedInvestigations = history.investigations;
|
|
2057
|
-
this.state.completedCRs = history.crs;
|
|
2058
1889
|
const roots = this.config.autoApprovedDirs;
|
|
2059
1890
|
const requester = this.interactionHandler ? this : void 0;
|
|
2060
1891
|
const grantedPaths = this.grantedPaths;
|
|
@@ -2086,8 +1917,8 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2086
1917
|
[{ name: "message", type: "STRING" /* STRING */, description: "Message for the user", required: true }],
|
|
2087
1918
|
async (args) => {
|
|
2088
1919
|
const message = args["message"] ?? "";
|
|
2089
|
-
if (this.currentInvestigationSource
|
|
2090
|
-
this.state.
|
|
1920
|
+
if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
|
|
1921
|
+
this.state.setBackgroundAgentMessage(this.currentBackgroundId, message);
|
|
2091
1922
|
} else {
|
|
2092
1923
|
this.state.setAgentMessage(message);
|
|
2093
1924
|
}
|
|
@@ -2104,9 +1935,8 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2104
1935
|
if (config.ipcMain) {
|
|
2105
1936
|
this.hookRendererLogs(config.ipcMain, config.rendererLogChannel ?? "prbe-renderer-log");
|
|
2106
1937
|
}
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
this.trackedSessionIDs = existingSessions;
|
|
1938
|
+
if (this.config.backgroundPolling) {
|
|
1939
|
+
this.startPolling();
|
|
2110
1940
|
}
|
|
2111
1941
|
}
|
|
2112
1942
|
// ---------- Log integration ----------
|
|
@@ -2150,8 +1980,8 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2150
1980
|
get investigationSource() {
|
|
2151
1981
|
return this.currentInvestigationSource;
|
|
2152
1982
|
}
|
|
2153
|
-
sendConversationMessage(content) {
|
|
2154
|
-
this.activeConnection?.sendConversationMessage(content);
|
|
1983
|
+
sendConversationMessage(content, role, label) {
|
|
1984
|
+
this.activeConnection?.sendConversationMessage(content, role, label);
|
|
2155
1985
|
}
|
|
2156
1986
|
async requestUserInteraction(payload) {
|
|
2157
1987
|
if (!this.interactionHandler) {
|
|
@@ -2160,15 +1990,31 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2160
1990
|
"No interaction handler configured"
|
|
2161
1991
|
);
|
|
2162
1992
|
}
|
|
2163
|
-
if (
|
|
2164
|
-
|
|
1993
|
+
if (payload.type === "request_permission" /* REQUEST_PERMISSION */) {
|
|
1994
|
+
const p = payload;
|
|
1995
|
+
const content = p.reason ? `${p.command}
|
|
1996
|
+
|
|
1997
|
+
${p.reason}` : p.command;
|
|
1998
|
+
this.sendConversationMessage(content, "agent" /* Agent */, p.action);
|
|
1999
|
+
} else if (payload.type === "request_path_access" /* REQUEST_PATH_ACCESS */) {
|
|
2000
|
+
const p = payload;
|
|
2001
|
+
const content = p.reason ? `${p.path}
|
|
2002
|
+
|
|
2003
|
+
${p.reason}` : p.path;
|
|
2004
|
+
this.sendConversationMessage(content, "agent" /* Agent */, "Request path access");
|
|
2005
|
+
} else if (payload.type === "ask_question" /* ASK_QUESTION */) {
|
|
2006
|
+
const p = payload;
|
|
2007
|
+
this.sendConversationMessage(p.question, "agent" /* Agent */);
|
|
2008
|
+
}
|
|
2009
|
+
if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
|
|
2010
|
+
this.state.setBackgroundPendingInteraction(this.currentBackgroundId, payload);
|
|
2165
2011
|
} else {
|
|
2166
2012
|
this.state.setPendingInteraction(payload);
|
|
2167
2013
|
}
|
|
2168
2014
|
try {
|
|
2169
2015
|
const response = await this.interactionHandler.handleInteraction(payload);
|
|
2170
|
-
if (this.currentInvestigationSource
|
|
2171
|
-
this.state.
|
|
2016
|
+
if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
|
|
2017
|
+
this.state.resolveBackgroundInteraction(this.currentBackgroundId, response);
|
|
2172
2018
|
} else {
|
|
2173
2019
|
this.state.resolveInteraction(response);
|
|
2174
2020
|
}
|
|
@@ -2181,8 +2027,8 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2181
2027
|
}
|
|
2182
2028
|
return response;
|
|
2183
2029
|
} catch (err) {
|
|
2184
|
-
if (this.currentInvestigationSource
|
|
2185
|
-
this.state.
|
|
2030
|
+
if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
|
|
2031
|
+
this.state.clearBackgroundPendingInteraction(this.currentBackgroundId);
|
|
2186
2032
|
} else {
|
|
2187
2033
|
this.state.clearPendingInteraction();
|
|
2188
2034
|
}
|
|
@@ -2254,58 +2100,100 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2254
2100
|
new PRBEClosureTool(name, description, parameters, handler, options)
|
|
2255
2101
|
);
|
|
2256
2102
|
}
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
this.currentInvestigationSource = "user" /* USER */;
|
|
2263
|
-
this.currentCRId = null;
|
|
2264
|
-
this.state.beginInvestigation(query);
|
|
2103
|
+
// ---------- Unified Investigation ----------
|
|
2104
|
+
async runInvestigation(opts) {
|
|
2105
|
+
this.currentInvestigationSource = opts.source;
|
|
2106
|
+
this.currentBackgroundId = opts.sourceId ?? null;
|
|
2107
|
+
const isBackground = opts.source !== "user" /* USER */;
|
|
2265
2108
|
const emitter = (status) => {
|
|
2266
2109
|
switch (status.type) {
|
|
2267
2110
|
case "started" /* STARTED */:
|
|
2268
|
-
|
|
2111
|
+
if (isBackground && opts.sourceId) {
|
|
2112
|
+
this.state.appendBackgroundEvent(opts.sourceId, "Starting investigation...");
|
|
2113
|
+
} else {
|
|
2114
|
+
this.state.appendEvent("Starting investigation...");
|
|
2115
|
+
}
|
|
2269
2116
|
break;
|
|
2270
2117
|
case "thinking" /* THINKING */:
|
|
2271
2118
|
break;
|
|
2272
2119
|
case "tool_call" /* TOOL_CALL */:
|
|
2273
|
-
|
|
2120
|
+
if (isBackground && opts.sourceId) {
|
|
2121
|
+
this.state.appendBackgroundEvent(opts.sourceId, status.label);
|
|
2122
|
+
} else {
|
|
2123
|
+
this.state.appendEvent(status.label);
|
|
2124
|
+
}
|
|
2274
2125
|
break;
|
|
2275
2126
|
case "observation" /* OBSERVATION */:
|
|
2276
|
-
|
|
2127
|
+
if (isBackground && opts.sourceId) {
|
|
2128
|
+
this.state.attachBackgroundObservation(opts.sourceId, status.text);
|
|
2129
|
+
} else {
|
|
2130
|
+
this.state.attachObservation(status.text);
|
|
2131
|
+
}
|
|
2277
2132
|
break;
|
|
2278
2133
|
case "thought" /* THOUGHT */:
|
|
2279
|
-
|
|
2134
|
+
if (isBackground && opts.sourceId) {
|
|
2135
|
+
this.state.appendBackgroundEvent(opts.sourceId, "Thinking", status.text);
|
|
2136
|
+
} else {
|
|
2137
|
+
this.state.appendEvent("Thinking", status.text);
|
|
2138
|
+
}
|
|
2280
2139
|
break;
|
|
2281
2140
|
case "completed" /* COMPLETED */:
|
|
2282
|
-
|
|
2283
|
-
|
|
2141
|
+
if (isBackground && opts.sourceId) {
|
|
2142
|
+
this.state.completeBackgroundInvestigation(opts.sourceId, status.report);
|
|
2143
|
+
} else {
|
|
2144
|
+
this.state.completeInvestigation(status.report, status.ticketId);
|
|
2145
|
+
}
|
|
2284
2146
|
break;
|
|
2285
2147
|
case "error" /* ERROR */:
|
|
2286
|
-
|
|
2148
|
+
if (isBackground && opts.sourceId) {
|
|
2149
|
+
this.state.failBackgroundInvestigation(opts.sourceId, status.message);
|
|
2150
|
+
} else {
|
|
2151
|
+
this.state.failInvestigation(status.message);
|
|
2152
|
+
}
|
|
2153
|
+
break;
|
|
2154
|
+
case "privacy_sanitizing" /* PRIVACY_SANITIZING */:
|
|
2155
|
+
if (isBackground && opts.sourceId) {
|
|
2156
|
+
this.state.appendBackgroundEvent(opts.sourceId, "Sanitizing data for privacy review...");
|
|
2157
|
+
} else {
|
|
2158
|
+
this.state.appendEvent("Sanitizing data for privacy review...");
|
|
2159
|
+
}
|
|
2160
|
+
this.state.setPrivacySanitizing(true);
|
|
2287
2161
|
break;
|
|
2288
2162
|
}
|
|
2289
2163
|
};
|
|
2290
2164
|
const result = await this.connectToProxy(
|
|
2291
|
-
query,
|
|
2292
|
-
|
|
2165
|
+
opts.query,
|
|
2166
|
+
opts.contextRequestId,
|
|
2167
|
+
opts.externalRequestId,
|
|
2168
|
+
opts.externalRequestSource,
|
|
2169
|
+
opts.externalRequestSourceDetail,
|
|
2293
2170
|
emitter,
|
|
2294
|
-
() => this.userCancelled
|
|
2171
|
+
opts.cancellable ? () => this.userCancelled : () => false,
|
|
2172
|
+
opts.ticketId
|
|
2295
2173
|
);
|
|
2296
2174
|
this.currentInvestigationSource = "user" /* USER */;
|
|
2297
|
-
this.
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2175
|
+
this.currentBackgroundId = null;
|
|
2176
|
+
return result;
|
|
2177
|
+
}
|
|
2178
|
+
/**
|
|
2179
|
+
* User-initiated investigation. Updates `state` events/report directly.
|
|
2180
|
+
*/
|
|
2181
|
+
async investigate(query, contextRequestID) {
|
|
2182
|
+
this.userCancelled = false;
|
|
2183
|
+
this.state.beginInvestigation(query);
|
|
2184
|
+
const result = await this.runInvestigation({
|
|
2185
|
+
query,
|
|
2186
|
+
source: "user" /* USER */,
|
|
2187
|
+
contextRequestId: contextRequestID,
|
|
2188
|
+
cancellable: true
|
|
2189
|
+
});
|
|
2190
|
+
if (!result && this.state.isInvestigating) {
|
|
2191
|
+
const message = this.userCancelled ? "Investigation cancelled" : "Investigation ended unexpectedly";
|
|
2192
|
+
this.state.failInvestigation(message);
|
|
2305
2193
|
}
|
|
2306
2194
|
}
|
|
2307
2195
|
/**
|
|
2308
|
-
* Cancel user-initiated investigation only (does not cancel background
|
|
2196
|
+
* Cancel user-initiated investigation only (does not cancel background investigations).
|
|
2309
2197
|
*/
|
|
2310
2198
|
cancelInvestigation() {
|
|
2311
2199
|
this.userCancelled = true;
|
|
@@ -2327,41 +2215,21 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2327
2215
|
this.stopPolling();
|
|
2328
2216
|
}
|
|
2329
2217
|
/**
|
|
2330
|
-
* Poll the backend for context requests
|
|
2331
|
-
* Resolves session IDs → ticket IDs first, then polls with ticket IDs.
|
|
2218
|
+
* Poll the backend for context requests and external requests.
|
|
2332
2219
|
*/
|
|
2333
2220
|
async poll() {
|
|
2334
|
-
const sessionIDs = this.trackedSessionIDs;
|
|
2335
|
-
if (sessionIDs.length === 0) return null;
|
|
2336
2221
|
try {
|
|
2337
|
-
const
|
|
2338
|
-
const
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
);
|
|
2344
|
-
const survivingSessions = sessionIDs.filter(
|
|
2345
|
-
(id) => returnedSessionIDs.has(id) && !resolvedSessionIDs.has(id)
|
|
2346
|
-
);
|
|
2347
|
-
if (survivingSessions.length !== sessionIDs.length) {
|
|
2348
|
-
this.trackedSessionIDs = survivingSessions;
|
|
2222
|
+
const request = { agent_id: this.agentID };
|
|
2223
|
+
const response = await this.post("/api/agent/poll", request);
|
|
2224
|
+
for (const cr of response.context_requests) {
|
|
2225
|
+
if (!cr.is_active) continue;
|
|
2226
|
+
if (this.state.activeBackgroundInvestigations.has(cr.id)) continue;
|
|
2227
|
+
await this.investigateForCR(cr, cr.ticket_id);
|
|
2349
2228
|
}
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
ticket_ids: ticketIDs
|
|
2355
|
-
};
|
|
2356
|
-
const response = await this.post(
|
|
2357
|
-
"/api/agent/poll",
|
|
2358
|
-
request
|
|
2359
|
-
);
|
|
2360
|
-
for (const ticket of response.tickets) {
|
|
2361
|
-
for (const cr of ticket.context_requests) {
|
|
2362
|
-
if (!cr.is_active) continue;
|
|
2363
|
-
await this.investigateForCR(cr, ticket.ticket_id);
|
|
2364
|
-
}
|
|
2229
|
+
for (const er of response.external_requests) {
|
|
2230
|
+
if (!er.is_active) continue;
|
|
2231
|
+
if (this.state.activeBackgroundInvestigations.has(er.id)) continue;
|
|
2232
|
+
await this.investigateForER(er);
|
|
2365
2233
|
}
|
|
2366
2234
|
return response;
|
|
2367
2235
|
} catch {
|
|
@@ -2369,27 +2237,44 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2369
2237
|
}
|
|
2370
2238
|
}
|
|
2371
2239
|
/**
|
|
2372
|
-
* Fetch
|
|
2373
|
-
* Resolves session IDs → ticket IDs first, then fetches ticket info.
|
|
2240
|
+
* Fetch agent history (tickets + sessions) from the backend.
|
|
2374
2241
|
*/
|
|
2375
|
-
async
|
|
2376
|
-
const sessionIDs = this.trackedSessionIDs;
|
|
2377
|
-
if (sessionIDs.length === 0) return [];
|
|
2242
|
+
async fetchHistory() {
|
|
2378
2243
|
try {
|
|
2379
|
-
const resolved = await this.resolveSessions(sessionIDs);
|
|
2380
|
-
const ticketIDs = resolved.tickets.map((t) => t.ticket_id);
|
|
2381
|
-
if (ticketIDs.length === 0) return [];
|
|
2382
|
-
const request = { ticket_ids: ticketIDs };
|
|
2383
2244
|
const response = await this.post(
|
|
2384
|
-
"/api/agent/
|
|
2385
|
-
|
|
2245
|
+
"/api/agent/history",
|
|
2246
|
+
{ agent_id: this.agentID }
|
|
2386
2247
|
);
|
|
2387
|
-
this.state.
|
|
2388
|
-
return response
|
|
2248
|
+
this.state.updateAgentHistory(response.tickets);
|
|
2249
|
+
return response;
|
|
2389
2250
|
} catch {
|
|
2390
|
-
return
|
|
2251
|
+
return null;
|
|
2391
2252
|
}
|
|
2392
2253
|
}
|
|
2254
|
+
async fetchSanitizedFile(url) {
|
|
2255
|
+
const res = await fetch(url, {
|
|
2256
|
+
headers: { "X-API-Key": this.config.apiKey }
|
|
2257
|
+
});
|
|
2258
|
+
if (!res.ok) throw new Error(`Failed to fetch sanitized file: ${res.status}`);
|
|
2259
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
2260
|
+
if (!_PRBEAgent.isTextContent(buffer)) {
|
|
2261
|
+
return { isText: false, url };
|
|
2262
|
+
}
|
|
2263
|
+
return { isText: true, content: buffer.toString("utf-8"), url };
|
|
2264
|
+
}
|
|
2265
|
+
/**
|
|
2266
|
+
* Detect whether a buffer contains text by checking for null bytes
|
|
2267
|
+
* and verifying the content is valid UTF-8.
|
|
2268
|
+
*/
|
|
2269
|
+
static isTextContent(buffer) {
|
|
2270
|
+
const checkLength = Math.min(buffer.length, 8192);
|
|
2271
|
+
for (let i = 0; i < checkLength; i++) {
|
|
2272
|
+
if (buffer[i] === 0) return false;
|
|
2273
|
+
}
|
|
2274
|
+
const decoded = buffer.toString("utf-8");
|
|
2275
|
+
const reEncoded = Buffer.from(decoded, "utf-8");
|
|
2276
|
+
return buffer.length === reEncoded.length;
|
|
2277
|
+
}
|
|
2393
2278
|
stopPolling() {
|
|
2394
2279
|
if (this.pollingTimer !== null) {
|
|
2395
2280
|
clearInterval(this.pollingTimer);
|
|
@@ -2397,7 +2282,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2397
2282
|
}
|
|
2398
2283
|
}
|
|
2399
2284
|
resumePolling() {
|
|
2400
|
-
if (this.
|
|
2285
|
+
if (!this.config.backgroundPolling) return;
|
|
2401
2286
|
this.startPolling();
|
|
2402
2287
|
}
|
|
2403
2288
|
/**
|
|
@@ -2415,13 +2300,11 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2415
2300
|
this.stopPolling();
|
|
2416
2301
|
this.persistedData = {};
|
|
2417
2302
|
savePersistedData(this.persistedData);
|
|
2418
|
-
HistoryStore.clear();
|
|
2419
2303
|
this.state.resetInvestigation();
|
|
2420
2304
|
this.state.completedInvestigations = [];
|
|
2421
|
-
this.state.
|
|
2422
|
-
this.state.
|
|
2423
|
-
this.state.
|
|
2424
|
-
this.state.ticketInfo = [];
|
|
2305
|
+
this.state.activeBackgroundInvestigations.clear();
|
|
2306
|
+
this.state.completedBackgroundInvestigations = [];
|
|
2307
|
+
this.state.agentHistory = [];
|
|
2425
2308
|
this.state.emit("status" /* STATUS */);
|
|
2426
2309
|
}
|
|
2427
2310
|
/**
|
|
@@ -2430,61 +2313,38 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2430
2313
|
static clearPersistedData() {
|
|
2431
2314
|
try {
|
|
2432
2315
|
const filePath = getPersistencePath();
|
|
2433
|
-
if (
|
|
2434
|
-
|
|
2316
|
+
if (fs2.existsSync(filePath)) {
|
|
2317
|
+
fs2.unlinkSync(filePath);
|
|
2435
2318
|
}
|
|
2436
|
-
HistoryStore.clear();
|
|
2437
2319
|
} catch {
|
|
2438
2320
|
}
|
|
2439
2321
|
}
|
|
2440
|
-
// ----------
|
|
2322
|
+
// ---------- Background Investigation ----------
|
|
2441
2323
|
async investigateForCR(cr, ticketId) {
|
|
2442
|
-
|
|
2443
|
-
this.
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
this.state.completeCR(crID, status.report);
|
|
2464
|
-
this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
|
|
2465
|
-
break;
|
|
2466
|
-
case "error" /* ERROR */:
|
|
2467
|
-
this.state.failCR(crID, status.message);
|
|
2468
|
-
this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
|
|
2469
|
-
break;
|
|
2470
|
-
}
|
|
2471
|
-
};
|
|
2472
|
-
const result = await this.connectToProxy(
|
|
2473
|
-
cr.query,
|
|
2474
|
-
crID,
|
|
2475
|
-
emitter,
|
|
2476
|
-
() => false,
|
|
2477
|
-
// CRs are not user-cancellable
|
|
2478
|
-
ticketId
|
|
2479
|
-
);
|
|
2480
|
-
this.currentInvestigationSource = "user" /* USER */;
|
|
2481
|
-
this.currentCRId = null;
|
|
2482
|
-
if (result?.sessionId) {
|
|
2483
|
-
this.addTrackedSession(result.sessionId);
|
|
2484
|
-
}
|
|
2324
|
+
this.state.beginBackgroundInvestigation(cr.id, cr.query, cr.slug ?? void 0, ticketId);
|
|
2325
|
+
await this.runInvestigation({
|
|
2326
|
+
query: cr.query,
|
|
2327
|
+
source: "context_request" /* CONTEXT_REQUEST */,
|
|
2328
|
+
sourceId: cr.id,
|
|
2329
|
+
contextRequestId: cr.id,
|
|
2330
|
+
ticketId,
|
|
2331
|
+
cancellable: false
|
|
2332
|
+
});
|
|
2333
|
+
}
|
|
2334
|
+
async investigateForER(er) {
|
|
2335
|
+
this.state.beginBackgroundInvestigation(er.id, er.query, void 0, void 0, er.source, er.source_detail);
|
|
2336
|
+
await this.runInvestigation({
|
|
2337
|
+
query: er.query,
|
|
2338
|
+
source: "external_request" /* EXTERNAL_REQUEST */,
|
|
2339
|
+
sourceId: er.id,
|
|
2340
|
+
externalRequestId: er.id,
|
|
2341
|
+
externalRequestSource: er.source,
|
|
2342
|
+
externalRequestSourceDetail: er.source_detail,
|
|
2343
|
+
cancellable: false
|
|
2344
|
+
});
|
|
2485
2345
|
}
|
|
2486
2346
|
// ---------- WebSocket Investigation ----------
|
|
2487
|
-
connectToProxy(query, contextRequestID, emit, isCancelled, ticketId) {
|
|
2347
|
+
connectToProxy(query, contextRequestID, externalRequestId, externalRequestSource, externalRequestSourceDetail, emit, isCancelled, ticketId) {
|
|
2488
2348
|
return new Promise((resolve2) => {
|
|
2489
2349
|
const wsUrl = `${MIDDLEWARE_URL}/api/agent/client/ws`;
|
|
2490
2350
|
let uploadBaseUrl;
|
|
@@ -2504,8 +2364,8 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2504
2364
|
uploadBaseUrl = url;
|
|
2505
2365
|
}),
|
|
2506
2366
|
(message) => {
|
|
2507
|
-
if (!isCancelled()) emit({ type: "error" /* ERROR */, message });
|
|
2508
|
-
finish(null);
|
|
2367
|
+
if (!resolved && !isCancelled()) emit({ type: "error" /* ERROR */, message });
|
|
2368
|
+
if (!resolved) finish(null);
|
|
2509
2369
|
},
|
|
2510
2370
|
() => {
|
|
2511
2371
|
if (!resolved) {
|
|
@@ -2539,11 +2399,14 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2539
2399
|
const startMetadata = {
|
|
2540
2400
|
agent_id: this.agentID,
|
|
2541
2401
|
custom_tools: toolDeclarations,
|
|
2542
|
-
platform:
|
|
2543
|
-
os_version:
|
|
2544
|
-
arch:
|
|
2402
|
+
platform: os.platform(),
|
|
2403
|
+
os_version: os.release(),
|
|
2404
|
+
arch: os.arch()
|
|
2545
2405
|
};
|
|
2546
2406
|
if (contextRequestID) startMetadata["context_request_id"] = contextRequestID;
|
|
2407
|
+
if (externalRequestId) startMetadata["external_request_id"] = externalRequestId;
|
|
2408
|
+
if (externalRequestSource) startMetadata["external_request_source"] = externalRequestSource;
|
|
2409
|
+
if (externalRequestSourceDetail) startMetadata["external_request_source_detail"] = externalRequestSourceDetail;
|
|
2547
2410
|
if (ticketId) startMetadata["ticket_id"] = ticketId;
|
|
2548
2411
|
if (this.appDataPath) startMetadata["app_data_path"] = this.appDataPath;
|
|
2549
2412
|
const enrichedMetadata = { ...this.sessionMetadata };
|
|
@@ -2591,7 +2454,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2591
2454
|
const uploadPrefix = this.extractUploadPrefix(uploadBaseUrl);
|
|
2592
2455
|
const uploadedRefs = [];
|
|
2593
2456
|
for (const file of this.pendingFlaggedFiles) {
|
|
2594
|
-
const filename =
|
|
2457
|
+
const filename = path4.basename(file.originalPath);
|
|
2595
2458
|
const safeName = encodeURIComponent(filename);
|
|
2596
2459
|
const storagePath = `${uploadPrefix}/${safeName}`;
|
|
2597
2460
|
uploadedRefs.push({
|
|
@@ -2636,8 +2499,47 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2636
2499
|
case "conversation_update" /* CONVERSATION_UPDATE */: {
|
|
2637
2500
|
try {
|
|
2638
2501
|
const entry = JSON.parse(msg.content ?? "{}");
|
|
2639
|
-
this.
|
|
2502
|
+
if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
|
|
2503
|
+
this.state.appendBackgroundConversation(this.currentBackgroundId, entry);
|
|
2504
|
+
} else {
|
|
2505
|
+
this.state.appendConversation(entry);
|
|
2506
|
+
}
|
|
2507
|
+
} catch {
|
|
2508
|
+
}
|
|
2509
|
+
break;
|
|
2510
|
+
}
|
|
2511
|
+
case "privacy_sanitizing" /* PRIVACY_SANITIZING */: {
|
|
2512
|
+
emit({ type: "privacy_sanitizing" /* PRIVACY_SANITIZING */ });
|
|
2513
|
+
break;
|
|
2514
|
+
}
|
|
2515
|
+
case "privacy_review" /* PRIVACY_REVIEW */: {
|
|
2516
|
+
const sanitizedText = msg.content ?? "";
|
|
2517
|
+
const issues = msg.metadata?.issues ?? [];
|
|
2518
|
+
const files = msg.metadata?.files ?? [];
|
|
2519
|
+
const summary = msg.metadata?.summary ?? "";
|
|
2520
|
+
const payload = {
|
|
2521
|
+
type: "review_sanitized_output" /* REVIEW_SANITIZED_OUTPUT */,
|
|
2522
|
+
interactionId: (0, import_crypto5.randomUUID)(),
|
|
2523
|
+
sanitizedAnalysis: sanitizedText,
|
|
2524
|
+
files,
|
|
2525
|
+
summary,
|
|
2526
|
+
issues
|
|
2527
|
+
};
|
|
2528
|
+
try {
|
|
2529
|
+
const response = await this.requestUserInteraction(payload);
|
|
2530
|
+
const reviewResponse = response;
|
|
2531
|
+
conn.send({
|
|
2532
|
+
type: "privacy_review_response" /* PRIVACY_REVIEW_RESPONSE */,
|
|
2533
|
+
metadata: {
|
|
2534
|
+
approved: reviewResponse.approved,
|
|
2535
|
+
...reviewResponse.editedText ? { editedText: reviewResponse.editedText } : {}
|
|
2536
|
+
}
|
|
2537
|
+
});
|
|
2640
2538
|
} catch {
|
|
2539
|
+
conn.send({
|
|
2540
|
+
type: "privacy_review_response" /* PRIVACY_REVIEW_RESPONSE */,
|
|
2541
|
+
metadata: { approved: false }
|
|
2542
|
+
});
|
|
2641
2543
|
}
|
|
2642
2544
|
break;
|
|
2643
2545
|
}
|
|
@@ -2694,24 +2596,9 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2694
2596
|
startPolling() {
|
|
2695
2597
|
this.stopPolling();
|
|
2696
2598
|
this.pollingTimer = setInterval(() => {
|
|
2697
|
-
void this.poll()
|
|
2698
|
-
if (this.trackedSessionIDs.length === 0) {
|
|
2699
|
-
this.stopPolling();
|
|
2700
|
-
}
|
|
2701
|
-
});
|
|
2599
|
+
void this.poll();
|
|
2702
2600
|
}, this.config.pollingInterval);
|
|
2703
2601
|
}
|
|
2704
|
-
// ---------- Session Resolution ----------
|
|
2705
|
-
async resolveSessions(sessionIDs) {
|
|
2706
|
-
const request = {
|
|
2707
|
-
agent_id: this.agentID,
|
|
2708
|
-
session_ids: sessionIDs
|
|
2709
|
-
};
|
|
2710
|
-
return this.post(
|
|
2711
|
-
"/api/agent/resolve-sessions",
|
|
2712
|
-
request
|
|
2713
|
-
);
|
|
2714
|
-
}
|
|
2715
2602
|
// ---------- Networking ----------
|
|
2716
2603
|
/**
|
|
2717
2604
|
* Abort all in-flight fetch requests to prevent orphaned DNS lookups
|
|
@@ -2758,6 +2645,7 @@ var PRBEAgent = class _PRBEAgent {
|
|
|
2758
2645
|
// src/serialization.ts
|
|
2759
2646
|
var DEFAULT_PRBE_STATE = {
|
|
2760
2647
|
isInvestigating: false,
|
|
2648
|
+
isPrivacySanitizing: false,
|
|
2761
2649
|
events: [],
|
|
2762
2650
|
report: "",
|
|
2763
2651
|
summary: "",
|
|
@@ -2765,34 +2653,38 @@ var DEFAULT_PRBE_STATE = {
|
|
|
2765
2653
|
resolvedInteractions: [],
|
|
2766
2654
|
conversationHistory: [],
|
|
2767
2655
|
completedInvestigations: [],
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
trackedSessionIDs: [],
|
|
2656
|
+
activeBackgroundInvestigations: [],
|
|
2657
|
+
completedBackgroundInvestigations: [],
|
|
2771
2658
|
ticketInfo: [],
|
|
2659
|
+
agentHistory: [],
|
|
2772
2660
|
hasActiveWork: false
|
|
2773
2661
|
};
|
|
2774
|
-
function
|
|
2662
|
+
function serializeBackgroundInvestigation(bg) {
|
|
2775
2663
|
return {
|
|
2776
|
-
id:
|
|
2777
|
-
query:
|
|
2778
|
-
slug:
|
|
2779
|
-
ticketId:
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2664
|
+
id: bg.id,
|
|
2665
|
+
query: bg.query,
|
|
2666
|
+
slug: bg.slug,
|
|
2667
|
+
ticketId: bg.ticketId,
|
|
2668
|
+
source: bg.source,
|
|
2669
|
+
sourceDetail: bg.sourceDetail,
|
|
2670
|
+
events: bg.events,
|
|
2671
|
+
isRunning: bg.isRunning,
|
|
2672
|
+
isCompleted: bg.isCompleted,
|
|
2673
|
+
isFailed: bg.isFailed,
|
|
2674
|
+
report: bg.report,
|
|
2675
|
+
summary: bg.summary,
|
|
2676
|
+
errorMessage: bg.errorMessage,
|
|
2677
|
+
agentMessage: bg.agentMessage,
|
|
2678
|
+
startedAt: bg.startedAt.toISOString(),
|
|
2679
|
+
pendingInteraction: bg.pendingInteraction,
|
|
2680
|
+
resolvedInteractions: bg.resolvedInteractions ?? [],
|
|
2681
|
+
conversationHistory: bg.conversationHistory ?? []
|
|
2791
2682
|
};
|
|
2792
2683
|
}
|
|
2793
2684
|
function serializePRBEState(state) {
|
|
2794
2685
|
return {
|
|
2795
2686
|
isInvestigating: state.isInvestigating,
|
|
2687
|
+
isPrivacySanitizing: state.isPrivacySanitizing,
|
|
2796
2688
|
events: state.events,
|
|
2797
2689
|
report: state.report,
|
|
2798
2690
|
summary: state.summary,
|
|
@@ -2813,10 +2705,10 @@ function serializePRBEState(state) {
|
|
|
2813
2705
|
conversationHistory: inv.conversationHistory,
|
|
2814
2706
|
completedAt: inv.completedAt.toISOString()
|
|
2815
2707
|
})),
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
trackedSessionIDs: state.trackedSessionIDs,
|
|
2708
|
+
activeBackgroundInvestigations: Array.from(state.activeBackgroundInvestigations.values()).map(serializeBackgroundInvestigation),
|
|
2709
|
+
completedBackgroundInvestigations: state.completedBackgroundInvestigations.map(serializeBackgroundInvestigation),
|
|
2819
2710
|
ticketInfo: state.ticketInfo,
|
|
2711
|
+
agentHistory: state.agentHistory,
|
|
2820
2712
|
hasActiveWork: state.hasActiveWork
|
|
2821
2713
|
};
|
|
2822
2714
|
}
|