@sema-agent/core 5.37.0 → 5.39.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 (58) hide show
  1. package/CHANGELOG.md +151 -0
  2. package/dist/agents/send-message-tool.d.ts +8 -0
  3. package/dist/agents/send-message-tool.js +8 -0
  4. package/dist/agents/subagent.js +6 -0
  5. package/dist/agents/teacher.js +12 -3
  6. package/dist/agents/team.d.ts +7 -1
  7. package/dist/agents/team.js +11 -9
  8. package/dist/agents/verify.js +12 -3
  9. package/dist/core/auto-mode-prompt-assets.d.ts +5 -3
  10. package/dist/core/auto-mode-prompt-assets.js +1 -1
  11. package/dist/core/checkpoint-store.d.ts +26 -1
  12. package/dist/core/hooks.d.ts +152 -2
  13. package/dist/core/hooks.js +65 -7
  14. package/dist/core/mailbox-store.d.ts +39 -0
  15. package/dist/core/mailbox-store.js +9 -0
  16. package/dist/core/permission-rule-consent.d.ts +27 -4
  17. package/dist/core/permission-rule-consent.js +29 -4
  18. package/dist/core/permission-rule-model.d.ts +7 -1
  19. package/dist/core/runner/prepare-config-doors.d.ts +17 -0
  20. package/dist/core/runner/prepare-config-doors.js +33 -2
  21. package/dist/core/runner/prepare-task.d.ts +17 -2
  22. package/dist/core/runner/prepare-task.js +135 -44
  23. package/dist/core/runner/runtask.js +46 -11
  24. package/dist/core/sensitive-path-policy.js +3 -3
  25. package/dist/core/store-contracts/mailbox-store-contract.d.ts +29 -1
  26. package/dist/core/store-contracts/mailbox-store-contract.js +78 -0
  27. package/dist/core/tool-model-gate.d.ts +125 -0
  28. package/dist/core/tool-model-gate.js +303 -0
  29. package/dist/core/tool-policy.d.ts +1 -1
  30. package/dist/core/types.d.ts +210 -1
  31. package/dist/core/types.js +21 -0
  32. package/dist/core/untrusted-text.d.ts +1 -1
  33. package/dist/core/write-protect.d.ts +93 -0
  34. package/dist/core/write-protect.js +194 -0
  35. package/dist/index.d.ts +7 -5
  36. package/dist/index.js +5 -3
  37. package/dist/orchestration/builtin-workflows.d.ts +68 -6
  38. package/dist/orchestration/builtin-workflows.js +26 -9
  39. package/dist/orchestration/governance-baseline-validity.d.ts +44 -0
  40. package/dist/orchestration/governance-baseline-validity.js +55 -0
  41. package/dist/orchestration/run-workflow-tool.d.ts +10 -1
  42. package/dist/orchestration/run-workflow-tool.js +99 -31
  43. package/dist/orchestration/workflow-script-runner.js +9 -4
  44. package/dist/orchestration/workflow-script-store.d.ts +8 -3
  45. package/dist/prompts/coordinator.d.ts +4 -1
  46. package/dist/prompts/coordinator.js +8 -0
  47. package/dist/prompts/default.d.ts +14 -4
  48. package/dist/prompts/default.js +2 -1
  49. package/dist/scenarios/full-body.d.ts +5 -0
  50. package/dist/scenarios/full-body.js +8 -4
  51. package/dist/tools/fs/fs-shared.d.ts +3 -2
  52. package/dist/tools/fs/fs-shared.js +19 -9
  53. package/dist/tools/fs/read-deny.d.ts +15 -5
  54. package/dist/tools/fs/read-deny.js +33 -12
  55. package/dist/tools/fs/safety.d.ts +4 -1
  56. package/dist/tools/fs/safety.js +4 -2
  57. package/package.json +1 -1
  58. package/test/export-surface.snapshot.json +24 -1
