@kadi.build/core 0.0.1-alpha.8 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +362 -1305
- package/dist/client.d.ts +573 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +1673 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +107 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +147 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +37 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -23
- package/dist/index.js.map +1 -1
- package/dist/lockfile.d.ts +190 -0
- package/dist/lockfile.d.ts.map +1 -0
- package/dist/lockfile.js +373 -0
- package/dist/lockfile.js.map +1 -0
- package/dist/transports/broker.d.ts +75 -0
- package/dist/transports/broker.d.ts.map +1 -0
- package/dist/transports/broker.js +383 -0
- package/dist/transports/broker.js.map +1 -0
- package/dist/transports/native.d.ts +39 -0
- package/dist/transports/native.d.ts.map +1 -0
- package/dist/transports/native.js +189 -0
- package/dist/transports/native.js.map +1 -0
- package/dist/transports/stdio.d.ts +46 -0
- package/dist/transports/stdio.d.ts.map +1 -0
- package/dist/transports/stdio.js +460 -0
- package/dist/transports/stdio.js.map +1 -0
- package/dist/types.d.ts +664 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/zod.d.ts +34 -0
- package/dist/zod.d.ts.map +1 -0
- package/dist/zod.js +60 -0
- package/dist/zod.js.map +1 -0
- package/package.json +13 -28
- package/dist/KadiClient.d.ts +0 -432
- package/dist/KadiClient.d.ts.map +0 -1
- package/dist/KadiClient.js +0 -1506
- package/dist/KadiClient.js.map +0 -1
- package/dist/errors/error-codes.d.ts +0 -985
- package/dist/errors/error-codes.d.ts.map +0 -1
- package/dist/errors/error-codes.js +0 -638
- package/dist/errors/error-codes.js.map +0 -1
- package/dist/loadAbility.d.ts +0 -105
- package/dist/loadAbility.d.ts.map +0 -1
- package/dist/loadAbility.js +0 -370
- package/dist/loadAbility.js.map +0 -1
- package/dist/messages/BrokerMessages.d.ts +0 -84
- package/dist/messages/BrokerMessages.d.ts.map +0 -1
- package/dist/messages/BrokerMessages.js +0 -125
- package/dist/messages/BrokerMessages.js.map +0 -1
- package/dist/messages/MessageBuilder.d.ts +0 -83
- package/dist/messages/MessageBuilder.d.ts.map +0 -1
- package/dist/messages/MessageBuilder.js +0 -144
- package/dist/messages/MessageBuilder.js.map +0 -1
- package/dist/schemas/events.schemas.d.ts +0 -177
- package/dist/schemas/events.schemas.d.ts.map +0 -1
- package/dist/schemas/events.schemas.js +0 -265
- package/dist/schemas/events.schemas.js.map +0 -1
- package/dist/schemas/index.d.ts +0 -3
- package/dist/schemas/index.d.ts.map +0 -1
- package/dist/schemas/index.js +0 -4
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/kadi.schemas.d.ts +0 -70
- package/dist/schemas/kadi.schemas.d.ts.map +0 -1
- package/dist/schemas/kadi.schemas.js +0 -120
- package/dist/schemas/kadi.schemas.js.map +0 -1
- package/dist/transports/BrokerTransport.d.ts +0 -102
- package/dist/transports/BrokerTransport.d.ts.map +0 -1
- package/dist/transports/BrokerTransport.js +0 -177
- package/dist/transports/BrokerTransport.js.map +0 -1
- package/dist/transports/NativeTransport.d.ts +0 -82
- package/dist/transports/NativeTransport.d.ts.map +0 -1
- package/dist/transports/NativeTransport.js +0 -263
- package/dist/transports/NativeTransport.js.map +0 -1
- package/dist/transports/StdioTransport.d.ts +0 -112
- package/dist/transports/StdioTransport.d.ts.map +0 -1
- package/dist/transports/StdioTransport.js +0 -450
- package/dist/transports/StdioTransport.js.map +0 -1
- package/dist/transports/Transport.d.ts +0 -93
- package/dist/transports/Transport.d.ts.map +0 -1
- package/dist/transports/Transport.js +0 -13
- package/dist/transports/Transport.js.map +0 -1
- package/dist/types/broker.d.ts +0 -31
- package/dist/types/broker.d.ts.map +0 -1
- package/dist/types/broker.js +0 -6
- package/dist/types/broker.js.map +0 -1
- package/dist/types/core.d.ts +0 -139
- package/dist/types/core.d.ts.map +0 -1
- package/dist/types/core.js +0 -26
- package/dist/types/core.js.map +0 -1
- package/dist/types/events.d.ts +0 -186
- package/dist/types/events.d.ts.map +0 -1
- package/dist/types/events.js +0 -16
- package/dist/types/events.js.map +0 -1
- package/dist/types/index.d.ts +0 -9
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -13
- package/dist/types/index.js.map +0 -1
- package/dist/types/protocol.d.ts +0 -160
- package/dist/types/protocol.d.ts.map +0 -1
- package/dist/types/protocol.js +0 -5
- package/dist/types/protocol.js.map +0 -1
- package/dist/utils/agentUtils.d.ts +0 -187
- package/dist/utils/agentUtils.d.ts.map +0 -1
- package/dist/utils/agentUtils.js +0 -185
- package/dist/utils/agentUtils.js.map +0 -1
- package/dist/utils/commandUtils.d.ts +0 -45
- package/dist/utils/commandUtils.d.ts.map +0 -1
- package/dist/utils/commandUtils.js +0 -145
- package/dist/utils/commandUtils.js.map +0 -1
- package/dist/utils/configUtils.d.ts +0 -55
- package/dist/utils/configUtils.d.ts.map +0 -1
- package/dist/utils/configUtils.js +0 -100
- package/dist/utils/configUtils.js.map +0 -1
- package/dist/utils/logger.d.ts +0 -59
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js +0 -122
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/pathUtils.d.ts +0 -48
- package/dist/utils/pathUtils.d.ts.map +0 -1
- package/dist/utils/pathUtils.js +0 -128
- package/dist/utils/pathUtils.js.map +0 -1
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KadiClient for kadi-core v0.1.0
|
|
3
|
+
*
|
|
4
|
+
* The main entry point for building KADI agents.
|
|
5
|
+
* This client handles:
|
|
6
|
+
* - Broker connections (WebSocket with Ed25519 authentication)
|
|
7
|
+
* - Tool registration (local tools that can be invoked remotely)
|
|
8
|
+
* - Ability loading (native, stdio, broker transports)
|
|
9
|
+
* - Remote invocation (call tools on other agents)
|
|
10
|
+
* - Serve modes (stdio server, broker server)
|
|
11
|
+
*
|
|
12
|
+
* Design principles:
|
|
13
|
+
* - Named brokers with optional defaultBroker
|
|
14
|
+
* - Explicit over implicit (no proxy magic)
|
|
15
|
+
* - Readable, traceable code flow
|
|
16
|
+
*/
|
|
17
|
+
import type { ClientConfig, BrokerState, ToolDefinition, ZodToolDefinition, ToolHandler, LoadedAbility, RegisterToolOptions, LoadNativeOptions, LoadStdioOptions, LoadBrokerOptions, InvokeRemoteOptions, BrokerEventHandler, PublishOptions, SubscribeOptions } from './types.js';
|
|
18
|
+
/**
|
|
19
|
+
* The main client for building KADI agents.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* // Create a client with named brokers
|
|
24
|
+
* const client = new KadiClient({
|
|
25
|
+
* name: 'my-agent',
|
|
26
|
+
* brokers: {
|
|
27
|
+
* production: 'ws://broker-prod:8080',
|
|
28
|
+
* internal: 'ws://broker-internal:8080',
|
|
29
|
+
* },
|
|
30
|
+
* defaultBroker: 'production',
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* // Register a tool
|
|
34
|
+
* client.registerTool({
|
|
35
|
+
* name: 'add',
|
|
36
|
+
* description: 'Add two numbers',
|
|
37
|
+
* input: z.object({ a: z.number(), b: z.number() }),
|
|
38
|
+
* }, async ({ a, b }) => ({ result: a + b }));
|
|
39
|
+
*
|
|
40
|
+
* // Connect to brokers
|
|
41
|
+
* await client.connect();
|
|
42
|
+
*
|
|
43
|
+
* // Load and use abilities
|
|
44
|
+
* const calc = await client.loadNative('calculator');
|
|
45
|
+
* const result = await calc.invoke('multiply', { x: 5, y: 3 });
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare class KadiClient {
|
|
49
|
+
/** Resolved configuration with defaults applied */
|
|
50
|
+
private readonly config;
|
|
51
|
+
/** Registered tools (local tools this agent provides) */
|
|
52
|
+
private readonly tools;
|
|
53
|
+
/** Broker connections by name */
|
|
54
|
+
private readonly brokers;
|
|
55
|
+
/** Counter for generating unique request IDs */
|
|
56
|
+
private nextRequestId;
|
|
57
|
+
/** Event handler callback (set by native transport) */
|
|
58
|
+
private eventHandler;
|
|
59
|
+
/** Whether we're serving via stdio (set by serve('stdio')) */
|
|
60
|
+
private isServingStdio;
|
|
61
|
+
constructor(config: ClientConfig);
|
|
62
|
+
/**
|
|
63
|
+
* Connect to all configured brokers.
|
|
64
|
+
* Call this after registering tools.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* await client.connect(); // Connects to all brokers
|
|
69
|
+
* await client.connect('production'); // Connect to specific broker
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
connect(brokerName?: string): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Connect to a specific broker by name.
|
|
75
|
+
*
|
|
76
|
+
* Protocol:
|
|
77
|
+
* 1. Generate Ed25519 keypair
|
|
78
|
+
* 2. Open WebSocket connection
|
|
79
|
+
* 3. Send kadi.session.hello
|
|
80
|
+
* 4. Receive nonce from broker
|
|
81
|
+
* 5. Send kadi.session.authenticate with signed nonce
|
|
82
|
+
* 6. Receive agentId from broker
|
|
83
|
+
* 7. Register tools with broker
|
|
84
|
+
* 8. Start heartbeat
|
|
85
|
+
*/
|
|
86
|
+
private connectToBroker;
|
|
87
|
+
private buildHelloMessage;
|
|
88
|
+
private buildAuthMessage;
|
|
89
|
+
private buildRegisterMessage;
|
|
90
|
+
private buildHeartbeatMessage;
|
|
91
|
+
/**
|
|
92
|
+
* Open WebSocket connection to broker.
|
|
93
|
+
*/
|
|
94
|
+
private openWebSocket;
|
|
95
|
+
/**
|
|
96
|
+
* Perform handshake: hello → authenticate.
|
|
97
|
+
*
|
|
98
|
+
* Protocol:
|
|
99
|
+
* 1. Client sends kadi.session.hello
|
|
100
|
+
* 2. Broker responds with { nonce: "..." }
|
|
101
|
+
* 3. Client signs nonce and sends kadi.session.authenticate
|
|
102
|
+
* 4. Broker responds with { agentId: "..." }
|
|
103
|
+
*/
|
|
104
|
+
private performHandshake;
|
|
105
|
+
/**
|
|
106
|
+
* Register with broker after authentication.
|
|
107
|
+
*
|
|
108
|
+
* This transitions the session from "authenticated" to "ready" state.
|
|
109
|
+
* Must be called even if no tools are registered - the broker requires
|
|
110
|
+
* the agent to be in "ready" state before it can invoke remote tools.
|
|
111
|
+
*/
|
|
112
|
+
private registerWithBroker;
|
|
113
|
+
/**
|
|
114
|
+
* Send a JSON-RPC request and wait for the response.
|
|
115
|
+
*
|
|
116
|
+
* Design: Returns the result directly (not the full JSON-RPC response).
|
|
117
|
+
*
|
|
118
|
+
* Why? The JSON-RPC envelope (jsonrpc, id) is transport metadata.
|
|
119
|
+
* Once we've matched the response to the pending request, that metadata
|
|
120
|
+
* has served its purpose. Callers care about the result, not the envelope.
|
|
121
|
+
*
|
|
122
|
+
* Errors are handled via Promise rejection in handleBrokerResponse,
|
|
123
|
+
* so by the time this resolves, we know it's a successful response.
|
|
124
|
+
*
|
|
125
|
+
* IMPORTANT: The type parameter T is NOT validated at runtime.
|
|
126
|
+
* It provides TypeScript type hints but the broker could return any shape.
|
|
127
|
+
* Callers MUST validate critical fields before using them.
|
|
128
|
+
*
|
|
129
|
+
* @template T - Expected type of the result (defaults to unknown for safety)
|
|
130
|
+
* @param state - Broker connection state
|
|
131
|
+
* @param request - JSON-RPC request to send
|
|
132
|
+
* @returns Promise resolving to the typed result
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* // Caller specifies expected result type
|
|
137
|
+
* const result = await this.sendRequest<{ nonce: string }>(state, helloMessage);
|
|
138
|
+
* // IMPORTANT: Validate before using - the type is not runtime-enforced
|
|
139
|
+
* if (!result.nonce) throw new Error('Missing nonce');
|
|
140
|
+
* console.log(result.nonce);
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
private sendRequest;
|
|
144
|
+
/**
|
|
145
|
+
* Handle incoming messages from broker.
|
|
146
|
+
*/
|
|
147
|
+
private handleBrokerMessage;
|
|
148
|
+
/**
|
|
149
|
+
* Handle kadi.ability.response notification.
|
|
150
|
+
*
|
|
151
|
+
* This is the second part of the async tool invocation pattern:
|
|
152
|
+
* 1. Client sends kadi.ability.request → gets { status: 'pending', requestId }
|
|
153
|
+
* 2. Provider executes tool and sends result back to broker
|
|
154
|
+
* 3. Broker sends this notification with the actual result
|
|
155
|
+
*
|
|
156
|
+
* The notification contains:
|
|
157
|
+
* - requestId: matches what we got in step 1
|
|
158
|
+
* - result: the tool's return value (if successful)
|
|
159
|
+
* - error: error message (if failed)
|
|
160
|
+
*/
|
|
161
|
+
private handleAbilityResponse;
|
|
162
|
+
/**
|
|
163
|
+
* Handle kadi.event.delivery notification from broker.
|
|
164
|
+
*
|
|
165
|
+
* When an event is published to a channel that matches one of our subscribed
|
|
166
|
+
* patterns, the broker sends us this notification with the event data.
|
|
167
|
+
*
|
|
168
|
+
* Flow:
|
|
169
|
+
* 1. Some agent calls publish('user.login', data)
|
|
170
|
+
* 2. Broker routes to all subscribers matching 'user.*' or 'user.#' etc.
|
|
171
|
+
* 3. We receive this notification and dispatch to local handlers
|
|
172
|
+
*
|
|
173
|
+
* The notification params contain:
|
|
174
|
+
* - channel: The exact channel name (e.g., 'user.login')
|
|
175
|
+
* - data: The event payload
|
|
176
|
+
* - networkId: Which network the event was published to
|
|
177
|
+
* - source: Session ID of the publisher
|
|
178
|
+
* - timestamp: When the event was published
|
|
179
|
+
*/
|
|
180
|
+
private handleEventDelivery;
|
|
181
|
+
/**
|
|
182
|
+
* Check if a subscription pattern matches an event channel.
|
|
183
|
+
*
|
|
184
|
+
* Pattern matching follows RabbitMQ topic exchange rules:
|
|
185
|
+
* - '*' matches exactly one word (between dots)
|
|
186
|
+
* - '#' matches zero or more words
|
|
187
|
+
* - Literal strings match exactly
|
|
188
|
+
*
|
|
189
|
+
* Examples:
|
|
190
|
+
* - 'user.*' matches 'user.login', 'user.logout', NOT 'user.profile.update'
|
|
191
|
+
* - 'user.#' matches 'user.login', 'user.profile.update', even just 'user'
|
|
192
|
+
* - 'user.login' matches only 'user.login'
|
|
193
|
+
*
|
|
194
|
+
* @param pattern - The subscription pattern (e.g., 'user.*')
|
|
195
|
+
* @param channel - The event channel (e.g., 'user.login')
|
|
196
|
+
*/
|
|
197
|
+
private patternMatchesChannel;
|
|
198
|
+
/**
|
|
199
|
+
* Recursive pattern matcher (RabbitMQ topic exchange style).
|
|
200
|
+
*
|
|
201
|
+
* Example: pattern "user.#.status" vs channel "user.profile.settings.status"
|
|
202
|
+
* → # eats "profile.settings" → match!
|
|
203
|
+
*/
|
|
204
|
+
private matchPatternRecursive;
|
|
205
|
+
/**
|
|
206
|
+
* Subscribe to events matching a pattern.
|
|
207
|
+
*
|
|
208
|
+
* Pattern matching follows RabbitMQ topic exchange rules:
|
|
209
|
+
* - '*' matches exactly one word (between dots)
|
|
210
|
+
* - '#' matches zero or more words
|
|
211
|
+
*
|
|
212
|
+
* @param pattern - Pattern to subscribe to (e.g., 'user.*', 'order.#')
|
|
213
|
+
* @param handler - Function called when matching event is received
|
|
214
|
+
* @param options - Optional: which broker to subscribe through
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* // Subscribe to all user events
|
|
219
|
+
* client.subscribe('user.*', (event) => {
|
|
220
|
+
* console.log(`User event: ${event.channel}`, event.data);
|
|
221
|
+
* });
|
|
222
|
+
*
|
|
223
|
+
* // Subscribe to all order events at any depth
|
|
224
|
+
* client.subscribe('order.#', (event) => {
|
|
225
|
+
* console.log(`Order event: ${event.channel}`, event.data);
|
|
226
|
+
* });
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
subscribe(pattern: string, handler: BrokerEventHandler, options?: SubscribeOptions): Promise<void>;
|
|
230
|
+
/**
|
|
231
|
+
* Unsubscribe from events.
|
|
232
|
+
*
|
|
233
|
+
* Removes the specified handler from the pattern. If no handlers remain
|
|
234
|
+
* for a pattern, the broker subscription is also removed.
|
|
235
|
+
*
|
|
236
|
+
* @param pattern - Pattern to unsubscribe from
|
|
237
|
+
* @param handler - The handler function to remove
|
|
238
|
+
* @param options - Optional: which broker to unsubscribe from
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```typescript
|
|
242
|
+
* const handler = (event) => console.log(event);
|
|
243
|
+
* client.subscribe('user.*', handler);
|
|
244
|
+
* // ... later
|
|
245
|
+
* client.unsubscribe('user.*', handler);
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
unsubscribe(pattern: string, handler: BrokerEventHandler, options?: SubscribeOptions): Promise<void>;
|
|
249
|
+
/**
|
|
250
|
+
* Publish an event to a channel.
|
|
251
|
+
*
|
|
252
|
+
* Events are published to a specific network. All agents subscribed to
|
|
253
|
+
* matching patterns on that network will receive the event.
|
|
254
|
+
*
|
|
255
|
+
* @param channel - Channel/topic to publish to (e.g., 'user.login')
|
|
256
|
+
* @param data - Event payload (any JSON-serializable data)
|
|
257
|
+
* @param options - Optional: network and broker to publish through
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```typescript
|
|
261
|
+
* // Publish to default network
|
|
262
|
+
* await client.publish('user.login', { userId: '123', timestamp: Date.now() });
|
|
263
|
+
*
|
|
264
|
+
* // Publish to specific network
|
|
265
|
+
* await client.publish('order.created', orderData, { network: 'internal' });
|
|
266
|
+
* ```
|
|
267
|
+
*/
|
|
268
|
+
publish(channel: string, data: unknown, options?: PublishOptions): Promise<void>;
|
|
269
|
+
/**
|
|
270
|
+
* Handle incoming request from broker (tool invocation).
|
|
271
|
+
*/
|
|
272
|
+
private handleBrokerRequest;
|
|
273
|
+
/**
|
|
274
|
+
* Handle incoming tool invocation request from broker.
|
|
275
|
+
*
|
|
276
|
+
* When callerProtocol is 'mcp', responses are formatted for MCP clients:
|
|
277
|
+
* - If result is already MCP-shaped (has valid content array), pass through unchanged
|
|
278
|
+
* - Otherwise, wrap as text: { content: [{ type: 'text', text: '...' }], isError: false }
|
|
279
|
+
*
|
|
280
|
+
* This allows tools to return images, audio, or other MCP content types directly,
|
|
281
|
+
* while plain JSON results are automatically wrapped as text.
|
|
282
|
+
*
|
|
283
|
+
* When callerProtocol is 'kadi' or undefined, raw structured data is returned.
|
|
284
|
+
*/
|
|
285
|
+
private handleInvokeRequest;
|
|
286
|
+
/**
|
|
287
|
+
* Handle response to a pending request.
|
|
288
|
+
*/
|
|
289
|
+
private handleBrokerResponse;
|
|
290
|
+
/**
|
|
291
|
+
* Send heartbeat to keep connection alive.
|
|
292
|
+
*/
|
|
293
|
+
private sendHeartbeat;
|
|
294
|
+
/**
|
|
295
|
+
* Cleanup broker connection state.
|
|
296
|
+
* Called on disconnect or connection failure.
|
|
297
|
+
*/
|
|
298
|
+
private cleanupBroker;
|
|
299
|
+
/**
|
|
300
|
+
* Handle WebSocket close event.
|
|
301
|
+
*
|
|
302
|
+
* Decides whether to attempt reconnection based on:
|
|
303
|
+
* - Was the connection ever established? (don't reconnect on initial failure)
|
|
304
|
+
* - autoReconnect config setting
|
|
305
|
+
* - Whether this was an intentional disconnect (user called disconnect())
|
|
306
|
+
*/
|
|
307
|
+
private handleWebSocketClose;
|
|
308
|
+
/**
|
|
309
|
+
* Calculate reconnection delay using exponential backoff with jitter.
|
|
310
|
+
*
|
|
311
|
+
* Formula: min(baseDelay * 2^attempt, maxDelay) ± 20% jitter
|
|
312
|
+
*
|
|
313
|
+
* Examples (with maxDelay=30s):
|
|
314
|
+
* - Attempt 0: ~1s (1000ms ± 200ms)
|
|
315
|
+
* - Attempt 1: ~2s (2000ms ± 400ms)
|
|
316
|
+
* - Attempt 2: ~4s (4000ms ± 800ms)
|
|
317
|
+
* - Attempt 3: ~8s
|
|
318
|
+
* - Attempt 4: ~16s
|
|
319
|
+
* - Attempt 5+: ~30s (capped)
|
|
320
|
+
*
|
|
321
|
+
* Why jitter? When a broker restarts and 100 agents try to reconnect,
|
|
322
|
+
* jitter spreads them out so they don't all hit at once (thundering herd).
|
|
323
|
+
*/
|
|
324
|
+
private getReconnectDelay;
|
|
325
|
+
/**
|
|
326
|
+
* Schedule a reconnection attempt.
|
|
327
|
+
*
|
|
328
|
+
* Logs the attempt number and delay for visibility.
|
|
329
|
+
*
|
|
330
|
+
* Note: Reconnection continues indefinitely until successful or
|
|
331
|
+
* disconnect() is called. There is no max attempt limit - only
|
|
332
|
+
* the delay is capped at maxReconnectDelay.
|
|
333
|
+
*/
|
|
334
|
+
private scheduleReconnect;
|
|
335
|
+
/**
|
|
336
|
+
* Attempt to reconnect to the broker.
|
|
337
|
+
*
|
|
338
|
+
* This reuses the existing keypair (agentId stays the same) and
|
|
339
|
+
* re-registers tools with the broker.
|
|
340
|
+
*
|
|
341
|
+
* On failure, schedules another attempt with increased delay.
|
|
342
|
+
*/
|
|
343
|
+
private attemptReconnect;
|
|
344
|
+
/**
|
|
345
|
+
* Disconnect from broker(s).
|
|
346
|
+
*
|
|
347
|
+
* @param brokerName - If provided, disconnect only from that broker.
|
|
348
|
+
* If not provided, disconnect from all brokers.
|
|
349
|
+
*/
|
|
350
|
+
disconnect(brokerName?: string): Promise<void>;
|
|
351
|
+
/**
|
|
352
|
+
* Internal helper to disconnect a single broker.
|
|
353
|
+
*
|
|
354
|
+
* IMPORTANT: The order of operations matters!
|
|
355
|
+
* 1. Set intentionalDisconnect BEFORE closing WebSocket
|
|
356
|
+
* 2. ws.close() triggers handleWebSocketClose(), which checks this flag
|
|
357
|
+
* 3. If the flag isn't set first, reconnection would be triggered
|
|
358
|
+
*/
|
|
359
|
+
private disconnectBroker;
|
|
360
|
+
/**
|
|
361
|
+
* Set the event handler callback.
|
|
362
|
+
* Called by native/stdio transport when loading this ability.
|
|
363
|
+
* @internal
|
|
364
|
+
*/
|
|
365
|
+
setEventHandler(handler: (event: string, data: unknown) => void): void;
|
|
366
|
+
/**
|
|
367
|
+
* Emit an event to the consumer that loaded this ability.
|
|
368
|
+
*
|
|
369
|
+
* Events are fire-and-forget notifications - the consumer does not
|
|
370
|
+
* send a response. Use this for real-time updates, state changes,
|
|
371
|
+
* or any notification that doesn't require a response.
|
|
372
|
+
*
|
|
373
|
+
* @param event - Event name (e.g., 'file.changed', 'user.login')
|
|
374
|
+
* @param data - Event payload
|
|
375
|
+
*
|
|
376
|
+
* @example
|
|
377
|
+
* ```typescript
|
|
378
|
+
* // Emit an event when something happens
|
|
379
|
+
* client.emit('file.changed', { path: '/tmp/foo.txt', action: 'modified' });
|
|
380
|
+
*
|
|
381
|
+
* // Emit progress updates
|
|
382
|
+
* client.emit('job.progress', { percent: 50, message: 'Halfway done' });
|
|
383
|
+
* ```
|
|
384
|
+
*/
|
|
385
|
+
emit(event: string, data: unknown): void;
|
|
386
|
+
/**
|
|
387
|
+
* Register a tool with this agent.
|
|
388
|
+
*
|
|
389
|
+
* @param definition - Tool definition (with Zod schemas)
|
|
390
|
+
* @param handler - Function to handle invocations
|
|
391
|
+
* @param options - Registration options (broker targeting)
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* ```typescript
|
|
395
|
+
* client.registerTool({
|
|
396
|
+
* name: 'add',
|
|
397
|
+
* description: 'Add two numbers',
|
|
398
|
+
* input: z.object({ a: z.number(), b: z.number() }),
|
|
399
|
+
* output: z.object({ result: z.number() }),
|
|
400
|
+
* }, async ({ a, b }) => ({ result: a + b }));
|
|
401
|
+
*
|
|
402
|
+
* // Register only on specific broker
|
|
403
|
+
* client.registerTool(def, handler, { brokers: ['internal'] });
|
|
404
|
+
* ```
|
|
405
|
+
*/
|
|
406
|
+
registerTool<TInput, TOutput>(definition: ZodToolDefinition<TInput, TOutput>, handler: ToolHandler<TInput, TOutput>, options?: RegisterToolOptions): void;
|
|
407
|
+
/**
|
|
408
|
+
*/
|
|
409
|
+
/**
|
|
410
|
+
* Get tool definitions, optionally filtered for a specific broker.
|
|
411
|
+
*
|
|
412
|
+
* @param forBroker - If provided, only return tools targeted for this broker.
|
|
413
|
+
* Tools with empty targetBrokers are included for all brokers.
|
|
414
|
+
*/
|
|
415
|
+
private getToolDefinitions;
|
|
416
|
+
/**
|
|
417
|
+
* Invoke a local tool by name.
|
|
418
|
+
*/
|
|
419
|
+
invoke(toolName: string, params: unknown): Promise<unknown>;
|
|
420
|
+
/**
|
|
421
|
+
* Load an in-process ability via dynamic import.
|
|
422
|
+
*
|
|
423
|
+
* @param name - Ability name (resolved from agent-lock.json)
|
|
424
|
+
* @param options - Optional explicit path
|
|
425
|
+
*
|
|
426
|
+
* @example
|
|
427
|
+
* ```typescript
|
|
428
|
+
* // Load by name (resolves from agent-lock.json)
|
|
429
|
+
* const calc = await client.loadNative('calculator');
|
|
430
|
+
*
|
|
431
|
+
* // Load by explicit path
|
|
432
|
+
* const calc = await client.loadNative('calculator', { path: './abilities/calc' });
|
|
433
|
+
* ```
|
|
434
|
+
*/
|
|
435
|
+
loadNative(name: string, options?: LoadNativeOptions): Promise<LoadedAbility>;
|
|
436
|
+
/**
|
|
437
|
+
* Load a child process ability via stdio.
|
|
438
|
+
*
|
|
439
|
+
* Three modes of operation:
|
|
440
|
+
*
|
|
441
|
+
* 1. **Explicit mode** — Provide `command` and `args` directly (bypasses agent.json):
|
|
442
|
+
* ```typescript
|
|
443
|
+
* await client.loadStdio('analyzer', {
|
|
444
|
+
* command: 'python3',
|
|
445
|
+
* args: ['./analyzer/main.py', '--verbose'],
|
|
446
|
+
* });
|
|
447
|
+
* ```
|
|
448
|
+
*
|
|
449
|
+
* 2. **Script selection mode** — Choose which script from ability's agent.json:
|
|
450
|
+
* ```typescript
|
|
451
|
+
* await client.loadStdio('analyzer', { script: 'dev' });
|
|
452
|
+
* // Uses scripts.dev from the ability's agent.json
|
|
453
|
+
* ```
|
|
454
|
+
*
|
|
455
|
+
* 3. **Default mode** — Uses scripts.start from ability's agent.json:
|
|
456
|
+
* ```typescript
|
|
457
|
+
* await client.loadStdio('analyzer');
|
|
458
|
+
* // Resolves from agent-lock.json, reads scripts.start from agent.json
|
|
459
|
+
* ```
|
|
460
|
+
*
|
|
461
|
+
* @param name - Ability name (used for error messages and lock file lookup)
|
|
462
|
+
* @param options - Command/args override, or script selection
|
|
463
|
+
*/
|
|
464
|
+
loadStdio(name: string, options?: LoadStdioOptions): Promise<LoadedAbility>;
|
|
465
|
+
/**
|
|
466
|
+
* Load a remote ability via broker.
|
|
467
|
+
*
|
|
468
|
+
* @param name - Ability name to discover on broker
|
|
469
|
+
* @param options - Broker to use, networks to filter
|
|
470
|
+
*
|
|
471
|
+
* @example
|
|
472
|
+
* ```typescript
|
|
473
|
+
* // Load from default broker
|
|
474
|
+
* const ai = await client.loadBroker('text-analyzer');
|
|
475
|
+
*
|
|
476
|
+
* // Load from specific broker
|
|
477
|
+
* const ai = await client.loadBroker('text-analyzer', { broker: 'internal' });
|
|
478
|
+
* ```
|
|
479
|
+
*/
|
|
480
|
+
loadBroker(name: string, options?: LoadBrokerOptions): Promise<LoadedAbility>;
|
|
481
|
+
/**
|
|
482
|
+
* Invoke a tool on a remote agent directly (without loading the ability).
|
|
483
|
+
*
|
|
484
|
+
* This uses the KADI async invocation pattern:
|
|
485
|
+
* 1. Send kadi.ability.request → broker immediately returns { status: 'pending', requestId }
|
|
486
|
+
* 2. Broker forwards request to provider agent
|
|
487
|
+
* 3. Provider executes tool and sends result back to broker
|
|
488
|
+
* 4. Broker sends kadi.ability.response notification with the actual result
|
|
489
|
+
*
|
|
490
|
+
* @param toolName - Tool name (e.g., "add"). Broker routes to any provider.
|
|
491
|
+
* @param params - Tool parameters
|
|
492
|
+
* @param options - Broker to use, timeout
|
|
493
|
+
*
|
|
494
|
+
* @example
|
|
495
|
+
* ```typescript
|
|
496
|
+
* // Invoke on default broker (broker finds any provider)
|
|
497
|
+
* const result = await client.invokeRemote('add', { a: 5, b: 3 });
|
|
498
|
+
*
|
|
499
|
+
* // Invoke on specific broker
|
|
500
|
+
* const result = await client.invokeRemote('analyze', { text: 'hi' }, {
|
|
501
|
+
* broker: 'internal',
|
|
502
|
+
* });
|
|
503
|
+
* ```
|
|
504
|
+
*/
|
|
505
|
+
invokeRemote<T = unknown>(toolName: string, params: unknown, options?: InvokeRemoteOptions): Promise<T>;
|
|
506
|
+
/**
|
|
507
|
+
* Start serving this agent.
|
|
508
|
+
*
|
|
509
|
+
* @param mode - 'stdio' for JSON-RPC over stdin/stdout, 'broker' for broker connection
|
|
510
|
+
*
|
|
511
|
+
* @example
|
|
512
|
+
* ```typescript
|
|
513
|
+
* // Serve as a stdio server (for loadStdio)
|
|
514
|
+
* await client.serve('stdio');
|
|
515
|
+
*
|
|
516
|
+
* // Serve via broker (connects and waits)
|
|
517
|
+
* await client.serve('broker');
|
|
518
|
+
* ```
|
|
519
|
+
*/
|
|
520
|
+
serve(mode: 'stdio' | 'broker'): Promise<void>;
|
|
521
|
+
/**
|
|
522
|
+
* Serve as a stdio server (JSON-RPC over stdin/stdout).
|
|
523
|
+
*
|
|
524
|
+
* Steps:
|
|
525
|
+
* 1. Redirect console.log to stderr (keeps stdout clean for JSON-RPC)
|
|
526
|
+
* 2. Set up binary-safe buffer for message parsing
|
|
527
|
+
* 3. Set up signal handlers for graceful shutdown
|
|
528
|
+
* 4. Process incoming messages
|
|
529
|
+
*/
|
|
530
|
+
private serveStdio;
|
|
531
|
+
/**
|
|
532
|
+
* Handle a stdio message.
|
|
533
|
+
*/
|
|
534
|
+
private handleStdioMessage;
|
|
535
|
+
/**
|
|
536
|
+
* Send a response via stdio.
|
|
537
|
+
*/
|
|
538
|
+
private sendStdioResponse;
|
|
539
|
+
/**
|
|
540
|
+
* Send an error response via stdio.
|
|
541
|
+
*/
|
|
542
|
+
private sendStdioError;
|
|
543
|
+
/**
|
|
544
|
+
* Serve via broker (connect and wait for requests).
|
|
545
|
+
*
|
|
546
|
+
* Connects to configured brokers and waits for incoming tool requests.
|
|
547
|
+
* Sets up graceful shutdown to disconnect loaded abilities.
|
|
548
|
+
*/
|
|
549
|
+
private serveBroker;
|
|
550
|
+
/**
|
|
551
|
+
* Get agent information (for readAgentJson protocol).
|
|
552
|
+
*/
|
|
553
|
+
readAgentJson(): {
|
|
554
|
+
name: string;
|
|
555
|
+
version: string;
|
|
556
|
+
tools: ToolDefinition[];
|
|
557
|
+
};
|
|
558
|
+
/**
|
|
559
|
+
* Get broker connection state (for broker transport).
|
|
560
|
+
*/
|
|
561
|
+
getBrokerState(brokerName: string): BrokerState | undefined;
|
|
562
|
+
/**
|
|
563
|
+
* Check if connected to a specific broker or any broker.
|
|
564
|
+
*
|
|
565
|
+
* @param brokerName - Optional broker name to check. If not specified, checks any.
|
|
566
|
+
*/
|
|
567
|
+
isConnected(brokerName?: string): boolean;
|
|
568
|
+
/**
|
|
569
|
+
* Get list of connected broker names.
|
|
570
|
+
*/
|
|
571
|
+
getConnectedBrokers(): string[];
|
|
572
|
+
}
|
|
573
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|