agentroam 0.2.0-preview.1 → 0.2.0-preview.2

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 (45) hide show
  1. package/README.md +4 -4
  2. package/dist/cli.js +15 -4
  3. package/dist/cloudflared/installer.js +19 -4
  4. package/dist/cloudflared/installer.test.js +15 -0
  5. package/dist/native-runtime.js +15 -0
  6. package/dist/native-runtime.test.js +19 -0
  7. package/dist/network.js +17 -0
  8. package/dist/network.test.js +20 -0
  9. package/dist/runtime-manager.js +2 -1
  10. package/package.json +2 -2
  11. package/runtime/.next/BUILD_ID +1 -1
  12. package/runtime/.next/app-build-manifest.json +3 -3
  13. package/runtime/.next/app-path-routes-manifest.json +1 -1
  14. package/runtime/.next/build-manifest.json +5 -5
  15. package/runtime/.next/prerender-manifest.json +1 -1
  16. package/runtime/.next/react-loadable-manifest.json +1 -1
  17. package/runtime/.next/server/app/_not-found.html +1 -1
  18. package/runtime/.next/server/app/_not-found.rsc +1 -1
  19. package/runtime/.next/server/app/web.html +1 -1
  20. package/runtime/.next/server/app/web.rsc +1 -1
  21. package/runtime/.next/server/app-paths-manifest.json +2 -2
  22. package/runtime/.next/server/chunks/322.js +31 -31
  23. package/runtime/.next/server/middleware-build-manifest.js +1 -1
  24. package/runtime/.next/server/middleware-react-loadable-manifest.js +1 -1
  25. package/runtime/.next/server/pages/404.html +1 -1
  26. package/runtime/.next/server/pages/500.html +1 -1
  27. package/runtime/.next/server/server-reference-manifest.json +1 -1
  28. package/runtime/.next/static/chunks/804.0e20fa702013ffef.js +1 -0
  29. package/runtime/.next/static/chunks/{webpack-3a28d671c5a42bf1.js → webpack-e56f3a1950168597.js} +1 -1
  30. package/runtime/node_modules/@agent/core/dist/domain/agent/AgentBuilder.d.ts +3 -0
  31. package/runtime/node_modules/@agent/core/dist/domain/agent/AgentBuilder.d.ts.map +1 -1
  32. package/runtime/node_modules/@agent/core/dist/domain/context/ContextLoader.d.ts +1 -0
  33. package/runtime/node_modules/@agent/core/dist/domain/context/ContextLoader.d.ts.map +1 -1
  34. package/runtime/node_modules/@agent/core/dist/domain/skill/SkillRegistry.d.ts +4 -0
  35. package/runtime/node_modules/@agent/core/dist/domain/skill/SkillRegistry.d.ts.map +1 -1
  36. package/runtime/node_modules/@agent/core/dist/domain/tool/builtin/WebSearchTool.d.ts +5 -2
  37. package/runtime/node_modules/@agent/core/dist/domain/tool/builtin/WebSearchTool.d.ts.map +1 -1
  38. package/runtime/node_modules/@agent/core/dist/index.js +206 -67
  39. package/runtime/node_modules/@agent/core/dist/index.js.map +8 -8
  40. package/runtime/node_modules/@agent/core/dist/infrastructure/SQLiteSessionStore.d.ts +4 -0
  41. package/runtime/node_modules/@agent/core/dist/infrastructure/SQLiteSessionStore.d.ts.map +1 -1
  42. package/runtime/node_modules/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
  43. package/runtime/.next/static/chunks/804.33d400571801aa9e.js +0 -1
  44. /package/runtime/.next/static/{DmJe8rRLl3EQW0weZvItS → 47UkTmBGxP5qz2mnMbNEp}/_buildManifest.js +0 -0
  45. /package/runtime/.next/static/{DmJe8rRLl3EQW0weZvItS → 47UkTmBGxP5qz2mnMbNEp}/_ssgManifest.js +0 -0
