mcp-event-intelligence 0.6.1 → 0.7.1
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/CHANGELOG.md +34 -1
- package/README.md +53 -3
- package/dist/src/intelligenceProtocol/activationSchemas.d.ts +101 -0
- package/dist/src/intelligenceProtocol/activationSchemas.js +3 -0
- package/dist/src/intelligenceProtocol/index.d.ts +2 -2
- package/dist/src/intelligenceProtocol/index.js +1 -1
- package/dist/src/intelligenceProtocol/schemas.d.ts +2 -14
- package/dist/src/intelligenceProtocol/schemas.js +3 -1
- package/dist/src/intelligenceProtocol/triggerPlanSchemas.d.ts +1 -7
- package/dist/src/intelligenceProtocol/triggerSchemas.d.ts +1 -7
- package/package.json +10 -3
- package/scripts/embedded-host-kit.d.mts +160 -0
- package/scripts/embedded-host-kit.mjs +567 -0
- package/scripts/host-integration.mjs +24 -2
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.1] - 2026-10-04
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- serialize and coalesce concurrent host MCP registry refreshes so an embedded runtime cannot observe a half-attached Events connection while `events/list` is still in flight;
|
|
8
|
+
- add a regression test for the subscribe + explicit-refresh race found while integrating Artemis.
|
|
9
|
+
|
|
10
|
+
## [0.7.0] - 2026-10-04
|
|
11
|
+
|
|
12
|
+
Embedded-host integration release.
|
|
13
|
+
|
|
14
|
+
### Runtime-neutral embedded host kit
|
|
15
|
+
|
|
16
|
+
- add `mcp-event-intelligence/embedded` as the high-level in-process integration surface;
|
|
17
|
+
- add `createEmbeddedEventIntelligence()` to compose host-owned MCP connections, lifecycle, activation delivery and optional portable agent tools;
|
|
18
|
+
- add `createActivationDispatcher()` for runtime-neutral target resolution, host-side receipt/idempotency checks and activation delivery;
|
|
19
|
+
- add `createEventIntelligenceAgentTools()` with portable tool descriptors independent of OpenAI, Anthropic, MCP tool objects, Muffin, Artemis or any other runtime;
|
|
20
|
+
- make continuation target `kind` host-defined rather than constrained to Event Intelligence's historical task vocabulary;
|
|
21
|
+
- expose runtime-neutral `EventActivation`, `EventEvidence` and `ContinuationTarget` type aliases.
|
|
22
|
+
|
|
23
|
+
### Host ownership boundaries
|
|
24
|
+
|
|
25
|
+
- Event Intelligence remains embedded: it does not become a separate MCP server or own agent-runtime credentials;
|
|
26
|
+
- MCP transports, OAuth/API credentials and connection lifecycle remain host-owned;
|
|
27
|
+
- authorization, tenant policy and continuation semantics remain host-owned;
|
|
28
|
+
- EI persists and evaluates future conditions, then returns the opaque continuation target and activation evidence to the host.
|
|
29
|
+
|
|
30
|
+
### Packaging and verification
|
|
31
|
+
|
|
32
|
+
- build `dist/` during git-based installs through `prepare`, so pinned GitHub revisions are usable by embedded hosts;
|
|
33
|
+
- add generic host-kit tests with a third-party runtime-shaped target to guard against Muffin/Artemis coupling;
|
|
34
|
+
- validate the packed npm surface including the new `./embedded` export.
|
|
35
|
+
|
|
3
36
|
## [0.6.1] - 2026-09-30
|
|
4
37
|
|
|
5
38
|
Patch release for post-merge v0.6 review findings.
|
|
@@ -363,4 +396,4 @@ Initial public reference release.
|
|
|
363
396
|
- JSONL persistence is single-writer and reference-grade;
|
|
364
397
|
- no multi-replica / HA storage backend is included;
|
|
365
398
|
- the v0.1 MCP control plane is stdio-only; a Streamable HTTP control-plane transport is not included;
|
|
366
|
-
- Stateful Facts / current-state materialization is intentionally deferred.
|
|
399
|
+
- Stateful Facts / current-state materialization is intentionally deferred.
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://github.com/sarooo17/event-intelligence/actions/workflows/ci.yml)
|
|
6
6
|
[](https://www.npmjs.com/package/mcp-event-intelligence)
|
|
7
|
-
[](https://registry.modelcontextprotocol.io/?q=io.github.sarooo17%2Fevent-intelligence)
|
|
8
8
|
[](LICENSE)
|
|
9
9
|
|
|
10
10
|
MCP Event Intelligence is an experimental event runtime for agents that need to react to **future conditions over multiple event sources** without keeping an LLM or agent loop alive.
|
|
@@ -31,6 +31,56 @@ npm install mcp-event-intelligence
|
|
|
31
31
|
|
|
32
32
|
Published package: [npm](https://www.npmjs.com/package/mcp-event-intelligence) · [Official MCP Registry](https://registry.modelcontextprotocol.io/?q=io.github.sarooo17%2Fevent-intelligence)
|
|
33
33
|
|
|
34
|
+
For most runtimes, start with the runtime-neutral embedded host kit:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
import {
|
|
38
|
+
createEmbeddedEventIntelligence,
|
|
39
|
+
} from 'mcp-event-intelligence/embedded';
|
|
40
|
+
|
|
41
|
+
const ei = await createEmbeddedEventIntelligence({
|
|
42
|
+
dataDir: './data/event-intelligence',
|
|
43
|
+
|
|
44
|
+
// The host keeps ownership of MCP transports, auth and connection lifecycle.
|
|
45
|
+
mcp: {
|
|
46
|
+
listConnections: () => runtime.mcp.connections(),
|
|
47
|
+
subscribe: (refresh) => runtime.mcp.onConnectionsChanged(refresh),
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
// EI produces an activation; the host decides how its own work resumes.
|
|
51
|
+
activation: {
|
|
52
|
+
resolveTarget: (target) => runtime.resolveContinuation(target),
|
|
53
|
+
hasReceipt: (receiptId) => runtime.hasWakeReceipt(receiptId),
|
|
54
|
+
deliver: ({ activation, target, receiptId }) =>
|
|
55
|
+
runtime.resumeFromEvent({ activation, target, receiptId }),
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The continuation target is intentionally opaque to EI apart from
|
|
61
|
+
`{ runtime, kind, id }`. A host may map it to a Turn, Execution, thread,
|
|
62
|
+
graph checkpoint, workflow, Case, or any other durable continuation primitive.
|
|
63
|
+
The package contains no `runtime === "muffin"` / `"artemis"` branches.
|
|
64
|
+
|
|
65
|
+
Portable agent-facing trigger tools are optional:
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
const tools = ei.createAgentTools({
|
|
69
|
+
resolveContext: (ctx) => ({
|
|
70
|
+
target: runtime.currentContinuation(ctx),
|
|
71
|
+
actor: runtime.currentActor(ctx),
|
|
72
|
+
owner: runtime.currentOwner(ctx),
|
|
73
|
+
}),
|
|
74
|
+
authorize: (request) => runtime.policy.authorize(request),
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Each tool is a neutral `{ name, description, inputSchema, execute }`
|
|
79
|
+
descriptor. Adapt that descriptor to OpenAI, Anthropic, an internal capability
|
|
80
|
+
graph, or any other host SDK without changing EI core.
|
|
81
|
+
|
|
82
|
+
The lower-level host API remains available when a runtime needs direct control:
|
|
83
|
+
|
|
34
84
|
Pass the harness-level MCP registry once — not every MCP one by one:
|
|
35
85
|
|
|
36
86
|
```js
|
|
@@ -275,7 +325,7 @@ timezone normalization and deterministic occurrence IDs. The local factory in
|
|
|
275
325
|
this package should therefore be read as a typed convenience API, not as the
|
|
276
326
|
production ERP connector itself.
|
|
277
327
|
|
|
278
|
-
## What v0.
|
|
328
|
+
## What v0.7 implements
|
|
279
329
|
|
|
280
330
|
### Host-owned event sources
|
|
281
331
|
|
|
@@ -558,4 +608,4 @@ Apache License 2.0. See [LICENSE](LICENSE).
|
|
|
558
608
|
|
|
559
609
|
## Disclaimer
|
|
560
610
|
|
|
561
|
-
This is an independent open-source project. It is not an official Model Context Protocol specification and is not affiliated with or endorsed by the MCP maintainers.
|
|
611
|
+
This is an independent open-source project. It is not an official Model Context Protocol specification and is not affiliated with or endorsed by the MCP maintainers.
|
|
@@ -100,3 +100,104 @@ export declare const ActivationEnvelopeSchema: z.ZodObject<{
|
|
|
100
100
|
export type ActivationEvidence = z.infer<typeof ActivationEvidenceSchema>;
|
|
101
101
|
export type ActivationEnvelope = z.infer<typeof ActivationEnvelopeSchema>;
|
|
102
102
|
export declare function parseActivationEnvelope(value: unknown): ActivationEnvelope;
|
|
103
|
+
/** Runtime-neutral public names for embedded-host integrations. */
|
|
104
|
+
export declare const EventEvidenceSchema: z.ZodObject<{
|
|
105
|
+
clauseId: z.ZodString;
|
|
106
|
+
serverId: z.ZodNullable<z.ZodString>;
|
|
107
|
+
eventId: z.ZodString;
|
|
108
|
+
eventName: z.ZodString;
|
|
109
|
+
traceId: z.ZodString;
|
|
110
|
+
occurredAt: z.ZodString;
|
|
111
|
+
receivedAt: z.ZodOptional<z.ZodString>;
|
|
112
|
+
payloadHash: z.ZodNullable<z.ZodString>;
|
|
113
|
+
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
114
|
+
}, z.core.$strict>;
|
|
115
|
+
export declare const EventActivationSchema: z.ZodObject<{
|
|
116
|
+
activationVersion: z.ZodLiteral<"2">;
|
|
117
|
+
wake: z.ZodObject<{
|
|
118
|
+
wakeId: z.ZodString;
|
|
119
|
+
status: z.ZodString;
|
|
120
|
+
runtimeReceiptId: z.ZodNullable<z.ZodString>;
|
|
121
|
+
matchedAt: z.ZodString;
|
|
122
|
+
}, z.core.$strict>;
|
|
123
|
+
target: z.ZodObject<{
|
|
124
|
+
runtime: z.ZodString;
|
|
125
|
+
kind: z.ZodString;
|
|
126
|
+
id: z.ZodString;
|
|
127
|
+
}, z.core.$strict>;
|
|
128
|
+
trigger: z.ZodObject<{
|
|
129
|
+
triggerId: z.ZodString;
|
|
130
|
+
version: z.ZodString;
|
|
131
|
+
description: z.ZodNullable<z.ZodString>;
|
|
132
|
+
pattern: z.ZodObject<{
|
|
133
|
+
version: z.ZodDefault<z.ZodLiteral<"2">>;
|
|
134
|
+
root: z.ZodType<any, unknown, z.core.$ZodTypeInternals<any, unknown>>;
|
|
135
|
+
partitionBy: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
136
|
+
key: z.ZodString;
|
|
137
|
+
fields: z.ZodArray<z.ZodObject<{
|
|
138
|
+
ref: z.ZodString;
|
|
139
|
+
path: z.ZodString;
|
|
140
|
+
}, z.core.$strict>>;
|
|
141
|
+
}, z.core.$strict>>>;
|
|
142
|
+
selection: z.ZodDefault<z.ZodObject<{
|
|
143
|
+
overlap: z.ZodDefault<z.ZodEnum<{
|
|
144
|
+
allow: "allow";
|
|
145
|
+
disallow: "disallow";
|
|
146
|
+
}>>;
|
|
147
|
+
afterMatch: z.ZodDefault<z.ZodUnion<readonly [z.ZodEnum<{
|
|
148
|
+
skipPastLast: "skipPastLast";
|
|
149
|
+
skipToNext: "skipToNext";
|
|
150
|
+
keepAll: "keepAll";
|
|
151
|
+
}>, z.ZodObject<{
|
|
152
|
+
kind: z.ZodEnum<{
|
|
153
|
+
skipToFirst: "skipToFirst";
|
|
154
|
+
skipToLast: "skipToLast";
|
|
155
|
+
}>;
|
|
156
|
+
ref: z.ZodString;
|
|
157
|
+
}, z.core.$strict>]>>;
|
|
158
|
+
maxMatchesPerEvent: z.ZodDefault<z.ZodNumber>;
|
|
159
|
+
}, z.core.$strict>>;
|
|
160
|
+
execution: z.ZodDefault<z.ZodObject<{
|
|
161
|
+
maxCandidates: z.ZodDefault<z.ZodNumber>;
|
|
162
|
+
maxSemanticEvaluations: z.ZodDefault<z.ZodNumber>;
|
|
163
|
+
maxBufferedEvents: z.ZodDefault<z.ZodNumber>;
|
|
164
|
+
}, z.core.$strict>>;
|
|
165
|
+
}, z.core.$strict>;
|
|
166
|
+
lifecycle: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
167
|
+
}, z.core.$strict>;
|
|
168
|
+
continuation: z.ZodNullable<z.ZodObject<{
|
|
169
|
+
instruction: z.ZodString;
|
|
170
|
+
contextPolicy: z.ZodDefault<z.ZodObject<{
|
|
171
|
+
evidence: z.ZodDefault<z.ZodEnum<{
|
|
172
|
+
matched_events: "matched_events";
|
|
173
|
+
refs_only: "refs_only";
|
|
174
|
+
}>>;
|
|
175
|
+
maxEvents: z.ZodDefault<z.ZodNumber>;
|
|
176
|
+
includeData: z.ZodDefault<z.ZodBoolean>;
|
|
177
|
+
}, z.core.$strict>>;
|
|
178
|
+
}, z.core.$strict>>;
|
|
179
|
+
match: z.ZodObject<{
|
|
180
|
+
matchId: z.ZodString;
|
|
181
|
+
status: z.ZodString;
|
|
182
|
+
partitionKey: z.ZodNullable<z.ZodString>;
|
|
183
|
+
openedAt: z.ZodString;
|
|
184
|
+
updatedAt: z.ZodString;
|
|
185
|
+
}, z.core.$strict>;
|
|
186
|
+
evidence: z.ZodArray<z.ZodObject<{
|
|
187
|
+
clauseId: z.ZodString;
|
|
188
|
+
serverId: z.ZodNullable<z.ZodString>;
|
|
189
|
+
eventId: z.ZodString;
|
|
190
|
+
eventName: z.ZodString;
|
|
191
|
+
traceId: z.ZodString;
|
|
192
|
+
occurredAt: z.ZodString;
|
|
193
|
+
receivedAt: z.ZodOptional<z.ZodString>;
|
|
194
|
+
payloadHash: z.ZodNullable<z.ZodString>;
|
|
195
|
+
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
196
|
+
}, z.core.$strict>>;
|
|
197
|
+
trust: z.ZodObject<{
|
|
198
|
+
continuation: z.ZodLiteral<"configured_trigger_instruction">;
|
|
199
|
+
evidence: z.ZodLiteral<"untrusted_external_signal">;
|
|
200
|
+
}, z.core.$strict>;
|
|
201
|
+
}, z.core.$strict>;
|
|
202
|
+
export type EventEvidence = ActivationEvidence;
|
|
203
|
+
export type EventActivation = ActivationEnvelope;
|
|
@@ -51,3 +51,6 @@ export const ActivationEnvelopeSchema = z.object({
|
|
|
51
51
|
export function parseActivationEnvelope(value) {
|
|
52
52
|
return ActivationEnvelopeSchema.parse(value);
|
|
53
53
|
}
|
|
54
|
+
/** Runtime-neutral public names for embedded-host integrations. */
|
|
55
|
+
export const EventEvidenceSchema = ActivationEvidenceSchema;
|
|
56
|
+
export const EventActivationSchema = ActivationEnvelopeSchema;
|
|
@@ -15,5 +15,5 @@ export { COMPOSITE_TRIGGER_PROTOCOL_VERSION, COMPOSITE_TRIGGER_SCHEMA_VERSION, S
|
|
|
15
15
|
export type { StructuredPredicate, TriggerClause, ContinuationContextPolicy, ContinuationContract, EventTimePolicy, DerivedEventDefinition, DerivedEventRecord, CompositeTriggerDefinition, CorrelatableEvent, TriggerSourceEvent, PatternMatchState, TriggerMatchRecord, PatternSemanticDecision, } from './triggerSchemas.js';
|
|
16
16
|
export { TriggerPlanEventSchema, TriggerPlanInputSchema, parseTriggerPlanInput, } from './triggerPlanSchemas.js';
|
|
17
17
|
export type { TriggerPlanEvent, TriggerPlanInput, } from './triggerPlanSchemas.js';
|
|
18
|
-
export { ActivationEvidenceSchema, ActivationEnvelopeSchema, parseActivationEnvelope, } from './activationSchemas.js';
|
|
19
|
-
export type { ActivationEvidence, ActivationEnvelope, } from './activationSchemas.js';
|
|
18
|
+
export { ActivationEvidenceSchema, ActivationEnvelopeSchema, EventEvidenceSchema, EventActivationSchema, parseActivationEnvelope, } from './activationSchemas.js';
|
|
19
|
+
export type { ActivationEvidence, ActivationEnvelope, EventEvidence, EventActivation, } from './activationSchemas.js';
|
|
@@ -8,4 +8,4 @@ export { canonicalJson, sha256Hex, } from './canonical.js';
|
|
|
8
8
|
export { AuditChain, } from './audit.js';
|
|
9
9
|
export { COMPOSITE_TRIGGER_PROTOCOL_VERSION, COMPOSITE_TRIGGER_SCHEMA_VERSION, StructuredPredicateSchema, TriggerClauseSchema, ContinuationContextPolicySchema, ContinuationContractSchema, EventTimePolicySchema, DerivedEventProjectionSchema, DerivedEventDefinitionSchema, DerivedEventEvidenceRefSchema, DerivedEventRecordSchema, CompositeTriggerDefinitionSchema, CorrelatableEventSchema, TriggerSourceEventSchema, PatternSemanticDecisionSchema, TriggerMatchStatusSchema, PatternMatchStateSchema, TriggerMatchRecordSchema, parseCompositeTriggerDefinition, parseCorrelatableEvent, parseTriggerMatchRecord, parseDerivedEventRecord, } from './triggerSchemas.js';
|
|
10
10
|
export { TriggerPlanEventSchema, TriggerPlanInputSchema, parseTriggerPlanInput, } from './triggerPlanSchemas.js';
|
|
11
|
-
export { ActivationEvidenceSchema, ActivationEnvelopeSchema, parseActivationEnvelope, } from './activationSchemas.js';
|
|
11
|
+
export { ActivationEvidenceSchema, ActivationEnvelopeSchema, EventEvidenceSchema, EventActivationSchema, parseActivationEnvelope, } from './activationSchemas.js';
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const RuntimeTargetSchema: z.ZodObject<{
|
|
3
3
|
runtime: z.ZodString;
|
|
4
|
-
kind: z.
|
|
5
|
-
goal: "goal";
|
|
6
|
-
session: "session";
|
|
7
|
-
conversation: "conversation";
|
|
8
|
-
task: "task";
|
|
9
|
-
spawn_template: "spawn_template";
|
|
10
|
-
}>;
|
|
4
|
+
kind: z.ZodString;
|
|
11
5
|
id: z.ZodString;
|
|
12
6
|
}, z.core.$strip>;
|
|
13
7
|
export declare const WakeRecordSchema: z.ZodObject<{
|
|
@@ -19,13 +13,7 @@ export declare const WakeRecordSchema: z.ZodObject<{
|
|
|
19
13
|
createdAt: z.ZodString;
|
|
20
14
|
target: z.ZodObject<{
|
|
21
15
|
runtime: z.ZodString;
|
|
22
|
-
kind: z.
|
|
23
|
-
goal: "goal";
|
|
24
|
-
session: "session";
|
|
25
|
-
conversation: "conversation";
|
|
26
|
-
task: "task";
|
|
27
|
-
spawn_template: "spawn_template";
|
|
28
|
-
}>;
|
|
16
|
+
kind: z.ZodString;
|
|
29
17
|
id: z.ZodString;
|
|
30
18
|
}, z.core.$strip>;
|
|
31
19
|
status: z.ZodEnum<{
|
|
@@ -3,7 +3,9 @@ const Id = z.string().min(1).max(200);
|
|
|
3
3
|
const Timestamp = z.string().datetime({ offset: true });
|
|
4
4
|
export const RuntimeTargetSchema = z.object({
|
|
5
5
|
runtime: z.string().min(1),
|
|
6
|
-
kind
|
|
6
|
+
// Host-owned continuation kind. Event Intelligence persists and returns
|
|
7
|
+
// this opaque discriminator; it must not encode one runtime's task model.
|
|
8
|
+
kind: z.string().min(1).max(100),
|
|
7
9
|
id: Id,
|
|
8
10
|
});
|
|
9
11
|
export const WakeRecordSchema = z.object({
|
|
@@ -210,13 +210,7 @@ export declare const TriggerPlanInputSchema: z.ZodObject<{
|
|
|
210
210
|
conditionOnly: z.ZodDefault<z.ZodBoolean>;
|
|
211
211
|
target: z.ZodOptional<z.ZodObject<{
|
|
212
212
|
runtime: z.ZodString;
|
|
213
|
-
kind: z.
|
|
214
|
-
goal: "goal";
|
|
215
|
-
session: "session";
|
|
216
|
-
conversation: "conversation";
|
|
217
|
-
task: "task";
|
|
218
|
-
spawn_template: "spawn_template";
|
|
219
|
-
}>;
|
|
213
|
+
kind: z.ZodString;
|
|
220
214
|
id: z.ZodString;
|
|
221
215
|
}, z.core.$strip>>;
|
|
222
216
|
continuation: z.ZodOptional<z.ZodObject<{
|
|
@@ -379,13 +379,7 @@ export declare const CompositeTriggerDefinitionSchema: z.ZodObject<{
|
|
|
379
379
|
withinMs: z.ZodNumber;
|
|
380
380
|
target: z.ZodOptional<z.ZodObject<{
|
|
381
381
|
runtime: z.ZodString;
|
|
382
|
-
kind: z.
|
|
383
|
-
goal: "goal";
|
|
384
|
-
session: "session";
|
|
385
|
-
conversation: "conversation";
|
|
386
|
-
task: "task";
|
|
387
|
-
spawn_template: "spawn_template";
|
|
388
|
-
}>;
|
|
382
|
+
kind: z.ZodString;
|
|
389
383
|
id: z.ZodString;
|
|
390
384
|
}, z.core.$strip>>;
|
|
391
385
|
derivedEvent: z.ZodOptional<z.ZodObject<{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-event-intelligence",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "MCP-native complex event processing for durable agent workflows: event-time patterns, semantic predicates, derived events, and targeted wakeups.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
"./provider/erpnext": {
|
|
23
23
|
"types": "./dist/src/mcpEvents/erpnextProvider.d.ts",
|
|
24
24
|
"import": "./dist/src/mcpEvents/erpnextProvider.js"
|
|
25
|
+
},
|
|
26
|
+
"./embedded": {
|
|
27
|
+
"types": "./scripts/embedded-host-kit.d.mts",
|
|
28
|
+
"import": "./scripts/embedded-host-kit.mjs"
|
|
25
29
|
}
|
|
26
30
|
},
|
|
27
31
|
"bin": {
|
|
@@ -41,7 +45,9 @@
|
|
|
41
45
|
"scripts/mcp-stdio-server.mjs",
|
|
42
46
|
"scripts/host-integration.mjs",
|
|
43
47
|
"scripts/host-integration.d.mts",
|
|
44
|
-
"scripts/run-tests.mjs"
|
|
48
|
+
"scripts/run-tests.mjs",
|
|
49
|
+
"scripts/embedded-host-kit.mjs",
|
|
50
|
+
"scripts/embedded-host-kit.d.mts"
|
|
45
51
|
],
|
|
46
52
|
"scripts": {
|
|
47
53
|
"build": "tsc -p tsconfig.json",
|
|
@@ -57,7 +63,8 @@
|
|
|
57
63
|
"pack:mcp-smoke": "node scripts/package-mcp-smoke.mjs",
|
|
58
64
|
"conformance:pattern-v2": "npm run build && node scripts/evidence/pattern-v2-conformance.mjs",
|
|
59
65
|
"bench:pattern-v2": "npm run build && node scripts/evidence/pattern-v2-benchmark.mjs --profile quick",
|
|
60
|
-
"evidence:pattern-v2": "npm run build && node scripts/evidence/pattern-v2-conformance.mjs && node scripts/evidence/pattern-v2-benchmark.mjs --profile quick"
|
|
66
|
+
"evidence:pattern-v2": "npm run build && node scripts/evidence/pattern-v2-conformance.mjs && node scripts/evidence/pattern-v2-benchmark.mjs --profile quick",
|
|
67
|
+
"prepare": "npm run build"
|
|
61
68
|
},
|
|
62
69
|
"keywords": [
|
|
63
70
|
"mcp",
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ActivationEnvelope,
|
|
3
|
+
RuntimeTarget,
|
|
4
|
+
} from '../dist/src/intelligenceProtocol/index.js';
|
|
5
|
+
|
|
6
|
+
export type {
|
|
7
|
+
ActivationEnvelope as EventActivation,
|
|
8
|
+
RuntimeTarget as ContinuationTarget,
|
|
9
|
+
};
|
|
10
|
+
import type {
|
|
11
|
+
EventIntelligenceHost,
|
|
12
|
+
EventIntelligenceHostOptions,
|
|
13
|
+
HostMcpConnectionOptions,
|
|
14
|
+
HostMcpRegistry,
|
|
15
|
+
HostWakeHandler,
|
|
16
|
+
HostWakeReceipt,
|
|
17
|
+
} from './host-integration.d.mts';
|
|
18
|
+
|
|
19
|
+
export interface EmbeddedHostIdentity {
|
|
20
|
+
type: string;
|
|
21
|
+
principal_id: string;
|
|
22
|
+
tenant_id?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface EmbeddedToolContext {
|
|
26
|
+
scopeId?: string;
|
|
27
|
+
target: RuntimeTarget;
|
|
28
|
+
actor: EmbeddedHostIdentity;
|
|
29
|
+
owner: EmbeddedHostIdentity;
|
|
30
|
+
confirmationId?: string;
|
|
31
|
+
[key: string]: unknown;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface PortableToolResult {
|
|
35
|
+
ok: boolean;
|
|
36
|
+
data?: any;
|
|
37
|
+
error?: {
|
|
38
|
+
code: string;
|
|
39
|
+
message: string;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface PortableAgentTool<RuntimeContext = unknown> {
|
|
44
|
+
name: string;
|
|
45
|
+
description: string;
|
|
46
|
+
inputSchema: Record<string, unknown>;
|
|
47
|
+
execute(
|
|
48
|
+
args: unknown,
|
|
49
|
+
runtimeContext: RuntimeContext,
|
|
50
|
+
): Promise<PortableToolResult>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface AuthorizationDecision {
|
|
54
|
+
allowed: boolean;
|
|
55
|
+
code?: string;
|
|
56
|
+
message?: string;
|
|
57
|
+
actor?: EmbeddedHostIdentity;
|
|
58
|
+
owner?: EmbeddedHostIdentity;
|
|
59
|
+
confirmationId?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface ActivationDeliveryInput<Target = unknown> {
|
|
63
|
+
packet: Record<string, unknown>;
|
|
64
|
+
activation: ActivationEnvelope;
|
|
65
|
+
target: Target;
|
|
66
|
+
receiptId: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ActivationDispatcherOptions<Target = RuntimeTarget> {
|
|
70
|
+
resolveTarget?: (
|
|
71
|
+
target: RuntimeTarget,
|
|
72
|
+
activation: ActivationEnvelope,
|
|
73
|
+
) => Target | null | Promise<Target | null>;
|
|
74
|
+
hasReceipt?: (
|
|
75
|
+
receiptId: string,
|
|
76
|
+
activation: ActivationEnvelope,
|
|
77
|
+
) => boolean | Promise<boolean>;
|
|
78
|
+
receiptId?: (input: {
|
|
79
|
+
packet: Record<string, unknown>;
|
|
80
|
+
activation: ActivationEnvelope;
|
|
81
|
+
}) => string | Promise<string>;
|
|
82
|
+
deliver(
|
|
83
|
+
input: ActivationDeliveryInput<Target>,
|
|
84
|
+
): HostWakeReceipt | string | void | Promise<HostWakeReceipt | string | void>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface EventIntelligenceAgentToolsOptions<RuntimeContext = unknown> {
|
|
88
|
+
host: EventIntelligenceHost;
|
|
89
|
+
resolveContext(
|
|
90
|
+
runtimeContext: RuntimeContext,
|
|
91
|
+
request: {
|
|
92
|
+
action: 'event.sources.list' | 'trigger.create';
|
|
93
|
+
input?: unknown;
|
|
94
|
+
},
|
|
95
|
+
): EmbeddedToolContext | Promise<EmbeddedToolContext>;
|
|
96
|
+
authorize(input: {
|
|
97
|
+
action: 'trigger.create';
|
|
98
|
+
runtimeContext: RuntimeContext;
|
|
99
|
+
context: EmbeddedToolContext;
|
|
100
|
+
input: unknown;
|
|
101
|
+
plan: any;
|
|
102
|
+
}):
|
|
103
|
+
| boolean
|
|
104
|
+
| AuthorizationDecision
|
|
105
|
+
| Promise<boolean | AuthorizationDecision>;
|
|
106
|
+
names?: {
|
|
107
|
+
sources?: string;
|
|
108
|
+
create?: string;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface EmbeddedEventIntelligenceOptions<RuntimeContext = unknown>
|
|
113
|
+
extends Omit<EventIntelligenceHostOptions, 'wake' | 'mcpRegistry'> {
|
|
114
|
+
mcpRegistry?: HostMcpRegistry;
|
|
115
|
+
mcp?: {
|
|
116
|
+
listConnections(): Iterable<HostMcpConnectionOptions> | Promise<Iterable<HostMcpConnectionOptions>>;
|
|
117
|
+
subscribe?: (listener: () => void) => void | (() => void);
|
|
118
|
+
};
|
|
119
|
+
activation?: ActivationDispatcherOptions<any>;
|
|
120
|
+
wake?: HostWakeHandler;
|
|
121
|
+
agentTools?: Omit<EventIntelligenceAgentToolsOptions<RuntimeContext>, 'host'>;
|
|
122
|
+
/** Test/advanced injection; normal callers should omit it. */
|
|
123
|
+
createHost?: (options: EventIntelligenceHostOptions) => Promise<EventIntelligenceHost>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface EmbeddedEventIntelligence<RuntimeContext = unknown> {
|
|
127
|
+
readonly host: EventIntelligenceHost;
|
|
128
|
+
readonly runtime: any;
|
|
129
|
+
readonly tools: PortableAgentTool<RuntimeContext>[];
|
|
130
|
+
createAgentTools<Context = RuntimeContext>(
|
|
131
|
+
options: Omit<EventIntelligenceAgentToolsOptions<Context>, 'host'>,
|
|
132
|
+
): PortableAgentTool<Context>[];
|
|
133
|
+
refresh(): Promise<any[]>;
|
|
134
|
+
status(): Promise<any[]> | any[];
|
|
135
|
+
scope(scopeId?: string): ReturnType<EventIntelligenceHost['scope']>;
|
|
136
|
+
close(): Promise<void>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function createContinuationTarget(input: {
|
|
140
|
+
runtime: string;
|
|
141
|
+
kind: string;
|
|
142
|
+
id: string;
|
|
143
|
+
}): RuntimeTarget;
|
|
144
|
+
|
|
145
|
+
export function createActivationDispatcher<Target = RuntimeTarget>(
|
|
146
|
+
options: ActivationDispatcherOptions<Target>,
|
|
147
|
+
): HostWakeHandler;
|
|
148
|
+
|
|
149
|
+
export function createEventIntelligenceAgentTools<RuntimeContext = unknown>(
|
|
150
|
+
options: EventIntelligenceAgentToolsOptions<RuntimeContext>,
|
|
151
|
+
): PortableAgentTool<RuntimeContext>[];
|
|
152
|
+
|
|
153
|
+
export function createEmbeddedEventIntelligence<RuntimeContext = unknown>(
|
|
154
|
+
options?: EmbeddedEventIntelligenceOptions<RuntimeContext>,
|
|
155
|
+
): Promise<EmbeddedEventIntelligence<RuntimeContext>>;
|
|
156
|
+
|
|
157
|
+
export const PORTABLE_EVENT_INTELLIGENCE_TOOL_NAMES: Readonly<{
|
|
158
|
+
sources: 'event_sources_list';
|
|
159
|
+
create: 'trigger_create';
|
|
160
|
+
}>;
|
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import {
|
|
3
|
+
RuntimeTargetSchema,
|
|
4
|
+
parseActivationEnvelope,
|
|
5
|
+
} from '../dist/src/intelligenceProtocol/index.js';
|
|
6
|
+
import {
|
|
7
|
+
createEventIntelligenceHost,
|
|
8
|
+
createMcpRegistryAdapter,
|
|
9
|
+
} from './host-integration.mjs';
|
|
10
|
+
|
|
11
|
+
const DEFAULT_TOOL_NAMES = Object.freeze({
|
|
12
|
+
sources: 'event_sources_list',
|
|
13
|
+
create: 'trigger_create',
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const TriggerClauseInput = z.object({
|
|
17
|
+
id: z.string().min(1).max(200).optional(),
|
|
18
|
+
event: z.string().min(1).max(200),
|
|
19
|
+
serverId: z.string().min(1).max(200).optional(),
|
|
20
|
+
arguments: z.record(z.string(), z.unknown()).optional(),
|
|
21
|
+
where: z.array(z.record(z.string(), z.unknown())).max(32).optional(),
|
|
22
|
+
}).strict();
|
|
23
|
+
|
|
24
|
+
const TriggerCreateInput = z.object({
|
|
25
|
+
trigger_id: z.string().min(1).max(200).optional(),
|
|
26
|
+
version: z.string().min(1).max(100).optional(),
|
|
27
|
+
description: z.string().max(500).optional(),
|
|
28
|
+
events: z.array(TriggerClauseInput).min(1).max(32),
|
|
29
|
+
pattern: z.record(z.string(), z.unknown()).optional(),
|
|
30
|
+
within_ms: z.number().int().positive().max(30 * 24 * 60 * 60 * 1000)
|
|
31
|
+
.optional(),
|
|
32
|
+
event_time: z.object({
|
|
33
|
+
allowed_lateness_ms: z.number().int().nonnegative()
|
|
34
|
+
.max(30 * 24 * 60 * 60 * 1000),
|
|
35
|
+
}).strict().optional(),
|
|
36
|
+
instruction: z.string().min(1).max(4000),
|
|
37
|
+
one_shot: z.boolean().optional(),
|
|
38
|
+
max_firings: z.number().int().min(1).optional(),
|
|
39
|
+
cooldown_ms: z.number().int().nonnegative().optional(),
|
|
40
|
+
expires_at: z.string().datetime({ offset: true }).optional(),
|
|
41
|
+
lease_until: z.string().datetime({ offset: true }).optional(),
|
|
42
|
+
complete_on_goal: z.boolean().optional(),
|
|
43
|
+
}).strict();
|
|
44
|
+
|
|
45
|
+
const SOURCES_INPUT_SCHEMA = Object.freeze({
|
|
46
|
+
type: 'object',
|
|
47
|
+
additionalProperties: false,
|
|
48
|
+
properties: {},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const CREATE_INPUT_SCHEMA = Object.freeze({
|
|
52
|
+
type: 'object',
|
|
53
|
+
additionalProperties: false,
|
|
54
|
+
required: ['events', 'instruction'],
|
|
55
|
+
properties: {
|
|
56
|
+
trigger_id: { type: 'string', minLength: 1, maxLength: 200 },
|
|
57
|
+
version: { type: 'string', minLength: 1, maxLength: 100 },
|
|
58
|
+
description: { type: 'string', maxLength: 500 },
|
|
59
|
+
events: {
|
|
60
|
+
type: 'array',
|
|
61
|
+
minItems: 1,
|
|
62
|
+
maxItems: 32,
|
|
63
|
+
items: {
|
|
64
|
+
type: 'object',
|
|
65
|
+
additionalProperties: false,
|
|
66
|
+
required: ['event'],
|
|
67
|
+
properties: {
|
|
68
|
+
id: { type: 'string', minLength: 1, maxLength: 200 },
|
|
69
|
+
event: { type: 'string', minLength: 1, maxLength: 200 },
|
|
70
|
+
serverId: { type: 'string', minLength: 1, maxLength: 200 },
|
|
71
|
+
arguments: { type: 'object', additionalProperties: true },
|
|
72
|
+
where: {
|
|
73
|
+
type: 'array',
|
|
74
|
+
maxItems: 32,
|
|
75
|
+
items: { type: 'object', additionalProperties: true },
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
pattern: { type: 'object', additionalProperties: true },
|
|
81
|
+
within_ms: {
|
|
82
|
+
type: 'integer',
|
|
83
|
+
minimum: 1,
|
|
84
|
+
maximum: 30 * 24 * 60 * 60 * 1000,
|
|
85
|
+
},
|
|
86
|
+
event_time: {
|
|
87
|
+
type: 'object',
|
|
88
|
+
additionalProperties: false,
|
|
89
|
+
required: ['allowed_lateness_ms'],
|
|
90
|
+
properties: {
|
|
91
|
+
allowed_lateness_ms: {
|
|
92
|
+
type: 'integer',
|
|
93
|
+
minimum: 0,
|
|
94
|
+
maximum: 30 * 24 * 60 * 60 * 1000,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
instruction: { type: 'string', minLength: 1, maxLength: 4000 },
|
|
99
|
+
one_shot: { type: 'boolean' },
|
|
100
|
+
max_firings: { type: 'integer', minimum: 1 },
|
|
101
|
+
cooldown_ms: { type: 'integer', minimum: 0 },
|
|
102
|
+
expires_at: { type: 'string' },
|
|
103
|
+
lease_until: { type: 'string' },
|
|
104
|
+
complete_on_goal: { type: 'boolean' },
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
function errorCode(error, fallback) {
|
|
109
|
+
return String(error?.code || fallback);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function fail(error, fallbackCode = 'EVENT_INTELLIGENCE_TOOL_FAILED') {
|
|
113
|
+
return {
|
|
114
|
+
ok: false,
|
|
115
|
+
error: {
|
|
116
|
+
code: errorCode(error, fallbackCode),
|
|
117
|
+
message: error instanceof Error ? error.message : String(error),
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function normalizeIdentity(input, label) {
|
|
123
|
+
if (!input || typeof input !== 'object') {
|
|
124
|
+
throw new Error(`${label} is required`);
|
|
125
|
+
}
|
|
126
|
+
const type = String(input.type || '').trim();
|
|
127
|
+
const principalId = String(
|
|
128
|
+
input.principal_id ?? input.principalId ?? '',
|
|
129
|
+
).trim();
|
|
130
|
+
const tenantId = String(
|
|
131
|
+
input.tenant_id ?? input.tenantId ?? '',
|
|
132
|
+
).trim();
|
|
133
|
+
if (!type || !principalId) {
|
|
134
|
+
throw new Error(`${label} requires type and principal_id`);
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
type,
|
|
138
|
+
principal_id: principalId,
|
|
139
|
+
...(tenantId ? { tenant_id: tenantId } : {}),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function normalizeAuthorization(decision) {
|
|
144
|
+
if (decision === true) return { allowed: true };
|
|
145
|
+
if (decision === false || decision == null) return { allowed: false };
|
|
146
|
+
if (typeof decision !== 'object') {
|
|
147
|
+
throw new Error('authorize() must return boolean or an authorization decision');
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
...decision,
|
|
151
|
+
allowed: decision.allowed === true,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function normalizedReceipt(result, fallbackId) {
|
|
156
|
+
if (typeof result === 'string' && result.trim()) {
|
|
157
|
+
return { runtimeReceiptId: result };
|
|
158
|
+
}
|
|
159
|
+
if (
|
|
160
|
+
result &&
|
|
161
|
+
typeof result === 'object' &&
|
|
162
|
+
typeof result.runtimeReceiptId === 'string' &&
|
|
163
|
+
result.runtimeReceiptId.trim()
|
|
164
|
+
) {
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
if (result === undefined && fallbackId) {
|
|
168
|
+
return { runtimeReceiptId: fallbackId };
|
|
169
|
+
}
|
|
170
|
+
throw new Error('Activation delivery must return runtimeReceiptId');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function wakeIdFromPacket(packet) {
|
|
174
|
+
if (!packet || typeof packet !== 'object') return null;
|
|
175
|
+
const value = packet.wake_id ?? packet.wakeId;
|
|
176
|
+
return typeof value === 'string' && value.trim() ? value : null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* A runtime-neutral continuation target. EI persists and returns this value
|
|
181
|
+
* without assigning semantics to runtime/kind/id.
|
|
182
|
+
*/
|
|
183
|
+
export function createContinuationTarget(input) {
|
|
184
|
+
return RuntimeTargetSchema.parse(input);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Runtime-neutral wake boundary.
|
|
189
|
+
*
|
|
190
|
+
* EI owns wake retries; the host owns target resolution and the side effect
|
|
191
|
+
* that resumes work. Optional receipt hooks close the host-side crash window
|
|
192
|
+
* without teaching EI what a Turn, Execution, thread, graph or Case is.
|
|
193
|
+
*/
|
|
194
|
+
export function createActivationDispatcher({
|
|
195
|
+
resolveTarget,
|
|
196
|
+
hasReceipt,
|
|
197
|
+
receiptId,
|
|
198
|
+
deliver,
|
|
199
|
+
} = {}) {
|
|
200
|
+
if (resolveTarget !== undefined && typeof resolveTarget !== 'function') {
|
|
201
|
+
throw new Error('resolveTarget must be a function');
|
|
202
|
+
}
|
|
203
|
+
if (hasReceipt !== undefined && typeof hasReceipt !== 'function') {
|
|
204
|
+
throw new Error('hasReceipt must be a function');
|
|
205
|
+
}
|
|
206
|
+
if (receiptId !== undefined && typeof receiptId !== 'function') {
|
|
207
|
+
throw new Error('receiptId must be a function');
|
|
208
|
+
}
|
|
209
|
+
if (typeof deliver !== 'function') {
|
|
210
|
+
throw new Error('Activation dispatcher requires deliver()');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return async (packet = {}, activationInput) => {
|
|
214
|
+
const activation = parseActivationEnvelope(activationInput);
|
|
215
|
+
const packetWakeId = wakeIdFromPacket(packet);
|
|
216
|
+
if (packetWakeId && packetWakeId !== activation.wake.wakeId) {
|
|
217
|
+
const error = new Error(
|
|
218
|
+
`Wake id mismatch: packet ${packetWakeId} != activation ${activation.wake.wakeId}`,
|
|
219
|
+
);
|
|
220
|
+
error.code = 'EVENT_ACTIVATION_WAKE_ID_MISMATCH';
|
|
221
|
+
throw error;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const candidateReceiptId = String(
|
|
225
|
+
await (receiptId
|
|
226
|
+
? receiptId({ packet, activation })
|
|
227
|
+
: activation.wake.wakeId),
|
|
228
|
+
).trim();
|
|
229
|
+
if (!candidateReceiptId) {
|
|
230
|
+
const error = new Error('Activation receipt id must be non-empty');
|
|
231
|
+
error.code = 'EVENT_ACTIVATION_RECEIPT_ID_REQUIRED';
|
|
232
|
+
throw error;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (hasReceipt && await hasReceipt(candidateReceiptId, activation)) {
|
|
236
|
+
return {
|
|
237
|
+
runtimeReceiptId: candidateReceiptId,
|
|
238
|
+
duplicate: true,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const target = resolveTarget
|
|
243
|
+
? await resolveTarget(activation.target, activation)
|
|
244
|
+
: activation.target;
|
|
245
|
+
if (target == null) {
|
|
246
|
+
const error = new Error(
|
|
247
|
+
`Continuation target unavailable: ${activation.target.runtime}/${activation.target.kind}/${activation.target.id}`,
|
|
248
|
+
);
|
|
249
|
+
error.code = 'EVENT_ACTIVATION_TARGET_UNAVAILABLE';
|
|
250
|
+
throw error;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
return normalizedReceipt(
|
|
255
|
+
await deliver({
|
|
256
|
+
packet,
|
|
257
|
+
activation,
|
|
258
|
+
target,
|
|
259
|
+
receiptId: candidateReceiptId,
|
|
260
|
+
}),
|
|
261
|
+
candidateReceiptId,
|
|
262
|
+
);
|
|
263
|
+
} catch (error) {
|
|
264
|
+
if (hasReceipt && await hasReceipt(candidateReceiptId, activation)) {
|
|
265
|
+
return {
|
|
266
|
+
runtimeReceiptId: candidateReceiptId,
|
|
267
|
+
duplicate: true,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
throw error;
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async function scopedHostFor(host, resolvedContext) {
|
|
276
|
+
if (
|
|
277
|
+
resolvedContext?.scopeId !== undefined &&
|
|
278
|
+
typeof host.scope === 'function'
|
|
279
|
+
) {
|
|
280
|
+
return host.scope(resolvedContext.scopeId);
|
|
281
|
+
}
|
|
282
|
+
return host;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function sourceSummary(source) {
|
|
286
|
+
return {
|
|
287
|
+
connectionId: source.connectionId,
|
|
288
|
+
serverId: source.serverId,
|
|
289
|
+
eventName: source.eventName,
|
|
290
|
+
description: source.description ?? null,
|
|
291
|
+
delivery: source.delivery ?? [],
|
|
292
|
+
inputSchema: source.inputSchema ?? {},
|
|
293
|
+
payloadSchema: source.payloadSchema ?? {},
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function buildPlanInput(parsed, target) {
|
|
298
|
+
return {
|
|
299
|
+
...(parsed.trigger_id ? { triggerId: parsed.trigger_id } : {}),
|
|
300
|
+
...(parsed.version ? { version: parsed.version } : {}),
|
|
301
|
+
...(parsed.description ? { description: parsed.description } : {}),
|
|
302
|
+
events: parsed.events.map((event) => ({
|
|
303
|
+
...(event.id ? { id: event.id } : {}),
|
|
304
|
+
event: event.event,
|
|
305
|
+
...(event.serverId ? { serverId: event.serverId } : {}),
|
|
306
|
+
arguments: event.arguments ?? {},
|
|
307
|
+
where: event.where ?? [],
|
|
308
|
+
})),
|
|
309
|
+
...(parsed.pattern ? { pattern: parsed.pattern } : {}),
|
|
310
|
+
...(parsed.within_ms !== undefined ? { withinMs: parsed.within_ms } : {}),
|
|
311
|
+
...(parsed.event_time
|
|
312
|
+
? { eventTime: { allowedLatenessMs: parsed.event_time.allowed_lateness_ms } }
|
|
313
|
+
: {}),
|
|
314
|
+
lifecycle: {
|
|
315
|
+
oneShot: parsed.one_shot ?? true,
|
|
316
|
+
...(parsed.max_firings !== undefined
|
|
317
|
+
? { maxFirings: parsed.max_firings }
|
|
318
|
+
: {}),
|
|
319
|
+
...(parsed.cooldown_ms !== undefined
|
|
320
|
+
? { cooldownMs: parsed.cooldown_ms }
|
|
321
|
+
: {}),
|
|
322
|
+
...(parsed.expires_at ? { expiresAt: parsed.expires_at } : {}),
|
|
323
|
+
...(parsed.lease_until ? { leaseUntil: parsed.lease_until } : {}),
|
|
324
|
+
...(parsed.complete_on_goal !== undefined
|
|
325
|
+
? { completeOnGoal: parsed.complete_on_goal }
|
|
326
|
+
: {}),
|
|
327
|
+
},
|
|
328
|
+
target,
|
|
329
|
+
continuation: {
|
|
330
|
+
instruction: parsed.instruction,
|
|
331
|
+
contextPolicy: {
|
|
332
|
+
evidence: 'matched_events',
|
|
333
|
+
maxEvents: 20,
|
|
334
|
+
includeData: true,
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Portable agent-facing tools. The descriptors do not depend on OpenAI,
|
|
342
|
+
* Anthropic, MCP tool objects, Muffin, Artemis, LangGraph, or any other host.
|
|
343
|
+
* Adapters only need to translate {name, description, inputSchema, execute}.
|
|
344
|
+
*/
|
|
345
|
+
export function createEventIntelligenceAgentTools({
|
|
346
|
+
host,
|
|
347
|
+
resolveContext,
|
|
348
|
+
authorize,
|
|
349
|
+
names = {},
|
|
350
|
+
} = {}) {
|
|
351
|
+
if (!host || typeof host !== 'object') {
|
|
352
|
+
throw new Error('Agent tools require an Event Intelligence host');
|
|
353
|
+
}
|
|
354
|
+
if (typeof resolveContext !== 'function') {
|
|
355
|
+
throw new Error('Agent tools require resolveContext()');
|
|
356
|
+
}
|
|
357
|
+
if (typeof authorize !== 'function') {
|
|
358
|
+
throw new Error('Agent tools require authorize() for durable mutations');
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const toolNames = {
|
|
362
|
+
...DEFAULT_TOOL_NAMES,
|
|
363
|
+
...names,
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
return [
|
|
367
|
+
{
|
|
368
|
+
name: toolNames.sources,
|
|
369
|
+
description:
|
|
370
|
+
'List live future-event sources discovered from MCP connections already owned by the host runtime. Use this before creating a trigger so event names and schemas are not guessed.',
|
|
371
|
+
inputSchema: SOURCES_INPUT_SCHEMA,
|
|
372
|
+
async execute(_args, runtimeContext) {
|
|
373
|
+
try {
|
|
374
|
+
const resolved = await resolveContext(runtimeContext, {
|
|
375
|
+
action: 'event.sources.list',
|
|
376
|
+
});
|
|
377
|
+
if (typeof host.refreshMcpRegistry === 'function') {
|
|
378
|
+
await host.refreshMcpRegistry();
|
|
379
|
+
}
|
|
380
|
+
const scoped = await scopedHostFor(host, resolved);
|
|
381
|
+
const sources = await Promise.resolve(scoped.eventSources);
|
|
382
|
+
return {
|
|
383
|
+
ok: true,
|
|
384
|
+
data: {
|
|
385
|
+
sources: Array.isArray(sources)
|
|
386
|
+
? sources.map(sourceSummary)
|
|
387
|
+
: [],
|
|
388
|
+
},
|
|
389
|
+
};
|
|
390
|
+
} catch (error) {
|
|
391
|
+
return fail(error, 'EVENT_SOURCES_LIST_FAILED');
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
name: toolNames.create,
|
|
397
|
+
description:
|
|
398
|
+
'Create a durable future condition. The host, not the model, supplies the continuation target and authority context; Event Intelligence wakes that target only when the condition matches.',
|
|
399
|
+
inputSchema: CREATE_INPUT_SCHEMA,
|
|
400
|
+
async execute(args, runtimeContext) {
|
|
401
|
+
const parsed = TriggerCreateInput.safeParse(args ?? {});
|
|
402
|
+
if (!parsed.success) {
|
|
403
|
+
const issue = parsed.error.issues[0];
|
|
404
|
+
return {
|
|
405
|
+
ok: false,
|
|
406
|
+
error: {
|
|
407
|
+
code: 'EVENT_TRIGGER_INPUT_INVALID',
|
|
408
|
+
message:
|
|
409
|
+
`${issue?.path?.join('.') || 'input'} — ${issue?.message || 'invalid'}`,
|
|
410
|
+
},
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
try {
|
|
415
|
+
const resolved = await resolveContext(runtimeContext, {
|
|
416
|
+
action: 'trigger.create',
|
|
417
|
+
input: parsed.data,
|
|
418
|
+
});
|
|
419
|
+
const target = createContinuationTarget(resolved?.target);
|
|
420
|
+
if (typeof host.refreshMcpRegistry === 'function') {
|
|
421
|
+
await host.refreshMcpRegistry();
|
|
422
|
+
}
|
|
423
|
+
const scoped = await scopedHostFor(host, resolved);
|
|
424
|
+
const plan = await scoped.planTrigger(
|
|
425
|
+
buildPlanInput(parsed.data, target),
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
const decision = normalizeAuthorization(
|
|
429
|
+
await authorize({
|
|
430
|
+
action: 'trigger.create',
|
|
431
|
+
runtimeContext,
|
|
432
|
+
context: resolved,
|
|
433
|
+
input: parsed.data,
|
|
434
|
+
plan,
|
|
435
|
+
}),
|
|
436
|
+
);
|
|
437
|
+
if (!decision.allowed) {
|
|
438
|
+
return {
|
|
439
|
+
ok: false,
|
|
440
|
+
error: {
|
|
441
|
+
code: String(
|
|
442
|
+
decision.code || 'EVENT_TRIGGER_AUTHORIZATION_DENIED',
|
|
443
|
+
),
|
|
444
|
+
message: String(
|
|
445
|
+
decision.message || 'Host denied durable trigger creation',
|
|
446
|
+
),
|
|
447
|
+
},
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const actor = normalizeIdentity(
|
|
452
|
+
decision.actor ?? resolved?.actor,
|
|
453
|
+
'actor',
|
|
454
|
+
);
|
|
455
|
+
const owner = normalizeIdentity(
|
|
456
|
+
decision.owner ?? resolved?.owner,
|
|
457
|
+
'owner',
|
|
458
|
+
);
|
|
459
|
+
const confirmationId = String(
|
|
460
|
+
decision.confirmationId ?? resolved?.confirmationId ?? '',
|
|
461
|
+
).trim();
|
|
462
|
+
|
|
463
|
+
const created = await scoped.triggerControl.createTrigger({
|
|
464
|
+
definition: plan.definition,
|
|
465
|
+
connectionIds: plan.connectionIds,
|
|
466
|
+
actor,
|
|
467
|
+
owner,
|
|
468
|
+
...(confirmationId ? { confirmationId } : {}),
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
return {
|
|
472
|
+
ok: true,
|
|
473
|
+
data: {
|
|
474
|
+
receiptId: created.receiptId,
|
|
475
|
+
triggerId: created.definition?.triggerId,
|
|
476
|
+
version: created.definition?.version,
|
|
477
|
+
state: created.state,
|
|
478
|
+
connectionIds: plan.connectionIds,
|
|
479
|
+
warnings: plan.warnings ?? [],
|
|
480
|
+
},
|
|
481
|
+
};
|
|
482
|
+
} catch (error) {
|
|
483
|
+
return fail(error, 'EVENT_TRIGGER_CREATE_FAILED');
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
];
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* High-level embedded install. EI remains in-process; MCP transports/auth and
|
|
492
|
+
* continuation semantics remain owned by the host.
|
|
493
|
+
*/
|
|
494
|
+
export async function createEmbeddedEventIntelligence({
|
|
495
|
+
dataDir,
|
|
496
|
+
store,
|
|
497
|
+
env = {},
|
|
498
|
+
mcpRegistry,
|
|
499
|
+
mcp,
|
|
500
|
+
mcpClients = [],
|
|
501
|
+
semanticEvaluator,
|
|
502
|
+
activation,
|
|
503
|
+
wake,
|
|
504
|
+
wakeHandlers = {},
|
|
505
|
+
agentTools,
|
|
506
|
+
createHost = createEventIntelligenceHost,
|
|
507
|
+
} = {}) {
|
|
508
|
+
if (activation !== undefined && wake !== undefined) {
|
|
509
|
+
throw new Error('Provide activation or wake, not both');
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
let registry = mcpRegistry;
|
|
513
|
+
if (!registry && mcp) {
|
|
514
|
+
registry = createMcpRegistryAdapter({
|
|
515
|
+
listConnections: mcp.listConnections,
|
|
516
|
+
...(mcp.subscribe ? { subscribe: mcp.subscribe } : {}),
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const wakeHandler = activation
|
|
521
|
+
? createActivationDispatcher(activation)
|
|
522
|
+
: wake;
|
|
523
|
+
|
|
524
|
+
const host = await createHost({
|
|
525
|
+
dataDir,
|
|
526
|
+
store,
|
|
527
|
+
env,
|
|
528
|
+
mcpRegistry: registry,
|
|
529
|
+
mcpClients,
|
|
530
|
+
semanticEvaluator,
|
|
531
|
+
...(wakeHandler ? { wake: wakeHandler } : {}),
|
|
532
|
+
wakeHandlers,
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
const tools = agentTools
|
|
536
|
+
? createEventIntelligenceAgentTools({
|
|
537
|
+
host,
|
|
538
|
+
...agentTools,
|
|
539
|
+
})
|
|
540
|
+
: [];
|
|
541
|
+
|
|
542
|
+
return {
|
|
543
|
+
host,
|
|
544
|
+
runtime: host.runtime,
|
|
545
|
+
tools,
|
|
546
|
+
createAgentTools(options) {
|
|
547
|
+
return createEventIntelligenceAgentTools({
|
|
548
|
+
host,
|
|
549
|
+
...options,
|
|
550
|
+
});
|
|
551
|
+
},
|
|
552
|
+
refresh() {
|
|
553
|
+
return host.refreshMcpRegistry();
|
|
554
|
+
},
|
|
555
|
+
status() {
|
|
556
|
+
return host.mcpStatus();
|
|
557
|
+
},
|
|
558
|
+
scope(scopeId) {
|
|
559
|
+
return host.scope(scopeId);
|
|
560
|
+
},
|
|
561
|
+
close() {
|
|
562
|
+
return host.close();
|
|
563
|
+
},
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export const PORTABLE_EVENT_INTELLIGENCE_TOOL_NAMES = DEFAULT_TOOL_NAMES;
|
|
@@ -144,8 +144,10 @@ export async function createEventIntelligenceHost({
|
|
|
144
144
|
|
|
145
145
|
const registryManaged = new Set();
|
|
146
146
|
let unsubscribe = null;
|
|
147
|
+
let registryRefreshPromise = null;
|
|
148
|
+
let registryRefreshRequested = false;
|
|
147
149
|
|
|
148
|
-
const
|
|
150
|
+
const refreshMcpRegistryOnce = async () => {
|
|
149
151
|
const entries = await listRegistryConnections(mcpRegistry);
|
|
150
152
|
const desired = new Map();
|
|
151
153
|
|
|
@@ -213,6 +215,26 @@ export async function createEventIntelligenceHost({
|
|
|
213
215
|
return outcomes;
|
|
214
216
|
};
|
|
215
217
|
|
|
218
|
+
const refreshMcpRegistry = () => {
|
|
219
|
+
if (registryRefreshPromise) {
|
|
220
|
+
registryRefreshRequested = true;
|
|
221
|
+
return registryRefreshPromise;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
registryRefreshPromise = (async () => {
|
|
225
|
+
const outcomes = [];
|
|
226
|
+
do {
|
|
227
|
+
registryRefreshRequested = false;
|
|
228
|
+
outcomes.push(...await refreshMcpRegistryOnce());
|
|
229
|
+
} while (registryRefreshRequested);
|
|
230
|
+
return outcomes;
|
|
231
|
+
})().finally(() => {
|
|
232
|
+
registryRefreshPromise = null;
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
return registryRefreshPromise;
|
|
236
|
+
};
|
|
237
|
+
|
|
216
238
|
if (mcpRegistry) {
|
|
217
239
|
await refreshMcpRegistry();
|
|
218
240
|
|
|
@@ -297,4 +319,4 @@ export {
|
|
|
297
319
|
describeStoreCapabilities,
|
|
298
320
|
PersistentEventStore,
|
|
299
321
|
validateSharedStoreCapabilities,
|
|
300
|
-
};
|
|
322
|
+
};
|
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.sarooo17/event-intelligence",
|
|
4
4
|
"title": "MCP Event Intelligence",
|
|
5
5
|
"description": "MCP-native CEP for durable agents: event-time patterns, semantic predicates, derived events.",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.7.1",
|
|
7
7
|
"repository": {
|
|
8
8
|
"url": "https://github.com/sarooo17/event-intelligence",
|
|
9
9
|
"source": "github"
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
15
15
|
"identifier": "mcp-event-intelligence",
|
|
16
|
-
"version": "0.
|
|
16
|
+
"version": "0.7.1",
|
|
17
17
|
"transport": {
|
|
18
18
|
"type": "stdio"
|
|
19
19
|
},
|