clementine-agent 1.1.16 → 1.1.17

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.
@@ -732,6 +732,10 @@ export class Gateway {
732
732
  });
733
733
  }
734
734
  async _handleMessageInner(sessionKey, text, onText, model, maxTurns, onToolActivity, onProgress) {
735
+ // Per-segment latency capture — emitted as a single 'chat:latency' line
736
+ // on the happy path so we can grep/aggregate without parsing many lines.
737
+ const tInnerStart = Date.now();
738
+ const timings = {};
735
739
  // ── Auth circuit breaker — stop spamming error messages ────────
736
740
  if (this.authCircuitOpen) {
737
741
  if (!this.shouldProbeAuth()) {
@@ -765,6 +769,7 @@ export class Gateway {
765
769
  await onProgress('thinking...').catch(() => { });
766
770
  }
767
771
  const laneWaitMs = Date.now() - laneWaitStart;
772
+ timings.laneWaitMs = laneWaitMs;
768
773
  if (laneWaitMs > 1000) {
769
774
  logger.info({ sessionKey, laneWaitMs }, 'Chat lane wait was non-trivial');
770
775
  }
@@ -775,8 +780,10 @@ export class Gateway {
775
780
  // ── Pre-flight injection scan ───────────────────────────────
776
781
  // Re-baseline integrity before scanning — auto-memory, crons, and heartbeats
777
782
  // legitimately modify vault files between messages. Skip if refreshed within 5s.
783
+ const tScanStart = Date.now();
778
784
  scanner.refreshIfStale(5000);
779
785
  const scan = scanner.scan(text);
786
+ timings.scanMs = Date.now() - tScanStart;
780
787
  // Owner DMs are trusted — only block on high-confidence injection patterns,
781
788
  // not integrity changes (which are usually caused by Clementine's own writes).
782
789
  const isOwnerDm = sessionKey.startsWith('discord:user:') ||
@@ -873,9 +880,11 @@ export class Gateway {
873
880
  if (!isInternalMsg && !sess?.profile && !text.startsWith('!') && !isStructuredWorkflowMsg && onProgress) {
874
881
  await onProgress('checking if a teammate should handle this...').catch(() => { });
875
882
  }
883
+ const tRoutingStart = Date.now();
876
884
  const routingResult = !isInternalMsg && !sess?.profile && !text.startsWith('!') && !isStructuredWorkflowMsg
877
885
  ? await this._maybeRouteToSpecialist(sessionKey, text, onText)
878
886
  : null;
887
+ timings.routingMs = Date.now() - tRoutingStart;
879
888
  if (routingResult?.delegated) {
880
889
  return routingResult.ackMessage;
881
890
  }
@@ -1013,9 +1022,12 @@ export class Gateway {
1013
1022
  let toolActivityCount = 0;
1014
1023
  let lastStreamedText = '';
1015
1024
  let lastProgressEmitAt = Date.now();
1025
+ let firstTokenAt;
1016
1026
  const sessState = this.getSession(sessionKey);
1017
1027
  const wrappedOnText = onText
1018
1028
  ? async (token) => {
1029
+ if (firstTokenAt === undefined)
1030
+ firstTokenAt = Date.now();
1019
1031
  resetIdleTimer();
1020
1032
  lastStreamedText = token;
1021
1033
  // Mirror to session state so a concurrent acquireSessionLock()
@@ -1098,10 +1110,23 @@ export class Gateway {
1098
1110
  if (cs)
1099
1111
  delete cs.abortController;
1100
1112
  }
1113
+ const chatMs = Date.now() - queryStartMs;
1114
+ timings.chatMs = chatMs;
1115
+ if (firstTokenAt !== undefined) {
1116
+ timings.firstTokenMs = firstTokenAt - queryStartMs;
1117
+ }
1101
1118
  events.emit('query:complete', {
1102
1119
  sessionKey, responseLength: response?.length ?? 0,
1103
- toolActivityCount, durationMs: Date.now() - queryStartMs,
1120
+ toolActivityCount, durationMs: chatMs,
1104
1121
  });
1122
+ // One greppable line per chat completion — feed for the latency dashboard.
1123
+ logger.info({
1124
+ sessionKey,
1125
+ totalMs: Date.now() - tInnerStart,
1126
+ ...timings,
1127
+ toolActivityCount,
1128
+ responseLen: response?.length ?? 0,
1129
+ }, 'chat:latency');
1105
1130
  // Re-baseline integrity checksums after chat (auto-memory may write to vault)
1106
1131
  scanner.refreshIntegrity();
1107
1132
  // ── Auto-plan detection ──────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clementine-agent",
3
- "version": "1.1.16",
3
+ "version": "1.1.17",
4
4
  "description": "Clementine — Personal AI Assistant (TypeScript)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",