@animalabs/agent-framework 0.15.0 → 0.17.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 +22 -1
- package/dist/src/agent.d.ts +32 -0
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +55 -0
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/server.d.ts +9 -0
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +156 -0
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/api/types.d.ts +15 -0
- package/dist/src/api/types.d.ts.map +1 -1
- package/dist/src/framework.d.ts +423 -3
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +1857 -75
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +16 -0
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +41 -3
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/index.d.ts +4 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +172 -0
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +444 -2
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +9 -0
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +71 -13
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/modules/history/index.d.ts +89 -13
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +655 -24
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/operator-log.d.ts +78 -0
- package/dist/src/operator-log.d.ts.map +1 -0
- package/dist/src/operator-log.js +102 -0
- package/dist/src/operator-log.js.map +1 -0
- package/dist/src/recovery/discord-awareness-outbox.d.ts +10 -0
- package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.js +20 -0
- package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
- package/dist/src/types/framework.d.ts +56 -0
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +36 -0
- package/dist/src/types/trace.d.ts.map +1 -1
- package/dist/test/agent-runtime-settings.test.js +199 -1
- package/dist/test/agent-runtime-settings.test.js.map +1 -1
- package/dist/test/api-admin-gate.test.d.ts +2 -0
- package/dist/test/api-admin-gate.test.d.ts.map +1 -0
- package/dist/test/api-admin-gate.test.js +116 -0
- package/dist/test/api-admin-gate.test.js.map +1 -0
- package/dist/test/channel-label-history.test.d.ts +2 -0
- package/dist/test/channel-label-history.test.d.ts.map +1 -0
- package/dist/test/channel-label-history.test.js +424 -0
- package/dist/test/channel-label-history.test.js.map +1 -0
- package/dist/test/discord-awareness-outbox.test.js +16 -0
- package/dist/test/discord-awareness-outbox.test.js.map +1 -1
- package/dist/test/event-gate.test.js +44 -0
- package/dist/test/event-gate.test.js.map +1 -1
- package/dist/test/helpers/quiesce-crash-child.d.ts +2 -0
- package/dist/test/helpers/quiesce-crash-child.d.ts.map +1 -0
- package/dist/test/helpers/quiesce-crash-child.js +156 -0
- package/dist/test/helpers/quiesce-crash-child.js.map +1 -0
- package/dist/test/history-module-overview.test.d.ts +2 -0
- package/dist/test/history-module-overview.test.d.ts.map +1 -0
- package/dist/test/history-module-overview.test.js +711 -0
- package/dist/test/history-module-overview.test.js.map +1 -0
- package/dist/test/history-module.test.js +146 -0
- package/dist/test/history-module.test.js.map +1 -1
- package/dist/test/host-quiesce.test.d.ts +2 -0
- package/dist/test/host-quiesce.test.d.ts.map +1 -0
- package/dist/test/host-quiesce.test.js +863 -0
- package/dist/test/host-quiesce.test.js.map +1 -0
- package/dist/test/liveness-watchdog.test.js +18 -2
- package/dist/test/liveness-watchdog.test.js.map +1 -1
- package/dist/test/operator-surgery.test.d.ts +2 -0
- package/dist/test/operator-surgery.test.d.ts.map +1 -0
- package/dist/test/operator-surgery.test.js +398 -0
- package/dist/test/operator-surgery.test.js.map +1 -0
- package/dist/test/provider-acceleration-cooldown.test.js +145 -0
- package/dist/test/provider-acceleration-cooldown.test.js.map +1 -1
- package/dist/test/puppet-tool-call.test.js +5 -0
- package/dist/test/puppet-tool-call.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/agent.ts +69 -0
- package/src/api/server.ts +159 -2
- package/src/api/types.ts +15 -0
- package/src/framework.ts +2155 -96
- package/src/gate/event-gate.ts +47 -4
- package/src/index.ts +5 -1
- package/src/mcpl/channel-registry.ts +495 -2
- package/src/mcpl/server-connection.ts +73 -13
- package/src/modules/history/index.ts +689 -25
- package/src/operator-log.ts +132 -0
- package/src/recovery/discord-awareness-outbox.ts +19 -0
- package/src/types/framework.ts +63 -0
- package/src/types/trace.ts +42 -0
|
@@ -199,6 +199,15 @@ export class McplServerConnection extends EventEmitter {
|
|
|
199
199
|
private controlPlaneReady = false;
|
|
200
200
|
private dataPlaneReady = false;
|
|
201
201
|
private bufferedEvents: Array<{ event: string; args: unknown[] }> = [];
|
|
202
|
+
/** Cap on buffered responder-less events during a plane pause (issue #122).
|
|
203
|
+
* Held server→host requests are never dropped and may exceed this. */
|
|
204
|
+
private static readonly MAX_BUFFERED_EVENTS = 1000;
|
|
205
|
+
private droppedBufferedEvents = 0;
|
|
206
|
+
/** True while ready()/readyControlPlane() re-emit a buffer snapshot. Items
|
|
207
|
+
* re-buffering mid-flush were already admitted once — applying the cap to
|
|
208
|
+
* them again would evict events that were legally held (the cap targets
|
|
209
|
+
* NEW arrivals during a pause, not churn from control-plane flushes). */
|
|
210
|
+
private flushDepth = 0;
|
|
202
211
|
|
|
203
212
|
// Reconnect state (adapted from Anarchid/agent-framework@mcpl-module-proto)
|
|
204
213
|
private config: McplServerConfig | null = null;
|
|
@@ -250,11 +259,22 @@ export class McplServerConnection extends EventEmitter {
|
|
|
250
259
|
this.dataPlaneReady = true;
|
|
251
260
|
const pending = this.bufferedEvents;
|
|
252
261
|
this.bufferedEvents = [];
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
262
|
+
if (pending.length > 200) {
|
|
263
|
+
console.error(
|
|
264
|
+
`[mcpl] ${this.id}: flushing ${pending.length} buffered event(s) synchronously ` +
|
|
265
|
+
`(long pause backlog${this.droppedBufferedEvents > 0 ? `; ${this.droppedBufferedEvents} dropped at cap` : ''})`,
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
this.flushDepth++;
|
|
269
|
+
try {
|
|
270
|
+
for (const { event, args } of pending) {
|
|
271
|
+
// Re-enter the gate for every buffered item. A control handler (notably
|
|
272
|
+
// tools/list_changed) may install a newer data-plane barrier while this
|
|
273
|
+
// snapshot is being flushed; later data items must observe that pause.
|
|
274
|
+
this.emit(event, ...args);
|
|
275
|
+
}
|
|
276
|
+
} finally {
|
|
277
|
+
this.flushDepth--;
|
|
258
278
|
}
|
|
259
279
|
}
|
|
260
280
|
|
|
@@ -268,13 +288,18 @@ export class McplServerConnection extends EventEmitter {
|
|
|
268
288
|
this.controlPlaneReady = true;
|
|
269
289
|
const pending = this.bufferedEvents;
|
|
270
290
|
this.bufferedEvents = [];
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
291
|
+
this.flushDepth++;
|
|
292
|
+
try {
|
|
293
|
+
for (const item of pending) {
|
|
294
|
+
// Re-enter the ADMISSION gate (this.emit), never super.emit: control
|
|
295
|
+
// events include channels-register/changed, which are grant-gated —
|
|
296
|
+
// the old direct flush bypassed positive-grant enforcement entirely
|
|
297
|
+
// (PR #79 review blocker 3). Data-plane items re-buffer in order via
|
|
298
|
+
// the same call, since dataPlaneReady is still false.
|
|
299
|
+
this.emit(item.event, ...item.args);
|
|
300
|
+
}
|
|
301
|
+
} finally {
|
|
302
|
+
this.flushDepth--;
|
|
278
303
|
}
|
|
279
304
|
}
|
|
280
305
|
|
|
@@ -335,6 +360,34 @@ export class McplServerConnection extends EventEmitter {
|
|
|
335
360
|
}
|
|
336
361
|
return super.emit(event, ...args);
|
|
337
362
|
}
|
|
363
|
+
// Buffer cap (issue #122): a long data-plane pause (quiesce window) on a
|
|
364
|
+
// busy server would otherwise grow this array without bound. Only
|
|
365
|
+
// responder-LESS events are ever dropped — a buffered server→host REQUEST
|
|
366
|
+
// holds a live responder the server is blocking on, and dropping it would
|
|
367
|
+
// strand that call forever (the server timing out and reconnecting is the
|
|
368
|
+
// accepted bound there, and reconnect re-runs the barrier funnel).
|
|
369
|
+
if (this.flushDepth === 0 && this.bufferedEvents.length >= McplServerConnection.MAX_BUFFERED_EVENTS) {
|
|
370
|
+
const hasResponder = (item: { args: unknown[] }): boolean => {
|
|
371
|
+
const responder = item.args[1] as { respond?: unknown } | undefined;
|
|
372
|
+
return typeof responder?.respond === 'function';
|
|
373
|
+
};
|
|
374
|
+
if (!hasResponder({ args })) {
|
|
375
|
+
this.droppedBufferedEvents++;
|
|
376
|
+
if (this.droppedBufferedEvents % 100 === 1) {
|
|
377
|
+
console.error(
|
|
378
|
+
`[mcpl] ${this.id}: buffered-event cap (${McplServerConnection.MAX_BUFFERED_EVENTS}) — ` +
|
|
379
|
+
`dropped ${this.droppedBufferedEvents} responder-less event(s) while the plane is paused`,
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
const dropIndex = this.bufferedEvents.findIndex((item) => !hasResponder(item));
|
|
383
|
+
if (dropIndex >= 0) {
|
|
384
|
+
this.bufferedEvents.splice(dropIndex, 1); // drop-oldest non-request
|
|
385
|
+
this.bufferedEvents.push({ event: name, args });
|
|
386
|
+
}
|
|
387
|
+
// else: buffer is all held requests — drop the incoming event instead.
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
338
391
|
this.bufferedEvents.push({ event: name, args });
|
|
339
392
|
return true;
|
|
340
393
|
}
|
|
@@ -359,7 +412,14 @@ export class McplServerConnection extends EventEmitter {
|
|
|
359
412
|
|| event === 'tools-list-changed'
|
|
360
413
|
|| event === 'connect-failed'
|
|
361
414
|
|| event === 'reconnect-failed'
|
|
362
|
-
|| event === 'orphaned-response'
|
|
415
|
+
|| event === 'orphaned-response'
|
|
416
|
+
// host/command is OPERATOR traffic, not agent-wake traffic: it must
|
|
417
|
+
// stay deliverable while the data plane is paused, or a quiesced host
|
|
418
|
+
// could never receive the `resume` that lifts the pause (issue #122 —
|
|
419
|
+
// the command would buffer behind the very gate it is meant to open).
|
|
420
|
+
// The allowHostCommands authority check lives on the emit pass path
|
|
421
|
+
// below, so promotion does not widen who may issue commands.
|
|
422
|
+
|| event === 'host-command';
|
|
363
423
|
}
|
|
364
424
|
|
|
365
425
|
private static isLifecycleEvent(event: string): boolean {
|