mcp-event-intelligence 0.2.1 → 0.3.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.
@@ -21,6 +21,22 @@ export declare const StructuredPredicateSchema: z.ZodDiscriminatedUnion<[z.ZodOb
21
21
  path: z.ZodString;
22
22
  op: z.ZodLiteral<"exists">;
23
23
  value: z.ZodDefault<z.ZodBoolean>;
24
+ }, z.core.$strip>, z.ZodObject<{
25
+ path: z.ZodString;
26
+ op: z.ZodLiteral<"gt">;
27
+ value: z.ZodNumber;
28
+ }, z.core.$strip>, z.ZodObject<{
29
+ path: z.ZodString;
30
+ op: z.ZodLiteral<"gte">;
31
+ value: z.ZodNumber;
32
+ }, z.core.$strip>, z.ZodObject<{
33
+ path: z.ZodString;
34
+ op: z.ZodLiteral<"lt">;
35
+ value: z.ZodNumber;
36
+ }, z.core.$strip>, z.ZodObject<{
37
+ path: z.ZodString;
38
+ op: z.ZodLiteral<"lte">;
39
+ value: z.ZodNumber;
24
40
  }, z.core.$strip>], "op">;
25
41
  export declare const TriggerClauseSchema: z.ZodObject<{
26
42
  id: z.ZodString;
@@ -47,6 +63,22 @@ export declare const TriggerClauseSchema: z.ZodObject<{
47
63
  path: z.ZodString;
48
64
  op: z.ZodLiteral<"exists">;
49
65
  value: z.ZodDefault<z.ZodBoolean>;
66
+ }, z.core.$strip>, z.ZodObject<{
67
+ path: z.ZodString;
68
+ op: z.ZodLiteral<"gt">;
69
+ value: z.ZodNumber;
70
+ }, z.core.$strip>, z.ZodObject<{
71
+ path: z.ZodString;
72
+ op: z.ZodLiteral<"gte">;
73
+ value: z.ZodNumber;
74
+ }, z.core.$strip>, z.ZodObject<{
75
+ path: z.ZodString;
76
+ op: z.ZodLiteral<"lt">;
77
+ value: z.ZodNumber;
78
+ }, z.core.$strip>, z.ZodObject<{
79
+ path: z.ZodString;
80
+ op: z.ZodLiteral<"lte">;
81
+ value: z.ZodNumber;
50
82
  }, z.core.$strip>], "op">>>;
51
83
  }, z.core.$strip>;
