livekit-plugins-anthropic 0.2.6__py3-none-any.whl → 0.2.8__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.
- livekit/plugins/anthropic/llm.py +46 -98
- livekit/plugins/anthropic/version.py +1 -1
- {livekit_plugins_anthropic-0.2.6.dist-info → livekit_plugins_anthropic-0.2.8.dist-info}/METADATA +2 -2
- livekit_plugins_anthropic-0.2.8.dist-info/RECORD +10 -0
- livekit_plugins_anthropic-0.2.6.dist-info/RECORD +0 -10
- {livekit_plugins_anthropic-0.2.6.dist-info → livekit_plugins_anthropic-0.2.8.dist-info}/WHEEL +0 -0
- {livekit_plugins_anthropic-0.2.6.dist-info → livekit_plugins_anthropic-0.2.8.dist-info}/top_level.txt +0 -0
livekit/plugins/anthropic/llm.py
CHANGED
@@ -24,8 +24,8 @@ from typing import (
|
|
24
24
|
Awaitable,
|
25
25
|
List,
|
26
26
|
Literal,
|
27
|
-
Tuple,
|
28
27
|
Union,
|
28
|
+
cast,
|
29
29
|
get_args,
|
30
30
|
get_origin,
|
31
31
|
)
|
@@ -40,6 +40,10 @@ from livekit.agents import (
|
|
40
40
|
utils,
|
41
41
|
)
|
42
42
|
from livekit.agents.llm import ToolChoice
|
43
|
+
from livekit.agents.llm.function_context import (
|
44
|
+
_create_ai_function_info,
|
45
|
+
_is_optional_type,
|
46
|
+
)
|
43
47
|
from livekit.agents.types import DEFAULT_API_CONNECT_OPTIONS, APIConnectOptions
|
44
48
|
|
45
49
|
import anthropic
|
@@ -402,8 +406,10 @@ def _build_anthropic_message(
|
|
402
406
|
|
403
407
|
return a_msg
|
404
408
|
elif msg.role == "tool":
|
409
|
+
if isinstance(msg.content, dict):
|
410
|
+
msg.content = json.dumps(msg.content)
|
405
411
|
if not isinstance(msg.content, str):
|
406
|
-
logger.warning("tool message content is not a string")
|
412
|
+
logger.warning("tool message content is not a string or dict")
|
407
413
|
return None
|
408
414
|
if not msg.tool_call_id:
|
409
415
|
return None
|
@@ -425,11 +431,36 @@ def _build_anthropic_message(
|
|
425
431
|
def _build_anthropic_image_content(
|
426
432
|
image: llm.ChatImage, cache_key: Any
|
427
433
|
) -> anthropic.types.ImageBlockParam:
|
428
|
-
if isinstance(image.image, str): # image
|
429
|
-
|
430
|
-
"
|
431
|
-
|
432
|
-
|
434
|
+
if isinstance(image.image, str): # image is a URL
|
435
|
+
if not image.image.startswith("data:"):
|
436
|
+
raise ValueError("LiveKit Anthropic Plugin: Image URLs must be data URLs")
|
437
|
+
|
438
|
+
try:
|
439
|
+
header, b64_data = image.image.split(",", 1)
|
440
|
+
media_type = header.split(";")[0].split(":")[1]
|
441
|
+
|
442
|
+
supported_types = {"image/jpeg", "image/png", "image/webp", "image/gif"}
|
443
|
+
if media_type not in supported_types:
|
444
|
+
raise ValueError(
|
445
|
+
f"LiveKit Anthropic Plugin: Unsupported media type {media_type}. Must be jpeg, png, webp, or gif"
|
446
|
+
)
|
447
|
+
|
448
|
+
return {
|
449
|
+
"type": "image",
|
450
|
+
"source": {
|
451
|
+
"type": "base64",
|
452
|
+
"data": b64_data,
|
453
|
+
"media_type": cast(
|
454
|
+
Literal["image/jpeg", "image/png", "image/gif", "image/webp"],
|
455
|
+
media_type,
|
456
|
+
),
|
457
|
+
},
|
458
|
+
}
|
459
|
+
except (ValueError, IndexError) as e:
|
460
|
+
raise ValueError(
|
461
|
+
f"LiveKit Anthropic Plugin: Invalid image data URL {str(e)}"
|
462
|
+
)
|
463
|
+
elif isinstance(image.image, rtc.VideoFrame): # image is a VideoFrame
|
433
464
|
if cache_key not in image._cache:
|
434
465
|
# inside our internal implementation, we allow to put extra metadata to
|
435
466
|
# each ChatImage (avoid to reencode each time we do a chatcompletion request)
|
@@ -438,7 +469,7 @@ def _build_anthropic_image_content(
|
|
438
469
|
opts.resize_options = utils.images.ResizeOptions(
|
439
470
|
width=image.inference_width,
|
440
471
|
height=image.inference_height,
|
441
|
-
strategy="
|
472
|
+
strategy="scale_aspect_fit",
|
442
473
|
)
|
443
474
|
|
444
475
|
encoded_data = utils.images.encode(image.image, opts)
|
@@ -453,65 +484,8 @@ def _build_anthropic_image_content(
|
|
453
484
|
},
|
454
485
|
}
|
455
486
|
|
456
|
-
raise ValueError(
|
457
|
-
|
458
|
-
|
459
|
-
def _create_ai_function_info(
|
460
|
-
fnc_ctx: llm.function_context.FunctionContext,
|
461
|
-
tool_call_id: str,
|
462
|
-
fnc_name: str,
|
463
|
-
raw_arguments: str, # JSON string
|
464
|
-
) -> llm.function_context.FunctionCallInfo:
|
465
|
-
if fnc_name not in fnc_ctx.ai_functions:
|
466
|
-
raise ValueError(f"AI function {fnc_name} not found")
|
467
|
-
|
468
|
-
parsed_arguments: dict[str, Any] = {}
|
469
|
-
try:
|
470
|
-
if raw_arguments: # ignore empty string
|
471
|
-
parsed_arguments = json.loads(raw_arguments)
|
472
|
-
except json.JSONDecodeError:
|
473
|
-
raise ValueError(
|
474
|
-
f"AI function {fnc_name} received invalid JSON arguments - {raw_arguments}"
|
475
|
-
)
|
476
|
-
|
477
|
-
fnc_info = fnc_ctx.ai_functions[fnc_name]
|
478
|
-
|
479
|
-
# Ensure all necessary arguments are present and of the correct type.
|
480
|
-
sanitized_arguments: dict[str, Any] = {}
|
481
|
-
for arg_info in fnc_info.arguments.values():
|
482
|
-
if arg_info.name not in parsed_arguments:
|
483
|
-
if arg_info.default is inspect.Parameter.empty:
|
484
|
-
raise ValueError(
|
485
|
-
f"AI function {fnc_name} missing required argument {arg_info.name}"
|
486
|
-
)
|
487
|
-
continue
|
488
|
-
|
489
|
-
arg_value = parsed_arguments[arg_info.name]
|
490
|
-
if get_origin(arg_info.type) is not None:
|
491
|
-
if not isinstance(arg_value, list):
|
492
|
-
raise ValueError(
|
493
|
-
f"AI function {fnc_name} argument {arg_info.name} should be a list"
|
494
|
-
)
|
495
|
-
|
496
|
-
inner_type = get_args(arg_info.type)[0]
|
497
|
-
sanitized_value = [
|
498
|
-
_sanitize_primitive(
|
499
|
-
value=v, expected_type=inner_type, choices=arg_info.choices
|
500
|
-
)
|
501
|
-
for v in arg_value
|
502
|
-
]
|
503
|
-
else:
|
504
|
-
sanitized_value = _sanitize_primitive(
|
505
|
-
value=arg_value, expected_type=arg_info.type, choices=arg_info.choices
|
506
|
-
)
|
507
|
-
|
508
|
-
sanitized_arguments[arg_info.name] = sanitized_value
|
509
|
-
|
510
|
-
return llm.function_context.FunctionCallInfo(
|
511
|
-
tool_call_id=tool_call_id,
|
512
|
-
raw_arguments=raw_arguments,
|
513
|
-
function_info=fnc_info,
|
514
|
-
arguments=sanitized_arguments,
|
487
|
+
raise ValueError(
|
488
|
+
"LiveKit Anthropic Plugin: ChatImage must be an rtc.VideoFrame or a data URL"
|
515
489
|
)
|
516
490
|
|
517
491
|
|
@@ -538,8 +512,10 @@ def _build_function_description(
|
|
538
512
|
if arg_info.description:
|
539
513
|
p["description"] = arg_info.description
|
540
514
|
|
541
|
-
|
542
|
-
|
515
|
+
is_optional, inner_th = _is_optional_type(arg_info.type)
|
516
|
+
|
517
|
+
if get_origin(inner_th) is list:
|
518
|
+
inner_type = get_args(inner_th)[0]
|
543
519
|
p["type"] = "array"
|
544
520
|
p["items"] = {}
|
545
521
|
p["items"]["type"] = type2str(inner_type)
|
@@ -547,7 +523,7 @@ def _build_function_description(
|
|
547
523
|
if arg_info.choices:
|
548
524
|
p["items"]["enum"] = arg_info.choices
|
549
525
|
else:
|
550
|
-
p["type"] = type2str(
|
526
|
+
p["type"] = type2str(inner_th)
|
551
527
|
if arg_info.choices:
|
552
528
|
p["enum"] = arg_info.choices
|
553
529
|
|
@@ -563,31 +539,3 @@ def _build_function_description(
|
|
563
539
|
"description": fnc_info.description,
|
564
540
|
"input_schema": input_schema,
|
565
541
|
}
|
566
|
-
|
567
|
-
|
568
|
-
def _sanitize_primitive(
|
569
|
-
*, value: Any, expected_type: type, choices: Tuple[Any] | None
|
570
|
-
) -> Any:
|
571
|
-
if expected_type is str:
|
572
|
-
if not isinstance(value, str):
|
573
|
-
raise ValueError(f"expected str, got {type(value)}")
|
574
|
-
elif expected_type in (int, float):
|
575
|
-
if not isinstance(value, (int, float)):
|
576
|
-
raise ValueError(f"expected number, got {type(value)}")
|
577
|
-
|
578
|
-
if expected_type is int:
|
579
|
-
if value % 1 != 0:
|
580
|
-
raise ValueError("expected int, got float")
|
581
|
-
|
582
|
-
value = int(value)
|
583
|
-
elif expected_type is float:
|
584
|
-
value = float(value)
|
585
|
-
|
586
|
-
elif expected_type is bool:
|
587
|
-
if not isinstance(value, bool):
|
588
|
-
raise ValueError(f"expected bool, got {type(value)}")
|
589
|
-
|
590
|
-
if choices and value not in choices:
|
591
|
-
raise ValueError(f"invalid value {value}, not in {choices}")
|
592
|
-
|
593
|
-
return value
|
{livekit_plugins_anthropic-0.2.6.dist-info → livekit_plugins_anthropic-0.2.8.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: livekit-plugins-anthropic
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.8
|
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
|
@@ -19,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
19
19
|
Classifier: Programming Language :: Python :: 3 :: Only
|
20
20
|
Requires-Python: >=3.9.0
|
21
21
|
Description-Content-Type: text/markdown
|
22
|
-
Requires-Dist: livekit-agents>=0.
|
22
|
+
Requires-Dist: livekit-agents>=0.12.3
|
23
23
|
Requires-Dist: anthropic>=0.34
|
24
24
|
|
25
25
|
# LiveKit Plugins Anthropic
|
@@ -0,0 +1,10 @@
|
|
1
|
+
livekit/plugins/anthropic/__init__.py,sha256=1WCyNEaR6qBsX54qJQM0SeY-QHIucww16PLXcSnMqRo,1175
|
2
|
+
livekit/plugins/anthropic/llm.py,sha256=e65Z_YchNHCXN2F1kKb8lczfSY1_Ak8Y_94nT12pZGI,18975
|
3
|
+
livekit/plugins/anthropic/log.py,sha256=fG1pYSY88AnT738gZrmzF9FO4l4BdGENj3VKHMQB3Yo,72
|
4
|
+
livekit/plugins/anthropic/models.py,sha256=wyTr2nl6SL4ylN6s4mHJcqtmgV2mjJysZo89FknWdhI,213
|
5
|
+
livekit/plugins/anthropic/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
+
livekit/plugins/anthropic/version.py,sha256=711Prlpzg5p2xCBjcE2dctFtzW_seKcOBI5-dvNUVK4,600
|
7
|
+
livekit_plugins_anthropic-0.2.8.dist-info/METADATA,sha256=xG06Y2Xf9RjmmBqJ314_6ZmFlEM0ZCo00K82wJHEHHo,1265
|
8
|
+
livekit_plugins_anthropic-0.2.8.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
9
|
+
livekit_plugins_anthropic-0.2.8.dist-info/top_level.txt,sha256=OoDok3xUmXbZRvOrfvvXB-Juu4DX79dlq188E19YHoo,8
|
10
|
+
livekit_plugins_anthropic-0.2.8.dist-info/RECORD,,
|
@@ -1,10 +0,0 @@
|
|
1
|
-
livekit/plugins/anthropic/__init__.py,sha256=1WCyNEaR6qBsX54qJQM0SeY-QHIucww16PLXcSnMqRo,1175
|
2
|
-
livekit/plugins/anthropic/llm.py,sha256=Qz8POfM4A4Z-MuwcNoD9uJt8lpNi0SvatJvNtqls5p4,20650
|
3
|
-
livekit/plugins/anthropic/log.py,sha256=fG1pYSY88AnT738gZrmzF9FO4l4BdGENj3VKHMQB3Yo,72
|
4
|
-
livekit/plugins/anthropic/models.py,sha256=wyTr2nl6SL4ylN6s4mHJcqtmgV2mjJysZo89FknWdhI,213
|
5
|
-
livekit/plugins/anthropic/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
livekit/plugins/anthropic/version.py,sha256=qiU8NmY5thT_I47ndTlA5TMw4pNi5-r9qqSsLmz-9ps,600
|
7
|
-
livekit_plugins_anthropic-0.2.6.dist-info/METADATA,sha256=7v72icRCffOPETvp3GbhrJXKRO2yZG7O1eU3OpCeGnM,1263
|
8
|
-
livekit_plugins_anthropic-0.2.6.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
9
|
-
livekit_plugins_anthropic-0.2.6.dist-info/top_level.txt,sha256=OoDok3xUmXbZRvOrfvvXB-Juu4DX79dlq188E19YHoo,8
|
10
|
-
livekit_plugins_anthropic-0.2.6.dist-info/RECORD,,
|
{livekit_plugins_anthropic-0.2.6.dist-info → livekit_plugins_anthropic-0.2.8.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|