@kadi.build/core 0.7.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -0
- package/dist/client.d.ts +16 -7
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +113 -142
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/protocol.d.ts +49 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +109 -0
- package/dist/protocol.js.map +1 -0
- package/dist/transports/stdio.d.ts.map +1 -1
- package/dist/transports/stdio.js +2 -6
- package/dist/transports/stdio.js.map +1 -1
- package/dist/types.d.ts +61 -23
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +143 -145
- package/src/index.ts +7 -1
- package/src/protocol.ts +161 -0
- package/src/transports/stdio.ts +2 -6
- package/src/types.ts +58 -25
package/src/protocol.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KADI Protocol Message Builders
|
|
3
|
+
* ==============================
|
|
4
|
+
*
|
|
5
|
+
* Pure functions that construct JSON-RPC 2.0 message objects for the KADI protocol.
|
|
6
|
+
*
|
|
7
|
+
* All functions return typed objects ready for `JSON.stringify()`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import * as protocol from './protocol.js';
|
|
12
|
+
*
|
|
13
|
+
* const msg = protocol.heartbeat(1);
|
|
14
|
+
* ws.send(JSON.stringify(msg));
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Python Equivalent:
|
|
18
|
+
* kadi-core-py/src/kadi/protocol.py
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type { JsonRpcNotification, JsonRpcRequest, JsonRpcResponse } from './types.js';
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Generic request builder
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
/** Build a standard JSON-RPC 2.0 request. */
|
|
28
|
+
export function request(id: string | number, method: string, params: unknown): JsonRpcRequest {
|
|
29
|
+
return { jsonrpc: '2.0', id, method, params };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ===========================================================================
|
|
33
|
+
// Session
|
|
34
|
+
// ===========================================================================
|
|
35
|
+
|
|
36
|
+
/** Build a `kadi.session.hello` request. */
|
|
37
|
+
export function hello(id: number): JsonRpcRequest {
|
|
38
|
+
return request(id, 'kadi.session.hello', { role: 'agent' });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Build a `kadi.session.authenticate` request. */
|
|
42
|
+
export function authenticate(
|
|
43
|
+
id: number,
|
|
44
|
+
publicKey: string,
|
|
45
|
+
signature: string,
|
|
46
|
+
nonce: string,
|
|
47
|
+
): JsonRpcRequest {
|
|
48
|
+
return request(id, 'kadi.session.authenticate', { publicKey, signature, nonce });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Build a `kadi.session.heartbeat` request. */
|
|
52
|
+
export function heartbeat(id: number): JsonRpcRequest {
|
|
53
|
+
return request(id, 'kadi.session.heartbeat', { timestamp: Date.now() });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ===========================================================================
|
|
57
|
+
// Agent
|
|
58
|
+
// ===========================================================================
|
|
59
|
+
|
|
60
|
+
/** Build a `kadi.agent.register` request. */
|
|
61
|
+
export function register(
|
|
62
|
+
id: number,
|
|
63
|
+
tools: unknown[],
|
|
64
|
+
networks: string[],
|
|
65
|
+
displayName?: string,
|
|
66
|
+
): JsonRpcRequest {
|
|
67
|
+
const params: Record<string, unknown> = { tools, networks };
|
|
68
|
+
if (displayName !== undefined) {
|
|
69
|
+
params.displayName = displayName;
|
|
70
|
+
}
|
|
71
|
+
return request(id, 'kadi.agent.register', params);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ===========================================================================
|
|
75
|
+
// Ability
|
|
76
|
+
// ===========================================================================
|
|
77
|
+
|
|
78
|
+
/** Build a `kadi.ability.request` request. */
|
|
79
|
+
export function abilityRequest(
|
|
80
|
+
id: number,
|
|
81
|
+
toolName: string,
|
|
82
|
+
toolInput: unknown,
|
|
83
|
+
requestId: string,
|
|
84
|
+
timeout?: number,
|
|
85
|
+
): JsonRpcRequest {
|
|
86
|
+
const params: Record<string, unknown> = { toolName, toolInput, requestId };
|
|
87
|
+
if (timeout !== undefined) {
|
|
88
|
+
params.timeout = timeout;
|
|
89
|
+
}
|
|
90
|
+
return request(id, 'kadi.ability.request', params);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Build a `kadi.ability.list` request. */
|
|
94
|
+
export function abilityList(
|
|
95
|
+
id: number,
|
|
96
|
+
networks: string[],
|
|
97
|
+
includeProviders = true,
|
|
98
|
+
): JsonRpcRequest {
|
|
99
|
+
return request(id, 'kadi.ability.list', { networks, includeProviders });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ===========================================================================
|
|
103
|
+
// Event
|
|
104
|
+
// ===========================================================================
|
|
105
|
+
|
|
106
|
+
/** Build a `kadi.event.subscribe` request. */
|
|
107
|
+
export function eventSubscribe(id: number, pattern: string): JsonRpcRequest {
|
|
108
|
+
return request(id, 'kadi.event.subscribe', { pattern });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Build a `kadi.event.unsubscribe` request. */
|
|
112
|
+
export function eventUnsubscribe(id: number, pattern: string): JsonRpcRequest {
|
|
113
|
+
return request(id, 'kadi.event.unsubscribe', { pattern });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Build a `kadi.event.publish` request. */
|
|
117
|
+
export function eventPublish(
|
|
118
|
+
id: number,
|
|
119
|
+
channel: string,
|
|
120
|
+
data: unknown,
|
|
121
|
+
networkId: string,
|
|
122
|
+
): JsonRpcRequest {
|
|
123
|
+
return request(id, 'kadi.event.publish', { channel, data, networkId });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ===========================================================================
|
|
127
|
+
// Response (JSON-RPC result/error envelopes)
|
|
128
|
+
// ===========================================================================
|
|
129
|
+
|
|
130
|
+
/** Build a JSON-RPC 2.0 success response. */
|
|
131
|
+
export function resultResponse(id: string | number, result: unknown): JsonRpcResponse {
|
|
132
|
+
return { jsonrpc: '2.0', id, result };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Build a JSON-RPC 2.0 error response. */
|
|
136
|
+
export function errorResponse(
|
|
137
|
+
id: string | number,
|
|
138
|
+
code: number,
|
|
139
|
+
message: string,
|
|
140
|
+
data?: unknown,
|
|
141
|
+
): JsonRpcResponse {
|
|
142
|
+
const error: { code: number; message: string; data?: unknown } = { code, message };
|
|
143
|
+
if (data !== undefined) {
|
|
144
|
+
error.data = data;
|
|
145
|
+
}
|
|
146
|
+
return { jsonrpc: '2.0', id, error };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ===========================================================================
|
|
150
|
+
// Stdio
|
|
151
|
+
// ===========================================================================
|
|
152
|
+
|
|
153
|
+
/** Build a `readAgentJson` request for stdio transport. */
|
|
154
|
+
export function readAgentJson(id: number): JsonRpcRequest {
|
|
155
|
+
return request(id, 'readAgentJson', {});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Build an `event` notification (no `id` field). */
|
|
159
|
+
export function eventNotification(name: string, data: unknown): JsonRpcNotification {
|
|
160
|
+
return { jsonrpc: '2.0', method: 'event', params: { name, data } };
|
|
161
|
+
}
|
package/src/transports/stdio.ts
CHANGED
|
@@ -23,6 +23,7 @@ import type { Readable, Writable } from 'stream';
|
|
|
23
23
|
import { z } from 'zod';
|
|
24
24
|
import type { LoadedAbility, InvokeOptions, ToolDefinition, JsonRpcRequest, JsonRpcResponse, EventHandler } from '../types.js';
|
|
25
25
|
import { KadiError } from '../errors.js';
|
|
26
|
+
import * as protocol from '../protocol.js';
|
|
26
27
|
|
|
27
28
|
/** Schema for event notification params */
|
|
28
29
|
const EventNotificationParams = z.object({
|
|
@@ -393,12 +394,7 @@ export async function loadStdioTransport(
|
|
|
393
394
|
}
|
|
394
395
|
|
|
395
396
|
const id = idCounter++;
|
|
396
|
-
const request
|
|
397
|
-
jsonrpc: '2.0',
|
|
398
|
-
id,
|
|
399
|
-
method,
|
|
400
|
-
params,
|
|
401
|
-
};
|
|
397
|
+
const request = protocol.request(id, method, params);
|
|
402
398
|
|
|
403
399
|
writer.write(request);
|
|
404
400
|
const response = await reader.waitForResponse(id, timeoutMs);
|
package/src/types.ts
CHANGED
|
@@ -27,6 +27,30 @@ export type JSONSchema = JSONSchemaTypes.JSONSchema;
|
|
|
27
27
|
// 1. CONFIGURATION
|
|
28
28
|
// ═══════════════════════════════════════════════════════════════════════
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Per-broker connection configuration.
|
|
32
|
+
*
|
|
33
|
+
* Use this when different brokers should join different networks.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* brokers: {
|
|
38
|
+
* local: { url: 'ws://localhost:8080/kadi', networks: ['private', 'public'] },
|
|
39
|
+
* remote: { url: 'wss://remote/kadi', networks: ['public'] },
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export interface BrokerEntry {
|
|
44
|
+
/** WebSocket URL for this broker */
|
|
45
|
+
url: string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Networks to join on this broker.
|
|
49
|
+
* Defaults to `['global']` if omitted.
|
|
50
|
+
*/
|
|
51
|
+
networks?: string[];
|
|
52
|
+
}
|
|
53
|
+
|
|
30
54
|
/**
|
|
31
55
|
* Configuration options for creating a KadiClient.
|
|
32
56
|
*
|
|
@@ -36,8 +60,8 @@ export type JSONSchema = JSONSchemaTypes.JSONSchema;
|
|
|
36
60
|
* name: 'my-agent',
|
|
37
61
|
* version: '1.0.0',
|
|
38
62
|
* brokers: {
|
|
39
|
-
* prod: 'ws://broker-prod:8080',
|
|
40
|
-
* internal: 'ws://broker-internal:8080',
|
|
63
|
+
* prod: { url: 'ws://broker-prod:8080/kadi', networks: ['public'] },
|
|
64
|
+
* internal: { url: 'ws://broker-internal:8080/kadi', networks: ['private'] },
|
|
41
65
|
* },
|
|
42
66
|
* defaultBroker: 'prod',
|
|
43
67
|
* });
|
|
@@ -55,17 +79,17 @@ export interface ClientConfig {
|
|
|
55
79
|
|
|
56
80
|
/**
|
|
57
81
|
* Named brokers to connect to.
|
|
58
|
-
* Keys are friendly names, values are
|
|
82
|
+
* Keys are friendly names, values are BrokerEntry objects.
|
|
59
83
|
*
|
|
60
84
|
* @example
|
|
61
85
|
* ```typescript
|
|
62
86
|
* brokers: {
|
|
63
|
-
*
|
|
64
|
-
*
|
|
87
|
+
* local: { url: 'ws://localhost:8080/kadi', networks: ['private'] },
|
|
88
|
+
* remote: { url: 'wss://remote/kadi', networks: ['public'] },
|
|
65
89
|
* }
|
|
66
90
|
* ```
|
|
67
91
|
*/
|
|
68
|
-
brokers?: Record<string,
|
|
92
|
+
brokers?: Record<string, BrokerEntry>;
|
|
69
93
|
|
|
70
94
|
/**
|
|
71
95
|
* Which broker to use by default for invokeRemote() and loadBroker().
|
|
@@ -73,13 +97,6 @@ export interface ClientConfig {
|
|
|
73
97
|
*/
|
|
74
98
|
defaultBroker?: string;
|
|
75
99
|
|
|
76
|
-
/**
|
|
77
|
-
* Networks this agent belongs to.
|
|
78
|
-
* Used for filtering when discovering abilities.
|
|
79
|
-
* Default: ['global']
|
|
80
|
-
*/
|
|
81
|
-
networks?: string[];
|
|
82
|
-
|
|
83
100
|
/**
|
|
84
101
|
* Heartbeat interval in milliseconds.
|
|
85
102
|
* Broker expects heartbeats to stay connected.
|
|
@@ -147,9 +164,9 @@ export interface ResolvedConfig {
|
|
|
147
164
|
name: string;
|
|
148
165
|
version: string;
|
|
149
166
|
description: string;
|
|
150
|
-
|
|
167
|
+
/** Normalized broker configs. Each entry has a url and resolved networks array. */
|
|
168
|
+
brokers: Record<string, { url: string; networks: string[] }>;
|
|
151
169
|
defaultBroker: string | undefined;
|
|
152
|
-
networks: string[];
|
|
153
170
|
heartbeatInterval: number;
|
|
154
171
|
requestTimeout: number;
|
|
155
172
|
autoReconnect: boolean;
|
|
@@ -178,6 +195,15 @@ export interface ToolDefinition {
|
|
|
178
195
|
outputSchema?: JSONSchema;
|
|
179
196
|
}
|
|
180
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Tool definition extended with optional per-tool network scoping.
|
|
200
|
+
* Used when sending tool definitions to brokers and in readAgentJson().
|
|
201
|
+
*/
|
|
202
|
+
export interface BrokerToolDefinition extends ToolDefinition {
|
|
203
|
+
/** Networks this tool is visible on (omitted if visible on all client networks) */
|
|
204
|
+
networks?: string[];
|
|
205
|
+
}
|
|
206
|
+
|
|
181
207
|
/**
|
|
182
208
|
* Tool definition using Zod schemas.
|
|
183
209
|
* Recommended approach - provides type inference.
|
|
@@ -280,11 +306,8 @@ export interface RegisteredTool {
|
|
|
280
306
|
/** The handler function */
|
|
281
307
|
handler: ToolHandler;
|
|
282
308
|
|
|
283
|
-
/**
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
/** Which brokers this tool is registered with (empty = all) */
|
|
287
|
-
targetBrokers: string[];
|
|
309
|
+
/** Per-broker network targeting (empty = all brokers, all networks) */
|
|
310
|
+
brokerNetworks: Record<string, { networks: string[] }>;
|
|
288
311
|
}
|
|
289
312
|
|
|
290
313
|
/**
|
|
@@ -476,6 +499,9 @@ export interface BrokerState {
|
|
|
476
499
|
/** WebSocket URL */
|
|
477
500
|
url: string;
|
|
478
501
|
|
|
502
|
+
/** Networks this broker connection has joined */
|
|
503
|
+
networks: string[];
|
|
504
|
+
|
|
479
505
|
/** WebSocket connection (null if disconnected) */
|
|
480
506
|
ws: WebSocket | null;
|
|
481
507
|
|
|
@@ -721,16 +747,23 @@ export interface AbilityLockEntry {
|
|
|
721
747
|
*/
|
|
722
748
|
export interface RegisterToolOptions {
|
|
723
749
|
/**
|
|
724
|
-
*
|
|
725
|
-
*
|
|
750
|
+
* Per-broker network scoping.
|
|
751
|
+
* Keys are broker names, values specify which networks to register on for that broker.
|
|
752
|
+
* Each broker name must exist in client's configured brokers.
|
|
753
|
+
* Each network list must be a subset of that specific broker's networks.
|
|
754
|
+
* If not specified, registers with ALL brokers on ALL their networks.
|
|
726
755
|
*
|
|
727
756
|
* @example
|
|
728
757
|
* ```typescript
|
|
729
|
-
*
|
|
730
|
-
*
|
|
758
|
+
* client.registerTool(def, handler, {
|
|
759
|
+
* brokers: {
|
|
760
|
+
* local: { networks: ['private'] },
|
|
761
|
+
* remote: { networks: ['sensitive'] },
|
|
762
|
+
* },
|
|
763
|
+
* });
|
|
731
764
|
* ```
|
|
732
765
|
*/
|
|
733
|
-
brokers?: string[]
|
|
766
|
+
brokers?: Record<string, { networks: string[] }>;
|
|
734
767
|
}
|
|
735
768
|
|
|
736
769
|
/**
|