@animalabs/agent-framework 0.23.1 → 0.24.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 +212 -42
- package/dist/src/agent.d.ts +60 -9
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +92 -12
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +14 -12
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/code-execution/engine.d.ts +177 -0
- package/dist/src/code-execution/engine.d.ts.map +1 -0
- package/dist/src/code-execution/engine.js +494 -0
- package/dist/src/code-execution/engine.js.map +1 -0
- package/dist/src/code-execution/index.d.ts +5 -10
- package/dist/src/code-execution/index.d.ts.map +1 -1
- package/dist/src/code-execution/index.js +5 -9
- package/dist/src/code-execution/index.js.map +1 -1
- package/dist/src/code-execution/isolate/calls.d.ts +114 -0
- package/dist/src/code-execution/isolate/calls.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/calls.js +145 -0
- package/dist/src/code-execution/isolate/calls.js.map +1 -0
- package/dist/src/code-execution/isolate/child-entry.d.ts +2 -0
- package/dist/src/code-execution/isolate/child-entry.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child-entry.js +5 -0
- package/dist/src/code-execution/isolate/child-entry.js.map +1 -0
- package/dist/src/code-execution/isolate/child-main.d.ts +26 -0
- package/dist/src/code-execution/isolate/child-main.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child-main.js +132 -0
- package/dist/src/code-execution/isolate/child-main.js.map +1 -0
- package/dist/src/code-execution/isolate/child.d.ts +44 -0
- package/dist/src/code-execution/isolate/child.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child.js +315 -0
- package/dist/src/code-execution/isolate/child.js.map +1 -0
- package/dist/src/code-execution/isolate/frames.d.ts +80 -0
- package/dist/src/code-execution/isolate/frames.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/frames.js +210 -0
- package/dist/src/code-execution/isolate/frames.js.map +1 -0
- package/dist/src/code-execution/isolate/output.d.ts +68 -0
- package/dist/src/code-execution/isolate/output.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/output.js +143 -0
- package/dist/src/code-execution/isolate/output.js.map +1 -0
- package/dist/src/code-execution/isolate/prelude.d.ts +109 -0
- package/dist/src/code-execution/isolate/prelude.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/prelude.js +401 -0
- package/dist/src/code-execution/isolate/prelude.js.map +1 -0
- package/dist/src/code-execution/isolate/protocol.d.ts +151 -0
- package/dist/src/code-execution/isolate/protocol.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/protocol.js +150 -0
- package/dist/src/code-execution/isolate/protocol.js.map +1 -0
- package/dist/src/code-execution/isolate/render.d.ts +57 -0
- package/dist/src/code-execution/isolate/render.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/render.js +214 -0
- package/dist/src/code-execution/isolate/render.js.map +1 -0
- package/dist/src/code-execution/isolate/runner.d.ts +250 -0
- package/dist/src/code-execution/isolate/runner.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/runner.js +854 -0
- package/dist/src/code-execution/isolate/runner.js.map +1 -0
- package/dist/src/code-execution/isolate/scripts.d.ts +175 -0
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/scripts.js +357 -0
- package/dist/src/code-execution/isolate/scripts.js.map +1 -0
- package/dist/src/code-execution/quickjs.wasm +0 -0
- package/dist/src/code-execution/tool-definition.d.ts +93 -43
- package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
- package/dist/src/code-execution/tool-definition.js +176 -142
- package/dist/src/code-execution/tool-definition.js.map +1 -1
- package/dist/src/deadline-timer.d.ts +3 -0
- package/dist/src/deadline-timer.d.ts.map +1 -1
- package/dist/src/deadline-timer.js +1 -1
- package/dist/src/deadline-timer.js.map +1 -1
- package/dist/src/framework.d.ts +1036 -440
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +4131 -2228
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +28 -1
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +88 -10
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/held-writes.d.ts +16 -3
- package/dist/src/held-writes.d.ts.map +1 -1
- package/dist/src/held-writes.js +16 -3
- package/dist/src/held-writes.js.map +1 -1
- package/dist/src/index.d.ts +6 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -8
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +471 -75
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +1673 -337
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts +12 -7
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +12 -7
- package/dist/src/mcpl/conversation-router.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts.map +1 -1
- package/dist/src/mcpl/convert-block.js +9 -5
- package/dist/src/mcpl/convert-block.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +50 -0
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +130 -0
- package/dist/src/mcpl/inbound-source.js.map +1 -1
- package/dist/src/mcpl/index.d.ts +2 -1
- package/dist/src/mcpl/index.d.ts.map +1 -1
- package/dist/src/mcpl/index.js +3 -2
- package/dist/src/mcpl/index.js.map +1 -1
- package/dist/src/mcpl/log-value.d.ts +6 -0
- package/dist/src/mcpl/log-value.d.ts.map +1 -1
- package/dist/src/mcpl/log-value.js +8 -0
- package/dist/src/mcpl/log-value.js.map +1 -1
- package/dist/src/mcpl/modern-connection.d.ts +15 -6
- package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
- package/dist/src/mcpl/modern-connection.js +168 -53
- package/dist/src/mcpl/modern-connection.js.map +1 -1
- package/dist/src/mcpl/prose-grammar.d.ts +4 -5
- package/dist/src/mcpl/prose-grammar.d.ts.map +1 -1
- package/dist/src/mcpl/prose-grammar.js +4 -5
- package/dist/src/mcpl/prose-grammar.js.map +1 -1
- package/dist/src/mcpl/protocol-family.d.ts +97 -10
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
- package/dist/src/mcpl/protocol-family.js +173 -16
- package/dist/src/mcpl/protocol-family.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +132 -14
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +227 -50
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts +6 -1
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js +4 -1
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/reference-fetcher.d.ts +2 -2
- package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
- package/dist/src/mcpl/reference-fetcher.js +4 -4
- package/dist/src/mcpl/reference-fetcher.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +50 -21
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +158 -74
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/tags.d.ts +24 -0
- package/dist/src/mcpl/tags.d.ts.map +1 -1
- package/dist/src/mcpl/tags.js +33 -0
- package/dist/src/mcpl/tags.js.map +1 -1
- package/dist/src/mcpl/tool-result-normalize.d.ts +2 -1
- package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -1
- package/dist/src/mcpl/tool-result-normalize.js.map +1 -1
- package/dist/src/mcpl/transport.d.ts +55 -7
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +163 -34
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +22 -6
- 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 +4 -2
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +100 -13
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +8 -13
- 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 +27 -4
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/history/semantic.d.ts +15 -3
- package/dist/src/modules/history/semantic.d.ts.map +1 -1
- package/dist/src/modules/history/semantic.js +27 -5
- package/dist/src/modules/history/semantic.js.map +1 -1
- package/dist/src/modules/index.d.ts +1 -1
- package/dist/src/modules/index.d.ts.map +1 -1
- package/dist/src/modules/index.js.map +1 -1
- package/dist/src/modules/unknown-tool.d.ts +4 -1
- package/dist/src/modules/unknown-tool.d.ts.map +1 -1
- package/dist/src/modules/unknown-tool.js +4 -1
- package/dist/src/modules/unknown-tool.js.map +1 -1
- package/dist/src/modules/workspace/branch-intent.d.ts +3 -1
- package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
- package/dist/src/modules/workspace/branch-intent.js +3 -1
- package/dist/src/modules/workspace/branch-intent.js.map +1 -1
- package/dist/src/modules/workspace/edit-plan.d.ts +265 -0
- package/dist/src/modules/workspace/edit-plan.d.ts.map +1 -0
- package/dist/src/modules/workspace/edit-plan.js +794 -0
- package/dist/src/modules/workspace/edit-plan.js.map +1 -0
- package/dist/src/modules/workspace/edit-text.d.ts +117 -0
- package/dist/src/modules/workspace/edit-text.d.ts.map +1 -0
- package/dist/src/modules/workspace/edit-text.js +584 -0
- package/dist/src/modules/workspace/edit-text.js.map +1 -0
- package/dist/src/modules/workspace/effects.d.ts +5 -4
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +78 -25
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +484 -61
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +2173 -645
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +213 -38
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +416 -36
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
- package/dist/src/modules/workspace/reconcile.js +15 -8
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/modules/workspace/text.d.ts +32 -0
- package/dist/src/modules/workspace/text.d.ts.map +1 -0
- package/dist/src/modules/workspace/text.js +67 -0
- package/dist/src/modules/workspace/text.js.map +1 -0
- package/dist/src/modules/workspace/types.d.ts +210 -6
- 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 +3 -2
- package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
- package/dist/src/modules/workspace/watcher.js.map +1 -1
- package/dist/src/operator-log.d.ts +52 -24
- package/dist/src/operator-log.d.ts.map +1 -1
- package/dist/src/operator-log.js.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.d.ts +496 -72
- package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.js +1196 -289
- package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
- package/dist/src/recovery/offline-branch.d.ts +26 -1
- package/dist/src/recovery/offline-branch.d.ts.map +1 -1
- package/dist/src/recovery/offline-branch.js +164 -39
- package/dist/src/recovery/offline-branch.js.map +1 -1
- package/dist/src/recovery/recover-cli.js +23 -4
- package/dist/src/recovery/recover-cli.js.map +1 -1
- package/dist/src/send-tools.d.ts +11 -0
- package/dist/src/send-tools.d.ts.map +1 -0
- package/dist/src/send-tools.js +11 -0
- package/dist/src/send-tools.js.map +1 -0
- package/dist/src/tool-result-guard.d.ts +4 -3
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +5 -4
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tool-result-history.d.ts +1 -1
- package/dist/src/tool-result-history.js +1 -1
- package/dist/src/tune-out/coordinator.d.ts +21 -0
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +139 -37
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/types/agent.d.ts +4 -0
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +62 -9
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +62 -58
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +40 -8
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +111 -10
- package/dist/src/types/trace.d.ts.map +1 -1
- package/dist/src/usage/types.d.ts +16 -0
- package/dist/src/usage/types.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.d.ts +14 -1
- package/dist/src/usage/usage-tracker.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.js +81 -41
- package/dist/src/usage/usage-tracker.js.map +1 -1
- package/package.json +6 -5
- package/src/agent.ts +93 -12
- package/src/api/server.ts +14 -12
- package/src/code-execution/engine.ts +595 -0
- package/src/code-execution/index.ts +5 -17
- package/src/code-execution/isolate/calls.ts +199 -0
- package/src/code-execution/isolate/child-entry.ts +5 -0
- package/src/code-execution/isolate/child-main.ts +132 -0
- package/src/code-execution/isolate/child.ts +327 -0
- package/src/code-execution/isolate/frames.ts +209 -0
- package/src/code-execution/isolate/output.ts +161 -0
- package/src/code-execution/isolate/prelude.ts +409 -0
- package/src/code-execution/isolate/protocol.ts +240 -0
- package/src/code-execution/isolate/render.ts +230 -0
- package/src/code-execution/isolate/runner.ts +911 -0
- package/src/code-execution/isolate/scripts.ts +479 -0
- package/src/code-execution/quickjs.wasm +0 -0
- package/src/code-execution/quickjs.wasm.LICENSES +149 -0
- package/src/code-execution/tool-definition.ts +236 -167
- package/src/deadline-timer.ts +1 -1
- package/src/framework.ts +4507 -2406
- package/src/gate/event-gate.ts +78 -11
- package/src/held-writes.ts +17 -3
- package/src/index.ts +30 -22
- package/src/mcpl/channel-registry.ts +1825 -368
- package/src/mcpl/conversation-router.ts +12 -7
- package/src/mcpl/convert-block.ts +9 -5
- package/src/mcpl/inbound-source.ts +131 -0
- package/src/mcpl/index.ts +4 -2
- package/src/mcpl/log-value.ts +9 -0
- package/src/mcpl/modern-connection.ts +162 -53
- package/src/mcpl/prose-grammar.ts +4 -5
- package/src/mcpl/protocol-family.ts +199 -21
- package/src/mcpl/push-coalescer.ts +306 -62
- package/src/mcpl/push-handler.ts +10 -2
- package/src/mcpl/reference-fetcher.ts +4 -4
- package/src/mcpl/server-connection.ts +180 -79
- package/src/mcpl/tags.ts +36 -0
- package/src/mcpl/tool-result-normalize.ts +2 -1
- package/src/mcpl/transport.ts +162 -33
- package/src/mcpl/types.ts +23 -6
- package/src/module-registry.ts +92 -13
- package/src/modules/discord/index.ts +8 -13
- package/src/modules/history/index.ts +25 -3
- package/src/modules/history/semantic.ts +29 -6
- package/src/modules/index.ts +1 -0
- package/src/modules/unknown-tool.ts +4 -1
- package/src/modules/workspace/branch-intent.ts +3 -1
- package/src/modules/workspace/edit-plan.ts +954 -0
- package/src/modules/workspace/edit-text.ts +618 -0
- package/src/modules/workspace/effects.ts +70 -19
- package/src/modules/workspace/index.ts +2247 -642
- package/src/modules/workspace/observe.ts +465 -56
- package/src/modules/workspace/reconcile.ts +14 -7
- package/src/modules/workspace/text.ts +68 -0
- package/src/modules/workspace/types.ts +211 -6
- package/src/modules/workspace/watcher.ts +3 -2
- package/src/operator-log.ts +47 -19
- package/src/recovery/discord-awareness-outbox.ts +1500 -356
- package/src/recovery/offline-branch.ts +189 -55
- package/src/recovery/recover-cli.ts +25 -4
- package/src/send-tools.ts +11 -0
- package/src/tool-result-guard.ts +6 -5
- package/src/tool-result-history.ts +1 -1
- package/src/tune-out/coordinator.ts +163 -42
- package/src/types/agent.ts +4 -0
- package/src/types/events.ts +62 -9
- package/src/types/framework.ts +62 -58
- package/src/types/module.ts +40 -8
- package/src/types/trace.ts +121 -15
- package/src/usage/types.ts +16 -0
- package/src/usage/usage-tracker.ts +86 -43
- package/dist/src/code-execution/py-runner.d.ts +0 -191
- package/dist/src/code-execution/py-runner.d.ts.map +0 -1
- package/dist/src/code-execution/py-runner.js +0 -655
- package/dist/src/code-execution/py-runner.js.map +0 -1
- package/dist/src/code-execution/runtime-py.d.ts +0 -50
- package/dist/src/code-execution/runtime-py.d.ts.map +0 -1
- package/dist/src/code-execution/runtime-py.js +0 -677
- package/dist/src/code-execution/runtime-py.js.map +0 -1
- package/dist/src/mcpl/prose-stream-router.d.ts +0 -88
- package/dist/src/mcpl/prose-stream-router.d.ts.map +0 -1
- package/dist/src/mcpl/prose-stream-router.js +0 -291
- package/dist/src/mcpl/prose-stream-router.js.map +0 -1
- package/src/code-execution/py-runner.ts +0 -791
- package/src/code-execution/runtime-py.ts +0 -677
- package/src/mcpl/prose-stream-router.ts +0 -268
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { JsStore } from '@animalabs/chronicle';
|
|
2
|
+
import type { SurgeryMarkerReceipt } from '../operator-log.js';
|
|
2
3
|
import { ContextManager, continuesBody, type BodyShard } from '@animalabs/context-manager';
|
|
3
4
|
import { removeStoredInterval } from '../stored-removal.js';
|
|
4
5
|
import { firstFreeBranchName } from '../branch-names.js';
|
|
5
6
|
import {
|
|
6
7
|
DEFAULT_DISCORD_AWARENESS_EMOJI,
|
|
7
8
|
DiscordAwarenessOutbox,
|
|
9
|
+
boundDiscordAwarenessText,
|
|
8
10
|
defaultDiscordAwarenessOutboxPath,
|
|
11
|
+
checkedDiscordAwarenessMarks,
|
|
9
12
|
extractDiscordAwarenessRefs,
|
|
13
|
+
selectDiscordAwarenessRefs,
|
|
14
|
+
type DiscordAwarenessMarks,
|
|
10
15
|
type DiscordAwarenessRef,
|
|
16
|
+
type DiscordMessageMetadataCarrier,
|
|
11
17
|
} from './discord-awareness-outbox.js';
|
|
12
18
|
|
|
13
19
|
export interface OfflineRecoveryBranchOptions {
|
|
@@ -29,8 +35,14 @@ export interface OfflineRecoveryBranchOptions {
|
|
|
29
35
|
namespace?: string;
|
|
30
36
|
/** Use for old message records that do not carry metadata.serverId. */
|
|
31
37
|
discordServerId?: string;
|
|
38
|
+
/** The awareness ledger (default: under the store). */
|
|
32
39
|
outboxPath?: string;
|
|
33
40
|
emoji?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Awareness marks on the removed Discord messages: an explicit publication
|
|
43
|
+
* choice, `none` by default. The recovery itself stays local either way.
|
|
44
|
+
*/
|
|
45
|
+
marks?: DiscordAwarenessMarks;
|
|
34
46
|
dryRun?: boolean;
|
|
35
47
|
}
|
|
36
48
|
|
|
@@ -40,9 +52,27 @@ export interface OfflineRecoveryBranchResult {
|
|
|
40
52
|
targetBranch: string;
|
|
41
53
|
messagesRemoved: number;
|
|
42
54
|
messagesSuppressed: number;
|
|
55
|
+
/** Removed messages that carry a Discord address. */
|
|
56
|
+
discordAddressable: number;
|
|
57
|
+
/** The publication scope recorded for this recovery. */
|
|
58
|
+
marksScope: 'none' | 'addressed' | 'all';
|
|
59
|
+
/** Marks queued for delivery (planned, for a dry run); not delivered. */
|
|
43
60
|
discordMarkersQueued: number;
|
|
61
|
+
/** What became of the marks once the branch was made (absent on a dry
|
|
62
|
+
* run): scheduling only, never Discord acceptance. */
|
|
63
|
+
markers?: SurgeryMarkerReceipt;
|
|
64
|
+
/** The refs that will be marked (empty unless marks were chosen). */
|
|
44
65
|
refs: DiscordAwarenessRef[];
|
|
66
|
+
/** Removed addressable messages the marks choice leaves unmarked (outside
|
|
67
|
+
* its scope); `markers` says whether the chosen ones are scheduled. */
|
|
68
|
+
unmarked: number;
|
|
69
|
+
/** Authorized refs (marks.refs) this recovery does not remove. */
|
|
70
|
+
notRemoved: number;
|
|
71
|
+
/** The awareness ledger the batch is recorded in. */
|
|
45
72
|
outboxPath: string;
|
|
73
|
+
/** Set when a suppression-only batch's resume record couldn't be closed:
|
|
74
|
+
* what of it is left, as the host's surgeries report it. */
|
|
75
|
+
suppressionRecord?: string;
|
|
46
76
|
}
|
|
47
77
|
|
|
48
78
|
/**
|
|
@@ -65,6 +95,10 @@ export async function createOfflineRecoveryBranch(
|
|
|
65
95
|
if (count !== undefined && (!Number.isFinite(count) || count < 1)) {
|
|
66
96
|
throw new Error('messages must be a positive integer');
|
|
67
97
|
}
|
|
98
|
+
// The marks choice is checked as the live methods check it, before the
|
|
99
|
+
// store is opened: a malformed one would otherwise mark every removed
|
|
100
|
+
// message.
|
|
101
|
+
const marks = checkedDiscordAwarenessMarks(options.marks);
|
|
68
102
|
|
|
69
103
|
const store = JsStore.openOrCreate({ path: options.storePath });
|
|
70
104
|
let contextManager: ContextManager | null = null;
|
|
@@ -84,7 +118,7 @@ export async function createOfflineRecoveryBranch(
|
|
|
84
118
|
let target: StoredWindowMessage;
|
|
85
119
|
let targetIndex: number;
|
|
86
120
|
let removedCount: number;
|
|
87
|
-
let
|
|
121
|
+
let carriers: DiscordMessageMetadataCarrier[];
|
|
88
122
|
|
|
89
123
|
if (options.messageId) {
|
|
90
124
|
// Search backward in bounded windows: recovery anchors are normally near
|
|
@@ -101,12 +135,7 @@ export async function createOfflineRecoveryBranch(
|
|
|
101
135
|
target = located.message;
|
|
102
136
|
targetIndex = located.index;
|
|
103
137
|
removedCount = total - located.index - 1;
|
|
104
|
-
|
|
105
|
-
contextManager,
|
|
106
|
-
located.index + 1,
|
|
107
|
-
total,
|
|
108
|
-
options.discordServerId,
|
|
109
|
-
);
|
|
138
|
+
carriers = collectDiscordCarriers(contextManager, located.index + 1, total);
|
|
110
139
|
} else if (options.contextId) {
|
|
111
140
|
const located = findInternalMessageFromTail(contextManager, total, options.contextId.trim());
|
|
112
141
|
if (!located) {
|
|
@@ -115,12 +144,7 @@ export async function createOfflineRecoveryBranch(
|
|
|
115
144
|
target = located.message;
|
|
116
145
|
targetIndex = located.index;
|
|
117
146
|
removedCount = total - located.index - 1;
|
|
118
|
-
|
|
119
|
-
contextManager,
|
|
120
|
-
located.index + 1,
|
|
121
|
-
total,
|
|
122
|
-
options.discordServerId,
|
|
123
|
-
);
|
|
147
|
+
carriers = collectDiscordCarriers(contextManager, located.index + 1, total);
|
|
124
148
|
} else {
|
|
125
149
|
// Count mode remains for compatibility. Read only the target plus suffix,
|
|
126
150
|
// avoiding full-history materialization and attachment blob inflation.
|
|
@@ -135,7 +159,7 @@ export async function createOfflineRecoveryBranch(
|
|
|
135
159
|
target = countTarget;
|
|
136
160
|
targetIndex = total - count! - 1;
|
|
137
161
|
removedCount = count!;
|
|
138
|
-
|
|
162
|
+
carriers = discarded.map(addressingOnly);
|
|
139
163
|
}
|
|
140
164
|
|
|
141
165
|
validateAnchorBoundary(contextManager, targetIndex, total, target);
|
|
@@ -145,7 +169,6 @@ export async function createOfflineRecoveryBranch(
|
|
|
145
169
|
targetIndex,
|
|
146
170
|
options.suppressMessageIds ?? [],
|
|
147
171
|
options.suppressRanges ?? [],
|
|
148
|
-
options.discordServerId,
|
|
149
172
|
);
|
|
150
173
|
validateRemovalIntegrity(
|
|
151
174
|
contextManager,
|
|
@@ -160,7 +183,10 @@ export async function createOfflineRecoveryBranch(
|
|
|
160
183
|
...suppression.intervals,
|
|
161
184
|
],
|
|
162
185
|
);
|
|
163
|
-
|
|
186
|
+
carriers = [...carriers, ...suppression.carriers];
|
|
187
|
+
const addressable = extractDiscordAwarenessRefs(carriers, options.discordServerId).length;
|
|
188
|
+
const selection = selectDiscordAwarenessRefs(carriers, marks, options.discordServerId);
|
|
189
|
+
const refs = selection.refs;
|
|
164
190
|
|
|
165
191
|
const sourceBranch = store.currentBranch().name;
|
|
166
192
|
const held = new Set(store.listBranches().map((branch) => branch.name));
|
|
@@ -169,6 +195,10 @@ export async function createOfflineRecoveryBranch(
|
|
|
169
195
|
if (targetBranch === sourceBranch) {
|
|
170
196
|
throw new Error('Recovery branch name must differ from the active source branch');
|
|
171
197
|
}
|
|
198
|
+
// A known collision is refused before anything is prepared.
|
|
199
|
+
if (store.listBranches().some((branch) => branch.name === targetBranch)) {
|
|
200
|
+
throw new Error(`Recovery branch ${targetBranch} already exists; choose another --branch`);
|
|
201
|
+
}
|
|
172
202
|
const outboxPath = options.outboxPath
|
|
173
203
|
?? defaultDiscordAwarenessOutboxPath(options.storePath);
|
|
174
204
|
|
|
@@ -178,33 +208,44 @@ export async function createOfflineRecoveryBranch(
|
|
|
178
208
|
targetBranch,
|
|
179
209
|
messagesRemoved: removedCount,
|
|
180
210
|
messagesSuppressed: suppression.messageCount,
|
|
211
|
+
discordAddressable: addressable,
|
|
212
|
+
marksScope: marks === 'none' ? 'none' : marks.scope,
|
|
181
213
|
discordMarkersQueued: refs.length,
|
|
182
214
|
refs,
|
|
215
|
+
unmarked: selection.unmarked,
|
|
216
|
+
notRemoved: selection.notRemoved,
|
|
183
217
|
outboxPath,
|
|
184
218
|
};
|
|
185
219
|
if (options.dryRun) return result;
|
|
186
220
|
|
|
187
|
-
|
|
188
|
-
const
|
|
221
|
+
// The host is stopped, so this process is the ledger's only writer.
|
|
222
|
+
const outbox = new DiscordAwarenessOutbox(outboxPath, { store });
|
|
223
|
+
const batch = await outbox.prepare({
|
|
189
224
|
agentName: options.agentName,
|
|
190
225
|
sourceBranch,
|
|
191
226
|
targetBranch,
|
|
192
227
|
refs,
|
|
228
|
+
scope: marks === 'none' ? 'none' : marks.scope,
|
|
229
|
+
unmarked: selection.unmarked,
|
|
230
|
+
notRemoved: selection.notRemoved,
|
|
193
231
|
emoji: options.emoji ?? DEFAULT_DISCORD_AWARENESS_EMOJI,
|
|
194
232
|
// Merely seeing targetBranch active does not prove branch-local
|
|
195
|
-
// suppressions finished
|
|
196
|
-
// batch
|
|
197
|
-
|
|
233
|
+
// suppressions finished: a start on it applies them again while the
|
|
234
|
+
// batch is prepared. Only the recovery may activate it, after every
|
|
235
|
+
// removal below succeeds.
|
|
198
236
|
suppressionIntervals: suppression.intervals.map((interval) => ({
|
|
199
237
|
fromId: String(interval.fromId),
|
|
200
238
|
toId: String(interval.toId),
|
|
201
239
|
})),
|
|
202
240
|
});
|
|
203
241
|
|
|
204
|
-
|
|
205
|
-
// compiled or submitted to Membrane during this operation.
|
|
206
|
-
const createdBranch = contextManager.branchAt(target.id, targetBranch);
|
|
242
|
+
let createdBranch: string | undefined;
|
|
207
243
|
try {
|
|
244
|
+
// branchAt uses the target message's origin sequence. No message
|
|
245
|
+
// content is compiled or submitted to Membrane during this operation.
|
|
246
|
+
// Creating the branch is part of the body: a failure here settles the
|
|
247
|
+
// batch like a failed switch or redaction.
|
|
248
|
+
createdBranch = contextManager.branchAt(target.id, targetBranch);
|
|
208
249
|
await contextManager.switchBranch(createdBranch);
|
|
209
250
|
// Each interval is removed by its messages' ids, so the order doesn't
|
|
210
251
|
// change the result. removeStoredInterval takes a single message outside
|
|
@@ -213,18 +254,109 @@ export async function createOfflineRecoveryBranch(
|
|
|
213
254
|
for (const interval of [...suppression.intervals].reverse()) {
|
|
214
255
|
removeStoredInterval(contextManager, interval.fromId, interval.toId);
|
|
215
256
|
}
|
|
216
|
-
if (batch) outbox.activate(batch.id);
|
|
217
257
|
} catch (error) {
|
|
218
258
|
// A partially suppressed branch is not safe to boot into. Preserve it
|
|
219
|
-
// for diagnosis, but
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
|
|
259
|
+
// for diagnosis, but put Chronicle back on the untouched source branch.
|
|
260
|
+
// Once the source is confirmed, the batch is retired (discard syncs the
|
|
261
|
+
// restored state before it records that): its surgery never happened.
|
|
262
|
+
// If it can't be confirmed, the batch stays prepared as the body's
|
|
263
|
+
// record: a start on its target branch finishes a suppression's
|
|
264
|
+
// removals, since its body is in effect there, and a start retires the
|
|
265
|
+
// batch, none of its marks sent. The error says which, and names the
|
|
266
|
+
// branch.
|
|
267
|
+
const failure = error instanceof Error ? error.message : String(error);
|
|
268
|
+
let restore = '';
|
|
269
|
+
try {
|
|
270
|
+
if (store.currentBranch().name !== sourceBranch) await contextManager.switchBranch(sourceBranch);
|
|
271
|
+
} catch (restoreError) {
|
|
272
|
+
restore = `; restoring ${sourceBranch} failed: ${boundDiscordAwarenessText(
|
|
273
|
+
restoreError instanceof Error ? restoreError.message : String(restoreError),
|
|
274
|
+
)}`;
|
|
275
|
+
}
|
|
276
|
+
const sourceConfirmed = store.currentBranch().name === sourceBranch;
|
|
277
|
+
let retire = '';
|
|
278
|
+
// A batch with marks never sends them once kept: the recovery, run
|
|
279
|
+
// again, chooses them again.
|
|
280
|
+
const redo = batch && batch.refs.length > 0
|
|
281
|
+
? '. To apply its marks, run the recovery again onto a new --branch, choosing them again' : '';
|
|
282
|
+
if (batch) {
|
|
283
|
+
if (!sourceConfirmed) {
|
|
284
|
+
// The recovery starts from the store's current branch, which this
|
|
285
|
+
// one couldn't put back: a run from there would start from the fork.
|
|
286
|
+
const redoFromSource = batch.refs.length > 0
|
|
287
|
+
? `. To apply its marks, redo it from ${sourceBranch}, choosing them again: the recovery starts from the ` +
|
|
288
|
+
`store's current branch, which isn't ${sourceBranch} now, so start the host, switch to ${sourceBranch} ` +
|
|
289
|
+
'through the host API\'s branch.switch, stop the host, and run the recovery again onto a new --branch'
|
|
290
|
+
: '';
|
|
291
|
+
retire = `; awareness batch ${batch.id} kept, since the source branch could not be confirmed: ` +
|
|
292
|
+
(suppression.intervals.length > 0
|
|
293
|
+
? `a start on ${targetBranch} finishes its removals and retires it`
|
|
294
|
+
: 'the next start retires it') + `, none of its marks sent${redoFromSource}`;
|
|
295
|
+
} else {
|
|
296
|
+
try {
|
|
297
|
+
await outbox.discard(batch.id);
|
|
298
|
+
retire = `; awareness batch ${batch.id} retired, none of its marks sent${redo}`;
|
|
299
|
+
} catch (discardError) {
|
|
300
|
+
// None of its marks is ever sent: a start retires it. A write that
|
|
301
|
+
// fails leaves the batch as it was, prepared, as in the host's
|
|
302
|
+
// retireAfterRestore. A suppression's removals stay pending for
|
|
303
|
+
// its target branch: a start on a branch with that name finishes
|
|
304
|
+
// them.
|
|
305
|
+
const detail = boundDiscordAwarenessText(
|
|
306
|
+
discardError instanceof Error ? discardError.message : String(discardError),
|
|
307
|
+
);
|
|
308
|
+
const kept = `; awareness batch ${batch.id} could not be retired (${detail}); it stays prepared, none of ` +
|
|
309
|
+
'its marks to be sent';
|
|
310
|
+
if (suppression.intervals.length === 0) {
|
|
311
|
+
retire = `${kept}, until the next start retires it${redo}`;
|
|
312
|
+
} else {
|
|
313
|
+
let forked = true;
|
|
314
|
+
try {
|
|
315
|
+
forked = store.listBranches().some((branch) => branch.name === targetBranch);
|
|
316
|
+
} catch { /* unknown: say what a start on an existing branch would do */ }
|
|
317
|
+
retire = `${kept}. Its removals stay pending for ${targetBranch}: a start on a branch with that ` +
|
|
318
|
+
'name would finish them there and retire the batch' + (forked
|
|
319
|
+
? `, and ${targetBranch} is kept, so delete it unless you want that, through the host API's ` +
|
|
320
|
+
'branch.delete once the host runs'
|
|
321
|
+
: '') + redo;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
223
325
|
}
|
|
224
|
-
|
|
326
|
+
// A partly suppressed branch is unsafe to start on, unless its batch was
|
|
327
|
+
// kept because the source couldn't be confirmed: a start on it then
|
|
328
|
+
// completes the suppression, as the batch's note says.
|
|
329
|
+
const kept = createdBranch === undefined ? ''
|
|
330
|
+
: suppression.intervals.length === 0 ? `; branch ${createdBranch} is kept for diagnosis`
|
|
331
|
+
: batch && !sourceConfirmed ? `; branch ${createdBranch} is kept: it may be partly suppressed`
|
|
332
|
+
: `; branch ${createdBranch} is kept for diagnosis: it may be partly suppressed, so don't start on it, and ` +
|
|
333
|
+
'delete it once it has been looked at (the host API\'s branch.delete, once the host runs)';
|
|
334
|
+
if (!restore && !retire && !kept) throw error;
|
|
335
|
+
throw new Error(`${failure}${restore}${kept}${retire}`, { cause: error });
|
|
225
336
|
}
|
|
226
337
|
|
|
227
|
-
|
|
338
|
+
// The body change landed. Marker bookkeeping is reported apart from it
|
|
339
|
+
// and never undoes it.
|
|
340
|
+
const facts = {
|
|
341
|
+
scope: (marks === 'none' ? 'none' : marks.scope) as SurgeryMarkerReceipt['scope'],
|
|
342
|
+
unmarked: selection.unmarked,
|
|
343
|
+
notRemoved: selection.notRemoved,
|
|
344
|
+
};
|
|
345
|
+
let markers: SurgeryMarkerReceipt = { ...facts, status: 'none', queued: 0 };
|
|
346
|
+
let suppressionRecord: string | undefined;
|
|
347
|
+
if (batch) {
|
|
348
|
+
const settled = await outbox.settleActivation(batch.id);
|
|
349
|
+
if (batch.refs.length > 0) {
|
|
350
|
+
markers = settled.status === 'queued'
|
|
351
|
+
? { ...facts, status: 'queued', queued: settled.queued, batchId: batch.id }
|
|
352
|
+
: { ...facts, status: 'not-scheduled', queued: 0, error: settled.error };
|
|
353
|
+
} else if (settled.status === 'not-scheduled') {
|
|
354
|
+
// A suppression-only batch carries no marks, and its activation
|
|
355
|
+
// closes the body's resume record: if that failed, say what became of it.
|
|
356
|
+
suppressionRecord = `the resume record (awareness batch ${batch.id}, no marks) could not be closed: ${settled.error}`;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return { ...result, discordMarkersQueued: markers.queued, markers, ...(suppressionRecord ? { suppressionRecord } : {}) };
|
|
228
360
|
} finally {
|
|
229
361
|
contextManager?.close();
|
|
230
362
|
store.close();
|
|
@@ -372,8 +504,7 @@ function buildSuppressionPlan(
|
|
|
372
504
|
targetIndex: number,
|
|
373
505
|
rawMessageIds: string[],
|
|
374
506
|
rawRanges: Array<{ fromMessageId: string; toMessageId: string }>,
|
|
375
|
-
|
|
376
|
-
): { intervals: SuppressionInterval[]; refs: DiscordAwarenessRef[]; messageCount: number } {
|
|
507
|
+
): { intervals: SuppressionInterval[]; carriers: DiscordMessageMetadataCarrier[]; messageCount: number } {
|
|
377
508
|
const messageIds = rawMessageIds.map(normalizeDiscordMessageId);
|
|
378
509
|
const ranges = rawRanges.map((range) => ({
|
|
379
510
|
fromMessageId: normalizeDiscordMessageId(range.fromMessageId),
|
|
@@ -383,7 +514,7 @@ function buildSuppressionPlan(
|
|
|
383
514
|
...messageIds,
|
|
384
515
|
...ranges.flatMap((range) => [range.fromMessageId, range.toMessageId]),
|
|
385
516
|
]);
|
|
386
|
-
if (wanted.size === 0) return { intervals: [],
|
|
517
|
+
if (wanted.size === 0) return { intervals: [], carriers: [], messageCount: 0 };
|
|
387
518
|
|
|
388
519
|
const locations = new Map<string, MessageLocation>();
|
|
389
520
|
for (let offset = 0; offset <= targetIndex; offset += RECOVERY_SCAN_WINDOW) {
|
|
@@ -473,45 +604,48 @@ function buildSuppressionPlan(
|
|
|
473
604
|
}
|
|
474
605
|
}
|
|
475
606
|
|
|
476
|
-
const
|
|
607
|
+
const carriers: DiscordMessageMetadataCarrier[] = [];
|
|
477
608
|
for (const interval of merged) {
|
|
478
|
-
|
|
479
|
-
contextManager,
|
|
480
|
-
interval.start,
|
|
481
|
-
interval.end + 1,
|
|
482
|
-
forcedServerId,
|
|
483
|
-
));
|
|
609
|
+
carriers.push(...collectDiscordCarriers(contextManager, interval.start, interval.end + 1));
|
|
484
610
|
}
|
|
485
611
|
return {
|
|
486
612
|
intervals: merged,
|
|
487
|
-
|
|
613
|
+
carriers,
|
|
488
614
|
messageCount: merged.reduce((sum, interval) => sum + interval.end - interval.start + 1, 0),
|
|
489
615
|
};
|
|
490
616
|
}
|
|
491
617
|
|
|
492
|
-
|
|
618
|
+
/**
|
|
619
|
+
* The addressing metadata of removed messages, read in bounded windows: only
|
|
620
|
+
* the Discord address and the MCPL tags (for `addressed` selection) are kept,
|
|
621
|
+
* never content. A sharded message may repeat its metadata across adjacent
|
|
622
|
+
* records; selection dedupes by address.
|
|
623
|
+
*/
|
|
624
|
+
function collectDiscordCarriers(
|
|
493
625
|
contextManager: ContextManager,
|
|
494
626
|
start: number,
|
|
495
627
|
end: number,
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
const refs: DiscordAwarenessRef[] = [];
|
|
628
|
+
): DiscordMessageMetadataCarrier[] {
|
|
629
|
+
const carriers: DiscordMessageMetadataCarrier[] = [];
|
|
499
630
|
for (let offset = start; offset < end; offset += RECOVERY_SCAN_WINDOW) {
|
|
500
631
|
const messages = contextManager.getMessageWindow(
|
|
501
632
|
offset,
|
|
502
633
|
Math.min(RECOVERY_SCAN_WINDOW, end - offset),
|
|
503
634
|
{ resolveBlobs: false },
|
|
504
635
|
).messages;
|
|
505
|
-
|
|
636
|
+
carriers.push(...messages.map(addressingOnly));
|
|
506
637
|
}
|
|
507
|
-
|
|
508
|
-
return dedupeDiscordRefs(refs);
|
|
638
|
+
return carriers;
|
|
509
639
|
}
|
|
510
640
|
|
|
511
|
-
function
|
|
512
|
-
const
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
641
|
+
function addressingOnly(message: { metadata?: Record<string, unknown> }): DiscordMessageMetadataCarrier {
|
|
642
|
+
const metadata = message.metadata ?? {};
|
|
643
|
+
return {
|
|
644
|
+
metadata: {
|
|
645
|
+
serverId: metadata.serverId,
|
|
646
|
+
channelId: metadata.channelId,
|
|
647
|
+
messageId: metadata.messageId,
|
|
648
|
+
tags: metadata.tags,
|
|
649
|
+
},
|
|
650
|
+
};
|
|
517
651
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { createOfflineRecoveryBranch } from './offline-branch.js';
|
|
4
|
+
import type { DiscordAwarenessMarks } from './discord-awareness-outbox.js';
|
|
4
5
|
|
|
5
6
|
interface CliOptions {
|
|
6
7
|
storePath?: string;
|
|
@@ -15,6 +16,7 @@ interface CliOptions {
|
|
|
15
16
|
discordServerId?: string;
|
|
16
17
|
outboxPath?: string;
|
|
17
18
|
emoji?: string;
|
|
19
|
+
marks: 'none' | 'addressed' | 'all';
|
|
18
20
|
dryRun: boolean;
|
|
19
21
|
}
|
|
20
22
|
|
|
@@ -22,9 +24,12 @@ function usage(): string {
|
|
|
22
24
|
return `Usage:
|
|
23
25
|
agent-framework-recover --store <path> --agent <name> <anchor> [options]
|
|
24
26
|
|
|
25
|
-
Creates and activates a Chronicle recovery branch while the normal host is
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
Creates and activates a Chronicle recovery branch while the normal host is
|
|
28
|
+
down. The recovery is local to the resident: by default no Discord reaction is
|
|
29
|
+
placed. --marks chooses to mark removed Discord messages with an awareness
|
|
30
|
+
reaction (queued here, delivered when the host and its Discord MCPL server
|
|
31
|
+
next connect). Message content is never compiled or written to the awareness
|
|
32
|
+
ledger.
|
|
28
33
|
|
|
29
34
|
Options:
|
|
30
35
|
--message-id <id|link> Last Discord message the agent should still see
|
|
@@ -35,6 +40,10 @@ Options:
|
|
|
35
40
|
--branch <name> Recovery branch name (generated by default)
|
|
36
41
|
--namespace <namespace> Context namespace (default: agents/<agent>)
|
|
37
42
|
--discord-server <id> Override/inject the Discord MCPL server id
|
|
43
|
+
--marks <none|addressed|all>
|
|
44
|
+
Awareness marks on removed Discord messages
|
|
45
|
+
(default none; addressed = mentions, replies to
|
|
46
|
+
the bot and DMs; all = every addressable message)
|
|
38
47
|
--outbox <path> Override the branch-independent outbox path
|
|
39
48
|
--emoji <emoji> Marker reaction (default: 💤)
|
|
40
49
|
--dry-run Inspect counts/addresses without writing
|
|
@@ -44,7 +53,7 @@ The agent host must be stopped before running this command.`;
|
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
function parseArgs(args: string[]): CliOptions {
|
|
47
|
-
const options: CliOptions = { dryRun: false, suppressMessageIds: [], suppressRanges: [] };
|
|
56
|
+
const options: CliOptions = { dryRun: false, suppressMessageIds: [], suppressRanges: [], marks: 'none' };
|
|
48
57
|
for (let i = 0; i < args.length; i++) {
|
|
49
58
|
const arg = args[i];
|
|
50
59
|
const value = () => {
|
|
@@ -80,6 +89,14 @@ function parseArgs(args: string[]): CliOptions {
|
|
|
80
89
|
case '--discord-server': options.discordServerId = value(); break;
|
|
81
90
|
case '--outbox': options.outboxPath = value(); break;
|
|
82
91
|
case '--emoji': options.emoji = value(); break;
|
|
92
|
+
case '--marks': {
|
|
93
|
+
const marks = value();
|
|
94
|
+
if (marks !== 'none' && marks !== 'addressed' && marks !== 'all') {
|
|
95
|
+
throw new Error('--marks must be none, addressed or all');
|
|
96
|
+
}
|
|
97
|
+
options.marks = marks;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
83
100
|
case '--dry-run': options.dryRun = true; break;
|
|
84
101
|
case '--help':
|
|
85
102
|
case '-h':
|
|
@@ -101,6 +118,9 @@ async function main(): Promise<void> {
|
|
|
101
118
|
throw new Error(`--store, --agent, and one anchor (--message-id, --context-id, or --messages) are required\n\n${usage()}`);
|
|
102
119
|
}
|
|
103
120
|
|
|
121
|
+
// A CLI choice and its application are the same moment (the host is
|
|
122
|
+
// stopped), so the scope is evaluated now rather than frozen to refs.
|
|
123
|
+
const marks: DiscordAwarenessMarks = options.marks === 'none' ? 'none' : { scope: options.marks };
|
|
104
124
|
const result = await createOfflineRecoveryBranch({
|
|
105
125
|
storePath: options.storePath,
|
|
106
126
|
agentName: options.agentName,
|
|
@@ -114,6 +134,7 @@ async function main(): Promise<void> {
|
|
|
114
134
|
discordServerId: options.discordServerId,
|
|
115
135
|
outboxPath: options.outboxPath,
|
|
116
136
|
emoji: options.emoji,
|
|
137
|
+
marks,
|
|
117
138
|
dryRun: options.dryRun,
|
|
118
139
|
});
|
|
119
140
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tools whose call delivers the resident's message to a channel or person,
|
|
3
|
+
* by bare name (an MCPL server's `<prefix>--` stripped). The framework reads
|
|
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 its message argument as
|
|
6
|
+
* what the resident wrote to someone, whether or not it was delivered.
|
|
7
|
+
*/
|
|
8
|
+
export const SEND_TOOLS = new Set(['channel_publish', 'send_message', 'reply_message', 'send_dm']);
|
|
9
|
+
|
|
10
|
+
/** Strip the `server--` MCPL prefix from a tool name. */
|
|
11
|
+
export const bareToolName = (n: string): string => n.split('--').pop()!;
|
package/src/tool-result-guard.ts
CHANGED
|
@@ -18,7 +18,7 @@ export const TOOL_RESULT_GUARD_AUDIT_STATE = 'framework/tool-result-guard';
|
|
|
18
18
|
* left the stub's branch when the file would have been committed
|
|
19
19
|
* (`branch_changed`), or because the batch used its deadline before this
|
|
20
20
|
* write could start (`batch_deadline`); or null when no file is written at all (no writable
|
|
21
|
-
*
|
|
21
|
+
* mount without an include, or the host is stopping). */
|
|
22
22
|
export type WithheldSpill =
|
|
23
23
|
| { path: string; error?: string; unfinished?: true }
|
|
24
24
|
| { skipped: 'workspace_unanswered' | 'branch_changed' | 'batch_deadline' }
|
|
@@ -497,8 +497,9 @@ export class ToolResultGuard {
|
|
|
497
497
|
|
|
498
498
|
/**
|
|
499
499
|
* Turn a withheld batch's notices into stubs that say where each original
|
|
500
|
-
* is (agent-framework #277): written to the workspace when
|
|
501
|
-
*
|
|
500
|
+
* is (agent-framework #277): written to the workspace when it has a
|
|
501
|
+
* writable mount without an include to take it, else kept in the audit
|
|
502
|
+
* record. A stub also keeps the file
|
|
502
503
|
* lists its tool marked. Its own unedited placeholder is
|
|
503
504
|
* the only thing it edits: an operator's later edit, removal or rollback
|
|
504
505
|
* stands.
|
|
@@ -596,8 +597,8 @@ export class ToolResultGuard {
|
|
|
596
597
|
if (block.type !== 'tool_result') return [];
|
|
597
598
|
if (thrown.has(index)) return [{ toolUseId: block.toolUseId, error: thrown.get(index)! }];
|
|
598
599
|
const spill = spills.get(index) ?? null;
|
|
599
|
-
// No file was written: no writable
|
|
600
|
-
// was stopping.
|
|
600
|
+
// No file was written: no writable mount without an include,
|
|
601
|
+
// or the framework was stopping.
|
|
601
602
|
if (spill === null) return [{ toolUseId: block.toolUseId, skipped: 'no_workspace_file' }];
|
|
602
603
|
if ('skipped' in spill) return [{ toolUseId: block.toolUseId, skipped: spill.skipped }];
|
|
603
604
|
return [{ toolUseId: block.toolUseId, path: spill.path,
|
|
@@ -49,7 +49,7 @@ export interface HistorySerializeOptions {
|
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* House-safe default inline cap (chars) for tool results, error results, and
|
|
52
|
-
*
|
|
52
|
+
* script wake payloads (issue #89: a resident should never eat a
|
|
53
53
|
* 42k blob they didn't ask for). Durable per-residence value comes from
|
|
54
54
|
* `FrameworkConfig.toolResultInlineMaxChars`; a per-agent value from
|
|
55
55
|
* agent_settings `tool_result_inline_max_chars`.
|