@sema-agent/core 5.28.0 → 5.30.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 +99 -3
- package/dist/agents/cascade.d.ts +1 -1
- package/dist/agents/observer.d.ts +3 -3
- package/dist/agents/peer-admission.d.ts +1 -1
- package/dist/agents/send-message-tool.js +2 -0
- package/dist/agents/subagent.d.ts +2 -0
- package/dist/agents/subagent.js +6 -0
- package/dist/agents/teacher.d.ts +1 -1
- package/dist/agents/teacher.js +2 -0
- package/dist/agents/verify.d.ts +6 -6
- package/dist/agents/verify.js +2 -0
- package/dist/bench/metrics.d.ts +1 -1
- package/dist/brain/retry.d.ts +1 -1
- package/dist/core/arg-summary.d.ts +1 -1
- package/dist/core/ask-class.d.ts +2 -2
- package/dist/core/ask-question.d.ts +1 -1
- package/dist/core/ask-question.js +14 -1
- package/dist/core/auto-compaction.d.ts +5 -1
- package/dist/core/auto-compaction.js +10 -1
- package/dist/core/background-shell.d.ts +5 -5
- package/dist/core/checkpoint-store.d.ts +65 -19
- package/dist/core/checkpoint-store.js +2 -1
- package/dist/core/file-snapshot-store.d.ts +1 -1
- package/dist/core/hooks.d.ts +15 -4
- package/dist/core/hooks.js +8 -2
- package/dist/core/human-input-projection.d.ts +2 -2
- package/dist/core/memory-admission.d.ts +2 -2
- package/dist/core/memory-engine/engine.d.ts +1 -1
- package/dist/core/memory-engine/file-backend.d.ts +2 -2
- package/dist/core/memory-engine/header-hints.d.ts +1 -1
- package/dist/core/memory-engine/layout.d.ts +2 -2
- package/dist/core/memory-recall.d.ts +1 -1
- package/dist/core/memory.d.ts +2 -2
- package/dist/core/oracle-isolation.d.ts +2 -2
- package/dist/core/permission-rule-consent.d.ts +1 -1
- package/dist/core/permission-rule-model.d.ts +1 -1
- package/dist/core/permission-rule-org.d.ts +1 -1
- package/dist/core/permission-rule-store.d.ts +1 -1
- package/dist/core/permission-rules.js +2 -2
- package/dist/core/runner/active-skill-scope.d.ts +1 -1
- package/dist/core/runner/memory-consolidation.d.ts +1 -1
- package/dist/core/runner/prepare-task.d.ts +29 -8
- package/dist/core/runner/prepare-task.js +118 -22
- package/dist/core/runner/runtask.d.ts +1 -1
- package/dist/core/runner/runtask.js +34 -8
- package/dist/core/runner/session-rule-policy.d.ts +4 -3
- package/dist/core/runner/teardown-bounded.d.ts +1 -1
- package/dist/core/runner/tool-disclosure.d.ts +1 -1
- package/dist/core/runner/tool-output-projection.js +1 -1
- package/dist/core/scheduler.d.ts +4 -4
- package/dist/core/sensitive-path-policy.js +5 -16
- package/dist/core/session-policy-store.d.ts +3 -3
- package/dist/core/shared-memory/normalize.d.ts +1 -1
- package/dist/core/skill-tool-specifier.d.ts +1 -1
- package/dist/core/store-contracts/tool-result-store-contract.js +23 -0
- package/dist/core/task-notification.d.ts +2 -2
- package/dist/core/task-registry-agent.d.ts +9 -9
- package/dist/core/task-registry-shared.d.ts +4 -4
- package/dist/core/tighten-task-spec.js +18 -0
- package/dist/core/tool-errors.d.ts +2 -2
- package/dist/core/tool-policy.d.ts +64 -12
- package/dist/core/tool-policy.js +68 -8
- package/dist/core/tool-result-store.d.ts +2 -2
- package/dist/core/tool-result-store.js +3 -1
- package/dist/core/trace.d.ts +1 -1
- package/dist/core/types.d.ts +68 -13
- package/dist/core/untrusted-text.d.ts +6 -0
- package/dist/core/untrusted-text.js +1 -0
- package/dist/engine/compaction/compaction.d.ts +1 -1
- package/dist/engine/harness/messages.d.ts +1 -1
- package/dist/engine/harness/types.d.ts +12 -2
- package/dist/engine/llm/types.d.ts +1 -1
- package/dist/engine/loop/types.d.ts +2 -2
- package/dist/engine/session/import-validate.d.ts +1 -1
- package/dist/engine/session/log-digest.d.ts +1 -1
- package/dist/fixtures/index.d.ts +18 -2
- package/dist/fixtures/index.js +11 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/orchestration/goal.d.ts +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +21 -0
- package/dist/orchestration/run-workflow-tool.js +6 -3
- package/dist/orchestration/workflow-primitives.d.ts +10 -1
- package/dist/orchestration/workflow-primitives.js +12 -1
- package/dist/orchestration/workflow-types.d.ts +5 -4
- package/dist/orchestration/workflow.js +11 -3
- package/dist/prompt-assembly/artifact.d.ts +1 -1
- package/dist/prompt-assembly/epoch.js +2 -0
- package/dist/prompt-assembly/packs/sema-default.js +2 -2
- package/dist/prompt-assembly/types.d.ts +4 -0
- package/dist/prompts/default.d.ts +14 -9
- package/dist/prompts/default.js +14 -4
- package/dist/scenarios/scenario-registry.d.ts +3 -3
- package/dist/stores/file/tool-result-store.d.ts +2 -2
- package/dist/tools/fs/bash-readonly-classifier.d.ts +23 -2
- package/dist/tools/fs/bash-readonly-classifier.js +11 -0
- package/dist/tools/fs/fs-bash.d.ts +8 -1
- package/dist/tools/fs/fs-bash.js +8 -3
- package/dist/tools/fs/fs-pdf.d.ts +1 -1
- package/dist/tools/fs/fs-pdf.js +2 -2
- package/dist/tools/fs/fs-read.d.ts +1 -1
- package/dist/tools/fs/fs-read.js +11 -7
- package/dist/tools/fs/fs-search-tools.d.ts +5 -3
- package/dist/tools/fs/fs-search-tools.js +15 -8
- package/dist/tools/fs/fs-shared.d.ts +6 -2
- package/dist/tools/fs/fs-shared.js +8 -3
- package/dist/tools/fs/index.d.ts +18 -0
- package/dist/tools/fs/index.js +13 -2
- package/dist/tools/fs/read-deny.d.ts +105 -0
- package/dist/tools/fs/read-deny.js +151 -0
- package/dist/tools/fs/read-face.d.ts +43 -0
- package/dist/tools/fs/read-face.js +38 -0
- package/dist/tools/fs/repo-map.d.ts +3 -1
- package/dist/tools/fs/repo-map.js +11 -5
- package/dist/tools/fs/safety.d.ts +34 -12
- package/dist/tools/fs/safety.js +88 -7
- package/dist/tools/fs/search.d.ts +54 -5
- package/dist/tools/fs/search.js +103 -21
- package/dist/tools/scheduler-tools.d.ts +1 -1
- package/dist/tools/task-list.d.ts +1 -1
- package/dist/tools/web.d.ts +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,99 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.30.0 — 2026-08-13
|
|
4
|
+
|
|
5
|
+
No API-BREAKING changes (exports grow only: `resolveReadFace`, `ReadFace`, `ReadFaceInputs`,
|
|
6
|
+
`READ_FACE_DEFAULT_DENY_ENTRIES`, `compileReadDeny`, `ReadDenyEntry`, `ReadDenyMatcher`,
|
|
7
|
+
`NormalizedReadDenyEntry`; `TaskSpec`/`RunnerDeps`/`HandsToolkitOptions` gain `readFace`/
|
|
8
|
+
`readDenyPatterns`). Narrowings are tighten-direction and named below.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **A read-face containment knob (`readFace: "open" | "roots"`, default `"roots"` — byte-compatible
|
|
13
|
+
with prior behavior).** `TaskSpec`/`RunnerDeps`/`HandsToolkitOptions` each gain the seat; task-layer
|
|
14
|
+
may only tighten under governance, deployment-layer sets the default. Beside a read-only (verifier)
|
|
15
|
+
mount, a task-seat `"open"` is a genuine contradiction and refuses loudly; a deployment-seat
|
|
16
|
+
`"open"` there silently clamps to `"roots"` (a deployment default cannot override a load-bearing
|
|
17
|
+
containment wall). Every workflow/subagent/SendMessage delegation lane inherits the resolved face
|
|
18
|
+
tighten-only (stricter-wins), including `run_workflow`'s script-spawned children, which previously
|
|
19
|
+
did not inherit it at all. Checkpoint schema bumps to v9 (`FACE_CHECKPOINT_VERSION`) to carry the
|
|
20
|
+
resolved face across suspend/resume; an absent v9 section on an older checkpoint row is the default
|
|
21
|
+
posture (roots) — no existing row's behavior changes.
|
|
22
|
+
- **A built-in sensitive-path READ deny set**, exported as `READ_FACE_DEFAULT_DENY_ENTRIES` (SSH
|
|
23
|
+
keys, cloud/VCS credential files, browser profile directories, crypto wallet files, shell history,
|
|
24
|
+
and similar). Enforced under BOTH containment modes — an `"open"` face does not exempt it — and not
|
|
25
|
+
shrinkable by any deployment configuration, including the `readFace: "roots"` compatibility seat
|
|
26
|
+
(the two axes are orthogonal). `.env`-family files are deliberately excluded (write-side guards
|
|
27
|
+
already cover them). Deployments may extend the table (`readDenyPatterns` on the same three seats,
|
|
28
|
+
additive-only; `compileReadDeny` lets a host pre-validate additions with the engine's own rules).
|
|
29
|
+
|
|
30
|
+
### Narrowed (behavior)
|
|
31
|
+
|
|
32
|
+
- **A UNC-rooted deployment's `..` can no longer walk out of its declared root.** Lexical folding now
|
|
33
|
+
normalizes `..` segments and Win32 device-namespace prefixes (`\\?\`, `\\.\`) before they reach the
|
|
34
|
+
containment check; this is a security repair with no compatibility escape hatch (unaffected by any
|
|
35
|
+
"keep old behavior" knob).
|
|
36
|
+
- **`bashReversibilityProbe` no longer auto-executes an operand with an unexpanded shell glob
|
|
37
|
+
metacharacter it can't verify against the deny/boundary check.** A command whose read target is
|
|
38
|
+
undecided at the classifier layer now routes to the ask flow instead of running unattended.
|
|
39
|
+
- **A hands-less resume no longer clones the `realApproval` governance marker onto an ungoverned
|
|
40
|
+
re-park.** The seed-carry now picks only `{face, denyEntries}`; previously, a worker resuming into a
|
|
41
|
+
plain (non-governed) ask could inherit a stale `realApproval: true` and permanently wedge the row on
|
|
42
|
+
its next resume (`real_approval_damaged`, fail-closed by design).
|
|
43
|
+
- **The auto-mode classifier can no longer resolve an ask that originated from an explicit
|
|
44
|
+
user-written permission rule or a hook-raised promotion.** Both are now excluded from classifier
|
|
45
|
+
judgment and the persisted-rule-clearing lane, closing two asymmetric gaps against the existing
|
|
46
|
+
`decisionReason === "hook"` exclusion.
|
|
47
|
+
- **`resolveAsk`'s object-arm reads share one exception boundary.** A throwing getter on `settledBy`/
|
|
48
|
+
`allow`/`updatedInput` now fails closed (deny) instead of propagating an unhandled rejection; a
|
|
49
|
+
non-boolean `allow` is refused loudly by name instead of silently rendering as a human refusal.
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- `run_workflow`'s durable-store off switch (`spec.checkpointStore === null`) and design/148's
|
|
54
|
+
center-artifact inheritance (`centerArtifactDigest`/`centerSourceRevision`) were dead reads on the
|
|
55
|
+
tool's auto-mounted execute context (which never carries them) — neither ever reached a
|
|
56
|
+
script-spawned child. Both now fall back to a mount-time dependency, matching the tool's other two
|
|
57
|
+
ctx-or-deps fields.
|
|
58
|
+
- Under `readFace: "open"`, compaction's attachment-reader legs (`readTaskFile`/
|
|
59
|
+
`normalizeAttachmentPath`) refused files the Read tool had already legitimately served out-of-root;
|
|
60
|
+
they now thread the resolved face like the structured read tools do.
|
|
61
|
+
- `deleteBySession` joins the `ToolResultStore` contract kit as an honest optional member: when
|
|
62
|
+
implemented, the four-state semantics (same-session rows deleted, other-session rows untouched,
|
|
63
|
+
unowned rows counted not deleted, idempotent re-delete) are asserted; when absent, the contract
|
|
64
|
+
probe reports it by name instead of silently passing.
|
|
65
|
+
|
|
66
|
+
## 5.29.0 — 2026-08-13
|
|
67
|
+
|
|
68
|
+
No API-BREAKING changes (exports grow only: `AskOutcome.reason`, `AskRequest.isDelegatedChild`).
|
|
69
|
+
|
|
70
|
+
### Changed (behavior)
|
|
71
|
+
|
|
72
|
+
- **A human deny speaks a posture and can carry the decider's words.** The sync approval seat
|
|
73
|
+
`AskOutcome` gains `reason?: string` on its object arm: attached to a deny, the text reaches the
|
|
74
|
+
model inside the untrusted fence, bounded to 2048 code points — the same containment and bound as
|
|
75
|
+
the durable leg's reviewer note (whose four relay sites were previously unbounded and now share
|
|
76
|
+
the cap). Refusal messages fork on the issuing run's position (`AskRequest.isDelegatedChild`,
|
|
77
|
+
forks included): a parent-thread run is told to STOP and wait for the user, a delegated child is
|
|
78
|
+
told to adapt or report; the machine-greppable head line is unchanged. On an allow the seat is
|
|
79
|
+
never read; a non-string reason on a deny is refused loudly; timeout denials carry the note under
|
|
80
|
+
a neutral bridge. NOTE: the posture is model-facing text — making a parent-thread denial abort the
|
|
81
|
+
in-flight batch is registered follow-up work.
|
|
82
|
+
- **`worktreeDir` never names a non-host path.** A remote isolated agent's sandbox cwd is no longer
|
|
83
|
+
recorded (`ResolvedWorkspace` gains a required `remote` key; absence on the record now means
|
|
84
|
+
"shared tree OR remote sandbox"), and a workspace observation is authoritative replacement state —
|
|
85
|
+
a local→remote retry clears the stale host path.
|
|
86
|
+
- **Session freshness is judged by conversation content, not branch entries.** A pre-minted
|
|
87
|
+
sessionId or a host-pre-seeded marker (naming the chat, recording a model pick before the first
|
|
88
|
+
turn) no longer stamps `legacy_migration` on a brand-new session's first epoch pin — and no longer
|
|
89
|
+
silently costs such a session its published center prompt (the adoption arm shared the same
|
|
90
|
+
refuted entry-count proxy; all three freshness sites now share one predicate).
|
|
91
|
+
- **The ask-question tool teaches previews.** The tool description carries the Preview feature block
|
|
92
|
+
(CC markdown variant, verbatim), so the preview card form — the only question form whose answer
|
|
93
|
+
carries user notes — is reachable.
|
|
94
|
+
- The resident execution-environment prompt line about denied calls no longer instructs a blanket
|
|
95
|
+
"adjust and continue" — it defers to the denial message's own guidance (prompt golden re-frozen).
|
|
96
|
+
|
|
3
97
|
## 5.28.0 — 2026-08-12
|
|
4
98
|
|
|
5
99
|
No API-BREAKING changes (exports grow only). Narrowings are tighten-direction and named below.
|
|
@@ -35,9 +129,11 @@ No API-BREAKING changes (exports grow only). Narrowings are tighten-direction an
|
|
|
35
129
|
|
|
36
130
|
### Added
|
|
37
131
|
|
|
38
|
-
- `onNotice` structured notice seat (
|
|
39
|
-
|
|
40
|
-
|
|
132
|
+
- `onNotice` structured notice seat (three families: `config.env_timeout_discarded`,
|
|
133
|
+
`config.materialize_env_discarded`, `tool_result.offload_put_failed` — this entry originally said
|
|
134
|
+
"first two families"; corrected 2026-08-12, the third family shipped in the same release) — absent
|
|
135
|
+
keeps the `console.warn` text verbatim; a present non-function seat is announced once and falls
|
|
136
|
+
back loudly instead of silencing both channels.
|
|
41
137
|
- `tool_end.errorCode` now reads both discriminator spellings — `details.code` first (string), then
|
|
42
138
|
`details.errorKind` — so loop-thrown error frames are classifiable; `code` wins when both exist.
|
|
43
139
|
- `ToolResultStore.deleteBySession?` (optional member; File + in-memory implementations, not on the
|
package/dist/agents/cascade.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { ModelRef, TaskResult, TaskSpec } from "../core/types.js";
|
|
|
9
9
|
* APPLICABILITY: cascade only helps when the gate is **decidable** (a schema check, a verifier model, a
|
|
10
10
|
* concrete assertion). Open-ended "completeness" tasks (find every bug, writing quality) have no oracle —
|
|
11
11
|
* the gate keeps passing the first plausible cheap answer and escalation idles. Those want breadth /
|
|
12
|
-
*
|
|
12
|
+
* falsification-style debate (a `team`), not a depth ladder.
|
|
13
13
|
*
|
|
14
14
|
* Cost note (design/27 §2): each rung is an independent COLD `runTask` — every escalation repays the
|
|
15
15
|
* full input cost. Cascade wins when (a) the cheap rung usually passes and (b) the prompt isn't so large
|
|
@@ -36,11 +36,11 @@ export type ObserverDigestEvent = {
|
|
|
36
36
|
type: "turn_ended";
|
|
37
37
|
reason: string;
|
|
38
38
|
};
|
|
39
|
-
/** CC `S$r` — anti-injection: a
|
|
39
|
+
/** CC `S$r` — anti-injection: a caller-declared envelope tag inside observed content is defused in place. */
|
|
40
40
|
export declare function escapeObserverTags(text: string): string;
|
|
41
41
|
/**
|
|
42
42
|
* CC `zZe` @8339092 — verbatim: `t.replace(new RegExp(`<(?=/?${e}(?:[>\\s/]|$))`, "gi"), "<\\")`.
|
|
43
|
-
* Defuses a
|
|
43
|
+
* Defuses a caller-declared occurrence of ONE specific tag (opening AND closing) inside content — the second
|
|
44
44
|
* escape layer CC applies to the DYNAMIC envelope tag (`<{slug}-activity>`) after joining, which the
|
|
45
45
|
* static four-tag `escapeObserverTags` (Scg layer) cannot cover. Deviation from CC (hardening): the
|
|
46
46
|
* tag is regex-escaped before entering the RegExp — CC interpolates raw, safe only because its slugs
|
|
@@ -281,7 +281,7 @@ export interface ObserverReportToolOptions {
|
|
|
281
281
|
* `<${$Bt} from="${Yp(e)}">\n${zZe($Bt, t)}\n</${$Bt}>` with `$Bt = "agent-message"` @1344442.
|
|
282
282
|
* Deviation from CC ($Bt=agent-message → observer-report, sovereign choice): we keep a dedicated
|
|
283
283
|
* frame tag so the observed agent can tell an observer report from generic agent traffic. The
|
|
284
|
-
* escape mechanics are CC-faithful: the frame tag itself is zZe-defused in the body (so a
|
|
284
|
+
* escape mechanics are CC-faithful: the frame tag itself is zZe-defused in the body (so a caller-declared
|
|
285
285
|
* `</observer-report>` cannot break the frame) and the `from=` attribute value is Yp-escaped.
|
|
286
286
|
* Additional hardening beyond CC: the body also rides through the four-event-tag Scg layer.
|
|
287
287
|
*
|
|
@@ -145,7 +145,7 @@ export declare function resetPeerAdmissionRegistryForTests(): void;
|
|
|
145
145
|
* mounting is structurally single-sourced and survives any downstream projection of the payload).
|
|
146
146
|
* Layered WITH the session-level `SUBAGENT_CONSENT_NOTICE` (prompts/default.ts), not replacing it:
|
|
147
147
|
* that section governs COMMAND authority at session level; this block narrows AUTHORIZATION per
|
|
148
|
-
* message. Placement per leg: OUTSIDE the `<teammate-message>` frame (a
|
|
148
|
+
* message. Placement per leg: OUTSIDE the `<teammate-message>` frame (a caller-declared copy inside the
|
|
149
149
|
* sender-controlled body arrives escaped, so position distinguishes the real block); the L3 resume
|
|
150
150
|
* leg carries it in the TRUST-FRAME layer of the peer-resume prompt, never inside the data fence
|
|
151
151
|
* (a load-bearing instruction inside a "this is DATA" fence would demote itself).
|
|
@@ -680,6 +680,8 @@ export function createSendMessageTool(opts) {
|
|
|
680
680
|
...(ctx.onQuestion !== undefined && row.sessionScoped !== true ? { currentOnQuestion: ctx.onQuestion } : {}),
|
|
681
681
|
currentClamps: {
|
|
682
682
|
...(ctx.handsReadOnly === true ? { handsReadOnly: true } : {}),
|
|
683
|
+
...(ctx.readFace === "roots" ? { readFaceRoots: true } : {}),
|
|
684
|
+
...(ctx.readDenyPatterns !== undefined ? { readDenyPatterns: ctx.readDenyPatterns } : {}),
|
|
683
685
|
...(ctx.interactiveTools === false ? { interactiveTools: false } : {}),
|
|
684
686
|
...(ctx.oneShot === true ? { oneShot: true } : {}),
|
|
685
687
|
...(ctx.memoryPersistenceCapable === false ? { memoryPersistenceCapable: false } : {}),
|
|
@@ -404,6 +404,8 @@ export declare function createSubagentResume(deps: {
|
|
|
404
404
|
interactiveTools?: false;
|
|
405
405
|
oneShot?: true;
|
|
406
406
|
memoryPersistenceCapable?: false;
|
|
407
|
+
readFaceRoots?: true;
|
|
408
|
+
readDenyPatterns?: readonly import("../tools/fs/read-deny.js").ReadDenyEntry[];
|
|
407
409
|
};
|
|
408
410
|
/** The RESUMING caller's own handback-review seat (its trusted `ToolExecuteContext.autoModeReview`),
|
|
409
411
|
* same turn-bound reasoning as `currentOnQuestion` above: a resumed cycle is a completion like any
|
package/dist/agents/subagent.js
CHANGED
|
@@ -520,6 +520,10 @@ export function createSubagentResume(deps) {
|
|
|
520
520
|
requireExistingSession: true,
|
|
521
521
|
...(deps.currentOnQuestion !== undefined ? { onQuestion: deps.currentOnQuestion } : {}),
|
|
522
522
|
...(entry.specSnapshot.handsReadOnly === true || deps.currentClamps?.handsReadOnly === true ? { handsReadOnly: true } : {}),
|
|
523
|
+
...(entry.specSnapshot.readFace === "roots" || deps.currentClamps?.readFaceRoots === true ? { readFace: "roots" } : {}),
|
|
524
|
+
...(entry.specSnapshot.readDenyPatterns !== undefined || deps.currentClamps?.readDenyPatterns !== undefined
|
|
525
|
+
? { readDenyPatterns: [...(entry.specSnapshot.readDenyPatterns ?? []), ...(deps.currentClamps?.readDenyPatterns ?? [])] }
|
|
526
|
+
: {}),
|
|
523
527
|
...(entry.specSnapshot.interactiveTools === false || deps.currentClamps?.interactiveTools === false ? { interactiveTools: false } : {}),
|
|
524
528
|
...(entry.specSnapshot.oneShot === true || deps.currentClamps?.oneShot === true ? { oneShot: true } : {}),
|
|
525
529
|
...(entry.specSnapshot.memoryPersistenceCapable === false || deps.currentClamps?.memoryPersistenceCapable === false
|
|
@@ -1693,6 +1697,8 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
1693
1697
|
...(ctx.onQuestion !== undefined ? { onQuestion: ctx.onQuestion } : {}),
|
|
1694
1698
|
...(ctx.interactiveTools === false ? { interactiveTools: false } : {}),
|
|
1695
1699
|
...(ctx.handsReadOnly === true ? { handsReadOnly: true } : {}),
|
|
1700
|
+
...(ctx.readFace === "roots" ? { readFace: "roots" } : {}),
|
|
1701
|
+
...(ctx.readDenyPatterns !== undefined ? { readDenyPatterns: [...ctx.readDenyPatterns] } : {}),
|
|
1696
1702
|
...(childMemoryPersistenceCapable !== undefined ? { memoryPersistenceCapable: childMemoryPersistenceCapable } : {}),
|
|
1697
1703
|
...(ctx.oneShot === true ? { oneShot: true } : {}),
|
|
1698
1704
|
...(ctx.clientContext !== undefined ? { clientContext: ctx.clientContext } : {}),
|
package/dist/agents/teacher.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ import type { ModelRef, TaskResult, TaskSpec } from "../core/types.js";
|
|
|
13
13
|
* creative quality — because there is no oracle for *completeness*: the verifier can't know how many bugs
|
|
14
14
|
* the code has or which one was missed, so a student that finds one obvious issue passes the rubric while
|
|
15
15
|
* silently missing others, and the escalation machinery idles (verified in practice: 0 escalations, the
|
|
16
|
-
* verifier becomes pure added cost). Such tasks are solved by **breadth +
|
|
16
|
+
* verifier becomes pure added cost). Such tasks are solved by **breadth + falsification-style debate** (a `team`
|
|
17
17
|
* council), not by **depth escalation** — the two are orthogonal. See design/12 §六 for the full reasoning.
|
|
18
18
|
*/
|
|
19
19
|
/** Default teacher (advisor) system prompt — returns ONLY structured JSON guidance. */
|
package/dist/agents/teacher.js
CHANGED
|
@@ -180,6 +180,8 @@ async function runTeacherCore(runner, studentSpec, teacher) {
|
|
|
180
180
|
...(studentSpec.clientContext !== undefined ? { clientContext: studentSpec.clientContext } : {}),
|
|
181
181
|
...(studentSpec.promptProfile !== undefined ? { promptProfile: studentSpec.promptProfile } : {}),
|
|
182
182
|
...(studentSpec.handsReadOnly === true ? { handsReadOnly: true } : {}),
|
|
183
|
+
...(studentSpec.readFace === "roots" ? { readFace: "roots" } : {}),
|
|
184
|
+
...(studentSpec.readDenyPatterns !== undefined ? { readDenyPatterns: [...studentSpec.readDenyPatterns] } : {}),
|
|
183
185
|
...(studentSpec.interactiveTools === false ? { interactiveTools: false } : {}),
|
|
184
186
|
...(studentSpec.excludeTools !== undefined ? { excludeTools: [...studentSpec.excludeTools] } : {}),
|
|
185
187
|
...(studentSpec.deferTools !== undefined ? { deferTools: [...studentSpec.deferTools] } : {}),
|
package/dist/agents/verify.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { Runner, ResumeTaskConfig } from "../core/runner/runtask.js";
|
|
|
3
3
|
import type { CheckpointGate, CheckpointToken, ResumeOutcome } from "../core/checkpoint-store.js";
|
|
4
4
|
import type { ModelRef, TaskResult, TaskSpec, ToolSpec } from "../core/types.js";
|
|
5
5
|
/**
|
|
6
|
-
* Verification gate (developer mode, design/28 §4). An **independent
|
|
6
|
+
* Verification gate (developer mode, design/28 §4). An **independent falsification-style verifier** runs after
|
|
7
7
|
* an implementation task and tries to BREAK it — read-only, evidence-required, returning a structured
|
|
8
8
|
* verdict — then the gate loops fix→re-verify until PASS or a round cap.
|
|
9
9
|
*
|
|
@@ -20,7 +20,7 @@ import type { ModelRef, TaskResult, TaskSpec, ToolSpec } from "../core/types.js"
|
|
|
20
20
|
* SKILL.md` closest to the code it covers … and if that file does not exist, create it." So upstream's
|
|
21
21
|
* position is "verification is project-specific; teach the user's repo to describe its own", not "here
|
|
22
22
|
* is a verifier". This primitive is therefore a SUPERSET of what upstream ships in a different
|
|
23
|
-
* direction than the old note implied: a spawned
|
|
23
|
+
* direction than the old note implied: a spawned falsification-style verifier with a fix loop, bundled. It is
|
|
24
24
|
* orthogonal to and composable with the Stop hook (wire the verdict into a stop() hook to make it a
|
|
25
25
|
* hard completion gate).
|
|
26
26
|
*
|
|
@@ -31,7 +31,7 @@ import type { ModelRef, TaskResult, TaskSpec, ToolSpec } from "../core/types.js"
|
|
|
31
31
|
* per task via {@link runWithVerification} (or {@link runDeveloperTask}).
|
|
32
32
|
*
|
|
33
33
|
* Boundary vs teacher mode: teacher's Tier-1 is a *lenient* rubric verifier that triggers escalation to
|
|
34
|
-
* an advisor (stuck/wrong recovery); this is a *strict
|
|
34
|
+
* an advisor (stuck/wrong recovery); this is a *strict falsification-style* completion gate with a fix loop.
|
|
35
35
|
* Orthogonal, composable, not merged.
|
|
36
36
|
*/
|
|
37
37
|
export declare const VERIFICATION_PROMPT = "You are a verification specialist. Your job is NOT to confirm the implementation works \u2014 it is to try to BREAK it.\n\nYou have two documented failure patterns. First, verification avoidance: faced with a check, you find reasons not to run it \u2014 you read code, narrate what you would test, declare \"PASS,\" and move on. Second, being seduced by the first 80%: a polished result or a passing test suite makes you inclined to pass it, not noticing the edge that crashes, the state that vanishes, the bad input that is unhandled. The first 80% is the easy part. Your entire value is in finding the last 20%.\n\n## Hard boundary \u2014 do not modify the project\nYou are STRICTLY a verifier. Do NOT create, modify, or delete project files; do NOT install packages; do NOT run version-control write operations. Use only the read/probe/execute tools available to you. (If you need a scratch file, use a temp directory, and clean up.)\n\n## Evidence is mandatory\nReading code is NOT verification. Every check must actually run something \u2014 execute the code, hit the endpoint, run the build/tests \u2014 and record the command and its real output. A \"PASS\" with no command output is a skip, not a pass.\n\n## Strategy (adapt to what changed)\n- Build/lib changes: build it, run the full test suite, exercise the public API as a consumer would.\n- Backend/API: start it, call endpoints, check response *shapes* (not just status codes), test error paths.\n- CLI/script: run with representative AND edge inputs (empty, malformed, boundary); check stdout/stderr/exit codes.\n- Bug fix: reproduce the original bug first, verify the fix, then check for regressions and side effects.\n- Refactor (no behavior change): the existing suite must pass unchanged; diff the public surface; same inputs \u2192 same outputs.\nRun the project's own build/tests/linters as a baseline, then apply the type-specific checks. Test results are context, not proof \u2014 the implementer is an LLM too; its tests may be happy-path or circular.\n\n## Adversarial probes (pick the ones that fit)\nBoundary values (0, -1, empty, very long, unicode, max), idempotency (same mutating call twice), orphan operations (ids that don't exist), concurrency (parallel create-if-not-exists). Your verdict must include at least one adversarial probe you actually ran and its result \u2014 even if it was handled correctly.\n\n## Before you FAIL\nCheck you haven't missed why it's actually fine: defensive code elsewhere, intentional behavior documented in comments/specs, or an unfixable external-contract limitation (note that as an observation, not a FAIL). Don't wave away real issues, but don't FAIL on intentional behavior.\n\n## Verdict\nSubmit exactly one verdict via the provided output tool:\n- PASS \u2014 you ran real checks (including \u22651 adversarial probe) and it holds up. Put the commands + observed output in `evidence`.\n- FAIL \u2014 something is broken. Put each concrete problem (with how to reproduce) in `findings`.\n- PARTIAL \u2014 environmental limitation only (no test framework, a tool/server unavailable). Not for \"I'm unsure\": if you can run the check, decide PASS or FAIL. Note what you couldn't verify and why in `findings`.";
|
|
@@ -202,7 +202,7 @@ export interface VerificationResult extends TaskResult {
|
|
|
202
202
|
verification: VerificationOutcome;
|
|
203
203
|
}
|
|
204
204
|
/**
|
|
205
|
-
* Verify an already-**completed** implementation `result` behind the independent
|
|
205
|
+
* Verify an already-**completed** implementation `result` behind the independent falsification-style verifier,
|
|
206
206
|
* looping fix→re-verify until PASS (or a round cap) — **without re-running the implementation**. This is the
|
|
207
207
|
* L3 entry for the L2+L3 composition (design/54 §4): in a fan-out, a worker's module has already been
|
|
208
208
|
* produced, so the orchestrator runs the mechanical L2 gate ({@link runExecGate}), computes the diff, then
|
|
@@ -219,7 +219,7 @@ export interface VerificationResult extends TaskResult {
|
|
|
219
219
|
*/
|
|
220
220
|
export declare function verifyCompleted(runner: Runner, result: TaskResult, specBase: ResumeTaskConfig, objective: string, config: VerifyConfig): Promise<VerificationResult>;
|
|
221
221
|
/**
|
|
222
|
-
* Run an implementation task, then gate it behind an independent
|
|
222
|
+
* Run an implementation task, then gate it behind an independent falsification-style verifier, looping
|
|
223
223
|
* fix→re-verify until PASS (or a round cap). Returns the implementation result plus the
|
|
224
224
|
* {@link VerificationOutcome}. The caller decides WHEN to use this (explicit opt-in) — it always
|
|
225
225
|
* verifies once invoked. If the impl **suspends on a durable HITL gate**, it is surfaced as
|
|
@@ -232,7 +232,7 @@ export declare function runWithVerification(runner: Runner, implSpec: TaskSpec,
|
|
|
232
232
|
* durable + HITL + verify integration (design/51 P1-b). The mirror of {@link runWithVerification} for the
|
|
233
233
|
* resume path: `runWithVerification` surfaces a HITL suspend as failed-with-token; once the human
|
|
234
234
|
* adjudicates, the caller calls this with the `token` + `outcome`, and it resumes the implementation and —
|
|
235
|
-
* **if it COMPLETES** — runs the identical
|
|
235
|
+
* **if it COMPLETES** — runs the identical falsification-style verifier + fix loop. If the resumed run suspends
|
|
236
236
|
* AGAIN (a later durable gate), it is surfaced as failed-with-token (`unverified`) for the caller to resume
|
|
237
237
|
* once more. `objective` is the ORIGINAL task objective (the resume carries none of its own) — the verifier
|
|
238
238
|
* needs it as context; pass the same objective the original `runWithVerification` ran with.
|
package/dist/agents/verify.js
CHANGED
|
@@ -99,6 +99,8 @@ export async function verifyCompleted(runner, result, specBase, objective, confi
|
|
|
99
99
|
roles: specBase.roles,
|
|
100
100
|
tools: verifierTools,
|
|
101
101
|
handsReadOnly: config.verifierHandsReadOnly ?? true,
|
|
102
|
+
...(specBase.readFace === "roots" ? { readFace: "roots" } : {}),
|
|
103
|
+
...(specBase.readDenyPatterns !== undefined ? { readDenyPatterns: [...specBase.readDenyPatterns] } : {}),
|
|
102
104
|
interactiveTools: false,
|
|
103
105
|
outputSchema: VerdictSchema,
|
|
104
106
|
enableBlockedReport: false,
|
package/dist/bench/metrics.d.ts
CHANGED
|
@@ -458,7 +458,7 @@ export interface PairedBinaryComparison {
|
|
|
458
458
|
/**
|
|
459
459
|
* codex B2 — compare two arms' delivered truly-correct as PAIRED binary. Pairs runs by the COMPOSITE
|
|
460
460
|
* `(taskId, seed)` key (codex MAJOR-A: a bare `seed` collides across tasks — the same repeat index
|
|
461
|
-
* recurs per task — so cross-task input would overwrite pairs and
|
|
461
|
+
* recurs per task — so cross-task input would overwrite pairs and contaminate the McNemar sample);
|
|
462
462
|
* only rows where BOTH arms delivered (not withheld, both scored) form a pair — a
|
|
463
463
|
* withheld run has no delivered binary to pair (it is scored in the withhold/avoided-loss axis, not
|
|
464
464
|
* here). `mde` is the pre-registered minimum detectable effect (default 0.20 absolute = a 20pp swing).
|
package/dist/brain/retry.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* - `Retry-After` (delta-seconds or HTTP-date), on any retryable response.
|
|
14
14
|
* - `anthropic-ratelimit-unified-reset` (an absolute epoch-seconds stamp of when the rate-limit window
|
|
15
15
|
* reopens), read only off a 429 — it is a rate-limit signal.
|
|
16
|
-
* When both are present the larger wins. Both are clamped so a
|
|
16
|
+
* When both are present the larger wins. Both are clamped so a untrusted/buggy value
|
|
17
17
|
* (`Retry-After: 2147483647`, a reset stamp years out) cannot pin the caller for hours.
|
|
18
18
|
*/
|
|
19
19
|
/** Parse a `Retry-After` header (delta-seconds or HTTP-date) to ms; undefined if absent/unparseable. */
|
|
@@ -52,7 +52,7 @@ export interface SummarizableFinding {
|
|
|
52
52
|
export declare function summarizeRedactions(findings: readonly SummarizableFinding[]): string;
|
|
53
53
|
/** The optional collector every redaction entry point accepts. `preexistingMarkers` (ANG-11) counts
|
|
54
54
|
* marker-shaped literals ALREADY present in the input before any pass ran — a nonzero value means the
|
|
55
|
-
* text arrived pre-redacted or carries
|
|
55
|
+
* text arrived pre-redacted or carries caller-declared markers, either way "marker present" is not proof this
|
|
56
56
|
* pipeline ran. Caller-owned: pass `{ findings: [] }` and read it back after the call. */
|
|
57
57
|
export interface RedactionReport {
|
|
58
58
|
findings: RedactionFinding[];
|
package/dist/core/ask-class.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* self-reported "this ask is sandbox-local" field would be the same trust hole as the
|
|
9
9
|
* `decisionReason:"safety"` self-declaration this codebase already refuses. Instead, BUILT-IN policy
|
|
10
10
|
* factories register their instances here (private WeakMap brand — nothing a deployment policy can
|
|
11
|
-
*
|
|
11
|
+
* self-declare by shaping its return value), and everything unregistered reads as `unknown`.
|
|
12
12
|
*
|
|
13
13
|
* Classes and their dominance (STRICT — merge keeps the strongest; only an all-`sandbox_local` set
|
|
14
14
|
* may auto-admit):
|
|
@@ -27,7 +27,7 @@ export type AskClass = "sandbox_local" | "external_authority" | "hook" | "mandat
|
|
|
27
27
|
/**
|
|
28
28
|
* Brand a built-in policy instance with its ask class (engine factories only — not exported from the
|
|
29
29
|
* package). The `check` binding is LOCKED as a non-writable, non-configurable DATA property before the
|
|
30
|
-
* policy is returned (codex
|
|
30
|
+
* policy is returned (codex falsification-style round 4, HIGH): reading `policy.check` and INVOKING it must
|
|
31
31
|
* name the same callable, atomically. A plain `===` re-read was TOCTOU-able by an accessor — a getter
|
|
32
32
|
* could return the branded function to `policyAskClassOf` and a deployment ask to the gate's
|
|
33
33
|
* invocation. Locking the property makes the callable un-swappable and un-redefinable, so the class
|
|
@@ -234,7 +234,7 @@ export declare function askQuestionContinuationCard(questionId: string, continua
|
|
|
234
234
|
* The ONE shape validator for a question batch, shared by the tool body and by the engine's routing lane
|
|
235
235
|
* (which validates BEFORE it puts anything in front of a person — a malformed batch must be refused to
|
|
236
236
|
* the model, not rendered). Returns the model-facing error text, or `undefined` when the batch is well
|
|
237
|
-
* formed. Total: it never throws on
|
|
237
|
+
* formed. Total: it never throws on untrusted field shapes.
|
|
238
238
|
*/
|
|
239
239
|
export declare function validateAskQuestions(questions: unknown): string | undefined;
|
|
240
240
|
/** design/173 件3 — engine-side options for the mounted tool (prepare wires them; a deployment
|
|
@@ -184,7 +184,20 @@ export function createAskUserQuestionTool(onQuestion, source, opts) {
|
|
|
184
184
|
"Usage notes:\n" +
|
|
185
185
|
'- Users will always be able to select "Other" to provide custom text input\n' +
|
|
186
186
|
"- Use multiSelect: true to allow multiple answers to be selected for a question\n" +
|
|
187
|
-
'- If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label'
|
|
187
|
+
'- If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label' +
|
|
188
|
+
"\n" +
|
|
189
|
+
"\n" +
|
|
190
|
+
"Preview feature:\n" +
|
|
191
|
+
"Use the optional `preview` field on options when presenting concrete artifacts that users need to visually compare:\n" +
|
|
192
|
+
"- ASCII mockups of UI layouts or components\n" +
|
|
193
|
+
"- Code snippets showing different implementations\n" +
|
|
194
|
+
"- Diagram variations\n" +
|
|
195
|
+
"- Configuration examples\n" +
|
|
196
|
+
"\n" +
|
|
197
|
+
"Preview content is rendered as markdown in a monospace box. Multi-line text with newlines is supported. " +
|
|
198
|
+
"When any option has a preview, the UI switches to a side-by-side layout with a vertical option list on " +
|
|
199
|
+
"the left and preview on the right. Do not use previews for simple preference questions where labels and " +
|
|
200
|
+
"descriptions suffice. Note: previews are only supported for single-select questions (not multiSelect).",
|
|
188
201
|
parameters: Type.Object({
|
|
189
202
|
questions: Type.Array(Type.Object({
|
|
190
203
|
question: Type.String({
|
|
@@ -244,7 +244,11 @@ export interface MaybeCompactOptions {
|
|
|
244
244
|
*/
|
|
245
245
|
workingFileAttachments?: {
|
|
246
246
|
/** Read a task workspace file; null/throw = skip it. Wired by the Runner from the task's ExecutionEnv. */
|
|
247
|
-
readFile: (path: string) => Promise<string | null
|
|
247
|
+
readFile: (path: string) => Promise<string | null | {
|
|
248
|
+
withheld: {
|
|
249
|
+
pattern: string;
|
|
250
|
+
};
|
|
251
|
+
}>;
|
|
248
252
|
/** Max modified files to attach. Default 3. */
|
|
249
253
|
maxFiles?: number;
|
|
250
254
|
/** Per-file char cap (≈4 chars/token). Default 16_000 (~4k tokens). */
|
|
@@ -397,12 +397,21 @@ export async function maybeCompact(opts) {
|
|
|
397
397
|
if (remaining <= 0)
|
|
398
398
|
break;
|
|
399
399
|
let content = null;
|
|
400
|
+
let withheldPattern;
|
|
400
401
|
try {
|
|
401
|
-
|
|
402
|
+
const r = await att.readFile(path);
|
|
403
|
+
if (typeof r === "string")
|
|
404
|
+
content = r;
|
|
405
|
+
else if (r !== null && typeof r === "object")
|
|
406
|
+
withheldPattern = r.withheld.pattern;
|
|
402
407
|
}
|
|
403
408
|
catch {
|
|
404
409
|
content = null;
|
|
405
410
|
}
|
|
411
|
+
if (withheldPattern !== undefined) {
|
|
412
|
+
blocks.push(`<working-file path="${escapeWorkingFilePathAttr(path)}" withheld="content withheld: matches the sensitive-path read deny list (pattern ${escapeWorkingFilePathAttr(withheldPattern)})"/>`);
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
406
415
|
if (content === null)
|
|
407
416
|
continue;
|
|
408
417
|
const cap = Math.min(perFileCap, remaining);
|
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
* 这是一个 **env 上的可选能力**(非一种独立 env 类型),所以不 `extends ExecutionEnv` —— 用交叉类型挂到具体实现上,并经
|
|
7
7
|
* {@link hasBackgroundShell} 运行时检测(对齐 remote-env.ts 的 `hasDestroy`/`isRemoteExecutionEnv` 模式,零 vendor 接口改动)。
|
|
8
8
|
*
|
|
9
|
-
* 设计裁定(经 codex + workflow 5-lens
|
|
9
|
+
* 设计裁定(经 codex + workflow 5-lens 双轨证伪式复审收敛,design/103 v2):
|
|
10
10
|
* - **不跨 durable suspend**:后台进程在每条退出路径被 dispose;Runner 必须在 suspendVM **之前** 调
|
|
11
11
|
* {@link BackgroundShellCapability.disposeBackgroundShells}(detached job 不在 suspendVM 的 in-flight 契约射程内)。
|
|
12
|
-
* -
|
|
12
|
+
* - **越界隔离**:`pollBackground`/`killBackground` 的 shellId MUST 被校验为本 env 自己 spawn 过的;非本 env 走 `not_found`。
|
|
13
13
|
* - **按-id-可重读**:实现 MUST 保证按 shellId 跨多次独立调用可重复读取累积/增量输出(execStream 的 consume-once 不满足)。
|
|
14
14
|
*/
|
|
15
15
|
import type { ExecutionEnv, ExecutionEnvExecOptions, Result } from "../internal/harness-types.js";
|
|
16
16
|
/**
|
|
17
17
|
* 一个 long-running / detached 进程的句柄。**env-local、非 durable、对调用方不透明** —— adapter 内部把它映射到真实进程/
|
|
18
|
-
* provider job,**绝不**把可猜的 raw provider job id 暴露成 shellId(否则跨租户可枚举,design/103 §3.8
|
|
18
|
+
* provider job,**绝不**把可猜的 raw provider job id 暴露成 shellId(否则跨租户可枚举,design/103 §3.8 越界红线)。
|
|
19
19
|
*/
|
|
20
20
|
export type BackgroundShellId = string & {
|
|
21
21
|
readonly __brand: "BackgroundShellId";
|
|
@@ -105,11 +105,11 @@ export interface BackgroundShellCapability {
|
|
|
105
105
|
/**
|
|
106
106
|
* 读一个后台进程**自上次 poll 以来的新增**输出 + 当前状态(cursor 语义)。退出后仍可读残余 + exitCode,直到被 dispose/reap。
|
|
107
107
|
*
|
|
108
|
-
* 🔴
|
|
108
|
+
* 🔴 越界契约:`shellId` MUST 被校验为**本 env 自己 spawnBackground 返回过**的;非本 env 一律 `not_found`,绝不解析外部 job id。
|
|
109
109
|
* 🔴 重读契约:实现 MUST 保证「按 shellId 跨多次独立调用可重复读取累积/增量」(remote 的 execStream consume-once 不满足 —— 见 design/103 §5.2 两条路径)。
|
|
110
110
|
*/
|
|
111
111
|
pollBackground(shellId: BackgroundShellId): Promise<Result<BackgroundPoll, BackgroundShellError>>;
|
|
112
|
-
/** 杀一个后台进程(幂等:杀已死的是 no-op,返回 ok)。`shellId` 同 {@link pollBackground}
|
|
112
|
+
/** 杀一个后台进程(幂等:杀已死的是 no-op,返回 ok)。`shellId` 同 {@link pollBackground} 的越界校验。 */
|
|
113
113
|
killBackground(shellId: BackgroundShellId): Promise<Result<void, BackgroundShellError>>;
|
|
114
114
|
/**
|
|
115
115
|
* 杀掉并清理**本 env 的所有**后台进程。Runner 在每条退出路径调:finish/abort/throw 在 run-loop tail finally,**suspend/
|