mcp-event-intelligence 0.7.0 → 0.8.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/CHANGELOG.md +20 -0
- package/README.md +62 -23
- package/bin/mcp-event-intelligence.mjs +10 -3
- package/package.json +1 -1
- package/scripts/embedded-host-kit.d.mts +160 -3
- package/scripts/embedded-host-kit.mjs +355 -53
- package/scripts/host-integration.mjs +24 -2
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.0] - 2026-10-05
|
|
4
|
+
|
|
5
|
+
### Embedded runtime integration
|
|
6
|
+
|
|
7
|
+
- add `createEmbeddedRuntimeIntegration()` above the lower-level host kit;
|
|
8
|
+
- add a runtime-neutral `EventSourceRegistry` over host-owned event connections;
|
|
9
|
+
- add portable EI capability metadata and a neutral tool catalog for host-owned exposure;
|
|
10
|
+
- add host-owned result projection with optional runtime result references;
|
|
11
|
+
- replace boolean authorization in the new integration surface with a host control contract that can execute or return an opaque deny/approval/interrupt/defer result;
|
|
12
|
+
- preserve native host interrupt/suspension exceptions instead of normalizing them into EI errors;
|
|
13
|
+
- keep tooling optional so headless/workflow runtimes can embed EI without exposing agent tools;
|
|
14
|
+
- document and test the invariant that EI core contains no named-runtime dispatch or per-runtime adapter matrix.
|
|
15
|
+
|
|
16
|
+
## [0.7.1] - 2026-10-04
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- 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;
|
|
21
|
+
- add a regression test for the subscribe + explicit-refresh race found while integrating Artemis.
|
|
22
|
+
|
|
3
23
|
## [0.7.0] - 2026-10-04
|
|
4
24
|
|
|
5
25
|
Embedded-host integration release.
|
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,53 +31,92 @@ 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
|
|
34
|
+
For most runtimes, start with the runtime-neutral integration surface:
|
|
35
35
|
|
|
36
36
|
```js
|
|
37
37
|
import {
|
|
38
|
-
|
|
38
|
+
createEmbeddedRuntimeIntegration,
|
|
39
|
+
createEventSourceRegistry,
|
|
39
40
|
} from 'mcp-event-intelligence/embedded';
|
|
40
41
|
|
|
41
|
-
const ei = await
|
|
42
|
+
const ei = await createEmbeddedRuntimeIntegration({
|
|
42
43
|
dataDir: './data/event-intelligence',
|
|
43
44
|
|
|
44
|
-
// The host
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
subscribe: (refresh) => runtime.
|
|
48
|
-
},
|
|
45
|
+
// The host owns transports, auth and connection lifecycle.
|
|
46
|
+
eventSources: createEventSourceRegistry({
|
|
47
|
+
list: () => runtime.events.connections(),
|
|
48
|
+
subscribe: (refresh) => runtime.events.onConnectionsChanged(refresh),
|
|
49
|
+
}),
|
|
49
50
|
|
|
50
|
-
// EI
|
|
51
|
+
// EI emits an activation. The host decides what "resume" means.
|
|
51
52
|
activation: {
|
|
52
53
|
resolveTarget: (target) => runtime.resolveContinuation(target),
|
|
53
54
|
hasReceipt: (receiptId) => runtime.hasWakeReceipt(receiptId),
|
|
54
55
|
deliver: ({ activation, target, receiptId }) =>
|
|
55
56
|
runtime.resumeFromEvent({ activation, target, receiptId }),
|
|
56
57
|
},
|
|
58
|
+
|
|
59
|
+
// Optional. Runtimes without an agent-tool surface can omit tooling entirely.
|
|
60
|
+
tooling: {
|
|
61
|
+
resolveContext: (ctx) => ({
|
|
62
|
+
target: runtime.currentContinuation(ctx),
|
|
63
|
+
actor: runtime.currentActor(ctx),
|
|
64
|
+
owner: runtime.currentOwner(ctx),
|
|
65
|
+
}),
|
|
66
|
+
|
|
67
|
+
// Host-owned control. EI does not reduce authorization/approval/interrupt
|
|
68
|
+
// semantics to a boolean.
|
|
69
|
+
control: (request) => runtime.policy.control(request),
|
|
70
|
+
|
|
71
|
+
// Optional host-owned result projection. Large results may be externalized
|
|
72
|
+
// behind a runtime-specific reference instead of entering model context.
|
|
73
|
+
projectResult: (request) => runtime.results.project(request),
|
|
74
|
+
},
|
|
57
75
|
});
|
|
58
76
|
```
|
|
59
77
|
|
|
60
78
|
The continuation target is intentionally opaque to EI apart from
|
|
61
79
|
`{ runtime, kind, id }`. A host may map it to a Turn, Execution, thread,
|
|
62
80
|
graph checkpoint, workflow, Case, or any other durable continuation primitive.
|
|
63
|
-
The package contains no `runtime === "muffin"` / `"artemis"` branches.
|
|
64
81
|
|
|
65
|
-
|
|
82
|
+
The returned tools are neutral descriptors with EI-neutral capability metadata:
|
|
66
83
|
|
|
67
84
|
```js
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
owner: runtime.currentOwner(ctx),
|
|
73
|
-
}),
|
|
74
|
-
authorize: (request) => runtime.policy.authorize(request),
|
|
75
|
-
});
|
|
85
|
+
for (const tool of ei.toolCatalog.all) {
|
|
86
|
+
// The host translates this descriptor into its own tool/capability system.
|
|
87
|
+
runtime.tools.register(tool);
|
|
88
|
+
}
|
|
76
89
|
```
|
|
77
90
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
91
|
+
EI intentionally ships **no per-runtime adapter matrix** such as
|
|
92
|
+
`toOpenAI()`, `toAnthropic()`, `toMuffin()` or `toArtemis()`.
|
|
93
|
+
There are too many runtimes, and adding one runtime must never require changing
|
|
94
|
+
EI core. The host consumes the same neutral contract and performs the final
|
|
95
|
+
translation at its own boundary.
|
|
96
|
+
|
|
97
|
+
Tool exposure is also host-owned. `toolCatalog.list({ capabilityIds })` can
|
|
98
|
+
project only the capabilities the host has decided to expose. EI supplies
|
|
99
|
+
metadata such as read vs durable mutation; it does not decide the host's RBAC,
|
|
100
|
+
risk tiers, approval flow or interrupt UX.
|
|
101
|
+
|
|
102
|
+
For durable mutations, `tooling.control()` returns either:
|
|
103
|
+
|
|
104
|
+
- `{ action: 'execute', execution?: ... }` — proceed, optionally attaching
|
|
105
|
+
host policy/approval provenance; or
|
|
106
|
+
- `{ action: 'return', result: ... }` — stop and return an opaque host-owned
|
|
107
|
+
outcome. That outcome may mean denied, approval required, interrupted,
|
|
108
|
+
deferred, or anything else the host runtime supports.
|
|
109
|
+
|
|
110
|
+
EI never interprets the second case. This keeps authorization, human approval
|
|
111
|
+
and interrupt semantics entirely outside the event engine.
|
|
112
|
+
|
|
113
|
+
Result handling follows the same boundary. `projectResult()` may keep a small
|
|
114
|
+
value inline or replace it with a host-owned reference. EI does not become a
|
|
115
|
+
blob store, artifact system or model-context manager.
|
|
116
|
+
|
|
117
|
+
The package contains no named-runtime dispatch such as
|
|
118
|
+
`if (runtime === "muffin")`, `"artemis"`, `"openai"` or `"anthropic"`.
|
|
119
|
+
A new runtime should require only host-boundary code outside EI core.
|
|
81
120
|
|
|
82
121
|
The lower-level host API remains available when a runtime needs direct control:
|
|
83
122
|
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
|
|
5
|
+
const packageJson = JSON.parse(
|
|
6
|
+
readFileSync(new URL('../package.json', import.meta.url), 'utf8'),
|
|
7
|
+
);
|
|
8
|
+
const packageVersion = String(packageJson.version || '').trim();
|
|
9
|
+
|
|
3
10
|
const args = process.argv.slice(2);
|
|
4
11
|
const flags = new Set(args);
|
|
5
12
|
|
|
6
13
|
if (flags.has('--version') || flags.has('-v')) {
|
|
7
|
-
console.log(
|
|
14
|
+
console.log(packageVersion);
|
|
8
15
|
process.exit(0);
|
|
9
16
|
}
|
|
10
17
|
|
|
11
18
|
if (flags.has('--help') || flags.has('-h')) {
|
|
12
|
-
console.log(`MCP Event Intelligence
|
|
19
|
+
console.log(`MCP Event Intelligence v${packageVersion}
|
|
13
20
|
|
|
14
21
|
MCP-native complex event processing for durable agents.
|
|
15
22
|
|
|
@@ -53,4 +60,4 @@ if (args[0] === 'mcp' || flags.has('--mcp')) {
|
|
|
53
60
|
await import('../scripts/mcp-stdio.mjs');
|
|
54
61
|
} else {
|
|
55
62
|
await import('../scripts/service.mjs');
|
|
56
|
-
}
|
|
63
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-event-intelligence",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
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",
|
|
@@ -7,6 +7,7 @@ export type {
|
|
|
7
7
|
ActivationEnvelope as EventActivation,
|
|
8
8
|
RuntimeTarget as ContinuationTarget,
|
|
9
9
|
};
|
|
10
|
+
|
|
10
11
|
import type {
|
|
11
12
|
EventIntelligenceHost,
|
|
12
13
|
EventIntelligenceHostOptions,
|
|
@@ -25,31 +26,58 @@ export interface EmbeddedHostIdentity {
|
|
|
25
26
|
export interface EmbeddedToolContext {
|
|
26
27
|
scopeId?: string;
|
|
27
28
|
target: RuntimeTarget;
|
|
28
|
-
actor
|
|
29
|
-
owner
|
|
29
|
+
actor?: EmbeddedHostIdentity;
|
|
30
|
+
owner?: EmbeddedHostIdentity;
|
|
30
31
|
confirmationId?: string;
|
|
31
32
|
[key: string]: unknown;
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
export interface EventIntelligenceCapabilityMetadata {
|
|
36
|
+
id: string;
|
|
37
|
+
operation: 'read' | 'create' | 'update' | 'delete' | string;
|
|
38
|
+
resource: string;
|
|
39
|
+
effect: 'none' | 'durable-state' | string;
|
|
40
|
+
durability: 'ephemeral' | 'durable' | string;
|
|
41
|
+
hostControl: 'none' | 'required' | string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface PortableResultReference {
|
|
45
|
+
id: string;
|
|
46
|
+
kind?: string;
|
|
47
|
+
metadata?: Record<string, unknown>;
|
|
48
|
+
[key: string]: unknown;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface PortableProjectedResult {
|
|
52
|
+
inline?: unknown;
|
|
53
|
+
reference?: PortableResultReference;
|
|
54
|
+
summary?: string;
|
|
55
|
+
metadata?: Record<string, unknown>;
|
|
56
|
+
}
|
|
57
|
+
|
|
34
58
|
export interface PortableToolResult {
|
|
35
59
|
ok: boolean;
|
|
36
60
|
data?: any;
|
|
61
|
+
result?: PortableProjectedResult;
|
|
37
62
|
error?: {
|
|
38
63
|
code: string;
|
|
39
64
|
message: string;
|
|
40
65
|
};
|
|
66
|
+
[key: string]: unknown;
|
|
41
67
|
}
|
|
42
68
|
|
|
43
69
|
export interface PortableAgentTool<RuntimeContext = unknown> {
|
|
44
70
|
name: string;
|
|
45
71
|
description: string;
|
|
46
72
|
inputSchema: Record<string, unknown>;
|
|
73
|
+
capability: EventIntelligenceCapabilityMetadata;
|
|
47
74
|
execute(
|
|
48
75
|
args: unknown,
|
|
49
76
|
runtimeContext: RuntimeContext,
|
|
50
77
|
): Promise<PortableToolResult>;
|
|
51
78
|
}
|
|
52
79
|
|
|
80
|
+
/** @deprecated Prefer the host-owned control() contract. */
|
|
53
81
|
export interface AuthorizationDecision {
|
|
54
82
|
allowed: boolean;
|
|
55
83
|
code?: string;
|
|
@@ -59,6 +87,33 @@ export interface AuthorizationDecision {
|
|
|
59
87
|
confirmationId?: string;
|
|
60
88
|
}
|
|
61
89
|
|
|
90
|
+
export interface HostControlExecuteDecision {
|
|
91
|
+
action: 'execute';
|
|
92
|
+
execution?: {
|
|
93
|
+
actor?: EmbeddedHostIdentity;
|
|
94
|
+
owner?: EmbeddedHostIdentity;
|
|
95
|
+
/** Host policy/approval receipt persisted by EI as confirmation provenance. */
|
|
96
|
+
receiptId?: string;
|
|
97
|
+
/** Legacy alias accepted for compatibility. */
|
|
98
|
+
confirmationId?: string;
|
|
99
|
+
[key: string]: unknown;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface HostControlReturnDecision {
|
|
104
|
+
action: 'return';
|
|
105
|
+
/**
|
|
106
|
+
* Opaque host-owned outcome. It may represent deny, approval required,
|
|
107
|
+
* interruption, deferral or another runtime-specific control path.
|
|
108
|
+
* EI does not interpret the reason.
|
|
109
|
+
*/
|
|
110
|
+
result: PortableToolResult;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export type HostControlDecision =
|
|
114
|
+
| HostControlExecuteDecision
|
|
115
|
+
| HostControlReturnDecision;
|
|
116
|
+
|
|
62
117
|
export interface ActivationDeliveryInput<Target = unknown> {
|
|
63
118
|
packet: Record<string, unknown>;
|
|
64
119
|
activation: ActivationEnvelope;
|
|
@@ -84,16 +139,69 @@ export interface ActivationDispatcherOptions<Target = RuntimeTarget> {
|
|
|
84
139
|
): HostWakeReceipt | string | void | Promise<HostWakeReceipt | string | void>;
|
|
85
140
|
}
|
|
86
141
|
|
|
142
|
+
export type EventSourceConnection = HostMcpConnectionOptions;
|
|
143
|
+
|
|
144
|
+
export interface EventSourceRegistry {
|
|
145
|
+
list(): Iterable<EventSourceConnection> | Promise<Iterable<EventSourceConnection>>;
|
|
146
|
+
subscribe?: (listener: () => void) => void | (() => void);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface EventSourceRegistryOptions {
|
|
150
|
+
list(): Iterable<EventSourceConnection> | Promise<Iterable<EventSourceConnection>>;
|
|
151
|
+
subscribe?: (listener: () => void) => void | (() => void);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface PortableToolCatalog<RuntimeContext = unknown> {
|
|
155
|
+
readonly all: readonly PortableAgentTool<RuntimeContext>[];
|
|
156
|
+
get(name: string): PortableAgentTool<RuntimeContext> | null;
|
|
157
|
+
list(options?: {
|
|
158
|
+
capabilityIds?: Iterable<string>;
|
|
159
|
+
}): PortableAgentTool<RuntimeContext>[];
|
|
160
|
+
capabilities(): EventIntelligenceCapabilityMetadata[];
|
|
161
|
+
}
|
|
162
|
+
|
|
87
163
|
export interface EventIntelligenceAgentToolsOptions<RuntimeContext = unknown> {
|
|
88
164
|
host: EventIntelligenceHost;
|
|
89
165
|
resolveContext(
|
|
90
166
|
runtimeContext: RuntimeContext,
|
|
91
167
|
request: {
|
|
92
168
|
action: 'event.sources.list' | 'trigger.create';
|
|
169
|
+
capability: EventIntelligenceCapabilityMetadata;
|
|
93
170
|
input?: unknown;
|
|
94
171
|
},
|
|
95
172
|
): EmbeddedToolContext | Promise<EmbeddedToolContext>;
|
|
96
|
-
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Host-owned control gate for durable mutations.
|
|
176
|
+
*
|
|
177
|
+
* Return action:'execute' to allow EI to perform the mutation, or
|
|
178
|
+
* action:'return' with a fully host-owned PortableToolResult to represent
|
|
179
|
+
* deny/interrupt/approval/defer semantics without EI interpreting them.
|
|
180
|
+
*/
|
|
181
|
+
control?(input: {
|
|
182
|
+
capability: EventIntelligenceCapabilityMetadata;
|
|
183
|
+
action: 'trigger.create';
|
|
184
|
+
runtimeContext: RuntimeContext;
|
|
185
|
+
context: EmbeddedToolContext;
|
|
186
|
+
input: unknown;
|
|
187
|
+
plan: any;
|
|
188
|
+
}): HostControlDecision | Promise<HostControlDecision>;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Host-owned result projection. Use it to inline, summarize or externalize
|
|
192
|
+
* large results behind a runtime-specific reference.
|
|
193
|
+
*/
|
|
194
|
+
projectResult?(input: {
|
|
195
|
+
capability: EventIntelligenceCapabilityMetadata;
|
|
196
|
+
runtimeContext: RuntimeContext;
|
|
197
|
+
context: EmbeddedToolContext;
|
|
198
|
+
value: unknown;
|
|
199
|
+
}): PortableProjectedResult | void | Promise<PortableProjectedResult | void>;
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* @deprecated Compatibility only. New integrations should use control().
|
|
203
|
+
*/
|
|
204
|
+
authorize?(input: {
|
|
97
205
|
action: 'trigger.create';
|
|
98
206
|
runtimeContext: RuntimeContext;
|
|
99
207
|
context: EmbeddedToolContext;
|
|
@@ -103,6 +211,7 @@ export interface EventIntelligenceAgentToolsOptions<RuntimeContext = unknown> {
|
|
|
103
211
|
| boolean
|
|
104
212
|
| AuthorizationDecision
|
|
105
213
|
| Promise<boolean | AuthorizationDecision>;
|
|
214
|
+
|
|
106
215
|
names?: {
|
|
107
216
|
sources?: string;
|
|
108
217
|
create?: string;
|
|
@@ -136,6 +245,45 @@ export interface EmbeddedEventIntelligence<RuntimeContext = unknown> {
|
|
|
136
245
|
close(): Promise<void>;
|
|
137
246
|
}
|
|
138
247
|
|
|
248
|
+
export interface EmbeddedRuntimeTooling<RuntimeContext = unknown> {
|
|
249
|
+
resolveContext: EventIntelligenceAgentToolsOptions<RuntimeContext>['resolveContext'];
|
|
250
|
+
control: NonNullable<EventIntelligenceAgentToolsOptions<RuntimeContext>['control']>;
|
|
251
|
+
projectResult?: EventIntelligenceAgentToolsOptions<RuntimeContext>['projectResult'];
|
|
252
|
+
names?: {
|
|
253
|
+
sources?: string;
|
|
254
|
+
create?: string;
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export interface EmbeddedRuntimeIntegrationOptions<RuntimeContext = unknown>
|
|
259
|
+
extends Omit<
|
|
260
|
+
EmbeddedEventIntelligenceOptions<RuntimeContext>,
|
|
261
|
+
'mcpRegistry' | 'mcp' | 'agentTools'
|
|
262
|
+
> {
|
|
263
|
+
eventSources?: EventSourceRegistry | EventSourceRegistryOptions;
|
|
264
|
+
tooling?: EmbeddedRuntimeTooling<RuntimeContext>;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export interface EmbeddedRuntimeIntegration<RuntimeContext = unknown>
|
|
268
|
+
extends Omit<EmbeddedEventIntelligence<RuntimeContext>, 'tools'> {
|
|
269
|
+
readonly tools: readonly PortableAgentTool<RuntimeContext>[];
|
|
270
|
+
readonly toolCatalog: PortableToolCatalog<RuntimeContext>;
|
|
271
|
+
readonly capabilities: readonly EventIntelligenceCapabilityMetadata[];
|
|
272
|
+
readonly eventSources: EventSourceRegistry | null;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function createResultReference(
|
|
276
|
+
input: PortableResultReference,
|
|
277
|
+
): PortableResultReference;
|
|
278
|
+
|
|
279
|
+
export function createEventSourceRegistry(
|
|
280
|
+
options: EventSourceRegistryOptions,
|
|
281
|
+
): EventSourceRegistry;
|
|
282
|
+
|
|
283
|
+
export function createPortableToolCatalog<RuntimeContext = unknown>(
|
|
284
|
+
tools?: PortableAgentTool<RuntimeContext>[],
|
|
285
|
+
): PortableToolCatalog<RuntimeContext>;
|
|
286
|
+
|
|
139
287
|
export function createContinuationTarget(input: {
|
|
140
288
|
runtime: string;
|
|
141
289
|
kind: string;
|
|
@@ -154,6 +302,15 @@ export function createEmbeddedEventIntelligence<RuntimeContext = unknown>(
|
|
|
154
302
|
options?: EmbeddedEventIntelligenceOptions<RuntimeContext>,
|
|
155
303
|
): Promise<EmbeddedEventIntelligence<RuntimeContext>>;
|
|
156
304
|
|
|
305
|
+
export function createEmbeddedRuntimeIntegration<RuntimeContext = unknown>(
|
|
306
|
+
options: EmbeddedRuntimeIntegrationOptions<RuntimeContext>,
|
|
307
|
+
): Promise<EmbeddedRuntimeIntegration<RuntimeContext>>;
|
|
308
|
+
|
|
309
|
+
export const EVENT_INTELLIGENCE_CAPABILITIES: Readonly<{
|
|
310
|
+
eventSourcesList: Readonly<EventIntelligenceCapabilityMetadata>;
|
|
311
|
+
triggerCreate: Readonly<EventIntelligenceCapabilityMetadata>;
|
|
312
|
+
}>;
|
|
313
|
+
|
|
157
314
|
export const PORTABLE_EVENT_INTELLIGENCE_TOOL_NAMES: Readonly<{
|
|
158
315
|
sources: 'event_sources_list';
|
|
159
316
|
create: 'trigger_create';
|
|
@@ -13,6 +13,25 @@ const DEFAULT_TOOL_NAMES = Object.freeze({
|
|
|
13
13
|
create: 'trigger_create',
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
+
export const EVENT_INTELLIGENCE_CAPABILITIES = Object.freeze({
|
|
17
|
+
eventSourcesList: Object.freeze({
|
|
18
|
+
id: 'event-intelligence.event-sources.list',
|
|
19
|
+
operation: 'read',
|
|
20
|
+
resource: 'event-source',
|
|
21
|
+
effect: 'none',
|
|
22
|
+
durability: 'ephemeral',
|
|
23
|
+
hostControl: 'none',
|
|
24
|
+
}),
|
|
25
|
+
triggerCreate: Object.freeze({
|
|
26
|
+
id: 'event-intelligence.trigger.create',
|
|
27
|
+
operation: 'create',
|
|
28
|
+
resource: 'trigger',
|
|
29
|
+
effect: 'durable-state',
|
|
30
|
+
durability: 'durable',
|
|
31
|
+
hostControl: 'required',
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
|
|
16
35
|
const TriggerClauseInput = z.object({
|
|
17
36
|
id: z.string().min(1).max(200).optional(),
|
|
18
37
|
event: z.string().min(1).max(200),
|
|
@@ -140,15 +159,121 @@ function normalizeIdentity(input, label) {
|
|
|
140
159
|
};
|
|
141
160
|
}
|
|
142
161
|
|
|
143
|
-
function
|
|
144
|
-
if (decision === true) return {
|
|
145
|
-
if (decision === false || decision == null)
|
|
162
|
+
function normalizeLegacyAuthorization(decision) {
|
|
163
|
+
if (decision === true) return { action: 'execute' };
|
|
164
|
+
if (decision === false || decision == null) {
|
|
165
|
+
return {
|
|
166
|
+
action: 'return',
|
|
167
|
+
result: {
|
|
168
|
+
ok: false,
|
|
169
|
+
error: {
|
|
170
|
+
code: 'EVENT_TRIGGER_AUTHORIZATION_DENIED',
|
|
171
|
+
message: 'Host denied durable trigger creation',
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
146
176
|
if (typeof decision !== 'object') {
|
|
147
177
|
throw new Error('authorize() must return boolean or an authorization decision');
|
|
148
178
|
}
|
|
179
|
+
if (decision.allowed === true) {
|
|
180
|
+
return {
|
|
181
|
+
action: 'execute',
|
|
182
|
+
execution: {
|
|
183
|
+
actor: decision.actor,
|
|
184
|
+
owner: decision.owner,
|
|
185
|
+
receiptId: decision.confirmationId,
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
action: 'return',
|
|
191
|
+
result: {
|
|
192
|
+
ok: false,
|
|
193
|
+
error: {
|
|
194
|
+
code: String(decision.code || 'EVENT_TRIGGER_AUTHORIZATION_DENIED'),
|
|
195
|
+
message: String(
|
|
196
|
+
decision.message || 'Host denied durable trigger creation',
|
|
197
|
+
),
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function normalizeHostControlDecision(decision) {
|
|
204
|
+
if (!decision || typeof decision !== 'object') {
|
|
205
|
+
throw new Error(
|
|
206
|
+
'Host control must return { action: "execute" } or { action: "return", result }',
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
if (decision.action === 'return') {
|
|
210
|
+
if (!decision.result || typeof decision.result.ok !== 'boolean') {
|
|
211
|
+
throw new Error('Host control return action requires a portable tool result');
|
|
212
|
+
}
|
|
213
|
+
return decision;
|
|
214
|
+
}
|
|
215
|
+
if (decision.action !== 'execute') {
|
|
216
|
+
throw new Error(
|
|
217
|
+
'Host control action must be "execute" or "return"',
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
action: 'execute',
|
|
222
|
+
execution:
|
|
223
|
+
decision.execution && typeof decision.execution === 'object'
|
|
224
|
+
? decision.execution
|
|
225
|
+
: {},
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function createResultReference(reference) {
|
|
230
|
+
if (reference == null) return undefined;
|
|
231
|
+
if (typeof reference !== 'object') {
|
|
232
|
+
throw new Error('result reference must be an object');
|
|
233
|
+
}
|
|
234
|
+
const id = String(reference.id || '').trim();
|
|
235
|
+
if (!id) throw new Error('result reference id is required');
|
|
236
|
+
return {
|
|
237
|
+
...reference,
|
|
238
|
+
id,
|
|
239
|
+
...(reference.kind == null
|
|
240
|
+
? {}
|
|
241
|
+
: { kind: String(reference.kind).trim() || undefined }),
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function projectPortableResult(projectResult, input) {
|
|
246
|
+
if (typeof projectResult !== 'function') {
|
|
247
|
+
return { ok: true, data: input.value };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const projected = await projectResult(input);
|
|
251
|
+
if (projected == null) {
|
|
252
|
+
return { ok: true, data: input.value };
|
|
253
|
+
}
|
|
254
|
+
if (typeof projected !== 'object') {
|
|
255
|
+
throw new Error('projectResult() must return an object');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const reference = createResultReference(projected.reference);
|
|
259
|
+
const hasInline = Object.prototype.hasOwnProperty.call(projected, 'inline');
|
|
260
|
+
if (!hasInline && !reference) {
|
|
261
|
+
throw new Error('projectResult() must return inline and/or reference');
|
|
262
|
+
}
|
|
263
|
+
|
|
149
264
|
return {
|
|
150
|
-
|
|
151
|
-
|
|
265
|
+
ok: true,
|
|
266
|
+
...(hasInline ? { data: projected.inline } : {}),
|
|
267
|
+
result: {
|
|
268
|
+
...(hasInline ? { inline: projected.inline } : {}),
|
|
269
|
+
...(reference ? { reference } : {}),
|
|
270
|
+
...(projected.summary == null
|
|
271
|
+
? {}
|
|
272
|
+
: { summary: String(projected.summary) }),
|
|
273
|
+
...(projected.metadata && typeof projected.metadata === 'object'
|
|
274
|
+
? { metadata: projected.metadata }
|
|
275
|
+
: {}),
|
|
276
|
+
},
|
|
152
277
|
};
|
|
153
278
|
}
|
|
154
279
|
|
|
@@ -176,6 +301,53 @@ function wakeIdFromPacket(packet) {
|
|
|
176
301
|
return typeof value === 'string' && value.trim() ? value : null;
|
|
177
302
|
}
|
|
178
303
|
|
|
304
|
+
/**
|
|
305
|
+
* Runtime-neutral registry over host-owned event connections.
|
|
306
|
+
*
|
|
307
|
+
* The host keeps credentials, transport and lifecycle ownership. EI only asks
|
|
308
|
+
* for the currently available connections and listens for topology changes.
|
|
309
|
+
*/
|
|
310
|
+
export function createEventSourceRegistry({
|
|
311
|
+
list,
|
|
312
|
+
subscribe,
|
|
313
|
+
} = {}) {
|
|
314
|
+
if (typeof list !== 'function') {
|
|
315
|
+
throw new Error('Event source registry requires list()');
|
|
316
|
+
}
|
|
317
|
+
if (subscribe !== undefined && typeof subscribe !== 'function') {
|
|
318
|
+
throw new Error('Event source registry subscribe must be a function');
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return Object.freeze({
|
|
322
|
+
list,
|
|
323
|
+
...(subscribe ? { subscribe } : {}),
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Neutral catalog for host tool exposure. It does not decide policy or adapt
|
|
329
|
+
* descriptors to any vendor SDK; the embedding runtime owns both.
|
|
330
|
+
*/
|
|
331
|
+
export function createPortableToolCatalog(tools = []) {
|
|
332
|
+
const all = Object.freeze([...tools]);
|
|
333
|
+
const byName = new Map(all.map((tool) => [tool.name, tool]));
|
|
334
|
+
|
|
335
|
+
return Object.freeze({
|
|
336
|
+
all,
|
|
337
|
+
get(name) {
|
|
338
|
+
return byName.get(name) ?? null;
|
|
339
|
+
},
|
|
340
|
+
list({ capabilityIds } = {}) {
|
|
341
|
+
if (!capabilityIds) return [...all];
|
|
342
|
+
const allowed = new Set(capabilityIds);
|
|
343
|
+
return all.filter((tool) => allowed.has(tool.capability?.id));
|
|
344
|
+
},
|
|
345
|
+
capabilities() {
|
|
346
|
+
return all.map((tool) => tool.capability).filter(Boolean);
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
179
351
|
/**
|
|
180
352
|
* A runtime-neutral continuation target. EI persists and returns this value
|
|
181
353
|
* without assigning semantics to runtime/kind/id.
|
|
@@ -338,13 +510,14 @@ function buildPlanInput(parsed, target) {
|
|
|
338
510
|
}
|
|
339
511
|
|
|
340
512
|
/**
|
|
341
|
-
* Portable agent-facing tools. The descriptors
|
|
342
|
-
*
|
|
343
|
-
* Adapters only need to translate {name, description, inputSchema, execute}.
|
|
513
|
+
* Portable agent-facing tools. The descriptors are runtime-neutral.
|
|
514
|
+
* The embedding host performs any final translation into its own tool system.
|
|
344
515
|
*/
|
|
345
516
|
export function createEventIntelligenceAgentTools({
|
|
346
517
|
host,
|
|
347
518
|
resolveContext,
|
|
519
|
+
control,
|
|
520
|
+
projectResult,
|
|
348
521
|
authorize,
|
|
349
522
|
names = {},
|
|
350
523
|
} = {}) {
|
|
@@ -354,8 +527,19 @@ export function createEventIntelligenceAgentTools({
|
|
|
354
527
|
if (typeof resolveContext !== 'function') {
|
|
355
528
|
throw new Error('Agent tools require resolveContext()');
|
|
356
529
|
}
|
|
357
|
-
if (typeof
|
|
358
|
-
throw new Error('Agent tools
|
|
530
|
+
if (control !== undefined && typeof control !== 'function') {
|
|
531
|
+
throw new Error('Agent tools control must be a function');
|
|
532
|
+
}
|
|
533
|
+
if (authorize !== undefined && typeof authorize !== 'function') {
|
|
534
|
+
throw new Error('Agent tools authorize must be a function');
|
|
535
|
+
}
|
|
536
|
+
if (!control && !authorize) {
|
|
537
|
+
throw new Error(
|
|
538
|
+
'Durable mutations require a host control() callback',
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
if (projectResult !== undefined && typeof projectResult !== 'function') {
|
|
542
|
+
throw new Error('Agent tools projectResult must be a function');
|
|
359
543
|
}
|
|
360
544
|
|
|
361
545
|
const toolNames = {
|
|
@@ -363,30 +547,40 @@ export function createEventIntelligenceAgentTools({
|
|
|
363
547
|
...names,
|
|
364
548
|
};
|
|
365
549
|
|
|
550
|
+
const sourcesCapability =
|
|
551
|
+
EVENT_INTELLIGENCE_CAPABILITIES.eventSourcesList;
|
|
552
|
+
const createCapability =
|
|
553
|
+
EVENT_INTELLIGENCE_CAPABILITIES.triggerCreate;
|
|
554
|
+
|
|
366
555
|
return [
|
|
367
556
|
{
|
|
368
557
|
name: toolNames.sources,
|
|
369
558
|
description:
|
|
370
|
-
'List live future-event sources discovered from
|
|
559
|
+
'List live future-event sources discovered from event connections already owned by the host runtime. Use this before creating a trigger so event names and schemas are not guessed.',
|
|
371
560
|
inputSchema: SOURCES_INPUT_SCHEMA,
|
|
561
|
+
capability: sourcesCapability,
|
|
372
562
|
async execute(_args, runtimeContext) {
|
|
373
563
|
try {
|
|
374
564
|
const resolved = await resolveContext(runtimeContext, {
|
|
375
565
|
action: 'event.sources.list',
|
|
566
|
+
capability: sourcesCapability,
|
|
376
567
|
});
|
|
377
568
|
if (typeof host.refreshMcpRegistry === 'function') {
|
|
378
569
|
await host.refreshMcpRegistry();
|
|
379
570
|
}
|
|
380
571
|
const scoped = await scopedHostFor(host, resolved);
|
|
381
572
|
const sources = await Promise.resolve(scoped.eventSources);
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
? sources.map(sourceSummary)
|
|
387
|
-
: [],
|
|
388
|
-
},
|
|
573
|
+
const value = {
|
|
574
|
+
sources: Array.isArray(sources)
|
|
575
|
+
? sources.map(sourceSummary)
|
|
576
|
+
: [],
|
|
389
577
|
};
|
|
578
|
+
return await projectPortableResult(projectResult, {
|
|
579
|
+
capability: sourcesCapability,
|
|
580
|
+
runtimeContext,
|
|
581
|
+
context: resolved,
|
|
582
|
+
value,
|
|
583
|
+
});
|
|
390
584
|
} catch (error) {
|
|
391
585
|
return fail(error, 'EVENT_SOURCES_LIST_FAILED');
|
|
392
586
|
}
|
|
@@ -395,8 +589,9 @@ export function createEventIntelligenceAgentTools({
|
|
|
395
589
|
{
|
|
396
590
|
name: toolNames.create,
|
|
397
591
|
description:
|
|
398
|
-
'Create a durable future condition. The host
|
|
592
|
+
'Create a durable future condition. The host supplies continuation, control and identity context; Event Intelligence wakes the opaque continuation target only when the condition matches.',
|
|
399
593
|
inputSchema: CREATE_INPUT_SCHEMA,
|
|
594
|
+
capability: createCapability,
|
|
400
595
|
async execute(args, runtimeContext) {
|
|
401
596
|
const parsed = TriggerCreateInput.safeParse(args ?? {});
|
|
402
597
|
if (!parsed.success) {
|
|
@@ -411,53 +606,69 @@ export function createEventIntelligenceAgentTools({
|
|
|
411
606
|
};
|
|
412
607
|
}
|
|
413
608
|
|
|
609
|
+
let resolved;
|
|
610
|
+
let scoped;
|
|
611
|
+
let plan;
|
|
414
612
|
try {
|
|
415
|
-
|
|
613
|
+
resolved = await resolveContext(runtimeContext, {
|
|
416
614
|
action: 'trigger.create',
|
|
615
|
+
capability: createCapability,
|
|
417
616
|
input: parsed.data,
|
|
418
617
|
});
|
|
419
618
|
const target = createContinuationTarget(resolved?.target);
|
|
420
619
|
if (typeof host.refreshMcpRegistry === 'function') {
|
|
421
620
|
await host.refreshMcpRegistry();
|
|
422
621
|
}
|
|
423
|
-
|
|
424
|
-
|
|
622
|
+
scoped = await scopedHostFor(host, resolved);
|
|
623
|
+
plan = await scoped.planTrigger(
|
|
425
624
|
buildPlanInput(parsed.data, target),
|
|
426
625
|
);
|
|
626
|
+
} catch (error) {
|
|
627
|
+
return fail(error, 'EVENT_TRIGGER_PLAN_FAILED');
|
|
628
|
+
}
|
|
427
629
|
|
|
428
|
-
|
|
429
|
-
|
|
630
|
+
// Host control is intentionally outside EI's error-normalization
|
|
631
|
+
// boundary. A runtime may return an opaque result or throw its native
|
|
632
|
+
// interrupt/suspension signal; EI must not reinterpret that mechanism.
|
|
633
|
+
const rawDecision = control
|
|
634
|
+
? await control({
|
|
635
|
+
capability: createCapability,
|
|
430
636
|
action: 'trigger.create',
|
|
431
637
|
runtimeContext,
|
|
432
638
|
context: resolved,
|
|
433
639
|
input: parsed.data,
|
|
434
640
|
plan,
|
|
435
|
-
})
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
641
|
+
})
|
|
642
|
+
: normalizeLegacyAuthorization(
|
|
643
|
+
await authorize({
|
|
644
|
+
action: 'trigger.create',
|
|
645
|
+
runtimeContext,
|
|
646
|
+
context: resolved,
|
|
647
|
+
input: parsed.data,
|
|
648
|
+
plan,
|
|
649
|
+
}),
|
|
650
|
+
);
|
|
651
|
+
const decision = normalizeHostControlDecision(rawDecision);
|
|
652
|
+
|
|
653
|
+
if (decision.action === 'return') {
|
|
654
|
+
return decision.result;
|
|
655
|
+
}
|
|
450
656
|
|
|
657
|
+
try {
|
|
658
|
+
const execution = decision.execution ?? {};
|
|
451
659
|
const actor = normalizeIdentity(
|
|
452
|
-
|
|
660
|
+
execution.actor ?? resolved?.actor,
|
|
453
661
|
'actor',
|
|
454
662
|
);
|
|
455
663
|
const owner = normalizeIdentity(
|
|
456
|
-
|
|
664
|
+
execution.owner ?? resolved?.owner,
|
|
457
665
|
'owner',
|
|
458
666
|
);
|
|
459
667
|
const confirmationId = String(
|
|
460
|
-
|
|
668
|
+
execution.receiptId ??
|
|
669
|
+
execution.confirmationId ??
|
|
670
|
+
resolved?.confirmationId ??
|
|
671
|
+
'',
|
|
461
672
|
).trim();
|
|
462
673
|
|
|
463
674
|
const created = await scoped.triggerControl.createTrigger({
|
|
@@ -468,17 +679,21 @@ export function createEventIntelligenceAgentTools({
|
|
|
468
679
|
...(confirmationId ? { confirmationId } : {}),
|
|
469
680
|
});
|
|
470
681
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
connectionIds: plan.connectionIds,
|
|
479
|
-
warnings: plan.warnings ?? [],
|
|
480
|
-
},
|
|
682
|
+
const value = {
|
|
683
|
+
receiptId: created.receiptId,
|
|
684
|
+
triggerId: created.definition?.triggerId,
|
|
685
|
+
version: created.definition?.version,
|
|
686
|
+
state: created.state,
|
|
687
|
+
connectionIds: plan.connectionIds,
|
|
688
|
+
warnings: plan.warnings ?? [],
|
|
481
689
|
};
|
|
690
|
+
|
|
691
|
+
return await projectPortableResult(projectResult, {
|
|
692
|
+
capability: createCapability,
|
|
693
|
+
runtimeContext,
|
|
694
|
+
context: resolved,
|
|
695
|
+
value,
|
|
696
|
+
});
|
|
482
697
|
} catch (error) {
|
|
483
698
|
return fail(error, 'EVENT_TRIGGER_CREATE_FAILED');
|
|
484
699
|
}
|
|
@@ -564,4 +779,91 @@ export async function createEmbeddedEventIntelligence({
|
|
|
564
779
|
};
|
|
565
780
|
}
|
|
566
781
|
|
|
567
|
-
|
|
782
|
+
|
|
783
|
+
/**
|
|
784
|
+
* Runtime-level composition over the lower-level embedded host kit.
|
|
785
|
+
*
|
|
786
|
+
* This is deliberately not an adapter for any named runtime. It returns
|
|
787
|
+
* neutral tool descriptors + capability metadata; the embedding host decides
|
|
788
|
+
* how those descriptors are exposed to its model/tool system.
|
|
789
|
+
*/
|
|
790
|
+
export async function createEmbeddedRuntimeIntegration({
|
|
791
|
+
dataDir,
|
|
792
|
+
store,
|
|
793
|
+
env = {},
|
|
794
|
+
eventSources,
|
|
795
|
+
mcpClients = [],
|
|
796
|
+
semanticEvaluator,
|
|
797
|
+
activation,
|
|
798
|
+
wake,
|
|
799
|
+
wakeHandlers = {},
|
|
800
|
+
tooling,
|
|
801
|
+
createHost = createEventIntelligenceHost,
|
|
802
|
+
} = {}) {
|
|
803
|
+
if (tooling !== undefined && (!tooling || typeof tooling !== 'object')) {
|
|
804
|
+
throw new Error('tooling must be an object when provided');
|
|
805
|
+
}
|
|
806
|
+
if (tooling && typeof tooling.resolveContext !== 'function') {
|
|
807
|
+
throw new Error('tooling.resolveContext() is required');
|
|
808
|
+
}
|
|
809
|
+
if (tooling && typeof tooling.control !== 'function') {
|
|
810
|
+
throw new Error(
|
|
811
|
+
'tooling.control() is required for host-owned mutation control',
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
if (
|
|
815
|
+
tooling?.projectResult !== undefined &&
|
|
816
|
+
typeof tooling.projectResult !== 'function'
|
|
817
|
+
) {
|
|
818
|
+
throw new Error('tooling.projectResult must be a function');
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
const sourceRegistry = eventSources
|
|
822
|
+
? createEventSourceRegistry(eventSources)
|
|
823
|
+
: null;
|
|
824
|
+
|
|
825
|
+
const embedded = await createEmbeddedEventIntelligence({
|
|
826
|
+
dataDir,
|
|
827
|
+
store,
|
|
828
|
+
env,
|
|
829
|
+
...(sourceRegistry
|
|
830
|
+
? {
|
|
831
|
+
mcpRegistry: createMcpRegistryAdapter({
|
|
832
|
+
listConnections: () => sourceRegistry.list(),
|
|
833
|
+
...(typeof sourceRegistry.subscribe === 'function'
|
|
834
|
+
? { subscribe: (listener) => sourceRegistry.subscribe(listener) }
|
|
835
|
+
: {}),
|
|
836
|
+
}),
|
|
837
|
+
}
|
|
838
|
+
: {}),
|
|
839
|
+
mcpClients,
|
|
840
|
+
semanticEvaluator,
|
|
841
|
+
activation,
|
|
842
|
+
wake,
|
|
843
|
+
wakeHandlers,
|
|
844
|
+
createHost,
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
const tools = tooling
|
|
848
|
+
? createEventIntelligenceAgentTools({
|
|
849
|
+
host: embedded.host,
|
|
850
|
+
resolveContext: tooling.resolveContext,
|
|
851
|
+
control: tooling.control,
|
|
852
|
+
...(tooling.projectResult
|
|
853
|
+
? { projectResult: tooling.projectResult }
|
|
854
|
+
: {}),
|
|
855
|
+
names: tooling.names ?? {},
|
|
856
|
+
})
|
|
857
|
+
: [];
|
|
858
|
+
const toolCatalog = createPortableToolCatalog(tools);
|
|
859
|
+
|
|
860
|
+
return Object.freeze({
|
|
861
|
+
...embedded,
|
|
862
|
+
tools: toolCatalog.all,
|
|
863
|
+
toolCatalog,
|
|
864
|
+
capabilities: Object.freeze(toolCatalog.capabilities()),
|
|
865
|
+
eventSources: sourceRegistry,
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
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.8.0",
|
|
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.8.0",
|
|
17
17
|
"transport": {
|
|
18
18
|
"type": "stdio"
|
|
19
19
|
},
|