@animalabs/agent-framework 0.7.4 → 0.9.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/dist/src/agent.d.ts +10 -0
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +33 -3
- package/dist/src/agent.js.map +1 -1
- package/dist/src/code-execution/index.d.ts +1 -1
- package/dist/src/code-execution/index.d.ts.map +1 -1
- package/dist/src/code-execution/index.js.map +1 -1
- package/dist/src/code-execution/py-runner.d.ts +23 -1
- package/dist/src/code-execution/py-runner.d.ts.map +1 -1
- package/dist/src/code-execution/py-runner.js +40 -4
- package/dist/src/code-execution/py-runner.js.map +1 -1
- package/dist/src/code-execution/runtime-py.d.ts +15 -2
- package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
- package/dist/src/code-execution/runtime-py.js +156 -7
- package/dist/src/code-execution/runtime-py.js.map +1 -1
- package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
- package/dist/src/code-execution/tool-definition.js +27 -2
- package/dist/src/code-execution/tool-definition.js.map +1 -1
- package/dist/src/framework.d.ts +234 -5
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +1818 -188
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +11 -0
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +66 -0
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/capability-grant.d.ts +115 -0
- package/dist/src/mcpl/capability-grant.d.ts.map +1 -0
- package/dist/src/mcpl/capability-grant.js +291 -0
- package/dist/src/mcpl/capability-grant.js.map +1 -0
- package/dist/src/mcpl/capability-mask.d.ts +51 -0
- package/dist/src/mcpl/capability-mask.d.ts.map +1 -0
- package/dist/src/mcpl/capability-mask.js +190 -0
- package/dist/src/mcpl/capability-mask.js.map +1 -0
- package/dist/src/mcpl/channel-registry.d.ts +30 -2
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +216 -43
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.d.ts +8 -3
- package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.js +28 -8
- package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
- package/dist/src/mcpl/errors.d.ts +6 -0
- package/dist/src/mcpl/errors.d.ts.map +1 -1
- package/dist/src/mcpl/errors.js +6 -0
- package/dist/src/mcpl/errors.js.map +1 -1
- package/dist/src/mcpl/feature-set-manager.d.ts +10 -1
- package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
- package/dist/src/mcpl/feature-set-manager.js +45 -4
- package/dist/src/mcpl/feature-set-manager.js.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.d.ts +10 -14
- package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.js +58 -67
- package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
- package/dist/src/mcpl/index.d.ts +1 -1
- package/dist/src/mcpl/index.d.ts.map +1 -1
- package/dist/src/mcpl/index.js.map +1 -1
- package/dist/src/mcpl/prose-stream-router.d.ts +9 -0
- package/dist/src/mcpl/prose-stream-router.d.ts.map +1 -1
- package/dist/src/mcpl/prose-stream-router.js +16 -0
- package/dist/src/mcpl/prose-stream-router.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js +20 -2
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +93 -9
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +231 -32
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/server-registry.d.ts.map +1 -1
- package/dist/src/mcpl/server-registry.js +4 -3
- package/dist/src/mcpl/server-registry.js.map +1 -1
- package/dist/src/mcpl/tags.d.ts +24 -0
- package/dist/src/mcpl/tags.d.ts.map +1 -0
- package/dist/src/mcpl/tags.js +52 -0
- package/dist/src/mcpl/tags.js.map +1 -0
- package/dist/src/mcpl/transport.d.ts +1 -1
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +35 -7
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +169 -64
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js +16 -2
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/module-registry.d.ts +12 -0
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +26 -0
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +20 -0
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +48 -15
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/sync.d.ts +4 -0
- package/dist/src/modules/workspace/sync.d.ts.map +1 -1
- package/dist/src/modules/workspace/sync.js +1 -1
- package/dist/src/modules/workspace/sync.js.map +1 -1
- package/dist/src/refusal-reactions.d.ts +27 -0
- package/dist/src/refusal-reactions.d.ts.map +1 -0
- package/dist/src/refusal-reactions.js +35 -0
- package/dist/src/refusal-reactions.js.map +1 -0
- package/dist/src/tool-result-history.d.ts +10 -0
- package/dist/src/tool-result-history.d.ts.map +1 -1
- package/dist/src/tool-result-history.js +16 -5
- package/dist/src/tool-result-history.js.map +1 -1
- package/dist/src/types/agent.d.ts +35 -0
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +26 -0
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +22 -0
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +24 -0
- package/dist/src/types/trace.d.ts.map +1 -1
- package/dist/test/busy-agent-scheduler.test.js +1 -0
- package/dist/test/busy-agent-scheduler.test.js.map +1 -1
- package/dist/test/channel-registry-routing.test.js +38 -10
- package/dist/test/channel-registry-routing.test.js.map +1 -1
- package/dist/test/channel-registry-typing.test.js +10 -1
- package/dist/test/channel-registry-typing.test.js.map +1 -1
- package/dist/test/checkpoint-attribution.test.js +168 -8
- package/dist/test/checkpoint-attribution.test.js.map +1 -1
- package/dist/test/code-execution.test.js +327 -1
- package/dist/test/code-execution.test.js.map +1 -1
- package/dist/test/conversation-fork-injection-scoping.test.js +8 -3
- package/dist/test/conversation-fork-injection-scoping.test.js.map +1 -1
- package/dist/test/deferred-wake-integrity.test.d.ts +29 -0
- package/dist/test/deferred-wake-integrity.test.d.ts.map +1 -0
- package/dist/test/deferred-wake-integrity.test.js +320 -0
- package/dist/test/deferred-wake-integrity.test.js.map +1 -0
- package/dist/test/event-gate-selfwake.test.d.ts +15 -0
- package/dist/test/event-gate-selfwake.test.d.ts.map +1 -0
- package/dist/test/event-gate-selfwake.test.js +125 -0
- package/dist/test/event-gate-selfwake.test.js.map +1 -0
- package/dist/test/machine-close-provenance.test.d.ts +2 -0
- package/dist/test/machine-close-provenance.test.d.ts.map +1 -0
- package/dist/test/machine-close-provenance.test.js +116 -0
- package/dist/test/machine-close-provenance.test.js.map +1 -0
- package/dist/test/mcpl-access-provider.test.d.ts +2 -0
- package/dist/test/mcpl-access-provider.test.d.ts.map +1 -0
- package/dist/test/mcpl-access-provider.test.js +20 -0
- package/dist/test/mcpl-access-provider.test.js.map +1 -0
- package/dist/test/mcpl-awareness-barrier.test.js +10 -0
- package/dist/test/mcpl-awareness-barrier.test.js.map +1 -1
- package/dist/test/mcpl-capability-grant.test.d.ts +10 -0
- package/dist/test/mcpl-capability-grant.test.d.ts.map +1 -0
- package/dist/test/mcpl-capability-grant.test.js +109 -0
- package/dist/test/mcpl-capability-grant.test.js.map +1 -0
- package/dist/test/mcpl-capability-scoping.test.d.ts +2 -0
- package/dist/test/mcpl-capability-scoping.test.d.ts.map +1 -0
- package/dist/test/mcpl-capability-scoping.test.js +266 -0
- package/dist/test/mcpl-capability-scoping.test.js.map +1 -0
- package/dist/test/mcpl-gate-roundtrip.test.js +13 -0
- package/dist/test/mcpl-gate-roundtrip.test.js.map +1 -1
- package/dist/test/mcpl-list-status.test.d.ts +2 -0
- package/dist/test/mcpl-list-status.test.d.ts.map +1 -0
- package/dist/test/mcpl-list-status.test.js +78 -0
- package/dist/test/mcpl-list-status.test.js.map +1 -0
- package/dist/test/mcpl-manifest-changed.test.d.ts +2 -0
- package/dist/test/mcpl-manifest-changed.test.d.ts.map +1 -0
- package/dist/test/mcpl-manifest-changed.test.js +177 -0
- package/dist/test/mcpl-manifest-changed.test.js.map +1 -0
- package/dist/test/mcpl-reconnect-events.test.js +27 -2
- package/dist/test/mcpl-reconnect-events.test.js.map +1 -1
- package/dist/test/mcpl-reconnect-reregistration.test.js +53 -17
- package/dist/test/mcpl-reconnect-reregistration.test.js.map +1 -1
- package/dist/test/mcpl-request-timeout.test.js +1 -1
- package/dist/test/mcpl-request-timeout.test.js.map +1 -1
- package/dist/test/module-context-integration.test.d.ts +18 -0
- package/dist/test/module-context-integration.test.d.ts.map +1 -0
- package/dist/test/module-context-integration.test.js +181 -0
- package/dist/test/module-context-integration.test.js.map +1 -0
- package/dist/test/physical-window-restart.test.d.ts +14 -0
- package/dist/test/physical-window-restart.test.d.ts.map +1 -0
- package/dist/test/physical-window-restart.test.js +222 -0
- package/dist/test/physical-window-restart.test.js.map +1 -0
- package/dist/test/present-while-acting.test.js +270 -0
- package/dist/test/present-while-acting.test.js.map +1 -1
- package/dist/test/refusal-reaction-baseline.test.d.ts +2 -0
- package/dist/test/refusal-reaction-baseline.test.d.ts.map +1 -0
- package/dist/test/refusal-reaction-baseline.test.js +74 -0
- package/dist/test/refusal-reaction-baseline.test.js.map +1 -0
- package/dist/test/state-scaling-e2e.test.js +7 -1
- package/dist/test/state-scaling-e2e.test.js.map +1 -1
- package/dist/test/state-scaling.test.js +9 -1
- package/dist/test/state-scaling.test.js.map +1 -1
- package/dist/test/tool-result-spill.test.d.ts +13 -0
- package/dist/test/tool-result-spill.test.d.ts.map +1 -0
- package/dist/test/tool-result-spill.test.js +463 -0
- package/dist/test/tool-result-spill.test.js.map +1 -0
- package/dist/test/trunk-channel-routing.test.js +45 -0
- package/dist/test/trunk-channel-routing.test.js.map +1 -1
- package/dist/test/utils-surface.test.d.ts +2 -0
- package/dist/test/utils-surface.test.d.ts.map +1 -0
- package/dist/test/utils-surface.test.js +145 -0
- package/dist/test/utils-surface.test.js.map +1 -0
- package/dist/test/workspace-read-image.test.js +71 -0
- package/dist/test/workspace-read-image.test.js.map +1 -1
- package/dist/test/workspace-restore-order.test.d.ts +16 -0
- package/dist/test/workspace-restore-order.test.d.ts.map +1 -0
- package/dist/test/workspace-restore-order.test.js +140 -0
- package/dist/test/workspace-restore-order.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/agent.ts +37 -3
- package/src/code-execution/index.ts +1 -0
- package/src/code-execution/py-runner.ts +56 -4
- package/src/code-execution/runtime-py.ts +156 -7
- package/src/code-execution/tool-definition.ts +27 -2
- package/src/framework.ts +2080 -203
- package/src/gate/event-gate.ts +72 -0
- package/src/index.ts +1 -0
- package/src/mcpl/capability-grant.ts +319 -0
- package/src/mcpl/capability-mask.ts +228 -0
- package/src/mcpl/channel-registry.ts +265 -43
- package/src/mcpl/checkpoint-manager.ts +28 -8
- package/src/mcpl/errors.ts +7 -0
- package/src/mcpl/feature-set-manager.ts +50 -5
- package/src/mcpl/hook-orchestrator.ts +64 -86
- package/src/mcpl/index.ts +0 -2
- package/src/mcpl/prose-stream-router.ts +17 -0
- package/src/mcpl/push-handler.ts +18 -2
- package/src/mcpl/server-connection.ts +262 -34
- package/src/mcpl/server-registry.ts +4 -3
- package/src/mcpl/tags.ts +50 -0
- package/src/mcpl/transport.ts +37 -7
- package/src/mcpl/types.ts +187 -78
- package/src/module-registry.ts +34 -0
- package/src/modules/workspace/index.ts +49 -15
- package/src/modules/workspace/sync.ts +1 -1
- package/src/refusal-reactions.ts +37 -0
- package/src/tool-result-history.ts +17 -5
- package/src/types/agent.ts +36 -0
- package/src/types/framework.ts +27 -0
- package/src/types/module.ts +24 -0
- package/src/types/trace.ts +22 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deferred-message / wake integrity (2026-07-31 Mythos "phantom skip").
|
|
3
|
+
*
|
|
4
|
+
* The incident: a DM arrived while a turn was streaming → the message body
|
|
5
|
+
* was deferred (hear-while-acting) but its inference wake was pushed
|
|
6
|
+
* immediately. The wake fired a new turn whose compile ran BEFORE the
|
|
7
|
+
* previous turn's finally flushed the deferred DM; the new turn saw only the
|
|
8
|
+
* routing-shift notice, reasonably skipped, and the DM then landed in the
|
|
9
|
+
* window mid-compile — positioned before the skip. Result: falsified history
|
|
10
|
+
* (the window testified the agent saw the DM and skipped it; the agent later
|
|
11
|
+
* confabulated an apology for a choice it never made) and a KV bust (every
|
|
12
|
+
* later compile diverged from the live prefix at the inserted message).
|
|
13
|
+
*
|
|
14
|
+
* Invariants under test:
|
|
15
|
+
* 1. A turn started by a queued wake CONTAINS the deferred message that woke
|
|
16
|
+
* it (turn-start flush runs before the locus announcement and compile).
|
|
17
|
+
* 2. addMessage defers on turn-alive (activeTurnTokens), not merely
|
|
18
|
+
* stream-alive — the compile window between dequeue and stream
|
|
19
|
+
* registration is closed to cross-turn writers.
|
|
20
|
+
* 3. endTurn edge: a message stored at an endTurn tool boundary (collected
|
|
21
|
+
* for injection but never delivered — the stream is cancelled) is seen by
|
|
22
|
+
* the follow-up turn its own wake starts, positioned AFTER the turn that
|
|
23
|
+
* never saw it, never before.
|
|
24
|
+
* 4. Turn tokens never leak: after runUntilIdle, no turn-alive markers
|
|
25
|
+
* remain (a leaked token would permanently requeue every wake — the
|
|
26
|
+
* 'idle+turn-alive' wedge).
|
|
27
|
+
*/
|
|
28
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
29
|
+
import assert from 'node:assert/strict';
|
|
30
|
+
import { tmpdir } from 'node:os';
|
|
31
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
32
|
+
import { join } from 'node:path';
|
|
33
|
+
import { AgentFramework } from '../src/index.js';
|
|
34
|
+
import { MockMembrane, MockYieldingStream, createMockResponse } from './helpers/mock-membrane.js';
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Test module: a halt tool that ends the turn, and mid-turn interjections
|
|
37
|
+
// that DO request inference (unlike present-while-acting's, which don't) —
|
|
38
|
+
// this suite is about the wake/payload split, so the wake matters.
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
class DmModule {
|
|
41
|
+
name = 'dm';
|
|
42
|
+
framework = null;
|
|
43
|
+
/** Next `halt` call pushes this text as an external message (with
|
|
44
|
+
* requestInference) BEFORE returning its endTurn result. */
|
|
45
|
+
interjection = null;
|
|
46
|
+
async start(_ctx) { }
|
|
47
|
+
async stop() { }
|
|
48
|
+
getTools() {
|
|
49
|
+
return [
|
|
50
|
+
{
|
|
51
|
+
name: 'halt',
|
|
52
|
+
description: 'End the turn',
|
|
53
|
+
inputSchema: { type: 'object', properties: {} },
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
async handleToolCall(call) {
|
|
58
|
+
if (call.name.endsWith('halt')) {
|
|
59
|
+
if (this.interjection) {
|
|
60
|
+
const text = this.interjection;
|
|
61
|
+
this.interjection = null;
|
|
62
|
+
this.framework.pushEvent({
|
|
63
|
+
type: 'external-message',
|
|
64
|
+
source: 'test',
|
|
65
|
+
content: text,
|
|
66
|
+
metadata: { channelId: 'dm-antra' },
|
|
67
|
+
});
|
|
68
|
+
// Let the run loop process the queued message while this tool round
|
|
69
|
+
// is still pending, so it lands in deferredMessages with its wake
|
|
70
|
+
// queued behind the busy agent.
|
|
71
|
+
await new Promise((r) => setTimeout(r, 30));
|
|
72
|
+
}
|
|
73
|
+
return { success: true, data: { halted: true }, endTurn: true };
|
|
74
|
+
}
|
|
75
|
+
return { success: true, data: { ok: true } };
|
|
76
|
+
}
|
|
77
|
+
async onProcess(event, _state) {
|
|
78
|
+
if (event.type === 'external-message') {
|
|
79
|
+
const text = String(event.content);
|
|
80
|
+
const metadata = event.metadata;
|
|
81
|
+
return {
|
|
82
|
+
addMessages: [
|
|
83
|
+
{
|
|
84
|
+
participant: 'Antra',
|
|
85
|
+
content: [{ type: 'text', text }],
|
|
86
|
+
...(metadata ? { metadata: { ...metadata, triggered: true } } : {}),
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
requestInference: true,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return {};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** Minimal ChannelRegistry stub (same shape as present-while-acting's). */
|
|
96
|
+
function stubChannelRegistry(framework) {
|
|
97
|
+
const routed = [];
|
|
98
|
+
const explicit = {
|
|
99
|
+
resolveLocus: () => 'dm-antra',
|
|
100
|
+
routeSpeech: async (_agent, text, locus) => {
|
|
101
|
+
routed.push({ text, locus: locus ?? null });
|
|
102
|
+
},
|
|
103
|
+
getDefaultPublishChannel: () => null,
|
|
104
|
+
isChannelOpen: () => true,
|
|
105
|
+
getDescriptor: () => undefined,
|
|
106
|
+
getChannelTools: () => [],
|
|
107
|
+
};
|
|
108
|
+
framework.channelRegistry = new Proxy(explicit, {
|
|
109
|
+
get: (target, prop) => (prop in target ? target[prop] : () => undefined),
|
|
110
|
+
});
|
|
111
|
+
return routed;
|
|
112
|
+
}
|
|
113
|
+
/** Serialize a request's messages for containment/ordering checks. */
|
|
114
|
+
function flatten(req) {
|
|
115
|
+
return req.messages.map((m) => JSON.stringify(m));
|
|
116
|
+
}
|
|
117
|
+
function indexContaining(flat, needle) {
|
|
118
|
+
return flat.findIndex((s) => s.includes(needle));
|
|
119
|
+
}
|
|
120
|
+
/** Per-turn response scheduling: MockMembrane's streamYielding hands ALL
|
|
121
|
+
* remaining responses to the first stream, which starves multi-turn tests.
|
|
122
|
+
* This override gives each turn exactly its own slate. */
|
|
123
|
+
function scheduleTurns(membrane, turns) {
|
|
124
|
+
let turnIdx = 0;
|
|
125
|
+
membrane.streamYielding = (req) => {
|
|
126
|
+
membrane.calls.push(req);
|
|
127
|
+
const slate = turns[turnIdx++] ?? [createMockResponse([{ type: 'text', text: 'fallback' }])];
|
|
128
|
+
const stream = new MockYieldingStream(slate);
|
|
129
|
+
membrane.lastStream = stream;
|
|
130
|
+
return stream;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
describe('deferred-message wake integrity', () => {
|
|
135
|
+
let tempDir;
|
|
136
|
+
let membrane;
|
|
137
|
+
let module;
|
|
138
|
+
beforeEach(() => {
|
|
139
|
+
tempDir = mkdtempSync(join(tmpdir(), 'dwi-test-'));
|
|
140
|
+
membrane = new MockMembrane();
|
|
141
|
+
module = new DmModule();
|
|
142
|
+
});
|
|
143
|
+
afterEach(() => {
|
|
144
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
145
|
+
});
|
|
146
|
+
async function createFramework() {
|
|
147
|
+
const framework = await AgentFramework.create({
|
|
148
|
+
storePath: join(tempDir, 'test.chronicle'),
|
|
149
|
+
membrane: membrane.asMembrane(),
|
|
150
|
+
agents: [
|
|
151
|
+
{ name: 'assistant', model: 'test-model', systemPrompt: 'You are Mythos.' },
|
|
152
|
+
],
|
|
153
|
+
modules: [module],
|
|
154
|
+
});
|
|
155
|
+
module.framework = framework;
|
|
156
|
+
return framework;
|
|
157
|
+
}
|
|
158
|
+
const internals = (f) => f;
|
|
159
|
+
// -------------------------------------------------------------------------
|
|
160
|
+
it('a turn started by a queued wake contains the deferred message that woke it', async () => {
|
|
161
|
+
scheduleTurns(membrane, [
|
|
162
|
+
[createMockResponse([{ type: 'text', text: 'answering the DM' }])],
|
|
163
|
+
]);
|
|
164
|
+
const framework = await createFramework();
|
|
165
|
+
stubChannelRegistry(framework);
|
|
166
|
+
const fw = internals(framework);
|
|
167
|
+
// The incident state, seeded directly: payload deferred, wake queued,
|
|
168
|
+
// agent idle. (Live, this arises when a message lands during another
|
|
169
|
+
// turn's stream: addMessage defers the body, the wake pushes anyway.)
|
|
170
|
+
const dmText = 'and then the restaurant, and the hike — the deferred DM';
|
|
171
|
+
fw.deferredMessages.push({
|
|
172
|
+
participant: 'Antra',
|
|
173
|
+
content: [{ type: 'text', text: dmText }],
|
|
174
|
+
metadata: { channelId: 'dm-antra', triggered: true },
|
|
175
|
+
});
|
|
176
|
+
fw.pendingRequests.push({
|
|
177
|
+
agentName: 'assistant',
|
|
178
|
+
reason: 'mcpl:channel-incoming',
|
|
179
|
+
source: 'test',
|
|
180
|
+
timestamp: Date.now(),
|
|
181
|
+
channelId: 'dm-antra',
|
|
182
|
+
addressed: true,
|
|
183
|
+
});
|
|
184
|
+
await framework.runUntilIdle();
|
|
185
|
+
assert.equal(membrane.calls.length, 1, 'the wake fired exactly one turn');
|
|
186
|
+
const flat = flatten(membrane.calls[0]);
|
|
187
|
+
assert.ok(indexContaining(flat, dmText) >= 0, 'the compiled request contains the message that woke the turn (turn-start flush)');
|
|
188
|
+
assert.equal(fw.deferredMessages.length, 0, 'deferred queue drained');
|
|
189
|
+
assert.equal(fw.activeTurnTokens.size, 0, 'no turn token leaked');
|
|
190
|
+
await framework.stop();
|
|
191
|
+
});
|
|
192
|
+
it('addMessage defers on turn-alive even when no stream is registered (compile window)', async () => {
|
|
193
|
+
const framework = await createFramework();
|
|
194
|
+
stubChannelRegistry(framework);
|
|
195
|
+
const fw = internals(framework);
|
|
196
|
+
// Simulate the dequeue→stream gap: a turn is alive (token set) but its
|
|
197
|
+
// stream has not registered yet. This is exactly when the incident's
|
|
198
|
+
// deferred flush wrote into the window mid-compile.
|
|
199
|
+
fw.activeTurnTokens.set('assistant', 999999);
|
|
200
|
+
assert.equal(fw.activeStreams.size, 0, 'precondition: no live stream');
|
|
201
|
+
const id = fw.addMessage('Antra', [{ type: 'text', text: 'arrives mid-compile' }]);
|
|
202
|
+
assert.equal(id, '', 'message was deferred, not appended');
|
|
203
|
+
assert.equal(fw.deferredMessages.length, 1, 'message waits in the deferred queue');
|
|
204
|
+
fw.activeTurnTokens.delete('assistant');
|
|
205
|
+
fw.deferredMessages.length = 0; // don't leak state into stop()
|
|
206
|
+
await framework.stop();
|
|
207
|
+
});
|
|
208
|
+
it('endTurn edge: a message stored at an endTurn boundary is answered by its own wake, positioned after the turn that never saw it', async () => {
|
|
209
|
+
scheduleTurns(membrane, [
|
|
210
|
+
// Turn A: the agent is mid-scene and halts (skip_reply-shaped: an
|
|
211
|
+
// endTurn tool result cancels the stream — collected injections are
|
|
212
|
+
// never delivered).
|
|
213
|
+
[createMockResponse([{ type: 'tool_use', id: 'c1', name: 'dm--halt', input: {} }], 'tool_use')],
|
|
214
|
+
// Turn B: the DM's own wake.
|
|
215
|
+
[createMockResponse([{ type: 'text', text: 'answering antra now' }])],
|
|
216
|
+
]);
|
|
217
|
+
const framework = await createFramework();
|
|
218
|
+
stubChannelRegistry(framework);
|
|
219
|
+
const fw = internals(framework);
|
|
220
|
+
const dmText = 'laria read me your messages aloud on the trail';
|
|
221
|
+
module.interjection = dmText;
|
|
222
|
+
// Start turn A.
|
|
223
|
+
framework.pushEvent({
|
|
224
|
+
type: 'external-message',
|
|
225
|
+
source: 'test',
|
|
226
|
+
content: 'go',
|
|
227
|
+
metadata: {},
|
|
228
|
+
});
|
|
229
|
+
await framework.runUntilIdle();
|
|
230
|
+
assert.equal(membrane.calls.length, 2, 'turn A (go → halt) and the DM-wake turn B ran');
|
|
231
|
+
// Turn B contains the DM.
|
|
232
|
+
const flatB = flatten(membrane.calls[1]);
|
|
233
|
+
const dmIdx = indexContaining(flatB, dmText);
|
|
234
|
+
assert.ok(dmIdx >= 0, "turn B's request contains the DM");
|
|
235
|
+
// History integrity: in turn B's request the DM appears AFTER turn A's
|
|
236
|
+
// halt (the turn that never saw it) — never retroactively before it.
|
|
237
|
+
const haltIdx = indexContaining(flatB, 'dm--halt');
|
|
238
|
+
assert.ok(haltIdx >= 0, "turn A's halt is in turn B's history");
|
|
239
|
+
assert.ok(dmIdx > haltIdx, `DM (idx ${dmIdx}) must be positioned after the halt (idx ${haltIdx}) — ` +
|
|
240
|
+
'a DM placed before it would testify the agent saw and skipped it');
|
|
241
|
+
// And turn A itself must NOT contain the DM (it arrived mid-turn and was
|
|
242
|
+
// never injected — the endTurn cancelled the stream before delivery).
|
|
243
|
+
const flatA = flatten(membrane.calls[0]);
|
|
244
|
+
assert.equal(indexContaining(flatA, dmText), -1, "turn A's request predates the DM");
|
|
245
|
+
assert.equal(fw.activeTurnTokens.size, 0, 'no turn token leaked across the sequence');
|
|
246
|
+
assert.equal(fw.deferredMessages.length, 0, 'no message stranded in the deferred queue');
|
|
247
|
+
await framework.stop();
|
|
248
|
+
});
|
|
249
|
+
it('a throw before the compile (checkpoint/store failure) does not leak the turn token', async () => {
|
|
250
|
+
// ENOSPC-class failure: recordTurnCheckpoint (a store write) throws after
|
|
251
|
+
// the token is set but before driveStream exists. Without the caller's
|
|
252
|
+
// token-matched finally, the token leaks and every later wake requeues
|
|
253
|
+
// forever (the 'idle+turn-alive' wedge) — a one-turn failure must stay a
|
|
254
|
+
// one-turn failure.
|
|
255
|
+
scheduleTurns(membrane, [
|
|
256
|
+
[createMockResponse([{ type: 'text', text: 'recovered turn' }])],
|
|
257
|
+
]);
|
|
258
|
+
const framework = await createFramework();
|
|
259
|
+
stubChannelRegistry(framework);
|
|
260
|
+
const fw = internals(framework);
|
|
261
|
+
const patchable = framework;
|
|
262
|
+
const original = patchable.recordTurnCheckpoint.bind(framework);
|
|
263
|
+
patchable.recordTurnCheckpoint = () => {
|
|
264
|
+
patchable.recordTurnCheckpoint = original; // one-shot
|
|
265
|
+
throw new Error('ENOSPC: simulated store-write failure');
|
|
266
|
+
};
|
|
267
|
+
framework.pushEvent({
|
|
268
|
+
type: 'external-message',
|
|
269
|
+
source: 'test',
|
|
270
|
+
content: 'go',
|
|
271
|
+
metadata: {},
|
|
272
|
+
});
|
|
273
|
+
// The throw propagates out of the event loop iteration (runUntilIdle
|
|
274
|
+
// surfaces it in this harness; production runLoop logs and continues).
|
|
275
|
+
await assert.rejects(framework.runUntilIdle(), /ENOSPC/);
|
|
276
|
+
assert.equal(fw.activeTurnTokens.size, 0, 'the failed turn cleared its own token');
|
|
277
|
+
// The agent is not wedged: a fresh wake still runs to completion.
|
|
278
|
+
framework.pushEvent({
|
|
279
|
+
type: 'external-message',
|
|
280
|
+
source: 'test',
|
|
281
|
+
content: 'go again',
|
|
282
|
+
metadata: {},
|
|
283
|
+
});
|
|
284
|
+
await framework.runUntilIdle();
|
|
285
|
+
assert.equal(membrane.calls.length, 1, 'the follow-up wake produced a turn');
|
|
286
|
+
assert.equal(fw.activeTurnTokens.size, 0, 'no token leaked after recovery either');
|
|
287
|
+
await framework.stop();
|
|
288
|
+
});
|
|
289
|
+
it('turn tokens are released on normal completion (no idle+turn-alive wedge)', async () => {
|
|
290
|
+
scheduleTurns(membrane, [
|
|
291
|
+
[createMockResponse([{ type: 'text', text: 'plain turn' }])],
|
|
292
|
+
]);
|
|
293
|
+
const framework = await createFramework();
|
|
294
|
+
stubChannelRegistry(framework);
|
|
295
|
+
const fw = internals(framework);
|
|
296
|
+
framework.pushEvent({
|
|
297
|
+
type: 'external-message',
|
|
298
|
+
source: 'test',
|
|
299
|
+
content: 'go',
|
|
300
|
+
metadata: {},
|
|
301
|
+
});
|
|
302
|
+
await framework.runUntilIdle();
|
|
303
|
+
assert.equal(fw.activeTurnTokens.size, 0, 'token cleared at teardown');
|
|
304
|
+
// A fresh wake still runs (the agent is not wedged).
|
|
305
|
+
scheduleTurns(membrane, [
|
|
306
|
+
[createMockResponse([{ type: 'text', text: 'second turn' }])],
|
|
307
|
+
]);
|
|
308
|
+
const callsBefore = membrane.calls.length;
|
|
309
|
+
framework.pushEvent({
|
|
310
|
+
type: 'external-message',
|
|
311
|
+
source: 'test',
|
|
312
|
+
content: 'go again',
|
|
313
|
+
metadata: {},
|
|
314
|
+
});
|
|
315
|
+
await framework.runUntilIdle();
|
|
316
|
+
assert.equal(membrane.calls.length, callsBefore + 1, 'agent takes the next turn');
|
|
317
|
+
await framework.stop();
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
//# sourceMappingURL=deferred-wake-integrity.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deferred-wake-integrity.test.js","sourceRoot":"","sources":["../../test/deferred-wake-integrity.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-wake (skip_reply's wake_in_seconds) — EventGate.armSelfWake.
|
|
3
|
+
*
|
|
4
|
+
* Contract (2026-08-02, antra's QoL request):
|
|
5
|
+
* - armSelfWake(agent, N) fires a normal inference request after ~N
|
|
6
|
+
* seconds. NO suppression window is involved (unlike sleep) — external
|
|
7
|
+
* wakes flow normally in the meantime.
|
|
8
|
+
* - Any turn start for the agent (onInferenceStarted) cancels the pending
|
|
9
|
+
* self-wake: the semantics are "if nothing else wakes me by then".
|
|
10
|
+
* - Re-arming replaces the pending timer (single timer per agent).
|
|
11
|
+
* - Seconds clamp to [1, 3600].
|
|
12
|
+
* - dispose() clears pending timers.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=event-gate-selfwake.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-gate-selfwake.test.d.ts","sourceRoot":"","sources":["../../test/event-gate-selfwake.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-wake (skip_reply's wake_in_seconds) — EventGate.armSelfWake.
|
|
3
|
+
*
|
|
4
|
+
* Contract (2026-08-02, antra's QoL request):
|
|
5
|
+
* - armSelfWake(agent, N) fires a normal inference request after ~N
|
|
6
|
+
* seconds. NO suppression window is involved (unlike sleep) — external
|
|
7
|
+
* wakes flow normally in the meantime.
|
|
8
|
+
* - Any turn start for the agent (onInferenceStarted) cancels the pending
|
|
9
|
+
* self-wake: the semantics are "if nothing else wakes me by then".
|
|
10
|
+
* - Re-arming replaces the pending timer (single timer per agent).
|
|
11
|
+
* - Seconds clamp to [1, 3600].
|
|
12
|
+
* - dispose() clears pending timers.
|
|
13
|
+
*/
|
|
14
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
15
|
+
import assert from 'node:assert';
|
|
16
|
+
import { existsSync, mkdirSync, rmSync } from 'node:fs';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
import { EventGate } from '../src/gate/event-gate.js';
|
|
19
|
+
const TMP_DIR = join(import.meta.dirname, '../.test-tmp-gate-selfwake');
|
|
20
|
+
function makeGate() {
|
|
21
|
+
const inferenceRequests = [];
|
|
22
|
+
const messages = [];
|
|
23
|
+
const gate = new EventGate({
|
|
24
|
+
configPath: join(TMP_DIR, 'gate.json'),
|
|
25
|
+
emitTrace: () => { },
|
|
26
|
+
addMessage: (p, c, m) => {
|
|
27
|
+
messages.push({ participant: p, text: c.map((b) => b.text).join('\n'), metadata: m });
|
|
28
|
+
return '';
|
|
29
|
+
},
|
|
30
|
+
requestInference: (a, r, s) => inferenceRequests.push({ agentName: a, reason: r, source: s }),
|
|
31
|
+
getAgentNames: () => ['agent'],
|
|
32
|
+
});
|
|
33
|
+
return { gate, inferenceRequests, messages };
|
|
34
|
+
}
|
|
35
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
36
|
+
describe('EventGate self-wake', () => {
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
if (existsSync(TMP_DIR))
|
|
39
|
+
rmSync(TMP_DIR, { recursive: true });
|
|
40
|
+
mkdirSync(TMP_DIR, { recursive: true });
|
|
41
|
+
});
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
if (existsSync(TMP_DIR))
|
|
44
|
+
rmSync(TMP_DIR, { recursive: true });
|
|
45
|
+
});
|
|
46
|
+
it('fires an inference request after the delay', async () => {
|
|
47
|
+
const { gate, inferenceRequests } = makeGate();
|
|
48
|
+
const { inMs } = gate.armSelfWake('agent', 1, 'skip_reply');
|
|
49
|
+
assert.strictEqual(inMs, 1000);
|
|
50
|
+
assert.strictEqual(inferenceRequests.length, 0, 'must not fire synchronously');
|
|
51
|
+
await sleep(1150);
|
|
52
|
+
assert.strictEqual(inferenceRequests.length, 1);
|
|
53
|
+
assert.strictEqual(inferenceRequests[0].agentName, 'agent');
|
|
54
|
+
assert.strictEqual(inferenceRequests[0].source, 'self-wake');
|
|
55
|
+
assert.match(inferenceRequests[0].reason, /skip_reply/);
|
|
56
|
+
gate.dispose();
|
|
57
|
+
});
|
|
58
|
+
it('drops a compact timestamped notice into the window when it fires', async () => {
|
|
59
|
+
const { gate, messages } = makeGate();
|
|
60
|
+
gate.armSelfWake('agent', 1, 'skip_reply');
|
|
61
|
+
assert.strictEqual(messages.length, 0, 'arming must not add a message');
|
|
62
|
+
await sleep(1150);
|
|
63
|
+
assert.strictEqual(messages.length, 1);
|
|
64
|
+
const msg = messages[0];
|
|
65
|
+
assert.strictEqual(msg.participant, 'user');
|
|
66
|
+
assert.strictEqual(msg.metadata?.source, 'gate:self-wake');
|
|
67
|
+
// One line: what woke it (its own skip_reply timer, with the armed
|
|
68
|
+
// duration) and when (ISO to the second).
|
|
69
|
+
assert.match(msg.text, /^\[self-wake\] your skip_reply timer \(1s\) elapsed — now \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/);
|
|
70
|
+
gate.dispose();
|
|
71
|
+
});
|
|
72
|
+
it('a superseded self-wake adds no notice', async () => {
|
|
73
|
+
const { gate, messages } = makeGate();
|
|
74
|
+
gate.armSelfWake('agent', 1);
|
|
75
|
+
gate.onInferenceStarted('agent');
|
|
76
|
+
gate.onInferenceEnded('agent');
|
|
77
|
+
await sleep(1150);
|
|
78
|
+
assert.strictEqual(messages.length, 0);
|
|
79
|
+
gate.dispose();
|
|
80
|
+
});
|
|
81
|
+
it('is cancelled by a turn start (external wake supersedes)', async () => {
|
|
82
|
+
const { gate, inferenceRequests } = makeGate();
|
|
83
|
+
gate.armSelfWake('agent', 1);
|
|
84
|
+
// Something else woke the agent first.
|
|
85
|
+
gate.onInferenceStarted('agent');
|
|
86
|
+
gate.onInferenceEnded('agent');
|
|
87
|
+
await sleep(1150);
|
|
88
|
+
assert.strictEqual(inferenceRequests.length, 0, 'superseded self-wake must not fire');
|
|
89
|
+
gate.dispose();
|
|
90
|
+
});
|
|
91
|
+
it('survives the arming turn itself (arm mid-turn, fire after end)', async () => {
|
|
92
|
+
const { gate, inferenceRequests } = makeGate();
|
|
93
|
+
// Turn starts, THEN skip_reply arms the wake mid-turn, then the turn ends
|
|
94
|
+
// — exactly the production sequence. The arm must not be eaten by its
|
|
95
|
+
// own turn's lifecycle.
|
|
96
|
+
gate.onInferenceStarted('agent');
|
|
97
|
+
gate.armSelfWake('agent', 1);
|
|
98
|
+
gate.onInferenceEnded('agent');
|
|
99
|
+
await sleep(1150);
|
|
100
|
+
assert.strictEqual(inferenceRequests.length, 1);
|
|
101
|
+
gate.dispose();
|
|
102
|
+
});
|
|
103
|
+
it('re-arming replaces the pending timer; only one wake fires', async () => {
|
|
104
|
+
const { gate, inferenceRequests } = makeGate();
|
|
105
|
+
gate.armSelfWake('agent', 1);
|
|
106
|
+
gate.armSelfWake('agent', 1);
|
|
107
|
+
await sleep(1200);
|
|
108
|
+
assert.strictEqual(inferenceRequests.length, 1);
|
|
109
|
+
gate.dispose();
|
|
110
|
+
});
|
|
111
|
+
it('clamps seconds to [1, 3600]', () => {
|
|
112
|
+
const { gate } = makeGate();
|
|
113
|
+
assert.strictEqual(gate.armSelfWake('agent', 0.05).inMs, 1000);
|
|
114
|
+
assert.strictEqual(gate.armSelfWake('agent', 999999).inMs, 3_600_000);
|
|
115
|
+
gate.dispose();
|
|
116
|
+
});
|
|
117
|
+
it('dispose clears pending timers', async () => {
|
|
118
|
+
const { gate, inferenceRequests } = makeGate();
|
|
119
|
+
gate.armSelfWake('agent', 1);
|
|
120
|
+
gate.dispose();
|
|
121
|
+
await sleep(1150);
|
|
122
|
+
assert.strictEqual(inferenceRequests.length, 0);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
//# sourceMappingURL=event-gate-selfwake.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-gate-selfwake.test.js","sourceRoot":"","sources":["../../test/event-gate-selfwake.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine-close-provenance.test.d.ts","sourceRoot":"","sources":["../../test/machine-close-provenance.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { CapabilityGrant, ALL_CAPABILITY_PATHS } from '../src/mcpl/capability-grant.js';
|
|
2
|
+
import { test } from 'node:test';
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import { ChannelRegistry } from '../src/mcpl/channel-registry.js';
|
|
5
|
+
/**
|
|
6
|
+
* Machine-close provenance + explicit-open protection (issue #5): closes
|
|
7
|
+
* invoked by housekeeping modules must record their own decision source —
|
|
8
|
+
* never 'agent-tool' — and must not override a channel the resident or
|
|
9
|
+
* operator explicitly opened, unless the caller certifies an explicit idle
|
|
10
|
+
* lease. The Mythos "channel settings keep getting reset" mechanism was
|
|
11
|
+
* subscription-GC closes wearing the agent's badge.
|
|
12
|
+
*/
|
|
13
|
+
function makeRegistry() {
|
|
14
|
+
const closeCalls = [];
|
|
15
|
+
const mockServer = {
|
|
16
|
+
// Post-policy state: full grant, so tests exercise delivery, not §5.3 denial.
|
|
17
|
+
grant: new CapabilityGrant(new Set(ALL_CAPABILITY_PATHS), []),
|
|
18
|
+
sendChannelsOpen: async () => ({}),
|
|
19
|
+
sendChannelsClose: async (params) => {
|
|
20
|
+
closeCalls.push(params);
|
|
21
|
+
return {};
|
|
22
|
+
},
|
|
23
|
+
sendChannelsPublish: async () => ({ delivered: true }),
|
|
24
|
+
};
|
|
25
|
+
const serverRegistry = {
|
|
26
|
+
getServer: (_id) => mockServer,
|
|
27
|
+
};
|
|
28
|
+
const registry = new ChannelRegistry(serverRegistry, {}, () => { }, () => { });
|
|
29
|
+
const internals = registry;
|
|
30
|
+
const desired = (channelId) => internals.desiredStates.get(internals.lifecycleKey('discord', channelId));
|
|
31
|
+
// Register the channel the way a live server would surface it.
|
|
32
|
+
registry.channels.set('discord:c1', {
|
|
33
|
+
serverId: 'discord', descriptor: { id: 'c1', type: 'discord', label: '#commons' }, open: false,
|
|
34
|
+
});
|
|
35
|
+
registry.handleIncoming('discord', {
|
|
36
|
+
messages: [{
|
|
37
|
+
channelId: 'c1',
|
|
38
|
+
messageId: 'm1',
|
|
39
|
+
author: { id: 'u1', name: 'Antra' },
|
|
40
|
+
timestamp: '2026-07-28T00:00:00.000Z',
|
|
41
|
+
content: [{ type: 'text', text: 'hello' }],
|
|
42
|
+
metadata: { channelName: '#commons' },
|
|
43
|
+
}],
|
|
44
|
+
});
|
|
45
|
+
return { registry, internals, desired, closeCalls };
|
|
46
|
+
}
|
|
47
|
+
const MODULE_ORIGIN = { kind: 'module' };
|
|
48
|
+
test('a machine close of an explicitly-opened channel is refused, structurally', async () => {
|
|
49
|
+
const { registry, desired, closeCalls } = makeRegistry();
|
|
50
|
+
await registry.handleChannelToolCall('channel_open', { channelId: 'c1' });
|
|
51
|
+
assert.deepEqual(desired('c1'), { state: 'open', source: 'agent-tool' });
|
|
52
|
+
const result = await registry.handleChannelToolCall('channel_close', { channelId: 'c1', source: 'subscription-gc' }, MODULE_ORIGIN);
|
|
53
|
+
assert.equal(result.success, false);
|
|
54
|
+
assert.equal(result.data?.refusal, 'explicit-open');
|
|
55
|
+
// Stated intent survives: desired state untouched, nothing sent to the server.
|
|
56
|
+
assert.deepEqual(desired('c1'), { state: 'open', source: 'agent-tool' });
|
|
57
|
+
assert.equal(closeCalls.length, 0);
|
|
58
|
+
});
|
|
59
|
+
test('an explicit idle lease lets the machine close through, with honest provenance', async () => {
|
|
60
|
+
const { registry, desired, closeCalls } = makeRegistry();
|
|
61
|
+
await registry.handleChannelToolCall('channel_open', { channelId: 'c1' });
|
|
62
|
+
const result = await registry.handleChannelToolCall('channel_close', { channelId: 'c1', source: 'subscription-gc', overrideExplicitOpen: true }, MODULE_ORIGIN);
|
|
63
|
+
assert.equal(result.success, true);
|
|
64
|
+
// The durable record names the janitor, not the agent.
|
|
65
|
+
assert.deepEqual(desired('c1'), { state: 'closed', source: 'subscription-gc' });
|
|
66
|
+
assert.equal(closeCalls.length, 1);
|
|
67
|
+
});
|
|
68
|
+
test('agent closes are recorded as agent-tool, exactly as before', async () => {
|
|
69
|
+
const { registry, desired } = makeRegistry();
|
|
70
|
+
await registry.handleChannelToolCall('channel_open', { channelId: 'c1' });
|
|
71
|
+
const result = await registry.handleChannelToolCall('channel_close', { channelId: 'c1' }, { kind: 'agent', agentName: 'mythos' });
|
|
72
|
+
assert.equal(result.success, true);
|
|
73
|
+
assert.deepEqual(desired('c1'), { state: 'closed', source: 'agent-tool' });
|
|
74
|
+
});
|
|
75
|
+
test('machine closes of policy-opened channels proceed without a lease', async () => {
|
|
76
|
+
const { registry, internals, desired, closeCalls } = makeRegistry();
|
|
77
|
+
// A channel nobody explicitly chose — opened by delivery/policy.
|
|
78
|
+
internals.setDesiredState('discord', 'c1', 'open', 'opened-by-delivery');
|
|
79
|
+
const result = await registry.handleChannelToolCall('channel_close', { channelId: 'c1', source: 'subscription-gc' }, MODULE_ORIGIN);
|
|
80
|
+
assert.equal(result.success, true);
|
|
81
|
+
assert.deepEqual(desired('c1'), { state: 'closed', source: 'subscription-gc' });
|
|
82
|
+
assert.equal(closeCalls.length, 1);
|
|
83
|
+
});
|
|
84
|
+
test('forged machine fields on a MODEL-origin call are ignored: agent-tool is recorded', async () => {
|
|
85
|
+
const { registry, desired, closeCalls } = makeRegistry();
|
|
86
|
+
await registry.handleChannelToolCall('channel_open', { channelId: 'c1' });
|
|
87
|
+
// The schema omits these fields but does not reject extras — a model can
|
|
88
|
+
// emit them. Trusted dispatch context must win over self-description.
|
|
89
|
+
const result = await registry.handleChannelToolCall('channel_close', { channelId: 'c1', source: 'subscription-gc', overrideExplicitOpen: true }, { kind: 'agent', agentName: 'mythos' });
|
|
90
|
+
assert.equal(result.success, true);
|
|
91
|
+
// The close succeeds (the resident may close their own channel) but the
|
|
92
|
+
// record attributes it to them, not to housekeeping.
|
|
93
|
+
assert.deepEqual(desired('c1'), { state: 'closed', source: 'agent-tool' });
|
|
94
|
+
assert.equal(closeCalls.length, 1);
|
|
95
|
+
});
|
|
96
|
+
test('origin-less calls default to agent semantics (safe for legacy callers)', async () => {
|
|
97
|
+
const { registry, desired } = makeRegistry();
|
|
98
|
+
await registry.handleChannelToolCall('channel_open', { channelId: 'c1' });
|
|
99
|
+
const result = await registry.handleChannelToolCall('channel_close', {
|
|
100
|
+
channelId: 'c1',
|
|
101
|
+
source: 'subscription-gc',
|
|
102
|
+
overrideExplicitOpen: true,
|
|
103
|
+
});
|
|
104
|
+
assert.equal(result.success, true);
|
|
105
|
+
assert.deepEqual(desired('c1'), { state: 'closed', source: 'agent-tool' });
|
|
106
|
+
});
|
|
107
|
+
test('module-origin closes outside the closed source vocabulary are rejected loudly', async () => {
|
|
108
|
+
const { registry, desired } = makeRegistry();
|
|
109
|
+
await registry.handleChannelToolCall('channel_open', { channelId: 'c1' });
|
|
110
|
+
const result = await registry.handleChannelToolCall('channel_close', { channelId: 'c1', source: 'gremlin-module' }, MODULE_ORIGIN);
|
|
111
|
+
assert.equal(result.success, false);
|
|
112
|
+
assert.equal(result.isError, true);
|
|
113
|
+
assert.match(result.error ?? '', /Unknown machine close source/);
|
|
114
|
+
assert.deepEqual(desired('c1'), { state: 'open', source: 'agent-tool' });
|
|
115
|
+
});
|
|
116
|
+
//# sourceMappingURL=machine-close-provenance.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine-close-provenance.test.js","sourceRoot":"","sources":["../../test/machine-close-provenance.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpl-access-provider.test.d.ts","sourceRoot":"","sources":["../../test/mcpl-access-provider.test.ts"],"names":[],"mappings":""}
|