@@ -5398,9 +5398,37 @@ ${truncated}`
5398
5398
  }
5399
5399
  }
5400
5400
  // src/domain/tool/builtin/WebSearchTool.ts
5401
+ var BROWSER_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36";
5402
+ function stripTags(html) {
5403
+ return html.replace(/<[^>]+>/g, "");
5404
+ }
5405
+ function decodeEntities(text) {
5406
+ return text.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;|&apos;/g, "'").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&");
5407
+ }
5408
+ function describeError(err) {
5409
+ if (!(err instanceof Error))
5410
+ return "Search failed";
5411
+ const cause = err.cause;
5412
+ const causeMsg = cause instanceof Error ? cause.message : typeof cause === "string" ? cause : "";
5413
+ return causeMsg ? `${err.message}: ${causeMsg}` : err.message;
5414
+ }
5415
+ function decodeBingRedirect(href) {
5416
+ const decoded = decodeEntities(href);
5417
+ const u = /[?&]u=([^&]+)/.exec(decoded)?.[1];
5418
+ if (u && u.length > 2) {
5419
+ try {
5420
+ const b64 = u.slice(2).replace(/-/g, "+").replace(/_/g, "/");
5421
+ const real = atob(b64);
5422
+ if (/^https?:\/\//.test(real))
5423
+ return real;
5424
+ } catch {}
5425
+ }
5426
+ return decoded;
5427
+ }
5428
+
5401
5429
  class WebSearchTool {
5402
5430
  name = "web_search";
5403
- description = "Search the web for information using DuckDuckGo HTML";
5431
+ description = "Search the web for information using DuckDuckGo HTML, falling back to Bing";
5404
5432
  schema = exports_external.object({
5405
5433
  query: exports_external.string().min(2).describe("The search query")
5406
5434
  });
@@ -5420,44 +5448,63 @@ class WebSearchTool {
5420
5448
  isError: true
5421
5449
  };
5422
5450
  }
5423
- try {
5424
- const response = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(parsed.data.query)}`, {
5425
- headers: { "User-Agent": "customer-agent/0.1" },
5426
- signal: AbortSignal.timeout(15000)
5427
- });
5428
- if (!response.ok) {
5429
- return {
5430
- toolCallId: "",
5431
- content: `Search failed: HTTP ${response.status}`,
5432
- isError: true
5433
- };
5434
- }
5435
- const html = await response.text();
5436
- const results = this.parseResults(html);
5437
- return {
5438
- toolCallId: "",
5439
- content: results.length > 0 ? results.map((r, i) => `${i + 1}. ${r.title}
5451
+ const errors2 = [];
5452
+ let anySourceResponded = false;
5453
+ for (const search of [this.searchDuckDuckGo, this.searchBing]) {
5454
+ try {
5455
+ const results = await search.call(this, parsed.data.query);
5456
+ anySourceResponded = true;
5457
+ if (results.length > 0) {
5458
+ return {
5459
+ toolCallId: "",
5460
+ content: results.map((r, i) => `${i + 1}. ${r.title}
5440
5461
  ${r.snippet}
5441
5462
  ${r.url}`).join(`
5442
5463
 
5443
- `) : "No results found."
5444
- };
5445
- } catch (err) {
5464
+ `)
5465
+ };
5466
+ }
5467
+ } catch (err) {
5468
+ errors2.push(describeError(err));
5469
+ }
5470
+ }
5471
+ if (!anySourceResponded && errors2.length > 0) {
5446
5472
  return {
5447
5473
  toolCallId: "",
5448
- content: err instanceof Error ? err.message : "Search failed",
5474
+ content: `Search failed: ${errors2.join(" | ")}`,
5449
5475
  isError: true
5450
5476
  };
5451
5477
  }
5478
+ return { toolCallId: "", content: "No results found." };
5479
+ }
5480
+ async searchDuckDuckGo(query) {
5481
+ const response = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`, {
5482
+ headers: { "User-Agent": "customer-agent/0.1" },
5483
+ signal: AbortSignal.timeout(15000)
5484
+ });
5485
+ if (!response.ok) {
5486
+ throw new Error(`DuckDuckGo HTTP ${response.status}`);
5487
+ }
5488
+ return this.parseDuckDuckGoResults(await response.text());
5489
+ }
5490
+ async searchBing(query) {
5491
+ const response = await fetch(`https://www.bing.com/search?q=${encodeURIComponent(query)}`, {
5492
+ headers: { "User-Agent": BROWSER_UA, Accept: "text/html" },
5493
+ signal: AbortSignal.timeout(15000)
5494
+ });
5495
+ if (!response.ok) {
5496
+ throw new Error(`Bing HTTP ${response.status}`);
5497
+ }
5498
+ return this.parseBingResults(await response.text());
5452
5499
  }
