@kadi.build/core 0.0.1-alpha.1 → 0.0.1-alpha.3
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 +1145 -216
- package/examples/example-abilities/echo-js/README.md +131 -0
- package/examples/example-abilities/echo-js/agent.json +63 -0
- package/examples/example-abilities/echo-js/package.json +24 -0
- package/examples/example-abilities/echo-js/service.js +43 -0
- package/examples/example-abilities/hash-go/agent.json +53 -0
- package/examples/example-abilities/hash-go/cmd/hash_ability/main.go +340 -0
- package/examples/example-abilities/hash-go/go.mod +3 -0
- package/examples/example-agent/abilities/echo-js/0.0.1/README.md +131 -0
- package/examples/example-agent/abilities/echo-js/0.0.1/agent.json +63 -0
- package/examples/example-agent/abilities/echo-js/0.0.1/package-lock.json +93 -0
- package/examples/example-agent/abilities/echo-js/0.0.1/package.json +24 -0
- package/examples/example-agent/abilities/echo-js/0.0.1/service.js +41 -0
- package/examples/example-agent/abilities/hash-go/0.0.1/agent.json +53 -0
- package/examples/example-agent/abilities/hash-go/0.0.1/bin/hash_ability +0 -0
- package/examples/example-agent/abilities/hash-go/0.0.1/cmd/hash_ability/main.go +340 -0
- package/examples/example-agent/abilities/hash-go/0.0.1/go.mod +3 -0
- package/examples/example-agent/agent.json +39 -0
- package/examples/example-agent/index.js +102 -0
- package/examples/example-agent/package-lock.json +93 -0
- package/examples/example-agent/package.json +17 -0
- package/package.json +4 -2
- package/src/KadiAbility.js +478 -0
- package/src/index.js +65 -0
- package/src/loadAbility.js +1086 -0
- package/src/servers/BaseRpcServer.js +404 -0
- package/src/servers/BrokerRpcServer.js +776 -0
- package/src/servers/StdioRpcServer.js +360 -0
- package/src/transport/BrokerMessageBuilder.js +377 -0
- package/src/transport/IpcMessageBuilder.js +1229 -0
- package/src/utils/agentUtils.js +137 -0
- package/src/utils/commandUtils.js +64 -0
- package/src/utils/configUtils.js +72 -0
- package/src/utils/logger.js +161 -0
- package/src/utils/pathUtils.js +86 -0
- package/broker.js +0 -214
- package/index.js +0 -370
- package/ipc.js +0 -220
- package/ipcInterfaces/pythonAbilityIPC.py +0 -177
package/README.md
CHANGED
|
@@ -1,306 +1,1235 @@
|
|
|
1
1
|
# @kadi.build/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> A comprehensive toolkit for building and managing KADI abilities with multiple transport protocols
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@kadi.build/core)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## 🎯 Overview
|
|
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.
|
|
11
|
+
|
|
12
|
+
## 📚 Table of Contents
|
|
13
|
+
|
|
14
|
+
- [🎯 Overview](#-overview)
|
|
15
|
+
- [📦 Installation](#-installation)
|
|
16
|
+
- [🚀 Quick Start](#-quick-start)
|
|
17
|
+
- [🔌 Transport Protocols](#-transport-protocols)
|
|
18
|
+
- [🛠️ Creating Abilities](#-creating-abilities)
|
|
19
|
+
- [🔄 Architecture Deep Dive](#-architecture-deep-dive)
|
|
20
|
+
- [📥 Loading Abilities](#-loading-abilities)
|
|
21
|
+
- [⚙️ Configuration](#-configuration)
|
|
22
|
+
- [🚀 Advanced Usage](#-advanced-usage)
|
|
23
|
+
- [🔧 Development Workflow](#-development-workflow)
|
|
24
|
+
- [📖 API Reference](#-api-reference)
|
|
25
|
+
- [🎮 Running the Examples](#-running-the-examples)
|
|
26
|
+
- [💡 Additional Examples](#-additional-examples)
|
|
27
|
+
- [🐛 Troubleshooting](#-troubleshooting)
|
|
28
|
+
- [🤝 Contributing](#-contributing)
|
|
29
|
+
- [📄 License](#-license)
|
|
30
|
+
- [🔗 Related Projects](#-related-projects)
|
|
31
|
+
- [📚 Resources](#-resources)
|
|
32
|
+
|
|
33
|
+
## 📦 Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install @kadi.build/core
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
For global CLI tools:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install -g @kadi.build/cli
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 🚀 Quick Start
|
|
4
46
|
|
|
5
|
-
|
|
47
|
+
### Creating Your First Ability
|
|
6
48
|
|
|
7
|
-
|
|
49
|
+
```javascript
|
|
50
|
+
#!/usr/bin/env node
|
|
51
|
+
import { KadiAbility } from '@kadi.build/core';
|
|
52
|
+
|
|
53
|
+
// Create an ability instance
|
|
54
|
+
const mathAbility = new KadiAbility({
|
|
55
|
+
name: 'math-ability',
|
|
56
|
+
version: '1.0.0',
|
|
57
|
+
description: 'Simple math operations'
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Register a method
|
|
61
|
+
mathAbility.method('add', async ({ a, b }) => {
|
|
62
|
+
return { result: a + b };
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Start serving requests
|
|
66
|
+
mathAbility.serve().catch(console.error);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Loading and Using Abilities
|
|
8
70
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- **Multi-Broker Support**: Dynamic broker selection and management with environment/runtime configuration.
|
|
12
|
-
- **Broker Interaction**: Facilitate communications with WebSocket brokers.
|
|
13
|
-
- **IPC Support**: Tools for interprocess communication across various programming languages.
|
|
71
|
+
```javascript
|
|
72
|
+
import { loadAbility } from '@kadi.build/core';
|
|
14
73
|
|
|
15
|
-
|
|
74
|
+
async function main() {
|
|
75
|
+
// Load an ability (uses first interface defined in agent.json)
|
|
76
|
+
const math = await loadAbility('math-ability');
|
|
16
77
|
|
|
17
|
-
|
|
78
|
+
// Call methods like regular functions
|
|
79
|
+
const result = await math.add({ a: 5, b: 3 });
|
|
80
|
+
console.log(result); // { result: 8 }
|
|
81
|
+
|
|
82
|
+
// List available methods
|
|
83
|
+
console.log(math.__list()); // ['add']
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
main().catch(console.error);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## 🔌 Transport Protocols
|
|
90
|
+
|
|
91
|
+
KADI abilities support three transport protocols, each optimized for different use cases:
|
|
92
|
+
|
|
93
|
+
### 1. Native Protocol (Fastest)
|
|
94
|
+
|
|
95
|
+
- **Use Case**: High-performance, in-process execution
|
|
96
|
+
- **How it Works**: Loads abilities as ES modules, enabling direct function calls
|
|
97
|
+
- **Performance**: Zero IPC overhead - functions run in the same process
|
|
98
|
+
- **Best For**: Utility libraries, data processing, performance-critical operations
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
// Loads as native module by default if available
|
|
102
|
+
const ability = await loadAbility('my-ability', 'native');
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 2. Stdio Protocol (Balanced)
|
|
106
|
+
|
|
107
|
+
- **Use Case**: Language-agnostic local execution
|
|
108
|
+
- **How it Works**: Spawns abilities as child processes, communicates via LSP-style JSON-RPC over stdin/stdout
|
|
109
|
+
- **Performance**: Minimal overhead, reliable local IPC
|
|
110
|
+
- **Best For**: Python scripts, Go binaries, Node.js services, development/testing
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
// Force stdio protocol
|
|
114
|
+
const ability = await loadAbility('my-ability', 'stdio');
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Environment Variables Passed to Child Process:**
|
|
18
118
|
|
|
19
119
|
```bash
|
|
20
|
-
|
|
120
|
+
KADI_PROTOCOL=stdio # Identifies the protocol being used
|
|
121
|
+
# Plus all parent process.env variables
|
|
21
122
|
```
|
|
22
123
|
|
|
23
|
-
|
|
124
|
+
### 3. Broker Protocol (Distributed)
|
|
24
125
|
|
|
25
|
-
|
|
126
|
+
- **Use Case**: Distributed services, containerized deployments
|
|
127
|
+
- **How it Works**: Abilities connect to a WebSocket broker for network communication
|
|
128
|
+
- **Performance**: Network overhead, but enables scaling and distribution
|
|
129
|
+
- **Best For**: Microservices, cloud deployments, load-balanced services
|
|
26
130
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
- **`getProjectJSON()`**: Fetches the `agent.json` for the current project.
|
|
32
|
-
- **`getProjectJSONPath()`**: Gets the file path for the project's `agent.json`.
|
|
33
|
-
- **`getKadiCoreJSON()`**: Retrieves the `agent.json` for the Kadi core.
|
|
34
|
-
- **`getKadiCoreJSONPath()`**: Provides the file path to the Kadi core's `agent.json`.
|
|
35
|
-
- **`getKadiJSON()`**: Fetches the `agent.json` for the Kadi system.
|
|
36
|
-
- **`getKadiJSONPath()`**: Returns the file path for the Kadi system's `agent.json`.
|
|
131
|
+
```javascript
|
|
132
|
+
// Use broker for distributed execution
|
|
133
|
+
const ability = await loadAbility('my-ability', 'broker');
|
|
134
|
+
```
|
|
37
135
|
|
|
38
|
-
|
|
136
|
+
**Environment Variables Passed to Child Process:**
|
|
39
137
|
|
|
40
|
-
|
|
138
|
+
```bash
|
|
139
|
+
KADI_PROTOCOL=broker # Identifies the protocol
|
|
140
|
+
KADI_BROKER_URL=ws://localhost:8080 # Broker connection URL
|
|
141
|
+
KADI_SERVICE_NAME=ability.echo.1_0_0 # Service identifier
|
|
142
|
+
KADI_AGENT_SCOPE=uuid-here # Agent's scope/namespace
|
|
143
|
+
# Plus all parent process.env variables
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Scope/Namespace Visibility:**
|
|
147
|
+
|
|
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:
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
// In your ability code:
|
|
152
|
+
const echoAbility = new KadiAbility({
|
|
153
|
+
name: 'echo-js',
|
|
154
|
+
version: '0.0.1',
|
|
155
|
+
description: 'Echo ability with broker support',
|
|
156
|
+
scope: process.env.KADI_AGENT_SCOPE // Use agent's scope for visibility
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Without this, the ability would only be visible in the 'global' scope
|
|
160
|
+
// and the parent agent wouldn't be able to communicate with it
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Protocol Selection Strategy
|
|
164
|
+
|
|
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.
|
|
166
|
+
|
|
167
|
+
```mermaid
|
|
168
|
+
graph TD
|
|
169
|
+
A[Load Ability] --> B{Protocol Specified?}
|
|
170
|
+
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:**
|
|
41
177
|
|
|
42
178
|
```json
|
|
43
179
|
{
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
180
|
+
"interfaces": {
|
|
181
|
+
"native": { "entry": "service.js" }, // 1st choice: Fastest
|
|
182
|
+
"stdio": { "discover": true }, // 2nd choice: Balanced
|
|
183
|
+
"broker": { "discover": true } // 3rd choice: Distributed
|
|
48
184
|
}
|
|
49
185
|
}
|
|
50
186
|
```
|
|
51
187
|
|
|
52
|
-
|
|
188
|
+
## 🛠️ Creating Abilities
|
|
189
|
+
|
|
190
|
+
### Basic Ability Structure
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
import { KadiAbility } from '@kadi.build/core';
|
|
194
|
+
|
|
195
|
+
const ability = new KadiAbility({
|
|
196
|
+
name: 'echo-ability',
|
|
197
|
+
version: '1.0.0',
|
|
198
|
+
description: 'Echo service with metadata',
|
|
199
|
+
scope: process.env.KADI_AGENT_SCOPE || 'global'
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Method 1: Simple handler
|
|
203
|
+
ability.method('echo', async ({ message }) => ({
|
|
204
|
+
echo: message,
|
|
205
|
+
timestamp: new Date().toISOString()
|
|
206
|
+
}));
|
|
207
|
+
|
|
208
|
+
// Method 2: Handler with inline schema
|
|
209
|
+
ability.method(
|
|
210
|
+
'format',
|
|
211
|
+
async ({ text, style }) => ({
|
|
212
|
+
formatted: style === 'upper' ? text.toUpperCase() : text.toLowerCase()
|
|
213
|
+
}),
|
|
214
|
+
{
|
|
215
|
+
description: 'Format text with specified style',
|
|
216
|
+
inputSchema: {
|
|
217
|
+
type: 'object',
|
|
218
|
+
properties: {
|
|
219
|
+
text: { type: 'string', description: 'Text to format' },
|
|
220
|
+
style: {
|
|
221
|
+
type: 'string',
|
|
222
|
+
enum: ['upper', 'lower'],
|
|
223
|
+
description: 'Formatting style'
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
required: ['text', 'style']
|
|
227
|
+
},
|
|
228
|
+
outputSchema: {
|
|
229
|
+
type: 'object',
|
|
230
|
+
properties: {
|
|
231
|
+
formatted: { type: 'string', description: 'Formatted text' }
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
);
|
|
53
236
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
- **`getBrokerNames()`**: Get array of all available broker names.
|
|
58
|
-
- **`setActiveBroker(brokerName)`**: Set the active broker for the session. Returns `true` if successful.
|
|
59
|
-
- **`getActiveBrokerName()`**: Get the name of the currently active broker.
|
|
60
|
-
- **`getActiveBrokerUrl()`**: Get the URL of the currently active broker.
|
|
61
|
-
- **`getDefaultBrokerName()`**: Get the name of the default broker (first one defined).
|
|
62
|
-
- **`selectBrokerFromEnv()`**: Set active broker from `KADI_BROKER` environment variable.
|
|
237
|
+
// Start serving
|
|
238
|
+
ability.serve().catch(console.error);
|
|
239
|
+
```
|
|
63
240
|
|
|
64
|
-
###
|
|
241
|
+
### Event Publishing and Subscription
|
|
65
242
|
|
|
66
|
-
|
|
67
|
-
- **`runSpawnCommand(name, version, command)`**: Uses `spawn` to execute commands for subprocesses.
|
|
243
|
+
**Note**: Events currently work for `native` and `stdio` protocols. Broker protocol event support is planned for future releases.
|
|
68
244
|
|
|
69
|
-
|
|
245
|
+
Abilities can publish events that agents can subscribe to:
|
|
70
246
|
|
|
71
247
|
```javascript
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
248
|
+
// In your ability (service.js)
|
|
249
|
+
const ability = new KadiAbility({ name: 'my-ability' });
|
|
250
|
+
|
|
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' });
|
|
256
|
+
|
|
257
|
+
return { echo: message, timestamp: new Date().toISOString() };
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// In your agent (index.js)
|
|
261
|
+
const ability = await loadAbility('my-ability');
|
|
262
|
+
|
|
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);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// Now call the method that emits events
|
|
269
|
+
const result = await ability.echo({ message: 'Hello world' });
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Important**: Always subscribe to events before calling methods that emit them, as events are emitted immediately when `publishEvent()` is called.
|
|
273
|
+
|
|
274
|
+
### Ability Configuration (agent.json)
|
|
275
|
+
|
|
276
|
+
Every ability should have an `agent.json` file that defines its capabilities and interfaces:
|
|
78
277
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
278
|
+
```json
|
|
279
|
+
{
|
|
280
|
+
"name": "echo-ability",
|
|
281
|
+
"kind": "ability",
|
|
282
|
+
"version": "1.0.0",
|
|
283
|
+
"license": "MIT",
|
|
284
|
+
"description": "Echo service with multiple transport support",
|
|
285
|
+
"scripts": {
|
|
286
|
+
"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
|
+
}
|
|
302
|
+
},
|
|
303
|
+
"exports": [
|
|
304
|
+
{
|
|
305
|
+
"name": "echo",
|
|
306
|
+
"description": "Echo the input message",
|
|
307
|
+
"inputSchema": {
|
|
308
|
+
"type": "object",
|
|
309
|
+
"properties": {
|
|
310
|
+
"message": { "type": "string" }
|
|
311
|
+
},
|
|
312
|
+
"required": ["message"]
|
|
313
|
+
},
|
|
314
|
+
"outputSchema": {
|
|
315
|
+
"type": "object",
|
|
316
|
+
"properties": {
|
|
317
|
+
"echo": { "type": "string" },
|
|
318
|
+
"timestamp": { "type": "string" }
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
],
|
|
323
|
+
"brokers": {
|
|
324
|
+
"local": "ws://localhost:8080",
|
|
325
|
+
"remote": "ws://api.example.com:8080"
|
|
326
|
+
}
|
|
109
327
|
}
|
|
110
328
|
```
|
|
111
329
|
|
|
112
|
-
###
|
|
330
|
+
### Schema Definition Options
|
|
113
331
|
|
|
114
|
-
|
|
115
|
-
- **`IBroker`**: Broker instance interface with methods to manage its lifecycle and communications.
|
|
116
|
-
- **`BrokerMessageBuilder`**: Assists in constructing messages for broker communication.
|
|
332
|
+
The ability system provides two ways to define method schemas:
|
|
117
333
|
|
|
118
|
-
|
|
334
|
+
1. **Export Schemas** (defined in `agent.json` exports section)
|
|
335
|
+
2. **Inline Schemas** (passed directly to `.method()`)
|
|
119
336
|
|
|
120
|
-
|
|
337
|
+
```javascript
|
|
338
|
+
// Option 1: Define in agent.json exports section
|
|
339
|
+
// The schema is picked up automatically if the method name matches
|
|
340
|
+
// agent.json:
|
|
341
|
+
{
|
|
342
|
+
"exports": [
|
|
343
|
+
{
|
|
344
|
+
"name": "process",
|
|
345
|
+
"description": "Process data",
|
|
346
|
+
"inputSchema": { /* ... */ },
|
|
347
|
+
"outputSchema": { /* ... */ }
|
|
348
|
+
}
|
|
349
|
+
]
|
|
350
|
+
}
|
|
121
351
|
|
|
122
|
-
|
|
352
|
+
// Option 2: Define inline when registering the method
|
|
353
|
+
ability.method('process', handler, {
|
|
354
|
+
description: 'Process data',
|
|
355
|
+
inputSchema: { /* ... */ },
|
|
356
|
+
outputSchema: { /* ... */ }
|
|
357
|
+
});
|
|
123
358
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
- **`deleteBroker(name = 'default')`**: Deletes the broker specified by the name and closes its connection.
|
|
127
|
-
- **`send(message, brokerName = 'default')`**: Sends a message through the broker specified by the name.
|
|
128
|
-
- **`addEventListener(event, listener, brokerName = 'default')`**: Adds an event listener to the specified broker.
|
|
129
|
-
- **`removeEventListener(event, listener, brokerName = 'default')`**: Removes an event listener from the specified broker.
|
|
130
|
-
- **`removeAllListeners(brokerName = 'default')`**: Removes all event listeners from the specified broker.
|
|
131
|
-
- **`getBroker(brokerName = 'default')`**: Retrieves a broker instance by name.
|
|
359
|
+
// Note: If both are defined, inline schemas take precedence over exports
|
|
360
|
+
```
|
|
132
361
|
|
|
133
|
-
|
|
362
|
+
**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
|
+
|
|
364
|
+
## 🔄 Architecture Deep Dive
|
|
365
|
+
|
|
366
|
+
### Ability Loading Sequence
|
|
367
|
+
|
|
368
|
+
The loading process adapts based on the selected protocol:
|
|
369
|
+
|
|
370
|
+
```mermaid
|
|
371
|
+
sequenceDiagram
|
|
372
|
+
participant Client
|
|
373
|
+
participant loadAbility
|
|
374
|
+
participant FileSystem
|
|
375
|
+
participant ChildProcess
|
|
376
|
+
participant Ability
|
|
377
|
+
participant Broker
|
|
378
|
+
|
|
379
|
+
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
|
|
384
|
+
|
|
385
|
+
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
|
|
391
|
+
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
|
|
405
|
+
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
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
loadAbility->>Client: Return ability proxy
|
|
432
|
+
Client->>Client: ability.method({ params })
|
|
433
|
+
```
|
|
134
434
|
|
|
135
|
-
|
|
435
|
+
### Method Registration & Serving
|
|
436
|
+
|
|
437
|
+
How abilities register methods and start serving:
|
|
438
|
+
|
|
439
|
+
```mermaid
|
|
440
|
+
sequenceDiagram
|
|
441
|
+
participant Dev as Developer
|
|
442
|
+
participant KA as KadiAbility
|
|
443
|
+
participant Server as RpcServer
|
|
444
|
+
participant Transport
|
|
445
|
+
participant Client
|
|
446
|
+
|
|
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
|
|
451
|
+
|
|
452
|
+
Dev->>KA: ability.method('transform', handler, schema)
|
|
453
|
+
KA->>KA: Store handler in methodHandlers
|
|
454
|
+
KA->>KA: Store schema in methodMCPSchemas
|
|
455
|
+
|
|
456
|
+
Note over KA,Transport: Serving Phase
|
|
457
|
+
Dev->>KA: ability.serve()
|
|
458
|
+
KA->>KA: Detect protocol from env/options
|
|
459
|
+
|
|
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
|
|
465
|
+
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 })
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
Server->>KA: Forward events (start, request, response, error)
|
|
475
|
+
|
|
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
|
|
484
|
+
```
|
|
136
485
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
486
|
+
### Broker Protocol Communication Flow
|
|
487
|
+
|
|
488
|
+
Detailed view of broker-based communication:
|
|
489
|
+
|
|
490
|
+
```mermaid
|
|
491
|
+
sequenceDiagram
|
|
492
|
+
participant Agent as Agent (Parent)
|
|
493
|
+
participant Ability as Ability (Child)
|
|
494
|
+
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
|
|
529
|
+
```
|
|
140
530
|
|
|
141
|
-
###
|
|
531
|
+
### Stdio Protocol Frame Processing
|
|
532
|
+
|
|
533
|
+
How LSP-style frames are processed:
|
|
534
|
+
|
|
535
|
+
```mermaid
|
|
536
|
+
sequenceDiagram
|
|
537
|
+
participant Parent as Parent Process
|
|
538
|
+
participant SR as StdioFrameReader
|
|
539
|
+
participant SW as StdioFrameWriter
|
|
540
|
+
participant Server as StdioRpcServer
|
|
541
|
+
participant Ability as KadiAbility
|
|
542
|
+
|
|
543
|
+
Note over Parent,SR: Incoming Request
|
|
544
|
+
Parent->>SR: Write to stdin: "Kadi-Content-Length: 52\r\n\r\n{...}"
|
|
545
|
+
SR->>SR: Buffer incoming data
|
|
546
|
+
SR->>SR: Look for Content-Length header
|
|
547
|
+
SR->>SR: Parse header, extract body length
|
|
548
|
+
SR->>SR: Wait for complete body
|
|
549
|
+
SR->>SR: Parse JSON from body
|
|
550
|
+
SR->>Server: onMessage({ success: true, data: request })
|
|
551
|
+
|
|
552
|
+
Server->>Server: Validate JSON-RPC format
|
|
553
|
+
Server->>Ability: getMethodHandler(request.method)
|
|
554
|
+
Ability-->>Server: Return handler
|
|
555
|
+
Server->>Server: Execute handler(params) with timeout
|
|
556
|
+
|
|
557
|
+
Note over Server,Parent: Response
|
|
558
|
+
Server->>SW: write(response)
|
|
559
|
+
SW->>SW: JSON.stringify(response)
|
|
560
|
+
SW->>SW: Calculate byte length
|
|
561
|
+
SW->>SW: Create header: "Kadi-Content-Length: N\r\n\r\n"
|
|
562
|
+
SW->>Parent: Write header + body to stdout
|
|
563
|
+
|
|
564
|
+
Note over SR: Error Recovery
|
|
565
|
+
alt Frame Corruption
|
|
566
|
+
SR->>SR: Detect invalid frame
|
|
567
|
+
SR->>SR: Search for next Content-Length marker
|
|
568
|
+
SR->>SR: Skip corrupted bytes
|
|
569
|
+
SR->>Server: onMessage({ success: false, error: 'FRAME_CORRUPTION' })
|
|
570
|
+
Server->>Server: Log error, continue processing
|
|
571
|
+
end
|
|
572
|
+
```
|
|
142
573
|
|
|
143
|
-
|
|
574
|
+
## 📥 Loading Abilities
|
|
144
575
|
|
|
145
|
-
|
|
146
|
-
- **`message(to, content)`**: Constructs a message directed to a specific peer.
|
|
147
|
-
- **`setup(name, description, limit, uuid)`**: Creates a setup message for registering the broker.
|
|
148
|
-
- **`suspend()`**: Constructs a suspend message.
|
|
149
|
-
- **`finish()`**: Constructs a finish message.
|
|
150
|
-
- **`list()`**: Constructs a list message to request a list of connected agents.
|
|
576
|
+
### Basic Loading
|
|
151
577
|
|
|
152
|
-
|
|
578
|
+
```javascript
|
|
579
|
+
import { loadAbility } from '@kadi.build/core';
|
|
153
580
|
|
|
154
|
-
-
|
|
155
|
-
|
|
156
|
-
- **`IAbilityIPC`**: Represents an IPC ability instance with methods to manage its lifecycle and communications.
|
|
581
|
+
// Auto-detect protocol from agent.json
|
|
582
|
+
const ability = await loadAbility('my-ability');
|
|
157
583
|
|
|
158
|
-
|
|
584
|
+
// Explicitly specify protocol
|
|
585
|
+
const stdioAbility = await loadAbility('my-ability', 'stdio');
|
|
586
|
+
const brokerAbility = await loadAbility('my-ability', 'broker');
|
|
587
|
+
const nativeAbility = await loadAbility('my-ability', 'native');
|
|
588
|
+
```
|
|
159
589
|
|
|
160
|
-
|
|
590
|
+
### Working with Loaded Abilities
|
|
161
591
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
592
|
+
```javascript
|
|
593
|
+
// List available methods
|
|
594
|
+
const methods = ability.__list();
|
|
595
|
+
console.log('Available methods:', methods);
|
|
165
596
|
|
|
166
|
-
|
|
597
|
+
// Call methods
|
|
598
|
+
const result = await ability.someMethod({ param: 'value' });
|
|
167
599
|
|
|
168
|
-
|
|
600
|
+
// Direct RPC call (bypasses method validation)
|
|
601
|
+
const response = await ability.call('someMethod', { param: 'value' });
|
|
169
602
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
603
|
+
// Subscribe to events
|
|
604
|
+
ability.events.on('custom:event', (data) => {
|
|
605
|
+
console.log('Event received:', data);
|
|
606
|
+
});
|
|
174
607
|
|
|
175
|
-
|
|
608
|
+
// Note: Events work for native and stdio protocols
|
|
609
|
+
// Subscribe before calling methods that emit events
|
|
610
|
+
```
|
|
176
611
|
|
|
177
|
-
|
|
612
|
+
### Loading Context
|
|
178
613
|
|
|
179
|
-
|
|
180
|
-
- **`launch(commandString)`**: Constructs a launch message with the specified command string.
|
|
181
|
-
- **`shutdown()`**: Constructs a shutdown message.
|
|
182
|
-
- **`message(content)`**: Constructs a general message with the specified content.
|
|
614
|
+
The loader automatically resolves ability versions from:
|
|
183
615
|
|
|
184
|
-
|
|
616
|
+
1. **Project context**: Reads from project's `agent.json`
|
|
617
|
+
2. **Nested context**: When loading from within another ability
|
|
618
|
+
3. **Explicit version**: Can be specified in ability name
|
|
185
619
|
|
|
186
|
-
|
|
620
|
+
## ⚙️ Configuration
|
|
187
621
|
|
|
188
|
-
###
|
|
622
|
+
### Environment Variables
|
|
623
|
+
|
|
624
|
+
```bash
|
|
625
|
+
# Set default protocol
|
|
626
|
+
export KADI_PROTOCOL=stdio
|
|
627
|
+
|
|
628
|
+
# Configure broker
|
|
629
|
+
export KADI_BROKER_URL=ws://localhost:8080
|
|
630
|
+
export KADI_SERVICE_NAME=my-service
|
|
631
|
+
export KADI_AGENT_SCOPE=project-123
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### Environment Variables for Child Processes
|
|
635
|
+
|
|
636
|
+
When abilities are spawned as child processes (stdio and broker protocols), the parent process passes down important environment variables:
|
|
189
637
|
|
|
190
638
|
```javascript
|
|
191
|
-
|
|
639
|
+
// In your ability code, you can access these variables:
|
|
640
|
+
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
|
|
644
|
+
|
|
645
|
+
// Use them to configure your ability behavior
|
|
646
|
+
const ability = new KadiAbility({
|
|
647
|
+
name: 'my-ability',
|
|
648
|
+
scope: process.env.KADI_AGENT_SCOPE || 'global'
|
|
649
|
+
// Ability automatically uses KADI_PROTOCOL to determine transport
|
|
650
|
+
});
|
|
651
|
+
```
|
|
192
652
|
|
|
193
|
-
|
|
194
|
-
const pythonIPC = IPCManager.createInstance(
|
|
195
|
-
'python',
|
|
196
|
-
'echo "Hello, World!"',
|
|
197
|
-
'pythonTest'
|
|
198
|
-
);
|
|
653
|
+
### Project Structure
|
|
199
654
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
655
|
+
```
|
|
656
|
+
my-project/
|
|
657
|
+
├── agent.json # Project configuration
|
|
658
|
+
├── abilities/ # Installed abilities
|
|
659
|
+
│ └── echo-ability/
|
|
660
|
+
│ └── 1.0.0/
|
|
661
|
+
│ ├── agent.json # Ability configuration
|
|
662
|
+
│ ├── service.js # Ability implementation
|
|
663
|
+
│ └── package.json
|
|
664
|
+
├── modules/ # Source modules
|
|
665
|
+
│ └── echo-ability/ # Development version
|
|
666
|
+
└── index.js # Main entry point
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
## 🚀 Advanced Usage
|
|
670
|
+
|
|
671
|
+
### Event System
|
|
672
|
+
|
|
673
|
+
KADI abilities support two types of events:
|
|
674
|
+
|
|
675
|
+
#### 1. Lifecycle Events (All Protocols)
|
|
676
|
+
|
|
677
|
+
These are internal ability lifecycle events that work across all protocols:
|
|
678
|
+
|
|
679
|
+
```javascript
|
|
680
|
+
const ability = new KadiAbility({ name: 'events-ability' });
|
|
681
|
+
|
|
682
|
+
// Listen to lifecycle events
|
|
683
|
+
ability.on('start', ({ protocol, methods }) => {
|
|
684
|
+
console.log(`Started with ${protocol}, methods: ${methods.join(', ')}`);
|
|
203
685
|
});
|
|
204
686
|
|
|
205
|
-
|
|
206
|
-
console.
|
|
207
|
-
// Handle critical errors, potentially restarting the process or alerting administrators
|
|
687
|
+
ability.on('request', ({ id, method, params }) => {
|
|
688
|
+
console.log(`Request ${id}: ${method}`);
|
|
208
689
|
});
|
|
209
690
|
|
|
210
|
-
|
|
211
|
-
console.
|
|
691
|
+
ability.on('response', ({ id, result, error }) => {
|
|
692
|
+
if (error) console.error(`Error in ${id}:`, error);
|
|
693
|
+
else console.log(`Response ${id}:`, result);
|
|
212
694
|
});
|
|
213
695
|
|
|
214
|
-
|
|
215
|
-
console.
|
|
696
|
+
ability.on('error', (error) => {
|
|
697
|
+
console.error('Ability error:', error);
|
|
216
698
|
});
|
|
699
|
+
```
|
|
217
700
|
|
|
218
|
-
|
|
219
|
-
|
|
701
|
+
#### 2. Custom Events (Native and Stdio Protocols Only - for now)
|
|
702
|
+
|
|
703
|
+
Abilities can publish custom events that agents can subscribe to:
|
|
704
|
+
|
|
705
|
+
```javascript
|
|
706
|
+
// In your ability
|
|
707
|
+
const ability = new KadiAbility({ name: 'my-ability' });
|
|
708
|
+
|
|
709
|
+
ability.method('process', async ({ data }) => {
|
|
710
|
+
// Publish events during processing
|
|
711
|
+
ability.publishEvent('process:started', {
|
|
712
|
+
timestamp: new Date().toISOString()
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
// ... do work ...
|
|
716
|
+
|
|
717
|
+
ability.publishEvent('process:completed', {
|
|
718
|
+
result: 'success',
|
|
719
|
+
timestamp: new Date().toISOString()
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
return { processed: data };
|
|
220
723
|
});
|
|
221
724
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
brk.on('open', function open() {
|
|
229
|
-
console.log(`Connected to ${brk.url}`);
|
|
230
|
-
const jsonObject = BrokerMessageBuilder.setup(
|
|
231
|
-
'TestAgent',
|
|
232
|
-
'A Broker Testing Agent',
|
|
233
|
-
null,
|
|
234
|
-
null
|
|
235
|
-
);
|
|
236
|
-
brk.send(jsonObject);
|
|
725
|
+
// In your agent (index.js)
|
|
726
|
+
const ability = await loadAbility('my-ability');
|
|
727
|
+
|
|
728
|
+
// Subscribe to custom events BEFORE calling methods
|
|
729
|
+
ability.events.on('process:started', (data) => {
|
|
730
|
+
console.log(`Process started at: ${data.timestamp}`);
|
|
237
731
|
});
|
|
238
732
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
733
|
+
ability.events.on('process:completed', (data) => {
|
|
734
|
+
console.log(`Process completed: ${data.result} at ${data.timestamp}`);
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
// Now call the method that emits events
|
|
738
|
+
await ability.process({ data: 'test' });
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
**Important Notes:**
|
|
742
|
+
|
|
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
|
|
747
|
+
|
|
748
|
+
### Error Handling
|
|
749
|
+
|
|
750
|
+
```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);
|
|
249
765
|
}
|
|
250
|
-
|
|
766
|
+
}
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
## 🔧 Development Workflow
|
|
770
|
+
|
|
771
|
+
### Testing Local Changes
|
|
772
|
+
|
|
773
|
+
When developing new features or testing changes to `@kadi.build/core` before publishing to NPM:
|
|
774
|
+
|
|
775
|
+
0. **clone the repository**
|
|
776
|
+
|
|
777
|
+
```bash
|
|
778
|
+
git clone https://gitlab.com/humin-game-lab/kadi/kadi-core.git
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
1. **Pack the local version** (in the kadi-core directory):
|
|
782
|
+
|
|
783
|
+
```bash
|
|
784
|
+
cd /path/to/kadi-core
|
|
785
|
+
npm pack
|
|
786
|
+
# This creates: kadi.build-core-X.Y.Z.tgz
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
1. **Install in your project**:
|
|
790
|
+
|
|
791
|
+
```bash
|
|
792
|
+
cd /path/to/your-project
|
|
793
|
+
npm install /path/to/kadi-core/kadi.build-core-X.Y.Z.tgz
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
1. **For ability development**, update the ability's preflight script:
|
|
797
|
+
|
|
798
|
+
```json
|
|
799
|
+
{
|
|
800
|
+
"scripts": {
|
|
801
|
+
"preflight": "npm uninstall @kadi.build/core && npm install /path/to/kadi.build-core-X.Y.Z.tgz"
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
## 📖 API Reference
|
|
807
|
+
|
|
808
|
+
### Core Classes
|
|
809
|
+
|
|
810
|
+
#### `KadiAbility`
|
|
811
|
+
|
|
812
|
+
The main class for creating abilities.
|
|
813
|
+
|
|
814
|
+
```javascript
|
|
815
|
+
import { KadiAbility } from '@kadi.build/core';
|
|
816
|
+
|
|
817
|
+
const ability = new KadiAbility({
|
|
818
|
+
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'
|
|
251
823
|
});
|
|
824
|
+
```
|
|
825
|
+
|
|
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:
|
|
844
|
+
|
|
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
|
|
849
|
+
|
|
850
|
+
### Utility Functions
|
|
851
|
+
|
|
852
|
+
```javascript
|
|
853
|
+
import {
|
|
854
|
+
createLogger,
|
|
855
|
+
getProjectJSON,
|
|
856
|
+
getAbilityJSON,
|
|
857
|
+
getBrokerUrl,
|
|
858
|
+
runExecCommand
|
|
859
|
+
} from '@kadi.build/core';
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
## 🎮 Running the Examples
|
|
863
|
+
|
|
864
|
+
### Quick Start with Example Agent
|
|
865
|
+
|
|
866
|
+
The `@kadi.build/core` package includes a complete example demonstrating multi-language abilities (JavaScript and Go) with all three transport protocols.
|
|
867
|
+
|
|
868
|
+
The `examples` folder contains:
|
|
869
|
+
|
|
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
|
+
```
|
|
886
|
+
|
|
887
|
+
#### Step 0: Have the KADI broker running locally
|
|
888
|
+
|
|
889
|
+
```bash
|
|
890
|
+
kadi broker up
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
#### Step 1: Navigate to the example agent
|
|
252
894
|
|
|
253
|
-
|
|
254
|
-
|
|
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
|
+
```
|
|
937
|
+
|
|
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**:
|
|
988
|
+
|
|
989
|
+
```javascript
|
|
990
|
+
#!/usr/bin/env node
|
|
991
|
+
import { KadiAbility } from '@kadi.build/core';
|
|
992
|
+
|
|
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
|
|
255
998
|
});
|
|
256
999
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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
|
+
};
|
|
260
1011
|
});
|
|
261
1012
|
|
|
262
|
-
//
|
|
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 };
|
|
1032
|
+
},
|
|
1033
|
+
{
|
|
1034
|
+
description: 'Transform text with multiple operations',
|
|
1035
|
+
inputSchema: {
|
|
1036
|
+
type: 'object',
|
|
1037
|
+
properties: {
|
|
1038
|
+
text: { type: 'string' },
|
|
1039
|
+
operations: {
|
|
1040
|
+
type: 'array',
|
|
1041
|
+
items: { enum: ['upper', 'lower', 'reverse'] }
|
|
1042
|
+
}
|
|
1043
|
+
},
|
|
1044
|
+
required: ['text', 'operations']
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
);
|
|
1048
|
+
|
|
1049
|
+
echoAbility.serve().catch(console.error);
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
**Using the service**:
|
|
1053
|
+
|
|
1054
|
+
```javascript
|
|
1055
|
+
import { loadAbility } from '@kadi.build/core';
|
|
1056
|
+
|
|
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
|
+
}
|
|
1087
|
+
|
|
1088
|
+
demo();
|
|
1089
|
+
```
|
|
1090
|
+
|
|
1091
|
+
## 🎯 Real-World Event Example
|
|
1092
|
+
|
|
1093
|
+
Here's the exact event pattern used in the example code:
|
|
1094
|
+
|
|
1095
|
+
**In your ability (service.js):**
|
|
1096
|
+
|
|
1097
|
+
```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;
|
|
263
1108
|
|
|
264
|
-
//
|
|
265
|
-
|
|
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' });
|
|
266
1112
|
|
|
267
|
-
|
|
268
|
-
|
|
1113
|
+
return { echo: messageText, timestamp, length };
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
echoAbility.method('echo', echo);
|
|
269
1117
|
```
|
|
270
1118
|
|
|
271
|
-
|
|
1119
|
+
**In your agent (index.js):**
|
|
272
1120
|
|
|
273
1121
|
```javascript
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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
|
+
});
|
|
1131
|
+
```
|
|
1132
|
+
|
|
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
|
|
1140
|
+
|
|
1141
|
+
## 🐛 Troubleshooting
|
|
1142
|
+
|
|
1143
|
+
### Common Issues
|
|
1144
|
+
|
|
1145
|
+
**Ability Not Found**
|
|
1146
|
+
|
|
1147
|
+
```
|
|
1148
|
+
Error: Ability 'my-ability' version '1.0.0' is not installed
|
|
1149
|
+
```
|
|
1150
|
+
|
|
1151
|
+
**Solution**: Run `kadi install` to install project dependencies
|
|
1152
|
+
|
|
1153
|
+
**Broker Connection Failed**
|
|
1154
|
+
|
|
1155
|
+
```
|
|
1156
|
+
Error: Failed to connect to KADI Broker at ws://localhost:8080
|
|
1157
|
+
```
|
|
1158
|
+
|
|
1159
|
+
**Solution**: Ensure the broker is running: `kadi broker start`
|
|
1160
|
+
|
|
1161
|
+
**Method Not Found**
|
|
1162
|
+
|
|
1163
|
+
```
|
|
1164
|
+
Error: Method 'someMethod' is not exposed by this ability
|
|
1165
|
+
```
|
|
1166
|
+
|
|
1167
|
+
**Solution**: Check ability exports or use `__list()` to see available methods
|
|
1168
|
+
|
|
1169
|
+
**Protocol Not Supported**
|
|
1170
|
+
|
|
1171
|
+
```
|
|
1172
|
+
Error: Unsupported ability interface protocol: custom
|
|
1173
|
+
```
|
|
1174
|
+
|
|
1175
|
+
**Solution**: Ability must define the protocol in its `agent.json` interfaces
|
|
1176
|
+
|
|
1177
|
+
**Event Subscription Issues**
|
|
1178
|
+
|
|
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
|
|
1184
|
+
|
|
1185
|
+
**Event Protocol Support**
|
|
1186
|
+
|
|
1187
|
+
```
|
|
1188
|
+
Events are only supported for 'native' and 'stdio' protocols
|
|
277
1189
|
```
|
|
278
1190
|
|
|
1191
|
+
**Solution**: Events currently work for `native` and `stdio` protocols only. Broker protocol event support is planned for future releases.
|
|
1192
|
+
|
|
1193
|
+
### Debug Mode
|
|
1194
|
+
|
|
1195
|
+
Enable detailed logging:
|
|
1196
|
+
|
|
1197
|
+
```bash
|
|
1198
|
+
DEBUG=kadi:* node index.js
|
|
1199
|
+
```
|
|
1200
|
+
|
|
1201
|
+
Check ability logs:
|
|
1202
|
+
|
|
1203
|
+
```bash
|
|
1204
|
+
tail -f abilities/my-ability/1.0.0/my-ability.log
|
|
1205
|
+
```
|
|
1206
|
+
|
|
1207
|
+
## 🤝 Contributing
|
|
1208
|
+
|
|
1209
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
1210
|
+
|
|
1211
|
+
1. Fork the repository
|
|
1212
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
1213
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
1214
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
1215
|
+
5. Open a Pull Request
|
|
1216
|
+
|
|
1217
|
+
## 📄 License
|
|
1218
|
+
|
|
1219
|
+
MIT License - see [LICENSE](LICENSE) file for details
|
|
1220
|
+
|
|
1221
|
+
## 🔗 Related Projects
|
|
1222
|
+
|
|
1223
|
+
- [@kadi.build/cli](https://gitlab.com/humin-game-lab/kadi/kadi) - Command-line interface
|
|
1224
|
+
- [@kadi.build/broker](https://gitlab.com/humin-game-lab/kadi/kadi-broker) - The KADI broker
|
|
1225
|
+
|
|
1226
|
+
## 📚 Resources
|
|
1227
|
+
|
|
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)
|
|
1232
|
+
|
|
279
1233
|
---
|
|
280
1234
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
- Once @kadi.build/core and dependencies are done, @kadi.build/cli (and all commands), need to be rewritten, using the @kadi.build/core module. this will be v1.0 release
|
|
284
|
-
|
|
285
|
-
* [ ] add getConnectedAgents to the Broker, it should call the IBroker method
|
|
286
|
-
|
|
287
|
-
* [x] add key to IBroker object
|
|
288
|
-
* [ ] IBroker on 'message' should listen for setup event, and update teh uuid and key for the IBroker object
|
|
289
|
-
|
|
290
|
-
* [ ] Extract Broker and IPC to their own node module and host on npm
|
|
291
|
-
* [x] Publish @kadi.build/core to npm
|
|
292
|
-
* [x] Setup of python environment needs to happen once an IPC Inteface is created
|
|
293
|
-
This include setting up the virtual environment and installing the required packages
|
|
294
|
-
* [x] Add method to IPCManger to set IPCInterfaces from agent.json. If IPCManger has empty list, it thorws an error that no IAbilityIPC's can be created. IPCManger passes the proper interface command to IAbilityIPC on creation from this list, IAbilityIPC does not need access directly to agent.json. Controlling app can update this list anytime a new IAbilityInterface is created, allowing the agent.json to be updated during runtime.
|
|
295
|
-
* [x] Need to adapt ipc.js to read from the @kadi.build/core folder when trying to open IPC instances, instead of project folder. @kadi.build/core should be in the npm_modules folder (when deployed)
|
|
296
|
-
* [x] The test code needs to fully test the IPCManger interface, and not just the IPCAbility
|
|
297
|
-
* [x] If node fails, we need to make sure python IPC interface and child processes also close out.
|
|
298
|
-
* [x] Add buffer to error handeling in IAbilityIPC, mimic same process used in std input
|
|
299
|
-
* [x] Verify if Python IAbilityIPC needs to utilize buffering, and node passing '\n' at end of jso
|
|
300
|
-
* [x] Setup passthrough for broker messages to/from Language IPC interface
|
|
301
|
-
* [x] Add broker message builder/parser in python IAbilityIPC
|
|
302
|
-
* [x] Update BrokerMessageBuilder to use same format at IPCMessageBuilder
|
|
303
|
-
* [x] Update Broker so it extends EventEmitter, rather than have a property of event emitter (similar to IAbilityIPC)
|
|
304
|
-
* [x] update python IAbility so that it creates a timestamped command_output.log file, new file for each run, in the project root directory... not the @kadi.build/core directory
|
|
305
|
-
* [x] Comment out debug messages
|
|
306
|
-
* [x] Add ability to allow for launched process to be piped to event handler (launch command should default to process, but allow user to set flag that will save all outputs to file in the event handler)
|
|
1235
|
+
Built with ❤️ by the KADI team
|