@animalabs/agent-framework 0.31.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.
- package/README.md +204 -14
- package/dist/src/admission/admit.d.ts +18 -0
- package/dist/src/admission/admit.d.ts.map +1 -1
- package/dist/src/admission/admit.js +16 -3
- package/dist/src/admission/admit.js.map +1 -1
- package/dist/src/agent.d.ts +185 -78
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +279 -102
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/mcp-server-core.d.ts.map +1 -1
- package/dist/src/api/mcp-server-core.js +50 -12
- package/dist/src/api/mcp-server-core.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +4 -20
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/code-execution/isolate/scripts.d.ts +12 -8
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
- package/dist/src/code-execution/isolate/scripts.js +24 -0
- package/dist/src/code-execution/isolate/scripts.js.map +1 -1
- package/dist/src/config-checks.d.ts +7 -0
- package/dist/src/config-checks.d.ts.map +1 -1
- package/dist/src/config-checks.js +14 -0
- package/dist/src/config-checks.js.map +1 -1
- package/dist/src/context-manager-errors.d.ts +25 -0
- package/dist/src/context-manager-errors.d.ts.map +1 -0
- package/dist/src/context-manager-errors.js +31 -0
- package/dist/src/context-manager-errors.js.map +1 -0
- package/dist/src/context-options.d.ts +67 -0
- package/dist/src/context-options.d.ts.map +1 -0
- package/dist/src/context-options.js +85 -0
- package/dist/src/context-options.js.map +1 -0
- package/dist/src/deferred-import.d.ts +93 -0
- package/dist/src/deferred-import.d.ts.map +1 -0
- package/dist/src/deferred-import.js +177 -0
- package/dist/src/deferred-import.js.map +1 -0
- package/dist/src/dendrite/audience.d.ts +223 -0
- package/dist/src/dendrite/audience.d.ts.map +1 -0
- package/dist/src/dendrite/audience.js +202 -0
- package/dist/src/dendrite/audience.js.map +1 -0
- package/dist/src/dendrite/index.d.ts +5 -3
- package/dist/src/dendrite/index.d.ts.map +1 -1
- package/dist/src/dendrite/index.js +2 -1
- package/dist/src/dendrite/index.js.map +1 -1
- package/dist/src/dendrite/presets.d.ts +10 -5
- package/dist/src/dendrite/presets.d.ts.map +1 -1
- package/dist/src/dendrite/presets.js +17 -5
- package/dist/src/dendrite/presets.js.map +1 -1
- package/dist/src/dendrite/registry.d.ts +62 -7
- package/dist/src/dendrite/registry.d.ts.map +1 -1
- package/dist/src/dendrite/registry.js +179 -10
- package/dist/src/dendrite/registry.js.map +1 -1
- package/dist/src/dendrite/types.d.ts +91 -8
- package/dist/src/dendrite/types.d.ts.map +1 -1
- package/dist/src/foreign-rounds.d.ts +69 -0
- package/dist/src/foreign-rounds.d.ts.map +1 -0
- package/dist/src/foreign-rounds.js +152 -0
- package/dist/src/foreign-rounds.js.map +1 -0
- package/dist/src/framework.d.ts +1977 -820
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +7571 -3457
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +85 -15
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +421 -47
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/gate/index.d.ts +1 -1
- package/dist/src/gate/index.d.ts.map +1 -1
- package/dist/src/gate/index.js.map +1 -1
- package/dist/src/gate/rule-scope.d.ts +30 -0
- package/dist/src/gate/rule-scope.d.ts.map +1 -0
- package/dist/src/gate/rule-scope.js +41 -0
- package/dist/src/gate/rule-scope.js.map +1 -0
- package/dist/src/gate/suppress-script-worker.d.ts +2 -0
- package/dist/src/gate/suppress-script-worker.d.ts.map +1 -0
- package/dist/src/gate/suppress-script-worker.js +103 -0
- package/dist/src/gate/suppress-script-worker.js.map +1 -0
- package/dist/src/gate/suppress-scripts.d.ts +105 -0
- package/dist/src/gate/suppress-scripts.d.ts.map +1 -0
- package/dist/src/gate/suppress-scripts.js +403 -0
- package/dist/src/gate/suppress-scripts.js.map +1 -0
- package/dist/src/gate/suppression-review.d.ts +143 -0
- package/dist/src/gate/suppression-review.d.ts.map +1 -0
- package/dist/src/gate/suppression-review.js +463 -0
- package/dist/src/gate/suppression-review.js.map +1 -0
- package/dist/src/gate/suppression-stats.d.ts +125 -0
- package/dist/src/gate/suppression-stats.d.ts.map +1 -0
- package/dist/src/gate/suppression-stats.js +214 -0
- package/dist/src/gate/suppression-stats.js.map +1 -0
- package/dist/src/gate/types.d.ts +135 -7
- package/dist/src/gate/types.d.ts.map +1 -1
- package/dist/src/gate/wake-onboarding.d.ts +119 -0
- package/dist/src/gate/wake-onboarding.d.ts.map +1 -0
- package/dist/src/gate/wake-onboarding.js +277 -0
- package/dist/src/gate/wake-onboarding.js.map +1 -0
- package/dist/src/held-writes.d.ts +31 -23
- package/dist/src/held-writes.d.ts.map +1 -1
- package/dist/src/held-writes.js +44 -59
- package/dist/src/held-writes.js.map +1 -1
- package/dist/src/index.d.ts +5 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/jsonrpc-envelope.d.ts +69 -0
- package/dist/src/jsonrpc-envelope.d.ts.map +1 -0
- package/dist/src/jsonrpc-envelope.js +66 -0
- package/dist/src/jsonrpc-envelope.js.map +1 -0
- package/dist/src/mcpl/channel-registry.d.ts +131 -15
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +290 -46
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.d.ts +2 -4
- package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
- package/dist/src/mcpl/feature-set-manager.d.ts +2 -4
- package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
- package/dist/src/mcpl/feature-set-manager.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +2 -1
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +2 -1
- package/dist/src/mcpl/inbound-source.js.map +1 -1
- package/dist/src/mcpl/inference-router.d.ts +6 -6
- package/dist/src/mcpl/inference-router.d.ts.map +1 -1
- package/dist/src/mcpl/inference-router.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +132 -22
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +105 -15
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts +9 -7
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +13 -10
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +134 -56
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/tool-classes.d.ts.map +1 -1
- package/dist/src/mcpl/tool-classes.js +3 -0
- package/dist/src/mcpl/tool-classes.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +8 -2
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/module-registry.d.ts +24 -1
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +68 -18
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts +45 -8
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +237 -86
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/history/index.d.ts +59 -0
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +432 -67
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/history/semantic.d.ts +6 -5
- package/dist/src/modules/history/semantic.d.ts.map +1 -1
- package/dist/src/modules/history/semantic.js +15 -22
- package/dist/src/modules/history/semantic.js.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.d.ts +1 -1
- package/dist/src/modules/workspace/disk-agreement.js +1 -1
- package/dist/src/modules/workspace/index.d.ts +28 -7
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +76 -22
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/notice-tags.d.ts +10 -1
- package/dist/src/notice-tags.d.ts.map +1 -1
- package/dist/src/notice-tags.js +10 -1
- package/dist/src/notice-tags.js.map +1 -1
- package/dist/src/operator-log.d.ts +36 -3
- package/dist/src/operator-log.d.ts.map +1 -1
- package/dist/src/operator-log.js +2 -2
- package/dist/src/operator-log.js.map +1 -1
- package/dist/src/presentation.d.ts +746 -0
- package/dist/src/presentation.d.ts.map +1 -0
- package/dist/src/presentation.js +1435 -0
- package/dist/src/presentation.js.map +1 -0
- package/dist/src/prose-drafts.d.ts +15 -11
- package/dist/src/prose-drafts.d.ts.map +1 -1
- package/dist/src/prose-drafts.js +16 -12
- package/dist/src/prose-drafts.js.map +1 -1
- package/dist/src/read-marks.d.ts +192 -0
- package/dist/src/read-marks.d.ts.map +1 -0
- package/dist/src/read-marks.js +242 -0
- package/dist/src/read-marks.js.map +1 -0
- package/dist/src/recovery/offline-branch.d.ts +91 -6
- package/dist/src/recovery/offline-branch.d.ts.map +1 -1
- package/dist/src/recovery/offline-branch.js +273 -29
- package/dist/src/recovery/offline-branch.js.map +1 -1
- package/dist/src/recovery/recover-cli.js +22 -3
- package/dist/src/recovery/recover-cli.js.map +1 -1
- package/dist/src/send-tools.d.ts +5 -9
- package/dist/src/send-tools.d.ts.map +1 -1
- package/dist/src/send-tools.js +40 -7
- package/dist/src/send-tools.js.map +1 -1
- package/dist/src/stored-injections.d.ts +2 -2
- package/dist/src/stored-injections.js +2 -2
- package/dist/src/stored-removal.d.ts +17 -4
- package/dist/src/stored-removal.d.ts.map +1 -1
- package/dist/src/stored-removal.js +29 -5
- package/dist/src/stored-removal.js.map +1 -1
- package/dist/src/tool-result-guard.d.ts +12 -1
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +42 -8
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +1159 -79
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +3709 -363
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/tune-out/tools.d.ts +114 -17
- package/dist/src/tune-out/tools.d.ts.map +1 -1
- package/dist/src/tune-out/tools.js +87 -27
- package/dist/src/tune-out/tools.js.map +1 -1
- package/dist/src/tune-out/window-anchor.d.ts +143 -0
- package/dist/src/tune-out/window-anchor.d.ts.map +1 -0
- package/dist/src/tune-out/window-anchor.js +202 -0
- package/dist/src/tune-out/window-anchor.js.map +1 -0
- package/dist/src/types/agent.d.ts +86 -31
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +2 -0
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +43 -21
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +180 -69
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +510 -36
- package/dist/src/types/trace.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/admission/admit.ts +32 -3
- package/src/agent.ts +323 -120
- package/src/api/mcp-server-core.ts +54 -17
- package/src/api/server.ts +4 -23
- package/src/code-execution/isolate/scripts.ts +28 -3
- package/src/config-checks.ts +14 -0
- package/src/context-manager-errors.ts +37 -0
- package/src/context-options.ts +96 -0
- package/src/deferred-import.ts +239 -0
- package/src/dendrite/audience.ts +315 -0
- package/src/dendrite/index.ts +14 -2
- package/src/dendrite/presets.ts +18 -6
- package/src/dendrite/registry.ts +209 -12
- package/src/dendrite/types.ts +92 -8
- package/src/foreign-rounds.ts +199 -0
- package/src/framework.ts +7814 -3585
- package/src/gate/event-gate.ts +428 -65
- package/src/gate/index.ts +3 -0
- package/src/gate/rule-scope.ts +45 -0
- package/src/gate/suppress-script-worker.ts +89 -0
- package/src/gate/suppress-scripts.ts +414 -0
- package/src/gate/suppression-review.ts +517 -0
- package/src/gate/suppression-stats.ts +314 -0
- package/src/gate/types.ts +141 -7
- package/src/gate/wake-onboarding.ts +309 -0
- package/src/held-writes.ts +49 -60
- package/src/index.ts +9 -2
- package/src/jsonrpc-envelope.ts +81 -0
- package/src/mcpl/channel-registry.ts +353 -85
- package/src/mcpl/checkpoint-manager.ts +3 -2
- package/src/mcpl/feature-set-manager.ts +2 -1
- package/src/mcpl/inbound-source.ts +2 -1
- package/src/mcpl/inference-router.ts +7 -4
- package/src/mcpl/push-coalescer.ts +193 -34
- package/src/mcpl/push-handler.ts +10 -5
- package/src/mcpl/server-connection.ts +141 -60
- package/src/mcpl/tool-classes.ts +3 -0
- package/src/mcpl/types.ts +8 -2
- package/src/module-registry.ts +73 -17
- package/src/modules/discord/index.ts +229 -81
- package/src/modules/history/index.ts +439 -70
- package/src/modules/history/semantic.ts +15 -21
- package/src/modules/workspace/disk-agreement.ts +1 -1
- package/src/modules/workspace/index.ts +85 -23
- package/src/notice-tags.ts +10 -1
- package/src/operator-log.ts +36 -3
- package/src/presentation.ts +1676 -0
- package/src/prose-drafts.ts +16 -12
- package/src/read-marks.ts +328 -0
- package/src/recovery/offline-branch.ts +346 -32
- package/src/recovery/recover-cli.ts +21 -3
- package/src/send-tools.ts +40 -7
- package/src/stored-injections.ts +2 -2
- package/src/stored-removal.ts +31 -7
- package/src/tool-result-guard.ts +41 -7
- package/src/tune-out/coordinator.ts +4089 -457
- package/src/tune-out/tools.ts +160 -43
- package/src/tune-out/window-anchor.ts +277 -0
- package/src/types/agent.ts +90 -31
- package/src/types/events.ts +2 -0
- package/src/types/framework.ts +43 -21
- package/src/types/module.ts +181 -68
- package/src/types/trace.ts +542 -40
- package/dist/src/reasoning-loss-notice.d.ts +0 -23
- package/dist/src/reasoning-loss-notice.d.ts.map +0 -1
- package/dist/src/reasoning-loss-notice.js +0 -52
- package/dist/src/reasoning-loss-notice.js.map +0 -1
- package/dist/src/reasoning-loss.d.ts +0 -24
- package/dist/src/reasoning-loss.d.ts.map +0 -1
- package/dist/src/reasoning-loss.js +0 -102
- package/dist/src/reasoning-loss.js.map +0 -1
- package/src/reasoning-loss-notice.ts +0 -64
- package/src/reasoning-loss.ts +0 -120
package/src/prose-drafts.ts
CHANGED
|
@@ -11,12 +11,14 @@
|
|
|
11
11
|
* the exact words until the resident resends or dismisses them, or the
|
|
12
12
|
* retention below lets it go.
|
|
13
13
|
*
|
|
14
|
-
* The boundary is publication and agency
|
|
14
|
+
* The boundary is publication and agency: a draft is never
|
|
15
15
|
* published except by its resident's explicit resend (or `{{unsent}}`), and
|
|
16
16
|
* only that resident can list or act on it. Its notices go into the
|
|
17
|
-
* resident's own history
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* resident's own history: residents that share one message slot store
|
|
18
|
+
* them in that slot, but each is stamped as its resident's: the drafts
|
|
19
|
+
* notice as its own row, which enters no other resident's window but an
|
|
20
|
+
* observer's (AgentConfig.observes), as the assistant turn the words came
|
|
21
|
+
* from does, and a bounce notice as for that resident alone.
|
|
20
22
|
*
|
|
21
23
|
* Durability is outside the conversation. Drafts live in a RecordJournal of
|
|
22
24
|
* typed Chronicle records, which do not follow branch switches: undo,
|
|
@@ -24,8 +26,10 @@
|
|
|
24
26
|
* in a turn that is later undone stays usable (the words were genuinely
|
|
25
27
|
* written and held back), and a delivered draft stays delivered. The
|
|
26
28
|
* notices that name a draft are conversation, so they do follow the branch: a draft counts as
|
|
27
|
-
* named while a message naming it is on the current branch
|
|
28
|
-
*
|
|
29
|
+
* named while a message naming it is on the current branch and, on a
|
|
30
|
+
* presented window, not taken out of it by an undo; one a rollback or
|
|
31
|
+
* branch move has left unnamed, or whose notice an undo took out of the
|
|
32
|
+
* window, is named again.
|
|
29
33
|
*
|
|
30
34
|
* Drafts are kept, not hoarded. Each resident's KEEP_NEWEST newest drafts
|
|
31
35
|
* are always kept; an older one, in any state, is let go at the journal's
|
|
@@ -405,13 +409,13 @@ export class ProseDraftStore {
|
|
|
405
409
|
}
|
|
406
410
|
|
|
407
411
|
/**
|
|
408
|
-
* Open drafts, newest first, that no notice
|
|
409
|
-
*
|
|
410
|
-
*
|
|
411
|
-
* message, by id,
|
|
412
|
+
* Open drafts, newest first, that no standing notice names: none was
|
|
413
|
+
* recorded (a crash before the notice), or a rollback, a branch move or an
|
|
414
|
+
* undo took away every message that named them. `stands` says whether a
|
|
415
|
+
* message, by id, still names them to the agent.
|
|
412
416
|
*/
|
|
413
|
-
unnoticed(agent: string,
|
|
414
|
-
return this.open(agent).filter((d) => !d.noticedIn?.some(
|
|
417
|
+
unnoticed(agent: string, stands: (messageId: string) => boolean): Draft[] {
|
|
418
|
+
return this.open(agent).filter((d) => !d.noticedIn?.some(stands));
|
|
415
419
|
}
|
|
416
420
|
|
|
417
421
|
/**
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read marks (#291): how far an agent had read, or been shown, or answered,
|
|
3
|
+
* when something happened, and whether a stored row falls within it.
|
|
4
|
+
*
|
|
5
|
+
* Every such question used to compare a row's own store sequence with the
|
|
6
|
+
* chronicle head taken at the moment (`{ branch, sequence }`). While the
|
|
7
|
+
* window an agent reads is the record itself (context-manager's legacy
|
|
8
|
+
* mode) that is exact: a compile reads every row stored so far that its
|
|
9
|
+
* view keeps (a row its view leaves out it never read, and each reader of a
|
|
10
|
+
* row is weighed by its own view, agentSees). Once the
|
|
11
|
+
* agent's window follows its presentation index (`presentRows`), a row is
|
|
12
|
+
* stored first and presented later, so a row stored before the head was
|
|
13
|
+
* taken can still be out of the window then, and the head says nothing of
|
|
14
|
+
* what the agent was shown; a mark is taken at a request, which carries the
|
|
15
|
+
* window as it then stands. The window's own coordinate is the index ordinal: a
|
|
16
|
+
* row is in the window as of a mark when its ordinal is below the index
|
|
17
|
+
* length taken with the mark (`indexLength()` is exclusive: the ordinal the
|
|
18
|
+
* next row will take).
|
|
19
|
+
*
|
|
20
|
+
* A mark keeps both: the head, as before, and the index length when the
|
|
21
|
+
* manager was in presented mode. A mark taken in legacy mode stands for a
|
|
22
|
+
* window that was the record up to its head. Read against a manager still
|
|
23
|
+
* in legacy mode, it covers by sequence. Read once the branch's window is
|
|
24
|
+
* written down (presented mode), it covers the rows the window has held,
|
|
25
|
+
* where they stand now, since its head or before: the rows a branch cut at
|
|
26
|
+
* the head would keep in its window (ContextManager.branchSequenceOf at or
|
|
27
|
+
* below the head). That sequence is a row's own for a row the write-down put
|
|
28
|
+
* in the window, and the write that presented it for any other, so it only
|
|
29
|
+
* grows along the window: the rows a cut at the head keeps are the window's
|
|
30
|
+
* first ones, and the mark reads as one taken in presented mode whose length
|
|
31
|
+
* is the ordinal of the first row past them (windowLengthAt). For a mark taken
|
|
32
|
+
* before the write-down, which lists the record in record order, those are
|
|
33
|
+
* the rows the write-down put in the window at or below the head that are
|
|
34
|
+
* still where it put them. A row stored after the head isn't covered, and
|
|
35
|
+
* neither is a row taken out of the window since, or one presented again,
|
|
36
|
+
* at a new ordinal past the write-down, which a compare by sequence would
|
|
37
|
+
* cover: a reader walking the window back from its newest row (the turn's
|
|
38
|
+
* inputs, turnInputs) would stop at that older row and leave the rows the
|
|
39
|
+
* agent hadn't read before it out. Nothing is converted in place: every
|
|
40
|
+
* reader reads a mark through coverTest, which makes the same reading for
|
|
41
|
+
* each.
|
|
42
|
+
*
|
|
43
|
+
* The mark is opaque: its fields are keyed by symbols this module keeps, so
|
|
44
|
+
* a `mark.sequence` read or a hand-built `{ branch, sequence }` doesn't
|
|
45
|
+
* compile. Every compare goes through `covers` (or `coverTest` for many
|
|
46
|
+
* rows) and `markAtOrAfter`. The keys are symbols rather than `#private`
|
|
47
|
+
* fields so two marks taken at the same place are deep-equal.
|
|
48
|
+
*/
|
|
49
|
+
import type { ContextManager, StoredMessage } from '@animalabs/context-manager';
|
|
50
|
+
|
|
51
|
+
declare const ordinalBrand: unique symbol;
|
|
52
|
+
/** A row's index ordinal in one agent's window on one branch (ContextManager.ordinalOf). Never a store sequence. */
|
|
53
|
+
export type WindowOrdinal = number & { readonly [ordinalBrand]: true };
|
|
54
|
+
|
|
55
|
+
declare const lengthBrand: unique symbol;
|
|
56
|
+
/** An index length (ContextManager.indexLength): exclusive, the ordinal the next presented row will take. */
|
|
57
|
+
export type WindowLength = number & { readonly [lengthBrand]: true };
|
|
58
|
+
|
|
59
|
+
declare const headBrand: unique symbol;
|
|
60
|
+
/** The store's head sequence (currentSequence) when a mark was taken. */
|
|
61
|
+
export type StoreHead = number & { readonly [headBrand]: true };
|
|
62
|
+
|
|
63
|
+
const HEAD: unique symbol = Symbol('read-mark head');
|
|
64
|
+
const LENGTH: unique symbol = Symbol('read-mark length');
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Where an agent had read to on one branch: the store's head then, and the
|
|
68
|
+
* window's index length when the agent's manager was in presented mode (null
|
|
69
|
+
* in legacy mode). Read only through this module (coverTest): a mark taken in
|
|
70
|
+
* legacy mode covers by sequence while its window is the record, and, once
|
|
71
|
+
* the window is written down, as a mark taken in presented mode that covers
|
|
72
|
+
* the rows the window held by its head where they still stand.
|
|
73
|
+
*/
|
|
74
|
+
export interface ReadMark {
|
|
75
|
+
readonly branch: string;
|
|
76
|
+
readonly [HEAD]: StoreHead;
|
|
77
|
+
readonly [LENGTH]: WindowLength | null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Whether a mark covers a row: `'covered'` and `'not-covered'` are answers;
|
|
82
|
+
* `'doubt'` is a mark that can't say (none, one on another branch, or one
|
|
83
|
+
* taken in presented mode read against a manager that no longer presents),
|
|
84
|
+
* which each reader maps to the choice it makes when it doesn't know.
|
|
85
|
+
*/
|
|
86
|
+
export type Cover = 'covered' | 'not-covered' | 'doubt';
|
|
87
|
+
|
|
88
|
+
/** What a mark is taken from and read against: a context manager, or a double of one. */
|
|
89
|
+
export type MarkCm = Partial<Pick<ContextManager,
|
|
90
|
+
'currentBranch' | 'getStore' | 'getAllMessages' | 'getMessageCount' | 'windowMode' | 'indexLength' | 'ordinalOf'
|
|
91
|
+
| 'getPresentedMessages' | 'branchSequenceOf'>>;
|
|
92
|
+
|
|
93
|
+
/** A row as a cover reads it. */
|
|
94
|
+
export type MarkedRow = Pick<StoredMessage, 'id' | 'sequence'>;
|
|
95
|
+
|
|
96
|
+
function mark(branch: string, head: number, length: number | null): ReadMark {
|
|
97
|
+
return Object.freeze({ branch, [HEAD]: head as StoreHead, [LENGTH]: length as WindowLength | null });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* A mark of where `cm` stands now: its branch, the store's head (the
|
|
102
|
+
* chronicle head, not the slot's last row: in legacy mode a compile reads
|
|
103
|
+
* everything stored on the branch that its view keeps, rows merged in from
|
|
104
|
+
* another slot included; a double without a store gives its last row's
|
|
105
|
+
* sequence), and
|
|
106
|
+
* its index length when it is in presented mode, where a compile reads the
|
|
107
|
+
* window and the mark covers by that length, not by the head. Null for a
|
|
108
|
+
* double that can't say, or when reading throws.
|
|
109
|
+
*/
|
|
110
|
+
export function readMarkOf(cm: MarkCm): ReadMark | null {
|
|
111
|
+
try {
|
|
112
|
+
const head = storeHeadOf(cm);
|
|
113
|
+
if (head === null) return null;
|
|
114
|
+
const presented = typeof cm.windowMode === 'function' && cm.windowMode() === 'presented'
|
|
115
|
+
&& typeof cm.indexLength === 'function';
|
|
116
|
+
return mark(cm.currentBranch!().name, head, presented ? cm.indexLength!() : null);
|
|
117
|
+
} catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The store's head as `cm` reads it now, the head a mark readMarkOf takes
|
|
124
|
+
* keeps: the chronicle head, not the slot's last message, since in legacy
|
|
125
|
+
* mode a compile reads everything stored on the branch so far, rows merged
|
|
126
|
+
* in from another slot included (in presented mode it reads the window,
|
|
127
|
+
* which a mark covers by its index length). A record sequence, on the
|
|
128
|
+
* branch `cm` is on: for a reader
|
|
129
|
+
* that compares stored rows' sequences with it on that branch (Agent's
|
|
130
|
+
* branchHead), not a cover of the window. Null for a context double that
|
|
131
|
+
* can't say.
|
|
132
|
+
*/
|
|
133
|
+
export function storeHeadOf(cm: MarkCm): number | null {
|
|
134
|
+
try {
|
|
135
|
+
if (typeof cm.currentBranch !== 'function' || typeof cm.getAllMessages !== 'function') return null;
|
|
136
|
+
const store = typeof cm.getStore === 'function' ? cm.getStore() as { currentSequence?: () => number } : undefined;
|
|
137
|
+
let head = typeof store?.currentSequence === 'function' ? store.currentSequence() : undefined;
|
|
138
|
+
if (head === undefined) {
|
|
139
|
+
const count = typeof cm.getMessageCount === 'function' ? cm.getMessageCount() : cm.getAllMessages().length;
|
|
140
|
+
head = count > 0 ? cm.getAllMessages().at(-1)?.sequence ?? 0 : 0;
|
|
141
|
+
}
|
|
142
|
+
return head;
|
|
143
|
+
} catch {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* A mark of where `cm` stands now, as readMarkOf takes one, that covers its
|
|
150
|
+
* window only below `length` (an index length of that window, at most its
|
|
151
|
+
* own): for a redo on the window (AgentFramework.redo), which puts back,
|
|
152
|
+
* at new ordinals and in their order, rows a mark covered before they were
|
|
153
|
+
* undone and rows it didn't, so the mark it gives again covers the first
|
|
154
|
+
* and not the rest. Null where readMarkOf gives null, and in legacy mode,
|
|
155
|
+
* where a mark has no length.
|
|
156
|
+
*/
|
|
157
|
+
export function readMarkThrough(cm: MarkCm, length: number): ReadMark | null {
|
|
158
|
+
const now = readMarkOf(cm);
|
|
159
|
+
if (!now || now[LENGTH] === null) return null;
|
|
160
|
+
return mark(now.branch, now[HEAD], Math.min(length, now[LENGTH]));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Whether a mark was taken in presented mode: it keeps the window's index
|
|
165
|
+
* length, and covers rows by their ordinals there, so a row taken out of the
|
|
166
|
+
* window and presented again, at a new ordinal past its length, leaves it.
|
|
167
|
+
* A mark taken in legacy mode keeps none: it covers by sequence while its
|
|
168
|
+
* window is the record, and, once the window is written down, by ordinal
|
|
169
|
+
* too, below the first row the window didn't hold by its head (coverTest),
|
|
170
|
+
* so a row presented again after it leaves it in the same way.
|
|
171
|
+
*/
|
|
172
|
+
export function coversByOrdinal(mark: ReadMark | null): boolean {
|
|
173
|
+
return !!mark && mark[LENGTH] !== null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* A test of many rows against one mark, read against `reader` (the manager
|
|
178
|
+
* whose window the mark is of), which reads the reader's branch and mode
|
|
179
|
+
* once. The rules:
|
|
180
|
+
*
|
|
181
|
+
* - no mark: doubt;
|
|
182
|
+
* - a mark on another branch than the reader's: doubt, except that a mark
|
|
183
|
+
* taken in legacy mode, read `across` a branch point (`partAt`, the last
|
|
184
|
+
* sequence the two branches share), reads as one on the reader's branch
|
|
185
|
+
* (below) through the lower of its head and the branch point;
|
|
186
|
+
* - a mark taken in legacy mode, read against a reader in legacy mode: a
|
|
187
|
+
* row at or below its head is covered;
|
|
188
|
+
* - a mark taken in legacy mode, read against a reader in presented mode:
|
|
189
|
+
* a row the window has held where it stands since the head or before is
|
|
190
|
+
* covered (windowLengthAt: the window's rows below the ordinal of its first
|
|
191
|
+
* row a branch cut at the head wouldn't keep), and no other: not a row
|
|
192
|
+
* stored after the head, out of the window, or presented after the head,
|
|
193
|
+
* again or for the first time. A reader that can't say where its window
|
|
194
|
+
* held a row (a double without ordinalOf, getPresentedMessages,
|
|
195
|
+
* branchSequenceOf or indexLength) is read by sequence, as in legacy
|
|
196
|
+
* mode; a read of the window that throws is doubt for the rows at or
|
|
197
|
+
* below the head;
|
|
198
|
+
* - a mark taken in presented mode, read against a reader no longer in it:
|
|
199
|
+
* doubt;
|
|
200
|
+
* - else a row is covered when its ordinal is below the mark's length:
|
|
201
|
+
* strictly, since the length is the ordinal the next row would take. A row
|
|
202
|
+
* out of the window (never presented, or taken out) is not covered.
|
|
203
|
+
*/
|
|
204
|
+
export function coverTest(mark: ReadMark | null, reader: MarkCm, across?: { partAt: number }): (row: MarkedRow) => Cover {
|
|
205
|
+
if (!mark) return () => 'doubt';
|
|
206
|
+
let branch: string | undefined;
|
|
207
|
+
let presented = false;
|
|
208
|
+
try {
|
|
209
|
+
branch = typeof reader.currentBranch === 'function' ? reader.currentBranch().name : undefined;
|
|
210
|
+
presented = typeof reader.windowMode === 'function' && reader.windowMode() === 'presented';
|
|
211
|
+
} catch {
|
|
212
|
+
return () => 'doubt';
|
|
213
|
+
}
|
|
214
|
+
const head = mark[HEAD];
|
|
215
|
+
const length = mark[LENGTH];
|
|
216
|
+
if (branch !== mark.branch) {
|
|
217
|
+
if (!across || length !== null) return () => 'doubt';
|
|
218
|
+
return legacyCover(reader, presented, Math.min(head, across.partAt));
|
|
219
|
+
}
|
|
220
|
+
if (length === null) return legacyCover(reader, presented, head);
|
|
221
|
+
if (!presented || typeof reader.ordinalOf !== 'function') return () => 'doubt';
|
|
222
|
+
return byOrdinal(reader.ordinalOf.bind(reader), length);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function byOrdinal(ordinalOf: (id: MarkedRow['id']) => number | undefined, length: number): (row: MarkedRow) => Cover {
|
|
226
|
+
return (row) => {
|
|
227
|
+
const ordinal = ordinalOf(row.id);
|
|
228
|
+
return ordinal !== undefined && ordinal < length ? 'covered' : 'not-covered';
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* How a mark taken in legacy mode covers through `through` (its head, or the
|
|
234
|
+
* lower of its head and a branch point): by sequence against a reader in
|
|
235
|
+
* legacy mode, or one that can't say where its window held a row; against
|
|
236
|
+
* one in presented mode, by ordinal below windowLengthAt(reader, through),
|
|
237
|
+
* read once, at the first row that needs it. A row stored after `through`
|
|
238
|
+
* entered the window after it, wherever it stands, so it is not covered
|
|
239
|
+
* without that read.
|
|
240
|
+
*/
|
|
241
|
+
function legacyCover(reader: MarkCm, presented: boolean, through: number): (row: MarkedRow) => Cover {
|
|
242
|
+
const bySequence = (row: MarkedRow): Cover => (row.sequence <= through ? 'covered' : 'not-covered');
|
|
243
|
+
if (!presented || typeof reader.ordinalOf !== 'function' || typeof reader.getPresentedMessages !== 'function'
|
|
244
|
+
|| typeof reader.branchSequenceOf !== 'function' || typeof reader.indexLength !== 'function') {
|
|
245
|
+
return bySequence;
|
|
246
|
+
}
|
|
247
|
+
let cover: ((row: MarkedRow) => Cover) | undefined;
|
|
248
|
+
return (row) => {
|
|
249
|
+
if (row.sequence > through) return 'not-covered';
|
|
250
|
+
if (!cover) {
|
|
251
|
+
const length = windowLengthAt(reader, through);
|
|
252
|
+
cover = length === null ? () => 'doubt' : byOrdinal(reader.ordinalOf!.bind(reader), length);
|
|
253
|
+
}
|
|
254
|
+
return cover(row);
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* The index length a mark taken in presented mode would hold to cover the
|
|
260
|
+
* rows `reader`'s window (in presented mode) has held, where they stand
|
|
261
|
+
* now, since sequence `through` or before: the ordinal of the window's first
|
|
262
|
+
* row that a branch cut at `through` wouldn't keep in its window, or the
|
|
263
|
+
* index length when such a cut keeps them all. A cut keeps a row when its
|
|
264
|
+
* branchSequenceOf (the sequence a cut has to reach for its window to hold
|
|
265
|
+
* the row) is at or below `through`: a row's own sequence (its body's last
|
|
266
|
+
* shard's) for a row the write-down put in the window, which lists the
|
|
267
|
+
* record in record order, and the write that presented it for any other,
|
|
268
|
+
* which comes after the write-down and after every write that presented a
|
|
269
|
+
* row before it. So that sequence only grows along the window, and the
|
|
270
|
+
* first row past `through` is found by a binary search over it: a few reads
|
|
271
|
+
* per mark, whatever the window's length. Null when a read throws.
|
|
272
|
+
*/
|
|
273
|
+
function windowLengthAt(reader: MarkCm, through: number): number | null {
|
|
274
|
+
try {
|
|
275
|
+
const window = reader.getPresentedMessages!();
|
|
276
|
+
let low = 0;
|
|
277
|
+
let high = window.length;
|
|
278
|
+
while (low < high) {
|
|
279
|
+
const middle = (low + high) >>> 1;
|
|
280
|
+
if (reader.branchSequenceOf!(window[middle]!.id) <= through) low = middle + 1;
|
|
281
|
+
else high = middle;
|
|
282
|
+
}
|
|
283
|
+
if (low === window.length) return reader.indexLength!();
|
|
284
|
+
return reader.ordinalOf!(window[low]!.id) ?? null;
|
|
285
|
+
} catch {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** Whether `mark` covers `row` in `reader`'s window (see coverTest for the rules). */
|
|
291
|
+
export function covers(mark: ReadMark | null, reader: MarkCm, row: MarkedRow, across?: { partAt: number }): Cover {
|
|
292
|
+
return coverTest(mark, reader, across)(row);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Whether mark `a` was taken at or after mark `b`: on one branch, by the
|
|
297
|
+
* window's index length when both keep one, which only grows there and
|
|
298
|
+
* grows at every presentation, and by the store's head, which only grows
|
|
299
|
+
* there too, where the lengths are equal or either mark keeps none;
|
|
300
|
+
* `'other-branch'` when they are on two. Two marks at one head can keep two
|
|
301
|
+
* lengths: a mark readMarkThrough gives (a redo's) covers less of the window
|
|
302
|
+
* than one taken at the same head, and a double without a store reads its
|
|
303
|
+
* head from its last row, which no presentation moves. The one with the
|
|
304
|
+
* greater length is the later: a publish noted with it (Agent.notePublished)
|
|
305
|
+
* is credited with the rows presented between.
|
|
306
|
+
*/
|
|
307
|
+
export function markAtOrAfter(a: ReadMark, b: ReadMark): boolean | 'other-branch' {
|
|
308
|
+
if (a.branch !== b.branch) return 'other-branch';
|
|
309
|
+
const [aLength, bLength] = [a[LENGTH], b[LENGTH]];
|
|
310
|
+
if (aLength !== null && bLength !== null && aLength !== bLength) return aLength > bLength;
|
|
311
|
+
return a[HEAD] >= b[HEAD];
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** A mark for a log line or a test's message: `main@412` in legacy mode, `main@412#57` with its index length. */
|
|
315
|
+
export function describeReadMark(mark: ReadMark | null): string {
|
|
316
|
+
if (!mark) return 'no mark';
|
|
317
|
+
return `${mark.branch}@${mark[HEAD]}${mark[LENGTH] === null ? '' : `#${mark[LENGTH]}`}`;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* A mark built from its parts, for a test that needs one taken at a given
|
|
322
|
+
* place. Production code takes marks with readMarkOf.
|
|
323
|
+
*
|
|
324
|
+
* @internal
|
|
325
|
+
*/
|
|
326
|
+
export function readMarkForTest(branch: string, head: number, length: number | null): ReadMark {
|
|
327
|
+
return mark(branch, head, length);
|
|
328
|
+
}
|