amalgm 0.1.84 → 0.1.85
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/lib/supervisor.js
CHANGED
|
@@ -402,9 +402,17 @@ function sleep(ms) {
|
|
|
402
402
|
|
|
403
403
|
function writeAutoUpdateState(update) {
|
|
404
404
|
const current = readJson(AUTO_UPDATE_STATE_FILE, {});
|
|
405
|
+
const updateValue = (key, fallback = null) => (
|
|
406
|
+
Object.prototype.hasOwnProperty.call(update, key) ? update[key] : fallback
|
|
407
|
+
);
|
|
405
408
|
const next = {
|
|
406
409
|
...current,
|
|
407
410
|
...update,
|
|
411
|
+
active_turns: updateValue('active_turns'),
|
|
412
|
+
tempstore_count: updateValue('tempstore_count'),
|
|
413
|
+
mcp_active: updateValue('mcp_active'),
|
|
414
|
+
tunnel_active: updateValue('tunnel_active'),
|
|
415
|
+
idle_blocked_reason: updateValue('idle_blocked_reason'),
|
|
408
416
|
updated_at: new Date().toISOString(),
|
|
409
417
|
};
|
|
410
418
|
writeJsonSecret(AUTO_UPDATE_STATE_FILE, next);
|
|
@@ -419,6 +427,7 @@ function writeAutoUpdateState(update) {
|
|
|
419
427
|
last_checked_at: next.last_checked_at || null,
|
|
420
428
|
last_error: next.last_error || null,
|
|
421
429
|
active_turns: next.active_turns ?? null,
|
|
430
|
+
tempstore_count: next.tempstore_count ?? null,
|
|
422
431
|
mcp_active: next.mcp_active ?? null,
|
|
423
432
|
tunnel_active: next.tunnel_active ?? null,
|
|
424
433
|
},
|
|
@@ -462,20 +471,43 @@ function localJsonRequest(port, requestPath, runtimeToken, timeoutMs) {
|
|
|
462
471
|
});
|
|
463
472
|
}
|
|
464
473
|
|
|
465
|
-
|
|
466
|
-
|
|
474
|
+
function runtimeTunnelActive(tunnels = []) {
|
|
475
|
+
return tunnels.reduce((sum, tunnel) => (
|
|
467
476
|
sum + (typeof tunnel.activeCount === 'function' ? Number(tunnel.activeCount()) || 0 : 0)
|
|
468
477
|
), 0);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function autoUpdateIdleBlockedReason(idle) {
|
|
481
|
+
if (idle.idle) return null;
|
|
482
|
+
if (idle.reason) return idle.reason;
|
|
483
|
+
|
|
484
|
+
const tempstoreCount = Number(idle.tempstore_count ?? idle.active_turns) || 0;
|
|
485
|
+
if (tempstoreCount > 0) {
|
|
486
|
+
return `tempstore has ${tempstoreCount} active turn${tempstoreCount === 1 ? '' : 's'}`;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const mcpActive = Number(idle.mcp_active) || 0;
|
|
490
|
+
if (mcpActive > 0) {
|
|
491
|
+
return `mcp has ${mcpActive} active agent conversation${mcpActive === 1 ? '' : 's'}`;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return 'runtime is busy';
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
async function runtimeIdleStatus({ ports, runtimeToken, tunnels }) {
|
|
498
|
+
const tunnelActive = runtimeTunnelActive(tunnels);
|
|
469
499
|
const timeoutMs = numberFromEnv('AMALGM_UPDATE_IDLE_TIMEOUT_MS', AUTO_UPDATE_POLICY.idleTimeoutMs, 500);
|
|
470
500
|
const [chat, mcp] = await Promise.all([
|
|
471
501
|
localJsonRequest(ports.chatServer, '/runtime-idle', runtimeToken, timeoutMs),
|
|
472
502
|
localJsonRequest(ports.amalgmMcp, '/healthz', runtimeToken, timeoutMs),
|
|
473
503
|
]);
|
|
474
|
-
const
|
|
504
|
+
const tempstoreCount = Number(chat?.tempstore_count ?? chat?.active_turns) || 0;
|
|
505
|
+
const activeTurns = Number(chat?.active_turns ?? tempstoreCount) || 0;
|
|
475
506
|
const mcpActive = Number(mcp?.activeAgentConversations) || 0;
|
|
476
507
|
return {
|
|
477
|
-
idle:
|
|
508
|
+
idle: tempstoreCount === 0 && mcpActive === 0,
|
|
478
509
|
active_turns: activeTurns,
|
|
510
|
+
tempstore_count: tempstoreCount,
|
|
479
511
|
mcp_active: mcpActive,
|
|
480
512
|
tunnel_active: tunnelActive,
|
|
481
513
|
};
|
|
@@ -573,8 +605,9 @@ function createAutoUpdateManager({ ports, runtimeToken, tunnels, foreground, req
|
|
|
573
605
|
idle = {
|
|
574
606
|
idle: false,
|
|
575
607
|
active_turns: null,
|
|
608
|
+
tempstore_count: null,
|
|
576
609
|
mcp_active: null,
|
|
577
|
-
tunnel_active:
|
|
610
|
+
tunnel_active: runtimeTunnelActive(tunnels),
|
|
578
611
|
reason: error.message,
|
|
579
612
|
};
|
|
580
613
|
}
|
|
@@ -587,9 +620,10 @@ function createAutoUpdateManager({ ports, runtimeToken, tunnels, foreground, req
|
|
|
587
620
|
critical: false,
|
|
588
621
|
service_managed: true,
|
|
589
622
|
active_turns: idle.active_turns,
|
|
623
|
+
tempstore_count: idle.tempstore_count,
|
|
590
624
|
mcp_active: idle.mcp_active,
|
|
591
625
|
tunnel_active: idle.tunnel_active,
|
|
592
|
-
idle_blocked_reason: idle
|
|
626
|
+
idle_blocked_reason: autoUpdateIdleBlockedReason(idle),
|
|
593
627
|
});
|
|
594
628
|
|
|
595
629
|
if (idle.idle) {
|
package/package.json
CHANGED
|
@@ -109,10 +109,11 @@ class ChatCore {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
idleStatus() {
|
|
112
|
-
const
|
|
112
|
+
const tempstoreCount = typeof this.turns.activeCount === 'function' ? this.turns.activeCount() : 0;
|
|
113
113
|
return {
|
|
114
|
-
idle:
|
|
115
|
-
active_turns:
|
|
114
|
+
idle: tempstoreCount === 0,
|
|
115
|
+
active_turns: tempstoreCount,
|
|
116
|
+
tempstore_count: tempstoreCount,
|
|
116
117
|
};
|
|
117
118
|
}
|
|
118
119
|
|
|
@@ -118,7 +118,7 @@ test('POST /chat streams from the same indexed raw chunks as /raw-temp', async (
|
|
|
118
118
|
}
|
|
119
119
|
});
|
|
120
120
|
|
|
121
|
-
test('GET /runtime-idle reports
|
|
121
|
+
test('GET /runtime-idle reports tempstore count', async () => {
|
|
122
122
|
process.env.AMALGM_RUNTIME_AUTH = 'disabled';
|
|
123
123
|
|
|
124
124
|
const core = new ChatCore({
|
|
@@ -137,7 +137,7 @@ test('GET /runtime-idle reports active turn count', async () => {
|
|
|
137
137
|
try {
|
|
138
138
|
let res = await fetch(`${baseUrl}/runtime-idle`);
|
|
139
139
|
assert.equal(res.status, 200);
|
|
140
|
-
assert.deepEqual(await res.json(), { idle: true, active_turns: 0 });
|
|
140
|
+
assert.deepEqual(await res.json(), { idle: true, active_turns: 0, tempstore_count: 0 });
|
|
141
141
|
|
|
142
142
|
const entry = core.turns.start({
|
|
143
143
|
sessionId: 'session-test',
|
|
@@ -147,12 +147,12 @@ test('GET /runtime-idle reports active turn count', async () => {
|
|
|
147
147
|
});
|
|
148
148
|
res = await fetch(`${baseUrl}/runtime-idle`);
|
|
149
149
|
assert.equal(res.status, 200);
|
|
150
|
-
assert.deepEqual(await res.json(), { idle: false, active_turns: 1 });
|
|
150
|
+
assert.deepEqual(await res.json(), { idle: false, active_turns: 1, tempstore_count: 1 });
|
|
151
151
|
|
|
152
152
|
core.turns.mark(entry.turnId, 'complete');
|
|
153
153
|
res = await fetch(`${baseUrl}/runtime-idle`);
|
|
154
154
|
assert.equal(res.status, 200);
|
|
155
|
-
assert.deepEqual(await res.json(), { idle: true, active_turns: 0 });
|
|
155
|
+
assert.deepEqual(await res.json(), { idle: true, active_turns: 0, tempstore_count: 0 });
|
|
156
156
|
} finally {
|
|
157
157
|
await new Promise((resolve) => server.close(resolve));
|
|
158
158
|
}
|