casual-llm 0.4.2__tar.gz → 0.4.3__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.
Files changed (40) hide show
  1. {casual_llm-0.4.2/src/casual_llm.egg-info → casual_llm-0.4.3}/PKG-INFO +1 -1
  2. {casual_llm-0.4.2 → casual_llm-0.4.3}/pyproject.toml +1 -1
  3. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/__init__.py +1 -1
  4. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/tools.py +8 -2
  5. {casual_llm-0.4.2 → casual_llm-0.4.3/src/casual_llm.egg-info}/PKG-INFO +1 -1
  6. {casual_llm-0.4.2 → casual_llm-0.4.3}/tests/test_tools.py +64 -0
  7. {casual_llm-0.4.2 → casual_llm-0.4.3}/LICENSE +0 -0
  8. {casual_llm-0.4.2 → casual_llm-0.4.3}/README.md +0 -0
  9. {casual_llm-0.4.2 → casual_llm-0.4.3}/setup.cfg +0 -0
  10. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/config.py +0 -0
  11. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/message_converters/__init__.py +0 -0
  12. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/message_converters/anthropic.py +0 -0
  13. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/message_converters/ollama.py +0 -0
  14. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/message_converters/openai.py +0 -0
  15. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/messages.py +0 -0
  16. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/providers/__init__.py +0 -0
  17. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/providers/anthropic.py +0 -0
  18. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/providers/base.py +0 -0
  19. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/providers/ollama.py +0 -0
  20. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/providers/openai.py +0 -0
  21. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/py.typed +0 -0
  22. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/tool_converters/__init__.py +0 -0
  23. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/tool_converters/anthropic.py +0 -0
  24. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/tool_converters/ollama.py +0 -0
  25. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/tool_converters/openai.py +0 -0
  26. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/usage.py +0 -0
  27. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/utils/__init__.py +0 -0
  28. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm/utils/image.py +0 -0
  29. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm.egg-info/SOURCES.txt +0 -0
  30. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm.egg-info/dependency_links.txt +0 -0
  31. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm.egg-info/requires.txt +0 -0
  32. {casual_llm-0.4.2 → casual_llm-0.4.3}/src/casual_llm.egg-info/top_level.txt +0 -0
  33. {casual_llm-0.4.2 → casual_llm-0.4.3}/tests/test_anthropic_provider.py +0 -0
  34. {casual_llm-0.4.2 → casual_llm-0.4.3}/tests/test_backward_compatibility.py +0 -0
  35. {casual_llm-0.4.2 → casual_llm-0.4.3}/tests/test_image_utils.py +0 -0
  36. {casual_llm-0.4.2 → casual_llm-0.4.3}/tests/test_messages.py +0 -0
  37. {casual_llm-0.4.2 → casual_llm-0.4.3}/tests/test_providers.py +0 -0
  38. {casual_llm-0.4.2 → casual_llm-0.4.3}/tests/test_vision_integration.py +0 -0
  39. {casual_llm-0.4.2 → casual_llm-0.4.3}/tests/test_vision_ollama.py +0 -0
  40. {casual_llm-0.4.2 → casual_llm-0.4.3}/tests/test_vision_openai.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: casual-llm
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: Lightweight LLM provider abstraction with standardized message models
5
5
  Author-email: Alex Stansfield <alex@casualgenius.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "casual-llm"
3
- version = "0.4.2"
3
+ version = "0.4.3"
4
4
  description = "Lightweight LLM provider abstraction with standardized message models"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -7,7 +7,7 @@ A simple, protocol-based library for working with different LLM providers
7
7
  Part of the casual-* ecosystem of lightweight AI tools.
8
8
  """
9
9
 
10
- __version__ = "0.4.2"
10
+ __version__ = "0.4.3"
11
11
 
12
12
  # Model configuration
13
13
  from casual_llm.config import ModelConfig, Provider
@@ -7,6 +7,7 @@ Provides unified tool models compatible with Ollama, OpenAI, and MCP.
7
7
  from __future__ import annotations
8
8
 
9
9
  from typing import Any
10
+
10
11
  from pydantic import BaseModel, Field
11
12
 
12
13
 
@@ -14,10 +15,13 @@ class ToolParameter(BaseModel):
14
15
  """
15
16
  A single tool parameter definition following JSON Schema.
16
17
 
