@kadi.build/core 0.0.1-alpha.3 → 0.0.1-alpha.5

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.
Files changed (128) hide show
  1. package/README.md +754 -606
  2. package/dist/KadiClient.d.ts +440 -0
  3. package/dist/KadiClient.d.ts.map +1 -0
  4. package/dist/KadiClient.js +1518 -0
  5. package/dist/KadiClient.js.map +1 -0
  6. package/dist/errors/error-codes.d.ts +215 -0
  7. package/dist/errors/error-codes.d.ts.map +1 -0
  8. package/dist/errors/error-codes.js +295 -0
  9. package/dist/errors/error-codes.js.map +1 -0
  10. package/dist/index.d.ts +15 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +24 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/loadAbility.d.ts +106 -0
  15. package/dist/loadAbility.d.ts.map +1 -0
  16. package/dist/loadAbility.js +376 -0
  17. package/dist/loadAbility.js.map +1 -0
  18. package/dist/messages/BrokerMessages.d.ts +84 -0
  19. package/dist/messages/BrokerMessages.d.ts.map +1 -0
  20. package/dist/messages/BrokerMessages.js +125 -0
  21. package/dist/messages/BrokerMessages.js.map +1 -0
  22. package/dist/messages/MessageBuilder.d.ts +83 -0
  23. package/dist/messages/MessageBuilder.d.ts.map +1 -0
  24. package/dist/messages/MessageBuilder.js +144 -0
  25. package/dist/messages/MessageBuilder.js.map +1 -0
  26. package/dist/schemas/events.schemas.d.ts +177 -0
  27. package/dist/schemas/events.schemas.d.ts.map +1 -0
  28. package/dist/schemas/events.schemas.js +265 -0
  29. package/dist/schemas/events.schemas.js.map +1 -0
  30. package/dist/schemas/index.d.ts +3 -0
  31. package/dist/schemas/index.d.ts.map +1 -0
  32. package/dist/schemas/index.js +4 -0
  33. package/dist/schemas/index.js.map +1 -0
  34. package/dist/schemas/kadi.schemas.d.ts +70 -0
  35. package/dist/schemas/kadi.schemas.d.ts.map +1 -0
  36. package/dist/schemas/kadi.schemas.js +120 -0
  37. package/dist/schemas/kadi.schemas.js.map +1 -0
  38. package/dist/transports/BrokerTransport.d.ts +106 -0
  39. package/dist/transports/BrokerTransport.d.ts.map +1 -0
  40. package/dist/transports/BrokerTransport.js +177 -0
  41. package/dist/transports/BrokerTransport.js.map +1 -0
  42. package/dist/transports/NativeTransport.d.ts +82 -0
  43. package/dist/transports/NativeTransport.d.ts.map +1 -0
  44. package/dist/transports/NativeTransport.js +263 -0
  45. package/dist/transports/NativeTransport.js.map +1 -0
  46. package/dist/transports/StdioTransport.d.ts +112 -0
  47. package/dist/transports/StdioTransport.d.ts.map +1 -0
  48. package/dist/transports/StdioTransport.js +445 -0
  49. package/dist/transports/StdioTransport.js.map +1 -0
  50. package/dist/transports/Transport.d.ts +93 -0
  51. package/dist/transports/Transport.d.ts.map +1 -0
  52. package/dist/transports/Transport.js +13 -0
  53. package/dist/transports/Transport.js.map +1 -0
  54. package/dist/types/broker.d.ts +31 -0
  55. package/dist/types/broker.d.ts.map +1 -0
  56. package/dist/types/broker.js +6 -0
  57. package/dist/types/broker.js.map +1 -0
  58. package/dist/types/core.d.ts +139 -0
  59. package/dist/types/core.d.ts.map +1 -0
  60. package/dist/types/core.js +26 -0
  61. package/dist/types/core.js.map +1 -0
  62. package/dist/types/events.d.ts +186 -0
  63. package/dist/types/events.d.ts.map +1 -0
  64. package/dist/types/events.js +16 -0
  65. package/dist/types/events.js.map +1 -0
  66. package/dist/types/index.d.ts +9 -0
  67. package/dist/types/index.d.ts.map +1 -0
  68. package/dist/types/index.js +13 -0
  69. package/dist/types/index.js.map +1 -0
  70. package/dist/types/protocol.d.ts +160 -0
  71. package/dist/types/protocol.d.ts.map +1 -0
  72. package/dist/types/protocol.js +5 -0
  73. package/dist/types/protocol.js.map +1 -0
  74. package/dist/utils/agentUtils.d.ts +187 -0
  75. package/dist/utils/agentUtils.d.ts.map +1 -0
  76. package/dist/utils/agentUtils.js +185 -0
  77. package/dist/utils/agentUtils.js.map +1 -0
  78. package/dist/utils/commandUtils.d.ts +45 -0
  79. package/dist/utils/commandUtils.d.ts.map +1 -0
  80. package/dist/utils/commandUtils.js +145 -0
  81. package/dist/utils/commandUtils.js.map +1 -0
  82. package/dist/utils/configUtils.d.ts +55 -0
  83. package/dist/utils/configUtils.d.ts.map +1 -0
  84. package/dist/utils/configUtils.js +100 -0
  85. package/dist/utils/configUtils.js.map +1 -0
  86. package/dist/utils/logger.d.ts +59 -0
  87. package/dist/utils/logger.d.ts.map +1 -0
  88. package/dist/utils/logger.js +122 -0
  89. package/dist/utils/logger.js.map +1 -0
  90. package/dist/utils/pathUtils.d.ts +48 -0
  91. package/dist/utils/pathUtils.d.ts.map +1 -0
  92. package/dist/utils/pathUtils.js +128 -0
  93. package/dist/utils/pathUtils.js.map +1 -0
  94. package/package.json +56 -5
  95. package/agent.json +0 -18
  96. package/examples/example-abilities/echo-js/README.md +0 -131
  97. package/examples/example-abilities/echo-js/agent.json +0 -63
  98. package/examples/example-abilities/echo-js/package.json +0 -24
  99. package/examples/example-abilities/echo-js/service.js +0 -43
  100. package/examples/example-abilities/hash-go/agent.json +0 -53
  101. package/examples/example-abilities/hash-go/cmd/hash_ability/main.go +0 -340
  102. package/examples/example-abilities/hash-go/go.mod +0 -3
  103. package/examples/example-agent/abilities/echo-js/0.0.1/README.md +0 -131
  104. package/examples/example-agent/abilities/echo-js/0.0.1/agent.json +0 -63
  105. package/examples/example-agent/abilities/echo-js/0.0.1/package-lock.json +0 -93
  106. package/examples/example-agent/abilities/echo-js/0.0.1/package.json +0 -24
  107. package/examples/example-agent/abilities/echo-js/0.0.1/service.js +0 -41
  108. package/examples/example-agent/abilities/hash-go/0.0.1/agent.json +0 -53
  109. package/examples/example-agent/abilities/hash-go/0.0.1/bin/hash_ability +0 -0
  110. package/examples/example-agent/abilities/hash-go/0.0.1/cmd/hash_ability/main.go +0 -340
  111. package/examples/example-agent/abilities/hash-go/0.0.1/go.mod +0 -3
  112. package/examples/example-agent/agent.json +0 -39
  113. package/examples/example-agent/index.js +0 -102
  114. package/examples/example-agent/package-lock.json +0 -93
  115. package/examples/example-agent/package.json +0 -17
  116. package/src/KadiAbility.js +0 -478
  117. package/src/index.js +0 -65
  118. package/src/loadAbility.js +0 -1086
  119. package/src/servers/BaseRpcServer.js +0 -404
  120. package/src/servers/BrokerRpcServer.js +0 -776
  121. package/src/servers/StdioRpcServer.js +0 -360
  122. package/src/transport/BrokerMessageBuilder.js +0 -377
  123. package/src/transport/IpcMessageBuilder.js +0 -1229
  124. package/src/utils/agentUtils.js +0 -137
  125. package/src/utils/commandUtils.js +0 -64
  126. package/src/utils/configUtils.js +0 -72
  127. package/src/utils/logger.js +0 -161
  128. package/src/utils/pathUtils.js +0 -86
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  ## 🎯 Overview
9
9
 
10
- `@kadi.build/core` is the foundational library for creating KADI abilities - modular, protocol-agnostic services that can communicate via multiple transport layers. Whether you're building local tools, distributed microservices, or high-performance native modules, this toolkit provides a unified, developer-friendly API that abstracts away transport complexity.
10
+ `@kadi.build/core` is the foundational library for creating KADI abilities - modular, protocol-agnostic components that can communicate via multiple transport layers. Whether you're building local tools, distributed systems, or high-performance native modules, this toolkit provides a unified, developer-friendly API that abstracts away transport complexity.
11
11
 
12
12
  ## 📚 Table of Contents
13
13
 
