@sema-agent/core 7.49.5 → 7.50.1

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 (200) hide show
  1. package/CHANGELOG.md +157 -0
  2. package/dist/agents/observer.js +3 -10
  3. package/dist/agents/subagent-steps.d.ts +6 -14
  4. package/dist/agents/subagent-steps.js +3 -17
  5. package/dist/brain/stream-shared.d.ts +1 -1
  6. package/dist/core/allow-entry.d.ts +1 -1
  7. package/dist/core/allow-entry.js +1 -1
  8. package/dist/core/ask-origin.d.ts +15 -11
  9. package/dist/core/ask-origin.js +6 -14
  10. package/dist/core/auto-mode-prompt.js +6 -2
  11. package/dist/core/checkpoint-store.d.ts +6 -4
  12. package/dist/core/checkpoint-store.js +1 -1
  13. package/dist/core/context-edit.d.ts +2 -2
  14. package/dist/core/decision-receipt.d.ts +2 -2
  15. package/dist/core/decision-receipt.js +30 -11
  16. package/dist/core/delegation-frames.d.ts +66 -18
  17. package/dist/core/delegation-frames.js +22 -0
  18. package/dist/core/engine-notice.d.ts +7 -5
  19. package/dist/core/frame-settlement.d.ts +6 -1
  20. package/dist/core/gate-fold.js +34 -19
  21. package/dist/core/gate-lanes.js +15 -13
  22. package/dist/core/gate-outcome.d.ts +2 -2
  23. package/dist/core/governance-codes.js +2 -0
  24. package/dist/core/hooks.d.ts +28 -20
  25. package/dist/core/human-input-projection.js +2 -0
  26. package/dist/core/lsp-diagnostics.d.ts +3 -0
  27. package/dist/core/lsp-diagnostics.js +6 -0
  28. package/dist/core/lsp-session.d.ts +39 -17
  29. package/dist/core/lsp-session.js +118 -58
  30. package/dist/core/lsp.d.ts +83 -3
  31. package/dist/core/lsp.js +146 -16
  32. package/dist/core/mcp.js +2 -1
  33. package/dist/core/media-byte-cap.d.ts +14 -0
  34. package/dist/core/media-byte-cap.js +15 -3
  35. package/dist/core/memory-engine/consolidation-driver.d.ts +23 -1
  36. package/dist/core/memory-engine/consolidation-driver.js +54 -6
  37. package/dist/core/memory-engine/consolidation-write-gate.d.ts +46 -0
  38. package/dist/core/memory-engine/consolidation-write-gate.js +82 -0
  39. package/dist/core/memory-engine/consolidation.d.ts +17 -0
  40. package/dist/core/memory-engine/consolidation.js +1 -0
  41. package/dist/core/memory-engine/distiller.d.ts +8 -2
  42. package/dist/core/memory-engine/distiller.js +8 -6
  43. package/dist/core/memory-engine/engine.d.ts +37 -4
  44. package/dist/core/memory-engine/engine.js +127 -38
  45. package/dist/core/memory-engine/file-backend.d.ts +8 -3
  46. package/dist/core/memory-engine/file-backend.js +44 -16
  47. package/dist/core/memory-engine/index.d.ts +2 -2
  48. package/dist/core/memory-engine/index.js +1 -1
  49. package/dist/core/memory-engine/landing-admission.d.ts +65 -0
  50. package/dist/core/memory-engine/landing-admission.js +68 -0
  51. package/dist/core/memory-engine/types.d.ts +23 -0
  52. package/dist/core/mode-policy.d.ts +3 -2
  53. package/dist/core/mode-policy.js +2 -0
  54. package/dist/core/permission-rule-model.d.ts +19 -13
  55. package/dist/core/permission-rule-model.js +7 -4
  56. package/dist/core/permission-rule-provider.d.ts +11 -0
  57. package/dist/core/permission-rules.d.ts +1 -1
  58. package/dist/core/permission-rules.js +5 -2
  59. package/dist/core/persisted-rule-arms.d.ts +15 -7
  60. package/dist/core/persisted-rule-arms.js +13 -6
  61. package/dist/core/reminder-mint.d.ts +5 -0
  62. package/dist/core/reminder-mint.js +1 -0
  63. package/dist/core/retired-keys.d.ts +8 -0
  64. package/dist/core/retired-keys.js +4 -0
  65. package/dist/core/rule-lane-reads.d.ts +4 -4
  66. package/dist/core/rule-lane-reads.js +10 -1
  67. package/dist/core/runner/construction-doors.d.ts +10 -4
  68. package/dist/core/runner/construction-doors.js +25 -2
  69. package/dist/core/runner/contracts.d.ts +20 -3
  70. package/dist/core/runner/env-capability-census.js +1 -1
  71. package/dist/core/runner/gate-exit.js +2 -1
  72. package/dist/core/runner/memory-consolidation-driver.d.ts +6 -4
  73. package/dist/core/runner/memory-consolidation-driver.js +5 -2
  74. package/dist/core/runner/memory-consolidation-write-judge.d.ts +17 -0
  75. package/dist/core/runner/memory-consolidation-write-judge.js +14 -0
  76. package/dist/core/runner/permission-rule-lanes.d.ts +16 -22
  77. package/dist/core/runner/permission-rule-lanes.js +13 -43
  78. package/dist/core/runner/person-path-rows.d.ts +244 -0
  79. package/dist/core/runner/person-path-rows.js +387 -0
  80. package/dist/core/runner/policy-throw.d.ts +34 -0
  81. package/dist/core/runner/policy-throw.js +25 -0
  82. package/dist/core/runner/prepare-acquire-reconcile.js +8 -1
  83. package/dist/core/runner/prepare-artifact.d.ts +5 -3
  84. package/dist/core/runner/prepare-artifact.js +2 -8
  85. package/dist/core/runner/prepare-ask-lane.d.ts +2 -1
  86. package/dist/core/runner/prepare-ask-lane.js +14 -16
  87. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -3
  88. package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
  89. package/dist/core/runner/prepare-context-lane.js +2 -2
  90. package/dist/core/runner/prepare-gate-stations.d.ts +3 -3
  91. package/dist/core/runner/prepare-gate-stations.js +1 -1
  92. package/dist/core/runner/prepare-hands-readface.d.ts +19 -10
  93. package/dist/core/runner/prepare-hands-readface.js +57 -43
  94. package/dist/core/runner/prepare-lsp.d.ts +15 -13
  95. package/dist/core/runner/prepare-lsp.js +11 -11
  96. package/dist/core/runner/prepare-policy-chain.d.ts +8 -4
  97. package/dist/core/runner/prepare-policy-chain.js +11 -10
  98. package/dist/core/runner/prepare-run-refs.js +1 -1
  99. package/dist/core/runner/prepare-task.js +24 -16
  100. package/dist/core/runner/prepare-turn-wiring.d.ts +13 -6
  101. package/dist/core/runner/prepare-turn-wiring.js +19 -8
  102. package/dist/core/runner/read-root-grant.d.ts +1 -25
  103. package/dist/core/runner/read-root-grant.js +1 -17
  104. package/dist/core/runner/retired-runner-deps.d.ts +2 -2
  105. package/dist/core/runner/run-brain-sinks.d.ts +1 -5
  106. package/dist/core/runner/run-brain-sinks.js +2 -4
  107. package/dist/core/runner/run-harness-handlers.js +5 -4
  108. package/dist/core/runner/run-identity-wiring.d.ts +4 -4
  109. package/dist/core/runner/run-identity-wiring.js +10 -1
  110. package/dist/core/runner/run-leg.d.ts +1 -1
  111. package/dist/core/runner/run-leg.js +22 -9
  112. package/dist/core/runner/run-settle-and-teardown.d.ts +0 -4
  113. package/dist/core/runner/run-settle-and-teardown.js +7 -4
  114. package/dist/core/runner/run-terminal-adoption.d.ts +1 -1
  115. package/dist/core/runner/run-terminal-adoption.js +1 -1
  116. package/dist/core/runner/run-turn-boundary.js +2 -2
  117. package/dist/core/runner/runtask.js +8 -8
  118. package/dist/core/runner/session-file-state-replay.d.ts +14 -4
  119. package/dist/core/runner/session-file-state-replay.js +8 -0
  120. package/dist/core/runner/stream-steer-verb.js +3 -0
  121. package/dist/core/runner/tool-end-body.d.ts +5 -4
  122. package/dist/core/runner/tool-end-body.js +4 -4
  123. package/dist/core/runner/tool-output-projection.d.ts +6 -4
  124. package/dist/core/runner/tool-output-projection.js +66 -47
  125. package/dist/core/runner-deps.d.ts +6 -3
  126. package/dist/core/shared-memory/types.d.ts +2 -2
  127. package/dist/core/shell-read-silence.d.ts +23 -0
  128. package/dist/core/shell-read-silence.js +18 -0
  129. package/dist/core/synthetic-read-verdict.d.ts +80 -21
  130. package/dist/core/synthetic-read-verdict.js +89 -18
  131. package/dist/core/task-event.d.ts +113 -25
  132. package/dist/core/task-spec.d.ts +44 -0
  133. package/dist/core/task-tool-shape.d.ts +1 -1
  134. package/dist/core/tool-catalog-entries.js +16 -2
  135. package/dist/core/tool-policy.d.ts +25 -15
  136. package/dist/core/tool-policy.js +9 -13
  137. package/dist/core/trace.d.ts +3 -2
  138. package/dist/core/types.d.ts +3 -3
  139. package/dist/core/types.js +1 -1
  140. package/dist/core/untrusted-text.d.ts +2 -2
  141. package/dist/core/user-attachment.d.ts +164 -0
  142. package/dist/core/user-attachment.js +437 -0
  143. package/dist/engine/compaction/compaction.js +10 -3
  144. package/dist/engine/compaction/utils.js +6 -0
  145. package/dist/engine/execution-env/node-execution-env.d.ts +19 -1
  146. package/dist/engine/execution-env/node-execution-env.js +125 -0
  147. package/dist/engine/harness/agent-harness.d.ts +12 -2
  148. package/dist/engine/harness/agent-harness.js +15 -3
  149. package/dist/engine/harness/types.d.ts +21 -0
  150. package/dist/engine/llm/content-block-render.d.ts +15 -0
  151. package/dist/engine/llm/content-block-render.js +10 -0
  152. package/dist/engine/llm/index.d.ts +1 -0
  153. package/dist/engine/llm/index.js +1 -0
  154. package/dist/engine/llm/types.d.ts +80 -4
  155. package/dist/engine/llm/types.js +43 -1
  156. package/dist/engine/session/import-validate.js +2 -0
  157. package/dist/index.d.ts +6 -4
  158. package/dist/index.js +2 -1
  159. package/dist/internal/harness-types.d.ts +1 -1
  160. package/dist/internal/llm.d.ts +2 -2
  161. package/dist/internal/llm.js +1 -1
  162. package/dist/orchestration/workflow.d.ts +4 -5
  163. package/dist/orchestration/workflow.js +2 -2
  164. package/dist/prompts/default.d.ts +1 -1
  165. package/dist/tools/artifact/artifact-tool.js +1 -1
  166. package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
  167. package/dist/tools/fs/dir-entries.d.ts +4 -10
  168. package/dist/tools/fs/dir-entries.js +4 -11
  169. package/dist/tools/fs/file-read-check.js +3 -3
  170. package/dist/tools/fs/fs-pdf.js +2 -4
  171. package/dist/tools/fs/fs-read.d.ts +47 -4
  172. package/dist/tools/fs/fs-read.js +63 -19
  173. package/dist/tools/fs/fs-search-tools.d.ts +3 -3
  174. package/dist/tools/fs/fs-search-tools.js +7 -2
  175. package/dist/tools/fs/fs-write.d.ts +1 -1
  176. package/dist/tools/fs/fs-write.js +7 -6
  177. package/dist/tools/fs/index.d.ts +7 -1
  178. package/dist/tools/fs/index.js +56 -34
  179. package/dist/tools/fs/read-deny-home.d.ts +19 -1
  180. package/dist/tools/fs/read-deny-home.js +32 -22
  181. package/dist/tools/fs/read-deny.d.ts +14 -0
  182. package/dist/tools/fs/read-deny.js +8 -0
  183. package/dist/tools/fs/repo-map.d.ts +3 -2
  184. package/dist/tools/fs/repo-map.js +11 -3
  185. package/dist/tools/fs/safety.d.ts +41 -2
  186. package/dist/tools/fs/safety.js +12 -3
  187. package/dist/tools/fs/shell-read-check.d.ts +12 -3
  188. package/dist/tools/fs/shell-read-check.js +44 -24
  189. package/dist/tools/fs/shell-read-device.d.ts +1 -1
  190. package/dist/tools/fs/shell-read-face.d.ts +15 -0
  191. package/dist/tools/fs/shell-read-face.js +5 -0
  192. package/dist/tools/fs/shell-read-judge.d.ts +9 -4
  193. package/dist/tools/fs/shell-read-judge.js +1 -1
  194. package/dist/tools/loop-tick.d.ts +2 -2
  195. package/package.json +3 -1
  196. package/test/export-surface.snapshot.json +39 -1
  197. package/wire-changes/core@7.50.0.json +1699 -0
  198. package/wire-changes/core@7.50.1.json +65 -0
  199. package/dist/core/runner/persisted-path-rows.d.ts +0 -88
  200. package/dist/core/runner/persisted-path-rows.js +0 -108