17
- Supports common JSON Schema fields for describing function parameters.
18
+ Supports common JSON Schema fields for describing function parameters,
19
+ including union types via anyOf/oneOf schemas.
18
20
  """
19
21
 
20
- type: str = Field(..., description="JSON Schema type (string, number, object, array, etc.)")
22
+ type: str | None = Field(
23
+ None, description="JSON Schema type (string, number, object, array, etc.)"
24
+ )
21
25
  description: str | None = Field(None, description="Parameter description")
22
26
  enum: list[Any] | None = Field(None, description="Allowed values for enum types")
23
27
  items: dict[str, Any] | None = Field(None, description="Array item schema")
@@ -26,6 +30,8 @@ class ToolParameter(BaseModel):
26
30
  )
27
31
  required: list[str] | None = Field(None, description="Required properties for nested objects")
28
32
  default: Any | None = Field(None, description="Default value")
33
+ anyOf: list[dict[str, Any]] | None = Field(None, description="Union type schemas")
34
+ oneOf: list[dict[str, Any]] | None = Field(None, description="Exclusive union type schemas")
29
35
 
30
36
  model_config = {"extra": "allow"} # Allow additional JSON Schema fields
31
37
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: casual-llm
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: Lightweight LLM provider abstraction with standardized message models
5
5
  Author-email: Alex Stansfield <alex@casualgenius.com>
6
6
  License: MIT
@@ -71,6 +71,35 @@ class TestToolParameter:
71
71
  assert dumped["maxLength"] == 100
72
72
  assert dumped["pattern"] == "^[a-z]+$"
73
73
 
74
+ def test_anyof_parameter(self):
75
+ """Test parameter with anyOf union type."""
76
+ param = ToolParameter(
77
+ anyOf=[{"type": "string"}, {"type": "null"}],
78
+ description="Optional string",
79
+ )
80
+ assert param.type is None
81
+ assert param.anyOf is not None
82
+
83
+ def test_oneof_parameter(self):
84
+ """Test parameter with oneOf exclusive union type."""
85
+ param = ToolParameter(
86
+ oneOf=[{"type": "string"}, {"type": "number"}],
87
+ description="String or number",
88
+ )
89
+ assert param.type is None
90
+ assert param.oneOf is not None
91
+
92
+ def test_anyof_serialization(self):
93
+ """Test that anyOf is properly serialized."""
94
+ param = ToolParameter(
95
+ anyOf=[{"type": "string"}, {"type": "null"}],
96
+ description="Optional",
97
+ )
98
+ dumped = param.model_dump(exclude_none=True)
99
+ assert "anyOf" in dumped
100
+ assert len(dumped["anyOf"]) == 2
101
+ assert "type" not in dumped # type is None, excluded
102
+
74
103
 
75
104
  class TestTool:
76
105
  """Tests for Tool model."""
@@ -188,6 +217,41 @@ class TestTool:
188
217
  assert reconstructed.required == original_tool.required
189
218
  assert len(reconstructed.parameters) == len(original_tool.parameters)
190
219
 
220
+ def test_input_schema_with_anyof(self):
221
+ """Test that input_schema preserves anyOf without injecting type."""
222
+ tool = Tool(
223
+ name="test",
224
+ description="Test",
225
+ parameters={
226
+ "optional_field": ToolParameter(
227
+ anyOf=[{"type": "string"}, {"type": "null"}],
228
+ description="An optional string",
229
+ )
230
+ },
231
+ )
232
+ schema = tool.input_schema
233
+ # anyOf should be preserved as-is
234
+ assert "anyOf" in schema["properties"]["optional_field"]
235
+ # type should NOT be injected (anyOf is valid JSON Schema)
236
+ assert "type" not in schema["properties"]["optional_field"]
237
+
238
+ def test_input_schema_with_oneof(self):
239
+ """Test that input_schema preserves oneOf without injecting type."""
240
+ tool = Tool(
241
+ name="test",
242
+ description="Test",
243
+ parameters={
244
+ "mixed_field": ToolParameter(
245
+ oneOf=[{"type": "number"}, {"type": "string"}],
246
+ )
247
+ },
248
+ )
249
+ schema = tool.input_schema
250
+ # oneOf should be preserved as-is
251
+ assert "oneOf" in schema["properties"]["mixed_field"]
252
+ # type should NOT be injected
253
+ assert "type" not in schema["properties"]["mixed_field"]
254
+
191
255
 
192
256
  class TestOllamaConverters:
193
257
  """Tests for Ollama format converters."""
File without changes
File without changes
File without changes