@cryptiklemur/lattice 5.13.1 → 5.13.3
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,23 +41,27 @@ 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;
|
|
48
49
|
return {
|
|
49
50
|
push: function (msg) {
|
|
50
51
|
if (waiting) {
|
|
52
|
+
log.chat("MQ[%s] push: SDK was waiting, delivering immediately (queued=%d)", label || "?", queue.length);
|
|
51
53
|
const resolve = waiting;
|
|
52
54
|
waiting = null;
|
|
53
55
|
resolve({ value: msg, done: false });
|
|
54
56
|
}
|
|
55
57
|
else {
|
|
56
58
|
queue.push(msg);
|
|
59
|
+
log.chat("MQ[%s] push: buffered (queued=%d)", label || "?", queue.length);
|
|
57
60
|
}
|
|
58
61
|
},
|
|
59
62
|
end: function () {
|
|
60
63
|
ended = true;
|
|
64
|
+
log.chat("MQ[%s] end called (queued=%d, waiting=%s)", label || "?", queue.length, String(!!waiting));
|
|
61
65
|
if (waiting) {
|
|
62
66
|
const resolve = waiting;
|
|
63
67
|
waiting = null;
|
|
@@ -67,12 +71,16 @@ function createMessageQueue() {
|
|
|
67
71
|
[Symbol.asyncIterator]: function () {
|
|
68
72
|
return {
|
|
69
73
|
next: function () {
|
|
74
|
+
readCount++;
|
|
70
75
|
if (queue.length > 0) {
|
|
76
|
+
log.chat("MQ[%s] read #%d: from buffer (remaining=%d)", label || "?", readCount, queue.length - 1);
|
|
71
77
|
return Promise.resolve({ value: queue.shift(), done: false });
|
|
72
78
|
}
|
|
73
79
|
if (ended) {
|
|
80
|
+
log.chat("MQ[%s] read #%d: ended", label || "?", readCount);
|
|
74
81
|
return Promise.resolve({ value: undefined, done: true });
|
|
75
82
|
}
|
|
83
|
+
log.chat("MQ[%s] read #%d: waiting for push", label || "?", readCount);
|
|
76
84
|
return new Promise(function (resolve) {
|
|
77
85
|
waiting = resolve;
|
|
78
86
|
});
|
|
@@ -654,7 +662,7 @@ export function startChatStream(options) {
|
|
|
654
662
|
text,
|
|
655
663
|
uuid: crypto.randomUUID(),
|
|
656
664
|
});
|
|
657
|
-
const mq = createMessageQueue();
|
|
665
|
+
const mq = createMessageQueue(sessionId.slice(0, 8));
|
|
658
666
|
const firstMsg = buildSDKUserMessage(prompt, attachments, sessionId);
|
|
659
667
|
const stream = query({ prompt: mq, options: queryOptions });
|
|
660
668
|
pendingStreams.delete(sessionId);
|
|
@@ -695,40 +703,48 @@ export function startChatStream(options) {
|
|
|
695
703
|
catch (initErr) {
|
|
696
704
|
log.chat("Session %s SDK initialization FAILED: %O", sessionId, initErr);
|
|
697
705
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
706
|
+
log.chat("Session %s pushing first message to queue", sessionId);
|
|
707
|
+
mq.push(firstMsg);
|
|
708
|
+
let retrying = false;
|
|
709
|
+
const TURN_TIMEOUT_MS = 30000;
|
|
710
|
+
let turnTimer = null;
|
|
711
|
+
function resetTurnTimer() {
|
|
712
|
+
if (turnTimer)
|
|
713
|
+
clearTimeout(turnTimer);
|
|
714
|
+
turnTimer = setTimeout(function () {
|
|
715
|
+
if (!sessionStream.sawNewTurnContent && !sessionStream.ended) {
|
|
716
|
+
log.chat("Session %s turn timeout: no new content after %dms, aborting", sessionId, TURN_TIMEOUT_MS);
|
|
717
|
+
abortController.abort();
|
|
718
|
+
}
|
|
719
|
+
}, TURN_TIMEOUT_MS);
|
|
701
720
|
}
|
|
721
|
+
resetTurnTimer();
|
|
702
722
|
try {
|
|
703
723
|
log.chat("Session %s entering stream loop", sessionId);
|
|
704
724
|
let msgCount = 0;
|
|
705
|
-
let replayDone = !shouldResume;
|
|
706
725
|
for await (const msg of stream) {
|
|
707
726
|
msgCount++;
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
if (!replayDone && msg.type === "result") {
|
|
712
|
-
replayDone = true;
|
|
713
|
-
log.chat("Session %s replay complete at msg #%d, waiting for connection settle", sessionId, msgCount);
|
|
714
|
-
await new Promise(function (resolve) { setTimeout(resolve, 200); });
|
|
715
|
-
log.chat("Session %s pushing first message after replay", sessionId);
|
|
716
|
-
mq.push(firstMsg);
|
|
717
|
-
continue;
|
|
727
|
+
log.chat("Session %s msg #%d type=%s", sessionId, msgCount, msg.type);
|
|
728
|
+
if (msg.type === "stream_event" || (msg.type === "assistant" && msg.message?.model !== "<synthetic>")) {
|
|
729
|
+
resetTurnTimer();
|
|
718
730
|
}
|
|
719
731
|
processMessage(sessionStream, msg);
|
|
720
732
|
}
|
|
733
|
+
if (turnTimer)
|
|
734
|
+
clearTimeout(turnTimer);
|
|
721
735
|
log.chat("Session %s stream ended normally after %d messages", sessionId, msgCount);
|
|
722
736
|
}
|
|
723
737
|
catch (err) {
|
|
738
|
+
if (turnTimer)
|
|
739
|
+
clearTimeout(turnTimer);
|
|
724
740
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
725
741
|
log.chat("Session %s stream error: %s", sessionId, errMsg);
|
|
726
742
|
if (errMsg.includes("aborted") || errMsg.includes("AbortError")) {
|
|
727
743
|
log.chat("Session %s stream aborted", sessionId);
|
|
728
744
|
}
|
|
729
|
-
else if (errMsg.includes("Sent before connected")) {
|
|
730
|
-
log.chat("Session %s
|
|
731
|
-
|
|
745
|
+
else if (errMsg.includes("Sent before connected") && shouldResume) {
|
|
746
|
+
log.chat("Session %s WebSocket not ready after resume, retrying in 500ms", sessionId);
|
|
747
|
+
retrying = true;
|
|
732
748
|
}
|
|
733
749
|
else {
|
|
734
750
|
console.error("[lattice] SDK stream error: " + errMsg);
|
|
@@ -740,6 +756,12 @@ export function startChatStream(options) {
|
|
|
740
756
|
pendingStreams.delete(sessionId);
|
|
741
757
|
sessionStreams.delete(sessionId);
|
|
742
758
|
persistStreamState();
|
|
759
|
+
if (retrying) {
|
|
760
|
+
log.chat("Session %s cleaning up for retry", sessionId);
|
|
761
|
+
await new Promise(function (resolve) { setTimeout(resolve, 500); });
|
|
762
|
+
startChatStream(options);
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
743
765
|
broadcast({ type: "session:busy", sessionId, busy: false }, sessionStream.clientId);
|
|
744
766
|
const toCleanup = [];
|
|
745
767
|
pendingPermissions.forEach(function (entry, reqId) {
|
|
@@ -812,6 +834,7 @@ function processMessage(ss, msg) {
|
|
|
812
834
|
}
|
|
813
835
|
if (msg.type === "assistant") {
|
|
814
836
|
const assistantMsg = msg;
|
|
837
|
+
log.chat("Session %s assistant message: model=%s", sessionId, assistantMsg.message.model || "unknown");
|
|
815
838
|
const msgUsage = assistantMsg.message.usage;
|
|
816
839
|
if (msgUsage && msgUsage.input_tokens != null) {
|
|
817
840
|
const ctxWindow = guessContextWindow(assistantMsg.message.model || "");
|
|
@@ -836,6 +859,8 @@ function processMessage(ss, msg) {
|
|
|
836
859
|
const partial = msg;
|
|
837
860
|
const evt = partial.event;
|
|
838
861
|
if (evt.type === "content_block_start") {
|
|
862
|
+
const blockInfo = evt.content_block;
|
|
863
|
+
log.chat("Session %s content_block_start: type=%s name=%s", sessionId, blockInfo.type, blockInfo.name || "text");
|
|
839
864
|
ss.sawNewTurnContent = true;
|
|
840
865
|
const block = evt.content_block;
|
|
841
866
|
const idx = evt.index;
|
|
@@ -967,11 +992,12 @@ function processMessage(ss, msg) {
|
|
|
967
992
|
return;
|
|
968
993
|
}
|
|
969
994
|
if (msg.type === "result") {
|
|
995
|
+
const resultMsg = msg;
|
|
996
|
+
log.chat("Session %s result: cost=$%s, sawContent=%s", sessionId, String(resultMsg.total_cost_usd || 0), String(ss.sawNewTurnContent));
|
|
970
997
|
if (!ss.sawNewTurnContent) {
|
|
971
998
|
log.chat("Session %s ignoring replayed result (no new turn content seen)", sessionId);
|
|
972
999
|
return;
|
|
973
1000
|
}
|
|
974
|
-
const resultMsg = msg;
|
|
975
1001
|
const dur = Date.now() - ss.turnStartTime;
|
|
976
1002
|
const cost = resultMsg.total_cost_usd || 0;
|
|
977
1003
|
if (resultMsg.usage) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cryptiklemur/lattice",
|
|
3
|
-
"version": "5.13.
|
|
3
|
+
"version": "5.13.3",
|
|
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>",
|