@sema-agent/core 5.12.0 → 5.14.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.
- package/CHANGELOG.md +320 -0
- package/dist/agents/send-message-tool.js +1 -0
- package/dist/agents/subagent.d.ts +4 -0
- package/dist/agents/subagent.js +137 -43
- package/dist/brain/anthropic.js +33 -10
- package/dist/brain/context-overflow.d.ts +20 -0
- package/dist/brain/context-overflow.js +58 -0
- package/dist/brain/open-responses.js +24 -10
- package/dist/brain/openai.js +29 -11
- package/dist/brain/request-params.d.ts +2 -0
- package/dist/brain/request-params.js +16 -0
- package/dist/brain/stream-engine.d.ts +9 -1
- package/dist/brain/stream-engine.js +256 -27
- package/dist/brain/timeout.d.ts +1 -0
- package/dist/brain/timeout.js +1 -0
- package/dist/core/a2a.d.ts +2 -2
- package/dist/core/a2a.js +3 -3
- package/dist/core/ask-question.d.ts +47 -2
- package/dist/core/ask-question.js +209 -28
- package/dist/core/background-agent-store.d.ts +2 -0
- package/dist/core/checkpoint-store.d.ts +49 -18
- package/dist/core/checkpoint-store.js +117 -4
- package/dist/core/compliance.d.ts +11 -0
- package/dist/core/compliance.js +34 -0
- package/dist/core/governance-codes.d.ts +12 -0
- package/dist/core/governance-codes.js +24 -0
- package/dist/core/hooks.d.ts +24 -2
- package/dist/core/hooks.js +97 -10
- package/dist/core/human-input-projection.d.ts +12 -0
- package/dist/core/human-input-projection.js +27 -0
- package/dist/core/locked-config.d.ts +27 -0
- package/dist/core/locked-config.js +42 -0
- package/dist/core/mcp.d.ts +7 -2
- package/dist/core/mcp.js +7 -7
- package/dist/core/memory-admission.d.ts +51 -0
- package/dist/core/memory-admission.js +159 -0
- package/dist/core/memory.d.ts +2 -0
- package/dist/core/memory.js +3 -2
- package/dist/core/retention.d.ts +36 -0
- package/dist/core/retention.js +31 -0
- package/dist/core/runner/assemble-result.d.ts +1 -0
- package/dist/core/runner/assemble-result.js +2 -2
- package/dist/core/runner/prepare-memory.d.ts +9 -0
- package/dist/core/runner/prepare-memory.js +28 -2
- package/dist/core/runner/prepare-task.d.ts +18 -6
- package/dist/core/runner/prepare-task.js +428 -38
- package/dist/core/runner/runtask.d.ts +3 -6
- package/dist/core/runner/runtask.js +258 -77
- package/dist/core/runner/tool-output-projection.js +1 -0
- package/dist/core/session-store.d.ts +4 -0
- package/dist/core/session-store.js +5 -0
- package/dist/core/session.d.ts +1 -0
- package/dist/core/store-contracts/background-agent-store-contract.js +19 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +62 -3
- package/dist/core/task-notification.d.ts +2 -0
- package/dist/core/task-notification.js +5 -3
- package/dist/core/task-registry-agent.d.ts +1 -0
- package/dist/core/task-registry-agent.js +6 -0
- package/dist/core/task-registry.d.ts +1 -0
- package/dist/core/task-registry.js +4 -1
- package/dist/core/tool-policy.d.ts +5 -0
- package/dist/core/tool-policy.js +2 -1
- package/dist/core/tool-result-store.d.ts +2 -0
- package/dist/core/tool-result-store.js +1 -0
- package/dist/core/types.d.ts +38 -2
- package/dist/core/wiring-manifest.d.ts +97 -0
- package/dist/core/wiring-manifest.js +186 -0
- package/dist/engine/compaction/compaction.js +2 -2
- package/dist/engine/harness/agent-harness.d.ts +2 -1
- package/dist/engine/harness/agent-harness.js +19 -2
- package/dist/engine/harness/types.d.ts +3 -1
- package/dist/engine/llm/types.d.ts +7 -0
- package/dist/engine/llm/types.js +8 -1
- package/dist/engine/llm/validation.js +11 -1
- package/dist/engine/session/import-validate.d.ts +6 -1
- package/dist/engine/session/import-validate.js +29 -6
- package/dist/engine/session/memory-repo.d.ts +3 -1
- package/dist/engine/session/memory-repo.js +2 -2
- package/dist/index.d.ts +12 -4
- package/dist/index.js +12 -4
- package/dist/internal/harness-types.d.ts +1 -1
- package/dist/internal/llm.d.ts +2 -2
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +4 -0
- package/dist/orchestration/run-workflow-tool.js +3 -0
- package/dist/orchestration/workflow-types.d.ts +8 -0
- package/dist/orchestration/workflow-types.js +14 -0
- package/dist/orchestration/workflow.d.ts +4 -0
- package/dist/orchestration/workflow.js +134 -5
- package/dist/prompts/default.js +1 -1
- package/dist/stores/file/checkpoint-store.d.ts +3 -5
- package/dist/stores/file/checkpoint-store.js +31 -2
- package/dist/stores/file/index.js +1 -1
- package/dist/stores/file/session-store.d.ts +3 -1
- package/dist/stores/file/session-store.js +2 -2
- package/dist/stores/file/shared-ledger.js +8 -1
- package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -0
- package/dist/tools/fs/bash-readonly-classifier.js +94 -0
- package/dist/tools/fs/fs-bash.js +31 -12
- package/dist/tools/fs/safety.js +34 -10
- package/package.json +1 -1
package/dist/tools/fs/fs-bash.js
CHANGED
|
@@ -7,10 +7,10 @@ import { hasBackgroundShell } from "../../core/background-shell.js";
|
|
|
7
7
|
import { delimitUntrusted } from "../../core/untrusted-text.js";
|
|
8
8
|
import { MCP_IMAGE_MAX_BASE64 } from "../../core/mcp.js";
|
|
9
9
|
import { imageMagicMatches, withinAnyRoot } from "./safety.js";
|
|
10
|
-
import { isRemoteExecutionEnv } from "../../core/remote-env.js";
|
|
10
|
+
import { isRemoteExecutionEnv, hasDestroy, isIsolated } from "../../core/remote-env.js";
|
|
11
11
|
import { ghRateLimitHint } from "./gh-rate-limit.js";
|
|
12
12
|
import { resolveBashTimeoutCaps, bashTimeoutCapsSec, bashMaxOutputChars, clipShellOutput, writeShellOverflowFile, createShellOverflowSpoolFence, shellRecoveryHint, CWD_SENTINEL, } from "./fs-shared.js";
|
|
13
|
-
import { BASH_READONLY_DEFAULT_ALLOW, coarseReadonlyCheck, classifyCompoundReadonly, classifySimpleCommandReadBoundary, } from "./bash-readonly-classifier.js";
|
|
13
|
+
import { BASH_READONLY_DEFAULT_ALLOW, coarseReadonlyCheck, classifyBoundedReadonlyPollLoop, classifyCompoundReadonly, classifySimpleCommandReadBoundary, } from "./bash-readonly-classifier.js";
|
|
14
14
|
export function bashReversibilityProbe(allow, boundary) {
|
|
15
15
|
const allowSet = new Set(allow ?? BASH_READONLY_DEFAULT_ALLOW);
|
|
16
16
|
return (args) => {
|
|
@@ -18,7 +18,9 @@ export function bashReversibilityProbe(allow, boundary) {
|
|
|
18
18
|
if (typeof command !== "string")
|
|
19
19
|
return { reversible: false };
|
|
20
20
|
const resolved = typeof boundary === "function" ? boundary() : boundary;
|
|
21
|
-
|
|
21
|
+
if (classifyCompoundReadonly(command, allowSet, resolved) === undefined)
|
|
22
|
+
return { reversible: true };
|
|
23
|
+
return { reversible: classifyBoundedReadonlyPollLoop(command, allowSet, resolved) === undefined };
|
|
22
24
|
};
|
|
23
25
|
}
|
|
24
26
|
const EXIT1_INTERPRETATION = {
|
|
@@ -399,7 +401,22 @@ async function runShell(env, cwd, toolName, command, timeoutSec, caps, signal, c
|
|
|
399
401
|
},
|
|
400
402
|
};
|
|
401
403
|
}
|
|
402
|
-
function
|
|
404
|
+
function bgReapClause(sessionScoped, envIsolatedOwned) {
|
|
405
|
+
if (!sessionScoped)
|
|
406
|
+
return "when this task ends";
|
|
407
|
+
return envIsolatedOwned
|
|
408
|
+
? "at session end, not when this task ends — UNLESS this task's own isolated sandbox is torn down, which reaps it right then instead"
|
|
409
|
+
: "at session end, not when this task ends: it keeps running across tasks in the same session, and a later task can still read its output or stop it";
|
|
410
|
+
}
|
|
411
|
+
function bgNohupCaveat(envIsolatedOwned) {
|
|
412
|
+
return envIsolatedOwned
|
|
413
|
+
? " — on a per-task isolated sandbox this only helps if the sandbox itself survives; if the deployment tears it down at task end, host the deliverable outside the sandbox instead"
|
|
414
|
+
: "";
|
|
415
|
+
}
|
|
416
|
+
function bgRetainedIsolatedNote() {
|
|
417
|
+
return " This environment declares retention for background processes — normally one keeps running past this task and the session. The one exception: a per-task isolated sandbox that gets torn down still reaps it right then despite the retention declaration; if the deliverable must survive that too, host it outside the sandbox instead.";
|
|
418
|
+
}
|
|
419
|
+
function bashDescription(coAuthor, caps, bgNotifies = false, bgRetained = false, bgSessionScoped = false, bgEnvIsolatedOwned = false) {
|
|
403
420
|
const coAuthorLines = coAuthor === false
|
|
404
421
|
? "- Follow the deployment's commit-message conventions."
|
|
405
422
|
: `- End git commit messages with:\nCo-Authored-By: ${coAuthor}`;
|
|
@@ -409,7 +426,7 @@ function bashDescription(coAuthor, caps, bgNotifies = false, bgRetained = false)
|
|
|
409
426
|
- IMPORTANT: Avoid using this tool to run \`cat\`, \`head\`, \`tail\`, \`sed\`, \`awk\`, or \`echo\` commands, unless explicitly instructed or after you have verified that a dedicated tool cannot accomplish your task. Instead, use the appropriate dedicated tool as this will provide a much better experience for the user.
|
|
410
427
|
- File search by name: use the Glob tool (NOT \`find\` or \`ls\`); content search: use the Grep tool (NOT \`grep\`/\`rg\` in the shell).
|
|
411
428
|
- \`timeout\` is in milliseconds: default ${caps.defaultMs}, max ${caps.maxMs}.
|
|
412
|
-
- \`run_in_background\` runs the command detached: it keeps running across turns and ${bgNotifies ? "re-invokes you when it exits" : "you read its output later with TaskOutput(task_id)"}. No \`&\` needed.${bgRetained ? "" :
|
|
429
|
+
- \`run_in_background\` runs the command detached: it keeps running across turns and ${bgNotifies ? "re-invokes you when it exits" : "you read its output later with TaskOutput(task_id)"}. No \`&\` needed.${bgRetained ? (bgEnvIsolatedOwned ? bgRetainedIsolatedNote() : "") : ` Background processes do NOT survive the session — they are reaped ${bgReapClause(bgSessionScoped, bgEnvIsolatedOwned)}. A deliverable that must stay alive afterwards (a server, a daemon) needs a self-detaching FOREGROUND start instead: run \`nohup cmd >log 2>&1 &\` as a normal foreground command (portable; setsid does not exist on macOS), or use a service manager${bgNohupCaveat(bgEnvIsolatedOwned)}.`}
|
|
413
430
|
|
|
414
431
|
# Git
|
|
415
432
|
- Interactive flags (\`-i\`, e.g. \`git rebase -i\`, \`git add -i\`) are not supported in this environment.
|
|
@@ -463,20 +480,22 @@ async function adoptBackgroundShell(req) {
|
|
|
463
480
|
return { ok: false, reason, killed: false, killMsg: kill !== undefined && !kill.ok ? kill.error.message : "killBackground threw" };
|
|
464
481
|
}
|
|
465
482
|
}
|
|
466
|
-
function backgroundLifetimeNote(caps) {
|
|
467
|
-
|
|
468
|
-
? ""
|
|
469
|
-
|
|
483
|
+
function backgroundLifetimeNote(caps, sessionScoped, envIsolatedOwned) {
|
|
484
|
+
if (caps.retainBackgroundProcesses === true)
|
|
485
|
+
return envIsolatedOwned ? bgRetainedIsolatedNote() : "";
|
|
486
|
+
return ` NOTE: background processes do NOT survive the session (reaped ${bgReapClause(sessionScoped, envIsolatedOwned)}). If this is a deliverable service that must stay alive afterwards, host it with a FOREGROUND command instead: \`nohup cmd >log 2>&1 &\` (self-detaching — survives the session)${bgNohupCaveat(envIsolatedOwned)}.`;
|
|
470
487
|
}
|
|
471
488
|
export function createBashTool(env, rootCanonical, coAuthor = false, cwdRef = { current: rootCanonical }, taskOpts = {}) {
|
|
472
489
|
const timeoutCaps = resolveBashTimeoutCaps(taskOpts);
|
|
473
490
|
const timeoutCapsSecView = bashTimeoutCapsSec(timeoutCaps);
|
|
474
491
|
const bgNotifies = taskOpts.taskRegistry !== undefined && taskOpts.onTaskNotification !== undefined;
|
|
475
492
|
const bgRetained = hasBackgroundShell(env) && env.backgroundCapabilities.retainBackgroundProcesses === true;
|
|
493
|
+
const bgSessionScoped = taskOpts.sessionId !== undefined && taskOpts.taskRegistry !== undefined;
|
|
494
|
+
const bgEnvIsolatedOwned = hasDestroy(env) && isIsolated(env);
|
|
476
495
|
return defineTool({
|
|
477
496
|
name: "Bash",
|
|
478
497
|
contract: { contractId: "core.bash@1", implementationRevision: "1" },
|
|
479
|
-
description: bashDescription(coAuthor, timeoutCaps, bgNotifies, bgRetained),
|
|
498
|
+
description: bashDescription(coAuthor, timeoutCaps, bgNotifies, bgRetained, bgSessionScoped, bgEnvIsolatedOwned),
|
|
480
499
|
parameters: Type.Object({
|
|
481
500
|
command: Type.String({ description: "The command to execute" }),
|
|
482
501
|
timeout: Type.Optional(Type.Number({ description: `Optional timeout in milliseconds (max ${timeoutCaps.maxMs}; requests above the max are capped to it)` })),
|
|
@@ -535,7 +554,7 @@ export function createBashTool(env, rootCanonical, coAuthor = false, cwdRef = {
|
|
|
535
554
|
? ` Time budget: requested ${requestedTimeoutSec}s, capped at ${bgCaps.maxBgTimeoutSec}s (env ceiling: requests above ${bgCaps.maxBgTimeoutSec}s are reduced to it) — auto-terminates if still running after ${appliedTimeoutSec}s.`
|
|
536
555
|
: ` Time budget: auto-terminates if still running after ${appliedTimeoutSec}s (hard cap ${bgCaps.maxBgTimeoutSec}s).`
|
|
537
556
|
: "";
|
|
538
|
-
const lifetimeNote = backgroundLifetimeNote(bgCaps);
|
|
557
|
+
const lifetimeNote = backgroundLifetimeNote(bgCaps, bgSessionScoped, bgEnvIsolatedOwned);
|
|
539
558
|
const registry = taskOpts.taskRegistry;
|
|
540
559
|
if (registry !== undefined) {
|
|
541
560
|
const onNotify = taskOpts.onTaskNotification;
|
|
@@ -649,7 +668,7 @@ export function createBashTool(env, rootCanonical, coAuthor = false, cwdRef = {
|
|
|
649
668
|
? `You will be notified when it completes — do not poll.`
|
|
650
669
|
: `Poll TaskOutput until its status is no longer "running".`) +
|
|
651
670
|
adoptBudgetNote +
|
|
652
|
-
backgroundLifetimeNote(adoptCaps) +
|
|
671
|
+
backgroundLifetimeNote(adoptCaps, bgSessionScoped, bgEnvIsolatedOwned) +
|
|
653
672
|
(tail ? `\n--- output so far (tail) ---\n${tail}` : ""),
|
|
654
673
|
details: { type: "bash", detached: true, task_id: taskId, ...(description !== undefined ? { description } : {}), ...(outputFile !== undefined ? { output_file: outputFile } : {}), ...(cause === "timeout" ? { autoBackgrounded: true } : {}) },
|
|
655
674
|
};
|
package/dist/tools/fs/safety.js
CHANGED
|
@@ -309,15 +309,29 @@ export async function canonicalizeTarget(env, path, signal, baseCwd) {
|
|
|
309
309
|
let abs = absR.value;
|
|
310
310
|
for (let hop = 0; hop < 16; hop++) {
|
|
311
311
|
const exists = await env.exists(abs, signal);
|
|
312
|
-
if (!
|
|
313
|
-
return { ok:
|
|
312
|
+
if (!exists.ok) {
|
|
313
|
+
return { ok: false, message: `cannot determine whether "${path}" exists: ${exists.error.message}`, unresolvedSymlink: true };
|
|
314
|
+
}
|
|
315
|
+
if (!exists.value) {
|
|
316
|
+
const newPath = await canonicalizeNewPath(env, abs, signal);
|
|
317
|
+
if (!newPath.ok) {
|
|
318
|
+
return { ok: false, message: newPath.message, unresolvedSymlink: true };
|
|
319
|
+
}
|
|
320
|
+
return { ok: true, key: newPath.key };
|
|
314
321
|
}
|
|
315
322
|
const canon = await env.canonicalPath(abs, signal);
|
|
316
323
|
if (canon.ok)
|
|
317
324
|
return { ok: true, key: canon.value };
|
|
318
325
|
const info = await env.fileInfo(abs, signal);
|
|
319
|
-
if (!
|
|
320
|
-
return { ok:
|
|
326
|
+
if (!info.ok) {
|
|
327
|
+
return { ok: false, message: `cannot determine whether "${path}" is a symlink: ${info.error.message}`, unresolvedSymlink: true };
|
|
328
|
+
}
|
|
329
|
+
if (info.value.kind !== "symlink") {
|
|
330
|
+
const viaAncestors = await canonicalizeNewPath(env, abs, signal, { skipLeaf: true });
|
|
331
|
+
if (!viaAncestors.ok) {
|
|
332
|
+
return { ok: false, message: viaAncestors.message, unresolvedSymlink: true };
|
|
333
|
+
}
|
|
334
|
+
return { ok: true, key: viaAncestors.key };
|
|
321
335
|
}
|
|
322
336
|
if (!env.readLink) {
|
|
323
337
|
return { ok: false, message: `cannot resolve symlink "${path}" (env has no readLink)`, unresolvedSymlink: true };
|
|
@@ -328,7 +342,10 @@ export async function canonicalizeTarget(env, path, signal, baseCwd) {
|
|
|
328
342
|
}
|
|
329
343
|
const linkTarget = isAbsolutePathForm(link.value) ? link.value : `${parentDir(abs)}${nativeSepOf(abs)}${link.value}`;
|
|
330
344
|
const reabs = await env.absolutePath(linkTarget, signal);
|
|
331
|
-
|
|
345
|
+
if (!reabs.ok) {
|
|
346
|
+
return { ok: false, message: `cannot resolve symlink target "${linkTarget}" for "${path}": ${reabs.error.message}`, unresolvedSymlink: true };
|
|
347
|
+
}
|
|
348
|
+
abs = reabs.value;
|
|
332
349
|
}
|
|
333
350
|
return { ok: false, message: `symlink chain for "${path}" exceeded the hop cap; target unresolved`, unresolvedSymlink: true };
|
|
334
351
|
}
|
|
@@ -339,21 +356,28 @@ function parentDir(abs) {
|
|
|
339
356
|
const head = abs.slice(0, i);
|
|
340
357
|
return /^[A-Za-z]:$/.test(head) ? head + abs[i] : head;
|
|
341
358
|
}
|
|
342
|
-
async function canonicalizeNewPath(env, abs, signal) {
|
|
359
|
+
async function canonicalizeNewPath(env, abs, signal, opts) {
|
|
343
360
|
const sep = nativeSepOf(abs);
|
|
344
361
|
const parts = isWinFormPath(abs) ? abs.split(/[\\/]/) : abs.split("/");
|
|
345
362
|
const tail = [];
|
|
363
|
+
if (opts?.skipLeaf === true && parts.length > 1)
|
|
364
|
+
tail.push(parts.pop());
|
|
346
365
|
while (parts.length > 1) {
|
|
347
366
|
const candidate = parts.join(sep) || sep;
|
|
348
367
|
const ex = await env.exists(candidate, signal);
|
|
349
|
-
if (ex.ok
|
|
368
|
+
if (!ex.ok) {
|
|
369
|
+
return { ok: false, message: `cannot determine whether ancestor "${candidate}" exists: ${ex.error.message}` };
|
|
370
|
+
}
|
|
371
|
+
if (ex.value) {
|
|
350
372
|
const canon = await env.canonicalPath(candidate, signal);
|
|
351
|
-
|
|
352
|
-
|
|
373
|
+
if (!canon.ok) {
|
|
374
|
+
return { ok: false, message: `cannot canonicalize existing ancestor "${candidate}": ${canon.error.message}` };
|
|
375
|
+
}
|
|
376
|
+
return { ok: true, key: [canon.value, ...tail.reverse()].join(nativeSepOf(canon.value)) };
|
|
353
377
|
}
|
|
354
378
|
tail.push(parts.pop());
|
|
355
379
|
}
|
|
356
|
-
return abs;
|
|
380
|
+
return { ok: true, key: abs };
|
|
357
381
|
}
|
|
358
382
|
export function violationText(toolName, v) {
|
|
359
383
|
return `Error (${toolName}): ${v.message}`;
|