52
84
  export declare const CalendarTemporalConditionSchema: z.ZodObject<{
@@ -169,6 +201,25 @@ export declare const TriggerLifecyclePolicySchema: z.ZodObject<{
169
201
  leaseUntil: z.ZodOptional<z.ZodString>;
170
202
  completeOnGoal: z.ZodDefault<z.ZodBoolean>;
171
203
  }, z.core.$strip>;
204
+ export declare const ContinuationContextPolicySchema: z.ZodObject<{
205
+ evidence: z.ZodDefault<z.ZodEnum<{
206
+ matched_events: "matched_events";
207
+ refs_only: "refs_only";
208
+ }>>;
209
+ maxEvents: z.ZodDefault<z.ZodNumber>;
210
+ includeData: z.ZodDefault<z.ZodBoolean>;
211
+ }, z.core.$strict>;
212
+ export declare const ContinuationContractSchema: z.ZodObject<{
213
+ instruction: z.ZodString;
214
+ contextPolicy: z.ZodDefault<z.ZodObject<{
215
+ evidence: z.ZodDefault<z.ZodEnum<{
216
+ matched_events: "matched_events";
217
+ refs_only: "refs_only";
218
+ }>>;
219
+ maxEvents: z.ZodDefault<z.ZodNumber>;
220
+ includeData: z.ZodDefault<z.ZodBoolean>;
221
+ }, z.core.$strict>>;
222
+ }, z.core.$strict>;
172
223
  export declare const DeterministicCorrelationSchema: z.ZodObject<{
173
224
  kind: z.ZodLiteral<"same_value">;
174
225
  fields: z.ZodArray<z.ZodObject<{
@@ -193,6 +244,17 @@ export declare const CompositeTriggerDefinitionSchema: z.ZodObject<{
193
244
  triggerId: z.ZodString;
194
245
  version: z.ZodString;
195
246
  description: z.ZodOptional<z.ZodString>;
247
+ continuation: z.ZodOptional<z.ZodObject<{
248
+ instruction: z.ZodString;
249
+ contextPolicy: z.ZodDefault<z.ZodObject<{
250
+ evidence: z.ZodDefault<z.ZodEnum<{
251
+ matched_events: "matched_events";
252
+ refs_only: "refs_only";
253
+ }>>;
254
+ maxEvents: z.ZodDefault<z.ZodNumber>;
255
+ includeData: z.ZodDefault<z.ZodBoolean>;
256
+ }, z.core.$strict>>;
257
+ }, z.core.$strict>>;
196
258
  clauses: z.ZodArray<z.ZodObject<{
197
259
  id: z.ZodString;
198
260
  event: z.ZodString;
@@ -218,6 +280,22 @@ export declare const CompositeTriggerDefinitionSchema: z.ZodObject<{
218
280
  path: z.ZodString;
219
281
  op: z.ZodLiteral<"exists">;
220
282
  value: z.ZodDefault<z.ZodBoolean>;
283
+ }, z.core.$strip>, z.ZodObject<{
284
+ path: z.ZodString;
285
+ op: z.ZodLiteral<"gt">;
286
+ value: z.ZodNumber;
287
+ }, z.core.$strip>, z.ZodObject<{
288
+ path: z.ZodString;
289
+ op: z.ZodLiteral<"gte">;
290
+ value: z.ZodNumber;
291
+ }, z.core.$strip>, z.ZodObject<{
292
+ path: z.ZodString;
293
+ op: z.ZodLiteral<"lt">;
294
+ value: z.ZodNumber;
295
+ }, z.core.$strip>, z.ZodObject<{
296
+ path: z.ZodString;
297
+ op: z.ZodLiteral<"lte">;
298
+ value: z.ZodNumber;
221
299
  }, z.core.$strip>], "op">>>;
222
300
  }, z.core.$strip>>;
223
301
  expression: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -475,6 +553,8 @@ export type StructuredPredicate = z.infer<typeof StructuredPredicateSchema>;
475
553
  export type TriggerClause = z.infer<typeof TriggerClauseSchema>;
476
554
  export type TemporalCondition = z.infer<typeof TemporalConditionSchema>;
477
555
  export type TriggerLifecyclePolicy = z.infer<typeof TriggerLifecyclePolicySchema>;
556
+ export type ContinuationContextPolicy = z.infer<typeof ContinuationContextPolicySchema>;
557
+ export type ContinuationContract = z.infer<typeof ContinuationContractSchema>;
478
558
  export type DerivedEventDefinition = z.infer<typeof DerivedEventDefinitionSchema>;
479
559
  export type DerivedEventRecord = z.infer<typeof DerivedEventRecordSchema>;
480
560
  export type CompositeTriggerDefinition = z.infer<typeof CompositeTriggerDefinitionSchema>;
@@ -13,6 +13,10 @@ export const StructuredPredicateSchema = z.discriminatedUnion('op', [
13
13
  z.object({ path: z.string().min(1), op: z.literal('contains'), value: Scalar }),
14
14
  z.object({ path: z.string().min(1), op: z.literal('in'), value: z.array(Scalar).min(1) }),
15
15
  z.object({ path: z.string().min(1), op: z.literal('exists'), value: z.boolean().default(true) }),
16
+ z.object({ path: z.string().min(1), op: z.literal('gt'), value: z.number() }),
17
+ z.object({ path: z.string().min(1), op: z.literal('gte'), value: z.number() }),
18
+ z.object({ path: z.string().min(1), op: z.literal('lt'), value: z.number() }),
19
+ z.object({ path: z.string().min(1), op: z.literal('lte'), value: z.number() }),
16
20
  ]);
17
21
  export const TriggerClauseSchema = z.object({
18
22
  id: Id,
@@ -142,6 +146,19 @@ export const TriggerLifecyclePolicySchema = z.object({
142
146
  });
143
147
  }
144
148
  });
149
+ export const ContinuationContextPolicySchema = z.object({
150
+ evidence: z.enum(['matched_events', 'refs_only']).default('matched_events'),
151
+ maxEvents: z.number().int().min(1).max(50).default(50),
152
+ includeData: z.boolean().default(true),
153
+ }).strict();
154
+ export const ContinuationContractSchema = z.object({
155
+ instruction: z.string().min(1).max(4000),
156
+ contextPolicy: ContinuationContextPolicySchema.default({
157
+ evidence: 'matched_events',
158
+ maxEvents: 50,
159
+ includeData: true,
160
+ }),
161
+ }).strict();
145
162
  export const DeterministicCorrelationSchema = z.object({
146
163
  kind: z.literal('same_value'),
147
164
  fields: z.array(z.object({
@@ -164,6 +181,7 @@ export const CompositeTriggerDefinitionSchema = z.object({
164
181
  triggerId: Id,
165
182
  version: z.string().min(1),
166
183
  description: z.string().max(500).optional(),
184
+ continuation: ContinuationContractSchema.optional(),
167
185
  clauses: z.array(TriggerClauseSchema).min(1),
168
186
  expression: TriggerExpressionSchema,
169
187
  temporal: z.array(TemporalConditionSchema).default([]),
@@ -186,6 +204,12 @@ export const CompositeTriggerDefinitionSchema = z.object({
186
204
  message: 'Trigger requires target, derivedEvent, or both',
187
205
  });
188
206
  }
207
+ if (value.continuation && !value.target) {
208
+ ctx.addIssue({
209
+ code: 'custom',
210
+ message: 'Trigger continuation requires a runtime target',
211
+ });
212
+ }
189
213
  const ids = new Set(value.clauses.map((clause) => clause.id));
190
214
  if (ids.size !== value.clauses.length) {
191
215
  ctx.addIssue({ code: 'custom', message: 'Trigger clause ids must be unique' });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-event-intelligence",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "Durable temporal event intelligence for agent hosts: host-owned MCP event discovery, composite triggers, derived events, and targeted wakeups.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -1,3 +1,8 @@
1
+ import type {
2
+ ActivationEnvelope,
3
+ TriggerPlanInput,
4
+ } from '../dist/src/intelligenceProtocol/index.js';
5
+
1
6
  export interface HostMcpClientLike {
2
7
  request(
3
8
  request: { method: string; params?: unknown },
@@ -38,6 +43,7 @@ export interface HostWakeReceipt {
38
43
 
39
44
  export type HostWakeHandler = (
40
45
  packet: Record<string, unknown>,
46
+ activation?: ActivationEnvelope,
41
47
  ) => Promise<HostWakeReceipt | string> | HostWakeReceipt | string;
42
48
 
43
49
  export interface EventIntelligenceStore {
@@ -69,7 +75,18 @@ export interface EventIntelligenceScopedHost {
69
75
  readonly store: EventIntelligenceStore;
70
76
  readonly triggerControl: any;
71
77
  readonly triggerInspector: any;
78
+ readonly triggerPlanner: any;
79
+ readonly activationHydrator: any;
72
80
  readonly eventSources: any[];
81
+ planTrigger(input: TriggerPlanInput): Promise<{
82
+ planVersion: '1';
83
+ definition: any;
84
+ connectionIds: string[];
85
+ resolvedSources: any[];
86
+ warnings: any[];
87
+ explanation: any;
88
+ }>;
89
+ hydrateWake(wakeId: string): ActivationEnvelope;
73
90
  attachMcpClient(connection: HostMcpConnectionOptions): Promise<{
74
91
  connectionId: string;
75
92
  events: any[];
@@ -74,6 +74,14 @@ function scopedHostView(runtime, context) {
74
74
  store: context.store,
75
75
  triggerControl: context.triggerControl,
76
76
  triggerInspector: context.triggerInspector,
77
+ triggerPlanner: context.triggerPlanner,
78
+ activationHydrator: context.activationHydrator,
79
+ planTrigger(input) {
80
+ return context.triggerPlanner.plan(input);
81
+ },
82
+ hydrateWake(wakeId) {
83
+ return context.activationHydrator.hydrateWake(wakeId);
84
+ },
77
85
  get eventSources() {
78
86
  return context.triggerControl.listEventSources();
79
87
  },
@@ -223,6 +231,18 @@ export async function createEventIntelligenceHost({
223
231
  get triggerInspector() {
224
232
  return runtime.triggerInspector;
225
233
  },
234
+ get triggerPlanner() {
235
+ return runtime.triggerPlanner;
236
+ },
237
+ get activationHydrator() {
238
+ return runtime.activationHydrator;
239
+ },
240
+ planTrigger(input) {
241
+ return runtime.triggerPlanner.plan(input);
242
+ },
243
+ hydrateWake(wakeId) {
244
+ return runtime.activationHydrator.hydrateWake(wakeId);
245
+ },
226
246
  get eventSources() {
227
247
  return runtime.triggerControl.listEventSources();
228
248
  },
@@ -0,0 +1,140 @@
1
+ import {
2
+ parseActivationEnvelope,
3
+ } from '../../dist/src/intelligenceProtocol/index.js';
4
+
5
+ function latestMatchForWake(store, wake, delivery) {
6
+ const matchId =
7
+ delivery?.matchId ||
8
+ (wake?.subscriptionId?.startsWith('trigger:') ? wake.sourceEventId : null);
9
+ if (!matchId) return null;
10
+
11
+ return store.listTriggerMatches()
12
+ .find((candidate) => candidate.matchId === matchId) ?? null;
13
+ }
14
+
15
+ function definitionForMatch(store, match, delivery) {
16
+ if (!match && !delivery) return null;
17
+ const triggerId = match?.triggerId ?? delivery?.triggerId;
18
+ const triggerVersion = match?.triggerVersion ?? delivery?.triggerVersion;
19
+ return store.listTriggers().find((candidate) =>
20
+ candidate.triggerId === triggerId &&
21
+ candidate.version === triggerVersion
22
+ ) ?? null;
23
+ }
24
+
25
+ function continuationFor(definition) {
26
+ if (definition?.continuation) return definition.continuation;
27
+
28
+ const fallback = String(definition?.description || '').trim();
29
+ if (!fallback) return null;
30
+ return {
31
+ instruction: fallback,
32
+ contextPolicy: {
33
+ evidence: 'refs_only',
34
+ maxEvents: 50,
35
+ includeData: false,
36
+ },
37
+ };
38
+ }
39
+
40
+ export class ActivationHydrator {
41
+ constructor({ store }) {
42
+ this.store = store;
43
+ }
44
+
45
+ hydrateWake(wakeIdInput) {
46
+ const wakeId = String(wakeIdInput || '').trim();
47
+ if (!wakeId) {
48
+ const error = new Error('wakeId is required');
49
+ error.code = 'ACTIVATION_WAKE_ID_REQUIRED';
50
+ throw error;
51
+ }
52
+
53
+ const wake = this.store.latestWake(wakeId);
54
+ if (!wake) {
55
+ const error = new Error(`Unknown wake: ${wakeId}`);
56
+ error.code = 'ACTIVATION_WAKE_NOT_FOUND';
57
+ throw error;
58
+ }
59
+
60
+ const delivery =
61
+ typeof this.store.getWakeDelivery === 'function'
62
+ ? this.store.getWakeDelivery(wakeId)
63
+ : null;
64
+ const match = latestMatchForWake(this.store, wake, delivery);
65
+ if (!match) {
66
+ const error = new Error(
67
+ `Wake ${wakeId} is not backed by a composite trigger match`,
68
+ );
69
+ error.code = 'ACTIVATION_TRIGGER_MATCH_NOT_FOUND';
70
+ throw error;
71
+ }
72
+
73
+ const definition = definitionForMatch(this.store, match, delivery);
74
+ if (!definition?.target) {
75
+ const error = new Error(
76
+ `Trigger definition missing for wake ${wakeId}`,
77
+ );
78
+ error.code = 'ACTIVATION_TRIGGER_NOT_FOUND';
79
+ throw error;
80
+ }
81
+
82
+ const continuation = continuationFor(definition);
83
+ const policy = continuation?.contextPolicy ?? {
84
+ evidence: 'refs_only',
85
+ maxEvents: 50,
86
+ includeData: false,
87
+ };
88
+ const includeData =
89
+ policy.evidence === 'matched_events' &&
90
+ policy.includeData !== false;
91
+ const maxEvents = Math.max(
92
+ 1,
93
+ Math.min(50, Number(policy.maxEvents) || 50),
94
+ );
95
+
96
+ const evidence = match.sourceEvents.slice(-maxEvents).map((event) => ({
97
+ clauseId: event.clauseId,
98
+ serverId: event.serverId ?? null,
99
+ eventId: event.sourceEventId,
100
+ eventName: event.eventName,
101
+ traceId: event.traceId,
102
+ occurredAt: event.occurredAt,
103
+ payloadHash: event.payloadHash ?? null,
104
+ ...(includeData ? { data: event.data } : {}),
105
+ }));
106
+
107
+ return parseActivationEnvelope({
108
+ activationVersion: '1',
109
+ wake: {
110
+ wakeId,
111
+ status: wake.status,
112
+ runtimeReceiptId: wake.runtimeReceiptId ?? null,
113
+ matchedAt: match.updatedAt,
114
+ },
115
+ target: definition.target,
116
+ trigger: {
117
+ triggerId: definition.triggerId,
118
+ version: definition.version,
119
+ description: definition.description ?? null,
120
+ expression: definition.expression,
121
+ lifecycle: definition.lifecycle ?? {},
122
+ },
123
+ continuation,
124
+ match: {
125
+ matchId: match.matchId,
126
+ status: match.status,
127
+ correlationKey: match.correlationKey,
128
+ openedAt: match.openedAt,
129
+ updatedAt: match.updatedAt,
130
+ },
131
+ evidence,
132
+ trust: {
133
+ continuation: 'configured_trigger_instruction',
134
+ evidence: 'untrusted_external_signal',
135
+ },
136
+ });
137
+ }
138
+ }
139
+
140
+ export default { ActivationHydrator };
@@ -38,6 +38,12 @@ import {
38
38
  import {
39
39
  WakeRetryScheduler,
40
40
  } from './wake-retry-scheduler.mjs';
41
+ import {
42
+ TriggerPlanner,
43
+ } from './trigger-planner.mjs';
44
+ import {
45
+ ActivationHydrator,
46
+ } from './activation-hydrator.mjs';
41
47
 
42
48
  const REQUIRED_STORE_METHODS = [
43
49
  'putTrigger',
@@ -155,6 +161,8 @@ export async function createLocalEventIntelligenceRuntime({
155
161
  }
156
162
 
157
163
  const triggerEngine = new CompositeTriggerEngine(store, evaluator);
164
+ const triggerPlanner = new TriggerPlanner({ store });
165
+ const activationHydrator = new ActivationHydrator({ store });
158
166
  const wakeCoordinators = new Map();
159
167
  const packetBuilder = scopedPacketBuilder(scopeId);
160
168
  const deliveryOptions = {
@@ -186,7 +194,8 @@ export async function createLocalEventIntelligenceRuntime({
186
194
  packetBuilder,
187
195
  ...deliveryOptions,
188
196
  deliverer: async (packet) => {
189
- const result = await handler(packet);
197
+ const activation = activationHydrator.hydrateWake(packet.wake_id);
198
+ const result = await handler(packet, activation);
190
199
  if (typeof result === 'string' && result) {
191
200
  return { runtimeReceiptId: result };
192
201
  }
@@ -214,7 +223,8 @@ export async function createLocalEventIntelligenceRuntime({
214
223
  packetBuilder,
215
224
  ...deliveryOptions,
216
225
  deliverer: async (packet) => {
217
- const result = await wake(packet);
226
+ const activation = activationHydrator.hydrateWake(packet.wake_id);
227
+ const result = await wake(packet, activation);
218
228
  if (typeof result === 'string' && result) {
219
229
  return { runtimeReceiptId: result };
220
230
  }
@@ -270,6 +280,8 @@ export async function createLocalEventIntelligenceRuntime({
270
280
  triggerEngine,
271
281
  triggerControl,
272
282
  triggerInspector,
283
+ triggerPlanner,
284
+ activationHydrator,
273
285
  compositeEventConsumer,
274
286
  temporalScheduler,
275
287
  wakeRetryScheduler,
@@ -322,6 +334,8 @@ export async function createLocalEventIntelligenceRuntime({
322
334
  triggerEngine: defaultContext.triggerEngine,
323
335
  triggerControl: defaultContext.triggerControl,
324
336
  triggerInspector: defaultContext.triggerInspector,
337
+ triggerPlanner: defaultContext.triggerPlanner,
338
+ activationHydrator: defaultContext.activationHydrator,
325
339
  compositeEventConsumer: defaultContext.compositeEventConsumer,
326
340
  temporalScheduler: defaultContext.temporalScheduler,
327
341
  mcpEventsClient,
@@ -307,6 +307,7 @@ export class TriggerInspector {
307
307
  triggerId: definition.triggerId,
308
308
  version: definition.version,
309
309
  description: definition.description ?? null,
310
+ continuation: definition.continuation ?? null,
310
311
  target: definition.target ?? null,
311
312
  derivedEvent: definition.derivedEvent ?? null,
312
313
  expression: definition.expression,