Repository navigation
feat(expressive): expose expressive mode and add expressive agent example #2245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@livekit/agents': minor | ||
| --- | ||
|
|
||
| Expose expressive session options, normalize expression metadata into moods, and expand the expressive TTS provider support. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| // SPDX-FileCopyrightText: 2026 LiveKit, Inc. | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| import { MOOD_KEYWORDS } from './_mood_data.js'; | ||
|
|
||
| export type AgentMood = | ||
| | 'excited' | ||
| | 'happy' | ||
| | 'playful' | ||
| | 'curious' | ||
| | 'surprised' | ||
| | 'hopeful' | ||
| | 'empathetic' | ||
| | 'sad' | ||
| | 'angry' | ||
| | 'anxious' | ||
| | 'calm'; | ||
|
|
||
| export const MOOD_PRIORITY: AgentMood[] = [ | ||
| 'angry', | ||
| 'sad', | ||
| 'anxious', | ||
| 'surprised', | ||
| 'playful', | ||
| 'empathetic', | ||
| 'excited', | ||
| 'curious', | ||
| 'hopeful', | ||
| 'happy', | ||
| 'calm', | ||
| ]; | ||
| export const DEFAULT_MOOD: AgentMood = 'calm'; | ||
|
|
||
| function matchesWord(text: string, keyword: string): boolean { | ||
| let start = 0; | ||
| while (true) { | ||
| const at = text.indexOf(keyword, start); | ||
| if (at === -1) return false; | ||
| if (at === 0 || !/\p{L}/u.test(text[at - 1]!)) return true; | ||
| start = at + 1; | ||
| } | ||
| } | ||
|
|
||
| export function matchMood(label: string): AgentMood; | ||
| export function matchMood(label: string, fallback: AgentMood): AgentMood; | ||
| export function matchMood(label: string, fallback: null): AgentMood | null; | ||
| export function matchMood( | ||
| label: string, | ||
| fallback: AgentMood | null = DEFAULT_MOOD, | ||
| ): AgentMood | null { | ||
| const text = label.toLowerCase(); | ||
| let best: AgentMood | null = null; | ||
| let bestScore = 0; | ||
| for (const mood of MOOD_PRIORITY) { | ||
| const score = Object.entries(MOOD_KEYWORDS[mood]).reduce( | ||
| (total, [keyword, weight]) => total + (matchesWord(text, keyword) ? weight : 0), | ||
| 0, | ||
| ); | ||
| if (score > bestScore) { | ||
| best = mood; | ||
| bestScore = score; | ||
| } | ||
| } | ||
|
Comment on lines
+54
to
+63
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Delivery labels that describe curiosity are reported as empathy instead A label whose descriptive words tie in weight is resolved by a fixed priority list ( Impact: Frontends reading the published mood get the wrong feeling for common mixed labels, and the new mood test in this PR fails. Score computation and tie-break mechanismScoring is a sum over keyword prefix matches. For the lowercased label
Prompt for agentsWas this helpful? React with 👍 or 👎 to provide feedback. |
||
| return best ?? fallback; | ||
| } | ||
|
|
||
| export { MOOD_KEYWORDS } from './_mood_data.js'; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 New public helpers in the mood module ship without documentation comments
The newly added exported type, constants and function (
AgentMood,MOOD_PRIORITY,DEFAULT_MOOD,matchMoodatagents/src/tts/_mood.ts:6-50) carry no TSDoc, which the repository's contribution rules require for every new interface/method addition.Impact: Generated API docs omit the mood normalization surface, and reviewers/consumers have no stated contract for the fallback behaviour.
Rule reference
CONTRIBUTING.md: "If writing new methods/interfaces/enums/classes, document them. This project uses TypeDoc for automatic API documentation generation, and every new addition has to be properly documented."
The same omission applies to
SessionConfigandparseSessionConfiginexamples/src/expressive_agent/protocol.ts:54-60.Was this helpful? React with 👍 or 👎 to provide feedback.