livekit-plugins-anthropic 0.2.0__py3-none-any.whl → 0.2.1__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.
@@ -43,7 +43,7 @@ class LLM(llm.LLM):
43
43
  def __init__(
44
44
  self,
45
45
  *,
46
- model: str | ChatModels = "claude-3-opus-20240229",
46
+ model: str | ChatModels = "claude-3-haiku-20240307",
47
47
  api_key: str | None = None,
48
48
  base_url: str | None = None,
49
49
  user: str | None = None,
@@ -144,6 +144,9 @@ class LLMStream(llm.LLMStream):
144
144
  if not self._anthropic_stream:
145
145
  self._anthropic_stream = await self._awaitable_anthropic_stream
146
146
 
147
+ fn_calling_enabled = self._fnc_ctx is not None
148
+ ignore = False
149
+
147
150
  async for event in self._anthropic_stream:
148
151
  if event.type == "message_start":
149
152
  pass
@@ -159,18 +162,34 @@ class LLMStream(llm.LLMStream):
159
162
  elif event.type == "content_block_delta":
160
163
  delta = event.delta
161
164
  if delta.type == "text_delta":
165
+ text = delta.text
166
+
167
+ # Anthropic seems to add a prompt when tool calling is enabled
168
+ # where responses always start with a "<thinking>" block containing
169
+ # the LLM's chain of thought. It's very verbose and not useful for voice
170
+ # applications.
171
+ if fn_calling_enabled:
172
+ if text.startswith("<thinking>"):
173
+ ignore = True
174
+
175
+ if "</thinking>" in text:
176
+ text = text.split("</thinking>")[-1]
177
+ ignore = False
178
+
179
+ if ignore:
180
+ continue
181
+
162
182
  return llm.ChatChunk(
163
183
  choices=[
164
184
  llm.Choice(
165
- delta=llm.ChoiceDelta(
166
- content=delta.text, role="assistant"
167
- )
185
+ delta=llm.ChoiceDelta(content=text, role="assistant")
168
186
  )
169
187
  ]
170
188
  )
171
189
  elif delta.type == "input_json_delta":
172
190
  assert self._fnc_raw_arguments is not None
173
191
  self._fnc_raw_arguments += delta.partial_json
192
+
174
193
  elif event.type == "content_block_stop":
175
194
  if self._tool_call_id is not None and self._fnc_ctx:
176
195
  assert self._fnc_name is not None
@@ -249,13 +268,15 @@ def _build_anthropic_context(
249
268
  ) -> List[anthropic.types.MessageParam]:
250
269
  result: List[anthropic.types.MessageParam] = []
251
270
  for msg in chat_ctx:
252
- a_msg = _build_anthropic_message(msg, cache_key)
271
+ a_msg = _build_anthropic_message(msg, cache_key, chat_ctx)
253
272
  if a_msg:
254
273
  result.append(a_msg)
255
274
  return result
256
275
 
257
276
 
258
- def _build_anthropic_message(msg: llm.ChatMessage, cache_key: Any):
277
+ def _build_anthropic_message(
278
+ msg: llm.ChatMessage, cache_key: Any, chat_ctx: List[llm.ChatMessage]
279
+ ) -> anthropic.types.MessageParam | None:
259
280
  if msg.role == "user" or msg.role == "assistant":
260
281
  a_msg: anthropic.types.MessageParam = {
261
282
  "role": msg.role,
@@ -282,38 +303,35 @@ def _build_anthropic_message(msg: llm.ChatMessage, cache_key: Any):
282
303
  a_content.append(content)
283
304
  elif isinstance(cnt, llm.ChatImage):
284
305
  a_content.append(_build_anthropic_image_content(cnt, cache_key))
285
- return a_msg
286
- elif msg.role == "tool":
287
- ant_msg: anthropic.types.MessageParam = {
288
- "role": "assistant",
289
- "content": [],
290
- }
291
- assert isinstance(ant_msg["content"], list)
292
- # make sure to provide when function has been called inside the context
293
- # (+ raw_arguments)
306
+
294
307
  if msg.tool_calls is not None:
295
308
  for fnc in msg.tool_calls:
296
- ant_msg["content"].append(
297
- {
298
- "id": fnc.tool_call_id,
299
- "type": "tool_use",
300
- "input": fnc.arguments,
301
- "name": fnc.function_info.name,
302
- }
309
+ tool_use = anthropic.types.ToolUseBlockParam(
310
+ id=fnc.tool_call_id,
311
+ type="tool_use",
312
+ name=fnc.function_info.name,
313
+ input=fnc.arguments,
303
314
  )
304
- if isinstance(msg.content, str):
305
- ant_msg["content"].append(
306
- {
307
- "tool_use_id": fnc.tool_call_id,
308
- "type": "tool_result",
309
- "content": msg.content,
310
- }
311
- )
312
- else:
313
- logger.warning(
314
- "tool result content is not a string, this is not supported by anthropic"
315
- )
316
- return ant_msg
315
+ a_content.append(tool_use)
316
+
317
+ return a_msg
318
+ elif msg.role == "tool":
319
+ if not isinstance(msg.content, str):
320
+ logger.warning("tool message content is not a string")
321
+ return None
322
+ if not msg.tool_call_id:
323
+ return None
324
+
325
+ u_content = anthropic.types.ToolResultBlockParam(
326
+ tool_use_id=msg.tool_call_id,
327
+ type="tool_result",
328
+ content=msg.content,
329
+ is_error=msg.tool_exception is not None,
330
+ )
331
+ return {
332
+ "role": "user",
333
+ "content": [u_content],
334
+ }
317
335
 
318
336
  return None
319
337
 
@@ -12,4 +12,4 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- __version__ = "0.2.0"
15
+ __version__ = "0.2.1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: livekit-plugins-anthropic
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Agent Framework plugin for services from Anthropic
5
5
  Home-page: https://github.com/livekit/agents
6
6
  License: Apache-2.0
@@ -0,0 +1,10 @@
1
+ livekit/plugins/anthropic/__init__.py,sha256=g6KUqOfZo9DIBwBD98u6QOWY7pr8ZYJJ61fk3AWpoa4,1006
2
+ livekit/plugins/anthropic/llm.py,sha256=s6Xt_5kuvypG1ZLUq_aYaYO_ZaTgagyM4b1c5iI2WUo,17652
3
+ livekit/plugins/anthropic/log.py,sha256=fG1pYSY88AnT738gZrmzF9FO4l4BdGENj3VKHMQB3Yo,72
4
+ livekit/plugins/anthropic/models.py,sha256=AVEhrEtKfWxsd-R03u7R74hcKjJq4oDVSTukvoPQGb0,179
5
+ livekit/plugins/anthropic/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ livekit/plugins/anthropic/version.py,sha256=tb-eucPKT0bz3vQDaI1ltUZEhGKRFOFhN3U5ZIv_-xY,600
7
+ livekit_plugins_anthropic-0.2.1.dist-info/METADATA,sha256=-m1Q9gn3H1gRoVjFb1uIDfyJ5TP6p1HEMrh-zDyGeQs,1264
8
+ livekit_plugins_anthropic-0.2.1.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
9
+ livekit_plugins_anthropic-0.2.1.dist-info/top_level.txt,sha256=OoDok3xUmXbZRvOrfvvXB-Juu4DX79dlq188E19YHoo,8
10
+ livekit_plugins_anthropic-0.2.1.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- livekit/plugins/anthropic/__init__.py,sha256=g6KUqOfZo9DIBwBD98u6QOWY7pr8ZYJJ61fk3AWpoa4,1006
2
- livekit/plugins/anthropic/llm.py,sha256=SJo_opc9_2rKYvcDW8-ltuOD-p7QUc0oROGDHu04htY,17162
3
- livekit/plugins/anthropic/log.py,sha256=fG1pYSY88AnT738gZrmzF9FO4l4BdGENj3VKHMQB3Yo,72
4
- livekit/plugins/anthropic/models.py,sha256=AVEhrEtKfWxsd-R03u7R74hcKjJq4oDVSTukvoPQGb0,179
5
- livekit/plugins/anthropic/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- livekit/plugins/anthropic/version.py,sha256=cLFCdnm5S21CiJ5UJBcqfRvvFkCQ8p6M5fFUJVJkEiM,600
7
- livekit_plugins_anthropic-0.2.0.dist-info/METADATA,sha256=1VWzsOFCxwtoB2m-NVZgKPoPI8xwsZctTbZJO8FYxbI,1264
8
- livekit_plugins_anthropic-0.2.0.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
9
- livekit_plugins_anthropic-0.2.0.dist-info/top_level.txt,sha256=OoDok3xUmXbZRvOrfvvXB-Juu4DX79dlq188E19YHoo,8
10
- livekit_plugins_anthropic-0.2.0.dist-info/RECORD,,