@animalabs/agent-framework 0.32.0 → 0.33.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 (288) hide show
  1. package/README.md +204 -14
  2. package/dist/src/admission/admit.d.ts +18 -0
  3. package/dist/src/admission/admit.d.ts.map +1 -1
  4. package/dist/src/admission/admit.js +16 -3
  5. package/dist/src/admission/admit.js.map +1 -1
  6. package/dist/src/agent.d.ts +185 -78
  7. package/dist/src/agent.d.ts.map +1 -1
  8. package/dist/src/agent.js +279 -102
  9. package/dist/src/agent.js.map +1 -1
  10. package/dist/src/api/mcp-server-core.d.ts.map +1 -1
  11. package/dist/src/api/mcp-server-core.js +50 -12
  12. package/dist/src/api/mcp-server-core.js.map +1 -1
  13. package/dist/src/api/server.d.ts.map +1 -1
  14. package/dist/src/api/server.js +4 -20
  15. package/dist/src/api/server.js.map +1 -1
  16. package/dist/src/code-execution/isolate/scripts.d.ts +12 -8
  17. package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
  18. package/dist/src/code-execution/isolate/scripts.js +24 -0
  19. package/dist/src/code-execution/isolate/scripts.js.map +1 -1
  20. package/dist/src/config-checks.d.ts +7 -0
  21. package/dist/src/config-checks.d.ts.map +1 -1
  22. package/dist/src/config-checks.js +14 -0
  23. package/dist/src/config-checks.js.map +1 -1
  24. package/dist/src/context-manager-errors.d.ts +25 -0
  25. package/dist/src/context-manager-errors.d.ts.map +1 -0
  26. package/dist/src/context-manager-errors.js +31 -0
  27. package/dist/src/context-manager-errors.js.map +1 -0
  28. package/dist/src/context-options.d.ts +67 -0
  29. package/dist/src/context-options.d.ts.map +1 -0
  30. package/dist/src/context-options.js +85 -0
  31. package/dist/src/context-options.js.map +1 -0
  32. package/dist/src/deferred-import.d.ts +93 -0
  33. package/dist/src/deferred-import.d.ts.map +1 -0
  34. package/dist/src/deferred-import.js +177 -0
  35. package/dist/src/deferred-import.js.map +1 -0
  36. package/dist/src/dendrite/audience.d.ts +223 -0
  37. package/dist/src/dendrite/audience.d.ts.map +1 -0
  38. package/dist/src/dendrite/audience.js +202 -0
  39. package/dist/src/dendrite/audience.js.map +1 -0
  40. package/dist/src/dendrite/index.d.ts +5 -3
  41. package/dist/src/dendrite/index.d.ts.map +1 -1
  42. package/dist/src/dendrite/index.js +2 -1
  43. package/dist/src/dendrite/index.js.map +1 -1
  44. package/dist/src/dendrite/presets.d.ts +10 -5
  45. package/dist/src/dendrite/presets.d.ts.map +1 -1
  46. package/dist/src/dendrite/presets.js +17 -5
  47. package/dist/src/dendrite/presets.js.map +1 -1
  48. package/dist/src/dendrite/registry.d.ts +62 -7
  49. package/dist/src/dendrite/registry.d.ts.map +1 -1
  50. package/dist/src/dendrite/registry.js +179 -10
  51. package/dist/src/dendrite/registry.js.map +1 -1
  52. package/dist/src/dendrite/types.d.ts +91 -8
  53. package/dist/src/dendrite/types.d.ts.map +1 -1
  54. package/dist/src/foreign-rounds.d.ts +69 -0
  55. package/dist/src/foreign-rounds.d.ts.map +1 -0
  56. package/dist/src/foreign-rounds.js +152 -0
  57. package/dist/src/foreign-rounds.js.map +1 -0
  58. package/dist/src/framework.d.ts +1976 -818
  59. package/dist/src/framework.d.ts.map +1 -1
  60. package/dist/src/framework.js +7566 -3422
  61. package/dist/src/framework.js.map +1 -1
  62. package/dist/src/gate/event-gate.d.ts +85 -15
  63. package/dist/src/gate/event-gate.d.ts.map +1 -1
  64. package/dist/src/gate/event-gate.js +421 -47
  65. package/dist/src/gate/event-gate.js.map +1 -1
  66. package/dist/src/gate/index.d.ts +1 -1
  67. package/dist/src/gate/index.d.ts.map +1 -1
  68. package/dist/src/gate/index.js.map +1 -1
  69. package/dist/src/gate/rule-scope.d.ts +30 -0
  70. package/dist/src/gate/rule-scope.d.ts.map +1 -0
  71. package/dist/src/gate/rule-scope.js +41 -0
  72. package/dist/src/gate/rule-scope.js.map +1 -0
  73. package/dist/src/gate/suppress-script-worker.d.ts +2 -0
  74. package/dist/src/gate/suppress-script-worker.d.ts.map +1 -0
  75. package/dist/src/gate/suppress-script-worker.js +103 -0
  76. package/dist/src/gate/suppress-script-worker.js.map +1 -0
  77. package/dist/src/gate/suppress-scripts.d.ts +105 -0
  78. package/dist/src/gate/suppress-scripts.d.ts.map +1 -0
  79. package/dist/src/gate/suppress-scripts.js +403 -0
  80. package/dist/src/gate/suppress-scripts.js.map +1 -0
  81. package/dist/src/gate/suppression-review.d.ts +143 -0
  82. package/dist/src/gate/suppression-review.d.ts.map +1 -0
  83. package/dist/src/gate/suppression-review.js +463 -0
  84. package/dist/src/gate/suppression-review.js.map +1 -0
  85. package/dist/src/gate/suppression-stats.d.ts +125 -0
  86. package/dist/src/gate/suppression-stats.d.ts.map +1 -0
  87. package/dist/src/gate/suppression-stats.js +214 -0
  88. package/dist/src/gate/suppression-stats.js.map +1 -0
  89. package/dist/src/gate/types.d.ts +135 -7
  90. package/dist/src/gate/types.d.ts.map +1 -1
  91. package/dist/src/gate/wake-onboarding.d.ts +119 -0
  92. package/dist/src/gate/wake-onboarding.d.ts.map +1 -0
  93. package/dist/src/gate/wake-onboarding.js +277 -0
  94. package/dist/src/gate/wake-onboarding.js.map +1 -0
  95. package/dist/src/held-writes.d.ts +31 -23
  96. package/dist/src/held-writes.d.ts.map +1 -1
  97. package/dist/src/held-writes.js +44 -59
  98. package/dist/src/held-writes.js.map +1 -1
  99. package/dist/src/index.d.ts +5 -2
  100. package/dist/src/index.d.ts.map +1 -1
  101. package/dist/src/index.js +3 -0
  102. package/dist/src/index.js.map +1 -1
  103. package/dist/src/jsonrpc-envelope.d.ts +69 -0
  104. package/dist/src/jsonrpc-envelope.d.ts.map +1 -0
  105. package/dist/src/jsonrpc-envelope.js +66 -0
  106. package/dist/src/jsonrpc-envelope.js.map +1 -0
  107. package/dist/src/mcpl/channel-registry.d.ts +131 -15
  108. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  109. package/dist/src/mcpl/channel-registry.js +290 -46
  110. package/dist/src/mcpl/channel-registry.js.map +1 -1
  111. package/dist/src/mcpl/checkpoint-manager.d.ts +2 -4
  112. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  113. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  114. package/dist/src/mcpl/feature-set-manager.d.ts +2 -4
  115. package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
  116. package/dist/src/mcpl/feature-set-manager.js.map +1 -1
  117. package/dist/src/mcpl/inbound-source.d.ts +2 -1
  118. package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
  119. package/dist/src/mcpl/inbound-source.js +2 -1
  120. package/dist/src/mcpl/inbound-source.js.map +1 -1
  121. package/dist/src/mcpl/inference-router.d.ts +6 -6
  122. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  123. package/dist/src/mcpl/inference-router.js.map +1 -1
  124. package/dist/src/mcpl/push-coalescer.d.ts +132 -22
  125. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  126. package/dist/src/mcpl/push-coalescer.js +105 -15
  127. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  128. package/dist/src/mcpl/push-handler.d.ts +9 -7
  129. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  130. package/dist/src/mcpl/push-handler.js.map +1 -1
  131. package/dist/src/mcpl/server-connection.d.ts +13 -10
  132. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  133. package/dist/src/mcpl/server-connection.js +134 -56
  134. package/dist/src/mcpl/server-connection.js.map +1 -1
  135. package/dist/src/mcpl/tool-classes.d.ts.map +1 -1
  136. package/dist/src/mcpl/tool-classes.js +3 -0
  137. package/dist/src/mcpl/tool-classes.js.map +1 -1
  138. package/dist/src/mcpl/types.d.ts +8 -2
  139. package/dist/src/mcpl/types.d.ts.map +1 -1
  140. package/dist/src/mcpl/types.js.map +1 -1
  141. package/dist/src/module-registry.d.ts +24 -1
  142. package/dist/src/module-registry.d.ts.map +1 -1
  143. package/dist/src/module-registry.js +68 -18
  144. package/dist/src/module-registry.js.map +1 -1
  145. package/dist/src/modules/discord/index.d.ts +45 -8
  146. package/dist/src/modules/discord/index.d.ts.map +1 -1
  147. package/dist/src/modules/discord/index.js +237 -86
  148. package/dist/src/modules/discord/index.js.map +1 -1
  149. package/dist/src/modules/history/index.d.ts +59 -0
  150. package/dist/src/modules/history/index.d.ts.map +1 -1
  151. package/dist/src/modules/history/index.js +432 -67
  152. package/dist/src/modules/history/index.js.map +1 -1
  153. package/dist/src/modules/history/semantic.d.ts +6 -5
  154. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  155. package/dist/src/modules/history/semantic.js +15 -22
  156. package/dist/src/modules/history/semantic.js.map +1 -1
  157. package/dist/src/modules/workspace/disk-agreement.d.ts +1 -1
  158. package/dist/src/modules/workspace/disk-agreement.js +1 -1
  159. package/dist/src/modules/workspace/index.d.ts +28 -7
  160. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  161. package/dist/src/modules/workspace/index.js +76 -22
  162. package/dist/src/modules/workspace/index.js.map +1 -1
  163. package/dist/src/notice-tags.d.ts +10 -1
  164. package/dist/src/notice-tags.d.ts.map +1 -1
  165. package/dist/src/notice-tags.js +10 -1
  166. package/dist/src/notice-tags.js.map +1 -1
  167. package/dist/src/operator-log.d.ts +36 -3
  168. package/dist/src/operator-log.d.ts.map +1 -1
  169. package/dist/src/operator-log.js +2 -2
  170. package/dist/src/operator-log.js.map +1 -1
  171. package/dist/src/presentation.d.ts +746 -0
  172. package/dist/src/presentation.d.ts.map +1 -0
  173. package/dist/src/presentation.js +1435 -0
  174. package/dist/src/presentation.js.map +1 -0
  175. package/dist/src/prose-drafts.d.ts +15 -11
  176. package/dist/src/prose-drafts.d.ts.map +1 -1
  177. package/dist/src/prose-drafts.js +16 -12
  178. package/dist/src/prose-drafts.js.map +1 -1
  179. package/dist/src/read-marks.d.ts +192 -0
  180. package/dist/src/read-marks.d.ts.map +1 -0
  181. package/dist/src/read-marks.js +242 -0
  182. package/dist/src/read-marks.js.map +1 -0
  183. package/dist/src/recovery/offline-branch.d.ts +91 -6
  184. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  185. package/dist/src/recovery/offline-branch.js +273 -29
  186. package/dist/src/recovery/offline-branch.js.map +1 -1
  187. package/dist/src/recovery/recover-cli.js +22 -3
  188. package/dist/src/recovery/recover-cli.js.map +1 -1
  189. package/dist/src/send-tools.d.ts +5 -9
  190. package/dist/src/send-tools.d.ts.map +1 -1
  191. package/dist/src/send-tools.js +40 -7
  192. package/dist/src/send-tools.js.map +1 -1
  193. package/dist/src/stored-injections.d.ts +2 -2
  194. package/dist/src/stored-injections.js +2 -2
  195. package/dist/src/stored-removal.d.ts +17 -4
  196. package/dist/src/stored-removal.d.ts.map +1 -1
  197. package/dist/src/stored-removal.js +29 -5
  198. package/dist/src/stored-removal.js.map +1 -1
  199. package/dist/src/tool-result-guard.d.ts +12 -1
  200. package/dist/src/tool-result-guard.d.ts.map +1 -1
  201. package/dist/src/tool-result-guard.js +42 -8
  202. package/dist/src/tool-result-guard.js.map +1 -1
  203. package/dist/src/tune-out/coordinator.d.ts +1159 -79
  204. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  205. package/dist/src/tune-out/coordinator.js +3709 -363
  206. package/dist/src/tune-out/coordinator.js.map +1 -1
  207. package/dist/src/tune-out/tools.d.ts +114 -17
  208. package/dist/src/tune-out/tools.d.ts.map +1 -1
  209. package/dist/src/tune-out/tools.js +87 -27
  210. package/dist/src/tune-out/tools.js.map +1 -1
  211. package/dist/src/tune-out/window-anchor.d.ts +143 -0
  212. package/dist/src/tune-out/window-anchor.d.ts.map +1 -0
  213. package/dist/src/tune-out/window-anchor.js +202 -0
  214. package/dist/src/tune-out/window-anchor.js.map +1 -0
  215. package/dist/src/types/agent.d.ts +82 -20
  216. package/dist/src/types/agent.d.ts.map +1 -1
  217. package/dist/src/types/events.d.ts +2 -0
  218. package/dist/src/types/events.d.ts.map +1 -1
  219. package/dist/src/types/framework.d.ts +32 -12
  220. package/dist/src/types/framework.d.ts.map +1 -1
  221. package/dist/src/types/module.d.ts +180 -69
  222. package/dist/src/types/module.d.ts.map +1 -1
  223. package/dist/src/types/trace.d.ts +510 -36
  224. package/dist/src/types/trace.d.ts.map +1 -1
  225. package/package.json +3 -3
  226. package/src/admission/admit.ts +32 -3
  227. package/src/agent.ts +323 -120
  228. package/src/api/mcp-server-core.ts +54 -17
  229. package/src/api/server.ts +4 -23
  230. package/src/code-execution/isolate/scripts.ts +28 -3
  231. package/src/config-checks.ts +14 -0
  232. package/src/context-manager-errors.ts +37 -0
  233. package/src/context-options.ts +96 -0
  234. package/src/deferred-import.ts +239 -0
  235. package/src/dendrite/audience.ts +315 -0
  236. package/src/dendrite/index.ts +14 -2
  237. package/src/dendrite/presets.ts +18 -6
  238. package/src/dendrite/registry.ts +209 -12
  239. package/src/dendrite/types.ts +92 -8
  240. package/src/foreign-rounds.ts +199 -0
  241. package/src/framework.ts +7804 -3546
  242. package/src/gate/event-gate.ts +428 -65
  243. package/src/gate/index.ts +3 -0
  244. package/src/gate/rule-scope.ts +45 -0
  245. package/src/gate/suppress-script-worker.ts +89 -0
  246. package/src/gate/suppress-scripts.ts +414 -0
  247. package/src/gate/suppression-review.ts +517 -0
  248. package/src/gate/suppression-stats.ts +314 -0
  249. package/src/gate/types.ts +141 -7
  250. package/src/gate/wake-onboarding.ts +309 -0
  251. package/src/held-writes.ts +49 -60
  252. package/src/index.ts +9 -2
  253. package/src/jsonrpc-envelope.ts +81 -0
  254. package/src/mcpl/channel-registry.ts +353 -85
  255. package/src/mcpl/checkpoint-manager.ts +3 -2
  256. package/src/mcpl/feature-set-manager.ts +2 -1
  257. package/src/mcpl/inbound-source.ts +2 -1
  258. package/src/mcpl/inference-router.ts +7 -4
  259. package/src/mcpl/push-coalescer.ts +193 -34
  260. package/src/mcpl/push-handler.ts +10 -5
  261. package/src/mcpl/server-connection.ts +141 -60
  262. package/src/mcpl/tool-classes.ts +3 -0
  263. package/src/mcpl/types.ts +8 -2
  264. package/src/module-registry.ts +73 -17
  265. package/src/modules/discord/index.ts +229 -81
  266. package/src/modules/history/index.ts +439 -70
  267. package/src/modules/history/semantic.ts +15 -21
  268. package/src/modules/workspace/disk-agreement.ts +1 -1
  269. package/src/modules/workspace/index.ts +85 -23
  270. package/src/notice-tags.ts +10 -1
  271. package/src/operator-log.ts +36 -3
  272. package/src/presentation.ts +1676 -0
  273. package/src/prose-drafts.ts +16 -12
  274. package/src/read-marks.ts +328 -0
  275. package/src/recovery/offline-branch.ts +346 -32
  276. package/src/recovery/recover-cli.ts +21 -3
  277. package/src/send-tools.ts +40 -7
  278. package/src/stored-injections.ts +2 -2
  279. package/src/stored-removal.ts +31 -7
  280. package/src/tool-result-guard.ts +41 -7
  281. package/src/tune-out/coordinator.ts +4089 -457
  282. package/src/tune-out/tools.ts +160 -43
  283. package/src/tune-out/window-anchor.ts +277 -0
  284. package/src/types/agent.ts +86 -20
  285. package/src/types/events.ts +2 -0
  286. package/src/types/framework.ts +32 -12
  287. package/src/types/module.ts +181 -68
  288. package/src/types/trace.ts +542 -40
