@animalabs/agent-framework 0.22.4 → 0.22.5
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/dist/src/framework.d.ts +9 -0
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +55 -6
- package/dist/src/framework.js.map +1 -1
- package/package.json +1 -1
- package/src/framework.ts +58 -6
package/package.json
CHANGED
package/src/framework.ts
CHANGED
|
@@ -238,6 +238,29 @@ const silenceCauseOf = (calls: Array<{ name: string; input?: unknown }>): 'send'
|
|
|
238
238
|
return calls.some(isSilencingCall) ? 'send' : null;
|
|
239
239
|
};
|
|
240
240
|
|
|
241
|
+
/**
|
|
242
|
+
* The keys of a stored message's metadata that only the host writes and that
|
|
243
|
+
* some reader takes on its own as what the message is: `system` makes it a
|
|
244
|
+
* host notice, `draftOwner` and `draftIds` one that names those drafts,
|
|
245
|
+
* `tuneOut` a message a tune-out holds from the residents,
|
|
246
|
+
* `coalescingSubject` (beside the occurrence's `eventId`) the delivery of a
|
|
247
|
+
* coalesced occurrence, `deferredWriteId` the landed copy of a deferred
|
|
248
|
+
* write, `external` a module's own row for an outside message,
|
|
249
|
+
* `silentHeartbeat` a row of a silent heartbeat tick, which marks the tick
|
|
250
|
+
* started whoever's row it is (indexSilentTickRows), and
|
|
251
|
+
* `openaiResponsesItems` membrane's mark of an imported Responses history. A
|
|
252
|
+
* server's metadata, a channel message's `metadata` or a push event's
|
|
253
|
+
* `origin`, is stored without them, and the host writes its own after it:
|
|
254
|
+
* MCPL SPEC §16.6 makes metadata the producer's untrusted claims, which a
|
|
255
|
+
* host may disbelieve. Keys a server writes by protocol, such as `tags` and
|
|
256
|
+
* `mentioned`, stay. So does the Discord module's `discordTextFirst`, which
|
|
257
|
+
* it reads only on a row it found by `external`.
|
|
258
|
+
*/
|
|
259
|
+
const HOST_METADATA_KEYS = [
|
|
260
|
+
'system', 'draftOwner', 'draftIds', 'tuneOut', 'coalescingSubject', 'deferredWriteId', 'external',
|
|
261
|
+
'silentHeartbeat', 'openaiResponsesItems',
|
|
262
|
+
] as const;
|
|
263
|
+
|
|
241
264
|
/**
|
|
242
265
|
* True when an injected message is real conversational input — something the
|
|
243
266
|
* agent might actually be replying to — rather than ambient machinery.
|
|
@@ -10345,9 +10368,9 @@ export class AgentFramework {
|
|
|
10345
10368
|
// turn ends. The window stores them here, right after the
|
|
10346
10369
|
// tool_result message, which is exactly where the membrane appends
|
|
10347
10370
|
// them in the live conversation — same participant, same content
|
|
10348
|
-
// blocks,
|
|
10349
|
-
// verbatim, so the next turn's compiled prefix
|
|
10350
|
-
// live request (prompt-cache safe).
|
|
10371
|
+
// blocks, and neither carries the row's metadata — and compile()
|
|
10372
|
+
// emits recent messages verbatim, so the next turn's compiled prefix
|
|
10373
|
+
// byte-matches the live request (prompt-cache safe).
|
|
10351
10374
|
//
|
|
10352
10375
|
// The queue is drained ONLY at the target agent's own boundary:
|
|
10353
10376
|
// draining at another agent's boundary would store the messages
|
|
@@ -10589,9 +10612,13 @@ export class AgentFramework {
|
|
|
10589
10612
|
// Mid-turn messages collected above ride along as injected user
|
|
10590
10613
|
// messages (membrane ≥0.5.72) — appended after the tool_result
|
|
10591
10614
|
// envelope so the next round of THIS turn hears them.
|
|
10615
|
+
// Each goes as its participant and content alone: a stored row's
|
|
10616
|
+
// metadata is the host's record, not input for membrane.
|
|
10592
10617
|
currentState.stream.provideToolResults(
|
|
10593
10618
|
agent.toolResultGuard.submissionResults(membraneResults),
|
|
10594
|
-
midTurnInjections.length > 0
|
|
10619
|
+
midTurnInjections.length > 0
|
|
10620
|
+
? { injectedMessages: midTurnInjections.map(({ participant, content }) => ({ participant, content })) }
|
|
10621
|
+
: undefined,
|
|
10595
10622
|
);
|
|
10596
10623
|
// RFC-006 §3.3: consumption is determined at assembly, and this
|
|
10597
10624
|
// is assembly too when the stream carries the injected messages
|
|
@@ -10789,6 +10816,31 @@ export class AgentFramework {
|
|
|
10789
10816
|
// Built-in MCPL event → context message conversion
|
|
10790
10817
|
// ==========================================================================
|
|
10791
10818
|
|
|
10819
|
+
/** The servers and keys whose drop withoutHostKeys has logged, each as
|
|
10820
|
+
* `${serverId}\u0000${key}`. */
|
|
10821
|
+
private readonly hostKeysDropped = new Set<string>();
|
|
10822
|
+
|
|
10823
|
+
/**
|
|
10824
|
+
* A server's metadata as it is stored: a copy without HOST_METADATA_KEYS.
|
|
10825
|
+
* A server may use one of those names for something of its own, so the
|
|
10826
|
+
* first drop of each key from each server is logged.
|
|
10827
|
+
*/
|
|
10828
|
+
private withoutHostKeys(serverId: string, given: Record<string, unknown> | undefined): Record<string, unknown> {
|
|
10829
|
+
const kept: Record<string, unknown> = { ...given };
|
|
10830
|
+
for (const key of HOST_METADATA_KEYS) {
|
|
10831
|
+
if (!Object.hasOwn(kept, key)) continue;
|
|
10832
|
+
delete kept[key];
|
|
10833
|
+
const logged = `${serverId}\u0000${key}`;
|
|
10834
|
+
if (this.hostKeysDropped.has(logged)) continue;
|
|
10835
|
+
this.hostKeysDropped.add(logged);
|
|
10836
|
+
console.error(
|
|
10837
|
+
`[mcpl] ${serverId}: dropped "${key}" from a message, since only the host writes that key ` +
|
|
10838
|
+
`(logged once for each server and key)`,
|
|
10839
|
+
);
|
|
10840
|
+
}
|
|
10841
|
+
return kept;
|
|
10842
|
+
}
|
|
10843
|
+
|
|
10792
10844
|
/**
|
|
10793
10845
|
* Convert an incoming MCPL channel message to a context message.
|
|
10794
10846
|
* This replaces the old MCPLModule.onProcess() message conversion.
|
|
@@ -10825,7 +10877,7 @@ export class AgentFramework {
|
|
|
10825
10877
|
return undefined;
|
|
10826
10878
|
}
|
|
10827
10879
|
const metadata: Record<string, unknown> = {
|
|
10828
|
-
...event.metadata,
|
|
10880
|
+
...this.withoutHostKeys(event.serverId, event.metadata),
|
|
10829
10881
|
...(event.eventId ? { eventId: event.eventId } : {}),
|
|
10830
10882
|
...(event.coalescingSubject ? { coalescingSubject: event.coalescingSubject } : {}),
|
|
10831
10883
|
channelId: event.channelId,
|
|
@@ -12267,7 +12319,7 @@ export class AgentFramework {
|
|
|
12267
12319
|
}
|
|
12268
12320
|
|
|
12269
12321
|
const metadata: Record<string, unknown> = {
|
|
12270
|
-
...event.origin,
|
|
12322
|
+
...this.withoutHostKeys(event.serverId, event.origin),
|
|
12271
12323
|
serverId: event.serverId,
|
|
12272
12324
|
featureSet: event.featureSet,
|
|
12273
12325
|
eventId: event.eventId,
|