You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extends stripMarkdownFromSpeech with additional passes to strip emoji, decorative Unicode, standalone special chars, math operators, and repeated punctuation from TTS input text. All passes are configurable via options with sensible defaults (strip everything by default).
Streaming control tokens (<|ACT|>, <|DELAY|>, <|CALL|>) are preserved via Private Use Area placeholder extraction.
Closes: extends plaintext-response-format spec
Summary
Extends the plaintext-response-format spec by adding a new stripUnreadableSymbols function that strips emoji, decorative Unicode, standalone special characters, math operators, and repeated punctuation from TTS input text — complementing the existing stripMarkdownFromSpeech function.
What changed
New file:packages/core-agent/src/runtime/unreadable-symbols-stripper.ts
Both stripMarkdownFromSpeech calls (streaming path + final categorization path) replaced with stripUnreadableSymbols
Modified:packages/core-agent/src/index.ts
Added exports for stripUnreadableSymbols and StripUnreadableSymbolsOptions
New spec:.roo/specs/unreadable-symbols-stripper/ (requirements.md, design.md, tasks.md)
How tested
pnpm -F @proj-airi/core-agent typecheck — passed
pnpm -F @proj-airi/core-agent exec vitest run — 164 tests passed (14 test files)
Summary by Sourcery
Introduce a configurable TTS text sanitization utility and integrate it into the chat orchestrator to replace Markdown-only stripping.
New Features:
Add a new stripUnreadableSymbols function with configurable options for removing unreadable symbols from TTS input text and preserving streaming control tokens.
Export stripUnreadableSymbols and its StripUnreadableSymbolsOptions type from the core-agent public API.
Enhancements:
Update the chat orchestrator runtime to use the new stripUnreadableSymbols sanitizer instead of the Markdown-only stripper for both streaming and final categorization paths.
Documentation:
Add design, requirements, and task specs for the unreadable symbols stripper module.
Tests:
Add comprehensive unit tests for stripUnreadableSymbols covering symbol categories, options behavior, token preservation, edge cases, and backward compatibility.
Extends stripMarkdownFromSpeech with additional passes to strip emoji,
decorative Unicode, standalone special chars, math operators, and
repeated punctuation from TTS input text. All passes are configurable
via options with sensible defaults (strip everything by default).
Streaming control tokens (<|ACT|>, <|DELAY|>, <|CALL|>) are preserved
via Private Use Area placeholder extraction.
Closes: extends plaintext-response-format spec
Adds a new configurable TTS sanitization utility stripUnreadableSymbols, wires it into the chat orchestrator in place of stripMarkdownFromSpeech, exports it from core-agent, and documents the behavior with a dedicated spec and tests.
Flow diagram for stripUnreadableSymbols sanitization pipeline
flowchart TD
A[Input text with streaming tokens and markdown] --> B[extractStreamingTokens]
B --> C[safeText]
C --> D[stripMarkdownFromSpeech]
D --> E[Pass 2: stripEmoji]
E --> F[Pass 3: stripDecorativeUnicode]
F --> G[Pass 4: stripStandaloneSpecialChars]
G --> H[Pass 5: stripMathOperators]
H --> I[Pass 6: collapseRepeatedPunctuation]
I --> J[Collapse multiple spaces]
J --> K[restoreStreamingTokens]
K --> L[Trim result]
L --> M[Sanitized TTS text output]
Loading
File-Level Changes
Change
Details
Files
Introduce stripUnreadableSymbols TTS sanitization utility with configurable passes and streaming token preservation.
Define StripUnreadableSymbolsOptions with 5 boolean flags defaulting to true.
Implement stripUnreadableSymbols to first delegate to stripMarkdownFromSpeech, then run emoji, decorative Unicode, standalone special char, math-operator, and repeated-punctuation passes in sequence.
Add extractStreamingTokens/restoreStreamingTokens helpers using Private Use Area placeholders to protect <
...
Add comprehensive tests for the unreadable symbols stripper behavior and options.
Cover emoji, decorative Unicode, standalone special chars, math operators, repeated punctuation collapsing, and their combinations.
Verify streaming control tokens like <
ACT
Wire stripUnreadableSymbols into the chat orchestrator runtime instead of stripMarkdownFromSpeech for TTS speech text.
Import stripUnreadableSymbols alongside stripMarkdownFromSpeech in chat-orchestrator-runtime.
Replace the streaming path call that sanitized categorizer.filterToSpeech(...) with stripUnreadableSymbols.
Replace the final categorization speech sanitization with stripUnreadableSymbols while leaving reasoning handling unchanged.
Trigger a new review: Comment @sourcery-ai review on the pull request.
Continue discussions: Reply directly to Sourcery's review comments.
Generate a GitHub issue from a review comment: Ask Sourcery to create an
issue from a review comment by replying to it. You can also reply to a
review comment with @sourcery-ai issue to create an issue from it.
Generate a pull request title: Write @sourcery-ai anywhere in the pull
request title to generate a title at any time. You can also comment @sourcery-ai title on the pull request to (re-)generate the title at any time.
Generate a pull request summary: Write @sourcery-ai summary anywhere in
the pull request body to generate a PR summary at any time exactly where you
want it. You can also comment @sourcery-ai summary on the pull request to
(re-)generate the summary at any time.
Generate reviewer's guide: Comment @sourcery-ai guide on the pull
request to (re-)generate the reviewer's guide at any time.
Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
pull request to resolve all Sourcery comments. Useful if you've already
addressed all the comments and don't want to see them anymore.
Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
request to dismiss all existing Sourcery reviews. Especially useful if you
want to start fresh with a new review - don't forget to comment @sourcery-ai review to trigger a new review!
We reviewed changes in 3bdd1ac...77f95c8 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.
Some issues found as part of this review are outside of the diff in this pull request and aren't shown in the inline review comments due to GitHub's API limitations. You can see those issues on the DeepSource dashboard.
PR Report Card
Overall Grade
Focus Area: Reliability
Security
Reliability
Complexity
Hygiene
Feedback
Logging pattern in browser-facing code
The same console usage appears across multiple browser runtime files, which is why it shows up as nine occurrences of the same reliability issue.
Might be worth deciding when/where you want logging in these paths, since TTS and chat runtimes are going to be user-facing and potentially noisy if this sticks around.
AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.
The reason will be displayed to describe this comment to others. Learn more.
Hey - I've left some high level feedback:
The streaming token placeholder implementation (TOKEN_PLACEHOLDER_BASE = '\uE0000' with surrounding the index) deviates from the spec’s null-byte approach and relies on a specific Private Use Area codepoint; consider switching to a delimiter that cannot plausibly appear in user text (e.g. \x00-wrapped index) to avoid accidental collisions and simplify the restore regex.
The stripMathOperators regex uses a lookbehind (?<=\s), which can be brittle across JS runtimes and is slightly inconsistent with the boundary-based approach documented in the design; you might want to rework this to use an explicit (^|\s)-style grouping so behavior is both more portable and easier to reason about at string boundaries.
The emoji/decorative Unicode passes chain many overlapping and partially duplicated ranges with multiple replace calls; it may be easier to maintain and reason about if you consolidate these into a smaller number of well-documented ranges (or a single compiled regex) that more directly reflects the categories described in the design.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments- The streaming token placeholder implementation (`TOKEN_PLACEHOLDER_BASE = '\uE0000'` with surrounding the index) deviates from the spec’s null-byte approach and relies on a specific Private Use Area codepoint; consider switching to a delimiter that cannot plausibly appear in user text (e.g. `\x00`-wrapped index) to avoid accidental collisions and simplify the restore regex.
- The `stripMathOperators` regex uses a lookbehind `(?<=\s)`, which can be brittle across JS runtimes and is slightly inconsistent with the boundary-based approach documented in the design; you might want to rework this to use an explicit `(^|\s)`-style grouping so behavior is both more portable and easier to reason about at string boundaries.
- The emoji/decorative Unicode passes chain many overlapping and partially duplicated ranges with multiple `replace` calls; it may be easier to maintain and reason about if you consolidate these into a smaller number of well-documented ranges (or a single compiled regex) that more directly reflects the categories described in the design.
Sourcery is free for open source - if you like our reviews please consider sharing them ✨
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces the stripUnreadableSymbols utility to sanitize LLM response text for TTS by stripping emoji, decorative Unicode, standalone special characters, math operators, and collapsing repeated punctuation. It integrates this utility into the chat orchestrator runtime and exports it from the core agent package. Feedback on the implementation highlights a bug in the Unicode escape sequence for the token placeholder base, which evaluates to a two-character string instead of a single character. Additionally, it is recommended to combine the numerous consecutive .replace() calls for emoji and decorative Unicode stripping into single regular expressions to improve streaming performance and eliminate redundant range matches.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
The reason will be displayed to describe this comment to others. Learn more.
Similarly to the emoji pass, we can combine all decorative Unicode ranges and characters into a single regular expression to reduce the number of .replace() calls from 6 to 1, improving performance during streaming.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
result = result.replace(/[\u{267F}\u{2693}\u{26A1}\u{26AA}-\u{26AB}\u{26BD}-\u{26BE}\u{26C4}-\u{26C5}\u{26CE}\u{26D4}\u{26EA}\u{26F2}-\u{26F3}\u{26F5}\u{26FA}\u{26FD}]/gu, '')
// U+2934-U+2935: Arrows
result = result.replace(/[\u{2934}-\u{2935}]/gu, '')
// U+2B05-U+2B07: Arrows
result = result.replace(/[\u{2B05}-\u{2B07}]/gu, '')
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
`stripUnreadableSymbols` has a cyclomatic complexity of 6 with "medium" risk
A function with high cyclomatic complexity can be hard to understand and
maintain. Cyclomatic complexity is a software metric that measures the number of
independent paths through a function. A higher cyclomatic complexity indicates
that the function has more decision points and is more complex.
- Switch streaming token placeholders from PUA codepoints to null-byte
delimiters (\x00) to match the spec and avoid collision risk
- Rework math operator regex to use explicit (^|\s) grouping instead of
lookbehind for better portability across JS runtimes
- Consolidate emoji/decorative Unicode ranges into fewer, well-documented
regex calls (2 passes each instead of ~20 individual replace calls)
…regex calls
Deduplicate overlapping ranges (e.g. \u{1F600}-\u{1F64F} is a subset of
\u{1F300}-\u{1F9FF}, \u{2614}-\u{2615} is a subset of \u{2600}-\u{26FF})
and combine variation selectors, ZWJ, and keycap chars into the same regex.
Reduces from ~23 individual .replace() calls to 2 for all emoji/decorative
symbol stripping.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected modified Emoji in character class
Unicode includes the characters which are made with multiple code points. RegExp character class syntax (/[abc]/) cannot handle characters which are made by multiple code points as a character; those characters will be dissolved to each code point. Probably the most important concept about Unicode in JavaScript is to treat strings as sequences of code units, as they really are. The confusion appears when the developer thinks that strings are composed of graphemes (or symbols), ignoring the code unit sequence concept.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
`stripUnreadableSymbols` has a cyclomatic complexity of 8 with "medium" risk
A function with high cyclomatic complexity can be hard to understand and
maintain. Cyclomatic complexity is a software metric that measures the number of
independent paths through a function. A higher cyclomatic complexity indicates
that the function has more decision points and is more complex.
…tch em/en dashes, arrows, and other symbols
Em dash (U+2014), en dash (U+2013), and other punctuation in the
General Punctuation block were leaking through to TTS. Adding
\u{2000}-\u{206F} to the decorative Unicode ranges ensures these
symbols are stripped along with arrows and box-drawing characters.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
- Add stripMarkdown option to TtsInputChunkOptions and SpeechPipelineOptions
- Add stripMarkdownFromText function to strip Markdown formatting
- Fix starsUnclosed to detect unclosed ** (bold) patterns by counting **
- Fix early return in segmenter to also check stripMarkdown option
- Pass stripMarkdown to segmenter in speech-pipeline.ts
- Add tests for stripMarkdown option in speech-pipeline.test.ts
Fixes TTS reading **bold** markers as STARSTARboldSTARSTAR when split across chunks.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Found `async` function without any `await` expressions
A function that does not contain any await expressions should not be async (except for some edge cases in TypeScript which are discussed below). Asynchronous functions in JavaScript behave differently than other functions in two important ways:
Remove any remaining ** markers that survived the markdown pass.
This handles split markers like **bold + text** where neither chunk
has a complete **...** pattern.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
The reason will be displayed to describe this comment to others. Learn more.
Unexpected function declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable
It is considered a best practice to avoid 'polluting' the global scope with variables that are intended to be local to the script. Global variables created from a script can produce name collisions with global variables created from another script, which will usually lead to runtime errors or unexpected behavior. It is mostly useful for browser scripts.
- Log in chat-orchestrator-runtime.ts (onLiteral, filterToSpeech, stripUnreadableSymbols)
- Log in unreadable-symbols-stripper.ts (input, after markdown, after aggressive strip)
- Log in pipeline-runtime.ts (applyToken)
- Log in streaming-pipeline.ts (appendText)
- Log in tts-session.ts (appendText segmenter path)
The reason will be displayed to describe this comment to others. Learn more.
Avoid using console in code that runs on the browser
It is considered a best practice to avoid the use of any console methods in JavaScript code that will run on the browser.
NOTE: If your repository contains a server side project, you can add "nodejs" to the environment property of analyzer meta in .deepsource.toml.
This will prevent this issue from getting raised.
Documentation for the analyzer meta can be found here.
Alternatively, you can silence this issue for your repository as shown here.
If a specific console call is meant to stay for other reasons, you can add a skipcq comment to that line.
This will inform other developers about the reason behind the log's presence, and prevent DeepSource from flagging it.
The reason will be displayed to describe this comment to others. Learn more.
Avoid using console in code that runs on the browser
It is considered a best practice to avoid the use of any console methods in JavaScript code that will run on the browser.
NOTE: If your repository contains a server side project, you can add "nodejs" to the environment property of analyzer meta in .deepsource.toml.
This will prevent this issue from getting raised.
Documentation for the analyzer meta can be found here.
Alternatively, you can silence this issue for your repository as shown here.
If a specific console call is meant to stay for other reasons, you can add a skipcq comment to that line.
This will inform other developers about the reason behind the log's presence, and prevent DeepSource from flagging it.
The reason will be displayed to describe this comment to others. Learn more.
Avoid using console in code that runs on the browser
It is considered a best practice to avoid the use of any console methods in JavaScript code that will run on the browser.
NOTE: If your repository contains a server side project, you can add "nodejs" to the environment property of analyzer meta in .deepsource.toml.
This will prevent this issue from getting raised.
Documentation for the analyzer meta can be found here.
Alternatively, you can silence this issue for your repository as shown here.
If a specific console call is meant to stay for other reasons, you can add a skipcq comment to that line.
This will inform other developers about the reason behind the log's presence, and prevent DeepSource from flagging it.
The reason will be displayed to describe this comment to others. Learn more.
Avoid using console in code that runs on the browser
It is considered a best practice to avoid the use of any console methods in JavaScript code that will run on the browser.
NOTE: If your repository contains a server side project, you can add "nodejs" to the environment property of analyzer meta in .deepsource.toml.
This will prevent this issue from getting raised.
Documentation for the analyzer meta can be found here.
Alternatively, you can silence this issue for your repository as shown here.
If a specific console call is meant to stay for other reasons, you can add a skipcq comment to that line.
This will inform other developers about the reason behind the log's presence, and prevent DeepSource from flagging it.
The reason will be displayed to describe this comment to others. Learn more.
Avoid using console in code that runs on the browser
It is considered a best practice to avoid the use of any console methods in JavaScript code that will run on the browser.
NOTE: If your repository contains a server side project, you can add "nodejs" to the environment property of analyzer meta in .deepsource.toml.
This will prevent this issue from getting raised.
Documentation for the analyzer meta can be found here.
Alternatively, you can silence this issue for your repository as shown here.
If a specific console call is meant to stay for other reasons, you can add a skipcq comment to that line.
This will inform other developers about the reason behind the log's presence, and prevent DeepSource from flagging it.
The reason will be displayed to describe this comment to others. Learn more.
Avoid using console in code that runs on the browser
It is considered a best practice to avoid the use of any console methods in JavaScript code that will run on the browser.
NOTE: If your repository contains a server side project, you can add "nodejs" to the environment property of analyzer meta in .deepsource.toml.
This will prevent this issue from getting raised.
Documentation for the analyzer meta can be found here.
Alternatively, you can silence this issue for your repository as shown here.
If a specific console call is meant to stay for other reasons, you can add a skipcq comment to that line.
This will inform other developers about the reason behind the log's presence, and prevent DeepSource from flagging it.
The reason will be displayed to describe this comment to others. Learn more.
Avoid using console in code that runs on the browser
It is considered a best practice to avoid the use of any console methods in JavaScript code that will run on the browser.
NOTE: If your repository contains a server side project, you can add "nodejs" to the environment property of analyzer meta in .deepsource.toml.
This will prevent this issue from getting raised.
Documentation for the analyzer meta can be found here.
Alternatively, you can silence this issue for your repository as shown here.
If a specific console call is meant to stay for other reasons, you can add a skipcq comment to that line.
This will inform other developers about the reason behind the log's presence, and prevent DeepSource from flagging it.
The reason will be displayed to describe this comment to others. Learn more.
Avoid using console in code that runs on the browser
It is considered a best practice to avoid the use of any console methods in JavaScript code that will run on the browser.
NOTE: If your repository contains a server side project, you can add "nodejs" to the environment property of analyzer meta in .deepsource.toml.
This will prevent this issue from getting raised.
Documentation for the analyzer meta can be found here.
Alternatively, you can silence this issue for your repository as shown here.
If a specific console call is meant to stay for other reasons, you can add a skipcq comment to that line.
This will inform other developers about the reason behind the log's presence, and prevent DeepSource from flagging it.
The reason will be displayed to describe this comment to others. Learn more.
Avoid using console in code that runs on the browser
It is considered a best practice to avoid the use of any console methods in JavaScript code that will run on the browser.
NOTE: If your repository contains a server side project, you can add "nodejs" to the environment property of analyzer meta in .deepsource.toml.
This will prevent this issue from getting raised.
Documentation for the analyzer meta can be found here.
Alternatively, you can silence this issue for your repository as shown here.
If a specific console call is meant to stay for other reasons, you can add a skipcq comment to that line.
This will inform other developers about the reason behind the log's presence, and prevent DeepSource from flagging it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Extends stripMarkdownFromSpeech with additional passes to strip emoji, decorative Unicode, standalone special chars, math operators, and repeated punctuation from TTS input text. All passes are configurable via options with sensible defaults (strip everything by default).
Streaming control tokens (<|ACT|>, <|DELAY|>, <|CALL|>) are preserved via Private Use Area placeholder extraction.
Closes: extends plaintext-response-format spec
Summary
Extends the
plaintext-response-formatspec by adding a newstripUnreadableSymbolsfunction that strips emoji, decorative Unicode, standalone special characters, math operators, and repeated punctuation from TTS input text — complementing the existingstripMarkdownFromSpeechfunction.What changed
New file:
packages/core-agent/src/runtime/unreadable-symbols-stripper.tsstripUnreadableSymbols(text, options?)— 6-pass sanitizer (Markdown + emoji + decorative Unicode + standalone special chars + math operators + repeated punctuation collapsing)StripUnreadableSymbolsOptionsinterface with 5 configurable boolean flags (all defaulttrue)<|ACT|>,<|DELAY|>,<|CALL|>) preserved via Private Use Area placeholder extractionstripMarkdownFromSpeechremains exported unchanged (backward compatibility)New file:
packages/core-agent/src/runtime/unreadable-symbols-stripper.test.tsModified:
packages/core-agent/src/runtime/chat-orchestrator-runtime.tsstripMarkdownFromSpeechcalls (streaming path + final categorization path) replaced withstripUnreadableSymbolsModified:
packages/core-agent/src/index.tsstripUnreadableSymbolsandStripUnreadableSymbolsOptionsNew spec:
.roo/specs/unreadable-symbols-stripper/(requirements.md, design.md, tasks.md)How tested
pnpm -F @proj-airi/core-agent typecheck— passedpnpm -F @proj-airi/core-agent exec vitest run— 164 tests passed (14 test files)Summary by Sourcery
Introduce a configurable TTS text sanitization utility and integrate it into the chat orchestrator to replace Markdown-only stripping.
New Features:
Enhancements:
Documentation:
Tests: