@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.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  // package.json
2
- var version = "0.1.17";
2
+ var version = "0.1.18";
3
3
 
4
4
  // src/agent.ts
5
- import * as fs3 from "fs";
6
- import * as path5 from "path";
7
- import * as os2 from "os";
5
+ import * as fs2 from "fs";
6
+ import * as path4 from "path";
7
+ import * as os from "os";
8
8
  import { randomUUID as randomUUID5 } from "crypto";
9
9
 
10
10
  // src/models.ts
@@ -192,8 +192,8 @@ var PRBEStateEvent = /* @__PURE__ */ ((PRBEStateEvent2) => {
192
192
  PRBEStateEvent2["EVENT"] = "event";
193
193
  PRBEStateEvent2["COMPLETE"] = "complete";
194
194
  PRBEStateEvent2["ERROR"] = "error";
195
- PRBEStateEvent2["CR_START"] = "cr-start";
196
- PRBEStateEvent2["CR_COMPLETE"] = "cr-complete";
195
+ PRBEStateEvent2["BACKGROUND_START"] = "background-start";
196
+ PRBEStateEvent2["BACKGROUND_COMPLETE"] = "background-complete";
197
197
  PRBEStateEvent2["TICKETS_CHANGED"] = "tickets-changed";
198
198
  PRBEStateEvent2["TICKET_INFO"] = "ticket-info";
199
199
  PRBEStateEvent2["INTERACTION_REQUESTED"] = "interaction-requested";
@@ -215,18 +215,20 @@ var PRBEAgentState = class extends EventEmitter {
215
215
  conversationHistory = [];
216
216
  // Completed user investigations (history)
217
217
  completedInvestigations = [];
218
- // Background context requests
219
- activeCRs = /* @__PURE__ */ new Map();
220
- completedCRs = [];
218
+ // Background investigations (context requests, external requests, etc.)
219
+ activeBackgroundInvestigations = /* @__PURE__ */ new Map();
220
+ completedBackgroundInvestigations = [];
221
221
  // Tracked tickets
222
222
  trackedSessionIDs = [];
223
223
  ticketInfo = [];
224
+ // Agent history
225
+ agentHistory = [];
224
226
  // Computed
225
227
  get hasActiveWork() {
226
- return this.isInvestigating || this.activeCRs.size > 0;
228
+ return this.isInvestigating || this.activeBackgroundInvestigations.size > 0;
227
229
  }
228
- get activeCRCount() {
229
- return this.activeCRs.size;
230
+ get activeBackgroundCount() {
231
+ return this.activeBackgroundInvestigations.size;
230
232
  }
231
233
  get isActive() {
232
234
  return this.isInvestigating || this.report.length > 0 || this.investigationError != null;
@@ -248,6 +250,12 @@ var PRBEAgentState = class extends EventEmitter {
248
250
  this.conversationHistory.push(entry);
249
251
  this.emit("status" /* STATUS */);
250
252
  }
253
+ appendBackgroundConversation(backgroundId, entry) {
254
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
255
+ if (!bg) return;
256
+ bg.conversationHistory.push(entry);
257
+ this.emit("status" /* STATUS */);
258
+ }
251
259
  resetInvestigation() {
252
260
  this.isInvestigating = false;
253
261
  this.events = [];
@@ -323,17 +331,17 @@ var PRBEAgentState = class extends EventEmitter {
323
331
  this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
324
332
  this.emit("status" /* STATUS */);
325
333
  }
326
- setCRPendingInteraction(crID, payload) {
327
- const cr = this.activeCRs.get(crID);
328
- if (!cr) return;
329
- cr.pendingInteraction = payload;
334
+ setBackgroundPendingInteraction(backgroundId, payload) {
335
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
336
+ if (!bg) return;
337
+ bg.pendingInteraction = payload;
330
338
  this.emit("interaction-requested" /* INTERACTION_REQUESTED */, payload);
331
339
  this.emit("status" /* STATUS */);
332
340
  }
333
- clearCRPendingInteraction(crID) {
334
- const cr = this.activeCRs.get(crID);
335
- if (!cr) return;
336
- cr.pendingInteraction = void 0;
341
+ clearBackgroundPendingInteraction(backgroundId) {
342
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
343
+ if (!bg) return;
344
+ bg.pendingInteraction = void 0;
337
345
  this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
338
346
  this.emit("status" /* STATUS */);
339
347
  }
@@ -349,18 +357,18 @@ var PRBEAgentState = class extends EventEmitter {
349
357
  this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
350
358
  this.emit("status" /* STATUS */);
351
359
  }
352
- resolveCRInteraction(crID, response) {
353
- const cr = this.activeCRs.get(crID);
354
- if (!cr || !cr.pendingInteraction) return;
355
- const resolved = cr.resolvedInteractions ?? [];
360
+ resolveBackgroundInteraction(backgroundId, response) {
361
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
362
+ if (!bg || !bg.pendingInteraction) return;
363
+ const resolved = bg.resolvedInteractions ?? [];
356
364
  resolved.push({
357
- interactionId: cr.pendingInteraction.interactionId,
358
- payload: cr.pendingInteraction,
365
+ interactionId: bg.pendingInteraction.interactionId,
366
+ payload: bg.pendingInteraction,
359
367
  response,
360
- eventIndex: cr.events.length
368
+ eventIndex: bg.events.length
361
369
  });
362
- cr.resolvedInteractions = resolved;
363
- cr.pendingInteraction = void 0;
370
+ bg.resolvedInteractions = resolved;
371
+ bg.pendingInteraction = void 0;
364
372
  this.emit("interaction-resolved" /* INTERACTION_RESOLVED */);
365
373
  this.emit("status" /* STATUS */);
366
374
  }
@@ -369,10 +377,10 @@ var PRBEAgentState = class extends EventEmitter {
369
377
  this.emit("agent-message" /* AGENT_MESSAGE */, { message });
370
378
  this.emit("status" /* STATUS */);
371
379
  }
372
- setCRAgentMessage(crID, message) {
373
- const cr = this.activeCRs.get(crID);
374
- if (!cr) return;
375
- cr.agentMessage = message;
380
+ setBackgroundAgentMessage(backgroundId, message) {
381
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
382
+ if (!bg) return;
383
+ bg.agentMessage = message;
376
384
  this.emit("agent-message" /* AGENT_MESSAGE */, { message });
377
385
  this.emit("status" /* STATUS */);
378
386
  }
@@ -383,14 +391,17 @@ var PRBEAgentState = class extends EventEmitter {
383
391
  this.emit("status" /* STATUS */);
384
392
  }
385
393
  }
386
- // ---------- CR state mutations ----------
387
- beginCR(id, query, slug, ticketId) {
388
- const cr = {
394
+ // ---------- Background investigation state mutations ----------
395
+ beginBackgroundInvestigation(id, query, slug, ticketId, source, sourceDetail) {
396
+ const bg = {
389
397
  id,
390
398
  query,
391
399
  slug,
392
400
  ticketId,
401
+ source,
402
+ sourceDetail,
393
403
  events: [],
404
+ conversationHistory: [],
394
405
  resolvedInteractions: [],
395
406
  isRunning: true,
396
407
  isCompleted: false,
@@ -399,20 +410,20 @@ var PRBEAgentState = class extends EventEmitter {
399
410
  summary: "",
400
411
  startedAt: /* @__PURE__ */ new Date()
401
412
  };
402
- this.activeCRs.set(id, cr);
403
- this.emit("cr-start" /* CR_START */, cr);
413
+ this.activeBackgroundInvestigations.set(id, bg);
414
+ this.emit("background-start" /* BACKGROUND_START */, bg);
404
415
  this.emit("status" /* STATUS */);
405
416
  }
406
- appendCREvent(crID, label, detail, completed = false) {
407
- const cr = this.activeCRs.get(crID);
408
- if (!cr) return;
409
- if (cr.events.length > 0) {
410
- const last = cr.events[cr.events.length - 1];
417
+ appendBackgroundEvent(backgroundId, label, detail, completed = false) {
418
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
419
+ if (!bg) return;
420
+ if (bg.events.length > 0) {
421
+ const last = bg.events[bg.events.length - 1];
411
422
  if (!last.isCompleted && !completed) {
412
423
  last.isCompleted = true;
413
424
  }
414
425
  }
415
- cr.events.push({
426
+ bg.events.push({
416
427
  id: randomUUID(),
417
428
  label,
418
429
  detail,
@@ -421,47 +432,47 @@ var PRBEAgentState = class extends EventEmitter {
421
432
  });
422
433
  this.emit("status" /* STATUS */);
423
434
  }
424
- attachCRObservation(crID, text) {
425
- const cr = this.activeCRs.get(crID);
426
- if (!cr || cr.events.length === 0) return;
427
- cr.events[cr.events.length - 1].detail = text;
435
+ attachBackgroundObservation(backgroundId, text) {
436
+ const bg = this.activeBackgroundInvestigations.get(backgroundId);
437
+ if (!bg || bg.events.length === 0) return;
438
+ bg.events[bg.events.length - 1].detail = text;
428
439
  this.emit("status" /* STATUS */);
429
440
  }
430
- completeCR(id, report) {
431
- const cr = this.activeCRs.get(id);
432
- if (!cr) return;
433
- this.activeCRs.delete(id);
434
- if (cr.events.length > 0) {
435
- cr.events[cr.events.length - 1].isCompleted = true;
441
+ completeBackgroundInvestigation(id, report) {
442
+ const bg = this.activeBackgroundInvestigations.get(id);
443
+ if (!bg) return;
444
+ this.activeBackgroundInvestigations.delete(id);
445
+ if (bg.events.length > 0) {
446
+ bg.events[bg.events.length - 1].isCompleted = true;
436
447
  }
437
- cr.events.push({
448
+ bg.events.push({
438
449
  id: randomUUID(),
439
450
  label: "Done",
440
451
  isCompleted: true,
441
452
  isExpanded: false
442
453
  });
443
- cr.isRunning = false;
444
- cr.isCompleted = true;
445
- cr.report = report;
446
- this.completedCRs.unshift(cr);
447
- this.emit("cr-complete" /* CR_COMPLETE */, cr);
454
+ bg.isRunning = false;
455
+ bg.isCompleted = true;
456
+ bg.report = report;
457
+ this.completedBackgroundInvestigations.unshift(bg);
458
+ this.emit("background-complete" /* BACKGROUND_COMPLETE */, bg);
448
459
  this.emit("status" /* STATUS */);
449
460
  }
450
- failCR(id, message) {
451
- const cr = this.activeCRs.get(id);
452
- if (!cr) return;
453
- this.activeCRs.delete(id);
454
- cr.events.push({
461
+ failBackgroundInvestigation(id, message) {
462
+ const bg = this.activeBackgroundInvestigations.get(id);
463
+ if (!bg) return;
464
+ this.activeBackgroundInvestigations.delete(id);
465
+ bg.events.push({
455
466
  id: randomUUID(),
456
467
  label: `Error: ${message}`,
457
468
  isCompleted: false,
458
469
  isExpanded: false
459
470
  });
460
- cr.isRunning = false;
461
- cr.isFailed = true;
462
- cr.errorMessage = message;
463
- this.completedCRs.unshift(cr);
464
- this.emit("cr-complete" /* CR_COMPLETE */, cr);
471
+ bg.isRunning = false;
472
+ bg.isFailed = true;
473
+ bg.errorMessage = message;
474
+ this.completedBackgroundInvestigations.unshift(bg);
475
+ this.emit("background-complete" /* BACKGROUND_COMPLETE */, bg);
465
476
  this.emit("status" /* STATUS */);
466
477
  }
467
478
  // ---------- Tickets ----------
@@ -475,6 +486,10 @@ var PRBEAgentState = class extends EventEmitter {
475
486
  this.emit("ticket-info" /* TICKET_INFO */, info);
476
487
  this.emit("status" /* STATUS */);
477
488
  }
489
+ updateAgentHistory(tickets) {
490
+ this.agentHistory = tickets;
491
+ this.emit("status" /* STATUS */);
492
+ }
478
493
  };
479
494
 
480
495
  // src/tools/index.ts
@@ -490,6 +505,7 @@ var InteractionType = /* @__PURE__ */ ((InteractionType2) => {
490
505
  var InvestigationSource = /* @__PURE__ */ ((InvestigationSource2) => {
491
506
  InvestigationSource2["USER"] = "user";
492
507
  InvestigationSource2["CONTEXT_REQUEST"] = "context_request";
508
+ InvestigationSource2["EXTERNAL_REQUEST"] = "external_request";
493
509
  return InvestigationSource2;
494
510
  })(InvestigationSource || {});
495
511
 
@@ -1697,197 +1713,20 @@ var BashExecuteTool = class {
1697
1713
  }
1698
1714
  };
1699
1715
 
1700
- // src/history.ts
1701
- import * as fs2 from "fs";
1702
- import * as path4 from "path";
1703
- import * as os from "os";
1704
- import * as crypto from "crypto";
1705
- var HKDF_SALT = Buffer.from("prbe-history-encryption-salt", "utf-8");
1706
- var HKDF_INFO = Buffer.from("prbe-history-v1", "utf-8");
1707
- function getAppDataDir() {
1716
+ // src/agent.ts
1717
+ function getPersistencePath() {
1708
1718
  const appData = process.env["APPDATA"] || (process.platform === "darwin" ? path4.join(os.homedir(), "Library", "Application Support") : path4.join(os.homedir(), ".local", "share"));
1709
- return path4.join(appData, "prbe-agent");
1710
- }
1711
- function getHistoryDir() {
1712
- const dir = path4.join(getAppDataDir(), "history" /* HISTORY_DIR */);
1719
+ const dir = path4.join(appData, "prbe-agent");
1713
1720
  if (!fs2.existsSync(dir)) {
1714
1721
  fs2.mkdirSync(dir, { recursive: true });
1715
1722
  }
1716
- return dir;
1717
- }
1718
- function deriveKey(apiKey) {
1719
- return Buffer.from(
1720
- crypto.hkdfSync(
1721
- "sha256",
1722
- Buffer.from(apiKey, "utf-8"),
1723
- HKDF_SALT,
1724
- HKDF_INFO,
1725
- 32 /* KEY_LENGTH */
1726
- )
1727
- );
1728
- }
1729
- function encrypt(plaintext, key) {
1730
- const iv = crypto.randomBytes(12 /* IV_LENGTH */);
1731
- const cipher = crypto.createCipheriv(
1732
- "aes-256-gcm" /* ALGORITHM */,
1733
- key,
1734
- iv,
1735
- { authTagLength: 16 /* AUTH_TAG_LENGTH */ }
1736
- );
1737
- const encrypted = Buffer.concat([cipher.update(plaintext, "utf-8"), cipher.final()]);
1738
- const authTag = cipher.getAuthTag();
1739
- return Buffer.concat([iv, authTag, encrypted]);
1740
- }
1741
- function decrypt(data, key) {
1742
- const iv = data.subarray(0, 12 /* IV_LENGTH */);
1743
- const authTag = data.subarray(
1744
- 12 /* IV_LENGTH */,
1745
- 12 /* IV_LENGTH */ + 16 /* AUTH_TAG_LENGTH */
1746
- );
1747
- const ciphertext = data.subarray(
1748
- 12 /* IV_LENGTH */ + 16 /* AUTH_TAG_LENGTH */
1749
- );
1750
- const decipher = crypto.createDecipheriv(
1751
- "aes-256-gcm" /* ALGORITHM */,
1752
- key,
1753
- iv,
1754
- { authTagLength: 16 /* AUTH_TAG_LENGTH */ }
1755
- );
1756
- decipher.setAuthTag(authTag);
1757
- return decipher.update(ciphertext) + decipher.final("utf-8");
1758
- }
1759
- var HistoryStore = class {
1760
- key;
1761
- constructor(apiKey) {
1762
- this.key = deriveKey(apiKey);
1763
- }
1764
- load() {
1765
- const investigations = [];
1766
- const crs = [];
1767
- try {
1768
- const dir = getHistoryDir();
1769
- let files;
1770
- try {
1771
- files = fs2.readdirSync(dir);
1772
- } catch {
1773
- return { investigations, crs };
1774
- }
1775
- for (const filename of files) {
1776
- try {
1777
- const filePath = path4.join(dir, filename);
1778
- const raw = fs2.readFileSync(filePath);
1779
- const json = decrypt(raw, this.key);
1780
- if (filename.startsWith("inv-") && filename.endsWith(".json")) {
1781
- const item = JSON.parse(json);
1782
- investigations.push({
1783
- ...item,
1784
- completedAt: new Date(item.completedAt)
1785
- });
1786
- } else if (filename.startsWith("cr-") && filename.endsWith(".json")) {
1787
- const item = JSON.parse(json);
1788
- crs.push({
1789
- ...item,
1790
- startedAt: new Date(item.startedAt),
1791
- resolvedInteractions: item.resolvedInteractions ?? []
1792
- });
1793
- }
1794
- } catch {
1795
- console.warn(`[PRBEAgent] Skipping unreadable history file: ${filename}`);
1796
- }
1797
- }
1798
- } catch {
1799
- }
1800
- investigations.sort(
1801
- (a, b) => b.completedAt.getTime() - a.completedAt.getTime()
1802
- );
1803
- crs.sort((a, b) => b.startedAt.getTime() - a.startedAt.getTime());
1804
- return { investigations, crs };
1805
- }
1806
- save(investigations, crs) {
1807
- try {
1808
- const dir = getHistoryDir();
1809
- const desiredFiles = /* @__PURE__ */ new Set();
1810
- for (const inv of investigations) {
1811
- const filename = `inv-${inv.id}.json`;
1812
- desiredFiles.add(filename);
1813
- const data = {
1814
- id: inv.id,
1815
- query: inv.query,
1816
- report: inv.report,
1817
- summary: inv.summary,
1818
- ticketId: inv.ticketId,
1819
- events: inv.events,
1820
- resolvedInteractions: inv.resolvedInteractions,
1821
- conversationHistory: inv.conversationHistory,
1822
- completedAt: inv.completedAt.toISOString()
1823
- };
1824
- fs2.writeFileSync(
1825
- path4.join(dir, filename),
1826
- encrypt(JSON.stringify(data), this.key)
1827
- );
1828
- }
1829
- for (const cr of crs) {
1830
- const filename = `cr-${cr.id}.json`;
1831
- desiredFiles.add(filename);
1832
- const data = {
1833
- id: cr.id,
1834
- query: cr.query,
1835
- slug: cr.slug,
1836
- ticketId: cr.ticketId,
1837
- events: cr.events,
1838
- isRunning: cr.isRunning,
1839
- isCompleted: cr.isCompleted,
1840
- isFailed: cr.isFailed,
1841
- report: cr.report,
1842
- summary: cr.summary,
1843
- errorMessage: cr.errorMessage,
1844
- startedAt: cr.startedAt.toISOString(),
1845
- pendingInteraction: cr.pendingInteraction,
1846
- resolvedInteractions: cr.resolvedInteractions ?? []
1847
- };
1848
- fs2.writeFileSync(
1849
- path4.join(dir, filename),
1850
- encrypt(JSON.stringify(data), this.key)
1851
- );
1852
- }
1853
- try {
1854
- const existing = fs2.readdirSync(dir);
1855
- for (const filename of existing) {
1856
- if (!desiredFiles.has(filename)) {
1857
- fs2.unlinkSync(path4.join(dir, filename));
1858
- }
1859
- }
1860
- } catch {
1861
- }
1862
- } catch {
1863
- console.error("[PRBEAgent] Failed to save investigation history");
1864
- }
1865
- }
1866
- static clear() {
1867
- try {
1868
- const dir = path4.join(getAppDataDir(), "history" /* HISTORY_DIR */);
1869
- if (fs2.existsSync(dir)) {
1870
- fs2.rmSync(dir, { recursive: true, force: true });
1871
- }
1872
- } catch {
1873
- }
1874
- }
1875
- };
1876
-
1877
- // src/agent.ts
1878
- function getPersistencePath() {
1879
- const appData = process.env["APPDATA"] || (process.platform === "darwin" ? path5.join(os2.homedir(), "Library", "Application Support") : path5.join(os2.homedir(), ".local", "share"));
1880
- const dir = path5.join(appData, "prbe-agent");
1881
- if (!fs3.existsSync(dir)) {
1882
- fs3.mkdirSync(dir, { recursive: true });
1883
- }
1884
- return path5.join(dir, "agent-state.json");
1723
+ return path4.join(dir, "agent-state.json");
1885
1724
  }
1886
1725
  function loadPersistedData() {
1887
1726
  try {
1888
1727
  const filePath = getPersistencePath();
1889
- if (fs3.existsSync(filePath)) {
1890
- const raw = fs3.readFileSync(filePath, "utf-8");
1728
+ if (fs2.existsSync(filePath)) {
1729
+ const raw = fs2.readFileSync(filePath, "utf-8");
1891
1730
  return JSON.parse(raw);
1892
1731
  }
1893
1732
  } catch {
@@ -1897,7 +1736,7 @@ function loadPersistedData() {
1897
1736
  function savePersistedData(data) {
1898
1737
  try {
1899
1738
  const filePath = getPersistencePath();
1900
- fs3.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
1739
+ fs2.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
1901
1740
  } catch {
1902
1741
  console.error("[PRBEAgent] Failed to save persisted data");
1903
1742
  }
@@ -1917,8 +1756,7 @@ var PRBEAgent = class _PRBEAgent {
1917
1756
  persistedData;
1918
1757
  fetchAbortController = null;
1919
1758
  currentInvestigationSource = "user" /* USER */;
1920
- currentCRId = null;
1921
- historyStore;
1759
+ currentBackgroundId = null;
1922
1760
  /** Files flagged during the current tool call — uploaded immediately after the tool returns. */
1923
1761
  pendingFlaggedFiles = [];
1924
1762
  // ---------- User Identifier ----------
@@ -1934,30 +1772,6 @@ var PRBEAgent = class _PRBEAgent {
1934
1772
  savePersistedData(this.persistedData);
1935
1773
  return newID;
1936
1774
  }
1937
- get trackedSessionIDs() {
1938
- return this.persistedData.sessionIds ?? [];
1939
- }
1940
- set trackedSessionIDs(ids) {
1941
- this.persistedData.sessionIds = ids;
1942
- savePersistedData(this.persistedData);
1943
- this.state.updateTrackedSessionIDs(ids);
1944
- this.syncPolling(ids.length > 0);
1945
- }
1946
- syncPolling(hasSessions) {
1947
- if (this.config.backgroundPolling && hasSessions) {
1948
- if (this.pollingTimer === null) {
1949
- this.startPolling();
1950
- }
1951
- } else if (!hasSessions) {
1952
- this.stopPolling();
1953
- }
1954
- }
1955
- addTrackedSession(id) {
1956
- const ids = this.trackedSessionIDs;
1957
- if (!ids.includes(id)) {
1958
- this.trackedSessionIDs = [...ids, id];
1959
- }
1960
- }
1961
1775
  // ---------- Constructor ----------
1962
1776
  constructor(config) {
1963
1777
  this.config = {
@@ -1977,11 +1791,7 @@ var PRBEAgent = class _PRBEAgent {
1977
1791
  this.state = new PRBEAgentState();
1978
1792
  this.logCapture = new PRBELogCapture(this.config.maxLogEntries);
1979
1793
  this.persistedData = loadPersistedData();
1980
- this.historyStore = new HistoryStore(this.config.apiKey);
1981
1794
  void this.agentID;
1982
- const history = this.historyStore.load();
1983
- this.state.completedInvestigations = history.investigations;
1984
- this.state.completedCRs = history.crs;
1985
1795
  const roots = this.config.autoApprovedDirs;
1986
1796
  const requester = this.interactionHandler ? this : void 0;
1987
1797
  const grantedPaths = this.grantedPaths;
@@ -2013,8 +1823,8 @@ var PRBEAgent = class _PRBEAgent {
2013
1823
  [{ name: "message", type: "STRING" /* STRING */, description: "Message for the user", required: true }],
2014
1824
  async (args) => {
2015
1825
  const message = args["message"] ?? "";
2016
- if (this.currentInvestigationSource === "context_request" /* CONTEXT_REQUEST */ && this.currentCRId) {
2017
- this.state.setCRAgentMessage(this.currentCRId, message);
1826
+ if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
1827
+ this.state.setBackgroundAgentMessage(this.currentBackgroundId, message);
2018
1828
  } else {
2019
1829
  this.state.setAgentMessage(message);
2020
1830
  }
@@ -2031,9 +1841,8 @@ var PRBEAgent = class _PRBEAgent {
2031
1841
  if (config.ipcMain) {
2032
1842
  this.hookRendererLogs(config.ipcMain, config.rendererLogChannel ?? "prbe-renderer-log");
2033
1843
  }
2034
- const existingSessions = this.trackedSessionIDs;
2035
- if (existingSessions.length > 0) {
2036
- this.trackedSessionIDs = existingSessions;
1844
+ if (this.config.backgroundPolling) {
1845
+ this.startPolling();
2037
1846
  }
2038
1847
  }
2039
1848
  // ---------- Log integration ----------
@@ -2087,15 +1896,15 @@ var PRBEAgent = class _PRBEAgent {
2087
1896
  "No interaction handler configured"
2088
1897
  );
2089
1898
  }
2090
- if (this.currentInvestigationSource === "context_request" /* CONTEXT_REQUEST */ && this.currentCRId) {
2091
- this.state.setCRPendingInteraction(this.currentCRId, payload);
1899
+ if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
1900
+ this.state.setBackgroundPendingInteraction(this.currentBackgroundId, payload);
2092
1901
  } else {
2093
1902
  this.state.setPendingInteraction(payload);
2094
1903
  }
2095
1904
  try {
2096
1905
  const response = await this.interactionHandler.handleInteraction(payload);
2097
- if (this.currentInvestigationSource === "context_request" /* CONTEXT_REQUEST */ && this.currentCRId) {
2098
- this.state.resolveCRInteraction(this.currentCRId, response);
1906
+ if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
1907
+ this.state.resolveBackgroundInteraction(this.currentBackgroundId, response);
2099
1908
  } else {
2100
1909
  this.state.resolveInteraction(response);
2101
1910
  }
@@ -2108,8 +1917,8 @@ var PRBEAgent = class _PRBEAgent {
2108
1917
  }
2109
1918
  return response;
2110
1919
  } catch (err) {
2111
- if (this.currentInvestigationSource === "context_request" /* CONTEXT_REQUEST */ && this.currentCRId) {
2112
- this.state.clearCRPendingInteraction(this.currentCRId);
1920
+ if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
1921
+ this.state.clearBackgroundPendingInteraction(this.currentBackgroundId);
2113
1922
  } else {
2114
1923
  this.state.clearPendingInteraction();
2115
1924
  }
@@ -2181,58 +1990,92 @@ var PRBEAgent = class _PRBEAgent {
2181
1990
  new PRBEClosureTool(name, description, parameters, handler, options)
2182
1991
  );
2183
1992
  }
2184
- /**
2185
- * User-initiated investigation. Updates `state` events/report directly.
2186
- */
2187
- async investigate(query, contextRequestID) {
2188
- this.userCancelled = false;
2189
- this.currentInvestigationSource = "user" /* USER */;
2190
- this.currentCRId = null;
2191
- this.state.beginInvestigation(query);
1993
+ // ---------- Unified Investigation ----------
1994
+ async runInvestigation(opts) {
1995
+ this.currentInvestigationSource = opts.source;
1996
+ this.currentBackgroundId = opts.sourceId ?? null;
1997
+ const isBackground = opts.source !== "user" /* USER */;
2192
1998
  const emitter = (status) => {
2193
1999
  switch (status.type) {
2194
2000
  case "started" /* STARTED */:
2195
- this.state.appendEvent("Starting investigation...");
2001
+ if (isBackground && opts.sourceId) {
2002
+ this.state.appendBackgroundEvent(opts.sourceId, "Starting investigation...");
2003
+ } else {
2004
+ this.state.appendEvent("Starting investigation...");
2005
+ }
2196
2006
  break;
2197
2007
  case "thinking" /* THINKING */:
2198
2008
  break;
2199
2009
  case "tool_call" /* TOOL_CALL */:
2200
- this.state.appendEvent(status.label);
2010
+ if (isBackground && opts.sourceId) {
2011
+ this.state.appendBackgroundEvent(opts.sourceId, status.label);
2012
+ } else {
2013
+ this.state.appendEvent(status.label);
2014
+ }
2201
2015
  break;
2202
2016
  case "observation" /* OBSERVATION */:
2203
- this.state.attachObservation(status.text);
2017
+ if (isBackground && opts.sourceId) {
2018
+ this.state.attachBackgroundObservation(opts.sourceId, status.text);
2019
+ } else {
2020
+ this.state.attachObservation(status.text);
2021
+ }
2204
2022
  break;
2205
2023
  case "thought" /* THOUGHT */:
2206
- this.state.appendEvent("Thinking", status.text);
2024
+ if (isBackground && opts.sourceId) {
2025
+ this.state.appendBackgroundEvent(opts.sourceId, "Thinking", status.text);
2026
+ } else {
2027
+ this.state.appendEvent("Thinking", status.text);
2028
+ }
2207
2029
  break;
2208
2030
  case "completed" /* COMPLETED */:
2209
- this.state.completeInvestigation(status.report, status.ticketId);
2210
- this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
2031
+ if (isBackground && opts.sourceId) {
2032
+ this.state.completeBackgroundInvestigation(opts.sourceId, status.report);
2033
+ } else {
2034
+ this.state.completeInvestigation(status.report, status.ticketId);
2035
+ }
2211
2036
  break;
2212
2037
  case "error" /* ERROR */:
2213
- this.state.failInvestigation(status.message);
2038
+ if (isBackground && opts.sourceId) {
2039
+ this.state.failBackgroundInvestigation(opts.sourceId, status.message);
2040
+ } else {
2041
+ this.state.failInvestigation(status.message);
2042
+ }
2214
2043
  break;
2215
2044
  }
2216
2045
  };
2217
2046
  const result = await this.connectToProxy(
2218
- query,
2219
- contextRequestID,
2047
+ opts.query,
2048
+ opts.contextRequestId,
2049
+ opts.externalRequestId,
2050
+ opts.externalRequestSource,
2051
+ opts.externalRequestSourceDetail,
2220
2052
  emitter,
2221
- () => this.userCancelled
2053
+ opts.cancellable ? () => this.userCancelled : () => false,
2054
+ opts.ticketId
2222
2055
  );
2223
2056
  this.currentInvestigationSource = "user" /* USER */;
2224
- this.currentCRId = null;
2225
- if (result?.sessionId) {
2226
- this.addTrackedSession(result.sessionId);
2227
- } else if (!result) {
2228
- if (this.state.isInvestigating) {
2229
- const message = this.userCancelled ? "Investigation cancelled" : "Investigation ended unexpectedly";
2230
- this.state.failInvestigation(message);
2231
- }
2057
+ this.currentBackgroundId = null;
2058
+ return result;
2059
+ }
2060
+ /**
2061
+ * User-initiated investigation. Updates `state` events/report directly.
2062
+ */
2063
+ async investigate(query, contextRequestID) {
2064
+ this.userCancelled = false;
2065
+ this.state.beginInvestigation(query);
2066
+ const result = await this.runInvestigation({
2067
+ query,
2068
+ source: "user" /* USER */,
2069
+ contextRequestId: contextRequestID,
2070
+ cancellable: true
2071
+ });
2072
+ if (!result && this.state.isInvestigating) {
2073
+ const message = this.userCancelled ? "Investigation cancelled" : "Investigation ended unexpectedly";
2074
+ this.state.failInvestigation(message);
2232
2075
  }
2233
2076
  }
2234
2077
  /**
2235
- * Cancel user-initiated investigation only (does not cancel background CRs).
2078
+ * Cancel user-initiated investigation only (does not cancel background investigations).
2236
2079
  */
2237
2080
  cancelInvestigation() {
2238
2081
  this.userCancelled = true;
@@ -2254,41 +2097,21 @@ var PRBEAgent = class _PRBEAgent {
2254
2097
  this.stopPolling();
2255
2098
  }
2256
2099
  /**
2257
- * Poll the backend for context requests on tracked tickets.
2258
- * Resolves session IDs → ticket IDs first, then polls with ticket IDs.
2100
+ * Poll the backend for context requests and external requests.
2259
2101
  */
2260
2102
  async poll() {
2261
- const sessionIDs = this.trackedSessionIDs;
2262
- if (sessionIDs.length === 0) return null;
2263
2103
  try {
2264
- const resolved = await this.resolveSessions(sessionIDs);
2265
- const returnedSessionIDs = new Set(
2266
- resolved.tickets.flatMap((t) => t.session_ids)
2267
- );
2268
- const resolvedSessionIDs = new Set(
2269
- resolved.tickets.filter((t) => t.status === "resolved").flatMap((t) => t.session_ids)
2270
- );
2271
- const survivingSessions = sessionIDs.filter(
2272
- (id) => returnedSessionIDs.has(id) && !resolvedSessionIDs.has(id)
2273
- );
2274
- if (survivingSessions.length !== sessionIDs.length) {
2275
- this.trackedSessionIDs = survivingSessions;
2104
+ const request = { agent_id: this.agentID };
2105
+ const response = await this.post("/api/agent/poll", request);
2106
+ for (const cr of response.context_requests) {
2107
+ if (!cr.is_active) continue;
2108
+ if (this.state.activeBackgroundInvestigations.has(cr.id)) continue;
2109
+ await this.investigateForCR(cr, cr.ticket_id);
2276
2110
  }
2277
- const ticketIDs = resolved.tickets.filter((t) => t.status !== "resolved").map((t) => t.ticket_id);
2278
- if (ticketIDs.length === 0) return { tickets: [] };
2279
- const request = {
2280
- agent_id: this.agentID,
2281
- ticket_ids: ticketIDs
2282
- };
2283
- const response = await this.post(
2284
- "/api/agent/poll",
2285
- request
2286
- );
2287
- for (const ticket of response.tickets) {
2288
- for (const cr of ticket.context_requests) {
2289
- if (!cr.is_active) continue;
2290
- await this.investigateForCR(cr, ticket.ticket_id);
2291
- }
2111
+ for (const er of response.external_requests) {
2112
+ if (!er.is_active) continue;
2113
+ if (this.state.activeBackgroundInvestigations.has(er.id)) continue;
2114
+ await this.investigateForER(er);
2292
2115
  }
2293
2116
  return response;
2294
2117
  } catch {
@@ -2296,25 +2119,18 @@ var PRBEAgent = class _PRBEAgent {
2296
2119
  }
2297
2120
  }
2298
2121
  /**
2299
- * Fetch ticket display info for all tracked sessions.
2300
- * Resolves session IDs → ticket IDs first, then fetches ticket info.
2122
+ * Fetch agent history (tickets + sessions) from the backend.
2301
2123
  */
2302
- async fetchTicketInfo() {
2303
- const sessionIDs = this.trackedSessionIDs;
2304
- if (sessionIDs.length === 0) return [];
2124
+ async fetchHistory() {
2305
2125
  try {
2306
- const resolved = await this.resolveSessions(sessionIDs);
2307
- const ticketIDs = resolved.tickets.map((t) => t.ticket_id);
2308
- if (ticketIDs.length === 0) return [];
2309
- const request = { ticket_ids: ticketIDs };
2310
2126
  const response = await this.post(
2311
- "/api/agent/tickets",
2312
- request
2127
+ "/api/agent/history",
2128
+ { agent_id: this.agentID }
2313
2129
  );
2314
- this.state.updateTicketInfo(response.tickets);
2315
- return response.tickets;
2130
+ this.state.updateAgentHistory(response.tickets);
2131
+ return response;
2316
2132
  } catch {
2317
- return [];
2133
+ return null;
2318
2134
  }
2319
2135
  }
2320
2136
  stopPolling() {
@@ -2324,7 +2140,7 @@ var PRBEAgent = class _PRBEAgent {
2324
2140
  }
2325
2141
  }
2326
2142
  resumePolling() {
2327
- if (this.trackedSessionIDs.length === 0) return;
2143
+ if (!this.config.backgroundPolling) return;
2328
2144
  this.startPolling();
2329
2145
  }
2330
2146
  /**
@@ -2342,13 +2158,11 @@ var PRBEAgent = class _PRBEAgent {
2342
2158
  this.stopPolling();
2343
2159
  this.persistedData = {};
2344
2160
  savePersistedData(this.persistedData);
2345
- HistoryStore.clear();
2346
2161
  this.state.resetInvestigation();
2347
2162
  this.state.completedInvestigations = [];
2348
- this.state.activeCRs.clear();
2349
- this.state.completedCRs = [];
2350
- this.state.trackedSessionIDs = [];
2351
- this.state.ticketInfo = [];
2163
+ this.state.activeBackgroundInvestigations.clear();
2164
+ this.state.completedBackgroundInvestigations = [];
2165
+ this.state.agentHistory = [];
2352
2166
  this.state.emit("status" /* STATUS */);
2353
2167
  }
2354
2168
  /**
@@ -2357,61 +2171,38 @@ var PRBEAgent = class _PRBEAgent {
2357
2171
  static clearPersistedData() {
2358
2172
  try {
2359
2173
  const filePath = getPersistencePath();
2360
- if (fs3.existsSync(filePath)) {
2361
- fs3.unlinkSync(filePath);
2174
+ if (fs2.existsSync(filePath)) {
2175
+ fs2.unlinkSync(filePath);
2362
2176
  }
2363
- HistoryStore.clear();
2364
2177
  } catch {
2365
2178
  }
2366
2179
  }
2367
- // ---------- CR Investigation ----------
2180
+ // ---------- Background Investigation ----------
2368
2181
  async investigateForCR(cr, ticketId) {
2369
- const crID = cr.id;
2370
- this.currentInvestigationSource = "context_request" /* CONTEXT_REQUEST */;
2371
- this.currentCRId = crID;
2372
- this.state.beginCR(crID, cr.query, cr.slug ?? void 0, ticketId);
2373
- const emitter = (status) => {
2374
- switch (status.type) {
2375
- case "started" /* STARTED */:
2376
- this.state.appendCREvent(crID, "Starting investigation...");
2377
- break;
2378
- case "thinking" /* THINKING */:
2379
- break;
2380
- case "tool_call" /* TOOL_CALL */:
2381
- this.state.appendCREvent(crID, status.label);
2382
- break;
2383
- case "observation" /* OBSERVATION */:
2384
- this.state.attachCRObservation(crID, status.text);
2385
- break;
2386
- case "thought" /* THOUGHT */:
2387
- this.state.appendCREvent(crID, "Thinking", status.text);
2388
- break;
2389
- case "completed" /* COMPLETED */:
2390
- this.state.completeCR(crID, status.report);
2391
- this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
2392
- break;
2393
- case "error" /* ERROR */:
2394
- this.state.failCR(crID, status.message);
2395
- this.historyStore.save(this.state.completedInvestigations, this.state.completedCRs);
2396
- break;
2397
- }
2398
- };
2399
- const result = await this.connectToProxy(
2400
- cr.query,
2401
- crID,
2402
- emitter,
2403
- () => false,
2404
- // CRs are not user-cancellable
2405
- ticketId
2406
- );
2407
- this.currentInvestigationSource = "user" /* USER */;
2408
- this.currentCRId = null;
2409
- if (result?.sessionId) {
2410
- this.addTrackedSession(result.sessionId);
2411
- }
2182
+ this.state.beginBackgroundInvestigation(cr.id, cr.query, cr.slug ?? void 0, ticketId);
2183
+ await this.runInvestigation({
2184
+ query: cr.query,
2185
+ source: "context_request" /* CONTEXT_REQUEST */,
2186
+ sourceId: cr.id,
2187
+ contextRequestId: cr.id,
2188
+ ticketId,
2189
+ cancellable: false
2190
+ });
2191
+ }
2192
+ async investigateForER(er) {
2193
+ this.state.beginBackgroundInvestigation(er.id, er.query, void 0, void 0, er.source, er.source_detail);
2194
+ await this.runInvestigation({
2195
+ query: er.query,
2196
+ source: "external_request" /* EXTERNAL_REQUEST */,
2197
+ sourceId: er.id,
2198
+ externalRequestId: er.id,
2199
+ externalRequestSource: er.source,
2200
+ externalRequestSourceDetail: er.source_detail,
2201
+ cancellable: false
2202
+ });
2412
2203
  }
2413
2204
  // ---------- WebSocket Investigation ----------
2414
- connectToProxy(query, contextRequestID, emit, isCancelled, ticketId) {
2205
+ connectToProxy(query, contextRequestID, externalRequestId, externalRequestSource, externalRequestSourceDetail, emit, isCancelled, ticketId) {
2415
2206
  return new Promise((resolve2) => {
2416
2207
  const wsUrl = `${MIDDLEWARE_URL}/api/agent/client/ws`;
2417
2208
  let uploadBaseUrl;
@@ -2466,11 +2257,14 @@ var PRBEAgent = class _PRBEAgent {
2466
2257
  const startMetadata = {
2467
2258
  agent_id: this.agentID,
2468
2259
  custom_tools: toolDeclarations,
2469
- platform: os2.platform(),
2470
- os_version: os2.release(),
2471
- arch: os2.arch()
2260
+ platform: os.platform(),
2261
+ os_version: os.release(),
2262
+ arch: os.arch()
2472
2263
  };
2473
2264
  if (contextRequestID) startMetadata["context_request_id"] = contextRequestID;
2265
+ if (externalRequestId) startMetadata["external_request_id"] = externalRequestId;
2266
+ if (externalRequestSource) startMetadata["external_request_source"] = externalRequestSource;
2267
+ if (externalRequestSourceDetail) startMetadata["external_request_source_detail"] = externalRequestSourceDetail;
2474
2268
  if (ticketId) startMetadata["ticket_id"] = ticketId;
2475
2269
  if (this.appDataPath) startMetadata["app_data_path"] = this.appDataPath;
2476
2270
  const enrichedMetadata = { ...this.sessionMetadata };
@@ -2518,7 +2312,7 @@ var PRBEAgent = class _PRBEAgent {
2518
2312
  const uploadPrefix = this.extractUploadPrefix(uploadBaseUrl);
2519
2313
  const uploadedRefs = [];
2520
2314
  for (const file of this.pendingFlaggedFiles) {
2521
- const filename = path5.basename(file.originalPath);
2315
+ const filename = path4.basename(file.originalPath);
2522
2316
  const safeName = encodeURIComponent(filename);
2523
2317
  const storagePath = `${uploadPrefix}/${safeName}`;
2524
2318
  uploadedRefs.push({
@@ -2563,7 +2357,11 @@ var PRBEAgent = class _PRBEAgent {
2563
2357
  case "conversation_update" /* CONVERSATION_UPDATE */: {
2564
2358
  try {
2565
2359
  const entry = JSON.parse(msg.content ?? "{}");
2566
- this.state.appendConversation(entry);
2360
+ if (this.currentInvestigationSource !== "user" /* USER */ && this.currentBackgroundId) {
2361
+ this.state.appendBackgroundConversation(this.currentBackgroundId, entry);
2362
+ } else {
2363
+ this.state.appendConversation(entry);
2364
+ }
2567
2365
  } catch {
2568
2366
  }
2569
2367
  break;
@@ -2621,24 +2419,9 @@ var PRBEAgent = class _PRBEAgent {
2621
2419
  startPolling() {
2622
2420
  this.stopPolling();
2623
2421
  this.pollingTimer = setInterval(() => {
2624
- void this.poll().then(() => {
2625
- if (this.trackedSessionIDs.length === 0) {
2626
- this.stopPolling();
2627
- }
2628
- });
2422
+ void this.poll();
2629
2423
  }, this.config.pollingInterval);
2630
2424
  }
2631
- // ---------- Session Resolution ----------
2632
- async resolveSessions(sessionIDs) {
2633
- const request = {
2634
- agent_id: this.agentID,
2635
- session_ids: sessionIDs
2636
- };
2637
- return this.post(
2638
- "/api/agent/resolve-sessions",
2639
- request
2640
- );
2641
- }
2642
2425
  // ---------- Networking ----------
2643
2426
  /**
2644
2427
  * Abort all in-flight fetch requests to prevent orphaned DNS lookups
@@ -2692,29 +2475,32 @@ var DEFAULT_PRBE_STATE = {
2692
2475
  resolvedInteractions: [],
2693
2476
  conversationHistory: [],
2694
2477
  completedInvestigations: [],
2695
- activeCRs: [],
2696
- completedCRs: [],
2697
- trackedSessionIDs: [],
2478
+ activeBackgroundInvestigations: [],
2479
+ completedBackgroundInvestigations: [],
2698
2480
  ticketInfo: [],
2481
+ agentHistory: [],
2699
2482
  hasActiveWork: false
2700
2483
  };
2701
- function serializeCR(cr) {
2484
+ function serializeBackgroundInvestigation(bg) {
2702
2485
  return {
2703
- id: cr.id,
2704
- query: cr.query,
2705
- slug: cr.slug,
2706
- ticketId: cr.ticketId,
2707
- events: cr.events,
2708
- isRunning: cr.isRunning,
2709
- isCompleted: cr.isCompleted,
2710
- isFailed: cr.isFailed,
2711
- report: cr.report,
2712
- summary: cr.summary,
2713
- errorMessage: cr.errorMessage,
2714
- agentMessage: cr.agentMessage,
2715
- startedAt: cr.startedAt.toISOString(),
2716
- pendingInteraction: cr.pendingInteraction,
2717
- resolvedInteractions: cr.resolvedInteractions ?? []
2486
+ id: bg.id,
2487
+ query: bg.query,
2488
+ slug: bg.slug,
2489
+ ticketId: bg.ticketId,
2490
+ source: bg.source,
2491
+ sourceDetail: bg.sourceDetail,
2492
+ events: bg.events,
2493
+ isRunning: bg.isRunning,
2494
+ isCompleted: bg.isCompleted,
2495
+ isFailed: bg.isFailed,
2496
+ report: bg.report,
2497
+ summary: bg.summary,
2498
+ errorMessage: bg.errorMessage,
2499
+ agentMessage: bg.agentMessage,
2500
+ startedAt: bg.startedAt.toISOString(),
2501
+ pendingInteraction: bg.pendingInteraction,
2502
+ resolvedInteractions: bg.resolvedInteractions ?? [],
2503
+ conversationHistory: bg.conversationHistory ?? []
2718
2504
  };
2719
2505
  }
2720
2506
  function serializePRBEState(state) {
@@ -2740,10 +2526,10 @@ function serializePRBEState(state) {
2740
2526
  conversationHistory: inv.conversationHistory,
2741
2527
  completedAt: inv.completedAt.toISOString()
2742
2528
  })),
2743
- activeCRs: Array.from(state.activeCRs.values()).map(serializeCR),
2744
- completedCRs: state.completedCRs.map(serializeCR),
2745
- trackedSessionIDs: state.trackedSessionIDs,
2529
+ activeBackgroundInvestigations: Array.from(state.activeBackgroundInvestigations.values()).map(serializeBackgroundInvestigation),
2530
+ completedBackgroundInvestigations: state.completedBackgroundInvestigations.map(serializeBackgroundInvestigation),
2746
2531
  ticketInfo: state.ticketInfo,
2532
+ agentHistory: state.agentHistory,
2747
2533
  hasActiveWork: state.hasActiveWork
2748
2534
  };
2749
2535
  }