@ray-js/t-agent-plugin-aistream 0.2.8-beta.3 → 0.2.8-beta.5

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.
@@ -1,6 +1,15 @@
1
1
  import { ChatAgent } from '@ray-js/t-agent';
2
2
  interface WithBuildInOptions {
3
+ /** 是否开启 TTS 自动播放,默认 false */
3
4
  audioAutoPlay?: boolean;
5
+ /** 是否开启智能家居技能(设备控制、场景管理),默认 true */
6
+ smartHome?: boolean;
7
+ /** 是否开启知识库关联文档展示,默认 true */
8
+ documents?: boolean;
9
+ /** 是否开启图片附件展示,默认 true */
10
+ image?: boolean;
11
+ /** 是否开启 TTS 语音播放能力,默认 true */
12
+ audio?: boolean;
4
13
  }
5
14
  export declare function withBuildIn(options?: WithBuildInOptions): (_agent: ChatAgent) => {};
6
15
  export {};
@@ -33,9 +33,38 @@ export function withBuildIn(options) {
33
33
  });
34
34
 
35
35
  // 关联文档
36
-
37
- // 关联智能家居卡片
38
- (() => {
36
+ const enableDocuments = () => {
37
+ onSkillsEnd((skills, responseMessage) => {
38
+ if (!responseMessage) {
39
+ return;
40
+ }
41
+ const data = {
42
+ documents: []
43
+ };
44
+ for (let i = 0; i < skills.length; i++) {
45
+ var _content$custom;
46
+ const skill = skills[i];
47
+ if (skill.code !== BuildInSkillCode.SEARCH_KNOWLEDGE) {
48
+ continue;
49
+ }
50
+ const content = skill;
51
+ if (!((_content$custom = content.custom) !== null && _content$custom !== void 0 && (_content$custom = _content$custom.data) !== null && _content$custom !== void 0 && _content$custom.documents)) {
52
+ continue;
53
+ }
54
+ for (let i1 = 0; i1 < content.custom.data.documents.length; i1++) {
55
+ const doc = content.custom.data.documents[i1];
56
+ data.documents.push({
57
+ title: doc.title,
58
+ url: doc.url
59
+ });
60
+ }
61
+ }
62
+ if (data.documents.length) {
63
+ responseMessage.bubble.addTile('documents', data);
64
+ }
65
+ });
66
+ };
67
+ const enableSmartHome = () => {
39
68
  onSkillsEnd((skills, responseMessage) => {
40
69
  if (!responseMessage) {
41
70
  return;
@@ -117,41 +146,8 @@ export function withBuildIn(options) {
117
146
  responseMessage.bubble.addTile('operateCard', operateData);
118
147
  }
119
148
  });
120
- })();
121
- // 最后是关联文档
122
- (() => {
123
- onSkillsEnd((skills, responseMessage) => {
124
- if (!responseMessage) {
125
- return;
126
- }
127
- const data = {
128
- documents: []
129
- };
130
- for (let i = 0; i < skills.length; i++) {
131
- var _content$custom;
132
- const skill = skills[i];
133
- if (skill.code !== BuildInSkillCode.SEARCH_KNOWLEDGE) {
134
- continue;
135
- }
136
- const content = skill;
137
- if (!((_content$custom = content.custom) !== null && _content$custom !== void 0 && (_content$custom = _content$custom.data) !== null && _content$custom !== void 0 && _content$custom.documents)) {
138
- continue;
139
- }
140
- for (let i1 = 0; i1 < content.custom.data.documents.length; i1++) {
141
- const doc = content.custom.data.documents[i1];
142
- data.documents.push({
143
- title: doc.title,
144
- url: doc.url
145
- });
146
- }
147
- }
148
- if (data.documents.length) {
149
- responseMessage.bubble.addTile('documents', data);
150
- }
151
- });
152
- })();
153
- // 图片
154
- (() => {
149
+ };
150
+ const enableImage = () => {
155
151
  onAttachmentsEnd((parts, respMsg) => {
156
152
  const streamSession = session.get('AIStream.streamSession');
157
153
  const prefix = streamSession.baseCacheDir;
@@ -166,9 +162,8 @@ export function withBuildIn(options) {
166
162
  }
167
163
  });
168
164
  });
169
- })();
170
- // 语音
171
- (() => {
165
+ };
166
+ const enableAudio = () => {
172
167
  // 当前正在播放的消息 id 保存在 session 中,保证同一时刻只播一条;
173
168
  // 组件里的 playing 状态从 session 的 audioPlaying / playingMessageId 派生。
174
169
  // playing 是纯运行时状态,不落到 tile.data(避免被持久化)。
@@ -216,52 +211,39 @@ export function withBuildIn(options) {
216
211
  // 音频包结束时,往气泡里插入一个语音播放按钮(BubbleToolTile)。
217
212
  // 只持久化播放所需的音频参数,不含 playing 状态。
218
213
  //
219
- // 注意:音频按流式分多包下发,格式头(codecType/sampleRate/channels/bitDepth)
220
- // 只在 START 包里携带,END 包通常只带最终的 path/pts。因此不能只取 END 包,
221
- // 需要按音频流 id(part.id 在同一段音频的所有分包间一致)聚合,
222
- // START 包的格式参数与 END 包的 path 合并后再建 tile,
223
- // 否则持久化后点击播放时格式参数会全部丢失,只剩 path。
214
+ // 注意:音频按流式分多包下发,播放所需的完整参数(path + 格式头
215
+ // codecType/sampleRate/channels/bitDepth)只在首包(START/ONLY_ONE)携带;
216
+ // 后续 END 等包里这些字段是 0(而非 null/undefined),会污染数据。
217
+ // 因此只取每段音频的首包,丢弃后续包,按音频流 id(part.id 在同一段音频的
218
+ // 所有分包间一致)去重。
224
219
  onAttachmentsEnd((parts, respMsg) => {
225
220
  const audioMap = new Map();
226
221
  parts.forEach(i => {
227
- var _audio$path, _audio$pts, _audio$codecType, _audio$sampleRate, _audio$channels, _audio$bitDepth;
228
222
  if (i.attachmentType !== 'audio') {
229
223
  return;
230
224
  }
231
225
  const audio = i.attachment;
232
- const entry = audioMap.get(i.id) || {
233
- audio: {},
234
- complete: false
235
- };
236
226
 
237
- // 合并各分包:后到的非空字段覆盖,空字段保留先前值(END 包不会用 undefined 覆盖掉格式参数)
238
- entry.audio = {
239
- path: (_audio$path = audio.path) !== null && _audio$path !== void 0 ? _audio$path : entry.audio.path,
240
- pts: (_audio$pts = audio.pts) !== null && _audio$pts !== void 0 ? _audio$pts : entry.audio.pts,
241
- codecType: (_audio$codecType = audio.codecType) !== null && _audio$codecType !== void 0 ? _audio$codecType : entry.audio.codecType,
242
- sampleRate: (_audio$sampleRate = audio.sampleRate) !== null && _audio$sampleRate !== void 0 ? _audio$sampleRate : entry.audio.sampleRate,
243
- channels: (_audio$channels = audio.channels) !== null && _audio$channels !== void 0 ? _audio$channels : entry.audio.channels,
244
- bitDepth: (_audio$bitDepth = audio.bitDepth) !== null && _audio$bitDepth !== void 0 ? _audio$bitDepth : entry.audio.bitDepth
245
- };
246
- if (audio.streamFlag === StreamFlag.ONLY_ONE || audio.streamFlag === StreamFlag.END) {
247
- entry.complete = true;
248
- // END 包的 path 是最终完整文件,确保覆盖
249
- if (audio.path) {
250
- entry.audio.path = audio.path;
251
- }
227
+ // 只接收首包,后续包直接丢弃
228
+ if (audio.streamFlag !== StreamFlag.START && audio.streamFlag !== StreamFlag.ONLY_ONE) {
229
+ return;
252
230
  }
253
- audioMap.set(i.id, entry);
254
- });
255
- audioMap.forEach(_ref => {
256
- let {
257
- audio,
258
- complete
259
- } = _ref;
260
- if (complete) {
261
- respMsg.bubble.addTile('bubbleTool', {
262
- audio
263
- });
231
+ if (audioMap.has(i.id)) {
232
+ return;
264
233
  }
234
+ audioMap.set(i.id, {
235
+ path: audio.path,
236
+ pts: audio.pts,
237
+ codecType: audio.codecType,
238
+ sampleRate: audio.sampleRate,
239
+ channels: audio.channels,
240
+ bitDepth: audio.bitDepth
241
+ });
242
+ });
243
+ audioMap.forEach(audio => {
244
+ respMsg.bubble.addTile('bubbleTool', {
245
+ audio
246
+ });
265
247
  });
266
248
  });
267
249
 
@@ -291,7 +273,25 @@ export function withBuildIn(options) {
291
273
  await setPlayingMessage(messageId);
292
274
  }
293
275
  });
294
- })();
276
+ };
277
+
278
+ // 各功能默认开启,不传选项保持兼容;显式传 false 才关闭
279
+ // 关联智能家居卡片
280
+ if ((options === null || options === void 0 ? void 0 : options.smartHome) !== false) {
281
+ enableSmartHome();
282
+ }
283
+ // 关联文档
284
+ if ((options === null || options === void 0 ? void 0 : options.documents) !== false) {
285
+ enableDocuments();
286
+ }
287
+ // 图片
288
+ if ((options === null || options === void 0 ? void 0 : options.image) !== false) {
289
+ enableImage();
290
+ }
291
+ // 语音
292
+ if ((options === null || options === void 0 ? void 0 : options.audio) !== false) {
293
+ enableAudio();
294
+ }
295
295
  return {};
296
296
  };
297
297
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/t-agent-plugin-aistream",
3
- "version": "0.2.8-beta.3",
3
+ "version": "0.2.8-beta.5",
4
4
  "author": "Tuya.inc",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -36,5 +36,5 @@
36
36
  "devDependencies": {
37
37
  "@types/url-parse": "^1.4.11"
38
38
  },
39
- "gitHead": "938bc0c7da7d23dbbad8c3c14c97e5f4007f06f7"
39
+ "gitHead": "433a3716af02d01c19f670855e62000fcae37d34"
40
40
  }