package/dist/src/agent.js CHANGED
@@ -3,13 +3,16 @@ import { heartbeatToolAlias } from './heartbeat/heartbeat.js';
3
3
  import { isAbortedResponse } from '@animalabs/membrane';
4
4
  import { streamBounds } from './inference-bounds.js';
5
5
  import { ToolResultGuard } from './tool-result-guard.js';
6
+ import { storeOwnRow } from './dendrite/audience.js';
6
7
  import { withoutTokenEstimates } from './thinking-token-stamp.js';
7
8
  import { placeThinkingDrops } from './thinking-drops.js';
8
9
  import { carriedBlock } from './sent-rows.js';
10
+ import { foreignRowAsSent, transcribeForeignRounds } from './foreign-rounds.js';
9
11
  import { injectionsAsStored } from './text-as-stored.js';
10
12
  import { stableHash } from './stable-hash.js';
11
13
  import { hasRenderedContent, storedInjectionMarkOf } from './stored-injections.js';
12
- import { assertBooleanSetting, holdsSettings, kindOf } from './config-checks.js';
14
+ import { covers, markAtOrAfter, readMarkOf, storeHeadOf } from './read-marks.js';
15
+ import { assertBooleanSetting, assertOneOfSetting, holdsSettings, kindOf } from './config-checks.js';
13
16
  import { CONTINUE_ROW, continueTurn, indexRequestOnlyRows, renderRequestOnlyRows, silentHeartbeatSeparatorTurn, tickKey, toolLoopPrompt, } from './silent-heartbeat.js';
