mirror of
https://github.com/imartinez/privateGPT.git
synced 2026-07-17 01:48:03 +00:00
219 lines
7.0 KiB
Python
219 lines
7.0 KiB
Python
from private_gpt.components.chat.models.chat_config_models import ToolSpec
|
|
|
|
|
|
def test_convert_into_function_tool_tool() -> None:
|
|
tool = ToolSpec(
|
|
name="test_tool",
|
|
description="Test description",
|
|
input_schema={
|
|
"type": "object",
|
|
"properties": {"param1": {"type": "string"}, "_param2": {"type": "number"}},
|
|
"required": ["param1"],
|
|
},
|
|
)
|
|
|
|
result = tool.to_function_tool()
|
|
|
|
from llama_index.core.tools import FunctionTool
|
|
|
|
assert isinstance(result, FunctionTool)
|
|
|
|
assert result.metadata.name == "test_tool"
|
|
assert result.metadata.description == "Test description"
|
|
assert result.metadata.return_direct is True
|
|
|
|
assert hasattr(result, "metadata")
|
|
assert hasattr(result.metadata, "fn_schema")
|
|
|
|
schema_model = result.metadata.fn_schema
|
|
assert schema_model.__name__ == "test_tool_schema"
|
|
|
|
schema_fields = schema_model.__fields__
|
|
assert "param1" in schema_fields
|
|
assert "param2" in schema_fields
|
|
assert schema_fields["param1"].is_required()
|
|
assert not schema_fields["param2"].is_required()
|
|
|
|
|
|
def test_model_serialization_without_alias() -> None:
|
|
tool = ToolSpec(
|
|
name="test_tool",
|
|
description="Test description",
|
|
input_schema={
|
|
"type": "object",
|
|
"properties": {
|
|
"param1": {"type": "string"},
|
|
"_param2": {"type": "number"},
|
|
"class": {"type": "string"},
|
|
"match": {"type": "string"},
|
|
},
|
|
"required": ["param1"],
|
|
},
|
|
)
|
|
|
|
result = tool.to_function_tool()
|
|
schema_model = result.metadata.fn_schema
|
|
|
|
instance = schema_model(
|
|
param1="test", _param2=42.0, **{"class": "test_class", "match": "test_match"}
|
|
)
|
|
|
|
# Explicitly request serialization without aliases
|
|
serialized = instance.model_dump(by_alias=False)
|
|
|
|
assert "param1" in serialized
|
|
assert "param2" in serialized # Sanitized name (leading underscore removed)
|
|
assert "class_" in serialized # Sanitized name (keyword + underscore)
|
|
assert "match_" in serialized # Sanitized name (soft keyword + underscore)
|
|
|
|
# Original names should not be present
|
|
assert "_param2" not in serialized
|
|
assert "class" not in serialized
|
|
assert "match" not in serialized
|
|
|
|
|
|
def test_model_serialization_with_original_schema() -> None:
|
|
tool = ToolSpec(
|
|
name="test_tool",
|
|
description="Test description",
|
|
input_schema={
|
|
"type": "object",
|
|
"properties": {
|
|
"param1": {"type": "string", "description": "First parameter"},
|
|
"_param2": {
|
|
"type": "number",
|
|
"description": "Second parameter with underscore",
|
|
},
|
|
"normal_param": {"type": "boolean", "description": "Normal parameter"},
|
|
"class": {"type": "string", "description": "Keyword field"},
|
|
"match": {"type": "string", "description": "Soft keyword field"},
|
|
},
|
|
"required": ["param1"],
|
|
},
|
|
)
|
|
|
|
result = tool.to_function_tool()
|
|
schema_model = result.metadata.fn_schema
|
|
|
|
# Create instance with original field names (using aliases)
|
|
instance = schema_model(
|
|
param1="test_value",
|
|
_param2=42.5,
|
|
normal_param=True,
|
|
**{"class": "test_class", "match": "test_match"},
|
|
)
|
|
|
|
# Test default serialization returns original field names
|
|
serialized = instance.model_dump()
|
|
|
|
# Should contain original field names with underscores by default
|
|
assert "param1" in serialized
|
|
assert "_param2" in serialized
|
|
assert "normal_param" in serialized
|
|
assert "class" in serialized
|
|
assert "match" in serialized
|
|
|
|
# Values should be preserved
|
|
assert serialized["param1"] == "test_value"
|
|
assert serialized["_param2"] == 42.5
|
|
assert serialized["normal_param"] is True
|
|
assert serialized["class"] == "test_class"
|
|
assert serialized["match"] == "test_match"
|
|
|
|
# Test JSON serialization also uses original names by default
|
|
import json
|
|
|
|
json_str = instance.model_dump_json()
|
|
json_data = json.loads(json_str)
|
|
|
|
assert "_param2" in json_data
|
|
assert json_data["_param2"] == 42.5
|
|
assert "class" in json_data
|
|
assert "match" in json_data
|
|
|
|
|
|
def test_keyword_sanitization() -> None:
|
|
"""Test that Python keywords and soft keywords are properly sanitized."""
|
|
tool = ToolSpec(
|
|
name="test_tool",
|
|
description="Test description",
|
|
input_schema={
|
|
"type": "object",
|
|
"properties": {
|
|
"def": {"type": "string"},
|
|
"return": {"type": "string"},
|
|
"case": {"type": "string"},
|
|
"_": {"type": "string"},
|
|
},
|
|
"required": [],
|
|
},
|
|
)
|
|
|
|
result = tool.to_function_tool()
|
|
schema_model = result.metadata.fn_schema
|
|
|
|
instance = schema_model(
|
|
**{
|
|
"def": "test_def",
|
|
"return": "test_return",
|
|
"case": "test_case",
|
|
"_": "test_underscore",
|
|
}
|
|
)
|
|
|
|
# Test serialization with aliases (should use original names)
|
|
with_aliases = instance.model_dump(by_alias=True)
|
|
assert "def" in with_aliases
|
|
assert "return" in with_aliases
|
|
assert "case" in with_aliases
|
|
assert "_" in with_aliases
|
|
|
|
# Test serialization without aliases (should use sanitized names)
|
|
without_aliases = instance.model_dump(by_alias=False)
|
|
assert "def_" in without_aliases
|
|
assert "return_" in without_aliases
|
|
assert "case_" in without_aliases
|
|
assert "field" in without_aliases # "_" becomes "field"
|
|
|
|
|
|
def test_field_name_collisions() -> None:
|
|
"""Test that field name collisions are resolved with counters."""
|
|
tool = ToolSpec(
|
|
name="test_tool",
|
|
description="Test description",
|
|
input_schema={
|
|
"type": "object",
|
|
"properties": {
|
|
"": {"type": "string"}, # becomes "field"
|
|
" ": {"type": "string"}, # becomes "field_1"
|
|
"123": {"type": "string"}, # becomes "field_2"
|
|
"field": {"type": "string"}, # becomes "field_3"
|
|
"_field": {"type": "string"}, # becomes "field_4"
|
|
},
|
|
},
|
|
)
|
|
|
|
result = tool.to_function_tool()
|
|
schema_model = result.metadata.fn_schema
|
|
|
|
instance = schema_model(
|
|
**{
|
|
"": "test1",
|
|
" ": "test2",
|
|
"field": "test4",
|
|
"_field": "test5",
|
|
}
|
|
)
|
|
|
|
# Test serialization without aliases shows unique field names
|
|
without_aliases = instance.model_dump(by_alias=False)
|
|
assert "field" in without_aliases
|
|
assert without_aliases["field"] == "test1"
|
|
assert "field_1" in without_aliases
|
|
assert without_aliases["field_1"] == "test2"
|
|
assert "field_2" in without_aliases
|
|
assert without_aliases["field_2"] == "test4"
|
|
assert "field_3" in without_aliases
|
|
assert without_aliases["field_3"] == "test5"
|
|
assert len(without_aliases) == 5 # All fields are unique
|