@animalabs/agent-framework 0.26.2 → 0.27.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 +56 -6
- package/dist/src/agent.d.ts +263 -22
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +531 -54
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +1 -2
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/auto-continue.d.ts +33 -0
- package/dist/src/auto-continue.d.ts.map +1 -0
- package/dist/src/auto-continue.js +35 -0
- package/dist/src/auto-continue.js.map +1 -0
- package/dist/src/code-execution/isolate/scripts.d.ts +11 -0
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
- package/dist/src/code-execution/isolate/scripts.js +5 -1
- package/dist/src/code-execution/isolate/scripts.js.map +1 -1
- package/dist/src/framework.d.ts +759 -129
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +3482 -928
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +309 -46
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +2117 -395
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/gate/index.d.ts +2 -2
- package/dist/src/gate/index.d.ts.map +1 -1
- package/dist/src/gate/index.js +1 -1
- package/dist/src/gate/index.js.map +1 -1
- package/dist/src/gate/recipe-reconcile.d.ts +103 -0
- package/dist/src/gate/recipe-reconcile.d.ts.map +1 -0
- package/dist/src/gate/recipe-reconcile.js +325 -0
- package/dist/src/gate/recipe-reconcile.js.map +1 -0
- package/dist/src/gate/types.d.ts +68 -8
- package/dist/src/gate/types.d.ts.map +1 -1
- package/dist/src/index.d.ts +6 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +433 -113
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +1152 -434
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts +16 -8
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +29 -15
- 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 +14 -2
- package/dist/src/mcpl/convert-block.js.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.d.ts +7 -1
- package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.js +32 -7
- package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
- package/dist/src/mcpl/index.d.ts +5 -1
- package/dist/src/mcpl/index.d.ts.map +1 -1
- package/dist/src/mcpl/index.js +4 -0
- package/dist/src/mcpl/index.js.map +1 -1
- package/dist/src/mcpl/inference-router.d.ts +14 -2
- package/dist/src/mcpl/inference-router.d.ts.map +1 -1
- package/dist/src/mcpl/inference-router.js +73 -28
- package/dist/src/mcpl/inference-router.js.map +1 -1
- package/dist/src/mcpl/prose-grammar.d.ts +4 -0
- package/dist/src/mcpl/prose-grammar.d.ts.map +1 -1
- package/dist/src/mcpl/prose-grammar.js +6 -0
- package/dist/src/mcpl/prose-grammar.js.map +1 -1
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
- package/dist/src/mcpl/protocol-family.js +3 -0
- package/dist/src/mcpl/protocol-family.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +20 -2
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +33 -11
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/reference-fetcher.d.ts +63 -42
- package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
- package/dist/src/mcpl/reference-fetcher.js +177 -145
- package/dist/src/mcpl/reference-fetcher.js.map +1 -1
- package/dist/src/mcpl/references.d.ts +380 -46
- package/dist/src/mcpl/references.d.ts.map +1 -1
- package/dist/src/mcpl/references.js +736 -77
- package/dist/src/mcpl/references.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +82 -3
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +132 -7
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/tool-lifecycle.d.ts +11 -0
- package/dist/src/mcpl/tool-lifecycle.d.ts.map +1 -1
- package/dist/src/mcpl/tool-lifecycle.js +21 -0
- package/dist/src/mcpl/tool-lifecycle.js.map +1 -1
- package/dist/src/mcpl/tool-presence.d.ts +259 -0
- package/dist/src/mcpl/tool-presence.d.ts.map +1 -0
- package/dist/src/mcpl/tool-presence.js +628 -0
- package/dist/src/mcpl/tool-presence.js.map +1 -0
- package/dist/src/mcpl/tool-result-normalize.d.ts +9 -3
- package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -1
- package/dist/src/mcpl/tool-result-normalize.js +14 -6
- package/dist/src/mcpl/tool-result-normalize.js.map +1 -1
- package/dist/src/mcpl/tool-signature.d.ts +39 -0
- package/dist/src/mcpl/tool-signature.d.ts.map +1 -0
- package/dist/src/mcpl/tool-signature.js +292 -0
- package/dist/src/mcpl/tool-signature.js.map +1 -0
- package/dist/src/mcpl/toolset-host.d.ts +200 -0
- package/dist/src/mcpl/toolset-host.d.ts.map +1 -0
- package/dist/src/mcpl/toolset-host.js +621 -0
- package/dist/src/mcpl/toolset-host.js.map +1 -0
- package/dist/src/mcpl/toolsets-module.d.ts +80 -0
- package/dist/src/mcpl/toolsets-module.d.ts.map +1 -0
- package/dist/src/mcpl/toolsets-module.js +431 -0
- package/dist/src/mcpl/toolsets-module.js.map +1 -0
- package/dist/src/mcpl/transport.d.ts +2 -2
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +3 -2
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +21 -1
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/mcpl/visible-content.d.ts +7 -9
- package/dist/src/mcpl/visible-content.d.ts.map +1 -1
- package/dist/src/mcpl/visible-content.js +21 -9
- package/dist/src/mcpl/visible-content.js.map +1 -1
- package/dist/src/module-registry.d.ts +23 -8
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +68 -15
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/discord/index.js +1 -1
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/history/index.d.ts +2 -1
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +51 -17
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/history/semantic.d.ts +108 -6
- package/dist/src/modules/history/semantic.d.ts.map +1 -1
- package/dist/src/modules/history/semantic.js +273 -57
- package/dist/src/modules/history/semantic.js.map +1 -1
- package/dist/src/modules/workspace/direct-write.d.ts +181 -0
- package/dist/src/modules/workspace/direct-write.d.ts.map +1 -0
- package/dist/src/modules/workspace/direct-write.js +384 -0
- package/dist/src/modules/workspace/direct-write.js.map +1 -0
- package/dist/src/modules/workspace/edit-text.d.ts +26 -12
- package/dist/src/modules/workspace/edit-text.d.ts.map +1 -1
- package/dist/src/modules/workspace/edit-text.js +58 -28
- package/dist/src/modules/workspace/edit-text.js.map +1 -1
- package/dist/src/modules/workspace/effects.d.ts +10 -0
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +1 -1
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +246 -27
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +1216 -236
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/read-page.d.ts +41 -0
- package/dist/src/modules/workspace/read-page.d.ts.map +1 -0
- package/dist/src/modules/workspace/read-page.js +213 -0
- package/dist/src/modules/workspace/read-page.js.map +1 -0
- package/dist/src/modules/workspace/result-text.d.ts +67 -0
- package/dist/src/modules/workspace/result-text.d.ts.map +1 -0
- package/dist/src/modules/workspace/result-text.js +94 -0
- package/dist/src/modules/workspace/result-text.js.map +1 -0
- package/dist/src/modules/workspace/text.d.ts +29 -12
- package/dist/src/modules/workspace/text.d.ts.map +1 -1
- package/dist/src/modules/workspace/text.js +35 -33
- package/dist/src/modules/workspace/text.js.map +1 -1
- package/dist/src/modules/workspace/types.d.ts +41 -17
- package/dist/src/modules/workspace/types.d.ts.map +1 -1
- package/dist/src/modules/workspace/types.js.map +1 -1
- package/dist/src/sent-rows.d.ts +59 -0
- package/dist/src/sent-rows.d.ts.map +1 -0
- package/dist/src/sent-rows.js +145 -0
- package/dist/src/sent-rows.js.map +1 -0
- package/dist/src/silent-heartbeat.d.ts +17 -10
- package/dist/src/silent-heartbeat.d.ts.map +1 -1
- package/dist/src/silent-heartbeat.js.map +1 -1
- package/dist/src/stable-hash.d.ts +3 -0
- package/dist/src/stable-hash.d.ts.map +1 -0
- package/dist/src/stable-hash.js +15 -0
- package/dist/src/stable-hash.js.map +1 -0
- package/dist/src/stored-injections.d.ts +99 -0
- package/dist/src/stored-injections.d.ts.map +1 -0
- package/dist/src/stored-injections.js +106 -0
- package/dist/src/stored-injections.js.map +1 -0
- package/dist/src/text-as-stored.d.ts +4 -3
- package/dist/src/text-as-stored.d.ts.map +1 -1
- package/dist/src/text-as-stored.js +4 -3
- package/dist/src/text-as-stored.js.map +1 -1
- package/dist/src/thinking-drops.d.ts +81 -0
- package/dist/src/thinking-drops.d.ts.map +1 -0
- package/dist/src/thinking-drops.js +103 -0
- package/dist/src/thinking-drops.js.map +1 -0
- package/dist/src/tool-image-ledger.d.ts +9 -8
- package/dist/src/tool-image-ledger.d.ts.map +1 -1
- package/dist/src/tool-image-ledger.js +9 -8
- package/dist/src/tool-image-ledger.js.map +1 -1
- package/dist/src/tool-presentation.d.ts.map +1 -1
- package/dist/src/tool-presentation.js +3 -1
- package/dist/src/tool-presentation.js.map +1 -1
- package/dist/src/tool-result-guard.d.ts +4 -2
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +21 -6
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tool-result-history.d.ts +176 -24
- package/dist/src/tool-result-history.d.ts.map +1 -1
- package/dist/src/tool-result-history.js +411 -91
- package/dist/src/tool-result-history.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +17 -9
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +84 -37
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/types/agent.d.ts +186 -7
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +15 -1
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +24 -3
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +90 -7
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +57 -2
- package/dist/src/types/trace.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/agent.ts +593 -60
- package/src/api/server.ts +1 -2
- package/src/auto-continue.ts +42 -0
- package/src/code-execution/isolate/scripts.ts +11 -3
- package/src/framework.ts +3601 -967
- package/src/gate/event-gate.ts +2315 -389
- package/src/gate/index.ts +2 -1
- package/src/gate/recipe-reconcile.ts +355 -0
- package/src/gate/types.ts +70 -8
- package/src/index.ts +7 -4
- package/src/mcpl/channel-registry.ts +1220 -467
- package/src/mcpl/conversation-router.ts +34 -16
- package/src/mcpl/convert-block.ts +14 -1
- package/src/mcpl/hook-orchestrator.ts +33 -6
- package/src/mcpl/index.ts +6 -1
- package/src/mcpl/inference-router.ts +79 -34
- package/src/mcpl/prose-grammar.ts +7 -0
- package/src/mcpl/protocol-family.ts +2 -0
- package/src/mcpl/push-coalescer.ts +51 -13
- package/src/mcpl/reference-fetcher.ts +201 -162
- package/src/mcpl/references.ts +851 -77
- package/src/mcpl/server-connection.ts +145 -7
- package/src/mcpl/tool-lifecycle.ts +21 -0
- package/src/mcpl/tool-presence.ts +650 -0
- package/src/mcpl/tool-result-normalize.ts +18 -6
- package/src/mcpl/tool-signature.ts +285 -0
- package/src/mcpl/toolset-host.ts +637 -0
- package/src/mcpl/toolsets-module.ts +451 -0
- package/src/mcpl/transport.ts +3 -2
- package/src/mcpl/types.ts +22 -1
- package/src/mcpl/visible-content.ts +22 -9
- package/src/module-registry.ts +77 -24
- package/src/modules/discord/index.ts +1 -1
- package/src/modules/history/index.ts +48 -18
- package/src/modules/history/semantic.ts +308 -54
- package/src/modules/workspace/direct-write.ts +425 -0
- package/src/modules/workspace/edit-text.ts +82 -35
- package/src/modules/workspace/effects.ts +1 -1
- package/src/modules/workspace/index.ts +1274 -241
- package/src/modules/workspace/read-page.ts +222 -0
- package/src/modules/workspace/result-text.ts +119 -0
- package/src/modules/workspace/text.ts +58 -32
- package/src/modules/workspace/types.ts +41 -17
- package/src/sent-rows.ts +162 -0
- package/src/silent-heartbeat.ts +17 -10
- package/src/stable-hash.ts +14 -0
- package/src/stored-injections.ts +131 -0
- package/src/text-as-stored.ts +4 -3
- package/src/thinking-drops.ts +141 -0
- package/src/tool-image-ledger.ts +9 -8
- package/src/tool-presentation.ts +3 -1
- package/src/tool-result-guard.ts +19 -6
- package/src/tool-result-history.ts +471 -90
- package/src/tune-out/coordinator.ts +80 -37
- package/src/types/agent.ts +189 -7
- package/src/types/events.ts +15 -1
- package/src/types/framework.ts +21 -3
- package/src/types/module.ts +86 -7
- package/src/types/trace.ts +58 -2
package/src/module-registry.ts
CHANGED
|
@@ -21,6 +21,7 @@ import type {
|
|
|
21
21
|
ProcessEvent,
|
|
22
22
|
TraceEventListener,
|
|
23
23
|
ModuleMessage,
|
|
24
|
+
ModuleContextInjection,
|
|
24
25
|
MessageQueryResult,
|
|
25
26
|
} from './types/index.js';
|
|
26
27
|
import { heldWriteId } from './held-writes.js';
|
|
@@ -110,11 +111,11 @@ export class ModuleRegistry {
|
|
|
110
111
|
private store: JsStore;
|
|
111
112
|
private queue: ModuleQueue;
|
|
112
113
|
private getAgents: () => Agent[];
|
|
113
|
-
private addMessageFn: (participant: string, content: ContentBlock[], metadata?: MessageMetadata) => MessageId;
|
|
114
|
+
private addMessageFn: (participant: string, content: ContentBlock[], metadata?: MessageMetadata, opts?: { forAgent?: string }) => MessageId;
|
|
114
115
|
private editMessageFn: (id: MessageId, content: ContentBlock[]) => void;
|
|
115
116
|
private removeMessageFn: (id: MessageId) => void;
|
|
116
117
|
private getMessageFn: (id: MessageId) => ModuleMessage | null;
|
|
117
|
-
private queryMessagesFn: (filter: MessageQuery) => MessageQueryResult;
|
|
118
|
+
private queryMessagesFn: (filter: MessageQuery, opts?: { forAgent?: string }) => MessageQueryResult;
|
|
118
119
|
|
|
119
120
|
private pushEventFn: (event: ProcessEvent, moduleName?: string) => void;
|
|
120
121
|
private onTraceFn: (listener: TraceEventListener) => () => void;
|
|
@@ -134,11 +135,11 @@ export class ModuleRegistry {
|
|
|
134
135
|
queue: ModuleQueue,
|
|
135
136
|
options: {
|
|
136
137
|
getAgents: () => Agent[];
|
|
137
|
-
addMessage: (participant: string, content: ContentBlock[], metadata?: MessageMetadata) => MessageId;
|
|
138
|
+
addMessage: (participant: string, content: ContentBlock[], metadata?: MessageMetadata, opts?: { forAgent?: string }) => MessageId;
|
|
138
139
|
editMessage: (id: MessageId, content: ContentBlock[]) => void;
|
|
139
140
|
removeMessage: (id: MessageId) => void;
|
|
140
141
|
getMessage: (id: MessageId) => ModuleMessage | null;
|
|
141
|
-
queryMessages: (filter: MessageQuery) => MessageQueryResult;
|
|
142
|
+
queryMessages: (filter: MessageQuery, opts?: { forAgent?: string }) => MessageQueryResult;
|
|
142
143
|
/** Called with the pushing module's name. */
|
|
143
144
|
pushEvent: (event: ProcessEvent, moduleName?: string) => void;
|
|
144
145
|
onTrace: (listener: TraceEventListener) => () => void;
|
|
@@ -230,7 +231,8 @@ export class ModuleRegistry {
|
|
|
230
231
|
|
|
231
232
|
/**
|
|
232
233
|
* Set state for a module by name.
|
|
233
|
-
* Used by the framework to apply stateUpdate from EventResponse
|
|
234
|
+
* Used by the framework to apply stateUpdate from EventResponse after its
|
|
235
|
+
* message changes.
|
|
234
236
|
*/
|
|
235
237
|
setModuleState(moduleName: string, state: unknown): void {
|
|
236
238
|
const ctx = this.moduleContexts.get(moduleName);
|
|
@@ -439,8 +441,18 @@ export class ModuleRegistry {
|
|
|
439
441
|
|
|
440
442
|
/**
|
|
441
443
|
* Gather context injections from all modules before inference.
|
|
442
|
-
* Calls each module's gatherContext() in parallel with a per-module timeout
|
|
443
|
-
*
|
|
444
|
+
* Calls each module's gatherContext() in parallel with a per-module timeout,
|
|
445
|
+
* and returns their injections in the modules' registration order, whatever
|
|
446
|
+
* order they finish in. Fail-open: timed-out or erroring modules are skipped
|
|
447
|
+
* (with a stderr line), whether the call throws, rejects, or answers with
|
|
448
|
+
* something that isn't an array of objects, or with a `system` entry whose
|
|
449
|
+
* content isn't an array of objects, every block of which the agent's
|
|
450
|
+
* buildSystemPrompt reads, and one that answers after its timeout adds
|
|
451
|
+
* nothing. An array returned without a promise is taken as the module's
|
|
452
|
+
* answer. An entry's other fields are the module's to get right. Each
|
|
453
|
+
* module's budget starts once its call returns, after its own synchronous
|
|
454
|
+
* work and every earlier module's; a later module's synchronous work still
|
|
455
|
+
* counts against it.
|
|
444
456
|
*
|
|
445
457
|
* The per-module budget is `module.contextTimeoutMs` when declared, else the
|
|
446
458
|
* `timeoutMs` default (15s). Modules whose gatherContext does real work —
|
|
@@ -450,12 +462,16 @@ export class ModuleRegistry {
|
|
|
450
462
|
* to MAX_CONTEXT_TIMEOUT_MS so no single module can hold every turn hostage.
|
|
451
463
|
* Adapted from Anarchid/agent-framework@mcpl-module-proto.
|
|
452
464
|
*/
|
|
453
|
-
async gatherContext(agentName: string, timeoutMs = 15_000): Promise<
|
|
454
|
-
|
|
465
|
+
async gatherContext(agentName: string, timeoutMs = 15_000): Promise<ModuleContextInjection[]> {
|
|
466
|
+
// Each module's result in registration order, whatever order they finish
|
|
467
|
+
// in: a stored injection's content hash follows that order, and a module
|
|
468
|
+
// that answers after its timeout adds nothing (it's skipped, fail-open).
|
|
469
|
+
const results: ModuleContextInjection[][] = [];
|
|
455
470
|
const promises: Promise<void>[] = [];
|
|
456
471
|
|
|
457
472
|
for (const module of this.modules.values()) {
|
|
458
|
-
|
|
473
|
+
const gather = module.gatherContext;
|
|
474
|
+
if (!gather) continue;
|
|
459
475
|
|
|
460
476
|
// Clamp the per-module budget. A module declaring `contextTimeoutMs`
|
|
461
477
|
// legitimately needs more than the shared default (e.g. a retrieval
|
|
@@ -467,14 +483,43 @@ export class ModuleRegistry {
|
|
|
467
483
|
MAX_CONTEXT_TIMEOUT_MS,
|
|
468
484
|
);
|
|
469
485
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
486
|
+
let timedOut = false;
|
|
487
|
+
const slot = results.length;
|
|
488
|
+
results.push([]);
|
|
489
|
+
// Called here, before its timer is set, so its budget starts after its
|
|
490
|
+
// synchronous work; a call that throws is skipped as a rejection is.
|
|
491
|
+
let call: Promise<ModuleContextInjection[]>;
|
|
492
|
+
try {
|
|
493
|
+
call = Promise.resolve(gather.call(module, agentName));
|
|
494
|
+
} catch (err) {
|
|
495
|
+
call = Promise.reject(err);
|
|
496
|
+
}
|
|
470
497
|
const promise = Promise.race([
|
|
471
|
-
|
|
472
|
-
|
|
498
|
+
call.then(r => {
|
|
499
|
+
if (timedOut) return;
|
|
500
|
+
// Checked before it's kept, so an answer that isn't an array of
|
|
501
|
+
// objects skips the module, as does a system entry whose content
|
|
502
|
+
// isn't an array of objects: buildSystemPrompt reads every block
|
|
503
|
+
// of it, and one it can't read would fail the turn. Each array is
|
|
504
|
+
// read through Array.from, which reads a hole as `undefined`, as
|
|
505
|
+
// context-manager's compile does when it spreads the content.
|
|
506
|
+
if (!Array.isArray(r) || Array.from(r).some((entry) => entry === null || typeof entry !== 'object')) {
|
|
507
|
+
throw new TypeError(`gatherContext answered with ${Array.isArray(r) ? 'an array holding an entry that is not an object' : r === null ? 'null' : typeof r}, not an array of objects`);
|
|
508
|
+
}
|
|
509
|
+
const unreadable = r.find((entry) => entry.position === 'system'
|
|
510
|
+
&& !(Array.isArray(entry.content) && Array.from(entry.content).every((block) => block !== null && typeof block === 'object')));
|
|
511
|
+
if (unreadable) {
|
|
512
|
+
throw new TypeError(`gatherContext answered with a system injection in namespace ${logValue(unreadable.namespace)} whose content isn't an array of objects`);
|
|
513
|
+
}
|
|
473
514
|
this.noteBlocksNotShown(module.name, r);
|
|
515
|
+
results[slot] = [...r];
|
|
474
516
|
}),
|
|
475
517
|
new Promise<void>((_, rej) => {
|
|
476
518
|
timer = setTimeout(
|
|
477
|
-
() =>
|
|
519
|
+
() => {
|
|
520
|
+
timedOut = true;
|
|
521
|
+
rej(new Error(`gatherContext timed out after ${budgetMs}ms`));
|
|
522
|
+
},
|
|
478
523
|
budgetMs,
|
|
479
524
|
);
|
|
480
525
|
}),
|
|
@@ -486,7 +531,7 @@ export class ModuleRegistry {
|
|
|
486
531
|
}
|
|
487
532
|
|
|
488
533
|
await Promise.all(promises);
|
|
489
|
-
return
|
|
534
|
+
return results.flat();
|
|
490
535
|
}
|
|
491
536
|
|
|
492
537
|
/**
|
|
@@ -607,11 +652,11 @@ class ModuleContextImpl implements ModuleContext {
|
|
|
607
652
|
private registry: ModuleRegistry;
|
|
608
653
|
readonly isRestart: boolean;
|
|
609
654
|
private getAgentsFn: () => Agent[];
|
|
610
|
-
private addMessageFn: (participant: string, content: ContentBlock[], metadata?: MessageMetadata) => MessageId;
|
|
655
|
+
private addMessageFn: (participant: string, content: ContentBlock[], metadata?: MessageMetadata, opts?: { forAgent?: string }) => MessageId;
|
|
611
656
|
private editMessageFn: (id: MessageId, content: ContentBlock[]) => void;
|
|
612
657
|
private removeMessageFn: (id: MessageId) => void;
|
|
613
658
|
private getMessageFn: (id: MessageId) => ModuleMessage | null;
|
|
614
|
-
private queryMessagesFn: (filter: MessageQuery) => MessageQueryResult;
|
|
659
|
+
private queryMessagesFn: (filter: MessageQuery, opts?: { forAgent?: string }) => MessageQueryResult;
|
|
615
660
|
private pushEventFn: (event: ProcessEvent, moduleName?: string) => void;
|
|
616
661
|
private onTraceFn: (listener: TraceEventListener) => () => void;
|
|
617
662
|
private callToolFn: (call: ToolCall) => Promise<ToolResult>;
|
|
@@ -627,11 +672,11 @@ class ModuleContextImpl implements ModuleContext {
|
|
|
627
672
|
registry: ModuleRegistry,
|
|
628
673
|
isRestart: boolean,
|
|
629
674
|
getAgents: () => Agent[],
|
|
630
|
-
addMessage: (participant: string, content: ContentBlock[], metadata?: MessageMetadata) => MessageId,
|
|
675
|
+
addMessage: (participant: string, content: ContentBlock[], metadata?: MessageMetadata, opts?: { forAgent?: string }) => MessageId,
|
|
631
676
|
editMessage: (id: MessageId, content: ContentBlock[]) => void,
|
|
632
677
|
removeMessage: (id: MessageId) => void,
|
|
633
678
|
getMessage: (id: MessageId) => ModuleMessage | null,
|
|
634
|
-
queryMessages: (filter: MessageQuery) => MessageQueryResult,
|
|
679
|
+
queryMessages: (filter: MessageQuery, opts?: { forAgent?: string }) => MessageQueryResult,
|
|
635
680
|
pushEvent: (event: ProcessEvent, moduleName?: string) => void,
|
|
636
681
|
onTrace: (listener: TraceEventListener) => () => void,
|
|
637
682
|
callTool: (call: ToolCall) => Promise<ToolResult>
|
|
@@ -753,9 +798,17 @@ class ModuleContextImpl implements ModuleContext {
|
|
|
753
798
|
addMessage(
|
|
754
799
|
participant: string,
|
|
755
800
|
content: ContentBlock[],
|
|
756
|
-
metadata?: MessageMetadata & { external?: ExternalIdRef }
|
|
801
|
+
metadata?: MessageMetadata & { external?: ExternalIdRef },
|
|
802
|
+
opts?: { forAgent?: string },
|
|
757
803
|
): MessageId {
|
|
758
|
-
|
|
804
|
+
// The external id map is read in the primary's store
|
|
805
|
+
// (findMessageByExternalId), so a mapping into another window would
|
|
806
|
+
// answer wrong.
|
|
807
|
+
if (metadata?.external && opts?.forAgent !== undefined) {
|
|
808
|
+
throw new Error(`A message for agent ${JSON.stringify(opts.forAgent)} can't carry metadata.external: `
|
|
809
|
+
+ "its external id would be looked up in the primary's window. Leave forAgent out, or the external id.");
|
|
810
|
+
}
|
|
811
|
+
const id = this.addMessageFn(participant, content, metadata, opts);
|
|
759
812
|
|
|
760
813
|
// Track external ID if provided. A write the framework holds keeps '',
|
|
761
814
|
// as it did before held writes had handles: the map is module state an
|
|
@@ -819,8 +872,8 @@ class ModuleContextImpl implements ModuleContext {
|
|
|
819
872
|
return this.getMessageFn(id);
|
|
820
873
|
}
|
|
821
874
|
|
|
822
|
-
queryMessages(filter: MessageQuery): MessageQueryResult {
|
|
823
|
-
return this.queryMessagesFn(filter);
|
|
875
|
+
queryMessages(filter: MessageQuery, opts?: { forAgent?: string }): MessageQueryResult {
|
|
876
|
+
return this.queryMessagesFn(filter, opts);
|
|
824
877
|
}
|
|
825
878
|
|
|
826
879
|
getAgents(): AgentInfo[] {
|
|
@@ -976,7 +1029,7 @@ function withoutRefusal(call: ToolCall, result: ToolResult): ToolResult {
|
|
|
976
1029
|
}
|
|
977
1030
|
|
|
978
1031
|
/** A result's flags, which consumers read for their truth: booleans here. */
|
|
979
|
-
const RESULT_FLAGS = ['success', 'isError', 'endTurn'] as const;
|
|
1032
|
+
const RESULT_FLAGS = ['success', 'isError', 'endTurn', 'dataIsContent'] as const;
|
|
980
1033
|
|
|
981
1034
|
/**
|
|
982
1035
|
* A module's tool result as the framework can store, send and trace it. A
|
|
@@ -1047,7 +1100,7 @@ export function checkedToolResult(call: ToolCall, result: unknown): { result: To
|
|
|
1047
1100
|
endTurn = Boolean(fields.endTurn);
|
|
1048
1101
|
read('error');
|
|
1049
1102
|
ownText = errorText(fields.error);
|
|
1050
|
-
for (const key of ['success', 'isError', 'data']) read(key);
|
|
1103
|
+
for (const key of ['success', 'isError', 'data', 'dataIsContent']) read(key);
|
|
1051
1104
|
for (const key of Object.keys(candidate)) {
|
|
1052
1105
|
if (key !== 'toJSON' && !(key in fields)) fields[key] = candidate[key];
|
|
1053
1106
|
}
|
|
@@ -828,7 +828,7 @@ export class DiscordModule implements Module {
|
|
|
828
828
|
const stored = this.storedRow(msg.discordMessageId);
|
|
829
829
|
if (live) live.phase = 'writing';
|
|
830
830
|
|
|
831
|
-
// Return declarative response - framework applies
|
|
831
|
+
// Return declarative response - the framework applies its writes
|
|
832
832
|
return {
|
|
833
833
|
...(stored ? {} : {
|
|
834
834
|
addMessages: [
|
|
@@ -49,7 +49,7 @@ import type { ToolDefinition, ToolCall, ToolResult, ProcessEvent } from '../../t
|
|
|
49
49
|
import type { EventResponse, ProcessState } from '../../types/module.js';
|
|
50
50
|
import type { SearchWorkerMessage, SearchWorkerMatch } from './search-regex-worker.js';
|
|
51
51
|
import type { ChannelRegistry } from '../../mcpl/channel-registry.js';
|
|
52
|
-
import { EmbedServiceError, SemanticIndexClient, SemanticIndexer, messageIndexText, summaryIndexText, type SearchResponse, type SemanticIndexConfig, type SyncReport, type PendingChanges } from './semantic.js';
|
|
52
|
+
import { EmbedServiceError, SemanticIndexClient, SemanticIndexer, messageIndexText, parseSummaryKey, summaryIndexText, type SearchResponse, type SemanticIndexConfig, type SyncReport, type PendingChanges, type SyncCursors } from './semantic.js';
|
|
53
53
|
import { unknownToolMessage } from '../unknown-tool.js';
|
|
54
54
|
import { safeSlice } from '../../safe-slice.js';
|
|
55
55
|
|
|
@@ -624,6 +624,16 @@ export class HistoryModule implements Module {
|
|
|
624
624
|
const prev = this.ctx?.getState<Record<string, unknown>>() ?? {};
|
|
625
625
|
this.ctx?.setState({ ...prev, semanticPending: p });
|
|
626
626
|
};
|
|
627
|
+
// Module state follows the store's branches, so each branch keeps its
|
|
628
|
+
// own sync cursors, and a branch made at an earlier point inherits them
|
|
629
|
+
// as they were there.
|
|
630
|
+
this.indexer.cursorStore = {
|
|
631
|
+
read: () => this.ctx?.getState<{ semanticCursors?: SyncCursors }>()?.semanticCursors ?? null,
|
|
632
|
+
write: (cursors) => {
|
|
633
|
+
const prev = this.ctx?.getState<Record<string, unknown>>() ?? {};
|
|
634
|
+
this.ctx?.setState({ ...prev, semanticCursors: cursors });
|
|
635
|
+
},
|
|
636
|
+
};
|
|
627
637
|
this.indexer.attach();
|
|
628
638
|
}
|
|
629
639
|
|
|
@@ -631,13 +641,16 @@ export class HistoryModule implements Module {
|
|
|
631
641
|
this.ctx = null;
|
|
632
642
|
if (this.syncTimer) { clearInterval(this.syncTimer); this.syncTimer = null; }
|
|
633
643
|
if (this.firstSyncTimer) { clearTimeout(this.firstSyncTimer); this.firstSyncTimer = null; }
|
|
634
|
-
|
|
644
|
+
// Unwired from the state it can no longer reach, the indexer goes on
|
|
645
|
+
// from the cursors it last wrote for each branch, kept in memory.
|
|
646
|
+
if (this.indexer) { this.indexer.onPendingChange = null; this.indexer.cursorStore = null; }
|
|
635
647
|
this.indexer?.dispose();
|
|
636
648
|
}
|
|
637
649
|
|
|
638
650
|
/**
|
|
639
651
|
* Background sync into the semantic index: every `syncIntervalMs` (default
|
|
640
|
-
* 60 s)
|
|
652
|
+
* 60 s) write at most `maxSyncPerTick` items to the index, counted as its
|
|
653
|
+
* doc says. Idempotent to call — starts
|
|
641
654
|
* once we have both a context-manager (bind) and a config; `unref`'d so it
|
|
642
655
|
* never keeps a shutting-down process alive. A first tick runs after 5 s so
|
|
643
656
|
* a fresh store starts backfilling immediately rather than a minute later.
|
|
@@ -1608,7 +1621,10 @@ export class HistoryModule implements Module {
|
|
|
1608
1621
|
);
|
|
1609
1622
|
}
|
|
1610
1623
|
|
|
1611
|
-
//
|
|
1624
|
+
// A catch-up bounded in what it writes, so the newest messages are
|
|
1625
|
+
// searchable without waiting on a backlog. It can re-send many items the
|
|
1626
|
+
// index holds unchanged, as on a branch's first pass (maxSyncPerTick's
|
|
1627
|
+
// doc), which costs a request per batch and no embedding.
|
|
1612
1628
|
let sync: SyncReport | null = null;
|
|
1613
1629
|
if (this.indexer) {
|
|
1614
1630
|
try { sync = await this.indexer.catchUp(this.semanticCfg.maxSyncBeforeSearch ?? 256); } catch { /* reported via indexer.lastError */ }
|
|
@@ -1672,9 +1688,10 @@ export class HistoryModule implements Module {
|
|
|
1672
1688
|
// to the model — getMessage/getSummary rebuild on branch switch, so an
|
|
1673
1689
|
// undone message, or a summary this branch doesn't hold, answers null.
|
|
1674
1690
|
// A branch made from an earlier point, as an undo makes one, can mint a
|
|
1675
|
-
// summary id another branch already used, so a summary
|
|
1676
|
-
//
|
|
1677
|
-
// k is small, so this is at most `limit` local
|
|
1691
|
+
// summary id another branch already used, so a summary's key carries its
|
|
1692
|
+
// creation time too, and a hit whose time isn't this branch's summary's
|
|
1693
|
+
// is another branch's. k is small, so this is at most `limit` local
|
|
1694
|
+
// lookups.
|
|
1678
1695
|
// A message hit whose current text has nothing left to index (edited
|
|
1679
1696
|
// blank, delete not yet applied) is dropped too, so its stale snippet is
|
|
1680
1697
|
// never served. Dropped hits are replaced by over-fetching: when the
|
|
@@ -1685,14 +1702,12 @@ export class HistoryModule implements Module {
|
|
|
1685
1702
|
// A message hit's snippet is rebuilt from the CURRENT local text, never
|
|
1686
1703
|
// the remote copy: an edit not yet synced (or one the index never got)
|
|
1687
1704
|
// must not leak a passage the edit removed. Only the ranking can be stale.
|
|
1688
|
-
// A summary hit's snippet is rebuilt from the local summary too
|
|
1689
|
-
// service that keeps only vectors and ids (no text) still yields one
|
|
1690
|
-
// a summary whose id another branch also minted shows this branch's text
|
|
1691
|
-
// in its snippet and chars.
|
|
1705
|
+
// A summary hit's snippet is rebuilt from the local summary too, so a
|
|
1706
|
+
// service that keeps only vectors and ids (no text) still yields one.
|
|
1692
1707
|
const currentText = new Map<string, string>();
|
|
1693
|
-
const keep = (h: { id: string }): 'ok' | 'offBranch' | 'stale' => {
|
|
1708
|
+
const keep = (h: { id: string }): 'ok' | 'offBranch' | 'stale' | 'superseded' => {
|
|
1694
1709
|
const msgId = /^msg:(.+)$/.exec(h.id)?.[1];
|
|
1695
|
-
const
|
|
1710
|
+
const sum = parseSummaryKey(h.id);
|
|
1696
1711
|
if (msgId !== undefined) {
|
|
1697
1712
|
const m = cm.getMessage(msgId);
|
|
1698
1713
|
if (!m) return 'offBranch';
|
|
@@ -1701,9 +1716,18 @@ export class HistoryModule implements Module {
|
|
|
1701
1716
|
currentText.set(h.id, text);
|
|
1702
1717
|
return 'ok';
|
|
1703
1718
|
}
|
|
1704
|
-
if (
|
|
1705
|
-
|
|
1719
|
+
if (sum !== null) {
|
|
1720
|
+
// An item from before keys carried the creation time is never a hit.
|
|
1721
|
+
// One whose id names no summary on this branch is another branch's,
|
|
1722
|
+
// and is counted as such. One whose id this branch has can hold this
|
|
1723
|
+
// branch's summary or another's under the same id, and isn't counted.
|
|
1724
|
+
// Until this branch's passes send the summary under its own key, as
|
|
1725
|
+
// the search's catch-up does within its budget after any queued
|
|
1726
|
+
// edits, a search can miss it.
|
|
1727
|
+
const s = cm.getSummary(sum.id);
|
|
1706
1728
|
if (!s) return 'offBranch';
|
|
1729
|
+
if (sum.createdMs === null) return 'superseded';
|
|
1730
|
+
if (s.created !== sum.createdMs) return 'offBranch';
|
|
1707
1731
|
const text = summaryIndexText(s, this.semanticCfg!);
|
|
1708
1732
|
// An empty text here is mostly defensive: context-manager drops a
|
|
1709
1733
|
// summary that's empty after trimming when it loads, and refuses to
|
|
@@ -1771,10 +1795,13 @@ export class HistoryModule implements Module {
|
|
|
1771
1795
|
const meta = typeof h.meta === 'object' && h.meta !== null && !Array.isArray(h.meta)
|
|
1772
1796
|
? h.meta as { participant?: unknown; author?: unknown }
|
|
1773
1797
|
: null;
|
|
1798
|
+
// A summary is shown as `sum:<id>`, as it was before its key carried its creation time.
|
|
1799
|
+
const sum = parseSummaryKey(h.id);
|
|
1800
|
+
const id = sum ? `sum:${sum.id}` : h.id;
|
|
1774
1801
|
const missing = [...(h.ts !== null && timestamp === null ? ['ts'] : []), ...(meta === null ? ['meta'] : [])];
|
|
1775
|
-
if (missing.length > 0) unread.push(`${shown(
|
|
1802
|
+
if (missing.length > 0) unread.push(`${shown(id)} (${missing.join(' and ')})`);
|
|
1776
1803
|
return {
|
|
1777
|
-
id
|
|
1804
|
+
id,
|
|
1778
1805
|
/** Raw message id for a `msg:` hit (null for summaries) — pass it to extract({ aroundId }). */
|
|
1779
1806
|
messageId: h.id.startsWith('msg:') ? h.id.slice(4) : null,
|
|
1780
1807
|
kind: h.kind,
|
|
@@ -1797,7 +1824,10 @@ export class HistoryModule implements Module {
|
|
|
1797
1824
|
hits,
|
|
1798
1825
|
index: {
|
|
1799
1826
|
indexed: res.count_indexed,
|
|
1800
|
-
|
|
1827
|
+
// The pass may have read another branch: one the search joined
|
|
1828
|
+
// that started before a switch, or one the search left while it
|
|
1829
|
+
// waited.
|
|
1830
|
+
behind: this.indexer === null ? null : sync && this.indexer.passedOn(sync) === this.indexer.branchId() ? sync.more : true,
|
|
1801
1831
|
syncedThisCall: sync ? sync.pushed : 0,
|
|
1802
1832
|
lastError: this.indexer?.lastError ?? null,
|
|
1803
1833
|
/** Hits the index returned for messages/summaries not on the current branch (undone, checked out past). */
|