@sema-agent/core 2.11.0 → 2.13.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 (37) hide show
  1. package/dist/agents/agent-transcript-tool.d.ts +1 -0
  2. package/dist/agents/agent-transcript-tool.js +1 -1
  3. package/dist/brain/stream-engine.js +4 -1
  4. package/dist/core/auto-promote.js +2 -1
  5. package/dist/core/checkpoint-store.d.ts +1 -0
  6. package/dist/core/checkpoint-store.js +3 -0
  7. package/dist/core/git-worktree-env.js +5 -0
  8. package/dist/core/mcp.d.ts +3 -0
  9. package/dist/core/mcp.js +91 -7
  10. package/dist/core/remote-env.d.ts +3 -0
  11. package/dist/core/remote-env.js +19 -1
  12. package/dist/core/runner/active-skill-scope.js +34 -6
  13. package/dist/core/runner/assemble-result.d.ts +3 -0
  14. package/dist/core/runner/assemble-result.js +4 -1
  15. package/dist/core/runner/prepare-task.d.ts +4 -0
  16. package/dist/core/runner/prepare-task.js +120 -25
  17. package/dist/core/runner/runtask.js +49 -10
  18. package/dist/core/runner/tool-disclosure.d.ts +1 -0
  19. package/dist/core/runner/tool-disclosure.js +26 -7
  20. package/dist/core/session-store.js +15 -4
  21. package/dist/core/skill-tool-specifier.d.ts +8 -0
  22. package/dist/core/skill-tool-specifier.js +58 -0
  23. package/dist/core/skills-directory.d.ts +1 -1
  24. package/dist/core/skills-directory.js +16 -4
  25. package/dist/core/types.d.ts +11 -5
  26. package/dist/core/with-retry.js +0 -1
  27. package/dist/engine/harness/types.d.ts +1 -1
  28. package/dist/index.d.ts +3 -3
  29. package/dist/index.js +1 -1
  30. package/dist/internal/llm.d.ts +1 -1
  31. package/dist/orchestration/workflow.js +8 -4
  32. package/dist/tools/fs/bash-readonly-classifier.js +38 -6
  33. package/dist/tools/fs/fs-bash.js +14 -0
  34. package/dist/tools/scheduler-tools.js +38 -18
  35. package/dist/tools/web.d.ts +8 -2
  36. package/dist/tools/web.js +46 -17
  37. package/package.json +1 -1
package/dist/tools/web.js CHANGED
@@ -495,6 +495,7 @@ export function webFetchToolSpec(config = {}) {
495
495
  }
496
496
  const text = /html/i.test(contentType) || /^\s*</.test(raw) ? htmlToText(raw) : raw;
497
497
  let out = text;
498
+ let summaryTruncated = false;
498
499
  let note;
