@sesamespace/hivemind 0.8.13 → 0.10.0

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.
Files changed (54) hide show
  1. package/README.md +2 -1
  2. package/dist/{chunk-MLY4VFOO.js → chunk-BHCDOHSK.js} +3 -3
  3. package/dist/{chunk-PFZO67E2.js → chunk-DPLCEMEC.js} +2 -2
  4. package/dist/{chunk-HTLHMXAL.js → chunk-FBQBBAPZ.js} +2 -2
  5. package/dist/{chunk-NSTTILSN.js → chunk-FK6WYXRM.js} +79 -2
  6. package/dist/chunk-FK6WYXRM.js.map +1 -0
  7. package/dist/{chunk-LJHJGDKY.js → chunk-ICSJNKI6.js} +62 -2
  8. package/dist/chunk-ICSJNKI6.js.map +1 -0
  9. package/dist/{chunk-4Y7A25UG.js → chunk-IXBIAX76.js} +2 -2
  10. package/dist/{chunk-ZM7RK5YV.js → chunk-M3A2WRXM.js} +560 -37
  11. package/dist/chunk-M3A2WRXM.js.map +1 -0
  12. package/dist/commands/fleet.js +3 -3
  13. package/dist/commands/init.js +3 -3
  14. package/dist/commands/start.js +3 -3
  15. package/dist/commands/upgrade.js +1 -1
  16. package/dist/commands/watchdog.js +3 -3
  17. package/dist/dashboard.html +873 -131
  18. package/dist/index.js +2 -2
  19. package/dist/main.js +375 -7
  20. package/dist/main.js.map +1 -1
  21. package/dist/start.js +1 -1
  22. package/install.sh +162 -0
  23. package/package.json +24 -23
  24. package/packages/memory/Cargo.lock +6480 -0
  25. package/packages/memory/Cargo.toml +21 -0
  26. package/packages/memory/src/src/context.rs +179 -0
  27. package/packages/memory/src/src/embeddings.rs +51 -0
  28. package/packages/memory/src/src/main.rs +887 -0
  29. package/packages/memory/src/src/promotion.rs +808 -0
  30. package/packages/memory/src/src/scoring.rs +142 -0
  31. package/packages/memory/src/src/store.rs +460 -0
  32. package/packages/memory/src/src/tasks.rs +321 -0
  33. package/.pnpmrc.json +0 -1
  34. package/AUTO-DEBUG-DESIGN.md +0 -267
  35. package/DASHBOARD-PLAN.md +0 -206
  36. package/MEMORY-ENHANCEMENT-PLAN.md +0 -211
  37. package/TOOL-USE-DESIGN.md +0 -173
  38. package/dist/chunk-LJHJGDKY.js.map +0 -1
  39. package/dist/chunk-NSTTILSN.js.map +0 -1
  40. package/dist/chunk-ZM7RK5YV.js.map +0 -1
  41. package/docs/TOOL-PARITY-PLAN.md +0 -191
  42. package/src/memory/dashboard-integration.ts +0 -295
  43. package/src/memory/index.ts +0 -187
  44. package/src/memory/performance-test.ts +0 -208
  45. package/src/memory/processors/agent-sync.ts +0 -312
  46. package/src/memory/processors/command-learner.ts +0 -298
  47. package/src/memory/processors/memory-api-client.ts +0 -105
  48. package/src/memory/processors/message-flow-integration.ts +0 -168
  49. package/src/memory/processors/research-digester.ts +0 -204
  50. package/test-caitlin-access.md +0 -11
  51. /package/dist/{chunk-MLY4VFOO.js.map → chunk-BHCDOHSK.js.map} +0 -0
  52. /package/dist/{chunk-PFZO67E2.js.map → chunk-DPLCEMEC.js.map} +0 -0
  53. /package/dist/{chunk-HTLHMXAL.js.map → chunk-FBQBBAPZ.js.map} +0 -0
  54. /package/dist/{chunk-4Y7A25UG.js.map → chunk-IXBIAX76.js.map} +0 -0
@@ -1343,14 +1343,15 @@ var Agent = class {
1343
1343
  });
1344
1344
  if (relevantEpisodes.length > 0) {
1345
1345
  const episodeIds = relevantEpisodes.map((e) => e.id);
1346
- this.memory.recordCoAccess(episodeIds).catch(() => {
1347
- });
1346
+ this.memory.recordCoAccess(episodeIds).catch((err) => console.warn("[memory] recordCoAccess failed:", err.message));
1348
1347
  for (const ep of relevantEpisodes) {
1349
- this.memory.recordAccess(ep.id).catch(() => {
1350
- });
1348
+ this.memory.recordAccess(ep.id).catch((err) => console.warn("[memory] recordAccess failed:", err.message));
1351
1349
  }
1352
1350
  }
