@mulingai-npm/redis 3.40.24 → 3.40.26

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.
@@ -65,6 +65,15 @@ export type MulingstreamChunkData = {
65
65
  transcriptionSource: 'stt' | 'llm';
66
66
  routeUsed?: 'LLM' | 'AZURE' | 'AZURE_FALLBACK';
67
67
  sttHistory?: SttHistoryEntry[];
68
+ /** Lifecycle status w.r.t. the pending-fragment buffer.
69
+ * - 'EMITTED' (default): chunk produced sanitized output and translations.
70
+ * - 'DEFERRED': chunk held back; its content lives in the pending buffer until consumed.
71
+ * - 'USED': chunk's content was rolled into a later chunk's emission. */
72
+ bufferStatus?: 'EMITTED' | 'DEFERRED' | 'USED';
73
+ /** Trailing fragment buffered for the next chunk (set on DEFERRED rows). */
74
+ pendingText?: string;
75
+ /** Chunks whose deferred content was absorbed into this chunk's emission. */
76
+ consumedChunkNumbers?: number[];
68
77
  };
69
78
  export declare class MulingstreamChunkManager {
70
79
  private redisClient;
@@ -146,6 +155,16 @@ export declare class MulingstreamChunkManager {
146
155
  isEmitted?: boolean;
147
156
  duration?: number;
148
157
  }): Promise<MulingstreamChunkData | null>;
158
+ /**
159
+ * Update SmartTranslate buffering metadata on a chunk (Section 22).
160
+ * Writes `bufferStatus`, `pendingText`, and `consumedChunkNumbers` so the chunk row
161
+ * persisted at the end of the pipeline reflects whether it was DEFERRED / USED / EMITTED.
162
+ */
163
+ setBufferStatus(roomId: string, n: number, opt: {
164
+ bufferStatus?: 'EMITTED' | 'DEFERRED' | 'USED';
165
+ pendingText?: string;
166
+ consumedChunkNumbers?: number[];
167
+ }): Promise<MulingstreamChunkData | null>;
149
168
  areTranslationsProcessed(roomId: string, n: number): Promise<boolean>;
