@cryptiklemur/lattice 5.13.0 → 5.13.2

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.
@@ -380,6 +380,7 @@ function pushToExistingStream(session, options) {
380
380
  session.clientId = clientId;
381
381
  session.turnStartTime = Date.now();
382
382
  session.turnDoneSent = false;
383
+ session.sawNewTurnContent = false;
383
384
  session.activeToolBlocks = {};
384
385
  const prompt = resolvePromptText(text);
385
386
  const userMsg = buildSDKUserMessage(prompt, attachments, sessionId);
@@ -675,6 +676,7 @@ export function startChatStream(options) {
675
676
  ended: false,
676
677
  accumulatedText: "",
677
678
  specId: options.specId,
679
+ sawNewTurnContent: false,
678
680
  analyzer: new ContextAnalyzer(function (msg) {
679
681
  const ss = sessionStreams.get(sessionId);
680
682
  if (ss)
@@ -695,14 +697,13 @@ export function startChatStream(options) {
695
697
  }
696
698
  log.chat("Session %s pushing first message to queue", sessionId);
697
699
  mq.push(firstMsg);
700
+ let retrying = false;
698
701
  try {
699
702
  log.chat("Session %s entering stream loop", sessionId);
700
703
  let msgCount = 0;
701
704
  for await (const msg of stream) {
702
705
  msgCount++;
703
- if (msgCount <= 3 || msg.type === "result") {
704
- log.chat("Session %s msg #%d type=%s", sessionId, msgCount, msg.type);
705
- }
706
+ log.chat("Session %s msg #%d type=%s", sessionId, msgCount, msg.type);
706
707
  processMessage(sessionStream, msg);
707
708
  }
708
709
  log.chat("Session %s stream ended normally after %d messages", sessionId, msgCount);
@@ -713,8 +714,9 @@ export function startChatStream(options) {
713
714
  if (errMsg.includes("aborted") || errMsg.includes("AbortError")) {
714
715
  log.chat("Session %s stream aborted", sessionId);
715
716
  }
716
- else if (errMsg.includes("Sent before connected")) {
717
- log.chat("Session %s SDK WebSocket race condition: %s", sessionId, errMsg);
717
+ else if (errMsg.includes("Sent before connected") && shouldResume) {
718
+ log.chat("Session %s WebSocket not ready after resume, retrying in 500ms", sessionId);
719
+ retrying = true;
718
720
  }
719
721
  else {
720
722
  console.error("[lattice] SDK stream error: " + errMsg);
@@ -726,6 +728,12 @@ export function startChatStream(options) {
726
728
  pendingStreams.delete(sessionId);
727
729
  sessionStreams.delete(sessionId);
728
730
  persistStreamState();
731
+ if (retrying) {
732
+ log.chat("Session %s cleaning up for retry", sessionId);
733
+ await new Promise(function (resolve) { setTimeout(resolve, 500); });
734
+ startChatStream(options);
735
+ return;
736
+ }
729
737
  broadcast({ type: "session:busy", sessionId, busy: false }, sessionStream.clientId);
730
738
  const toCleanup = [];
731
739
  pendingPermissions.forEach(function (entry, reqId) {
@@ -798,6 +806,7 @@ function processMessage(ss, msg) {
798
806
  }
799
807
  if (msg.type === "assistant") {
800
808
  const assistantMsg = msg;
809
+ log.chat("Session %s assistant message: model=%s", sessionId, assistantMsg.message.model || "unknown");
801
810
  const msgUsage = assistantMsg.message.usage;
802
811
  if (msgUsage && msgUsage.input_tokens != null) {
803
812
  const ctxWindow = guessContextWindow(assistantMsg.message.model || "");
@@ -822,6 +831,9 @@ function processMessage(ss, msg) {
822
831
  const partial = msg;
823
832
  const evt = partial.event;
824
833
  if (evt.type === "content_block_start") {
834
+ const blockInfo = evt.content_block;
835
+ log.chat("Session %s content_block_start: type=%s name=%s", sessionId, blockInfo.type, blockInfo.name || "text");
836
+ ss.sawNewTurnContent = true;
825
837
  const block = evt.content_block;
826
838
  const idx = evt.index;
827
839
  if (block.type === "tool_use" && block.id && block.name) {
@@ -953,6 +965,11 @@ function processMessage(ss, msg) {
953
965
  }
954
966
  if (msg.type === "result") {
955
967
  const resultMsg = msg;
968
+ log.chat("Session %s result: cost=$%s, sawContent=%s", sessionId, String(resultMsg.total_cost_usd || 0), String(ss.sawNewTurnContent));
969
+ if (!ss.sawNewTurnContent) {
970
+ log.chat("Session %s ignoring replayed result (no new turn content seen)", sessionId);
971
+ return;
972
+ }
956
973
  const dur = Date.now() - ss.turnStartTime;
957
974
  const cost = resultMsg.total_cost_usd || 0;
958
975
  if (resultMsg.usage) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cryptiklemur/lattice",
3
- "version": "5.13.0",
3
+ "version": "5.13.2",
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>",