@cryptiklemur/lattice 5.13.2 → 5.13.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.
|
@@ -41,38 +41,59 @@ const sessionPermissionOverrides = new Map();
|
|
|
41
41
|
export function getAvailableModels() {
|
|
42
42
|
return getWarmupModels();
|
|
43
43
|
}
|
|
44
|
-
function createMessageQueue() {
|
|
44
|
+
function createMessageQueue(label) {
|
|
45
45
|
const queue = [];
|
|
46
46
|
let waiting = null;
|
|
47
47
|
let ended = false;
|
|
48
|
+
let readCount = 0;
|
|
49
|
+
const readWaiters = new Map();
|
|
48
50
|
return {
|
|
49
51
|
push: function (msg) {
|
|
50
52
|
if (waiting) {
|
|
53
|
+
log.chat("MQ[%s] push: SDK was waiting, delivering immediately (queued=%d)", label || "?", queue.length);
|
|
51
54
|
const resolve = waiting;
|
|
52
55
|
waiting = null;
|
|
53
56
|
resolve({ value: msg, done: false });
|
|
54
57
|
}
|
|
55
58
|
else {
|
|
56
59
|
queue.push(msg);
|
|
60
|
+
log.chat("MQ[%s] push: buffered (queued=%d)", label || "?", queue.length);
|
|
57
61
|
}
|
|
58
62
|
},
|
|
59
63
|
end: function () {
|
|
60
64
|
ended = true;
|
|
65
|
+
log.chat("MQ[%s] end called (queued=%d, waiting=%s)", label || "?", queue.length, String(!!waiting));
|
|
61
66
|
if (waiting) {
|
|
62
67
|
const resolve = waiting;
|
|
63
68
|
waiting = null;
|
|
64
69
|
resolve({ value: undefined, done: true });
|
|
65
70
|
}
|
|
66
71
|
},
|
|
72
|
+
waitForRead: function (n) {
|
|
73
|
+
if (readCount >= n)
|
|
74
|
+
return Promise.resolve();
|
|
75
|
+
return new Promise(function (resolve) {
|
|
76
|
+
readWaiters.set(n, resolve);
|
|
77
|
+
});
|
|
78
|
+
},
|
|
67
79
|
[Symbol.asyncIterator]: function () {
|
|
68
80
|
return {
|
|
69
81
|
next: function () {
|
|
82
|
+
readCount++;
|
|
83
|
+
const waiter = readWaiters.get(readCount);
|
|
84
|
+
if (waiter) {
|
|
85
|
+
readWaiters.delete(readCount);
|
|
86
|
+
waiter();
|
|
87
|
+
}
|
|
70
88
|
if (queue.length > 0) {
|
|
89
|
+
log.chat("MQ[%s] read #%d: from buffer (remaining=%d)", label || "?", readCount, queue.length - 1);
|
|
71
90
|
return Promise.resolve({ value: queue.shift(), done: false });
|
|
72
91
|
}
|
|
73
92
|
if (ended) {
|
|
93
|
+
log.chat("MQ[%s] read #%d: ended", label || "?", readCount);
|
|
74
94
|
return Promise.resolve({ value: undefined, done: true });
|
|
75
95
|
}
|
|
96
|
+
log.chat("MQ[%s] read #%d: waiting for push", label || "?", readCount);
|
|
76
97
|
return new Promise(function (resolve) {
|
|
77
98
|
waiting = resolve;
|
|
78
99
|
});
|
|
@@ -654,7 +675,7 @@ export function startChatStream(options) {
|
|
|
654
675
|
text,
|
|
655
676
|
uuid: crypto.randomUUID(),
|
|
656
677
|
});
|
|
657
|
-
const mq = createMessageQueue();
|
|
678
|
+
const mq = createMessageQueue(sessionId.slice(0, 8));
|
|
658
679
|
const firstMsg = buildSDKUserMessage(prompt, attachments, sessionId);
|
|
659
680
|
const stream = query({ prompt: mq, options: queryOptions });
|
|
660
681
|
pendingStreams.delete(sessionId);
|
|
@@ -695,20 +716,47 @@ export function startChatStream(options) {
|
|
|
695
716
|
catch (initErr) {
|
|
696
717
|
log.chat("Session %s SDK initialization FAILED: %O", sessionId, initErr);
|
|
697
718
|
}
|
|
698
|
-
|
|
719
|
+
if (shouldResume) {
|
|
720
|
+
log.chat("Session %s waiting for SDK read #2 before pushing message", sessionId);
|
|
721
|
+
await mq.waitForRead(2);
|
|
722
|
+
log.chat("Session %s SDK read #2 triggered, pushing first message", sessionId);
|
|
723
|
+
}
|
|
724
|
+
else {
|
|
725
|
+
log.chat("Session %s pushing first message to queue", sessionId);
|
|
726
|
+
}
|
|
699
727
|
mq.push(firstMsg);
|
|
700
728
|
let retrying = false;
|
|
729
|
+
const TURN_TIMEOUT_MS = 30000;
|
|
730
|
+
let turnTimer = null;
|
|
731
|
+
function resetTurnTimer() {
|
|
732
|
+
if (turnTimer)
|
|
733
|
+
clearTimeout(turnTimer);
|
|
734
|
+
turnTimer = setTimeout(function () {
|
|
735
|
+
if (!sessionStream.sawNewTurnContent && !sessionStream.ended) {
|
|
736
|
+
log.chat("Session %s turn timeout: no new content after %dms, aborting", sessionId, TURN_TIMEOUT_MS);
|
|
737
|
+
abortController.abort();
|
|
738
|
+
}
|
|
739
|
+
}, TURN_TIMEOUT_MS);
|
|
740
|
+
}
|
|
741
|
+
resetTurnTimer();
|
|
701
742
|
try {
|
|
702
743
|
log.chat("Session %s entering stream loop", sessionId);
|
|
703
744
|
let msgCount = 0;
|
|
704
745
|
for await (const msg of stream) {
|
|
705
746
|
msgCount++;
|
|
706
747
|
log.chat("Session %s msg #%d type=%s", sessionId, msgCount, msg.type);
|
|
748
|
+
if (msg.type === "stream_event" || (msg.type === "assistant" && msg.message?.model !== "<synthetic>")) {
|
|
749
|
+
resetTurnTimer();
|
|
750
|
+
}
|
|
707
751
|
processMessage(sessionStream, msg);
|
|
708
752
|
}
|
|
753
|
+
if (turnTimer)
|
|
754
|
+
clearTimeout(turnTimer);
|
|
709
755
|
log.chat("Session %s stream ended normally after %d messages", sessionId, msgCount);
|
|
710
756
|
}
|
|
711
757
|
catch (err) {
|
|
758
|
+
if (turnTimer)
|
|
759
|
+
clearTimeout(turnTimer);
|
|
712
760
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
713
761
|
log.chat("Session %s stream error: %s", sessionId, errMsg);
|
|
714
762
|
if (errMsg.includes("aborted") || errMsg.includes("AbortError")) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cryptiklemur/lattice",
|
|
3
|
-
"version": "5.13.
|
|
3
|
+
"version": "5.13.4",
|
|
4
4
|
"description": "Multi-machine agentic dashboard for Claude Code. Monitor sessions, manage MCP servers and skills, orchestrate across mesh-networked nodes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Aaron Scherer <me@aaronscherer.me>",
|