150
169
  /**
151
170
  * Check if all TTS for all target languages are done (READY, USED, or DISCARDED - not INIT)
@@ -342,6 +342,21 @@ class MulingstreamChunkManager {
342
342
  e.duration = opt.duration;
343
343
  });
344
344
  }
345
+ /**
346
+ * Update SmartTranslate buffering metadata on a chunk (Section 22).
347
+ * Writes `bufferStatus`, `pendingText`, and `consumedChunkNumbers` so the chunk row
348
+ * persisted at the end of the pipeline reflects whether it was DEFERRED / USED / EMITTED.
349
+ */
350
+ async setBufferStatus(roomId, n, opt) {
351
+ return this.withChunk(roomId, n, (c) => {
352
+ if (opt.bufferStatus !== undefined)
353
+ c.bufferStatus = opt.bufferStatus;
354
+ if (opt.pendingText !== undefined)
355
+ c.pendingText = opt.pendingText;
356
+ if (opt.consumedChunkNumbers !== undefined)
357
+ c.consumedChunkNumbers = opt.consumedChunkNumbers;
358
+ });
359
+ }
345
360
  async areTranslationsProcessed(roomId, n) {
346
361
  const c = await this.getMulingstreamChunkById(roomId, n);
347
362
  return !!c && Object.values(c.translation).every((t) => t.status !== 'INIT');
@@ -15,10 +15,22 @@ export interface ContextChunk {
15
15
  san: boolean;
16
16
  ts: number;
17
17
  }
18
+ /**
19
+ * Pending buffer entry for the SmartTranslate buffering contract (Section 22).
20
+ * Stores the trailing fragment from the most-recent LLM response so it can be
21
+ * prepended to the next chunk's input.
22
+ */
23
+ export interface PendingBuffer {
24
+ text: string;
25
+ seqs: number[];
26
+ consecutiveDeferred: number;
27
+ ts: number;
28
+ }
18
29
  export declare class SmartTranslateContextManager {
19
30
  private redisClient;
20
31
  constructor(redisClient: RedisClient);
21
32
  private contextKey;
33
+ private pendingKey;
22
34
  /**
23
35
  * Get the last N context chunks for a session (best-effort).
24
36
  * Returns whatever is available RIGHT NOW — doesn't wait for pending LLM results.
@@ -47,4 +59,20 @@ export declare class SmartTranslateContextManager {
47
59
  * Clean up context for a session (called when streaming ends).
48
60
  */
49
61
  cleanupSession(sessionId: string): Promise<void>;
62
+ /**
63
+ * Read the current pending fragment for a session (best-effort).
64
+ * Returns null if no buffer is set or Redis is unavailable.
65
+ */
66
+ getPending(sessionId: string): Promise<PendingBuffer | null>;
67
+ /**
68
+ * Overwrite the pending fragment for a session.
69
+ * Pass an empty `text` to clear the buffer (a no-op write that effectively
70
+ * resets the deferred-chunk tracking).
71
+ */
72
+ setPending(sessionId: string, buffer: PendingBuffer): Promise<void>;
73
+ /**
74
+ * Clear the pending fragment unconditionally. Returns the cleared buffer (if any)
75
+ * so callers performing a session-end flush can emit the dropped fragment.
76
+ */
77
+ clearPending(sessionId: string): Promise<PendingBuffer | null>;
50
78
  }
@@ -20,6 +20,9 @@ class SmartTranslateContextManager {
20
20
  contextKey(sessionId) {
21
21
  return `smarttranslate:context:${sessionId}`;
22
22
  }
23
+ pendingKey(sessionId) {
24
+ return `smarttranslate:pending:${sessionId}`;
25
+ }
23
26
  /**
24
27
  * Get the last N context chunks for a session (best-effort).
25
28
  * Returns whatever is available RIGHT NOW — doesn't wait for pending LLM results.
@@ -122,10 +125,70 @@ class SmartTranslateContextManager {
122
125
  async cleanupSession(sessionId) {
123
126
  try {
124
127
  await this.redisClient.del(this.contextKey(sessionId));
128
+ await this.redisClient.del(this.pendingKey(sessionId));
125
129
  }
126
130
  catch {
127
131
  // Cleanup failure is non-critical
128
132
  }
129
133
  }
134
+ // ──────────────────────────────────────────────────────────────────────
135
+ // Pending Buffer (Section 22 — Incomplete Chunk Merging / Buffering)
136
+ // ──────────────────────────────────────────────────────────────────────
137
+ /**
138
+ * Read the current pending fragment for a session (best-effort).
139
+ * Returns null if no buffer is set or Redis is unavailable.
140
+ */
141
+ async getPending(sessionId) {
142
+ try {
143
+ const raw = await this.redisClient.get(this.pendingKey(sessionId));
144
+ if (!raw)
145
+ return null;
146
+ try {
147
+ return JSON.parse(raw);
148
+ }
149
+ catch {
150
+ return null;
151
+ }
152
+ }
153
+ catch (err) {
154
+ console.warn(`[SmartTranslateContextManager] getPending FAILED for ${sessionId}: ${err}`);
155
+ return null;
156
+ }
157
+ }
158
+ /**
159
+ * Overwrite the pending fragment for a session.
160
+ * Pass an empty `text` to clear the buffer (a no-op write that effectively
161
+ * resets the deferred-chunk tracking).
162
+ */
163
+ async setPending(sessionId, buffer) {
164
+ try {
165
+ const key = this.pendingKey(sessionId);
166
+ if (!buffer.text) {
167
+ await this.redisClient.del(key);
168
+ return;
169
+ }
170
+ const pipe = this.redisClient.pipeline();
171
+ pipe.set(key, JSON.stringify(buffer));
172
+ pipe.expire(key, CONTEXT_TTL);
173
+ await pipe.exec();
174
+ }
175
+ catch (err) {
176
+ console.warn(`[SmartTranslateContextManager] setPending FAILED for ${sessionId}: ${err}`);
177
+ }
178
+ }
179
+ /**
180
+ * Clear the pending fragment unconditionally. Returns the cleared buffer (if any)
181
+ * so callers performing a session-end flush can emit the dropped fragment.
182
+ */
183
+ async clearPending(sessionId) {
184
+ const current = await this.getPending(sessionId);
185
+ try {
186
+ await this.redisClient.del(this.pendingKey(sessionId));
187
+ }
188
+ catch (err) {
189
+ console.warn(`[SmartTranslateContextManager] clearPending FAILED for ${sessionId}: ${err}`);
190
+ }
191
+ return current;
192
+ }
130
193
  }
131
194
  exports.SmartTranslateContextManager = SmartTranslateContextManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mulingai-npm/redis",
3
- "version": "3.40.24",
3
+ "version": "3.40.26",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "repository": {