@animalabs/agent-framework 0.28.0 → 0.30.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 +88 -25
- package/dist/src/admission/admit.d.ts +90 -0
- package/dist/src/admission/admit.d.ts.map +1 -0
- package/dist/src/admission/admit.js +43 -0
- package/dist/src/admission/admit.js.map +1 -0
- package/dist/src/agent.d.ts +21 -0
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +47 -7
- 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 +3 -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 +7 -3
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/author-presentation.d.ts +50 -0
- package/dist/src/author-presentation.d.ts.map +1 -0
- package/dist/src/author-presentation.js +58 -0
- package/dist/src/author-presentation.js.map +1 -0
- package/dist/src/auto-continue.d.ts +2 -0
- package/dist/src/auto-continue.d.ts.map +1 -1
- package/dist/src/auto-continue.js +5 -2
- package/dist/src/auto-continue.js.map +1 -1
- package/dist/src/code-execution/isolate/runner.d.ts +7 -5
- package/dist/src/code-execution/isolate/runner.d.ts.map +1 -1
- package/dist/src/code-execution/isolate/runner.js +7 -5
- package/dist/src/code-execution/isolate/runner.js.map +1 -1
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
- package/dist/src/code-execution/isolate/scripts.js +3 -2
- package/dist/src/code-execution/isolate/scripts.js.map +1 -1
- package/dist/src/dendrite/index.d.ts +6 -0
- package/dist/src/dendrite/index.d.ts.map +1 -0
- package/dist/src/dendrite/index.js +3 -0
- package/dist/src/dendrite/index.js.map +1 -0
- package/dist/src/dendrite/presets.d.ts +60 -0
- package/dist/src/dendrite/presets.d.ts.map +1 -0
- package/dist/src/dendrite/presets.js +117 -0
- package/dist/src/dendrite/presets.js.map +1 -0
- package/dist/src/dendrite/registry.d.ts +260 -0
- package/dist/src/dendrite/registry.d.ts.map +1 -0
- package/dist/src/dendrite/registry.js +742 -0
- package/dist/src/dendrite/registry.js.map +1 -0
- package/dist/src/dendrite/types.d.ts +392 -0
- package/dist/src/dendrite/types.d.ts.map +1 -0
- package/dist/src/dendrite/types.js +24 -0
- package/dist/src/dendrite/types.js.map +1 -0
- package/dist/src/framework.d.ts +846 -67
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +4213 -924
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +46 -14
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +143 -53
- 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 +1 -1
- package/dist/src/gate/index.js.map +1 -1
- package/dist/src/gate/types.d.ts +12 -2
- package/dist/src/gate/types.d.ts.map +1 -1
- package/dist/src/heartbeat/heartbeat.d.ts +18 -0
- package/dist/src/heartbeat/heartbeat.d.ts.map +1 -1
- package/dist/src/heartbeat/heartbeat.js +34 -8
- package/dist/src/heartbeat/heartbeat.js.map +1 -1
- package/dist/src/held-writes.d.ts +3 -3
- package/dist/src/held-writes.js +3 -3
- package/dist/src/host-presentation.d.ts +174 -0
- package/dist/src/host-presentation.d.ts.map +1 -0
- package/dist/src/host-presentation.js +565 -0
- package/dist/src/host-presentation.js.map +1 -0
- package/dist/src/index.d.ts +7 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +7 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/line-reader.d.ts +4 -0
- package/dist/src/line-reader.d.ts.map +1 -0
- package/dist/src/line-reader.js +59 -0
- package/dist/src/line-reader.js.map +1 -0
- package/dist/src/mcpl/channel-registry.d.ts +118 -15
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +266 -110
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +2 -1
- package/dist/src/mcpl/conversation-router.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts +1 -0
- package/dist/src/mcpl/convert-block.d.ts.map +1 -1
- package/dist/src/mcpl/convert-block.js +16 -4
- package/dist/src/mcpl/convert-block.js.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.js +4 -3
- package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +3 -1
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +3 -1
- package/dist/src/mcpl/inbound-source.js.map +1 -1
- package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
- package/dist/src/mcpl/modern-connection.js +11 -7
- package/dist/src/mcpl/modern-connection.js.map +1 -1
- package/dist/src/mcpl/protocol-family.d.ts +3 -2
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
- package/dist/src/mcpl/protocol-family.js +25 -3
- package/dist/src/mcpl/protocol-family.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +9 -0
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +21 -0
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.js +2 -2
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/references.d.ts +12 -40
- package/dist/src/mcpl/references.d.ts.map +1 -1
- package/dist/src/mcpl/references.js +29 -23
- package/dist/src/mcpl/references.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +20 -20
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/skip-reply-wake.d.ts +25 -0
- package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -1
- package/dist/src/mcpl/skip-reply-wake.js +25 -0
- package/dist/src/mcpl/skip-reply-wake.js.map +1 -1
- package/dist/src/mcpl/tool-presence.d.ts.map +1 -1
- package/dist/src/mcpl/tool-presence.js +18 -17
- package/dist/src/mcpl/tool-presence.js.map +1 -1
- package/dist/src/mcpl/tool-signature.d.ts.map +1 -1
- package/dist/src/mcpl/tool-signature.js +17 -16
- package/dist/src/mcpl/tool-signature.js.map +1 -1
- package/dist/src/mcpl/toolset-host.d.ts +8 -26
- package/dist/src/mcpl/toolset-host.d.ts.map +1 -1
- package/dist/src/mcpl/toolset-host.js +16 -6
- package/dist/src/mcpl/toolset-host.js.map +1 -1
- package/dist/src/mcpl/toolsets-module.d.ts +14 -25
- package/dist/src/mcpl/toolsets-module.d.ts.map +1 -1
- package/dist/src/mcpl/toolsets-module.js +187 -50
- package/dist/src/mcpl/toolsets-module.js.map +1 -1
- package/dist/src/mcpl/transport.d.ts +1 -1
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +16 -16
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +28 -12
- 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 +6 -7
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +6 -7
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/api/index.d.ts.map +1 -1
- package/dist/src/modules/api/index.js +4 -2
- package/dist/src/modules/api/index.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +33 -25
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/history/index.js +8 -6
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/sender-name.d.ts +7 -0
- package/dist/src/modules/sender-name.d.ts.map +1 -0
- package/dist/src/modules/sender-name.js +10 -0
- package/dist/src/modules/sender-name.js.map +1 -0
- package/dist/src/modules/workspace/answers.d.ts +5 -1
- package/dist/src/modules/workspace/answers.d.ts.map +1 -1
- package/dist/src/modules/workspace/answers.js +16 -1
- package/dist/src/modules/workspace/answers.js.map +1 -1
- package/dist/src/modules/workspace/direct-write.d.ts.map +1 -1
- package/dist/src/modules/workspace/direct-write.js +6 -4
- package/dist/src/modules/workspace/direct-write.js.map +1 -1
- package/dist/src/modules/workspace/effects.d.ts +4 -2
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +50 -40
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +1 -0
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +66 -36
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +51 -20
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +120 -82
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/reconcile.d.ts +7 -1
- package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
- package/dist/src/modules/workspace/reconcile.js +133 -37
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/notice-tags.d.ts +81 -0
- package/dist/src/notice-tags.d.ts.map +1 -0
- package/dist/src/notice-tags.js +85 -0
- package/dist/src/notice-tags.js.map +1 -0
- package/dist/src/reasoning-loss-notice.d.ts.map +1 -1
- package/dist/src/reasoning-loss-notice.js +5 -3
- package/dist/src/reasoning-loss-notice.js.map +1 -1
- package/dist/src/silent-heartbeat.d.ts +5 -55
- package/dist/src/silent-heartbeat.d.ts.map +1 -1
- package/dist/src/silent-heartbeat.js +63 -7
- package/dist/src/silent-heartbeat.js.map +1 -1
- package/dist/src/stored-injections.d.ts +4 -0
- package/dist/src/stored-injections.d.ts.map +1 -1
- package/dist/src/stored-injections.js +6 -0
- package/dist/src/stored-injections.js.map +1 -1
- package/dist/src/supplied-text.d.ts +35 -0
- package/dist/src/supplied-text.d.ts.map +1 -0
- package/dist/src/supplied-text.js +141 -0
- package/dist/src/supplied-text.js.map +1 -0
- package/dist/src/tool-args.d.ts.map +1 -1
- package/dist/src/tool-args.js +9 -8
- package/dist/src/tool-args.js.map +1 -1
- package/dist/src/tool-image-ledger.d.ts.map +1 -1
- package/dist/src/tool-image-ledger.js +2 -1
- package/dist/src/tool-image-ledger.js.map +1 -1
- package/dist/src/tool-presentation.d.ts.map +1 -1
- package/dist/src/tool-presentation.js +5 -4
- package/dist/src/tool-presentation.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +382 -11
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +1100 -119
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/tune-out/tools.d.ts +101 -5
- package/dist/src/tune-out/tools.d.ts.map +1 -1
- package/dist/src/tune-out/tools.js +55 -18
- package/dist/src/tune-out/tools.js.map +1 -1
- package/dist/src/types/agent.d.ts +48 -9
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +142 -0
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +22 -11
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +136 -0
- package/dist/src/types/trace.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/admission/admit.ts +113 -0
- package/src/agent.ts +52 -7
- package/src/api/mcp-server-core.ts +3 -14
- package/src/api/server.ts +7 -3
- package/src/author-presentation.ts +81 -0
- package/src/auto-continue.ts +8 -2
- package/src/code-execution/isolate/runner.ts +7 -5
- package/src/code-execution/isolate/scripts.ts +3 -2
- package/src/dendrite/index.ts +32 -0
- package/src/dendrite/presets.ts +149 -0
- package/src/dendrite/registry.ts +808 -0
- package/src/dendrite/types.ts +397 -0
- package/src/framework.ts +4362 -852
- package/src/gate/event-gate.ts +159 -52
- package/src/gate/index.ts +1 -1
- package/src/gate/types.ts +12 -2
- package/src/heartbeat/heartbeat.ts +48 -9
- package/src/held-writes.ts +3 -3
- package/src/host-presentation.ts +612 -0
- package/src/index.ts +17 -4
- package/src/line-reader.ts +58 -0
- package/src/mcpl/channel-registry.ts +306 -111
- package/src/mcpl/conversation-router.ts +2 -1
- package/src/mcpl/convert-block.ts +17 -4
- package/src/mcpl/hook-orchestrator.ts +4 -3
- package/src/mcpl/inbound-source.ts +3 -1
- package/src/mcpl/modern-connection.ts +11 -7
- package/src/mcpl/protocol-family.ts +24 -3
- package/src/mcpl/push-coalescer.ts +19 -0
- package/src/mcpl/push-handler.ts +2 -2
- package/src/mcpl/references.ts +31 -23
- package/src/mcpl/server-connection.ts +20 -18
- package/src/mcpl/skip-reply-wake.ts +35 -0
- package/src/mcpl/tool-presence.ts +18 -17
- package/src/mcpl/tool-signature.ts +17 -16
- package/src/mcpl/toolset-host.ts +18 -6
- package/src/mcpl/toolsets-module.ts +149 -50
- package/src/mcpl/transport.ts +18 -14
- package/src/mcpl/types.ts +29 -12
- package/src/module-registry.ts +6 -7
- package/src/modules/api/index.ts +4 -2
- package/src/modules/discord/index.ts +37 -25
- package/src/modules/history/index.ts +8 -6
- package/src/modules/sender-name.ts +9 -0
- package/src/modules/workspace/answers.ts +20 -2
- package/src/modules/workspace/direct-write.ts +4 -3
- package/src/modules/workspace/effects.ts +50 -40
- package/src/modules/workspace/index.ts +58 -34
- package/src/modules/workspace/observe.ts +139 -88
- package/src/modules/workspace/reconcile.ts +159 -36
- package/src/notice-tags.ts +86 -0
- package/src/reasoning-loss-notice.ts +5 -3
- package/src/silent-heartbeat.ts +11 -7
- package/src/stored-injections.ts +7 -0
- package/src/supplied-text.ts +154 -0
- package/src/tool-args.ts +9 -8
- package/src/tool-image-ledger.ts +2 -1
- package/src/tool-presentation.ts +5 -4
- package/src/tune-out/coordinator.ts +1252 -123
- package/src/tune-out/tools.ts +152 -11
- package/src/types/agent.ts +51 -9
- package/src/types/framework.ts +146 -0
- package/src/types/module.ts +23 -11
- package/src/types/trace.ts +150 -0
package/src/tune-out/tools.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { ContentBlock } from '@animalabs/membrane';
|
|
2
|
+
import { authorLine } from '../author-presentation.js';
|
|
3
|
+
import type { StoredMessage } from '@animalabs/context-manager';
|
|
1
4
|
/**
|
|
2
5
|
* The subconscious's tool surface (issue #77).
|
|
3
6
|
*
|
|
@@ -51,11 +54,13 @@ export const SUBCONSCIOUS_TOOLS: ToolDefinition[] = [
|
|
|
51
54
|
'End the tune-out on a channel now — use when something needs the ' +
|
|
52
55
|
'resident\'s full attention. The diverted backlog is delivered to ' +
|
|
53
56
|
'them (capped), and normal attention resumes. Add your own note in ' +
|
|
54
|
-
'`text`; it arrives alongside the backlog, in your voice.'
|
|
57
|
+
'`text`; it arrives alongside the backlog, in your voice. If you were ' +
|
|
58
|
+
'started to read one hold, you can end only that hold.',
|
|
55
59
|
inputSchema: {
|
|
56
60
|
type: 'object',
|
|
57
61
|
properties: {
|
|
58
|
-
channelId: { type: 'string' },
|
|
62
|
+
channelId: { type: 'string', description: 'A tuned-out channel, or a channel held by the all-except hold (which ends that hold, unless scope is "channel").' },
|
|
63
|
+
scope: { type: 'string', enum: ['channel', 'all-except'], description: '"all-except" ends the all-except hold outright; "channel" ends only the channel\'s own tune-out.' },
|
|
59
64
|
text: {
|
|
60
65
|
type: 'string',
|
|
61
66
|
description: 'Your accompanying note to the resident (optional).',
|
|
@@ -86,10 +91,14 @@ export const SUBCONSCIOUS_TOOLS: ToolDefinition[] = [
|
|
|
86
91
|
{
|
|
87
92
|
name: 'speak_in_channel',
|
|
88
93
|
description:
|
|
89
|
-
'Post a message into a tuned-out channel,
|
|
90
|
-
'as the resident)
|
|
91
|
-
'
|
|
92
|
-
'
|
|
94
|
+
'Post a message into a tuned-out channel, in your own words and ' +
|
|
95
|
+
'clearly as yourself (not as the resident); it goes out through the ' +
|
|
96
|
+
'resident\'s publish path, so the channel sees it under their account. ' +
|
|
97
|
+
'Use sparingly — e.g. to tell someone the resident is tuned out and ' +
|
|
98
|
+
'when to expect them. If you were started to read one hold, you can ' +
|
|
99
|
+
'post only into a channel that hold still holds, and a post made once ' +
|
|
100
|
+
'it has ended is refused; your report can say it instead. Disabled unless ' +
|
|
101
|
+
'the resident\'s configuration allows it.',
|
|
93
102
|
inputSchema: {
|
|
94
103
|
type: 'object',
|
|
95
104
|
properties: {
|
|
@@ -102,11 +111,42 @@ export const SUBCONSCIOUS_TOOLS: ToolDefinition[] = [
|
|
|
102
111
|
];
|
|
103
112
|
|
|
104
113
|
/**
|
|
105
|
-
* Configuration for the subconscious
|
|
114
|
+
* Configuration for the subconscious (FrameworkConfig.subconscious). Two
|
|
115
|
+
* shapes, by `reader`:
|
|
116
|
+
*
|
|
117
|
+
* - `'persistent'` (default): one persistent side-agent with an isolated
|
|
118
|
+
* slot and a windowed read-only view of the residents' timeline, as
|
|
119
|
+
* issue #77 built it. Its `systemPrompt` is a system prompt.
|
|
120
|
+
* - `'forks'`: a succession of forks of the resident (Dendrite). Each
|
|
121
|
+
* cadence tick, coalesced wake and cancel derives a short-lived fork at
|
|
122
|
+
* the resident's head — the resident's whole prefix, its refusals
|
|
123
|
+
* included, ending with it — hands it the traffic held since the last
|
|
124
|
+
* look as the first message after the fork point, and lets it report
|
|
125
|
+
* back as attributed mail. No agent persists between invocations;
|
|
126
|
+
* dispositions do, in the coordinator's state. Its `voice` is framing,
|
|
127
|
+
* not a system prompt, and residents are shown the reader's four tools
|
|
128
|
+
* in their tool block (refused at dispatch), so the fork's request is
|
|
129
|
+
* the resident's up to the fork point.
|
|
106
130
|
*/
|
|
107
|
-
export
|
|
131
|
+
export type SubconsciousConfig = PersistentReaderConfig | ForkReaderConfig;
|
|
132
|
+
|
|
133
|
+
interface SubconsciousConfigBase {
|
|
108
134
|
/** Master switch. */
|
|
109
135
|
enabled: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Allow speak_in_channel. Default false until the voice block has passed
|
|
138
|
+
* its canary round. A reader's post goes out through the resident's own
|
|
139
|
+
* publish path, so the channel sees it under the resident's account, in
|
|
140
|
+
* the reader's words; nothing in the request names the reader. With it
|
|
141
|
+
* off, a reader fork can post nowhere: every tool but its own is refused
|
|
142
|
+
* at dispatch (the block it is shown stays the resident's, for the
|
|
143
|
+
* shared prefix).
|
|
144
|
+
*/
|
|
145
|
+
allowChannelSpeech?: boolean;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface PersistentReaderConfig extends SubconsciousConfigBase {
|
|
149
|
+
reader?: 'persistent';
|
|
110
150
|
/**
|
|
111
151
|
* Registry + participant name. Default 'Subconscious' — following the
|
|
112
152
|
* Context Manager precedent: a title-case functional voice, not an
|
|
@@ -124,9 +164,110 @@ export interface SubconsciousConfig {
|
|
|
124
164
|
* person toward the resident. Canary before fleet use (issue #77).
|
|
125
165
|
*/
|
|
126
166
|
systemPrompt: string;
|
|
127
|
-
/** Allow speak_in_channel. Default false until the voice block has
|
|
128
|
-
* passed its canary round. */
|
|
129
|
-
allowChannelSpeech?: boolean;
|
|
130
167
|
/** WindowedPassthroughStrategy re-anchor fraction (default 0.5). */
|
|
131
168
|
reAnchorFraction?: number;
|
|
132
169
|
}
|
|
170
|
+
|
|
171
|
+
export interface ForkReaderConfig extends SubconsciousConfigBase {
|
|
172
|
+
reader: 'forks';
|
|
173
|
+
/**
|
|
174
|
+
* Whose weights run the fork. Required, never defaulted: a fork holds the
|
|
175
|
+
* resident's whole prefix, and which model reads it is the one fact the
|
|
176
|
+
* resident's consent names. The resident's own model is the copy; another
|
|
177
|
+
* model is allowed when stated here. `create` refuses the omission.
|
|
178
|
+
*/
|
|
179
|
+
model: string;
|
|
180
|
+
/**
|
|
181
|
+
* The reader's voice block — report-shaped, second person toward the
|
|
182
|
+
* resident, co-authored with them. Delivered as the first message after
|
|
183
|
+
* the fork point, with the notice, the standing dispositions and the held
|
|
184
|
+
* traffic; never a system prompt.
|
|
185
|
+
*/
|
|
186
|
+
voice: string;
|
|
187
|
+
/**
|
|
188
|
+
* A fresh context strategy instance for each fork, same class and
|
|
189
|
+
* configuration as the resident's, so the fork reuses the resident's fold
|
|
190
|
+
* state and rendering. Required unless the resident runs a passthrough
|
|
191
|
+
* strategy.
|
|
192
|
+
*/
|
|
193
|
+
strategyFactory?: () => import('@animalabs/context-manager').ContextStrategy;
|
|
194
|
+
/** Idle timeout for one reader fork (default 10 minutes). */
|
|
195
|
+
forkIdleTimeoutMs?: number;
|
|
196
|
+
/**
|
|
197
|
+
* How a reader fork is prompted: the content of the one message it
|
|
198
|
+
* receives after the fork point. Default `defaultReaderFraming`. The
|
|
199
|
+
* framework stores whatever this returns as a user message with
|
|
200
|
+
* `metadata.kind = 'tune-out-reader-framing'`; the notice, voice,
|
|
201
|
+
* dispositions and held traffic are in the context, and nothing else
|
|
202
|
+
* about the fork's prompt is fixed by the path.
|
|
203
|
+
*/
|
|
204
|
+
framing?: (context: ReaderFramingContext) => ContentBlock[];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** What a reader fork's framing is built from. */
|
|
208
|
+
export interface ReaderFramingContext {
|
|
209
|
+
/** The resident the fork was derived from. */
|
|
210
|
+
resident: string;
|
|
211
|
+
/** The fork's own name. */
|
|
212
|
+
fork: string;
|
|
213
|
+
/** `ForkReaderConfig.voice`. */
|
|
214
|
+
voice: string;
|
|
215
|
+
channelId: string;
|
|
216
|
+
epochId: string;
|
|
217
|
+
trigger: 'cadence' | 'wake' | 'cancel';
|
|
218
|
+
/** The coordinator's notice for this invocation (`[Tune-out wake: …]` etc.). */
|
|
219
|
+
notice: string;
|
|
220
|
+
/** Standing dispositions recorded on the epoch, or null. */
|
|
221
|
+
dispositions: string | null;
|
|
222
|
+
/**
|
|
223
|
+
* The traffic held since the last look, oldest first; empty when nothing
|
|
224
|
+
* arrived. It includes the messages still queued behind the resident's
|
|
225
|
+
* turn (admitted, not yet stored), last: their ids are held handles and
|
|
226
|
+
* their sequences provisional, as a module's held rows are.
|
|
227
|
+
*/
|
|
228
|
+
backlog: StoredMessage[];
|
|
229
|
+
/** How many of `backlog`'s last entries are still queued behind the resident's turn. Absent is none. */
|
|
230
|
+
queuedCount?: number;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* The default reader-fork framing: a header naming the channel, epoch and
|
|
235
|
+
* trigger; the notice; the voice block; standing dispositions if any; then
|
|
236
|
+
* the held traffic as `author: text` lines with non-text blocks (images,
|
|
237
|
+
* documents) preserved in order as the source supplied them.
|
|
238
|
+
*/
|
|
239
|
+
export function defaultReaderFraming(ctx: ReaderFramingContext): ContentBlock[] {
|
|
240
|
+
const header =
|
|
241
|
+
`[Tune-out reader — ${ctx.channelId}, epoch ${ctx.epochId.slice(0, 8)}, ${ctx.trigger}]\n` +
|
|
242
|
+
`${ctx.notice}\n\n${ctx.voice}` +
|
|
243
|
+
(ctx.dispositions ? `\n\n[Standing dispositions]\n${ctx.dispositions}` : '');
|
|
244
|
+
const content: ContentBlock[] = [{ type: 'text', text: header }];
|
|
245
|
+
if (ctx.backlog.length === 0) {
|
|
246
|
+
content.push({ type: 'text', text: '\n[Nothing new has been held since your last look.]' });
|
|
247
|
+
return content;
|
|
248
|
+
}
|
|
249
|
+
const n = ctx.backlog.length;
|
|
250
|
+
const q = Math.min(Math.max(0, Math.floor(ctx.queuedCount ?? 0)), n);
|
|
251
|
+
const lines: string[] = [`\n[Held in ${ctx.channelId} since your last look: ${n} message${n === 1 ? '' : 's'}]`];
|
|
252
|
+
const flush = () => {
|
|
253
|
+
if (lines.length > 0) content.push({ type: 'text', text: lines.splice(0).join('\n') });
|
|
254
|
+
};
|
|
255
|
+
const which = q === n ? (q === 1 ? 'It' : 'They') : (q === 1 ? 'The last one' : `The last ${q}`);
|
|
256
|
+
const queuedNote = `[${which} arrived while ${ctx.resident}'s turn was running, so ${q === 1 ? 'it is' : 'they are'} still queued, not yet stored.]`;
|
|
257
|
+
for (const [i, message] of ctx.backlog.entries()) {
|
|
258
|
+
if (q > 0 && i === n - q) lines.push(queuedNote);
|
|
259
|
+
const author = (message.metadata as { author?: { name?: string } } | undefined)?.author?.name ?? message.participant;
|
|
260
|
+
const text = message.content
|
|
261
|
+
.filter((b): b is Extract<ContentBlock, { type: 'text' }> => b.type === 'text')
|
|
262
|
+
.map((b) => b.text)
|
|
263
|
+
.join('\n');
|
|
264
|
+
lines.push(authorLine(author, text));
|
|
265
|
+
const media = message.content.filter((b) => b.type !== 'text');
|
|
266
|
+
if (media.length > 0) {
|
|
267
|
+
flush();
|
|
268
|
+
content.push(...media);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
flush();
|
|
272
|
+
return content;
|
|
273
|
+
}
|
package/src/types/agent.ts
CHANGED
|
@@ -55,13 +55,15 @@ export interface AgentConfig {
|
|
|
55
55
|
* Enforced at dispatch for registered agent callers; omitted means 'all'.
|
|
56
56
|
* - 'all': all available tools
|
|
57
57
|
* - string[]: exact tool names, including module--utility names for utilities.
|
|
58
|
-
* Utilities
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* '
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
58
|
+
* Utilities and the host's other rarely-used tools are in the host's
|
|
59
|
+
* built-in toolset ("settings"), out of the tool list: the model reaches
|
|
60
|
+
* them with toolsets--open {toolset:"settings"} and toolsets--act, each
|
|
61
|
+
* checked under the tool's own name. An agent that should use a utility
|
|
62
|
+
* from its model lists 'toolsets--open', 'toolsets--act' and
|
|
63
|
+
* 'module--utility' (an agent without the two meta-tools keeps every other
|
|
64
|
+
* tool in its list, but no utility). The name alone passes the dispatch
|
|
65
|
+
* check for any call by that name, whether the host makes it with
|
|
66
|
+
* executeToolCall on the agent's behalf or the model or a script makes it.
|
|
65
67
|
* Trusted module calls are exempt. Genuinely unidentified public callers,
|
|
66
68
|
* including unknown legacy names, remain unrestricted. Framework-created
|
|
67
69
|
* identities have tool authority only while registered.
|
|
@@ -338,6 +340,34 @@ export interface AgentConfig {
|
|
|
338
340
|
*/
|
|
339
341
|
proseRouting?: 'locus' | 'explicit' | 'hybrid' | 'disabled';
|
|
340
342
|
|
|
343
|
+
/**
|
|
344
|
+
* Stored participants that are this agent's own voice, in addition to its
|
|
345
|
+
* name: their turns are presented to the model as this agent's assistant
|
|
346
|
+
* turns. A derived agent sets this to the agent it inherited from, so the
|
|
347
|
+
* parent's turns read as its own history. Model-facing role assignment
|
|
348
|
+
* only, applied at request assembly — stored authorship is never rewritten.
|
|
349
|
+
*/
|
|
350
|
+
selfParticipants?: string[];
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* The participant name this agent's own turns are presented under at
|
|
354
|
+
* request assembly. Defaults to `name`. A derived agent that should share
|
|
355
|
+
* its parent's provider prefix sets the parent's name, so the two
|
|
356
|
+
* requests are identical in formatters that render participant names as
|
|
357
|
+
* well as in those that only assign roles. New turns are still STORED
|
|
358
|
+
* under the agent's own name.
|
|
359
|
+
*/
|
|
360
|
+
presentAs?: string;
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Tools refused when this agent calls them, although they stay advertised.
|
|
364
|
+
* Restricts a derived agent without changing the tool block at the front
|
|
365
|
+
* of its request — removing a tool from `allowedTools` instead would
|
|
366
|
+
* change those bytes and forfeit the provider prefix it shares with its
|
|
367
|
+
* parent.
|
|
368
|
+
*/
|
|
369
|
+
denyToolsAtDispatch?: string[];
|
|
370
|
+
|
|
341
371
|
/**
|
|
342
372
|
* Fail-closed containment for a text response whose entire visible prose is
|
|
343
373
|
* an invocation-shaped wrapper naming a tool registered on that exact turn.
|
|
@@ -580,8 +610,9 @@ export interface InferenceRequest {
|
|
|
580
610
|
* the turn's auto-published plain-text speech here so a single TRUNK agent
|
|
581
611
|
* replies in the channel it is answering — not the process-global most-recent-
|
|
582
612
|
* inbound locus, which a concurrent message elsewhere can hijack (item-3
|
|
583
|
-
* redux). Undefined for non-channel wakes (heartbeat, timers, module events)
|
|
584
|
-
*
|
|
613
|
+
* redux). Undefined for non-channel wakes (heartbeat, timers, module events).
|
|
614
|
+
* A heartbeat's turn takes no channel at all, and holds its plain speech as
|
|
615
|
+
* drafts; any other falls back to the global default channel, except an
|
|
585
616
|
* ephemeral run's (a subagent's), which takes no global fallback.
|
|
586
617
|
*/
|
|
587
618
|
channelId?: string;
|
|
@@ -604,6 +635,17 @@ export interface InferenceRequest {
|
|
|
604
635
|
* it starts. Hosts don't set it.
|
|
605
636
|
*/
|
|
606
637
|
autoContinueRun?: AutoContinueRun;
|
|
638
|
+
/**
|
|
639
|
+
* Framework-set: whether this wake's turn is a heartbeat's, which has no
|
|
640
|
+
* channel and holds its plain speech as drafts. True on a wake that
|
|
641
|
+
* continues a heartbeat's turn with no channel of its own (an autoContinue
|
|
642
|
+
* continuation, a bounce's resend wake, a ` !` continuation, and a re-arm,
|
|
643
|
+
* which copies its trigger), and on a merged batch whose causes include a
|
|
644
|
+
* heartbeat's wake and name no channel; false on a merged batch with none,
|
|
645
|
+
* so the batch's first request doesn't decide it. Unset, a wake is a
|
|
646
|
+
* heartbeat's when its `source` is `heartbeat`. Hosts don't set it.
|
|
647
|
+
*/
|
|
648
|
+
heartbeatTurn?: boolean;
|
|
607
649
|
/**
|
|
608
650
|
* True when the triggering message explicitly addressed the agent (mention,
|
|
609
651
|
* reply-to-bot, DM — `chat:addressed` in MCPL RFC-001 terms). When a wake
|
package/src/types/framework.ts
CHANGED
|
@@ -116,6 +116,48 @@ export type ProviderHoldHook = (
|
|
|
116
116
|
) => ProviderHold | undefined;
|
|
117
117
|
|
|
118
118
|
export interface FrameworkConfig {
|
|
119
|
+
/**
|
|
120
|
+
* Dendrite agent lifecycle options.
|
|
121
|
+
*/
|
|
122
|
+
dendrite?: {
|
|
123
|
+
/**
|
|
124
|
+
* When an agent ends while task work it spawned is still running, the
|
|
125
|
+
* orphan is always told. With this on (the default), the first agent
|
|
126
|
+
* that could adopt it — its nearest live ancestor, else the primary —
|
|
127
|
+
* also receives a factual notice, which is what makes the reparenting
|
|
128
|
+
* offer visible to a model. Turn it off when the host makes adoption
|
|
129
|
+
* decisions itself from the `dendrite:agent-orphaned` trace.
|
|
130
|
+
*/
|
|
131
|
+
announceOrphans?: boolean;
|
|
132
|
+
/**
|
|
133
|
+
* By default every derivation tells the agent it was made from, in one
|
|
134
|
+
* host-framed line. After this many derivations of one kind from one
|
|
135
|
+
* agent, that agent hears a count line every so many instead of a line
|
|
136
|
+
* per fork, so a reader loop that forks a hundred times a session doesn't
|
|
137
|
+
* fill its source's context with stamps; every derivation still emits its
|
|
138
|
+
* `dendrite:agent-created` trace. Default 10; 0 never collapses.
|
|
139
|
+
*/
|
|
140
|
+
collapseDerivationNoticesAfter?: number;
|
|
141
|
+
/**
|
|
142
|
+
* A host's say over each derivation, ephemeral spawn and resume, before the
|
|
143
|
+
* agent or its new incarnation exists, given the spec of what is about to
|
|
144
|
+
* exist (name, kind, spawner, route, inheritance, metadata). A shared
|
|
145
|
+
* derivation's record then adds the child's branch, and names the
|
|
146
|
+
* parent's namespace as its own. Return nothing to allow, or `{ refuse }`
|
|
147
|
+
* with the reason, which the caller gets as the error. The framework
|
|
148
|
+
* attaches no meaning to the decision: consent, budget, hours, a mind's
|
|
149
|
+
* standing instruction, a use not yet imagined are all the host's.
|
|
150
|
+
*/
|
|
151
|
+
beforeDerive?: (spec: import('../dendrite/types.js').AgentSpec) => void | { refuse: string };
|
|
152
|
+
/**
|
|
153
|
+
* What an agent is told when something is derived from it. Given the
|
|
154
|
+
* record, the agent it was derived from and the framework's default line,
|
|
155
|
+
* return the text to add, or null to add nothing. Absent, the default
|
|
156
|
+
* line is used. The `dendrite:agent-created` trace is emitted either way.
|
|
157
|
+
*/
|
|
158
|
+
derivationNotice?: (record: import('../dendrite/types.js').AgentRecord, from: string, defaultText: string) => string | null;
|
|
159
|
+
};
|
|
160
|
+
|
|
119
161
|
/**
|
|
120
162
|
* The subconscious resident (issue #77): a persistent side-agent that
|
|
121
163
|
* receives diverted traffic from tuned-out channels and reports to the
|
|
@@ -123,6 +165,46 @@ export interface FrameworkConfig {
|
|
|
123
165
|
*/
|
|
124
166
|
subconscious?: import('../tune-out/tools.js').SubconsciousConfig;
|
|
125
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Tune-out without a reader (issue #232 §3.3). The hold machinery always
|
|
170
|
+
* runs when MCPL channels exist, so a persisted epoch is resumed and
|
|
171
|
+
* released whatever the configuration; this switch only decides whether
|
|
172
|
+
* residents are offered `tune_out` when no reader is configured. Without
|
|
173
|
+
* a reader a tune-out is a silent hold: no cadence, no wake budget,
|
|
174
|
+
* mentions are acknowledged, the backlog is released on cancel.
|
|
175
|
+
*/
|
|
176
|
+
tuneOut?: {
|
|
177
|
+
/** Offer `tune_out` without a subconscious. Default: only with one. */
|
|
178
|
+
enabled?: boolean;
|
|
179
|
+
/**
|
|
180
|
+
* Announce the all-except scope in the excepted channel: one bracketed
|
|
181
|
+
* line under the resident's name when it opens (who, for how long) and
|
|
182
|
+
* one when it closes. Default true — a hold the room cannot see is the
|
|
183
|
+
* failure the scope exists to prevent. `false` keeps both quiet.
|
|
184
|
+
*/
|
|
185
|
+
announce?: boolean;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Where a turn's plain prose lands when nothing names a destination
|
|
190
|
+
* (architecture channel, 2026-10-06: the §3 carve-out accepted by the
|
|
191
|
+
* residents).
|
|
192
|
+
*
|
|
193
|
+
* - `'delivery'` (default): the locus comes only from the delivery that
|
|
194
|
+
* woke the turn, a conversation fork's home channel, or a channel the
|
|
195
|
+
* agent opened during the turn. Incoming traffic never moves it — not
|
|
196
|
+
* between turns, not mid-turn. A turn with no such locus keeps its
|
|
197
|
+
* prose private, and says so in a `[routing]` notice.
|
|
198
|
+
* - `'latest-inbound'`: the previous rule. The most recent delivered
|
|
199
|
+
* inbound message is a global fallback locus for turns without one, and
|
|
200
|
+
* an addressed message injected mid-turn re-pins the turn's locus.
|
|
201
|
+
*
|
|
202
|
+
* Held traffic never moves the locus under either rule.
|
|
203
|
+
*/
|
|
204
|
+
speech?: {
|
|
205
|
+
locus?: 'delivery' | 'latest-inbound';
|
|
206
|
+
};
|
|
207
|
+
|
|
126
208
|
/**
|
|
127
209
|
* IANA zone of the agent's wall clock: it renders wall-clock times for the
|
|
128
210
|
* agent, and it sets where clock rows' boundaries fall (AgentConfig.clock,
|
|
@@ -160,6 +242,26 @@ export interface FrameworkConfig {
|
|
|
160
242
|
*/
|
|
161
243
|
deferredWritesPath?: string;
|
|
162
244
|
|
|
245
|
+
/**
|
|
246
|
+
* The Dendrite agent registry's recovery file: its live records and the
|
|
247
|
+
* results it holds for delivery, written atomically and fsynced, and read
|
|
248
|
+
* first at boot. Defaults to `<storePath>/recovery/dendrite-registry.json`.
|
|
249
|
+
* Outside the chronicle for the reason `hostModePath` is: a branch switch
|
|
250
|
+
* or historical rollback would otherwise take back held results. Set
|
|
251
|
+
* explicitly when providing an app-owned `store` without `storePath`;
|
|
252
|
+
* without either, the registry persists only in the branch-local store,
|
|
253
|
+
* with a warning at create.
|
|
254
|
+
*/
|
|
255
|
+
agentRegistryPath?: string;
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* The registry's ended-record log recovery file (its newest records, as
|
|
259
|
+
* many as a restart reads). Defaults to
|
|
260
|
+
* `<storePath>/recovery/dendrite-ended.json`; same rationale and fallback
|
|
261
|
+
* as `agentRegistryPath`.
|
|
262
|
+
*/
|
|
263
|
+
agentRegistryEndedPath?: string;
|
|
264
|
+
|
|
163
265
|
/** Emoji used for branch-awareness markers (default: 💤). */
|
|
164
266
|
discordAwarenessEmoji?: string;
|
|
165
267
|
|
|
@@ -218,6 +320,50 @@ export interface FrameworkConfig {
|
|
|
218
320
|
*/
|
|
219
321
|
providerHold?: ProviderHoldHook;
|
|
220
322
|
|
|
323
|
+
/**
|
|
324
|
+
* Delays before a turn whose retries ran out is sent again, in ms (default
|
|
325
|
+
* `[120000, 480000, 1920000]`: 2, 8 and 32 minutes), or `false` never to.
|
|
326
|
+
* When a persistent agent's turn ends exhausted on a transient failure (a
|
|
327
|
+
* server error, an overload, a rate limit, a network failure, or a timeout
|
|
328
|
+
* membrane marks retryable and not as a deadline it reports as run out, such
|
|
329
|
+
* as a 408 or a socket's ETIMEDOUT), its trigger is queued again after the
|
|
330
|
+
* first delay, as a wake of its own. It opens where the exhausted turn's
|
|
331
|
+
* plain speech was going: its locus, where a message mid-turn may have moved
|
|
332
|
+
* it, else its trigger channel. Carrying that channel, it ranks as addressed
|
|
333
|
+
* in a merged wake's choice of channel, so a newer ambient wake from
|
|
334
|
+
* elsewhere doesn't take it; an autoContinue continuation's still yields its
|
|
335
|
+
* channel to any wake's, as it does on main; a continuation's, such as a
|
|
336
|
+
* budget restart's, names no author. A re-arm that would have to guess a
|
|
337
|
+
* channel isn't sent again: one whose turn was woken for a channel id that
|
|
338
|
+
* names no one registered channel and never found one, and whose request
|
|
339
|
+
* names none of its own. A failure that states a wait is held for that wait
|
|
340
|
+
* first, as any turn's is, and a deadline ends the turn as before, whether
|
|
341
|
+
* the host set it or membrane marks one as run out: the runtime's or
|
|
342
|
+
* undici's on a sent request, the Anthropic adapter's watchdogs, or the
|
|
343
|
+
* Anthropic SDK's timeout, which covers its connect timeout too. Until one
|
|
344
|
+
* of the re-armed turn's rounds has run or had its tool calls cut off, its
|
|
345
|
+
* failure gets no retries from the error policy: on another transient
|
|
346
|
+
* failure the next delay follows, until the list runs out, and a failure of
|
|
347
|
+
* any other kind ends the re-arming. A wake for the agent while it waits
|
|
348
|
+
* starts its turn at once, with the re-armed trigger merged in. That turn is
|
|
349
|
+
* the wake's: the error policy retries its failures. A completed turn starts
|
|
350
|
+
* the count again, and so does a message said to the agent: not a system
|
|
351
|
+
* message or notice; not an edit, reaction or deletion, unless an edit is
|
|
352
|
+
* the first version of a message the agent sees; not a message its own view
|
|
353
|
+
* leaves out, such as one a tune-out holds from it; and not the agent's own
|
|
354
|
+
* schedule, the heartbeat's tick or reminder, a self-wake timer it set, or a
|
|
355
|
+
* script's wake. A notice a module or an MCPL server stores as a message
|
|
356
|
+
* counts. A message in the residents' shared slot counts for each resident
|
|
357
|
+
* that reads it. Any other wake leaves the count going on. A re-armed turn's
|
|
358
|
+
* transient failure writes no `[inference-failed]` marker unless a round of
|
|
359
|
+
* it ran or had its tool calls cut off; any other failure of it writes one.
|
|
360
|
+
* Each counts toward the hard-down streak. Ephemeral runs and conversation
|
|
361
|
+
* forks are never re-armed. The wait and the count are kept in memory:
|
|
362
|
+
* `stop()` drops them, and so does a restart. The wait isn't a turn, so
|
|
363
|
+
* `abortInference()` doesn't end it.
|
|
364
|
+
*/
|
|
365
|
+
exhaustedTurnRearmMs?: number[] | false;
|
|
366
|
+
|
|
221
367
|
/** Interval for periodic store sync in milliseconds (default: 1000ms, 0 to disable) */
|
|
222
368
|
syncIntervalMs?: number;
|
|
223
369
|
|
package/src/types/module.ts
CHANGED
|
@@ -72,10 +72,11 @@ export type ModuleMessage = StoredMessage & {
|
|
|
72
72
|
* True on a message a tune-out holds from the residents: one that arrived
|
|
73
73
|
* in a tuned-out channel, stamped `metadata.tuneOut` as it came in. The
|
|
74
74
|
* store keeps it, but no resident is shown the row itself: no resident's
|
|
75
|
-
* compiled view includes it, during the tune-out or after it, and a
|
|
76
|
-
* boundary of a turn alive when it arrived stores it
|
|
77
|
-
* into the live turn. The subconscious reads it. Its
|
|
78
|
-
* a resident in rows of their own, which aren't
|
|
75
|
+
* compiled view includes it, during the tune-out or after it, and a
|
|
76
|
+
* resident's tool boundary of a turn alive when it arrived stores it
|
|
77
|
+
* without injecting it into the live turn. The subconscious reads it. Its
|
|
78
|
+
* text can still reach a resident in rows of their own, which aren't
|
|
79
|
+
* marked, such as the
|
|
79
80
|
* cancel's `<tuned-out-backlog>` row, with the text of the tune-out's newest
|
|
80
81
|
* messages, up to `backlogCap` of them and as many as fit in one of the
|
|
81
82
|
* residents' messages, the stored ones first and then those still held;
|
|
@@ -142,16 +143,27 @@ export interface Module {
|
|
|
142
143
|
|
|
143
144
|
/**
|
|
144
145
|
* Utilities: agent-invocable operations that deliberately do NOT get a
|
|
145
|
-
*
|
|
146
|
-
* capability used twice a month shouldn't. Utilities
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
146
|
+
* slot in the tool list. Every tool schema taxes every inference; a
|
|
147
|
+
* capability used twice a month shouldn't. Utilities belong to the host's
|
|
148
|
+
* built-in toolset ("settings"): an agent sees them with
|
|
149
|
+
* `toolsets--look {toolset:"settings"}` and calls them with
|
|
150
|
+
* `toolsets--act` once it has opened it. Same ToolDefinition shape, same
|
|
151
|
+
* un-prefixed names, and dispatch arrives at the SAME handleToolCall as
|
|
152
|
+
* getTools() output. Optional; omitting it means the module contributes no
|
|
153
|
+
* utilities.
|
|
152
154
|
*/
|
|
153
155
|
getUtilities?(): ToolDefinition[];
|
|
154
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Where one of this module's tools (a getTools() name, unprefixed) is
|
|
159
|
+
* presented: in the agent's tool list (`'header'`, the default), or in the
|
|
160
|
+
* host's built-in toolset (`'builtin'`), out of the tool list, opened with
|
|
161
|
+
* `toolsets--open {toolset:"settings"}` and called with `toolsets--act`.
|
|
162
|
+
* For tools an agent uses rarely: settings, administration, status reads.
|
|
163
|
+
* Optional; omitting it keeps every tool in the tool list.
|
|
164
|
+
*/
|
|
165
|
+
toolPlacement?(toolName: string): 'header' | 'builtin' | undefined;
|
|
166
|
+
|
|
155
167
|
/**
|
|
156
168
|
* Handle a tool call.
|
|
157
169
|
* Tool name is without module prefix.
|
package/src/types/trace.ts
CHANGED
|
@@ -887,6 +887,156 @@ export type TraceEvent =
|
|
|
887
887
|
since?: number;
|
|
888
888
|
})
|
|
889
889
|
|
|
890
|
+
/** A reader fork ended in prose without `deliver_summary`; its final prose was delivered as its report. */
|
|
891
|
+
| (TraceEventBase & {
|
|
892
|
+
type: 'tune-out:reader-prose-delivered';
|
|
893
|
+
agentName: string;
|
|
894
|
+
serverId: string;
|
|
895
|
+
channelId: string;
|
|
896
|
+
epochId: string;
|
|
897
|
+
chars: number;
|
|
898
|
+
})
|
|
899
|
+
|
|
900
|
+
/** Bounded work the host's stop() cut off: left live for the next boot to end as `host-restart`. */
|
|
901
|
+
| (TraceEventBase & {
|
|
902
|
+
type: 'dendrite:agent-interrupted';
|
|
903
|
+
agentName: string;
|
|
904
|
+
kind: string;
|
|
905
|
+
incarnation: number;
|
|
906
|
+
reason: 'host-stop';
|
|
907
|
+
})
|
|
908
|
+
|
|
909
|
+
/** A tune-out reader fork was derived for one invocation (subconscious.reader: 'forks'). */
|
|
910
|
+
| (TraceEventBase & {
|
|
911
|
+
type: 'tune-out:reader-fork';
|
|
912
|
+
agentName: string;
|
|
913
|
+
serverId: string;
|
|
914
|
+
channelId: string;
|
|
915
|
+
epochId: string;
|
|
916
|
+
trigger: 'cadence' | 'wake' | 'cancel';
|
|
917
|
+
/** Held messages the fork was handed, stored and queued. */
|
|
918
|
+
held: number;
|
|
919
|
+
/** Of those, the ones still queued behind the resident's turn. */
|
|
920
|
+
queued: number;
|
|
921
|
+
})
|
|
922
|
+
|
|
923
|
+
/**
|
|
924
|
+
* A tune-out reader fork threw: its framing, its derive or its run. One
|
|
925
|
+
* that failed before it reported gives its held messages back to the
|
|
926
|
+
* channel's backlog while the epoch still holds the channel (`returned`
|
|
927
|
+
* counts them), so the next reader for the channel is handed them.
|
|
928
|
+
*/
|
|
929
|
+
| (TraceEventBase & {
|
|
930
|
+
type: 'tune-out:reader-fork-failed';
|
|
931
|
+
agentName: string;
|
|
932
|
+
serverId: string;
|
|
933
|
+
channelId: string;
|
|
934
|
+
epochId: string;
|
|
935
|
+
trigger: 'cadence' | 'wake' | 'cancel';
|
|
936
|
+
error: string;
|
|
937
|
+
/** Whether the fork had reported through `deliver_summary` before it failed. */
|
|
938
|
+
reported: boolean;
|
|
939
|
+
returned: number;
|
|
940
|
+
})
|
|
941
|
+
|
|
942
|
+
// Dendrite: agent registry and lifecycle.
|
|
943
|
+
// `agent-created` is the consent event: it names the kind of agent, what
|
|
944
|
+
// ends it, and what happens to it when its spawner ends.
|
|
945
|
+
| (TraceEventBase & {
|
|
946
|
+
type: 'dendrite:agent-created';
|
|
947
|
+
agentName: string;
|
|
948
|
+
kind: string;
|
|
949
|
+
/** Whose weights; `inherit.from` is whose context. */
|
|
950
|
+
model?: string;
|
|
951
|
+
incarnation: number;
|
|
952
|
+
lifetime: import('../dendrite/types.js').AgentLifetime;
|
|
953
|
+
spawnedBy?: string;
|
|
954
|
+
onParentEnd?: import('../dendrite/types.js').ParentEndPolicy;
|
|
955
|
+
resultTo?: import('../dendrite/types.js').ResultRoute;
|
|
956
|
+
inherit?: import('../dendrite/types.js').ContextInheritance;
|
|
957
|
+
})
|
|
958
|
+
| (TraceEventBase & {
|
|
959
|
+
type: 'dendrite:agent-ended';
|
|
960
|
+
agentName: string;
|
|
961
|
+
kind: string;
|
|
962
|
+
incarnation: number;
|
|
963
|
+
reason: string;
|
|
964
|
+
by?: string;
|
|
965
|
+
/** The agent that spawned it, when its record names one. */
|
|
966
|
+
spawnedBy?: string;
|
|
967
|
+
})
|
|
968
|
+
| (TraceEventBase & {
|
|
969
|
+
/** The last event a replay of create()'s traces delivers when the
|
|
970
|
+
* buffer kept only their first 1,000: how many came after. */
|
|
971
|
+
type: 'dendrite:early-traces-dropped';
|
|
972
|
+
dropped: number;
|
|
973
|
+
})
|
|
974
|
+
| (TraceEventBase & {
|
|
975
|
+
type: 'dendrite:agent-orphaned';
|
|
976
|
+
agentName: string;
|
|
977
|
+
formerParent: string;
|
|
978
|
+
reason: string;
|
|
979
|
+
/** Agents offered as a new parent, nearest first. */
|
|
980
|
+
candidates: string[];
|
|
981
|
+
})
|
|
982
|
+
| (TraceEventBase & {
|
|
983
|
+
type: 'dendrite:agent-reparented';
|
|
984
|
+
agentName: string;
|
|
985
|
+
parent: string;
|
|
986
|
+
by?: string;
|
|
987
|
+
})
|
|
988
|
+
| (TraceEventBase & {
|
|
989
|
+
type: 'dendrite:activation-cancelled';
|
|
990
|
+
agentName: string;
|
|
991
|
+
by?: string;
|
|
992
|
+
reason?: string;
|
|
993
|
+
})
|
|
994
|
+
/** The message entered the recipient's store (not merely queued for it). */
|
|
995
|
+
| (TraceEventBase & {
|
|
996
|
+
type: 'dendrite:mail-delivered';
|
|
997
|
+
mailId: string;
|
|
998
|
+
kind: string;
|
|
999
|
+
from: string;
|
|
1000
|
+
to: string;
|
|
1001
|
+
})
|
|
1002
|
+
/** Queued for the recipient's next boundary; `mail-delivered` follows when it lands. */
|
|
1003
|
+
| (TraceEventBase & {
|
|
1004
|
+
type: 'dendrite:mail-deferred';
|
|
1005
|
+
mailId: string;
|
|
1006
|
+
kind: string;
|
|
1007
|
+
from: string;
|
|
1008
|
+
to: string;
|
|
1009
|
+
})
|
|
1010
|
+
| (TraceEventBase & {
|
|
1011
|
+
type: 'dendrite:mail-held';
|
|
1012
|
+
mailId: string;
|
|
1013
|
+
kind: string;
|
|
1014
|
+
from: string;
|
|
1015
|
+
to: string;
|
|
1016
|
+
reason: string;
|
|
1017
|
+
})
|
|
1018
|
+
/**
|
|
1019
|
+
* The admission stage's decision for one inbound event (Dendrite §D):
|
|
1020
|
+
* who may receive it, whether it is held (the epoch id) or delivered,
|
|
1021
|
+
* whether it may wake them, and the gate's verdict.
|
|
1022
|
+
*/
|
|
1023
|
+
| (TraceEventBase & {
|
|
1024
|
+
type: 'admission:decided';
|
|
1025
|
+
lane: 'channel' | 'push';
|
|
1026
|
+
serverId: string;
|
|
1027
|
+
channelId?: string;
|
|
1028
|
+
messageId: string;
|
|
1029
|
+
recipients: string[];
|
|
1030
|
+
held: string | null;
|
|
1031
|
+
wake: boolean;
|
|
1032
|
+
gatePass: boolean;
|
|
1033
|
+
})
|
|
1034
|
+
/** Batched gate events dropped at delivery because their channel is held now. */
|
|
1035
|
+
| (TraceEventBase & {
|
|
1036
|
+
type: 'gate:held-dropped';
|
|
1037
|
+
dropped: number;
|
|
1038
|
+
channels: Array<string | undefined>;
|
|
1039
|
+
})
|
|
890
1040
|
// Inbound acceptance observation (mcpl/inbound-source.ts): an installed
|
|
891
1041
|
// InboundAcceptanceObserver threw. Delivery is unaffected; the observer's
|
|
892
1042
|
// own coverage is interrupted for that acceptance.
|