meshagent-livekit 0.0.20__py3-none-any.whl → 0.0.21__py3-none-any.whl

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.

Potentially problematic release.


This version of meshagent-livekit might be problematic. Click here for more details.

@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import asyncio
3
3
 
4
- from meshagent.api import RoomMessage, ErrorResponse, JsonResponse, FileResponse, Requirement, Participant
4
+ from meshagent.api import RoomMessage, ErrorResponse, JsonResponse, FileResponse, Requirement, Participant, JsonResponse, EmptyResponse, TextResponse
5
5
  from meshagent.api.room_server_client import RoomClient
6
6
 
7
7
  from meshagent.agents import ToolResponseAdapter
@@ -9,12 +9,17 @@ from meshagent.tools import ToolContext, Toolkit
9
9
  from livekit.agents import Agent, AgentSession
10
10
  from livekit.agents.llm import RawFunctionTool, ToolError, function_tool
11
11
 
12
+ from livekit.agents import BackgroundAudioPlayer, AudioConfig, BuiltinAudioClip
13
+
14
+ from typing import Annotated
12
15
  from livekit.plugins import openai, silero
13
16
  #from livekit.plugins.turn_detector.multilingual import MultilingualModel
14
17
  import uuid
15
18
  import asyncio
16
19
  import logging
17
20
 
21
+ import os
22
+
18
23
  import json
19
24
 
20
25
  from typing import Any
@@ -23,7 +28,7 @@ from livekit.plugins import openai
23
28
 
24
29
  from livekit.plugins import openai, silero
25
30
  from livekit import rtc
26
- from livekit.agents import Agent, AgentSession
31
+ from livekit.agents import Agent, AgentSession, RunContext
27
32
 
28
33
  from typing import Optional
29
34
 
@@ -33,10 +38,40 @@ from meshagent.api.schema_util import merge, prompt_schema
33
38
 
34
39
  from meshagent.agents import SingleRoomAgent
35
40
 
41
+ from livekit.plugins.turn_detector.multilingual import MultilingualModel
42
+
43
+ import re
36
44
 
37
45
  logger = logging.getLogger("voice")
38
46
 
39
47
 
48
+ def _replace_non_matching(text: str, allowed_chars: str, replacement: str) -> str:
49
+ """
50
+ Replaces every character in `text` that does not match the given
51
+ `allowed_chars` regex set with `replacement`.
52
+
53
+ Parameters:
54
+ -----------
55
+ text : str
56
+ The input string on which the replacement is to be done.
57
+ allowed_chars : str
58
+ A string defining the set of allowed characters (part of a character set).
59
+ For example, "a-zA-Z0-9" will keep only letters and digits.
60
+ replacement : str
61
+ The string to replace non-matching characters with.
62
+
63
+ Returns:
64
+ --------
65
+ str
66
+ A new string where all characters not in `allowed_chars` are replaced.
67
+ """
68
+ # Build a regex that matches any character NOT in allowed_chars
69
+ pattern = rf"[^{allowed_chars}]"
70
+ return re.sub(pattern, replacement, text)
71
+
72
+ def safe_tool_name(name: str):
73
+ return _replace_non_matching(name, "a-zA-Z0-9_-", "_")
74
+
40
75
  class VoiceConnection:
41
76
  def __init__(self, *, room: RoomClient, breakout_room: str):
42
77
  self.room = room
@@ -166,13 +201,14 @@ class Voicebot(SingleRoomAgent):
166
201
  self, toolkits: list[Toolkit], context: ToolContext, name: str, description: str | None, input_schema: dict
167
202
  ) -> RawFunctionTool:
168
203
 
204
+ name = safe_tool_name(name)
169
205
  async def _tool_called(raw_arguments: dict) -> Any:
170
206
  try:
171
207
 
172
208
  tool = None
173
209
  for toolkit in toolkits:
174
210
  for t in toolkit.tools:
175
- if t.name == name:
211
+ if safe_tool_name(t.name) == name:
176
212
  tool = t
177
213
 
178
214
  if tool is None:
@@ -180,8 +216,12 @@ class Voicebot(SingleRoomAgent):
180
216
  f"Could not find tool {name}"
181
217
  )
182
218
 
