@tbrandenburg/node-red-agents 0.1.5 → 0.3.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/nodes/agent/agent.html
CHANGED
|
@@ -84,6 +84,9 @@
|
|
|
84
84
|
runtime: { value: 'direct' },
|
|
85
85
|
invocation: { value: 'prompt' },
|
|
86
86
|
|
|
87
|
+
agentName: { value: '' },
|
|
88
|
+
agentNameType: { value: 'str' },
|
|
89
|
+
|
|
87
90
|
model: { value: '' },
|
|
88
91
|
modelType: { value: 'str' },
|
|
89
92
|
|
|
@@ -140,6 +143,11 @@
|
|
|
140
143
|
MODEL_SUGGESTIONS.forEach((m) => datalist.append('<option value="' + m + '">'));
|
|
141
144
|
}
|
|
142
145
|
|
|
146
|
+
$('#node-input-agentName').typedInput({
|
|
147
|
+
typeField: '#node-input-agentNameType',
|
|
148
|
+
types: ['str', 'msg', 'flow', 'global', 'env']
|
|
149
|
+
});
|
|
150
|
+
|
|
143
151
|
$('#node-input-prompt').typedInput({
|
|
144
152
|
typeField: '#node-input-promptType',
|
|
145
153
|
types: ['msg', 'str', 'flow', 'global', 'env']
|
|
@@ -317,6 +325,15 @@
|
|
|
317
325
|
<input type="text" id="node-input-name" placeholder="Agent">
|
|
318
326
|
</div>
|
|
319
327
|
|
|
328
|
+
<div class="form-row">
|
|
329
|
+
<label for="node-input-agentName"><i class="fa fa-id-badge"></i> Agent name
|
|
330
|
+
<i class="fa fa-info-circle" style="color:#888; cursor:help; margin-left:4px;"
|
|
331
|
+
title="Reported as msg.agentName on the result/event outputs. Leave blank (str) to use the Name field above; set to msg/flow/global to make it dynamic per message."></i>
|
|
332
|
+
</label>
|
|
333
|
+
<input type="text" id="node-input-agentName" placeholder="leave blank to use the Name field above" style="width:60%">
|
|
334
|
+
<input type="hidden" id="node-input-agentNameType">
|
|
335
|
+
</div>
|
|
336
|
+
|
|
320
337
|
<div class="form-row">
|
|
321
338
|
<label for="node-input-agent"><i class="fa fa-cube"></i> Agent</label>
|
|
322
339
|
<select id="node-input-agent" style="width:70%">
|
|
@@ -475,6 +492,12 @@
|
|
|
475
492
|
the id of the execution to kill, as returned by an earlier run in
|
|
476
493
|
<code>msg.agentExecution.id</code> or an Events message's
|
|
477
494
|
<code>executionId</code>.</dd>
|
|
495
|
+
<dt class="optional">concurrency <span class="property-type">number</span></dt>
|
|
496
|
+
<dd>Overrides the Concurrency field at runtime, applied before this
|
|
497
|
+
message is submitted -- no redeploy needed. Raising it starts any
|
|
498
|
+
already-queued messages immediately; lowering it only affects
|
|
499
|
+
future scheduling (already-running executions are never
|
|
500
|
+
cancelled). Non-numeric/non-positive values are ignored.</dd>
|
|
478
501
|
</dl>
|
|
479
502
|
<h3>Outputs</h3>
|
|
480
503
|
<ol class="node-ports">
|
|
@@ -488,6 +511,16 @@
|
|
|
488
511
|
conversation on the next message.</dd>
|
|
489
512
|
<dt>agentExecution <span class="property-type">object</span></dt>
|
|
490
513
|
<dd>id, status, exitCode, signal, timedOut, durationMs, sessionID.</dd>
|
|
514
|
+
<dt>agentId <span class="property-type">string</span></dt>
|
|
515
|
+
<dd>This node instance's own Node-RED id, so a flow with
|
|
516
|
+
several agent nodes can tell which one produced a
|
|
517
|
+
given message.</dd>
|
|
518
|
+
<dt>agentName <span class="property-type">string</span></dt>
|
|
519
|
+
<dd>The resolved Agent name field, falling back to this node
|
|
520
|
+
instance's configured Name if the Agent name field is
|
|
521
|
+
blank/unresolved for this message (e.g. via
|
|
522
|
+
<code>msg.agentName</code> when configured as a msg
|
|
523
|
+
property).</dd>
|
|
491
524
|
</dl>
|
|
492
525
|
</li>
|
|
493
526
|
<li>Events
|
|
@@ -498,6 +531,10 @@
|
|
|
498
531
|
<dt>executionId <span class="property-type">string</span></dt>
|
|
499
532
|
<dd>Correlates events (and the eventual result) belonging to
|
|
500
533
|
the same execution when several run concurrently.</dd>
|
|
534
|
+
<dt>agentId <span class="property-type">string</span></dt>
|
|
535
|
+
<dd>This node instance's own Node-RED id (see Result output).</dd>
|
|
536
|
+
<dt>agentName <span class="property-type">string</span></dt>
|
|
537
|
+
<dd>The resolved Agent name for this execution (see Result output).</dd>
|
|
501
538
|
</dl>
|
|
502
539
|
</li>
|
|
503
540
|
</ol>
|
|
@@ -509,7 +546,9 @@
|
|
|
509
546
|
complete in a different order than the messages arrived; ordering is
|
|
510
547
|
not guaranteed above concurrency 1. On redeploy/removal, queued
|
|
511
548
|
messages are cancelled (a <code>cancelled</code> event plus a Node-RED
|
|
512
|
-
error) and any still-running agent processes are terminated
|
|
549
|
+
error) and any still-running agent processes are terminated. Send
|
|
550
|
+
<code>msg.concurrency</code> to change the bound at runtime without a
|
|
551
|
+
redeploy -- see Inputs below.</p>
|
|
513
552
|
<p><b>Terminating a specific execution on demand</b>: send a message with
|
|
514
553
|
<code>msg.operation = "terminate"</code> and <code>msg.executionId</code>
|
|
515
554
|
set to the id to kill (from a prior run's <code>msg.agentExecution.id</code>
|
package/nodes/agent/agent.js
CHANGED
|
@@ -45,6 +45,14 @@ module.exports = function (RED) {
|
|
|
45
45
|
node.runtime = config.runtime || "direct";
|
|
46
46
|
node.invocation = config.invocation || "prompt";
|
|
47
47
|
|
|
48
|
+
// Typed-input override of the agentName reported on outgoing/event
|
|
49
|
+
// messages (see lifecycleEnvelope below). Same typed-input pattern as
|
|
50
|
+
// every other overridable field: blank/unresolved falls back to
|
|
51
|
+
// node.name, so existing flows relying on the (previously static)
|
|
52
|
+
// node.name value keep working unchanged.
|
|
53
|
+
node.agentName = config.agentName !== undefined ? config.agentName : "";
|
|
54
|
+
node.agentNameType = config.agentNameType || "str";
|
|
55
|
+
|
|
48
56
|
node.model = config.model || "";
|
|
49
57
|
node.modelType = config.modelType || "str";
|
|
50
58
|
|
|
@@ -150,19 +158,30 @@ module.exports = function (RED) {
|
|
|
150
158
|
}
|
|
151
159
|
}
|
|
152
160
|
|
|
161
|
+
// Per-message resolution of the reported agentName: the typed-input
|
|
162
|
+
// agentName/agentNameType field (e.g. msg.agentName) if configured and
|
|
163
|
+
// present, else node.name -- same fallback behavior a blank/unset
|
|
164
|
+
// typed-input field has always had for every other field.
|
|
165
|
+
function resolveAgentName(msg) {
|
|
166
|
+
const v = resolveTyped(node.agentName, node.agentNameType, msg, node.name);
|
|
167
|
+
return v === undefined || v === null || v === "" ? node.name : String(v).trim();
|
|
168
|
+
}
|
|
169
|
+
|
|
153
170
|
// Common envelope for every message on output 2 (the lifecycle/event
|
|
154
171
|
// stream): correlation (topic, executionId), live scheduler counts
|
|
155
172
|
// (so a widget bound to this stream always has the current
|
|
156
173
|
// active/queued numbers, no separate polling needed) and a
|
|
157
174
|
// timestamp (so external aggregation/history doesn't have to rely
|
|
158
175
|
// on message-arrival time).
|
|
159
|
-
function lifecycleEnvelope(msg, executionId, payload) {
|
|
176
|
+
function lifecycleEnvelope(msg, executionId, payload, agentName) {
|
|
160
177
|
return {
|
|
161
178
|
_msgid: msg._msgid,
|
|
162
179
|
topic: msg.topic,
|
|
163
180
|
payload,
|
|
164
181
|
agent: node.agent,
|
|
165
182
|
runtime: node.runtime,
|
|
183
|
+
agentId: node.id,
|
|
184
|
+
agentName,
|
|
166
185
|
executionId,
|
|
167
186
|
active: node.scheduler.activeCount,
|
|
168
187
|
queued: node.scheduler.queuedCount,
|
|
@@ -170,8 +189,8 @@ module.exports = function (RED) {
|
|
|
170
189
|
};
|
|
171
190
|
}
|
|
172
191
|
|
|
173
|
-
function emitEvent(send, msg, executionId, type) {
|
|
174
|
-
send([null, lifecycleEnvelope(msg, executionId, { type })]);
|
|
192
|
+
function emitEvent(send, msg, executionId, type, agentName) {
|
|
193
|
+
send([null, lifecycleEnvelope(msg, executionId, { type }, agentName)]);
|
|
175
194
|
}
|
|
176
195
|
|
|
177
196
|
// The actual work for one execution. Only ever invoked by the
|
|
@@ -188,11 +207,11 @@ module.exports = function (RED) {
|
|
|
188
207
|
resolved,
|
|
189
208
|
executionId,
|
|
190
209
|
onEvent: (event) => {
|
|
191
|
-
send([null, lifecycleEnvelope(msg, executionId, event)]);
|
|
210
|
+
send([null, lifecycleEnvelope(msg, executionId, event, resolved.agentName)]);
|
|
192
211
|
},
|
|
193
212
|
onStatus: (status) => {
|
|
194
213
|
if (status === "running") {
|
|
195
|
-
emitEvent(send, msg, executionId, "running");
|
|
214
|
+
emitEvent(send, msg, executionId, "running", resolved.agentName);
|
|
196
215
|
} else {
|
|
197
216
|
// Terminal (completed/failed/timeout): stash rather
|
|
198
217
|
// than emit immediately -- the scheduler hasn't
|
|
@@ -214,6 +233,8 @@ module.exports = function (RED) {
|
|
|
214
233
|
payload: result.payload,
|
|
215
234
|
agent: node.agent,
|
|
216
235
|
runtime: node.runtime,
|
|
236
|
+
agentId: node.id,
|
|
237
|
+
agentName: resolved.agentName,
|
|
217
238
|
// Top-level, in addition to agentExecution.sessionID
|
|
218
239
|
// below: matches the agent-server node's convention
|
|
219
240
|
// so this output can be fed straight back into the
|
|
@@ -261,13 +282,22 @@ module.exports = function (RED) {
|
|
|
261
282
|
node.scheduler = new ExecutionScheduler({
|
|
262
283
|
concurrency: node.concurrency,
|
|
263
284
|
onStart: startExecution,
|
|
264
|
-
onQueued: (item) =>
|
|
285
|
+
onQueued: (item) =>
|
|
286
|
+
emitEvent(item.send, item.msg, item.executionId, "queued", item.resolved.agentName),
|
|
265
287
|
// Runs after this item is removed from `active` and any newly-
|
|
266
288
|
// eligible queued item has already been started, so the terminal
|
|
267
289
|
// event's active/queued counts are accurate (see the onStatus
|
|
268
290
|
// comment in startExecution for why it's deferred to here).
|
|
269
291
|
onSettled: (item) => {
|
|
270
|
-
if (item.finalStatus)
|
|
292
|
+
if (item.finalStatus) {
|
|
293
|
+
emitEvent(
|
|
294
|
+
item.send,
|
|
295
|
+
item.msg,
|
|
296
|
+
item.executionId,
|
|
297
|
+
item.finalStatus,
|
|
298
|
+
item.resolved.agentName,
|
|
299
|
+
);
|
|
300
|
+
}
|
|
271
301
|
updateStatus();
|
|
272
302
|
},
|
|
273
303
|
});
|
|
@@ -287,6 +317,7 @@ module.exports = function (RED) {
|
|
|
287
317
|
return;
|
|
288
318
|
}
|
|
289
319
|
|
|
320
|
+
const agentName = resolveAgentName(msg);
|
|
290
321
|
const result = node.scheduler.cancel(executionId);
|
|
291
322
|
if (!result) {
|
|
292
323
|
done(new Error(`agent: unknown or already-finished executionId "${executionId}"`));
|
|
@@ -295,7 +326,13 @@ module.exports = function (RED) {
|
|
|
295
326
|
|
|
296
327
|
if (result.status === "queued") {
|
|
297
328
|
const queuedItem = result.item;
|
|
298
|
-
emitEvent(
|
|
329
|
+
emitEvent(
|
|
330
|
+
queuedItem.send,
|
|
331
|
+
queuedItem.msg,
|
|
332
|
+
executionId,
|
|
333
|
+
"cancelled",
|
|
334
|
+
queuedItem.resolved ? queuedItem.resolved.agentName : agentName,
|
|
335
|
+
);
|
|
299
336
|
queuedItem.done(
|
|
300
337
|
new Error("agent: execution cancelled before it started (terminate requested)"),
|
|
301
338
|
);
|
|
@@ -303,6 +340,8 @@ module.exports = function (RED) {
|
|
|
303
340
|
send([
|
|
304
341
|
Object.assign({}, msg, {
|
|
305
342
|
payload: { executionId, terminated: true, status: "cancelled" },
|
|
343
|
+
agentId: node.id,
|
|
344
|
+
agentName,
|
|
306
345
|
}),
|
|
307
346
|
null,
|
|
308
347
|
]);
|
|
@@ -320,6 +359,8 @@ module.exports = function (RED) {
|
|
|
320
359
|
send([
|
|
321
360
|
Object.assign({}, msg, {
|
|
322
361
|
payload: { executionId, terminated: true, status: "terminating" },
|
|
362
|
+
agentId: node.id,
|
|
363
|
+
agentName,
|
|
323
364
|
}),
|
|
324
365
|
null,
|
|
325
366
|
]);
|
|
@@ -342,9 +383,19 @@ module.exports = function (RED) {
|
|
|
342
383
|
return;
|
|
343
384
|
}
|
|
344
385
|
|
|
386
|
+
// Optional per-message override of the deploy-time Concurrency
|
|
387
|
+
// field, applied before this message is submitted so a raised
|
|
388
|
+
// bound can immediately start any items already queued from
|
|
389
|
+
// earlier messages. Invalid values (non-numeric/non-positive)
|
|
390
|
+
// are ignored -- see ExecutionScheduler.setConcurrency.
|
|
391
|
+
if (msg.concurrency !== undefined) {
|
|
392
|
+
node.scheduler.setConcurrency(Number(msg.concurrency));
|
|
393
|
+
}
|
|
394
|
+
|
|
345
395
|
let resolved;
|
|
346
396
|
try {
|
|
347
397
|
resolved = {
|
|
398
|
+
agentName: resolveAgentName(msg),
|
|
348
399
|
invocation: node.invocation,
|
|
349
400
|
prompt:
|
|
350
401
|
node.invocation === "prompt"
|
|
@@ -27,6 +27,20 @@ class ExecutionScheduler {
|
|
|
27
27
|
return this.active.size;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
// Runtime override of the concurrency bound (e.g. from a per-message
|
|
31
|
+
// msg.concurrency), as opposed to the fixed value passed into the
|
|
32
|
+
// constructor. Invalid input (non-finite/non-positive) is ignored
|
|
33
|
+
// rather than falling back to 1 -- an in-flight bound should never be
|
|
34
|
+
// silently reset by a bad message. Raising the bound immediately
|
|
35
|
+
// drains eligible queued items via _advance(); lowering it only
|
|
36
|
+
// affects future scheduling -- already-active items are never
|
|
37
|
+
// cancelled by this call.
|
|
38
|
+
setConcurrency(concurrency) {
|
|
39
|
+
if (!Number.isFinite(concurrency) || concurrency <= 0) return;
|
|
40
|
+
this.concurrency = Math.floor(concurrency);
|
|
41
|
+
this._advance();
|
|
42
|
+
}
|
|
43
|
+
|
|
30
44
|
get queuedCount() {
|
|
31
45
|
return this.queue.length;
|
|
32
46
|
}
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
defaults: {
|
|
19
19
|
name: { value: '' },
|
|
20
20
|
|
|
21
|
+
serverName: { value: '' },
|
|
22
|
+
serverNameType: { value: 'str' },
|
|
23
|
+
|
|
21
24
|
operation: { value: 'message' },
|
|
22
25
|
|
|
23
26
|
hostname: { value: '127.0.0.1' },
|
|
@@ -71,6 +74,10 @@
|
|
|
71
74
|
typeField: '#node-input-modelType',
|
|
72
75
|
types: ['str', 'msg', 'flow', 'global', 'env']
|
|
73
76
|
});
|
|
77
|
+
$('#node-input-serverName').typedInput({
|
|
78
|
+
typeField: '#node-input-serverNameType',
|
|
79
|
+
types: ['str', 'msg', 'flow', 'global', 'env']
|
|
80
|
+
});
|
|
74
81
|
|
|
75
82
|
function updateOperationRows() {
|
|
76
83
|
const op = $('#node-input-operation').val();
|
|
@@ -141,6 +148,15 @@
|
|
|
141
148
|
<input type="text" id="node-input-name" placeholder="Agent Server">
|
|
142
149
|
</div>
|
|
143
150
|
|
|
151
|
+
<div class="form-row">
|
|
152
|
+
<label for="node-input-serverName"><i class="fa fa-id-badge"></i> Server name
|
|
153
|
+
<i class="fa fa-info-circle" style="color:#888; cursor:help; margin-left:4px;"
|
|
154
|
+
title="Reported as msg.serverName on the result/event outputs. Leave blank (str) to use the Name field above; set to msg/flow/global to make it dynamic per message."></i>
|
|
155
|
+
</label>
|
|
156
|
+
<input type="text" id="node-input-serverName" placeholder="leave blank to use the Name field above" style="width:60%">
|
|
157
|
+
<input type="hidden" id="node-input-serverNameType">
|
|
158
|
+
</div>
|
|
159
|
+
|
|
144
160
|
<div class="form-row">
|
|
145
161
|
<label for="node-input-operation"><i class="fa fa-play"></i> Operation</label>
|
|
146
162
|
<select id="node-input-operation" style="width:70%">
|
|
@@ -194,7 +210,7 @@
|
|
|
194
210
|
<label for="node-input-maxInstances"><i class="fa fa-tasks"></i> Max instances</label>
|
|
195
211
|
<input type="text" id="node-input-maxInstances" placeholder="5" style="width:80px">
|
|
196
212
|
<i class="fa fa-info-circle" style="color:#888; cursor:help; margin-left:4px;"
|
|
197
|
-
title="Maximum number of daemons this node may have spawned at once. A new no-session-id trigger errors immediately once reached (no queueing). 0 = unlimited."></i>
|
|
213
|
+
title="Maximum number of daemons this node may have spawned at once. A new no-session-id trigger errors immediately once reached (no queueing). 0 = unlimited. Overridable at runtime via msg.maxInstances."></i>
|
|
198
214
|
</div>
|
|
199
215
|
<div class="form-row agent-server-row-spawn">
|
|
200
216
|
<label for="node-input-startupTimeoutMs"><i class="fa fa-clock-o"></i> Startup timeout</label>
|
|
@@ -340,6 +356,12 @@
|
|
|
340
356
|
configured Operation for a single trigger -- e.g. to ask a message-sending node
|
|
341
357
|
instance for its own current status, without needing a second node pointed at
|
|
342
358
|
nothing.</p>
|
|
359
|
+
<p>Set <code>msg.maxInstances</code> to override the Max instances field at
|
|
360
|
+
runtime, without a redeploy -- 0 keeps meaning "unlimited", and
|
|
361
|
+
negative/non-numeric values are ignored. Lowering it below the current
|
|
362
|
+
number of tracked daemons never kills any of them; it only blocks
|
|
363
|
+
<em>future</em> spawns until the count naturally drops back under the
|
|
364
|
+
new cap.</p>
|
|
343
365
|
<h3>Outputs</h3>
|
|
344
366
|
<ol class="node-ports">
|
|
345
367
|
<li>Result
|
|
@@ -348,6 +370,16 @@
|
|
|
348
370
|
<dd>Operation-dependent: assistant reply text (message), a status object, etc.</dd>
|
|
349
371
|
<dt>sessionID <span class="property-type">string</span></dt>
|
|
350
372
|
<dd>Echoed back so a later trigger can reuse the same daemon/session.</dd>
|
|
373
|
+
<dt>serverId <span class="property-type">string</span></dt>
|
|
374
|
+
<dd>This node instance's own Node-RED id, so a flow with
|
|
375
|
+
several agent-server nodes can tell which one produced a
|
|
376
|
+
given message.</dd>
|
|
377
|
+
<dt>serverName <span class="property-type">string</span></dt>
|
|
378
|
+
<dd>The resolved Server name field, falling back to this node
|
|
379
|
+
instance's configured Name if the Server name field is
|
|
380
|
+
blank/unresolved for this message (e.g. via
|
|
381
|
+
<code>msg.serverName</code> when configured as a msg
|
|
382
|
+
property).</dd>
|
|
351
383
|
</dl>
|
|
352
384
|
</li>
|
|
353
385
|
<li>Lifecycle events
|
|
@@ -357,6 +389,10 @@
|
|
|
357
389
|
<code>failed</code> / <code>closed</code>, each with <code>sessionID</code>,
|
|
358
390
|
<code>timestamp</code>, and this node instance's live <code>active</code>
|
|
359
391
|
(busy) / <code>tracked</code> (total) daemon counts.</dd>
|
|
392
|
+
<dt>serverId <span class="property-type">string</span></dt>
|
|
393
|
+
<dd>This node instance's own Node-RED id (see Result output).</dd>
|
|
394
|
+
<dt>serverName <span class="property-type">string</span></dt>
|
|
395
|
+
<dd>The resolved Server name for this event (see Result output).</dd>
|
|
360
396
|
</dl>
|
|
361
397
|
</li>
|
|
362
398
|
</ol>
|
|
@@ -21,6 +21,12 @@ module.exports = function (RED) {
|
|
|
21
21
|
|
|
22
22
|
node.operation = config.operation || "message";
|
|
23
23
|
|
|
24
|
+
// Typed-input override of the serverName reported on outgoing/event
|
|
25
|
+
// messages (see emitEvent below). Same typed-input pattern as every
|
|
26
|
+
// other overridable field: blank/unresolved falls back to node.name.
|
|
27
|
+
node.serverName = config.serverName !== undefined ? config.serverName : "";
|
|
28
|
+
node.serverNameType = config.serverNameType || "str";
|
|
29
|
+
|
|
24
30
|
node.sessionIdProp = config.sessionIdProp !== undefined ? config.sessionIdProp : "sessionID";
|
|
25
31
|
node.sessionIdPropType = config.sessionIdPropType || "msg";
|
|
26
32
|
|
|
@@ -105,6 +111,8 @@ module.exports = function (RED) {
|
|
|
105
111
|
topic: msg && msg.topic,
|
|
106
112
|
payload: { type },
|
|
107
113
|
sessionID,
|
|
114
|
+
serverId: node.id,
|
|
115
|
+
serverName: resolveServerName(msg),
|
|
108
116
|
active: summary.busy,
|
|
109
117
|
tracked: summary.total,
|
|
110
118
|
timestamp: Date.now(),
|
|
@@ -122,6 +130,16 @@ module.exports = function (RED) {
|
|
|
122
130
|
}
|
|
123
131
|
}
|
|
124
132
|
|
|
133
|
+
// Per-message resolution of the reported serverName: the typed-input
|
|
134
|
+
// serverName/serverNameType field (e.g. msg.serverName) if configured
|
|
135
|
+
// and present, else node.name -- same fallback every other typed-input
|
|
136
|
+
// field has when blank/unresolved. Tolerates a missing msg (emitEvent
|
|
137
|
+
// is sometimes called without one, e.g. from spawnNewInstance's own
|
|
138
|
+
// internal bookkeeping) by resolving against an empty object.
|
|
139
|
+
function resolveServerName(msg) {
|
|
140
|
+
return resolveTyped(node.serverName, node.serverNameType, msg || {}, node.name);
|
|
141
|
+
}
|
|
142
|
+
|
|
125
143
|
function authOptions() {
|
|
126
144
|
return node.authUsername || node.authPassword
|
|
127
145
|
? { username: node.authUsername, password: node.authPassword }
|
|
@@ -236,6 +254,8 @@ module.exports = function (RED) {
|
|
|
236
254
|
const resultMsg = Object.assign({}, msg, {
|
|
237
255
|
payload: extractText(response),
|
|
238
256
|
sessionID,
|
|
257
|
+
serverId: node.id,
|
|
258
|
+
serverName: resolveServerName(msg),
|
|
239
259
|
agentServer: {
|
|
240
260
|
sessionID,
|
|
241
261
|
host: record && record.host,
|
|
@@ -330,7 +350,14 @@ module.exports = function (RED) {
|
|
|
330
350
|
if (!sessionID) {
|
|
331
351
|
// Aggregate across every daemon this node instance is
|
|
332
352
|
// tracking -- purely local, no network calls.
|
|
333
|
-
send([
|
|
353
|
+
send([
|
|
354
|
+
Object.assign({}, msg, {
|
|
355
|
+
payload: node.registry.summary(),
|
|
356
|
+
serverId: node.id,
|
|
357
|
+
serverName: resolveServerName(msg),
|
|
358
|
+
}),
|
|
359
|
+
null,
|
|
360
|
+
]);
|
|
334
361
|
done();
|
|
335
362
|
return;
|
|
336
363
|
}
|
|
@@ -355,6 +382,8 @@ module.exports = function (RED) {
|
|
|
355
382
|
startedAt: record.startedAt,
|
|
356
383
|
lastUsed: record.lastUsed,
|
|
357
384
|
},
|
|
385
|
+
serverId: node.id,
|
|
386
|
+
serverName: resolveServerName(msg),
|
|
358
387
|
}),
|
|
359
388
|
null,
|
|
360
389
|
]);
|
|
@@ -387,7 +416,15 @@ module.exports = function (RED) {
|
|
|
387
416
|
.then(() => {
|
|
388
417
|
node.registry.setBusy(sessionID, false);
|
|
389
418
|
updateStatus();
|
|
390
|
-
send([
|
|
419
|
+
send([
|
|
420
|
+
Object.assign({}, msg, {
|
|
421
|
+
payload: true,
|
|
422
|
+
sessionID,
|
|
423
|
+
serverId: node.id,
|
|
424
|
+
serverName: resolveServerName(msg),
|
|
425
|
+
}),
|
|
426
|
+
null,
|
|
427
|
+
]);
|
|
391
428
|
done();
|
|
392
429
|
})
|
|
393
430
|
.catch((err) => done(new Error(`agent-server: abort failed: ${err.message}`)));
|
|
@@ -416,7 +453,15 @@ module.exports = function (RED) {
|
|
|
416
453
|
...authOptions(),
|
|
417
454
|
})
|
|
418
455
|
.then((history) => {
|
|
419
|
-
send([
|
|
456
|
+
send([
|
|
457
|
+
Object.assign({}, msg, {
|
|
458
|
+
payload: history,
|
|
459
|
+
sessionID,
|
|
460
|
+
serverId: node.id,
|
|
461
|
+
serverName: resolveServerName(msg),
|
|
462
|
+
}),
|
|
463
|
+
null,
|
|
464
|
+
]);
|
|
420
465
|
done();
|
|
421
466
|
})
|
|
422
467
|
.catch((err) => done(new Error(`agent-server: history fetch failed: ${err.message}`)));
|
|
@@ -450,7 +495,15 @@ module.exports = function (RED) {
|
|
|
450
495
|
.then(() => {
|
|
451
496
|
emitEvent(sessionID, "terminated", msg);
|
|
452
497
|
updateStatus();
|
|
453
|
-
send([
|
|
498
|
+
send([
|
|
499
|
+
Object.assign({}, msg, {
|
|
500
|
+
payload: true,
|
|
501
|
+
sessionID,
|
|
502
|
+
serverId: node.id,
|
|
503
|
+
serverName: resolveServerName(msg),
|
|
504
|
+
}),
|
|
505
|
+
null,
|
|
506
|
+
]);
|
|
454
507
|
done();
|
|
455
508
|
})
|
|
456
509
|
.catch((err) => done(new Error(`agent-server: terminate failed: ${err.message}`)));
|
|
@@ -464,6 +517,18 @@ module.exports = function (RED) {
|
|
|
464
517
|
return;
|
|
465
518
|
}
|
|
466
519
|
|
|
520
|
+
// Optional per-message override of the deploy-time Max instances
|
|
521
|
+
// field, applied before spawnNewInstance()'s guard clause reads it
|
|
522
|
+
// -- no redeploy needed. 0 stays "unlimited" (same as the
|
|
523
|
+
// constructor's semantics above); negative/non-numeric values are
|
|
524
|
+
// ignored. Lowering the limit below the current registry size
|
|
525
|
+
// never evicts already-spawned daemons -- it only blocks *future*
|
|
526
|
+
// spawns until the count naturally drops back under the new cap.
|
|
527
|
+
if (msg.maxInstances !== undefined) {
|
|
528
|
+
const n = Number(msg.maxInstances);
|
|
529
|
+
if (Number.isFinite(n) && n >= 0) node.maxInstances = Math.floor(n);
|
|
530
|
+
}
|
|
531
|
+
|
|
467
532
|
// msg.operation can override the configured default for this one
|
|
468
533
|
// trigger. This matters because each node instance's registry is
|
|
469
534
|
// private (per-node-instance scoping, same as the `agent` node's
|