@nullbridge/sdk 1.0.3 → 1.0.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/package.json +1 -1
- package/src/agents.js +72 -17
package/package.json
CHANGED
package/src/agents.js
CHANGED
|
@@ -9,34 +9,36 @@ class AgentRegistry {
|
|
|
9
9
|
constructor(config, http) {
|
|
10
10
|
this._config = config;
|
|
11
11
|
this._http = http;
|
|
12
|
-
this._agents = new Map();
|
|
12
|
+
this._agents = new Map();
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Register a new AI agent with NullBridge.
|
|
17
17
|
*
|
|
18
18
|
* @param {object} options
|
|
19
|
+
* @param {string} [options.id] - Stable unique identifier. Auto-generated if omitted.
|
|
19
20
|
* @param {string} options.name - Human-readable agent name (e.g. 'claims-processor')
|
|
20
21
|
* @param {string} options.type - Agent type: 'llm' | 'rpa' | 'workflow' | 'custom'
|
|
21
22
|
* @param {string} [options.model] - Model name (e.g. 'gpt-4o', 'claude-3-5-sonnet')
|
|
22
|
-
* @param {string[]} [options.scopes] -
|
|
23
|
-
* @param {object} [options.metadata] -
|
|
23
|
+
* @param {string[]} [options.scopes] - Permission scopes (e.g. ['read:claims', 'write:reports'])
|
|
24
|
+
* @param {object} [options.metadata] - Additional metadata
|
|
25
|
+
* @param {number} [options.heartbeatInterval] - Heartbeat interval in ms (default: 60000)
|
|
24
26
|
* @returns {Promise<Agent>}
|
|
25
27
|
*/
|
|
26
28
|
async register(options = {}) {
|
|
27
29
|
if (!options.name) throw new Error('[NullBridge] agent.name is required');
|
|
28
30
|
if (!options.type) throw new Error('[NullBridge] agent.type is required');
|
|
29
31
|
|
|
30
|
-
const agentId = this._generateAgentId(options.name);
|
|
32
|
+
const agentId = options.id || this._generateAgentId(options.name);
|
|
31
33
|
|
|
32
34
|
const payload = {
|
|
33
|
-
id:
|
|
34
|
-
name:
|
|
35
|
-
type:
|
|
36
|
-
model:
|
|
37
|
-
scopes:
|
|
38
|
-
metadata:
|
|
39
|
-
sdk_version:
|
|
35
|
+
id: agentId,
|
|
36
|
+
name: options.name,
|
|
37
|
+
type: options.type,
|
|
38
|
+
model: options.model || null,
|
|
39
|
+
scopes: options.scopes || [],
|
|
40
|
+
metadata: options.metadata || {},
|
|
41
|
+
sdk_version: '1.0.3',
|
|
40
42
|
registered_at: Math.floor(Date.now() / 1000),
|
|
41
43
|
};
|
|
42
44
|
|
|
@@ -47,13 +49,20 @@ class AgentRegistry {
|
|
|
47
49
|
{ license_key: this._config.licenseKey, agent: payload }
|
|
48
50
|
);
|
|
49
51
|
|
|
50
|
-
const agent = status === 200 || status === 201
|
|
52
|
+
const agent = (status === 200 || status === 201)
|
|
51
53
|
? { ...payload, ...body.agent, _registered: true }
|
|
52
54
|
: { ...payload, _registered: false, _local: true };
|
|
53
55
|
|
|
54
56
|
this._agents.set(agentId, agent);
|
|
55
57
|
console.info(`[NullBridge] Agent registered: ${options.name} (${agentId})`);
|
|
56
|
-
|
|
58
|
+
|
|
59
|
+
const instance = new Agent(agent, this._config, this._http);
|
|
60
|
+
|
|
61
|
+
// Start heartbeat automatically
|
|
62
|
+
const heartbeatMs = options.heartbeatInterval || 60000;
|
|
63
|
+
instance.startHeartbeat(heartbeatMs);
|
|
64
|
+
|
|
65
|
+
return instance;
|
|
57
66
|
|
|
58
67
|
} catch (err) {
|
|
59
68
|
// API unreachable — register locally and continue
|
|
@@ -103,9 +112,10 @@ class AgentRegistry {
|
|
|
103
112
|
*/
|
|
104
113
|
class Agent {
|
|
105
114
|
constructor(data, config, http) {
|
|
106
|
-
this._data
|
|
107
|
-
this._config
|
|
108
|
-
this._http
|
|
115
|
+
this._data = data;
|
|
116
|
+
this._config = config;
|
|
117
|
+
this._http = http;
|
|
118
|
+
this._heartbeatTimer = null;
|
|
109
119
|
|
|
110
120
|
// Expose agent properties
|
|
111
121
|
this.id = data.id;
|
|
@@ -166,9 +176,10 @@ class Agent {
|
|
|
166
176
|
}
|
|
167
177
|
|
|
168
178
|
/**
|
|
169
|
-
* Deregister this agent — revokes its identity and
|
|
179
|
+
* Deregister this agent — revokes its identity and stops heartbeat
|
|
170
180
|
*/
|
|
171
181
|
async deregister() {
|
|
182
|
+
this.stopHeartbeat();
|
|
172
183
|
try {
|
|
173
184
|
await this._http.post(
|
|
174
185
|
this._config.apiUrl,
|
|
@@ -181,6 +192,50 @@ class Agent {
|
|
|
181
192
|
}
|
|
182
193
|
}
|
|
183
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Send a heartbeat to update last_seen in the dashboard.
|
|
197
|
+
* Called automatically by startHeartbeat() — you don't need to call this manually.
|
|
198
|
+
*/
|
|
199
|
+
async heartbeat() {
|
|
200
|
+
try {
|
|
201
|
+
await this._http.post(
|
|
202
|
+
this._config.apiUrl,
|
|
203
|
+
`/sdk/agents/${this.id}/heartbeat`,
|
|
204
|
+
{ license_key: this._config.licenseKey }
|
|
205
|
+
);
|
|
206
|
+
if (this._config.debug) {
|
|
207
|
+
console.debug(`[NullBridge] Heartbeat sent: ${this.name}`);
|
|
208
|
+
}
|
|
209
|
+
} catch {
|
|
210
|
+
// Silently fail — heartbeat is best-effort
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Start sending periodic heartbeats to keep last_seen current in the dashboard.
|
|
216
|
+
* Called automatically after register(). You only need this if you stopped it manually.
|
|
217
|
+
*
|
|
218
|
+
* @param {number} [intervalMs=60000] - How often to ping in milliseconds
|
|
219
|
+
*/
|
|
220
|
+
startHeartbeat(intervalMs = 60000) {
|
|
221
|
+
if (this._heartbeatTimer) return; // already running
|
|
222
|
+
// Send immediately on start
|
|
223
|
+
this.heartbeat();
|
|
224
|
+
this._heartbeatTimer = setInterval(() => this.heartbeat(), intervalMs);
|
|
225
|
+
// Allow Node.js to exit even if heartbeat is still running
|
|
226
|
+
if (this._heartbeatTimer.unref) this._heartbeatTimer.unref();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Stop sending heartbeats. Called automatically by deregister() and shutdown().
|
|
231
|
+
*/
|
|
232
|
+
stopHeartbeat() {
|
|
233
|
+
if (this._heartbeatTimer) {
|
|
234
|
+
clearInterval(this._heartbeatTimer);
|
|
235
|
+
this._heartbeatTimer = null;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
184
239
|
toJSON() {
|
|
185
240
|
return {
|
|
186
241
|
id: this.id, name: this.name, type: this.type,
|