@adminforth/agent 1.42.2 → 1.43.1

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/build.log CHANGED
@@ -58,5 +58,5 @@ custom/speech_recognition_frontend/voiceActivityDetection.ts
58
58
  custom/speech_recognition_frontend/types/
59
59
  custom/speech_recognition_frontend/types/voice-activity-detection.d.ts
60
60
 
61
- sent 1,661,049 bytes received 860 bytes 3,323,818.00 bytes/sec
62
- total size is 1,657,187 speedup is 1.00
61
+ sent 1,661,128 bytes received 856 bytes 3,323,968.00 bytes/sec
62
+ total size is 1,657,212 speedup is 1.00
@@ -16,7 +16,7 @@ type StreamingAudioState = {
16
16
 
17
17
  let standByAudio: HTMLAudioElement | null = null;
18
18
  let isStandByAudioPlaying = false;
19
- function playStandByAudio() {
19
+ async function playStandByAudio() {
20
20
  if (!standByAudio) {
21
21
  standByAudio = new Audio(`/plugins/AdminForthAgentPlugin/agentAudio/agent-processing.mp3`);
22
22
  standByAudio.addEventListener('ended', () => {
@@ -26,7 +26,7 @@ function playStandByAudio() {
26
26
  });
27
27
  }
28
28
  standByAudio.currentTime = 0;
29
- standByAudio.play()
29
+ await standByAudio.play();
30
30
  isStandByAudioPlaying = true;
31
31
  }
32
32
 
@@ -215,7 +215,7 @@ export const useAgentAudio = defineStore('agentAudio', () => {
215
215
  }
216
216
  }
217
217
 
218
- function setIsPlaying(value: boolean) {
218
+ async function setIsPlaying(value: boolean) {
219
219
  isPlaying = value;
220
220
 
221
221
  if (!currentAudio) {
@@ -228,7 +228,7 @@ export const useAgentAudio = defineStore('agentAudio', () => {
228
228
  return;
229
229
  }
230
230
  agentAudioMode.value = 'playingAgentResponse';
231
- void currentAudio.play().catch((error) => {
231
+ await void currentAudio.play().catch((error) => {
232
232
  console.error('Failed to play audio:', error);
233
233
  });
234
234
  }
@@ -16,7 +16,7 @@ type StreamingAudioState = {
16
16
 
17
17
  let standByAudio: HTMLAudioElement | null = null;
18
18
  let isStandByAudioPlaying = false;
19
- function playStandByAudio() {
19
+ async function playStandByAudio() {
20
20
  if (!standByAudio) {
21
21
  standByAudio = new Audio(`/plugins/AdminForthAgentPlugin/agentAudio/agent-processing.mp3`);
22
22
  standByAudio.addEventListener('ended', () => {
@@ -26,7 +26,7 @@ function playStandByAudio() {
26
26
  });
27
27
  }
28
28
  standByAudio.currentTime = 0;
29
- standByAudio.play()
29
+ await standByAudio.play();
30
30
  isStandByAudioPlaying = true;
31
31
  }
32
32
 
@@ -215,7 +215,7 @@ export const useAgentAudio = defineStore('agentAudio', () => {
215
215
  }
216
216
  }
217
217
 
218
- function setIsPlaying(value: boolean) {
218
+ async function setIsPlaying(value: boolean) {
219
219
  isPlaying = value;
220
220
 
221
221
  if (!currentAudio) {
@@ -228,7 +228,7 @@ export const useAgentAudio = defineStore('agentAudio', () => {
228
228
  return;
229
229
  }
230
230
  agentAudioMode.value = 'playingAgentResponse';
231
- void currentAudio.play().catch((error) => {
231
+ await void currentAudio.play().catch((error) => {
232
232
  console.error('Failed to play audio:', error);
233
233
  });
234
234
  }
package/dist/index.js CHANGED
@@ -26,6 +26,7 @@ import { detectUserLanguage } from "./agent/languageDetect.js";
26
26
  import { prepareApiBasedTools as buildApiBasedTools } from './apiBasedTools.js';
27
27
  import { createAgentEventStream } from "./agentResponseEvents.js";
28
28
  import { appendCustomSystemPrompt, buildAgentSystemPrompt, buildAgentTurnSystemPrompt, DEFAULT_AGENT_SYSTEM_PROMPT } from "./agent/systemPrompt.js";
29
+ import { sanitizeSpeechText } from "./sanitizeSpeechText.js";
29
30
  const agentResponseBodySchema = z.object({
30
31
  message: z.string(),
31
32
  sessionId: z.string(),
@@ -474,7 +475,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
474
475
  text: agentResponse.text,
475
476
  }, sessionId, agentResponse.turnId);
476
477
  const speech = yield audioAdapter.synthesize({
477
- text: agentResponse.text,
478
+ text: sanitizeSpeechText(agentResponse.text),
478
479
  stream: true,
479
480
  streamFormat: "audio",
480
481
  format: "mp3",
@@ -0,0 +1,31 @@
1
+ const URL_RE = /\b(?:https?:\/\/|www\.)[^\s<>()]+/gi;
2
+ const MARKDOWN_LINK_RE = /\[([^\]]+)]\(([^)]+)\)/g;
3
+ const MARKDOWN_IMAGE_RE = /!\[([^\]]*)]\(([^)]+)\)/g;
4
+ const HTML_TAG_RE = /<[^>]+>/g;
5
+ const CODE_FENCE_RE = /```[\s\S]*?```/g;
6
+ const INLINE_CODE_RE = /`[^`]*`/g;
7
+ const BRACKETED_META_RE = /\[(?:ref|link|url|source|sources?|debug|meta|data):[^\]]*]/gi;
8
+ const MD_HEADING_LINE_RE = /^\s{0,3}#{1,6}\s+/gm;
9
+ const MD_BLOCKQUOTE_RE = /^\s{0,3}>\s?/gm;
10
+ const MD_HR_RE = /^\s{0,3}(-{3,}|\*{3,}|_{3,})\s*$/gm;
11
+ const MD_LIST_MARKER_RE = /^\s{0,3}(?:[-*+]|\d+\.)\s+/gm;
12
+ const MD_EMPHASIS_RE = /(\*\*|__)(.*?)\1/g;
13
+ const MD_ITALIC_RE = /(^|[^\\])(?:\*|_)([^\s].*?)(?:\*|_)/g;
14
+ export function sanitizeSpeechText(input) {
15
+ return input
16
+ .replace(CODE_FENCE_RE, " ")
17
+ .replace(MARKDOWN_IMAGE_RE, "$1")
18
+ .replace(MARKDOWN_LINK_RE, "$1")
19
+ .replace(URL_RE, " ")
20
+ .replace(MD_HEADING_LINE_RE, "")
21
+ .replace(MD_BLOCKQUOTE_RE, "")
22
+ .replace(MD_HR_RE, " ")
23
+ .replace(MD_LIST_MARKER_RE, "")
24
+ .replace(MD_EMPHASIS_RE, "$2")
25
+ .replace(MD_ITALIC_RE, "$1$2")
26
+ .replace(HTML_TAG_RE, " ")
27
+ .replace(INLINE_CODE_RE, " ")
28
+ .replace(BRACKETED_META_RE, " ")
29
+ .replace(/\s+/g, " ")
30
+ .trim();
31
+ }
package/index.ts CHANGED
@@ -16,6 +16,7 @@ import { createAgentEventStream } from "./agentResponseEvents.js";
16
16
  import { appendCustomSystemPrompt, buildAgentSystemPrompt, buildAgentTurnSystemPrompt, DEFAULT_AGENT_SYSTEM_PROMPT} from "./agent/systemPrompt.js";
17
17
  import type { ToolCallEvent } from "./agent/toolCallEvents.js";
18
18
  import type { CurrentPageContext } from "./agent/tools/getUserLocation.js";
19
+ import { sanitizeSpeechText } from "./sanitizeSpeechText.js";
19
20
 
20
21
  type MulterFile = {
21
22
  buffer: Buffer;
@@ -540,7 +541,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
540
541
  agentResponse.turnId,
541
542
  );
542
543
  const speech = await audioAdapter.synthesize({
543
- text: agentResponse.text,
544
+ text: sanitizeSpeechText(agentResponse.text),
544
545
  stream: true,
545
546
  streamFormat: "audio",
546
547
  format: "mp3",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/agent",
3
- "version": "1.42.2",
3
+ "version": "1.43.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -0,0 +1,32 @@
1
+ const URL_RE = /\b(?:https?:\/\/|www\.)[^\s<>()]+/gi;
2
+ const MARKDOWN_LINK_RE = /\[([^\]]+)]\(([^)]+)\)/g;
3
+ const MARKDOWN_IMAGE_RE = /!\[([^\]]*)]\(([^)]+)\)/g;
4
+ const HTML_TAG_RE = /<[^>]+>/g;
5
+ const CODE_FENCE_RE = /```[\s\S]*?```/g;
6
+ const INLINE_CODE_RE = /`[^`]*`/g;
7
+ const BRACKETED_META_RE = /\[(?:ref|link|url|source|sources?|debug|meta|data):[^\]]*]/gi;
8
+ const MD_HEADING_LINE_RE = /^\s{0,3}#{1,6}\s+/gm;
9
+ const MD_BLOCKQUOTE_RE = /^\s{0,3}>\s?/gm;
10
+ const MD_HR_RE = /^\s{0,3}(-{3,}|\*{3,}|_{3,})\s*$/gm;
11
+ const MD_LIST_MARKER_RE = /^\s{0,3}(?:[-*+]|\d+\.)\s+/gm;
12
+ const MD_EMPHASIS_RE = /(\*\*|__)(.*?)\1/g;
13
+ const MD_ITALIC_RE = /(^|[^\\])(?:\*|_)([^\s].*?)(?:\*|_)/g;
14
+
15
+ export function sanitizeSpeechText(input: string): string {
16
+ return input
17
+ .replace(CODE_FENCE_RE, " ")
18
+ .replace(MARKDOWN_IMAGE_RE, "$1")
19
+ .replace(MARKDOWN_LINK_RE, "$1")
20
+ .replace(URL_RE, " ")
21
+ .replace(MD_HEADING_LINE_RE, "")
22
+ .replace(MD_BLOCKQUOTE_RE, "")
23
+ .replace(MD_HR_RE, " ")
24
+ .replace(MD_LIST_MARKER_RE, "")
25
+ .replace(MD_EMPHASIS_RE, "$2")
26
+ .replace(MD_ITALIC_RE, "$1$2")
27
+ .replace(HTML_TAG_RE, " ")
28
+ .replace(INLINE_CODE_RE, " ")
29
+ .replace(BRACKETED_META_RE, " ")
30
+ .replace(/\s+/g, " ")
31
+ .trim();
32
+ }