@bdky/aaas-pilot-kit 1.0.5 → 1.0.6

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.
@@ -25,6 +25,15 @@ export interface IInterruptEventPayload {
25
25
  type ExtractResponseType<P> = P extends BaseAgentService<infer R, any> ? R : never;
26
26
  export interface IReplyStartEventPayload<AS extends BaseAgentService = BaseAgentService> {
27
27
  agentResponse: AgentResponse<ExtractResponseType<AS>> | null;
28
+ /**
29
+ * 数字人服务处理延迟(毫秒)
30
+ * 从第一次 renderStreamText 到 render_subtitle 的耗时
31
+ */
32
+ latency?: number;
33
+ /**
34
+ * 数字人服务的请求 ID,用于追踪
35
+ */
36
+ requestId: string;
28
37
  }
29
38
  export declare class AaaSPilotKitController<AS extends BaseAgentService = BaseAgentService> implements IAaaSPilotKitController<AS> {
30
39
  private readonly opts;
@@ -47,6 +56,8 @@ export declare class AaaSPilotKitController<AS extends BaseAgentService = BaseAg
47
56
  private multiModAbortControllers;
48
57
  /** playWaitFor监听listener */
49
58
  private playWaitForListener;
59
+ /** 记录每次 query 的开始时间,用于计算 TTFT */
60
+ private queryStartTime;
50
61
  private readonly weirwood;
51
62
  constructor(opts: IResolvedOptions, errorManager: ErrorManager, agentService: AS, asrService: BaseAsrService, digitalHumanService: BaseDigitalHumanService, conversationService: ConversationService);
52
63
  mount: ($container?: HTMLElement) => Promise<void>;
@@ -120,6 +131,10 @@ export declare class AaaSPilotKitController<AS extends BaseAgentService = BaseAg
120
131
  private readonly createNewAIWorkerConversation;
121
132
  private readonly handleAgentAnswerCompleted;
122
133
  private readonly handleAgentInstructionReceived;
134
+ /**
135
+ * 处理 TTFT 事件:计算总延迟并转发
136
+ */
137
+ private readonly handleTtft;
123
138
  private readonly handleAsrServiceStarted;
124
139
  /**
125
140
  * 处理asr消息
@@ -19,6 +19,11 @@ export declare namespace NBaseAgentService {
19
19
  }
20
20
  type IHangupEventPayload = IEventWithSessionIdPayload;
21
21
  type ICompletedEventPayload = IEventWithSessionIdPayload;
22
+ interface ITtftEventPayload extends IEventWithSessionIdPayload {
23
+ firstToken: string;
24
+ timestamp: number;
25
+ totalLatency?: number;
26
+ }
22
27
  interface IEmitter {
23
28
  data: IDataEventPayload;
24
29
  completed: ICompletedEventPayload;
@@ -28,6 +33,7 @@ export declare namespace NBaseAgentService {
28
33
  response: IResponseEventPayload;
29
34
  quota_expired: IEventWithSessionIdPayload;
30
35
  usage_quota_reached: IEventWithSessionIdPayload;
36
+ ttft: ITtftEventPayload;
31
37
  }
32
38
  }
33
39
  export declare abstract class BaseAgentService<R = any, E extends NBaseAgentService.IEmitter = NBaseAgentService.IEmitter> {
@@ -49,6 +55,10 @@ export declare abstract class BaseAgentService<R = any, E extends NBaseAgentServ
49
55
  * 响应管理器,维护所有 Agent 回复
50
56
  */
51
57
  protected responseManager: ResponseManager<R>;
58
+ /**
59
+ * TTFT 标记:是否已经发出首字返回事件
60
+ */
61
+ protected hasTtftEmitted: boolean;
52
62
  constructor(request: CommonRequest, errorManager: ErrorManager, opts: IResolvedOptions);
53
63
  get sessionId(): string;
54
64
  get queryId(): string;
@@ -77,6 +87,17 @@ export declare abstract class BaseAgentService<R = any, E extends NBaseAgentServ
77
87
  protected onResponse: (response: R) => void;
78
88
  protected onUsageQuotaReached: (payload: E["usage_quota_reached"]) => void;
79
89
  protected onQuotaExpired: (payload: E["quota_expired"]) => void;
90
+ /**
91
+ * 发射 TTFT 事件(仅触发一次)
92
+ * 注意:totalLatency 为可选字段,由 Controller 层自动计算并填充
93
+ */
94
+ protected onTtft: (payload: Omit<E["ttft"], "totalLatency"> & {
95
+ totalLatency?: number;
96
+ }) => void;
97
+ /**
98
+ * 重置 TTFT 标记(子类在 query 开始时调用)
99
+ */
100
+ protected resetTtftFlag: () => void;
80
101
  protected _dispose: () => void;
81
102
  abstract query(text: string): Promise<any>;
82
103
  abstract dispose(): void;
@@ -11,9 +11,18 @@ export declare namespace NAIWorkerConversationBean {
11
11
  content: string;
12
12
  completed: boolean;
13
13
  }
14
+ /**
15
+ * conversation_end 事件数据结构
16
+ * 当所有 contents 都完成渲染时触发
17
+ */
18
+ interface IConversationEndPayload extends IConversationBeanSnapshot<'aiWorker'> {
19
+ contents: Array<NMultimodalContent.ISnapshot<any>>;
20
+ timestamp: number;
21
+ }
14
22
  interface IEmitter extends NConversationBean.IEmitter {
15
23
  content_change: IContentChangePayload;
16
24
  queue_empty: never;
25
+ conversation_end: IConversationEndPayload;
17
26
  interrupt: never;
18
27
  }
19
28
  }
@@ -22,6 +31,11 @@ export declare class AIWorkerConversationBean extends ConversationBean<'aiWorker
22
31
  contents: Array<ImageContent | VideoContent | TextContent>;
23
32
  private readonly queue;
24
33
  private readonly customXmlParser;
34
+ /**
35
+ * 标记当前会话是否已接收到"结束"信号
36
+ * 只有在此标记为 true 且队列清空时,才触发 conversation_end 事件
37
+ */
38
+ private hasReceivedEndSignal;
25
39
  constructor(d: Partial<IConversationBeanSnapshot<'aiWorker'>>, opts: IResolvedOptions);
26
40
  get fulltext(): string;
27
41
  static create: (opts: IResolvedOptions) => AIWorkerConversationBean;
@@ -35,5 +49,10 @@ export declare class AIWorkerConversationBean extends ConversationBean<'aiWorker
35
49
  appendText: (text: string) => void;
36
50
  dispose: () => void;
37
51
  interrupt: () => void;
52
+ /**
53
+ * 标记当前会话已结束
54
+ * 调用此方法后,当队列清空时将触发 conversation_end 事件
55
+ */
56
+ markAsEnded: () => void;
38
57
  private readonly bindEvents;
39
58
  }
