@kadi.build/core 0.0.1-alpha.2 → 0.0.1-alpha.4
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 +1122 -216
- package/dist/KadiClient.d.ts +303 -0
- package/dist/KadiClient.d.ts.map +1 -0
- package/dist/KadiClient.js +1162 -0
- package/dist/KadiClient.js.map +1 -0
- package/dist/errors/error-codes.d.ts +215 -0
- package/dist/errors/error-codes.d.ts.map +1 -0
- package/dist/errors/error-codes.js +295 -0
- package/dist/errors/error-codes.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/loadAbility.d.ts +65 -0
- package/dist/loadAbility.d.ts.map +1 -0
- package/dist/loadAbility.js +335 -0
- package/dist/loadAbility.js.map +1 -0
- package/dist/messages/BrokerMessages.d.ts +84 -0
- package/dist/messages/BrokerMessages.d.ts.map +1 -0
- package/dist/messages/BrokerMessages.js +127 -0
- package/dist/messages/BrokerMessages.js.map +1 -0
- package/dist/messages/MessageBuilder.d.ts +83 -0
- package/dist/messages/MessageBuilder.d.ts.map +1 -0
- package/dist/messages/MessageBuilder.js +144 -0
- package/dist/messages/MessageBuilder.js.map +1 -0
- package/dist/schemas/events.schemas.d.ts +177 -0
- package/dist/schemas/events.schemas.d.ts.map +1 -0
- package/dist/schemas/events.schemas.js +265 -0
- package/dist/schemas/events.schemas.js.map +1 -0
- package/dist/schemas/index.d.ts +3 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +4 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/kadi.schemas.d.ts +70 -0
- package/dist/schemas/kadi.schemas.d.ts.map +1 -0
- package/dist/schemas/kadi.schemas.js +120 -0
- package/dist/schemas/kadi.schemas.js.map +1 -0
- package/dist/transports/BrokerTransport.d.ts +96 -0
- package/dist/transports/BrokerTransport.d.ts.map +1 -0
- package/dist/transports/BrokerTransport.js +145 -0
- package/dist/transports/BrokerTransport.js.map +1 -0
- package/dist/transports/NativeTransport.d.ts +92 -0
- package/dist/transports/NativeTransport.d.ts.map +1 -0
- package/dist/transports/NativeTransport.js +221 -0
- package/dist/transports/NativeTransport.js.map +1 -0
- package/dist/transports/StdioTransport.d.ts +112 -0
- package/dist/transports/StdioTransport.d.ts.map +1 -0
- package/dist/transports/StdioTransport.js +440 -0
- package/dist/transports/StdioTransport.js.map +1 -0
- package/dist/transports/Transport.d.ts +93 -0
- package/dist/transports/Transport.d.ts.map +1 -0
- package/dist/transports/Transport.js +13 -0
- package/dist/transports/Transport.js.map +1 -0
- package/dist/types/broker.d.ts +31 -0
- package/dist/types/broker.d.ts.map +1 -0
- package/dist/types/broker.js +6 -0
- package/dist/types/broker.js.map +1 -0
- package/dist/types/core.d.ts +138 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/types/core.js +26 -0
- package/dist/types/core.js.map +1 -0
- package/dist/types/events.d.ts +186 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +16 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +13 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/protocol.d.ts +160 -0
- package/dist/types/protocol.d.ts.map +1 -0
- package/dist/types/protocol.js +5 -0
- package/dist/types/protocol.js.map +1 -0
- package/dist/utils/agentUtils.d.ts +102 -0
- package/dist/utils/agentUtils.d.ts.map +1 -0
- package/dist/utils/agentUtils.js +166 -0
- package/dist/utils/agentUtils.js.map +1 -0
- package/dist/utils/commandUtils.d.ts +45 -0
- package/dist/utils/commandUtils.d.ts.map +1 -0
- package/dist/utils/commandUtils.js +145 -0
- package/dist/utils/commandUtils.js.map +1 -0
- package/dist/utils/configUtils.d.ts +55 -0
- package/dist/utils/configUtils.d.ts.map +1 -0
- package/dist/utils/configUtils.js +100 -0
- package/dist/utils/configUtils.js.map +1 -0
- package/dist/utils/logger.d.ts +59 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +122 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/pathUtils.d.ts +48 -0
- package/dist/utils/pathUtils.d.ts.map +1 -0
- package/dist/utils/pathUtils.js +128 -0
- package/dist/utils/pathUtils.js.map +1 -0
- package/package.json +58 -5
- package/agent.json +0 -18
- package/broker.js +0 -214
- package/index.js +0 -382
- package/ipc.js +0 -220
- package/ipcInterfaces/pythonAbilityIPC.py +0 -177
package/README.md
CHANGED
|
@@ -1,306 +1,1212 @@
|
|
|
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
|
+
- [🤖 Creating Agents](#-creating-agents)
|
|
20
|
+
- [🔄 Architecture Deep Dive](#-architecture-deep-dive)
|
|
21
|
+
- [📥 Loading Abilities](#-loading-abilities)
|
|
22
|
+
- [⚙️ Configuration](#-configuration)
|
|
23
|
+
- [🚀 Advanced Usage](#-advanced-usage)
|
|
24
|
+
- [🔧 Development Workflow](#-development-workflow)
|
|
25
|
+
- [📖 API Reference](#-api-reference)
|
|
26
|
+
- [🎮 Running the Examples](#-running-the-examples)
|
|
27
|
+
- [💡 Additional Examples](#-additional-examples)
|
|
28
|
+
- [🐛 Troubleshooting](#-troubleshooting)
|
|
29
|
+
- [🤝 Contributing](#-contributing)
|
|
30
|
+
- [📄 License](#-license)
|
|
31
|
+
- [🔗 Related Projects](#-related-projects)
|
|
32
|
+
- [📚 Resources](#-resources)
|
|
33
|
+
|
|
34
|
+
## 📦 Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install @kadi.build/core
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
For global CLI tools:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install -g @kadi.build/cli
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 🚀 Quick Start
|
|
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
|
+
- **As a Service**: Combining both roles - serving and consuming tools
|
|
53
|
+
|
|
54
|
+
### Creating Your First Service
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
#!/usr/bin/env node
|
|
58
|
+
import { KadiClient } from '@kadi.build/core';
|
|
59
|
+
|
|
60
|
+
// Create a service instance
|
|
61
|
+
const mathService = new KadiClient({
|
|
62
|
+
name: 'math-service',
|
|
63
|
+
role: 'ability', // 'agent', 'ability', or 'service'
|
|
64
|
+
protocol: 'stdio' // 'native', 'stdio', or 'broker'
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Register a tool
|
|
68
|
+
mathService.registerTool('add', async ({ a, b }) => {
|
|
69
|
+
return { result: a + b };
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Start serving requests
|
|
73
|
+
mathService.serve().catch(console.error);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Loading and Using Abilities
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
import { loadAbility } from '@kadi.build/core';
|
|
80
|
+
|
|
81
|
+
async function main() {
|
|
82
|
+
// Load an ability (uses first interface defined in agent.json)
|
|
83
|
+
const math = await loadAbility('math-ability');
|
|
84
|
+
|
|
85
|
+
// Call methods like regular functions
|
|
86
|
+
const result = await math.add({ a: 5, b: 3 });
|
|
87
|
+
console.log(result); // { result: 8 }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
main().catch(console.error);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Creating a Broker-Connected Agent
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
import { KadiClient } from '@kadi.build/core';
|
|
97
|
+
|
|
98
|
+
// Create an agent that connects to broker
|
|
99
|
+
const agent = new KadiClient({
|
|
100
|
+
name: 'my-agent',
|
|
101
|
+
role: 'agent',
|
|
102
|
+
protocol: 'broker',
|
|
103
|
+
brokerUrls: ['ws://localhost:8080'],
|
|
104
|
+
networks: ['global']
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Register tools that other agents can call
|
|
108
|
+
agent.registerTool(
|
|
109
|
+
'greet',
|
|
110
|
+
async ({ name }) => {
|
|
111
|
+
return { greeting: `Hello, ${name}!` };
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
description: 'Greet someone by name',
|
|
115
|
+
inputSchema: {
|
|
116
|
+
type: 'object',
|
|
117
|
+
properties: {
|
|
118
|
+
name: { type: 'string', description: 'Name to greet' }
|
|
119
|
+
},
|
|
120
|
+
required: ['name']
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Connect to broker and start serving
|
|
126
|
+
await agent.connectToBrokers();
|
|
127
|
+
|
|
128
|
+
// Call tools from OTHER agents connected to the same broker
|
|
129
|
+
const result = await agent.callTool('translate', 'text-tool', {
|
|
130
|
+
text: 'Hello world',
|
|
131
|
+
language: 'spanish'
|
|
132
|
+
});
|
|
133
|
+
console.log(result);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## 🔌 Transport Protocols
|
|
137
|
+
|
|
138
|
+
KADI abilities support three transport protocols, each optimized for different use cases:
|
|
139
|
+
|
|
140
|
+
### 1. Native Protocol (Fastest)
|
|
141
|
+
|
|
142
|
+
- **Use Case**: High-performance, in-process execution
|
|
143
|
+
- **How it Works**: Loads abilities as ES modules, enabling direct function calls
|
|
144
|
+
- **Performance**: Zero IPC overhead - functions run in the same process
|
|
145
|
+
- **Best For**: Utility libraries, data processing, performance-critical operations
|
|
146
|
+
|
|
147
|
+
```javascript
|
|
148
|
+
// Loads as native module by default if available
|
|
149
|
+
const ability = await loadAbility('my-ability', 'native');
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 2. Stdio Protocol (Balanced)
|
|
4
153
|
|
|
5
|
-
|
|
154
|
+
- **Use Case**: Language-agnostic local execution
|
|
155
|
+
- **How it Works**: Spawns abilities as child processes, communicates via LSP-style JSON-RPC over stdin/stdout
|
|
156
|
+
- **Performance**: Minimal overhead, reliable local IPC
|
|
157
|
+
- **Best For**: Python scripts, Go binaries, Node.js services, development/testing
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
// Force stdio protocol
|
|
161
|
+
const ability = await loadAbility('my-ability', 'stdio');
|
|
162
|
+
```
|
|
6
163
|
|
|
7
|
-
|
|
164
|
+
**Environment Variables Passed to Child Process:**
|
|
8
165
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- **IPC Support**: Tools for interprocess communication across various programming languages.
|
|
166
|
+
```bash
|
|
167
|
+
KADI_PROTOCOL=stdio # Identifies the protocol being used
|
|
168
|
+
# Plus all parent process.env variables
|
|
169
|
+
```
|
|
14
170
|
|
|
15
|
-
|
|
171
|
+
### 3. Broker Protocol (Distributed)
|
|
16
172
|
|
|
17
|
-
|
|
173
|
+
- **Use Case**: Distributed services, containerized deployments
|
|
174
|
+
- **How it Works**: Abilities connect to a WebSocket broker for network communication
|
|
175
|
+
- **Performance**: Network overhead, but enables scaling and distribution
|
|
176
|
+
- **Best For**: Microservices, cloud deployments, load-balanced services
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
// Use broker for distributed execution
|
|
180
|
+
const ability = await loadAbility('my-ability', 'broker');
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Environment Variables Passed to Child Process:**
|
|
18
184
|
|
|
19
185
|
```bash
|
|
20
|
-
|
|
186
|
+
KADI_PROTOCOL=broker # Identifies the protocol
|
|
187
|
+
KADI_BROKER_URL=ws://localhost:8080 # Broker connection URL
|
|
188
|
+
KADI_SERVICE_NAME=ability.echo.1_0_0 # Service identifier
|
|
189
|
+
KADI_AGENT_SCOPE=uuid-here # Agent's scope/namespace
|
|
190
|
+
# Plus all parent process.env variables
|
|
21
191
|
```
|
|
22
192
|
|
|
23
|
-
|
|
193
|
+
**Scope/Namespace Visibility:**
|
|
24
194
|
|
|
25
|
-
|
|
195
|
+
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:
|
|
26
196
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- **`getKadiJSON()`**: Fetches the `agent.json` for the Kadi system.
|
|
36
|
-
- **`getKadiJSONPath()`**: Returns the file path for the Kadi system's `agent.json`.
|
|
197
|
+
```javascript
|
|
198
|
+
// In your ability code:
|
|
199
|
+
const echoAbility = new KadiAbility({
|
|
200
|
+
name: 'echo-js',
|
|
201
|
+
version: '0.0.1',
|
|
202
|
+
description: 'Echo ability with broker support',
|
|
203
|
+
scope: process.env.KADI_AGENT_SCOPE // Use agent's scope for visibility
|
|
204
|
+
});
|
|
37
205
|
|
|
38
|
-
|
|
206
|
+
// Without this, the ability would only be visible in the 'global' scope
|
|
207
|
+
// and the parent agent wouldn't be able to communicate with it
|
|
208
|
+
```
|
|
39
209
|
|
|
40
|
-
|
|
210
|
+
### Protocol Selection Strategy
|
|
211
|
+
|
|
212
|
+
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.
|
|
213
|
+
|
|
214
|
+
```mermaid
|
|
215
|
+
graph TD
|
|
216
|
+
A[Load Ability] --> B{Protocol Specified?}
|
|
217
|
+
B -->|Yes| C[Use Specified Protocol]
|
|
218
|
+
B -->|No| D{Check agent.json interfaces}
|
|
219
|
+
D --> E[Use First Interface Listed]
|
|
220
|
+
E --> F[native/stdio/broker]
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Recommended Interface Order in agent.json:**
|
|
41
224
|
|
|
42
225
|
```json
|
|
43
226
|
{
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
227
|
+
"interfaces": {
|
|
228
|
+
"native": { "entry": "service.js" }, // 1st choice: Fastest
|
|
229
|
+
"stdio": { "discover": true }, // 2nd choice: Balanced
|
|
230
|
+
"broker": { "discover": true } // 3rd choice: Distributed
|
|
48
231
|
}
|
|
49
232
|
}
|
|
50
233
|
```
|
|
51
234
|
|
|
52
|
-
|
|
235
|
+
## 🛠️ Creating Services with KadiClient
|
|
236
|
+
|
|
237
|
+
### Basic Service Structure
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
import { KadiClient } from '@kadi.build/core';
|
|
53
241
|
|
|
54
|
-
|
|
55
|
-
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
242
|
+
const service = new KadiClient({
|
|
243
|
+
name: 'echo-service',
|
|
244
|
+
role: 'ability', // 'agent', 'ability', or 'service'
|
|
245
|
+
protocol: 'stdio', // 'native', 'stdio', or 'broker'
|
|
246
|
+
brokerUrls: ['ws://localhost:8080']
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Method 1: Simple tool registration
|
|
250
|
+
service.registerTool('echo', async ({ message }) => ({
|
|
251
|
+
echo: message,
|
|
252
|
+
timestamp: new Date().toISOString()
|
|
253
|
+
}));
|
|
254
|
+
|
|
255
|
+
// Method 2: Tool with inline schema
|
|
256
|
+
service.registerTool(
|
|
257
|
+
'format',
|
|
258
|
+
async ({ text, style }) => ({
|
|
259
|
+
formatted: style === 'upper' ? text.toUpperCase() : text.toLowerCase()
|
|
260
|
+
}),
|
|
261
|
+
{
|
|
262
|
+
description: 'Format text with specified style',
|
|
263
|
+
inputSchema: {
|
|
264
|
+
type: 'object',
|
|
265
|
+
properties: {
|
|
266
|
+
text: { type: 'string', description: 'Text to format' },
|
|
267
|
+
style: {
|
|
268
|
+
type: 'string',
|
|
269
|
+
enum: ['upper', 'lower'],
|
|
270
|
+
description: 'Formatting style'
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
required: ['text', 'style']
|
|
274
|
+
},
|
|
275
|
+
outputSchema: {
|
|
276
|
+
type: 'object',
|
|
277
|
+
properties: {
|
|
278
|
+
formatted: { type: 'string', description: 'Formatted text' }
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
// Start serving
|
|
285
|
+
service.serve().catch(console.error);
|
|
286
|
+
```
|
|
63
287
|
|
|
64
|
-
###
|
|
288
|
+
### Event Publishing and Subscription
|
|
65
289
|
|
|
66
|
-
|
|
67
|
-
- **`runSpawnCommand(name, version, command)`**: Uses `spawn` to execute commands for subprocesses.
|
|
290
|
+
**Full Support**: Events work across all protocols - native, stdio, and broker.
|
|
68
291
|
|
|
69
|
-
|
|
292
|
+
KadiClient provides a unified event system that works consistently across all transport protocols:
|
|
70
293
|
|
|
71
294
|
```javascript
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
295
|
+
// In your service (service.js)
|
|
296
|
+
const service = new KadiClient({
|
|
297
|
+
name: 'my-service',
|
|
298
|
+
role: 'ability',
|
|
299
|
+
protocol: 'broker' // Works with all protocols
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Publish events from tool handlers
|
|
303
|
+
service.registerTool('echo', async ({ message }) => {
|
|
304
|
+
// Publish events during processing
|
|
305
|
+
await service.publishEvent('echo.processing', { status: 'started' });
|
|
306
|
+
|
|
307
|
+
// Do work...
|
|
308
|
+
const result = { echo: message, timestamp: new Date().toISOString() };
|
|
309
|
+
|
|
310
|
+
await service.publishEvent('echo.completed', { result });
|
|
311
|
+
return result;
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// In your client (index.js)
|
|
315
|
+
const client = new KadiClient({
|
|
316
|
+
name: 'my-client',
|
|
317
|
+
role: 'agent',
|
|
318
|
+
protocol: 'broker'
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// Subscribe to events using patterns
|
|
322
|
+
client.subscribeToEvent('echo.*', (data) => {
|
|
323
|
+
console.log('Echo event received:', data);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// For loaded abilities with native/stdio protocols
|
|
327
|
+
const ability = await loadAbility('my-service', 'stdio');
|
|
328
|
+
ability.events.on('echo.completed', (data) => {
|
|
329
|
+
console.log('Completed:', data);
|
|
330
|
+
});
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Event Patterns**:
|
|
334
|
+
- Use wildcards: `math.*` matches `math.operation`, `math.milestone`
|
|
335
|
+
- Protocol-specific delivery:
|
|
336
|
+
- **Native**: Direct EventEmitter (synchronous)
|
|
337
|
+
- **Stdio**: JSON-RPC notifications over stdout
|
|
338
|
+
- **Broker**: RabbitMQ pub/sub via WebSocket
|
|
339
|
+
|
|
340
|
+
### Ability Configuration (agent.json)
|
|
78
341
|
|
|
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
|
-
|
|
342
|
+
Every ability should have an `agent.json` file that defines its capabilities and interfaces:
|
|
343
|
+
|
|
344
|
+
```json
|
|
345
|
+
{
|
|
346
|
+
"name": "echo-ability",
|
|
347
|
+
"kind": "ability",
|
|
348
|
+
"version": "1.0.0",
|
|
349
|
+
"license": "MIT",
|
|
350
|
+
"description": "Echo service with multiple transport support",
|
|
351
|
+
"scripts": {
|
|
352
|
+
"setup": "npm install",
|
|
353
|
+
"start": "node service.js"
|
|
354
|
+
},
|
|
355
|
+
"interfaces": {
|
|
356
|
+
"native": {
|
|
357
|
+
"entry": "service.js"
|
|
358
|
+
},
|
|
359
|
+
"stdio": {
|
|
360
|
+
"discover": true,
|
|
361
|
+
"timeoutMs": 10000
|
|
362
|
+
},
|
|
363
|
+
"broker": {
|
|
364
|
+
"discover": true,
|
|
365
|
+
"timeoutMs": 15000,
|
|
366
|
+
"serviceName": "echo-service"
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
"exports": [
|
|
370
|
+
{
|
|
371
|
+
"name": "echo",
|
|
372
|
+
"description": "Echo the input message",
|
|
373
|
+
"inputSchema": {
|
|
374
|
+
"type": "object",
|
|
375
|
+
"properties": {
|
|
376
|
+
"message": { "type": "string" }
|
|
377
|
+
},
|
|
378
|
+
"required": ["message"]
|
|
379
|
+
},
|
|
380
|
+
"outputSchema": {
|
|
381
|
+
"type": "object",
|
|
382
|
+
"properties": {
|
|
383
|
+
"echo": { "type": "string" },
|
|
384
|
+
"timestamp": { "type": "string" }
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
],
|
|
389
|
+
"brokers": {
|
|
390
|
+
"local": "ws://localhost:8080",
|
|
391
|
+
"remote": "ws://api.example.com:8080"
|
|
392
|
+
}
|
|
109
393
|
}
|
|
110
394
|
```
|
|
111
395
|
|
|
112
|
-
###
|
|
396
|
+
### Schema Definition Options
|
|
113
397
|
|
|
114
|
-
|
|
115
|
-
- **`IBroker`**: Broker instance interface with methods to manage its lifecycle and communications.
|
|
116
|
-
- **`BrokerMessageBuilder`**: Assists in constructing messages for broker communication.
|
|
398
|
+
The ability system provides two ways to define method schemas:
|
|
117
399
|
|
|
118
|
-
|
|
400
|
+
1. **Export Schemas** (defined in `agent.json` exports section)
|
|
401
|
+
2. **Inline Schemas** (passed directly to `.method()`)
|
|
119
402
|
|
|
120
|
-
|
|
403
|
+
```javascript
|
|
404
|
+
// Option 1: Define in agent.json exports section
|
|
405
|
+
// The schema is picked up automatically if the method name matches
|
|
406
|
+
// agent.json:
|
|
407
|
+
{
|
|
408
|
+
"exports": [
|
|
409
|
+
{
|
|
410
|
+
"name": "process",
|
|
411
|
+
"description": "Process data",
|
|
412
|
+
"inputSchema": { /* ... */ },
|
|
413
|
+
"outputSchema": { /* ... */ }
|
|
414
|
+
}
|
|
415
|
+
]
|
|
416
|
+
}
|
|
121
417
|
|
|
122
|
-
|
|
418
|
+
// Option 2: Define inline when registering the method
|
|
419
|
+
ability.method('process', handler, {
|
|
420
|
+
description: 'Process data',
|
|
421
|
+
inputSchema: { /* ... */ },
|
|
422
|
+
outputSchema: { /* ... */ }
|
|
423
|
+
});
|
|
123
424
|
|
|
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.
|
|
425
|
+
// Note: If both are defined, inline schemas take precedence over exports
|
|
426
|
+
```
|
|
132
427
|
|
|
133
|
-
|
|
428
|
+
**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.
|
|
134
429
|
|
|
135
|
-
|
|
430
|
+
## 🤖 Working with KadiClient
|
|
136
431
|
|
|
137
|
-
|
|
138
|
-
- **`send(message)`**: Sends a message through the WebSocket connection.
|
|
139
|
-
- **`getConnectedAgents()`**: Retrieves a list of currently connected agents.
|
|
432
|
+
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.
|
|
140
433
|
|
|
141
|
-
###
|
|
434
|
+
### Direct Approach (using loadAbility)
|
|
142
435
|
|
|
143
|
-
|
|
436
|
+
```javascript
|
|
437
|
+
import { loadAbility } from '@kadi.build/core';
|
|
144
438
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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.
|
|
439
|
+
// Load and call abilities directly
|
|
440
|
+
const echoAbility = await loadAbility('echo-js', 'stdio');
|
|
441
|
+
const result = await echoAbility.echo({ message: 'Hello world' });
|
|
151
442
|
|
|
152
|
-
|
|
443
|
+
// Load broker tools directly
|
|
444
|
+
const remoteService = await loadAbility('remote-service', 'broker', {
|
|
445
|
+
brokerUrl: 'ws://localhost:8080',
|
|
446
|
+
networks: ['global']
|
|
447
|
+
});
|
|
448
|
+
const brokerResult = await remoteService.process({ data: 'test' });
|
|
449
|
+
```
|
|
153
450
|
|
|
154
|
-
|
|
155
|
-
- **`IPCManager`**: Manages setup and lifecycle of IPC connections.
|
|
156
|
-
- **`IAbilityIPC`**: Represents an IPC ability instance with methods to manage its lifecycle and communications.
|
|
451
|
+
### Using KadiClient
|
|
157
452
|
|
|
158
|
-
|
|
453
|
+
```javascript
|
|
454
|
+
import { KadiClient } from '@kadi.build/core';
|
|
455
|
+
|
|
456
|
+
// Create a unified client
|
|
457
|
+
const client = new KadiClient({
|
|
458
|
+
name: 'my-service',
|
|
459
|
+
role: 'service', // Can both serve and consume
|
|
460
|
+
protocol: 'broker',
|
|
461
|
+
brokerUrls: ['ws://localhost:8080'],
|
|
462
|
+
networks: ['global']
|
|
463
|
+
});
|
|
159
464
|
|
|
160
|
-
|
|
465
|
+
// Register tools for others to call
|
|
466
|
+
client.registerTool(
|
|
467
|
+
'greet',
|
|
468
|
+
async ({ name }) => {
|
|
469
|
+
return { greeting: `Hello, ${name}!` };
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
description: 'Greet someone by name',
|
|
473
|
+
inputSchema: {
|
|
474
|
+
type: 'object',
|
|
475
|
+
properties: { name: { type: 'string' } },
|
|
476
|
+
required: ['name']
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
);
|
|
161
480
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
- **`shutdownInstance(name)`**: Shuts down an existing IPC instance by name.
|
|
481
|
+
// Connect and serve
|
|
482
|
+
await client.connectToBrokers();
|
|
165
483
|
|
|
166
|
-
|
|
484
|
+
// Call remote tools
|
|
485
|
+
const result = await client.callTool('translator', 'translate', {
|
|
486
|
+
text: 'Hello',
|
|
487
|
+
to: 'es'
|
|
488
|
+
});
|
|
167
489
|
|
|
168
|
-
|
|
490
|
+
// Load abilities for compatibility
|
|
491
|
+
const ability = await client.loadAbility('echo-js');
|
|
492
|
+
```
|
|
169
493
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
494
|
+
Use `loadAbility()` for simple consumption, or KadiClient for full-featured service development with tool registration, event publishing, and remote tool invocation.
|
|
495
|
+
|
|
496
|
+
## 🔄 Architecture Deep Dive
|
|
497
|
+
|
|
498
|
+
### Transport Architecture and Loading Sequence
|
|
499
|
+
|
|
500
|
+
The loading process uses modular transports based on the selected protocol:
|
|
501
|
+
|
|
502
|
+
```mermaid
|
|
503
|
+
sequenceDiagram
|
|
504
|
+
participant Client
|
|
505
|
+
participant loadAbility
|
|
506
|
+
participant Transport
|
|
507
|
+
participant FileSystem
|
|
508
|
+
participant ChildProcess
|
|
509
|
+
participant Service
|
|
510
|
+
participant Broker
|
|
511
|
+
|
|
512
|
+
Client->>loadAbility: loadAbility('echo-js', protocol?)
|
|
513
|
+
loadAbility->>FileSystem: Read agent.json manifests
|
|
514
|
+
FileSystem-->>loadAbility: Return config & version
|
|
515
|
+
|
|
516
|
+
alt protocol === 'native'
|
|
517
|
+
loadAbility->>Transport: new NativeTransport(config)
|
|
518
|
+
Transport->>FileSystem: import(entry point)
|
|
519
|
+
FileSystem-->>Transport: Module with KadiClient instance
|
|
520
|
+
Transport->>Service: Extract tool handlers via getToolNames()
|
|
521
|
+
Service-->>Transport: Return registered tools
|
|
522
|
+
Transport->>Transport: Store handlers in Map
|
|
523
|
+
else protocol === 'stdio'
|
|
524
|
+
loadAbility->>Transport: new StdioTransport(config)
|
|
525
|
+
Transport->>ChildProcess: spawn(startCmd, env: {KADI_PROTOCOL})
|
|
526
|
+
ChildProcess->>Service: KadiClient detects stdio mode
|
|
527
|
+
Service->>Service: Setup FrameReader/Writer
|
|
528
|
+
Transport->>Service: Send discovery request
|
|
529
|
+
Service-->>Transport: Return tool list
|
|
530
|
+
Transport->>Transport: Setup JSON-RPC proxy
|
|
531
|
+
else protocol === 'broker'
|
|
532
|
+
loadAbility->>Transport: new BrokerTransport(config)
|
|
533
|
+
Transport->>Transport: Create KadiClient wrapper
|
|
534
|
+
Transport->>Broker: WebSocket connect
|
|
535
|
+
Transport->>Broker: kadi.session.hello
|
|
536
|
+
Broker-->>Transport: { nonce, heartbeatIntervalSec }
|
|
537
|
+
Transport->>Broker: kadi.session.authenticate
|
|
538
|
+
Broker-->>Transport: { sessionId }
|
|
539
|
+
Transport->>Broker: kadi.ability.list
|
|
540
|
+
Broker-->>Transport: Available tools
|
|
541
|
+
Transport->>Transport: Start heartbeat timer
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
loadAbility->>loadAbility: Create proxy with tool methods
|
|
545
|
+
loadAbility-->>Client: Return ability proxy
|
|
546
|
+
|
|
547
|
+
Note over Client,Service: Tool invocation
|
|
548
|
+
Client->>Transport: ability.echo({ message })
|
|
549
|
+
|
|
550
|
+
alt native
|
|
551
|
+
Transport->>Service: Direct handler call
|
|
552
|
+
else stdio
|
|
553
|
+
Transport->>Service: JSON-RPC over frames
|
|
554
|
+
else broker
|
|
555
|
+
Transport->>Broker: kadi.ability.invoke
|
|
556
|
+
Broker->>Service: Route to target
|
|
557
|
+
Service->>Broker: kadi.ability.result
|
|
558
|
+
Broker-->>Transport: Forward result
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
Transport-->>Client: Return result
|
|
562
|
+
```
|
|
174
563
|
|
|
175
|
-
###
|
|
564
|
+
### KadiClient Architecture: Tool Registration & Serving
|
|
565
|
+
|
|
566
|
+
How KadiClient registers tools and starts serving:
|
|
567
|
+
|
|
568
|
+
```mermaid
|
|
569
|
+
sequenceDiagram
|
|
570
|
+
participant Dev as Developer
|
|
571
|
+
participant KC as KadiClient
|
|
572
|
+
participant Transport
|
|
573
|
+
participant Network as Network Layer
|
|
574
|
+
participant RemoteClient
|
|
575
|
+
|
|
576
|
+
Note over Dev,KC: Tool Registration Phase
|
|
577
|
+
Dev->>KC: new KadiClient({ name, role, protocol })
|
|
578
|
+
KC->>KC: Initialize based on role & protocol
|
|
579
|
+
|
|
580
|
+
Dev->>KC: registerTool('echo', handler, schema?)
|
|
581
|
+
KC->>KC: Store in toolHandlers Map<name, {handler, schema}>
|
|
582
|
+
|
|
583
|
+
Dev->>KC: registerTool('process', handler, schema)
|
|
584
|
+
KC->>KC: Add to toolHandlers Map
|
|
585
|
+
|
|
586
|
+
Note over KC,Network: Connection & Serving Phase
|
|
587
|
+
Dev->>KC: serve() or connectToBrokers()
|
|
588
|
+
|
|
589
|
+
alt protocol === 'native'
|
|
590
|
+
KC->>KC: Tools available via direct reference
|
|
591
|
+
KC->>KC: Emit 'start' event
|
|
592
|
+
else protocol === 'stdio'
|
|
593
|
+
KC->>Transport: Setup StdioTransport
|
|
594
|
+
Transport->>Transport: new FrameReader(stdin)
|
|
595
|
+
Transport->>Transport: new FrameWriter(stdout)
|
|
596
|
+
Transport->>KC: on('message', handleStdioMessage)
|
|
597
|
+
KC->>KC: Process JSON-RPC requests
|
|
598
|
+
else protocol === 'broker'
|
|
599
|
+
KC->>Network: WebSocket.connect(brokerUrl)
|
|
600
|
+
KC->>Network: kadi.session.hello({ role })
|
|
601
|
+
Network-->>KC: { nonce, heartbeatIntervalSec: 30 }
|
|
602
|
+
KC->>KC: Sign nonce with Ed25519
|
|
603
|
+
KC->>Network: kadi.session.authenticate({ signature })
|
|
604
|
+
Network-->>KC: { sessionId }
|
|
605
|
+
KC->>Network: kadi.agent.register({ tools, networks })
|
|
606
|
+
KC->>KC: Start heartbeat timer (30s interval)
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
Note over RemoteClient,KC: Tool Invocation Flow
|
|
610
|
+
RemoteClient->>Network: Request tool invocation
|
|
611
|
+
|
|
612
|
+
alt native
|
|
613
|
+
RemoteClient->>KC: Direct method call
|
|
614
|
+
KC->>KC: toolHandlers.get(name).handler(params)
|
|
615
|
+
else stdio
|
|
616
|
+
Network->>Transport: JSON-RPC frame
|
|
617
|
+
Transport->>KC: Parsed request
|
|
618
|
+
KC->>KC: toolHandlers.get(name).handler(params)
|
|
619
|
+
KC->>Transport: JSON-RPC response
|
|
620
|
+
Transport->>Network: Framed response
|
|
621
|
+
else broker
|
|
622
|
+
Network->>KC: kadi.ability.invoke message
|
|
623
|
+
KC->>KC: toolHandlers.get(toolName).handler(params)
|
|
624
|
+
KC->>Network: kadi.ability.result message
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
Network-->>RemoteClient: Tool result
|
|
628
|
+
```
|
|
176
629
|
|
|
177
|
-
|
|
630
|
+
### Event System Architecture
|
|
631
|
+
|
|
632
|
+
KadiClient provides a unified event API that works across all transport protocols:
|
|
633
|
+
|
|
634
|
+
```mermaid
|
|
635
|
+
sequenceDiagram
|
|
636
|
+
participant Publisher as Service (Publisher)
|
|
637
|
+
participant Transport as Transport Layer
|
|
638
|
+
participant EventBus as Event Bus
|
|
639
|
+
participant Subscriber as Client (Subscriber)
|
|
640
|
+
|
|
641
|
+
Note over Subscriber: Setup subscription
|
|
642
|
+
Subscriber->>Subscriber: subscribeToEvent('math.*', callback)
|
|
643
|
+
|
|
644
|
+
alt protocol === 'broker'
|
|
645
|
+
Subscriber->>EventBus: kadi.event.subscribe({channels: ['math.*']})
|
|
646
|
+
EventBus-->>Subscriber: {subscribed: ['math.*'], queueName}
|
|
647
|
+
else protocol === 'stdio'
|
|
648
|
+
Subscriber->>Transport: Setup event listener
|
|
649
|
+
Transport->>Subscriber: on('transport:event', dispatcher)
|
|
650
|
+
else protocol === 'native'
|
|
651
|
+
Subscriber->>Publisher: Direct EventEmitter reference
|
|
652
|
+
Publisher->>Subscriber: on('ability:event', dispatcher)
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
Note over Publisher: Publish event
|
|
656
|
+
Publisher->>Publisher: publishEvent('math.operation', data)
|
|
657
|
+
|
|
658
|
+
alt protocol === 'native'
|
|
659
|
+
Publisher->>Publisher: emit('ability:event', {eventName, data})
|
|
660
|
+
Publisher-->>Subscriber: Direct EventEmitter delivery
|
|
661
|
+
Subscriber->>Subscriber: Pattern match & invoke callback
|
|
662
|
+
else protocol === 'stdio'
|
|
663
|
+
Publisher->>Transport: writer.write(__kadi_event notification)
|
|
664
|
+
Transport->>Transport: Frame with LSP headers
|
|
665
|
+
Transport-->>Subscriber: Framed event over stdout
|
|
666
|
+
Subscriber->>Transport: FrameReader parses
|
|
667
|
+
Transport->>Subscriber: emit('transport:event', {name, data})
|
|
668
|
+
Subscriber->>Subscriber: Pattern match & invoke callback
|
|
669
|
+
else protocol === 'broker'
|
|
670
|
+
Publisher->>EventBus: kadi.event.publish({channel, data})
|
|
671
|
+
EventBus->>EventBus: Route via RabbitMQ
|
|
672
|
+
EventBus-->>Subscriber: kadi.event.delivery
|
|
673
|
+
Subscriber->>Subscriber: Pattern match & invoke callback
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
Note over Subscriber: Cleanup
|
|
677
|
+
Subscriber->>Subscriber: unsubscribe()
|
|
678
|
+
alt protocol === 'broker'
|
|
679
|
+
Subscriber->>EventBus: kadi.event.unsubscribe
|
|
680
|
+
else
|
|
681
|
+
Subscriber->>Subscriber: Remove local listener
|
|
682
|
+
end
|
|
683
|
+
```
|
|
178
684
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
685
|
+
### Broker Protocol Communication Flow
|
|
686
|
+
|
|
687
|
+
Detailed view of broker-based communication with heartbeat:
|
|
688
|
+
|
|
689
|
+
```mermaid
|
|
690
|
+
sequenceDiagram
|
|
691
|
+
participant Client as KadiClient
|
|
692
|
+
participant Broker as KADI Broker
|
|
693
|
+
participant Target as Target Service
|
|
694
|
+
|
|
695
|
+
Note over Client,Broker: Connection & Authentication
|
|
696
|
+
Client->>Broker: WebSocket connect
|
|
697
|
+
Client->>Broker: kadi.session.hello({ role })
|
|
698
|
+
Broker-->>Client: { nonce, heartbeatIntervalSec: 30 }
|
|
699
|
+
Client->>Client: Generate Ed25519 keypair
|
|
700
|
+
Client->>Client: Sign nonce
|
|
701
|
+
Client->>Broker: kadi.session.authenticate({ signature })
|
|
702
|
+
Broker-->>Client: { sessionId }
|
|
703
|
+
|
|
704
|
+
Note over Client,Broker: Heartbeat Management
|
|
705
|
+
Client->>Client: Start heartbeat timer (30s)
|
|
706
|
+
loop Every 30 seconds
|
|
707
|
+
Client->>Broker: kadi.session.ping
|
|
708
|
+
Note over Broker: Reset connection timeout (90s)
|
|
709
|
+
end
|
|
710
|
+
|
|
711
|
+
Note over Client,Broker: Tool Registration
|
|
712
|
+
Client->>Broker: kadi.agent.register({ tools, networks })
|
|
713
|
+
Broker->>Broker: Store in registry
|
|
714
|
+
Broker-->>Client: { registered: true }
|
|
715
|
+
|
|
716
|
+
Note over Client,Target: Remote Tool Invocation
|
|
717
|
+
Client->>Client: callTool('service-b', 'process', params)
|
|
718
|
+
Client->>Broker: kadi.ability.invoke({
|
|
719
|
+
targetAgent: 'service-b',
|
|
720
|
+
toolName: 'process',
|
|
721
|
+
toolInput: params
|
|
722
|
+
})
|
|
723
|
+
Broker->>Broker: Lookup service-b
|
|
724
|
+
Broker->>Target: kadi.ability.invoke
|
|
725
|
+
Target->>Target: Execute tool handler
|
|
726
|
+
Target->>Broker: JSON-RPC response
|
|
727
|
+
Broker-->>Client: Forward response
|
|
728
|
+
Client->>Client: Resolve promise
|
|
729
|
+
|
|
730
|
+
Note over Client,Broker: Event Publishing
|
|
731
|
+
Client->>Broker: kadi.event.publish({
|
|
732
|
+
channel: 'system.status',
|
|
733
|
+
data: { status: 'healthy' }
|
|
734
|
+
})
|
|
735
|
+
Broker->>Broker: Publish to RabbitMQ exchange
|
|
736
|
+
|
|
737
|
+
Note over Client,Broker: Graceful Shutdown
|
|
738
|
+
Client->>Client: Stop heartbeat timer
|
|
739
|
+
Client->>Broker: kadi.session.goodbye
|
|
740
|
+
Client->>Client: Close WebSocket
|
|
741
|
+
```
|
|
183
742
|
|
|
184
|
-
|
|
743
|
+
### Stdio Protocol: LSP-Style Frame Processing
|
|
744
|
+
|
|
745
|
+
How KadiClient handles stdio communication with LSP-style framing:
|
|
746
|
+
|
|
747
|
+
```mermaid
|
|
748
|
+
sequenceDiagram
|
|
749
|
+
participant Parent as Parent Process
|
|
750
|
+
participant SR as StdioFrameReader
|
|
751
|
+
participant SW as StdioFrameWriter
|
|
752
|
+
participant Server as StdioRpcServer
|
|
753
|
+
participant Ability as KadiAbility
|
|
754
|
+
|
|
755
|
+
Note over Parent,SR: Incoming Request
|
|
756
|
+
Parent->>SR: Write to stdin: "Kadi-Content-Length: 52\r\n\r\n{...}"
|
|
757
|
+
SR->>SR: Buffer incoming data
|
|
758
|
+
SR->>SR: Look for Content-Length header
|
|
759
|
+
SR->>SR: Parse header, extract body length
|
|
760
|
+
SR->>SR: Wait for complete body
|
|
761
|
+
SR->>SR: Parse JSON from body
|
|
762
|
+
SR->>Server: onMessage({ success: true, data: request })
|
|
763
|
+
|
|
764
|
+
Server->>Server: Validate JSON-RPC format
|
|
765
|
+
Server->>Ability: getMethodHandler(request.method)
|
|
766
|
+
Ability-->>Server: Return handler
|
|
767
|
+
Server->>Server: Execute handler(params) with timeout
|
|
768
|
+
|
|
769
|
+
Note over Server,Parent: Response
|
|
770
|
+
Server->>SW: write(response)
|
|
771
|
+
SW->>SW: JSON.stringify(response)
|
|
772
|
+
SW->>SW: Calculate byte length
|
|
773
|
+
SW->>SW: Create header: "Kadi-Content-Length: N\r\n\r\n"
|
|
774
|
+
SW->>Parent: Write header + body to stdout
|
|
775
|
+
|
|
776
|
+
Note over SR: Error Recovery
|
|
777
|
+
alt Frame Corruption
|
|
778
|
+
SR->>SR: Detect invalid frame
|
|
779
|
+
SR->>SR: Search for next Content-Length marker
|
|
780
|
+
SR->>SR: Skip corrupted bytes
|
|
781
|
+
SR->>Server: onMessage({ success: false, error: 'FRAME_CORRUPTION' })
|
|
782
|
+
Server->>Server: Log error, continue processing
|
|
783
|
+
end
|
|
784
|
+
```
|
|
185
785
|
|
|
186
|
-
|
|
786
|
+
## 📥 Loading Abilities
|
|
187
787
|
|
|
188
|
-
###
|
|
788
|
+
### Basic Loading
|
|
189
789
|
|
|
190
790
|
```javascript
|
|
191
|
-
|
|
791
|
+
import { loadAbility } from '@kadi.build/core';
|
|
192
792
|
|
|
193
|
-
//
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
);
|
|
793
|
+
// Auto-detect protocol from agent.json
|
|
794
|
+
const ability = await loadAbility('my-ability');
|
|
795
|
+
|
|
796
|
+
// Explicitly specify protocol
|
|
797
|
+
const stdioAbility = await loadAbility('my-ability', 'stdio');
|
|
798
|
+
const brokerAbility = await loadAbility('my-ability', 'broker');
|
|
799
|
+
const nativeAbility = await loadAbility('my-ability', 'native');
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
### Working with Loaded Abilities
|
|
199
803
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
804
|
+
```javascript
|
|
805
|
+
// Call methods directly - no need to discover them first
|
|
806
|
+
const result = await ability.echo({ message: 'hello' });
|
|
807
|
+
|
|
808
|
+
// Call methods
|
|
809
|
+
const result = await ability.someMethod({ param: 'value' });
|
|
810
|
+
|
|
811
|
+
// Direct RPC call (bypasses method validation)
|
|
812
|
+
const response = await ability.call('someMethod', { param: 'value' });
|
|
813
|
+
|
|
814
|
+
// Subscribe to events
|
|
815
|
+
ability.events.on('custom:event', (data) => {
|
|
816
|
+
console.log('Event received:', data);
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
// Note: Events work for native and stdio protocols
|
|
820
|
+
// Subscribe before calling methods that emit events
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
### Loading Context
|
|
824
|
+
|
|
825
|
+
The loader automatically resolves ability versions from:
|
|
826
|
+
|
|
827
|
+
1. **Project context**: Reads from project's `agent.json`
|
|
828
|
+
2. **Nested context**: When loading from within another ability
|
|
829
|
+
3. **Explicit version**: Can be specified in ability name
|
|
830
|
+
|
|
831
|
+
## ⚙️ Configuration
|
|
832
|
+
|
|
833
|
+
### Environment Variables
|
|
834
|
+
|
|
835
|
+
```bash
|
|
836
|
+
# Set default protocol
|
|
837
|
+
export KADI_PROTOCOL=stdio
|
|
838
|
+
|
|
839
|
+
# Configure broker
|
|
840
|
+
export KADI_BROKER_URL=ws://localhost:8080
|
|
841
|
+
export KADI_SERVICE_NAME=my-service
|
|
842
|
+
export KADI_AGENT_SCOPE=project-123
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
### Environment Variables for Child Processes
|
|
846
|
+
|
|
847
|
+
When abilities are spawned as child processes (stdio and broker protocols), the parent process passes down important environment variables:
|
|
848
|
+
|
|
849
|
+
```javascript
|
|
850
|
+
// In your ability code, you can access these variables:
|
|
851
|
+
const protocol = process.env.KADI_PROTOCOL; // 'stdio' or 'broker'
|
|
852
|
+
const brokerUrl = process.env.KADI_BROKER_URL;
|
|
853
|
+
const serviceName = process.env.KADI_SERVICE_NAME;
|
|
854
|
+
const agentScope = process.env.KADI_AGENT_SCOPE;
|
|
855
|
+
|
|
856
|
+
// Use them to configure your ability behavior
|
|
857
|
+
const ability = new KadiAbility({
|
|
858
|
+
name: 'my-ability',
|
|
859
|
+
scope: process.env.KADI_AGENT_SCOPE || 'global'
|
|
860
|
+
// Ability automatically uses KADI_PROTOCOL to determine transport
|
|
861
|
+
});
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
### Example Project Structure
|
|
865
|
+
|
|
866
|
+
```
|
|
867
|
+
my-project/
|
|
868
|
+
├── agent.json # Project configuration
|
|
869
|
+
├── abilities/ # Installed abilities
|
|
870
|
+
│ └── echo-ability/
|
|
871
|
+
│ └── 1.0.0/
|
|
872
|
+
│ ├── agent.json # Ability configuration
|
|
873
|
+
│ ├── service.js # Ability implementation
|
|
874
|
+
│ └── package.json
|
|
875
|
+
├── modules/ # Source modules
|
|
876
|
+
│ └── echo-ability/ # Development version
|
|
877
|
+
└── index.js # Main entry point
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
## 🚀 Advanced Usage
|
|
881
|
+
|
|
882
|
+
### Event System
|
|
883
|
+
|
|
884
|
+
KadiClient provides a comprehensive event system that works across all protocols:
|
|
885
|
+
|
|
886
|
+
#### 1. Lifecycle Events
|
|
887
|
+
|
|
888
|
+
Monitor the service lifecycle:
|
|
889
|
+
|
|
890
|
+
```javascript
|
|
891
|
+
const client = new KadiClient({ name: 'my-service' });
|
|
892
|
+
|
|
893
|
+
// Connection events
|
|
894
|
+
client.on('connected', ({ broker }) => {
|
|
895
|
+
console.log(`Connected to broker: ${broker}`);
|
|
203
896
|
});
|
|
204
897
|
|
|
205
|
-
|
|
206
|
-
console.
|
|
207
|
-
// Handle critical errors, potentially restarting the process or alerting administrators
|
|
898
|
+
client.on('disconnected', () => {
|
|
899
|
+
console.log('Disconnected from broker');
|
|
208
900
|
});
|
|
209
901
|
|
|
210
|
-
|
|
211
|
-
|
|
902
|
+
// Tool invocation events
|
|
903
|
+
client.on('tool:invoked', ({ toolName, params }) => {
|
|
904
|
+
console.log(`Tool ${toolName} invoked with:`, params);
|
|
212
905
|
});
|
|
213
906
|
|
|
214
|
-
|
|
215
|
-
console.log(
|
|
907
|
+
client.on('tool:completed', ({ toolName, result }) => {
|
|
908
|
+
console.log(`Tool ${toolName} completed:`, result);
|
|
216
909
|
});
|
|
217
910
|
|
|
218
|
-
|
|
219
|
-
console.
|
|
911
|
+
client.on('error', (error) => {
|
|
912
|
+
console.error('Service error:', error);
|
|
220
913
|
});
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
#### 2. Custom Events (All Protocols)
|
|
221
917
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const jsonObject = BrokerMessageBuilder.setup(
|
|
231
|
-
'TestAgent',
|
|
232
|
-
'A Broker Testing Agent',
|
|
233
|
-
null,
|
|
234
|
-
null
|
|
235
|
-
);
|
|
236
|
-
brk.send(jsonObject);
|
|
918
|
+
Publish and subscribe to custom events across all transport protocols:
|
|
919
|
+
|
|
920
|
+
```javascript
|
|
921
|
+
// Publishing events
|
|
922
|
+
const publisher = new KadiClient({
|
|
923
|
+
name: 'event-publisher',
|
|
924
|
+
role: 'service',
|
|
925
|
+
protocol: 'broker' // Works with all protocols
|
|
237
926
|
});
|
|
238
927
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
928
|
+
publisher.registerTool('process', async ({ data }) => {
|
|
929
|
+
// Publish events during processing
|
|
930
|
+
await publisher.publishEvent('process.started', {
|
|
931
|
+
timestamp: Date.now(),
|
|
932
|
+
data
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
// Do work...
|
|
936
|
+
const result = await processData(data);
|
|
937
|
+
|
|
938
|
+
await publisher.publishEvent('process.completed', {
|
|
939
|
+
timestamp: Date.now(),
|
|
940
|
+
result
|
|
941
|
+
});
|
|
942
|
+
|
|
943
|
+
return result;
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
// Subscribing to events
|
|
947
|
+
const subscriber = new KadiClient({
|
|
948
|
+
name: 'event-subscriber',
|
|
949
|
+
role: 'agent',
|
|
950
|
+
protocol: 'broker'
|
|
951
|
+
});
|
|
952
|
+
|
|
953
|
+
// Subscribe with wildcards
|
|
954
|
+
subscriber.subscribeToEvent('process.*', (data) => {
|
|
955
|
+
console.log('Process event:', data);
|
|
956
|
+
});
|
|
957
|
+
|
|
958
|
+
// One-time subscription
|
|
959
|
+
subscriber.onceEvent('process.completed', (data) => {
|
|
960
|
+
console.log('First completion:', data);
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
// Multiple pattern subscription
|
|
964
|
+
subscriber.subscribeToEvents(
|
|
965
|
+
['process.*', 'system.*'],
|
|
966
|
+
(pattern, data) => {
|
|
967
|
+
console.log(`Event from ${pattern}:`, data);
|
|
249
968
|
}
|
|
250
|
-
|
|
969
|
+
);
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
**Protocol-Specific Behavior:**
|
|
973
|
+
|
|
974
|
+
- **Native**: Direct EventEmitter, synchronous delivery
|
|
975
|
+
- **Stdio**: JSON-RPC notifications with LSP framing
|
|
976
|
+
- **Broker**: RabbitMQ pub/sub via WebSocket, persistent queues available
|
|
977
|
+
|
|
978
|
+
|
|
979
|
+
## 🔧 Development Workflow
|
|
980
|
+
|
|
981
|
+
### Testing Local Changes
|
|
982
|
+
|
|
983
|
+
When developing new features or testing changes to `@kadi.build/core` before publishing to NPM:
|
|
984
|
+
|
|
985
|
+
0. **clone the repository**
|
|
986
|
+
|
|
987
|
+
```bash
|
|
988
|
+
git clone https://gitlab.com/humin-game-lab/kadi/kadi-core.git
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
1. **Pack the local version** (in the kadi-core directory):
|
|
992
|
+
|
|
993
|
+
```bash
|
|
994
|
+
cd /path/to/kadi-core
|
|
995
|
+
npm pack
|
|
996
|
+
# This creates: kadi.build-core-X.Y.Z.tgz
|
|
997
|
+
```
|
|
998
|
+
|
|
999
|
+
1. **Install in your project**:
|
|
1000
|
+
|
|
1001
|
+
```bash
|
|
1002
|
+
cd /path/to/your-project
|
|
1003
|
+
npm install /path/to/kadi-core/kadi.build-core-X.Y.Z.tgz
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
1. **For ability development**, update the ability's preflight script:
|
|
1007
|
+
|
|
1008
|
+
```json
|
|
1009
|
+
{
|
|
1010
|
+
"scripts": {
|
|
1011
|
+
"preflight": "npm uninstall @kadi.build/core && npm install /path/to/kadi.build-core-X.Y.Z.tgz"
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
```
|
|
1015
|
+
|
|
1016
|
+
## 📖 API Reference
|
|
1017
|
+
|
|
1018
|
+
### Core Classes
|
|
1019
|
+
|
|
1020
|
+
#### `KadiClient`
|
|
1021
|
+
|
|
1022
|
+
The unified class for all KADI operations - serving tools, calling remote services, and managing events.
|
|
1023
|
+
|
|
1024
|
+
```javascript
|
|
1025
|
+
import { KadiClient } from '@kadi.build/core';
|
|
1026
|
+
|
|
1027
|
+
const client = new KadiClient({
|
|
1028
|
+
name: 'my-service',
|
|
1029
|
+
role: 'service', // 'agent', 'ability', or 'service'
|
|
1030
|
+
protocol: 'broker', // 'native', 'stdio', or 'broker'
|
|
1031
|
+
brokerUrls: ['ws://localhost:8080'],
|
|
1032
|
+
networks: ['global', 'custom-network']
|
|
251
1033
|
});
|
|
1034
|
+
```
|
|
1035
|
+
|
|
1036
|
+
**Configuration Options:**
|
|
1037
|
+
- `name` - Service/agent name
|
|
1038
|
+
- `role` - Operating role: 'agent' (consumer), 'ability' (provider), 'service' (both)
|
|
1039
|
+
- `protocol` - Transport protocol to use
|
|
1040
|
+
- `brokerUrls` - Array of broker WebSocket URLs (for broker protocol)
|
|
1041
|
+
- `networks` - Network namespaces for tool discovery
|
|
1042
|
+
- `heartbeatIntervalSec` - Custom heartbeat interval (default: from broker)
|
|
1043
|
+
|
|
1044
|
+
**Tool Registration Methods:**
|
|
1045
|
+
- `registerTool(name, handler, schema?)` - Register a single tool
|
|
1046
|
+
- `getTools()` - Get list of registered tool names
|
|
1047
|
+
- `getToolNames()` - Get filtered list of tool names
|
|
1048
|
+
- `getToolHandler(name)` - Get a specific tool's handler
|
|
1049
|
+
- `getToolSchema(name)` - Get a specific tool's schema
|
|
1050
|
+
- `hasTool(name)` - Check if a tool is registered
|
|
1051
|
+
|
|
1052
|
+
**Remote Tool Invocation:**
|
|
1053
|
+
- `callTool(targetAgent, toolName, params)` - Call a remote tool via broker
|
|
1054
|
+
- `discoverRemoteTools(targetAgent)` - List tools from a remote agent
|
|
1055
|
+
- `loadAbility(name, protocol?, options?)` - Load an ability (compatibility)
|
|
1056
|
+
|
|
1057
|
+
**Event System:**
|
|
1058
|
+
- `publishEvent(eventName, data)` - Publish an event
|
|
1059
|
+
- `subscribeToEvent(pattern, callback)` - Subscribe with wildcards
|
|
1060
|
+
- `subscribeToEvents(patterns[], callback)` - Multiple subscriptions
|
|
1061
|
+
- `unsubscribeFromEvent(pattern, callback)` - Remove subscription
|
|
1062
|
+
- `onceEvent(pattern, callback)` - One-time subscription
|
|
1063
|
+
|
|
1064
|
+
**Connection Management:**
|
|
1065
|
+
- `serve()` - Start serving (stdio/native modes)
|
|
1066
|
+
- `connectToBrokers(urls?)` - Connect to broker(s)
|
|
1067
|
+
- `disconnect()` - Clean disconnect
|
|
1068
|
+
- `isConnected` - Check connection status
|
|
1069
|
+
|
|
1070
|
+
**Properties:**
|
|
1071
|
+
- `agentId` - Unique agent identifier
|
|
1072
|
+
- `name` - Service name
|
|
1073
|
+
- `role` - Current operating role
|
|
1074
|
+
- `protocol` - Active protocol
|
|
1075
|
+
|
|
1076
|
+
**Complete Usage Example:**
|
|
252
1077
|
|
|
253
|
-
|
|
254
|
-
|
|
1078
|
+
```javascript
|
|
1079
|
+
import { KadiClient } from '@kadi.build/core';
|
|
1080
|
+
|
|
1081
|
+
// Create a service that can both serve and consume
|
|
1082
|
+
const service = new KadiClient({
|
|
1083
|
+
name: 'math-service',
|
|
1084
|
+
role: 'service',
|
|
1085
|
+
protocol: 'broker',
|
|
1086
|
+
brokerUrls: ['ws://localhost:8080'],
|
|
1087
|
+
networks: ['global']
|
|
255
1088
|
});
|
|
256
1089
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
1090
|
+
// Register tools with schemas
|
|
1091
|
+
service.registerTool(
|
|
1092
|
+
'add',
|
|
1093
|
+
async ({ a, b }) => {
|
|
1094
|
+
// Publish event before processing
|
|
1095
|
+
await service.publishEvent('math.operation', {
|
|
1096
|
+
operation: 'add',
|
|
1097
|
+
inputs: { a, b }
|
|
1098
|
+
});
|
|
1099
|
+
|
|
1100
|
+
const result = a + b;
|
|
1101
|
+
|
|
1102
|
+
// Publish completion event
|
|
1103
|
+
await service.publishEvent('math.completed', {
|
|
1104
|
+
operation: 'add',
|
|
1105
|
+
result
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
return { result };
|
|
1109
|
+
},
|
|
1110
|
+
{
|
|
1111
|
+
description: 'Add two numbers',
|
|
1112
|
+
inputSchema: {
|
|
1113
|
+
type: 'object',
|
|
1114
|
+
properties: {
|
|
1115
|
+
a: { type: 'number', description: 'First number' },
|
|
1116
|
+
b: { type: 'number', description: 'Second number' }
|
|
1117
|
+
},
|
|
1118
|
+
required: ['a', 'b']
|
|
1119
|
+
},
|
|
1120
|
+
outputSchema: {
|
|
1121
|
+
type: 'object',
|
|
1122
|
+
properties: {
|
|
1123
|
+
result: { type: 'number', description: 'Sum of a and b' }
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
);
|
|
1128
|
+
|
|
1129
|
+
// Subscribe to events from other services
|
|
1130
|
+
service.subscribeToEvent('system.*', (data) => {
|
|
1131
|
+
console.log('System event:', data);
|
|
260
1132
|
});
|
|
261
1133
|
|
|
262
|
-
//
|
|
1134
|
+
// Connect to broker
|
|
1135
|
+
await service.connectToBrokers();
|
|
263
1136
|
|
|
264
|
-
//
|
|
265
|
-
|
|
1137
|
+
// Call remote tools
|
|
1138
|
+
const result = await service.callTool(
|
|
1139
|
+
'translator-service',
|
|
1140
|
+
'translate',
|
|
1141
|
+
{ text: 'Hello', to: 'es' }
|
|
1142
|
+
);
|
|
266
1143
|
|
|
267
|
-
//
|
|
268
|
-
|
|
1144
|
+
// Graceful shutdown
|
|
1145
|
+
process.on('SIGTERM', async () => {
|
|
1146
|
+
await service.disconnect();
|
|
1147
|
+
process.exit(0);
|
|
1148
|
+
});
|
|
269
1149
|
```
|
|
270
1150
|
|
|
271
|
-
|
|
1151
|
+
#### `loadAbility`
|
|
1152
|
+
|
|
1153
|
+
Load an ability by name and protocol.
|
|
272
1154
|
|
|
273
1155
|
```javascript
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
1156
|
+
import { loadAbility } from '@kadi.build/core';
|
|
1157
|
+
|
|
1158
|
+
const ability = await loadAbility('ability-name', 'protocol');
|
|
277
1159
|
```
|
|
278
1160
|
|
|
1161
|
+
**Returns:** A proxy object with:
|
|
1162
|
+
|
|
1163
|
+
- Direct method calls (e.g., `ability.echo({ message: 'hello' })`)
|
|
1164
|
+
- `ability.events` - EventEmitter for subscribing to events (native/stdio protocols only)
|
|
1165
|
+
- `ability.__call(method, params)` - Direct RPC call
|
|
1166
|
+
|
|
1167
|
+
### Utility Functions
|
|
1168
|
+
|
|
1169
|
+
```javascript
|
|
1170
|
+
import {
|
|
1171
|
+
createLogger,
|
|
1172
|
+
getProjectJSON,
|
|
1173
|
+
getAbilityJSON,
|
|
1174
|
+
getBrokerUrl,
|
|
1175
|
+
runExecCommand
|
|
1176
|
+
} from '@kadi.build/core';
|
|
1177
|
+
```
|
|
1178
|
+
|
|
1179
|
+
### Debug Mode
|
|
1180
|
+
|
|
1181
|
+
Enable detailed logging:
|
|
1182
|
+
|
|
1183
|
+
```bash
|
|
1184
|
+
DEBUG=kadi:* node index.js
|
|
1185
|
+
```
|
|
1186
|
+
|
|
1187
|
+
Check ability logs:
|
|
1188
|
+
|
|
1189
|
+
```bash
|
|
1190
|
+
tail -f abilities/my-ability/1.0.0/my-ability.log
|
|
1191
|
+
```
|
|
1192
|
+
|
|
1193
|
+
## 🤝 Contributing
|
|
1194
|
+
|
|
1195
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
1196
|
+
|
|
1197
|
+
1. Fork the repository
|
|
1198
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
1199
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
1200
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
1201
|
+
5. Open a Pull Request
|
|
1202
|
+
|
|
1203
|
+
|
|
1204
|
+
|
|
1205
|
+
## 🔗 Related Projects
|
|
1206
|
+
|
|
1207
|
+
- [@kadi.build/cli](https://gitlab.com/humin-game-lab/kadi/kadi) - Command-line interface
|
|
1208
|
+
- [@kadi.build/broker](https://gitlab.com/humin-game-lab/kadi/kadi-broker) - The KADI broker
|
|
1209
|
+
|
|
279
1210
|
---
|
|
280
1211
|
|
|
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)
|
|
1212
|
+
Built with ❤️ by the KADI team
|