@@ -0,0 +1,93 @@
1
+ /**
2
+ * How one table row matches the judged path:
3
+ * · `"basename"` — the target's last segment equals the row name (CC `DANGEROUS_FILES` form);
4
+ * · `"segment"` — ANY path segment equals the row name (CC `DANGEROUS_DIRECTORIES` form);
5
+ * · `"segment-run"` — a CONSECUTIVE run of segments equals the row's `/`-separated segments
6
+ * (CC `DANGEROUS_DIRECTORY_PATHS` form, e.g. `.config/git`).
7
+ */
8
+ export type WriteProtectedKind = "basename" | "segment" | "segment-run";
9
+ /** One row of the write-protection table: a LITERAL name and how it matches. The `name` is also the
10
+ * row's stable identity — the string a refusal/ask message cites. */
11
+ export interface WriteProtectedRow {
12
+ readonly name: string;
13
+ readonly kind: WriteProtectedKind;
14
+ }
15
+ /**
16
+ * One deployment-authored entry for the replacement seat (`RunnerDeps.writeProtectedPaths`).
17
+ * String shorthand: a bare name ≡ `{ name, kind: "segment" }` (the WIDER single-segment kind —
18
+ * over-matching is the fail-safe direction for a tighten); a name containing `/` ≡
19
+ * `{ name, kind: "segment-run" }`. Spell `kind: "basename"` explicitly when last-segment-only
20
+ * matching is the intent.
21
+ */
22
+ export type WriteProtectedEntry = string | WriteProtectedRow;
23
+ /** A table hit: which row matched (the row's canonical name + kind). */
24
+ export interface WriteProtectedHit {
25
+ readonly name: string;
26
+ readonly kind: WriteProtectedKind;
27
+ }
28
+ /**
29
+ * WRITE_PROTECTED_DEFAULT_TABLE — the default-active table (the material basis of the deployment
30
+ * admin face: what an unconfigured deployment demotes to `ask`; visible here, deletable by
31
+ * replacing the seat with a filtered copy). CC 2.1.233 triple VERBATIM first, then the sema rows,
32
+ * each with its argument.
33
+ *
34
+ * NOT listed, deliberately (each a ruled-out candidate, recorded so the next reader does not
35
+ * re-litigate silently):
36
+ * · `.env` / `.env.*` — CC's own table excludes them too (only `.envrc`, the direnv AUTO-EXECUTION
37
+ * vector, is in): a plain `.env` is application config and routine workspace material for the
38
+ * tasks this engine runs (the read deny set rules it out on the same grounds); the opt-in write
39
+ * DENY (`RECOMMENDED_SENSITIVE_PATTERNS`) covers deployments that want it guarded.
40
+ * · key-material FILE patterns (`id_rsa*`, `*.pem`, …) — they are glob-shaped, and this table
41
+ * speaks literals; the opt-in deny policy owns that vocabulary.
42
+ * · cloud credential dirs (`.aws`, `.kube`, `.azure`, `.config/gcloud`) — writing cloud config IS
43
+ * the routine "configure this environment" action tasks are asked to perform, so a default ask
44
+ * on every such write is recurring friction without CC precedent; the opt-in deny policy covers
45
+ * them, and the READ side already default-refuses them (reading credentials exfiltrates; writing
46
+ * a fresh config file does not).
47
+ */
48
+ export declare const WRITE_PROTECTED_DEFAULT_TABLE: readonly WriteProtectedRow[];
49
+ /**
50
+ * The ONE case fold of this module, applied to BOTH sides of every comparison (table names at
51
+ * compile, path segments at match) — `toLowerCase` plus the two confusable letters CC's fold maps
52
+ * (U+0131 dotless ı → i, U+017F long ſ → s). Deliberately NOT full Unicode confusable folding:
53
+ * that would be a different, wider claim than the one made (the read deny set's ASCII-contract doc
54
+ * states the same boundary for its own fold).
55
+ */
56
+ export declare function foldWriteProtectCase(s: string): string;
57
+ /**
58
+ * Resolve the ACTIVE table under the deployment seat (validated, loud — #123's bad-value states all
59
+ * throw and name the knob). `undefined` = the default table; `[]` = NO table (an explicit, legal
60
+ * posture — the whole-table escape hatch's empty end); a non-empty list REPLACES the default table
61
+ * whole (compose additions as `[...WRITE_PROTECTED_DEFAULT_TABLE, …]`, drop rows by filtering the
62
+ * exported table — the visible/deletable admin face). Exact duplicates fold (idempotent, not one of
63
+ * #123's bad-value states). Exported so an admin face can preview the effective table under a
64
+ * candidate configuration with the engine's own rules.
65
+ */
66
+ export declare function resolveWriteProtectedTable(entries?: readonly WriteProtectedEntry[]): readonly WriteProtectedRow[];
67
+ /** The compiled judge over one resolved table. Pure and synchronous — literal folded comparisons,
68
+ * no filesystem access (see the module header for the declared lexical scope). */
69
+ export interface WriteProtectionMatcher {
70
+ /** The resolved rows this judge was compiled from (canonical names — the disclosure face). */
71
+ readonly rows: readonly WriteProtectedRow[];
72
+ /** Judge ONE path spelling. Returns the first matching row (basename rows first, then segment,
73
+ * then segment-run — deterministic), or null. */
74
+ matchPath(path: string): WriteProtectedHit | null;
75
+ }
76
+ /**
77
+ * Compile the write-protection judge for a deployment configuration. Returns `undefined` when the
78
+ * resolved table is EMPTY (`[]` replacement) — the caller then mounts no tighten at all, keeping an
79
+ * opted-out deployment's decision path byte-identical to a build without this layer.
80
+ */
81
+ export declare function compileWriteProtection(entries?: readonly WriteProtectedEntry[]): WriteProtectionMatcher | undefined;
82
+ /**
83
+ * Build the ENGINE-FILLED gate input (`ToolGateInput.writeProtectionCheck`): covered tools are the
84
+ * path-confinable write set (Write/Edit/NotebookEdit — the shared spelling), the judged target is
85
+ * the SAME string the tool itself will resolve (`writeTargetPath`, the shared single source with
86
+ * the sensitive-path guard and the fs-write gate), and the verdict is the table judge's. A covered
87
+ * write with NO resolvable target returns null here — this layer is ADDITIVE friction on a named
88
+ * set of targets, not a containment boundary (a target-less call cannot land on a named row, and
89
+ * the tool's own schema validation refuses it before any write); the fail-closed treatment of the
90
+ * unresolvable case belongs to the containment gates (fs-write-gate-policy documents that split).
91
+ * Returns `undefined` when the resolved table is empty — nothing to judge, mount nothing.
92
+ */
93
+ export declare function createWriteProtectionCheck(entries?: readonly WriteProtectedEntry[]): ((toolName: string, args: unknown) => WriteProtectedHit | null) | undefined;
@@ -0,0 +1,194 @@
1
+ import { writeTargetPath } from "../tools/fs/safety.js";
2
+ import { PATH_CONFINABLE_WRITE_TOOLS } from "./runner/session-rule-policy.js";
3
+ export const WRITE_PROTECTED_DEFAULT_TABLE = [
4
+ { name: ".gitconfig", kind: "basename" },
5
+ { name: ".gitmodules", kind: "basename" },
6
+ { name: ".bashrc", kind: "basename" },
7
+ { name: ".bash_profile", kind: "basename" },
8
+ { name: ".zshrc", kind: "basename" },
9
+ { name: ".zprofile", kind: "basename" },
10
+ { name: ".profile", kind: "basename" },
11
+ { name: ".zshenv", kind: "basename" },
12
+ { name: ".zlogin", kind: "basename" },
13
+ { name: ".zlogout", kind: "basename" },
14
+ { name: ".bash_login", kind: "basename" },
15
+ { name: ".bash_aliases", kind: "basename" },
16
+ { name: ".bash_logout", kind: "basename" },
17
+ { name: ".envrc", kind: "basename" },
18
+ { name: ".ripgreprc", kind: "basename" },
19
+ { name: ".mcp.json", kind: "basename" },
20
+ { name: ".claude.json", kind: "basename" },
21
+ { name: ".npmrc", kind: "basename" },
22
+ { name: ".yarnrc", kind: "basename" },
23
+ { name: ".yarnrc.yml", kind: "basename" },
24
+ { name: ".pnp.cjs", kind: "basename" },
25
+ { name: ".pnp.loader.mjs", kind: "basename" },
26
+ { name: ".pnpmfile.cjs", kind: "basename" },
27
+ { name: "bunfig.toml", kind: "basename" },
28
+ { name: ".bunfig.toml", kind: "basename" },
29
+ { name: ".bazelrc", kind: "basename" },
30
+ { name: ".bazelversion", kind: "basename" },
31
+ { name: ".bazeliskrc", kind: "basename" },
32
+ { name: ".pre-commit-config.yaml", kind: "basename" },
33
+ { name: "lefthook.yml", kind: "basename" },
34
+ { name: ".lefthook.yml", kind: "basename" },
35
+ { name: "lefthook.yaml", kind: "basename" },
36
+ { name: ".lefthook.yaml", kind: "basename" },
37
+ { name: "gradle-wrapper.properties", kind: "basename" },
38
+ { name: "maven-wrapper.properties", kind: "basename" },
39
+ { name: ".devcontainer.json", kind: "basename" },
40
+ { name: "pyrightconfig.json", kind: "basename" },
41
+ { name: ".git", kind: "segment" },
42
+ { name: ".vscode", kind: "segment" },
43
+ { name: ".idea", kind: "segment" },
44
+ { name: ".claude", kind: "segment" },
45
+ { name: ".husky", kind: "segment" },
46
+ { name: ".cargo", kind: "segment" },
47
+ { name: ".devcontainer", kind: "segment" },
48
+ { name: ".yarn", kind: "segment" },
49
+ { name: ".mvn", kind: "segment" },
50
+ { name: ".config/git", kind: "segment-run" },
51
+ { name: ".ssh", kind: "segment" },
52
+ { name: ".gnupg", kind: "segment" },
53
+ ];
54
+ export function foldWriteProtectCase(s) {
55
+ return s.toLowerCase().replace(/ı/g, "i").replace(/ſ/g, "s");
56
+ }
57
+ const KINDS = ["basename", "segment", "segment-run"];
58
+ function describeEntryValue(v) {
59
+ try {
60
+ return JSON.stringify(v) ?? String(v);
61
+ }
62
+ catch {
63
+ return String(v);
64
+ }
65
+ }
66
+ function normalizeWriteProtectedEntry(entry) {
67
+ const shape = typeof entry === "string" ? { name: entry, kind: entry.includes("/") ? "segment-run" : "segment" } : entry;
68
+ if (typeof shape !== "object" || shape === null || typeof shape.name !== "string") {
69
+ throw new Error(`writeProtectedPaths: entry ${describeEntryValue(entry)} is not a name string or { name, kind } row.`);
70
+ }
71
+ const name = shape.name;
72
+ if (!KINDS.includes(shape.kind)) {
73
+ throw new Error(`writeProtectedPaths: entry ${describeEntryValue(entry)} has kind ${describeEntryValue(shape.kind)} — known kinds: ${KINDS.join(", ")}.`);
74
+ }
75
+ const kind = shape.kind;
76
+ if (name.includes("*") || name.includes("?")) {
77
+ throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} contains a wildcard metacharacter — this table speaks LITERAL names only (a silently-literal "*" would guard less than it reads); pattern semantics live in createSensitivePathPolicy.`);
78
+ }
79
+ if (name.includes("\\")) {
80
+ throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} contains a backslash — names are "/"-separated (both path families are matched); spell the segments with "/".`);
81
+ }
82
+ const segments = name.split("/").filter((s) => s.length > 0);
83
+ if (segments.length === 0) {
84
+ throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} contains no path segments and would protect nothing — remove the entry or spell the name.`);
85
+ }
86
+ if (segments.some((s) => s === "." || s === "..")) {
87
+ throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} contains a "." or ".." segment — the judge folds dot segments lexically before matching, so such a row could never match anything; spell the real name.`);
88
+ }
89
+ if (segments.length > 1 && kind !== "segment-run") {
90
+ throw new Error(`writeProtectedPaths: entry ${describeEntryValue(name)} spans ${segments.length} segments but declares kind "${kind}" — multi-segment names match as kind "segment-run".`);
91
+ }
92
+ return { name: segments.join("/"), kind };
93
+ }
94
+ export function resolveWriteProtectedTable(entries) {
95
+ if (entries === undefined)
96
+ return WRITE_PROTECTED_DEFAULT_TABLE;
97
+ if (!Array.isArray(entries)) {
98
+ throw new Error(`writeProtectedPaths: expected an array of entries (whole-table replacement; [] = no write-protection table), got ${describeEntryValue(entries)}.`);
99
+ }
100
+ const out = [];
101
+ const seen = new Set();
102
+ for (const entry of entries) {
103
+ const row = normalizeWriteProtectedEntry(entry);
104
+ const key = `${row.kind}:${foldWriteProtectCase(row.name)}`;
105
+ if (seen.has(key))
106
+ continue;
107
+ seen.add(key);
108
+ out.push(row);
109
+ }
110
+ return out;
111
+ }
112
+ export function compileWriteProtection(entries) {
113
+ const rows = resolveWriteProtectedTable(entries);
114
+ if (rows.length === 0)
115
+ return undefined;
116
+ const basenames = new Map();
117
+ const segments = new Map();
118
+ const runs = [];
119
+ for (const row of rows) {
120
+ const folded = foldWriteProtectCase(row.name);
121
+ if (row.kind === "basename") {
122
+ if (!basenames.has(folded))
123
+ basenames.set(folded, row.name);
124
+ }
125
+ else if (row.kind === "segment") {
126
+ if (!segments.has(folded))
127
+ segments.set(folded, row.name);
128
+ }
129
+ else {
130
+ runs.push({ name: row.name, parts: folded.split("/").filter((s) => s.length > 0) });
131
+ }
132
+ }
133
+ return {
134
+ rows,
135
+ matchPath(path) {
136
+ const viewOf = (win32) => {
137
+ const segs = [];
138
+ for (const raw of path.split(/[\\/]/)) {
139
+ if (raw.length === 0)
140
+ continue;
141
+ const dot = !win32 || /^\.{1,2}$/.test(raw) ? raw : raw.replace(/ +$/, "");
142
+ if (dot === ".")
143
+ continue;
144
+ if (dot === "..") {
145
+ const last = segs[segs.length - 1];
146
+ if (segs.length > 0 && last !== "..")
147
+ segs.pop();
148
+ else
149
+ segs.push("..");
150
+ continue;
151
+ }
152
+ const stripped = win32 ? raw.replace(/[. ]+$/, "") : raw;
153
+ segs.push(foldWriteProtectCase(stripped.length > 0 ? stripped : raw));
154
+ }
155
+ return segs;
156
+ };
157
+ const judge = (segs) => {
158
+ if (segs.length === 0)
159
+ return null;
160
+ const base = basenames.get(segs[segs.length - 1] ?? "");
161
+ if (base !== undefined)
162
+ return { name: base, kind: "basename" };
163
+ for (const s of segs) {
164
+ const hit = segments.get(s);
165
+ if (hit !== undefined)
166
+ return { name: hit, kind: "segment" };
167
+ }
168
+ for (const run of runs) {
169
+ const n = run.parts.length;
170
+ for (let i = 0; i + n <= segs.length; i++) {
171
+ if (run.parts.every((p, j) => segs[i + j] === p))
172
+ return { name: run.name, kind: "segment-run" };
173
+ }
174
+ }
175
+ return null;
176
+ };
177
+ const posix = viewOf(false);
178
+ return judge(posix) ?? judge(viewOf(true));
179
+ },
180
+ };
181
+ }
182
+ export function createWriteProtectionCheck(entries) {
183
+ const matcher = compileWriteProtection(entries);
184
+ if (matcher === undefined)
185
+ return undefined;
186
+ return (toolName, args) => {
187
+ if (!PATH_CONFINABLE_WRITE_TOOLS.has(toolName))
188
+ return null;
189
+ const path = writeTargetPath(toolName, args);
190
+ if (typeof path !== "string" || path.length === 0)
191
+ return null;
192
+ return matcher.matchPath(path);
193
+ };
194
+ }
package/dist/index.d.ts CHANGED
@@ -21,6 +21,7 @@ export { createWebFetchTool, webFetchToolSpec, htmlToText, type WebFetchConfig,
21
21
  export { createTodoWriteTool } from "./tools/todo.js";
22
22
  export { createTaskListTools, createMemoryTaskListStore, assertJsonMetadata, type TaskListItem, type TaskListStore } from "./tools/task-list.js";
23
23
  export { assembleCodeTools, type CodeToolsConfig, CODE_ROLE } from "./scenarios/full-body.js";
24
+ export { TOOL_MODEL_GATE_CLASSES, isModelGatedForClass, type ToolModelGateRule } from "./core/tool-model-gate.js";
24
25
  export { capAggregateToolResults, AGGREGATE_TOOL_RESULT_BUDGET_CHARS, DEFAULT_BUDGET_EXEMPT_TOOLS, type AggregateBudgetOptions, } from "./core/tool-result-budget.js";
25
26
  export { capAggregateMediaBytes, AGGREGATE_MEDIA_BUDGET_BYTES, type MediaStripInfo } from "./core/media-byte-cap.js";
26
27
  export { createAskUserQuestionTool, createDurableQuestionPolicy, QUESTION_AWAITS_RESUME, isQuestionUnavailable, type OnQuestionOutcome, type QuestionUnavailable, type OnQuestion, type AskQuestion, type AskQuestionOption, type AskQuestionRequest, type QuestionAnswer, type QuestionAnswerItem, type AskQuestionCardDetails, type AskUserQuestionToolOptions, type AskAnswerContinuationSource, type SyntheticContinuationReason, } from "./core/ask-question.js";
@@ -90,6 +91,7 @@ export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, ty
90
91
  export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
91
92
  export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY_BUILTIN_TIERS, READ_DENY_DEFAULT_TIERS, resolveReadDenyBuiltins, compileReadDeny, type ReadDenyEntry, type ReadDenyMatcher, type NormalizedReadDenyEntry, type ReadDenyBuiltinTier, type ReadDenyBuiltinRow, type ReadDenyBuiltinConfig, } from "./tools/fs/index.js";
