kiln-ai 0.14.0__py3-none-any.whl → 0.15.0__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.

Potentially problematic release.


This version of kiln-ai might be problematic. Click here for more details.

@@ -65,6 +65,7 @@ class LiteLlmAdapter(BaseAdapter):
65
65
  run_strategy, cot_prompt = self.run_strategy()
66
66
 
67
67
  if run_strategy == "cot_as_message":
68
+ # Used for reasoning-capable models that can output thinking and structured format
68
69
  if not cot_prompt:
69
70
  raise ValueError("cot_prompt is required for cot_as_message strategy")
70
71
  messages.append({"role": "system", "content": cot_prompt})
@@ -73,9 +74,11 @@ class LiteLlmAdapter(BaseAdapter):
73
74
  raise ValueError("cot_prompt is required for cot_two_call strategy")
74
75
  messages.append({"role": "system", "content": cot_prompt})
75
76
 
76
- # First call for chain of thought - No logprobs as only needed for final answer
77
+ # First call for chain of thought
78
+ # No response format as this request is for "thinking" in plain text
79
+ # No logprobs as only needed for final answer
77
80
  completion_kwargs = await self.build_completion_kwargs(
78
- provider, messages, None
81
+ provider, messages, None, skip_response_format=True
79
82
  )
80
83
  cot_response = await litellm.acompletion(**completion_kwargs)
81
84
  if (
@@ -367,6 +370,7 @@ class LiteLlmAdapter(BaseAdapter):
367
370
  provider: KilnModelProvider,
368
371
  messages: list[dict[str, Any]],
369
372
  top_logprobs: int | None,
373
+ skip_response_format: bool = False,
370
374
  ) -> dict[str, Any]:
371
375
  extra_body = self.build_extra_body(provider)
372
376
 
@@ -380,9 +384,10 @@ class LiteLlmAdapter(BaseAdapter):
380
384
  **self._additional_body_options,
381
385
  }
382
386
 
383
- # Response format: json_schema, json_instructions, json_mode, function_calling, etc
384
- response_format_options = await self.response_format_options()
385
- completion_kwargs.update(response_format_options)
387
+ if not skip_response_format:
388
+ # Response format: json_schema, json_instructions, json_mode, function_calling, etc
389
+ response_format_options = await self.response_format_options()
390
+ completion_kwargs.update(response_format_options)
386
391
 
387
392
  if top_logprobs is not None:
388
393
  completion_kwargs["logprobs"] = True
@@ -268,6 +268,13 @@ def finetune_provider_model(
268
268
  model_id=fine_tune.fine_tune_model_id,
269
269
  )
270
270
 
271
+ if provider == ModelProviderName.vertex and fine_tune.fine_tune_model_id:
272
+ # Vertex AI trick: use the model_id "openai/endpoint_id". OpenAI calls the openai compatible API, which supports endpoint.
273
+ # Context: vertex has at least 3 APIS: vertex, openai compatible, and gemini. LiteLLM tries to infer which to use. This works
274
+ # on current LiteLLM version. Could also set base_model to gemini to tell it which to use, but same result.
275
+ endpoint_id = fine_tune.fine_tune_model_id.split("/")[-1]
276
+ model_provider.model_id = f"openai/{endpoint_id}"
277
+
271
278
  if fine_tune.structured_output_mode is not None:
272
279
  # If we know the model was trained with specific output mode, set it
273
280
  model_provider.structured_output_mode = fine_tune.structured_output_mode
@@ -791,3 +791,19 @@ def test_finetune_from_id_cache_hit(mock_project, mock_task, mock_finetune):
791
791
  mock_project.assert_not_called()
792
792
  mock_task.assert_not_called()
793
793
  mock_finetune.assert_not_called()
794
+
795
+
796
+ def test_finetune_provider_model_vertex_ai(mock_project, mock_task, mock_finetune):
797
+ """Test creation of provider for Vertex AI with endpoint ID transformation"""
798
+ finetune = Mock(spec=Finetune)
799
+ finetune.provider = ModelProviderName.vertex
800
+ finetune.fine_tune_model_id = "projects/123/locations/us-central1/endpoints/456"
801
+ finetune.structured_output_mode = StructuredOutputMode.json_mode
802
+ mock_finetune.return_value = finetune
803
+
804
+ provider = finetune_provider_model("project-123::task-456::finetune-789")
805
+
806
+ assert provider.name == ModelProviderName.vertex
807
+ # Verify the model_id is transformed into openai/endpoint_id format
808
+ assert provider.model_id == "openai/456"
809
+ assert provider.structured_output_mode == StructuredOutputMode.json_mode
@@ -41,16 +41,33 @@ def validate_schema(instance: Dict, schema_str: str) -> None:
41
41
 
42
42
  Raises:
43
43
  jsonschema.exceptions.ValidationError: If validation fails
