@vibexnpm/talkx 5.2.0 → 5.3.0
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/README.md +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/talkflow-sdk.esm.js +1 -1
- package/dist/talkflow-sdk.esm.js.map +1 -1
- package/dist/talkflow-sdk.standalone.js +1 -1
- package/dist/talkflow-sdk.standalone.js.map +1 -1
- package/dist/talkflow-sdk.umd.js +1 -1
- package/dist/talkflow-sdk.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/chat/ChatClient.js +69 -7
- package/src/talkflow/delegates.js +4 -0
- package/types/index.d.ts +45 -0
package/package.json
CHANGED
package/src/chat/ChatClient.js
CHANGED
|
@@ -320,6 +320,21 @@ class ChatClient extends EventEmitter {
|
|
|
320
320
|
// 1) WebSocket 구독을 먼저 — 이후 서버 read 이벤트 유실 방지
|
|
321
321
|
if (!wasAlreadySubscribed) {
|
|
322
322
|
await this.subscribeRoom(roomId);
|
|
323
|
+
} else if (this.assistantStreamReplay) {
|
|
324
|
+
// ⭐ <b>이미 구독 중인 방으로 재입장</b> — 구독을 유지한 채 방 화면만 나갔다 들어오는 흐름이다
|
|
325
|
+
// (목록 화면에서 unread 를 받으려면 구독을 끊지 않는 것이 정상 구현이다). 이때 subscribeRoom 이
|
|
326
|
+
// 통째로 건너뛰어져 <b>스냅샷 트리거가 하나도 돌지 않는다</b> — 재개 경로는 여기와 재연결
|
|
327
|
+
// (`resumeAssistantStreams`) 둘뿐이기 때문이다.
|
|
328
|
+
//
|
|
329
|
+
// 진행 표시는 transient 이벤트라 화면이 언마운트되면 프론트에서 사라지는데, SDK 슬롯에만 남은
|
|
330
|
+
// 그 상태를 다시 그려줄 신호가 없다 → 다음 PHASE 가 올 때까지(워커 heartbeat 간격 15초) 배지가
|
|
331
|
+
// 안 뜬다. 스냅샷을 다시 받아 그 공백을 없앤다.
|
|
332
|
+
//
|
|
333
|
+
// await 하지 않는다 — 구독은 살아 있으므로 그 사이 도착분은 보류함에 쌓였다가 병합 후 순서대로
|
|
334
|
+
// 풀린다(§6.1). 실패해도 보류분은 반드시 풀리므로 라이브만으로 계속 동작한다.
|
|
335
|
+
const generation = this._armAssistantSnapshot(roomId);
|
|
336
|
+
this._loadAssistantSnapshot(roomId, generation)
|
|
337
|
+
.catch((error) => this.logger.warn(`Assistant snapshot on re-enter failed: room=${roomId}`, error));
|
|
323
338
|
}
|
|
324
339
|
// 2) 자동 읽음 처리 활성 방 지정
|
|
325
340
|
this.setActiveRoom(roomId);
|
|
@@ -3490,17 +3505,29 @@ class ChatClient extends EventEmitter {
|
|
|
3490
3505
|
* @private
|
|
3491
3506
|
*/
|
|
3492
3507
|
_emitAssistantRoomProgress(roomId) {
|
|
3508
|
+
// 이벤트 계약은 종전 그대로 둔다 — stream 목록은 getter 전용(이벤트로 매 틱 배열을 실어 보내면
|
|
3509
|
+
// DELTA 마다 방 전체 스트림을 다시 만들어 흘리는 셈이다).
|
|
3510
|
+
const { streams, ...event } = this._assistantRoomProgressPayload(roomId);
|
|
3511
|
+
this.emit('assistantRoomProgress', event);
|
|
3512
|
+
}
|
|
3513
|
+
|
|
3514
|
+
/**
|
|
3515
|
+
* 방 단위 집계 payload 생성 — {@link #_emitAssistantRoomProgress} 와 {@link #getAssistantProgress} 의
|
|
3516
|
+
* <b>공통 SSOT</b>. 두 곳에서 각자 조립하면 "이벤트로 본 상태"와 "물어봐서 본 상태"가 갈린다.
|
|
3517
|
+
* @private
|
|
3518
|
+
*/
|
|
3519
|
+
_assistantRoomProgressPayload(roomId) {
|
|
3493
3520
|
const slots = this._assistantProgress.get(roomId);
|
|
3494
3521
|
const alive = slots ? Array.from(slots.entries()) : [];
|
|
3495
3522
|
if (alive.length === 0) {
|
|
3496
|
-
|
|
3523
|
+
return {
|
|
3497
3524
|
roomId, active: false, streamCount: 0,
|
|
3498
|
-
streamId: null, personaId: null, phase: null, label: null, text: null, textAvailable: true
|
|
3499
|
-
|
|
3500
|
-
|
|
3525
|
+
streamId: null, personaId: null, phase: null, label: null, text: null, textAvailable: true,
|
|
3526
|
+
streams: []
|
|
3527
|
+
};
|
|
3501
3528
|
}
|
|
3502
3529
|
const [streamId, slot] = alive.reduce((a, b) => (b[1].order > a[1].order ? b : a));
|
|
3503
|
-
|
|
3530
|
+
return {
|
|
3504
3531
|
roomId,
|
|
3505
3532
|
active: true,
|
|
3506
3533
|
streamCount: alive.length,
|
|
@@ -3509,8 +3536,43 @@ class ChatClient extends EventEmitter {
|
|
|
3509
3536
|
phase: slot.phase,
|
|
3510
3537
|
label: slot.phase ? (this._assistantPhaseLabels[slot.phase] || null) : null,
|
|
3511
3538
|
text: slot.textAvailable ? (slot.text || null) : null,
|
|
3512
|
-
textAvailable: slot.textAvailable
|
|
3513
|
-
|
|
3539
|
+
textAvailable: slot.textAvailable,
|
|
3540
|
+
// stream 단위 UI(권장 (B))가 마운트 즉시 버블을 복원할 수 있도록 전부 싣는다.
|
|
3541
|
+
// 도착 순서(order)대로 — 소비자가 "가장 최근"을 다시 계산하지 않아도 되게 한다.
|
|
3542
|
+
streams: alive
|
|
3543
|
+
.sort((a, b) => a[1].order - b[1].order)
|
|
3544
|
+
.map(([id, s]) => ({
|
|
3545
|
+
streamId: id,
|
|
3546
|
+
personaId: s.personaId,
|
|
3547
|
+
phase: s.phase,
|
|
3548
|
+
label: s.phase ? (this._assistantPhaseLabels[s.phase] || null) : null,
|
|
3549
|
+
text: s.textAvailable ? (s.text || null) : null,
|
|
3550
|
+
textAvailable: s.textAvailable,
|
|
3551
|
+
resumed: s.resumed === true
|
|
3552
|
+
}))
|
|
3553
|
+
};
|
|
3554
|
+
}
|
|
3555
|
+
|
|
3556
|
+
/**
|
|
3557
|
+
* 방의 <b>현재</b> AI 진행 상태를 즉시 반환 (네트워크 호출 없음).
|
|
3558
|
+
*
|
|
3559
|
+
* <p>{@code assistantProgress} / {@code assistantRoomProgress} 는 transient 이벤트라, 방 화면을 나갔다
|
|
3560
|
+
* 들어오면 프론트 상태가 비어 있는데 <b>이미 지나간 이벤트는 다시 오지 않는다</b>. 마운트 시점에 이걸
|
|
3561
|
+
* 한 번 읽으면 다음 이벤트를 기다리지 않고 바로 그릴 수 있다 — 재입장 스냅샷(1 RTT)보다도 빠르다.</p>
|
|
3562
|
+
*
|
|
3563
|
+
* <p>반환 형태는 {@code assistantRoomProgress} 이벤트와 동일하고, stream 단위 UI 를 위해 {@code streams}
|
|
3564
|
+
* 배열이 추가된다. 진행 중인 것이 없으면 {@code active:false} + 빈 배열.</p>
|
|
3565
|
+
*
|
|
3566
|
+
* @param {string} roomId - 채팅방 ID
|
|
3567
|
+
* @returns {Object} { roomId, active, streamCount, streamId, personaId, phase, label, text, textAvailable, streams[] }
|
|
3568
|
+
*
|
|
3569
|
+
* @example
|
|
3570
|
+
* // 방 화면 마운트 시 — 이벤트를 기다리지 않고 즉시 복원
|
|
3571
|
+
* const p = client.chat.getAssistantProgress(roomId);
|
|
3572
|
+
* if (p.active) renderBubble(p);
|
|
3573
|
+
*/
|
|
3574
|
+
getAssistantProgress(roomId) {
|
|
3575
|
+
return this._assistantRoomProgressPayload(roomId);
|
|
3514
3576
|
}
|
|
3515
3577
|
|
|
3516
3578
|
/**
|
|
@@ -52,6 +52,10 @@ const CHAT_DELEGATE_METHODS = [
|
|
|
52
52
|
'isSubscribed',
|
|
53
53
|
'startTyping',
|
|
54
54
|
'stopTyping',
|
|
55
|
+
// AI 진행 표시 — 마운트 즉시 복원용 동기 조회 + 수동 재개. 여기 없으면 최상위 클라이언트에서
|
|
56
|
+
// 런타임 undefined 가 된다(타입 선언만 있고 배선이 없으면 타입이 거짓말을 한다).
|
|
57
|
+
'getAssistantProgress',
|
|
58
|
+
'resumeAssistantStreams',
|
|
55
59
|
'getAssistants',
|
|
56
60
|
'getRoomAiMeta',
|
|
57
61
|
'rateAssistantMessage',
|
package/types/index.d.ts
CHANGED
|
@@ -1260,6 +1260,29 @@ export interface AssistantRoomProgressEvent {
|
|
|
1260
1260
|
textAvailable?: boolean;
|
|
1261
1261
|
}
|
|
1262
1262
|
|
|
1263
|
+
/** {@link ChatClient.getAssistantProgress} 가 돌려주는 stream 1건. */
|
|
1264
|
+
export interface AssistantProgressStreamSnapshot {
|
|
1265
|
+
streamId: string;
|
|
1266
|
+
personaId: string | null;
|
|
1267
|
+
phase: 'THINKING' | 'SEARCHING' | 'PLANNING' | 'WRITING' | null;
|
|
1268
|
+
label: string | null;
|
|
1269
|
+
text: string | null;
|
|
1270
|
+
textAvailable: boolean;
|
|
1271
|
+
/** 서버 스냅샷으로 복원된 진행분이면 true. */
|
|
1272
|
+
resumed: boolean;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
/**
|
|
1276
|
+
* 방의 **현재** AI 진행 상태 (v5.3.0 — {@link ChatClient.getAssistantProgress} 반환).
|
|
1277
|
+
*
|
|
1278
|
+
* <p>{@link AssistantRoomProgressEvent} 와 같은 형태에 stream 단위 UI 를 위한 `streams` 가 더해진다.
|
|
1279
|
+
* 이벤트는 transient 라 화면을 나갔다 들어오면 다시 오지 않는다 — 마운트 시 이걸 한 번 읽는다.</p>
|
|
1280
|
+
*/
|
|
1281
|
+
export interface AssistantProgressSnapshot extends AssistantRoomProgressEvent {
|
|
1282
|
+
/** 살아 있는 stream 전체 (도착 순서). 없으면 빈 배열. */
|
|
1283
|
+
streams: AssistantProgressStreamSnapshot[];
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1263
1286
|
// ============================================================================
|
|
1264
1287
|
// Options — constructor & method
|
|
1265
1288
|
// ============================================================================
|
|
@@ -2017,6 +2040,17 @@ export class ChatClient implements SdkEventEmitter<ChatClientEvents> {
|
|
|
2017
2040
|
|
|
2018
2041
|
startTyping(roomId: string): void;
|
|
2019
2042
|
stopTyping(roomId: string): void;
|
|
2043
|
+
|
|
2044
|
+
/**
|
|
2045
|
+
* 방의 현재 AI 진행 상태를 즉시 반환 (네트워크 호출 없음, v5.3.0).
|
|
2046
|
+
* 진행 표시 이벤트는 transient 라 방 화면 마운트 시 이걸 읽어 버블을 복원한다.
|
|
2047
|
+
*/
|
|
2048
|
+
getAssistantProgress(roomId: string): AssistantProgressSnapshot;
|
|
2049
|
+
/**
|
|
2050
|
+
* 구독 중인 모든 방의 진행 스트림 스냅샷을 서버에서 다시 받는다 (v5.1.0).
|
|
2051
|
+
* 재연결·탭 복귀 때 SDK 가 자동 호출하므로 보통은 직접 부를 일이 없다.
|
|
2052
|
+
*/
|
|
2053
|
+
resumeAssistantStreams(reason?: string): Promise<void>;
|
|
2020
2054
|
}
|
|
2021
2055
|
|
|
2022
2056
|
export class WebRTCClient implements SdkEventEmitter<WebRTCClientEvents> {
|
|
@@ -2400,6 +2434,17 @@ export default class TalkFlowClient implements SdkEventEmitter<TalkFlowClientEve
|
|
|
2400
2434
|
startTyping(roomId: string): void;
|
|
2401
2435
|
stopTyping(roomId: string): void;
|
|
2402
2436
|
|
|
2437
|
+
/**
|
|
2438
|
+
* 방의 현재 AI 진행 상태를 즉시 반환 (네트워크 호출 없음, v5.3.0).
|
|
2439
|
+
* 진행 표시 이벤트는 transient 라 방 화면 마운트 시 이걸 읽어 버블을 복원한다.
|
|
2440
|
+
*/
|
|
2441
|
+
getAssistantProgress(roomId: string): AssistantProgressSnapshot;
|
|
2442
|
+
/**
|
|
2443
|
+
* 구독 중인 모든 방의 진행 스트림 스냅샷을 서버에서 다시 받는다 (v5.1.0).
|
|
2444
|
+
* 재연결·탭 복귀 때 SDK 가 자동 호출하므로 보통은 직접 부를 일이 없다.
|
|
2445
|
+
*/
|
|
2446
|
+
resumeAssistantStreams(reason?: string): Promise<void>;
|
|
2447
|
+
|
|
2403
2448
|
// WebRTC delegations
|
|
2404
2449
|
initializeIceServers(): Promise<RTCIceServer[]>;
|
|
2405
2450
|
getTurnCredentials(): Promise<{ iceServers: RTCIceServer[] }>;
|