@prbe.ai/electron-sdk 0.1.17 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -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.17";
75
+ var version = "0.1.18";
76
76
 
77
77
  // src/agent.ts
78
- var fs3 = __toESM(require("fs"));
79
- var path5 = __toESM(require("path"));
80
- var os2 = __toESM(require("os"));
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
@@ -265,8 +265,8 @@ var PRBEStateEvent = /* @__PURE__ */ ((PRBEStateEvent2) => {
265
265
  PRBEStateEvent2["EVENT"] = "event";
266
266
  PRBEStateEvent2["COMPLETE"] = "complete";
267
267
  PRBEStateEvent2["ERROR"] = "error";
268
- PRBEStateEvent2["CR_START"] = "cr-start";
269
- PRBEStateEvent2["CR_COMPLETE"] = "cr-complete";
268
+ PRBEStateEvent2["BACKGROUND_START"] = "background-start";
269
+ PRBEStateEvent2["BACKGROUND_COMPLETE"] = "background-complete";
270
270
  PRBEStateEvent2["TICKETS_CHANGED"] = "tickets-changed";
271
271
  PRBEStateEvent2["TICKET_INFO"] = "ticket-info";
272
272
  PRBEStateEvent2["INTERACTION_REQUESTED"] = "interaction-requested";
@@ -288,18 +288,20 @@ var PRBEAgentState = class extends import_events.EventEmitter {
288
288
  conversationHistory = [];
289
289
  // Completed user investigations (history)
290
290
  completedInvestigations = [];
291
- // Background context requests
292
- activeCRs = /* @__PURE__ */ new Map();
293
- completedCRs = [];
291
+ // Background investigations (context requests, external requests, etc.)
292
+ activeBackgroundInvestigations = /* @__PURE__ */ new Map();
293
+ completedBackgroundInvestigations = [];
294
294
  // Tracked tickets
295
295
  trackedSessionIDs = [];
296
296
  ticketInfo = [];
297
+ // Agent history
298
+ agentHistory = [];
297
299
  // Computed
298
300
  get hasActiveWork() {
299
- return this.isInvestigating || this.activeCRs.size > 0;
301
+ return this.isInvestigating || this.activeBackgroundInvestigations.size > 0;
300
302
  }
301
- get activeCRCount() {
302
- return this.activeCRs.size;
303
+ get activeBackgroundCount() {
304
+ return this.activeBackgroundInvestigations.size;
303
305
  }
304
306
  get isActive() {
305
307
  return this.isInvestigating || this.report.length > 0 || this.investigationError != null;
@@ -321,6 +323,12 @@ var PRBEAgentState = class extends import_events.EventEmitter {
321
323
  this.conversationHistory.push(entry);
322
324
  this.emit("status" /* STATUS */);
323
325
  }
326
+ appendBackgroundConversation(backgroundId, entry) {
327
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
328
+ if (!bg) return;
329
+ bg.conversationHistory.push(entry);
330
+ this.emit("status" /* STATUS */);
331
+ }
324
332
  resetInvestigation() {
325
333
  this.isInvestigating = false;
326
334
  this.events = [];
@@ -396,17 +404,17 @@ var PRBEAgentState = class extends import_events.EventEmitter {
396
404
  this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
397
405
  this.emit("status" /* STATUS */);
398
406
  }
399
- setCRPendingInteraction(crID, payload) {
400
- const cr = this.activeCRs.get(crID);
401
- if (!cr) return;
402
- cr.pendingInteraction = payload;
407
+ setBackgroundPendingInteraction(backgroundId, payload) {
408
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
409
+ if (!bg) return;
410
+ bg.pendingInteraction = payload;
403
411
  this.emit("interaction-requested" /* INTERACTION_REQUESTED */, payload);
404
412
  this.emit("status" /* STATUS */);
405
413
  }
406
- clearCRPendingInteraction(crID) {
407
- const cr = this.activeCRs.get(crID);
408
- if (!cr) return;
409
- cr.pendingInteraction = void 0;
414
+ clearBackgroundPendingInteraction(backgroundId) {
415
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
416
+ if (!bg) return;
417
+ bg.pendingInteraction = void 0;
410
418
  this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
411
419
  this.emit("status" /* STATUS */);
412
420
  }
@@ -422,18 +430,18 @@ var PRBEAgentState = class extends import_events.EventEmitter {
422
430
  this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
423
431
  this.emit("status" /* STATUS */);
424
432
  }
425
- resolveCRInteraction(crID, response) {
426
- const cr = this.activeCRs.get(crID);
427
- if (!cr || !cr.pendingInteraction) return;
428
- const resolved = cr.resolvedInteractions ?? [];
433
+ resolveBackgroundInteraction(backgroundId, response) {
434
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
435
+ if (!bg || !bg.pendingInteraction) return;
436
+ const resolved = bg.resolvedInteractions ?? [];
429
437
  resolved.push({
430
- interactionId: cr.pendingInteraction.interactionId,
431
- payload: cr.pendingInteraction,
438
+ interactionId: bg.pendingInteraction.interactionId,
439
+ payload: bg.pendingInteraction,
432
440
  response,
433
- eventIndex: cr.events.length
441
+ eventIndex: bg.events.length
434
442
  });
435
- cr.resolvedInteractions = resolved;
436
- cr.pendingInteraction = void 0;
443
+ bg.resolvedInteractions = resolved;
444
+ bg.pendingInteraction = void 0;
437
445
  this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
438
446
  this.emit("status" /* STATUS */);
439
447
  }
@@ -442,10 +450,10 @@ var PRBEAgentState = class extends import_events.EventEmitter {
442
450
  this.emit("agent-message" /* AGENT_MESSAGE */, { message });
443
451
  this.emit("status" /* STATUS */);
444
452
  }
445
- setCRAgentMessage(crID, message) {
446
- const cr = this.activeCRs.get(crID);
447
- if (!cr) return;
448
- cr.agentMessage = message;
453
+ setBackgroundAgentMessage(backgroundId, message) {
454
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
455
+ if (!bg) return;
456
+ bg.agentMessage = message;
449
457
  this.emit("agent-message" /* AGENT_MESSAGE */, { message });
450
458
  this.emit("status" /* STATUS */);
451
459
  }
@@ -456,14 +464,17 @@ var PRBEAgentState = class extends import_events.EventEmitter {
456
464
  this.emit("status" /* STATUS */);
457
465
  }
458
466
  }
459
- // ---------- CR state mutations ----------
460
- beginCR(id, query, slug, ticketId) {
461
- const cr = {
467
+ // ---------- Background investigation state mutations ----------
468
+ beginBackgroundInvestigation(id, query, slug, ticketId, source, sourceDetail) {
469
+ const bg = {
462
470
  id,
463
471
  query,
464
472
  slug,
465
473
  ticketId,
474
+ source,
475
+ sourceDetail,
466
476
  events: [],
477
+ conversationHistory: [],
467
478
  resolvedInteractions: [],
468
479
  isRunning: true,
469
480
  isCompleted: false,
@@ -472,20 +483,20 @@ var PRBEAgentState = class extends import_events.EventEmitter {
472
483
  summary: "",
473
484
  startedAt: /* @__PURE__ */ new Date()
474
485
  };
475
- this.activeCRs.set(id, cr);
476
- this.emit("cr-start" /* CR_START */, cr);
486
+ this.activeBackgroundInvestigations.set(id, bg);
487
+ this.emit("background-start" /* BACKGROUND_START */, bg);
477
488
  this.emit("status" /* STATUS */);
478
489
  }
479
- appendCREvent(crID, label, detail, completed = false) {
480
- const cr = this.activeCRs.get(crID);
481
- if (!cr) return;
482
- if (cr.events.length > 0) {
483
- const last = cr.events[cr.events.length - 1];
490
+ appendBackgroundEvent(backgroundId, label, detail, completed = false) {
491
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
492
+ if (!bg) return;
493
+ if (bg.events.length > 0) {
494
+ const last = bg.events[bg.events.length - 1];
484
495
  if (!last.isCompleted && !completed) {
485
496
  last.isCompleted = true;
486
497
  }
487
498
  }
488
- cr.events.push({
499
+ bg.events.push({
489
500
  id: (0, import_crypto.randomUUID)(),
490
501
  label,
491
502
  detail,
@@ -494,47 +505,47 @@ var PRBEAgentState = class extends import_events.EventEmitter {
494
505
  });
495
506
  this.emit("status" /* STATUS */);
496
507
  }
497
- attachCRObservation(crID, text) {
498
- const cr = this.activeCRs.get(crID);
499
- if (!cr || cr.events.length === 0) return;
500
- cr.events[cr.events.length - 1].detail = text;
508
+ attachBackgroundObservation(backgroundId, text) {
509
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
510
+ if (!bg || bg.events.length === 0) return;
511
+ bg.events[bg.events.length - 1].detail = text;
501
512
  this.emit("status" /* STATUS */);
502
513
  }
503
- completeCR(id, report) {
504
- const cr = this.activeCRs.get(id);
505
- if (!cr) return;
506
- this.activeCRs.delete(id);
507
- if (cr.events.length > 0) {
508
- cr.events[cr.events.length - 1].isCompleted = true;
514
+ completeBackgroundInvestigation(id, report) {
515
+ const bg = this.activeBackgroundInvestigations.get(id);
516
+ if (!bg) return;
517
+ this.activeBackgroundInvestigations.delete(id);
518
+ if (bg.events.length > 0) {
519
+ bg.events[bg.events.length - 1].isCompleted = true;
509
520
  }
510
- cr.events.push({
521
+ bg.events.push({
511
522
  id: (0, import_crypto.randomUUID)(),
512
523
  label: "Done",
513
524
  isCompleted: true,
514
525
  isExpanded: false
515
526
  });
516
- cr.isRunning = false;
517
- cr.isCompleted = true;
518
- cr.report = report;
519
- this.completedCRs.unshift(cr);
520
- this.emit("cr-complete" /* CR_COMPLETE */, cr);
527
+ bg.isRunning = false;
528
+ bg.isCompleted = true;
529
+ bg.report = report;
530
+ this.completedBackgroundInvestigations.unshift(bg);
531
+ this.emit("background-complete" /* BACKGROUND_COMPLETE */, bg);
521
532
  this.emit("status" /* STATUS */);
522
533
  }
523
- failCR(id, message) {
524
- const cr = this.activeCRs.get(id);
525
- if (!cr) return;
526
- this.activeCRs.delete(id);
527
- cr.events.push({
534
+ failBackgroundInvestigation(id, message) {
535
+ const bg = this.activeBackgroundInvestigations.get(id);
536
+ if (!bg) return;
537
+ this.activeBackgroundInvestigations.delete(id);
538
+ bg.events.push({
528
539
  id: (0, import_crypto.randomUUID)(),
529
540
  label: `Error: ${message}`,
530
541
  isCompleted: false,
531
542
  isExpanded: false
532
543
  });
533
- cr.isRunning = false;
534
- cr.isFailed = true;
535
- cr.errorMessage = message;
536
- this.completedCRs.unshift(cr);
537
- this.emit("cr-complete" /* CR_COMPLETE */, cr);
544
+ bg.isRunning = false;
545
+ bg.isFailed = true;
546
+ bg.errorMessage = message;
547
+ this.completedBackgroundInvestigations.unshift(bg);
548
+ this.emit("background-complete" /* BACKGROUND_COMPLETE */, bg);
538
549
  this.emit("status" /* STATUS */);
539
550
  }
540
551
  // ---------- Tickets ----------
@@ -548,6 +559,10 @@ var PRBEAgentState = class extends import_events.EventEmitter {
548
559
  this.emit("ticket-info" /* TICKET_INFO */, info);
549
560
  this.emit("status" /* STATUS */);
550
561
  }
562
+ updateAgentHistory(tickets) {
563
+ this.agentHistory = tickets;
564
+ this.emit("status" /* STATUS */);
565
+ }
551
566
  };
552
567
 
553
568
  // src/tools/index.ts
@@ -563,6 +578,7 @@ var InteractionType = /* @__PURE__ */ ((InteractionType2) => {
563
578
  var InvestigationSource = /* @__PURE__ */ ((InvestigationSource2) => {
564
579
  InvestigationSource2["USER"] = "user";
565
580
  InvestigationSource2["CONTEXT_REQUEST"] = "context_request";
581
+ InvestigationSource2["EXTERNAL_REQUEST"] = "external_request";
566
582
  return InvestigationSource2;
567
583
  })(InvestigationSource || {});
568
584
 
@@ -1770,197 +1786,20 @@ var BashExecuteTool = class {
1770
1786
  }
1771
1787
  };
1772
1788
 
1773
- // src/history.ts
1774
- var fs2 = __toESM(require("fs"));
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() {
1789
+ // src/agent.ts
1790
+ function getPersistencePath() {
1781
1791
  const appData = process.env["APPDATA"] || (process.platform === "darwin" ? path4.join(os.homedir(), "Library", "Application Support") : path4.join(os.homedir(), ".local", "share"));
1782
- return path4.join(appData, "prbe-agent");
1783
- }
1784
- function getHistoryDir() {
1785
- const dir = path4.join(getAppDataDir(), "history" /* HISTORY_DIR */);
1792
+ const dir = path4.join(appData, "prbe-agent");
1786
1793
  if (!fs2.existsSync(dir)) {
1787
1794
  fs2.mkdirSync(dir, { recursive: true });
1788
1795
  }
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");
1796
+ return path4.join(dir, "agent-state.json");
1958
1797
  }
1959
1798
  function loadPersistedData() {
1960
1799
  try {
1961
1800
  const filePath = getPersistencePath();
1962
- if (fs3.existsSync(filePath)) {
1963
- const raw = fs3.readFileSync(filePath, "utf-8");
1801
+ if (fs2.existsSync(filePath)) {
1802
+ const raw = fs2.readFileSync(filePath, "utf-8");
1964
1803
  return JSON.parse(raw);
1965
1804
  }
1966
1805
  } catch {
@@ -1970,7 +1809,7 @@ function loadPersistedData() {
1970
1809
  function savePersistedData(data) {
1971
1810
  try {
1972
1811
  const filePath = getPersistencePath();
1973
- fs3.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
1812
+ fs2.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
1974
1813
  } catch {
1975
1814
  console.error("[PRBEAgent] Failed to save persisted data");
1976
1815
  }
@@ -1990,8 +1829,7 @@ var PRBEAgent = class _PRBEAgent {
1990
1829
  persistedData;
1991
1830
  fetchAbortController = null;
1992
1831
  currentInvestigationSource = "user" /* USER */;
1993
- currentCRId = null;
1994
- historyStore;
1832
+ currentBackgroundId = null;
1995
1833
  /** Files flagged during the current tool call — uploaded immediately after the tool returns. */
1996
1834
  pendingFlaggedFiles = [];
1997
1835
  // ---------- User Identifier ----------
@@ -2007,30 +1845,6 @@ var PRBEAgent = class _PRBEAgent {
2007
1845
  savePersistedData(this.persistedData);
2008
1846
  return newID;
2009
1847
  }
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
1848
  // ---------- Constructor ----------
2035
1849
  constructor(config) {
2036
1850
  this.config = {
@@ -2050,11 +1864,7 @@ var PRBEAgent = class _PRBEAgent {
2050
1864
  this.state = new PRBEAgentState();
2051
1865
  this.logCapture = new PRBELogCapture(this.config.maxLogEntries);
2052
1866
  this.persistedData = loadPersistedData();
2053
- this.historyStore = new HistoryStore(this.config.apiKey);
2054
1867
  void this.agentID;
2055
- const history = this.historyStore.load();
2056
- this.state.completedInvestigations = history.investigations;
2057
- this.state.completedCRs = history.crs;
2058
1868
  const roots = this.config.autoApprovedDirs;
2059
1869
  const requester = this.interactionHandler ? this : void 0;
2060
1870
  const grantedPaths = this.grantedPaths;
@@ -2086,8 +1896,8 @@ var PRBEAgent = class _PRBEAgent {
2086
1896
  [{ name: "message", type: "STRING" /* STRING */, description: "Message for the user", required: true }],
2087
1897
  async (args) => {
2088
1898
  const message = args["message"] ?? "";
2089
- if (this.currentInvestigationSource === "context_request" /* CONTEXT_REQUEST */ && this.currentCRId) {
2090
- this.state.setCRAgentMessage(this.currentCRId, message);
1899
+ if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
1900
+ this.state.setBackgroundAgentMessage(this.currentBackgroundId, message);
2091
1901
  } else {
2092
1902
  this.state.setAgentMessage(message);
2093
1903
  }
@@ -2104,9 +1914,8 @@ var PRBEAgent = class _PRBEAgent {
2104
1914
  if (config.ipcMain) {
2105
1915
  this.hookRendererLogs(config.ipcMain, config.rendererLogChannel ?? "prbe-renderer-log");
2106
1916
  }
2107
- const existingSessions = this.trackedSessionIDs;
2108
- if (existingSessions.length > 0) {
2109
- this.trackedSessionIDs = existingSessions;
1917
+ if (this.config.backgroundPolling) {
1918
+ this.startPolling();
2110
1919
  }
2111
1920
  }
2112
1921
  // ---------- Log integration ----------
@@ -2160,15 +1969,15 @@ var PRBEAgent = class _PRBEAgent {
2160
1969
  "No interaction handler configured"
2161
1970
  );
2162
1971
  }
2163
- if (this.currentInvestigationSource === "context_request" /* CONTEXT_REQUEST */ && this.currentCRId) {
2164
- this.state.setCRPendingInteraction(this.currentCRId, payload);
1972
+ if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
1973
+ this.state.setBackgroundPendingInteraction(this.currentBackgroundId, payload);
2165
1974
  } else {
2166
1975
  this.state.setPendingInteraction(payload);
2167
1976
  }
2168
1977
  try {
2169
1978
  const response = await this.interactionHandler.handleInteraction(payload);
2170
- if (this.currentInvestigationSource === "context_request" /* CONTEXT_REQUEST */ && this.currentCRId) {
2171
- this.state.resolveCRInteraction(this.currentCRId, response);
1979
+ if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
1980
+ this.state.resolveBackgroundInteraction(this.currentBackgroundId, response);
2172
1981
  } else {
2173
1982
  this.state.resolveInteraction(response);
2174
1983
  }
@@ -2181,8 +1990,8 @@ var PRBEAgent = class _PRBEAgent {
2181
1990
  }
2182
1991
  return response;
2183
1992
  } catch (err) {
2184
- if (this.currentInvestigationSource === "context_request" /* CONTEXT_REQUEST */ && this.currentCRId) {
2185
- this.state.clearCRPendingInteraction(this.currentCRId);
1993
+ if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
1994
+ this.state.clearBackgroundPendingInteraction(this.currentBackgroundId);
2186
1995
  } else {
2187
1996
  this.state.clearPendingInteraction();
2188
1997
  }
@@ -2254,58 +2063,92 @@ var PRBEAgent = class _PRBEAgent {
2254
2063
  new PRBEClosureTool(name, description, parameters, handler, options)
2255
2064
  );
2256
2065
  }
2257
- /**
2258
- * User-initiated investigation. Updates `state` events/report directly.
2259
- */
2260
- async investigate(query, contextRequestID) {
2261
- this.userCancelled = false;
2262
- this.currentInvestigationSource = "user" /* USER */;
2263
- this.currentCRId = null;
2264
- this.state.beginInvestigation(query);
2066
+ // ---------- Unified Investigation ----------
2067
+ async runInvestigation(opts) {
2068
+ this.currentInvestigationSource = opts.source;
2069
+ this.currentBackgroundId = opts.sourceId ?? null;
2070
+ const isBackground = opts.source !== "user" /* USER */;
2265
2071
  const emitter = (status) => {
2266
2072
  switch (status.type) {
2267
2073
  case "started" /* STARTED */:
2268
- this.state.appendEvent("Starting investigation...");
2074
+ if (isBackground && opts.sourceId) {
2075
+ this.state.appendBackgroundEvent(opts.sourceId, "Starting investigation...");
2076
+ } else {
2077
+ this.state.appendEvent("Starting investigation...");
2078
+ }
2269
2079
  break;
2270
2080
  case "thinking" /* THINKING */:
2271
2081
  break;
2272
2082
  case "tool_call" /* TOOL_CALL */:
2273
- this.state.appendEvent(status.label);
2083
+ if (isBackground && opts.sourceId) {
2084
+ this.state.appendBackgroundEvent(opts.sourceId, status.label);
2085
+ } else {
2086
+ this.state.appendEvent(status.label);
2087
+ }
2274
2088
  break;
2275
2089
  case "observation" /* OBSERVATION */:
2276
- this.state.attachObservation(status.text);
2090
+ if (isBackground && opts.sourceId) {
2091
+ this.state.attachBackgroundObservation(opts.sourceId, status.text);
2092
+ } else {
2093
+ this.state.attachObservation(status.text);
2094
+ }
2277
2095
  break;
2278
2096
  case "thought" /* THOUGHT */:
2279
- this.state.appendEvent("Thinking", status.text);
2097
+ if (isBackground && opts.sourceId) {
2098
+ this.state.appendBackgroundEvent(opts.sourceId, "Thinking", status.text);
2099
+ } else {
2100
+ this.state.appendEvent("Thinking", status.text);
2101
+ }
2280
2102
  break;
2281
2103
  case "completed" /* COMPLETED */:
2282
- this.state.completeInvestigation(status.report, status.ticketId);
2283
- this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
2104
+ if (isBackground && opts.sourceId) {
2105
+ this.state.completeBackgroundInvestigation(opts.sourceId, status.report);
2106
+ } else {
2107
+ this.state.completeInvestigation(status.report, status.ticketId);
2108
+ }
2284
2109
  break;
2285
2110
  case "error" /* ERROR */:
2286
- this.state.failInvestigation(status.message);
2111
+ if (isBackground && opts.sourceId) {
2112
+ this.state.failBackgroundInvestigation(opts.sourceId, status.message);
2113
+ } else {
2114
+ this.state.failInvestigation(status.message);
2115
+ }
2287
2116
  break;
2288
2117
  }
2289
2118
  };
2290
2119
  const result = await this.connectToProxy(
2291
- query,
2292
- contextRequestID,
2120
+ opts.query,
2121
+ opts.contextRequestId,
2122
+ opts.externalRequestId,
2123
+ opts.externalRequestSource,
2124
+ opts.externalRequestSourceDetail,
2293
2125
  emitter,
2294
- () => this.userCancelled
2126
+ opts.cancellable ? () => this.userCancelled : () => false,
2127
+ opts.ticketId
2295
2128
  );
2296
2129
  this.currentInvestigationSource = "user" /* USER */;
2297
- this.currentCRId = null;
2298
- if (result?.sessionId) {
2299
- this.addTrackedSession(result.sessionId);
2300
- } else if (!result) {
2301
- if (this.state.isInvestigating) {
2302
- const message = this.userCancelled ? "Investigation cancelled" : "Investigation ended unexpectedly";
2303
- this.state.failInvestigation(message);
2304
- }
2130
+ this.currentBackgroundId = null;
2131
+ return result;
2132
+ }
2133
+ /**
2134
+ * User-initiated investigation. Updates `state` events/report directly.
2135
+ */
2136
+ async investigate(query, contextRequestID) {
2137
+ this.userCancelled = false;
2138
+ this.state.beginInvestigation(query);
2139
+ const result = await this.runInvestigation({
2140
+ query,
2141
+ source: "user" /* USER */,
2142
+ contextRequestId: contextRequestID,
2143
+ cancellable: true
2144
+ });
2145
+ if (!result && this.state.isInvestigating) {
2146
+ const message = this.userCancelled ? "Investigation cancelled" : "Investigation ended unexpectedly";
2147
+ this.state.failInvestigation(message);
2305
2148
  }
2306
2149
  }
2307
2150
  /**
2308
- * Cancel user-initiated investigation only (does not cancel background CRs).
2151
+ * Cancel user-initiated investigation only (does not cancel background investigations).
2309
2152
  */
2310
2153
  cancelInvestigation() {
2311
2154
  this.userCancelled = true;
@@ -2327,41 +2170,21 @@ var PRBEAgent = class _PRBEAgent {
2327
2170
  this.stopPolling();
2328
2171
  }
2329
2172
  /**
2330
- * Poll the backend for context requests on tracked tickets.
2331
- * Resolves session IDs → ticket IDs first, then polls with ticket IDs.
2173
+ * Poll the backend for context requests and external requests.
2332
2174
  */
2333
2175
  async poll() {
2334
- const sessionIDs = this.trackedSessionIDs;
2335
- if (sessionIDs.length === 0) return null;
2336
2176
  try {
2337
- const resolved = await this.resolveSessions(sessionIDs);
2338
- const returnedSessionIDs = new Set(
2339
- resolved.tickets.flatMap((t) => t.session_ids)
2340
- );
2341
- const resolvedSessionIDs = new Set(
2342
- resolved.tickets.filter((t) => t.status === "resolved").flatMap((t) => t.session_ids)
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;
2177
+ const request = { agent_id: this.agentID };
2178
+ const response = await this.post("/api/agent/poll", request);
2179
+ for (const cr of response.context_requests) {
2180
+ if (!cr.is_active) continue;
2181
+ if (this.state.activeBackgroundInvestigations.has(cr.id)) continue;
2182
+ await this.investigateForCR(cr, cr.ticket_id);
2349
2183
  }
2350
- const ticketIDs = resolved.tickets.filter((t) => t.status !== "resolved").map((t) => t.ticket_id);
2351
- if (ticketIDs.length === 0) return { tickets: [] };
2352
- const request = {
2353
- agent_id: this.agentID,
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
- }
2184
+ for (const er of response.external_requests) {
2185
+ if (!er.is_active) continue;
2186
+ if (this.state.activeBackgroundInvestigations.has(er.id)) continue;
2187
+ await this.investigateForER(er);
2365
2188
  }
2366
2189
  return response;
2367
2190
  } catch {
@@ -2369,25 +2192,18 @@ var PRBEAgent = class _PRBEAgent {
2369
2192
  }
2370
2193
  }
2371
2194
  /**
2372
- * Fetch ticket display info for all tracked sessions.
2373
- * Resolves session IDs → ticket IDs first, then fetches ticket info.
2195
+ * Fetch agent history (tickets + sessions) from the backend.
2374
2196
  */
2375
- async fetchTicketInfo() {
2376
- const sessionIDs = this.trackedSessionIDs;
2377
- if (sessionIDs.length === 0) return [];
2197
+ async fetchHistory() {
2378
2198
  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
2199
  const response = await this.post(
2384
- "/api/agent/tickets",
2385
- request
2200
+ "/api/agent/history",
2201
+ { agent_id: this.agentID }
2386
2202
  );
2387
- this.state.updateTicketInfo(response.tickets);
2388
- return response.tickets;
2203
+ this.state.updateAgentHistory(response.tickets);
2204
+ return response;
2389
2205
  } catch {
2390
- return [];
2206
+ return null;
2391
2207
  }
2392
2208
  }
2393
2209
  stopPolling() {
@@ -2397,7 +2213,7 @@ var PRBEAgent = class _PRBEAgent {
2397
2213
  }
2398
2214
  }
2399
2215
  resumePolling() {
2400
- if (this.trackedSessionIDs.length === 0) return;
2216
+ if (!this.config.backgroundPolling) return;
2401
2217
  this.startPolling();
2402
2218
  }
2403
2219
  /**
@@ -2415,13 +2231,11 @@ var PRBEAgent = class _PRBEAgent {
2415
2231
  this.stopPolling();
2416
2232
  this.persistedData = {};
2417
2233
  savePersistedData(this.persistedData);
2418
- HistoryStore.clear();
2419
2234
  this.state.resetInvestigation();
2420
2235
  this.state.completedInvestigations = [];
2421
- this.state.activeCRs.clear();
2422
- this.state.completedCRs = [];
2423
- this.state.trackedSessionIDs = [];
2424
- this.state.ticketInfo = [];
2236
+ this.state.activeBackgroundInvestigations.clear();
2237
+ this.state.completedBackgroundInvestigations = [];
2238
+ this.state.agentHistory = [];
2425
2239
  this.state.emit("status" /* STATUS */);
2426
2240
  }
2427
2241
  /**
@@ -2430,61 +2244,38 @@ var PRBEAgent = class _PRBEAgent {
2430
2244
  static clearPersistedData() {
2431
2245
  try {
2432
2246
  const filePath = getPersistencePath();
2433
- if (fs3.existsSync(filePath)) {
2434
- fs3.unlinkSync(filePath);
2247
+ if (fs2.existsSync(filePath)) {
2248
+ fs2.unlinkSync(filePath);
2435
2249
  }
2436
- HistoryStore.clear();
2437
2250
  } catch {
2438
2251
  }
2439
2252
  }
2440
- // ---------- CR Investigation ----------
2253
+ // ---------- Background Investigation ----------
2441
2254
  async investigateForCR(cr, ticketId) {
2442
- const crID = cr.id;
2443
- this.currentInvestigationSource = "context_request" /* CONTEXT_REQUEST */;
2444
- this.currentCRId = crID;
2445
- this.state.beginCR(crID, cr.query, cr.slug ?? void 0, ticketId);
2446
- const emitter = (status) => {
2447
- switch (status.type) {
2448
- case "started" /* STARTED */:
2449
- this.state.appendCREvent(crID, "Starting investigation...");
2450
- break;
2451
- case "thinking" /* THINKING */:
2452
- break;
2453
- case "tool_call" /* TOOL_CALL */:
2454
- this.state.appendCREvent(crID, status.label);
2455
- break;
2456
- case "observation" /* OBSERVATION */:
2457
- this.state.attachCRObservation(crID, status.text);
2458
- break;
2459
- case "thought" /* THOUGHT */:
2460
- this.state.appendCREvent(crID, "Thinking", status.text);
2461
- break;
2462
- case "completed" /* COMPLETED */:
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
- }
2255
+ this.state.beginBackgroundInvestigation(cr.id, cr.query, cr.slug ?? void 0, ticketId);
2256
+ await this.runInvestigation({
2257
+ query: cr.query,
2258
+ source: "context_request" /* CONTEXT_REQUEST */,
2259
+ sourceId: cr.id,
2260
+ contextRequestId: cr.id,
2261
+ ticketId,
2262
+ cancellable: false
2263
+ });
2264
+ }
2265
+ async investigateForER(er) {
2266
+ this.state.beginBackgroundInvestigation(er.id, er.query, void 0, void 0, er.source, er.source_detail);
2267
+ await this.runInvestigation({
2268
+ query: er.query,
2269
+ source: "external_request" /* EXTERNAL_REQUEST */,
2270
+ sourceId: er.id,
2271
+ externalRequestId: er.id,
2272
+ externalRequestSource: er.source,
2273
+ externalRequestSourceDetail: er.source_detail,
2274
+ cancellable: false
2275
+ });
2485
2276
  }
2486
2277
  // ---------- WebSocket Investigation ----------
2487
- connectToProxy(query, contextRequestID, emit, isCancelled, ticketId) {
2278
+ connectToProxy(query, contextRequestID, externalRequestId, externalRequestSource, externalRequestSourceDetail, emit, isCancelled, ticketId) {
2488
2279
  return new Promise((resolve2) => {
2489
2280
  const wsUrl = `${MIDDLEWARE_URL}/api/agent/client/ws`;
2490
2281
  let uploadBaseUrl;
@@ -2539,11 +2330,14 @@ var PRBEAgent = class _PRBEAgent {
2539
2330
  const startMetadata = {
2540
2331
  agent_id: this.agentID,
2541
2332
  custom_tools: toolDeclarations,
2542
- platform: os2.platform(),
2543
- os_version: os2.release(),
2544
- arch: os2.arch()
2333
+ platform: os.platform(),
2334
+ os_version: os.release(),
2335
+ arch: os.arch()
2545
2336
  };
2546
2337
  if (contextRequestID) startMetadata["context_request_id"] = contextRequestID;
2338
+ if (externalRequestId) startMetadata["external_request_id"] = externalRequestId;
2339
+ if (externalRequestSource) startMetadata["external_request_source"] = externalRequestSource;
2340
+ if (externalRequestSourceDetail) startMetadata["external_request_source_detail"] = externalRequestSourceDetail;
2547
2341
  if (ticketId) startMetadata["ticket_id"] = ticketId;
2548
2342
  if (this.appDataPath) startMetadata["app_data_path"] = this.appDataPath;
2549
2343
  const enrichedMetadata = { ...this.sessionMetadata };
@@ -2591,7 +2385,7 @@ var PRBEAgent = class _PRBEAgent {
2591
2385
  const uploadPrefix = this.extractUploadPrefix(uploadBaseUrl);
2592
2386
  const uploadedRefs = [];
2593
2387
  for (const file of this.pendingFlaggedFiles) {
2594
- const filename = path5.basename(file.originalPath);
2388
+ const filename = path4.basename(file.originalPath);
2595
2389
  const safeName = encodeURIComponent(filename);
2596
2390
  const storagePath = `${uploadPrefix}/${safeName}`;
2597
2391
  uploadedRefs.push({
@@ -2636,7 +2430,11 @@ var PRBEAgent = class _PRBEAgent {
2636
2430
  case "conversation_update" /* CONVERSATION_UPDATE */: {
2637
2431
  try {
2638
2432
  const entry = JSON.parse(msg.content ?? "{}");
2639
- this.state.appendConversation(entry);
2433
+ if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
2434
+ this.state.appendBackgroundConversation(this.currentBackgroundId, entry);
2435
+ } else {
2436
+ this.state.appendConversation(entry);
2437
+ }
2640
2438
  } catch {
2641
2439
  }
2642
2440
  break;
@@ -2694,24 +2492,9 @@ var PRBEAgent = class _PRBEAgent {
2694
2492
  startPolling() {
2695
2493
  this.stopPolling();
2696
2494
  this.pollingTimer = setInterval(() => {
2697
- void this.poll().then(() => {
2698
- if (this.trackedSessionIDs.length === 0) {
2699
- this.stopPolling();
2700
- }
2701
- });
2495
+ void this.poll();
2702
2496
  }, this.config.pollingInterval);
2703
2497
  }
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
2498
  // ---------- Networking ----------
2716
2499
  /**
2717
2500
  * Abort all in-flight fetch requests to prevent orphaned DNS lookups
@@ -2765,29 +2548,32 @@ var DEFAULT_PRBE_STATE = {
2765
2548
  resolvedInteractions: [],
2766
2549
  conversationHistory: [],
2767
2550
  completedInvestigations: [],
2768
- activeCRs: [],
2769
- completedCRs: [],
2770
- trackedSessionIDs: [],
2551
+ activeBackgroundInvestigations: [],
2552
+ completedBackgroundInvestigations: [],
2771
2553
  ticketInfo: [],
2554
+ agentHistory: [],
2772
2555
  hasActiveWork: false
2773
2556
  };
2774
- function serializeCR(cr) {
2557
+ function serializeBackgroundInvestigation(bg) {
2775
2558
  return {
2776
- id: cr.id,
2777
- query: cr.query,
2778
- slug: cr.slug,
2779
- ticketId: cr.ticketId,
2780
- events: cr.events,
2781
- isRunning: cr.isRunning,
2782
- isCompleted: cr.isCompleted,
2783
- isFailed: cr.isFailed,
2784
- report: cr.report,
2785
- summary: cr.summary,
2786
- errorMessage: cr.errorMessage,
2787
- agentMessage: cr.agentMessage,
2788
- startedAt: cr.startedAt.toISOString(),
2789
- pendingInteraction: cr.pendingInteraction,
2790
- resolvedInteractions: cr.resolvedInteractions ?? []
2559
+ id: bg.id,
2560
+ query: bg.query,
2561
+ slug: bg.slug,
2562
+ ticketId: bg.ticketId,
2563
+ source: bg.source,
2564
+ sourceDetail: bg.sourceDetail,
2565
+ events: bg.events,
2566
+ isRunning: bg.isRunning,
2567
+ isCompleted: bg.isCompleted,
2568
+ isFailed: bg.isFailed,
2569
+ report: bg.report,
2570
+ summary: bg.summary,
2571
+ errorMessage: bg.errorMessage,
2572
+ agentMessage: bg.agentMessage,
2573
+ startedAt: bg.startedAt.toISOString(),
2574
+ pendingInteraction: bg.pendingInteraction,
2575
+ resolvedInteractions: bg.resolvedInteractions ?? [],
2576
+ conversationHistory: bg.conversationHistory ?? []
2791
2577
  };
2792
2578
  }
2793
2579
  function serializePRBEState(state) {
@@ -2813,10 +2599,10 @@ function serializePRBEState(state) {
2813
2599
  conversationHistory: inv.conversationHistory,
2814
2600
  completedAt: inv.completedAt.toISOString()
2815
2601
  })),
2816
- activeCRs: Array.from(state.activeCRs.values()).map(serializeCR),
2817
- completedCRs: state.completedCRs.map(serializeCR),
2818
- trackedSessionIDs: state.trackedSessionIDs,
2602
+ activeBackgroundInvestigations: Array.from(state.activeBackgroundInvestigations.values()).map(serializeBackgroundInvestigation),
2603
+ completedBackgroundInvestigations: state.completedBackgroundInvestigations.map(serializeBackgroundInvestigation),
2819
2604
  ticketInfo: state.ticketInfo,
2605
+ agentHistory: state.agentHistory,
2820
2606
  hasActiveWork: state.hasActiveWork
2821
2607
  };
2822
2608
  }