44
- ValueError: If the schema is invalid
44
+ """
45
+ schema = schema_from_json_str(schema_str)
46
+ v = jsonschema.Draft202012Validator(schema)
47
+ v.validate(instance)
48
+
49
+
50
+ def validate_schema_with_value_error(
51
+ instance: Dict, schema_str: str, error_prefix: str | None = None
52
+ ) -> None:
53
+ """Validate a dictionary against a JSON schema and raise a ValueError if the schema is invalid.
54
+
55
+ Args:
56
+ instance: Dictionary to validate
57
+ schema_str: JSON schema string to validate against
58
+ error_prefix: Error message prefix to include in the ValueError
59
+
60
+ Raises:
61
+ ValueError: If the instance does not match the schema
45
62
  """
46
63
  try:
47
- schema = schema_from_json_str(schema_str)
48
- v = jsonschema.Draft202012Validator(schema)
49
- v.validate(instance)
64
+ validate_schema(instance, schema_str)
50
65
  except jsonschema.exceptions.ValidationError as e:
51
- raise ValueError(
52
- f"This task requires a specific output schema. While the model produced JSON, that JSON didn't meet the schema. Search 'Troubleshooting Structured Data Issues' in our docs for more information. The error from the schema check was: {e.message}. The JSON was: \n```json\n{instance}\n```"
53
- ) from e
66
+ msg = f"The error from the schema check was: {e.message}. The JSON was: \n```json\n{instance}\n```"
67
+ if error_prefix:
68
+ msg = f"{error_prefix} {msg}"
69
+
70
+ raise ValueError(msg) from e
54
71
 
55
72
 
56
73
  def schema_from_json_str(v: str) -> Dict:
@@ -9,7 +9,7 @@ from typing_extensions import Self
9
9
 
10
10
  from kiln_ai.datamodel.basemodel import ID_TYPE, KilnBaseModel
11
11
  from kiln_ai.datamodel.datamodel_enums import TaskOutputRatingType
12
- from kiln_ai.datamodel.json_schema import validate_schema
12
+ from kiln_ai.datamodel.json_schema import validate_schema_with_value_error
13
13
  from kiln_ai.datamodel.strict_mode import strict_mode
14
14
  from kiln_ai.utils.exhaustive_error import raise_exhaustive_enum_error
15
15
 
@@ -308,11 +308,15 @@ class TaskOutput(KilnBaseModel):
308
308
  # validate output
309
309
  if task.output_json_schema is not None:
310
310
  try:
311
- validate_schema(json.loads(self.output), task.output_json_schema)
312
- except json.JSONDecodeError:
311
+ output_parsed = json.loads(self.output)
312
+ except json.JSONDecodeError as e:
313
313
  raise ValueError("Output is not a valid JSON object")
314
- except jsonschema.exceptions.ValidationError as e:
315
- raise ValueError(f"Output does not match task output schema: {e}")
314
+
315
+ validate_schema_with_value_error(
316
+ output_parsed,
317
+ task.output_json_schema,
318
+ "This task requires a specific output schema. While the model produced JSON, that JSON didn't meet the schema. Search 'Troubleshooting Structured Data Issues' in our docs for more information.",
319
+ )
316
320
  return self
317
321
 
318
322
  @model_validator(mode="after")
@@ -7,7 +7,7 @@ from pydantic import Field, ValidationInfo, model_validator
7
7
  from typing_extensions import Self
8
8
 
9
9
  from kiln_ai.datamodel.basemodel import KilnParentedModel
10
- from kiln_ai.datamodel.json_schema import validate_schema
10
+ from kiln_ai.datamodel.json_schema import validate_schema_with_value_error
11
11
  from kiln_ai.datamodel.strict_mode import strict_mode
12
12
  from kiln_ai.datamodel.task_output import DataSource, TaskOutput
13
13
 
@@ -87,14 +87,19 @@ class TaskRun(KilnParentedModel):
87
87
  # don't validate this relationship until we have a path or parent. Give them time to build it (but will catch it before saving)
88
88
  return self
89
89
 
90
- # validate output
90
+ # validate input
91
91
  if task.input_json_schema is not None:
92
92
  try:
93
- validate_schema(json.loads(self.input), task.input_json_schema)
93
+ input_parsed = json.loads(self.input)
94
94
  except json.JSONDecodeError:
95
95
  raise ValueError("Input is not a valid JSON object")
96
- except jsonschema.exceptions.ValidationError as e:
97
- raise ValueError(f"Input does not match task input schema: {e}")
96
+
97
+ validate_schema_with_value_error(
98
+ input_parsed,
99
+ task.input_json_schema,
100
+ "Input does not match task input schema.",
101
+ )
102
+
98
103
  self._last_validated_input = self.input
99
104
  return self
100
105
 
@@ -131,6 +136,24 @@ class TaskRun(KilnParentedModel):
131
136
  raise ValueError(
132
137
  "Repaired output rating must be None. Repaired outputs are assumed to have a perfect rating, as they have been fixed."
133
138
  )
139
+
140
+ task = self.parent_task()
141
+ if (
142
+ task is not None
143
+ and self.repaired_output.output is not None
144
+ and task.output_json_schema is not None
145
+ ):
146
+ try:
147
+ output_parsed = json.loads(self.repaired_output.output)
148
+ except json.JSONDecodeError:
149
+ raise ValueError("Repaired output is not a valid JSON object")
150
+
151
+ validate_schema_with_value_error(
152
+ output_parsed,
153
+ task.output_json_schema,
154
+ "Repaired output does not match task output schema.",
155
+ )
156
+
134
157
  if self.repair_instructions is None and self.repaired_output is not None:
135
158
  raise ValueError(
136
159
  "Repair instructions are required if providing a repaired output."
@@ -139,6 +162,7 @@ class TaskRun(KilnParentedModel):
139
162
  raise ValueError(
140
163
  "A repaired output is required if providing repair instructions."
141
164
  )
165
+
142
166
  return self
143
167
 
144
168
  @model_validator(mode="after")
@@ -358,6 +358,9 @@ def test_task_output_schema_validation(tmp_path):
358
358
  task_output.save_to_file()
359
359
 
360
360
 
361
+ _input_schema_match = "Input does not match task input schema"
362
+
363
+
361
364
  def test_task_input_schema_validation(tmp_path):
362
365
  # Create a project and task hierarchy
363
366
  project = Project(name="Test Project", path=(tmp_path / "test_project"))
@@ -395,18 +398,18 @@ def test_task_input_schema_validation(tmp_path):
395
398
  valid_task_output.save_to_file()
396
399
 
397
400
  # Changing to invalid input
398
- with pytest.raises(ValueError, match=_schema_match):
401
+ with pytest.raises(ValueError, match=_input_schema_match):
399
402
  valid_task_output.input = '{"name": "John Doe", "age": "thirty"}'
400
403
  valid_task_output.save_to_file()
401
404
 
402
405
  # loading from file, then changing to invalid input
403
406
  loaded_task_output = TaskRun.load_from_file(valid_task_output.path)
404
- with pytest.raises(ValueError, match=_schema_match):
407
+ with pytest.raises(ValueError, match=_input_schema_match):
405
408
  loaded_task_output.input = '{"name": "John Doe", "age": "thirty"}'
406
409
  loaded_task_output.save_to_file()
407
410
 
408
411
  # Invalid case: input does not match task input schema
409
- with pytest.raises(ValueError, match=_schema_match):
412
+ with pytest.raises(ValueError, match=_input_schema_match):
410
413
  task_output = TaskRun(
411
414
  input='{"name": "John Doe", "age": "thirty"}',
412
415
  input_source=DataSource(
@@ -642,3 +645,101 @@ def test_task_run_validate_repaired_output():
642
645
  )
643
646
 
644
647
  assert "Repaired output rating must be None" in str(exc_info.value)
648
+
649
+
650
+ def test_task_run_validate_repaired_output_structured(tmp_path):
651
+ # Create a project, task, and example hierarchy
652
+ project = Project(name="Test Project", path=(tmp_path / "test_project"))
653
+ project.save_to_file()
654
+ task = Task(
655
+ name="Test Task",
656
+ instruction="test instruction",
657
+ parent=project,
658
+ output_json_schema=json.dumps(
659
+ {
660
+ "type": "object",
661
+ "properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
662
+ "required": ["name", "age"],
663
+ }
664
+ ),
665
+ )
666
+ task.save_to_file()
667
+
668
+ # test valid repaired output schema
669
+ task_run = TaskRun(
670
+ parent=task,
671
+ input="test input",
672
+ input_source=DataSource(
673
+ type=DataSourceType.human,
674
+ properties={"created_by": "john_doe"},
675
+ ),
676
+ output=TaskOutput(
677
+ output='{"name": "John Doe", "age": 30}',
678
+ source=DataSource(
679
+ type=DataSourceType.human,
680
+ properties={"created_by": "john_doe"},
681
+ ),
682
+ ),
683
+ repair_instructions="Fix the output",
684
+ repaired_output=TaskOutput(
685
+ output='{"name": "John Doe", "age": 30}',
686
+ source=DataSource(
687
+ type=DataSourceType.human, properties={"created_by": "john_doe"}
688
+ ),
689
+ ),
690
+ )
691
+
692
+ assert task_run.repaired_output is not None
693
+ assert task_run.repaired_output.rating is None
694
+
695
+ # test invalid JSON
696
+ with pytest.raises(ValueError):
697
+ TaskRun(
698
+ parent=task,
699
+ input="test input",
700
+ input_source=DataSource(
701
+ type=DataSourceType.human,
702
+ properties={"created_by": "john_doe"},
703
+ ),
704
+ output=TaskOutput(
705
+ output='{"name": "John Doe", "age": 30}',
706
+ source=DataSource(
707
+ type=DataSourceType.human,
708
+ properties={"created_by": "john_doe"},
709
+ ),
710
+ ),
711
+ repair_instructions="Fix the output",
712
+ repaired_output=TaskOutput(
713
+ output='{"name": "John Doe", "age": 30', # missing closing brace
714
+ source=DataSource(
715
+ type=DataSourceType.human,
716
+ properties={"created_by": "john_doe"},
717
+ ),
718
+ ),
719
+ )
720
+
721
+ # test invalid repaired output schema
722
+ with pytest.raises(ValueError):
723
+ TaskRun(
724
+ parent=task,
725
+ input="test input",
726
+ input_source=DataSource(
727
+ type=DataSourceType.human,
728
+ properties={"created_by": "john_doe"},
729
+ ),
730
+ output=TaskOutput(
731
+ output='{"name": "John Doe", "age": 30}',
732
+ source=DataSource(
733
+ type=DataSourceType.human,
734
+ properties={"created_by": "john_doe"},
735
+ ),
736
+ ),
737
+ repair_instructions="Fix the output",
738
+ repaired_output=TaskOutput(
739
+ output='{"name": "John Doe", "age": "thirty"}', # invalid schema
740
+ source=DataSource(
741
+ type=DataSourceType.human,
742
+ properties={"created_by": "john_doe"},
743
+ ),
744
+ ),
745
+ )
@@ -1,3 +1,4 @@
1
+ import jsonschema
1
2
  import pytest
2
3
  from pydantic import BaseModel
3
4
 
@@ -6,6 +7,7 @@ from kiln_ai.datamodel.json_schema import (
6
7
  schema_from_json_str,
7
8
  string_to_json_key,
8
9
  validate_schema,
10
+ validate_schema_with_value_error,
9
11
  )
10
12
 
11
13
 
@@ -71,15 +73,32 @@ def test_validate_schema_content():
71
73
  o = {"setup": "asdf", "punchline": "asdf", "rating": 1}
72
74
  validate_schema(o, json_joke_schema)
73
75
  o = {"setup": "asdf"}
74
- with pytest.raises(Exception):
76
+ with pytest.raises(jsonschema.exceptions.ValidationError):
75
77
  validate_schema(0, json_joke_schema)
76
78
  o = {"setup": "asdf", "punchline": "asdf"}
77
79
  validate_schema(o, json_joke_schema)
78
80
  o = {"setup": "asdf", "punchline": "asdf", "rating": "1"}
79
- with pytest.raises(Exception):
81
+ with pytest.raises(jsonschema.exceptions.ValidationError):
80
82
  validate_schema(o, json_joke_schema)
81
83
 
82
84
 
85
+ def test_validate_schema_content_with_value_error():
86
+ o = {"setup": "asdf", "punchline": "asdf", "rating": 1}
87
+ validate_schema_with_value_error(o, json_joke_schema, "PREFIX")
88
+ o = {"setup": "asdf"}
89
+ with pytest.raises(
90
+ ValueError, match="PREFIX The error from the schema check was: "
91
+ ):
92
+ validate_schema_with_value_error(0, json_joke_schema, "PREFIX")
93
+ o = {"setup": "asdf", "punchline": "asdf"}
94
+ validate_schema_with_value_error(o, json_joke_schema, "PREFIX")
95
+ o = {"setup": "asdf", "punchline": "asdf", "rating": "1"}
96
+ with pytest.raises(
97
+ ValueError, match="PREFIX The error from the schema check was: "
98
+ ):
99
+ validate_schema_with_value_error(o, json_joke_schema, "PREFIX")
100
+
101
+
83
102
  json_triangle_schema = """{
84
103
  "type": "object",
85
104
  "properties": {
@@ -122,7 +141,7 @@ def test_triangle_schema():
122
141
  assert schema["properties"]["c"]["type"] == "integer"
123
142
  assert schema["required"] == ["a", "b", "c"]
124
143
  validate_schema({"a": 1, "b": 2, "c": 3}, json_triangle_schema)
125
- with pytest.raises(Exception):
144
+ with pytest.raises(jsonschema.exceptions.ValidationError):
126
145
  validate_schema({"a": 1, "b": 2, "c": "3"}, json_triangle_schema)
127
146
 
128
147
 
@@ -119,7 +119,8 @@ def test_benchmark_load_from_file(benchmark, task_run):
119
119
  avg_time_per_iteration = total_time / iterations
120
120
  ops_per_second = 1.0 / avg_time_per_iteration
121
121
 
122
- # I get 8k ops per second on my MBP. Lower value here for CI.
122
+ # I get 8k ops per second on my MBP. Lower value here for CI and parallel testing.
123
123
  # Prior to optimization was 290 ops per second.
124
- if ops_per_second < 1000:
124
+ print(f"Ops per second: {ops_per_second:.6f}")
125
+ if ops_per_second < 500:
125
126
  pytest.fail(f"Ops per second: {ops_per_second:.6f}, expected more than 1k ops")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kiln-ai
3
- Version: 0.14.0
3
+ Version: 0.15.0
4
4
  Summary: Kiln AI
5
5
  Project-URL: Homepage, https://getkiln.ai
6
6
  Project-URL: Repository, https://github.com/Kiln-AI/kiln
@@ -19,7 +19,7 @@ Requires-Dist: boto3>=1.37.10
19
19
  Requires-Dist: coverage>=7.6.4
20
20
  Requires-Dist: google-cloud-aiplatform>=1.84.0
21
21
  Requires-Dist: jsonschema>=4.23.0
22
- Requires-Dist: litellm>=1.63.5
22
+ Requires-Dist: litellm>=1.67.0
23
23
  Requires-Dist: openai>=1.53.0
24
24
  Requires-Dist: pdoc>=15.0.0
25
25
  Requires-Dist: pydantic>=2.9.2
@@ -28,6 +28,7 @@ Requires-Dist: pytest-cov>=6.0.0
28
28
  Requires-Dist: pyyaml>=6.0.2
29
29
  Requires-Dist: together
30
30
  Requires-Dist: typing-extensions>=4.12.2
31
+ Requires-Dist: vertexai>=1.43.0
31
32
  Description-Content-Type: text/markdown
32
33
 
33
34
  # Kiln AI Core Library
@@ -1,23 +1,22 @@
1
1
  kiln_ai/__init__.py,sha256=Sc4z8LRVFMwJUoc_DPVUriSXTZ6PO9MaJ80PhRbKyB8,34
2
2
  kiln_ai/adapters/__init__.py,sha256=XjGmWagEyOEVwVIAxjN5rYNsQWIEACT5DB7MMTxdPss,1005
3
3
  kiln_ai/adapters/adapter_registry.py,sha256=KmMHYQ3mxpjVLE6D-hMNWCGt6Cw9JvnFn6nMb48GE8Y,9166
4
- kiln_ai/adapters/ml_model_list.py,sha256=f_z1daFR_w4-ccJ4OWwqlIMY0ILFJt4X5LdQb3AMt_c,58592
4
+ kiln_ai/adapters/ml_model_list.py,sha256=RyRvPStx2TNGDjmRKSE02bOZjSWSWuJ030Ythu4Fgh4,68593
5
5
  kiln_ai/adapters/ollama_tools.py,sha256=uObtLWfqKb9RXHN-TGGw2Y1FQlEMe0u8FgszI0zQn6U,3550
6
6
  kiln_ai/adapters/prompt_builders.py,sha256=LYHTIaisQMBFtWDRIGo1QJgOsmQ-NBpQ8fI4eImHxaQ,15269
7
- kiln_ai/adapters/provider_tools.py,sha256=UL3XEnnxs1TrbqPPxxHSvnL7aBd84ggh38lI0yEsX6A,14725
7
+ kiln_ai/adapters/provider_tools.py,sha256=ciFQfGJuTuHDj3FARY-sUqbSb-7oAT9lMGJGCBJoF4I,15309
8
8
  kiln_ai/adapters/run_output.py,sha256=RAi2Qp6dmqJVNm3CxbNTdAuhitHfH5NiUGbf6ygUP-k,257
9
9
  kiln_ai/adapters/test_adapter_registry.py,sha256=eDLHqv9mwgdde221pa47bTV87vCXwkUyjqsas-iFUrY,6123
10
- kiln_ai/adapters/test_generate_docs.py,sha256=M-uKcgF3hQmlEFOJ0o7DyL-9RgitGzkfROV-Dxtooec,2770
11
10
  kiln_ai/adapters/test_ollama_tools.py,sha256=xAUzL0IVmmXadVehJu1WjqbhpKEYGAgGt3pWx7hrubc,2514
12
11
  kiln_ai/adapters/test_prompt_adaptors.py,sha256=J1ZGZ8GG7SxP3_J3Zw0e6XmZY4NyPmUGX3IPgjh2LD8,7767
13
12
  kiln_ai/adapters/test_prompt_builders.py,sha256=5Xvfr-oQg_LLrle6UqfpRHWcPUYa8ywG3aL1rM7q1Jw,22054
14
- kiln_ai/adapters/test_provider_tools.py,sha256=mzMubpUupQu8pXhjDTj0_Kgrr-xcu_crj9xpcgcAzzA,26671
13
+ kiln_ai/adapters/test_provider_tools.py,sha256=7s-njUBm_TJCTeNOh4TrP7R-Q6TXILAxbv-GK0p3YPU,27446
15
14
  kiln_ai/adapters/data_gen/__init__.py,sha256=QTZWaf7kq5BorhPvexJfwDEKmjRmIbhwW9ei8LW2SIs,276
16
15
  kiln_ai/adapters/data_gen/data_gen_prompts.py,sha256=kudjHnAz7L3q0k_NLyTlaIV7M0uRFrxXNcfcnjOE2uc,5810
17
16
  kiln_ai/adapters/data_gen/data_gen_task.py,sha256=0PuYCcj09BtpgNj23mKj_L45mKZBdV5VreUeZ-Tj_xM,6642
18
17
  kiln_ai/adapters/data_gen/test_data_gen_task.py,sha256=cRKUKMvC0uVompbmPTKwbnQ_N3c0cQDm4J_9H4Y5U18,10129
19
18
  kiln_ai/adapters/eval/__init__.py,sha256=0ptbK0ZxWuraxGn_WMgmE1tcaq0k5t-g-52kVohvWCg,693
20
- kiln_ai/adapters/eval/base_eval.py,sha256=jVXMiVBC07ZnLEuZVAjUAYewsnuV99put39n_GZcG1M,7261
19
+ kiln_ai/adapters/eval/base_eval.py,sha256=IF4kYGt93bqJqSfj8UUaTng38fwPmi3cFKRSKUZhXJs,7381
21
20
  kiln_ai/adapters/eval/eval_runner.py,sha256=h3DvRFM5J5LDJqaLzNJ-q9i5LRycv2J9Ev5nw1mUDUQ,10806
22
21
  kiln_ai/adapters/eval/g_eval.py,sha256=d3UcBsZWeDt7cWp4uvDcfG7qdGLsGaZEBsIEqkpiWh4,15253
23
22
  kiln_ai/adapters/eval/registry.py,sha256=gZ_s0VgEx79Fswkgi1tS4yOl7lzpkvUBJZ62RldhM_w,626
@@ -26,20 +25,22 @@ kiln_ai/adapters/eval/test_eval_runner.py,sha256=82WPE_frNRTSQ2lylqT0inkqcDgM72n
26
25
  kiln_ai/adapters/eval/test_g_eval.py,sha256=-Stx7E0D-WAH1HWrRSp48CiGsf-no1SHeFF9IqVXeMI,16433
27
26
  kiln_ai/adapters/eval/test_g_eval_data.py,sha256=8caiZfLWnXVX8alrBPrH7L7gqqSS9vO7u6PzcHurQcA,27769
28
27
  kiln_ai/adapters/fine_tune/__init__.py,sha256=DxdTR60chwgck1aEoVYWyfWi6Ed2ZkdJj0lar-SEAj4,257
29
- kiln_ai/adapters/fine_tune/base_finetune.py,sha256=ORTclQTQYksMWPu7vNoD7wBzOIqNVK0YOwFEnvsKPWA,5759
30
- kiln_ai/adapters/fine_tune/dataset_formatter.py,sha256=qRhSSkMhTWn13OMb6LKPVwAU7uY4bB49GDiVSuhDkNg,14449
31
- kiln_ai/adapters/fine_tune/finetune_registry.py,sha256=CvcEVxtKwjgCMA-oYH9Tpjn1DVWmMzgHpXJOZ0YQA8k,610
32
- kiln_ai/adapters/fine_tune/fireworks_finetune.py,sha256=OlXp8j6Afwvk6-ySwA3Q7iuqBlKO7VLeAfNCnB3pZPI,19963
28
+ kiln_ai/adapters/fine_tune/base_finetune.py,sha256=g-lWuZMkOj2djcczuHke_Ai7Z7RPg41AFSgoxHgsw3U,5889
29
+ kiln_ai/adapters/fine_tune/dataset_formatter.py,sha256=ky48er7lMIS3Kv5WflaLpUDvWiVGYgl8QlI0M_wy6Vo,14409
30
+ kiln_ai/adapters/fine_tune/finetune_registry.py,sha256=9RJLjviSoN3dQnKJE9Ss7df7dtdJgbuShB8IUcI-q9k,726
31
+ kiln_ai/adapters/fine_tune/fireworks_finetune.py,sha256=ze0QxghpHAqwO9nXOTkDEC9irmqduX5bjIhZDU0DCZQ,20101
33
32
  kiln_ai/adapters/fine_tune/openai_finetune.py,sha256=Dz9E_0BWfrIkvv8ArZe-RKPwbIKPZ3v8rfbc3JELyTY,8571
34
- kiln_ai/adapters/fine_tune/test_base_finetune.py,sha256=sjuDgJDA_dynGRelx9_wXdssaxAYIuEG-Z8NzRx9Hl0,10559
35
- kiln_ai/adapters/fine_tune/test_dataset_formatter.py,sha256=T3jbFZooLVBaGCE0LUVxwPxzM3l8IY41zUj3jPk-Zi8,24027
36
- kiln_ai/adapters/fine_tune/test_fireworks_tinetune.py,sha256=oLyLEG4TwW452lV2mvUo-wImLxzSwOuoKKeYFuGh3k8,36744
33
+ kiln_ai/adapters/fine_tune/test_base_finetune.py,sha256=Tq0Klw7ou5_6H_bouTbI3PxYw7H30K32wlgWJE_luYk,10751
34
+ kiln_ai/adapters/fine_tune/test_dataset_formatter.py,sha256=kUGn2kv2jwosuabuhYgA3oXJXAdqK1AAaJI496ScOGY,24015
35
+ kiln_ai/adapters/fine_tune/test_fireworks_tinetune.py,sha256=NCl2U6ZqqJ8dnysGGmfir9RGcV-StPtoi5cetRjW6Zc,36754
37
36
  kiln_ai/adapters/fine_tune/test_openai_finetune.py,sha256=H63Xk2PNHbt5Ev5IQpdR9JZ4uz-Huo2gfuC4mHHqe0w,20011
38
37
  kiln_ai/adapters/fine_tune/test_together_finetune.py,sha256=BUJFsyq_g77gU0JN3hg6FMBvqb0DIyTeAek-wxomKIg,18090
38
+ kiln_ai/adapters/fine_tune/test_vertex_finetune.py,sha256=rAmcQJNPXqRacxg6RzjEQ8FNLKCp9qZRHToH7fm-7W0,19214
39
39
  kiln_ai/adapters/fine_tune/together_finetune.py,sha256=EbMPsTyKMubfwOalkFLiNFlMFIRKxLibzMTyLeUkle4,14010
40
+ kiln_ai/adapters/fine_tune/vertex_finetune.py,sha256=Ik6Ov711-oruJnMHpVZTPimWJY2W_JnfdKIdR2djGrc,8545
40
41
  kiln_ai/adapters/model_adapters/__init__.py,sha256=m5GRtOHwVVvp_XDOss8c1X3NFf1wQQlC2eBgI4tXQhM,212
41
- kiln_ai/adapters/model_adapters/base_adapter.py,sha256=ifPJMg0nEKamfOSmBIsnp_MRFfBs47FLeQrLbav34yA,9872
42
- kiln_ai/adapters/model_adapters/litellm_adapter.py,sha256=c4J_tIpM96KWS2qzoPaQmBj7X7mHyRMShdkmEh7_EHM,16129
42
+ kiln_ai/adapters/model_adapters/base_adapter.py,sha256=ishm_oVTNxSDC0GPrydHnyOPqp_U4XiTOx0-iI2fEiU,10433
43
+ kiln_ai/adapters/model_adapters/litellm_adapter.py,sha256=pbXFfJckyvptp577-YXGMG2hltYMFQrUT97PsSWa2KQ,16437
43
44
  kiln_ai/adapters/model_adapters/litellm_config.py,sha256=7-tIh5cuVu23Uy2Sd6q7UCT_4VgevBsAzVhQMj6Svgw,425
44
45
  kiln_ai/adapters/model_adapters/test_base_adapter.py,sha256=uQyKrHLN3Jha6R-6SWkEME6brQecVFdPTSXogo-xpt0,6556
45
46
  kiln_ai/adapters/model_adapters/test_litellm_adapter.py,sha256=QpnzuReNeBzvvRYnNj_5c8l1PS7NyrDDUQx_o21IIH4,13731
@@ -63,7 +64,7 @@ kiln_ai/datamodel/dataset_filters.py,sha256=hWKxGJ-mSl4y0igyNcpmRoRYCiGrf0_uN4MM
63
64
  kiln_ai/datamodel/dataset_split.py,sha256=q4l4SlUvjLV547bzk7Z-fbmj_o26GDcYOZ2rA5RPh3c,5612
64
65
  kiln_ai/datamodel/eval.py,sha256=kio2LqQ87MsP75DJTiIVdVfopTZXH4xjGN9g11V1mUU,13826
65
66
  kiln_ai/datamodel/finetune.py,sha256=TYoNVRAfbjqvrY-1YmHwG6xSoDljiJWuuVcTbvQAJL4,4569
66
- kiln_ai/datamodel/json_schema.py,sha256=qIlR8btXhN-8Yj5GhwebzPLUHPw2sJC3uM1axV2xV7w,3032
67
+ kiln_ai/datamodel/json_schema.py,sha256=o50wSp8frRXjT-NZjml4-Is7LNoF7DQP4g3AaaYzBfI,3379
67
68
  kiln_ai/datamodel/model_cache.py,sha256=9X4aAigbkFdytckgw8InCMh86uBna0ME_1HJSeMPEn0,4495
68
69
  kiln_ai/datamodel/project.py,sha256=uVH2_3TDFtsG_tpts81A-zbd9uPDFxAwMCKZt_km3IE,727
69
70
  kiln_ai/datamodel/prompt.py,sha256=70JPYHfgyX18cHW_DXoMzIOA28Jbaz6gyabElmpycyc,1161
@@ -71,17 +72,17 @@ kiln_ai/datamodel/prompt_id.py,sha256=eU2TV0RZapn-BgnZ4sOSNOOVEQ3aPaLzW4YSYCd3OB
71
72
  kiln_ai/datamodel/registry.py,sha256=XwGFXJFKZtOpR1Z9ven6SftggfADdZRm8TFxCEVtfUQ,957
72
73
  kiln_ai/datamodel/strict_mode.py,sha256=sm4Xka8mnJHCShtbh6MMU5dDQv-cLj8lHgHkmFKpsl0,849
73
74
  kiln_ai/datamodel/task.py,sha256=r-_zgrQCIiIkN8gvBISdU449Z9oKp7E1XL0lkik_rVI,7036
74
- kiln_ai/datamodel/task_output.py,sha256=uIYR8EyWv8Bbl60gPRuTIUSvfGGzP9Ltc5P280HyTpY,12931
75
- kiln_ai/datamodel/task_run.py,sha256=yquE0jyr_9WzcvrMsEmZfXUnn8zZDEZIXZhVcVBMrT8,7038
75
+ kiln_ai/datamodel/task_output.py,sha256=PqI7Lyeox5lh9mItMOtpqP9Rk_K9dyMltKYu1c2p7A4,13125
76
+ kiln_ai/datamodel/task_run.py,sha256=mVKmHn90iPmwXGja7TNgDA3iFzXBlamJ_6KndRPkhRA,7745
76
77
  kiln_ai/datamodel/test_basemodel.py,sha256=sJ8wXGef2WxzbrbMTYgrOwmkd5J6sHkly-cQBO2IZh4,18126
77
78
  kiln_ai/datamodel/test_dataset_filters.py,sha256=v88QPkIsq4diUmoUF3-qj5KAW2rLRp0KDAm_pexbFy4,1894
78
79
  kiln_ai/datamodel/test_dataset_split.py,sha256=5CHO1Lq4xQBB72tV2SPER7OZODJNvj15qxi_cYBV2Rs,11157
79
80
  kiln_ai/datamodel/test_datasource.py,sha256=H4Kc-Im9eM7WnADWZXdoiOIrOl05RtkyuhTCKiRimyU,3905
80
81
  kiln_ai/datamodel/test_eval_model.py,sha256=J7MqwWBgPpeXGqh3IacVUUHdZFJSZ2MgTsUNu-hNOJw,19528
81
- kiln_ai/datamodel/test_example_models.py,sha256=fpqh0u7zFhWHcRHgtxCjX8RD2oKHYOP_mJJymaUhEZU,20944
82
- kiln_ai/datamodel/test_json_schema.py,sha256=UgKwAFcdrJTq2byh7Yf-HoSAtiHiGAsNZxfkIvoMxIg,3915
82
+ kiln_ai/datamodel/test_example_models.py,sha256=nrr13ZseFn-OVGa9bjCwoVHTVqydy0O0yJah4QiqqbU,24326
83
+ kiln_ai/datamodel/test_json_schema.py,sha256=R0Cfc9WbieMslgvYsj2HFx8RHIq2fF9NcT5jH-kEqh4,4793
83
84
  kiln_ai/datamodel/test_model_cache.py,sha256=Fy-ucYNzS5JEG-8SFY4nVHA8iRbXXxai20f8_oGl97o,8184
84
- kiln_ai/datamodel/test_model_perf.py,sha256=NdD7L8XraGkunaEKGPsfYwdcbIgdjhFanOO3G6hU158,3235
85
+ kiln_ai/datamodel/test_model_perf.py,sha256=9_76f__5XtZSHSjuaoiHRj2t-z3OWn-sSA4S9kH1jpY,3306
85
86
  kiln_ai/datamodel/test_models.py,sha256=hmV7sTbOamWJCwOY96w-g4PQRv4Uai-XaHtg0QKH-ak,19295
86
87
  kiln_ai/datamodel/test_nested_save.py,sha256=xciCddqvPyKyoyjC5Lx_3Kh1t4LJv1xYRAPazR3SRcs,5588
87
88
  kiln_ai/datamodel/test_output_rating.py,sha256=zvPIp2shAgCs2RQBgwYoL09fRA3krHvgAqUa91RlWR0,15125
@@ -97,7 +98,7 @@ kiln_ai/utils/name_generator.py,sha256=v26TgpCwQbhQFcZvzgjZvURinjrOyyFhxpsI6NQrH
97
98
  kiln_ai/utils/test_config.py,sha256=Jw3nMFeIgZUsZDRJJY2HpB-2EkR2NoZ-rDe_o9oA7ws,9174
98
99
  kiln_ai/utils/test_dataset_import.py,sha256=ZZOt7zqtaEIlMMx0VNXyRegDvnVqbWY2bcz-iMY_Oag,17427
99
100
  kiln_ai/utils/test_name_geneator.py,sha256=9-hSTBshyakqlPbFnNcggwLrL7lcPTitauBYHg9jFWI,1513
100
- kiln_ai-0.14.0.dist-info/METADATA,sha256=EjgZOnknE7P9uW5BsIFJZYQAN-aUQ817SAEXjtqtjK0,12231
101
- kiln_ai-0.14.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
102
- kiln_ai-0.14.0.dist-info/licenses/LICENSE.txt,sha256=_NA5pnTYgRRr4qH6lE3X-TuZJ8iRcMUi5ASoGr-lEx8,1209
103
- kiln_ai-0.14.0.dist-info/RECORD,,
101
+ kiln_ai-0.15.0.dist-info/METADATA,sha256=80EooOjbu5b-7YgyfnOY9uYjFk8bo5czNWm3QgWaFys,12263
102
+ kiln_ai-0.15.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
103
+ kiln_ai-0.15.0.dist-info/licenses/LICENSE.txt,sha256=_NA5pnTYgRRr4qH6lE3X-TuZJ8iRcMUi5ASoGr-lEx8,1209
104
+ kiln_ai-0.15.0.dist-info/RECORD,,
@@ -1,69 +0,0 @@
1
- import logging
2
- from typing import List
3
-
4
- import pytest
5
-
6
- from libs.core.kiln_ai.adapters.ml_model_list import KilnModelProvider, built_in_models
7
- from libs.core.kiln_ai.adapters.provider_tools import provider_name_from_id
8
-
9
- logger = logging.getLogger(__name__)
10
-
11
-
12
- def _all_providers_support(providers: List[KilnModelProvider], attribute: str) -> bool:
13
- """Check if all providers support a given feature"""
14
- return all(getattr(provider, attribute) for provider in providers)
15
-
16
-
17
- def _any_providers_support(providers: List[KilnModelProvider], attribute: str) -> bool:
18
- """Check if any providers support a given feature"""
19
- return any(getattr(provider, attribute) for provider in providers)
20
-
21
-
22
- def _get_support_status(providers: List[KilnModelProvider], attribute: str) -> str:
23
- """Get the support status for a feature"""
24
- if _all_providers_support(providers, attribute):
25
- return "✅︎"
26
- elif _any_providers_support(providers, attribute):
27
- return "✅︎ (some providers)"
28
- return ""
29
-
30
-
31
- def _has_finetune_support(providers: List[KilnModelProvider]) -> str:
32
- """Check if any provider supports fine-tuning"""
33
- return "✅︎" if any(p.provider_finetune_id for p in providers) else ""
34
-
35
-
36
- @pytest.mark.paid(reason="Marking as paid so it isn't run by default")
37
- def test_generate_model_table():
38
- """Generate a markdown table of all models and their capabilities"""
39
-
40
- # Table header
41
- table = [
42
- "| Model Name | Providers | Structured Output | Reasoning | Synthetic Data | API Fine-Tuneable |",
43
- "|------------|-----------|-------------------|-----------|----------------|-------------------|",
44
- ]
45
-
46
- for model in built_in_models:
47
- provider_names = ", ".join(
48
- sorted(provider_name_from_id(p.name.value) for p in model.providers)
49
- )
50
- structured_output = _get_support_status(
51
- model.providers, "supports_structured_output"
52
- )
53
- reasoning = _get_support_status(model.providers, "reasoning_capable")
54
- data_gen = _get_support_status(model.providers, "supports_data_gen")
55
- finetune = _has_finetune_support(model.providers)
56
-
57
- row = f"| {model.friendly_name} | {provider_names} | {structured_output} | {reasoning} | {data_gen} | {finetune} |"
58
- table.append(row)
59
-
60
- # Print the table (useful for documentation)
61
- print("\nModel Capability Matrix:\n")
62
- print("\n".join(table))
63
-
64
- # Basic assertions to ensure the table is well-formed
65
- assert len(table) > 2, "Table should have header and at least one row"
66
- assert all("|" in row for row in table), "All rows should be properly formatted"
67
- assert len(table[0].split("|")) == len(table[1].split("|")), (
68
- "Header and separator should have same number of columns"
69
- )