92
93
  export { deploymentReadFaceClampNotice, resolveReadFace, type ReadFace, type ReadFaceInputs } from "./tools/fs/index.js";
94
+ export { WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable, compileWriteProtection, type WriteProtectedEntry, type WriteProtectedRow, type WriteProtectedKind, type WriteProtectedHit, type WriteProtectionMatcher, } from "./core/write-protect.js";
93
95
  export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, buildToolResultRef, toolResultContentSegment, MAX_MINTED_TOOL_RESULT_REF_CHARS, type ToolResultProvenance, assertToolResultProvenanceMatch, normalizeToolResultProvenance, toolResultProvenanceOf, ToolResultRefConflictError, TOOL_RESULT_REF_CONFLICT_CODE, type ToolResultStore, type ToolResultSlice, type ToolResultDeletionReport, } from "./core/tool-result-store.js";
94
96
  export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, readPendingSteerQueue, appendPendingSteer, MAX_PENDING_STEER_CHARS, MAX_PENDING_STEER_ENTRIES, PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES, PENDING_STEER_FROZEN_FIELDS, ACTOR_ASSERTION_FROZEN_FIELDS, MAX_ACTOR_FIELD_CHARS, MAX_STEER_INPUT_ID_CHARS, LEGACY_PENDING_STEER_INPUT_ID, type ActorAssertion, type PendingSteerEntry, type PendingSteerInput, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, type RiskDescriptor, type ProbeCause, type ProbeCauseOperands, type CheckpointStore, type CheckpointSummary, type Checkpoint, type CheckpointToken, type CheckpointGate, type CheckpointState, type SerializedCheckpointState, type CheckpointFaultMode, type PendingAction, type ResumeOutcome, type ResolvedOutcome, type ReopenReason, type ResolveExpectation, type SafetyAxis, type RealApprovalGateBit, type ResourceLedger, type ResourceLimitReason, type PlatformLimitReason, } from "./core/checkpoint-store.js";
95
97
  export { InMemoryUsageWindowStore, GLOBAL_USAGE_KEY, EMPTY_USAGE_WINDOW_RECORD, chargeUsageRecord, readUsageRecord, usageRetryAfterMs, resolveUsageWindows, type UsageWindow, type UsageWindowStore, type UsageWindowReading, type UsageWindowRecord, type UsageSlot, type UsageBucketRow, } from "./core/usage-window-store.js";
@@ -113,7 +115,7 @@ export { type StoreDurability } from "./core/checkpoint-store.js";
113
115
  export { type StoreFidelity } from "./core/checkpoint-store.js";
114
116
  export { projectHumanInput, buildHumanInputEvent, type HumanInputSource, type HumanInputFrame, type HumanInputEvent, type HumanInputDelivery, } from "./core/human-input-projection.js";
115
117
  export { TaskRegistry, defaultTaskRegistry, createTaskOutputTool, createTaskStopTool, type SemaTaskType, type SemaTaskStatus, type SemaTaskHandle, type ParkedClaimTicket, type TaskAccess, type UnifiedTaskOutput, type TaskRetrievalStatus, type StopSource, type RegisterMonitorInput, type MonitorTimers, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccessWorkflowRun, DURABLE_AGENT_HANDLE_RE, } from "./core/task-registry.js";
116
- export { InMemoryMailboxStore, type MailboxStore, type MailboxMessage, type MailboxLease } from "./core/mailbox-store.js";
118
+ export { InMemoryMailboxStore, type MailboxStore, type MailboxMessage, type MailboxLease, MailboxStoreError, MAILBOX_TOMBSTONED_RECIPIENT_CODE, } from "./core/mailbox-store.js";
117
119
  export { FileMailboxStore, type FileMailboxStoreOptions } from "./stores/file/mailbox-store.js";
118
120
  export { createFileTaskListStore } from "./stores/file/task-list-store.js";
119
121
  export { createCcFileTaskListStore } from "./stores/cc/task-list-store.js";
@@ -162,7 +164,7 @@ export { FilePermissionRuleStoreProvider } from "./stores/file/permission-rule-s
162
164
  export { adoptFilePermissionRuleStore, type AdoptFileRuleStoreResult } from "./stores/file/permission-rule-adopt.js";
163
165
  export { AdoptionError, assertAdoptionBootGate, readRootAdoptionFile, writeRootAdoptionFile, ROOT_ADOPTION_FILE, type AdoptionErrorCode, type AdoptionSource, type AdoptionReport, type AdoptionReceipt, type AdoptionLegReport, type AffectedDeploymentConfig, type RootAdoptionFile, } from "./stores/file/adoption/marker.js";
164
166
  export { adoptLocalDataRoot, ackAdoptionConfig, witnessAdoptionConfig, listAdoptionQuarantine, readAdoptionStatus, type AdoptionStatus, type AdoptLocalDataRootOptions, type AdoptLocalDataRootResult, type AdoptionCarriageLeg, type AdoptionCarriageLegContext, type AdoptionConfigWitnessReceipt, } from "./stores/file/adoption/adopt.js";
