llm-gemini 0.14__tar.gz → 0.15__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: llm-gemini
3
- Version: 0.14
3
+ Version: 0.15
4
4
  Summary: LLM plugin to access Google's Gemini family of models
5
5
  Author: Simon Willison
6
6
  License: Apache-2.0
@@ -72,6 +72,7 @@ Other models are:
72
72
  - `gemini-2.0-flash` - Gemini 2.0 Flash
73
73
  - `gemini-2.0-flash-lite` - Gemini 2.0 Flash-Lite
74
74
  - `gemini-2.0-pro-exp-02-05` - experimental release of Gemini 2.0 Pro
75
+ - `gemma-3-27b-it` - [Gemma 3](https://blog.google/technology/developers/gemma-3/) 27B
75
76
 
76
77
  ### Images, audio and video
77
78
 
@@ -50,6 +50,7 @@ Other models are:
50
50
  - `gemini-2.0-flash` - Gemini 2.0 Flash
51
51
  - `gemini-2.0-flash-lite` - Gemini 2.0 Flash-Lite
52
52
  - `gemini-2.0-pro-exp-02-05` - experimental release of Gemini 2.0 Pro
53
+ - `gemma-3-27b-it` - [Gemma 3](https://blog.google/technology/developers/gemma-3/) 27B
53
54
 
54
55
  ### Images, audio and video
55
56
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: llm-gemini
3
- Version: 0.14
3
+ Version: 0.15
4
4
  Summary: LLM plugin to access Google's Gemini family of models
5
5
  Author: Simon Willison
6
6
  License: Apache-2.0
@@ -72,6 +72,7 @@ Other models are:
72
72
  - `gemini-2.0-flash` - Gemini 2.0 Flash
73
73
  - `gemini-2.0-flash-lite` - Gemini 2.0 Flash-Lite
74
74
  - `gemini-2.0-pro-exp-02-05` - experimental release of Gemini 2.0 Pro
75
+ - `gemma-3-27b-it` - [Gemma 3](https://blog.google/technology/developers/gemma-3/) 27B
75
76
 
76
77
  ### Images, audio and video
77
78
 
@@ -1,6 +1,8 @@
1
+ import click
1
2
  import copy
2
3
  import httpx
3
4
  import ijson
5
+ import json
4
6
  import llm
5
7
  from pydantic import Field
6
8
  from typing import Optional
@@ -62,6 +64,8 @@ def register_models(register):
62
64
  "gemini-2.0-pro-exp-02-05",
63
65
  # Released 25th Feb 2025:
64
66
  "gemini-2.0-flash-lite",
67
+ # Released 12th March 2025:
68
+ "gemma-3-27b-it",
65
69
  ]:
66
70
  can_google_search = model_id in GOOGLE_SEARCH_MODELS
67
71
  register(
@@ -88,18 +92,24 @@ def resolve_type(attachment):
88
92
  return mime_type
89
93
 
90
94
 
91
- def cleanup_schema(schema):
95
+ def cleanup_schema(schema, in_properties=False):
92
96
  "Gemini supports only a subset of JSON schema"
93
97
  keys_to_remove = ("$schema", "additionalProperties", "title")
94
- # Recursively remove them
98
+
95
99
  if isinstance(schema, dict):
96
- for key in keys_to_remove:
97
- schema.pop(key, None)
98
- for value in schema.values():
99
- cleanup_schema(value)
100
+ # Only remove keys if we're not inside a 'properties' block.
101
+ if not in_properties:
102
+ for key in keys_to_remove:
103
+ schema.pop(key, None)
104
+ for key, value in list(schema.items()):
105
+ # If the key is 'properties', set the flag for its value.
106
+ if key == "properties" and isinstance(value, dict):
107
+ cleanup_schema(value, in_properties=True)
108
+ else:
109
+ cleanup_schema(value, in_properties=in_properties)
100
110
  elif isinstance(schema, list):
101
- for value in schema:
102
- cleanup_schema(value)
111
+ for item in schema:
112
+ cleanup_schema(item, in_properties=in_properties)
103
113
  return schema
104
114
 
105
115
 
@@ -431,3 +441,21 @@ class GeminiEmbeddingModel(llm.EmbeddingModel):
431
441
  if self.truncate:
432
442
  values = [value[: self.truncate] for value in values]
433
443
  return values
444
+
445
+
446
+ @llm.hookimpl
447
+ def register_commands(cli):
448
+ @cli.group()
449
+ def gemini():
450
+ "Commands relating to the llm-gemini plugin"
451
+
452
+ @gemini.command()
453
+ @click.option("--key", help="API key to use")
454
+ def models(key):
455
+ "List of Gemini models pulled from their API"
456
+ key = llm.get_key(key, "gemini", "LLM_GEMINI_KEY")
457
+ response = httpx.get(
458
+ f"https://generativelanguage.googleapis.com/v1beta/models?key={key}",
459
+ )
460
+ response.raise_for_status()
461
+ click.echo(json.dumps(response.json(), indent=2))
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "llm-gemini"
3
- version = "0.14"
3
+ version = "0.15"
4
4
  description = "LLM plugin to access Google's Gemini family of models"
5
5
  readme = "README.md"
6
6
  authors = [{name = "Simon Willison"}]
@@ -25,3 +25,7 @@ gemini = "llm_gemini"
25
25
 
26
26
  [project.optional-dependencies]
27
27
  test = ["pytest", "pytest-recording", "pytest-asyncio", "nest-asyncio"]
28
+
29
+ [tool.pytest.ini_options]
30
+ asyncio_mode = "strict"
31
+ asyncio_default_fixture_loop_scope = "function"
@@ -4,6 +4,7 @@ import json
4
4
  import os
5
5
  import pytest
6
6
  import pydantic
7
+ from llm_gemini import cleanup_schema
7
8
 
8
9
  nest_asyncio.apply()
9
10
 
@@ -123,3 +124,89 @@ def test_embedding(model_id, monkeypatch):
123
124
  elif model_id.endswith("-512"):
124
125
  expected_length = 512
125
126
  assert len(response) == expected_length
127
+
128
+
129
+ @pytest.mark.parametrize(
130
+ "schema,expected",
131
+ [
132
+ # Test 1: Top-level keys removal
133
+ (
134
+ {
135
+ "$schema": "http://json-schema.org/draft-07/schema#",
136
+ "title": "Example Schema",
137
+ "additionalProperties": False,
138
+ "type": "object",
139
+ },
140
+ {"type": "object"},
141
+ ),
142
+ # Test 2: Preserve keys within a "properties" block
143
+ (
144
+ {
145
+ "type": "object",
146
+ "properties": {
147
+ "authors": {"type": "string"},
148
+ "title": {"type": "string"},
149
+ "reference": {"type": "string"},
150
+ "year": {"type": "string"},
151
+ },
152
+ "title": "This should be removed from the top-level",
153
+ },
154
+ {
155
+ "type": "object",
156
+ "properties": {
157
+ "authors": {"type": "string"},
158
+ "title": {"type": "string"},
159
+ "reference": {"type": "string"},
160
+ "year": {"type": "string"},
161
+ },
162
+ },
163
+ ),
164
+ # Test 3: Nested keys outside and inside properties block
165
+ (
166
+ {
167
+ "definitions": {
168
+ "info": {
169
+ "title": "Info title", # should be removed because it's not inside a "properties" block
170
+ "description": "A description",
171
+ "properties": {
172
+ "name": {
173
+ "title": "Name Title",
174
+ "type": "string",
175
+ }, # title here should be preserved
176
+ "$schema": {
177
+ "type": "string"
178
+ }, # should be preserved as it's within properties
179
+ },
180
+ }
181
+ },
182
+ "$schema": "http://example.com/schema",
183
+ },
184
+ {
185
+ "definitions": {
186
+ "info": {
187
+ "description": "A description",
188
+ "properties": {
189
+ "name": {"title": "Name Title", "type": "string"},
190
+ "$schema": {"type": "string"},
191
+ },
192
+ }
193
+ }
194
+ },
195
+ ),
196
+ # Test 4: List of schemas
197
+ (
198
+ [
199
+ {
200
+ "$schema": "http://json-schema.org/draft-07/schema#",
201
+ "type": "object",
202
+ },
203
+ {"title": "Should be removed", "type": "array"},
204
+ ],
205
+ [{"type": "object"}, {"type": "array"}],
206
+ ),
207
+ ],
208
+ )
209
+ def test_cleanup_schema(schema, expected):
210
+ # Use a deep copy so the original test data remains unchanged.
211
+ result = cleanup_schema(schema)
212
+ assert result == expected
File without changes
File without changes