@kadi.build/core 0.0.1-alpha.3 → 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 +571 -594
- 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 +56 -5
- package/agent.json +0 -18
- package/examples/example-abilities/echo-js/README.md +0 -131
- package/examples/example-abilities/echo-js/agent.json +0 -63
- package/examples/example-abilities/echo-js/package.json +0 -24
- package/examples/example-abilities/echo-js/service.js +0 -43
- package/examples/example-abilities/hash-go/agent.json +0 -53
- package/examples/example-abilities/hash-go/cmd/hash_ability/main.go +0 -340
- package/examples/example-abilities/hash-go/go.mod +0 -3
- package/examples/example-agent/abilities/echo-js/0.0.1/README.md +0 -131
- package/examples/example-agent/abilities/echo-js/0.0.1/agent.json +0 -63
- package/examples/example-agent/abilities/echo-js/0.0.1/package-lock.json +0 -93
- package/examples/example-agent/abilities/echo-js/0.0.1/package.json +0 -24
- package/examples/example-agent/abilities/echo-js/0.0.1/service.js +0 -41
- package/examples/example-agent/abilities/hash-go/0.0.1/agent.json +0 -53
- 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 +0 -340
- package/examples/example-agent/abilities/hash-go/0.0.1/go.mod +0 -3
- package/examples/example-agent/agent.json +0 -39
- package/examples/example-agent/index.js +0 -102
- package/examples/example-agent/package-lock.json +0 -93
- package/examples/example-agent/package.json +0 -17
- package/src/KadiAbility.js +0 -478
- package/src/index.js +0 -65
- package/src/loadAbility.js +0 -1086
- package/src/servers/BaseRpcServer.js +0 -404
- package/src/servers/BrokerRpcServer.js +0 -776
- package/src/servers/StdioRpcServer.js +0 -360
- package/src/transport/BrokerMessageBuilder.js +0 -377
- package/src/transport/IpcMessageBuilder.js +0 -1229
- package/src/utils/agentUtils.js +0 -137
- package/src/utils/commandUtils.js +0 -64
- package/src/utils/configUtils.js +0 -72
- package/src/utils/logger.js +0 -161
- package/src/utils/pathUtils.js +0 -86
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// npm install ../../kadi.build-core-0.0.1-alpha.2.tgz
|
|
4
|
-
import { loadAbility } from '@kadi.build/core';
|
|
5
|
-
|
|
6
|
-
async function main() {
|
|
7
|
-
console.log('🎬 KADI LoadAbility Mechanism Demo');
|
|
8
|
-
console.log('====================================================');
|
|
9
|
-
|
|
10
|
-
// === WORKING ABILITIES ===
|
|
11
|
-
console.log('\n✅ === WORKING ABILITIES ===');
|
|
12
|
-
|
|
13
|
-
// try {
|
|
14
|
-
// console.log('\n🔧 Loading hash-go ability (Go)...');
|
|
15
|
-
// let goAbility = await loadAbility('hash-go');
|
|
16
|
-
// console.log('Available methods:', goAbility.__list());
|
|
17
|
-
// const hashGoResult = await goAbility.digest({
|
|
18
|
-
// text: 'I am calling hash-go digest method from Javascript',
|
|
19
|
-
// algo: 'sha256'
|
|
20
|
-
// });
|
|
21
|
-
// console.log('Go digest result:', hashGoResult);
|
|
22
|
-
|
|
23
|
-
// // This is done on purpose to test the error handling
|
|
24
|
-
// const someFunctionResult = await goAbility.someFunction({
|
|
25
|
-
// message: 'this function does not exist'
|
|
26
|
-
// });
|
|
27
|
-
|
|
28
|
-
// console.log('Go ability someFunction result:', someFunctionResult);
|
|
29
|
-
// } catch (err) {
|
|
30
|
-
// console.error('❌ hash-go failed:', err.message);
|
|
31
|
-
// }
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
console.log('\n🔧 Loading echo-js ability using native (Javascript)...');
|
|
35
|
-
let echoJsAbility = await loadAbility('echo-js');
|
|
36
|
-
|
|
37
|
-
// Subscribe first
|
|
38
|
-
echoJsAbility.events.on('echo:test-event', (data) => {
|
|
39
|
-
console.log(`[NATIVE] echo:test-event received:`, data);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
console.log('Available methods:', echoJsAbility.__list());
|
|
43
|
-
const echoJsResult = await echoJsAbility.echo({
|
|
44
|
-
message: 'I am calling echo-js echo method from Javascript'
|
|
45
|
-
});
|
|
46
|
-
console.log('Echo-js echo result:', echoJsResult);
|
|
47
|
-
} catch (err) {
|
|
48
|
-
console.error('❌ echo-js failed:', err.message);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
console.log('\n🔧 Loading echo-js ability using stdio (Javascript)...');
|
|
53
|
-
let echoJsAbility = await loadAbility('echo-js', 'stdio');
|
|
54
|
-
console.log('Available methods:', echoJsAbility.__list());
|
|
55
|
-
|
|
56
|
-
// Subscribe first
|
|
57
|
-
echoJsAbility.events.on('echo:test-event', (data) => {
|
|
58
|
-
console.log(`[STDIO] echo:test-event received:`, data);
|
|
59
|
-
});
|
|
60
|
-
// Now trigger the method that emits the event
|
|
61
|
-
const echoJsResult = await echoJsAbility.echo({
|
|
62
|
-
message: 'I am calling echo-js echo method from Javascript'
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
console.log('Echo-js echo result:', echoJsResult);
|
|
66
|
-
} catch (err) {
|
|
67
|
-
console.error('❌ echo-js failed:', err.message);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// try {
|
|
71
|
-
// console.log('\n🔧 Loading echo-js ability using broker (Javascript)...');
|
|
72
|
-
// let echoJsAbility = await loadAbility('echo-js', 'broker');
|
|
73
|
-
// console.log('Available methods:', echoJsAbility.__list());
|
|
74
|
-
// const echoJsResult = await echoJsAbility.echo({
|
|
75
|
-
// message:
|
|
76
|
-
// 'I am calling echo-js echo method from Javascript - ability speaking through Broker - open your browser to http://kadi.build/network.html to see the network'
|
|
77
|
-
// });
|
|
78
|
-
// console.log('Echo-js ability result:', echoJsResult);
|
|
79
|
-
|
|
80
|
-
// const sayMessageResult = await echoJsAbility.say_message({
|
|
81
|
-
// message: 'I am calling echo-js say_message method from Javascript'
|
|
82
|
-
// });
|
|
83
|
-
// console.log('say_message result:', sayMessageResult);
|
|
84
|
-
// } catch (err) {
|
|
85
|
-
// console.error('❌ echo-js failed:', err.message);
|
|
86
|
-
// }
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Start the agent
|
|
90
|
-
main().catch((err) => {
|
|
91
|
-
// Display a concise, user-friendly message
|
|
92
|
-
console.error('❌ ' + (err?.message || err));
|
|
93
|
-
// Exit gracefully (0) so parent runner does not
|
|
94
|
-
// print an additional stack trace
|
|
95
|
-
process.exit(0);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
// Handle graceful shutdown
|
|
99
|
-
process.on('SIGINT', () => {
|
|
100
|
-
console.log('\nShutting down...');
|
|
101
|
-
process.exit(0);
|
|
102
|
-
});
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "example-agent",
|
|
3
|
-
"version": "0.0.1",
|
|
4
|
-
"lockfileVersion": 3,
|
|
5
|
-
"requires": true,
|
|
6
|
-
"packages": {
|
|
7
|
-
"": {
|
|
8
|
-
"name": "example-agent",
|
|
9
|
-
"version": "0.0.1",
|
|
10
|
-
"license": "ISC",
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"@kadi.build/core": "file:kadi.build-core-0.0.1-alpha.2.tgz"
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
"node_modules/@kadi.build/core": {
|
|
16
|
-
"version": "0.0.1-alpha.2",
|
|
17
|
-
"resolved": "file:kadi.build-core-0.0.1-alpha.2.tgz",
|
|
18
|
-
"integrity": "sha512-CLLvPCq6ZiUWb0pSIIUfBJdpbsB23J8Ie0lZ8OynTO9j98cOfUISMIBo4iL3vgMVA7E0UNf1hD+whVBWQSdqeA==",
|
|
19
|
-
"license": "MIT",
|
|
20
|
-
"dependencies": {
|
|
21
|
-
"chalk": "^5.5.0",
|
|
22
|
-
"debug": "^4.4.1",
|
|
23
|
-
"events": "^3.3.0",
|
|
24
|
-
"ws": "^8.16.0"
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
"node_modules/chalk": {
|
|
28
|
-
"version": "5.6.0",
|
|
29
|
-
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.0.tgz",
|
|
30
|
-
"integrity": "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==",
|
|
31
|
-
"license": "MIT",
|
|
32
|
-
"engines": {
|
|
33
|
-
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
|
34
|
-
},
|
|
35
|
-
"funding": {
|
|
36
|
-
"url": "https://github.com/chalk/chalk?sponsor=1"
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
"node_modules/debug": {
|
|
40
|
-
"version": "4.4.1",
|
|
41
|
-
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
|
|
42
|
-
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
|
|
43
|
-
"license": "MIT",
|
|
44
|
-
"dependencies": {
|
|
45
|
-
"ms": "^2.1.3"
|
|
46
|
-
},
|
|
47
|
-
"engines": {
|
|
48
|
-
"node": ">=6.0"
|
|
49
|
-
},
|
|
50
|
-
"peerDependenciesMeta": {
|
|
51
|
-
"supports-color": {
|
|
52
|
-
"optional": true
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
"node_modules/events": {
|
|
57
|
-
"version": "3.3.0",
|
|
58
|
-
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
|
59
|
-
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
|
|
60
|
-
"license": "MIT",
|
|
61
|
-
"engines": {
|
|
62
|
-
"node": ">=0.8.x"
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
"node_modules/ms": {
|
|
66
|
-
"version": "2.1.3",
|
|
67
|
-
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
|
68
|
-
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
|
69
|
-
"license": "MIT"
|
|
70
|
-
},
|
|
71
|
-
"node_modules/ws": {
|
|
72
|
-
"version": "8.18.3",
|
|
73
|
-
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
|
74
|
-
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
|
75
|
-
"license": "MIT",
|
|
76
|
-
"engines": {
|
|
77
|
-
"node": ">=10.0.0"
|
|
78
|
-
},
|
|
79
|
-
"peerDependencies": {
|
|
80
|
-
"bufferutil": "^4.0.1",
|
|
81
|
-
"utf-8-validate": ">=5.0.2"
|
|
82
|
-
},
|
|
83
|
-
"peerDependenciesMeta": {
|
|
84
|
-
"bufferutil": {
|
|
85
|
-
"optional": true
|
|
86
|
-
},
|
|
87
|
-
"utf-8-validate": {
|
|
88
|
-
"optional": true
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "example-agent",
|
|
3
|
-
"version": "0.0.1",
|
|
4
|
-
"main": "index.js",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"start": "node index.js",
|
|
8
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
9
|
-
},
|
|
10
|
-
"keywords": [],
|
|
11
|
-
"author": "",
|
|
12
|
-
"license": "ISC",
|
|
13
|
-
"description": "",
|
|
14
|
-
"dependencies": {
|
|
15
|
-
"@kadi.build/core": "file:kadi.build-core-0.0.1-alpha.2.tgz"
|
|
16
|
-
}
|
|
17
|
-
}
|
package/src/KadiAbility.js
DELETED
|
@@ -1,478 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'events';
|
|
2
|
-
import { StdioRpcServer } from './servers/StdioRpcServer.js';
|
|
3
|
-
import { BrokerRpcServer } from './servers/BrokerRpcServer.js';
|
|
4
|
-
import fs from 'fs';
|
|
5
|
-
import path from 'path';
|
|
6
|
-
import { createComponentLogger } from './utils/logger.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Factory for creating RPC servers based on protocol
|
|
10
|
-
*/
|
|
11
|
-
class RpcServerFactory {
|
|
12
|
-
static create(protocol, options = {}) {
|
|
13
|
-
switch (protocol?.toLowerCase()) {
|
|
14
|
-
case 'native':
|
|
15
|
-
return undefined; // Native protocol doesn't need an RPC server
|
|
16
|
-
case 'stdio':
|
|
17
|
-
return new StdioRpcServer(options);
|
|
18
|
-
case 'broker':
|
|
19
|
-
return new BrokerRpcServer(options);
|
|
20
|
-
default:
|
|
21
|
-
// Default to stdio for backward compatibility
|
|
22
|
-
return new StdioRpcServer(options);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* KadiAbility - High-level, user-friendly wrapper around RpcServer
|
|
29
|
-
*
|
|
30
|
-
* This class provides a clean API for creating abilities and handles
|
|
31
|
-
* transport selection automatically based on configuration.
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* const ability = new KadiAbility({ name: 'my-ability' });
|
|
35
|
-
* ability
|
|
36
|
-
* .method('doSomething', async (params) => {
|
|
37
|
-
* return { result: 'done' };
|
|
38
|
-
* })
|
|
39
|
-
* .serve();
|
|
40
|
-
*/
|
|
41
|
-
export class KadiAbility extends EventEmitter {
|
|
42
|
-
/**
|
|
43
|
-
* Create a new KadiAbility instance
|
|
44
|
-
*
|
|
45
|
-
* @param {Object} options - Configuration options
|
|
46
|
-
* @param {string} options.name - Ability name
|
|
47
|
-
* @param {string} options.version - Ability version
|
|
48
|
-
* @param {string} options.description - Ability description
|
|
49
|
-
* @param {string} options.scope - Ability scope - Same as the agent's. global if not specified
|
|
50
|
-
* @param {string} options.abilityAgentJSON - Path to the ability agent.json file
|
|
51
|
-
* @param {string} options.protocol - Transport mode: 'stdio' or 'broker'
|
|
52
|
-
*/
|
|
53
|
-
constructor(options = {}) {
|
|
54
|
-
super();
|
|
55
|
-
|
|
56
|
-
// Store basic ability information
|
|
57
|
-
this.name = options.name || 'unnamed-ability';
|
|
58
|
-
this.version = options.version || '1.0.0';
|
|
59
|
-
this.description = options.description || '';
|
|
60
|
-
this.protocol = options.protocol || process.env.KADI_PROTOCOL || 'native';
|
|
61
|
-
this.abilityAgentJSON = options.abilityAgentJSON;
|
|
62
|
-
this.scope = options.scope || 'global';
|
|
63
|
-
|
|
64
|
-
this.logger = createComponentLogger('KadiAbility');
|
|
65
|
-
this.logger.lifecycle(
|
|
66
|
-
'constructor',
|
|
67
|
-
`Creating ability: ${this.name}@${this.version}`
|
|
68
|
-
);
|
|
69
|
-
this.logger.trace('constructor options', {
|
|
70
|
-
name: this.name,
|
|
71
|
-
version: this.version,
|
|
72
|
-
protocol: options.protocol,
|
|
73
|
-
scope: this.scope
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Create RPC server for handling requests for the given protocol
|
|
77
|
-
this.rpcServer = RpcServerFactory.create(this.protocol, {
|
|
78
|
-
maxBufferSize: options.maxBufferSize,
|
|
79
|
-
brokerUrl: options.brokerUrl,
|
|
80
|
-
...options
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
this.methodHandlers = new Map(); // method name -> function
|
|
84
|
-
this.methodMCPSchemas = new Map(); // method name -> schema object
|
|
85
|
-
|
|
86
|
-
// Forward events from RPC server (only if server exists)
|
|
87
|
-
if (this.rpcServer) {
|
|
88
|
-
this.rpcServer.on('start', (data) =>
|
|
89
|
-
this.emit('start', { ...data, protocol: this.protocol })
|
|
90
|
-
);
|
|
91
|
-
this.rpcServer.on('error', (error) => this.emit('error', error));
|
|
92
|
-
this.rpcServer.on('stop', () => this.emit('stop'));
|
|
93
|
-
this.rpcServer.on('request', (data) => this.emit('request', data));
|
|
94
|
-
this.rpcServer.on('response', (data) => this.emit('response', data));
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Register a method with the ability
|
|
100
|
-
*
|
|
101
|
-
* @param {string} name - Method name
|
|
102
|
-
* @param {Function} handler - Handler function that processes the request
|
|
103
|
-
* @param {Object} [optionalMCPSchema] - Optional MCP schema for the method
|
|
104
|
-
* @returns {KadiAbility} - For chaining
|
|
105
|
-
*
|
|
106
|
-
* @example
|
|
107
|
-
* // Simple method
|
|
108
|
-
* ability.method('echo', async ({ message }) => ({ echo: message }));
|
|
109
|
-
*
|
|
110
|
-
* // Method with MCP schema
|
|
111
|
-
* ability.method('format', async ({ text }) => ({ formatted: text.toUpperCase() }), {
|
|
112
|
-
* description: 'Format text to uppercase',
|
|
113
|
-
* inputSchema: {
|
|
114
|
-
* type: 'object',
|
|
115
|
-
* properties: {
|
|
116
|
-
* text: { type: 'string', description: 'Text to format' }
|
|
117
|
-
* },
|
|
118
|
-
* required: ['text']
|
|
119
|
-
* },
|
|
120
|
-
* outputSchema: {
|
|
121
|
-
* type: 'object',
|
|
122
|
-
* properties: {
|
|
123
|
-
* formatted: { type: 'string', description: 'Formatted text' }
|
|
124
|
-
* }
|
|
125
|
-
* }
|
|
126
|
-
* });
|
|
127
|
-
*/
|
|
128
|
-
method(name, handler, optionalMCPSchema) {
|
|
129
|
-
if (typeof name !== 'string') {
|
|
130
|
-
throw new TypeError('Method name must be a string');
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (typeof handler !== 'function') {
|
|
134
|
-
throw new TypeError('Method handler must be a function');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
this.logger.methodCall('method', `Registering method: ${name}`);
|
|
138
|
-
if (optionalMCPSchema) {
|
|
139
|
-
this.logger.trace('method schema', { name, schema: optionalMCPSchema });
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
this.methodHandlers.set(name, handler);
|
|
143
|
-
|
|
144
|
-
if (optionalMCPSchema) {
|
|
145
|
-
this.methodMCPSchemas.set(name, optionalMCPSchema);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return this;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Publish an event to the connected agent/parent process
|
|
153
|
-
*
|
|
154
|
-
* Events are fire-and-forget notifications that flow from ability to agent.
|
|
155
|
-
* The transport layer determines how events are delivered:
|
|
156
|
-
* - Native: Direct EventEmitter (in-process)
|
|
157
|
-
* - Stdio: JSON-RPC notification with __kadi_event method
|
|
158
|
-
* - Broker: kadi.event message via WebSocket
|
|
159
|
-
*
|
|
160
|
-
* @param {string} eventName - Name of the event to publish
|
|
161
|
-
* @param {any} data - Event data payload (should be JSON-serializable for remote transports)
|
|
162
|
-
* @returns {void}
|
|
163
|
-
*
|
|
164
|
-
* @example
|
|
165
|
-
* // Publish a simple event
|
|
166
|
-
* ability.publishEvent('server:started', { port: 3000 });
|
|
167
|
-
*
|
|
168
|
-
* // Publish progress updates
|
|
169
|
-
* ability.publishEvent('download:progress', {
|
|
170
|
-
* file: 'data.zip',
|
|
171
|
-
* progress: 0.75,
|
|
172
|
-
* bytesDownloaded: 75000,
|
|
173
|
-
* totalBytes: 100000
|
|
174
|
-
* });
|
|
175
|
-
*
|
|
176
|
-
* // Publish error events
|
|
177
|
-
* ability.publishEvent('error', {
|
|
178
|
-
* message: 'Connection failed',
|
|
179
|
-
* code: 'ECONNREFUSED'
|
|
180
|
-
* });
|
|
181
|
-
*/
|
|
182
|
-
publishEvent(eventName, data = {}) {
|
|
183
|
-
if (typeof eventName !== 'string' || !eventName) {
|
|
184
|
-
throw new TypeError('Event name must be a non-empty string');
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
this.logger.trace('publishEvent', `Publishing event: ${eventName}`);
|
|
188
|
-
this.logger.trace('publishEvent data', { eventName, data });
|
|
189
|
-
|
|
190
|
-
// For native protocol, emit directly on this EventEmitter
|
|
191
|
-
// The agent will have direct access to this instance
|
|
192
|
-
if (this.protocol === 'native') {
|
|
193
|
-
this.logger.trace('publishEvent', 'Using native EventEmitter for event');
|
|
194
|
-
// Emit with a special prefix to distinguish from internal events
|
|
195
|
-
this.emit('ability:event', { eventName, data });
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// For remote protocols, delegate to the RPC server
|
|
200
|
-
if (this.rpcServer && typeof this.rpcServer.publishEvent === 'function') {
|
|
201
|
-
this.logger.trace(
|
|
202
|
-
'publishEvent',
|
|
203
|
-
`Delegating to ${this.protocol} RPC server`
|
|
204
|
-
);
|
|
205
|
-
this.rpcServer.publishEvent(eventName, data);
|
|
206
|
-
} else {
|
|
207
|
-
this.logger.warn(
|
|
208
|
-
'publishEvent',
|
|
209
|
-
`Cannot publish event: RPC server (${this.protocol}) does not support event publishing`
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Get all registered method names (excluding internal methods)
|
|
216
|
-
*/
|
|
217
|
-
getMethodNames() {
|
|
218
|
-
return Array.from(this.methodHandlers.keys()).filter(
|
|
219
|
-
(name) => !name.startsWith('__kadi_')
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Check if a method is registered
|
|
225
|
-
*/
|
|
226
|
-
hasMethod(name) {
|
|
227
|
-
return this.methodHandlers.has(name);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Get method handler
|
|
232
|
-
*/
|
|
233
|
-
getMethodHandler(name) {
|
|
234
|
-
return this.methodHandlers.get(name);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Get method schema (if available)
|
|
239
|
-
*/
|
|
240
|
-
getMethodSchema(name) {
|
|
241
|
-
return this.methodMCPSchemas.get(name);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Extract tool definitions for broker capability registration
|
|
246
|
-
* Combines schemas from agent.json exports and inline schemas
|
|
247
|
-
*
|
|
248
|
-
* @returns {Array<Object>} - Array of tool definitions for broker
|
|
249
|
-
*/
|
|
250
|
-
async extractToolsForBroker() {
|
|
251
|
-
this.logger.methodCall(
|
|
252
|
-
'extractToolsForBroker',
|
|
253
|
-
'Extracting tools for broker registration'
|
|
254
|
-
);
|
|
255
|
-
|
|
256
|
-
const tools = [];
|
|
257
|
-
|
|
258
|
-
// console.error(`Registered handlers: ${Array.from(this.methodHandlers.keys())}`);
|
|
259
|
-
// console.error(`Schema map: ${Array.from(this.methodMCPSchemas.entries())}`);
|
|
260
|
-
|
|
261
|
-
// 1. Try to load agent.json exports
|
|
262
|
-
const agentJsonExports = await this._loadAgentJsonExports();
|
|
263
|
-
|
|
264
|
-
this.logger.trace(
|
|
265
|
-
'extractToolsForBroker',
|
|
266
|
-
`Loaded ${agentJsonExports.length} exports from agent.json`
|
|
267
|
-
);
|
|
268
|
-
|
|
269
|
-
// 2. Build tools array from registered methods
|
|
270
|
-
for (const [methodName, handler] of this.methodHandlers) {
|
|
271
|
-
if (methodName.startsWith('__kadi_')) continue; // Skip internal methods
|
|
272
|
-
|
|
273
|
-
let schema = this.methodMCPSchemas.get(methodName);
|
|
274
|
-
|
|
275
|
-
// Resolve schema source
|
|
276
|
-
if (!schema) {
|
|
277
|
-
// Look in agent.json exports
|
|
278
|
-
schema = agentJsonExports.find((exp) => exp.name === methodName);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (!schema) {
|
|
282
|
-
this.logger.warn(
|
|
283
|
-
'extractToolsForBroker',
|
|
284
|
-
`No schema found for method '${methodName}', skipping broker registration`
|
|
285
|
-
);
|
|
286
|
-
|
|
287
|
-
continue;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
tools.push({
|
|
291
|
-
name: methodName,
|
|
292
|
-
description: schema.description || `Execute ${methodName}`,
|
|
293
|
-
inputSchema: schema.inputSchema || { type: 'object' },
|
|
294
|
-
outputSchema: schema.outputSchema
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
this.logger.success(
|
|
299
|
-
'extractToolsForBroker',
|
|
300
|
-
`Extracted ${tools.length} tools for broker`
|
|
301
|
-
);
|
|
302
|
-
return tools;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Start serving requests
|
|
307
|
-
*
|
|
308
|
-
* @param {Object} options - Serve options
|
|
309
|
-
* @param {string} options.mode - Override transport mode
|
|
310
|
-
* @returns {Promise<void>}
|
|
311
|
-
*/
|
|
312
|
-
async serve(options = {}) {
|
|
313
|
-
this.logger.lifecycle('serve', `Starting to serve ability: ${this.name}`);
|
|
314
|
-
this.logger.info(
|
|
315
|
-
'serve',
|
|
316
|
-
`Protocol: ${this.protocol}, Methods: ${this.getMethodNames().join(', ')}`
|
|
317
|
-
);
|
|
318
|
-
try {
|
|
319
|
-
// Override protocol if specified in options
|
|
320
|
-
if (options.mode && options.mode !== this.protocol) {
|
|
321
|
-
this.logger.info(
|
|
322
|
-
'serve',
|
|
323
|
-
`Protocol override: ${this.protocol} -> ${options.mode}`
|
|
324
|
-
);
|
|
325
|
-
|
|
326
|
-
this.protocol = options.mode;
|
|
327
|
-
this.rpcServer = RpcServerFactory.create(this.protocol, options);
|
|
328
|
-
|
|
329
|
-
// Re-wire events for new server (only if server exists)
|
|
330
|
-
if (this.rpcServer) {
|
|
331
|
-
this.rpcServer.on('start', (data) =>
|
|
332
|
-
this.emit('start', { ...data, protocol: this.protocol })
|
|
333
|
-
);
|
|
334
|
-
this.rpcServer.on('error', (error) => this.emit('error', error));
|
|
335
|
-
this.rpcServer.on('stop', () => this.emit('stop'));
|
|
336
|
-
this.rpcServer.on('request', (data) => this.emit('request', data));
|
|
337
|
-
this.rpcServer.on('response', (data) => this.emit('response', data));
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Start serving this ability using the RPC server (if it exists)
|
|
342
|
-
if (this.rpcServer) {
|
|
343
|
-
await this.rpcServer.serve(this);
|
|
344
|
-
this.logger.success(
|
|
345
|
-
'serve',
|
|
346
|
-
`Successfully started serving ${this.name} via ${this.protocol}`
|
|
347
|
-
);
|
|
348
|
-
} else {
|
|
349
|
-
// For native protocol, just emit start event and keep running
|
|
350
|
-
this.logger.success(
|
|
351
|
-
'serve',
|
|
352
|
-
`Successfully started serving ${this.name} via ${this.protocol} (native mode)`
|
|
353
|
-
);
|
|
354
|
-
this.emit('start', {
|
|
355
|
-
protocol: this.protocol,
|
|
356
|
-
methods: this.getMethodNames()
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
// Keep the process alive for native protocol
|
|
360
|
-
// This allows the ability to be imported and used directly
|
|
361
|
-
return new Promise(() => {
|
|
362
|
-
// Never resolve - keep the process running
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
} catch (error) {
|
|
366
|
-
this.logError('Failed to start serving', { error: error.message });
|
|
367
|
-
this.emit('error', error);
|
|
368
|
-
throw error;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Log a message to stderr (safe for stdio mode since stdout is used for RPC)
|
|
374
|
-
*
|
|
375
|
-
* @param {...any} args - Arguments to log
|
|
376
|
-
*/
|
|
377
|
-
log(...args) {
|
|
378
|
-
this.logger.info('general', args.join(' '));
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* Log an error to stderr
|
|
383
|
-
*
|
|
384
|
-
* @param {...any} args - Arguments to log
|
|
385
|
-
*/
|
|
386
|
-
logError(...args) {
|
|
387
|
-
this.logger.error('general', args.join(' '));
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Load exports from agent.json file
|
|
392
|
-
*
|
|
393
|
-
* @returns {Array<Object>} - Array of export definitions
|
|
394
|
-
* @private
|
|
395
|
-
*/
|
|
396
|
-
async _loadAgentJsonExports() {
|
|
397
|
-
this.logger.methodCall(
|
|
398
|
-
'_loadAgentJsonExports',
|
|
399
|
-
'Loading agent.json exports'
|
|
400
|
-
);
|
|
401
|
-
try {
|
|
402
|
-
const agentJsonPath = await this._findAgentJson();
|
|
403
|
-
|
|
404
|
-
this.logger.trace(
|
|
405
|
-
'_loadAgentJsonExports',
|
|
406
|
-
`Found agent.json at: ${agentJsonPath}`
|
|
407
|
-
);
|
|
408
|
-
|
|
409
|
-
const agentJson = JSON.parse(fs.readFileSync(agentJsonPath, 'utf8'));
|
|
410
|
-
|
|
411
|
-
const exportCount = agentJson.exports?.length || 0;
|
|
412
|
-
this.logger.success(
|
|
413
|
-
'_loadAgentJsonExports',
|
|
414
|
-
`Loaded ${exportCount} exports`
|
|
415
|
-
);
|
|
416
|
-
|
|
417
|
-
return agentJson.exports || [];
|
|
418
|
-
} catch (err) {
|
|
419
|
-
this.logger.warn(
|
|
420
|
-
'_loadAgentJsonExports',
|
|
421
|
-
`Could not load agent.json exports: ${err.message}`
|
|
422
|
-
);
|
|
423
|
-
|
|
424
|
-
return [];
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Find agent.json file in current directory or parent directories
|
|
430
|
-
*
|
|
431
|
-
* @returns {string} - Path to agent.json file
|
|
432
|
-
* @private
|
|
433
|
-
*/
|
|
434
|
-
async _findAgentJson() {
|
|
435
|
-
this.logger.methodCall('_findAgentJson', 'Searching for agent.json file');
|
|
436
|
-
this.logger.trace(
|
|
437
|
-
'_findAgentJson',
|
|
438
|
-
`Current working directory: ${process.cwd()}`
|
|
439
|
-
);
|
|
440
|
-
|
|
441
|
-
const possiblePaths = [
|
|
442
|
-
// Use explicit path if provided
|
|
443
|
-
this.abilityAgentJSON,
|
|
444
|
-
// Standard locations
|
|
445
|
-
path.join(process.cwd(), 'agent.json'),
|
|
446
|
-
path.join(path.dirname(process.argv[1]), 'agent.json'), // Same directory as the script
|
|
447
|
-
path.join(process.cwd(), '..', 'agent.json'),
|
|
448
|
-
path.join(process.cwd(), '..', '..', 'agent.json')
|
|
449
|
-
].filter(Boolean); // Remove undefined entries
|
|
450
|
-
|
|
451
|
-
this.logger.trace(
|
|
452
|
-
'_findAgentJson',
|
|
453
|
-
`Checking paths: ${possiblePaths.join(', ')}`
|
|
454
|
-
);
|
|
455
|
-
|
|
456
|
-
for (const agentPath of possiblePaths) {
|
|
457
|
-
this.logger.trace('_findAgentJson', `Checking: ${agentPath}`);
|
|
458
|
-
|
|
459
|
-
if (fs.existsSync(agentPath)) {
|
|
460
|
-
this.logger.success(
|
|
461
|
-
'_findAgentJson',
|
|
462
|
-
`Found agent.json at: ${agentPath}`
|
|
463
|
-
);
|
|
464
|
-
|
|
465
|
-
return agentPath;
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
this.logger.error(
|
|
470
|
-
'_findAgentJson',
|
|
471
|
-
'agent.json not found in any checked locations'
|
|
472
|
-
);
|
|
473
|
-
|
|
474
|
-
throw new Error('agent.json not found in any of the checked locations');
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
export default KadiAbility;
|