165
- export { formatHookFeedback, runToolGate, createHookEnvCapabilities, createPreToolUseConstraintPolicy, type PersistedRuleHit, type PersistedRuleUnreadable, type PersistedRuleAnswer, normalizePersistedRuleHit, type Hooks, type HookToolContext, type HookEnvCapabilities, type HookToolOutput, type PreToolUseResult, type PostToolUseResult, type UserPromptSubmitResult, type HookToolFailure, type PostToolUseFailureResult, type PostToolBatchCall, type PostToolBatchResult, type PreCompactContext, type PreCompactResult, type PostCompactContext, type StopFailureContext, type PermissionDeniedPayload, type PermissionDeniedSource, } from "./core/hooks.js";
167
+ export { formatHookFeedback, runToolGate, createHookEnvCapabilities, createPreToolUseConstraintPolicy, type PersistedRuleHit, type PersistedRuleUnreadable, type PersistedRuleAnswer, normalizePersistedRuleHit, type Hooks, type HookToolContext, type HookInvocationIdentity, type UserPromptSubmitContext, type PostToolBatchContext, type HookEnvCapabilities, type HookToolOutput, type PreToolUseResult, type PostToolUseResult, type UserPromptSubmitResult, type HookToolFailure, type PostToolUseFailureResult, type PostToolBatchCall, type PostToolBatchResult, type PreCompactContext, type PreCompactResult, type PostCompactContext, type StopFailureContext, type PermissionDeniedPayload, type PermissionDeniedSource, } from "./core/hooks.js";
166
168
  export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, type NormalizedMemorySpec, type MemorySpecInput, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, type Embedder, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, type UtilityGate, type MemoryStore, type MemoryVectorMode, type ScoredMemory, type MemoryNoteHeader, type MemoryNoteRecord, type MemoryNoteType, type StructuredNoteInput, } from "./core/memory.js";
167
169
  export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, type MemoryBackendContractHooks, buildMemoryInstruction, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, readV2HeaderHints, type V2HeaderHints, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, type ControlPlaneRebuildReceipt, type StrictControlPlaneLedger, type ChallengeAssignment, type ChallengeEvent, type ChallengedHistoryRow, type LineagePendingTxn, type LineagePromotion, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, type MemorySearchDetails, type MemorySearchHit, type MemoryGetDetails, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, type MemoryAnnouncement, type ScanFinding, type MemoryEngineOptions, type MemoryInjection, type EntryProvenanceAccount, type TransferEvidence, type CommittedBinding, type CommittedEntrySnapshot, type CommittedScopeSnapshots, type EntryCustodyReport, erasureSelectHash, type EraseMemoryEntriesInput, type ErasureSelect, type ErasedBinding, type MemoryErasureAttestation, type MemoryBackend, type MemoryEntry, type MemoryEntryFrontmatter, type MemoryEntryHeader, type ScoredMemoryEntry, type NotePatch, type PatchReport, type MaterializedFile, type MemorySessionHandle, type HarvestReport, type HarvestRejection, type HarvestRejectionCode, type ParsedEntryFile, type ScannedEntryFile, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, type ParsedScopeKey, migrateScope, type MigrateScopeReport, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, type RemoteMemoryFile, type RemoteMemoryBaseline, type RemoteMaterialization, type RemoteHarvestResult, type InboundEntryFinding, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, type MemorySyncCursor, type MemorySyncConflict, type MemorySyncPlan, type RecallSource, syncMemoryScope, type MemorySyncTransport, type MemorySyncRequestBody, type MemorySyncResponseBody, type MemorySyncClientConflict, type SyncMemoryScopeOptions, type MemorySyncClientResult, } from "./core/memory-engine/index.js";
168
170
  export { SHARED_MEMORY_READ_CAP_BYTES, SHARED_MEMORY_LIST_PAGE_SIZE, SharedMemoryStoreError, type SharedMemoryStoreProvider, type SharedMemoryStoreReader, type SharedMemoryPagedList, type SharedMemoryStoreInfo, type SharedMemoryDocumentEntry, type SharedMemorySnapshot, type SharedMemoryRequestContext, type MemoryListDetails, type MemoryReadDetails, } from "./core/shared-memory/types.js";
@@ -201,7 +203,7 @@ export { assertWorkflowSandboxConformance, assertWorkflowPrimitivesWiring, asser
201
203
  export { WorkflowModelNotAllowedError, type WorkflowAgentSpec } from "./orchestration/workflow-governance.js";
202
204
  export { WorkflowMaxAgentsError, WorkflowResultTooLargeError } from "./orchestration/workflow.js";
203
205
  export { createFileWorkflowScriptStore, mergeWorkflowArgs, type WorkflowScriptStore, type NamedWorkflowResolution, type NamedWorkflowListing, } from "./orchestration/workflow-script-store.js";
204
- export { TEAM_DISCUSSION_WORKFLOW_NAME, TEAM_DISCUSSION_SCRIPT, builtinWorkflowDefinitions, builtinWorkflowListings, resolveBuiltinWorkflow, type BuiltinWorkflowDefinition, } from "./orchestration/builtin-workflows.js";
206
+ export { DISCUSSION_WORKFLOW_NAME, DISCUSSION_SCRIPT, TEAM_DISCUSSION_WORKFLOW_NAME, TEAM_DISCUSSION_SCRIPT, canonicalWorkflowName, retiredWorkflowNameAliases, builtinWorkflowDefinitions, builtinWorkflowListings, resolveBuiltinWorkflow, type BuiltinWorkflowDefinition, } from "./orchestration/builtin-workflows.js";
205
207
  export { WORKFLOW_AGENT_STALL_MS, WORKFLOW_AGENT_MAX_RETRIES, WORKFLOW_AGENT_THROTTLE_BACKOFF_MS } from "./orchestration/workflow.js";
206
208
  export { createRunWorkflowTool, RUN_WORKFLOW_TOOL_NAME, workflowWhenToUseText, renderNamedWorkflowListing, type WorkflowCompletionNotifier, type WorkflowLimits, type RunWorkflowToolDeps, } from "./orchestration/run-workflow-tool.js";
207
209
  export { runSideQuery, type SideQuerySpec, type SideQueryResult, type SideQueryToolDef, type SideQueryDeps, type SideQueryMessage } from "./core/side-query.js";
@@ -216,7 +218,7 @@ export { sessionRepoContract } from "./core/store-contracts/session-repo-contrac
216
218
  export { toolResultStoreContract } from "./core/store-contracts/tool-result-store-contract.js";
217
219
  export { fileSnapshotStoreContract } from "./core/store-contracts/file-snapshot-store-contract.js";
218
220
  export { permissionRuleSyncContract, type PermissionRuleSyncContractHooks } from "./core/store-contracts/permission-rule-sync-contract.js";
219
- export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, } from "./core/store-contracts/mailbox-store-contract.js";
221
+ export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, mailboxTombstonedRecipientContract, type MailboxTombstonedRecipientContractHooks, } from "./core/store-contracts/mailbox-store-contract.js";
220
222
  export { BACKGROUND_AGENT_CONTRACT_SCOPE, backgroundAgentStoreContract, backgroundAgentStoreScopesContract, } from "./core/store-contracts/background-agent-store-contract.js";
221
223
  export { type BackgroundAgentStore, type BackgroundAgentRecord, type BackgroundAgentRowSummary, type BackgroundAgentUsage, canAccessAgentRecord, STALE_RUNNING_REAP_ATTRIBUTION, BackgroundAgentStoreError, InMemoryBackgroundAgentStore, reconcileParkedAgents, queryBackgroundAgents, type BackgroundAgentQuery, } from "./core/background-agent-store.js";
222
224
  export { serveDurableAgentRowLane, buildAgentPollDetails, type AgentPollDetailsInput, } from "./core/task-registry-agent.js";
@@ -254,7 +256,7 @@ export { retryBackoffMs, parseRetryAfter } from "./brain/retry.js";
254
256
  export { type BrainTimeoutConfig } from "./brain/timeout.js";
255
257
  export { createAssistantMessageEventStream } from "./internal/llm.js";
256
258
  export type { AssistantMessage, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, StopReason, StreamFn, TextContent, ThinkingContent, ToolCall, ToolResultMessage, Usage, UserMessage, } from "./internal/llm.js";
257
- export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, BrainRetryErrClass, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, EngineNotice, RuntimeCaps, BackgroundChildEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskLimits, StaleToolResultOffloadOptions, TaskResult, EffectiveMemoryScopes, RemoteEnvFailureNote, TaskSpec, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ReversibilityVerdict, ToolEffect, ToolContentOrigin, WorkflowGovernanceBaseline, DelegationTaskType, } from "./core/types.js";
259
+ export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, BrainRetryErrClass, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, EngineNotice, RuntimeCaps, BackgroundChildEvent, DelegationLifecycleEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskLimits, StaleToolResultOffloadOptions, TaskResult, EffectiveMemoryScopes, RemoteEnvFailureNote, TaskSpec, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ReversibilityVerdict, ToolEffect, ToolContentOrigin, WorkflowGovernanceBaseline, DelegationTaskType, } from "./core/types.js";
258
260
  export { Type } from "typebox";
259
261
  export type { TSchema, Static } from "typebox";
260
262
  export { explainPromptAssembly, describeDefaultPack, type DefaultPackDescription, type ExplainInput } from "./prompt-assembly/explain.js";
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ export { createWebFetchTool, webFetchToolSpec, htmlToText, createWebSearchTool,
10
10
  export { createTodoWriteTool } from "./tools/todo.js";
11
11
  export { createTaskListTools, createMemoryTaskListStore, assertJsonMetadata } from "./tools/task-list.js";
12
12
  export { assembleCodeTools, CODE_ROLE } from "./scenarios/full-body.js";
13
+ export { TOOL_MODEL_GATE_CLASSES, isModelGatedForClass } from "./core/tool-model-gate.js";
13
14
  export { capAggregateToolResults, AGGREGATE_TOOL_RESULT_BUDGET_CHARS, DEFAULT_BUDGET_EXEMPT_TOOLS, } from "./core/tool-result-budget.js";
14
15
  export { capAggregateMediaBytes, AGGREGATE_MEDIA_BUDGET_BYTES } from "./core/media-byte-cap.js";
15
16
  export { createAskUserQuestionTool, createDurableQuestionPolicy, QUESTION_AWAITS_RESUME, isQuestionUnavailable, } from "./core/ask-question.js";
@@ -70,6 +71,7 @@ export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, }
70
71
  export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