@@ -16,6 +16,7 @@
16
16
  - [🚀 Quick Start](#-quick-start)
17
17
  - [🔌 Transport Protocols](#-transport-protocols)
18
18
  - [🛠️ Creating Abilities](#-creating-abilities)
19
+ - [🤖 Creating Agents](#-creating-agents)
19
20
  - [🔄 Architecture Deep Dive](#-architecture-deep-dive)
20
21
  - [📥 Loading Abilities](#-loading-abilities)
21
22
  - [⚙️ Configuration](#-configuration)
@@ -44,21 +45,26 @@ npm install -g @kadi.build/cli
44
45
 
45
46
  ## 🚀 Quick Start
46
47
 
48
+ The library provides a unified way to work with KADI through the **KadiClient** class, which can operate in multiple roles:
49
+
50
+ - **As an Ability**: Serving tools/methods that others can call
51
+ - **As an Agent**: Calling remote tools via broker protocol
52
+
47
53
  ### Creating Your First Ability
48
54
 
49
55
  ```javascript
50
56
  #!/usr/bin/env node
51
- import { KadiAbility } from '@kadi.build/core';
57
+ import { KadiClient } from '@kadi.build/core';
52
58
 
53
- // Create an ability instance
54
- const mathAbility = new KadiAbility({
59
+ // Create a ability instance
60
+ const mathAbility = new KadiClient({
55
61
  name: 'math-ability',
56
- version: '1.0.0',
57
- description: 'Simple math operations'
62
+ role: 'ability', // 'agent', 'ability'
63
+ protocol: 'stdio' // 'native', 'stdio', or 'broker'
58
64
  });
59
65
 
60
- // Register a method
61
- mathAbility.method('add', async ({ a, b }) => {
66
+ // Register a tool
67
+ mathAbility.registerTool('add', async ({ a, b }) => {
62
68
  return { result: a + b };
63
69
  });
64
70
 
@@ -78,14 +84,58 @@ async function main() {
78
84
  // Call methods like regular functions
79
85
  const result = await math.add({ a: 5, b: 3 });
80
86
  console.log(result); // { result: 8 }
81
-
82
- // List available methods
83
- console.log(math.__list()); // ['add']
84
87
  }
85
88
 
86
89
  main().catch(console.error);
87
90
  ```
88
91
 
92
+ ### Creating a Broker-Connected Agent
93
+
94
+ ```javascript
95
+ import { KadiClient } from '@kadi.build/core';
96
+
97
+ // Create an agent that connects to broker
98
+ const agent = new KadiClient({
99
+ name: 'my-agent',
100
+ role: 'agent',
101
+ protocol: 'broker',
102
+ brokers: {
103
+ 'prod': 'ws://localhost:8080',
104
+ 'dev': 'ws://localhost:8081'
105
+ },
106
+ defaultBroker: 'prod',
107
+ networks: ['global']
108
+ });
109
+
110
+ // Register tools that other agents can call
111
+ agent.registerTool(
112
+ 'greet',
113
+ async ({ name }) => {
114
+ return { greeting: `Hello, ${name}!` };
115
+ },
116
+ {
117
+ description: 'Greet someone by name',
118
+ inputSchema: {
119
+ type: 'object',
120
+ properties: {
121
+ name: { type: 'string', description: 'Name to greet' }
122
+ },
123
+ required: ['name']
124
+ }
125
+ }
126
+ );
127
+
128
+ // Connect to brokers and start serving
129
+ await agent.connectToBrokers();
130
+
131
+ // Call tools from OTHER agents connected to the same broker
132
+ const result = await agent.callTool('translate', 'text-tool', {
133
+ text: 'Hello world',
134
+ language: 'spanish'
135
+ });
136
+ console.log(result);
137
+ ```
138
+
89
139
  ## 🔌 Transport Protocols
90
140
 
91
141
  KADI abilities support three transport protocols, each optimized for different use cases:
@@ -107,7 +157,7 @@ const ability = await loadAbility('my-ability', 'native');
107
157
  - **Use Case**: Language-agnostic local execution
108
158
  - **How it Works**: Spawns abilities as child processes, communicates via LSP-style JSON-RPC over stdin/stdout
109
159
  - **Performance**: Minimal overhead, reliable local IPC
110
- - **Best For**: Python scripts, Go binaries, Node.js services, development/testing
160
+ - **Best For**: Python scripts, Go binaries, Node.js abilities, development/testing
111
161
 
112
162
  ```javascript
113
163
  // Force stdio protocol
@@ -123,10 +173,10 @@ KADI_PROTOCOL=stdio # Identifies the protocol being used
123
173
 
124
174
  ### 3. Broker Protocol (Distributed)
125
175
 
126
- - **Use Case**: Distributed services, containerized deployments
176
+ - **Use Case**: Distributed systems, containerized deployments
127
177
  - **How it Works**: Abilities connect to a WebSocket broker for network communication
128
178
  - **Performance**: Network overhead, but enables scaling and distribution
129
- - **Best For**: Microservices, cloud deployments, load-balanced services
179
+ - **Best For**: Distributed abilities, cloud deployments, load-balanced systems
130
180
 
131
181
  ```javascript
132
182
  // Use broker for distributed execution
@@ -136,77 +186,67 @@ const ability = await loadAbility('my-ability', 'broker');
136
186
  **Environment Variables Passed to Child Process:**
137
187
 
138
188
  ```bash
139
- KADI_PROTOCOL=broker # Identifies the protocol
189
+ KADI_PROTOCOL=broker # Identifies the protocol
140
190
  KADI_BROKER_URL=ws://localhost:8080 # Broker connection URL
141
- KADI_SERVICE_NAME=ability.echo.1_0_0 # Service identifier
191
+ KADI_ABILITY_NAME=ability.echo.1_0_0 # Ability identifier
142
192
  KADI_AGENT_SCOPE=uuid-here # Agent's scope/namespace
143
193
  # Plus all parent process.env variables
144
194
  ```
145
195
 
146
- **Scope/Namespace Visibility:**
196
+ **Network/Namespace Visibility:**
147
197
 
148
- The `KADI_AGENT_SCOPE` environment variable represents the agent's namespace. For the ability to be visible to its parent agent via the broker, it must register with the same scope:
198
+ The `KADI_AGENT_SCOPE` environment variable represents the agent's namespace. For the ability to be visible to its parent agent via the broker, it must register with the same network:
149
199
 
150
200
  ```javascript
151
201
  // In your ability code:
152
- const echoAbility = new KadiAbility({
202
+ const echoAbility = new KadiClient({
153
203
  name: 'echo-js',
154
204
  version: '0.0.1',
155
205
  description: 'Echo ability with broker support',
156
- scope: process.env.KADI_AGENT_SCOPE // Use agent's scope for visibility
206
+ network: process.env.KADI_AGENT_SCOPE // Use agent's network for visibility
157
207
  });
158
208
 
159
- // Without this, the ability would only be visible in the 'global' scope
209
+ // Without this, the ability would only be visible in the 'global' network
160
210
  // and the parent agent wouldn't be able to communicate with it
161
211
  ```
162
212
 
163
213
  ### Protocol Selection Strategy
164
214
 
165
- When no protocol is specified, `loadAbility` uses the **first interface** defined in the ability's `agent.json`. The KADI team recommends ordering interfaces from fastest to slowest (native → stdio broker) for optimal default performance.
215
+ When no protocol is specified, `loadAbility` defaults to the 'native' protocol. You must explicitly specify the protocol if you want to use 'stdio' or 'broker'.
166
216
 
167
217
  ```mermaid
168
218
  graph TD
169
219
  A[Load Ability] --> B{Protocol Specified?}
170
220
  B -->|Yes| C[Use Specified Protocol]
171
- B -->|No| D{Check agent.json interfaces}
172
- D --> E[Use First Interface Listed]
173
- E --> F[native/stdio/broker]
174
- ```
175
-
176
- **Recommended Interface Order in agent.json:**
177
-
178
- ```json
179
- {
180
- "interfaces": {
181
- "native": { "entry": "service.js" }, // 1st choice: Fastest
182
- "stdio": { "discover": true }, // 2nd choice: Balanced
183
- "broker": { "discover": true } // 3rd choice: Distributed
184
- }
185
- }
221
+ B -->|No| D[Default to 'native']
186
222
  ```
187
223
 
188
- ## 🛠️ Creating Abilities
224
+ ## 🛠️ Creating Abilities with KadiClient
189
225
 
190
226
  ### Basic Ability Structure
191
227
 
192
228
  ```javascript
193
- import { KadiAbility } from '@kadi.build/core';
229
+ import { KadiClient } from '@kadi.build/core';
194
230
 
195
- const ability = new KadiAbility({
231
+ const ability = new KadiClient({
196
232
  name: 'echo-ability',
197
- version: '1.0.0',
198
- description: 'Echo service with metadata',
199
- scope: process.env.KADI_AGENT_SCOPE || 'global'
233
+ role: 'ability', // 'agent', 'ability',
234
+ protocol: 'stdio', // 'native', 'stdio', or 'broker'
235
+ brokers: {
236
+ 'local': 'ws://localhost:8080',
237
+ 'prod': 'ws://api.example.com:8080'
238
+ },
239
+ defaultBroker: 'local'
200
240
  });
201
241
 
202
- // Method 1: Simple handler
203
- ability.method('echo', async ({ message }) => ({
242
+ // Method 1: Simple tool registration
243
+ ability.registerTool('echo', async ({ message }) => ({
204
244
  echo: message,
205
245
  timestamp: new Date().toISOString()
206
246
  }));
207
247
 
208
- // Method 2: Handler with inline schema
209
- ability.method(
248
+ // Method 2: Tool with inline schema
249
+ ability.registerTool(
210
250
  'format',
211
251
  async ({ text, style }) => ({
212
252
  formatted: style === 'upper' ? text.toUpperCase() : text.toLowerCase()
@@ -240,40 +280,60 @@ ability.serve().catch(console.error);
240
280
 
241
281
  ### Event Publishing and Subscription
242
282
 
243
- **Note**: Events currently work for `native` and `stdio` protocols. Broker protocol event support is planned for future releases.
283
+ **Full Support**: Events work across all protocols - native, stdio, and broker.
244
284
 
245
- Abilities can publish events that agents can subscribe to:
285
+ KadiClient provides a unified event system that works consistently across all transport protocols:
246
286
 
247
287
  ```javascript
248
- // In your ability (service.js)
249
- const ability = new KadiAbility({ name: 'my-ability' });
288
+ // In your ability (ability.js)
289
+ const ability = new KadiClient({
290
+ name: 'my-ability',
291
+ role: 'ability',
292
+ protocol: 'broker' // Works with all protocols
293
+ });
250
294
 
251
- // Publish events from method handlers
252
- ability.method('echo', async ({ message }) => {
253
- // Publish an event before returning the result
254
- ability.publishEvent('echo:test-event', { from: 'message echo' });
255
- ability.publishEvent('echo:test-event', { from: 'message echo 2' });
295
+ // Publish events from tool handlers
296
+ ability.registerTool('echo', async ({ message }) => {
297
+ // Publish events during processing
298
+ await ability.publishEvent('echo.processing', { status: 'started' });
299
+
300
+ // Do work...
301
+ const result = { echo: message, timestamp: new Date().toISOString() };
256
302
 
257
- return { echo: message, timestamp: new Date().toISOString() };
303
+ await ability.publishEvent('echo.completed', { result });
304
+ return result;
258
305
  });
259
306
 
260
- // In your agent (index.js)
261
- const ability = await loadAbility('my-ability');
307
+ // In your agent (agent.js)
308
+ const agent = new KadiClient({
309
+ name: 'my-client',
310
+ role: 'agent',
311
+ protocol: 'broker'
312
+ });
262
313
 
263
- // Subscribe to events BEFORE calling methods that emit them
264
- ability.events.on('echo:test-event', (data) => {
265
- console.log(`[NATIVE] echo:test-event received:`, data);
314
+ // Subscribe to events using patterns
315
+ agent.subscribeToEvent('echo.*', (data) => {
316
+ console.log('Echo event received:', data);
266
317
  });
267
318
 
268
- // Now call the method that emits events
269
- const result = await ability.echo({ message: 'Hello world' });
319
+ // For loaded abilities with native/stdio protocols
320
+ const ability = await loadAbility('my-ability', 'stdio');
321
+ ability.events.on('echo.completed', (data) => {
322
+ console.log('Completed:', data);
323
+ });
270
324
  ```
271
325
 
272
- **Important**: Always subscribe to events before calling methods that emit them, as events are emitted immediately when `publishEvent()` is called.
326
+ **Event Patterns**:
327
+
328
+ - Use wildcards: `math.*` matches `math.operation`, `math.milestone`
329
+ - Protocol-specific delivery:
330
+ - **Native**: Direct EventEmitter (synchronous)
331
+ - **Stdio**: JSON-RPC notifications over stdout
332
+ - **Broker**: RabbitMQ pub/sub via WebSocket
273
333
 
274
334
  ### Ability Configuration (agent.json)
275
335
 
276
- Every ability should have an `agent.json` file that defines its capabilities and interfaces:
336
+ Every ability should have an `agent.json` file that defines its capabilities:
277
337
 
278
338
  ```json
279
339
  {
@@ -281,24 +341,10 @@ Every ability should have an `agent.json` file that defines its capabilities and
281
341
  "kind": "ability",
282
342
  "version": "1.0.0",
283
343
  "license": "MIT",
284
- "description": "Echo service with multiple transport support",
344
+ "description": "Echo ability with multiple transport support",
285
345
  "scripts": {
286
346
  "setup": "npm install",
287
- "start": "node service.js"
288
- },
289
- "interfaces": {
290
- "native": {
291
- "entry": "service.js"
292
- },
293
- "stdio": {
294
- "discover": true,
295
- "timeoutMs": 10000
296
- },
297
- "broker": {
298
- "discover": true,
299
- "timeoutMs": 15000,
300
- "serviceName": "echo-service"
301
- }
347
+ "start": "node ability.js"
302
348
  },
303
349
  "exports": [
304
350
  {
@@ -323,7 +369,8 @@ Every ability should have an `agent.json` file that defines its capabilities and
323
369
  "brokers": {
324
370
  "local": "ws://localhost:8080",
325
371
  "remote": "ws://api.example.com:8080"
326
- }
372
+ },
373
+ "defaultBroker": "local"
327
374
  }
328
375
  ```
329
376
 
@@ -332,7 +379,7 @@ Every ability should have an `agent.json` file that defines its capabilities and
332
379
  The ability system provides two ways to define method schemas:
333
380
 
334
381
  1. **Export Schemas** (defined in `agent.json` exports section)
335
- 2. **Inline Schemas** (passed directly to `.method()`)
382
+ 2. **Inline Schemas** (passed directly to `registerTool()`)
336
383
 
337
384
  ```javascript
338
385
  // Option 1: Define in agent.json exports section
@@ -350,7 +397,7 @@ The ability system provides two ways to define method schemas:
350
397
  }
351
398
 
352
399
  // Option 2: Define inline when registering the method
353
- ability.method('process', handler, {
400
+ ability.registerTool('process', handler, {
354
401
  description: 'Process data',
355
402
  inputSchema: { /* ... */ },
356
403
  outputSchema: { /* ... */ }
@@ -361,176 +408,327 @@ ability.method('process', handler, {
361
408
 
362
409
  **Important**: Specifying MCP schemas for ability handlers is particularly important for `broker` communication. If you only need `native` and `stdio` protocols, schemas can be omitted.
363
410
 
411
+ ## 🤖 Working with KadiClient
412
+
413
+ KadiClient is the unified API for all KADI operations. It replaces the previous separate KadiAbility and KadiAgent classes with a single, powerful interface that can operate in multiple roles.
414
+
415
+ ### Direct Approach (using loadAbility)
416
+
417
+ ```javascript
418
+ import { loadAbility } from '@kadi.build/core';
419
+
420
+ // Load and call abilities directly
421
+ const echoAbility = await loadAbility('echo-js', 'stdio');
422
+ const result = await echoAbility.echo({ message: 'Hello world' });
423
+
424
+ // Load broker tools directly
425
+ const remoteAbility = await loadAbility('remote-ability', 'broker', {
426
+ brokerUrl: 'ws://localhost:8080',
427
+ networks: ['global']
428
+ });
429
+ const brokerResult = await remoteAbility.process({ data: 'test' });
430
+ ```
431
+
432
+ ### Using KadiClient with Named Brokers
433
+
434
+ ```javascript
435
+ import { KadiClient } from '@kadi.build/core';
436
+
437
+ // Create a unified client with named brokers
438
+ const client = new KadiClient({
439
+ name: 'my-ability',
440
+ role: 'ability', // Provider role
441
+ protocol: 'broker',
442
+ brokers: {
443
+ 'dev': 'ws://localhost:8080',
444
+ 'staging': 'ws://staging.example.com:8080',
445
+ 'prod': 'ws://prod.example.com:8080'
446
+ },
447
+ defaultBroker: 'dev',
448
+ networks: ['global']
449
+ });
450
+
451
+ // Register tools for others to call
452
+ client.registerTool(
453
+ 'greet',
454
+ async ({ name }) => {
455
+ return { greeting: `Hello, ${name}!` };
456
+ },
457
+ {
458
+ description: 'Greet someone by name',
459
+ inputSchema: {
460
+ type: 'object',
461
+ properties: { name: { type: 'string' } },
462
+ required: ['name']
463
+ }
464
+ }
465
+ );
466
+
467
+ // Connect to all configured brokers
468
+ await client.connectToBrokers();
469
+
470
+ // Call remote tools
471
+ const result = await client.callTool('translator', 'translate', {
472
+ text: 'Hello',
473
+ to: 'es'
474
+ });
475
+
476
+ // Load abilities for compatibility
477
+ const ability = await client.loadAbility('echo-js');
478
+ ```
479
+
480
+ Use `loadAbility()` for simple consumption, or KadiClient for full-featured ability development with tool registration, event publishing, and remote tool invocation.
481
+
364
482
  ## 🔄 Architecture Deep Dive
365
483
 
366
- ### Ability Loading Sequence
484
+ ### Transport Architecture and Loading Sequence
367
485
 
368
- The loading process adapts based on the selected protocol:
486
+ The loading process uses modular transports based on the selected protocol:
369
487
 
370
488
  ```mermaid
371
489
  sequenceDiagram
372
490
  participant Client
373
491
  participant loadAbility
492
+ participant Transport
374
493
  participant FileSystem
375
494
  participant ChildProcess
376
495
  participant Ability
377
496
  participant Broker
378
497
 
379
498
  Client->>loadAbility: loadAbility('echo-js', protocol?)
380
- loadAbility->>FileSystem: Read project/ability agent.json
381
- FileSystem-->>loadAbility: Return ability version & config
382
- loadAbility->>FileSystem: Check ability directory exists
383
- loadAbility->>FileSystem: Read ability's agent.json manifest
499
+ loadAbility->>FileSystem: Read agent.json manifests
500
+ FileSystem-->>loadAbility: Return config & version
384
501
 
385
502
  alt protocol === 'native'
386
- loadAbility->>FileSystem: Read entry point from manifest
387
- loadAbility->>Ability: import(modulePath)
388
- Ability-->>loadAbility: Return module exports
389
- loadAbility->>loadAbility: Extract functions from module
390
- loadAbility->>loadAbility: Build proxy with direct function calls
503
+ loadAbility->>Transport: new NativeTransport(config)
504
+ Transport->>FileSystem: import(entry point)
505
+ FileSystem-->>Transport: Module with KadiClient instance
506
+ Transport->>Ability: Extract tool handlers via getToolNames()
507
+ Ability-->>Transport: Return registered tools
508
+ Transport->>Transport: Store handlers in Map
391
509
  else protocol === 'stdio'
392
- loadAbility->>ChildProcess: spawn(startCmd, { env: { KADI_PROTOCOL: 'stdio' }})
393
- ChildProcess->>Ability: Start ability process
394
- Ability->>Ability: Create StdioRpcServer
395
- loadAbility->>Ability: Send __kadi_init via LSP frames
396
- Ability-->>loadAbility: Return { name, version, functions }
397
-
398
- opt if discover enabled
399
- loadAbility->>Ability: Send __kadi_discover
400
- Ability-->>loadAbility: Return { functions: {...} }
401
- end
402
-
403
- loadAbility->>loadAbility: Merge static exports + discovered functions
404
- loadAbility->>loadAbility: Build proxy with RPC calls
510
+ loadAbility->>Transport: new StdioTransport(config)
511
+ Transport->>ChildProcess: spawn(startCmd, env: {KADI_PROTOCOL})
512
+ ChildProcess->>Ability: KadiClient detects stdio mode
513
+ Ability->>Ability: Setup FrameReader/Writer
514
+ Transport->>Ability: Send discovery request
515
+ Ability-->>Transport: Return tool list
516
+ Transport->>Transport: Setup JSON-RPC proxy
405
517
  else protocol === 'broker'
406
- loadAbility->>loadAbility: Generate scope UUID
407
- loadAbility->>ChildProcess: spawn(startCmd, { env: { KADI_PROTOCOL, KADI_BROKER_URL, KADI_AGENT_SCOPE, KADI_SERVICE_NAME }})
408
- ChildProcess->>Ability: Start ability process
409
-
410
- Note over Ability,Broker: Ability connects to broker
411
- Ability->>Broker: WebSocket connect
412
- Ability->>Broker: hello({ role: 'agent' })
413
- Broker-->>Ability: { nonce }
414
- Ability->>Broker: authenticate({ publicKey, signature })
415
- Broker-->>Ability: { agentId }
416
- Ability->>Broker: registerCapabilities({ tools, scopes: [KADI_AGENT_SCOPE] })
417
-
418
- Note over loadAbility,Broker: Parent connects to broker
419
- loadAbility->>Broker: WebSocket connect
420
- loadAbility->>Broker: hello/auth/register sequence
421
-
422
- opt if discover enabled
423
- loadAbility->>Broker: listTools({ scopes: [scope] })
424
- Broker-->>loadAbility: Return available tools
425
- end
426
-
427
- loadAbility->>loadAbility: Merge static exports + broker tools
428
- loadAbility->>loadAbility: Build proxy with broker RPC
518
+ loadAbility->>Transport: new BrokerTransport(config)
519
+ Transport->>Transport: Reuse existing KadiClient
520
+ Transport->>Broker: WebSocket connect
521
+ Transport->>Broker: kadi.session.hello
522
+ Broker-->>Transport: { nonce, heartbeatIntervalSec }
523
+ Transport->>Broker: kadi.session.authenticate
524
+ Broker-->>Transport: { sessionId }
525
+ Transport->>Broker: kadi.ability.list
526
+ Broker-->>Transport: Available tools
527
+ Transport->>Transport: Start heartbeat timer
429
528
  end
430
529
 
431
- loadAbility->>Client: Return ability proxy
432
- Client->>Client: ability.method({ params })
530
+ loadAbility->>loadAbility: Create proxy with tool methods
531
+ loadAbility-->>Client: Return ability proxy
532
+
533
+ Note over Client,Ability: Tool invocation
534
+ Client->>Transport: ability.echo({ message })
535
+
536
+ alt native
537
+ Transport->>Ability: Direct handler call
538
+ else stdio
539
+ Transport->>Ability: JSON-RPC over frames
540
+ else broker
541
+ Transport->>Broker: kadi.ability.invoke
542
+ Broker->>Ability: Route to target
543
+ Ability->>Broker: kadi.ability.result
544
+ Broker-->>Transport: Forward result
545
+ end
546
+
547
+ Transport-->>Client: Return result
433
548
  ```
434
549
 
435
- ### Method Registration & Serving
550
+ ### KadiClient Architecture: Tool Registration & Serving
436
551
 
437
- How abilities register methods and start serving:
552
+ How KadiClient registers tools and starts serving:
438
553
 
439
554
  ```mermaid
440
555
  sequenceDiagram
441
556
  participant Dev as Developer
442
- participant KA as KadiAbility
443
- participant Server as RpcServer
557
+ participant KC as KadiClient
444
558
  participant Transport
445
- participant Client
559
+ participant Network as Network Layer
560
+ participant RemoteClient
446
561
 
447
- Note over Dev,KA: Registration Phase
448
- Dev->>KA: new KadiAbility({ name, scope: process.env.KADI_AGENT_SCOPE })
449
- Dev->>KA: ability.method('echo', handler)
450
- KA->>KA: Store in methodHandlers Map
562
+ Note over Dev,KC: Tool Registration Phase
563
+ Dev->>KC: new KadiClient({ name, role, protocol })
564
+ KC->>KC: Initialize based on role & protocol
451
565
 
452
- Dev->>KA: ability.method('transform', handler, schema)
453
- KA->>KA: Store handler in methodHandlers
454
- KA->>KA: Store schema in methodMCPSchemas
566
+ Dev->>KC: registerTool('echo', handler, schema?)
567
+ KC->>KC: Store in toolHandlers Map<name, {handler, schema}>
455
568
 
456
- Note over KA,Transport: Serving Phase
457
- Dev->>KA: ability.serve()
458
- KA->>KA: Detect protocol from env/options
569
+ Dev->>KC: registerTool('process', handler, schema)
570
+ KC->>KC: Add to toolHandlers Map
459
571
 
460
- alt protocol === 'stdio'
461
- KA->>Server: new StdioRpcServer()
462
- Server->>Transport: new StdioFrameReader(stdin)
463
- Server->>Transport: new StdioFrameWriter(stdout)
464
- Transport->>Transport: Listen for LSP frames on stdin
572
+ Note over KC,Network: Connection & Serving Phase
573
+ Dev->>KC: serve() or connectToBrokers()
574
+
575
+ alt protocol === 'native'
576
+ KC->>KC: Tools available via direct reference
577
+ KC->>KC: Emit 'start' event
578
+ else protocol === 'stdio'
579
+ KC->>Transport: Setup StdioTransport
580
+ Transport->>Transport: new FrameReader(stdin)
581
+ Transport->>Transport: new FrameWriter(stdout)
582
+ Transport->>KC: on('message', handleStdioMessage)
583
+ KC->>KC: Process JSON-RPC requests
465
584
  else protocol === 'broker'
466
- KA->>Server: new BrokerRpcServer()
467
- Server->>Transport: WebSocket connect to broker
468
- Server->>Transport: Handshake (hello/auth)
469
- Server->>KA: ability.extractToolsForBroker()
470
- KA-->>Server: Return tools from exports + inline schemas
471
- Server->>Transport: registerCapabilities({ tools, scopes })
585
+ KC->>Network: WebSocket.connect(brokerUrl)
586
+ KC->>Network: kadi.session.hello({ role })
587
+ Network-->>KC: { nonce, heartbeatIntervalSec: 30 }
588
+ KC->>KC: Sign nonce with Ed25519
589
+ KC->>Network: kadi.session.authenticate({ signature })
590
+ Network-->>KC: { sessionId }
591
+ KC->>Network: kadi.agent.register({ tools, networks })
592
+ KC->>KC: Start heartbeat timer (30s interval)
472
593
  end
473
594
 
474
- Server->>KA: Forward events (start, request, response, error)
595
+ Note over RemoteClient,KC: Tool Invocation Flow
596
+ RemoteClient->>Network: Request tool invocation
597
+
598
+ alt native
599
+ RemoteClient->>KC: Direct method call
600
+ KC->>KC: toolHandlers.get(name).handler(params)
601
+ else stdio
602
+ Network->>Transport: JSON-RPC frame
603
+ Transport->>KC: Parsed request
604
+ KC->>KC: toolHandlers.get(name).handler(params)
605
+ KC->>Transport: JSON-RPC response
606
+ Transport->>Network: Framed response
607
+ else broker
608
+ Network->>KC: kadi.ability.invoke message
609
+ KC->>KC: toolHandlers.get(toolName).handler(params)
610
+ KC->>Network: kadi.ability.result message
611
+ end
475
612
 
476
- Note over Transport,Client: Request Handling
477
- Client->>Transport: Incoming request
478
- Transport->>Server: Parse & validate request
479
- Server->>KA: getMethodHandler(method)
480
- KA-->>Server: Return handler function
481
- Server->>Server: Execute handler with timeout
482
- Server->>Transport: Send response
483
- Transport->>Client: Return result
613
+ Network-->>RemoteClient: Tool result
614
+ ```
615
+
616
+ ### Event System Architecture
617
+
618
+ KadiClient provides a unified event API that works across all transport protocols:
619
+
620
+ ```mermaid
621
+ sequenceDiagram
622
+ participant Publisher as Ability (Publisher)
623
+ participant Transport as Transport Layer
624
+ participant EventBus as Event Bus
625
+ participant Subscriber as Client (Subscriber)
626
+
627
+ Note over Subscriber: Setup subscription
628
+ Subscriber->>Subscriber: subscribeToEvent('math.*', callback)
629
+
630
+ alt protocol === 'broker'
631
+ Subscriber->>EventBus: kadi.event.subscribe({channels: ['math.*']})
632
+ EventBus-->>Subscriber: {subscribed: ['math.*'], queueName}
633
+ else protocol === 'stdio'
634
+ Subscriber->>Transport: Setup event listener
635
+ Transport->>Subscriber: on('transport:event', dispatcher)
636
+ else protocol === 'native'
637
+ Subscriber->>Publisher: Direct EventEmitter reference
638
+ Publisher->>Subscriber: on('ability:event', dispatcher)
639
+ end
640
+
641
+ Note over Publisher: Publish event
642
+ Publisher->>Publisher: publishEvent('math.operation', data)
643
+
644
+ alt protocol === 'native'
645
+ Publisher->>Publisher: emit('ability:event', {eventName, data})
646
+ Publisher-->>Subscriber: Direct EventEmitter delivery
647
+ Subscriber->>Subscriber: Pattern match & invoke callback
648
+ else protocol === 'stdio'
649
+ Publisher->>Transport: writer.write(__kadi_event notification)
650
+ Transport->>Transport: Frame with LSP headers
651
+ Transport-->>Subscriber: Framed event over stdout
652
+ Subscriber->>Transport: FrameReader parses
653
+ Transport->>Subscriber: emit('transport:event', {name, data})
654
+ Subscriber->>Subscriber: Pattern match & invoke callback
655
+ else protocol === 'broker'
656
+ Publisher->>EventBus: kadi.event.publish({channel, data})
657
+ EventBus->>EventBus: Route via RabbitMQ
658
+ EventBus-->>Subscriber: kadi.event.delivery
659
+ Subscriber->>Subscriber: Pattern match & invoke callback
660
+ end
661
+
662
+ Note over Subscriber: Cleanup
663
+ Subscriber->>Subscriber: unsubscribe()
664
+ alt protocol === 'broker'
665
+ Subscriber->>EventBus: kadi.event.unsubscribe
666
+ else
667
+ Subscriber->>Subscriber: Remove local listener
668
+ end
484
669
  ```
485
670
 
486
671
  ### Broker Protocol Communication Flow
487
672
 
488
- Detailed view of broker-based communication:
673
+ Detailed view of broker-based communication with heartbeat:
489
674
 
490
675
  ```mermaid
491
676
  sequenceDiagram
492
- participant Agent as Agent (Parent)
493
- participant Ability as Ability (Child)
677
+ participant Client as KadiClient
494
678
  participant Broker as KADI Broker
495
- participant Consumer as Other Agent/Client
496
-
497
- Note over Agent,Ability: Initialization
498
- Agent->>Agent: Generate scope UUID
499
- Agent->>Ability: spawn(env: { KADI_AGENT_SCOPE: uuid })
500
-
501
- Note over Ability,Broker: Ability Registration
502
- Ability->>Broker: Connect WebSocket
503
- Ability->>Broker: hello({ role: 'agent' })
504
- Broker-->>Ability: { nonce: 'abc123' }
505
- Ability->>Ability: Generate ephemeral Ed25519 keypair
506
- Ability->>Broker: authenticate({ publicKey, signature(nonce) })
507
- Broker-->>Ability: { agentId: 'ability-123' }
508
- Ability->>Broker: registerCapabilities({ tools: [...], scopes: [uuid] })
509
- Broker->>Broker: Store capabilities in scope
510
-
511
- Note over Agent,Broker: Agent Connection
512
- Agent->>Broker: Connect WebSocket
513
- Agent->>Broker: hello/authenticate sequence
514
- Broker-->>Agent: { agentId: 'agent-456' }
515
-
516
- Note over Agent,Broker: Method Call via Broker
517
- Agent->>Broker: callAbility({ toolName: 'echo', args: { message: 'test' }, requestId })
518
- Broker-->>Agent: { requestId }
519
- Broker->>Ability: agent.message({ toolName, args, requestId, from: 'agent-456' })
520
- Ability->>Ability: Execute handler
521
- Ability->>Broker: ability.result({ requestId, toSessionId: 'agent-456', result })
522
- Broker->>Agent: ability.result({ requestId, result })
523
-
524
- Note over Broker,Consumer: Scope Isolation
525
- Consumer->>Broker: listTools({ scopes: ['global'] })
526
- Broker-->>Consumer: { tools: [] } // Ability not visible (wrong scope)
527
- Consumer->>Broker: listTools({ scopes: [uuid] })
528
- Broker-->>Consumer: { tools: ['echo', 'transform'] } // Now visible
679
+ participant Target as Target Ability
680
+
681
+ Note over Client,Broker: Connection & Authentication
682
+ Client->>Broker: WebSocket connect
683
+ Client->>Broker: kadi.session.hello({ role })
684
+ Broker-->>Client: { nonce, heartbeatIntervalSec: 30 }
685
+ Client->>Client: Generate Ed25519 keypair
686
+ Client->>Client: Sign nonce
687
+ Client->>Broker: kadi.session.authenticate({ signature })
688
+ Broker-->>Client: { sessionId }
689
+
690
+ Note over Client,Broker: Heartbeat Management
691
+ Client->>Client: Start heartbeat timer (30s)
692
+ loop Every 30 seconds
693
+ Client->>Broker: kadi.session.ping
694
+ Note over Broker: Reset connection timeout (90s)
695
+ end
696
+
697
+ Note over Client,Broker: Tool Registration
698
+ Client->>Broker: kadi.agent.register({ tools, networks })
699
+ Broker->>Broker: Store in registry
700
+ Broker-->>Client: { registered: true }
701
+
702
+ Note over Client,Target: Remote Tool Invocation
703
+ Client->>Client: callTool('ability-b', 'process', params)
704
+ Client->>Broker: kadi.ability.invoke({
705
+ targetAgent: 'ability-b',
706
+ toolName: 'process',
707
+ toolInput: params
708
+ })
709
+ Broker->>Broker: Lookup ability-b
710
+ Broker->>Target: kadi.ability.invoke
711
+ Target->>Target: Execute tool handler
712
+ Target->>Broker: JSON-RPC response
713
+ Broker-->>Client: Forward response
714
+ Client->>Client: Resolve promise
715
+
716
+ Note over Client,Broker: Event Publishing
717
+ Client->>Broker: kadi.event.publish({
718
+ channel: 'system.status',
719
+ data: { status: 'healthy' }
720
+ })
721
+ Broker->>Broker: Publish to RabbitMQ exchange
722
+
723
+ Note over Client,Broker: Graceful Shutdown
724
+ Client->>Client: Stop heartbeat timer
725
+ Client->>Broker: kadi.session.goodbye
726
+ Client->>Client: Close WebSocket
529
727
  ```
530
728
 
531
- ### Stdio Protocol Frame Processing
729
+ ### Stdio Protocol: LSP-Style Frame Processing
532
730
 
533
- How LSP-style frames are processed:
731
+ How KadiClient handles stdio communication with LSP-style framing:
534
732
 
535
733
  ```mermaid
536
734
  sequenceDiagram
@@ -538,10 +736,10 @@ sequenceDiagram
538
736
  participant SR as StdioFrameReader
539
737
  participant SW as StdioFrameWriter
540
738
  participant Server as StdioRpcServer
541
- participant Ability as KadiAbility
739
+ participant Ability as KadiClient
542
740
 
543
741
  Note over Parent,SR: Incoming Request
544
- Parent->>SR: Write to stdin: "Kadi-Content-Length: 52\r\n\r\n{...}"
742
+ Parent->>SR: Write to stdin: "Content-Length: 52\r\n\r\n{...}"
545
743
  SR->>SR: Buffer incoming data
546
744
  SR->>SR: Look for Content-Length header
547
745
  SR->>SR: Parse header, extract body length
@@ -558,7 +756,7 @@ sequenceDiagram
558
756
  Server->>SW: write(response)
559
757
  SW->>SW: JSON.stringify(response)
560
758
  SW->>SW: Calculate byte length
561
- SW->>SW: Create header: "Kadi-Content-Length: N\r\n\r\n"
759
+ SW->>SW: Create header: "Content-Length: N\r\n\r\n"
562
760
  SW->>Parent: Write header + body to stdout
563
761
 
564
762
  Note over SR: Error Recovery
@@ -590,22 +788,21 @@ const nativeAbility = await loadAbility('my-ability', 'native');
590
788
  ### Working with Loaded Abilities
591
789
 
592
790
  ```javascript
593
- // List available methods
594
- const methods = ability.__list();
595
- console.log('Available methods:', methods);
791
+ // Call methods directly - no need to discover them first
792
+ const result = await ability.echo({ message: 'hello' });
596
793
 
597
794
  // Call methods
598
795
  const result = await ability.someMethod({ param: 'value' });
599
796
 
600
797
  // Direct RPC call (bypasses method validation)
601
- const response = await ability.call('someMethod', { param: 'value' });
798
+ const response = await ability.__call('someMethod', { param: 'value' });
602
799
 
603
800
  // Subscribe to events
604
801
  ability.events.on('custom:event', (data) => {
605
802
  console.log('Event received:', data);
606
803
  });
607
804
 
608
- // Note: Events work for native and stdio protocols
805
+ // Note: Events work for all protocols (native, stdio, and broker)
609
806
  // Subscribe before calling methods that emit events
610
807
  ```
611
808
 
@@ -627,7 +824,7 @@ export KADI_PROTOCOL=stdio
627
824
 
628
825
  # Configure broker
629
826
  export KADI_BROKER_URL=ws://localhost:8080
630
- export KADI_SERVICE_NAME=my-service
827
+ export KADI_ABILITY_NAME=my-ability
631
828
  export KADI_AGENT_SCOPE=project-123
632
829
  ```
633
830
 
@@ -638,19 +835,19 @@ When abilities are spawned as child processes (stdio and broker protocols), the
638
835
  ```javascript
639
836
  // In your ability code, you can access these variables:
640
837
  const protocol = process.env.KADI_PROTOCOL; // 'stdio' or 'broker'
641
- const brokerUrl = process.env.KADI_BROKER_URL; // For broker protocol
642
- const serviceName = process.env.KADI_SERVICE_NAME; // For broker protocol
643
- const agentScope = process.env.KADI_AGENT_SCOPE; // For broker protocol
838
+ const brokerUrl = process.env.KADI_BROKER_URL;
839
+ const abilityName = process.env.KADI_ABILITY_NAME;
840
+ const agentScope = process.env.KADI_AGENT_SCOPE;
644
841
 
645
842
  // Use them to configure your ability behavior
646
- const ability = new KadiAbility({
843
+ const ability = new KadiClient({
647
844
  name: 'my-ability',
648
- scope: process.env.KADI_AGENT_SCOPE || 'global'
845
+ network: process.env.KADI_AGENT_SCOPE || 'global'
649
846
  // Ability automatically uses KADI_PROTOCOL to determine transport
650
847
  });
651
848
  ```
652
849
 
653
- ### Project Structure
850
+ ### Example Project Structure
654
851
 
655
852
  ```
656
853
  my-project/
@@ -659,7 +856,7 @@ my-project/
659
856
  │ └── echo-ability/
660
857
  │ └── 1.0.0/
661
858
  │ ├── agent.json # Ability configuration
662
- │ ├── service.js # Ability implementation
859
+ │ ├── ability.js # Ability implementation
663
860
  │ └── package.json
664
861
  ├── modules/ # Source modules
665
862
  │ └── echo-ability/ # Development version
@@ -670,100 +867,159 @@ my-project/
670
867
 
671
868
  ### Event System
672
869
 
673
- KADI abilities support two types of events:
870
+ KadiClient provides a comprehensive event system that works across all protocols:
674
871
 
675
- #### 1. Lifecycle Events (All Protocols)
872
+ #### 1. Lifecycle Events
676
873
 
677
- These are internal ability lifecycle events that work across all protocols:
874
+ Monitor the ability lifecycle:
678
875
 
679
876
  ```javascript
680
- const ability = new KadiAbility({ name: 'events-ability' });
877
+ const client = new KadiClient({ name: 'my-ability' });
681
878
 
682
- // Listen to lifecycle events
683
- ability.on('start', ({ protocol, methods }) => {
684
- console.log(`Started with ${protocol}, methods: ${methods.join(', ')}`);
879
+ // Connection events
880
+ client.on('connected', ({ broker }) => {
881
+ console.log(`Connected to broker: ${broker}`);
685
882
  });
686
883
 
687
- ability.on('request', ({ id, method, params }) => {
688
- console.log(`Request ${id}: ${method}`);
884
+ client.on('disconnected', () => {
885
+ console.log('Disconnected from broker');
689
886
  });
690
887
 
691
- ability.on('response', ({ id, result, error }) => {
692
- if (error) console.error(`Error in ${id}:`, error);
693
- else console.log(`Response ${id}:`, result);
888
+ // Tool invocation events
889
+ client.on('tool:invoked', ({ toolName, params }) => {
890
+ console.log(`Tool ${toolName} invoked with:`, params);
694
891
  });
695
892
 
696
- ability.on('error', (error) => {
893
+ client.on('tool:completed', ({ toolName, result }) => {
894
+ console.log(`Tool ${toolName} completed:`, result);
895
+ });
896
+
897
+ client.on('error', (error) => {
697
898
  console.error('Ability error:', error);
698
899
  });
699
900
  ```
700
901
 
701
- #### 2. Custom Events (Native and Stdio Protocols Only - for now)
902
+ #### 2. Custom Events (All Protocols)
702
903
 
703
- Abilities can publish custom events that agents can subscribe to:
904
+ Publish and subscribe to custom events across all transport protocols:
704
905
 
705
906
  ```javascript
706
- // In your ability
707
- const ability = new KadiAbility({ name: 'my-ability' });
907
+ // Publishing events
908
+ const publisher = new KadiClient({
909
+ name: 'event-publisher',
910
+ role: 'ability',
911
+ protocol: 'broker' // Works with all protocols
912
+ });
708
913
 
709
- ability.method('process', async ({ data }) => {
914
+ publisher.registerTool('process', async ({ data }) => {
710
915
  // Publish events during processing
711
- ability.publishEvent('process:started', {
712
- timestamp: new Date().toISOString()
916
+ await publisher.publishEvent('process.started', {
917
+ timestamp: Date.now(),
918
+ data
713
919
  });
714
920
 
715
- // ... do work ...
921
+ // Do work...
922
+ const result = await processData(data);
716
923
 
717
- ability.publishEvent('process:completed', {
718
- result: 'success',
719
- timestamp: new Date().toISOString()
924
+ await publisher.publishEvent('process.completed', {
925
+ timestamp: Date.now(),
926
+ result
720
927
  });
721
928
 
722
- return { processed: data };
929
+ return result;
723
930
  });
724
931
 
725
- // In your agent (index.js)
726
- const ability = await loadAbility('my-ability');
932
+ // Subscribing to events
933
+ const subscriber = new KadiClient({
934
+ name: 'event-subscriber',
935
+ role: 'agent',
936
+ protocol: 'broker'
937
+ });
727
938
 
728
- // Subscribe to custom events BEFORE calling methods
729
- ability.events.on('process:started', (data) => {
730
- console.log(`Process started at: ${data.timestamp}`);
939
+ // Subscribe with wildcards
940
+ subscriber.subscribeToEvent('process.*', (data) => {
941
+ console.log('Process event:', data);
731
942
  });
732
943
 
733
- ability.events.on('process:completed', (data) => {
734
- console.log(`Process completed: ${data.result} at ${data.timestamp}`);
944
+ // One-time subscription
945
+ subscriber.onceEvent('process.completed', (data) => {
946
+ console.log('First completion:', data);
735
947
  });
736
948
 
737
- // Now call the method that emits events
738
- await ability.process({ data: 'test' });
949
+ // Multiple pattern subscription
950
+ subscriber.subscribeToEvents(['process.*', 'system.*'], (pattern, data) => {
951
+ console.log(`Event from ${pattern}:`, data);
952
+ });
739
953
  ```
740
954
 
741
- **Important Notes:**
955
+ **Protocol-Specific Behavior:**
956
+
957
+ - **Native**: Direct EventEmitter, synchronous delivery
958
+ - **Stdio**: JSON-RPC notifications with LSP framing
959
+ - **Broker**: RabbitMQ pub/sub via WebSocket, persistent queues available
960
+
961
+ ### Multi-Broker Configuration
962
+
963
+ KadiClient supports connecting to multiple brokers simultaneously for redundancy and load distribution:
964
+
965
+ ```javascript
966
+ const client = new KadiClient({
967
+ name: 'multi-broker-ability',
968
+ role: 'ability',
969
+ protocol: 'broker',
970
+ brokers: {
971
+ 'primary': 'ws://broker1.example.com:8080',
972
+ 'secondary': 'ws://broker2.example.com:8080',
973
+ 'backup': 'ws://broker3.example.com:8080'
974
+ },
975
+ defaultBroker: 'primary', // Used for sending if no specific broker targeted
976
+ networks: ['production']
977
+ });
978
+
979
+ // Connect to all configured brokers
980
+ await client.connectToBrokers();
742
981
 
743
- - Custom events only work with `native` and `stdio` protocols for now
744
- - Always subscribe to events before calling methods that emit them
745
- - Events are emitted immediately when `publishEvent()` is called
746
- - Broker protocol event support is in progress
982
+ // The client will now:
983
+ // 1. Maintain connections to all three brokers
984
+ // 2. Receive messages from any broker
985
+ // 3. Send messages to the default broker unless specified
986
+ // 4. Automatically handle broker failover
987
+ ```
988
+
989
+ ### Cross-Language Ability Support
747
990
 
748
- ### Error Handling
991
+ KADI now fully supports abilities written in any language through the stdio protocol:
749
992
 
750
993
  ```javascript
751
- try {
752
- const ability = await loadAbility('my-ability', 'stdio');
753
- const result = await ability.riskyMethod({ data: 'test' });
754
- } catch (error) {
755
- if (error.message.includes('not found')) {
756
- console.error('Ability not installed. Run: kadi install');
757
- } else if (error.message.includes('timeout')) {
758
- console.error('Method timed out. Check ability health.');
759
- } else if (error.message.includes('not exposed by this ability')) {
760
- console.error(
761
- 'Method not available. Use ability.__list() to see available methods.'
762
- );
763
- } else {
764
- console.error('Unexpected error:', error);
994
+ // Go ability with agent.json:
995
+ {
996
+ "name": "hash-go",
997
+ "scripts": {
998
+ "setup": "go build -o bin/hash_ability",
999
+ "start": "./bin/hash_ability" // Binary executable
1000
+ }
1001
+ }
1002
+
1003
+ // Python ability:
1004
+ {
1005
+ "name": "ml-processor",
1006
+ "scripts": {
1007
+ "start": "python3 main.py"
765
1008
  }
766
1009
  }
1010
+
1011
+ // Rust ability:
1012
+ {
1013
+ "name": "crypto-rust",
1014
+ "scripts": {
1015
+ "setup": "cargo build --release",
1016
+ "start": "./target/release/crypto_ability"
1017
+ }
1018
+ }
1019
+
1020
+ // Load and use regardless of implementation language:
1021
+ const hashAbility = await loadAbility('hash-go', 'stdio');
1022
+ const result = await hashAbility.sha256({ data: 'hello' });
767
1023
  ```
768
1024
 
769
1025
  ## 🔧 Development Workflow
@@ -772,7 +1028,7 @@ try {
772
1028
 
773
1029
  When developing new features or testing changes to `@kadi.build/core` before publishing to NPM:
774
1030
 
775
- 0. **clone the repository**
1031
+ 0. **Clone the repository**
776
1032
 
777
1033
  ```bash
778
1034
  git clone https://gitlab.com/humin-game-lab/kadi/kadi-core.git
@@ -786,14 +1042,14 @@ npm pack
786
1042
  # This creates: kadi.build-core-X.Y.Z.tgz
787
1043
  ```
788
1044
 
789
- 1. **Install in your project**:
1045
+ 2. **Install in your project**:
790
1046
 
791
1047
  ```bash
792
1048
  cd /path/to/your-project
793
1049
  npm install /path/to/kadi-core/kadi.build-core-X.Y.Z.tgz
794
1050
  ```
795
1051
 
796
- 1. **For ability development**, update the ability's preflight script:
1052
+ 3. **For ability development**, update the ability's preflight script:
797
1053
 
798
1054
  ```json
799
1055
  {
@@ -807,402 +1063,295 @@ npm install /path/to/kadi-core/kadi.build-core-X.Y.Z.tgz
807
1063
 
808
1064
  ### Core Classes
809
1065
 
810
- #### `KadiAbility`
1066
+ #### `KadiClient`
811
1067
 
812
- The main class for creating abilities.
1068
+ The unified class for all KADI operations - serving tools, calling remote abilities, and managing events.
813
1069
 
814
1070
  ```javascript
815
- import { KadiAbility } from '@kadi.build/core';
1071
+ import { KadiClient } from '@kadi.build/core';
816
1072
 
817
- const ability = new KadiAbility({
1073
+ const client = new KadiClient({
818
1074
  name: 'my-ability',
819
- version: '1.0.0',
820
- description: 'My ability description',
821
- scope: 'global', // or process.env.KADI_AGENT_SCOPE
822
- protocol: 'stdio' // 'native', 'stdio', or 'broker'
1075
+ role: 'ability', // 'agent' or 'ability'
1076
+ protocol: 'broker', // 'native', 'stdio', or 'broker'
1077
+ brokers: {
1078
+ 'dev': 'ws://localhost:8080',
1079
+ 'prod': 'ws://prod.example.com:8080'
1080
+ },
1081
+ defaultBroker: 'dev',
1082
+ network: 'global', // Primary network
1083
+ networks: ['global', 'custom-network'] // All networks
823
1084
  });
824
1085
  ```
825
1086
 
826
- **Methods:**
827
-
828
- - `ability.method(name, handler, schema?)` - Register a method
829
- - `ability.serve()` - Start serving requests
830
- - `ability.publishEvent(eventName, data)` - Publish an event
831
- - `ability.on(event, handler)` - Listen to lifecycle events
832
-
833
- #### `loadAbility`
834
-
835
- Load an ability by name and protocol.
836
-
837
- ```javascript
838
- import { loadAbility } from '@kadi.build/core';
839
-
840
- const ability = await loadAbility('ability-name', 'protocol');
841
- ```
842
-
843
- **Returns:** A proxy object with:
1087
+ **Configuration Options:**
844
1088
 
845
- - Direct method calls (e.g., `ability.echo({ message: 'hello' })`)
846
- - `ability.__list()` - List available methods
847
- - `ability.events` - EventEmitter for subscribing to events (native/stdio protocols only)
848
- - `ability.call(method, params)` - Direct RPC call
1089
+ - `name` - Ability/agent name
1090
+ - `role` - Operating role: 'agent' (consumer) or 'ability' (provider)
1091
+ - `protocol` - Transport protocol to use
1092
+ - `brokers` - Named broker configurations (object mapping names to URLs)
1093
+ - `defaultBroker` - Default broker name for sending messages
1094
+ - `network` - Primary network segment for message routing
1095
+ - `networks` - All network namespaces for tool discovery
1096
+ - `heartbeatIntervalSec` - Custom heartbeat interval (default: from broker)
849
1097
 
850
- ### Utility Functions
1098
+ **Tool Registration Methods:**
851
1099
 
852
- ```javascript
853
- import {
854
- createLogger,
855
- getProjectJSON,
856
- getAbilityJSON,
857
- getBrokerUrl,
858
- runExecCommand
859
- } from '@kadi.build/core';
860
- ```
1100
+ - `registerTool(name, handler, schema?)` - Register a single tool
1101
+ - `getTools()` - Get list of registered tool names
1102
+ - `getToolNames()` - Get filtered list of tool names
1103
+ - `getToolHandler(name)` - Get a specific tool's handler
1104
+ - `getToolSchema(name)` - Get a specific tool's schema
1105
+ - `hasTool(name)` - Check if a tool is registered
861
1106
 
862
- ## 🎮 Running the Examples
1107
+ **Remote Tool Invocation:**
863
1108
 
864
- ### Quick Start with Example Agent
1109
+ - `callTool(targetAgent, toolName, params)` - Call a remote tool via broker
1110
+ - `discoverRemoteTools(targetAgent)` - List tools from a remote agent
1111
+ - `loadAbility(name, protocol?, options?)` - Load an ability (compatibility)
865
1112
 
866
- The `@kadi.build/core` package includes a complete example demonstrating multi-language abilities (JavaScript and Go) with all three transport protocols.
1113
+ **Event System:**
867
1114
 
868
- The `examples` folder contains:
1115
+ - `publishEvent(eventName, data)` - Publish an event
1116
+ - `subscribeToEvent(pattern, callback)` - Subscribe with wildcards
1117
+ - `subscribeToEvents(patterns[], callback)` - Multiple subscriptions
1118
+ - `unsubscribeFromEvent(pattern, callback)` - Remove subscription
1119
+ - `onceEvent(pattern, callback)` - One-time subscription
869
1120
 
870
- ```
871
- examples/
872
- ├── example-abilities/ # Sample abilities in different languages
873
- │ ├── echo-js/ # JavaScript ability using KadiAbility
874
- │ │ ├── agent.json # Ability configuration
875
- │ │ ├── service.js # Implementation
876
- │ │ └── package.json
877
- │ └── hash-go/ # Go ability demonstrating polyglot support
878
- │ ├── agent.json
879
- │ ├── go.mod
880
- │ └── cmd/hash_ability/main.go
881
- └── example-agent/ # Sample agent using the abilities
882
- ├── agent.json # Declares dependencies on abilities
883
- ├── index.js # Demonstrates all loading patterns
884
- └── package.json
885
- ```
1121
+ **Connection Management:**
886
1122
 
887
- #### Step 0: Have the KADI broker running locally
1123
+ - `serve()` - Start serving (stdio/native modes)
1124
+ - `connectToBrokers()` - Connect to all configured brokers
1125
+ - `disconnect()` - Clean disconnect
1126
+ - `isConnected` - Check connection status
888
1127
 
889
- ```bash
890
- kadi broker up
891
- ```
1128
+ **Properties:**
892
1129
 
893
- #### Step 1: Navigate to the example agent
894
-
895
- ```bash
896
- cd /path/to/kadi-core/examples/example-agent
897
- ```
898
-
899
- #### Step 2: Install abilities
900
-
901
- ```bash
902
- # Inside 'example-agent' folder
903
- kadi install
904
- ```
905
-
906
- This installs the `echo-js` (JavaScript) and `hash-go` (Go) abilities defined in the agent.json.
907
-
908
- #### Step 3: Run the agent
909
-
910
- ```bash
911
- kadi run
912
- ```
913
-
914
- #### Expected Output
915
-
916
- You should see the agent testing various abilities and protocols:
917
-
918
- ```
919
- === WORKING ABILITIES ===
920
-
921
- 🔧 Loading echo-js ability using native (Javascript)...
922
- Available methods: [ 'echo', 'say_message' ]
923
- Echo-js echo result: {
924
- echo: 'I am calling echo-js echo method from Javascript',
925
- timestamp: '2025-08-15T00:20:23.276Z',
926
- length: 48
927
- }
928
-
929
- 🔧 Loading echo-js ability using stdio (Javascript)...
930
- Available methods: [ 'echo', 'say_message' ]
931
- Echo-js echo result: {
932
- echo: 'I am calling echo-js echo method from Javascript',
933
- timestamp: '2025-08-15T00:20:23.339Z',
934
- length: 48
935
- }
936
- ```
1130
+ - `agentId` - Unique agent identifier
1131
+ - `name` - Ability name
1132
+ - `role` - Current operating role
1133
+ - `protocol` - Active protocol
1134
+ - `brokers` - Configured broker map
1135
+ - `defaultBroker` - Default broker name
1136
+ - `currentBroker` - Currently active broker for sending
937
1137
 
938
- #### Step 4: Stop and Clean Up
939
-
940
- ```bash
941
- # Stop the agent
942
- Ctrl + C
943
-
944
- # Clean up installed abilities and node_modules
945
- kadi run clean
946
- ```
947
-
948
- ### What the Example Demonstrates
949
-
950
- 1. **Polyglot Abilities**: Go (`hash-go`) and JavaScript (`echo-js`) abilities working together
951
- 2. **Protocol Flexibility**: Same ability (`echo-js`) loaded via native, stdio, and broker
952
- 3. **Error Handling**: Graceful handling when calling non-existent methods
953
- 4. **Method Discovery**: Using `__list()` to discover available methods
954
- 5. **Schema Support**: Both inline and export-based schema definitions
955
- 6. **Event System**: Publishing and subscribing to events across protocols
956
- 7. **Event Timing**: Demonstrates the importance of subscribing to events before calling methods
957
-
958
- ### Exploring the Code
959
-
960
- **echo-js ability** (`examples/example-abilities/echo-js/service.js`):
961
-
962
- - Shows method registration with and without schemas
963
- - Demonstrates scope configuration for broker visibility
964
- - Uses environment variables for protocol adaptation
965
- - Includes event publishing examples using `publishEvent()`
966
- - Demonstrates how to emit events from method handlers
967
-
968
- **hash-go ability** (`examples/example-abilities/hash-go/`):
969
-
970
- - Demonstrates Go SDK integration
971
- - Shows stdio protocol with a compiled language
972
- - Implements SHA256 hashing as a service
973
-
974
- **example-agent** (`examples/example-agent/index.js`):
975
-
976
- - Shows all three loading patterns
977
- - Demonstrates error handling
978
- - Tests cross-language ability communication
979
- - Includes event subscription examples using `ability.events.on()`
980
- - Shows how to subscribe to events before calling methods
981
- - Demonstrates event handling across different protocols (native/stdio)
982
-
983
- ## 💡 Additional Examples
984
-
985
- ### Complete Echo Service Example
986
-
987
- **service.js**:
1138
+ **Complete Usage Example:**
988
1139
 
989
1140
  ```javascript
990
- #!/usr/bin/env node
991
- import { KadiAbility } from '@kadi.build/core';
1141
+ import { KadiClient } from '@kadi.build/core';
992
1142
 
993
- const echoAbility = new KadiAbility({
994
- name: 'echo-service',
995
- version: '1.0.0',
996
- description: 'Multi-protocol echo service',
997
- scope: process.env.KADI_AGENT_SCOPE // Important for broker visibility
998
- });
999
-
1000
- // Simple echo with metadata
1001
- echoAbility.method('echo', async ({ message }) => {
1002
- // Publish events (works for native and stdio protocols)
1003
- echoAbility.publishEvent('echo:test-event', { from: 'message echo' });
1004
- echoAbility.publishEvent('echo:test-event', { from: 'message echo 2' });
1005
-
1006
- return {
1007
- echo: message,
1008
- timestamp: new Date().toISOString(),
1009
- length: message?.length || 0
1010
- };
1143
+ // Create an ability that can serve tools
1144
+ const ability = new KadiClient({
1145
+ name: 'math-ability',
1146
+ role: 'ability',
1147
+ protocol: 'broker',
1148
+ brokers: {
1149
+ 'local': 'ws://localhost:8080',
1150
+ 'cloud': 'wss://api.example.com'
1151
+ },
1152
+ defaultBroker: 'local',
1153
+ networks: ['global']
1011
1154
  });
1012
1155
 
1013
- // Transform text
1014
- echoAbility.method(
1015
- 'transform',
1016
- async ({ text, operations }) => {
1017
- let result = text;
1018
- for (const op of operations) {
1019
- switch (op) {
1020
- case 'upper':
1021
- result = result.toUpperCase();
1022
- break;
1023
- case 'lower':
1024
- result = result.toLowerCase();
1025
- break;
1026
- case 'reverse':
1027
- result = result.split('').reverse().join('');
1028
- break;
1029
- }
1030
- }
1031
- return { transformed: result };
1156
+ // Register tools with schemas
1157
+ ability.registerTool(
1158
+ 'add',
1159
+ async ({ a, b }) => {
1160
+ // Publish event before processing
1161
+ await ability.publishEvent('math.operation', {
1162
+ operation: 'add',
1163
+ inputs: { a, b }
1164
+ });
1165
+
1166
+ const result = a + b;
1167
+
1168
+ // Publish completion event
1169
+ await ability.publishEvent('math.completed', {
1170
+ operation: 'add',
1171
+ result
1172
+ });
1173
+
1174
+ return { result };
1032
1175
  },
1033
1176
  {
1034
- description: 'Transform text with multiple operations',
1177
+ description: 'Add two numbers',
1035
1178
  inputSchema: {
1036
1179
  type: 'object',
1037
1180
  properties: {
1038
- text: { type: 'string' },
1039
- operations: {
1040
- type: 'array',
1041
- items: { enum: ['upper', 'lower', 'reverse'] }
1042
- }
1181
+ a: { type: 'number', description: 'First number' },
1182
+ b: { type: 'number', description: 'Second number' }
1043
1183
  },
1044
- required: ['text', 'operations']
1184
+ required: ['a', 'b']
1185
+ },
1186
+ outputSchema: {
1187
+ type: 'object',
1188
+ properties: {
1189
+ result: { type: 'number', description: 'Sum of a and b' }
1190
+ }
1045
1191
  }
1046
1192
  }
1047
1193
  );
1048
1194
 
1049
- echoAbility.serve().catch(console.error);
1050
- ```
1051
-
1052
- **Using the service**:
1195
+ // Subscribe to events from other abilities
1196
+ ability.subscribeToEvent('system.*', (data) => {
1197
+ console.log('System event:', data);
1198
+ });
1053
1199
 
1054
- ```javascript
1055
- import { loadAbility } from '@kadi.build/core';
1200
+ // Connect to brokers
1201
+ await ability.connectToBrokers();
1056
1202
 
1057
- async function demo() {
1058
- // Try all protocols
1059
- for (const protocol of ['native', 'stdio', 'broker']) {
1060
- console.log(`\nTesting ${protocol} protocol:`);
1061
-
1062
- try {
1063
- const echo = await loadAbility('echo-service', protocol);
1064
-
1065
- // Subscribe to events (works for native and stdio protocols)
1066
- echo.events.on('echo:test-event', (data) => {
1067
- console.log(`Echo event received: ${data.from}`);
1068
- });
1069
-
1070
- // Simple echo
1071
- const result1 = await echo.echo({
1072
- message: `Hello from ${protocol}!`
1073
- });
1074
- console.log('Echo:', result1);
1075
-
1076
- // Transform
1077
- const result2 = await echo.transform({
1078
- text: 'Hello World',
1079
- operations: ['lower', 'reverse']
1080
- });
1081
- console.log('Transform:', result2);
1082
- } catch (error) {
1083
- console.error(`${protocol} failed:`, error.message);
1084
- }
1085
- }
1086
- }
1203
+ // Call remote tools
1204
+ const result = await ability.callTool('translator-ability', 'translate', {
1205
+ text: 'Hello',
1206
+ to: 'es'
1207
+ });
1087
1208
 
1088
- demo();
1209
+ // Graceful shutdown
1210
+ process.on('SIGTERM', async () => {
1211
+ await ability.disconnect();
1212
+ process.exit(0);
1213
+ });
1089
1214
  ```
1090
1215
 
1091
- ## 🎯 Real-World Event Example
1092
-
1093
- Here's the exact event pattern used in the example code:
1216
+ #### `loadAbility`
1094
1217
 
1095
- **In your ability (service.js):**
1218
+ Load an ability by name and protocol.
1096
1219
 
1097
1220
  ```javascript
1098
- const echoAbility = new KadiAbility({
1099
- name: 'echo-js',
1100
- version: '0.0.1',
1101
- scope: process.env.KADI_AGENT_SCOPE
1102
- });
1103
-
1104
- async function echo(message) {
1105
- const timestamp = new Date().toISOString();
1106
- const messageText = message?.message ?? message ?? '';
1107
- const length = messageText.length;
1221
+ import { loadAbility } from '@kadi.build/core';
1108
1222
 
1109
- // Publish events (works for native and stdio protocols)
1110
- echoAbility.publishEvent('echo:test-event', { from: 'message echo' });
1111
- echoAbility.publishEvent('echo:test-event', { from: 'message echo 2' });
1223
+ const ability = await loadAbility('ability-name', 'protocol', {
1224
+ brokerUrl: 'ws://localhost:8080', // For broker protocol
1225
+ brokerName: 'dev', // Named broker to use
1226
+ networks: ['global'], // Network segments
1227
+ existingClient: client // Reuse existing KadiClient for broker
1228
+ });
1229
+ ```
1112
1230
 
1113
- return { echo: messageText, timestamp, length };
1114
- }
1231
+ **Returns:** A proxy object with:
1115
1232
 
1116
- echoAbility.method('echo', echo);
1117
- ```
1233
+ - Direct method calls (e.g., `ability.echo({ message: 'hello' })`)
1234
+ - `ability.events` - EventEmitter for subscribing to events (all protocols)
1235
+ - `ability.__call(method, params)` - Direct RPC call
1236
+ - `ability.__disconnect()` - Clean up resources
1118
1237
 
1119
- **In your agent (index.js):**
1238
+ ### Utility Functions
1120
1239
 
1121
1240
  ```javascript
1122
- // Subscribe first
1123
- echoJsAbility.events.on('echo:test-event', (data) => {
1124
- console.log(`[NATIVE] echo:test-event received:`, data);
1125
- });
1126
-
1127
- // Now trigger the method that emits the event
1128
- const echoJsResult = await echoJsAbility.echo({
1129
- message: 'I am calling echo-js echo method from Javascript'
1130
- });
1241
+ import {
1242
+ createLogger,
1243
+ getProjectJSON,
1244
+ getAbilityJSON,
1245
+ getAgentJSON,
1246
+ getBrokerUrl,
1247
+ runExecCommand
1248
+ } from '@kadi.build/core';
1131
1249
  ```
1132
1250
 
1133
- **Key Points:**
1134
-
1135
- - Events work for `native` and `stdio` protocols only
1136
- - Always subscribe to events BEFORE calling methods that emit them
1137
- - Events are emitted immediately when `publishEvent()` is called
1138
- - Use `ability.events.on()` to subscribe to custom events
1139
- - Use `ability.on()` to listen to lifecycle events
1251
+ ### Debug Mode
1140
1252
 
1141
- ## 🐛 Troubleshooting
1253
+ Enable detailed logging:
1142
1254
 
1143
- ### Common Issues
1255
+ ```bash
1256
+ DEBUG=kadi:* node index.js
1257
+ ```
1144
1258
 
1145
- **Ability Not Found**
1259
+ Check ability logs:
1146
1260
 
1261
+ ```bash
1262
+ tail -f abilities/my-ability/1.0.0/my-ability.log
1147
1263
  ```
1148
- Error: Ability 'my-ability' version '1.0.0' is not installed
1149
- ```
1264
+ ## 💡 Additional Examples
1150
1265
 
1151
- **Solution**: Run `kadi install` to install project dependencies
1266
+ ### Error Handling Pattern
1152
1267
 
1153
- **Broker Connection Failed**
1268
+ ```javascript
1269
+ const client = new KadiClient({
1270
+ name: 'robust-ability',
1271
+ role: 'ability'
1272
+ });
1154
1273
 
1155
- ```
1156
- Error: Failed to connect to KADI Broker at ws://localhost:8080
1274
+ client.registerTool('riskyOperation', async (params) => {
1275
+ try {
1276
+ const result = await performOperation(params);
1277
+ await client.publishEvent('operation.success', { result });
1278
+ return { success: true, result };
1279
+ } catch (error) {
1280
+ await client.publishEvent('operation.error', {
1281
+ error: error.message,
1282
+ params
1283
+ });
1284
+ // Return error in structured format
1285
+ return {
1286
+ success: false,
1287
+ error: error.message
1288
+ };
1289
+ }
1290
+ });
1157
1291
  ```
1158
1292
 
1159
- **Solution**: Ensure the broker is running: `kadi broker start`
1293
+ ### Health Check Pattern
1160
1294
 
1161
- **Method Not Found**
1162
-
1163
- ```
1164
- Error: Method 'someMethod' is not exposed by this ability
1295
+ ```javascript
1296
+ // Register a standard health check tool
1297
+ client.registerTool('health', async () => {
1298
+ const checks = {
1299
+ memory: process.memoryUsage(),
1300
+ uptime: process.uptime(),
1301
+ brokers: client.isConnected ? 'connected' : 'disconnected',
1302
+ timestamp: Date.now()
1303
+ };
1304
+
1305
+ return {
1306
+ status: 'healthy',
1307
+ checks
1308
+ };
1309
+ });
1165
1310
  ```
1166
1311
 
1167
- **Solution**: Check ability exports or use `__list()` to see available methods
1312
+ ## 🐛 Troubleshooting
1168
1313
 
1169
- **Protocol Not Supported**
1314
+ ### Common Issues and Solutions
1170
1315
 
1171
- ```
1172
- Error: Unsupported ability interface protocol: custom
1173
- ```
1316
+ #### Broker Connection Failures
1174
1317
 
1175
- **Solution**: Ability must define the protocol in its `agent.json` interfaces
1318
+ **Problem**: "Failed to connect to any brokers"
1176
1319
 
1177
- **Event Subscription Issues**
1320
+ **Solutions**:
1321
+ - Verify broker URLs are correct
1322
+ - Check network connectivity
1323
+ - Ensure broker is running
1324
+ - Try connecting with lower security (ws:// before wss://)
1178
1325
 
1179
- ```
1180
- TypeError: Cannot read property 'on' of undefined
1181
- ```
1182
-
1183
- **Solution**: Make sure you're accessing `ability.events.on()` not `ability.on()` for custom events
1326
+ #### Events Not Arriving
1184
1327
 
1185
- **Event Protocol Support**
1328
+ **Problem**: Subscribed to events but callbacks not triggered
1186
1329
 
1187
- ```
1188
- Events are only supported for 'native' and 'stdio' protocols
1189
- ```
1330
+ **Solutions**:
1331
+ - Subscribe BEFORE triggering events
1332
+ - Check pattern matching (use exact match first)
1333
+ - Verify publisher and subscriber are on same network
1334
+ - Enable debug logging to trace event flow
1190
1335
 
1191
- **Solution**: Events currently work for `native` and `stdio` protocols only. Broker protocol event support is planned for future releases.
1336
+ #### Cross-Language Abilities Not Loading
1192
1337
 
1193
- ### Debug Mode
1338
+ **Problem**: "Cannot find module 'ability.js'" when loading Go/Python abilities
1194
1339
 
1195
- Enable detailed logging:
1340
+ **Solutions**:
1341
+ - Ensure `scripts.start` field exists in agent.json
1342
+ - Verify the binary/script is executable
1343
+ - Check that setup script has been run
1344
+ - Use stdio protocol, not native
1196
1345
 
1197
- ```bash
1198
- DEBUG=kadi:* node index.js
1199
- ```
1346
+ #### Memory Leaks
1200
1347
 
1201
- Check ability logs:
1348
+ **Problem**: Memory usage grows over time
1202
1349
 
1203
- ```bash
1204
- tail -f abilities/my-ability/1.0.0/my-ability.log
1205
- ```
1350
+ **Solutions**:
1351
+ - Always call unsubscribe functions
1352
+ - Use `onceEvent` for single-use subscriptions
1353
+ - Disconnect abilities when done
1354
+ - Clear event listeners on cleanup
1206
1355
 
1207
1356
  ## 🤝 Contributing
1208
1357
 
@@ -1216,7 +1365,7 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
1216
1365
 
1217
1366
  ## 📄 License
1218
1367
 
1219
- MIT License - see [LICENSE](LICENSE) file for details
1368
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
1220
1369
 
1221
1370
  ## 🔗 Related Projects
1222
1371
 
@@ -1225,11 +1374,10 @@ MIT License - see [LICENSE](LICENSE) file for details
1225
1374
 
1226
1375
  ## 📚 Resources
1227
1376
 
1228
- - [Official Documentation](https://docs.kadi.build)
1229
- - [API Reference](https://docs.kadi.build/api)
1230
- - [Tutorial: Building Your First Ability](https://docs.kadi.build/tutorial)
1231
- - [Architecture Deep Dive](https://docs.kadi.build/architecture)
1377
+ - [Event System Deep Dive](docs/event-system.md) - Complete guide to the event architecture
1378
+ - [API Documentation](https://docs.kadi.build) - Full API reference
1379
+ - [Examples Repository](https://github.com/kadi-examples) - More examples and patterns
1232
1380
 
1233
1381
  ---
1234
1382
 
1235
- Built with ❤️ by the KADI team
1383
+ Built with ❤️ by the KADI team