14
17
  import { randomUUID } from 'node:crypto';
15
18
  import { resolveClockConfig } from './clock-rows.js';
@@ -53,11 +56,13 @@ export function assertThinkingBinding(setting, value) {
53
56
  }
54
57
  /**
55
58
  * Refuse an agent config whose `promptCaching`, `toolResultGuard`,
56
- * `toolWrapperProseGuard`, `thinking.enabled`, `thinkingBinding.dropBlock`,
59
+ * `toolWrapperProseGuard`, `turnInputsPin`, `thinking.enabled`, `thinkingBinding.dropBlock`,
57
60
  * `thinkingBinding.binds` or `refusalHandling.autoRewind` holds anything but true or false
58
61
  * (assertBooleanSetting, where null counts as left out), or whose `thinking`, `thinkingBinding` or
59
62
  * `refusalHandling` is anything but an object, null or false (holdsSettings),
60
- * or whose `autoContinue` resolveAutoContinue refuses. The constructor runs it
63
+ * or whose `autoContinue` resolveAutoContinue refuses, or whose `observes`
64
+ * is anything but a list of names, or whose `foreignRounds` is neither of
65
+ * its modes (assertOneOfSetting). The constructor runs it
61
66
  * first, so the rule holds wherever an Agent is built. `create()` also runs it
62
67
  * for each of its agents before anything opens, and `createEphemeralAgent`
63
68
  * before it reserves the name, so a refusal there leaves nothing behind.
@@ -79,6 +84,15 @@ export function assertAgentSwitches(config) {
79
84
  'and false or leaving it out doesn\'t');
80
85
  assertBooleanSetting(`${agent} toolWrapperProseGuard`, config.toolWrapperProseGuard, 'true keeps a response whose whole prose is a tool-call-shaped wrapper from running or entering the agent\'s history, ' +
81
86
  'and false or leaving it out doesn\'t');
87
+ assertBooleanSetting(`${agent} turnInputsPin`, config.turnInputsPin, 'true or leaving it out pins the rows that open a turn raw until it ends, and false places no pin');
88
+ const observes = config.observes;
89
+ if (observes !== undefined && observes !== null
90
+ && (!Array.isArray(observes) || !observes.every((name) => typeof name === 'string'))) {
91
+ throw new Error(`${agent} observes must be a list of agent names, such as ["nova"], not ${Array.isArray(observes) ? 'a list holding something else' : kindOf(observes)}: ` +
92
+ 'each names another configured agent whose own rows this agent\'s window takes');
93
+ }
94
+ assertOneOfSetting(`${agent} foreignRounds`, config.foreignRounds, ['transcript', 'raw'], '\'transcript\' or leaving it out sends the rounds of an agent it observes as a line per call and result, ' +
95
+ 'without their thinking, and \'raw\' sends them as stored');
82
96
  resolveAutoContinue(config);
83
97
  }
84
98
  /** `AutoContinueConfig.maxConsecutive` when left out. */
