@sema-agent/core 2.0.1 → 2.2.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 (71) hide show
  1. package/dist/agents/observer.d.ts +14 -0
  2. package/dist/agents/observer.js +66 -12
  3. package/dist/agents/send-message-tool.js +164 -88
  4. package/dist/agents/subagent.d.ts +11 -4
  5. package/dist/agents/subagent.js +166 -62
  6. package/dist/core/context-edit.js +16 -3
  7. package/dist/core/file-snapshot-store.js +10 -1
  8. package/dist/core/memory-engine/dual-root.js +2 -0
  9. package/dist/core/memory-engine/engine.d.ts +4 -0
  10. package/dist/core/memory-engine/engine.js +6 -1
  11. package/dist/core/runner/prepare-memory.d.ts +4 -0
  12. package/dist/core/runner/prepare-memory.js +4 -1
  13. package/dist/core/runner/prepare-task.d.ts +9 -2
  14. package/dist/core/runner/prepare-task.js +68 -13
  15. package/dist/core/runner/runtask.js +919 -865
  16. package/dist/core/runner/synthetic-tools.d.ts +1 -0
  17. package/dist/core/runner/synthetic-tools.js +18 -15
  18. package/dist/core/runner/turn-attachments.d.ts +27 -3
  19. package/dist/core/runner/turn-attachments.js +101 -12
  20. package/dist/core/task-registry-agent.d.ts +9 -1
  21. package/dist/core/task-registry-agent.js +23 -2
  22. package/dist/core/task-registry-monitor.js +79 -24
  23. package/dist/core/task-registry-shared.d.ts +13 -1
  24. package/dist/core/task-registry-shared.js +21 -0
  25. package/dist/core/task-registry.d.ts +2 -0
  26. package/dist/core/task-registry.js +24 -26
  27. package/dist/core/tool-result-budget.js +2 -2
  28. package/dist/core/tool-result-store.d.ts +2 -0
  29. package/dist/core/tool-result-store.js +27 -2
  30. package/dist/core/types.d.ts +4 -2
  31. package/dist/core/workflow-journal-store.d.ts +13 -0
  32. package/dist/engine/session/import-validate.js +29 -0
  33. package/dist/engine/session/memory-repo.js +5 -0
  34. package/dist/index.d.ts +1 -1
  35. package/dist/index.js +1 -1
  36. package/dist/orchestration/workflow-size-guideline.d.ts +6 -1
  37. package/dist/orchestration/workflow-size-guideline.js +19 -9
  38. package/dist/orchestration/workflow.d.ts +1 -0
  39. package/dist/orchestration/workflow.js +44 -1
  40. package/dist/prompt-assembly/assemble.js +3 -7
  41. package/dist/prompt-assembly/event-registry.js +1 -1
  42. package/dist/prompt-assembly/packs/sema-default.js +8 -5
  43. package/dist/prompts/coordinator.d.ts +1 -1
  44. package/dist/prompts/coordinator.js +45 -0
  45. package/dist/prompts/default.d.ts +4 -5
  46. package/dist/prompts/default.js +16 -18
  47. package/dist/prompts/simple-sections.d.ts +3 -1
  48. package/dist/prompts/simple-sections.js +11 -1
  49. package/dist/stores/cc/task-list-store.js +3 -3
  50. package/dist/stores/file/memory-store.d.ts +3 -0
  51. package/dist/stores/file/memory-store.js +39 -12
  52. package/dist/stores/file/tool-result-store.js +16 -2
  53. package/dist/stores/file/workflow-journal-store.d.ts +23 -0
  54. package/dist/stores/file/workflow-journal-store.js +140 -3
  55. package/dist/tools/fs/bash-readonly-classifier.js +21 -2
  56. package/dist/tools/fs/fs-bash.d.ts +1 -0
  57. package/dist/tools/fs/fs-bash.js +10 -3
  58. package/dist/tools/fs/fs-read.js +12 -12
  59. package/dist/tools/fs/fs-search-tools.js +42 -7
  60. package/dist/tools/fs/fs-write.js +18 -6
  61. package/dist/tools/fs/index.d.ts +1 -0
  62. package/dist/tools/fs/index.js +2 -1
  63. package/dist/tools/fs/safety.d.ts +4 -0
  64. package/dist/tools/fs/safety.js +113 -10
  65. package/dist/tools/fs/search.d.ts +1 -0
  66. package/dist/tools/fs/search.js +23 -3
  67. package/dist/tools/monitor.js +1 -1
  68. package/dist/tools/task-list.d.ts +1 -0
  69. package/dist/tools/task-list.js +13 -2
  70. package/dist/tools/web.js +36 -6
  71. package/package.json +3 -2
