@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.
- 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 +1976 -818
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +7566 -3422
- 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 +82 -20
- 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 +32 -12
- 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 +7804 -3546
- 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 +86 -20
- package/src/types/events.ts +2 -0
- package/src/types/framework.ts +32 -12
- package/src/types/module.ts +181 -68
- package/src/types/trace.ts +542 -40
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The audience stamp (#291): who a stored row is for, written on the row
|
|
3
|
+
* when it is stored, in its metadata.
|
|
4
|
+
*
|
|
5
|
+
* A row's target used to live only in the write that stored it: the
|
|
6
|
+
* `forAgent` option, or which agent's context manager a writer called. In
|
|
7
|
+
* the residents' shared slot, rows meant for different agents then look
|
|
8
|
+
* alike in the store, and nothing read later can tell whose a row is. #291's
|
|
9
|
+
* presentation index decides from the row which agents it is presented to,
|
|
10
|
+
* and at boot which rows an agent has to be presented that it wasn't, so the
|
|
11
|
+
* framework now writes that on every row it stores:
|
|
12
|
+
*
|
|
13
|
+
* - `metadata.audience` lists the agents the row is meant for, computed when
|
|
14
|
+
* it is written: the agent a write names (`forAgent`); for an admitted
|
|
15
|
+
* inbound message, the recipients admission delivered it to; for a
|
|
16
|
+
* module's process response whose inference request names agents, those
|
|
17
|
+
* of them registered that read the slot it lands in. A write that names
|
|
18
|
+
* no agent (a module's write, a process response that asks every agent
|
|
19
|
+
* or none to read, or only agents that don't read that slot) is for the
|
|
20
|
+
* agents that take untargeted inbound and own the slot it lands in: on a
|
|
21
|
+
* residents' host every resident, as each reads the shared slot; with one
|
|
22
|
+
* resident that resident alone, as before. It falls back to the agent the
|
|
23
|
+
* write is delivered to when there are none.
|
|
24
|
+
* This is the rule #291's presentation index presents an untargeted row
|
|
25
|
+
* in the shared slot by, applied when the row is written, so the record
|
|
26
|
+
* tells an untargeted row from one written for the primary. A message a
|
|
27
|
+
* tune-out holds is meant for none of them, so its list is empty, unless
|
|
28
|
+
* the write names an agent whose own view keeps held traffic (the
|
|
29
|
+
* persistent subconscious), which it is for.
|
|
30
|
+
* Observers of a slot (the subconscious watching the residents' slot) are
|
|
31
|
+
* a relationship in the registry, not part of the list. An inbound
|
|
32
|
+
* message's target is stamped as named even where it doesn't read the
|
|
33
|
+
* slot the row lands in (a worker or a conversation fork, stored in the
|
|
34
|
+
* residents' slot): how such a row is presented is left to the
|
|
35
|
+
* presentation index. A process response's messages and the gate's
|
|
36
|
+
* batched line are stamped for the agents they name that read that slot,
|
|
37
|
+
* and as a write that names no agent when none of them does, so they
|
|
38
|
+
* reach the windows that read the slot, as on main. The wake-onboarding
|
|
39
|
+
* notice is stamped for its recipients that read that slot; one that
|
|
40
|
+
* doesn't (a conversation fork) gets its own copy where it reads, stamped
|
|
41
|
+
* for it, and the notice for an event with no recipients is for the
|
|
42
|
+
* agents that take untargeted inbound.
|
|
43
|
+
* - `metadata.ownRowOf` names the agent whose own row it is: one stored by
|
|
44
|
+
* that agent's turn or act (its rounds, its tool results, a puppeted
|
|
45
|
+
* call), or by the framework for that agent's own turn (a clock row, a
|
|
46
|
+
* `[continue]` row, a batched wake's line, a notice about its own speech
|
|
47
|
+
* or failure, a derived agent's inheritance and framing). Its audience is
|
|
48
|
+
* that agent alone. "Own" goes by who stored the row, never by its
|
|
49
|
+
* participant: a shared fork presents its parent's name as its own voice,
|
|
50
|
+
* but mail its parent sends it is the parent's, meant for the fork, and
|
|
51
|
+
* isn't the fork's own row.
|
|
52
|
+
*
|
|
53
|
+
* Both keys are the framework's. A write through the framework's
|
|
54
|
+
* `addMessage` is stamped there and a stamp its metadata carried (a copy of
|
|
55
|
+
* a stored row's, say) is replaced, as `deferredWriteId` is, but on an
|
|
56
|
+
* imported write, which keeps the stamp it was queued with. The compile
|
|
57
|
+
* (context-manager's) doesn't read the stamp, so a window compiles as the
|
|
58
|
+
* same rows unstamped do; the presentation index does, so another
|
|
59
|
+
* resident's own rows no longer enter a resident's window unless it
|
|
60
|
+
* observes that resident (AgentConfig.observes). Rows stored before the
|
|
61
|
+
* stamp existed carry none; `audienceOf` says so by returning undefined. A
|
|
62
|
+
* write an earlier version left in its deferred queue is stamped when the
|
|
63
|
+
* importer stores it at boot, as any write through `addMessage` is, unless
|
|
64
|
+
* it was queued stamped, so it isn't stored unstamped after the upgrade.
|
|
65
|
+
*/
|
|
66
|
+
import type { ContentBlock } from '@animalabs/membrane';
|
|
67
|
+
import type { AddMessageOptions, ContextManager, MessageId, MessageMetadata } from '@animalabs/context-manager';
|
|
68
|
+
import { WriteLandedError, WriteOutcomeUnknownError } from '../context-manager-errors.js';
|
|
69
|
+
import { suppressionRecordOf } from '../gate/suppression-stats.js';
|
|
70
|
+
import { isAnotherAgentsInjection } from '../stored-injections.js';
|
|
71
|
+
import type { AgentName, ObserveEdge } from './types.js';
|
|
72
|
+
|
|
73
|
+
/** The metadata key listing who a row is for. */
|
|
74
|
+
export const AUDIENCE_KEY = 'audience';
|
|
75
|
+
/** The metadata key naming whose own row a row is. */
|
|
76
|
+
export const OWN_ROW_KEY = 'ownRowOf';
|
|
77
|
+
|
|
78
|
+
/** A row's audience stamp, as `audienceOf` reads it. */
|
|
79
|
+
export interface AudienceStamp {
|
|
80
|
+
/** The agents the row is meant for, as computed when it was written. */
|
|
81
|
+
audience: AgentName[];
|
|
82
|
+
/** Set when the row is that agent's own (see the module comment). */
|
|
83
|
+
ownRowOf?: AgentName;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* `metadata` stamped as a row meant for `audience`, and as nobody's own
|
|
88
|
+
* row: a stamp it carried is replaced. A new object; `metadata` is unchanged.
|
|
89
|
+
*/
|
|
90
|
+
export function withAudience(metadata: MessageMetadata | undefined, audience: readonly AgentName[]): MessageMetadata {
|
|
91
|
+
const { [OWN_ROW_KEY]: _replaced, ...rest } = (metadata ?? {}) as MessageMetadata;
|
|
92
|
+
return { ...rest, [AUDIENCE_KEY]: [...audience] } as MessageMetadata;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* `metadata` stamped as `owner`'s own row, meant for `owner` alone: a stamp
|
|
97
|
+
* it carried is replaced. A new object; `metadata` is unchanged.
|
|
98
|
+
*/
|
|
99
|
+
export function asOwnRow(metadata: MessageMetadata | undefined, owner: AgentName): MessageMetadata {
|
|
100
|
+
return { ...(metadata ?? {}), [AUDIENCE_KEY]: [owner], [OWN_ROW_KEY]: owner } as MessageMetadata;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The audience stamp a row's metadata carries, or undefined when it carries
|
|
105
|
+
* none (a row stored before the stamp existed) or carries one that isn't a
|
|
106
|
+
* list of names.
|
|
107
|
+
*/
|
|
108
|
+
export function audienceOf(metadata: unknown): AudienceStamp | undefined {
|
|
109
|
+
if (!metadata || typeof metadata !== 'object') return undefined;
|
|
110
|
+
const audience = (metadata as Record<string, unknown>)[AUDIENCE_KEY];
|
|
111
|
+
if (!Array.isArray(audience) || !audience.every((name) => typeof name === 'string')) return undefined;
|
|
112
|
+
const own = (metadata as Record<string, unknown>)[OWN_ROW_KEY];
|
|
113
|
+
return { audience: [...audience], ...(typeof own === 'string' ? { ownRowOf: own } : {}) };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Whether a row's metadata stamps it as `agent`'s own row. */
|
|
117
|
+
export function isOwnRowOf(metadata: unknown, agent: AgentName): boolean {
|
|
118
|
+
return audienceOf(metadata)?.ownRowOf === agent;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* The admission record on a stored message: it was held from the residents
|
|
123
|
+
* by a policy epoch (`metadata.tuneOut = { epochId }`). ONE predicate for
|
|
124
|
+
* "held from the resident", read by the compiled-view filter, the mid-turn
|
|
125
|
+
* injection and the presentation index (#291) alike (#232 H1), so the window
|
|
126
|
+
* and the wire agree. Such a row is stamped for nobody (an empty audience),
|
|
127
|
+
* whatever store it lands in, unless its write names an agent whose own
|
|
128
|
+
* view keeps held traffic, such as the persistent subconscious, which it is
|
|
129
|
+
* for.
|
|
130
|
+
*/
|
|
131
|
+
export const heldFromResidents = (metadata: Record<string, unknown> | undefined): boolean =>
|
|
132
|
+
!!(metadata as { tuneOut?: unknown } | undefined)?.tuneOut;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The suppression record on a stored message: a suppress rule took it as it
|
|
136
|
+
* arrived (`metadata.suppressed = { rule, eventType }`, stamped by addMessage
|
|
137
|
+
* from the gate's suppressionFor). ONE predicate for "never rendered", read
|
|
138
|
+
* by every view filter the framework sets (the residents', the
|
|
139
|
+
* subconscious's, and through them every derived view's, context-options.ts)
|
|
140
|
+
* and so by agentSees too: the compile, a tool boundary's injection and the
|
|
141
|
+
* arrival and unread checks agree. The presentation index (#291) presents
|
|
142
|
+
* such a row to nobody (bearingOf, observedRowFor), the reader of held
|
|
143
|
+
* traffic included, and addMessage stamps it for nobody (an empty
|
|
144
|
+
* audience). The stamp never changes, so the view stays deterministic per
|
|
145
|
+
* row, as context-manager's viewFilter requires.
|
|
146
|
+
*/
|
|
147
|
+
export const suppressedRow = (metadata: Record<string, unknown> | undefined): boolean =>
|
|
148
|
+
suppressionRecordOf(metadata) !== undefined;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Whether a row of a slot an agent observes is for that agent (#291,
|
|
152
|
+
* decision 1): what an observe edge shows of the slot it reads. `observer`
|
|
153
|
+
* is the agent the edge is on, and `owners` are the agents whose own slot it
|
|
154
|
+
* reads (the registry's `slotOwners`).
|
|
155
|
+
*
|
|
156
|
+
* - Another agent's stored context injection: no. It is that agent's
|
|
157
|
+
* context, not conversation, as every view of the framework's leaves out.
|
|
158
|
+
* - A row stored under the observer's own name: no. It is the observer's
|
|
159
|
+
* delivery into the slot (the subconscious's summary or note into the
|
|
160
|
+
* residents' slot), which its own round already holds.
|
|
161
|
+
* - A row a suppress rule hid (suppressedRow): no. It renders for no
|
|
162
|
+
* reader, the reader of held traffic included.
|
|
163
|
+
* - A row a tune-out holds: only through an edge that shows held traffic
|
|
164
|
+
* (`includeHeld`, the subconscious's).
|
|
165
|
+
* - A row with no audience stamp (stored before the stamp, or by a host's
|
|
166
|
+
* writer that doesn't stamp): yes, as the merged view showed it.
|
|
167
|
+
* - An owner's own row (its rounds, results, clock rows, notices about its
|
|
168
|
+
* own turn), and a row whose audience names an owner (channel traffic,
|
|
169
|
+
* mail, module rows): yes.
|
|
170
|
+
* - A row whose audience names the observer itself, and that is nobody's
|
|
171
|
+
* own row (an operator's message or a module's write addressed to the
|
|
172
|
+
* subconscious alone, which lands in the residents' slot it watches):
|
|
173
|
+
* yes. The edge is how the observer reads that slot, and the merged view
|
|
174
|
+
* showed the row before the presentation index, so no window would hold
|
|
175
|
+
* it otherwise (#291).
|
|
176
|
+
* - Anything else, such as the own row of an agent that doesn't own the
|
|
177
|
+
* slot (the observer's own included), a row stamped only for an agent
|
|
178
|
+
* that neither owns nor observes the slot, or one for a derived agent on
|
|
179
|
+
* another branch: no.
|
|
180
|
+
*/
|
|
181
|
+
export function observedRowFor(
|
|
182
|
+
edge: Pick<ObserveEdge, 'includeHeld'>,
|
|
183
|
+
row: { participant: string; metadata?: unknown },
|
|
184
|
+
context: { observer: AgentName; owners: readonly AgentName[] },
|
|
185
|
+
): boolean {
|
|
186
|
+
if (isAnotherAgentsInjection(row.metadata, context.observer)) return false;
|
|
187
|
+
if (row.participant === context.observer) return false;
|
|
188
|
+
if (suppressedRow(row.metadata as Record<string, unknown> | undefined)) return false;
|
|
189
|
+
if (heldFromResidents(row.metadata as Record<string, unknown> | undefined)) return edge.includeHeld === true;
|
|
190
|
+
const stamp = audienceOf(row.metadata);
|
|
191
|
+
if (!stamp) return true;
|
|
192
|
+
if (stamp.ownRowOf !== undefined) return context.owners.includes(stamp.ownRowOf);
|
|
193
|
+
return stamp.audience.some((name) => name === context.observer || context.owners.includes(name));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** What `storeOwnRow` writes through: an agent, or anything that names one and holds its context. */
|
|
197
|
+
export interface OwnRowWriter {
|
|
198
|
+
readonly name: AgentName;
|
|
199
|
+
/** With `getMessage`, a write whose outcome the store can't tell presents
|
|
200
|
+
* the rows it may have stored that the store reads as held
|
|
201
|
+
* (presentLandedThenRethrow); without it, only those it knows landed. */
|
|
202
|
+
getContextManager(): Pick<ContextManager, 'addMessage'> & Partial<Pick<ContextManager, 'getMessage'>>;
|
|
203
|
+
/**
|
|
204
|
+
* Told the ids of the agent's own rows once they are stored (the
|
|
205
|
+
* presentation index's own-row sink, #291), each once its write has
|
|
206
|
+
* returned. A writer without it is told nothing.
|
|
207
|
+
*/
|
|
208
|
+
ownRowsStored?(ids: readonly MessageId[]): void;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Store a row in `agent`'s own context, stamped as its own row (asOwnRow).
|
|
213
|
+
* Every writer that stores into an agent's context directly, past the
|
|
214
|
+
* framework's `addMessage`, stores the agent's own rows through this, but
|
|
215
|
+
* the tool-result guard, which stamps the results it writes itself
|
|
216
|
+
* (asOwnRow, ToolResultGuard.storeResults) and tells its own-row sink of
|
|
217
|
+
* them, so none of them goes unstamped.
|
|
218
|
+
*
|
|
219
|
+
* With `present` (the default), the writer is told of the row once the add
|
|
220
|
+
* has returned (`ownRowsStored`), never from inside it, where a sharded body
|
|
221
|
+
* may still be storing its shards: under the presentation index (#291) that
|
|
222
|
+
* presents the row in the agent's window at once. That is right for a row
|
|
223
|
+
* the agent's stream carries (its round, its results, a notice injected at
|
|
224
|
+
* its boundary), one written before its next compile or after its stream's
|
|
225
|
+
* last request, and one written while the agent has no turn alive. A row
|
|
226
|
+
* written at another moment, where a turn the row isn't part of may be
|
|
227
|
+
* alive, passes `present: false`: it stays stored and out of the window,
|
|
228
|
+
* and the index's own-row sweep at the agent's next presentation point
|
|
229
|
+
* presents it there.
|
|
230
|
+
*/
|
|
231
|
+
export function storeOwnRow(
|
|
232
|
+
agent: OwnRowWriter,
|
|
233
|
+
participant: string,
|
|
234
|
+
content: ContentBlock[],
|
|
235
|
+
metadata?: MessageMetadata,
|
|
236
|
+
options?: AddMessageOptions,
|
|
237
|
+
present = true,
|
|
238
|
+
): MessageId {
|
|
239
|
+
const cm = agent.getContextManager();
|
|
240
|
+
let id: MessageId;
|
|
241
|
+
try {
|
|
242
|
+
id = cm.addMessage(participant, content, asOwnRow(metadata, agent.name), undefined, options);
|
|
243
|
+
} catch (error) {
|
|
244
|
+
presentLandedThenRethrow(
|
|
245
|
+
error,
|
|
246
|
+
agent.name,
|
|
247
|
+
present && agent.ownRowsStored ? (ids) => agent.ownRowsStored!(ids) : undefined,
|
|
248
|
+
cm.getMessage ? (row) => cm.getMessage!(row) !== null : undefined,
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
if (present) agent.ownRowsStored?.([id]);
|
|
252
|
+
return id;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* The catch of a write of an agent's own row whose add threw (storeOwnRow,
|
|
257
|
+
* and the tool-result guard's two writes of the results row): the rows of
|
|
258
|
+
* the write the store holds are told to `told`, the own-row sink, as the
|
|
259
|
+
* write's id would have been, then the add's error is thrown on. The write
|
|
260
|
+
* is answered by that error, as before the presentation index: what its
|
|
261
|
+
* caller does on it is the caller's. A row of it that is stored is out of
|
|
262
|
+
* the window until presented, like any stored row, and presented here so
|
|
263
|
+
* that an own row written after it can't enter the window ahead of it.
|
|
264
|
+
*
|
|
265
|
+
* - WriteLandedError: its `landed` rows, in store order.
|
|
266
|
+
* - WriteOutcomeUnknownError: its `landed` rows, then those its `unknown`
|
|
267
|
+
* names (the store holds all of these or none) that `holds` reads as
|
|
268
|
+
* stored, as addMessage presents such a write's rows (presentedThoughUnknown
|
|
269
|
+
* in framework.ts, whose afterStore reads the rows too). Where that read
|
|
270
|
+
* throws, every row `unknown` names, as presentedThoughUnknown gives them:
|
|
271
|
+
* the sink keeps a row it can't present and presents it ahead of the next
|
|
272
|
+
* own row, dropping one the store doesn't hold (presentOwn), so a landed
|
|
273
|
+
* row isn't put behind an own row written after it. Without `holds`, its
|
|
274
|
+
* `landed` rows only.
|
|
275
|
+
* - Any other error: none of the write is stored, so nothing is told.
|
|
276
|
+
*
|
|
277
|
+
* Without `told` (a writer that holds its row back, storeOwnRow's
|
|
278
|
+
* `present: false`, or one with no sink) nothing is told. A sink that
|
|
279
|
+
* throws is logged; the add's error is the one thrown.
|
|
280
|
+
*/
|
|
281
|
+
export function presentLandedThenRethrow(
|
|
282
|
+
error: unknown,
|
|
283
|
+
agentName: string,
|
|
284
|
+
told: ((ids: readonly MessageId[]) => void) | undefined,
|
|
285
|
+
holds?: (id: MessageId) => boolean,
|
|
286
|
+
): never {
|
|
287
|
+
const stored = told ? storedOfThrownWrite(error, holds) : [];
|
|
288
|
+
if (stored.length > 0) {
|
|
289
|
+
try {
|
|
290
|
+
told!(stored);
|
|
291
|
+
} catch (presentError) {
|
|
292
|
+
console.error(
|
|
293
|
+
`[store] agent=${agentName}: a write's add threw with ${stored.length === 1 ? `its row ${stored[0]}` : `rows ${stored.join(', ')}`} ` +
|
|
294
|
+
'stored, and telling its own-row sink of them threw too:',
|
|
295
|
+
presentError,
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
throw error;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** The rows of a write whose add threw that the store holds, by its error (presentLandedThenRethrow). */
|
|
303
|
+
function storedOfThrownWrite(error: unknown, holds: ((id: MessageId) => boolean) | undefined): MessageId[] {
|
|
304
|
+
if (error instanceof WriteLandedError) return [...error.landed];
|
|
305
|
+
if (!(error instanceof WriteOutcomeUnknownError)) return [];
|
|
306
|
+
let unknown: MessageId[] = [];
|
|
307
|
+
if (holds && error.unknown.length > 0) {
|
|
308
|
+
try {
|
|
309
|
+
unknown = error.unknown.filter((id) => holds(id));
|
|
310
|
+
} catch {
|
|
311
|
+
unknown = [...error.unknown];
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return [...error.landed, ...unknown];
|
|
315
|
+
}
|
package/src/dendrite/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { AgentRegistry, AgentSpecError } from './registry.js';
|
|
2
|
-
export type { AgentRegistryOptions, RestoreOutcome, ReconcileOutcome } from './registry.js';
|
|
1
|
+
export { AgentRegistry, AgentSpecError, RESIDENTS_SLOT, sameSlot, observedSlot } from './registry.js';
|
|
2
|
+
export type { AgentRegistryOptions, RegisterOptions, RestoreOutcome, ReconcileOutcome } from './registry.js';
|
|
3
3
|
export {
|
|
4
4
|
residentSpec,
|
|
5
5
|
subconsciousSpec,
|
|
@@ -17,6 +17,7 @@ export type {
|
|
|
17
17
|
ActivationBounds,
|
|
18
18
|
ParentEndPolicy,
|
|
19
19
|
ResultRoute,
|
|
20
|
+
MessageSlotRef,
|
|
20
21
|
ObserveEdge,
|
|
21
22
|
AgentRelationships,
|
|
22
23
|
ContextInheritance,
|
|
@@ -30,3 +31,14 @@ export type {
|
|
|
30
31
|
EndOutcome,
|
|
31
32
|
PolicyEpoch,
|
|
32
33
|
} from './types.js';
|
|
34
|
+
export {
|
|
35
|
+
AUDIENCE_KEY,
|
|
36
|
+
OWN_ROW_KEY,
|
|
37
|
+
withAudience,
|
|
38
|
+
asOwnRow,
|
|
39
|
+
audienceOf,
|
|
40
|
+
isOwnRowOf,
|
|
41
|
+
observedRowFor,
|
|
42
|
+
storeOwnRow,
|
|
43
|
+
} from './audience.js';
|
|
44
|
+
export type { AudienceStamp, OwnRowWriter } from './audience.js';
|
package/src/dendrite/presets.ts
CHANGED
|
@@ -11,10 +11,14 @@ import type { AgentName, AgentSpec, ContextInheritance, ResultRoute } from './ty
|
|
|
11
11
|
export const DEFAULT_TASK_IDLE_TIMEOUT_MS = 15 * 60_000;
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* A resident: persistent, declared in configuration,
|
|
15
|
-
* shared message slot. The first one declared owns default
|
|
14
|
+
* A resident: persistent, declared in configuration, its own rows stored in
|
|
15
|
+
* the residents' shared message slot. The first one declared owns default
|
|
16
|
+
* delivery. `observes` names the other agents whose own rows its window
|
|
17
|
+
* takes (AgentConfig.observes): an observe edge on each, `{ agent }`, which
|
|
18
|
+
* reads that agent's own slot, the residents' slot it shares, and shows it
|
|
19
|
+
* that agent's own rows there (bearingOf). None by default.
|
|
16
20
|
*/
|
|
17
|
-
export function residentSpec(name: AgentName, options: { primary: boolean }): AgentSpec {
|
|
21
|
+
export function residentSpec(name: AgentName, options: { primary: boolean; observes?: readonly AgentName[] }): AgentSpec {
|
|
18
22
|
return {
|
|
19
23
|
name,
|
|
20
24
|
kind: 'resident',
|
|
@@ -25,6 +29,11 @@ export function residentSpec(name: AgentName, options: { primary: boolean }): Ag
|
|
|
25
29
|
ownsProviderScheduling: true,
|
|
26
30
|
},
|
|
27
31
|
lifetime: { kind: 'persistent' },
|
|
32
|
+
...(options.observes?.length ? { observes: options.observes.map((agent) => ({ agent })) } : {}),
|
|
33
|
+
ownSlot: { namespace: null },
|
|
34
|
+
// Deprecated: kept for one release beside ownSlot, which the registry
|
|
35
|
+
// reads first, for a host that reads the flag off a preset's spec or
|
|
36
|
+
// builds its specs from one.
|
|
28
37
|
readsSharedSlot: true,
|
|
29
38
|
namespace: `agents/${name}`,
|
|
30
39
|
};
|
|
@@ -33,9 +42,9 @@ export function residentSpec(name: AgentName, options: { primary: boolean }): Ag
|
|
|
33
42
|
/**
|
|
34
43
|
* The subconscious: a persistent attention tenant of the resident it
|
|
35
44
|
* serves. It persists across policy epochs (cancelling a tune-out ends a
|
|
36
|
-
* channel's cadence, not this agent),
|
|
37
|
-
*
|
|
38
|
-
* resident.
|
|
45
|
+
* channel's cadence, not this agent), stores its own rows in a slot of its
|
|
46
|
+
* own and observes the residents' slot with held traffic included, is never
|
|
47
|
+
* a broadcast recipient, and ends with its resident.
|
|
39
48
|
*/
|
|
40
49
|
export function subconsciousSpec(name: AgentName, serves: AgentName): AgentSpec {
|
|
41
50
|
return {
|
|
@@ -52,6 +61,9 @@ export function subconsciousSpec(name: AgentName, serves: AgentName): AgentSpec
|
|
|
52
61
|
onParentEnd: 'end',
|
|
53
62
|
observes: [{ includeHeld: true }],
|
|
54
63
|
resultTo: { to: serves, as: 'message' },
|
|
64
|
+
ownSlot: { namespace: `subconscious/${serves}` },
|
|
65
|
+
// Deprecated, as on residentSpec: it reads the residents' slot through
|
|
66
|
+
// its observe edge; its ownSlot places its rows.
|
|
55
67
|
readsSharedSlot: true,
|
|
56
68
|
namespace: `subconscious/${serves}`,
|
|
57
69
|
};
|