71
72
  export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY_BUILTIN_TIERS, READ_DENY_DEFAULT_TIERS, resolveReadDenyBuiltins, compileReadDeny, } from "./tools/fs/index.js";
72
73
  export { deploymentReadFaceClampNotice, resolveReadFace } from "./tools/fs/index.js";
74
+ export { WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable, compileWriteProtection, } from "./core/write-protect.js";
73
75
  export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, buildToolResultRef, toolResultContentSegment, MAX_MINTED_TOOL_RESULT_REF_CHARS, assertToolResultProvenanceMatch, normalizeToolResultProvenance, toolResultProvenanceOf, ToolResultRefConflictError, TOOL_RESULT_REF_CONFLICT_CODE, } from "./core/tool-result-store.js";
74
76
  export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, readPendingSteerQueue, appendPendingSteer, MAX_PENDING_STEER_CHARS, MAX_PENDING_STEER_ENTRIES, PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES, PENDING_STEER_FROZEN_FIELDS, ACTOR_ASSERTION_FROZEN_FIELDS, MAX_ACTOR_FIELD_CHARS, MAX_STEER_INPUT_ID_CHARS, LEGACY_PENDING_STEER_INPUT_ID, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, } from "./core/checkpoint-store.js";
75
77
  export { InMemoryUsageWindowStore, GLOBAL_USAGE_KEY, EMPTY_USAGE_WINDOW_RECORD, chargeUsageRecord, readUsageRecord, usageRetryAfterMs, resolveUsageWindows, } from "./core/usage-window-store.js";
@@ -92,7 +94,7 @@ export {} from "./core/checkpoint-store.js";
92
94
  export {} from "./core/checkpoint-store.js";
93
95
  export { projectHumanInput, buildHumanInputEvent, } from "./core/human-input-projection.js";
94
96
  export { TaskRegistry, defaultTaskRegistry, createTaskOutputTool, createTaskStopTool, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccessWorkflowRun, DURABLE_AGENT_HANDLE_RE, } from "./core/task-registry.js";
95
- export { InMemoryMailboxStore } from "./core/mailbox-store.js";
97
+ export { InMemoryMailboxStore, MailboxStoreError, MAILBOX_TOMBSTONED_RECIPIENT_CODE, } from "./core/mailbox-store.js";
96
98
  export { FileMailboxStore } from "./stores/file/mailbox-store.js";
97
99
  export { createFileTaskListStore } from "./stores/file/task-list-store.js";
98
100
  export { createCcFileTaskListStore } from "./stores/cc/task-list-store.js";
@@ -162,7 +164,7 @@ export { assertWorkflowSandboxConformance, assertWorkflowPrimitivesWiring, asser
162
164
  export { WorkflowModelNotAllowedError } from "./orchestration/workflow-governance.js";
163
165
  export { WorkflowMaxAgentsError, WorkflowResultTooLargeError } from "./orchestration/workflow.js";
164
166
  export { createFileWorkflowScriptStore, mergeWorkflowArgs, } from "./orchestration/workflow-script-store.js";
165
- export { TEAM_DISCUSSION_WORKFLOW_NAME, TEAM_DISCUSSION_SCRIPT, builtinWorkflowDefinitions, builtinWorkflowListings, resolveBuiltinWorkflow, } from "./orchestration/builtin-workflows.js";
167
+ export { DISCUSSION_WORKFLOW_NAME, DISCUSSION_SCRIPT, TEAM_DISCUSSION_WORKFLOW_NAME, TEAM_DISCUSSION_SCRIPT, canonicalWorkflowName, retiredWorkflowNameAliases, builtinWorkflowDefinitions, builtinWorkflowListings, resolveBuiltinWorkflow, } from "./orchestration/builtin-workflows.js";
166
168
  export { WORKFLOW_AGENT_STALL_MS, WORKFLOW_AGENT_MAX_RETRIES, WORKFLOW_AGENT_THROTTLE_BACKOFF_MS } from "./orchestration/workflow.js";
167
169
  export { createRunWorkflowTool, RUN_WORKFLOW_TOOL_NAME, workflowWhenToUseText, renderNamedWorkflowListing, } from "./orchestration/run-workflow-tool.js";
168
170
  export { runSideQuery } from "./core/side-query.js";
@@ -177,7 +179,7 @@ export { sessionRepoContract } from "./core/store-contracts/session-repo-contrac
177
179
  export { toolResultStoreContract } from "./core/store-contracts/tool-result-store-contract.js";
178
180
  export { fileSnapshotStoreContract } from "./core/store-contracts/file-snapshot-store-contract.js";
179
181
  export { permissionRuleSyncContract } from "./core/store-contracts/permission-rule-sync-contract.js";
180
- export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, } from "./core/store-contracts/mailbox-store-contract.js";
182
+ export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, mailboxTombstonedRecipientContract, } from "./core/store-contracts/mailbox-store-contract.js";
181
183
  export { BACKGROUND_AGENT_CONTRACT_SCOPE, backgroundAgentStoreContract, backgroundAgentStoreScopesContract, } from "./core/store-contracts/background-agent-store-contract.js";
182
184
  export { canAccessAgentRecord, STALE_RUNNING_REAP_ATTRIBUTION, BackgroundAgentStoreError, InMemoryBackgroundAgentStore, reconcileParkedAgents, queryBackgroundAgents, } from "./core/background-agent-store.js";
183
185
  export { serveDurableAgentRowLane, buildAgentPollDetails, } from "./core/task-registry-agent.js";
@@ -7,7 +7,7 @@
7
7
  * - a deployment `WorkflowScriptStore.resolveName` hit for the SAME NAME wins (the built-in is consulted
8
8
  * only when the deployment registry does not resolve the name).
9
9
  *
10
- * The first built-in is `team-discussion` — the round-based collab profile design/140 §1 verified live
10
+ * The first built-in is `discussion` — the round-based collab profile design/140 §1 verified live
11
11
  * (docs/DESIGN-140-VERIFICATION-2026-07-11.md B 面: 2 members × 2 rounds + finalizer, 8.2s/10.5K tokens,
12
12
  * round 2 genuinely responding to round 1). It is pure SCRIPT CONTENT over the existing primitives — zero
13
13
  * new runtime mechanism:
@@ -19,14 +19,74 @@
19
19
  * budget-sensitive runs — design/140 §4 "两投影").
20
20
  */
21
21
  import type { NamedWorkflowListing } from "./workflow-script-store.js";
22
- /** The built-in round-based team-discussion workflow's registered name. */
23
- export declare const TEAM_DISCUSSION_WORKFLOW_NAME = "team-discussion";
22
+ /** The built-in round-based discussion workflow's registered name. */
23
+ export declare const DISCUSSION_WORKFLOW_NAME = "discussion";
24
24
  /**
25
- * The `team-discussion` script source (design/140 §1 table row 1, live-verified shape: for-loop rounds +
25
+ * The registered name this built-in carried before the C-R14 vocabulary ruling (2026-08-16), kept
26
+ * resolvable for ONE minor: "team" now names the agent-teams family (persistent named teammates) only,
27
+ * and a one-off multi-agent debate is a "discussion".
28
+ *
29
+ * @deprecated Use {@link DISCUSSION_WORKFLOW_NAME}. Removed in the next minor; the retired spelling still
30
+ * RESOLVES via {@link canonicalWorkflowName} until then, but the listing/card face shows the new name only.
31
+ */
32
+ export declare const TEAM_DISCUSSION_WORKFLOW_NAME = "discussion";
33
+ /**
34
+ * Map a REQUESTED built-in workflow name to its canonical name — identity for every name that is not a
35
+ * retired alias. The canonical name is the authority: a resolution reached through an alias returns the
36
+ * canonical definition (its `meta.name`, hence every run/card projection, is the new name).
37
+ *
38
+ * @deprecated together with the alias table — this becomes an identity function next minor (C-R14).
39
+ */
40
+ export declare function canonicalWorkflowName(name: string): string;
41
+ /**
42
+ * The retired spellings that address a given canonical built-in name (empty for every name with no
43
+ * alias). Callers that probe the deployment registry per built-in name (the card's shadow probe) must
44
+ * probe these too, so a deployment entry registered under EITHER spelling shadows the same built-in.
45
+ *
46
+ * @deprecated together with the alias table (C-R14).
47
+ */
48
+ export declare function retiredWorkflowNameAliases(canonicalName: string): string[];
49
+ /**
50
+ * Every spelling that addresses the SAME registry slot as `requested`, in lookup order: the requested
51
+ * spelling first (so a deployment entry registered under the exact name the caller used always wins), then
52
+ * its canonical name, then that canonical name's other retired spellings. Deduplicated in insertion order,
53
+ * so a name with no alias yields exactly `[requested]` — one probe, unchanged from before the alias existed.
54
+ *
55
+ * SINGLE SOURCE on purpose. The deployment registry is consulted from two places — the `{name}` execute
56
+ * path and the tool card's shadow probe — and design/140's card≡execute invariant means a SPELLING
57
+ * asymmetry between them is a lie on the card, not a cosmetic difference: the first draft of this rename
58
+ * probed the alias only on ONE side, so a deployment that had registered the RETIRED spelling was reported
59
+ * as shadowing the built-in on the card while a canonical-name call silently launched the built-in instead
60
+ * (found in adversarial review). Both sides iterate this list; neither builds its own.
61
+ *
62
+ * SCOPE of that guarantee, stated precisely: this aligns the two sites on WHICH SPELLINGS they ask about.
63
+ * The other card/execute asymmetries are older than this helper and unchanged by it — the card swallows a
64
+ * probe exception and keeps going while execute returns a structured error, the card treats any non-
65
+ * `undefined` answer as a shadow while execute refuses a malformed shape, the card resolves at mount time
66
+ * while execute resolves per call, and `list()` can overlay rows `resolveName` never answered. Equivalence
67
+ * holds for a stable, well-formed registry; it was never total, and this helper does not make it so.
68
+ *
69
+ * NOTE for store implementers: a single resolution may therefore call `resolveName` more than once, with
70
+ * different spellings, until one answers. `resolveName` must be a stable, side-effect-free lookup.
71
+ *
72
+ * Callers must apply the deployment's `builtinWorkflows` opt-out BEFORE using this: the equivalence is a
73
+ * fact about the built-in registry, so a deployment that removed the built-ins removed the alias with them.
74
+ *
75
+ * @deprecated together with the alias table — collapses to `[requested]` next minor (C-R14).
76
+ */
77
+ export declare function workflowNameProbeOrder(requested: string): string[];
78
+ /**
79
+ * The `discussion` script source (design/140 §1 table row 1, live-verified shape: for-loop rounds +
26
80
  * `agent()` members with transcript re-feed + a schema'd finalizer). Deterministic by construction — no
27
81
  * clock/randomness reads (locked by test against `workflowScriptReadsClockOrRandom`).
28
82
  */