5453
- parseResults(html) {
5500
+ parseDuckDuckGoResults(html) {
5454
5501
  const results = [];
5455
5502
  const linkRegex = /<a[^>]*class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/gi;
5456
5503
  const snippetRegex = /<a[^>]*class="result__snippet"[^>]*>([\s\S]*?)<\/a>/gi;
5457
5504
  let linkMatch;
5458
5505
  while ((linkMatch = linkRegex.exec(html)) !== null) {
5459
5506
  const url = linkMatch[1];
5460
- const title = linkMatch[2].replace(/<[^>]+>/g, "").trim();
5507
+ const title = decodeEntities(stripTags(linkMatch[2])).trim();
5461
5508
  if (url && title) {
5462
5509
  results.push({ title, url, snippet: "" });
5463
5510
  }
@@ -5465,11 +5512,30 @@ class WebSearchTool {
5465
5512
  let snippetMatch;
5466
5513
  let i = 0;
5467
5514
  while ((snippetMatch = snippetRegex.exec(html)) !== null && i < results.length) {
5468
- results[i].snippet = snippetMatch[1].replace(/<[^>]+>/g, "").trim();
5515
+ results[i].snippet = decodeEntities(stripTags(snippetMatch[1])).trim();
5469
5516
  i++;
5470
5517
  }
5471
5518
  return results.slice(0, 10);
5472
5519
  }
5520
+ parseBingResults(html) {
5521
+ const results = [];
5522
+ const blockRegex = /<li class="b_algo"[\s\S]*?<\/li>/gi;
5523
+ let block;
5524
+ while ((block = blockRegex.exec(html)) !== null && results.length < 10) {
5525
+ const chunk = block[0];
5526
+ const link = /<h2[^>]*>\s*<a[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/.exec(chunk);
5527
+ if (!link)
5528
+ continue;
5529
+ const title = decodeEntities(stripTags(link[2])).trim();
5530
+ const snippetMatch = /<p[^>]*>([\s\S]*?)<\/p>/.exec(chunk);
5531
+ const snippet = snippetMatch ? decodeEntities(stripTags(snippetMatch[1])).trim() : "";
5532
+ const url = decodeBingRedirect(link[1]);
5533
+ if (url && title) {
5534
+ results.push({ title, snippet, url });
5535
+ }
5536
+ }
5537
+ return results;
5538
+ }
5473
5539
  }
5474
5540
  // src/domain/tool/builtin/GrepTool.ts
5475
5541
  import { readFile as readFile3, readdir, stat } from "node:fs/promises";
@@ -7302,6 +7368,7 @@ class SkillRegistry {
7302
7368
  promptCache = new Map;
7303
7369
  semanticCache = new Map;
7304
7370
  modelProvider = null;
7371
+ semanticMatchingEnabled = true;
7305
7372
  constructor(loader) {
7306
7373
  this.loader = loader;
7307
7374
  }
@@ -7309,6 +7376,10 @@ class SkillRegistry {
7309
7376
  this.modelProvider = provider;
7310
7377
  this.semanticCache.clear();
7311
7378
  }
7379
+ setSemanticMatchingEnabled(enabled) {
7380
+ this.semanticMatchingEnabled = enabled;
7381
+ this.semanticCache.clear();
7382
+ }
7312
7383
  register(skill) {
7313
7384
  this.skills.set(skill.name, skill);
7314
7385
  if ("prompt" in skill) {
@@ -7326,9 +7397,12 @@ class SkillRegistry {
7326
7397
  return Array.from(this.skills.values());
7327
7398
  }
7328
7399
  findMatching(input) {
7400
+ return this.findMatchingFrom(input, this.skills.values());
7401
+ }
7402
+ findMatchingFrom(input, skills) {
7329
7403
  const lowerInput = input.toLowerCase();
7330
7404
  const matched = [];
7331
- for (const skill of this.skills.values()) {
7405
+ for (const skill of skills) {
7332
7406
  for (const trigger of skill.triggers) {
7333
7407
  if (lowerInput.includes(trigger.toLowerCase())) {
7334
7408
  matched.push(skill);
@@ -7338,14 +7412,15 @@ class SkillRegistry {
7338
7412
  }
7339
7413
  return matched;
7340
7414
  }
7341
- async findMatchingSemantic(input) {
7342
- if (!this.modelProvider || this.skills.size === 0)
7415
+ async findMatchingSemantic(input, candidates) {
7416
+ if (!this.modelProvider || candidates.length === 0)
7343
7417
  return [];
7344
- const cacheKey = input.trim().slice(0, 200);
7418
+ const candidateKey = candidates.map((skill) => skill.name).sort().join("\x00");
7419
+ const cacheKey = `${input.trim().slice(0, 200)}\x01${candidateKey}`;
7345
7420
  const cached = this.semanticCache.get(cacheKey);
7346
7421
  if (cached)
7347
7422
  return cached;
7348
- const skillList = Array.from(this.skills.values()).map((s, i) => `${i + 1}. ${s.name}: ${s.description || "(no description)"}`).join(`
7423
+ const skillList = candidates.map((s, i) => `${i + 1}. ${s.name}: ${s.description || "(no description)"}`).join(`
7349
7424
  `);
7350
7425
  const matchPrompt = `You are a skill matching assistant. Given the user's input and a list of available skills with their descriptions, determine which skills are semantically relevant to the user's request.
7351
7426
 
@@ -7379,8 +7454,9 @@ Return ONLY the names of relevant skills, one per line. If none are relevant, re
7379
7454
  const names = trimmed.split(`
7380
7455
  `).map((line) => line.replace(/^\d+\.\s*/, "").replace(/^[\s\-•*]+/, "").trim()).filter(Boolean);
7381
7456
  const matched = [];
7457
+ const candidatesByName = new Map(candidates.map((skill) => [skill.name, skill]));
7382
7458
  for (const name of names) {
7383
- const skill = this.skills.get(name);
7459
+ const skill = candidatesByName.get(name);
7384
7460
  if (skill && !matched.find((m) => m.name === skill.name)) {
7385
7461
  matched.push(skill);
7386
7462
  }
@@ -7392,24 +7468,22 @@ Return ONLY the names of relevant skills, one per line. If none are relevant, re
7392
7468
  }
7393
7469
  }
7394
7470
  async getSkillPrompts(input, enabledSkills) {
7395
- let matched = this.findMatching(input);
7471
+ const allowed = enabledSkills && enabledSkills.length > 0 ? new Set(enabledSkills) : null;
7472
+ const eligibleSkills = Array.from(this.skills.values()).filter((skill) => !allowed || allowed.has(skill.name));
7473
+ let matched = this.findMatchingFrom(input, eligibleSkills);
7396
7474
  const slashMatch = input.match(/^\/([\w-]+)/);
7397
7475
  if (slashMatch) {
7398
- const byName = this.skills.get(slashMatch[1]);
7476
+ const byName = eligibleSkills.find((skill) => skill.name === slashMatch[1]);
7399
7477
  if (byName && !matched.find((m) => m.name === byName.name)) {
7400
7478
  matched.unshift(byName);
7401
7479
  }
7402
7480
  }
7403
- if (matched.length === 0) {
7404
- const semanticMatches = await this.findMatchingSemantic(input);
7481
+ if (matched.length === 0 && this.semanticMatchingEnabled && eligibleSkills.length > 0) {
7482
+ const semanticMatches = await this.findMatchingSemantic(input, eligibleSkills);
7405
7483
  if (semanticMatches.length > 0) {
7406
7484
  matched = semanticMatches;
7407
7485
  }
7408
7486
  }
7409
- if (enabledSkills && enabledSkills.length > 0) {
7410
- const allowed = new Set(enabledSkills);
7411
- matched = matched.filter((s) => allowed.has(s.name));
7412
- }
7413
7487
  if (matched.length === 0)
7414
7488
  return "";
7415
7489
  const parts = [];
@@ -7432,35 +7506,46 @@ ${prompt}`);
7432
7506
  }
7433
7507
 
7434
7508
  // src/domain/context/ContextLoader.ts
7435
- import { readFile as readFile6, readdir as readdir4, stat as stat4 } from "node:fs/promises";
7436
- import { join as join6, basename as basename2 } from "node:path";
7437
- var PROJECT_FILES = [
7509
+ import { constants } from "node:fs";
7510
+ import { open, readFile as readFile6, readdir as readdir4, realpath, stat as stat4 } from "node:fs/promises";
7511
+ import { join as join6, basename as basename2, isAbsolute, relative as relative3, resolve as resolve8, sep } from "node:path";
7512
+ var ROOT_PROJECT_FILES = [
7513
+ "AGENTS.md",
7438
7514
  "CLAUDE.md",
7439
7515
  "README.md",
7440
7516
  "CONTRIBUTING.md",
7441
7517
  ".cursorrules",
7442
7518
  ".github/copilot-instructions.md"
7443
7519
  ];
7520
+ var CUSTOMER_AGENT_FILES = ROOT_PROJECT_FILES.map((file) => join6(".customer-agent", file));
7521
+ var INSTRUCTION_FILES = new Set(["AGENTS.md", "CLAUDE.md"]);
7522
+ var EXCLUDED_DIRECTORIES = new Set(["node_modules", ".git", "dist"]);
7444
7523
 
7445
7524
  class ContextLoader {
7446
7525
  async loadProjectContext(rootDir) {
7447
7526
  const files = [];
7448
- for (const relPath of PROJECT_FILES) {
7527
+ const loadedPaths = new Set;
7528
+ for (const relPath of [...ROOT_PROJECT_FILES, ...CUSTOMER_AGENT_FILES]) {
7449
7529
  const fullPath = join6(rootDir, relPath);
7530
+ if (loadedPaths.has(fullPath))
7531
+ continue;
7450
7532
  try {
7451
7533
  await stat4(fullPath);
7452
7534
  const file = await this.loadFile(fullPath);
7453
7535
  files.push(file);
7536
+ loadedPaths.add(fullPath);
7454
7537
  } catch {}
7455
7538
  }
7456
7539
  try {
7457
- const claudeFiles = await this.findClaudeMdFiles(rootDir);
7458
- for (const filePath of claudeFiles) {
7459
- if (filePath === join6(rootDir, "CLAUDE.md"))
7540
+ const resolvedRoot = await realpath(rootDir);
7541
+ const instructionFiles = await this.findClaudeMdFiles(rootDir);
7542
+ for (const filePath of instructionFiles) {
7543
+ if (loadedPaths.has(filePath))
7460
7544
  continue;
7461
7545
  try {
7462
- const file = await this.loadFile(filePath);
7546
+ const file = await this.loadRecursiveFile(rootDir, resolvedRoot, filePath);
7463
7547
  files.push(file);
7548
+ loadedPaths.add(filePath);
7464
7549
  } catch {}
7465
7550
  }
7466
7551
  } catch {}
@@ -7470,7 +7555,7 @@ class ContextLoader {
7470
7555
  const content = await readFile6(filePath, "utf-8");
7471
7556
  const fileName = basename2(filePath);
7472
7557
  let type = "other";
7473
- if (fileName === "CLAUDE.md")
7558
+ if (INSTRUCTION_FILES.has(fileName))
7474
7559
  type = "claude_md";
7475
7560
  else if (fileName === "README.md" || fileName === "CONTRIBUTING.md")
7476
7561
  type = "readme";
@@ -7480,25 +7565,52 @@ class ContextLoader {
7480
7565
  type = "code";
7481
7566
  return { path: filePath, content, type };
7482
7567
  }
7568
+ async loadRecursiveFile(rootDir, resolvedRoot, filePath) {
7569
+ const relativePath = relative3(rootDir, filePath);
7570
+ if (!relativePath || isAbsolute(relativePath) || relativePath === ".." || relativePath.startsWith(`..${sep}`)) {
7571
+ throw new Error("Recursive context candidate is outside the configured root");
7572
+ }
7573
+ const expectedPath = resolve8(resolvedRoot, relativePath);
7574
+ const fileHandle = await open(filePath, constants.O_RDONLY | constants.O_NOFOLLOW);
7575
+ try {
7576
+ const openedStat = await fileHandle.stat();
7577
+ if (!openedStat.isFile()) {
7578
+ throw new Error("Recursive context candidate is not a regular file");
7579
+ }
7580
+ const resolvedPath = await realpath(filePath);
7581
+ if (resolvedPath !== expectedPath) {
7582
+ throw new Error("Recursive context candidate traverses a symbolic link");
7583
+ }
7584
+ const resolvedStat = await stat4(resolvedPath);
7585
+ if (resolvedStat.dev !== openedStat.dev || resolvedStat.ino !== openedStat.ino) {
7586
+ throw new Error("Recursive context candidate changed while opening");
7587
+ }
7588
+ const content = await fileHandle.readFile({ encoding: "utf-8" });
7589
+ return { path: filePath, content, type: "claude_md" };
7590
+ } finally {
7591
+ await fileHandle.close();
7592
+ }
7593
+ }
7483
7594
  async findClaudeMdFiles(rootDir) {
7484
7595
  const results = [];
7485
7596
  const scan = async (dir) => {
7486
7597
  try {
7487
7598
  const entries = await readdir4(dir, { withFileTypes: true });
7599
+ entries.sort((left, right) => left.name.localeCompare(right.name));
7488
7600
  for (const entry of entries) {
7489
- if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "dist")
7601
+ if (EXCLUDED_DIRECTORIES.has(entry.name))
7490
7602
  continue;
7491
7603
  const fullPath = join6(dir, entry.name);
7492
7604
  if (entry.isDirectory()) {
7493
7605
  await scan(fullPath);
7494
- } else if (entry.name === "CLAUDE.md") {
7606
+ } else if (entry.isFile() && INSTRUCTION_FILES.has(entry.name)) {
7495
7607
  results.push(fullPath);
7496
7608
  }
7497
7609
  }
7498
7610
  } catch {}
7499
7611
  };
7500
7612
  await scan(rootDir);
7501
- return results;
7613
+ return results.sort((left, right) => left.localeCompare(right));
7502
7614
  }
7503
7615
  }
7504
7616
 
@@ -8612,6 +8724,7 @@ class AgentBuilder {
8612
8724
  compactThreshold;
8613
8725
  enabledTools = null;
8614
8726
  enabledSkills = null;
8727
+ semanticSkillMatching = true;
8615
8728
  withWorkingDirectory(path) {
8616
8729
  this.workingDirectory = path;
8617
8730
  return this;
@@ -8699,6 +8812,10 @@ class AgentBuilder {
8699
8812
  this.enabledSkills = skillNames.length > 0 ? skillNames : null;
8700
8813
  return this;
8701
8814
  }
8815
+ withSemanticSkillMatching(enabled) {
8816
+ this.semanticSkillMatching = enabled;
8817
+ return this;
8818
+ }
8702
8819
  async build() {
8703
8820
  if (!this.modelProvider) {
8704
8821
  throw new Error("Model provider is required. Call withModelProvider() or withModel()");
@@ -8706,6 +8823,7 @@ class AgentBuilder {
8706
8823
  const remoteToolStore = this.remoteToolStore;
8707
8824
  const projectId = this.projectId;
8708
8825
  this.skillRegistry.setModelProvider(this.modelProvider);
8826
+ this.skillRegistry.setSemanticMatchingEnabled(this.semanticSkillMatching);
8709
8827
  const memoryStore = this.memoryStore ?? new FileSystemMemoryStore(this.workingDirectory);
8710
8828
  const toolRegistry = this.createToolRegistry(remoteToolStore, projectId);
8711
8829
  this.toolRegistry = toolRegistry;
@@ -8753,6 +8871,7 @@ class AgentBuilder {
8753
8871
  const remoteToolStore = this.remoteToolStore;
8754
8872
  const projectId = this.projectId;
8755
8873
  this.skillRegistry.setModelProvider(this.modelProvider);
8874
+ this.skillRegistry.setSemanticMatchingEnabled(this.semanticSkillMatching);
8756
8875
  const memoryStore = this.memoryStore ?? new FileSystemMemoryStore(this.workingDirectory);
8757
8876
  const toolRegistry = this.createToolRegistry(remoteToolStore, projectId);
8758
8877
  this.toolRegistry = toolRegistry;
@@ -8845,7 +8964,7 @@ class MCPClient {
8845
8964
  if (!config.command) {
8846
8965
  return Promise.reject(new Error(`stdio 服务器 "${config.id}" 缺少 command 字段`));
8847
8966
  }
8848
- return new Promise((resolve8, reject) => {
8967
+ return new Promise((resolve9, reject) => {
8849
8968
  const proc = spawn2(config.command, config.args ?? [], {
8850
8969
  env: { ...process.env, ...config.env },
8851
8970
  stdio: ["pipe", "pipe", "pipe"]
@@ -8884,7 +9003,7 @@ class MCPClient {
8884
9003
  clientInfo: { name: "customer-agent", version: "0.1.0" }
8885
9004
  }).then(() => {
8886
9005
  this._connected = true;
8887
- resolve8();
9006
+ resolve9();
8888
9007
  }).catch(reject);
8889
9008
  });
8890
9009
  }
@@ -8934,7 +9053,7 @@ class MCPClient {
8934
9053
  if (this.config?.transport === "streamableHttp") {
8935
9054
  return this.sendRequestHttp(method, params);
8936
9055
  }
8937
- return new Promise((resolve8, reject) => {
9056
+ return new Promise((resolve9, reject) => {
8938
9057
  if (!this.process || !this.process.stdin) {
8939
9058
  reject(new Error("MCP client not connected"));
8940
9059
  return;
@@ -8950,7 +9069,7 @@ class MCPClient {
8950
9069
  if (response.error) {
8951
9070
  reject(new Error(response.error.message));
8952
9071
  } else {
8953
- resolve8(response.result);
9072
+ resolve9(response.result);
8954
9073
  }
8955
9074
  });
8956
9075
  const timeout = setTimeout(() => {
@@ -8968,7 +9087,7 @@ class MCPClient {
8968
9087
  });
8969
9088
  }
8970
9089
  sendRequestSSE(method, params) {
8971
- return new Promise((resolve8, reject) => {
9090
+ return new Promise((resolve9, reject) => {
8972
9091
  if (!this.ssePostUrl) {
8973
9092
  reject(new Error("SSE post URL not established"));
8974
9093
  return;
@@ -8981,7 +9100,7 @@ class MCPClient {
8981
9100
  if (response.error)
8982
9101
  reject(new Error(response.error.message));
8983
9102
  else
8984
- resolve8(response.result);
9103
+ resolve9(response.result);
8985
9104
  });
8986
9105
  const timeout = setTimeout(() => {
8987
9106
  this.pendingRequests.delete(id);
@@ -9047,7 +9166,7 @@ class MCPClient {
9047
9166
  this._connected = true;
9048
9167
  }
9049
9168
  sendRequestHttp(method, params) {
9050
- return new Promise((resolve8, reject) => {
9169
+ return new Promise((resolve9, reject) => {
9051
9170
  const urlStr = this.config?.url ?? this.config?.sseUrl;
9052
9171
  if (!urlStr) {
9053
9172
  reject(new Error("URL not set"));
@@ -9118,7 +9237,7 @@ class MCPClient {
9118
9237
  if (resp.error)
9119
9238
  reject(new Error(resp.error.message));
9120
9239
  else
9121
- resolve8(resp.result);
9240
+ resolve9(resp.result);
9122
9241
  }
9123
9242
  } catch {}
9124
9243
  evType = "";
@@ -9146,7 +9265,7 @@ class MCPClient {
9146
9265
  if (resp.error)
9147
9266
  reject(new Error(resp.error.message));
9148
9267
  else
9149
- resolve8(resp.result);
9268
+ resolve9(resp.result);
9150
9269
  } catch {
9151
9270
  reject(new Error(`Invalid JSON response: ${data.slice(0, 100)}`));
9152
9271
  }
@@ -9166,7 +9285,7 @@ class MCPClient {
9166
9285
  });
9167
9286
  }
9168
9287
  connectSSE(config) {
9169
- return new Promise((resolve8, reject) => {
9288
+ return new Promise((resolve9, reject) => {
9170
9289
  const sseUrl = config.url ?? config.sseUrl;
9171
9290
  if (!sseUrl) {
9172
9291
  reject(new Error("SSE URL is required for remote MCP servers"));
@@ -9220,7 +9339,7 @@ class MCPClient {
9220
9339
  clientInfo: { name: "customer-agent", version: "0.1.0" }
9221
9340
  }).then(() => {
9222
9341
  this._connected = true;
9223
- resolve8();
9342
+ resolve9();
9224
9343
  }).catch(reject);
9225
9344
  }
9226
9345
  } else if (eventType === "message" || eventType === "") {
@@ -10135,11 +10254,31 @@ class SQLiteSessionStore {
10135
10254
  }
10136
10255
  async create(session) {
10137
10256
  const db = getDatabase(this.baseDir);
10138
- const projectId = session.projectId || null;
10139
- const parentId = session.parentSessionId || null;
10257
+ const projectId = this.resolveProjectId(session.projectId);
10258
+ const parentId = this.resolveParentId(session.parentSessionId);
10140
10259
  db.db.prepare("INSERT INTO sessions (id, project_id, parent_id, title, status, created, updated, metadata) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(session.id, projectId, parentId, session.title, session.status, session.created, session.updated, JSON.stringify(session.metadata));
10141
10260
  return session;
10142
10261
  }
10262
+ resolveProjectId(projectId) {
10263
+ if (!projectId)
10264
+ return null;
10265
+ const db = getDatabase(this.baseDir);
10266
+ const exists = db.db.prepare("SELECT 1 FROM projects WHERE id = ?").get(projectId);
10267
+ if (exists)
10268
+ return projectId;
10269
+ console.warn(`[SQLiteSessionStore] project_id "${projectId}" not found — storing session without project (FK-safe).`);
10270
+ return null;
10271
+ }
10272
+ resolveParentId(parentId) {
10273
+ if (!parentId)
10274
+ return null;
10275
+ const db = getDatabase(this.baseDir);
10276
+ const exists = db.db.prepare("SELECT 1 FROM sessions WHERE id = ?").get(parentId);
10277
+ if (exists)
10278
+ return parentId;
10279
+ console.warn(`[SQLiteSessionStore] parent_id "${parentId}" not found — storing session as root (FK-safe).`);
10280
+ return null;
10281
+ }
10143
10282
  async get(id) {
10144
10283
  const db = getDatabase(this.baseDir);
10145
10284
  const row = db.db.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
@@ -10153,7 +10292,7 @@ class SQLiteSessionStore {
10153
10292
  if (!existing)
10154
10293
  throw new Error(`Session not found: ${id}`);
10155
10294
  const merged = { ...existing, ...update, updated: new Date().toISOString() };
10156
- db.db.prepare("UPDATE sessions SET project_id=?, title=?, status=?, updated=?, metadata=? WHERE id=?").run(merged.projectId, merged.title, merged.status, merged.updated, JSON.stringify(merged.metadata), id);
10295
+ db.db.prepare("UPDATE sessions SET project_id=?, title=?, status=?, updated=?, metadata=? WHERE id=?").run(this.resolveProjectId(merged.projectId), merged.title, merged.status, merged.updated, JSON.stringify(merged.metadata), id);
10157
10296
  return merged;
10158
10297
  }
10159
10298
  async delete(id) {
@@ -10547,7 +10686,7 @@ class SQLiteProjectStore {
10547
10686
  }
10548
10687
  async delete(id) {
10549
10688
  const db = getDatabase(this.baseDir);
10550
- db.db.prepare("UPDATE sessions SET project_id = '' WHERE project_id = ?").run(id);
10689
+ db.db.prepare("UPDATE sessions SET project_id = NULL WHERE project_id = ?").run(id);
10551
10690
  db.db.prepare("DELETE FROM projects WHERE id = ?").run(id);
10552
10691
  }
10553
10692
  async list() {
@@ -10898,4 +11037,4 @@ export {
10898
11037
  AgentBuilder
10899
11038
  };
10900
11039
 
10901
- //# debugId=A5D7CF646EBE851864756E2164756E21
11040
+ //# debugId=05A3BC3FF39651A264756E2164756E21