1353
- const l3Knowledge = await this.memory.getL3Knowledge(contextName).catch(() => []);
1351
+ const l3Knowledge = await this.memory.getL3Knowledge(contextName).catch((err) => {
1352
+ console.warn("[memory] getL3Knowledge failed:", err.message);
1353
+ return [];
1354
+ });
1354
1355
  const systemPromptResult = buildSystemPrompt({
1355
1356
  config: this.config.agent,
1356
1357
  episodes: relevantEpisodes,
@@ -1587,6 +1588,9 @@ var Agent = class {
1587
1588
  getActiveContext() {
1588
1589
  return this.contextManager.getActiveContext();
1589
1590
  }
1591
+ getConversationHistories() {
1592
+ return this.conversationHistories;
1593
+ }
1590
1594
  };
1591
1595
 
1592
1596
  // packages/runtime/src/events.ts
@@ -4745,29 +4749,43 @@ function parseQuery(url) {
4745
4749
  }
4746
4750
  return params;
4747
4751
  }
4748
- async function proxyMemory(memoryUrl, path, method, res) {
4752
+ function readBody(req) {
4753
+ return new Promise((resolve21, reject) => {
4754
+ const chunks = [];
4755
+ req.on("data", (chunk) => chunks.push(chunk));
4756
+ req.on("end", () => resolve21(Buffer.concat(chunks).toString()));
4757
+ req.on("error", reject);
4758
+ });
4759
+ }
4760
+ async function proxyMemory(memoryUrl, path, method, res, body) {
4749
4761
  try {
4750
- const resp = await fetch(`${memoryUrl}${path}`, { method });
4751
- const body = await resp.text();
4762
+ const opts = { method };
4763
+ if (body && (method === "POST" || method === "PATCH" || method === "PUT")) {
4764
+ opts.body = body;
4765
+ opts.headers = { "Content-Type": "application/json" };
4766
+ }
4767
+ const resp = await fetch(`${memoryUrl}${path}`, opts);
4768
+ const respBody = await resp.text();
4752
4769
  res.writeHead(resp.status, {
4753
4770
  "Content-Type": resp.headers.get("content-type") ?? "application/json",
4754
4771
  "Access-Control-Allow-Origin": "*"
4755
4772
  });
4756
- res.end(body);
4773
+ res.end(respBody);
4757
4774
  } catch (err) {
4758
4775
  json(res, { error: err.message }, 502);
4759
4776
  }
4760
4777
  }
4761
- function startDashboardServer(requestLogger, memoryConfig) {
4778
+ function startDashboardServer(requestLogger, memoryConfig, getL1) {
4762
4779
  const memoryUrl = memoryConfig.daemon_url;
4763
4780
  const server = createServer(async (req, res) => {
4764
4781
  const method = req.method ?? "GET";
4765
4782
  const rawUrl = req.url ?? "/";
4766
4783
  const urlPath = rawUrl.split("?")[0];
4784
+ const queryStr = rawUrl.includes("?") ? rawUrl.slice(rawUrl.indexOf("?")) : "";
4767
4785
  if (method === "OPTIONS") {
4768
4786
  res.writeHead(204, {
4769
4787
  "Access-Control-Allow-Origin": "*",
4770
- "Access-Control-Allow-Methods": "GET, DELETE, OPTIONS",
4788
+ "Access-Control-Allow-Methods": "GET, POST, PATCH, DELETE, OPTIONS",
4771
4789
  "Access-Control-Allow-Headers": "Content-Type"
4772
4790
  });
4773
4791
  res.end();
@@ -4800,10 +4818,32 @@ function startDashboardServer(requestLogger, memoryConfig) {
4800
4818
  }
4801
4819
  return;
4802
4820
  }
4821
+ if (method === "GET" && urlPath === "/api/health") {
4822
+ await proxyMemory(memoryUrl, "/health", "GET", res);
4823
+ return;
4824
+ }
4825
+ if (method === "GET" && urlPath === "/api/stats") {
4826
+ await proxyMemory(memoryUrl, "/stats", "GET", res);
4827
+ return;
4828
+ }
4829
+ if (method === "GET" && urlPath === "/api/search") {
4830
+ await proxyMemory(memoryUrl, `/search${queryStr}`, "GET", res);
4831
+ return;
4832
+ }
4833
+ if (method === "GET" && urlPath === "/api/search/cross-context") {
4834
+ await proxyMemory(memoryUrl, `/search/cross-context${queryStr}`, "GET", res);
4835
+ return;
4836
+ }
4803
4837
  if (method === "GET" && urlPath === "/api/contexts") {
4804
4838
  await proxyMemory(memoryUrl, "/contexts", "GET", res);
4805
4839
  return;
4806
4840
  }
4841
+ const ctxDeleteMatch = urlPath.match(/^\/api\/contexts\/([^/]+)$/);
4842
+ if (method === "DELETE" && ctxDeleteMatch) {
4843
+ const name = decodeURIComponent(ctxDeleteMatch[1]);
4844
+ await proxyMemory(memoryUrl, `/contexts/${encodeURIComponent(name)}`, "DELETE", res);
4845
+ return;
4846
+ }
4807
4847
  const episodesMatch = urlPath.match(/^\/api\/contexts\/([^/]+)\/episodes$/);
4808
4848
  if (method === "GET" && episodesMatch) {
4809
4849
  const name = decodeURIComponent(episodesMatch[1]);
@@ -4821,12 +4861,69 @@ function startDashboardServer(requestLogger, memoryConfig) {
4821
4861
  );
4822
4862
  return;
4823
4863
  }
4824
- const l3DeleteMatch = urlPath.match(/^\/api\/l3\/([^/]+)$/);
4825
- if (method === "DELETE" && l3DeleteMatch) {
4826
- const id = decodeURIComponent(l3DeleteMatch[1]);
4864
+ const scoringGetMatch = urlPath.match(/^\/api\/contexts\/([^/]+)\/scoring$/);
4865
+ if (method === "GET" && scoringGetMatch) {
4866
+ const name = decodeURIComponent(scoringGetMatch[1]);
4867
+ await proxyMemory(memoryUrl, `/scoring/${encodeURIComponent(name)}`, "GET", res);
4868
+ return;
4869
+ }
4870
+ if (method === "POST" && scoringGetMatch) {
4871
+ const name = decodeURIComponent(scoringGetMatch[1]);
4872
+ const body = await readBody(req);
4873
+ await proxyMemory(memoryUrl, `/contexts/${encodeURIComponent(name)}/scoring`, "POST", res, body);
4874
+ return;
4875
+ }
4876
+ const l3IdMatch = urlPath.match(/^\/api\/l3\/([^/]+)$/);
4877
+ if (method === "DELETE" && l3IdMatch) {
4878
+ const id = decodeURIComponent(l3IdMatch[1]);
4827
4879
  await proxyMemory(memoryUrl, `/promotion/l3/${encodeURIComponent(id)}`, "DELETE", res);
4828
4880
  return;
4829
4881
  }
4882
+ if (method === "PATCH" && l3IdMatch) {
4883
+ const id = decodeURIComponent(l3IdMatch[1]);
4884
+ const body = await readBody(req);
4885
+ await proxyMemory(memoryUrl, `/promotion/l3/${encodeURIComponent(id)}`, "PATCH", res, body);
4886
+ return;
4887
+ }
4888
+ if (method === "POST" && urlPath === "/api/promotion/run") {
4889
+ await proxyMemory(memoryUrl, `/promotion/run${queryStr}`, "POST", res);
4890
+ return;
4891
+ }
4892
+ if (method === "GET" && urlPath === "/api/access/top") {
4893
+ await proxyMemory(memoryUrl, `/access/top${queryStr}`, "GET", res);
4894
+ return;
4895
+ }
4896
+ const accessMatch = urlPath.match(/^\/api\/episodes\/([^/]+)\/access$/);
4897
+ if (method === "GET" && accessMatch) {
4898
+ const id = decodeURIComponent(accessMatch[1]);
4899
+ await proxyMemory(memoryUrl, `/access/${encodeURIComponent(id)}`, "GET", res);
4900
+ return;
4901
+ }
4902
+ if (method === "GET" && urlPath === "/api/l1") {
4903
+ if (!getL1) {
4904
+ json(res, { contexts: {} });
4905
+ return;
4906
+ }
4907
+ const histories = getL1();
4908
+ const result = {};
4909
+ for (const [ctx, msgs] of histories) {
4910
+ result[ctx] = { count: msgs.length };
4911
+ }
4912
+ json(res, { contexts: result });
4913
+ return;
4914
+ }
4915
+ const l1CtxMatch = urlPath.match(/^\/api\/l1\/([^/]+)$/);
4916
+ if (method === "GET" && l1CtxMatch) {
4917
+ if (!getL1) {
4918
+ json(res, { messages: [] });
4919
+ return;
4920
+ }
4921
+ const ctx = decodeURIComponent(l1CtxMatch[1]);
4922
+ const histories = getL1();
4923
+ const messages = histories.get(ctx) || [];
4924
+ json(res, { messages: messages.map((m) => ({ role: m.role, content: m.content ?? "" })) });
4925
+ return;
4926
+ }
4830
4927
  json(res, { error: "Not found" }, 404);
4831
4928
  } catch (err) {
4832
4929
  console.error("[dashboard] Request error:", err.message);
@@ -6039,6 +6136,7 @@ import { mkdirSync as mkdirSync9, existsSync as existsSync13 } from "fs";
6039
6136
  import { randomUUID as randomUUID5 } from "crypto";
6040
6137
  var MAX_OUTPUT2 = 5e4;
6041
6138
  var browserInstance = null;
6139
+ var contextInstances = /* @__PURE__ */ new Map();
6042
6140
  var lastUsed = 0;
6043
6141
  var idleTimer = null;
6044
6142
  var IDLE_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -6047,7 +6145,16 @@ async function getBrowser() {
6047
6145
  const modName = "playwright";
6048
6146
  const pw = await Function("m", "return import(m)")(modName);
6049
6147
  if (!browserInstance) {
6050
- browserInstance = await pw.chromium.launch({ headless: true });
6148
+ browserInstance = await pw.chromium.launch({
6149
+ headless: true,
6150
+ args: [
6151
+ "--disable-dev-shm-usage",
6152
+ "--disable-setuid-sandbox",
6153
+ "--no-sandbox",
6154
+ "--disable-web-security",
6155
+ "--disable-features=VizDisplayCompositor"
6156
+ ]
6157
+ });
6051
6158
  if (!idleTimer) {
6052
6159
  idleTimer = setInterval(async () => {
6053
6160
  if (browserInstance && Date.now() - lastUsed > IDLE_TIMEOUT_MS) {
@@ -6064,7 +6171,43 @@ async function getBrowser() {
6064
6171
  );
6065
6172
  }
6066
6173
  }
6174
+ async function getBrowserContext(sessionId = "default", options = {}) {
6175
+ const browser = await getBrowser();
6176
+ if (!contextInstances.has(sessionId)) {
6177
+ const contextOptions = {
6178
+ userAgent: options.userAgent || "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
6179
+ viewport: options.viewport || { width: 1280, height: 720 },
6180
+ locale: options.locale || "en-US",
6181
+ timezoneId: options.timezone || "America/New_York",
6182
+ deviceScaleFactor: options.deviceScaleFactor || 1,
6183
+ isMobile: options.isMobile || false,
6184
+ hasTouch: options.hasTouch || false,
6185
+ colorScheme: options.colorScheme || "light",
6186
+ reducedMotion: options.reducedMotion || "no-preference",
6187
+ permissions: options.permissions || [],
6188
+ geolocation: options.geolocation,
6189
+ offline: options.offline || false,
6190
+ acceptDownloads: options.downloadBehavior !== "deny"
6191
+ };
6192
+ const context = await browser.newContext(contextOptions);
6193
+ context.on("request", (request) => {
6194
+ console.log(`\u2192 ${request.method()} ${request.url()}`);
6195
+ });
6196
+ context.on("response", (response) => {
6197
+ console.log(`\u2190 ${response.status()} ${response.url()}`);
6198
+ });
6199
+ contextInstances.set(sessionId, context);
6200
+ }
6201
+ return contextInstances.get(sessionId);
6202
+ }
6067
6203
  async function closeBrowser() {
6204
+ for (const [sessionId, context] of contextInstances) {
6205
+ try {
6206
+ await context.close();
6207
+ } catch {
6208
+ }
6209
+ }
6210
+ contextInstances.clear();
6068
6211
  if (browserInstance) {
6069
6212
  try {
6070
6213
  await browserInstance.close();
@@ -6082,14 +6225,26 @@ function registerBrowserTools(registry, workspaceDir) {
6082
6225
  registry.register(
6083
6226
  "browse",
6084
6227
  [
6085
- "Navigate to a URL and interact with the page using a headless browser.",
6228
+ "Navigate to a URL and interact with the page using an enhanced headless browser with session persistence.",
6086
6229
  "Actions:",
6087
6230
  " extract (default) \u2014 get the readable text content of the page",
6088
6231
  " screenshot \u2014 take a PNG screenshot and return the file path",
6089
6232
  " click \u2014 click an element matching a CSS selector",
6090
6233
  " type \u2014 type text into an element matching a CSS selector",
6091
6234
  " evaluate \u2014 run arbitrary JavaScript in the page and return the result",
6092
- "Supports waitForSelector to wait for dynamic content before acting."
6235
+ " form_fill \u2014 fill out a form with multiple fields at once",
6236
+ " scroll \u2014 scroll the page (up, down, to element, or to coordinates)",
6237
+ " hover \u2014 hover over an element",
6238
+ " select \u2014 select an option from a dropdown",
6239
+ " upload \u2014 upload a file to a file input",
6240
+ " download \u2014 download a file and return the path",
6241
+ " pdf \u2014 generate a PDF of the page",
6242
+ " wait_for \u2014 wait for various conditions (selector, text, url, timeout)",
6243
+ " network_logs \u2014 get network request/response logs",
6244
+ " console_logs \u2014 get browser console logs",
6245
+ " cookies \u2014 get/set/clear cookies",
6246
+ " storage \u2014 get/set/clear localStorage/sessionStorage",
6247
+ "Supports session persistence, mobile simulation, and advanced browser features."
6093
6248
  ].join("\n"),
6094
6249
  {
6095
6250
  type: "object",
@@ -6100,21 +6255,101 @@ function registerBrowserTools(registry, workspaceDir) {
6100
6255
  },
6101
6256
  action: {
6102
6257
  type: "string",
6103
- enum: ["extract", "screenshot", "click", "type", "evaluate"],
6258
+ enum: [
6259
+ "extract",
6260
+ "screenshot",
6261
+ "click",
6262
+ "type",
6263
+ "evaluate",
6264
+ "form_fill",
6265
+ "scroll",
6266
+ "hover",
6267
+ "select",
6268
+ "upload",
6269
+ "download",
6270
+ "pdf",
6271
+ "wait_for",
6272
+ "network_logs",
6273
+ "console_logs",
6274
+ "cookies",
6275
+ "storage"
6276
+ ],
6104
6277
  description: "Action to perform (default: extract)."
6105
6278
  },
6106
6279
  selector: {
6107
6280
  type: "string",
6108
- description: "CSS selector for click/type actions."
6281
+ description: "CSS selector for element-based actions."
6109
6282
  },
6110
6283
  text: {
6111
6284
  type: "string",
6112
- description: "Text to type (for 'type' action)."
6285
+ description: "Text to type or search for."
6113
6286
  },
6114
6287
  javascript: {
6115
6288
  type: "string",
6116
6289
  description: "JavaScript to evaluate in the page (for 'evaluate' action)."
6117
6290
  },
6291
+ formData: {
6292
+ type: "object",
6293
+ description: "Key-value pairs for form filling (selector: value)."
6294
+ },
6295
+ scrollDirection: {
6296
+ type: "string",
6297
+ enum: ["up", "down", "left", "right", "top", "bottom"],
6298
+ description: "Scroll direction or position."
6299
+ },
6300
+ scrollDistance: {
6301
+ type: "number",
6302
+ description: "Pixels to scroll (default: 500)."
6303
+ },
6304
+ coordinates: {
6305
+ type: "object",
6306
+ properties: {
6307
+ x: { type: "number" },
6308
+ y: { type: "number" }
6309
+ },
6310
+ description: "X,Y coordinates for scrolling or clicking."
6311
+ },
6312
+ filePath: {
6313
+ type: "string",
6314
+ description: "Path to file for upload action."
6315
+ },
6316
+ waitCondition: {
6317
+ type: "string",
6318
+ enum: ["selector", "text", "url", "timeout", "networkidle"],
6319
+ description: "What to wait for."
6320
+ },
6321
+ waitValue: {
6322
+ type: "string",
6323
+ description: "Value to wait for (selector, text, URL pattern)."
6324
+ },
6325
+ cookieData: {
6326
+ type: "object",
6327
+ description: "Cookie data for cookie operations."
6328
+ },
6329
+ storageData: {
6330
+ type: "object",
6331
+ description: "Storage data for localStorage/sessionStorage operations."
6332
+ },
6333
+ session: {
6334
+ type: "string",
6335
+ description: "Session ID for persistent browser context (default: 'default')."
6336
+ },
6337
+ viewport: {
6338
+ type: "object",
6339
+ properties: {
6340
+ width: { type: "number" },
6341
+ height: { type: "number" }
6342
+ },
6343
+ description: "Browser viewport size."
6344
+ },
6345
+ userAgent: {
6346
+ type: "string",
6347
+ description: "Custom user agent string."
6348
+ },
6349
+ mobile: {
6350
+ type: "boolean",
6351
+ description: "Simulate mobile device."
6352
+ },
6118
6353
  waitForSelector: {
6119
6354
  type: "string",
6120
6355
  description: "CSS selector to wait for before performing the action."
@@ -6132,19 +6367,33 @@ function registerBrowserTools(registry, workspaceDir) {
6132
6367
  const selector = params.selector;
6133
6368
  const text = params.text;
6134
6369
  const javascript = params.javascript;
6370
+ const formData = params.formData;
6371
+ const scrollDirection = params.scrollDirection;
6372
+ const scrollDistance = params.scrollDistance || 500;
6373
+ const coordinates = params.coordinates;
6374
+ const filePath = params.filePath;
6375
+ const waitCondition = params.waitCondition;
6376
+ const waitValue = params.waitValue;
6377
+ const cookieData = params.cookieData;
6378
+ const storageData = params.storageData;
6379
+ const sessionId = params.session || "default";
6380
+ const viewport = params.viewport;
6381
+ const userAgent = params.userAgent;
6382
+ const mobile = params.mobile;
6135
6383
  const waitForSelector = params.waitForSelector;
6136
6384
  const timeout = params.timeout || 3e4;
6137
- let browser;
6138
- try {
6139
- browser = await getBrowser();
6140
- } catch (err) {
6141
- return err.message;
6142
- }
6385
+ let context;
6143
6386
  let page;
6144
6387
  try {
6145
- page = await browser.newPage({
6146
- userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
6147
- });
6388
+ const browserOptions = {
6389
+ session: sessionId,
6390
+ viewport,
6391
+ userAgent,
6392
+ isMobile: mobile,
6393
+ hasTouch: mobile
6394
+ };
6395
+ context = await getBrowserContext(sessionId, browserOptions);
6396
+ page = await context.newPage();
6148
6397
  page.setDefaultTimeout(timeout);
6149
6398
  await page.goto(url, { waitUntil: "domcontentloaded", timeout });
6150
6399
  if (waitForSelector) {
@@ -6170,12 +6419,31 @@ function registerBrowserTools(registry, workspaceDir) {
6170
6419
  await page.screenshot({ path: filepath, fullPage: true });
6171
6420
  return `Screenshot saved: ${filepath}`;
6172
6421
  }
6422
+ case "pdf": {
6423
+ if (!existsSync13(screenshotDir)) {
6424
+ mkdirSync9(screenshotDir, { recursive: true });
6425
+ }
6426
+ const filename = `${randomUUID5()}.pdf`;
6427
+ const filepath = resolve12(screenshotDir, filename);
6428
+ await page.pdf({
6429
+ path: filepath,
6430
+ format: "A4",
6431
+ printBackground: true,
6432
+ margin: { top: "1cm", right: "1cm", bottom: "1cm", left: "1cm" }
6433
+ });
6434
+ return `PDF saved: ${filepath}`;
6435
+ }
6173
6436
  case "click": {
6174
6437
  if (!selector) {
6175
6438
  return "Error: 'selector' parameter is required for click action.";
6176
6439
  }
6177
- await page.click(selector);
6178
- return `Clicked: ${selector}`;
6440
+ if (coordinates) {
6441
+ await page.mouse.click(coordinates.x, coordinates.y);
6442
+ return `Clicked at coordinates: (${coordinates.x}, ${coordinates.y})`;
6443
+ } else {
6444
+ await page.click(selector);
6445
+ return `Clicked: ${selector}`;
6446
+ }
6179
6447
  }
6180
6448
  case "type": {
6181
6449
  if (!selector) {
@@ -6187,6 +6455,169 @@ function registerBrowserTools(registry, workspaceDir) {
6187
6455
  await page.fill(selector, text);
6188
6456
  return `Typed into ${selector}: "${text}"`;
6189
6457
  }
6458
+ case "form_fill": {
6459
+ if (!formData) {
6460
+ return "Error: 'formData' parameter is required for form_fill action.";
6461
+ }
6462
+ const results = [];
6463
+ for (const [sel, value] of Object.entries(formData)) {
6464
+ await page.fill(sel, value);
6465
+ results.push(`${sel}: "${value}"`);
6466
+ }
6467
+ return `Form filled:
6468
+ ${results.join("\n")}`;
6469
+ }
6470
+ case "scroll": {
6471
+ if (coordinates) {
6472
+ await page.evaluate(({ x, y }) => window.scrollTo(x, y), coordinates);
6473
+ return `Scrolled to coordinates: (${coordinates.x}, ${coordinates.y})`;
6474
+ } else if (selector) {
6475
+ await page.locator(selector).scrollIntoViewIfNeeded();
6476
+ return `Scrolled to element: ${selector}`;
6477
+ } else if (scrollDirection) {
6478
+ switch (scrollDirection) {
6479
+ case "up":
6480
+ await page.keyboard.press("PageUp");
6481
+ break;
6482
+ case "down":
6483
+ await page.keyboard.press("PageDown");
6484
+ break;
6485
+ case "top":
6486
+ await page.keyboard.press("Home");
6487
+ break;
6488
+ case "bottom":
6489
+ await page.keyboard.press("End");
6490
+ break;
6491
+ default:
6492
+ await page.mouse.wheel(0, scrollDirection === "down" ? scrollDistance : -scrollDistance);
6493
+ }
6494
+ return `Scrolled ${scrollDirection}`;
6495
+ }
6496
+ return "Error: scroll requires coordinates, selector, or scrollDirection";
6497
+ }
6498
+ case "hover": {
6499
+ if (!selector) {
6500
+ return "Error: 'selector' parameter is required for hover action.";
6501
+ }
6502
+ await page.hover(selector);
6503
+ return `Hovered over: ${selector}`;
6504
+ }
6505
+ case "select": {
6506
+ if (!selector || !text) {
6507
+ return "Error: 'selector' and 'text' parameters are required for select action.";
6508
+ }
6509
+ await page.selectOption(selector, text);
6510
+ return `Selected "${text}" in ${selector}`;
6511
+ }
6512
+ case "upload": {
6513
+ if (!selector || !filePath) {
6514
+ return "Error: 'selector' and 'filePath' parameters are required for upload action.";
6515
+ }
6516
+ const absolutePath = resolve12(workspaceDir, filePath);
6517
+ if (!existsSync13(absolutePath)) {
6518
+ return `Error: File not found: ${absolutePath}`;
6519
+ }
6520
+ await page.setInputFiles(selector, absolutePath);
6521
+ return `Uploaded file ${filePath} to ${selector}`;
6522
+ }
6523
+ case "download": {
6524
+ const downloadPromise = page.waitForEvent("download");
6525
+ if (selector) {
6526
+ await page.click(selector);
6527
+ }
6528
+ const download = await downloadPromise;
6529
+ const filename = download.suggestedFilename() || `download_${randomUUID5()}`;
6530
+ const downloadPath = resolve12(workspaceDir, "downloads", filename);
6531
+ if (!existsSync13(resolve12(workspaceDir, "downloads"))) {
6532
+ mkdirSync9(resolve12(workspaceDir, "downloads"), { recursive: true });
6533
+ }
6534
+ await download.saveAs(downloadPath);
6535
+ return `Downloaded: ${downloadPath}`;
6536
+ }
6537
+ case "wait_for": {
6538
+ if (!waitCondition || !waitValue) {
6539
+ return "Error: 'waitCondition' and 'waitValue' parameters are required for wait_for action.";
6540
+ }
6541
+ switch (waitCondition) {
6542
+ case "selector":
6543
+ await page.waitForSelector(waitValue, { timeout });
6544
+ return `Waited for selector: ${waitValue}`;
6545
+ case "text":
6546
+ await page.waitForFunction(
6547
+ (text2) => document.body.innerText.includes(text2),
6548
+ waitValue,
6549
+ { timeout }
6550
+ );
6551
+ return `Waited for text: ${waitValue}`;
6552
+ case "url":
6553
+ await page.waitForURL(waitValue, { timeout });
6554
+ return `Waited for URL: ${waitValue}`;
6555
+ case "networkidle":
6556
+ await page.waitForLoadState("networkidle", { timeout });
6557
+ return "Waited for network idle";
6558
+ case "timeout":
6559
+ await page.waitForTimeout(parseInt(waitValue));
6560
+ return `Waited for ${waitValue}ms`;
6561
+ default:
6562
+ return `Unknown wait condition: ${waitCondition}`;
6563
+ }
6564
+ }
6565
+ case "network_logs": {
6566
+ const logs = await page.evaluate(() => {
6567
+ return "Network logging not yet implemented - use browser dev tools";
6568
+ });
6569
+ return logs;
6570
+ }
6571
+ case "console_logs": {
6572
+ const logs = [];
6573
+ page.on("console", (msg) => {
6574
+ logs.push(`[${msg.type()}] ${msg.text()}`);
6575
+ });
6576
+ await page.waitForTimeout(1e3);
6577
+ return logs.length > 0 ? logs.join("\n") : "No console logs";
6578
+ }
6579
+ case "cookies": {
6580
+ if (cookieData) {
6581
+ if (cookieData.action === "set") {
6582
+ await context.addCookies([cookieData.cookie]);
6583
+ return `Cookie set: ${cookieData.cookie.name}`;
6584
+ } else if (cookieData.action === "clear") {
6585
+ await context.clearCookies();
6586
+ return "Cookies cleared";
6587
+ }
6588
+ }
6589
+ const cookies = await context.cookies();
6590
+ return JSON.stringify(cookies, null, 2);
6591
+ }
6592
+ case "storage": {
6593
+ if (storageData) {
6594
+ const storageType = storageData.type || "localStorage";
6595
+ if (storageData.action === "set") {
6596
+ await page.evaluate(({ type, key, value }) => {
6597
+ if (type === "localStorage") {
6598
+ localStorage.setItem(key, value);
6599
+ } else {
6600
+ sessionStorage.setItem(key, value);
6601
+ }
6602
+ }, { type: storageType, key: storageData.key, value: storageData.value });
6603
+ return `${storageType} set: ${storageData.key}`;
6604
+ } else if (storageData.action === "clear") {
6605
+ await page.evaluate((type) => {
6606
+ if (type === "localStorage") {
6607
+ localStorage.clear();
6608
+ } else {
6609
+ sessionStorage.clear();
6610
+ }
6611
+ }, storageType);
6612
+ return `${storageType} cleared`;
6613
+ }
6614
+ }
6615
+ const storage = await page.evaluate(() => ({
6616
+ localStorage: Object.fromEntries(Object.entries(localStorage)),
6617
+ sessionStorage: Object.fromEntries(Object.entries(sessionStorage))
6618
+ }));
6619
+ return JSON.stringify(storage, null, 2);
6620
+ }
6190
6621
  case "evaluate": {
6191
6622
  if (!javascript) {
6192
6623
  return "Error: 'javascript' parameter is required for evaluate action.";
@@ -6200,7 +6631,7 @@ function registerBrowserTools(registry, workspaceDir) {
6200
6631
  return str ?? "(no result)";
6201
6632
  }
6202
6633
  default:
6203
- return `Unknown action: ${action}. Use: extract, screenshot, click, type, evaluate.`;
6634
+ return `Unknown action: ${action}. Available actions: extract, screenshot, click, type, evaluate, form_fill, scroll, hover, select, upload, download, pdf, wait_for, network_logs, console_logs, cookies, storage.`;
6204
6635
  }
6205
6636
  } catch (err) {
6206
6637
  return `browse error: ${err.message}`;
@@ -6214,6 +6645,98 @@ function registerBrowserTools(registry, workspaceDir) {
6214
6645
  }
6215
6646
  }
6216
6647
  );
6648
+ registry.register(
6649
+ "browser_session",
6650
+ [
6651
+ "Manage browser sessions for persistent contexts across multiple browse operations.",
6652
+ "Actions:",
6653
+ " list \u2014 list all active browser sessions",
6654
+ " create \u2014 create a new browser session with custom options",
6655
+ " close \u2014 close a specific browser session",
6656
+ " close_all \u2014 close all browser sessions",
6657
+ " info \u2014 get information about a specific session"
6658
+ ].join("\n"),
6659
+ {
6660
+ type: "object",
6661
+ properties: {
6662
+ action: {
6663
+ type: "string",
6664
+ enum: ["list", "create", "close", "close_all", "info"],
6665
+ description: "Session management action."
6666
+ },
6667
+ sessionId: {
6668
+ type: "string",
6669
+ description: "Session ID for create, close, or info actions."
6670
+ },
6671
+ options: {
6672
+ type: "object",
6673
+ description: "Browser options for create action (viewport, userAgent, mobile, etc.)."
6674
+ }
6675
+ },
6676
+ required: ["action"]
6677
+ },
6678
+ async (params) => {
6679
+ const action = params.action;
6680
+ const sessionId = params.sessionId;
6681
+ const options = params.options;
6682
+ try {
6683
+ switch (action) {
6684
+ case "list": {
6685
+ const sessions = Array.from(contextInstances.keys());
6686
+ return sessions.length > 0 ? `Active sessions: ${sessions.join(", ")}` : "No active browser sessions";
6687
+ }
6688
+ case "create": {
6689
+ if (!sessionId) {
6690
+ return "Error: 'sessionId' parameter is required for create action.";
6691
+ }
6692
+ if (contextInstances.has(sessionId)) {
6693
+ return `Error: Session '${sessionId}' already exists.`;
6694
+ }
6695
+ await getBrowserContext(sessionId, options || {});
6696
+ return `Created browser session: ${sessionId}`;
6697
+ }
6698
+ case "close": {
6699
+ if (!sessionId) {
6700
+ return "Error: 'sessionId' parameter is required for close action.";
6701
+ }
6702
+ const context = contextInstances.get(sessionId);
6703
+ if (!context) {
6704
+ return `Error: Session '${sessionId}' not found.`;
6705
+ }
6706
+ await context.close();
6707
+ contextInstances.delete(sessionId);
6708
+ return `Closed browser session: ${sessionId}`;
6709
+ }
6710
+ case "close_all": {
6711
+ const sessionCount = contextInstances.size;
6712
+ for (const [id, context] of contextInstances) {
6713
+ try {
6714
+ await context.close();
6715
+ } catch {
6716
+ }
6717
+ }
6718
+ contextInstances.clear();
6719
+ return `Closed ${sessionCount} browser sessions`;
6720
+ }
6721
+ case "info": {
6722
+ if (!sessionId) {
6723
+ return "Error: 'sessionId' parameter is required for info action.";
6724
+ }
6725
+ const context = contextInstances.get(sessionId);
6726
+ if (!context) {
6727
+ return `Error: Session '${sessionId}' not found.`;
6728
+ }
6729
+ const pages = context.pages();
6730
+ return `Session '${sessionId}': ${pages.length} active pages`;
6731
+ }
6732
+ default:
6733
+ return `Unknown action: ${action}. Available actions: list, create, close, close_all, info.`;
6734
+ }
6735
+ } catch (err) {
6736
+ return `browser_session error: ${err.message}`;
6737
+ }
6738
+ }
6739
+ );
6217
6740
  }
6218
6741
 
6219
6742
  // packages/runtime/src/tools/system.ts
@@ -7674,8 +8197,8 @@ async function startPipeline(configPath) {
7674
8197
  }
7675
8198
  }
7676
8199
  const requestLogger = new RequestLogger(resolve20(dirname8(configPath), "data", "dashboard.db"));
7677
- startDashboardServer(requestLogger, config.memory);
7678
8200
  const agent = new Agent(config);
8201
+ startDashboardServer(requestLogger, config.memory, () => agent.getConversationHistories());
7679
8202
  agent.setRequestLogger(requestLogger);
7680
8203
  const hivemindHome = process.env.HIVEMIND_HOME || resolve20(process.env.HOME || "/root", "hivemind");
7681
8204
  const toolRegistry = registerAllTools(hivemindHome, {
@@ -8029,7 +8552,7 @@ var WorkerServer = class {
8029
8552
  return this.handleHealth(res);
8030
8553
  }
8031
8554
  if (method === "POST" && path === "/assign") {
8032
- const body = await readBody(req);
8555
+ const body = await readBody2(req);
8033
8556
  return this.handleAssign(body, res);
8034
8557
  }
8035
8558
  if (method === "DELETE" && path.startsWith("/assign/")) {
@@ -8040,7 +8563,7 @@ var WorkerServer = class {
8040
8563
  return this.handleStatus(res);
8041
8564
  }
8042
8565
  if (method === "POST" && path === "/sync/push") {
8043
- const body = await readBody(req);
8566
+ const body = await readBody2(req);
8044
8567
  return this.handleSyncPush(body, res);
8045
8568
  }
8046
8569
  sendJson(res, 404, { error: "Not found" });
@@ -8118,7 +8641,7 @@ var WorkerServer = class {
8118
8641
  sendJson(res, 200, result);
8119
8642
  }
8120
8643
  };
8121
- function readBody(req) {
8644
+ function readBody2(req) {
8122
8645
  return new Promise((resolve21, reject) => {
8123
8646
  const chunks = [];
8124
8647
  req.on("data", (chunk) => chunks.push(chunk));
@@ -8464,4 +8987,4 @@ smol-toml/dist/index.js:
8464
8987
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8465
8988
  *)
8466
8989
  */
8467
- //# sourceMappingURL=chunk-ZM7RK5YV.js.map
8990
+ //# sourceMappingURL=chunk-M3A2WRXM.js.map