183
- tool_result = await tool.execute(context, **raw_arguments)
184
-
219
+ try:
220
+ logger.info(f"executing tool {name}: {raw_arguments}")
221
+ tool_result = await tool.execute(context=context, **raw_arguments)
222
+ except Exception as e:
223
+ logger.error(f"failed to call tool {tool.name}: {e}")
224
+ return ToolError("f{e}")
185
225
  if self.tool_adapter == None:
186
226
 
187
227
  if isinstance(tool_result, ErrorResponse):
@@ -189,7 +229,17 @@ class Voicebot(SingleRoomAgent):
189
229
 
190
230
  if isinstance(tool_result, JsonResponse):
191
231
  return json.dumps(tool_result.json)
232
+
233
+ if isinstance(tool_result, TextResponse):
234
+ return tool_result.text
192
235
 
236
+ if isinstance(tool_result, EmptyResponse):
237
+ return "success"
238
+
239
+ if tool_result == None:
240
+ return "success"
241
+
242
+
193
243
  raise ToolError(
194
244
  f"Tool '{name}' returned an unexpected result {type(tool_result)}, attach a tool response adapter"
195
245
  )
@@ -197,6 +247,8 @@ class Voicebot(SingleRoomAgent):
197
247
  else:
198
248
 
199
249
  text = await self.tool_adapter.to_plain_text(room=context.room, response=tool_result)
250
+ if text == None:
251
+ text = "success"
200
252
  return text
201
253
 
202
254
  except Exception as e:
@@ -206,15 +258,26 @@ class Voicebot(SingleRoomAgent):
206
258
 
207
259
  return function_tool(
208
260
  _tool_called,
209
- raw_schema={"name": name, "description": description, "parameters": input_schema},
261
+ raw_schema={"name": name, "description": description, "strict" : True, "parameters": input_schema},
210
262
  )
211
263
 
212
- async def create_agent(self, *, context: ToolContext):
213
- return Agent(
264
+ async def create_agent(self, *, context: ToolContext, session: AgentSession):
265
+
266
+ @function_tool
267
+ async def say(context: RunContext, text: str):
268
+ "says something out loud to the user"
269
+ logger.info(f"saying: {text}")
270
+ session.say(text)
271
+ return "success"
272
+
273
+ return Agent(
214
274
  instructions="\n".join(self.rules),
215
275
  allow_interruptions=True,
216
- tools=await self.make_function_tools(context=context)
217
- )
276
+ tools=[
277
+ *await self.make_function_tools(context=context),
278
+ say
279
+ ]
280
+ )
218
281
 
219
282
  # agent = Agent(
220
283
  # instructions="""
@@ -230,17 +293,14 @@ class Voicebot(SingleRoomAgent):
230
293
  def create_session(self) -> AgentSession:
231
294
 
232
295
  session = AgentSession(
296
+ max_tool_steps=50,
233
297
  allow_interruptions=True,
234
298
  vad=silero.VAD.load(),
235
299
  stt=openai.STT(),
236
300
  tts=openai.TTS(voice="echo"),
237
- llm=openai.realtime.RealtimeModel(
238
- # it's necessary to turn off turn detection in the Realtime API in order to use
239
- # LiveKit's turn detection model
240
- voice="alloy",
241
- turn_detection=None,
242
- input_audio_transcription=None,
243
- ),
301
+ llm=openai.LLM(),
302
+ #turn_detection=MultilingualModel(),
303
+
244
304
  )
245
305
  return session
246
306
 
@@ -251,12 +311,23 @@ class Voicebot(SingleRoomAgent):
251
311
 
252
312
  logger.info("starting voice agent")
253
313
 
314
+ session = self.create_session()
315
+
254
316
  agent = await self.create_agent(context=ToolContext(
255
317
  room=self.room,
256
318
  caller=self.room.local_participant,
257
319
  on_behalf_of=participant
258
- ))
259
- session = self.create_session()
320
+ ), session=session)
321
+
322
+ background_audio = BackgroundAudioPlayer(
323
+ thinking_sound=[
324
+ #AudioConfig(
325
+ # os.path.dirname(os.path.abspath(__file__)) +"/sfx/thinking.mp3", volume=0.2),
326
+ AudioConfig(BuiltinAudioClip.KEYBOARD_TYPING, volume=0.3),
327
+ AudioConfig(BuiltinAudioClip.KEYBOARD_TYPING2, volume=0.4),
328
+ ],
329
+ )
330
+ await background_audio.start(room=connection.livekit_room, agent_session=session)
260
331
 