@@ -13,6 +13,11 @@ export declare namespace NAbstractDigitalHumanService {
13
13
  }
14
14
  interface IRenderSubtitleEventPayload extends IBaseEmitterPayload {
15
15
  subtitle: ISubtitle;
16
+ /**
17
+ * 从第一次 renderStreamText 到 render_subtitle 的延迟(毫秒)
18
+ * 仅在首次 render_subtitle 时有值
19
+ */
20
+ latency?: number;
16
21
  }
17
22
  interface IEmitter {
18
23
  disconnect_alert: IBaseEmitterPayload;
@@ -38,6 +43,10 @@ export declare abstract class BaseDigitalHumanService {
38
43
  protected _canInterrupt: boolean;
39
44
  protected ssmlHandlers: NAbstractDigitalHumanService.ISsmlHandler[];
40
45
  protected token: string;
46
+ /**
47
+ * 记录每个 requestId 的开始时间,用于计算 latency
48
+ */
49
+ protected latencyStartMap: Map<string, number>;
41
50
  constructor(opts: IOptions, request: CommonRequest, errorManager: ErrorManager);
42
51
  get isRendering(): boolean;
43
52
  get isMuted(): boolean;
@@ -548,6 +548,42 @@ export interface IAaaSPilotKitEmitter<AS extends BaseAgentService = BaseAgentSer
548
548
  devices?: MediaDeviceInfo[];
549
549
  permissionState?: PermissionState;
550
550
  };
551
+ /**
552
+ * ⚡【TTFT 事件】Time To First Token - 大模型首字返回事件
553
+ *
554
+ * 💡 触发时机:
555
+ * - Agent SSE 返回第一个非空 answer 时立即触发
556
+ * - 早于 reply_start(数字人播报开始)约 100~500ms
557
+ *
558
+ * 🎯 使用场景:
559
+ * - 性能监控:统计大模型响应速度(TTFT 指标)
560
+ * - 用户体验:隐藏"正在思考..."加载动画
561
+ * - 埋点上报:记录首字延迟数据
562
+ *
563
+ * @payload {
564
+ * sessionId: string; // 会话 ID
565
+ * queryId: string; // 查询 ID
566
+ * firstToken: string; // 首个 token 内容(可能是字/词/句子片段)
567
+ * timestamp: number; // 首字返回时间戳(performance.now(),高精度)
568
+ * totalLatency: number; // 从 query 开始到首字的总延迟(毫秒,高精度)
569
+ * }
570
+ *
571
+ * ⚠️ 注意:
572
+ * - timestamp 和 totalLatency 使用 performance.now() 获取,提供亚毫秒级精度
573
+ * - 不受系统时间调整影响,适合性能测量
574
+ *
575
+ * @example 监听 TTFT 事件
576
+ * ```typescript
577
+ * controller.emitter.on('ttft', (payload) => {
578
+ * console.log('TTFT:', payload.totalLatency.toFixed(2), 'ms');
579
+ * console.log('首个 token:', payload.firstToken);
580
+ * setLoading(false); // 隐藏加载动画
581
+ * });
582
+ * ```
583
+ */
584
+ ttft: NBaseAgentService.ITtftEventPayload & {
585
+ totalLatency: number;
586
+ };
551
587
  }
552
588
  export interface IAaaSPilotKitController<AS extends BaseAgentService = BaseAgentService> {
553
589
  emitter: Emittery<IAaaSPilotKitEmitter<AS>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bdky/aaas-pilot-kit",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "license": "MIT",
5
5
  "contributors": [
6
6
  {