499
500
  if (prompt && bodyCut) {
500
501
  note =
@@ -503,7 +504,17 @@ export function webFetchToolSpec(config = {}) {
503
504
  }
504
505
  else if (prompt && config.summarize) {
505
506
  try {
506
- out = await config.summarize(text, prompt, ctx.signal);
507
+ const summarized = await config.summarize(text, prompt, ctx.signal);
508
+ if (typeof summarized === "string") {
509
+ out = summarized;
510
+ }
511
+ else {
512
+ out = summarized.text;
513
+ if (summarized.truncated) {
514
+ summaryTruncated = true;
515
+ note = `[note: the summary below is INCOMPLETE — the summarizer hit its output limit before finishing]`;
516
+ }
517
+ }
507
518
  }
508
519
  catch (e) {
509
520
  out = text;
@@ -534,7 +545,7 @@ export function webFetchToolSpec(config = {}) {
534
545
  bytes: bodyBytes ? bodyBytes.length : raw.length,
535
546
  result: out.length > RESULT_PREVIEW_CHARS ? `${out.slice(0, RESULT_PREVIEW_CHARS)}\n…[${out.length - RESULT_PREVIEW_CHARS} chars truncated — full text in the tool output]` : out,
536
547
  durationMs: Date.now() - startedAt,
537
- ...(truncationNote ? { truncated: true } : {}),
548
+ ...(truncationNote || summaryTruncated ? { truncated: true } : {}),
538
549
  ...transferStateDetails,
539
550
  },
540
551
  };
@@ -560,18 +571,17 @@ export function createWebFetchSummarizer(brain, model) {
560
571
  const msg = brain.complete
561
572
  ? await brain.complete(model, context, { signal })
562
573
  : await (await Promise.resolve(brain.stream(model, context, { signal }))).result();
563
- const am = msg;
564
- if (am?.stopReason === "error" || am?.stopReason === "aborted") {
565
- throw new Error(am.errorMessage ?? `summarizer stopped with ${am.stopReason}`);
574
+ if (msg.stopReason === "error" || msg.stopReason === "aborted") {
575
+ throw new Error(msg.errorMessage ?? `summarizer stopped with ${msg.stopReason}`);
566
576
  }
567
- const text = (am?.content ?? [])
568
- .filter((b) => b?.type === "text" && typeof b.text === "string")
577
+ const text = msg.content
578
+ .filter((b) => b.type === "text" && typeof b.text === "string")
569
579
  .map((b) => b.text)
570
580
  .join("\n")
571
581
  .trim();
572
582
  if (!text)
573
583
  throw new Error("summarizer returned no text");
574
- return text;
584
+ return msg.stopReason === "length" || msg.partialFinalized === true ? { text, truncated: true } : text;
575
585
  };
576
586
  }
577
587
  const DEFAULT_SEARCH_TIMEOUT_MS = 30_000;
@@ -801,25 +811,27 @@ export function createWebSearchTool(config) {
801
811
  export function createSearxngSearchBackend(baseUrl, options = {}) {
802
812
  const doFetch = options.fetchImpl ?? globalThis.fetch;
803
813
  const timeoutMs = options.timeoutMs ?? 10_000;
804
- const base = baseUrl.replace(/\/+$/, "");
814
+ const parsedBase = new URL(baseUrl);
815
+ parsedBase.hash = "";
816
+ parsedBase.pathname = `${parsedBase.pathname.replace(/\/+$/, "")}/search`;
805
817
  return async (query, signal, opts) => {
806
818
  const q = opts?.allowedDomains && opts.allowedDomains.length > 0
807
819
  ? `${opts.allowedDomains.map((d) => `site:${d}`).join(" OR ")} ${query}`
808
820
  : query;
809
- const url = new URL(`${base}/search`);
810
- url.searchParams.set("q", q);
811
- url.searchParams.set("format", "json");
821
+ const url = new URL(parsedBase);
812
822
  for (const [k, v] of Object.entries(options.extraParams ?? {}))
813
823
  url.searchParams.set(k, v);
824
+ url.searchParams.set("q", q);
825
+ url.searchParams.set("format", "json");
814
826
  const timeout = AbortSignal.timeout(timeoutMs);
815
827
  const res = await doFetch(url, { signal: signal ? AbortSignal.any([signal, timeout]) : timeout, headers: { accept: "application/json" } });
816
828
  if (!res.ok)
817
- throw new Error(`SearXNG ${res.status} ${res.statusText} from ${base}/search`);
829
+ throw new Error(`SearXNG ${res.status} ${res.statusText} from ${url.origin}${url.pathname}`);
818
830
  const body = (await res.json());
819
831
  if (!Array.isArray(body.results))
820
- throw new Error(`SearXNG returned no results array from ${base}/search — is format=json enabled on this instance?`);
832
+ throw new Error(`SearXNG returned no results array from ${url.origin}${url.pathname} — is format=json enabled on this instance?`);
821
833
  return body.results
822
- .filter((r) => typeof r.url === "string" && r.url !== "")
834
+ .filter((r) => typeof r === "object" && r !== null && typeof r.url === "string" && r.url !== "")
823
835
  .map((r) => ({
824
836
  title: typeof r.title === "string" && r.title !== "" ? r.title : r.url,
825
837
  url: r.url,
@@ -829,14 +841,31 @@ export function createSearxngSearchBackend(baseUrl, options = {}) {
829
841
  }
830
842
  export async function probeSearchBackend(search, options) {
831
843
  const budget = options?.timeoutMs ?? 15_000;
844
+ let timer;
832
845
  try {
833
846
  const results = await Promise.race([
834
847
  search("connectivity probe", AbortSignal.timeout(budget)),
835
- new Promise((_, reject) => setTimeout(() => reject(new Error(`probe timed out after ${budget}ms`)), budget)),
848
+ new Promise((_, reject) => {
849
+ timer = setTimeout(() => reject(new Error(`probe timed out after ${budget}ms`)), budget);
850
+ }),
836
851
  ]);
837
852
  return { ok: true, results: results.length };
838
853
  }
839
854
  catch (e) {
840
- return { ok: false, error: e instanceof Error ? e.message : String(e) };
855
+ let text;
856
+ if (e instanceof Error)
857
+ text = e.message;
858
+ else {
859
+ try {
860
+ text = String(e);
861
+ }
862
+ catch {
863
+ text = Object.prototype.toString.call(e);
864
+ }
865
+ }
866
+ return { ok: false, error: text };
867
+ }
868
+ finally {
869
+ clearTimeout(timer);
841
870
  }
842
871
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "2.11.0",
3
+ "version": "2.13.0",
4
4
  "description": "Stateless, task-oriented AI agent core",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",