@vibexnpm/talkx 3.0.2 → 3.0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibexnpm/talkx",
3
- "version": "3.0.2",
3
+ "version": "3.0.3",
4
4
  "type": "module",
5
5
  "description": "TalkFlow SDK - Chat & WebRTC unified client",
6
6
  "main": "dist/talkflow-sdk.umd.js",
@@ -477,30 +477,41 @@ class ChatClient extends EventEmitter {
477
477
  * Rolling 누적 요약 갱신 트리거 (비동기).
478
478
  *
479
479
  * <p>방의 <b>누적 대화 요약</b>을 갱신한다 — {@link #summarizeWithAssistant}(페르소나가 최근 N개를 방에
480
- * 어시스턴트 메시지로 발행)와 달리, <b>포맷별</b> 통합 요약본(rollup)을 마지막 요약 지점 이후 <b>새 대화만
481
- * 증분</b> 반영한다(같은 방을 여러 포맷으로 보관). 실제 요약은 서버 워커가 비동기로 수행하며, 완료/실패는
480
+ * 어시스턴트 메시지로 발행)와 달리, <b>포맷×언어별</b> 통합 요약본(rollup)을 마지막 요약 지점 이후 <b>새 대화만
481
+ * 증분</b> 반영한다(같은 방을 여러 포맷·언어로 보관). 실제 요약은 서버 워커가 비동기로 수행하며, 완료/실패는
482
482
  * {@code summaryUpdate} 이벤트로 통지된다. 확정 내용은 {@link #getSummary} 로 조회한다(알림 payload 에는 내용이 없다).</p>
483
483
  *
484
+ * <p><b>언어</b>: {@code lang} 미지정 시 서버가 요청자 언어(방 설정 ?? 사용자 선호)로 해소한다 — 자동번역으로
485
+ * 원문이 섞여도 그 언어로만 통합된다. {@code 'OFF'} 는 원문 유지. 응답에 해소된 {@code format}/{@code language} 가
486
+ * 담긴다.</p>
487
+ *
484
488
  * <p>전체 히스토리를 보는 방(예: TEAM) 대상 기능이며, AI capability {@code TOOL_SUMMARIZE} 가 필요하다.</p>
485
489
  *
486
490
  * @param {string} roomId - 채팅방 ID
487
491
  * @param {Object} [options]
488
492
  * @param {string} [options.format] - 요약 포맷 ({@link SummarizeFormat}). 미지정/알 수 없는 값이면 서버가 {@code SHORT} 적용.
489
- * @returns {Promise<{status: string}>} {@code status}: {@code 'STARTED'}(워커 시작 — {@code summaryUpdate} 대기) |
490
- * {@code 'ALREADY_RUNNING'}(이미 진행 중 — 재요청하지 말 것) | {@code 'NO_CHANGE'}(새 대화 없음 — 알림 발생 안 함)
493
+ * @param {string} [options.lang] - 출력 언어(BCP-47 예 {@code 'ko'}/{@code 'en'}, 또는 {@code 'OFF'}=원문). 미지정 시 요청자 언어로 해소.
494
+ * @returns {Promise<{status: string, format?: string, language?: string}>} {@code status}: {@code 'STARTED'}(워커 시작 —
495
+ * {@code summaryUpdate} 대기) | {@code 'ALREADY_RUNNING'}(방에서 <b>다른</b> 요약이 진행 중일 수 있음 — 응답의
496
+ * {@code format}/{@code language} 로 내 키인지 확인) | {@code 'NO_CHANGE'}(새 대화 없음 — 알림 발생 안 함).
497
+ * {@code format}/{@code language}=이번 요청이 해소한 키(방 단위 경합 식별용).
491
498
  *
492
- * @fires summaryUpdate - 완료/실패 시 { roomId, status: 'READY'|'NO_CHANGE'|'FAILED', format, updatedAt }
499
+ * @fires summaryUpdate - 완료/실패 시 { roomId, status: 'READY'|'NO_CHANGE'|'FAILED', format, language, updatedAt }
493
500
  *
494
501
  * @example
495
- * const { status } = await chat.refreshSummary(roomId, { format: SummarizeFormat.MINUTES });
496
- * if (status === 'STARTED' || status === 'ALREADY_RUNNING') showSpinner(); // summaryUpdate 를 기다린다
497
- * else if (status === 'NO_CHANGE') toast('변경 사항이 없습니다');
502
+ * const { status, format, language } = await chat.refreshSummary(roomId, { format: SummarizeFormat.MINUTES, lang: 'ko' });
503
+ * if (status === 'STARTED') showSpinner(); // 내 키 진행 시작 — summaryUpdate 대기
504
+ * else if (status === 'ALREADY_RUNNING') {
505
+ * // 방에서 다른 키가 도는 중일 수 있다. summaryUpdate 의 format+language 가 { minutes, ko } 가 아니면
506
+ * // 그때 다시 refreshSummary 로 내 키를 요청한다(재요청 금지가 아니라 "내 키가 아니면 재요청").
507
+ * showSpinner();
508
+ * } else if (status === 'NO_CHANGE') toast('변경 사항이 없습니다');
498
509
  */
499
510
  async refreshSummary(roomId, options = {}) {
500
- const { format } = options;
511
+ const { format, lang } = options;
501
512
  const response = await this.apiClient.post(
502
513
  `/api/v1/rooms/${roomId}/summary/refresh`,
503
- { format }
514
+ { format, lang }
504
515
  );
505
516
  return this._unwrapSuccessResponse(response);
506
517
  }
@@ -512,28 +523,32 @@ class ChatClient extends EventEmitter {
512
523
  * transient(저장 안 됨)라 유실될 수 있으므로 GET 으로 동기화한다. 아직 한 번도 요약된 적 없으면 {@code rollup}
513
524
  * 이 {@code null} 이다. segment 는 {@code afterSeq}/{@code size} 로 페이지네이션한다({@code hasNext}/{@code nextSeq}).</p>
514
525
  *
515
- * <p>같은 방을 여러 포맷으로 보관하므로 {@code options.format} 으로 골라 조회한다. 미지정 시 기본(SHORT 우선),
516
- * 요청 포맷이 아직 없으면 {@code rollup=null}(이때 {@code availableFormats} 로 보유 포맷 확인 또는 refreshSummary
517
- * 로 생성). {@code rollup.stale} 이 {@code true} 면 그 포맷이 최신 대화를 아직 반영 안 함(refresh 로 최신화).</p>
526
+ * <p>같은 방을 여러 포맷×언어로 보관하므로 {@code options.format}/{@code options.lang} 으로 골라 조회한다.
527
+ * {@code lang} 미지정 시 서버가 요청자 언어로 해소하고, 응답 {@code language} 로 <b>어느 언어 기준</b>인지
528
+ * 알려준다. {@code availableFormats} 는 <b>그 언어에 존재하는</b> 포맷만 담는다(타 언어로 fallback 하지 않음).
529
+ * 요청 포맷이 그 언어에 아직 없으면 {@code rollup=null}(refreshSummary 로 생성). {@code rollup.stale} 이
530
+ * {@code true} 면 그 키가 최신 대화를 아직 반영 안 함(refresh 로 최신화).</p>
518
531
  *
519
532
  * @param {string} roomId - 채팅방 ID
520
533
  * @param {Object} [options]
521
- * @param {string} [options.format] - 조회할 포맷({@link SummarizeFormat}). 미지정 시 기본. 미보유 포맷이면 rollup=null.
534
+ * @param {string} [options.format] - 조회할 포맷({@link SummarizeFormat}). 미지정 시 그 언어의 기본(SHORT 우선). 미보유면 rollup=null.
535
+ * @param {string} [options.lang] - 조회할 언어(BCP-47 예 {@code 'ko'}, 또는 {@code 'OFF'}=원문). 미지정 시 요청자 언어로 해소(응답 {@code language}).
522
536
  * @param {number} [options.afterSeq] - segment 페이지 커서(exclusive). 미지정 시 처음부터.
523
537
  * @param {number} [options.size=50] - segment 페이지 크기(서버 상한 50).
524
- * @returns {Promise<RoomSummaryView>} { rollup | null, availableFormats, segments, hasNext, nextSeq }
538
+ * @returns {Promise<RoomSummaryView>} { language, rollup | null, availableFormats, segments, hasNext, nextSeq }
525
539
  *
526
540
  * @example
527
- * const view = await chat.getSummary(roomId, { format: 'timeline' });
528
- * if (!view.rollup) return renderEmpty(); // 그 포맷 아직 없음 (availableFormats 로 탭 렌더)
541
+ * const view = await chat.getSummary(roomId, { format: 'timeline', lang: 'ko' });
542
+ * console.log(view.language); // 'ko' (미지정 조회였다면 서버가 해소한 언어)
543
+ * if (!view.rollup) return renderEmpty(); // 그 포맷×언어 아직 없음 (availableFormats 로 탭 렌더)
529
544
  * renderRollup(view.rollup, view.rollup.stale); // stale 이면 "최신화" 유도
530
- * renderTabs(view.availableFormats); // 보유 포맷 탭
545
+ * renderTabs(view.availableFormats); // 이 언어에 보유한 포맷 탭
531
546
  */
532
547
  async getSummary(roomId, options = {}) {
533
- const { format, afterSeq, size } = options;
548
+ const { format, lang, afterSeq, size } = options;
534
549
  const response = await this.apiClient.get(
535
550
  `/api/v1/rooms/${roomId}/summary`,
536
- { format, afterSeq, size }
551
+ { format, lang, afterSeq, size }
537
552
  );
538
553
  return this._unwrapSuccessResponse(response);
539
554
  }
@@ -2350,10 +2365,14 @@ class ChatClient extends EventEmitter {
2350
2365
  /**
2351
2366
  * Rolling 누적 요약 완료 알림(summary 채널) 수신 처리 — status 를 그대로 {@code summaryUpdate} 로 emit.
2352
2367
  *
2353
- * <p>서버 {@code SummaryStreamEvent}: {@code { status: 'READY'|'NO_CHANGE'|'FAILED', roomId, format?, updatedAt? }}.
2368
+ * <p>서버 {@code SummaryStreamEvent}: {@code { status: 'READY'|'NO_CHANGE'|'FAILED', roomId, format?, language?, updatedAt? }}.
2354
2369
  * assistant-stream 과 달리 단계/토큰 누적이 없어 상태 관리 없이 그대로 통지한다. transient(저장 안 됨)라 UI 는
2355
2370
  * 이벤트를 신호로만 쓰고 확정 내용은 {@link #getSummary} 로 읽는다. {@code READY}=요약 갱신됨(→ getSummary),
2356
2371
  * {@code FAILED}=실패(재시도 가능), {@code NO_CHANGE}=변경 없음(대개 refreshSummary 응답에서 동기로 이미 받음).</p>
2372
+ *
2373
+ * <p><b>키 식별(format+language)</b>: 방 단위로 한 번에 한 요약만 도므로, 여러 포맷·언어를 요청했다면 이 이벤트의
2374
+ * {@code format}+{@code language} 로 <b>어느 키</b>가 완료/실패했는지 가려 내 키가 아니면 다시 refreshSummary 한다.
2375
+ * {@code READY}·{@code FAILED} 모두 키를 싣는다({@code NO_CHANGE} 는 없음).</p>
2357
2376
  * @private
2358
2377
  */
2359
2378
  _handleSummaryEvent(roomId, event) {
@@ -2361,7 +2380,8 @@ class ChatClient extends EventEmitter {
2361
2380
  this.emit('summaryUpdate', {
2362
2381
  roomId,
2363
2382
  status: event.status, // 'READY' | 'NO_CHANGE' | 'FAILED'
2364
- format: event.format || null, // READY 만 포함(그 외 null)
2383
+ format: event.format || null, // READY/FAILED 포함(NO_CHANGE 는 null)
2384
+ language: event.language || null, // READY/FAILED 포함(NO_CHANGE 는 null) — 키 식별용
2365
2385
  updatedAt: event.updatedAt || null
2366
2386
  });
2367
2387
  }
package/types/index.d.ts CHANGED
@@ -288,6 +288,8 @@ export interface TranslateToolRequest {
288
288
  export interface RefreshSummaryOptions {
289
289
  /** 요약 포맷 ({@link SummarizeFormat}). 미지정/알 수 없는 값이면 서버가 {@code SHORT} 적용. */
290
290
  format?: SummarizeFormatValue;
291
+ /** 출력 언어(BCP-47 예 {@code 'ko'}/{@code 'en'}, 또는 {@code 'OFF'}=원문). 미지정 시 서버가 요청자 언어로 해소. */
292
+ lang?: string;
291
293
  }
292
294
 
293
295
  /**
@@ -298,17 +300,24 @@ export interface RefreshSummaryResult {
298
300
  /**
299
301
  * <ul>
300
302
  * <li>{@code 'STARTED'} — 요약 워커 시작됨({@code summaryUpdate} 대기).</li>
301
- * <li>{@code 'ALREADY_RUNNING'} — 이미 진행 중(중복 트리거 — 재요청하지 말 것).</li>
303
+ * <li>{@code 'ALREADY_RUNNING'} — 방에서 요약이 진행 중(<b>다른</b> 포맷·언어일 수 있음). {@code format}/{@code language}
304
+ * 로 내 키인지 확인하고, {@code summaryUpdate} 가 내 키가 아니면 그때 다시 요청한다(무조건 재요청 금지 아님).</li>
302
305
  * <li>{@code 'NO_CHANGE'} — 새 대화 없음(알림 발생 안 함; 직전 실패가 있었다면 자동 복구됨).</li>
303
306
  * </ul>
304
307
  */
305
308
  status: 'STARTED' | 'ALREADY_RUNNING' | 'NO_CHANGE';
309
+ /** 이번 요청이 해소한 포맷({@link SummarizeFormat} 소문자). 방 단위 경합 식별용. */
310
+ format?: string;
311
+ /** 이번 요청이 해소한 언어(소문자 BCP-47 / {@code 'OFF'}=원문). 방 단위 경합 식별용. */
312
+ language?: string;
306
313
  }
307
314
 
308
315
  /** {@link ChatClient.getSummary} 옵션. */
309
316
  export interface GetSummaryOptions {
310
- /** 조회할 포맷({@link SummarizeFormat}). 미지정 시 기본(SHORT 우선). 미보유 포맷이면 rollup=null. */
317
+ /** 조회할 포맷({@link SummarizeFormat}). 미지정 시 그 언어의 기본(SHORT 우선). 미보유 포맷이면 rollup=null. */
311
318
  format?: SummarizeFormatValue;
319
+ /** 조회할 언어(BCP-47 예 {@code 'ko'}, 또는 {@code 'OFF'}=원문). 미지정 시 요청자 언어로 해소(응답 {@code language}). */
320
+ lang?: string;
312
321
  /** segment 페이지 커서(exclusive). 미지정 시 처음부터. */
313
322
  afterSeq?: number;
314
323
  /** segment 페이지 크기(서버 상한 50). */
@@ -317,20 +326,20 @@ export interface GetSummaryOptions {
317
326
 
318
327
  /** Rolling 누적 요약 통합본 — {@link RoomSummaryView.rollup}. */
319
328
  export interface RoomSummaryRollup {
320
- /** 요약 본문 ({@code format} 적용됨). */
329
+ /** 요약 본문 ({@code format} 적용 + {@code language} 로 통합됨). */
321
330
  content: string;
322
331
  /** 적용된 포맷 ({@link SummarizeFormat} 소문자). */
323
332
  format: string;
333
+ /** 이 rollup 의 언어(소문자 BCP-47 / {@code 'OFF'}=원문). {@link RoomSummaryView.language} 와 동일. */
334
+ language: string;
324
335
  /** rollup 이 커버하는 가장 오래된 지점. */
325
336
  coverStartAt: string | null;
326
337
  /** 마지막으로 요약된 지점. */
327
338
  watermarkAt: string | null;
328
339
  /** 전체 segment 수(페이지 총량 힌트). */
329
340
  segmentCount: number;
330
- /** 이 포맷이 최신 대화를 아직 반영 안 함(reducedSegmentCount < segmentCount) — refreshSummary 로 최신화 가능. */
341
+ /** 이 키(포맷×언어)가 최신 대화를 아직 반영 안 함(reducedSegmentCount < segmentCount) — refreshSummary 로 최신화 가능. */
331
342
  stale: boolean;
332
- /** 진행 상태. {@code 'IDLE'}(완료/대기) | {@code 'RUNNING'}(요약 중) | {@code 'FAILED'}(실패). */
333
- status: 'IDLE' | 'RUNNING' | 'FAILED';
334
343
  /** 마지막 갱신 시각. */
335
344
  updatedAt: string;
336
345
  }
@@ -356,9 +365,21 @@ export interface RoomSummarySegment {
356
365
  * 아직 한 번도 요약되지 않았으면 {@code rollup} 이 {@code null} 이고 {@code segments} 는 빈 배열이다.
357
366
  */
358
367
  export interface RoomSummaryView {
359
- /** 요청/기본 포맷의 통합 요약본. 그 포맷으로 아직 요약 안 됐으면 null(availableFormats 로 다른 포맷 확인). */
368
+ /**
369
+ * 이 응답의 기준 언어(소문자 BCP-47 / {@code 'OFF'}=원문). {@code lang} 미지정 조회면 서버가 해소한 값이다 —
370
+ * {@code rollup}·{@code availableFormats} 가 이 언어 기준이다. 요약 이력이 없어도 서버가 요청자 언어로 해소해
371
+ * <b>항상</b> 채운다(never null).
372
+ */
373
+ language: string;
374
+ /**
375
+ * 방 전체 요약 프로세스 상태 — {@code 'IDLE'}(대기) | {@code 'RUNNING'}(요약 중) | {@code 'FAILED'}(실패).
376
+ * <b>방 단위(키별 아님)</b>: 방은 한 번에 한 키만 요약하므로, 지금 다른 포맷·언어를 요약 중이어도 {@code 'RUNNING'} 이다.
377
+ * 특정 rollup 의 최신 여부는 {@code rollup.stale} 로 판단한다(rollup 자체는 완료된 데이터). 요약 이력이 없으면 null.
378
+ */
379
+ roomStatus: 'IDLE' | 'RUNNING' | 'FAILED' | null;
380
+ /** 요청/기본 포맷의 통합 요약본. 그 포맷×언어로 아직 요약 안 됐으면 null(availableFormats 로 같은 언어의 다른 포맷 확인). */
360
381
  rollup: RoomSummaryRollup | null;
361
- /** 이 방이 보유한 포맷 목록(short/timeline/… — 탭 렌더용). */
382
+ /** 이 방이 <b>이 언어로</b> 보유한 포맷 목록(short/timeline/… — 탭 렌더용). 타 언어는 포함하지 않는다. */
362
383
  availableFormats: string[];
363
384
  /** 구간 부분요약 페이지(포맷 무관 공유). */
364
385
  segments: RoomSummarySegment[];
@@ -376,8 +397,10 @@ export interface SummaryUpdateEvent {
376
397
  roomId: string;
377
398
  /** {@code 'READY'}(갱신됨 → getSummary) | {@code 'FAILED'}(실패 → 재시도 가능) | {@code 'NO_CHANGE'}(변경 없음). */
378
399
  status: 'READY' | 'NO_CHANGE' | 'FAILED';
379
- /** 적용된 포맷. {@code READY} 만 포함, 그 외 null. */
400
+ /** 완료/실패한 포맷. {@code READY}·{@code FAILED} 포함, {@code NO_CHANGE} 는 null. */
380
401
  format: string | null;
402
+ /** 완료/실패한 언어(소문자 BCP-47 / {@code 'OFF'}). {@code READY}·{@code FAILED} 포함, {@code NO_CHANGE} 는 null — format 과 함께 키 식별. */
403
+ language: string | null;
381
404
  /** 갱신 시각. {@code READY} 만 포함, 그 외 null. */
382
405
  updatedAt: string | null;
383
406
  }