@downcity/plugins 1.0.174 → 1.0.193

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.
Files changed (301) hide show
  1. package/bin/BuiltinPlugins.d.ts +4 -9
  2. package/bin/BuiltinPlugins.d.ts.map +1 -1
  3. package/bin/BuiltinPlugins.js +4 -8
  4. package/bin/BuiltinPlugins.js.map +1 -1
  5. package/bin/chat/Action.d.ts +8 -2
  6. package/bin/chat/Action.d.ts.map +1 -1
  7. package/bin/chat/Action.js +9 -5
  8. package/bin/chat/Action.js.map +1 -1
  9. package/bin/chat/ChatPlugin.d.ts +2 -22
  10. package/bin/chat/ChatPlugin.d.ts.map +1 -1
  11. package/bin/chat/ChatPlugin.js +2 -21
  12. package/bin/chat/ChatPlugin.js.map +1 -1
  13. package/bin/chat/Index.d.ts +1 -1
  14. package/bin/chat/Index.d.ts.map +1 -1
  15. package/bin/chat/channels/BaseChatChannel.js +1 -1
  16. package/bin/chat/channels/BaseChatChannel.js.map +1 -1
  17. package/bin/chat/channels/Configuration.d.ts +1 -1
  18. package/bin/chat/channels/Configuration.js +1 -1
  19. package/bin/chat/channels/RuntimeChannel.d.ts +2 -3
  20. package/bin/chat/channels/RuntimeChannel.d.ts.map +1 -1
  21. package/bin/chat/channels/RuntimeChannel.js +0 -8
  22. package/bin/chat/channels/RuntimeChannel.js.map +1 -1
  23. package/bin/chat/channels/feishu/Feishu.d.ts.map +1 -1
  24. package/bin/chat/channels/feishu/Feishu.js +2 -1
  25. package/bin/chat/channels/feishu/Feishu.js.map +1 -1
  26. package/bin/chat/runtime/ChannelContextStore.d.ts.map +1 -1
  27. package/bin/chat/runtime/ChannelContextStore.js +13 -12
  28. package/bin/chat/runtime/ChannelContextStore.js.map +1 -1
  29. package/bin/chat/runtime/ChatActionExecution.d.ts +26 -1
  30. package/bin/chat/runtime/ChatActionExecution.d.ts.map +1 -1
  31. package/bin/chat/runtime/ChatActionExecution.js +31 -3
  32. package/bin/chat/runtime/ChatActionExecution.js.map +1 -1
  33. package/bin/chat/runtime/ChatActionInput.d.ts +1 -2
  34. package/bin/chat/runtime/ChatActionInput.d.ts.map +1 -1
  35. package/bin/chat/runtime/ChatActionInput.js +1 -27
  36. package/bin/chat/runtime/ChatActionInput.js.map +1 -1
  37. package/bin/chat/runtime/ChatChannelActions.d.ts +2 -66
  38. package/bin/chat/runtime/ChatChannelActions.d.ts.map +1 -1
  39. package/bin/chat/runtime/ChatChannelActions.js +3 -195
  40. package/bin/chat/runtime/ChatChannelActions.js.map +1 -1
  41. package/bin/chat/runtime/ChatChannelConfig.d.ts +2 -23
  42. package/bin/chat/runtime/ChatChannelConfig.d.ts.map +1 -1
  43. package/bin/chat/runtime/ChatChannelConfig.js +3 -116
  44. package/bin/chat/runtime/ChatChannelConfig.js.map +1 -1
  45. package/bin/chat/runtime/ChatChannelCore.d.ts +0 -14
  46. package/bin/chat/runtime/ChatChannelCore.d.ts.map +1 -1
  47. package/bin/chat/runtime/ChatChannelCore.js +1 -1
  48. package/bin/chat/runtime/ChatChannelCore.js.map +1 -1
  49. package/bin/chat/runtime/ChatChannelFacade.d.ts +1 -1
  50. package/bin/chat/runtime/ChatChannelFacade.d.ts.map +1 -1
  51. package/bin/chat/runtime/ChatChannelFacade.js +1 -1
  52. package/bin/chat/runtime/ChatChannelFacade.js.map +1 -1
  53. package/bin/chat/runtime/ChatHistoryStore.d.ts.map +1 -1
  54. package/bin/chat/runtime/ChatHistoryStore.js +4 -3
  55. package/bin/chat/runtime/ChatHistoryStore.js.map +1 -1
  56. package/bin/chat/runtime/ChatPluginActionRegistry.d.ts.map +1 -1
  57. package/bin/chat/runtime/ChatPluginActionRegistry.js +27 -89
  58. package/bin/chat/runtime/ChatPluginActionRegistry.js.map +1 -1
  59. package/bin/chat/runtime/ChatPluginSystem.d.ts +3 -2
  60. package/bin/chat/runtime/ChatPluginSystem.d.ts.map +1 -1
  61. package/bin/chat/runtime/ChatPluginSystem.js +5 -5
  62. package/bin/chat/runtime/ChatPluginSystem.js.map +1 -1
  63. package/bin/chat/runtime/ChatQueueStore.d.ts +1 -1
  64. package/bin/chat/runtime/ChatQueueStore.js +2 -2
  65. package/bin/chat/runtime/ChatQueueStore.js.map +1 -1
  66. package/bin/chat/runtime/ChatQueueWorker.js +1 -1
  67. package/bin/chat/runtime/ChatQueueWorker.js.map +1 -1
  68. package/bin/chat/runtime/ChatSessionDelete.d.ts.map +1 -1
  69. package/bin/chat/runtime/ChatSessionDelete.js +11 -20
  70. package/bin/chat/runtime/ChatSessionDelete.js.map +1 -1
  71. package/bin/chat/runtime/ChatStorage.d.ts +32 -0
  72. package/bin/chat/runtime/ChatStorage.d.ts.map +1 -0
  73. package/bin/chat/runtime/ChatStorage.js +158 -0
  74. package/bin/chat/runtime/ChatStorage.js.map +1 -0
  75. package/bin/chat/runtime/SystemPrompt.d.ts +3 -2
  76. package/bin/chat/runtime/SystemPrompt.d.ts.map +1 -1
  77. package/bin/chat/runtime/SystemPrompt.js +4 -5
  78. package/bin/chat/runtime/SystemPrompt.js.map +1 -1
  79. package/bin/chat/types/ChannelConfiguration.d.ts +2 -2
  80. package/bin/chat/types/ChatPluginActionPayload.d.ts +7 -45
  81. package/bin/chat/types/ChatPluginActionPayload.d.ts.map +1 -1
  82. package/bin/chat/types/ChatPluginOptions.d.ts +0 -21
  83. package/bin/chat/types/ChatPluginOptions.d.ts.map +1 -1
  84. package/bin/chat/types/ChatStorage.d.ts +36 -0
  85. package/bin/chat/types/ChatStorage.d.ts.map +1 -0
  86. package/bin/chat/types/ChatStorage.js +9 -0
  87. package/bin/chat/types/ChatStorage.js.map +1 -0
  88. package/bin/contact/Action.d.ts +3 -2
  89. package/bin/contact/Action.d.ts.map +1 -1
  90. package/bin/contact/Action.js +2 -2
  91. package/bin/contact/Action.js.map +1 -1
  92. package/bin/contact/ContactPlugin.d.ts.map +1 -1
  93. package/bin/contact/ContactPlugin.js +17 -14
  94. package/bin/contact/ContactPlugin.js.map +1 -1
  95. package/bin/contact/runtime/ChatRuntime.js +1 -1
  96. package/bin/contact/runtime/ChatRuntime.js.map +1 -1
  97. package/bin/contact/types/ContactPluginOptions.d.ts +4 -0
  98. package/bin/contact/types/ContactPluginOptions.d.ts.map +1 -1
  99. package/bin/index.d.ts +5 -5
  100. package/bin/index.d.ts.map +1 -1
  101. package/bin/index.js +2 -2
  102. package/bin/index.js.map +1 -1
  103. package/bin/memory/Action.d.ts.map +1 -1
  104. package/bin/memory/Action.js +16 -4
  105. package/bin/memory/Action.js.map +1 -1
  106. package/bin/memory/runtime/Store.d.ts.map +1 -1
  107. package/bin/memory/runtime/Store.js +0 -22
  108. package/bin/memory/runtime/Store.js.map +1 -1
  109. package/bin/memory/runtime/Writer.d.ts +1 -1
  110. package/bin/memory/runtime/Writer.d.ts.map +1 -1
  111. package/bin/memory/runtime/Writer.js +2 -4
  112. package/bin/memory/runtime/Writer.js.map +1 -1
  113. package/bin/skill/Command.d.ts +3 -11
  114. package/bin/skill/Command.d.ts.map +1 -1
  115. package/bin/skill/Command.js +3 -31
  116. package/bin/skill/Command.js.map +1 -1
  117. package/bin/skill/PROMPT.d.ts +1 -1
  118. package/bin/skill/PROMPT.d.ts.map +1 -1
  119. package/bin/skill/PROMPT.js +1 -1
  120. package/bin/skill/PROMPT.js.map +1 -1
  121. package/bin/skill/Plugin.d.ts +3 -2
  122. package/bin/skill/Plugin.d.ts.map +1 -1
  123. package/bin/skill/Plugin.js +37 -129
  124. package/bin/skill/Plugin.js.map +1 -1
  125. package/bin/skill/runtime/Prompt.d.ts +11 -2
  126. package/bin/skill/runtime/Prompt.d.ts.map +1 -1
  127. package/bin/skill/runtime/Prompt.js +93 -8
  128. package/bin/skill/runtime/Prompt.js.map +1 -1
  129. package/bin/skill/runtime/SystemProvider.d.ts +2 -1
  130. package/bin/skill/runtime/SystemProvider.d.ts.map +1 -1
  131. package/bin/skill/runtime/SystemProvider.js +4 -9
  132. package/bin/skill/runtime/SystemProvider.js.map +1 -1
  133. package/bin/skill/types/SkillPlugin.d.ts +6 -18
  134. package/bin/skill/types/SkillPlugin.d.ts.map +1 -1
  135. package/bin/skill/types/SkillPlugin.js +2 -2
  136. package/bin/sound/Plugin.d.ts +69 -0
  137. package/bin/sound/Plugin.d.ts.map +1 -0
  138. package/bin/sound/Plugin.js +623 -0
  139. package/bin/sound/Plugin.js.map +1 -0
  140. package/bin/sound/types/SoundPlugin.d.ts +150 -0
  141. package/bin/sound/types/SoundPlugin.d.ts.map +1 -0
  142. package/bin/sound/types/SoundPlugin.js +10 -0
  143. package/bin/sound/types/SoundPlugin.js.map +1 -0
  144. package/bin/task/Action.d.ts +2 -0
  145. package/bin/task/Action.d.ts.map +1 -1
  146. package/bin/task/Action.js +6 -0
  147. package/bin/task/Action.js.map +1 -1
  148. package/bin/task/runtime/Runner.d.ts +4 -0
  149. package/bin/task/runtime/Runner.d.ts.map +1 -1
  150. package/bin/task/runtime/Runner.js +15 -11
  151. package/bin/task/runtime/Runner.js.map +1 -1
  152. package/bin/task/runtime/TaskActionExecution.d.ts +2 -0
  153. package/bin/task/runtime/TaskActionExecution.d.ts.map +1 -1
  154. package/bin/task/runtime/TaskActionExecution.js +1 -0
  155. package/bin/task/runtime/TaskActionExecution.js.map +1 -1
  156. package/bin/task/runtime/TaskPluginActionRegistry.d.ts.map +1 -1
  157. package/bin/task/runtime/TaskPluginActionRegistry.js +1 -0
  158. package/bin/task/runtime/TaskPluginActionRegistry.js.map +1 -1
  159. package/bin/task/runtime/TaskRunChatDispatch.js +1 -1
  160. package/bin/task/runtime/TaskRunChatDispatch.js.map +1 -1
  161. package/bin/task/runtime/TaskRunnerRound.d.ts.map +1 -1
  162. package/bin/task/runtime/TaskRunnerRound.js +19 -26
  163. package/bin/task/runtime/TaskRunnerRound.js.map +1 -1
  164. package/bin/task/runtime/TaskRunnerSession.d.ts +6 -2
  165. package/bin/task/runtime/TaskRunnerSession.d.ts.map +1 -1
  166. package/bin/task/runtime/TaskRunnerSession.js +93 -72
  167. package/bin/task/runtime/TaskRunnerSession.js.map +1 -1
  168. package/bin/task/runtime/TaskRunnerTypes.d.ts +4 -4
  169. package/bin/task/runtime/TaskRunnerTypes.d.ts.map +1 -1
  170. package/bin/task/types/TaskPluginOptions.d.ts.map +1 -1
  171. package/bin/web/PROMPT.d.ts +1 -1
  172. package/bin/web/PROMPT.d.ts.map +1 -1
  173. package/bin/web/PROMPT.js +2 -2
  174. package/bin/web/PROMPT.js.map +1 -1
  175. package/bin/web/Plugin.d.ts +1 -21
  176. package/bin/web/Plugin.d.ts.map +1 -1
  177. package/bin/web/Plugin.js +14 -79
  178. package/bin/web/Plugin.js.map +1 -1
  179. package/bin/web/runtime/Prompt.d.ts +14 -0
  180. package/bin/web/runtime/Prompt.d.ts.map +1 -0
  181. package/bin/web/runtime/Prompt.js +77 -0
  182. package/bin/web/runtime/Prompt.js.map +1 -0
  183. package/bin/web/types/WebPlugin.d.ts +40 -29
  184. package/bin/web/types/WebPlugin.d.ts.map +1 -1
  185. package/bin/web/types/WebPlugin.js +11 -3
  186. package/bin/web/types/WebPlugin.js.map +1 -1
  187. package/bin/workboard/runtime/Collector.js +1 -1
  188. package/bin/workboard/runtime/Collector.js.map +1 -1
  189. package/bin/workboard/runtime/Normalizer.js +1 -1
  190. package/bin/workboard/runtime/Normalizer.js.map +1 -1
  191. package/bin/workboard/runtime/SessionSummary.d.ts.map +1 -1
  192. package/bin/workboard/runtime/SessionSummary.js +11 -38
  193. package/bin/workboard/runtime/SessionSummary.js.map +1 -1
  194. package/package.json +8 -4
  195. package/scripts/chat-access.test.mjs +1 -1
  196. package/scripts/chat-channel-config.test.mjs +15 -64
  197. package/scripts/chat-storage.test.mjs +92 -0
  198. package/scripts/skill-plugin.test.mjs +93 -0
  199. package/scripts/sound-plugin.test.mjs +250 -0
  200. package/scripts/web-plugin.test.mjs +85 -0
  201. package/src/BuiltinPlugins.ts +7 -17
  202. package/src/chat/Action.ts +16 -5
  203. package/src/chat/ChatPlugin.ts +6 -35
  204. package/src/chat/Index.ts +0 -1
  205. package/src/chat/channels/BaseChatChannel.ts +1 -1
  206. package/src/chat/channels/Configuration.ts +1 -1
  207. package/src/chat/channels/RuntimeChannel.ts +2 -14
  208. package/src/chat/channels/feishu/Feishu.ts +2 -1
  209. package/src/chat/runtime/ChannelContextStore.ts +16 -12
  210. package/src/chat/runtime/ChatActionExecution.ts +48 -3
  211. package/src/chat/runtime/ChatActionInput.ts +0 -31
  212. package/src/chat/runtime/ChatChannelActions.ts +3 -254
  213. package/src/chat/runtime/ChatChannelConfig.ts +4 -133
  214. package/src/chat/runtime/ChatChannelCore.ts +1 -15
  215. package/src/chat/runtime/ChatChannelFacade.ts +0 -4
  216. package/src/chat/runtime/ChatHistoryStore.ts +4 -3
  217. package/src/chat/runtime/ChatPluginActionRegistry.ts +26 -98
  218. package/src/chat/runtime/ChatPluginSystem.ts +9 -3
  219. package/src/chat/runtime/ChatQueueStore.ts +2 -2
  220. package/src/chat/runtime/ChatQueueWorker.ts +1 -1
  221. package/src/chat/runtime/ChatSessionDelete.ts +11 -21
  222. package/src/chat/runtime/ChatStorage.ts +203 -0
  223. package/src/chat/runtime/SystemPrompt.ts +8 -3
  224. package/src/chat/types/ChannelConfiguration.ts +2 -2
  225. package/src/chat/types/ChatPluginActionPayload.ts +8 -49
  226. package/src/chat/types/ChatPluginOptions.ts +0 -22
  227. package/src/chat/types/ChatStorage.ts +37 -0
  228. package/src/contact/Action.ts +9 -1
  229. package/src/contact/ContactPlugin.ts +38 -14
  230. package/src/contact/runtime/ChatRuntime.ts +1 -1
  231. package/src/contact/types/ContactPluginOptions.ts +6 -0
  232. package/src/index.ts +16 -14
  233. package/src/memory/Action.ts +19 -4
  234. package/src/memory/runtime/Store.ts +0 -27
  235. package/src/memory/runtime/Writer.ts +2 -5
  236. package/src/skill/Command.ts +3 -33
  237. package/src/skill/PROMPT.ts +1 -1
  238. package/src/skill/PROMPT.ts.txt +5 -1
  239. package/src/skill/Plugin.ts +49 -156
  240. package/src/skill/runtime/Prompt.ts +109 -9
  241. package/src/skill/runtime/SystemProvider.ts +5 -9
  242. package/src/skill/types/SkillPlugin.ts +6 -18
  243. package/src/sound/Plugin.ts +699 -0
  244. package/src/sound/types/SoundPlugin.ts +163 -0
  245. package/src/task/Action.ts +8 -0
  246. package/src/task/runtime/Runner.ts +19 -13
  247. package/src/task/runtime/TaskActionExecution.ts +3 -0
  248. package/src/task/runtime/TaskPluginActionRegistry.ts +1 -0
  249. package/src/task/runtime/TaskRunChatDispatch.ts +1 -1
  250. package/src/task/runtime/TaskRunnerRound.ts +20 -38
  251. package/src/task/runtime/TaskRunnerSession.ts +108 -72
  252. package/src/task/runtime/TaskRunnerTypes.ts +4 -4
  253. package/src/task/types/TaskPluginOptions.ts +1 -0
  254. package/src/web/PROMPT.ts +2 -2
  255. package/src/web/PROMPT.ts.txt +4 -2
  256. package/src/web/Plugin.ts +20 -90
  257. package/src/web/runtime/Prompt.ts +99 -0
  258. package/src/web/types/WebPlugin.ts +42 -29
  259. package/src/workboard/runtime/Collector.ts +1 -1
  260. package/src/workboard/runtime/Normalizer.ts +1 -1
  261. package/src/workboard/runtime/SessionSummary.ts +11 -42
  262. package/bin/asr/Plugin.d.ts +0 -63
  263. package/bin/asr/Plugin.d.ts.map +0 -1
  264. package/bin/asr/Plugin.js +0 -280
  265. package/bin/asr/Plugin.js.map +0 -1
  266. package/bin/asr/types/AsrPlugin.d.ts +0 -114
  267. package/bin/asr/types/AsrPlugin.d.ts.map +0 -1
  268. package/bin/asr/types/AsrPlugin.js +0 -10
  269. package/bin/asr/types/AsrPlugin.js.map +0 -1
  270. package/bin/chat/runtime/ChatSession.d.ts +0 -97
  271. package/bin/chat/runtime/ChatSession.d.ts.map +0 -1
  272. package/bin/chat/runtime/ChatSession.js +0 -91
  273. package/bin/chat/runtime/ChatSession.js.map +0 -1
  274. package/bin/chat/runtime/ChatSessionContextComposer.d.ts +0 -45
  275. package/bin/chat/runtime/ChatSessionContextComposer.d.ts.map +0 -1
  276. package/bin/chat/runtime/ChatSessionContextComposer.js +0 -60
  277. package/bin/chat/runtime/ChatSessionContextComposer.js.map +0 -1
  278. package/bin/chat/runtime/ChatSessionTypes.d.ts +0 -30
  279. package/bin/chat/runtime/ChatSessionTypes.d.ts.map +0 -1
  280. package/bin/chat/runtime/ChatSessionTypes.js +0 -9
  281. package/bin/chat/runtime/ChatSessionTypes.js.map +0 -1
  282. package/bin/tts/Plugin.d.ts +0 -49
  283. package/bin/tts/Plugin.d.ts.map +0 -1
  284. package/bin/tts/Plugin.js +0 -247
  285. package/bin/tts/Plugin.js.map +0 -1
  286. package/bin/tts/types/TtsPlugin.d.ts +0 -122
  287. package/bin/tts/types/TtsPlugin.d.ts.map +0 -1
  288. package/bin/tts/types/TtsPlugin.js +0 -10
  289. package/bin/tts/types/TtsPlugin.js.map +0 -1
  290. package/bin/web/runtime/Install.d.ts +0 -19
  291. package/bin/web/runtime/Install.d.ts.map +0 -1
  292. package/bin/web/runtime/Install.js +0 -178
  293. package/bin/web/runtime/Install.js.map +0 -1
  294. package/src/asr/Plugin.ts +0 -322
  295. package/src/asr/types/AsrPlugin.ts +0 -118
  296. package/src/chat/runtime/ChatSession.ts +0 -168
  297. package/src/chat/runtime/ChatSessionContextComposer.ts +0 -106
  298. package/src/chat/runtime/ChatSessionTypes.ts +0 -32
  299. package/src/tts/Plugin.ts +0 -284
  300. package/src/tts/types/TtsPlugin.ts +0 -129
  301. package/src/web/runtime/Install.ts +0 -241