@@ -116,6 +130,7 @@ export function resolveAutoContinue(config) {
116
130
  }
117
131
  return { maxConsecutive: max };
118
132
  }
133
+ /** A branch's key in Agent.unsentSince: its id and when it was created. */
119
134
  export function branchKey(branch) {
120
135
  return `${branch.id}\u0000${branch.created}`;
121
136
  }
@@ -153,6 +168,8 @@ export class Agent {
153
168
  toolResultGuard;
154
169
  /** Prose delivery mode (see AgentConfig.proseRouting). Default 'locus'. */
155
170
  proseRouting;
171
+ /** Locked mode's destination until the agent chooses one (see AgentConfig.proseLock). */
172
+ proseLock;
156
173
  /** Exact whole-response known-tool wrapper containment (default off). */
157
174
  toolWrapperProseGuard;
158
175
  /** Continuation after a turn the model ends itself (see
@@ -291,11 +308,13 @@ export class Agent {
291
308
  this.refusalHandling = config.refusalHandling;
292
309
  this.toolResultGuard = new ToolResultGuard(config.name, contextManager, config.toolResultGuard === true);
293
310
  this.proseRouting = config.proseRouting ?? 'locus';
311
+ this.proseLock = typeof config.proseLock === 'string' && config.proseLock.trim() ? config.proseLock.trim() : undefined;
294
312
  this.toolWrapperProseGuard = config.toolWrapperProseGuard === true;
295
313
  this.autoContinue = resolveAutoContinue(config);
296
314
  this.clock = resolveClockConfig(config.name, config.clock);
297
315
  this.cacheTtl = config.cacheTtl ?? '1h';
298
316
  this.promptCaching = config.promptCaching !== false;
317
+ this.pinsTurnInputs = config.turnInputsPin !== false;
299
318
  this.prefillUserMessage = config.prefillUserMessage;
300
319
  this.providerParams = config.providerParams;
301
320
  this.sameRoundThinkTextPolicy = config.sameRoundThinkTextPolicy;
@@ -368,6 +387,44 @@ export class Agent {
368
387
  isOwnParticipant(participant) {
369
388
  return this.ownParticipants.has(participant);
370
389
  }
390
+ /**
391
+ * How another agent's rounds go out in this agent's requests (#291, answer
392
+ * 13): `'raw'`, as stored, or `'transcript'` (foreign-rounds.ts), a line
393
+ * per call and per result and no thinking, the same in every compile and
394
+ * in what a tool boundary injects. The framework sets it, once the
395
+ * agent's window follows the presentation index, for the persistent
396
+ * subconscious, for a resident that observes another
397
+ * (AgentConfig.observes), as their configurations' `foreignRounds` say
398
+ * (`'transcript'` by default), and for an agent derived or forked from
399
+ * one of them, in that agent's mode (its inheritance holds them); every
400
+ * other agent reads no other agent's
401
+ * rounds, but for a co-resident's rows stored before audience stamps,
402
+ * which a window written down from the record keeps and which go out as
403
+ * stored ('raw'), as earlier releases sent them.
404
+ */
405
+ foreignRounds = 'raw';
406
+ /** Set how another agent's rounds go out in this agent's requests (see foreignRounds). */
407
+ setForeignRounds(mode) {
408
+ this.foreignRounds = mode;
409
+ }
410
+ /**
411
+ * A stored row as this agent's requests carry it, for a row a tool
412
+ * boundary injects: another participant's row as a transcript where this
413
+ * agent is sent other agents' rounds so (setForeignRounds), its own and
414
+ * every row otherwise as stored. An injected row holds no tool block (the
415
+ * boundary cuts at one), so what changes is its thinking.
416
+ */
417
+ injectedAsSent(participant, content) {
418
+ if (this.foreignRounds !== 'transcript' || this.isOwnParticipant(participant))
419
+ return content;
420
+ return foreignRowAsSent(content);
421
+ }
422
+ /** A compile's messages with other agents' rounds as this agent is sent them (setForeignRounds). */
423
+ foreignRoundsAsSent(messages) {
424
+ if (this.foreignRounds !== 'transcript')
425
+ return messages;
426
+ return transcribeForeignRounds(messages, (participant) => this.isOwnParticipant(participant));
427
+ }
371
428
  /**
372
429
  * Role assignment for a request: every participant that is this agent's
373
430
  * own voice — its name, and for a derived agent the agent it inherited
@@ -929,16 +986,28 @@ export class Agent {
929
986
  return true;
930
987
  }
931
988
  /**
932
- * RFC-006 consumed watermark, per branch: the newest stored message as of
933
- * the latest of the agent's creation, a committing compile that returns,
934
- * and a tool boundary that injected messages into a live stream declaring
935
- * it carries them (`supportsInjectedMessages` true: membrane's native
936
- * path, from membrane 0.6.0). A compile counts from when it takes its
937
- * value, before it awaits, so one that began before a boundary's mark
938
- * doesn't roll the mark back (applyCompileWatermark), and a dry run, such
939
- * as previewActivation's, doesn't move it. Each move takes the store's
940
- * head, a scalar, so it also covers stored messages the agent wasn't
941
- * given, such as another slot's.
989
+ * RFC-006 consumed watermark, per branch: how far the agent had read as of
990
+ * the latest of its creation, a committing compile that returns, and a
991
+ * tool boundary that injected messages into a live stream declaring it
992
+ * carries them (`supportsInjectedMessages` true: membrane's native path,
993
+ * from membrane 0.6.0). A compile counts from when it takes its mark,
994
+ * before it awaits, so one that began before a boundary's mark doesn't
995
+ * roll the mark back (applyCompileWatermark), and a dry run, such as
996
+ * previewActivation's, doesn't move it.
997
+ *
998
+ * It is a ReadMark (read-marks.ts), read only through `covers`. Once the
999
+ * agent's context presents rows (#291's presentation index, in presented
1000
+ * mode), it covers exactly the rows in the agent's window as of the mark:
1001
+ * a row stored then and not yet presented to the agent isn't covered.
1002
+ * While the context is in legacy mode, its window is the record, and the
1003
+ * mark covers every row stored on the branch by then, as it always did:
1004
+ * a prefix of the record, so it also covers stored messages the agent
1005
+ * wasn't given, such as another slot's. Once the window is written down
1006
+ * (an agent registered on a branch its window was never written down on
1007
+ * holds such a mark until its first compile), a mark taken in legacy mode
1008
+ * covers the rows its window held by the mark where they still stand, as
1009
+ * a mark taken in presented mode then would: a row stored after it, taken
1010
+ * out of the window since, or presented to the agent again, isn't.
942
1011
  *
943
1012
  * A message above it may still be replaced or withdrawn in place by its
944
1013
  * sender, though it may already have been in one of the agent's requests.
@@ -950,16 +1019,19 @@ export class Agent {
950
1019
  * compile that finishes can tell whether one was made while it ran. */
951
1020
  watermarkMarks = 0;
952
1021
  /**
953
- * The newest stored message a compile or a tool boundary may have put in
954
- * front of the agent, per branch. It moves where the consumed watermark
955
- * does, and sooner: when a committing compile takes its value, before it
956
- * awaits, and at every tool boundary that injects into its stream. A message above it may still
957
- * have been shown, though: for one, a live stream carries each round's own
958
- * content and results, stored at a boundary that injected nothing, into its
959
- * next request. A compile that throws assembled nothing, and gives its move
960
- * back where it can (unshowFailedCompile). A scalar counts a prefix, so a
961
- * message stored below it without having been shown counts as shown, which
962
- * errs toward a marker.
1022
+ * How far a compile or a tool boundary may have put the agent's context in
1023
+ * front of it, per branch. It moves where the consumed watermark does,
1024
+ * and sooner: when a committing compile takes its mark, before it awaits,
1025
+ * and at every tool boundary that injects into its stream. A message above
1026
+ * it may still have been shown, though: for one, a live stream carries each
1027
+ * round's own content and results, stored at a boundary that injected
1028
+ * nothing, into its next request. A compile that throws assembled nothing,
1029
+ * and gives its move back where it can (unshowFailedCompile). A mark taken
1030
+ * in legacy mode, read while the window is the record, counts a prefix of
1031
+ * the record, so a message stored below it without having been shown
1032
+ * counts as shown, which errs toward a marker; one taken in presented
1033
+ * mode, and one taken in legacy mode read once the window is written down,
1034
+ * cover the window as it stood.
963
1035
  */
964
1036
  shownWatermark = null;
965
1037
  getConsumedWatermark() {
@@ -987,14 +1059,18 @@ export class Agent {
987
1059
  if (watermark)
988
1060
  this.answeredWatermark = watermark;
989
1061
  }
1062
+ /** Whether a turn this agent opens pins its inputs (AgentConfig.turnInputsPin, on by default). */
1063
+ pinsTurnInputs;
990
1064
  /**
991
- * Keep the stored rows from `first` through `last` raw for the turn now
992
- * opening, with a raw pin under one name per agent. Any pin of that name
993
- * already held is removed first, one a crash left included. Under a
994
- * strategy without pins nothing is pinned. A committing compile that
995
- * refuses as over budget while a pin of that name is held removes it and
996
- * compiles once more, and `unpinTurnInputs` removes it. Returns the pin's
997
- * id, or undefined when nothing was pinned.
1065
+ * Keep the rows of the agent's window from `first` through `last` raw for
1066
+ * the turn now opening, with a raw pin under one name per agent: a
1067
+ * strategy reads a pin by its rows' positions in its message view, which
1068
+ * is the window, in its order (#291; in legacy mode the record). Any pin
1069
+ * of that name already held is removed first, one a crash left included.
1070
+ * Under a strategy without pins nothing is pinned. A committing compile
1071
+ * that refuses as over budget while a pin of that name is held removes it
1072
+ * and compiles once more, and `unpinTurnInputs` removes it. Returns the
1073
+ * pin's id, or undefined when nothing was pinned.
998
1074
  *
999
1075
  * @internal For the framework's turn starts; not a host API.
1000
1076
  */
@@ -1055,46 +1131,89 @@ export class Agent {
1055
1131
  * draft resend, or a send tool whose channel the framework records), on
1056
1132
  * the branch it was taken on. A wake that carries a channel, unless it's
1057
1133
  * marked ambient (InferenceRequest.ambient), keeps its turn unless the
1058
- * agent spoke there after reading the write the wake is for. It
1134
+ * agent spoke there after reading the row the wake is for. It
1059
1135
  * lives as long as this Agent: an agent made again starts it empty, and
1060
1136
  * such a wake then stays.
1061
1137
  */
1062
1138
  publishedThrough = new Map();
1063
1139
  /** Note a publish into `destination` (its key), made having read through
1064
1140
  * `readThrough`: the consumed watermark when its words were written, or
1065
- * its call made. */
1141
+ * its call made. A later mark on the same branch (markAtOrAfter: of two
1142
+ * at one head, the one whose window reached further) replaces an earlier
1143
+ * one; one on another branch replaces whatever was noted. */
1066
1144
  notePublished(destination, readThrough) {
1067
1145
  if (!readThrough)
1068
1146
  return;
1069
1147
  const noted = this.publishedThrough.get(destination);
1070
- if (noted && noted.branch === readThrough.branch && noted.sequence >= readThrough.sequence)
1148
+ if (noted && markAtOrAfter(noted, readThrough) === true)
1071
1149
  return;
1072
1150
  this.publishedThrough.set(destination, readThrough);
1073
1151
  }
1074
1152
  /** Whether the agent published into `destination` (its key) having read
1075
- * the row stored at `sequence` on `branch`. */
1076
- publishedAfterReading(destination, branch, sequence) {
1153
+ * `row`, as `cm` (the agent's context, where the row's place in its
1154
+ * window is read) says: the mark noted for the destination covers it. A
1155
+ * mark that can't say (one on another branch) says no. */
1156
+ publishedAfterReading(destination, row, cm) {
1077
1157
  const noted = this.publishedThrough.get(destination);
1078
- return !!noted && noted.branch === branch && noted.sequence >= sequence;
1158
+ return !!noted && covers(noted, cm, row) === 'covered';
1159
+ }
1160
+ /**
1161
+ * Every read mark this agent holds: its consumed, shown and answered
1162
+ * watermarks and the mark noted for each destination it published into,
1163
+ * each mark once (two of them are often the one mark). A redo on the
1164
+ * window (AgentFramework.redo) reads which of them covered the rows it
1165
+ * puts back, and gives those marks again (replaceReadMarks).
1166
+ */
1167
+ heldReadMarks() {
1168
+ const held = new Set();
1169
+ for (const mark of [this.consumedWatermark, this.shownWatermark, this.answeredWatermark, ...this.publishedThrough.values()]) {
1170
+ if (mark)
1171
+ held.add(mark);
1172
+ }
1173
+ return [...held];
1079
1174
  }
1080
- /** Mark everything currently stored as consumed (the agent's creation, at
1081
- * boot or later, and a tool boundary that injected messages into a live
1082
- * stream declaring it carries them; see consumedWatermark). */
1175
+ /**
1176
+ * Put each mark `replacements` maps in its place wherever this agent holds
1177
+ * it (heldReadMarks), so a mark held as two of them stays one: a redo on
1178
+ * the window (#291) puts rows back at new ordinals, past every mark that
1179
+ * covered them before their undo, and gives each such mark again where it
1180
+ * covers them now. It counts as a mark (watermarkMarks), so a compile that
1181
+ * began before it doesn't put its own older mark back over it.
1182
+ */
1183
+ replaceReadMarks(replacements) {
1184
+ const swap = (mark) => (mark && replacements.get(mark)) ?? mark;
1185
+ const consumed = swap(this.consumedWatermark);
1186
+ if (consumed !== this.consumedWatermark) {
1187
+ this.consumedWatermark = consumed;
1188
+ this.watermarkMarks++;
1189
+ }
1190
+ this.shownWatermark = swap(this.shownWatermark);
1191
+ this.answeredWatermark = swap(this.answeredWatermark);
1192
+ for (const [destination, mark] of this.publishedThrough) {
1193
+ const next = replacements.get(mark);
1194
+ if (next)
1195
+ this.publishedThrough.set(destination, next);
1196
+ }
1197
+ }
1198
+ /** Mark everything in the agent's window (in legacy mode, everything
1199
+ * stored) as consumed: the agent's creation, at boot or later, and a tool
1200
+ * boundary that injected messages into a live stream declaring it carries
1201
+ * them; see consumedWatermark. */
1083
1202
  markContextConsumed() {
1084
1203
  // Tolerates partial context-manager doubles (tests build Agents over
1085
1204
  // stubs). Without a watermark, a reader that looks for one takes its own
1086
1205
  // side: the coalescer counts the message as read, and the framework's
1087
- // unreadNoticesForPrimary counts it as unread. A wake for a deferred
1088
- // write or a stored message reads the answered watermark instead
1089
- // (deferredWriteDone, storedMessageDone).
1206
+ // releasedWindow counts it as unread. A wake for a row it reads
1207
+ // (InferenceRequest.readsRow) reads the answered watermark instead
1208
+ // (rowDone).
1090
1209
  this.consumedWatermark = this.pendingWatermark();
1091
1210
  this.watermarkMarks++;
1092
1211
  this.shownWatermark = this.consumedWatermark;
1093
1212
  }
1094
- /** Mark everything currently stored as possibly shown (a tool boundary
1095
- * that injected messages into its stream). Without
1096
- * a watermark the coalescer counts a message as shown, as it counts one
1097
- * read without a consumed watermark. */
1213
+ /** Mark everything in the agent's window (in legacy mode, everything
1214
+ * stored) as possibly shown (a tool boundary that injected messages into
1215
+ * its stream). Without a watermark the coalescer counts a message as
1216
+ * shown, as it counts one read without a consumed watermark. */
1098
1217
  markContextShown() {
1099
1218
  this.shownWatermark = this.pendingWatermark();
1100
1219
  }
@@ -1107,7 +1226,9 @@ export class Agent {
1107
1226
  * the second then throws, it restores the first's failed claim. Messages
1108
1227
  * up to that claim then count as shown, although no request held those
1109
1228
  * above the watermark the first compile found, which errs toward a marker
1110
- * until the next compile or boundary moves the watermark. */
1229
+ * until the next compile or boundary moves the watermark. Each mark is a
1230
+ * fresh object (readMarkOf), so the compare by identity is this compile's
1231
+ * own claim. */
1111
1232
  unshowFailedCompile(watermark, before) {
1112
1233
  if (watermark && this.shownWatermark === watermark)
1113
1234
  this.shownWatermark = before;
@@ -1119,52 +1240,42 @@ export class Agent {
1119
1240
  * mark's branch, so a boundary's mark is never rolled back by a compile
1120
1241
  * that started before it (a committing compile, such as compileContext's,
1121
1242
  * run during a live turn; a dry run, such as previewActivation's, never
1122
- * reaches here).
1243
+ * reaches here). Marks are ordered by markAtOrAfter: by the window's
1244
+ * index length where both keep one, else by the store's head, each of
1245
+ * which only grows on a branch.
1123
1246
  */
1124
1247
  applyCompileWatermark(watermark, marksBefore) {
1125
1248
  const current = this.consumedWatermark;
1126
- if (this.watermarkMarks !== marksBefore && current
1127
- && (current.branch !== watermark.branch || current.sequence >= watermark.sequence))
1249
+ if (this.watermarkMarks !== marksBefore && current && markAtOrAfter(current, watermark) !== false)
1128
1250
  return;
1129
1251
  this.consumedWatermark = watermark;
1130
1252
  this.watermarkMarks++;
1131
1253
  }
1132
1254
  /**
1133
- * The branch now (`branchKey`) and its head, as `pendingWatermark` reads it: a message stored on that branch later
1134
- * has a larger sequence. Sequences are numbered per branch, so one compares with another only on the same branch.
1255
+ * The branch now (`branchKey`) and the store's head on it (storeHeadOf, the
1256
+ * head a mark pendingWatermark takes keeps): a message stored on that
1257
+ * branch later has a larger sequence. Sequences are numbered per branch, so
1258
+ * one compares with another only on the same branch. A record sequence, not
1259
+ * a place in the agent's window (#291).
1135
1260
  */
1136
1261
  branchHead() {
1137
- const head = this.pendingWatermark();
1262
+ const sequence = storeHeadOf(this.contextManager);
1138
1263
  const cm = this.contextManager;
1139
- if (!head || typeof cm.currentBranchRef !== 'function')
1264
+ if (sequence === null || typeof cm.currentBranchRef !== 'function')
1140
1265
  return undefined;
1141
1266
  try {
1142
- return { branch: branchKey(cm.currentBranchRef()), sequence: head.sequence };
1267
+ return { branch: branchKey(cm.currentBranchRef()), sequence };
1143
1268
  }
1144
1269
  catch {
1145
1270
  return undefined;
1146
1271
  }
1147
1272
  }
1148
- /** The watermark a successful compile will establish (taken before, applied after). */
1273
+ /** The watermark a successful compile will establish (taken before, applied
1274
+ * after): where the agent's context stands now (readMarkOf), its window's
1275
+ * index length with the store's head once it presents rows. Null for a
1276
+ * context double that can't say. */
1149
1277
  pendingWatermark() {
1150
- const cm = this.contextManager;
1151
- try {
1152
- if (typeof cm.currentBranch !== 'function' || typeof cm.getAllMessages !== 'function')
1153
- return null;
1154
- // The chronicle head, not this slot's last message: a compile reads
1155
- // everything stored on the branch so far, including messages merged in
1156
- // from another slot (the subconscious reads the residents' shared slot).
1157
- const store = typeof cm.getStore === 'function' ? cm.getStore() : undefined;
1158
- let sequence = typeof store?.currentSequence === 'function' ? store.currentSequence() : undefined;
1159
- if (sequence === undefined) {
1160
- const count = typeof cm.getMessageCount === 'function' ? cm.getMessageCount() : cm.getAllMessages().length;
1161
- sequence = count > 0 ? cm.getAllMessages().at(-1)?.sequence ?? 0 : 0;
1162
- }
1163
- return { branch: cm.currentBranch().name, sequence };
1164
- }
1165
- catch {
1166
- return null;
1167
- }
1278
+ return readMarkOf(this.contextManager);
1168
1279
  }
1169
1280
  /** A committing compile, as for a request that is sent: the context
1170
1281
  * manager commits what it commits for one, the consumed watermark moves,
@@ -1233,9 +1344,8 @@ export class Agent {
1233
1344
  /**
1234
1345
  * A host's hook, called with each committing compile's `thinkingStrip` (never a dry run's) and the key of the
1235
1346
  * branch it read (`branchKey`), as the compile returns, whether or not its request is then sent, since the
1236
- * context manager's binding record takes the strip either way. One that throws is logged. The framework sets it
1237
- * at the agent's first stream unless a host has set one, so a host's own observer stands in for the framework's,
1238
- * whose `[reasoning]` line for the agent then isn't told.
1347
+ * context manager's binding record takes the strip either way. One that throws is logged. The framework sets none
1348
+ * of its own, and tells the agent nothing of a strip.
1239
1349
  */
1240
1350
  onThinkingStrip;
1241
1351
  /**
@@ -1248,8 +1358,16 @@ export class Agent {
1248
1358
  * start and the next (a host's own committing compile, or the compression
1249
1359
  * an over-budget retry waits for) can summarize them all the same: the
1250
1360
  * next request then has the summary's word for them, and the start after
1251
- * it stores them again, as after any fold. The window is read back 64
1252
- * rows at a time from the newest, stopping at that point.
1361
+ * it stores them again, as after any fold. The slot's record is read
1362
+ * back 64 rows at a time from the newest, stopping at that point.
1363
+ *
1364
+ * It reads the record, by sequence, not the agent's window, and that
1365
+ * holds once the context presents rows (#291): the rows it counts are
1366
+ * this agent's own stored injections, its own rows, which enter its
1367
+ * window as they are written, so one stored after the point is in no
1368
+ * request yet whatever else has been stored or presented since. Another
1369
+ * agent's rows, stored into a shared slot at once rather than queued, are
1370
+ * passed over, whatever they are.
1253
1371
  */
1254
1372
  unsentInjection(namespace) {
1255
1373
  let newest;
@@ -1272,6 +1390,10 @@ export class Agent {
1272
1390
  const mark = storedInjectionMarkOf(row.metadata);
1273
1391
  if (mark?.agent !== this.name || mark.namespace !== namespace)
1274
1392
  continue;
1393
+ // A copy an undo took out of the window (#291) is in no window
1394
+ // now, so it isn't the copy the agent will read.
1395
+ if (this.contextManager.windowMode?.() === 'presented' && this.contextManager.windowStatusOf(row.id) === 'undone')
1396
+ continue;
1275
1397
  // Read from the newest back, the first copy met is the newest
1276
1398
  // content; its other parts pool with it.
1277
1399
  newest ??= { contentHash: mark.contentHash, parts: mark.parts, held: new Set() };
@@ -1345,13 +1467,9 @@ export class Agent {
1345
1467
  const held = body.complete || (body.missing !== undefined && !body.missing.includes('shards'));
1346
1468
  const contents = byNamespace.get(mark.namespace) ?? new Map();
1347
1469
  byNamespace.set(mark.namespace, contents);
1348
- // Copies of the same content in view pool what they hold: the agent
1349
- // has each part that one of them holds.
1350
- const known = contents.get(mark.contentHash) ?? { parts: mark.parts, held: new Set(), sequence: body.sequence };
1351
- if (held)
1352
- known.held.add(mark.part);
1353
- known.sequence = Math.max(known.sequence, body.sequence);
1354
- contents.set(mark.contentHash, known);
1470
+ const copies = contents.get(mark.contentHash) ?? [];
1471
+ copies.push({ id: body.messageId, part: mark.part, parts: mark.parts, held, sequence: body.sequence });
1472
+ contents.set(mark.contentHash, copies);
1355
1473
  }
1356
1474
  }
1357
1475
  this.renderedInjections = { branch: provenance.branch, byNamespace };
@@ -1360,9 +1478,13 @@ export class Agent {
1360
1478
  * The newest content of `namespace` among this agent's stored injections
1361
1479
  * that the last compile built to send rendered, by its newest copy: its
1362
1480
  * content hash, and whether every part of that content was there in some
1363
- * copy, every shard, however the strategy shaped it. Undefined when none
1364
- * was, when this agent hasn't built a request since it started, or when
1365
- * the window's branch has changed since.
1481
+ * copy, every shard, however the strategy shaped it. Copies of the same
1482
+ * content pool what they hold: the agent has each part one of them holds.
1483
+ * A copy the agent's next request won't hold is passed over: one an undo
1484
+ * took out of its window since (#291: `'undone'`, which no presentation
1485
+ * point presents again until a redo), and one no longer stored. Undefined
1486
+ * when no copy is left, when this agent hasn't built a request since it
1487
+ * started, or when the window's branch has changed since.
1366
1488
  */
1367
1489
  renderedInjection(namespace) {
1368
1490
  const rendered = this.renderedInjections;
@@ -1370,11 +1492,38 @@ export class Agent {
1370
1492
  if (!rendered || rendered.branch.id !== branch.id || rendered.branch.created !== branch.created)
1371
1493
  return undefined;
1372
1494
  let newest;
1373
- for (const entry of rendered.byNamespace.get(namespace) ?? []) {
1374
- if (!newest || entry[1].sequence > newest[1].sequence)
1375
- newest = entry;
1495
+ for (const [contentHash, copies] of rendered.byNamespace.get(namespace) ?? []) {
1496
+ let pooled;
1497
+ for (const copy of copies) {
1498
+ if (!this.renderedCopyStands(copy.id))
1499
+ continue;
1500
+ pooled ??= { parts: copy.parts, held: new Set(), sequence: copy.sequence };
1501
+ if (copy.held)
1502
+ pooled.held.add(copy.part);
1503
+ pooled.sequence = Math.max(pooled.sequence, copy.sequence);
1504
+ }
1505
+ if (pooled && (!newest || pooled.sequence > newest.sequence))
1506
+ newest = { contentHash, ...pooled };
1507
+ }
1508
+ return newest ? { contentHash: newest.contentHash, whole: newest.held.size === newest.parts } : undefined;
1509
+ }
1510
+ /**
1511
+ * Whether a stored injection's copy the last compile rendered is still
1512
+ * where the agent's next request reads it: stored, and not taken out of
1513
+ * its window by an undo (#291). A copy out of the window otherwise
1514
+ * (`'out'`, as a redo leaves one presented since its undo) is presented
1515
+ * again at the agent's next point, its own rows' sweep, so it counts. A
1516
+ * context that can't say (a double without windowStatusOf, a read that
1517
+ * throws) counts it, as before the window was presented.
1518
+ */
1519
+ renderedCopyStands(id) {
1520
+ try {
1521
+ const status = this.contextManager.windowStatusOf?.(id);
1522
+ return status !== 'undone' && status !== 'absent';
1523
+ }
1524
+ catch {
1525
+ return true;
1376
1526
  }
1377
- return newest ? { contentHash: newest[0], whole: newest[1].held.size === newest[1].parts } : undefined;
1378
1527
  }
1379
1528
  /**
1380
1529
  * Whether compiled message `i` of `result` is a row of this agent's stored
@@ -1523,7 +1672,7 @@ export class Agent {
1523
1672
  const { systemInjections } = compiled;
1524
1673
  // The framework's own pricing stamp never goes out (thinking-token-stamp.ts);
1525
1674
  // the agent's own turns are then presented under its name (presentOwnTurns).
1526
- const messages = this.presentOwnTurns(withoutTokenEstimates(compiled.messages));
1675
+ const messages = this.presentOwnTurns(this.foreignRoundsAsSent(withoutTokenEstimates(compiled.messages)));
1527
1676
  // Read once, after the first compile, since results may have become
1528
1677
  // ready while it ran; the refusal retry, assembled while the agent is
1529
1678
  // inferring, sends the same ones.
@@ -1741,6 +1890,8 @@ export class Agent {
1741
1890
  // compression path.)
1742
1891
  // The same pass a tool boundary applies to what it notes as sent
1743
1892
  // (sent-rows.ts), so the two can't drift.
1893
+ // Another agent's rounds go out as this agent is sent them (setForeignRounds).
1894
+ messages = this.foreignRoundsAsSent(messages);
1744
1895
  messages = messages
1745
1896
  .map((m) => ({ ...m, content: m.content.filter(carriedBlock) }))
1746
1897
  .filter((m) => m.content.length > 0);
@@ -1897,17 +2048,23 @@ export class Agent {
1897
2048
  async buildActivationRequest(availableTools, injections, budget, compressionTools = availableTools, options = {}) {
1898
2049
  return (await this.assembleActivationRequest(availableTools, injections, budget, compressionTools, options)).request;
1899
2050
  }
1900
- /** Stored rows that follow a request-only turn, memoized on the store's
1901
- * cached message array (ContextManager returns the same array until the
1902
- * store changes). */
2051
+ /** Stored rows that follow a request-only turn, memoized on the window's
2052
+ * cached row array (ContextManager returns the same array until the
2053
+ * window changes): the rows a compile sends are the window's (#291), and
2054
+ * a write another agent stores, which the window doesn't take, leaves the
2055
+ * memo as it was. A context without a window reads the record, the same
2056
+ * array as the window's for a single slot that is still the record. */
1903
2057
  requestOnlyIndex = null;
1904
2058
  indexRequestOnlyRows() {
1905
2059
  const empty = { ticks: new Map(), prompts: new Map() };
1906
2060
  const cm = this.contextManager;
1907
- if (typeof cm.getAllMessages !== 'function')
2061
+ const read = typeof cm.getPresentedMessages === 'function' ? () => cm.getPresentedMessages()
2062
+ : typeof cm.getAllMessages === 'function' ? () => cm.getAllMessages()
2063
+ : undefined;
2064
+ if (!read)
1908
2065
  return empty;
1909
2066
  try {
1910
- const stored = cm.getAllMessages();
2067
+ const stored = read();
1911
2068
  if (this.requestOnlyIndex?.source === stored)
1912
2069
  return this.requestOnlyIndex.index;
1913
2070
  const index = indexRequestOnlyRows(stored, this.ownParticipants);
@@ -2099,7 +2256,9 @@ export class Agent {
2099
2256
  `output. See the refusal/inference-failed record for why.`);
2100
2257
  return undefined;
2101
2258
  }
2102
- return this.contextManager.addMessage(this.name, content, metadata);
2259
+ // The agent's own round, stamped as its own (#291's audience stamp); its
2260
+ // id is the stream's last reply for the thinking binding (noteStreamEnd).
2261
+ return storeOwnRow(this, this.name, content, metadata);
2103
2262
  }
2104
2263
  /**
2105
2264
  * Transition back to streaming state after tool results are provided.
@@ -2200,6 +2359,24 @@ export class Agent {
2200
2359
  getContextManager() {
2201
2360
  return this.contextManager;
2202
2361
  }
2362
+ /** Where this agent tells of its own rows once they are stored (setOwnRowSink). */
2363
+ ownRowSink;
2364
+ /**
2365
+ * Install where this agent tells of its own rows once they are stored
2366
+ * (its rounds and the rows the framework writes for it through
2367
+ * storeOwnRow, and its tool results through its guard), or take it off
2368
+ * with undefined. The presentation index (#291) installs one when it takes
2369
+ * the agent on, and presents each row in the agent's window as it is
2370
+ * told. With none, as for an agent nothing took on, nothing is told.
2371
+ */
2372
+ setOwnRowSink(sink) {
2373
+ this.ownRowSink = sink;
2374
+ this.toolResultGuard.setOwnRowSink(sink);
2375
+ }
2376
+ /** Tell the sink of own rows just stored (storeOwnRow calls it, once each add has returned). */
2377
+ ownRowsStored(ids) {
2378
+ this.ownRowSink?.(ids);
2379
+ }
2203
2380
  /**
2204
2381
  * Build the effective system prompt, appending any system-position
2205
2382
  * injections, their blocks joined by line breaks. The system prompt is
@@ -2280,9 +2457,9 @@ export class Agent {
2280
2457
  this.toolResultGuard.recovering = false;
2281
2458
  const content = guardedRefusal ? [] : response.content;
2282
2459
  const { toolCalls, speechContent } = this.extractToolCallsAndSpeech(content);
2283
- // Add assistant response to context
2460
+ // Add assistant response to context, as the agent's own row
2284
2461
  if (!guardedRefusal)
2285
- this.contextManager.addMessage(this.name, content);
2462
+ storeOwnRow(this, this.name, content);
2286
2463
  return {
2287
2464
  toolCalls,
2288
2465
  speechContent,