@@ -6,7 +6,7 @@
6
6
  * nothing else. Layer 0 vocabulary; `types.ts` re-exports every name below, so no consumer's import
7
7
  * changes.
8
8
  */
9
- import type { ActorAssertion } from "../internal/llm.js";
9
+ import type { ActorAssertion, UserAttachmentKind, UserAttachmentOutcome } from "../internal/llm.js";
10
10
  import type { TaskResult } from "./task-result.js";
11
11
  import type { TaskNotificationPayload } from "./task-notification.js";
12
12
  import type { ProviderCondition, ProviderConditionSource } from "../brain/provider-dialect.js";
@@ -383,17 +383,28 @@ export type TaskEvent = ({
383
383
  * (previously dropped here); the internal `details` payload is NOT exposed (e.g. a sub-agent tool's
384
384
  * `details` is the entire child `TaskResult`).
385
385
  *
386
- * **Type is `unknown` and intentionally non-uniform** — within size it passes through AS-IS to keep
387
- * structure a UI wants (a `string`, or `(TextContent|ImageContent)[]` blocks); when the serialized body
388
- * exceeds the core size cap it degrades to a single TRUNCATED STRING (see {@link truncated}). A consumer
389
- * must handle both shapes.
386
+ * **Type is `unknown` and intentionally non-uniform** — a `string` result stays a string (over the core text cap it is
387
+ * cut and ends with the `…[+N chars truncated]` marker); a `(TextContent|ImageContent|DocumentContent)[]` result stays
388
+ * an array whose blocks keep their slots. One rule for the array (see {@link truncated}): its text blocks (each at its
389
+ * text plus whatever else it carries) — with any block that is neither text nor an admitted image/document, at its
390
+ * serialization — are one character stream under the text cap, cut IN
391
+ * PLACE where the cap runs out (that block ends with the marker, the stream's later blocks leave); MEDIA blocks are not
392
+ * measured against the text cap and ride AS-IS while the leg's media budget lasts (`RunnerDeps.mediaByteCapBytes`,
393
+ * default `AGGREGATE_MEDIA_BUDGET_BYTES`: decoded bytes, spent as base64 on the wire — x 4/3 — after the text's
394
+ * serialized size), past which a block becomes `{ type, mimeType?, bytes, truncated: true }` in its slot (never a
395
+ * string; a media type over 255 characters is not echoed), and when not even a descriptor fits, it and every later
396
+ * media block fold into ONE `{ type: "omitted", blocks, bytes, truncated: true }` in its slot, so the media in an event
397
+ * is bounded at any block count. A consumer must handle both shapes.
390
398
  *
391
399
  * **UNTRUSTED RAW + for OBSERVABILITY ONLY**: it is external tool output (file reads, shell stderr, API
392
400
  * bodies) and may carry secrets/paths/PII — core bounds only its SIZE; a consumer MUST redact and MAY
393
401
  * further bound before it persists or displays it (same contract as `tool_start.args`). It is for a live
394
402
  * UI / trace, NOT for re-feeding to a model: a truncated body would mislead an LLM, and the model already
395
403
  * has the full, untruncated result in its own context — build model prompts from the session, never by
396
- * replaying this field. Absent when the tool produced no content body.
404
+ * replaying this field. The engine's two model-facing readers of it, the observer digest and the sub-agent step
405
+ * outcome, render a block through the one block rendering (text as text, any other block as its `[type: mimeType]`
406
+ * marker, never its payload).
407
+ * Absent when the tool produced no content body.
397
408
  */
398
409
  output?: unknown;
399
410
  /**
@@ -543,29 +554,31 @@ export type TaskEvent = ({
543
554
  */
544
555
  notExecuted?: true;
545
556
  /**
546
- * design/99 §E1 — `true` when {@link output} was SIZE-bounded by core (the full body exceeded the cap and
547
- * was degraded to a truncated string). Lets a consumer detect truncation programmatically instead of
548
- * parsing the `…[+N chars truncated]` marker out of the string. Absent/false = `output` is the complete
549
- * content body. (The full untruncated result still lives in the model's context / `ToolResultStore`.)
557
+ * design/99 §E1 — `true` exactly when {@link output} is not the content the tool returned: text was cut at the cap
558
+ * (the string, or the block at the cut, carries the marker; the stream's later blocks left), a media block was
559
+ * replaced by its descriptor, media folded into the summary, or content that could not be read was replaced by the
560
+ * one `[unserializable tool output]` string. Lets a consumer detect truncation programmatically
561
+ * instead of parsing the marker out of the text; a media block carries `truncated: true` on its own descriptor.
562
+ * Absent/false = `output` IS the returned content, every block in its slot. (The full untruncated result still
563
+ * lives in the model's context / `ToolResultStore`.)
550
564
  */
551
565
  truncated?: boolean;
552
566
  /**
553
- * Present iff {@link truncated}: the TRUE original size (characters) of
554
- * the content this event's {@link output} was degraded from — for a string result, the string's own
567
+ * Present iff {@link truncated} and the content could be read: the TRUE original size (characters) of
568
+ * the value this event's {@link output} was bounded from — for a string result, the string's own
555
569
  * length; for a non-string result (a blocks array), the SUM of each block's own true size (a text
556
- * block's `.text.length`; an image/document block's `.data.length`, i.e. its base64 payload) — never
557
- * `JSON.stringify(content).length`, which is polluted by two different kinds of noise: structural
558
- * overhead (field-name/punctuation bytes that aren't content at all) AND, for text containing quotes/
559
- * backslashes/control characters, escape inflation (the same class of bug this field was created to
560
- * fix in the first place — a real result: 17298 reported vs 13696 true content characters — reappearing
561
- * in a subtler form if the true count were ever taken from the serialized form instead of the blocks).
570
+ * block's `.text.length` plus whatever else it carries at its serialized length; an image/document block's
571
+ * `.data.length`, i.e. its base64 payload, whether the
572
+ * block rode as-is or was replaced by its descriptor; any other block, outside the tool contract, its serialized
573
+ * length) — never `JSON.stringify(content).length`, which is
574
+ * polluted by two different kinds of noise: structural overhead (field-name/punctuation bytes that aren't
575
+ * content at all) AND, for text containing quotes/backslashes/control characters, escape inflation (a
576
+ * real result: 17298 reported vs 13696 true content characters).
562
577
  *
563
- * **Not always arithmetically tied to the marker's own `N`**: the marker counts how much MORE of the
564
- * shown raw-text rendering exists beyond the cut point; `totalChars` counts the true size of the
565
- * ORIGINAL value, which for mixed content includes non-text blocks (e.g. an inlined image) that
566
- * `output` never renders as text at all. The two can legitimately diverge — `totalChars` may run far
567
- * ahead of the cap plus the marker's `N` — and that gap is itself the honest signal that non-text bulk
568
- * was dropped, not an inconsistency to paper over.
578
+ * **Not arithmetically tied to the marker's own `N`**: the marker counts how much MORE of the shown text
579
+ * exists beyond the cut point; `totalChars` counts the whole ORIGINAL value, media blocks included, so it
580
+ * can run far ahead of the cap plus `N`. Read what was cut from the marker (text) and from the
581
+ * descriptors' own `bytes` (media), not from the gap.
569
582
  */
570
583
  totalChars?: number;
571
584
  } & TaskEventIdentity) | ({
@@ -869,6 +882,10 @@ export type TaskEvent = ({
869
882
  * serving layer replaying the ledger); the core's live emissions precede the commit and
870
883
  * omit it — consumers there join via `message_committed` + stream order. */
871
884
  entryId?: string;
885
+ /** Present only on the `"applied"` frame of an objective that declared attachments: per attachment, in order, what
886
+ * the engine read for it and will send (`outcome`) — an admission result, not a delivery. Each attachment is
887
+ * delivered as its own message after the objective; its `message_committed` is the delivery. */
888
+ attachments?: readonly HumanInputAttachment[];
872
889
  } & TaskEventIdentity) | ({
873
890
  /**
874
891
  * design/99 §E3/§E10 — a live BRAIN-LAYER status the brain would otherwise absorb
@@ -897,11 +914,74 @@ export type TaskEvent = ({
897
914
  * fact, not a default: a pre-373 producer event, or a parked record whose tier was not
898
915
  * carried (the terminal sweep's re-pend) — never read absence as `"later"`. */
899
916
  priority?: import("./task-notification.js").SystemInjectionPriority;
917
+ } & TaskEventIdentity) | ({
918
+ /**
919
+ * A DELEGATED CHILD STARTED: the one frame that says who the child is, at the beat it starts —
920
+ * before its first model request, so a consumer opens the child's row (a foreground child's panel
921
+ * line, a background child's fleet entry) without waiting a model turn for the first
922
+ * `task_progress`. Mirrors CC's `system/task_started`.
923
+ *
924
+ * ONE MINT PER CYCLE, at the child leg's spawn station, for every delegation lane alike
925
+ * (foreground, background, fork, workflow agent, named teammate): a first spawn mints it, and so
926
+ * does every revival of a completed child (a new cycle — `seq` moves on, the `taskId`/`sessionId`
927
+ * of the revived run say which). A durable RESUME of a parked leg is the same cycle continuing and
928
+ * mints NOTHING; a child whose prepare throws never reaches the station and mints nothing either
929
+ * (its terminal still arrives on the lane that spawned it). Ordered strictly after the leg's
930
+ * `wiring_manifest` and strictly before anything its first turn produces, so on the forward
931
+ * channel it is the child's first frame. Rides the same door as `task_progress` (the child's own
932
+ * stream, and the forward channel to the deployment); the process-level delegation-lifecycle
933
+ * `spawn` frame is a projection of this mint, delivered at the same instant under the same gate.
934
+ *
935
+ * Live and ephemeral like `task_progress`: never persisted, never replayed on resume, absent from
936
+ * checkpoints. Every member below is a value the run already speaks elsewhere — this frame
937
+ * introduces no new reading of any of them.
938
+ *
939
+ * CC mapping: `task_id` → {@link taskId} (run domain; a background child's registry handle rides
940
+ * {@link TaskEventIdentity.bgAgentId}), `tool_use_id` → `parentToolCallId`, `description` →
941
+ * {@link name}, `subagent_type` → {@link agentType}, `task_type`/`is_backgrounded` → {@link taskType}
942
+ * (absent = a foreground child), `run_id` → {@link seq} (the cycle), `parent_task_id` →
943
+ * {@link parentTaskId}, `session_id` → {@link sessionId}. Not carried: `prompt` (a delegated
944
+ * objective can hold a secret — the same reason {@link name} never falls back to it), `awaited`,
945
+ * `spawn_depth` (the nesting is the `parentTaskId` chain), and the shell/monitor-only members.
946
+ */
947
+ type: "task_started";
948
+ /** The child RUN's id (`spec.taskId ?? sessionId`) — the key its `task_progress` frames carry. */
949
+ taskId: string;
950
+ /** The child run's session id — the handle its transcript is read by. */
951
+ sessionId: string;
952
+ /** The fleet-task kind, exactly as the child's `task_progress.taskType`: ABSENT for a foreground
953
+ * (synchronous) child, which has no fleet row. */
954
+ taskType?: DelegationTaskType;
955
+ /** The registry row's cycle generation, exactly as `task_progress.seq` (absent where the child has no
956
+ * `a*` row). A revived cycle's frame carries the bumped value. */
957
+ seq?: number;
958
+ /** Workflow-lane self-identification, as on `task_progress` (stamped where the workflow forwards). */
959
+ workflowRunId?: string;
960
+ /** The workflow agent's label, riding with {@link workflowRunId}. */
961
+ workflowAgentLabel?: string;
962
+ /** The spawning run's task id, exactly as `task_progress.parentTaskId`. */
963
+ parentTaskId?: string;
964
+ /** The spawning run's session id (the always-on parent linkage). */
965
+ parentSessionId?: string;
966
+ /** The delegation tree's root host session. */
967
+ rootSessionId?: string;
968
+ /** The child's display label, the same bounded single-line value its `task_progress.name` and its
969
+ * hook identity's `agentName` carry. UNTRUSTED display text. */
970
+ name?: string;
971
+ /** The explicit `Agent({name})` spawn identity (the teammate key), when the spawn carried one. */
972
+ spawnName?: string;
973
+ /** The resolved subagent type the child was spawned as (absent on a workflow-lane agent). */
974
+ agentType?: string;
975
+ /** The model the child leg was PREPARED with — the value its `task_progress.model` and
976
+ * `TaskResult.model` carry. */
977
+ model: string;
978
+ /** Epoch ms at the mint. */
979
+ startedAt: number;
900
980
  } & TaskEventIdentity) | ({
901
981
  /**
902
982
  * design/99 MF-10 — a SUBAGENT PROGRESS TICK: the delegated sub-run's usage ACCRUING
903
983
  * over time, emitted at each turn boundary WHILE it runs, so a parent UI animates the Task card's rollup
904
- * (tokens/tool-uses climbing). Emitted ONLY for a subagent (a task with `parentToolCallId`); a top-level
984
+ * (tokens/tool-uses climbing). Emitted ONLY for a delegated leg (the same eligibility as `task_started`); a top-level
905
985
  * run's own usage is the consumer's own. `status:"running"` mid-run; the terminal usage is the `done` result.
906
986
  * Live/ephemeral — NOT persisted (a resumable trace re-derives usage from the result), like `status`.
907
987
  * Maps to CC `SDKTaskProgress` (camelCase here → snake_case `task_id`/`total_tokens`/`tool_uses`/`duration_ms`
@@ -1075,6 +1155,14 @@ export type TaskEvent = ({
1075
1155
  export type HumanInputEvent = Extract<TaskEvent, {
1076
1156
  type: "human_input";
1077
1157
  }>;
1158
+ /** One attachment on a `human_input` frame: its position, the kind the engine found (absent when the read was refused
1159
+ * before the kind was known), what reached the model of its contents, and the path or name it was declared with. */
1160
+ export interface HumanInputAttachment {
1161
+ readonly ordinal: number;
1162
+ readonly kind?: UserAttachmentKind;
1163
+ readonly outcome: UserAttachmentOutcome;
1164
+ readonly label: string;
1165
+ }
1078
1166
  /**
1079
1167
  * Outcome of a manual {@link TaskStream.compact} request (the enum names align with
1080
1168
  * the diagnosis decision tree's drain exits, so a consumer can tell "202 processed" states apart):
@@ -31,6 +31,39 @@ export type ImageInput = {
31
31
  /** URL the runner will fetch and inline as base64 before sending to the model. */
32
32
  url: string;
33
33
  };
34
+ /**
35
+ * One file the user attached to the objective, by WHO HOLDS ITS BYTES (never by what kind of file it is — the engine
36
+ * finds that out and reports it):
37
+ * - `{ path, lines? }` — a file or directory the engine can reach in its workspace: the engine reads it through the
38
+ * Read tool's own read and admission (read-deny table, roots, the run's deny rules), as if the model had read it,
39
+ * minus the questions — the user's declaration is the answer to an ordinary ask; a read some layer would put to a
40
+ * person other than the asker (an organization rule, a deployment-authored or real-approval ask) is not attached.
41
+ * `lines` reads a line range (1-based, `end` inclusive).
42
+ * - `{ name, text, startLine? }` — text the host holds (a local file a remote engine cannot reach, an unsaved buffer):
43
+ * delivered as given, line-numbered from `startLine` (default 1). It opens nothing an objective could not carry,
44
+ * and records no read state.
45
+ * - `{ name, image: { data, mimeType } }` — an image file the host holds (base64), admitted like an image the Read tool
46
+ * serves.
47
+ * Each attachment reaches the model as its own message right after the objective, marked as the engine's: two
48
+ * marked sentences around the data, the name or path only in the data. See `USER_ATTACHMENT_SEAT` for the limits.
49
+ */
50
+ export type UserAttachment = {
51
+ readonly path: string;
52
+ readonly lines?: {
53
+ readonly start: number;
54
+ readonly end?: number;
55
+ };
56
+ } | {
57
+ readonly name: string;
58
+ readonly text: string;
59
+ readonly startLine?: number;
60
+ } | {
61
+ readonly name: string;
62
+ readonly image: {
63
+ readonly data: string;
64
+ readonly mimeType: string;
65
+ };
66
+ };
34
67
  /** A single self-contained task with its full configuration. */
35
68
  /** The shell-gate FLOOR vocabulary — {@link TaskSpec.shellGate}'s value set, the word the engine persists on a
36
69
  * shell-gated ask (`RiskDescriptor.shellGateDoctrine`) and carries down a delegation chain. One value: `"always"`
@@ -133,6 +166,17 @@ export interface TaskSpec {
133
166
  interactiveQuestionFallback?: boolean;
134
167
  /** Optional images attached to this turn's user message (model must support vision). */
135
168
  images?: ImageInput[];
169
+ /**
170
+ * Files the user attached to this objective ({@link UserAttachment}): at most 20, delivered after the
171
+ * UserPromptSubmit hook lets the objective through (a hook that blocks it reads nothing), each as its own
172
+ * engine-minted message right after the objective. A path entry needs a workspace (hands on). A malformed entry,
173
+ * a text entry over the Read limit (100 000 rendered characters), an image the API would not accept, a path entry
174
+ * on a run without a workspace, or any entry on a durable resume leg is refused at the door:
175
+ * `config.user_attachment_invalid`, the message opening with the field path (`TaskSpec.userAttachments[2].text: …`).
176
+ * A file the engine may not read is not refused: its message says it was not attached and why, and the
177
+ * `human_input` event's `attachments[]` reports each outcome.
178
+ */
179
+ userAttachments?: readonly UserAttachment[];
136
180
  /** Reuse an existing in-memory session for chat continuity; omit to start fresh. */
137
181
  sessionId?: string;
138
182
  /**
@@ -44,7 +44,7 @@ export interface TaskToolCapabilities {
44
44
  /** TaskStop accepts a background agent's spawn NAME as task_id (registry name resolution only). */
45
45
  nameAddressing: boolean;
46
46
  }
47
- /** Full-capability profile = the registry-backed mount with notifications wired (CC-209 verbatim form). */
47
+ /** Full-capability profile = the registry-backed mount with notifications wired (CC 209 verbatim form). */
48
48
  export declare const REGISTRY_TASK_TOOL_CAPS: TaskToolCapabilities;
49
49
  /** The env-direct thin-shell profile: cursor polling over a background shell, nothing else. */
50
50
  export declare const ENV_DIRECT_TASK_TOOL_CAPS: TaskToolCapabilities;
@@ -97,8 +97,22 @@ export const TOOL_CATALOG_ENTRIES = [
97
97
  compactable: true,
98
98
  },
99
99
  },
