livekit-plugins-anthropic 0.2.9__tar.gz → 0.2.11__tar.gz
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.
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/PKG-INFO +12 -2
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/livekit/plugins/anthropic/llm.py +111 -27
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/livekit/plugins/anthropic/version.py +1 -1
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/livekit_plugins_anthropic.egg-info/PKG-INFO +12 -2
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/README.md +0 -0
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/livekit/plugins/anthropic/__init__.py +0 -0
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/livekit/plugins/anthropic/log.py +0 -0
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/livekit/plugins/anthropic/models.py +0 -0
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/livekit/plugins/anthropic/py.typed +0 -0
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/livekit_plugins_anthropic.egg-info/SOURCES.txt +0 -0
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/livekit_plugins_anthropic.egg-info/dependency_links.txt +0 -0
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/livekit_plugins_anthropic.egg-info/requires.txt +0 -0
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/livekit_plugins_anthropic.egg-info/top_level.txt +0 -0
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/pyproject.toml +0 -0
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/setup.cfg +0 -0
- {livekit_plugins_anthropic-0.2.9 → livekit_plugins_anthropic-0.2.11}/setup.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: livekit-plugins-anthropic
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.11
|
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
|
@@ -21,6 +21,16 @@ Requires-Python: >=3.9.0
|
|
21
21
|
Description-Content-Type: text/markdown
|
22
22
|
Requires-Dist: livekit-agents>=0.12.3
|
23
23
|
Requires-Dist: anthropic>=0.34
|
24
|
+
Dynamic: classifier
|
25
|
+
Dynamic: description
|
26
|
+
Dynamic: description-content-type
|
27
|
+
Dynamic: home-page
|
28
|
+
Dynamic: keywords
|
29
|
+
Dynamic: license
|
30
|
+
Dynamic: project-url
|
31
|
+
Dynamic: requires-dist
|
32
|
+
Dynamic: requires-python
|
33
|
+
Dynamic: summary
|
24
34
|
|
25
35
|
# LiveKit Plugins Anthropic
|
26
36
|
|
@@ -39,7 +39,7 @@ from livekit.agents import (
|
|
39
39
|
llm,
|
40
40
|
utils,
|
41
41
|
)
|
42
|
-
from livekit.agents.llm import ToolChoice
|
42
|
+
from livekit.agents.llm import LLMCapabilities, ToolChoice
|
43
43
|
from livekit.agents.llm.function_context import (
|
44
44
|
_create_ai_function_info,
|
45
45
|
_is_optional_type,
|
@@ -53,6 +53,8 @@ from .models import (
|
|
53
53
|
ChatModels,
|
54
54
|
)
|
55
55
|
|
56
|
+
CACHE_CONTROL_EPHEMERAL = anthropic.types.CacheControlEphemeralParam(type="ephemeral")
|
57
|
+
|
56
58
|
|
57
59
|
@dataclass
|
58
60
|
class LLMOptions:
|
@@ -61,6 +63,8 @@ class LLMOptions:
|
|
61
63
|
temperature: float | None
|
62
64
|
parallel_tool_calls: bool | None
|
63
65
|
tool_choice: Union[ToolChoice, Literal["auto", "required", "none"]] | None
|
66
|
+
caching: Literal["ephemeral"] | None = None
|
67
|
+
"""If set to "ephemeral", the system prompt, tools, and chat history will be cached."""
|
64
68
|
|
65
69
|
|
66
70
|
class LLM(llm.LLM):
|
@@ -75,14 +79,31 @@ class LLM(llm.LLM):
|
|
75
79
|
temperature: float | None = None,
|
76
80
|
parallel_tool_calls: bool | None = None,
|
77
81
|
tool_choice: Union[ToolChoice, Literal["auto", "required", "none"]] = "auto",
|
82
|
+
caching: Literal["ephemeral"] | None = None,
|
78
83
|
) -> None:
|
79
84
|
"""
|
80
85
|
Create a new instance of Anthropic LLM.
|
81
86
|
|
82
87
|
``api_key`` must be set to your Anthropic API key, either using the argument or by setting
|
83
88
|
the ``ANTHROPIC_API_KEY`` environmental variable.
|
89
|
+
|
90
|
+
model (str | ChatModels): The model to use. Defaults to "claude-3-5-sonnet-20241022".
|
91
|
+
api_key (str | None): The Anthropic API key. Defaults to the ANTHROPIC_API_KEY environment variable.
|
92
|
+
base_url (str | None): The base URL for the Anthropic API. Defaults to None.
|
93
|
+
user (str | None): The user for the Anthropic API. Defaults to None.
|
94
|
+
client (anthropic.AsyncClient | None): The Anthropic client to use. Defaults to None.
|
95
|
+
temperature (float | None): The temperature for the Anthropic API. Defaults to None.
|
96
|
+
parallel_tool_calls (bool | None): Whether to parallelize tool calls. Defaults to None.
|
97
|
+
tool_choice (Union[ToolChoice, Literal["auto", "required", "none"]] | None): The tool choice for the Anthropic API. Defaults to "auto".
|
98
|
+
caching (Literal["ephemeral"] | None): If set to "ephemeral", caching will be enabled for the system prompt, tools, and chat history.
|
84
99
|
"""
|
85
|
-
|
100
|
+
|
101
|
+
super().__init__(
|
102
|
+
capabilities=LLMCapabilities(
|
103
|
+
requires_persistent_functions=True,
|
104
|
+
supports_choices_on_int=True,
|
105
|
+
)
|
106
|
+
)
|
86
107
|
|
87
108
|
# throw an error on our end
|
88
109
|
api_key = api_key or os.environ.get("ANTHROPIC_API_KEY")
|
@@ -95,6 +116,7 @@ class LLM(llm.LLM):
|
|
95
116
|
temperature=temperature,
|
96
117
|
parallel_tool_calls=parallel_tool_calls,
|
97
118
|
tool_choice=tool_choice,
|
119
|
+
caching=caching,
|
98
120
|
)
|
99
121
|
self._client = client or anthropic.AsyncClient(
|
100
122
|
api_key=api_key,
|
@@ -132,8 +154,20 @@ class LLM(llm.LLM):
|
|
132
154
|
opts: dict[str, Any] = dict()
|
133
155
|
if fnc_ctx and len(fnc_ctx.ai_functions) > 0:
|
134
156
|
fncs_desc: list[anthropic.types.ToolParam] = []
|
135
|
-
for fnc in fnc_ctx.ai_functions.values():
|
136
|
-
|
157
|
+
for i, fnc in enumerate(fnc_ctx.ai_functions.values()):
|
158
|
+
# caching last tool will cache all the tools if caching is enabled
|
159
|
+
cache_ctrl = (
|
160
|
+
CACHE_CONTROL_EPHEMERAL
|
161
|
+
if (i == len(fnc_ctx.ai_functions) - 1)
|
162
|
+
and self._opts.caching == "ephemeral"
|
163
|
+
else None
|
164
|
+
)
|
165
|
+
fncs_desc.append(
|
166
|
+
_build_function_description(
|
167
|
+
fnc,
|
168
|
+
cache_ctrl=cache_ctrl,
|
169
|
+
)
|
170
|
+
)
|
137
171
|
|
138
172
|
opts["tools"] = fncs_desc
|
139
173
|
if tool_choice is not None:
|
@@ -151,13 +185,19 @@ class LLM(llm.LLM):
|
|
151
185
|
anthropic_tool_choice["disable_parallel_tool_use"] = True
|
152
186
|
opts["tool_choice"] = anthropic_tool_choice
|
153
187
|
|
154
|
-
latest_system_message = _latest_system_message(
|
155
|
-
|
188
|
+
latest_system_message: anthropic.types.TextBlockParam = _latest_system_message(
|
189
|
+
chat_ctx, caching=self._opts.caching
|
190
|
+
)
|
191
|
+
anthropic_ctx = _build_anthropic_context(
|
192
|
+
chat_ctx.messages,
|
193
|
+
id(self),
|
194
|
+
caching=self._opts.caching,
|
195
|
+
)
|
156
196
|
collaped_anthropic_ctx = _merge_messages(anthropic_ctx)
|
157
197
|
|
158
198
|
stream = self._client.messages.create(
|
159
199
|
max_tokens=opts.get("max_tokens", 1024),
|
160
|
-
system=latest_system_message,
|
200
|
+
system=[latest_system_message],
|
161
201
|
messages=collaped_anthropic_ctx,
|
162
202
|
model=self._opts.model,
|
163
203
|
temperature=temperature or anthropic.NOT_GIVEN,
|
@@ -203,6 +243,8 @@ class LLMStream(llm.LLMStream):
|
|
203
243
|
self._request_id: str = ""
|
204
244
|
self._ignoring_cot = False # ignore chain of thought
|
205
245
|
self._input_tokens = 0
|
246
|
+
self._cache_creation_tokens = 0
|
247
|
+
self._cache_read_tokens = 0
|
206
248
|
self._output_tokens = 0
|
207
249
|
|
208
250
|
async def _run(self) -> None:
|
@@ -224,7 +266,12 @@ class LLMStream(llm.LLMStream):
|
|
224
266
|
usage=llm.CompletionUsage(
|
225
267
|
completion_tokens=self._output_tokens,
|
226
268
|
prompt_tokens=self._input_tokens,
|
227
|
-
total_tokens=self._input_tokens
|
269
|
+
total_tokens=self._input_tokens
|
270
|
+
+ self._output_tokens
|
271
|
+
+ self._cache_creation_tokens
|
272
|
+
+ self._cache_read_tokens,
|
273
|
+
cache_creation_input_tokens=self._cache_creation_tokens,
|
274
|
+
cache_read_input_tokens=self._cache_read_tokens,
|
228
275
|
),
|
229
276
|
)
|
230
277
|
)
|
@@ -247,6 +294,12 @@ class LLMStream(llm.LLMStream):
|
|
247
294
|
self._request_id = event.message.id
|
248
295
|
self._input_tokens = event.message.usage.input_tokens
|
249
296
|
self._output_tokens = event.message.usage.output_tokens
|
297
|
+
if event.message.usage.cache_creation_input_tokens:
|
298
|
+
self._cache_creation_tokens = (
|
299
|
+
event.message.usage.cache_creation_input_tokens
|
300
|
+
)
|
301
|
+
if event.message.usage.cache_read_input_tokens:
|
302
|
+
self._cache_read_tokens = event.message.usage.cache_read_input_tokens
|
250
303
|
elif event.type == "message_delta":
|
251
304
|
self._output_tokens += event.usage.output_tokens
|
252
305
|
elif event.type == "content_block_start":
|
@@ -311,7 +364,9 @@ class LLMStream(llm.LLMStream):
|
|
311
364
|
return None
|
312
365
|
|
313
366
|
|
314
|
-
def _latest_system_message(
|
367
|
+
def _latest_system_message(
|
368
|
+
chat_ctx: llm.ChatContext, caching: Literal["ephemeral"] | None = None
|
369
|
+
) -> anthropic.types.TextBlockParam:
|
315
370
|
latest_system_message: llm.ChatMessage | None = None
|
316
371
|
for m in chat_ctx.messages:
|
317
372
|
if m.role == "system":
|
@@ -326,7 +381,12 @@ def _latest_system_message(chat_ctx: llm.ChatContext) -> str:
|
|
326
381
|
latest_system_str = " ".join(
|
327
382
|
[c for c in latest_system_message.content if isinstance(c, str)]
|
328
383
|
)
|
329
|
-
|
384
|
+
system_text_block = anthropic.types.TextBlockParam(
|
385
|
+
text=latest_system_str,
|
386
|
+
type="text",
|
387
|
+
cache_control=CACHE_CONTROL_EPHEMERAL if caching == "ephemeral" else None,
|
388
|
+
)
|
389
|
+
return system_text_block
|
330
390
|
|
331
391
|
|
332
392
|
def _merge_messages(
|
@@ -356,18 +416,29 @@ def _merge_messages(
|
|
356
416
|
|
357
417
|
|
358
418
|
def _build_anthropic_context(
|
359
|
-
chat_ctx: List[llm.ChatMessage],
|
419
|
+
chat_ctx: List[llm.ChatMessage],
|
420
|
+
cache_key: Any,
|
421
|
+
caching: Literal["ephemeral"] | None,
|
360
422
|
) -> List[anthropic.types.MessageParam]:
|
361
423
|
result: List[anthropic.types.MessageParam] = []
|
362
|
-
for msg in chat_ctx:
|
363
|
-
|
424
|
+
for i, msg in enumerate(chat_ctx):
|
425
|
+
# caching last message will cache whole chat history if caching is enabled
|
426
|
+
cache_ctrl = (
|
427
|
+
CACHE_CONTROL_EPHEMERAL
|
428
|
+
if ((i == len(chat_ctx) - 1) and caching == "ephemeral")
|
429
|
+
else None
|
430
|
+
)
|
431
|
+
a_msg = _build_anthropic_message(msg, cache_key, cache_ctrl=cache_ctrl)
|
432
|
+
|
364
433
|
if a_msg:
|
365
434
|
result.append(a_msg)
|
366
435
|
return result
|
367
436
|
|
368
437
|
|
369
438
|
def _build_anthropic_message(
|
370
|
-
msg: llm.ChatMessage,
|
439
|
+
msg: llm.ChatMessage,
|
440
|
+
cache_key: Any,
|
441
|
+
cache_ctrl: anthropic.types.CacheControlEphemeralParam | None,
|
371
442
|
) -> anthropic.types.MessageParam | None:
|
372
443
|
if msg.role == "user" or msg.role == "assistant":
|
373
444
|
a_msg: anthropic.types.MessageParam = {
|
@@ -380,22 +451,27 @@ def _build_anthropic_message(
|
|
380
451
|
# add content if provided
|
381
452
|
if isinstance(msg.content, str) and msg.content:
|
382
453
|
a_msg["content"].append(
|
383
|
-
anthropic.types.
|
454
|
+
anthropic.types.TextBlockParam(
|
384
455
|
text=msg.content,
|
385
456
|
type="text",
|
457
|
+
cache_control=cache_ctrl,
|
386
458
|
)
|
387
459
|
)
|
388
460
|
elif isinstance(msg.content, list):
|
389
461
|
for cnt in msg.content:
|
390
462
|
if isinstance(cnt, str) and cnt:
|
391
|
-
content: anthropic.types.
|
392
|
-
|
393
|
-
|
463
|
+
content: anthropic.types.TextBlockParam = (
|
464
|
+
anthropic.types.TextBlockParam(
|
465
|
+
text=cnt,
|
466
|
+
type="text",
|
467
|
+
cache_control=cache_ctrl,
|
468
|
+
)
|
394
469
|
)
|
395
470
|
a_content.append(content)
|
396
471
|
elif isinstance(cnt, llm.ChatImage):
|
397
|
-
a_content.append(
|
398
|
-
|
472
|
+
a_content.append(
|
473
|
+
_build_anthropic_image_content(cnt, cache_key, cache_ctrl)
|
474
|
+
)
|
399
475
|
if msg.tool_calls is not None:
|
400
476
|
for fnc in msg.tool_calls:
|
401
477
|
tool_use = anthropic.types.ToolUseBlockParam(
|
@@ -403,6 +479,7 @@ def _build_anthropic_message(
|
|
403
479
|
type="tool_use",
|
404
480
|
name=fnc.function_info.name,
|
405
481
|
input=fnc.arguments,
|
482
|
+
cache_control=cache_ctrl,
|
406
483
|
)
|
407
484
|
a_content.append(tool_use)
|
408
485
|
|
@@ -421,6 +498,7 @@ def _build_anthropic_message(
|
|
421
498
|
type="tool_result",
|
422
499
|
content=msg.content,
|
423
500
|
is_error=msg.tool_exception is not None,
|
501
|
+
cache_control=cache_ctrl,
|
424
502
|
)
|
425
503
|
return {
|
426
504
|
"role": "user",
|
@@ -431,7 +509,9 @@ def _build_anthropic_message(
|
|
431
509
|
|
432
510
|
|
433
511
|
def _build_anthropic_image_content(
|
434
|
-
image: llm.ChatImage,
|
512
|
+
image: llm.ChatImage,
|
513
|
+
cache_key: Any,
|
514
|
+
cache_ctrl: anthropic.types.CacheControlEphemeralParam | None,
|
435
515
|
) -> anthropic.types.ImageBlockParam:
|
436
516
|
if isinstance(image.image, str): # image is a URL
|
437
517
|
if not image.image.startswith("data:"):
|
@@ -457,6 +537,7 @@ def _build_anthropic_image_content(
|
|
457
537
|
media_type,
|
458
538
|
),
|
459
539
|
},
|
540
|
+
"cache_control": cache_ctrl,
|
460
541
|
}
|
461
542
|
except (ValueError, IndexError) as e:
|
462
543
|
raise ValueError(
|
@@ -484,6 +565,7 @@ def _build_anthropic_image_content(
|
|
484
565
|
"data": image._cache[cache_key],
|
485
566
|
"media_type": "image/jpeg",
|
486
567
|
},
|
568
|
+
"cache_control": cache_ctrl,
|
487
569
|
}
|
488
570
|
|
489
571
|
raise ValueError(
|
@@ -493,6 +575,7 @@ def _build_anthropic_image_content(
|
|
493
575
|
|
494
576
|
def _build_function_description(
|
495
577
|
fnc_info: llm.function_context.FunctionInfo,
|
578
|
+
cache_ctrl: anthropic.types.CacheControlEphemeralParam | None,
|
496
579
|
) -> anthropic.types.ToolParam:
|
497
580
|
def build_schema_field(arg_info: llm.function_context.FunctionArgInfo):
|
498
581
|
def type2str(t: type) -> str:
|
@@ -514,7 +597,7 @@ def _build_function_description(
|
|
514
597
|
if arg_info.description:
|
515
598
|
p["description"] = arg_info.description
|
516
599
|
|
517
|
-
|
600
|
+
_, inner_th = _is_optional_type(arg_info.type)
|
518
601
|
|
519
602
|
if get_origin(inner_th) is list:
|
520
603
|
inner_type = get_args(inner_th)[0]
|
@@ -536,8 +619,9 @@ def _build_function_description(
|
|
536
619
|
for arg_info in fnc_info.arguments.values():
|
537
620
|
input_schema[arg_info.name] = build_schema_field(arg_info)
|
538
621
|
|
539
|
-
return
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
622
|
+
return anthropic.types.ToolParam(
|
623
|
+
name=fnc_info.name,
|
624
|
+
description=fnc_info.description,
|
625
|
+
input_schema=input_schema,
|
626
|
+
cache_control=cache_ctrl,
|
627
|
+
)
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: livekit-plugins-anthropic
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.11
|
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
|
@@ -21,6 +21,16 @@ Requires-Python: >=3.9.0
|
|
21
21
|
Description-Content-Type: text/markdown
|
22
22
|
Requires-Dist: livekit-agents>=0.12.3
|
23
23
|
Requires-Dist: anthropic>=0.34
|
24
|
+
Dynamic: classifier
|
25
|
+
Dynamic: description
|
26
|
+
Dynamic: description-content-type
|
27
|
+
Dynamic: home-page
|
28
|
+
Dynamic: keywords
|
29
|
+
Dynamic: license
|
30
|
+
Dynamic: project-url
|
31
|
+
Dynamic: requires-dist
|
32
|
+
Dynamic: requires-python
|
33
|
+
Dynamic: summary
|
24
34
|
|
25
35
|
# LiveKit Plugins Anthropic
|
26
36
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|