@@ -1,82 +1,33 @@
1
1
  /**
2
- * Chat channel 配置持久化公开行为测试。
2
+ * Chat channel 构造配置公开行为测试。
3
3
  */
4
4
  import assert from "node:assert/strict";
5
5
  import test from "node:test";
6
6
  import { ChatPlugin } from "../bin/index.js";
7
7
 
8
8
  function create_channel(name) {
9
- let enabled = false;
10
- let channel_account_id = "";
11
9
  return {
12
10
  name,
13
- isEnabled: () => enabled,
14
- getChannelAccountId: () => channel_account_id,
11
+ isEnabled: () => false,
12
+ getChannelAccountId: () => "",
15
13
  getAccount: () => null,
16
- applyRuntimePatch: (patch) => {
17
- if (typeof patch.enabled === "boolean") enabled = patch.enabled;
18
- if (Object.prototype.hasOwnProperty.call(patch, "channelAccountId")) {
19
- channel_account_id = String(patch.channelAccountId || "").trim();
20
- }
21
- },
22
14
  };
23
15
  }
24
16
 
25
- function create_context(plugin) {
26
- const writes = [];
27
- const context = {
28
- config: {
29
- id: "agent_test",
30
- version: "1.0.0",
31
- plugins: { memory: { enabled: true } },
32
- },
33
- pluginInstances: new Map([["chat", plugin]]),
34
- pluginConfig: {
35
- persistProjectPlugins: async (plugins) => {
36
- writes.push(structuredClone(plugins));
37
- return "/tmp/agent_test";
38
- },
39
- },
40
- };
41
- return { context, writes };
42
- }
43
-
44
- async function execute(plugin, action_name, context, input) {
45
- return await plugin.actions[action_name].execute({
46
- context,
47
- input,
48
- pluginName: "chat",
49
- actionName: action_name,
50
- });
51
- }
52
-
53
- test("chat.open/close/configure 持久化完整 plugins 配置", async () => {
17
+ test("ChatPlugin 配置只来自 constructor", () => {
54
18
  const telegram = create_channel("telegram");
55
- const plugin = new ChatPlugin({ channels: [telegram] });
56
- const { context, writes } = create_context(plugin);
57
-
58
- await execute(plugin, "open", context, { channel: "telegram" });
59
- assert.equal(writes.length, 1);
60
- assert.equal(writes[0].memory.enabled, true);
61
- assert.equal(writes[0].chat.channels.telegram.enabled, true);
62
- assert.equal(plugin.isChannelEnabled(context, "telegram"), true);
63
-
64
- await execute(plugin, "configure", context, {
65
- channel: "telegram",
66
- config: { enabled: false },
67
- restart: false,
68
- });
69
- assert.equal(writes.length, 2);
70
- assert.equal(writes[1].chat.channels.telegram.enabled, false);
71
- assert.equal(plugin.isChannelEnabled(context, "telegram"), false);
19
+ const queue = { maxConcurrency: 7, mergeDebounceMs: 123 };
20
+ const plugin = new ChatPlugin({ queue, channels: [telegram] });
72
21
 
73
- await execute(plugin, "close", context, { channel: "telegram" });
74
- assert.equal(writes.length, 3);
75
- assert.equal(context.config.plugins.chat.channels.telegram.enabled, false);
22
+ assert.equal(plugin.channels[0], telegram);
23
+ assert.deepEqual(plugin.getQueueWorkerConfig({}), queue);
76
24
  });
77
25
 
78
- test("ChatPlugin queue 只读取 constructor 配置", () => {
79
- const queue = { maxConcurrency: 7, mergeDebounceMs: 123 };
80
- const plugin = new ChatPlugin({ queue, channels: [] });
81
- assert.deepEqual(plugin.getQueueWorkerConfig({}), queue);
26
+ test("ChatPlugin 不提供配置修改 action", () => {
27
+ const plugin = new ChatPlugin({ channels: [] });
28
+
29
+ assert.equal("open" in plugin.actions, false);
30
+ assert.equal("close" in plugin.actions, false);
31
+ assert.equal("configuration" in plugin.actions, false);
32
+ assert.equal("configure" in plugin.actions, false);
82
33
  });
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Chat Plugin 存储所有权测试。
3
+ */
4
+
5
+ import assert from "node:assert/strict";
6
+ import fs from "node:fs";
7
+ import os from "node:os";
8
+ import path from "node:path";
9
+ import test from "node:test";
10
+ import { ChatPlugin, clean_chat_storage } from "../bin/index.js";
11
+
12
+ function create_project_root() {
13
+ return fs.mkdtempSync(path.join(os.tmpdir(), "downcity-chat-storage-"));
14
+ }
15
+
16
+ test("clean_chat_storage 只清理 Chat Plugin 自有数据", async () => {
17
+ const root_path = create_project_root();
18
+ try {
19
+ const session_id = "session_chat";
20
+ const meta_path = path.join(root_path, ".downcity", "channel", "meta.json");
21
+ const chat_dir = path.join(root_path, ".downcity", "chat", session_id);
22
+ const agent_session_dir = path.join(
23
+ root_path,
24
+ ".downcity",
25
+ "agents",
26
+ "agent_test",
27
+ "sessions",
28
+ session_id,
29
+ );
30
+ fs.mkdirSync(path.dirname(meta_path), { recursive: true });
31
+ fs.mkdirSync(chat_dir, { recursive: true });
32
+ fs.mkdirSync(agent_session_dir, { recursive: true });
33
+ fs.writeFileSync(path.join(chat_dir, "history.jsonl"), "{}\n");
34
+ fs.writeFileSync(meta_path, JSON.stringify({
35
+ v: 1,
36
+ updatedAt: Date.now(),
37
+ sessionIdByTargetKey: { "telegram|chat_1||": session_id },
38
+ routesBySessionId: {
39
+ [session_id]: {
40
+ v: 1,
41
+ sessionId: session_id,
42
+ channel: "telegram",
43
+ chatId: "chat_1",
44
+ updatedAt: Date.now(),
45
+ },
46
+ },
47
+ }));
48
+
49
+ const result = await clean_chat_storage({
50
+ root_path,
51
+ channel: "telegram",
52
+ chat_id: "chat_1",
53
+ });
54
+ assert.equal(result.session_id, session_id);
55
+ assert.equal(result.removed_chat_dir, true);
56
+ assert.equal(result.removed_route, true);
57
+ assert.equal(fs.existsSync(chat_dir), false);
58
+ assert.equal(fs.existsSync(agent_session_dir), true);
59
+ const meta = JSON.parse(fs.readFileSync(meta_path, "utf8"));
60
+ assert.equal(meta.routesBySessionId[session_id], undefined);
61
+ } finally {
62
+ fs.rmSync(root_path, { recursive: true, force: true });
63
+ }
64
+ });
65
+
66
+ test("chat.history_clear action 只清空事件历史", async () => {
67
+ const root_path = create_project_root();
68
+ try {
69
+ const session_id = "session_history";
70
+ const history_path = path.join(
71
+ root_path,
72
+ ".downcity",
73
+ "chat",
74
+ session_id,
75
+ "history.jsonl",
76
+ );
77
+ fs.mkdirSync(path.dirname(history_path), { recursive: true });
78
+ fs.writeFileSync(history_path, "{}\n");
79
+ const plugin = new ChatPlugin({ channels: [] });
80
+ const result = await plugin.actions.history_clear.execute({
81
+ context: { rootPath: root_path },
82
+ input: { sessionId: session_id },
83
+ pluginName: "chat",
84
+ actionName: "history_clear",
85
+ });
86
+ assert.equal(result.success, true);
87
+ assert.equal(result.data.cleared, true);
88
+ assert.equal(fs.existsSync(history_path), false);
89
+ } finally {
90
+ fs.rmSync(root_path, { recursive: true, force: true });
91
+ }
92
+ });
@@ -0,0 +1,93 @@
1
+ /**
2
+ * SkillPlugin action 目录与动态 system prompt 回归测试。
3
+ *
4
+ * 关键点(中文)
5
+ * - find/install action 只返回 shell 指引,不能执行命令或写入文件。
6
+ * - system prompt 必须根据构造参数输出项目、用户和自定义扫描根。
7
+ * - install action 的提示词应引导 Agent 调用 list 检查 Skill 是否进入可发现范围。
8
+ */
9
+
10
+ import assert from "node:assert/strict";
11
+ import fs from "node:fs";
12
+ import path from "node:path";
13
+ import test from "node:test";
14
+ import { SkillPlugin } from "../bin/index.js";
15
+
16
+ test("SkillPlugin 暴露四个职责清晰的 actions", () => {
17
+ const plugin = new SkillPlugin();
18
+
19
+ assert.deepEqual(Object.keys(plugin.actions).sort(), [
20
+ "find",
21
+ "install",
22
+ "list",
23
+ "lookup",
24
+ ]);
25
+ });
26
+
27
+ test("SkillPlugin 根据扫描参数生成 action 工作流提示", async () => {
28
+ const project_root = path.resolve("fixtures/skill-prompt-project");
29
+ const plugin = new SkillPlugin({
30
+ use: ["project", "home"],
31
+ paths: [".agents/shared-skills"],
32
+ ignore: ["hidden-skill"],
33
+ });
34
+
35
+ const prompt = await plugin.system({ rootPath: project_root });
36
+
37
+ assert.match(prompt, /\[project\] \.agents\/skills ->/);
38
+ assert.match(prompt, /\[custom\] \.agents\/shared-skills ->/);
39
+ assert.match(prompt, /\[home\] ~\/\.agents\/skills ->/);
40
+ assert.match(prompt, /Call `skill\.find`/);
41
+ assert.match(prompt, /call `skill\.install`/);
42
+ assert.match(prompt, /return prompts only/);
43
+ assert.match(prompt, /Configured ignore rules are active/);
44
+ });
45
+
46
+ test("find 和 install actions 只返回提示词且不创建扫描目录", async () => {
47
+ const project_root = path.resolve("fixtures/skill-instruction-actions");
48
+ const plugin = new SkillPlugin({
49
+ use: ["project", "home"],
50
+ paths: [".agents/shared-skills"],
51
+ });
52
+
53
+ assert.equal(fs.existsSync(project_root), false);
54
+
55
+ const find_result = await plugin.actions.find.execute({
56
+ context: { rootPath: project_root },
57
+ input: { query: "web access" },
58
+ });
59
+ const install_result = await plugin.actions.install.execute({
60
+ context: { rootPath: project_root },
61
+ input: { spec: "owner/repository@web-access" },
62
+ });
63
+
64
+ assert.equal(find_result.success, true);
65
+ assert.match(find_result.data.prompt, /https:\/\/www\.skills\.sh\//);
66
+ assert.match(
67
+ find_result.data.prompt,
68
+ /https:\/\/app\.lobehub\.com\/community\/skill/,
69
+ );
70
+ assert.match(find_result.data.prompt, /npx -y skills find 'web access'/);
71
+ assert.match(find_result.data.prompt, /has not searched for or installed anything/);
72
+ assert.equal(install_result.success, true);
73
+ assert.match(
74
+ install_result.data.prompt,
75
+ /npx -y skills add 'owner\/repository@web-access' -y/,
76
+ );
77
+ assert.match(install_result.data.prompt, /action: "list"/);
78
+ assert.match(install_result.data.prompt, /has not installed or changed any files/);
79
+ assert.equal(fs.existsSync(project_root), false);
80
+ });
81
+
82
+ test("install action 在没有扫描根时返回配置提示", async () => {
83
+ const project_root = path.resolve("fixtures/no-skill-root");
84
+ const plugin = new SkillPlugin({ use: [] });
85
+ const result = await plugin.actions.install.execute({
86
+ context: { rootPath: project_root },
87
+ input: { spec: "owner/repository@skill" },
88
+ });
89
+
90
+ assert.equal(result.success, true);
91
+ assert.match(result.data.prompt, /No scan roots are configured/);
92
+ assert.equal(fs.existsSync(project_root), false);
93
+ });
@@ -0,0 +1,250 @@
1
+ /**
2
+ * @file SoundPlugin 的 FED 模型发现、ASR/TTS 调用和自动转写测试。
3
+ *
4
+ * 关键点(中文)
5
+ * - 测试编译后的公开入口,确保 package 导出与用户实际使用方式一致。
6
+ * - ASR 测试验证本地音频只会转成 data URL,不会把本地路径传给 FED。
7
+ * - TTS 测试验证输出严格使用 AI SDK UIMessage。
8
+ */
9
+
10
+ import test from "node:test";
11
+ import assert from "node:assert/strict";
12
+ import fs from "node:fs/promises";
13
+ import os from "node:os";
14
+ import path from "node:path";
15
+
16
+ import { SoundPlugin } from "../bin/index.js";
17
+
18
+ function create_context(root_path) {
19
+ return {
20
+ rootPath: root_path,
21
+ };
22
+ }
23
+
24
+ async function run_action(plugin, action_name, context, input) {
25
+ return await plugin.actions[action_name].execute({
26
+ context,
27
+ input,
28
+ pluginName: plugin.name,
29
+ actionName: action_name,
30
+ });
31
+ }
32
+
33
+ function create_tts_message(url = "data:audio/mpeg;base64,dGVzdA==") {
34
+ return {
35
+ id: "sound:test",
36
+ role: "assistant",
37
+ parts: [
38
+ {
39
+ type: "file",
40
+ mediaType: "audio/mpeg",
41
+ filename: "speech.mp3",
42
+ url,
43
+ },
44
+ ],
45
+ };
46
+ }
47
+
48
+ test("sound.models 只返回 FED 中支持 ASR 或 TTS 的模型", async () => {
49
+ const plugin = new SoundPlugin({
50
+ list_models: () => [
51
+ { id: "asr", name: "ASR", modalities: ["asr"] },
52
+ { id: "tts", name: "TTS", modalities: ["tts"] },
53
+ { id: "both", name: "Both", modalities: ["asr", "tts"] },
54
+ { id: "text", name: "Text", modalities: ["text"] },
55
+ ],
56
+ asr: async () => ({ text: "ok" }),
57
+ tts: async () => create_tts_message(),
58
+ });
59
+ const context = create_context(process.cwd());
60
+
61
+ const all_result = await run_action(plugin, "models", context, {});
62
+ assert.equal(all_result.success, true);
63
+ assert.deepEqual(all_result.data.items.map((model) => model.id), ["asr", "tts", "both"]);
64
+
65
+ const asr_result = await run_action(plugin, "models", context, { capability: "asr" });
66
+ assert.equal(asr_result.success, true);
67
+ assert.deepEqual(asr_result.data.items.map((model) => model.id), ["asr", "both"]);
68
+
69
+ const tts_result = await run_action(plugin, "models", context, { capability: "tts" });
70
+ assert.equal(tts_result.success, true);
71
+ assert.deepEqual(tts_result.data.items.map((model) => model.id), ["tts", "both"]);
72
+ });
73
+
74
+ test("sound.asr 把本地音频转为 data URL 后直接调用 FED", async () => {
75
+ const root_path = await fs.mkdtemp(path.join(os.tmpdir(), "downcity-sound-"));
76
+ const audio_path = path.join(root_path, "voice.wav");
77
+ await fs.writeFile(audio_path, Buffer.from("audio-test"));
78
+ let received_input;
79
+ const plugin = new SoundPlugin({
80
+ default_asr_model: "fed-asr",
81
+ asr: async (input) => {
82
+ received_input = input;
83
+ return {
84
+ text: " transcript ",
85
+ segments: [{ text: " first ", startSecond: 0, endSecond: 1.25 }],
86
+ language: "en",
87
+ durationInSeconds: 1.25,
88
+ };
89
+ },
90
+ tts: async () => create_tts_message(),
91
+ });
92
+
93
+ try {
94
+ const result = await run_action(
95
+ plugin,
96
+ "asr",
97
+ create_context(root_path),
98
+ { audio_path: "./voice.wav" },
99
+ );
100
+ assert.equal(result.success, true);
101
+ assert.equal(received_input.model, "fed-asr");
102
+ assert.equal(received_input.audio_path, undefined);
103
+ assert.equal(received_input.media_type, "audio/wav");
104
+ assert.equal(received_input.filename, "voice.wav");
105
+ assert.match(received_input.data_url, /^data:audio\/wav;base64,/);
106
+ assert.deepEqual(result.data, {
107
+ text: "transcript",
108
+ segments: [{ text: "first", startSecond: 0, endSecond: 1.25 }],
109
+ language: "en",
110
+ durationInSeconds: 1.25,
111
+ });
112
+ } finally {
113
+ await fs.rm(root_path, { recursive: true, force: true });
114
+ }
115
+ });
116
+
117
+ test("sound.tts 使用默认参数并返回 AI SDK UIMessage", async () => {
118
+ let received_input;
119
+ const message = create_tts_message();
120
+ const plugin = new SoundPlugin({
121
+ default_tts_model: "fed-tts",
122
+ language: "zh",
123
+ voice: "alloy",
124
+ format: "mp3",
125
+ asr: async () => ({ text: "ok" }),
126
+ tts: async (input) => {
127
+ received_input = input;
128
+ return message;
129
+ },
130
+ });
131
+
132
+ const result = await run_action(
133
+ plugin,
134
+ "tts",
135
+ create_context(process.cwd()),
136
+ { text: " 你好 " },
137
+ );
138
+ assert.equal(result.success, true);
139
+ assert.deepEqual(received_input, {
140
+ model: "fed-tts",
141
+ text: "你好",
142
+ language: "zh",
143
+ voice: "alloy",
144
+ format: "mp3",
145
+ });
146
+ assert.deepEqual(result.data, message);
147
+ });
148
+
149
+ test("sound action 不会隐式选择模型或接受非 UIMessage TTS 结果", async () => {
150
+ const plugin = new SoundPlugin({
151
+ asr: async () => ({ text: "ok" }),
152
+ tts: async () => ({ url: "https://example.com/speech.mp3" }),
153
+ });
154
+ const context = create_context(process.cwd());
155
+
156
+ const asr_result = await run_action(plugin, "asr", context, {
157
+ url: "https://example.com/input.mp3",
158
+ });
159
+ assert.equal(asr_result.success, false);
160
+ assert.match(asr_result.error, /requires a model id/);
161
+
162
+ const tts_result = await run_action(plugin, "tts", context, {
163
+ model: "fed-tts",
164
+ text: "hello",
165
+ });
166
+ assert.equal(tts_result.success, false);
167
+ assert.match(tts_result.error, /must return an AI SDK UIMessage/);
168
+ });
169
+
170
+ test("sound.asr 只接受一种音频来源", async () => {
171
+ const plugin = new SoundPlugin({
172
+ asr: async () => ({ text: "ok" }),
173
+ tts: async () => create_tts_message(),
174
+ });
175
+ const result = await run_action(plugin, "asr", create_context(process.cwd()), {
176
+ model: "fed-asr",
177
+ url: "https://example.com/input.mp3",
178
+ data_url: "data:audio/mpeg;base64,dGVzdA==",
179
+ });
180
+ assert.equal(result.success, false);
181
+ assert.match(result.error, /requires exactly one/);
182
+ });
183
+
184
+ test("sound.tts 要求 UIMessage 包含音频 file part", async () => {
185
+ const plugin = new SoundPlugin({
186
+ asr: async () => ({ text: "ok" }),
187
+ tts: async () => ({
188
+ id: "sound:text-only",
189
+ role: "assistant",
190
+ parts: [{ type: "text", text: "not audio" }],
191
+ }),
192
+ });
193
+ const result = await run_action(plugin, "tts", create_context(process.cwd()), {
194
+ model: "fed-tts",
195
+ text: "hello",
196
+ });
197
+ assert.equal(result.success, false);
198
+ assert.match(result.error, /must contain an audio file part/);
199
+ });
200
+
201
+ test("auto_asr 必须配置默认 ASR 模型", () => {
202
+ assert.throws(
203
+ () => new SoundPlugin({
204
+ auto_asr: true,
205
+ asr: async () => ({ text: "ok" }),
206
+ tts: async () => create_tts_message(),
207
+ }),
208
+ /auto_asr requires default_asr_model/,
209
+ );
210
+ });
211
+
212
+ test("auto_asr 把 chat 语音附件转写追加到正文", async () => {
213
+ const root_path = await fs.mkdtemp(path.join(os.tmpdir(), "downcity-sound-auto-"));
214
+ const audio_path = path.join(root_path, "message.ogg");
215
+ await fs.writeFile(audio_path, Buffer.from("voice"));
216
+ const plugin = new SoundPlugin({
217
+ auto_asr: true,
218
+ default_asr_model: "fed-asr",
219
+ asr: async () => ({ text: "hello <world>" }),
220
+ tts: async () => create_tts_message(),
221
+ });
222
+
223
+ try {
224
+ const hook = Object.values(plugin.hooks.pipeline)[0][0];
225
+ const result = await hook({
226
+ context: create_context(root_path),
227
+ value: {
228
+ channel: "telegram",
229
+ chatId: "chat-1",
230
+ rootPath: root_path,
231
+ bodyText: "original",
232
+ attachments: [
233
+ {
234
+ channel: "telegram",
235
+ kind: "voice",
236
+ path: audio_path,
237
+ fileName: "message.ogg",
238
+ contentType: "audio/ogg",
239
+ },
240
+ ],
241
+ },
242
+ });
243
+ assert.equal(
244
+ result.bodyText,
245
+ "original\n\n<voice src=\"message.ogg\">hello &lt;world&gt;</voice>",
246
+ );
247
+ } finally {
248
+ await fs.rm(root_path, { recursive: true, force: true });
249
+ }
250
+ });
@@ -0,0 +1,85 @@
1
+ /**
2
+ * WebPlugin 纯提示 install action 回归测试。
3
+ *
4
+ * 关键点(中文)
5
+ * - install action 只返回 Agent 操作提示,不能执行命令或写入文件。
6
+ * - Skill 安装必须委托给 skill.install,避免 WebPlugin 重复维护扫描根规则。
7
+ * - agent-browser CLI 提示需要根据 user / project 作用域生成。
8
+ */
9
+
10
+ import assert from "node:assert/strict";
11
+ import fs from "node:fs";
12
+ import path from "node:path";
13
+ import test from "node:test";
14
+ import { WebPlugin } from "../bin/index.js";
15
+
16
+ test("WebPlugin 仅暴露纯提示 install action", () => {
17
+ const plugin = new WebPlugin();
18
+
19
+ assert.deepEqual(Object.keys(plugin.actions), ["install"]);
20
+ assert.equal(plugin.setup, undefined);
21
+ assert.match(plugin.actions.install.description, /does not install anything/);
22
+ });
23
+
24
+ test("install action 默认返回 web-access 安装工作流", async () => {
25
+ const project_root = path.resolve("fixtures/web-install-instructions");
26
+ const plugin = new WebPlugin();
27
+
28
+ assert.equal(fs.existsSync(project_root), false);
29
+
30
+ const result = await plugin.actions.install.execute({
31
+ context: { rootPath: project_root },
32
+ input: {},
33
+ });
34
+
35
+ assert.equal(result.success, true);
36
+ assert.equal(result.data.kind, "instructions");
37
+ assert.equal(result.data.target, "web-access");
38
+ assert.equal(result.data.scope, "user");
39
+ assert.match(result.data.prompt, /plugin: "skill", action: "install"/);
40
+ assert.match(result.data.prompt, /spec: "web-access"/);
41
+ assert.match(result.data.prompt, /has not executed commands/);
42
+ assert.match(result.data.prompt, /action: "list"/);
43
+ assert.equal(fs.existsSync(project_root), false);
44
+ });
45
+
46
+ test("agent-browser project 提示包含 Skill 与项目 CLI 安装步骤", async () => {
47
+ const plugin = new WebPlugin();
48
+ const result = await plugin.actions.install.execute({
49
+ context: { rootPath: path.resolve("fixtures/web-agent-browser-instructions") },
50
+ input: { target: "agent-browser", scope: "project" },
51
+ });
52
+
53
+ assert.equal(result.success, true);
54
+ assert.equal(result.data.target, "agent-browser");
55
+ assert.equal(result.data.scope, "project");
56
+ assert.match(result.data.prompt, /spec: "agent-browser"/);
57
+ assert.match(result.data.prompt, /pnpm add -D agent-browser/);
58
+ assert.match(result.data.prompt, /npm install -D agent-browser/);
59
+ assert.match(result.data.prompt, /yarn add -D agent-browser/);
60
+ assert.match(result.data.prompt, /skill\.lookup/);
61
+ });
62
+
63
+ test("all 目标返回两个 Skill 和用户级 CLI 提示", async () => {
64
+ const plugin = new WebPlugin();
65
+ const result = await plugin.actions.install.execute({
66
+ context: { rootPath: path.resolve("fixtures/web-all-instructions") },
67
+ input: { target: "all", scope: "user" },
68
+ });
69
+
70
+ assert.equal(result.success, true);
71
+ assert.match(result.data.prompt, /spec: "web-access"/);
72
+ assert.match(result.data.prompt, /spec: "agent-browser"/);
73
+ assert.match(result.data.prompt, /npm install -g agent-browser/);
74
+ assert.match(result.data.prompt, /no files were changed|changed files/i);
75
+ });
76
+
77
+ test("system prompt 明确 install 只返回提示", () => {
78
+ const plugin = new WebPlugin();
79
+ const prompt = plugin.system({ rootPath: process.cwd() });
80
+
81
+ assert.match(prompt, /return installation instructions/);
82
+ assert.match(prompt, /never executes commands/);
83
+ assert.match(prompt, /skill\.install/);
84
+ assert.match(prompt, /skill\.list/);
85
+ });
@@ -16,11 +16,9 @@ import { ContactPlugin } from "@/contact/ContactPlugin.js";
16
16
  import { TaskPlugin } from "@/task/TaskPlugin.js";
17
17
  import { MemoryPlugin } from "@/memory/MemoryPlugin.js";
18
18
  import { ImagePlugin } from "@/image/ImagePlugin.js";
19
- import { AsrPlugin } from "@/asr/Plugin.js";
20
- import { TtsPlugin } from "@/tts/Plugin.js";
19
+ import { SoundPlugin } from "@/sound/Plugin.js";
21
20
  import type { ImagePluginOptions } from "@/image/types/ImagePlugin.js";
22
- import type { AsrPluginOptions } from "@/asr/types/AsrPlugin.js";
23
- import type { TtsPluginOptions } from "@/tts/types/TtsPlugin.js";
21
+ import type { SoundPluginOptions } from "@/sound/types/SoundPlugin.js";
24
22
  import type { TaskPluginOptions } from "@/task/types/TaskPluginOptions.js";
25
23
  import type { MemoryPluginOptions } from "@/memory/types/Memory.js";
26
24
 
@@ -32,7 +30,7 @@ export type BuiltinPluginClass<T extends BasePlugin = BasePlugin> = new () => T;
32
30
  /**
33
31
  * 可直接无参创建的内建 plugin classes。
34
32
  *
35
- * 关键点(中文):image / asr / tts 需要宿主注入 City AI 能力,不能放入无参 class 列表。
33
+ * 关键点(中文):image / sound 需要宿主注入 City AI 能力,不能放入无参 class 列表。
36
34
  */
37
35
  export const BUILTIN_PLUGIN_CLASSES: BuiltinPluginClass[] = [
38
36
  SkillPlugin,
@@ -54,14 +52,9 @@ export interface BuiltinPluginOptions {
54
52
  image?: ImagePluginOptions;
55
53
 
56
54
  /**
57
- * 语音转写 plugin 的 City AI 能力注入。
55
+ * 统一语音 plugin 的 FED 模型目录、ASR 与 TTS 能力注入。
58
56
  */
59
- asr?: AsrPluginOptions;
60
-
61
- /**
62
- * 文本转语音 plugin 的 City AI 能力注入。
63
- */
64
- tts?: TtsPluginOptions;
57
+ sound?: SoundPluginOptions;
65
58
 
66
59
  /**
67
60
  * task plugin 的定时任务运行参数。
@@ -89,11 +82,8 @@ export function createBuiltinPlugins(options: BuiltinPluginOptions = {}): BasePl
89
82
  if (options.image?.image_create && options.image?.image_result) {
90
83
  plugins.push(new ImagePlugin(options.image));
91
84
  }
92
- if (options.asr?.asr) {
93
- plugins.push(new AsrPlugin(options.asr));
94
- }
95
- if (options.tts?.tts) {
96
- plugins.push(new TtsPlugin(options.tts));
85
+ if (options.sound) {
86
+ plugins.push(new SoundPlugin(options.sound));
97
87
  }
98
88
  return plugins;
99
89
  }