261
332
  await session.start(agent=agent, room=connection.livekit_room)
262
333
 
@@ -1 +1 @@
1
- __version__ = "0.0.20"
1
+ __version__ = "0.0.21"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshagent-livekit
3
- Version: 0.0.20
3
+ Version: 0.0.21
4
4
  Summary: Livekit support for Meshagent
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Documentation, https://meshagent.com
@@ -20,6 +20,6 @@ Requires-Dist: livekit-plugins-elevenlabs~=1.0.19
20
20
  Requires-Dist: livekit-plugins-playai~=1.0.19
21
21
  Requires-Dist: livekit-plugins-silero~=1.0.19
22
22
  Requires-Dist: livekit-plugins-turn-detector~=1.0.19
23
- Requires-Dist: meshagent-api~=0.0.20
24
- Requires-Dist: meshagent-tools~=0.0.20
23
+ Requires-Dist: meshagent-api~=0.0.21
24
+ Requires-Dist: meshagent-tools~=0.0.21
25
25
  Dynamic: license-file
@@ -1,12 +1,12 @@
1
1
  meshagent/livekit/__init__.py,sha256=8zLGg-DfQhnDl2Ky0n-zXpN-8e-g7iR0AcaI4l4Vvpk,32
2
2
  meshagent/livekit/livekit_protocol.py,sha256=K9yP-qpxag5_7TXlKjFEx3cOJJJpYI_z6zGzFHoN1Hs,1421
3
3
  meshagent/livekit/livekit_protocol_test.py,sha256=n_ZQjt7n4u7TM7eENzH8L0tw8LvypS_JHF_PuJ2o6h4,2836
4
- meshagent/livekit/version.py,sha256=cw-wPso5400rXRCR6WsHwthEUW8-b_VMrztjcYwBGfQ,22
4
+ meshagent/livekit/version.py,sha256=9_nCx08vWHyj8RiwIYqwqah3T4SPB46e0jnaNSxxfDc,22
5
5
  meshagent/livekit/agents/transcriber.py,sha256=Dq1Ijx4gmA-0jQGM-f3w7X-JIZpkRCFDxWae9AOwz-k,12290
6
- meshagent/livekit/agents/voice.py,sha256=yH3aon9s4Royb7gp3raRWKv_wMTXsVD5DcePkf9cPxQ,8599
6
+ meshagent/livekit/agents/voice.py,sha256=uVpm-YeP1oXkg6gk1zFSwVEdp5XGQVimgs3DdNjEpbg,11230
7
7
  meshagent/livekit/tools/speech.py,sha256=UMhdHhTo04xdzHhvvCeTayT_YT86dzx4ZERRF18C0-o,10188
8
- meshagent_livekit-0.0.20.dist-info/licenses/LICENSE,sha256=eTt0SPW-sVNdkZe9PS_S8WfCIyLjRXRl7sUBWdlteFg,10254
9
- meshagent_livekit-0.0.20.dist-info/METADATA,sha256=RsP4V6xdAyfx0L_pgT0IA8Ms5GvN9UKVR-8x7o4gyuY,924
10
- meshagent_livekit-0.0.20.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
11
- meshagent_livekit-0.0.20.dist-info/top_level.txt,sha256=GlcXnHtRP6m7zlG3Df04M35OsHtNXy_DY09oFwWrH74,10
12
- meshagent_livekit-0.0.20.dist-info/RECORD,,
8
+ meshagent_livekit-0.0.21.dist-info/licenses/LICENSE,sha256=eTt0SPW-sVNdkZe9PS_S8WfCIyLjRXRl7sUBWdlteFg,10254
9
+ meshagent_livekit-0.0.21.dist-info/METADATA,sha256=HNq297tsUcj91no9YiCAUOlJZCGfQTMlpVmaUBeUF_8,924
10
+ meshagent_livekit-0.0.21.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
11
+ meshagent_livekit-0.0.21.dist-info/top_level.txt,sha256=GlcXnHtRP6m7zlG3Df04M35OsHtNXy_DY09oFwWrH74,10
12
+ meshagent_livekit-0.0.21.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.4.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5