@animalabs/agent-framework 0.32.0 → 0.34.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 +340 -22
- package/dist/src/admission/admit.d.ts +18 -0
- package/dist/src/admission/admit.d.ts.map +1 -1
- package/dist/src/admission/admit.js +16 -3
- package/dist/src/admission/admit.js.map +1 -1
- package/dist/src/agent.d.ts +208 -80
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +345 -113
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/mcp-server-core.d.ts.map +1 -1
- package/dist/src/api/mcp-server-core.js +50 -12
- package/dist/src/api/mcp-server-core.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +4 -20
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/append-all.d.ts +5 -0
- package/dist/src/append-all.d.ts.map +1 -0
- package/dist/src/append-all.js +8 -0
- package/dist/src/append-all.js.map +1 -0
- package/dist/src/code-execution/isolate/scripts.d.ts +12 -8
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
- package/dist/src/code-execution/isolate/scripts.js +24 -0
- package/dist/src/code-execution/isolate/scripts.js.map +1 -1
- package/dist/src/config-checks.d.ts +7 -0
- package/dist/src/config-checks.d.ts.map +1 -1
- package/dist/src/config-checks.js +14 -0
- package/dist/src/config-checks.js.map +1 -1
- package/dist/src/context-manager-errors.d.ts +25 -0
- package/dist/src/context-manager-errors.d.ts.map +1 -0
- package/dist/src/context-manager-errors.js +31 -0
- package/dist/src/context-manager-errors.js.map +1 -0
- package/dist/src/context-options.d.ts +70 -0
- package/dist/src/context-options.d.ts.map +1 -0
- package/dist/src/context-options.js +90 -0
- package/dist/src/context-options.js.map +1 -0
- package/dist/src/cut-off-round.js +4 -4
- package/dist/src/deferred-import.d.ts +93 -0
- package/dist/src/deferred-import.d.ts.map +1 -0
- package/dist/src/deferred-import.js +177 -0
- package/dist/src/deferred-import.js.map +1 -0
- package/dist/src/dendrite/audience.d.ts +223 -0
- package/dist/src/dendrite/audience.d.ts.map +1 -0
- package/dist/src/dendrite/audience.js +202 -0
- package/dist/src/dendrite/audience.js.map +1 -0
- package/dist/src/dendrite/index.d.ts +5 -3
- package/dist/src/dendrite/index.d.ts.map +1 -1
- package/dist/src/dendrite/index.js +2 -1
- package/dist/src/dendrite/index.js.map +1 -1
- package/dist/src/dendrite/presets.d.ts +10 -5
- package/dist/src/dendrite/presets.d.ts.map +1 -1
- package/dist/src/dendrite/presets.js +17 -5
- package/dist/src/dendrite/presets.js.map +1 -1
- package/dist/src/dendrite/registry.d.ts +62 -7
- package/dist/src/dendrite/registry.d.ts.map +1 -1
- package/dist/src/dendrite/registry.js +183 -12
- package/dist/src/dendrite/registry.js.map +1 -1
- package/dist/src/dendrite/types.d.ts +91 -8
- package/dist/src/dendrite/types.d.ts.map +1 -1
- package/dist/src/failure-text.d.ts +36 -0
- package/dist/src/failure-text.d.ts.map +1 -0
- package/dist/src/failure-text.js +89 -0
- package/dist/src/failure-text.js.map +1 -0
- package/dist/src/foreign-rounds.d.ts +69 -0
- package/dist/src/foreign-rounds.d.ts.map +1 -0
- package/dist/src/foreign-rounds.js +152 -0
- package/dist/src/foreign-rounds.js.map +1 -0
- package/dist/src/framework.d.ts +2064 -842
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +8586 -3739
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +125 -21
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +487 -72
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/gate/index.d.ts +1 -1
- package/dist/src/gate/index.d.ts.map +1 -1
- package/dist/src/gate/index.js.map +1 -1
- package/dist/src/gate/reply-judge.d.ts +4 -0
- package/dist/src/gate/reply-judge.d.ts.map +1 -1
- package/dist/src/gate/reply-judge.js +12 -3
- package/dist/src/gate/reply-judge.js.map +1 -1
- package/dist/src/gate/rule-scope.d.ts +30 -0
- package/dist/src/gate/rule-scope.d.ts.map +1 -0
- package/dist/src/gate/rule-scope.js +41 -0
- package/dist/src/gate/rule-scope.js.map +1 -0
- package/dist/src/gate/suppress-script-worker.d.ts +2 -0
- package/dist/src/gate/suppress-script-worker.d.ts.map +1 -0
- package/dist/src/gate/suppress-script-worker.js +103 -0
- package/dist/src/gate/suppress-script-worker.js.map +1 -0
- package/dist/src/gate/suppress-scripts.d.ts +105 -0
- package/dist/src/gate/suppress-scripts.d.ts.map +1 -0
- package/dist/src/gate/suppress-scripts.js +403 -0
- package/dist/src/gate/suppress-scripts.js.map +1 -0
- package/dist/src/gate/suppression-review.d.ts +143 -0
- package/dist/src/gate/suppression-review.d.ts.map +1 -0
- package/dist/src/gate/suppression-review.js +463 -0
- package/dist/src/gate/suppression-review.js.map +1 -0
- package/dist/src/gate/suppression-stats.d.ts +125 -0
- package/dist/src/gate/suppression-stats.d.ts.map +1 -0
- package/dist/src/gate/suppression-stats.js +214 -0
- package/dist/src/gate/suppression-stats.js.map +1 -0
- package/dist/src/gate/types.d.ts +142 -7
- package/dist/src/gate/types.d.ts.map +1 -1
- package/dist/src/gate/wake-onboarding.d.ts +119 -0
- package/dist/src/gate/wake-onboarding.d.ts.map +1 -0
- package/dist/src/gate/wake-onboarding.js +277 -0
- package/dist/src/gate/wake-onboarding.js.map +1 -0
- package/dist/src/heartbeat/heartbeat.js +1 -1
- package/dist/src/heartbeat/heartbeat.js.map +1 -1
- package/dist/src/held-writes.d.ts +31 -23
- package/dist/src/held-writes.d.ts.map +1 -1
- package/dist/src/held-writes.js +44 -59
- package/dist/src/held-writes.js.map +1 -1
- package/dist/src/index.d.ts +6 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/inference-bounds.d.ts +2 -1
- package/dist/src/inference-bounds.d.ts.map +1 -1
- package/dist/src/inference-bounds.js +9 -6
- package/dist/src/inference-bounds.js.map +1 -1
- package/dist/src/jsonrpc-envelope.d.ts +69 -0
- package/dist/src/jsonrpc-envelope.d.ts.map +1 -0
- package/dist/src/jsonrpc-envelope.js +66 -0
- package/dist/src/jsonrpc-envelope.js.map +1 -0
- package/dist/src/mcpl/channel-registry.d.ts +188 -28
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +426 -70
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.d.ts +2 -4
- package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
- package/dist/src/mcpl/feature-set-manager.d.ts +2 -4
- package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
- package/dist/src/mcpl/feature-set-manager.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +2 -1
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +2 -1
- package/dist/src/mcpl/inbound-source.js.map +1 -1
- package/dist/src/mcpl/inference-router.d.ts +6 -6
- package/dist/src/mcpl/inference-router.d.ts.map +1 -1
- package/dist/src/mcpl/inference-router.js.map +1 -1
- package/dist/src/mcpl/modern-connection.d.ts +109 -15
- package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
- package/dist/src/mcpl/modern-connection.js +593 -86
- package/dist/src/mcpl/modern-connection.js.map +1 -1
- package/dist/src/mcpl/protocol-family.d.ts +3 -1
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
- package/dist/src/mcpl/protocol-family.js +15 -9
- package/dist/src/mcpl/protocol-family.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +132 -22
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +105 -15
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts +9 -7
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +50 -28
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +165 -72
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/tool-classes.d.ts.map +1 -1
- package/dist/src/mcpl/tool-classes.js +3 -0
- package/dist/src/mcpl/tool-classes.js.map +1 -1
- package/dist/src/mcpl/tool-presence.d.ts.map +1 -1
- package/dist/src/mcpl/tool-presence.js +10 -6
- package/dist/src/mcpl/tool-presence.js.map +1 -1
- package/dist/src/mcpl/toolset-host.d.ts.map +1 -1
- package/dist/src/mcpl/toolset-host.js +7 -6
- package/dist/src/mcpl/toolset-host.js.map +1 -1
- package/dist/src/mcpl/toolsets-module.d.ts.map +1 -1
- package/dist/src/mcpl/toolsets-module.js +2 -1
- package/dist/src/mcpl/toolsets-module.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +33 -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 +24 -1
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +68 -18
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts +45 -8
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +238 -87
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/health/index.js +2 -2
- package/dist/src/modules/health/index.js.map +1 -1
- package/dist/src/modules/history/index.d.ts +59 -0
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +432 -67
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/history/semantic.d.ts +6 -5
- package/dist/src/modules/history/semantic.d.ts.map +1 -1
- package/dist/src/modules/history/semantic.js +18 -25
- package/dist/src/modules/history/semantic.js.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.d.ts +1 -1
- package/dist/src/modules/workspace/disk-agreement.js +1 -1
- package/dist/src/modules/workspace/index.d.ts +28 -7
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +80 -25
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +2 -1
- 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 +3 -2
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/notice-tags.d.ts +20 -9
- package/dist/src/notice-tags.d.ts.map +1 -1
- package/dist/src/notice-tags.js +20 -9
- package/dist/src/notice-tags.js.map +1 -1
- package/dist/src/operator-log.d.ts +36 -3
- package/dist/src/operator-log.d.ts.map +1 -1
- package/dist/src/operator-log.js +2 -2
- package/dist/src/operator-log.js.map +1 -1
- package/dist/src/presentation.d.ts +747 -0
- package/dist/src/presentation.d.ts.map +1 -0
- package/dist/src/presentation.js +1437 -0
- package/dist/src/presentation.js.map +1 -0
- package/dist/src/prose-drafts.d.ts +15 -11
- package/dist/src/prose-drafts.d.ts.map +1 -1
- package/dist/src/prose-drafts.js +16 -12
- package/dist/src/prose-drafts.js.map +1 -1
- package/dist/src/read-marks.d.ts +192 -0
- package/dist/src/read-marks.d.ts.map +1 -0
- package/dist/src/read-marks.js +242 -0
- package/dist/src/read-marks.js.map +1 -0
- package/dist/src/reasoning-loss.d.ts +5 -0
- package/dist/src/reasoning-loss.d.ts.map +1 -0
- package/dist/src/reasoning-loss.js +8 -0
- package/dist/src/reasoning-loss.js.map +1 -0
- package/dist/src/recovery/offline-branch.d.ts +91 -6
- package/dist/src/recovery/offline-branch.d.ts.map +1 -1
- package/dist/src/recovery/offline-branch.js +277 -32
- package/dist/src/recovery/offline-branch.js.map +1 -1
- package/dist/src/recovery/recover-cli.js +24 -4
- package/dist/src/recovery/recover-cli.js.map +1 -1
- package/dist/src/send-tools.d.ts +5 -9
- package/dist/src/send-tools.d.ts.map +1 -1
- package/dist/src/send-tools.js +40 -7
- package/dist/src/send-tools.js.map +1 -1
- package/dist/src/sent-rows.js +1 -1
- package/dist/src/stored-injections.d.ts +2 -2
- package/dist/src/stored-injections.js +2 -2
- package/dist/src/stored-removal.d.ts +17 -4
- package/dist/src/stored-removal.d.ts.map +1 -1
- package/dist/src/stored-removal.js +29 -5
- package/dist/src/stored-removal.js.map +1 -1
- package/dist/src/supplied-text.d.ts +1 -1
- package/dist/src/supplied-text.js +3 -3
- package/dist/src/supplied-text.js.map +1 -1
- package/dist/src/thinking-drops.d.ts +2 -0
- package/dist/src/thinking-drops.d.ts.map +1 -1
- package/dist/src/thinking-drops.js.map +1 -1
- package/dist/src/tool-presentation.d.ts.map +1 -1
- package/dist/src/tool-presentation.js +38 -9
- package/dist/src/tool-presentation.js.map +1 -1
- package/dist/src/tool-result-guard.d.ts +12 -1
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +42 -8
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +1170 -81
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +3732 -369
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/tune-out/tools.d.ts +114 -17
- package/dist/src/tune-out/tools.d.ts.map +1 -1
- package/dist/src/tune-out/tools.js +89 -28
- package/dist/src/tune-out/tools.js.map +1 -1
- package/dist/src/tune-out/window-anchor.d.ts +143 -0
- package/dist/src/tune-out/window-anchor.d.ts.map +1 -0
- package/dist/src/tune-out/window-anchor.js +202 -0
- package/dist/src/tune-out/window-anchor.js.map +1 -0
- package/dist/src/types/agent.d.ts +121 -25
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +2 -0
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +72 -17
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/inference-log.d.ts +1 -0
- package/dist/src/types/inference-log.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +180 -69
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +573 -39
- package/dist/src/types/trace.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/admission/admit.ts +32 -3
- package/src/agent.ts +392 -132
- package/src/api/mcp-server-core.ts +54 -17
- package/src/api/server.ts +4 -23
- package/src/append-all.ts +6 -0
- package/src/code-execution/isolate/scripts.ts +28 -3
- package/src/config-checks.ts +14 -0
- package/src/context-manager-errors.ts +37 -0
- package/src/context-options.ts +106 -0
- package/src/cut-off-round.ts +4 -4
- package/src/deferred-import.ts +239 -0
- package/src/dendrite/audience.ts +315 -0
- package/src/dendrite/index.ts +14 -2
- package/src/dendrite/presets.ts +18 -6
- package/src/dendrite/registry.ts +213 -14
- package/src/dendrite/types.ts +92 -8
- package/src/failure-text.ts +88 -0
- package/src/foreign-rounds.ts +199 -0
- package/src/framework.ts +8796 -3813
- package/src/gate/event-gate.ts +518 -91
- package/src/gate/index.ts +3 -0
- package/src/gate/reply-judge.ts +12 -3
- package/src/gate/rule-scope.ts +45 -0
- package/src/gate/suppress-script-worker.ts +89 -0
- package/src/gate/suppress-scripts.ts +414 -0
- package/src/gate/suppression-review.ts +517 -0
- package/src/gate/suppression-stats.ts +314 -0
- package/src/gate/types.ts +148 -7
- package/src/gate/wake-onboarding.ts +309 -0
- package/src/heartbeat/heartbeat.ts +1 -1
- package/src/held-writes.ts +49 -60
- package/src/index.ts +10 -2
- package/src/inference-bounds.ts +11 -6
- package/src/jsonrpc-envelope.ts +81 -0
- package/src/mcpl/channel-registry.ts +513 -116
- package/src/mcpl/checkpoint-manager.ts +3 -2
- package/src/mcpl/feature-set-manager.ts +2 -1
- package/src/mcpl/inbound-source.ts +2 -1
- package/src/mcpl/inference-router.ts +7 -4
- package/src/mcpl/modern-connection.ts +629 -91
- package/src/mcpl/protocol-family.ts +15 -9
- package/src/mcpl/push-coalescer.ts +193 -34
- package/src/mcpl/push-handler.ts +10 -5
- package/src/mcpl/server-connection.ts +169 -75
- package/src/mcpl/tool-classes.ts +3 -0
- package/src/mcpl/tool-presence.ts +10 -5
- package/src/mcpl/toolset-host.ts +7 -6
- package/src/mcpl/toolsets-module.ts +2 -1
- package/src/mcpl/types.ts +33 -6
- package/src/module-registry.ts +73 -17
- package/src/modules/discord/index.ts +230 -82
- package/src/modules/health/index.ts +2 -2
- package/src/modules/history/index.ts +439 -70
- package/src/modules/history/semantic.ts +18 -24
- package/src/modules/workspace/disk-agreement.ts +1 -1
- package/src/modules/workspace/index.ts +89 -26
- package/src/modules/workspace/observe.ts +2 -1
- package/src/modules/workspace/reconcile.ts +3 -2
- package/src/notice-tags.ts +21 -9
- package/src/operator-log.ts +36 -3
- package/src/presentation.ts +1678 -0
- package/src/prose-drafts.ts +16 -12
- package/src/read-marks.ts +328 -0
- package/src/reasoning-loss.ts +7 -0
- package/src/recovery/offline-branch.ts +350 -35
- package/src/recovery/recover-cli.ts +23 -4
- package/src/send-tools.ts +40 -7
- package/src/sent-rows.ts +1 -1
- package/src/stored-injections.ts +2 -2
- package/src/stored-removal.ts +31 -7
- package/src/supplied-text.ts +3 -3
- package/src/thinking-drops.ts +2 -0
- package/src/tool-presentation.ts +34 -9
- package/src/tool-result-guard.ts +41 -7
- package/src/tune-out/coordinator.ts +4121 -472
- package/src/tune-out/tools.ts +162 -44
- package/src/tune-out/window-anchor.ts +277 -0
- package/src/types/agent.ts +122 -25
- package/src/types/events.ts +2 -0
- package/src/types/framework.ts +73 -17
- package/src/types/inference-log.ts +1 -0
- package/src/types/module.ts +181 -68
- package/src/types/trace.ts +607 -43
package/src/agent.ts
CHANGED
|
@@ -5,13 +5,16 @@ import { isAbortedResponse } from '@animalabs/membrane';
|
|
|
5
5
|
import { streamBounds, type InferenceBounds } from './inference-bounds.js';
|
|
6
6
|
import type { CacheWireReceipt, KvUnifiedRequestHooks } from './kv-unified-wire.js';
|
|
7
7
|
import { ToolResultGuard } from './tool-result-guard.js';
|
|
8
|
+
import { storeOwnRow } from './dendrite/audience.js';
|
|
8
9
|
import { withoutTokenEstimates } from './thinking-token-stamp.js';
|
|
9
10
|
import { placeThinkingDrops, type CompiledForRequest, type PlacedDrop } from './thinking-drops.js';
|
|
10
11
|
import { carriedBlock, type SentRow } from './sent-rows.js';
|
|
12
|
+
import { foreignRowAsSent, transcribeForeignRounds } from './foreign-rounds.js';
|
|
11
13
|
import { injectionsAsStored } from './text-as-stored.js';
|
|
12
14
|
import { stableHash } from './stable-hash.js';
|
|
13
15
|
import { hasRenderedContent, storedInjectionMarkOf } from './stored-injections.js';
|
|
14
|
-
import {
|
|
16
|
+
import { covers, markAtOrAfter, readMarkOf, storeHeadOf, type MarkCm, type MarkedRow, type ReadMark } from './read-marks.js';
|
|
17
|
+
import { assertBooleanSetting, assertOneOfSetting, holdsSettings, kindOf } from './config-checks.js';
|
|
15
18
|
import {
|
|
16
19
|
CONTINUE_ROW,
|
|
17
20
|
continueTurn,
|
|
@@ -32,6 +35,7 @@ import {
|
|
|
32
35
|
truncateForHistory,
|
|
33
36
|
DEFAULT_TOOL_RESULT_INLINE_MAX_CHARS,
|
|
34
37
|
} from './tool-result-history.js';
|
|
38
|
+
import { appendAll } from './append-all.js';
|
|
35
39
|
|
|
36
40
|
export interface ActivationRequestOptions {
|
|
37
41
|
/** The silent heartbeat tick this request answers, if any. */
|
|
@@ -109,6 +113,11 @@ export interface StartStreamResult {
|
|
|
109
113
|
* far in sent order, with this request's head (context-manager's `noteRequestSent`). Present only where the
|
|
110
114
|
* model binds its thinking and the context manager keeps a record it can be told of. */
|
|
111
115
|
noteRequestSent?: (rows: readonly SentRow[]) => boolean;
|
|
116
|
+
/** Tells the context manager which stored bodies' thinking the provider dropped from a call of this stream, by the
|
|
117
|
+
* ids `placeDrops` gives for a `reply` drop, with the compile the stream was built from (context-manager's
|
|
118
|
+
* `noteThinkingDropped`), so, once the context manager takes the note, its record leaves them without their
|
|
119
|
+
* thinking from the next compile on. Present only where `noteRequestSent` is. */
|
|
120
|
+
noteThinkingDropped?: (messageIds: readonly MessageId[]) => boolean;
|
|
112
121
|
/** The stored bodies the request's compile carried, by each body's first message id (its provenance's raw bodies).
|
|
113
122
|
* Absent when the compile reports no provenance. */
|
|
114
123
|
carriedBodies?: ReadonlySet<MessageId>;
|
|
@@ -187,11 +196,13 @@ export function assertThinkingBinding(setting: string, value: AgentConfig['think
|
|
|
187
196
|
|
|
188
197
|
/**
|
|
189
198
|
* Refuse an agent config whose `promptCaching`, `toolResultGuard`,
|
|
190
|
-
* `toolWrapperProseGuard`, `thinking.enabled`, `thinkingBinding.dropBlock`,
|
|
199
|
+
* `toolWrapperProseGuard`, `turnInputsPin`, `thinking.enabled`, `thinkingBinding.dropBlock`,
|
|
191
200
|
* `thinkingBinding.binds` or `refusalHandling.autoRewind` holds anything but true or false
|
|
192
201
|
* (assertBooleanSetting, where null counts as left out), or whose `thinking`, `thinkingBinding` or
|
|
193
202
|
* `refusalHandling` is anything but an object, null or false (holdsSettings),
|
|
194
|
-
* or whose `autoContinue` resolveAutoContinue refuses
|
|
203
|
+
* or whose `autoContinue` resolveAutoContinue refuses, or whose `observes`
|
|
204
|
+
* is anything but a list of names, or whose `foreignRounds` is neither of
|
|
205
|
+
* its modes (assertOneOfSetting). The constructor runs it
|
|
195
206
|
* first, so the rule holds wherever an Agent is built. `create()` also runs it
|
|
196
207
|
* for each of its agents before anything opens, and `createEphemeralAgent`
|
|
197
208
|
* before it reserves the name, so a refusal there leaves nothing behind.
|
|
@@ -233,6 +244,26 @@ export function assertAgentSwitches(config: AgentConfig): void {
|
|
|
233
244
|
'true keeps a response whose whole prose is a tool-call-shaped wrapper from running or entering the agent\'s history, ' +
|
|
234
245
|
'and false or leaving it out doesn\'t',
|
|
235
246
|
);
|
|
247
|
+
assertBooleanSetting(
|
|
248
|
+
`${agent} turnInputsPin`,
|
|
249
|
+
config.turnInputsPin,
|
|
250
|
+
'true or leaving it out pins the rows that open a turn raw until it ends, and false places no pin',
|
|
251
|
+
);
|
|
252
|
+
const observes: unknown = config.observes;
|
|
253
|
+
if (observes !== undefined && observes !== null
|
|
254
|
+
&& (!Array.isArray(observes) || !observes.every((name) => typeof name === 'string'))) {
|
|
255
|
+
throw new Error(
|
|
256
|
+
`${agent} observes must be a list of agent names, such as ["nova"], not ${Array.isArray(observes) ? 'a list holding something else' : kindOf(observes)}: ` +
|
|
257
|
+
'each names another configured agent whose own rows this agent\'s window takes',
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
assertOneOfSetting(
|
|
261
|
+
`${agent} foreignRounds`,
|
|
262
|
+
config.foreignRounds,
|
|
263
|
+
['transcript', 'raw'],
|
|
264
|
+
'\'transcript\' or leaving it out sends the rounds of an agent it observes as a line per call and result, ' +
|
|
265
|
+
'without their thinking, and \'raw\' sends them as stored',
|
|
266
|
+
);
|
|
236
267
|
resolveAutoContinue(config);
|
|
237
268
|
}
|
|
238
269
|
|
|
@@ -274,6 +305,18 @@ export function resolveAutoContinue(config: AgentConfig): { maxConsecutive: numb
|
|
|
274
305
|
return { maxConsecutive: max };
|
|
275
306
|
}
|
|
276
307
|
|
|
308
|
+
/** A stored injection's copy a compile built to send rendered (Agent.renderedInjection). */
|
|
309
|
+
interface RenderedInjectionCopy {
|
|
310
|
+
/** The row's id: the body the compile's provenance names. */
|
|
311
|
+
id: MessageId;
|
|
312
|
+
part: number;
|
|
313
|
+
parts: number;
|
|
314
|
+
/** Whether the compile held the part: every shard of it, however the strategy shaped it. */
|
|
315
|
+
held: boolean;
|
|
316
|
+
sequence: number;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** A branch's key in Agent.unsentSince: its id and when it was created. */
|
|
277
320
|
export function branchKey(branch: { readonly id: string; readonly created: number }): string {
|
|
278
321
|
return `${branch.id}\u0000${branch.created}`;
|
|
279
322
|
}
|
|
@@ -311,7 +354,9 @@ export class Agent {
|
|
|
311
354
|
readonly refusalHandling: AgentConfig['refusalHandling'];
|
|
312
355
|
readonly toolResultGuard: ToolResultGuard;
|
|
313
356
|
/** Prose delivery mode (see AgentConfig.proseRouting). Default 'locus'. */
|
|
314
|
-
readonly proseRouting: 'locus' | 'explicit' | 'hybrid' | 'disabled';
|
|
357
|
+
readonly proseRouting: 'locus' | 'explicit' | 'hybrid' | 'disabled' | 'locked';
|
|
358
|
+
/** Locked mode's destination until the agent chooses one (see AgentConfig.proseLock). */
|
|
359
|
+
readonly proseLock: string | undefined;
|
|
315
360
|
/** Exact whole-response known-tool wrapper containment (default off). */
|
|
316
361
|
readonly toolWrapperProseGuard: boolean;
|
|
317
362
|
/** Continuation after a turn the model ends itself (see
|
|
@@ -396,6 +441,7 @@ export class Agent {
|
|
|
396
441
|
* the next change.
|
|
397
442
|
*/
|
|
398
443
|
private liveBudgetEpoch = 0;
|
|
444
|
+
private contextSettingsChangeCount = 0;
|
|
399
445
|
/**
|
|
400
446
|
* Counts changes of the descent (each arm of one, the same target included,
|
|
401
447
|
* a reset, a cancel, a settle). A settle proves its target only to a
|
|
@@ -456,11 +502,13 @@ export class Agent {
|
|
|
456
502
|
this.refusalHandling = config.refusalHandling;
|
|
457
503
|
this.toolResultGuard = new ToolResultGuard(config.name, contextManager, config.toolResultGuard === true);
|
|
458
504
|
this.proseRouting = config.proseRouting ?? 'locus';
|
|
505
|
+
this.proseLock = typeof config.proseLock === 'string' && config.proseLock.trim() ? config.proseLock.trim() : undefined;
|
|
459
506
|
this.toolWrapperProseGuard = config.toolWrapperProseGuard === true;
|
|
460
507
|
this.autoContinue = resolveAutoContinue(config);
|
|
461
508
|
this.clock = resolveClockConfig(config.name, config.clock);
|
|
462
509
|
this.cacheTtl = config.cacheTtl ?? '1h';
|
|
463
510
|
this.promptCaching = config.promptCaching !== false;
|
|
511
|
+
this.pinsTurnInputs = config.turnInputsPin !== false;
|
|
464
512
|
this.prefillUserMessage = config.prefillUserMessage;
|
|
465
513
|
this.providerParams = config.providerParams;
|
|
466
514
|
this.sameRoundThinkTextPolicy = config.sameRoundThinkTextPolicy;
|
|
@@ -539,6 +587,46 @@ export class Agent {
|
|
|
539
587
|
return this.ownParticipants.has(participant);
|
|
540
588
|
}
|
|
541
589
|
|
|
590
|
+
/**
|
|
591
|
+
* How another agent's rounds go out in this agent's requests (#291, answer
|
|
592
|
+
* 13): `'raw'`, as stored, or `'transcript'` (foreign-rounds.ts), a line
|
|
593
|
+
* per call and per result and no thinking, the same in every compile and
|
|
594
|
+
* in what a tool boundary injects. The framework sets it, once the
|
|
595
|
+
* agent's window follows the presentation index, for the persistent
|
|
596
|
+
* subconscious, for a resident that observes another
|
|
597
|
+
* (AgentConfig.observes), as their configurations' `foreignRounds` say
|
|
598
|
+
* (`'transcript'` by default), and for an agent derived or forked from
|
|
599
|
+
* one of them, in that agent's mode (its inheritance holds them); every
|
|
600
|
+
* other agent reads no other agent's
|
|
601
|
+
* rounds, but for a co-resident's rows stored before audience stamps,
|
|
602
|
+
* which a window written down from the record keeps and which go out as
|
|
603
|
+
* stored ('raw'), as earlier releases sent them.
|
|
604
|
+
*/
|
|
605
|
+
private foreignRounds: 'raw' | 'transcript' = 'raw';
|
|
606
|
+
|
|
607
|
+
/** Set how another agent's rounds go out in this agent's requests (see foreignRounds). */
|
|
608
|
+
setForeignRounds(mode: 'raw' | 'transcript'): void {
|
|
609
|
+
this.foreignRounds = mode;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* A stored row as this agent's requests carry it, for a row a tool
|
|
614
|
+
* boundary injects: another participant's row as a transcript where this
|
|
615
|
+
* agent is sent other agents' rounds so (setForeignRounds), its own and
|
|
616
|
+
* every row otherwise as stored. An injected row holds no tool block (the
|
|
617
|
+
* boundary cuts at one), so what changes is its thinking.
|
|
618
|
+
*/
|
|
619
|
+
injectedAsSent(participant: string, content: ContentBlock[]): ContentBlock[] {
|
|
620
|
+
if (this.foreignRounds !== 'transcript' || this.isOwnParticipant(participant)) return content;
|
|
621
|
+
return foreignRowAsSent(content);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/** A compile's messages with other agents' rounds as this agent is sent them (setForeignRounds). */
|
|
625
|
+
private foreignRoundsAsSent(messages: NormalizedMessage[]): NormalizedMessage[] {
|
|
626
|
+
if (this.foreignRounds !== 'transcript') return messages;
|
|
627
|
+
return transcribeForeignRounds(messages, (participant) => this.isOwnParticipant(participant));
|
|
628
|
+
}
|
|
629
|
+
|
|
542
630
|
/**
|
|
543
631
|
* Role assignment for a request: every participant that is this agent's
|
|
544
632
|
* own voice — its name, and for a derived agent the agent it inherited
|
|
@@ -615,7 +703,19 @@ export class Agent {
|
|
|
615
703
|
if (typeof manager.updateHotContextSettings !== 'function') {
|
|
616
704
|
throw new Error('The active context strategy does not support live context settings');
|
|
617
705
|
}
|
|
618
|
-
|
|
706
|
+
const settings = (s: HotContextSettingsStatus | null) =>
|
|
707
|
+
JSON.stringify([s?.tailTokens, s?.transitionPaceTokens, s?.preparedWindowTokens]);
|
|
708
|
+
const before = settings(this.getHotContextSettings());
|
|
709
|
+
const status = manager.updateHotContextSettings(update);
|
|
710
|
+
if (settings(status) !== before) this.contextSettingsChangeCount++;
|
|
711
|
+
return status;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/** How many times the live budget, its descent target or the hot context
|
|
715
|
+
* settings have changed.
|
|
716
|
+
* @internal For the framework's budget holds; not a host API. */
|
|
717
|
+
contextSettingsChanges(): number {
|
|
718
|
+
return this.contextSettingsChangeCount;
|
|
619
719
|
}
|
|
620
720
|
|
|
621
721
|
getRuntimeSettings(): AgentRuntimeSettingsSnapshot {
|
|
@@ -682,6 +782,7 @@ export class Agent {
|
|
|
682
782
|
private setContextBudget(budget: number | undefined, target: number | undefined, armed = false): void {
|
|
683
783
|
if (budget !== this.contextBudgetTokens) this.liveBudgetEpoch++;
|
|
684
784
|
if (armed || target !== this.contextBudgetTargetTokens) this.descentEpoch++;
|
|
785
|
+
if (budget !== this.contextBudgetTokens || target !== this.contextBudgetTargetTokens) this.contextSettingsChangeCount++;
|
|
685
786
|
this.contextBudgetTokens = budget;
|
|
686
787
|
this.contextBudgetTargetTokens = target;
|
|
687
788
|
}
|
|
@@ -721,7 +822,7 @@ export class Agent {
|
|
|
721
822
|
return await this.compileAtLiveBudgetNoting(compile, started);
|
|
722
823
|
} finally {
|
|
723
824
|
this.compilesRunning.delete(started);
|
|
724
|
-
const earliest =
|
|
825
|
+
const earliest = [...this.compilesRunning].reduce((min, start) => Math.min(min, start), Infinity);
|
|
725
826
|
for (const [budget, start] of this.latestEndedStart) {
|
|
726
827
|
if (start < earliest) this.latestEndedStart.delete(budget);
|
|
727
828
|
}
|
|
@@ -1131,45 +1232,60 @@ export class Agent {
|
|
|
1131
1232
|
}
|
|
1132
1233
|
|
|
1133
1234
|
/**
|
|
1134
|
-
* RFC-006 consumed watermark, per branch: the
|
|
1135
|
-
* the latest of
|
|
1136
|
-
*
|
|
1137
|
-
*
|
|
1138
|
-
*
|
|
1139
|
-
*
|
|
1140
|
-
*
|
|
1141
|
-
*
|
|
1142
|
-
*
|
|
1143
|
-
*
|
|
1235
|
+
* RFC-006 consumed watermark, per branch: how far the agent had read as of
|
|
1236
|
+
* the latest of its creation, a committing compile that returns, and a
|
|
1237
|
+
* tool boundary that injected messages into a live stream declaring it
|
|
1238
|
+
* carries them (`supportsInjectedMessages` true: membrane's native path,
|
|
1239
|
+
* from membrane 0.6.0). A compile counts from when it takes its mark,
|
|
1240
|
+
* before it awaits, so one that began before a boundary's mark doesn't
|
|
1241
|
+
* roll the mark back (applyCompileWatermark), and a dry run, such as
|
|
1242
|
+
* previewActivation's, doesn't move it.
|
|
1243
|
+
*
|
|
1244
|
+
* It is a ReadMark (read-marks.ts), read only through `covers`. Once the
|
|
1245
|
+
* agent's context presents rows (#291's presentation index, in presented
|
|
1246
|
+
* mode), it covers exactly the rows in the agent's window as of the mark:
|
|
1247
|
+
* a row stored then and not yet presented to the agent isn't covered.
|
|
1248
|
+
* While the context is in legacy mode, its window is the record, and the
|
|
1249
|
+
* mark covers every row stored on the branch by then, as it always did:
|
|
1250
|
+
* a prefix of the record, so it also covers stored messages the agent
|
|
1251
|
+
* wasn't given, such as another slot's. Once the window is written down
|
|
1252
|
+
* (an agent registered on a branch its window was never written down on
|
|
1253
|
+
* holds such a mark until its first compile), a mark taken in legacy mode
|
|
1254
|
+
* covers the rows its window held by the mark where they still stand, as
|
|
1255
|
+
* a mark taken in presented mode then would: a row stored after it, taken
|
|
1256
|
+
* out of the window since, or presented to the agent again, isn't.
|
|
1144
1257
|
*
|
|
1145
1258
|
* A message above it may still be replaced or withdrawn in place by its
|
|
1146
1259
|
* sender, though it may already have been in one of the agent's requests.
|
|
1147
1260
|
* A live stream carries each round's own content and results, which it
|
|
1148
1261
|
* stores at its tool boundaries, into its next request.
|
|
1149
1262
|
*/
|
|
1150
|
-
private consumedWatermark:
|
|
1263
|
+
private consumedWatermark: ReadMark | null = null;
|
|
1151
1264
|
/** Counts marks (markContextConsumed's and applyCompileWatermark's), so a
|
|
1152
1265
|
* compile that finishes can tell whether one was made while it ran. */
|
|
1153
1266
|
private watermarkMarks = 0;
|
|
1154
1267
|
/**
|
|
1155
|
-
*
|
|
1156
|
-
* front of
|
|
1157
|
-
*
|
|
1158
|
-
*
|
|
1159
|
-
* have been shown, though: for one, a live stream carries each
|
|
1160
|
-
* content and results, stored at a boundary that injected
|
|
1161
|
-
* next request. A compile that throws assembled nothing,
|
|
1162
|
-
* back where it can (unshowFailedCompile). A
|
|
1163
|
-
*
|
|
1164
|
-
*
|
|
1268
|
+
* How far a compile or a tool boundary may have put the agent's context in
|
|
1269
|
+
* front of it, per branch. It moves where the consumed watermark does,
|
|
1270
|
+
* and sooner: when a committing compile takes its mark, before it awaits,
|
|
1271
|
+
* and at every tool boundary that injects into its stream. A message above
|
|
1272
|
+
* it may still have been shown, though: for one, a live stream carries each
|
|
1273
|
+
* round's own content and results, stored at a boundary that injected
|
|
1274
|
+
* nothing, into its next request. A compile that throws assembled nothing,
|
|
1275
|
+
* and gives its move back where it can (unshowFailedCompile). A mark taken
|
|
1276
|
+
* in legacy mode, read while the window is the record, counts a prefix of
|
|
1277
|
+
* the record, so a message stored below it without having been shown
|
|
1278
|
+
* counts as shown, which errs toward a marker; one taken in presented
|
|
1279
|
+
* mode, and one taken in legacy mode read once the window is written down,
|
|
1280
|
+
* cover the window as it stood.
|
|
1165
1281
|
*/
|
|
1166
|
-
private shownWatermark:
|
|
1282
|
+
private shownWatermark: ReadMark | null = null;
|
|
1167
1283
|
|
|
1168
|
-
getConsumedWatermark():
|
|
1284
|
+
getConsumedWatermark(): ReadMark | null {
|
|
1169
1285
|
return this.consumedWatermark;
|
|
1170
1286
|
}
|
|
1171
1287
|
|
|
1172
|
-
getShownWatermark():
|
|
1288
|
+
getShownWatermark(): ReadMark | null {
|
|
1173
1289
|
return this.shownWatermark;
|
|
1174
1290
|
}
|
|
1175
1291
|
|
|
@@ -1181,27 +1297,32 @@ export class Agent {
|
|
|
1181
1297
|
* request runs, so a request that fails, ending its stream with an error,
|
|
1182
1298
|
* leaves this as it was.
|
|
1183
1299
|
*/
|
|
1184
|
-
private answeredWatermark:
|
|
1300
|
+
private answeredWatermark: ReadMark | null = null;
|
|
1185
1301
|
|
|
1186
|
-
getAnsweredWatermark():
|
|
1302
|
+
getAnsweredWatermark(): ReadMark | null {
|
|
1187
1303
|
return this.answeredWatermark;
|
|
1188
1304
|
}
|
|
1189
1305
|
|
|
1190
1306
|
/** A request that carried `watermark` was answered. Requests are answered
|
|
1191
1307
|
* in the order they're sent, and the consumed watermark only advances
|
|
1192
1308
|
* within a branch, so the latest is the newest. */
|
|
1193
|
-
markAnswered(watermark:
|
|
1309
|
+
markAnswered(watermark: ReadMark | null): void {
|
|
1194
1310
|
if (watermark) this.answeredWatermark = watermark;
|
|
1195
1311
|
}
|
|
1196
1312
|
|
|
1313
|
+
/** Whether a turn this agent opens pins its inputs (AgentConfig.turnInputsPin, on by default). */
|
|
1314
|
+
readonly pinsTurnInputs: boolean;
|
|
1315
|
+
|
|
1197
1316
|
/**
|
|
1198
|
-
* Keep the
|
|
1199
|
-
* opening, with a raw pin under one name per agent
|
|
1200
|
-
*
|
|
1201
|
-
*
|
|
1202
|
-
*
|
|
1203
|
-
*
|
|
1204
|
-
*
|
|
1317
|
+
* Keep the rows of the agent's window from `first` through `last` raw for
|
|
1318
|
+
* the turn now opening, with a raw pin under one name per agent: a
|
|
1319
|
+
* strategy reads a pin by its rows' positions in its message view, which
|
|
1320
|
+
* is the window, in its order (#291; in legacy mode the record). Any pin
|
|
1321
|
+
* of that name already held is removed first, one a crash left included.
|
|
1322
|
+
* Under a strategy without pins nothing is pinned. A committing compile
|
|
1323
|
+
* that refuses as over budget while a pin of that name is held removes it
|
|
1324
|
+
* and compiles once more, and `unpinTurnInputs` removes it. Returns the
|
|
1325
|
+
* pin's id, or undefined when nothing was pinned.
|
|
1205
1326
|
*
|
|
1206
1327
|
* @internal For the framework's turn starts; not a host API.
|
|
1207
1328
|
*/
|
|
@@ -1258,48 +1379,91 @@ export class Agent {
|
|
|
1258
1379
|
* draft resend, or a send tool whose channel the framework records), on
|
|
1259
1380
|
* the branch it was taken on. A wake that carries a channel, unless it's
|
|
1260
1381
|
* marked ambient (InferenceRequest.ambient), keeps its turn unless the
|
|
1261
|
-
* agent spoke there after reading the
|
|
1382
|
+
* agent spoke there after reading the row the wake is for. It
|
|
1262
1383
|
* lives as long as this Agent: an agent made again starts it empty, and
|
|
1263
1384
|
* such a wake then stays.
|
|
1264
1385
|
*/
|
|
1265
|
-
private publishedThrough = new Map<string,
|
|
1386
|
+
private publishedThrough = new Map<string, ReadMark>();
|
|
1266
1387
|
|
|
1267
1388
|
/** Note a publish into `destination` (its key), made having read through
|
|
1268
1389
|
* `readThrough`: the consumed watermark when its words were written, or
|
|
1269
|
-
* its call made.
|
|
1270
|
-
|
|
1390
|
+
* its call made. A later mark on the same branch (markAtOrAfter: of two
|
|
1391
|
+
* at one head, the one whose window reached further) replaces an earlier
|
|
1392
|
+
* one; one on another branch replaces whatever was noted. */
|
|
1393
|
+
notePublished(destination: string, readThrough: ReadMark | null): void {
|
|
1271
1394
|
if (!readThrough) return;
|
|
1272
1395
|
const noted = this.publishedThrough.get(destination);
|
|
1273
|
-
if (noted && noted
|
|
1396
|
+
if (noted && markAtOrAfter(noted, readThrough) === true) return;
|
|
1274
1397
|
this.publishedThrough.set(destination, readThrough);
|
|
1275
1398
|
}
|
|
1276
1399
|
|
|
1277
1400
|
/** Whether the agent published into `destination` (its key) having read
|
|
1278
|
-
*
|
|
1279
|
-
|
|
1401
|
+
* `row`, as `cm` (the agent's context, where the row's place in its
|
|
1402
|
+
* window is read) says: the mark noted for the destination covers it. A
|
|
1403
|
+
* mark that can't say (one on another branch) says no. */
|
|
1404
|
+
publishedAfterReading(destination: string, row: MarkedRow, cm: MarkCm): boolean {
|
|
1280
1405
|
const noted = this.publishedThrough.get(destination);
|
|
1281
|
-
return !!noted && noted
|
|
1406
|
+
return !!noted && covers(noted, cm, row) === 'covered';
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
/**
|
|
1410
|
+
* Every read mark this agent holds: its consumed, shown and answered
|
|
1411
|
+
* watermarks and the mark noted for each destination it published into,
|
|
1412
|
+
* each mark once (two of them are often the one mark). A redo on the
|
|
1413
|
+
* window (AgentFramework.redo) reads which of them covered the rows it
|
|
1414
|
+
* puts back, and gives those marks again (replaceReadMarks).
|
|
1415
|
+
*/
|
|
1416
|
+
heldReadMarks(): ReadMark[] {
|
|
1417
|
+
const held = new Set<ReadMark>();
|
|
1418
|
+
for (const mark of [this.consumedWatermark, this.shownWatermark, this.answeredWatermark, ...this.publishedThrough.values()]) {
|
|
1419
|
+
if (mark) held.add(mark);
|
|
1420
|
+
}
|
|
1421
|
+
return [...held];
|
|
1282
1422
|
}
|
|
1283
1423
|
|
|
1284
|
-
/**
|
|
1285
|
-
*
|
|
1286
|
-
*
|
|
1424
|
+
/**
|
|
1425
|
+
* Put each mark `replacements` maps in its place wherever this agent holds
|
|
1426
|
+
* it (heldReadMarks), so a mark held as two of them stays one: a redo on
|
|
1427
|
+
* the window (#291) puts rows back at new ordinals, past every mark that
|
|
1428
|
+
* covered them before their undo, and gives each such mark again where it
|
|
1429
|
+
* covers them now. It counts as a mark (watermarkMarks), so a compile that
|
|
1430
|
+
* began before it doesn't put its own older mark back over it.
|
|
1431
|
+
*/
|
|
1432
|
+
replaceReadMarks(replacements: ReadonlyMap<ReadMark, ReadMark>): void {
|
|
1433
|
+
const swap = (mark: ReadMark | null): ReadMark | null => (mark && replacements.get(mark)) ?? mark;
|
|
1434
|
+
const consumed = swap(this.consumedWatermark);
|
|
1435
|
+
if (consumed !== this.consumedWatermark) {
|
|
1436
|
+
this.consumedWatermark = consumed;
|
|
1437
|
+
this.watermarkMarks++;
|
|
1438
|
+
}
|
|
1439
|
+
this.shownWatermark = swap(this.shownWatermark);
|
|
1440
|
+
this.answeredWatermark = swap(this.answeredWatermark);
|
|
1441
|
+
for (const [destination, mark] of this.publishedThrough) {
|
|
1442
|
+
const next = replacements.get(mark);
|
|
1443
|
+
if (next) this.publishedThrough.set(destination, next);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
/** Mark everything in the agent's window (in legacy mode, everything
|
|
1448
|
+
* stored) as consumed: the agent's creation, at boot or later, and a tool
|
|
1449
|
+
* boundary that injected messages into a live stream declaring it carries
|
|
1450
|
+
* them; see consumedWatermark. */
|
|
1287
1451
|
markContextConsumed(): void {
|
|
1288
1452
|
// Tolerates partial context-manager doubles (tests build Agents over
|
|
1289
1453
|
// stubs). Without a watermark, a reader that looks for one takes its own
|
|
1290
1454
|
// side: the coalescer counts the message as read, and the framework's
|
|
1291
|
-
//
|
|
1292
|
-
//
|
|
1293
|
-
// (
|
|
1455
|
+
// releasedWindow counts it as unread. A wake for a row it reads
|
|
1456
|
+
// (InferenceRequest.readsRow) reads the answered watermark instead
|
|
1457
|
+
// (rowDone).
|
|
1294
1458
|
this.consumedWatermark = this.pendingWatermark();
|
|
1295
1459
|
this.watermarkMarks++;
|
|
1296
1460
|
this.shownWatermark = this.consumedWatermark;
|
|
1297
1461
|
}
|
|
1298
1462
|
|
|
1299
|
-
/** Mark everything
|
|
1300
|
-
* that injected messages into
|
|
1301
|
-
* a watermark the coalescer counts a message as
|
|
1302
|
-
* read without a consumed watermark. */
|
|
1463
|
+
/** Mark everything in the agent's window (in legacy mode, everything
|
|
1464
|
+
* stored) as possibly shown (a tool boundary that injected messages into
|
|
1465
|
+
* its stream). Without a watermark the coalescer counts a message as
|
|
1466
|
+
* shown, as it counts one read without a consumed watermark. */
|
|
1303
1467
|
markContextShown(): void {
|
|
1304
1468
|
this.shownWatermark = this.pendingWatermark();
|
|
1305
1469
|
}
|
|
@@ -1313,11 +1477,10 @@ export class Agent {
|
|
|
1313
1477
|
* the second then throws, it restores the first's failed claim. Messages
|
|
1314
1478
|
* up to that claim then count as shown, although no request held those
|
|
1315
1479
|
* above the watermark the first compile found, which errs toward a marker
|
|
1316
|
-
* until the next compile or boundary moves the watermark.
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
): void {
|
|
1480
|
+
* until the next compile or boundary moves the watermark. Each mark is a
|
|
1481
|
+
* fresh object (readMarkOf), so the compare by identity is this compile's
|
|
1482
|
+
* own claim. */
|
|
1483
|
+
private unshowFailedCompile(watermark: ReadMark | null, before: ReadMark | null): void {
|
|
1321
1484
|
if (watermark && this.shownWatermark === watermark) this.shownWatermark = before;
|
|
1322
1485
|
}
|
|
1323
1486
|
|
|
@@ -1328,49 +1491,41 @@ export class Agent {
|
|
|
1328
1491
|
* mark's branch, so a boundary's mark is never rolled back by a compile
|
|
1329
1492
|
* that started before it (a committing compile, such as compileContext's,
|
|
1330
1493
|
* run during a live turn; a dry run, such as previewActivation's, never
|
|
1331
|
-
* reaches here).
|
|
1494
|
+
* reaches here). Marks are ordered by markAtOrAfter: by the window's
|
|
1495
|
+
* index length where both keep one, else by the store's head, each of
|
|
1496
|
+
* which only grows on a branch.
|
|
1332
1497
|
*/
|
|
1333
|
-
private applyCompileWatermark(watermark:
|
|
1498
|
+
private applyCompileWatermark(watermark: ReadMark, marksBefore: number): void {
|
|
1334
1499
|
const current = this.consumedWatermark;
|
|
1335
|
-
if (this.watermarkMarks !== marksBefore && current
|
|
1336
|
-
&& (current.branch !== watermark.branch || current.sequence >= watermark.sequence)) return;
|
|
1500
|
+
if (this.watermarkMarks !== marksBefore && current && markAtOrAfter(current, watermark) !== false) return;
|
|
1337
1501
|
this.consumedWatermark = watermark;
|
|
1338
1502
|
this.watermarkMarks++;
|
|
1339
1503
|
}
|
|
1340
1504
|
|
|
1341
1505
|
/**
|
|
1342
|
-
* The branch now (`branchKey`) and
|
|
1343
|
-
*
|
|
1506
|
+
* The branch now (`branchKey`) and the store's head on it (storeHeadOf, the
|
|
1507
|
+
* head a mark pendingWatermark takes keeps): a message stored on that
|
|
1508
|
+
* branch later has a larger sequence. Sequences are numbered per branch, so
|
|
1509
|
+
* one compares with another only on the same branch. A record sequence, not
|
|
1510
|
+
* a place in the agent's window (#291).
|
|
1344
1511
|
*/
|
|
1345
1512
|
branchHead(): { branch: string; sequence: number } | undefined {
|
|
1346
|
-
const
|
|
1513
|
+
const sequence = storeHeadOf(this.contextManager);
|
|
1347
1514
|
const cm = this.contextManager as Partial<ContextManager>;
|
|
1348
|
-
if (
|
|
1515
|
+
if (sequence === null || typeof cm.currentBranchRef !== 'function') return undefined;
|
|
1349
1516
|
try {
|
|
1350
|
-
return { branch: branchKey(cm.currentBranchRef()), sequence
|
|
1517
|
+
return { branch: branchKey(cm.currentBranchRef()), sequence };
|
|
1351
1518
|
} catch {
|
|
1352
1519
|
return undefined;
|
|
1353
1520
|
}
|
|
1354
1521
|
}
|
|
1355
1522
|
|
|
1356
|
-
/** The watermark a successful compile will establish (taken before, applied
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
// everything stored on the branch so far, including messages merged in
|
|
1363
|
-
// from another slot (the subconscious reads the residents' shared slot).
|
|
1364
|
-
const store = typeof cm.getStore === 'function' ? cm.getStore() as { currentSequence?: () => number } : undefined;
|
|
1365
|
-
let sequence = typeof store?.currentSequence === 'function' ? store.currentSequence() : undefined;
|
|
1366
|
-
if (sequence === undefined) {
|
|
1367
|
-
const count = typeof cm.getMessageCount === 'function' ? cm.getMessageCount() : cm.getAllMessages().length;
|
|
1368
|
-
sequence = count > 0 ? cm.getAllMessages().at(-1)?.sequence ?? 0 : 0;
|
|
1369
|
-
}
|
|
1370
|
-
return { branch: cm.currentBranch().name, sequence };
|
|
1371
|
-
} catch {
|
|
1372
|
-
return null;
|
|
1373
|
-
}
|
|
1523
|
+
/** The watermark a successful compile will establish (taken before, applied
|
|
1524
|
+
* after): where the agent's context stands now (readMarkOf), its window's
|
|
1525
|
+
* index length with the store's head once it presents rows. Null for a
|
|
1526
|
+
* context double that can't say. */
|
|
1527
|
+
private pendingWatermark(): ReadMark | null {
|
|
1528
|
+
return readMarkOf(this.contextManager);
|
|
1374
1529
|
}
|
|
1375
1530
|
|
|
1376
1531
|
/** A committing compile, as for a request that is sent: the context
|
|
@@ -1413,9 +1568,10 @@ export class Agent {
|
|
|
1413
1568
|
*/
|
|
1414
1569
|
private renderedInjections?: {
|
|
1415
1570
|
branch: { readonly id: string; readonly created: number };
|
|
1416
|
-
/** Per namespace, per content hash:
|
|
1417
|
-
*
|
|
1418
|
-
|
|
1571
|
+
/** Per namespace, per content hash: each copy of that content the
|
|
1572
|
+
* compile rendered, by its row's id, with the part it is, how many
|
|
1573
|
+
* parts the content has, whether the compile held it, and its sequence. */
|
|
1574
|
+
byNamespace: Map<string, Map<string, RenderedInjectionCopy[]>>;
|
|
1419
1575
|
};
|
|
1420
1576
|
|
|
1421
1577
|
/**
|
|
@@ -1446,9 +1602,8 @@ export class Agent {
|
|
|
1446
1602
|
/**
|
|
1447
1603
|
* A host's hook, called with each committing compile's `thinkingStrip` (never a dry run's) and the key of the
|
|
1448
1604
|
* branch it read (`branchKey`), as the compile returns, whether or not its request is then sent, since the
|
|
1449
|
-
* context manager's binding record takes the strip either way. One that throws is logged.
|
|
1450
|
-
*
|
|
1451
|
-
* whose `[reasoning]` line for the agent then isn't told.
|
|
1605
|
+
* context manager's binding record takes the strip either way. One that throws is logged. It is observational only;
|
|
1606
|
+
* the framework does not write agent-facing reasoning-loss notices.
|
|
1452
1607
|
*/
|
|
1453
1608
|
onThinkingStrip?: (strip: ThinkingStrip, branch: string) => void;
|
|
1454
1609
|
|
|
@@ -1462,18 +1617,23 @@ export class Agent {
|
|
|
1462
1617
|
* start and the next (a host's own committing compile, or the compression
|
|
1463
1618
|
* an over-budget retry waits for) can summarize them all the same: the
|
|
1464
1619
|
* next request then has the summary's word for them, and the start after
|
|
1465
|
-
* it stores them again, as after any fold. The
|
|
1466
|
-
* rows at a time from the newest, stopping at that point.
|
|
1620
|
+
* it stores them again, as after any fold. The slot's record is read
|
|
1621
|
+
* back 64 rows at a time from the newest, stopping at that point.
|
|
1622
|
+
*
|
|
1623
|
+
* It reads the record, by sequence, not the agent's window, and that
|
|
1624
|
+
* holds once the context presents rows (#291): the rows it counts are
|
|
1625
|
+
* this agent's own stored injections, its own rows, which enter its
|
|
1626
|
+
* window as they are written, so one stored after the point is in no
|
|
1627
|
+
* request yet whatever else has been stored or presented since. Another
|
|
1628
|
+
* agent's rows, stored into a shared slot at once rather than queued, are
|
|
1629
|
+
* passed over, whatever they are.
|
|
1467
1630
|
*/
|
|
1468
1631
|
unsentInjection(namespace: string): { contentHash: string; whole: boolean } | undefined {
|
|
1469
1632
|
let newest: { contentHash: string; parts: number; held: Set<number> } | undefined;
|
|
1470
1633
|
try {
|
|
1471
|
-
const
|
|
1472
|
-
const since = this.unsentSince.get(branch);
|
|
1634
|
+
const since = this.unsentSince.get(branchKey(this.contextManager.currentBranchRef()));
|
|
1473
1635
|
if (since === undefined) {
|
|
1474
|
-
|
|
1475
|
-
const top = count > 0 ? this.contextManager.getMessageWindow(count - 1, 1, { resolveBlobs: false }).messages[0]?.sequence ?? 0 : 0;
|
|
1476
|
-
this.unsentSince.set(branch, top);
|
|
1636
|
+
this.markUnsentPoint();
|
|
1477
1637
|
return undefined;
|
|
1478
1638
|
}
|
|
1479
1639
|
scan: for (let end = this.contextManager.getMessageCount(); end > 0;) {
|
|
@@ -1484,6 +1644,9 @@ export class Agent {
|
|
|
1484
1644
|
if (row.sequence <= since) break scan;
|
|
1485
1645
|
const mark = storedInjectionMarkOf(row.metadata);
|
|
1486
1646
|
if (mark?.agent !== this.name || mark.namespace !== namespace) continue;
|
|
1647
|
+
// A copy an undo took out of the window (#291) is in no window
|
|
1648
|
+
// now, so it isn't the copy the agent will read.
|
|
1649
|
+
if (this.contextManager.windowMode?.() === 'presented' && this.contextManager.windowStatusOf(row.id) === 'undone') continue;
|
|
1487
1650
|
// Read from the newest back, the first copy met is the newest
|
|
1488
1651
|
// content; its other parts pool with it.
|
|
1489
1652
|
newest ??= { contentHash: mark.contentHash, parts: mark.parts, held: new Set() };
|
|
@@ -1506,6 +1669,42 @@ export class Agent {
|
|
|
1506
1669
|
return newest && { contentHash: newest.contentHash, whole: newest.held.size === newest.parts };
|
|
1507
1670
|
}
|
|
1508
1671
|
|
|
1672
|
+
/** Set the unsent point where it isn't set, as a start's plan does: a row
|
|
1673
|
+
* stored after it counts as in no request until a compile built to send.
|
|
1674
|
+
* @internal For the framework's budget holds; not a host API. */
|
|
1675
|
+
markUnsentPoint(): void {
|
|
1676
|
+
const branch = branchKey(this.contextManager.currentBranchRef());
|
|
1677
|
+
if (this.unsentSince.has(branch)) return;
|
|
1678
|
+
const count = this.contextManager.getMessageCount();
|
|
1679
|
+
const top = count > 0 ? this.contextManager.getMessageWindow(count - 1, 1, { resolveBlobs: false }).messages[0]?.sequence ?? 0 : 0;
|
|
1680
|
+
this.unsentSince.set(branch, top);
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
/** The ids of this agent's stored injections, of every namespace, stored
|
|
1684
|
+
* on its branch since its last compile built to send and in its window
|
|
1685
|
+
* where it's presented, in the record's order, a sharded body's first
|
|
1686
|
+
* shard first: the rows unsentInjection counts, which no request has
|
|
1687
|
+
* carried. Reads only, so an unset point gives none. */
|
|
1688
|
+
unsentInjectionRows(): MessageId[] {
|
|
1689
|
+
const ids: MessageId[] = [];
|
|
1690
|
+
const since = this.unsentSince.get(branchKey(this.contextManager.currentBranchRef()));
|
|
1691
|
+
if (since === undefined) return ids;
|
|
1692
|
+
const presented = this.contextManager.windowMode?.() === 'presented';
|
|
1693
|
+
scan: for (let end = this.contextManager.getMessageCount(); end > 0;) {
|
|
1694
|
+
const span = Math.min(end, 64);
|
|
1695
|
+
const { messages } = this.contextManager.getMessageWindow(end - span, span, { resolveBlobs: false });
|
|
1696
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1697
|
+
const row = messages[i]!;
|
|
1698
|
+
if (row.sequence <= since) break scan;
|
|
1699
|
+
if (storedInjectionMarkOf(row.metadata)?.agent !== this.name) continue;
|
|
1700
|
+
if (presented && this.contextManager.windowStatusOf(row.id) !== 'in') continue;
|
|
1701
|
+
ids.push(row.id);
|
|
1702
|
+
}
|
|
1703
|
+
end -= span;
|
|
1704
|
+
}
|
|
1705
|
+
return ids.reverse();
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1509
1708
|
/** Record which of this agent's stored injections a compile built to send
|
|
1510
1709
|
* rendered. Another agent's stored rows never reach this agent's compile,
|
|
1511
1710
|
* since every compile of a shared store leaves them out by its view
|
|
@@ -1534,7 +1733,7 @@ export class Agent {
|
|
|
1534
1733
|
this.renderedInjections = undefined;
|
|
1535
1734
|
return;
|
|
1536
1735
|
}
|
|
1537
|
-
const byNamespace = new Map<string, Map<string,
|
|
1736
|
+
const byNamespace = new Map<string, Map<string, RenderedInjectionCopy[]>>();
|
|
1538
1737
|
for (const [i, source] of provenance.messages.entries()) {
|
|
1539
1738
|
// Only a message rendered as an injection's participant can be one, so
|
|
1540
1739
|
// the store is read for those alone.
|
|
@@ -1548,14 +1747,11 @@ export class Agent {
|
|
|
1548
1747
|
// would only add copies, every start. A part missing shards still
|
|
1549
1748
|
// says which content is newest.
|
|
1550
1749
|
const held = body.complete || (body.missing !== undefined && !body.missing.includes('shards'));
|
|
1551
|
-
const contents = byNamespace.get(mark.namespace) ?? new Map();
|
|
1750
|
+
const contents = byNamespace.get(mark.namespace) ?? new Map<string, RenderedInjectionCopy[]>();
|
|
1552
1751
|
byNamespace.set(mark.namespace, contents);
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
if (held) known.held.add(mark.part);
|
|
1557
|
-
known.sequence = Math.max(known.sequence, body.sequence);
|
|
1558
|
-
contents.set(mark.contentHash, known);
|
|
1752
|
+
const copies = contents.get(mark.contentHash) ?? [];
|
|
1753
|
+
copies.push({ id: body.messageId, part: mark.part, parts: mark.parts, held, sequence: body.sequence });
|
|
1754
|
+
contents.set(mark.contentHash, copies);
|
|
1559
1755
|
}
|
|
1560
1756
|
}
|
|
1561
1757
|
this.renderedInjections = { branch: provenance.branch, byNamespace };
|
|
@@ -1565,19 +1761,48 @@ export class Agent {
|
|
|
1565
1761
|
* The newest content of `namespace` among this agent's stored injections
|
|
1566
1762
|
* that the last compile built to send rendered, by its newest copy: its
|
|
1567
1763
|
* content hash, and whether every part of that content was there in some
|
|
1568
|
-
* copy, every shard, however the strategy shaped it.
|
|
1569
|
-
*
|
|
1570
|
-
* the
|
|
1764
|
+
* copy, every shard, however the strategy shaped it. Copies of the same
|
|
1765
|
+
* content pool what they hold: the agent has each part one of them holds.
|
|
1766
|
+
* A copy the agent's next request won't hold is passed over: one an undo
|
|
1767
|
+
* took out of its window since (#291: `'undone'`, which no presentation
|
|
1768
|
+
* point presents again until a redo), and one no longer stored. Undefined
|
|
1769
|
+
* when no copy is left, when this agent hasn't built a request since it
|
|
1770
|
+
* started, or when the window's branch has changed since.
|
|
1571
1771
|
*/
|
|
1572
1772
|
renderedInjection(namespace: string): { contentHash: string; whole: boolean } | undefined {
|
|
1573
1773
|
const rendered = this.renderedInjections;
|
|
1574
1774
|
const branch = this.contextManager.currentBranchRef();
|
|
1575
1775
|
if (!rendered || rendered.branch.id !== branch.id || rendered.branch.created !== branch.created) return undefined;
|
|
1576
|
-
let newest:
|
|
1577
|
-
for (const
|
|
1578
|
-
|
|
1776
|
+
let newest: { contentHash: string; parts: number; held: Set<number>; sequence: number } | undefined;
|
|
1777
|
+
for (const [contentHash, copies] of rendered.byNamespace.get(namespace) ?? []) {
|
|
1778
|
+
let pooled: { parts: number; held: Set<number>; sequence: number } | undefined;
|
|
1779
|
+
for (const copy of copies) {
|
|
1780
|
+
if (!this.renderedCopyStands(copy.id)) continue;
|
|
1781
|
+
pooled ??= { parts: copy.parts, held: new Set(), sequence: copy.sequence };
|
|
1782
|
+
if (copy.held) pooled.held.add(copy.part);
|
|
1783
|
+
pooled.sequence = Math.max(pooled.sequence, copy.sequence);
|
|
1784
|
+
}
|
|
1785
|
+
if (pooled && (!newest || pooled.sequence > newest.sequence)) newest = { contentHash, ...pooled };
|
|
1786
|
+
}
|
|
1787
|
+
return newest ? { contentHash: newest.contentHash, whole: newest.held.size === newest.parts } : undefined;
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
/**
|
|
1791
|
+
* Whether a stored injection's copy the last compile rendered is still
|
|
1792
|
+
* where the agent's next request reads it: stored, and not taken out of
|
|
1793
|
+
* its window by an undo (#291). A copy out of the window otherwise
|
|
1794
|
+
* (`'out'`, as a redo leaves one presented since its undo) is presented
|
|
1795
|
+
* again at the agent's next point, its own rows' sweep, so it counts. A
|
|
1796
|
+
* context that can't say (a double without windowStatusOf, a read that
|
|
1797
|
+
* throws) counts it, as before the window was presented.
|
|
1798
|
+
*/
|
|
1799
|
+
private renderedCopyStands(id: MessageId): boolean {
|
|
1800
|
+
try {
|
|
1801
|
+
const status = this.contextManager.windowStatusOf?.(id);
|
|
1802
|
+
return status !== 'undone' && status !== 'absent';
|
|
1803
|
+
} catch {
|
|
1804
|
+
return true;
|
|
1579
1805
|
}
|
|
1580
|
-
return newest ? { contentHash: newest[0], whole: newest[1].held.size === newest[1].parts } : undefined;
|
|
1581
1806
|
}
|
|
1582
1807
|
|
|
1583
1808
|
/**
|
|
@@ -1747,13 +1972,13 @@ export class Agent {
|
|
|
1747
1972
|
const { systemInjections } = compiled;
|
|
1748
1973
|
// The framework's own pricing stamp never goes out (thinking-token-stamp.ts);
|
|
1749
1974
|
// the agent's own turns are then presented under its name (presentOwnTurns).
|
|
1750
|
-
const messages = this.presentOwnTurns(withoutTokenEstimates(compiled.messages));
|
|
1975
|
+
const messages = this.presentOwnTurns(this.foreignRoundsAsSent(withoutTokenEstimates(compiled.messages)));
|
|
1751
1976
|
// Read once, after the first compile, since results may have become
|
|
1752
1977
|
// ready while it ran; the refusal retry, assembled while the agent is
|
|
1753
1978
|
// inferring, sends the same ones.
|
|
1754
1979
|
unguardedResults ??= this._state.status === 'ready' && !guardedResults
|
|
1755
1980
|
? this.buildToolResultMessages(this._state.toolResults) : [];
|
|
1756
|
-
messages
|
|
1981
|
+
appendAll(messages, unguardedResults);
|
|
1757
1982
|
return {
|
|
1758
1983
|
messages: this.toolResultGuard.prepareRequest(messages, true),
|
|
1759
1984
|
system: this.buildSystemPrompt(systemInjections),
|
|
@@ -1989,6 +2214,8 @@ export class Agent {
|
|
|
1989
2214
|
// compression path.)
|
|
1990
2215
|
// The same pass a tool boundary applies to what it notes as sent
|
|
1991
2216
|
// (sent-rows.ts), so the two can't drift.
|
|
2217
|
+
// Another agent's rounds go out as this agent is sent them (setForeignRounds).
|
|
2218
|
+
messages = this.foreignRoundsAsSent(messages);
|
|
1992
2219
|
messages = messages
|
|
1993
2220
|
.map((m) => ({ ...m, content: m.content.filter(carriedBlock) }))
|
|
1994
2221
|
.filter((m) => m.content.length > 0);
|
|
@@ -2094,9 +2321,10 @@ export class Agent {
|
|
|
2094
2321
|
return { ...own, blockBinding: { prefixMismatchBehavior: 'drop_block' } };
|
|
2095
2322
|
}
|
|
2096
2323
|
|
|
2097
|
-
/** The stream's way to tell the context manager what its later rounds sent, with the head its compile was given
|
|
2098
|
-
* where the agent's model binds its thinking
|
|
2099
|
-
|
|
2324
|
+
/** The stream's way to tell the context manager what its later rounds sent, with the head its compile was given,
|
|
2325
|
+
* and which stored bodies' thinking the provider dropped: where the agent's model binds its thinking
|
|
2326
|
+
* (context-manager's `noteRequestSent` and `noteThinkingDropped`). */
|
|
2327
|
+
private requestNotes(binding: BindingCompileOptions, compiled: CompiledForRequest): Pick<StartStreamResult, 'noteRequestSent' | 'noteThinkingDropped'> {
|
|
2100
2328
|
const identity = binding.identity;
|
|
2101
2329
|
// Each note names the compile the stream was built from, so a note can't vouch for this stream under a record a
|
|
2102
2330
|
// later committing compile with binds wrote. A compile that reports no provenance gives the stream nothing to name, and the
|
|
@@ -2104,7 +2332,10 @@ export class Agent {
|
|
|
2104
2332
|
const compileId = compiled.provenance?.compileId;
|
|
2105
2333
|
if (!identity || compileId === undefined) return {};
|
|
2106
2334
|
const cm = this.contextManager;
|
|
2107
|
-
return {
|
|
2335
|
+
return {
|
|
2336
|
+
noteRequestSent: (rows) => cm.noteRequestSent(rows, identity, compileId),
|
|
2337
|
+
noteThinkingDropped: (messageIds) => cm.noteThinkingDropped(messageIds, compileId),
|
|
2338
|
+
};
|
|
2108
2339
|
}
|
|
2109
2340
|
|
|
2110
2341
|
/**
|
|
@@ -2157,17 +2388,23 @@ export class Agent {
|
|
|
2157
2388
|
return (await this.assembleActivationRequest(availableTools, injections, budget, compressionTools, options)).request;
|
|
2158
2389
|
}
|
|
2159
2390
|
|
|
2160
|
-
/** Stored rows that follow a request-only turn, memoized on the
|
|
2161
|
-
* cached
|
|
2162
|
-
*
|
|
2391
|
+
/** Stored rows that follow a request-only turn, memoized on the window's
|
|
2392
|
+
* cached row array (ContextManager returns the same array until the
|
|
2393
|
+
* window changes): the rows a compile sends are the window's (#291), and
|
|
2394
|
+
* a write another agent stores, which the window doesn't take, leaves the
|
|
2395
|
+
* memo as it was. A context without a window reads the record, the same
|
|
2396
|
+
* array as the window's for a single slot that is still the record. */
|
|
2163
2397
|
private requestOnlyIndex: { source: readonly unknown[]; index: RequestOnlyRowIndex } | null = null;
|
|
2164
2398
|
|
|
2165
2399
|
private indexRequestOnlyRows(): RequestOnlyRowIndex {
|
|
2166
2400
|
const empty: RequestOnlyRowIndex = { ticks: new Map(), prompts: new Map() };
|
|
2167
2401
|
const cm = this.contextManager as Partial<ContextManager>;
|
|
2168
|
-
|
|
2402
|
+
const read = typeof cm.getPresentedMessages === 'function' ? () => cm.getPresentedMessages!()
|
|
2403
|
+
: typeof cm.getAllMessages === 'function' ? () => cm.getAllMessages!()
|
|
2404
|
+
: undefined;
|
|
2405
|
+
if (!read) return empty;
|
|
2169
2406
|
try {
|
|
2170
|
-
const stored =
|
|
2407
|
+
const stored = read() as unknown as readonly StoredRowLike[];
|
|
2171
2408
|
if (this.requestOnlyIndex?.source === stored) return this.requestOnlyIndex.index;
|
|
2172
2409
|
const index = indexRequestOnlyRows(stored, this.ownParticipants);
|
|
2173
2410
|
this.requestOnlyIndex = { source: stored, index };
|
|
@@ -2382,7 +2619,9 @@ export class Agent {
|
|
|
2382
2619
|
);
|
|
2383
2620
|
return undefined;
|
|
2384
2621
|
}
|
|
2385
|
-
|
|
2622
|
+
// The agent's own round, stamped as its own (#291's audience stamp); its
|
|
2623
|
+
// id is the stream's last reply for the thinking binding (noteStreamEnd).
|
|
2624
|
+
return storeOwnRow(this, this.name, content, metadata);
|
|
2386
2625
|
}
|
|
2387
2626
|
|
|
2388
2627
|
/**
|
|
@@ -2492,6 +2731,27 @@ export class Agent {
|
|
|
2492
2731
|
return this.contextManager;
|
|
2493
2732
|
}
|
|
2494
2733
|
|
|
2734
|
+
/** Where this agent tells of its own rows once they are stored (setOwnRowSink). */
|
|
2735
|
+
private ownRowSink?: (ids: readonly MessageId[]) => void;
|
|
2736
|
+
|
|
2737
|
+
/**
|
|
2738
|
+
* Install where this agent tells of its own rows once they are stored
|
|
2739
|
+
* (its rounds and the rows the framework writes for it through
|
|
2740
|
+
* storeOwnRow, and its tool results through its guard), or take it off
|
|
2741
|
+
* with undefined. The presentation index (#291) installs one when it takes
|
|
2742
|
+
* the agent on, and presents each row in the agent's window as it is
|
|
2743
|
+
* told. With none, as for an agent nothing took on, nothing is told.
|
|
2744
|
+
*/
|
|
2745
|
+
setOwnRowSink(sink: ((ids: readonly MessageId[]) => void) | undefined): void {
|
|
2746
|
+
this.ownRowSink = sink;
|
|
2747
|
+
this.toolResultGuard.setOwnRowSink(sink);
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2750
|
+
/** Tell the sink of own rows just stored (storeOwnRow calls it, once each add has returned). */
|
|
2751
|
+
ownRowsStored(ids: readonly MessageId[]): void {
|
|
2752
|
+
this.ownRowSink?.(ids);
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2495
2755
|
/**
|
|
2496
2756
|
* Build the effective system prompt, appending any system-position
|
|
2497
2757
|
* injections, their blocks joined by line breaks. The system prompt is
|
|
@@ -2583,8 +2843,8 @@ export class Agent {
|
|
|
2583
2843
|
const content = guardedRefusal ? [] : response.content;
|
|
2584
2844
|
const { toolCalls, speechContent } = this.extractToolCallsAndSpeech(content);
|
|
2585
2845
|
|
|
2586
|
-
// Add assistant response to context
|
|
2587
|
-
if (!guardedRefusal)
|
|
2846
|
+
// Add assistant response to context, as the agent's own row
|
|
2847
|
+
if (!guardedRefusal) storeOwnRow(this, this.name, content);
|
|
2588
2848
|
|
|
2589
2849
|
return {
|
|
2590
2850
|
toolCalls,
|