100
- { id: "repo-map", name: "RepoMap", source: "builtin", definedIn: "src/tools/fs/repo-map.ts", mountedBy: ["hands"], cards: ["repo-map"], face: { family: "search", effect: "read", contract: c("core.repo_map@1") } },
101
- { id: "lsp", name: "LSP", source: "builtin", definedIn: "src/core/lsp.ts", mountedBy: ["hands"], cards: [], face: { family: "search", effect: "read", contract: c("core.lsp@1") } },
100
+ {
101
+ id: "repo-map", name: "RepoMap", source: "builtin", definedIn: "src/tools/fs/repo-map.ts", mountedBy: ["hands"], cards: ["repo-map"],
102
+ face: {
103
+ family: "search", effect: "read", contract: c("core.repo_map@1"),
104
+ pathTarget: { param: "path", access: "read", base: "root", absent: "base" },
105
+ ruleFace: { params: ["path", "max_chars", "max_files"] },
106
+ },
107
+ },
108
+ {
109
+ id: "lsp", name: "LSP", source: "builtin", definedIn: "src/core/lsp.ts", mountedBy: ["hands"], cards: [],
110
+ face: {
111
+ family: "search", effect: "read", contract: c("core.lsp@1"),
112
+ pathTarget: { param: "filePath", access: "read", base: "cwd", absent: "none" },
113
+ ruleFace: { params: ["operation", "filePath", "line", "character", "query"] },
114
+ },
115
+ },
102
116
  {
103
117
  id: "artifact", name: ARTIFACT_TOOL_NAME, source: "builtin", definedIn: "src/tools/artifact/artifact-tool.ts", mountedBy: ["optional"], cards: ["artifact"],
104
118
  face: { family: "other", effect: "write", contract: c("core.artifact@1"), ruleFace: { primaryParams: ["action"] }, renderHints: { summaryParams: ["action", "file_path", "url"] } },
@@ -234,6 +234,9 @@ export interface EngineAttestation {
234
234
  readonly unresolvableCause?: import("./ask-unresolvable-notice.js").AskUnresolvableCause;
235
235
  /** The classes of the asks a policy fold collapsed — the proof behind a decision's `foldedAskClasses`. */
236
236
  readonly foldedClasses?: readonly import("./ask-origin.js").AskClass[];
237
+ /** Where a path deny row refused the call — the row, the view of the target it met, the face the call is on. The gate's
238
+ * exit mints the refusal's card from it; the judge that found the row is its only writer. */
239
+ readonly pathDenial?: import("../tools/fs/safety.js").PathDenialEvidence;
237
240
  }
238
241
  /** The members a station attests — everything but the call binding. */
239
242
  export type AttestationMembers = Omit<EngineAttestation, "toolCallId" | "toolName">;
@@ -302,6 +305,8 @@ export declare function screenApproverAttribution(v: unknown): {
302
305
  approver?: string;
303
306
  defect?: string;
304
307
  };
308
+ /** An integrity guard an ask stands on ({@link PermissionResult}'s `guards`). */
309
+ export type AskGuard = "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "artifact_shared_read";
305
310
  /**
306
311
  * A three-state permission decision for a tool call (design/37). Upgrades the old two-state
307
312
  * `{allow|deny}`:
@@ -327,11 +332,13 @@ export declare function screenApproverAttribution(v: unknown): {
327
332
  * record ({@link EngineAttestation}) the receipt refuses in any other form, and the gate's exit mints the one
328
333
  * settlement record ({@link import("./gate-outcome.js").GateOutcome}) from it; a policy that puts a `settledBy`
329
334
  * or `approver` member on its verdict is putting an unread property on it.
330
- * RB-479-B① (ruled 2026-08-02): the legacy `reason` field is REMOVED — one name for one thing.
335
+ * RB-479-B① (ruled 2026-08-02): the legacy `reason` field is REMOVED — one name for one thing. The ask arm's one-word
336
+ * `guard` is retired the same way, for `guards`.
331
337
  *
332
338
  * The TYPE carries that retirement only where a decision is a literal in an annotated position; an inferred `check`
333
- * return compiles green with a stray `reason`, so the enforcement is at RUNTIME — every point that consumes a decision
334
- * refuses one carrying an own `reason` property, fail-closed ({@link refuseOutOfContractDecision}).
339
+ * return compiles green with a stray `reason` or `guard`, so the enforcement is at RUNTIME — every point that consumes a
340
+ * decision refuses one that carries a retired member ({@link RETIRED_DECISION_MEMBERS}), fail-closed
341
+ * ({@link refuseOutOfContractDecision}).
335
342
  */
336
343
  export type PermissionResult = {
337
344
  action: "allow";
@@ -454,18 +461,21 @@ export type PermissionResult = {
454
461
  /** The ask's whole class set, in {@link import("./ask-origin.js").ASK_CLASSES} order (see
455
462
  * {@link AskRequest.classes}). Stamped beside {@link askClass}, under the same rule. */
456
463
  classes?: readonly import("./ask-origin.js").AskClass[];
457
- /** WHICH integrity guard minted this ask — a removal of a protected location, an unverifiable recursive delete,
458
- * shell text the engine cannot read or the session-transcript write. ENGINE-STAMPED by the guard policies; a fold-internal fact the class
459
- * derivation reads ({@link import("./ask-origin.js").classifyAsk}) so the guards, which mint the same
460
- * `requiresRealApproval` ask, are told apart by a fact and not by their prose. Never copied onto the
461
- * approval request or the park row. */
462
- guard?: "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "artifact_shared_read";
464
+ /** WHICH integrity guards stand behind this ask — a removal of a protected location, an unverifiable recursive delete,
465
+ * shell text the engine cannot read (or an environment that did not answer the read station), the session-transcript
466
+ * write. A set: one ask may stand on several, and each keeps its class. ENGINE-STAMPED by the guard policies and the
467
+ * gate fold; a fold-internal fact the class derivation reads ({@link import("./ask-origin.js").classifyAsk}) so the
468
+ * guards, which mint the same `requiresRealApproval` ask, are told apart by a fact and not by their prose. Never
469
+ * copied onto the approval request or the park row. Replaces the one-word `guard`, which a decision no longer carries:
470
+ * a decision that still does is refused by name ({@link RETIRED_DECISION_MEMBERS}). */
471
+ guards?: readonly AskGuard[];
463
472
  /** The call could not be READ against a rule that may reach it — a content-form deny row, a content-form
464
- * ask row, or a persisted-rule row (the lexer's word). ENGINE-STAMPED at the three unreadable mint sites;
465
- * the class derivation reads it as `rule_unreadable` (a mode may release it, a person may clear it, no
473
+ * ask row, a persisted-rule row (the lexer's word), or rows the shell read station's boundary stands on that
474
+ * could not be read (`persisted_rows`). ENGINE-STAMPED at the four unreadable mint sites;
475
+ * the class derivation reads it as `rule_unreadable` (no mode releases it, a person may clear it, no
466
476
  * automatic lane may). It replaces the former practice of stamping `matchedAskRule` on an unreadable
467
477
  * read: a rule that COULD NOT be matched is not a rule that matched. Fold-internal; not on the request. */
468
- ruleUnreadable?: "content_deny" | "content_ask" | "persisted_call";
478
+ ruleUnreadable?: "content_deny" | "content_ask" | "persisted_call" | "persisted_rows";
469
479
  /** The ask was authored by the DEPLOYMENT's own governance (an operator's must-ask list, a managed command
470
480
  * policy's default ask) — a fact a host's policy states on its own ask so the class derivation reads it
471
481
  * as `operator_forced`: a permission mode releases nothing an operator mandated (`dontAsk` refuses it like
@@ -853,8 +863,8 @@ export declare const DECISION_MEMBERS: readonly DecisionMember[];
853
863
  * taken off the carrier's own descriptor (a member outside the contract is neither read nor carried — a policy's self-declared
854
864
  * record on another name finds no reader); any other spelling refused by name — an accessor (never invoked), a member the
855
865
  * prototype or a non-enumerable property supplies unless that descriptor spells absence (an `undefined` data value) — judged by
856
- * descriptor, never read; (3) the retired `reason` field as an OWN property, judged without a read (authorship of the old
857
- * spelling: a prototype exposing it never wrote it; ignoring it silently dropped the policy's text); (4) the VALUES, off the engine's
866
+ * descriptor, never read; (3) a retired member ({@link RETIRED_DECISION_MEMBERS}: `reason`, `guard`) carried by the same presence law as a contract
867
+ * member — own, held by an accessor, or supplied by the prototype — judged without a read (ignoring it silently dropped the policy's text or the ask's guard); (4) the VALUES, off the engine's
858
868
  * one-read record, never a second read of the caller's object — the retired window absent, `action` in
859
869
  * its closed set (`screenContractValues`, decision-receipt.ts — every closed-set member is held to its set there; a consumer ranks a decision by testing two of its words, so any other value used to rank as an
860
870
  * allow; a `canUseTool` result outside its set is a failure in CC) and `decisionReason` in {@link DECISION_REASONS} when
@@ -1085,7 +1095,7 @@ export declare function createCoarseCommandNamePolicy(opts: {
1085
1095
  tools?: string[];
1086
1096
  }): ToolPolicy;
1087
1097
  /**
1088
- * CC 220 "Unverifiable Deletion Target" parity (auto-mode rule): ASK on a recursive+forced delete whose
1098
+ * CC 220 "Unverifiable Deletion Target" parity (auto-mode rule; its text is in 220–245, gone from 2.1.250 on): ASK on a recursive+forced delete whose
1089
1099
  * target is a variable / substitution that cannot be resolved from the command itself — fail-closed in the
1090
1100
  * sense that with no live classifier/approver the ask degrades to deny (see {@link PermissionResult}'s
1091
1101
  * `ask` doc), never to allow. The guard reads ONE plan, the read station's (`removalReadingOf`,
@@ -16,7 +16,7 @@ import { boundInputHashOf } from "./canonical-json.js";
16
16
  import { delimitUntrusted, inlineUntrusted, REVIEWER_NOTE_MAX_BODY } from "./untrusted-text.js";
17
17
  import { describeRejectedValue } from "./tool-search-setting.js";
18
18
  import { thrownText } from "./thrown-value.js";
19
- import { assertNoRetiredToolPolicyKeys } from "./retired-keys.js";
19
+ import { assertNoRetiredToolPolicyKeys, RETIRED_DECISION_MEMBERS } from "./retired-keys.js";
20
20
  import { isEngineRefusal, nestedRecordsOf, receiveContract, receiveNestedRecords, refusedOutOfContract, screenContractValues } from "./decision-receipt.js";
21
21
  export { isEngineRefusal } from "./decision-receipt.js";
22
22
  import { isNamespacedCoveringRuleName, namespacedRuleNameCovers, parsePermissionRule } from "./permission-rules.js";
@@ -43,6 +43,7 @@ const ATTESTATION_GROUP_OF = {
43
43
  classifierRound: "classifierRound",
44
44
  unresolvableCause: "unresolvableCause",
45
45
  foldedClasses: "foldedClasses",
46
+ pathDenial: "pathDenial",
46
47
  };
47
48
  const ATTESTATION_MEMBERS = Object.keys(ATTESTATION_GROUP_OF);
48
49
  const groupLead = (g) => ATTESTATION_MEMBERS.find((k) => ATTESTATION_GROUP_OF[k] === g);
@@ -238,18 +239,15 @@ export function constraintChainDigest(chain) {
238
239
  }
239
240
  const ALLOW = Object.freeze({ action: "allow" });
240
241
  const ALLOW_BY_RULE = Object.freeze({ action: "allow", decisionReason: "rule" });
241
- const RETIRED_TEXT_FIELD = "reason";
242
242
  export const DECISION_MEMBERS = Object.keys({
243
243
  action: 0, updatedInput: 0, message: 0, decisionReason: 0, requiresRealApproval: 0, denialLimitFallback: 0, classifierNoRuling: 0, allowRuleShadowed: 0, probeReason: 0,
244
244
  probeCause: 0, probeMandated: 0, mandated: 0, mandate: 0, probeReadRootCandidate: 0, matchedAskRule: 0, ruleEvidence: 0, segmentCoverage: 0,
245
- origin: 0, askClass: 0, classes: 0, guard: 0, ruleUnreadable: 0, authoredBy: 0, foldedAskClasses: 0, attestation: 0,
245
+ origin: 0, askClass: 0, classes: 0, guards: 0, ruleUnreadable: 0, authoredBy: 0, foldedAskClasses: 0, attestation: 0,
246
246
  });
247
247
  const HOOK_RESULT_MEMBERS = [...DECISION_MEMBERS, "additionalContext"];
248
248
  const HOOK_SEAM_UNREAD = new Set(["decisionReason"]);
249
249
  const HOOK_SEAM_OPTIONAL = new Set(["action"]);
250
250
  const HOOK_RECEIPTS = new WeakSet();
251
- const RETIRED_TEXT_FIELD_DENY_MESSAGE = `a permission decision carries the retired "${RETIRED_TEXT_FIELD}" field — rename it to "message" (the one text field ` +
252
- `a decision carries); denied fail-closed rather than executing a decision whose text this layer cannot read`;
253
251
  const ENGINE_RECEIPTS = new WeakSet();
254
252
  export function refuseOutOfContractDecision(d, opts) {
255
253
  const hookSeam = opts?.reasonIsNonInput === true;
@@ -260,11 +258,9 @@ export function refuseOutOfContractDecision(d, opts) {
260
258
  }
261
259
  if ((hookSeam ? HOOK_RECEIPTS : ENGINE_RECEIPTS).has(d) || isEngineRefusal(d))
262
260
  return d;
263
- const decision = receiveContract(d, hookSeam ? HOOK_RESULT_MEMBERS : DECISION_MEMBERS, "");
261
+ const decision = receiveContract(d, hookSeam ? HOOK_RESULT_MEMBERS : DECISION_MEMBERS, "", RETIRED_DECISION_MEMBERS);
264
262
  if (decision.kind === "refused")
265
263
  return decision.refused;
266
- if (Object.prototype.hasOwnProperty.call(d, RETIRED_TEXT_FIELD))
267
- return refusedOutOfContract(RETIRED_TEXT_FIELD_DENY_MESSAGE);
268
264
  const contract = decision.held;
269
265
  const refused = receiveNestedRecords(contract) ?? screenContractValues(contract, hookSeam ? { skip: HOOK_SEAM_UNREAD, optional: HOOK_SEAM_OPTIONAL } : undefined);
270
266
  if (refused !== undefined)
@@ -293,9 +289,9 @@ export function refuseOutOfContractDecision(d, opts) {
293
289
  `the engine keeps its own copy of what it read; denied fail-closed`);
294
290
  }
295
291
  const receipt = Object.freeze(attestation !== undefined ? { ...detached.value, attestation } : detached.value);
296
- for (const k of ["classes", "foldedAskClasses"])
297
- if (Object.hasOwn(receipt, k) && Array.isArray(receipt[k]))
298
- Object.freeze(receipt[k]);
292
+ for (const v of Object.values(receipt))
293
+ if (Array.isArray(v))
294
+ Object.freeze(v);
299
295
  for (const record of nestedRecordsOf(receipt)) {
300
296
  for (const v of Object.values(record))
301
297
  if (Array.isArray(v))
@@ -711,7 +707,7 @@ function removalAsk(guard, text) {
711
707
  unverifiable_delete: `Unverifiable recursive delete (fail-closed unless cleared): ${text}. Re-run the delete with the resolved literal path written into the command itself (or assign the variable a literal path in the same command, e.g. \`DIR=/exact/path; rm -rf "$DIR"\`) so the target can be verified.`,
712
708
  unverifiable_shell_text: `Unverifiable shell text (fail-closed unless cleared): ${text}. Write the text into the command itself (a \`-c\` string, a here-document or a here-string) and the engine reads it as it reads any command.`,
713
709
  };
714
- return { action: "ask", decisionReason: "safety", requiresRealApproval: true, guard, message: messages[guard] };
710
+ return { action: "ask", decisionReason: "safety", requiresRealApproval: true, guards: [guard], message: messages[guard] };
715
711
  }
716
712
  function pathSegments(p) {
717
713
  return p.split(/[\\/]/).filter(Boolean);
@@ -784,7 +780,7 @@ export function createTranscriptIntegrityPolicy(opts) {
784
780
  action: "ask",
785
781
  decisionReason: "safety",
786
782
  requiresRealApproval: true,
787
- guard: "transcript_write",
783
+ guards: ["transcript_write"],
788
784
  message: `Session-transcript write (fail-closed unless cleared): ${what}. Session transcripts (the .jsonl files ` +
789
785
  `under the agent data dir's sessions/ directory) are harness-written session state, not agent working ` +
790
786
  `files — modifying or deleting them tampers with the run's own audit trail. Reading them (ls/cat/grep ` +
@@ -475,8 +475,9 @@ export type TraceEvent = {
475
475
  } | {
476
476
  /**
477
477
  * design/179 — the person's persisted rule store could not be read (at prepare, or for one call), so
478
- * that read's rows took no part: the decision it served was made with ZERO persisted rows. The operator's
479
- * per-read record; the person hears it once per run (`permission.rule_store_unavailable`).
478
+ * that read's rows took no part: a call it served was judged without them — and, at a call, asks a person (the
479
+ * rows could hold a deny). The operator's per-read record; the person hears it once per run
480
+ * (`permission.rule_store_unavailable`).
480
481
  */
481
482
  kind: "permission.rule_store_unreadable";
482
483
  version: 1;
@@ -13,7 +13,7 @@ import type { AgentTool, ThinkingLevel, ToolInputValidationContext, ToolInputVer
13
13
  import type { Model, StreamFn } from "../internal/llm.js";
14
14
  export type { ModelRef, ModelRole, RoleSpec, ModelRoles, Brain } from "./model-seat.js";
15
15
  export { MODEL_ROLES } from "./model-seat.js";
16
- export type { StaleToolResultOffloadOptions, ImageInput, TaskSpec, ShellGateDoctrine } from "./task-spec.js";
16
+ export type { StaleToolResultOffloadOptions, ImageInput, TaskSpec, ShellGateDoctrine, UserAttachment } from "./task-spec.js";
17
17
  export type { PermissionMode } from "./ask-origin.js";
18
18
  export type { ToolEffect, ToolContentOrigin, ReversibilityVerdict, ReadRootGrantCandidate, ToolSpec, ToolReturn, NestedUsage, NestedUsageAccum, ToolExecuteContext } from "./tool-spec.js";
19
19
  export type { BeforeWriteRequest, BeforeWriteResult, BeforeWriteHook, TrackEditRequest, TrackEditResult, TrackFileEditHook, FileEditedNotice, FileEditedHook, HandsBandOptions } from "./hands-band.js";
@@ -22,12 +22,12 @@ export type { McpServerSpec, A2aServerSpec, McpElicitRequest, McpElicitResponse,
22
22
  export type { TaskLimits } from "./task-limits.js";
23
23
  export type { TaskStatus, RemoteEnvFailureNote, EffectiveMemoryScopes, TaskResult, HumanReviewGateRow } from "./task-result.js";
24
24
  export type { TerminalCause, PausedCause } from "./terminal-cause.js";
25
- export type { TaskEventIdentity, BrainStatusPhase, BrainRetryErrClass, BrainStatus, ToolActivity, HumanInputSource, HumanInputDelivery, DelegationTaskType, TaskEvent, HumanInputEvent, CompactOutcome } from "./task-event.js";
25
+ export type { TaskEventIdentity, BrainStatusPhase, BrainRetryErrClass, BrainStatus, ToolActivity, HumanInputSource, HumanInputDelivery, DelegationTaskType, TaskEvent, HumanInputEvent, HumanInputAttachment, CompactOutcome } from "./task-event.js";
26
26
  export type { TaskStream } from "./task-stream.js";
27
27
  export type { WorkflowGovernanceBaseline, RuntimeCaps, AutoModeDenySource } from "./runtime-caps.js";
28
28
  export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js";
29
29
  export type { BackgroundChildEvent, DelegationLifecycleEvent } from "./delegation-frames.js";
30
- export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle } from "./delegation-frames.js";
30
+ export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle, emitsChildRowFrames, taskStartedFrame } from "./delegation-frames.js";
31
31
  export type { ProjectMemoryLoad, ResumePreflightInfo, ResumePreflightVerdict, RunnerDeps } from "./runner-deps.js";
32
32
  export type { EngineNotice, OwedUserInputAccount, UserInputUndrainedCause } from "./engine-notice.js";
33
33
  export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
@@ -1,4 +1,4 @@
1
1
  export { MODEL_ROLES } from "./model-seat.js";
2
2
  export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js";
3
- export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle } from "./delegation-frames.js";
3
+ export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle, emitsChildRowFrames, taskStartedFrame } from "./delegation-frames.js";
4
4
  export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
@@ -330,8 +330,8 @@ export declare function cutEngineSegments(text: string, segments: unknown): {
330
330
  * offsets are DEFINED: a user-lane message qualifies only when its content is a plain string or a
331
331
  * SINGLE text block (whose text is that same string). Multi-block / image-bearing content returns
332
332
  * `undefined` and consumers render the message VERBATIM with their own local flatten — the two
333
- * projection sides flatten blocks DIFFERENTLY (the auto-mode window joins with `\n` + `[image]`
334
- * placeholders; the compaction serializer drops non-text blocks and joins with no separator), so a
333
+ * projection sides flatten blocks DIFFERENTLY (the auto-mode window joins with `\n` + `[image: …]`
334
+ * block markers; the compaction serializer drops non-text blocks and joins with no separator), so a
335
335
  * single `[start, end)` range would point at different characters on each side. The restriction
336
336
  * costs nothing real: every engine-assembled prefixed/segmented message (first-frame objective
337
337
  * concatenation, resume continuation) is minted from ONE plain string — the sole exception is a