@animalabs/agent-framework 0.27.0 → 0.29.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 +145 -41
- package/dist/src/agent.d.ts +29 -2
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +73 -12
- 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 +11 -5
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/auto-continue.d.ts +5 -2
- package/dist/src/auto-continue.d.ts.map +1 -1
- package/dist/src/auto-continue.js +9 -5
- 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/cut-off-round.d.ts +24 -0
- package/dist/src/cut-off-round.d.ts.map +1 -0
- package/dist/src/cut-off-round.js +87 -0
- package/dist/src/cut-off-round.js.map +1 -0
- package/dist/src/framework.d.ts +468 -125
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +3651 -1111
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +133 -13
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +654 -59
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/gate/index.d.ts +3 -2
- package/dist/src/gate/index.d.ts.map +1 -1
- package/dist/src/gate/index.js +2 -1
- package/dist/src/gate/index.js.map +1 -1
- package/dist/src/gate/reply-judge.d.ts +116 -0
- package/dist/src/gate/reply-judge.d.ts.map +1 -0
- package/dist/src/gate/reply-judge.js +467 -0
- package/dist/src/gate/reply-judge.js.map +1 -0
- package/dist/src/gate/types.d.ts +173 -2
- package/dist/src/gate/types.d.ts.map +1 -1
- package/dist/src/heartbeat/heartbeat.d.ts +202 -0
- package/dist/src/heartbeat/heartbeat.d.ts.map +1 -0
- package/dist/src/heartbeat/heartbeat.js +778 -0
- package/dist/src/heartbeat/heartbeat.js.map +1 -0
- package/dist/src/heartbeat/reminder-time.d.ts +5 -0
- package/dist/src/heartbeat/reminder-time.d.ts.map +1 -0
- package/dist/src/heartbeat/reminder-time.js +107 -0
- package/dist/src/heartbeat/reminder-time.js.map +1 -0
- package/dist/src/held-writes.d.ts +3 -3
- package/dist/src/held-writes.js +3 -3
- package/dist/src/host-presentation.d.ts +170 -0
- package/dist/src/host-presentation.d.ts.map +1 -0
- package/dist/src/host-presentation.js +561 -0
- package/dist/src/host-presentation.js.map +1 -0
- package/dist/src/index.d.ts +5 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- 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/capability-mask.d.ts.map +1 -1
- package/dist/src/mcpl/capability-mask.js +3 -2
- package/dist/src/mcpl/capability-mask.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +34 -6
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +133 -54
- 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 +29 -11
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +43 -70
- 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-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 +18 -8
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +70 -30
- 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/tags.d.ts +9 -2
- package/dist/src/mcpl/tags.d.ts.map +1 -1
- package/dist/src/mcpl/tags.js +12 -2
- package/dist/src/mcpl/tags.js.map +1 -1
- package/dist/src/mcpl/tool-presence.d.ts +66 -14
- package/dist/src/mcpl/tool-presence.d.ts.map +1 -1
- package/dist/src/mcpl/tool-presence.js +150 -80
- package/dist/src/mcpl/tool-presence.js.map +1 -1
- package/dist/src/mcpl/tool-signature.d.ts +10 -3
- package/dist/src/mcpl/tool-signature.d.ts.map +1 -1
- package/dist/src/mcpl/tool-signature.js +60 -30
- package/dist/src/mcpl/tool-signature.js.map +1 -1
- package/dist/src/mcpl/toolset-host.d.ts +88 -55
- package/dist/src/mcpl/toolset-host.d.ts.map +1 -1
- package/dist/src/mcpl/toolset-host.js +220 -111
- package/dist/src/mcpl/toolset-host.js.map +1 -1
- package/dist/src/mcpl/toolsets-module.d.ts +27 -35
- package/dist/src/mcpl/toolsets-module.d.ts.map +1 -1
- package/dist/src/mcpl/toolsets-module.js +313 -91
- 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 +31 -13
- 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 +10 -8
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +15 -9
- 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.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +30 -17
- 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 +26 -0
- package/dist/src/modules/workspace/answers.d.ts.map +1 -0
- package/dist/src/modules/workspace/answers.js +138 -0
- package/dist/src/modules/workspace/answers.js.map +1 -0
- package/dist/src/modules/workspace/branch-intent.d.ts +5 -3
- package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
- package/dist/src/modules/workspace/branch-intent.js +6 -2
- package/dist/src/modules/workspace/branch-intent.js.map +1 -1
- package/dist/src/modules/workspace/direct-write.d.ts +3 -0
- package/dist/src/modules/workspace/direct-write.d.ts.map +1 -1
- package/dist/src/modules/workspace/direct-write.js +59 -24
- package/dist/src/modules/workspace/direct-write.js.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.d.ts +33 -11
- package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.js +48 -17
- package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
- package/dist/src/modules/workspace/edit-text.d.ts +2 -1
- package/dist/src/modules/workspace/edit-text.d.ts.map +1 -1
- package/dist/src/modules/workspace/edit-text.js +4 -2
- package/dist/src/modules/workspace/edit-text.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 +67 -50
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +63 -51
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +980 -547
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +125 -82
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +465 -241
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/read-page.d.ts.map +1 -1
- package/dist/src/modules/workspace/read-page.js +7 -1
- package/dist/src/modules/workspace/read-page.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 +156 -50
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/modules/workspace/result-text.d.ts +1 -0
- package/dist/src/modules/workspace/result-text.d.ts.map +1 -1
- package/dist/src/modules/workspace/result-text.js.map +1 -1
- package/dist/src/modules/workspace/sync.d.ts +9 -0
- package/dist/src/modules/workspace/sync.d.ts.map +1 -1
- package/dist/src/modules/workspace/sync.js +14 -0
- package/dist/src/modules/workspace/sync.js.map +1 -1
- package/dist/src/modules/workspace/types.d.ts +96 -43
- package/dist/src/modules/workspace/types.d.ts.map +1 -1
- package/dist/src/modules/workspace/types.js.map +1 -1
- package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
- package/dist/src/modules/workspace/watcher.js +8 -3
- package/dist/src/modules/workspace/watcher.js.map +1 -1
- package/dist/src/notice-tags.d.ts +79 -0
- package/dist/src/notice-tags.d.ts.map +1 -0
- package/dist/src/notice-tags.js +83 -0
- package/dist/src/notice-tags.js.map +1 -0
- package/dist/src/prose-drafts.d.ts +4 -3
- package/dist/src/prose-drafts.d.ts.map +1 -1
- package/dist/src/prose-drafts.js +3 -2
- package/dist/src/prose-drafts.js.map +1 -1
- package/dist/src/reasoning-loss-notice.d.ts +23 -0
- package/dist/src/reasoning-loss-notice.d.ts.map +1 -0
- package/dist/src/reasoning-loss-notice.js +52 -0
- package/dist/src/reasoning-loss-notice.js.map +1 -0
- package/dist/src/reasoning-loss.d.ts +24 -0
- package/dist/src/reasoning-loss.d.ts.map +1 -0
- package/dist/src/reasoning-loss.js +102 -0
- package/dist/src/reasoning-loss.js.map +1 -0
- package/dist/src/send-tools.d.ts +3 -2
- package/dist/src/send-tools.d.ts.map +1 -1
- package/dist/src/send-tools.js +3 -2
- package/dist/src/send-tools.js.map +1 -1
- package/dist/src/sent-rows.js +1 -1
- package/dist/src/silent-heartbeat.d.ts +1 -53
- package/dist/src/silent-heartbeat.d.ts.map +1 -1
- package/dist/src/silent-heartbeat.js +56 -3
- package/dist/src/silent-heartbeat.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/thinking-drops.d.ts +4 -11
- package/dist/src/thinking-drops.d.ts.map +1 -1
- package/dist/src/thinking-drops.js +7 -14
- package/dist/src/thinking-drops.js.map +1 -1
- package/dist/src/tool-args.d.ts +12 -0
- package/dist/src/tool-args.d.ts.map +1 -1
- package/dist/src/tool-args.js +39 -4
- 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/tool-result-guard.d.ts +8 -4
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +23 -11
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +3 -2
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +24 -26
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/tune-out/tools.d.ts +4 -1
- package/dist/src/tune-out/tools.d.ts.map +1 -1
- package/dist/src/types/agent.d.ts +63 -18
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +18 -8
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +58 -0
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +27 -13
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +34 -1
- package/dist/src/types/trace.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/agent.ts +76 -12
- package/src/api/mcp-server-core.ts +3 -14
- package/src/api/server.ts +11 -5
- package/src/auto-continue.ts +12 -5
- package/src/code-execution/isolate/runner.ts +7 -5
- package/src/code-execution/isolate/scripts.ts +3 -2
- package/src/cut-off-round.ts +98 -0
- package/src/framework.ts +3772 -1138
- package/src/gate/event-gate.ts +705 -60
- package/src/gate/index.ts +9 -1
- package/src/gate/reply-judge.ts +512 -0
- package/src/gate/types.ts +176 -3
- package/src/heartbeat/heartbeat.ts +843 -0
- package/src/heartbeat/reminder-time.ts +107 -0
- package/src/held-writes.ts +3 -3
- package/src/host-presentation.ts +605 -0
- package/src/index.ts +5 -1
- package/src/line-reader.ts +58 -0
- package/src/mcpl/capability-mask.ts +3 -2
- package/src/mcpl/channel-registry.ts +139 -53
- 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 +45 -70
- package/src/mcpl/modern-connection.ts +11 -7
- package/src/mcpl/protocol-family.ts +24 -3
- package/src/mcpl/push-handler.ts +2 -2
- package/src/mcpl/references.ts +31 -23
- package/src/mcpl/server-connection.ts +76 -34
- package/src/mcpl/skip-reply-wake.ts +35 -0
- package/src/mcpl/tags.ts +13 -2
- package/src/mcpl/tool-presence.ts +149 -82
- package/src/mcpl/tool-signature.ts +64 -32
- package/src/mcpl/toolset-host.ts +212 -110
- package/src/mcpl/toolsets-module.ts +277 -91
- package/src/mcpl/transport.ts +18 -14
- package/src/mcpl/types.ts +32 -13
- package/src/module-registry.ts +14 -9
- package/src/modules/api/index.ts +4 -2
- package/src/modules/discord/index.ts +37 -25
- package/src/modules/history/index.ts +30 -18
- package/src/modules/sender-name.ts +9 -0
- package/src/modules/workspace/answers.ts +151 -0
- package/src/modules/workspace/branch-intent.ts +10 -5
- package/src/modules/workspace/direct-write.ts +59 -23
- package/src/modules/workspace/disk-agreement.ts +52 -21
- package/src/modules/workspace/edit-text.ts +7 -5
- package/src/modules/workspace/effects.ts +69 -50
- package/src/modules/workspace/index.ts +966 -556
- package/src/modules/workspace/observe.ts +497 -242
- package/src/modules/workspace/read-page.ts +7 -1
- package/src/modules/workspace/reconcile.ts +184 -49
- package/src/modules/workspace/result-text.ts +2 -0
- package/src/modules/workspace/sync.ts +16 -0
- package/src/modules/workspace/types.ts +96 -43
- package/src/modules/workspace/watcher.ts +8 -3
- package/src/notice-tags.ts +84 -0
- package/src/prose-drafts.ts +4 -3
- package/src/reasoning-loss-notice.ts +64 -0
- package/src/reasoning-loss.ts +120 -0
- package/src/send-tools.ts +3 -2
- package/src/sent-rows.ts +1 -1
- package/src/silent-heartbeat.ts +4 -3
- package/src/supplied-text.ts +154 -0
- package/src/thinking-drops.ts +10 -16
- package/src/tool-args.ts +38 -4
- package/src/tool-image-ledger.ts +2 -1
- package/src/tool-presentation.ts +5 -4
- package/src/tool-result-guard.ts +26 -11
- package/src/tune-out/coordinator.ts +25 -27
- package/src/tune-out/tools.ts +4 -1
- package/src/types/agent.ts +63 -18
- package/src/types/events.ts +18 -8
- package/src/types/framework.ts +59 -0
- package/src/types/module.ts +28 -13
- package/src/types/trace.ts +36 -1
|
@@ -58,7 +58,7 @@ export interface MountConfig {
|
|
|
58
58
|
* link is read and written where it leads now. Where that root now lies
|
|
59
59
|
* elsewhere than the last start placed it, each call nests in it, as a
|
|
60
60
|
* start would now, every mount
|
|
61
|
-
* configured beneath its path, where that path leads beneath its root,
|
|
61
|
+
* configured on or beneath its path, where that path leads beneath its root,
|
|
62
62
|
* and every other mount whose root, as that start placed it, lies
|
|
63
63
|
* beneath where its root lies now, or whose configured path lies
|
|
64
64
|
* beneath a directory that start found there. A mount configured
|
|
@@ -101,10 +101,32 @@ export interface MountConfig {
|
|
|
101
101
|
/** Poll interval in ms for checking watched root identity changes (default: 2000) */
|
|
102
102
|
watchRootPollMs?: number;
|
|
103
103
|
/**
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
104
|
+
* Patterns in these of gitignore's forms, each covering the files
|
|
105
|
+
* gitignore's reading of it covers, with three differences: names compare
|
|
106
|
+
* exactly, as git's do with `core.ignorecase` off (its default folds case
|
|
107
|
+
* on macOS and Windows); "?" matches one character where git's matches
|
|
108
|
+
* one byte, so the two differ on names outside ASCII; and on a mount that
|
|
109
|
+
* follows links, a link to a directory counts as a directory, where git
|
|
110
|
+
* reads every link as a file:
|
|
111
|
+
* - A name, matched at any depth: ".git", "node_modules". Within a name,
|
|
112
|
+
* "*" matches any run of characters and "?" any one: "*.pyc",
|
|
113
|
+
* "npm-debug.log*".
|
|
114
|
+
* - A trailing "/" matches only a directory: "build/" covers every
|
|
115
|
+
* directory named build, with what lies beneath it, and no file of that
|
|
116
|
+
* name.
|
|
117
|
+
* - A leading or inner "/" makes a path from the mount's root: "/dist"
|
|
118
|
+
* covers only the root's dist, and "a/b" only the root's a/b.
|
|
119
|
+
* - "**" as the first segment, before one name, matches that name at any
|
|
120
|
+
* depth, as the name alone does; with a trailing "/**" as well, it reads
|
|
121
|
+
* as the name with a trailing "/".
|
|
122
|
+
* - A trailing "/**" covers a directory from the root and what lies
|
|
123
|
+
* beneath it: "node_modules/**" covers only the root's node_modules, and
|
|
124
|
+
* no file of that name.
|
|
125
|
+
* The module refuses, when it's built, a pattern of any other form, such as
|
|
126
|
+
* a leading "!" or "#", a "[", a "\", a trailing space, "**" anywhere
|
|
127
|
+
* else, or an empty, "." or ".." segment, naming the pattern and why. A
|
|
128
|
+
* "?" can stand for a "[" or "\" in a name.
|
|
129
|
+
*
|
|
108
130
|
* A sync without a path and the watcher pass over what the list covers,
|
|
109
131
|
* and over entries with an editor's swap or backup file name whatever it
|
|
110
132
|
* says, a directory with what lies beneath it: `.name.swp` and `.name.swx`
|
|
@@ -124,13 +146,17 @@ export interface MountConfig {
|
|
|
124
146
|
ignore?: string[];
|
|
125
147
|
/**
|
|
126
148
|
* The files this mount holds, when it holds only some of what is under its
|
|
127
|
-
* path:
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
149
|
+
* path: patterns in `ignore`'s forms, read for files, and a `[` read as
|
|
150
|
+
* itself, so `[id].tsx` names that file. A pattern that matches
|
|
151
|
+
* only directories, with a trailing `/` or `/**`, covers what lies beneath a
|
|
152
|
+
* directory it matches: `fixtures/` every file beneath a directory named
|
|
153
|
+
* fixtures, at any depth, and `docs/**` or `/docs/` every file beneath the
|
|
154
|
+
* root's docs. Any other pattern covers a file by its own name, at any
|
|
155
|
+
* depth, or by its path from the root (`/gate.json`, `src/*.ts`). Unlike
|
|
156
|
+
* `ignore`, such a pattern covers nothing beneath a directory it matches,
|
|
157
|
+
* since each file is covered by its own name or path: `["gate.json"]` holds
|
|
158
|
+
* every file named `gate.json`, and no other file beneath a directory of
|
|
159
|
+
* that name.
|
|
134
160
|
*
|
|
135
161
|
* It's the mount's boundary for content: no workspace path reads, stores,
|
|
136
162
|
* serves or writes back a file it doesn't cover, and no tool lists,
|
|
@@ -199,31 +225,62 @@ export interface MountConfig {
|
|
|
199
225
|
* A path in a nested mount's directory is that mount's, whatever this
|
|
200
226
|
* include covers: every tool gives the answer that names the mount holding
|
|
201
227
|
* it and the path to use there. Through a link a mount follows, a place in
|
|
202
|
-
* that directory is named only where it's a directory, or a file
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
* directory
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
* mount
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
228
|
+
* that directory is named only where it's a directory, or a file covered,
|
|
229
|
+
* with no file on its way, by that mount's own include and by the include
|
|
230
|
+
* of each other nested mount whose directory may hold it, from the
|
|
231
|
+
* innermost out to the first that surely holds it, and is otherwise
|
|
232
|
+
* refused as leaving the mount. A listing, or a pass, names a file there
|
|
233
|
+
* only where those includes cover it. On a mount that doesn't follow
|
|
234
|
+
* links, a link on a path's way is refused, as on any such mount
|
|
235
|
+
* (followSymlinks).
|
|
236
|
+
* Every check compares a path with a nested mount's directory level by
|
|
237
|
+
* level, as any disk may compare names: in either Unicode normalization
|
|
238
|
+
* form and in any case, as fully as a disk that folds names may compare
|
|
239
|
+
* them, at every level, whatever the disk does there, and reading nothing
|
|
240
|
+
* from the disk to do so. Start places each root the same way, so a mount
|
|
241
|
+
* configured through a link, or in a spelling, other than disk's is found
|
|
242
|
+
* nested. So a path, a walk or the workspace's history that names the
|
|
243
|
+
* directory in any spelling a disk may take for it reaches that mount,
|
|
244
|
+
* whether or not the directory is on disk yet, and so does a link whose
|
|
245
|
+
* target spells it otherwise. Where a link leads into the directory, the
|
|
246
|
+
* place beneath it is judged, and named, as disk spells it. A path that names the directory itself keeps what lies
|
|
247
|
+
* beneath as given, since that is the nested mount's to name. Where a disk
|
|
248
|
+
* keeps apart two names the comparison joins, it errs toward the nested
|
|
249
|
+
* mount, in where start places a mount as in every check: a name in
|
|
250
|
+
* another case, on a disk that tells case apart; a name in the other
|
|
251
|
+
* normalization form, on a disk that keeps the forms apart; and a name the
|
|
252
|
+
* comparison folds with it that a disk keeps apart, such as `ss` beside a
|
|
253
|
+
* nested `ß`, or one that differs from it only by a default-ignorable code
|
|
254
|
+
* point, such as a soft hyphen, on a disk that keeps those. Such a
|
|
255
|
+
* directory, or file, is no mount's, and every tool that names it is
|
|
256
|
+
* refused as a path that may lie in the nested mount, with the two
|
|
257
|
+
* spellings the workspace can't tell apart, and, for a link, where it
|
|
258
|
+
* leads, when that lies in this mount. The answer gives a step for each
|
|
259
|
+
* thing the caller may have meant: that mount's path to use; for a new
|
|
260
|
+
* file of this mount's, a path outside both spellings; and for one already
|
|
261
|
+
* there, whoever runs the workspace renaming one of the two spellings.
|
|
262
|
+
* Where start placed the nested mount only by a guess, comparing the real
|
|
263
|
+
* roots, as for two mounts' roots configured in spellings it can't tell
|
|
264
|
+
* apart, a path there is a guess too, however exactly it matches, and the
|
|
265
|
+
* answer names that directory as the path spells it, with the nested
|
|
266
|
+
* directory's spelling only in the step for a new file, names no host
|
|
267
|
+
* path, and asks for the configuration to be checked. Three cases fall
|
|
268
|
+
* outside this, as for any nested mount, and a fourth on a direct one: on a
|
|
269
|
+
* disk whose folding goes past the comparison's, which joins names that
|
|
270
|
+
* differ only by default-ignorable code points, in normalization form or in
|
|
271
|
+
* case, in full case folding, as Linux's casefold does, a name the
|
|
272
|
+
* comparison keeps apart can reach the directory; a second path to the
|
|
273
|
+
* directory that isn't a link, such as a bind mount, isn't found to lead
|
|
274
|
+
* there, though a walk passes over it, knowing each nested root by which
|
|
275
|
+
* directory it is; a nested mount whose root moves while running, as
|
|
276
|
+
* `acceptRoot` takes, stays placed where it was until the next start, but
|
|
277
|
+
* for the calls of a direct mount whose root has moved and on or beneath
|
|
278
|
+
* whose path it's configured, which place it where it lies; and where a
|
|
279
|
+
* direct mount's root is repointed between a read's parse and its open, or
|
|
280
|
+
* a write's parse and its staging, a race left to whoever writes the disk,
|
|
281
|
+
* a mount nested in it by its directories alone, since its real root holds
|
|
282
|
+
* that root, can have the read serve a path in its directory, or the write
|
|
283
|
+
* land there.
|
|
227
284
|
*
|
|
228
285
|
* Text the host registers for a path (`registerGeneratedTextFile`) is
|
|
229
286
|
* served there whatever the include says, since it isn't one of the
|
|
@@ -237,12 +294,8 @@ export interface MountConfig {
|
|
|
237
294
|
* include covers it.
|
|
238
295
|
*
|
|
239
296
|
* Left out, the mount holds everything under its path. Given, it's a list
|
|
240
|
-
* of at least one
|
|
241
|
-
*
|
|
242
|
-
* with a `/` that isn't such a glob, a `*` anywhere but a leading `*.` or
|
|
243
|
-
* that trailing `/**`, an empty, `.` or `..` segment, and, where `\` is the
|
|
244
|
-
* platform's separator, a `\`. Any other pattern is a file name, matched
|
|
245
|
-
* literally, so `[id].tsx` names the file of that name.
|
|
297
|
+
* of at least one pattern, and the module refuses one `ignore` would
|
|
298
|
+
* refuse but for a `[`.
|
|
246
299
|
*/
|
|
247
300
|
include?: string[];
|
|
248
301
|
/**
|
|
@@ -126,10 +126,15 @@ export class MountWatcher {
|
|
|
126
126
|
// another mount's directory, the mount's ignore list and editors' swap
|
|
127
127
|
// and backup files. chokidar 4
|
|
128
128
|
// compares a string given here with the whole absolute path, so the
|
|
129
|
-
// list itself would match nothing.
|
|
130
|
-
|
|
129
|
+
// list itself would match nothing. It asks without stats before it
|
|
130
|
+
// stats a path, asking again with them before it watches the path, and
|
|
131
|
+
// when a path it watches is removed. So where it gives no kind, no
|
|
132
|
+
// directory-only pattern matches: a directory one matches never passed
|
|
133
|
+
// the check with its stats, so it is never watched, and its removal
|
|
134
|
+
// never reported.
|
|
135
|
+
ignored: (path: string, stats?: Stats) => {
|
|
131
136
|
const relative = this.toRelative(path);
|
|
132
|
-
return relative !== null && passedOverAt(relative, ignore, this.others) !== undefined;
|
|
137
|
+
return relative !== null && passedOverAt(relative, ignore, this.others, stats?.isDirectory() ?? false) !== undefined;
|
|
133
138
|
},
|
|
134
139
|
// Its filter for editors' files tested the whole path, so a directory
|
|
135
140
|
// with a dot in its name hid every `*.swp` beneath it, and the walk
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build every fixed bracket opening the framework writes into an agent's
|
|
3
|
+
* context outside a tool result (a notice, a heartbeat or reminder text, a
|
|
4
|
+
* placeholder in a message's content) from a tag here, as `[tag]`,
|
|
5
|
+
* `[tag: …]` or `[tag …]`: text the framework didn't write is marked
|
|
6
|
+
* wherever it would open with one of these (supplied-text.ts). A toolset's
|
|
7
|
+
* `[server/toolset:instance]` label is built from its server's id and names
|
|
8
|
+
* instead.
|
|
9
|
+
*/
|
|
10
|
+
export const NOTICE_TAG = {
|
|
11
|
+
turnInterrupted: 'turn-interrupted',
|
|
12
|
+
closedChannel: 'closed channel',
|
|
13
|
+
tunedOut: 'tuned out',
|
|
14
|
+
refusalRewind: 'refusal-rewind',
|
|
15
|
+
drafts: 'drafts',
|
|
16
|
+
delivered: 'delivered',
|
|
17
|
+
routing: 'routing',
|
|
18
|
+
channels: 'channels',
|
|
19
|
+
continue: 'continue',
|
|
20
|
+
proseRouting: 'prose-routing',
|
|
21
|
+
toolBoundary: 'tool-boundary',
|
|
22
|
+
gate: 'Gate',
|
|
23
|
+
selfWake: 'self-wake',
|
|
24
|
+
discordSendFailed: 'discord-send-failed',
|
|
25
|
+
sendUndeliverable: 'send-undeliverable',
|
|
26
|
+
inferenceFailed: 'inference-failed',
|
|
27
|
+
speechNotPosted: 'speech-not-posted',
|
|
28
|
+
reasoning: 'reasoning',
|
|
29
|
+
workspace: 'workspace',
|
|
30
|
+
workspaceEvent: 'workspace event',
|
|
31
|
+
conflictsWithDisk: 'conflicts with disk',
|
|
32
|
+
tuneOut: 'Tune-out',
|
|
33
|
+
tuneOutWake: 'Tune-out wake',
|
|
34
|
+
tuneOutCadence: 'Tune-out cadence',
|
|
35
|
+
tuneOutCancelled: 'Tune-out cancelled',
|
|
36
|
+
standingDispositions: 'Standing dispositions',
|
|
37
|
+
channelInvitation: 'Channel invitation',
|
|
38
|
+
system: 'system',
|
|
39
|
+
toolsets: 'toolsets',
|
|
40
|
+
heartbeat: 'heartbeat',
|
|
41
|
+
silentHeartbeat: 'silent heartbeat',
|
|
42
|
+
heartbeatTick: 'heartbeat tick',
|
|
43
|
+
heartbeatContinue: 'Continue',
|
|
44
|
+
currentTime: 'current time',
|
|
45
|
+
reminder: 'reminder',
|
|
46
|
+
attachment: 'Attachment',
|
|
47
|
+
emptyMessage: 'Empty message',
|
|
48
|
+
imageNotShown: 'Image not shown',
|
|
49
|
+
audioNotShown: 'Audio not shown',
|
|
50
|
+
contentNotShown: 'Content not shown',
|
|
51
|
+
resourceNotShown: 'Resource not shown',
|
|
52
|
+
referenceNotShown: 'Reference not shown',
|
|
53
|
+
textNotShown: 'Text not shown',
|
|
54
|
+
reference: 'reference',
|
|
55
|
+
referenceId: 'ref',
|
|
56
|
+
resourceLink: 'resource link',
|
|
57
|
+
withheld: 'withheld',
|
|
58
|
+
unserializableConnectorValue: 'unserializable connector value',
|
|
59
|
+
unprintableValue: 'a value that cannot be printed',
|
|
60
|
+
undescribedFailure: 'failure could not be described',
|
|
61
|
+
script: 'script',
|
|
62
|
+
truncated: 'truncated',
|
|
63
|
+
cutToFit: 'cut to fit',
|
|
64
|
+
blockNotShown: 'block not shown',
|
|
65
|
+
} as const;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The bracket openings context-manager 0.23.0 and 0.23.1 write into an
|
|
69
|
+
* agent's context outside a tool result or read back from it, marked as the
|
|
70
|
+
* framework's own are. Check them against each context-manager release the
|
|
71
|
+
* framework takes.
|
|
72
|
+
*/
|
|
73
|
+
export const CONTEXT_MANAGER_TAGS = [
|
|
74
|
+
'content omitted', 'image not shown', 'Operator note', 'Recall', 'tool call omitted', 'tool result moved', 'Topic Transition',
|
|
75
|
+
] as const;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The bracket openings membrane 0.8.0 writes into an agent's request outside
|
|
79
|
+
* a tool result, marked as the framework's own are. Check them against each
|
|
80
|
+
* membrane release the framework takes.
|
|
81
|
+
*/
|
|
82
|
+
export const MEMBRANE_TAGS = [
|
|
83
|
+
'Audio', 'continuing', 'Document', 'duplicate tool_result for', 'Image', 'orphan tool_result for', 'Start', 'Tool Result', 'Video',
|
|
84
|
+
] as const;
|
package/src/prose-drafts.ts
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Held prose drafts: a resident's plain speech that was not sent.
|
|
3
3
|
*
|
|
4
4
|
* Plain speech is held back for reasons that are right in themselves: an
|
|
5
|
-
* explicit send
|
|
6
|
-
*
|
|
5
|
+
* explicit send suppresses plain speech aimed where it may have posted, in
|
|
6
|
+
* its round and the turn's later ones (so a "sent it" postscript is not
|
|
7
|
+
* posted twice), a turn may have no destination, and a
|
|
7
8
|
* malformed or unresolvable routing prefix bounces. Before drafts, the held words were
|
|
8
9
|
* kept only as a count (or, in explicit mode, as one in-memory latest-wins
|
|
9
10
|
* clipboard): the law was right, and the penalty was amnesia. A draft keeps
|
|
@@ -53,7 +54,7 @@ export const PROSE_DRAFT_RECORD_TYPE = 'framework/prose-draft';
|
|
|
53
54
|
|
|
54
55
|
/** Why words were held instead of sent. */
|
|
55
56
|
export type DraftReason =
|
|
56
|
-
/** An explicit send in
|
|
57
|
+
/** An explicit send in its turn may have posted where the speech was going. */
|
|
57
58
|
| 'explicit-send'
|
|
58
59
|
/** The speech had no destination (no route this turn, or a failed envelope). */
|
|
59
60
|
| 'no-destination'
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { NOTICE_TAG } from './notice-tags.js';
|
|
2
|
+
import { oneLine, suppliedValue } from './supplied-text.js';
|
|
3
|
+
import { safeSlice } from './safe-slice.js';
|
|
4
|
+
|
|
5
|
+
export type ReasoningLossCause = 'tools' | 'system' | 'model';
|
|
6
|
+
|
|
7
|
+
export type ReasoningLossAnchor = { text: string } | { toolCall: string };
|
|
8
|
+
|
|
9
|
+
export interface ReasoningLossNoticeInput {
|
|
10
|
+
agentName: string;
|
|
11
|
+
scope:
|
|
12
|
+
| { kind: 'all'; through?: ReasoningLossAnchor; thisTurn: boolean }
|
|
13
|
+
| { kind: 'some'; count: number; first?: ReasoningLossAnchor; unplaced?: boolean; thisTurn: boolean };
|
|
14
|
+
causes: readonly ReasoningLossCause[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const ANCHOR_CHARS = 80;
|
|
18
|
+
|
|
19
|
+
const CAUSE_WORDS: Record<ReasoningLossCause, string> = {
|
|
20
|
+
tools: 'your tools changed',
|
|
21
|
+
system: 'your system prompt changed',
|
|
22
|
+
model: 'your model changed',
|
|
23
|
+
};
|
|
24
|
+
const CAUSE_ORDER: readonly ReasoningLossCause[] = ['tools', 'system', 'model'];
|
|
25
|
+
|
|
26
|
+
export function reasoningLossNotice(input: ReasoningLossNoticeInput): string {
|
|
27
|
+
const causes = CAUSE_ORDER.filter((c) => input.causes.includes(c)).map((c) => CAUSE_WORDS[c]);
|
|
28
|
+
const because = causes.length > 0 ? `, because ${joinAnd(causes)}` : '';
|
|
29
|
+
const scope = input.scope;
|
|
30
|
+
let lost: string;
|
|
31
|
+
let reread: string;
|
|
32
|
+
if (scope.kind === 'all') {
|
|
33
|
+
const through = scope.through ? anchorWords(scope.through) : undefined;
|
|
34
|
+
const among = scope.thisTurn ? ", this turn's earlier steps among them," : '';
|
|
35
|
+
lost = through
|
|
36
|
+
? `The reasoning behind your replies up to the one ${through}${among} is no longer in your context${because}.`
|
|
37
|
+
: `The reasoning behind your earlier replies${among} is no longer in your context${because}.`;
|
|
38
|
+
reread = 'Re-read before relying on an earlier decision.';
|
|
39
|
+
} else {
|
|
40
|
+
const one = scope.count === 1 && !scope.unplaced;
|
|
41
|
+
const replies = scope.unplaced
|
|
42
|
+
? `at least ${scope.count} of your replies`
|
|
43
|
+
: one ? 'one of your replies' : `${scope.count} of your replies`;
|
|
44
|
+
const named = scope.first && !scope.unplaced ? anchorWords(scope.first) : undefined;
|
|
45
|
+
const first = named ? (one ? `, the one ${named}` : `, the first being the one ${named}`) : '';
|
|
46
|
+
const among = scope.thisTurn ? (one ? ', an earlier step of this turn' : ", this turn's earlier steps among them") : '';
|
|
47
|
+
lost = `Some of your earlier reasoning is no longer in your context: the reasoning behind ${replies}${first}${among}${because}.`;
|
|
48
|
+
reread = named ? 'Re-read before relying on a decision made since then.' : 'Re-read before relying on an earlier decision.';
|
|
49
|
+
}
|
|
50
|
+
return `[${NOTICE_TAG.reasoning}] ${input.agentName}: ${lost} Their words are still here. ${reread}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function anchorWords(anchor: ReasoningLossAnchor): string | undefined {
|
|
54
|
+
if ('toolCall' in anchor) return anchor.toolCall ? `that called \`${suppliedValue(anchor.toolCall)}\`` : undefined;
|
|
55
|
+
const text = oneLine(anchor.text).replace(/\s+/g, ' ').trim();
|
|
56
|
+
if (!text) return undefined;
|
|
57
|
+
const clipped = text.length > ANCHOR_CHARS ? `${safeSlice(text, 0, ANCHOR_CHARS).trimEnd()}…` : text;
|
|
58
|
+
return `beginning "${clipped}"`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function joinAnd(parts: readonly string[]): string {
|
|
62
|
+
if (parts.length <= 1) return parts.join('');
|
|
63
|
+
return `${parts.slice(0, -1).join(', ')} and ${parts[parts.length - 1]}`;
|
|
64
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { ContentBlock } from '@animalabs/membrane';
|
|
2
|
+
import type { MessageId, ThinkingStrip } from '@animalabs/context-manager';
|
|
3
|
+
import { ThinkingLossIncidents, type PlacedDrop } from './thinking-drops.js';
|
|
4
|
+
import {
|
|
5
|
+
reasoningLossNotice,
|
|
6
|
+
type ReasoningLossAnchor,
|
|
7
|
+
type ReasoningLossCause,
|
|
8
|
+
} from './reasoning-loss-notice.js';
|
|
9
|
+
|
|
10
|
+
export interface StoredReplyReader {
|
|
11
|
+
getMessage(id: MessageId): { sequence: number; content: readonly ContentBlock[] } | null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ReasoningLossTurn {
|
|
15
|
+
start?: { branch: string; sequence: number };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const HEAD_CAUSES: Partial<Record<NonNullable<ThinkingStrip['changed']>[number], ReasoningLossCause>> = {
|
|
19
|
+
tools: 'tools',
|
|
20
|
+
system: 'system',
|
|
21
|
+
model: 'model',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export class ReasoningLossTeller {
|
|
25
|
+
private readonly told = new Map<string, Map<string, Set<MessageId>>>();
|
|
26
|
+
private readonly drops = new ThinkingLossIncidents();
|
|
27
|
+
|
|
28
|
+
forStrip(
|
|
29
|
+
agentName: string,
|
|
30
|
+
branch: string,
|
|
31
|
+
strip: ThinkingStrip,
|
|
32
|
+
turn: ReasoningLossTurn,
|
|
33
|
+
store: StoredReplyReader,
|
|
34
|
+
): string | undefined {
|
|
35
|
+
const told = this.toldFor(agentName, branch);
|
|
36
|
+
const taken = strip.newly
|
|
37
|
+
.map((id) => ({ id, sequence: store.getMessage(id)?.sequence }))
|
|
38
|
+
.sort((a, b) => (a.sequence ?? Infinity) - (b.sequence ?? Infinity));
|
|
39
|
+
const replies = taken.filter((r) => !told.has(r.id));
|
|
40
|
+
if (replies.length === 0) return undefined;
|
|
41
|
+
const thisTurn = replies.some((r) => isThisTurn(r.sequence, branch, turn));
|
|
42
|
+
if (strip.cause === 'head') {
|
|
43
|
+
const causes = (strip.changed ?? [])
|
|
44
|
+
.map((c) => HEAD_CAUSES[c])
|
|
45
|
+
.filter((c): c is ReasoningLossCause => c !== undefined);
|
|
46
|
+
const newest = taken.filter((r) => r.sequence !== undefined).at(-1);
|
|
47
|
+
const through = newest ? anchorOf(store.getMessage(newest.id)?.content) : undefined;
|
|
48
|
+
const amongThisTurn = taken.some((r) => isThisTurn(r.sequence, branch, turn));
|
|
49
|
+
for (const r of replies) told.add(r.id);
|
|
50
|
+
return reasoningLossNotice({ agentName, scope: { kind: 'all', ...(through ? { through } : {}), thisTurn: amongThisTurn }, causes });
|
|
51
|
+
}
|
|
52
|
+
if (strip.cause !== 'first' && !taken.some((r) => isThisTurn(r.sequence, branch, turn))) return undefined;
|
|
53
|
+
const first = anchorOf(store.getMessage(replies[0]!.id)?.content);
|
|
54
|
+
for (const r of replies) told.add(r.id);
|
|
55
|
+
return reasoningLossNotice({
|
|
56
|
+
agentName,
|
|
57
|
+
scope: { kind: 'some', count: replies.length, ...(first ? { first } : {}), thisTurn },
|
|
58
|
+
causes: [],
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
forDrops(
|
|
63
|
+
agentName: string,
|
|
64
|
+
branch: string,
|
|
65
|
+
placed: readonly PlacedDrop[],
|
|
66
|
+
turn: ReasoningLossTurn,
|
|
67
|
+
store: StoredReplyReader,
|
|
68
|
+
): string | undefined {
|
|
69
|
+
const replies = new Map<MessageId, number>();
|
|
70
|
+
const rounds = new Set<number>();
|
|
71
|
+
let blocks = 0;
|
|
72
|
+
for (const drop of placed) {
|
|
73
|
+
if (drop.kind === 'unplaced') continue;
|
|
74
|
+
blocks++;
|
|
75
|
+
if (drop.kind === 'round') rounds.add(drop.round);
|
|
76
|
+
else for (const body of drop.bodies) replies.set(body.messageId, body.sequence);
|
|
77
|
+
}
|
|
78
|
+
const unplaced = blocks < placed.length;
|
|
79
|
+
const count = replies.size + rounds.size;
|
|
80
|
+
const ordered = [...replies].sort((a, b) => a[1] - b[1]);
|
|
81
|
+
const thisTurn = rounds.size > 0 || ordered.some(([, sequence]) => isThisTurn(sequence, branch, turn));
|
|
82
|
+
const first = ordered.length > 0 && !unplaced ? anchorOf(store.getMessage(ordered[0]![0])?.content) : undefined;
|
|
83
|
+
if (this.drops.observe(agentName, blocks, branch) === undefined) return undefined;
|
|
84
|
+
const told = this.toldFor(agentName, branch);
|
|
85
|
+
for (const id of replies.keys()) told.add(id);
|
|
86
|
+
return reasoningLossNotice({
|
|
87
|
+
agentName,
|
|
88
|
+
scope: { kind: 'some', count, ...(first ? { first } : {}), ...(unplaced ? { unplaced: true } : {}), thisTurn },
|
|
89
|
+
causes: [],
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
forget(agentName: string): void {
|
|
94
|
+
this.told.delete(agentName);
|
|
95
|
+
this.drops.forget(agentName);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private toldFor(agentName: string, branch: string): Set<MessageId> {
|
|
99
|
+
let branches = this.told.get(agentName);
|
|
100
|
+
if (!branches) this.told.set(agentName, (branches = new Map()));
|
|
101
|
+
let told = branches.get(branch);
|
|
102
|
+
if (!told) branches.set(branch, (told = new Set()));
|
|
103
|
+
return told;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function isThisTurn(sequence: number | undefined, branch: string, turn: ReasoningLossTurn): boolean {
|
|
108
|
+
return sequence !== undefined && turn.start?.branch === branch && sequence > turn.start.sequence;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function anchorOf(content: readonly ContentBlock[] | undefined): ReasoningLossAnchor | undefined {
|
|
112
|
+
if (!content) return undefined;
|
|
113
|
+
for (const block of content) {
|
|
114
|
+
if (block.type === 'text' && typeof block.text === 'string' && block.text.trim() !== '') return { text: block.text };
|
|
115
|
+
}
|
|
116
|
+
for (const block of content) {
|
|
117
|
+
if (block.type === 'tool_use' && typeof block.name === 'string' && block.name !== '') return { toolCall: block.name };
|
|
118
|
+
}
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
package/src/send-tools.ts
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Tools whose call delivers the resident's message to a channel or person,
|
|
3
3
|
* by bare name (an MCPL server's `<prefix>--` stripped). The framework reads
|
|
4
4
|
* a call of one as an explicit send that silences the round's auto-routed
|
|
5
|
-
* prose; the history module's semantic index reads
|
|
6
|
-
* what the resident wrote to someone, whether or not
|
|
5
|
+
* prose where it may have posted; the history module's semantic index reads
|
|
6
|
+
* its message argument as what the resident wrote to someone, whether or not
|
|
7
|
+
* it was delivered.
|
|
7
8
|
*/
|
|
8
9
|
export const SEND_TOOLS = new Set(['channel_publish', 'send_message', 'reply_message', 'send_dm']);
|
|
9
10
|
|
package/src/sent-rows.ts
CHANGED
|
@@ -152,7 +152,7 @@ export function roundRows(
|
|
|
152
152
|
* the two alike (read from the provider on 2026-10-23: Haiku 5.5 with the drop control, on an enforcing API-key
|
|
153
153
|
* organization and on a subscription account, reported no drop for either, and dropped both replies' blocks when an
|
|
154
154
|
* earlier user message changed). The store's own fields beside them, such as
|
|
155
|
-
* `toolName`, don't reach the provider on membrane's native path, the only one noted (membrane 0.
|
|
155
|
+
* `toolName`, don't reach the provider on membrane's native path, the only one noted (membrane 0.8.0's XML
|
|
156
156
|
* formatter reads `toolName`, and an XML stream is never noted).
|
|
157
157
|
*/
|
|
158
158
|
function normalizedResult(block: ContentBlock): unknown {
|
package/src/silent-heartbeat.ts
CHANGED
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
* another reply's row and rewrite cached history. Exact matching for every
|
|
51
51
|
* row would need the compile result to expose each message's source rows.
|
|
52
52
|
*/
|
|
53
|
+
import { NOTICE_TAG } from './notice-tags.js';
|
|
53
54
|
import type { ContentBlock, NormalizedMessage } from '@animalabs/membrane';
|
|
54
55
|
|
|
55
56
|
/** Request-only separator a silent tick's request ends on. It carries the
|
|
@@ -59,15 +60,15 @@ import type { ContentBlock, NormalizedMessage } from '@animalabs/membrane';
|
|
|
59
60
|
* text their request rendered (`SilentHeartbeatStamp.separator`), so changing
|
|
60
61
|
* this constant changes only ticks that open afterwards. */
|
|
61
62
|
export const SILENT_HEARTBEAT_SEPARATOR =
|
|
62
|
-
|
|
63
|
+
`[${NOTICE_TAG.silentHeartbeat}] Scheduled private self-check. Review pending matters privately. ` +
|
|
63
64
|
'Do not narrate or publish plain prose; use an explicit send tool only if you deliberately choose to contact someone.';
|
|
64
65
|
|
|
65
66
|
/** The separator ticks rendered before their rows recorded its text: rows
|
|
66
67
|
* stamped without `separator` still render it, byte for byte. */
|
|
67
|
-
const LEGACY_SILENT_HEARTBEAT_SEPARATOR =
|
|
68
|
+
const LEGACY_SILENT_HEARTBEAT_SEPARATOR = `[${NOTICE_TAG.heartbeatTick}]`;
|
|
68
69
|
|
|
69
70
|
/** Request-only turn a compile that ends on the agent's own message gets. */
|
|
70
|
-
export const CONTINUE_ROW =
|
|
71
|
+
export const CONTINUE_ROW = `[${NOTICE_TAG.heartbeatContinue}]`;
|
|
71
72
|
|
|
72
73
|
/** Identity of one authenticated silent heartbeat tick. */
|
|
73
74
|
export interface SilentHeartbeatTick {
|