29
- export declare const TEAM_DISCUSSION_SCRIPT = "export const meta = {\n name: \"team-discussion\",\n description: \"Round-based team discussion: configurable members debate a topic across rounds (each member sees the transcript so far), then a finalizer synthesizes a structured verdict.\",\n whenToUse: \"Use for a genuinely contested question that benefits from several perspectives arguing across rounds - design trade-offs, plan or risk reviews, adversarial critique of a proposal. Do NOT use it for a single factual question, a task with one obvious answer, or a budget-sensitive run: every round costs one agent call per member, so a discussion is never cheaper than asking once. args (all optional): { topic, members?: [{ role, prompt?, model? }], rounds?, finalizer?: { prompt?, model? } }. Hard ceilings: members is capped at 6 and rounds is capped at 5 regardless of what you pass; the run reports it via log() and a capped field on the result when a request exceeds either.\",\n phases: [\n { title: \"Discussion\" },\n { title: \"Synthesis\" },\n ],\n};\n// Zero-config runnable (design/140 \u00A76 1c): every arg has an opinionated fallback.\nconst raw = args;\nconst a = raw !== null && typeof raw === \"object\" && !Array.isArray(raw) ? raw : {};\nconst topic =\n typeof a.topic === \"string\" && a.topic.trim() !== \"\"\n ? a.topic\n : typeof raw === \"string\" && raw.trim() !== \"\"\n ? raw // ergonomic form: a bare string args IS the topic\n : \"No topic was provided. Discuss: what information should a caller supply to make a team discussion like this productive, and when should they NOT convene one?\";\nconst defaultMembers = [\n { role: \"advocate\", prompt: \"Make the strongest constructive case. Propose concrete options and argue their benefits with specifics.\" },\n { role: \"skeptic\", prompt: \"Stress-test every claim made so far. Surface risks, hidden costs, failure modes, and cheaper alternatives.\" },\n];\nconst rawMembers = Array.isArray(a.members) && a.members.length > 0 ? a.members : defaultMembers;\nconst members = rawMembers.slice(0, 6).map((m, i) => {\n const mm = m !== null && typeof m === \"object\" ? m : {};\n const member = {\n role: typeof mm.role === \"string\" && mm.role.trim() !== \"\" ? mm.role : \"member-\" + (i + 1),\n prompt: typeof mm.prompt === \"string\" && mm.prompt.trim() !== \"\" ? mm.prompt : \"Contribute your own distinct perspective: be concrete, give reasons, and engage with what others said.\",\n };\n if (typeof mm.model === \"string\" && mm.model.trim() !== \"\") member.model = mm.model;\n // Slot-tools carrier (design/140 \u2461-3 + F4): a member may BE a registered agent type ({agent:\"reviewer\"}) \u2014\n // persona/tools/model then come from the deployment's AgentDefinition (role library), args stay thin.\n if (typeof mm.agent === \"string\" && mm.agent.trim() !== \"\") member.agent = mm.agent;\n return member;\n});\n// Deterministic budget truncation (design/140 \u00A71 \u9884\u7B97 row): a HARD rounds ceiling + member cap \u2014 never an\n// evaluator agent. The engine's budget/maxAgents hard stops remain the backstop.\nconst requestedRounds = Math.floor(Number(a.rounds));\nconst normalizedRounds = Number.isFinite(requestedRounds) && requestedRounds >= 1 ? requestedRounds : 2;\nconst rounds = Math.min(normalizedRounds, 5);\n// RB-380 disclosure: the member/round slices above are silent by construction (Array.prototype.slice /\n// Math.min just drop the excess) \u2014 record + surface it instead of a caller finding out only by counting\n// transcript entries. Fires only when a request actually exceeded a ceiling (never on the common path).\nconst capNotes = [];\nif (rawMembers.length > 6) capNotes.push(\"requested \" + rawMembers.length + \" members, capped at 6\");\nif (normalizedRounds > 5) capNotes.push(\"requested \" + normalizedRounds + \" rounds, capped at 5\");\nfor (const note of capNotes) log(\"team-discussion: \" + note);\nconst fin = a.finalizer !== null && typeof a.finalizer === \"object\" && !Array.isArray(a.finalizer) ? a.finalizer : {};\nconst finalizerPrompt = typeof fin.prompt === \"string\" && fin.prompt.trim() !== \"\"\n ? fin.prompt\n : \"You are the synthesis lead. Read the full discussion transcript and produce the final verdict: the decision/answer, the key supporting points, and the strongest unresolved dissent (if any). Do not introduce new arguments of your own.\";\nconst clip = (s) => { const t = String(s); return t.length > 4000 ? t.slice(0, 4000) + \" ...[truncated]\" : t; };\nconst isBudgetStop = (e) => e !== null && typeof e === \"object\" && e.code === \"workflow.budget_exceeded\";\n\nphase(\"Discussion\");\nconst transcript = [];\nlet truncated = null;\nfor (let r = 1; r <= rounds && truncated === null; r++) {\n // Deterministic early stop on an exhausted budget (a live read of the engine budget; the engine's\n // hard WorkflowBudgetExceededError remains the backstop if a member call itself crosses the line).\n if (budget.total !== null && budget.remaining() <= 0) { truncated = \"budget exhausted before round \" + r; break; }\n for (const m of members) {\n const history = transcript.length === 0 ? \"(none yet - you open the discussion)\" : transcript.join(\"\\n\\n\");\n const spec = {\n objective:\n \"Team discussion on: \" + topic + \"\\n\\n\" +\n 'You are \"' + m.role + '\" in round ' + r + \" of \" + rounds + \".\\n\" +\n \"Your brief: \" + m.prompt + \"\\n\\n\" +\n \"Transcript so far:\\n\" + history + \"\\n\\n\" +\n \"Respond to the strongest points others made (do not repeat yourself), then advance your own position. Be concise: a few tight paragraphs at most.\",\n };\n if (m.model !== undefined) spec.modelName = m.model;\n let res;\n try {\n res = await agent(spec, m.agent !== undefined ? { label: m.role + \"-r\" + r, phase: \"Discussion\", agentType: m.agent } : { label: m.role + \"-r\" + r, phase: \"Discussion\" });\n } catch (e) {\n // The engine's budget hard stop: keep what the discussion already produced instead of failing the run.\n if (isBudgetStop(e)) { truncated = \"budget exhausted at \" + m.role + \", round \" + r; break; }\n throw e;\n }\n const text = res && res.status === \"completed\" ? clip(res.result) : \"(no contribution - agent ended \" + (res ? res.status : \"unknown\") + \")\";\n transcript.push(m.role + \" (round \" + r + \"): \" + text);\n }\n}\n\nphase(\"Synthesis\");\nconst finalSpec = {\n objective:\n finalizerPrompt + \"\\n\\nTopic: \" + topic + \"\\n\\nFull transcript:\\n\" +\n (transcript.length === 0 ? \"(the discussion produced no contributions)\" : transcript.join(\"\\n\\n\")) +\n (truncated ? \"\\n\\nNote: the discussion was cut short (\" + truncated + \").\" : \"\"),\n};\nif (typeof fin.model === \"string\" && fin.model.trim() !== \"\") finalSpec.modelName = fin.model;\nlet verdict = null;\ntry {\n verdict = await agent(finalSpec, {\n label: \"finalizer\",\n phase: \"Synthesis\",\n schema: {\n type: \"object\",\n properties: {\n decision: { type: \"string\", description: \"The final answer/decision, one paragraph.\" },\n keyPoints: { type: \"array\", items: { type: \"string\" }, description: \"The strongest supporting points from the discussion.\" },\n dissent: { type: \"string\", description: \"The strongest unresolved counter-position, if any.\" },\n },\n required: [\"decision\", \"keyPoints\"],\n },\n });\n} catch (e) {\n // Budget died before synthesis: return the transcript honestly rather than failing the whole run.\n if (!isBudgetStop(e)) throw e;\n truncated = truncated === null ? \"budget exhausted before synthesis\" : truncated;\n}\n\nreturn {\n topic,\n rounds,\n members: members.map((m) => m.role),\n ...(capNotes.length > 0 ? { capped: capNotes } : {}),\n ...(truncated ? { truncated } : {}),\n transcript,\n verdict: verdict && verdict.structuredOutput !== undefined ? verdict.structuredOutput : (verdict ? verdict.result : null),\n};\n";
83
+ export declare const DISCUSSION_SCRIPT = "export const meta = {\n name: \"discussion\",\n description: \"Round-based discussion: configurable members debate a topic across rounds (each member sees the transcript so far), then a finalizer synthesizes a structured verdict.\",\n whenToUse: \"Use for a genuinely contested question that benefits from several perspectives arguing across rounds - design trade-offs, plan or risk reviews, adversarial critique of a proposal. Do NOT use it for a single factual question, a task with one obvious answer, or a budget-sensitive run: every round costs one agent call per member, so a discussion is never cheaper than asking once. args (all optional): { topic, members?: [{ role, prompt?, model? }], rounds?, finalizer?: { prompt?, model? } }. Hard ceilings: members is capped at 6 and rounds is capped at 5 regardless of what you pass; the run reports it via log() and a capped field on the result when a request exceeds either.\",\n phases: [\n { title: \"Discussion\" },\n { title: \"Synthesis\" },\n ],\n};\n// Zero-config runnable (design/140 \u00A76 1c): every arg has an opinionated fallback.\nconst raw = args;\nconst a = raw !== null && typeof raw === \"object\" && !Array.isArray(raw) ? raw : {};\nconst topic =\n typeof a.topic === \"string\" && a.topic.trim() !== \"\"\n ? a.topic\n : typeof raw === \"string\" && raw.trim() !== \"\"\n ? raw // ergonomic form: a bare string args IS the topic\n : \"No topic was provided. Discuss: what information should a caller supply to make a discussion like this productive, and when should they NOT convene one?\";\nconst defaultMembers = [\n { role: \"advocate\", prompt: \"Make the strongest constructive case. Propose concrete options and argue their benefits with specifics.\" },\n { role: \"skeptic\", prompt: \"Stress-test every claim made so far. Surface risks, hidden costs, failure modes, and cheaper alternatives.\" },\n];\nconst rawMembers = Array.isArray(a.members) && a.members.length > 0 ? a.members : defaultMembers;\nconst members = rawMembers.slice(0, 6).map((m, i) => {\n const mm = m !== null && typeof m === \"object\" ? m : {};\n const member = {\n role: typeof mm.role === \"string\" && mm.role.trim() !== \"\" ? mm.role : \"member-\" + (i + 1),\n prompt: typeof mm.prompt === \"string\" && mm.prompt.trim() !== \"\" ? mm.prompt : \"Contribute your own distinct perspective: be concrete, give reasons, and engage with what others said.\",\n };\n if (typeof mm.model === \"string\" && mm.model.trim() !== \"\") member.model = mm.model;\n // Slot-tools carrier (design/140 \u2461-3 + F4): a member may BE a registered agent type ({agent:\"reviewer\"}) \u2014\n // persona/tools/model then come from the deployment's AgentDefinition (role library), args stay thin.\n if (typeof mm.agent === \"string\" && mm.agent.trim() !== \"\") member.agent = mm.agent;\n return member;\n});\n// Deterministic budget truncation (design/140 \u00A71 \u9884\u7B97 row): a HARD rounds ceiling + member cap \u2014 never an\n// evaluator agent. The engine's budget/maxAgents hard stops remain the backstop.\nconst requestedRounds = Math.floor(Number(a.rounds));\nconst normalizedRounds = Number.isFinite(requestedRounds) && requestedRounds >= 1 ? requestedRounds : 2;\nconst rounds = Math.min(normalizedRounds, 5);\n// RB-380 disclosure: the member/round slices above are silent by construction (Array.prototype.slice /\n// Math.min just drop the excess) \u2014 record + surface it instead of a caller finding out only by counting\n// transcript entries. Fires only when a request actually exceeded a ceiling (never on the common path).\nconst capNotes = [];\nif (rawMembers.length > 6) capNotes.push(\"requested \" + rawMembers.length + \" members, capped at 6\");\nif (normalizedRounds > 5) capNotes.push(\"requested \" + normalizedRounds + \" rounds, capped at 5\");\nfor (const note of capNotes) log(\"discussion: \" + note);\nconst fin = a.finalizer !== null && typeof a.finalizer === \"object\" && !Array.isArray(a.finalizer) ? a.finalizer : {};\nconst finalizerPrompt = typeof fin.prompt === \"string\" && fin.prompt.trim() !== \"\"\n ? fin.prompt\n : \"You are the synthesis lead. Read the full discussion transcript and produce the final verdict: the decision/answer, the key supporting points, and the strongest unresolved dissent (if any). Do not introduce new arguments of your own.\";\nconst clip = (s) => { const t = String(s); return t.length > 4000 ? t.slice(0, 4000) + \" ...[truncated]\" : t; };\nconst isBudgetStop = (e) => e !== null && typeof e === \"object\" && e.code === \"workflow.budget_exceeded\";\n\nphase(\"Discussion\");\nconst transcript = [];\nlet truncated = null;\nfor (let r = 1; r <= rounds && truncated === null; r++) {\n // Deterministic early stop on an exhausted budget (a live read of the engine budget; the engine's\n // hard WorkflowBudgetExceededError remains the backstop if a member call itself crosses the line).\n if (budget.total !== null && budget.remaining() <= 0) { truncated = \"budget exhausted before round \" + r; break; }\n for (const m of members) {\n const history = transcript.length === 0 ? \"(none yet - you open the discussion)\" : transcript.join(\"\\n\\n\");\n const spec = {\n objective:\n \"Discussion on: \" + topic + \"\\n\\n\" +\n 'You are \"' + m.role + '\" in round ' + r + \" of \" + rounds + \".\\n\" +\n \"Your brief: \" + m.prompt + \"\\n\\n\" +\n \"Transcript so far:\\n\" + history + \"\\n\\n\" +\n \"Respond to the strongest points others made (do not repeat yourself), then advance your own position. Be concise: a few tight paragraphs at most.\",\n };\n if (m.model !== undefined) spec.modelName = m.model;\n let res;\n try {\n res = await agent(spec, m.agent !== undefined ? { label: m.role + \"-r\" + r, phase: \"Discussion\", agentType: m.agent } : { label: m.role + \"-r\" + r, phase: \"Discussion\" });\n } catch (e) {\n // The engine's budget hard stop: keep what the discussion already produced instead of failing the run.\n if (isBudgetStop(e)) { truncated = \"budget exhausted at \" + m.role + \", round \" + r; break; }\n throw e;\n }\n const text = res && res.status === \"completed\" ? clip(res.result) : \"(no contribution - agent ended \" + (res ? res.status : \"unknown\") + \")\";\n transcript.push(m.role + \" (round \" + r + \"): \" + text);\n }\n}\n\nphase(\"Synthesis\");\nconst finalSpec = {\n objective:\n finalizerPrompt + \"\\n\\nTopic: \" + topic + \"\\n\\nFull transcript:\\n\" +\n (transcript.length === 0 ? \"(the discussion produced no contributions)\" : transcript.join(\"\\n\\n\")) +\n (truncated ? \"\\n\\nNote: the discussion was cut short (\" + truncated + \").\" : \"\"),\n};\nif (typeof fin.model === \"string\" && fin.model.trim() !== \"\") finalSpec.modelName = fin.model;\nlet verdict = null;\ntry {\n verdict = await agent(finalSpec, {\n label: \"finalizer\",\n phase: \"Synthesis\",\n schema: {\n type: \"object\",\n properties: {\n decision: { type: \"string\", description: \"The final answer/decision, one paragraph.\" },\n keyPoints: { type: \"array\", items: { type: \"string\" }, description: \"The strongest supporting points from the discussion.\" },\n dissent: { type: \"string\", description: \"The strongest unresolved counter-position, if any.\" },\n },\n required: [\"decision\", \"keyPoints\"],\n },\n });\n} catch (e) {\n // Budget died before synthesis: return the transcript honestly rather than failing the whole run.\n if (!isBudgetStop(e)) throw e;\n truncated = truncated === null ? \"budget exhausted before synthesis\" : truncated;\n}\n\nreturn {\n topic,\n rounds,\n members: members.map((m) => m.role),\n ...(capNotes.length > 0 ? { capped: capNotes } : {}),\n ...(truncated ? { truncated } : {}),\n transcript,\n verdict: verdict && verdict.structuredOutput !== undefined ? verdict.structuredOutput : (verdict ? verdict.result : null),\n};\n";
84
+ /**
85
+ * @deprecated Use {@link DISCUSSION_SCRIPT}. Retired spelling kept for one minor (C-R14) so a deployment
86
+ * importing the constant by its old name keeps compiling; the value is the SAME script (its `meta.name`
87
+ * is the new `discussion`).
88
+ */
89
+ export declare const TEAM_DISCUSSION_SCRIPT = "export const meta = {\n name: \"discussion\",\n description: \"Round-based discussion: configurable members debate a topic across rounds (each member sees the transcript so far), then a finalizer synthesizes a structured verdict.\",\n whenToUse: \"Use for a genuinely contested question that benefits from several perspectives arguing across rounds - design trade-offs, plan or risk reviews, adversarial critique of a proposal. Do NOT use it for a single factual question, a task with one obvious answer, or a budget-sensitive run: every round costs one agent call per member, so a discussion is never cheaper than asking once. args (all optional): { topic, members?: [{ role, prompt?, model? }], rounds?, finalizer?: { prompt?, model? } }. Hard ceilings: members is capped at 6 and rounds is capped at 5 regardless of what you pass; the run reports it via log() and a capped field on the result when a request exceeds either.\",\n phases: [\n { title: \"Discussion\" },\n { title: \"Synthesis\" },\n ],\n};\n// Zero-config runnable (design/140 \u00A76 1c): every arg has an opinionated fallback.\nconst raw = args;\nconst a = raw !== null && typeof raw === \"object\" && !Array.isArray(raw) ? raw : {};\nconst topic =\n typeof a.topic === \"string\" && a.topic.trim() !== \"\"\n ? a.topic\n : typeof raw === \"string\" && raw.trim() !== \"\"\n ? raw // ergonomic form: a bare string args IS the topic\n : \"No topic was provided. Discuss: what information should a caller supply to make a discussion like this productive, and when should they NOT convene one?\";\nconst defaultMembers = [\n { role: \"advocate\", prompt: \"Make the strongest constructive case. Propose concrete options and argue their benefits with specifics.\" },\n { role: \"skeptic\", prompt: \"Stress-test every claim made so far. Surface risks, hidden costs, failure modes, and cheaper alternatives.\" },\n];\nconst rawMembers = Array.isArray(a.members) && a.members.length > 0 ? a.members : defaultMembers;\nconst members = rawMembers.slice(0, 6).map((m, i) => {\n const mm = m !== null && typeof m === \"object\" ? m : {};\n const member = {\n role: typeof mm.role === \"string\" && mm.role.trim() !== \"\" ? mm.role : \"member-\" + (i + 1),\n prompt: typeof mm.prompt === \"string\" && mm.prompt.trim() !== \"\" ? mm.prompt : \"Contribute your own distinct perspective: be concrete, give reasons, and engage with what others said.\",\n };\n if (typeof mm.model === \"string\" && mm.model.trim() !== \"\") member.model = mm.model;\n // Slot-tools carrier (design/140 \u2461-3 + F4): a member may BE a registered agent type ({agent:\"reviewer\"}) \u2014\n // persona/tools/model then come from the deployment's AgentDefinition (role library), args stay thin.\n if (typeof mm.agent === \"string\" && mm.agent.trim() !== \"\") member.agent = mm.agent;\n return member;\n});\n// Deterministic budget truncation (design/140 \u00A71 \u9884\u7B97 row): a HARD rounds ceiling + member cap \u2014 never an\n// evaluator agent. The engine's budget/maxAgents hard stops remain the backstop.\nconst requestedRounds = Math.floor(Number(a.rounds));\nconst normalizedRounds = Number.isFinite(requestedRounds) && requestedRounds >= 1 ? requestedRounds : 2;\nconst rounds = Math.min(normalizedRounds, 5);\n// RB-380 disclosure: the member/round slices above are silent by construction (Array.prototype.slice /\n// Math.min just drop the excess) \u2014 record + surface it instead of a caller finding out only by counting\n// transcript entries. Fires only when a request actually exceeded a ceiling (never on the common path).\nconst capNotes = [];\nif (rawMembers.length > 6) capNotes.push(\"requested \" + rawMembers.length + \" members, capped at 6\");\nif (normalizedRounds > 5) capNotes.push(\"requested \" + normalizedRounds + \" rounds, capped at 5\");\nfor (const note of capNotes) log(\"discussion: \" + note);\nconst fin = a.finalizer !== null && typeof a.finalizer === \"object\" && !Array.isArray(a.finalizer) ? a.finalizer : {};\nconst finalizerPrompt = typeof fin.prompt === \"string\" && fin.prompt.trim() !== \"\"\n ? fin.prompt\n : \"You are the synthesis lead. Read the full discussion transcript and produce the final verdict: the decision/answer, the key supporting points, and the strongest unresolved dissent (if any). Do not introduce new arguments of your own.\";\nconst clip = (s) => { const t = String(s); return t.length > 4000 ? t.slice(0, 4000) + \" ...[truncated]\" : t; };\nconst isBudgetStop = (e) => e !== null && typeof e === \"object\" && e.code === \"workflow.budget_exceeded\";\n\nphase(\"Discussion\");\nconst transcript = [];\nlet truncated = null;\nfor (let r = 1; r <= rounds && truncated === null; r++) {\n // Deterministic early stop on an exhausted budget (a live read of the engine budget; the engine's\n // hard WorkflowBudgetExceededError remains the backstop if a member call itself crosses the line).\n if (budget.total !== null && budget.remaining() <= 0) { truncated = \"budget exhausted before round \" + r; break; }\n for (const m of members) {\n const history = transcript.length === 0 ? \"(none yet - you open the discussion)\" : transcript.join(\"\\n\\n\");\n const spec = {\n objective:\n \"Discussion on: \" + topic + \"\\n\\n\" +\n 'You are \"' + m.role + '\" in round ' + r + \" of \" + rounds + \".\\n\" +\n \"Your brief: \" + m.prompt + \"\\n\\n\" +\n \"Transcript so far:\\n\" + history + \"\\n\\n\" +\n \"Respond to the strongest points others made (do not repeat yourself), then advance your own position. Be concise: a few tight paragraphs at most.\",\n };\n if (m.model !== undefined) spec.modelName = m.model;\n let res;\n try {\n res = await agent(spec, m.agent !== undefined ? { label: m.role + \"-r\" + r, phase: \"Discussion\", agentType: m.agent } : { label: m.role + \"-r\" + r, phase: \"Discussion\" });\n } catch (e) {\n // The engine's budget hard stop: keep what the discussion already produced instead of failing the run.\n if (isBudgetStop(e)) { truncated = \"budget exhausted at \" + m.role + \", round \" + r; break; }\n throw e;\n }\n const text = res && res.status === \"completed\" ? clip(res.result) : \"(no contribution - agent ended \" + (res ? res.status : \"unknown\") + \")\";\n transcript.push(m.role + \" (round \" + r + \"): \" + text);\n }\n}\n\nphase(\"Synthesis\");\nconst finalSpec = {\n objective:\n finalizerPrompt + \"\\n\\nTopic: \" + topic + \"\\n\\nFull transcript:\\n\" +\n (transcript.length === 0 ? \"(the discussion produced no contributions)\" : transcript.join(\"\\n\\n\")) +\n (truncated ? \"\\n\\nNote: the discussion was cut short (\" + truncated + \").\" : \"\"),\n};\nif (typeof fin.model === \"string\" && fin.model.trim() !== \"\") finalSpec.modelName = fin.model;\nlet verdict = null;\ntry {\n verdict = await agent(finalSpec, {\n label: \"finalizer\",\n phase: \"Synthesis\",\n schema: {\n type: \"object\",\n properties: {\n decision: { type: \"string\", description: \"The final answer/decision, one paragraph.\" },\n keyPoints: { type: \"array\", items: { type: \"string\" }, description: \"The strongest supporting points from the discussion.\" },\n dissent: { type: \"string\", description: \"The strongest unresolved counter-position, if any.\" },\n },\n required: [\"decision\", \"keyPoints\"],\n },\n });\n} catch (e) {\n // Budget died before synthesis: return the transcript honestly rather than failing the whole run.\n if (!isBudgetStop(e)) throw e;\n truncated = truncated === null ? \"budget exhausted before synthesis\" : truncated;\n}\n\nreturn {\n topic,\n rounds,\n members: members.map((m) => m.role),\n ...(capNotes.length > 0 ? { capped: capNotes } : {}),\n ...(truncated ? { truncated } : {}),\n transcript,\n verdict: verdict && verdict.structuredOutput !== undefined ? verdict.structuredOutput : (verdict ? verdict.result : null),\n};\n";
30
90
  /** One built-in named workflow: the registered name + its self-contained script source. The name is the
31
91
  * routing key of the `{name}` calling surface; the script's `meta.name` matches it (locked by test). */
32
92
  export interface BuiltinWorkflowDefinition {
@@ -56,7 +116,9 @@ export interface BuiltinWorkflowDefinition {
56
116
  */
57
117
  export declare function builtinWorkflowDefinitions(): BuiltinWorkflowDefinition[];
58
118
  /** Resolve a built-in workflow by name (the `{name}` surface's SECOND lookup — a deployment
59
- * `scriptStore.resolveName` hit for the same name shadows this, design/140 §6 1c). */
119
+ * `scriptStore.resolveName` hit for the same name shadows this, design/140 §6 1c). A retired spelling
120
+ * (C-R14, one minor) resolves through {@link canonicalWorkflowName} to the SAME definition, so the
121
+ * returned `name` — and therefore every downstream projection — is the canonical one. */
60
122
  export declare function resolveBuiltinWorkflow(name: string): BuiltinWorkflowDefinition | undefined;
61
123
  /** design/140 §6 1b — the built-ins' listing projection rows (name + description + whenToUse, parsed from
62
124
  * each script's static meta). Consumed by the Workflow tool card renderer. */