@sema-agent/core 5.49.0 → 5.51.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 +112 -0
- package/dist/agents/roster-store.js +4 -1
- package/dist/agents/send-message-tool.js +5 -5
- package/dist/agents/subagent.d.ts +6 -0
- package/dist/agents/subagent.js +142 -5
- package/dist/agents/teacher.js +4 -1
- package/dist/brain/anthropic.js +11 -20
- package/dist/brain/open-responses.js +6 -14
- package/dist/brain/openai.js +6 -18
- package/dist/brain/reasoning.d.ts +100 -8
- package/dist/brain/reasoning.js +39 -15
- package/dist/brain/request-params.d.ts +37 -1
- package/dist/brain/request-params.js +40 -2
- package/dist/core/auto-mode-prompt.js +9 -1
- package/dist/core/hooks.d.ts +24 -1
- package/dist/core/hooks.js +26 -4
- package/dist/core/mcp.d.ts +7 -1
- package/dist/core/mcp.js +64 -8
- package/dist/core/memory-engine/engine.d.ts +30 -1
- package/dist/core/memory-engine/engine.js +219 -18
- package/dist/core/memory-engine/layout.d.ts +43 -0
- package/dist/core/memory-engine/layout.js +59 -0
- package/dist/core/memory-engine/memory-backend-contract.js +87 -0
- package/dist/core/memory-engine/types.d.ts +13 -1
- package/dist/core/runner/assemble-result.d.ts +6 -0
- package/dist/core/runner/assemble-result.js +1 -1
- package/dist/core/runner/prepare-task.d.ts +15 -0
- package/dist/core/runner/prepare-task.js +104 -44
- package/dist/core/runner/runtask.d.ts +5 -1
- package/dist/core/runner/runtask.js +14 -7
- package/dist/core/task-registry-agent.js +9 -3
- package/dist/core/task-registry-shared.d.ts +6 -0
- package/dist/core/task-registry.js +4 -2
- package/dist/core/tool-policy.d.ts +37 -0
- package/dist/core/tool-policy.js +36 -3
- package/dist/core/tools.js +7 -0
- package/dist/core/types.d.ts +53 -1
- package/dist/engine/loop/agent-loop.js +95 -30
- package/dist/engine/loop/types.d.ts +32 -0
- package/dist/orchestration/run-workflow-tool.d.ts +12 -0
- package/dist/orchestration/run-workflow-tool.js +1 -1
- package/dist/orchestration/workflow-governance.d.ts +27 -0
- package/dist/orchestration/workflow-governance.js +13 -0
- package/dist/orchestration/workflow-primitives.d.ts +8 -1
- package/dist/orchestration/workflow-primitives.js +11 -3
- package/package.json +1 -1
|
@@ -234,6 +234,18 @@ export interface RunWorkflowToolDeps {
|
|
|
234
234
|
parentReadFace?: () => import("../core/types.js").TaskSpec["readFace"];
|
|
235
235
|
/** Twin of the above for the deny-set additions (union, not replace). */
|
|
236
236
|
parentReadDenyPatterns?: () => import("../core/types.js").TaskSpec["readDenyPatterns"];
|
|
237
|
+
/** #345 ③ — the HOST task's write-hands clamp, the read-face clamp's sibling on this lane (the
|
|
238
|
+
* subagent delegation lane has carried it as `ToolExecuteContext.handsReadOnly` since its own
|
|
239
|
+
* tighten-only ruling; the workflow lane was the remaining gap — a read-only host's workflow
|
|
240
|
+
* children spawned with full write hands). Filled ONLY when the clamp is ON (`true`), exactly
|
|
241
|
+
* like the ctx seat, so an unclamped deployment's mount gains no key. Known at prepare-time
|
|
242
|
+
* (frozen TaskSpec snapshot — no lazy getter needed, the `parentCheckpointStoreDisabled` shape). */
|
|
243
|
+
parentHandsReadOnly?: true;
|
|
244
|
+
/** #345 ③ — the HOST task's hard-headless clamp (`interactiveTools: false`), same carriage rules
|
|
245
|
+
* as `parentHandsReadOnly` above: only the DISABLING value travels, mirroring the subagent lane's
|
|
246
|
+
* `ToolExecuteContext.interactiveTools` seat — without it a headless-clamped host's workflow
|
|
247
|
+
* children could re-mount the interactive tool the host run disabled. */
|
|
248
|
+
parentInteractiveTools?: false;
|
|
237
249
|
/** [1238](A) — call-time getter for the HOST task's RESOLVED Model object: a spawned agent whose
|
|
238
250
|
* fold chain produced no model inherits the parent's full object (baseUrl/key routing included),
|
|
239
251
|
* mirroring the subagent lane's ctx.model semantics. */
|
|
@@ -468,7 +468,7 @@ export async function createRunWorkflowTool(d) {
|
|
|
468
468
|
}
|
|
469
469
|
: governance;
|
|
470
470
|
const scriptFn = (wfCtx) => {
|
|
471
|
-
const primitives = buildWorkflowPrimitives(wfCtx, runGovernance, d.onAgentSpawn, d.parentThinking, principal, ctx.checkpointStoreDisabledForChildren === true || d.parentCheckpointStoreDisabled === true, d.parentReadFace, d.parentReadDenyPatterns);
|
|
471
|
+
const primitives = buildWorkflowPrimitives(wfCtx, runGovernance, d.onAgentSpawn, d.parentThinking, principal, ctx.checkpointStoreDisabledForChildren === true || d.parentCheckpointStoreDisabled === true, d.parentReadFace, d.parentReadDenyPatterns, ctx.handsReadOnly === true || d.parentHandsReadOnly === true, ctx.interactiveTools === false || d.parentInteractiveTools === false);
|
|
472
472
|
return d.scriptRunner.run({ scriptSource: script, primitives, scriptArgs: effectiveArgs, signal: wfCtx.signal }).then((r) => r.result);
|
|
473
473
|
};
|
|
474
474
|
if (ctx.signal?.aborted) {
|
|
@@ -125,6 +125,33 @@ export interface ResourceClampNote {
|
|
|
125
125
|
/** The effective value the child actually runs under (min of script/baseline/caps, or a forced ceiling). */
|
|
126
126
|
applied: number;
|
|
127
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* The worktree-overlay merge — `{ ...base, ...worktreeBase }` with ONE amendment: an overlay key
|
|
130
|
+
* whose value is OWN NULLISH (`undefined` OR `null` — both plain-JS deployment shapes) never
|
|
131
|
+
* overrides `base`; it reads as the absent key its value spells ("an absent overlay field inherits
|
|
132
|
+
* from base", the documented semantics). The GENERIC successor of the per-key protections that grew
|
|
133
|
+
* one field at a time (three face arrays, then `onAsk` — the mount-side deletes, which remain for
|
|
134
|
+
* their base-slot readings) while every OTHER same-shaped key stayed destructive: a surviving own
|
|
135
|
+
* nullish overlay key erased the base value — `toolPolicy` / `shellGate` / `limits` / `hooks` /
|
|
136
|
+
* `restoreGatedTools` / `readFace` / … — for exactly the children an untrusted script can route to
|
|
137
|
+
* the overlay (`isolation: "worktree"`), own-`undefined` keys included (a spread copies them; the
|
|
138
|
+
* old `=== null` face drop missed that half). One rule at the one merge point: a new baseline key
|
|
139
|
+
* is safe with no list to extend. The single exception is {@link NULL_VALUED_BASELINE_KEYS}
|
|
140
|
+
* (`checkpointStore: null` — the deployment disarming durable suspend for isolated children is a
|
|
141
|
+
* capability removal it must be able to spell). Explicit non-nullish overlay values keep winning
|
|
142
|
+
* wholesale — the documented deployment override.
|
|
143
|
+
*
|
|
144
|
+
* ACCEPTED COST, stated (adversarial-review round 2): the rule is direction-blind — a CAPABILITY
|
|
145
|
+
* key's out-of-type overlay `null` used to WITHHOLD the base value by the same spread accident
|
|
146
|
+
* (e.g. `worktreeBase: { getApiKeyAndHeaders: null }` overwrote the base resolver AND defeated the
|
|
147
|
+
* parent-credential `=== undefined` fill in workflow.ts — silently blocking the documented
|
|
148
|
+
* inheritance, the same seam-defeat disease the onAsk r3 ruling deleted null for), and such a key
|
|
149
|
+
* now inherits per the documented contract. Deployments withhold capabilities from isolated
|
|
150
|
+
* children with IN-TYPE spellings (`tools: []`, a deny `toolPolicy`, `handsReadOnly: true`);
|
|
151
|
+
* `getApiKeyAndHeaders` currently has no in-type disable value — that expressiveness gap is a
|
|
152
|
+
* baseline-contract question, deliberately not solved by resurrecting undocumented null semantics.
|
|
153
|
+
*/
|
|
154
|
+
export declare function overlayWorktreeBaseline(base: WorkflowGovernanceBaseline["base"], worktreeBase: WorkflowGovernanceBaseline["base"]): WorkflowGovernanceBaseline["base"];
|
|
128
155
|
/** Resolve an LLM-supplied model NAME to a deploy-configured `Model`, FAIL-CLOSED against the allowlist.
|
|
129
156
|
* Throws (never falls open to the whole catalog) when no allowlist is configured or the name is not on it. */
|
|
130
157
|
export declare function resolveModelName(name: string, allowlist: string[] | undefined, models: Record<string, Model> | undefined): Model;
|
|
@@ -57,6 +57,19 @@ function emitStrippedKeysNotice(survey, onNotice) {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
const VALID_THINKING = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
60
|
+
const NULL_VALUED_BASELINE_KEYS = new Set(["checkpointStore"]);
|
|
61
|
+
export function overlayWorktreeBaseline(base, worktreeBase) {
|
|
62
|
+
let overlay = worktreeBase;
|
|
63
|
+
for (const key of Object.keys(worktreeBase)) {
|
|
64
|
+
const v = worktreeBase[key];
|
|
65
|
+
if (v !== undefined && (v !== null || NULL_VALUED_BASELINE_KEYS.has(key)))
|
|
66
|
+
continue;
|
|
67
|
+
if (overlay === worktreeBase)
|
|
68
|
+
overlay = { ...worktreeBase };
|
|
69
|
+
delete overlay[key];
|
|
70
|
+
}
|
|
71
|
+
return { ...base, ...overlay };
|
|
72
|
+
}
|
|
60
73
|
export function resolveModelName(name, allowlist, models) {
|
|
61
74
|
if (!allowlist || allowlist.length === 0) {
|
|
62
75
|
throw new WorkflowModelNotAllowedError(name, "no workflowModelAllowlist is configured (fail-closed: an LLM-authored script cannot pick a model)");
|
|
@@ -44,4 +44,11 @@ parentCheckpointStoreDisabled?: boolean,
|
|
|
44
44
|
parentReadFace?: () => TaskSpec["readFace"],
|
|
45
45
|
/** Twin of the above for the deny-set additions (built-ins always apply; these are the extra
|
|
46
46
|
* entries the host's own deployment/task layers stacked on). */
|
|
47
|
-
parentReadDenyPatterns?: () => TaskSpec["readDenyPatterns"]
|
|
47
|
+
parentReadDenyPatterns?: () => TaskSpec["readDenyPatterns"],
|
|
48
|
+
/** #345 ③ — the HOST task's write-hands clamp is ON (`spec.handsReadOnly === true`). Injected
|
|
49
|
+
* tighten-only into every spawned child, like the read-face clamp above; see the injection
|
|
50
|
+
* below for why it outranks even a `worktreeBase: { handsReadOnly: false }` overlay. */
|
|
51
|
+
parentHandsReadOnly?: boolean,
|
|
52
|
+
/** #345 ③ — the HOST task's hard-headless clamp is ON (`spec.interactiveTools === false`).
|
|
53
|
+
* Same tighten-only injection; only the disabling value ever arrives here as `true`. */
|
|
54
|
+
parentInteractiveToolsOff?: boolean): WorkflowPrimitives;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { assertSupportedAgentIsolation } from "./workflow.js";
|
|
2
|
-
import { buildGovernedChildSpec } from "./workflow-governance.js";
|
|
2
|
+
import { buildGovernedChildSpec, overlayWorktreeBaseline } from "./workflow-governance.js";
|
|
3
3
|
function safeAgentOptions(opts) {
|
|
4
4
|
if (typeof opts !== "object" || opts === null)
|
|
5
5
|
return {};
|
|
@@ -22,12 +22,12 @@ function formatResourceClampNote(notes) {
|
|
|
22
22
|
const parts = notes.map((n) => `${n.field}: requested ${n.requested === undefined ? "unset" : n.requested} → applied ${n.applied}`);
|
|
23
23
|
return `workflow governance tightened this agent's resource limits (${parts.join("; ")})`;
|
|
24
24
|
}
|
|
25
|
-
export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentThinking, parentPrincipal, parentCheckpointStoreDisabled, parentReadFace, parentReadDenyPatterns) {
|
|
25
|
+
export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentThinking, parentPrincipal, parentCheckpointStoreDisabled, parentReadFace, parentReadDenyPatterns, parentHandsReadOnly, parentInteractiveToolsOff) {
|
|
26
26
|
const agent = (spec, opts) => {
|
|
27
27
|
if (typeof spec === "string")
|
|
28
28
|
spec = { objective: spec };
|
|
29
29
|
const agentOpts = safeAgentOptions(opts);
|
|
30
|
-
const effectiveBaseline = (b) => agentOpts.isolation === "worktree" && b.worktreeBase
|
|
30
|
+
const effectiveBaseline = (b) => agentOpts.isolation === "worktree" && b.worktreeBase != null ? { ...b, base: overlayWorktreeBaseline(b.base, b.worktreeBase) } : b;
|
|
31
31
|
const childSpec = governance
|
|
32
32
|
? buildGovernedChildSpec(spec, effectiveBaseline(governance.baseline), governance.models, governance.caps, (notes) => ctx.log(formatResourceClampNote(notes)), governance.onNotice)
|
|
33
33
|
: { ...spec };
|
|
@@ -53,6 +53,14 @@ export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentThi
|
|
|
53
53
|
childSpec.readDenyPatterns = childSpec.readDenyPatterns !== undefined ? [...childSpec.readDenyPatterns, ...pd] : [...pd];
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
+
if (parentHandsReadOnly === true) {
|
|
57
|
+
childSpec.handsReadOnly = true;
|
|
58
|
+
}
|
|
59
|
+
if (parentInteractiveToolsOff === true) {
|
|
60
|
+
childSpec.interactiveTools = false;
|
|
61
|
+
if (childSpec.interactionPosture === "interactive")
|
|
62
|
+
delete childSpec.interactionPosture;
|
|
63
|
+
}
|
|
56
64
|
if (onAgentSpawn) {
|
|
57
65
|
return ctx.agentStream(childSpec, agentOpts).then((handle) => {
|
|
58
66
|
onAgentSpawn(handle);
|