package/dist/tools/web.js CHANGED
@@ -577,6 +577,13 @@ export function createWebFetchSummarizer(brain, model) {
577
577
  const DEFAULT_SEARCH_TIMEOUT_MS = 30_000;
578
578
  const SEARCH_ERROR_EXCERPT_CHARS = 2048;
579
579
  const SEARCH_QUERY_MAX_CHARS = 2_000;
580
+ const DETAILS_QUERY_ECHO_MAX_CHARS = 500;
581
+ function clipQueryEcho(query) {
582
+ const cps = [...query];
583
+ return cps.length > DETAILS_QUERY_ECHO_MAX_CHARS
584
+ ? cps.slice(0, DETAILS_QUERY_ECHO_MAX_CHARS).join("") + `…[${cps.length} chars total]`
585
+ : query;
586
+ }
580
587
  function classifySearchFailure(message) {
581
588
  const m = message.toLowerCase();
582
589
  const status = /(?:\bhttp\b|\bstatus\b|\bcode\b|\berror\b)\D{0,12}?(\d{3})\b/.exec(m)?.[1];
@@ -619,6 +626,18 @@ function hostMatchesDomain(host, domain) {
619
626
  return false;
620
627
  return h === d || h.endsWith("." + d);
621
628
  }
629
+ const URL_SCHEME_PREFIX = /^([a-z][a-z0-9+.-]*):/i;
630
+ function normalizeResultUrl(raw) {
631
+ const s = raw.trim();
632
+ if (!s)
633
+ return { url: raw, schemeAssumed: false };
634
+ if (s.startsWith("//"))
635
+ return { url: "https:" + s, schemeAssumed: true };
636
+ const scheme = URL_SCHEME_PREFIX.exec(s)?.[1];
637
+ if (scheme !== undefined && !scheme.includes("."))
638
+ return { url: s, schemeAssumed: false };
639
+ return { url: "https://" + s, schemeAssumed: true };
640
+ }
622
641
  function webSearchResultAllowed(url, allowed, blocked) {
623
642
  let host;
624
643
  try {
@@ -662,7 +681,7 @@ export function createWebSearchTool(config) {
662
681
  const startedAt = Date.now();
663
682
  const failCard = (extra = {}) => ({
664
683
  type: "web-search",
665
- query,
684
+ query: clipQueryEcho(query),
666
685
  results: [],
667
686
  durationSeconds: (Date.now() - startedAt) / 1000,
668
687
  searchCount: 0,
@@ -723,13 +742,18 @@ export function createWebSearchTool(config) {
723
742
  clearTimeout(timer);
724
743
  ctx.signal?.removeEventListener("abort", onOuterAbort);
725
744
  }
726
- const usable = results.filter((r) => webSearchResultAllowed(r.url));
727
- const droppedUnusable = results.length - usable.length;
745
+ const normalized = results.map((r) => {
746
+ const n = normalizeResultUrl(r.url);
747
+ return { ...r, url: n.url, schemeAssumed: n.schemeAssumed };
748
+ });
749
+ const usable = normalized.filter((r) => webSearchResultAllowed(r.url));
750
+ const droppedUnusable = normalized.length - usable.length;
728
751
  const domainFiltered = usable.filter((r) => webSearchResultAllowed(r.url, allowed_domains, blocked_domains));
729
752
  const droppedByDomain = usable.length - domainFiltered.length;
730
- results = domainFiltered.slice(0, max);
753
+ const kept = domainFiltered.slice(0, max);
754
+ const schemeAssumed = kept.filter((r) => r.schemeAssumed).length;
731
755
  let clipped = false;
732
- const shown = results.map((r) => {
756
+ const shown = kept.map((r) => {
733
757
  const title = clipCodePoints(r.title, SEARCH_TITLE_MAX_CHARS);
734
758
  const url = clipCodePoints(r.url, MAX_URL_LENGTH);
735
759
  const snippet = clipCodePoints(r.snippet, SEARCH_SNIPPET_MAX_CHARS);
@@ -750,7 +774,13 @@ export function createWebSearchTool(config) {
750
774
  const clipNote = clipped
751
775
  ? "\n\n[WebSearch: one or more result fields exceeded the display limits and were truncated — treat the text above as an excerpt, not the backend's full result.]"
752
776
  : "";
753
- const modelText = `${fenced}${dropNote}${domainNote}${clipNote}\n\nREMINDER: You MUST include the sources above in your response to the user using markdown hyperlinks.`;
777
+ const schemeNote = schemeAssumed > 0
778
+ ? `\n\n[WebSearch: ${schemeAssumed} result(s) came back with no URL scheme (a bare domain or a protocol-relative URL) and are shown normalized to https:// — that scheme is this tool's assumption, not the backend's claim.]`
779
+ : "";
780
+ const tailReminder = shown.length > 0
781
+ ? "REMINDER: You MUST include the sources above in your response to the user using markdown hyperlinks."
782
+ : "REMINDER: this search returned ZERO usable sources — there is nothing above to cite. Do not fabricate sources, URLs or citations; tell the user the search returned no usable results (the notes above say why, when there is a why) and answer from what you already know, or try a different query.";
783
+ const modelText = `${fenced}${dropNote}${domainNote}${schemeNote}${clipNote}\n\n${tailReminder}`;
754
784
  return {
755
785
  content: modelText,
756
786
  details: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "2.0.1",
3
+ "version": "2.2.0",
4
4
  "description": "Stateless, task-oriented AI agent core",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -56,7 +56,8 @@
56
56
  "smoke": "tsx src/examples/smoke.ts",
57
57
  "eval": "tsx eval/run.ts",
58
58
  "prepare": "npm run build",
59
- "prepublishOnly": "npm run build && npm run test"
59
+ "prepublishOnly": "npm run build && npm run test",
60
+ "gate:blackbox": "node scripts/run-blackbox-gate.mjs"
60
61
  },
61
62
  "dependencies": {
62
63
  "@modelcontextprotocol/sdk": "1.29.0",